Rendered from docs/process/decisions/README.md in the Headwater
corpus. Every document on this half of the site is typed by the taxonomy
the descriptor names: corpus.json.
Process decisions
The documents on this shelf, in the reading order this corpus derives.
- Orchestration prose has one owner per sentence — Every sentence of orchestration prose has exactly one home, decided by who must obey it and whether it changes per dispatch. So the command holds only what the parent decides and each agent loads only what it must obey. (asserted, and no human has accepted it)
- Adjudication is a separate stage, and refusal is licensed — Adjudication runs as its own stage before construction, and its prompt licenses refusal. That is because a run that separated them returned a refusal or a correction from six of eight slots. The separation costs one parent turn per issue, and that cost is paid. (asserted, and no human has accepted it)
- A dispatch pays when it retires more parent turns than it costs — The unit of orchestration cost is one parent turn at full context. So a dispatch is worth making only when it retires more parent turns than the one it spends. The integrator passes that test, and a fresh agent per poll fails it. (asserted, and no human has accepted it)
- Coordination is a create-only claim, and authority stays on the tree — Workers coordinate through create-only claim files that every worktree can reach and the parent never relays. By contrast, the merge veto and a re-verification stay messages from the parent, because a peer's message carries no owner authority.
- The ledger is split, its tabular parts are JSONL, and its totals are derived — The run ledger is one directory of small files rather than one markdown file. Its per-iteration log and its findings are JSONL read by the line, and every total is derived and never stored. A database is deferred until a cross-run question asks for one. (asserted, and no human has accepted it)
- The entrypoint keeps its name and becomes a resumable run — The build order keeps the name next-run and gains a run directory it writes as it goes. That way, a compaction, a crash or a second invocation resumes from a doctrine block of ten lines and a log read by the line. Each stage's model is declared in its own frontmatter. (asserted, and no human has accepted it)
- A background wait caps below the cache lifetime and re-issues itself — A wait that might outlive the five-minute prompt-cache lifetime is wrapped in a timeout under it and re-issued on return. So a background wait still ends the turn without paying to rewrite a context the cache would otherwise have kept warm. (asserted, and no human has accepted it)
- The board has an owner of its structure, and its milestones are capped versions — One agent owns where work sits on the board and never what the work is, and each milestone is a capped version. (asserted, and no human has accepted it)
- A release gets all its assets in one create call, and a person deletes it to run again — A release is immutable once gh release create returns, so every asset goes into that one call. A second run refuses, and a person deletes the release to retry. (asserted, and no human has accepted it)
- Each release workflow compares the tag with the version its artifact states and refuses an empty reading — Each release workflow refuses a tag whose version differs from its artifact. It reads under pipefail and refuses an empty reading, because the default shell passed every tag. (asserted, and no human has accepted it)
- Crates publish in one fixed order that a test holds, and a rerun continues where the last run stopped — publish-crates.yml walks one leaves-first crate list that publish_order.rs holds, skips a published crate, waits for the index, and waits out a 429. (asserted, and no human has accepted it)
- The release workflows are separate from CI, one tag value serves both entry points, and fixtures read them statically — Release workflows are files apart from ci.yml and read the tag from one step output. No pull request runs them, so fixtures read their text. (asserted, and no human has accepted it)
- Self-hosted eligibility in CI is decided by the event alone, and a push to any branch is eligible — Only github.event_name decides whether a CI job may run on the self-hosted pool. A push is eligible on every branch, and a pull request never is. (asserted, and no human has accepted it)
- The boundary against a fork is the approval of outside runs, and a person reads a .github diff before approving one — No expression in ci.yml defends against a fork. The approval setting for outside contributors is the boundary, and the reader of a .github diff enforces it. (asserted, and no human has accepted it)
- A condition in CI may take work away and never grant it, so one run per commit comes from a job-level if — The job-level if skips a duplicate pull_request run and grants nothing. No trigger filter replaces it, and each job name stays a literal. (asserted, and no human has accepted it)
- CI_RUNNER is an opt-in that only a push or a merge group reads, and an unset value falls back to ubuntu-latest — The self-hosted labels reach runs-on only when the CI_RUNNER variable names them and the event is a push or a merge group. The default is a hosted runner. (asserted, and no human has accepted it)
- CI concurrency is per ref, and every ref but main cancels a superseded run — A newer push cancels the older run on the same branch or pull request. Runs on main never cancel, because each merge needs its own verdict. (asserted, and no human has accepted it)
- A router sends a push or merge group run to a hosted runner when the self-hosted pool is full, and it can only take work away — The route job counts the jobs on the self-hosted label and outputs overflow. A failure in it gives an empty output and changes no routing. (asserted, and no human has accepted it)
- CI runs actions from the actions organization only, and carries no build state between self-hosted jobs — Only actions from GitHub's own organization run in ci.yml. No self-hosted job inherits engine/target from another, and sccache makes a cold target cheap. (asserted, and no human has accepted it)
- Merges go through the GitHub merge queue, one squash commit per pull request — The integrator hands each ruled pull request to the GitHub merge queue. The queue tests up to five at once on the group tip, and lands one squash commit per pull request.
- A subagent waits in the foreground, because a background wait wakes its parent — A stage runs its bounded wait in the foreground and keeps its turn. A background wait ends the stage's turn, and each attempt then wakes the parent at its full context.
- The verify and rework loop for one issue runs below the parent — One agent per issue, hw-iterate, dispatches the builder and each verifier and sends every FAIL back to the same builder. It reports to the parent once per issue, and again only after the parent sends it a message. The parent rules the final PASS and never reads the branch with git show or git diff.
- A build-order parent restarts every few merges, drains to zero first, and resumes from the handover files on disk — A loop script restarts the build-order parent when a call passes 130k tokens of context or the session reaches four merges. The parent drains to zero before it exits, and the next session resumes from the handover file of each issue.
- A document that moves to a process shelf keeps its identifier — A specification, an evaluation or an obligation record that moves from a product shelf to a process shelf keeps its identifier. Each process kind binds the scheme of the product kind it mirrors, and the move rewrites every relative link to the file. (asserted, and no human has accepted it)