saphan gate
Record a HUMAN gate decision for a stream (the only fleet_gate writer, §3.2)
saphan gate
Record a HUMAN gate decision for a stream (the only fleet_gate writer, §3.2)
Record one human gate decision for a stream, appended to the fleet_gate audit log (§1.1). The engine transports the decision, it never makes one: there is no default decision, no engine actor, and no "merged" decision — merged is only ever OBSERVED from a real merge commit (§1.7). A decision that would skip a gate in the §3.1 order is refused with a STOP list and exit 2; nothing is written on refusal.
The §3.1 order binds BACKWARD too: a gate sitting EARLIER in that order
than one this stream has already resolved is refused by the named class
gate-out-of-order, because recording it asserts an event that never
happened — a true act under a wrong label. A deliberate late correction is
still possible, and it must say so in the record: pass
--out-of-order "<why>". The reason is the flag's own VALUE, so a flag with
no ground is not representable; the ground is folded into the recorded
row's detail, inside the signed bytes.
saphan dry-run gate runs the SAME validation the real write runs (CheckGate,
the identical seam RecordGate calls — never fleet next's state-only
projection, which cannot see the act's arguments) and writes NOTHING TO
fleet_gate: no row, no signature. It is NOT a read-only invocation of the
engine as a whole — like every other verb, it reconciles the channel first
(§2.4), which DOES ingest fresh channel activity into fleet_event/
fleet_session exactly as the real write's own preamble would (review F-3:
an earlier version of this text claimed "nothing written" outright, which a
first invocation on a fresh workspace measurably contradicts). An
inadmissible act refuses with the IDENTICAL reason text a real write would
print; an admissible act prints the row that would be inserted and the
stream's next state, then exits 0.
The teardown gate (adr-0018) is NOT recorded here. It records that a human
may now remove the stream's worktree — the engine NEVER removes anything —
and that decision belongs to saphan teardown, which writes the IDENTICAL
signed row on top of the archive commandment 01 requires first: the channel
family, the return manifest, .provision/ and the provisioned bytes, plus the
provisioned-sha-must-be-resolvable check over the run record's citations.
This verb archives none of that, so --gate teardown refuses here and
prints the equivalent saphan teardown command with the same --actor,
--note and --return arguments already folded in. It is one decision with one
road, not a capability withdrawn: everything the gate verb enforced for it —
merged projection, git's untracked-guard over non-ignored strays, a --return
disposition for every "- artifacts:" manifest entry, the named refusal of a
status still using the pre-fix "- return:" key — is the same
routing.RecordGate check running inside that verb.
The review gate (order verdict-in-record-v1) records the reviewer's judgment
— accept/conditions/reject — as a review-class record fact: JUDGMENT, never
the owner's own decision (§1.10 — a recommendation, not a gate the reviewer
advances themself) and never mechanical follow-through either. It never
advances the stream lifecycle by itself; saphan merge consults the
INGESTED _REVIEW_STATUS verdict only for its PRESENCE: a non-empty verdict
means the review lane is engaged. Once engaged, merge refuses unless the
latest recorded fleet_gate review decision is accept OR conditions
(conditions is not a refusal, it is more work owed, and still counts as the
human's gate); reject, or the absence of any review-gate row at all, refuses
— the raw token's value never substitutes for this recorded row.
Subcommands
| Subcommand | What it does |
|---|---|
saphan gate batch | Record many explicit owner gate decisions after one fleet reconcile |
Options
| Option | Type | Default | Description |
|---|---|---|---|
--actor | string | unset | the human deciding (falls back to env SAPHAN_ACTOR, then ~/.saphan/config's identity.actor; the engine is never an actor) |
--decision | string | unset | the decision: accept | conditions | reject | ready-to-merge | closed-without-merge (stop1/stop2 only — closes the leg WITHOUT a merge, §1.1) (required, no default) |
--gate | string | unset | which gate: stop1 | stop2 | merge | promotion | review (required, no default; the teardown gate is recorded by 'saphan teardown', which writes the same row on top of the archive it requires first) |
--note | string | unset | free-form audit detail (names and references only, §1.6) |
--out-of-order | string | unset | deliberately record a gate that sits EARLIER in the §3.1 order than one this stream already resolved: the flag's VALUE is the required ground, folded into the row's detail (a blank value is no flag at all — the act is then refused as gate-out-of-order) |
--ref | string | unset | recommendation reference: path/id of the review return the decision gates |
--return | stringArray | [] | retained for the refusal's own remedy: this flag belongs to 'saphan teardown', and a --gate teardown act named here is refused with these dispositions folded into the printed command |
saphan gate batch
Record many explicit owner gate decisions after one fleet reconcile
Record one owner gesture as N separate, signed fleet_gate rows after ONE channel reconcile. The input is one JSON object with a non-empty "decisions" array. Every item must explicitly carry stream, gate, decision, and a non-empty note; recommendation_ref and out_of_order are per-stream optional fields. Only owner-class gates are admitted by this owner surface.
The batch is intentionally not transactional. Every item is attempted in file order. Integrity refusals are named per stream and do not hide successful rows: the final outcome is "partial" when some rows landed and some refused, "refused" when none landed, and "complete" only when every item succeeded. An unexpected engine/store error names the current item and every remaining item as not-attempted. Re-running is safe because already-recorded decisions are reported explicitly.
saphan dry-run gate batch uses routing.CheckGate for EVERY item, previews each admissible row, reports each refusal, and writes no fleet_gate rows. It still performs the one shared reconcile, exactly like the real batch and the singular gate verb.
Options
| Option | Type | Default | Description |
|---|---|---|---|
--actor | string | unset | the human deciding (falls back to env SAPHAN_ACTOR, then identity.actor) |
Examples
Everything below this line is written by hand and is not regenerated.
Accepting a return
Recording a reviewer's verdict, with the artifact it points at
⚠ --ref is the durable path the delivery minted, not a file name you compose. It exists
only after the verdict has been brought home, which is why the review gate cannot be recorded
before that step.
Closing a stream that will never merge
Not every stream ends in a merge, and a stream that ends without one still needs a closing decision on the record — that is the normal shape for a review or a probe, not an error.
Rehearse before you record. Prefixing the same line with dry-run performs every read
the real act performs and writes nothing, so you see the refusal — or the state change it
would make — before the record moves.