Merging
The gate sequence, why a merge is a human act, and the two-stage close that follows it.
Merging
The gate sequence
Six gates exist: stop1, stop2, review, merge, promotion, teardown. Five decisions are writable: accept, conditions, reject, ready-to-merge, closed-without-merge. Which decisions each gate accepts is a closed list, and a pair outside it is refused by name.
⚠ merged is not on that list, and its absence is the design. It is not a decision anyone
may record — it is a git observation. There is no writable path to it anywhere in the
product.
The ordinary path, once a stream has returned its finished status:
--gate merge requires the stream's latest stop-2 decision to be accept, re-read from the
record rather than trusted from the caller. When a review lane is engaged, --gate review
records the reviewer's judgement, and the merge refuses while that judgement is on record with no
decision answering it.
⛔ A gate is never skipped. Every refusal in this sequence names the state the stream is actually in and the state the act needed.
If you would rather be told than remember:
One read gives the stream's resolved state, every gate it still owes forward to a terminal, each act the record makes legal from here with a ready command, and each act it does not with that act's own refusal text.
The merge itself
The rehearsal previews the ordinary preconditions and the composed commit message. It does not run the conflict probe and it does not land.
The act verifies its preconditions read-only, before git is touched: the stream stands at a gated accept or at ready-to-merge, the merge gate is legal, the branch exists, the base is checked out and clean, the work is not already merged, and the base has not diverged from its remote. Any failure is a named refusal with a remediation line, and nothing is landed. After those checks it materializes the current branch-and-trunk pair in a detached scratch tree and merges there, with no test suite: a conflict refuses and names the unmerged paths; a clean probe lands in the same serialized act. The commit message is composed from the record and reaches git byte-exact, blank lines included, and the resulting commit's trailers print as proof-of-done.
A merge is a human act
This is worth stating plainly for anyone who has to answer for it later.
The product holds one mutating merge command. Its arguments are fixed inside the product —
there is no caller-shaped git — and it is reachable only from the verb a human invokes, after the
preconditions verified. --actor names that human, and the invocation is the act: the engine
executes a decision, it never makes one.
Everything else the product does to git is either a read, from a small closed allowlist of subcommands that are read-only in every form, or one of a short list of individually named operations whose arguments are likewise fixed: the merge above, importing a branch from a local bundle file, provisioning a local landing repository, creating and removing working trees, and the detached probes. None of them accepts a URL or a remote name. There is no push path anywhere in the product, and the closing gate cannot be reached by adding a flag.
The two-stage close
Merging is not the end. Teardown is a second, separate decision, and it stands on a fact the product read rather than a fact it asserted.
-
Merge — as above. The merge commit exists.
-
The record shows merged —
mergedenters through exactly one door, the observation:This is why stage two exists as a stage. The product will not write "merged" from having performed a merge; it writes it from having looked.
-
Only then, teardown:
It archives the stream's channel documents into that stream's channel archive, verified byte-exact against a generated checksum manifest, and then records the teardown gate's accept. The teardown gate admits only
accept— a teardown you decline is a refusal, loud and unrecorded, never a decision row. The archive happens before any removal, so the channel survives the tree.
⚠ Both terminals admit a teardown: a stream closed without a merge has a live worktree with no merge ahead of it, and it needs a legal end too.
Verifying what came home
What to measure before anyone gates it — including the branch merged onto its trunk — and the three things a green result has to name.
Pull requests and forge integrations
What the product does and does not do against your forge, what a forge-side merge is designed to require, and where the pull-request path stops on this release.