Six months after an edition ships, somebody will ask who was allowed to publish it and which checks actually ran. If the only copy of that procedure is the runner at HEAD, you are reading today’s code and calling it last August. The runner will have changed. Put the procedure in a file the edition can point at.
Listing the tools is the easy part, and people stop there. The rest is
who may draft, fail a check, kill the piece, or hit publish. If the
writer can also publish, stop.publish: human is lying.
Newspapers print a masthead for this. Camunda draws it as swimlanes. A wiki page of the procedure will get edited in place, and then you cannot say which wording an old edition used. The edition needs an id and a hash, which means the procedure has to live in a file you can hash.
People reach for UML here. Class diagrams describe objects, so they’re the wrong drawing. Swimlanes are the useful one: writer, machine, checker, desk, publisher. Draw those off the JSON if you want them on a wall.
Calling it
You ask for work under a named process. Something like: draft the 26 August
waste volume under ledger-monthly-v1. A connector opens that
pack, runs the tools in order, and writes process plus
process_hash on the new edition. If the pack says a human
publishes, it stops, and the writer can’t override.
Tighten the monthly checks in September and that’s a new pack with a new hash. The August edition still points at the old one. Daily specials that skip the long check need their own pack. A flag in the runner feels neat until October, when you can no longer tell which branch ran.
Checkers have limits. A URL grader will miss a date that isn’t on the page it opened. That belongs in the checker’s notes. The process only has to say whether that checker ran, and whether anything ran after it.
What we actually store
The in-tree example is small on purpose. desk-docket-v1 is an
editor, a connector, and a human publish stop. That validates today.
{
"id": "desk-docket-v1",
"version": "1",
"cites_type": "docket",
"steps": [
{ "tool": "docket-editor", "as": "editor" },
{ "tool": "docket-webmcp", "as": "webmcp" }
],
"stop": { "publish": "human" }
}
Ledger’s monthly walk needs more than that: named roles, a gate after verify so blockers send it back, desk can kill the line, publish is a different person, and a record of the run. Those keys type-check if you put them in. They aren’t required yet. The connector that would enforce them isn’t finished.
{
"id": "ledger-monthly-v1",
"version": "1",
"cites_type": "edition",
"roles": {
"writer": { "may": ["draft"] },
"desk": { "may": ["edit", "kill"] },
"verifier": { "may": ["grade"] },
"publisher": { "may": ["publish"] }
},
"steps": [
{ "id": "draft", "tool": "volume-shell", "role": "writer" },
{ "id": "lock", "tool": "lock-gate", "role": "system" },
{ "id": "verify-cited", "tool": "verify-prompt", "role": "verifier" },
{ "id": "census", "tool": "sentence-census", "role": "verifier" },
{ "id": "desk", "tool": "draft-desk", "role": "desk", "human": true },
{ "id": "publish", "tool": "draft-desk", "role": "publisher", "human": true }
],
"gates": [
{ "after": "verify-cited", "pass": "blockers == 0", "fail": "return:draft" },
{ "after": "desk", "pass": "desk.approve", "fail": "kill" }
],
"stop": { "publish": "human", "kill": "desk" },
"record": ["job_runs", "verdicts", "approvals"]
}
Bump version when the walk changes. Leave the old file on
disk. cites_type is the kind of piece this is for, and it
can’t be process. Don’t copy the steps onto the edition:
process: ledger-monthly-v1 process_hash: sha256:…
If you paste the steps into the docket, editing the docket looks like
editing the procedure. The procedure stays in profiles/process.
Most prims never point at one of these. Siliconfall Score
is tracks and a player. Don’t mint prim.pipeline. The order
and the permissions already live in this file.