In-turn gates: agents run the runner-owned gate CLI before stopping; SubagentStop shrinks to a presence check #477
Labels
No labels
P0
P1
P2
P3
bug
create
delete
enhancement
filed-by/agent
filed-by/user
frozen
lint-rule
needs-info
needs-triage
next
plugin/cc-architect
plugin/os
plugin/os-adr
plugin/os-aidd-lint
plugin/os-backlog
plugin/os-context
plugin/os-doc-hygiene
plugin/os-sdlc
plugin/os-vault
project/cc-os
ready-for-agent
ready-for-human
recurring
review
update
waiting
wayfinder:grilling
wayfinder:map
wayfinder:map
wayfinder:research
wayfinder:task
wayfinder:task
wontfix
worklist/deviations
worklist/lint-rule
worklist/new-implement-build
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
jared/cc-os#477
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Problem Statement
Gate execution (tests, lint) currently runs after an agent stops, inside machinery spawned from the SubagentStop hook. Because gates take minutes and the hook has seconds, ADR-0140 added a detached settlement process: spawn, pid stamp, liveness probe, a
gates_settlingstate, and anUnsettlederror path. This solves a timing problem the design itself created. It also makes correction loops slow: a programmer whose change fails the gate only learns after its dispatch ends, and the fix costs a full dispatch round-trip. The operator maintains an async state machine whose only purpose is to move a verdict from one process to another.Solution
Move gate execution inside the agent's turn. The producing agent runs a runner-owned
gatesubcommand as the final act before it stops, and iterates until it reaches its required outcome — the programmer until green, the test-writer until red for the right reason. The runner executes the gates and writes step results and the verdict to the pipeline database itself; the agent can invoke the gate but cannot author the result. SubagentStop keeps its role as the unconditional final record, but shrinks to a millisecond presence check: if a gate verdict is on the dispatch, route on it; if the agent stopped without gating, stamp a loud error verdict and let the map route the failure. The detached settlement machinery — spawn, pid, liveness,gates_settling— is deleted, not replaced. The async problem is not solved; it stops existing.This supersedes ADR-0140 and inverts the "agents never run tests" contract for gated roles. Precedent already exists: the test-writer's red-assert/green-assert path is an agent invoking a runner-owned gate CLI today.
User Stories
nextto route on a verdict that is already present, so that thegates_settlingpolling state and its retry logic disappear from my contract.Implementation Decisions
gate <dispatch_id>on the runner CLI, replacingsettle-gatesone for one. It resolves the dispatch, its implementation, and its map node; builds the gate command hash; runs each gate; records step results; and stamps the verdict — synchronously, returning before the agent's turn ends. The rewritten settlement class is its body; the gate-verdict runner, gate-command builder, step-result recorder, and verdict stamper are reused unchanged.errorwith a gate-skip reason recorded on the dispatch, routed by the map's existing error edge. No new verdict value, no new state. The agent-sourced-verdict branch is unchanged.nextloses settlement resolution. Thegates_settlingpayload, the settlement model (queue, resolve, pid liveness, the unsettled error), the detached and inline settlement classes, and the settlement seam are deleted.nextroutes on a present verdict; an absent verdict on a completed dispatch is impossible by construction after intake runs.Testing Decisions
gatewith stubbed pass and fail commands; assert step-result rows and the stamped verdict.nextroutes on a present verdict and that thegates_settlingstate is gone.Out of Scope
Further Notes
Decomposition
VERDICT: CREATE — hard floor, explicit user-approved work (skeptic gate 2026-08-22).
Decomposed into children #478-#481; supersession ADR being recorded on main thread. Skeptic verdict: CREATE.
Work starting on branch worktree-477-in-turn-gates via os-sdlc pipeline.
Resolution
Done: In-turn gate execution shipped: gated producers run the runner-owned 'os-sdlc-runner gate DISPATCH_ID' in-turn and iterate until green; CompletionIntake is a fail-closed presence check stamping error/gate_skip on a missing verdict; detached-settlement machinery, settlement_pid/settlement_started_at columns (schema 15), and gates_settling routing removed; gated map nodes carry the inverted role contract. ADR-0141 committed, superseding ADR-0140; ADR-0139 untouched.
Evidence: Commits
e578c1b(implementation) and11d7e09(ADR-0141) merged fast-forward to main. Full suite 1017 runs, 2593 assertions, 0 failures; rubocop 12 files, 0 offenses. Reviewer (opus) verdict pass after one correction round; gate tests pin in-turn synchrony, fail-closed gate_skip, and the crashing-gate error path.Follow-ups: Existing ticket #481 carries the deferred items: stale docs (deterministic-gates.md, CONTEXT.md, implement/SKILL.md, pipeline-state-investigate/SKILL.md), GateSettlement->GateRun and settlement_step_output renames, gates_settling negative assertion, BUSY_TIMEOUT_MS decision, ADR-0097/0107/0134/0137 amendments. Closing #470 as superseded is left to the user. No new tickets captured.