Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 6 additions & 6 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,11 @@ never rebuild the gate by hand.

1. Before dispatching `docket-implement-next`, run `run.gate-before` with `implement-next`. It prints
`gate-armed <key> <epoch> <dispatch-context>`; keep all three (they won't survive the next tool
call) and copy the `<dispatch-context>` into the dispatch prompt. The `<epoch>` is the run epoch id
you thread into `run.cancel --epoch` (below) and every `--run-epoch` dispatch flag (`agent.enter`,
`gate drive start`, `gate drive prepare-scope`). Add `--resume <id>` to arm for resuming an
already-in-progress change. `gate-unarmed` still lets you dispatch, but keyless (step 2's fallback)
and can never authorize a re-dispatch.
call) and copy the `<dispatch-context>` and the `<epoch>` into the dispatch prompt. The `<epoch>`
is the run epoch id you thread into `run.cancel --epoch` (below) and every `--run-epoch` dispatch
flag (`agent.enter`, `gate drive start`, `gate drive prepare-scope`). Add `--resume <id>` to arm
for resuming an already-in-progress change. `gate-unarmed` still lets you dispatch, but keyless
(step 2's fallback) and can never authorize a re-dispatch.
2. After the run returns, or its completion notification arrives, run `run.gate-verdict`
with `<key>`; without a key, run it with `--unattributed` plus any change id the notification
names. Obey the resulting `gate-*` report line exactly, never its exit code or the child's prose.
Expand Down Expand Up @@ -95,7 +95,7 @@ the existing agent (or re-dispatches with the change id and continuation id) as

For Codex, description markers select the native launch over the general named-child wording. `[docket launch: root-coordinator]` takes precedence: foreground catalog-resolved `agent.enter` at the caller cwd. Otherwise `[docket worktree: feature]` requires foreground catalog-resolved `agent.enter` with the owning workflow's exact `--worktree`; an unmarked metadata child uses direct native named-agent dispatch.

For any `agent.enter` route: Write a request file containing the user's request unchanged; for implement-next include the unchanged gate dispatch-context token, labeled for `change.claim --gate-context` and gate-drive operations. Preserve resume/continuation ids and gate keys. Pass `--request`, `--role`, the active absolute caller `--cwd`, approval policy, and sandbox; pass the owning workflow's exact `--worktree` explicitly for feature children. Never omit dispatch context.
For any `agent.enter` route: Write a request file containing the user's request unchanged; for implement-next include the unchanged gate dispatch-context token, labeled for `change.claim --gate-context` and gate-drive operations, and the unchanged run epoch, labeled for `--run-epoch` on prepare-scope and build-owned starts. Preserve resume/continuation ids and gate keys. Pass `--request`, `--role`, the active absolute caller `--cwd`, approval policy, and sandbox; pass the owning workflow's exact `--worktree` explicitly for feature children. Never omit dispatch context.

A shell-tool yield carrying a live task/session identity is a liveness transition, not completion. You must retain that exact task/session identity and collect its terminal exit and final output through the harness-native observation/wait mechanism. Never re-run `agent.enter`, start a second watcher, or return a completion report while the original task remains live or unobserved. Only after terminal output is collected may implement-next run the parent's keyed `run.gate-verdict` and obey its report. Coordinator prose, thread or turn ids, and process exit alone do not prove gate ownership or completion. Do not substitute `codex exec`, another harness, a generic agent, or a parent relay.
<!-- docket:dispatch:end -->
Expand Down
10 changes: 5 additions & 5 deletions cursor-rules/run-gate.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,11 @@ never rebuild the gate by hand.

1. Before dispatching `docket-implement-next`, run `run.gate-before` with `implement-next`. It prints
`gate-armed <key> <epoch> <dispatch-context>`; keep all three (they won't survive the next tool
call) and copy the `<dispatch-context>` into the dispatch prompt. The `<epoch>` is the run epoch id
you thread into `run.cancel --epoch` (below) and every `--run-epoch` dispatch flag (`agent.enter`,
`gate drive start`, `gate drive prepare-scope`). Add `--resume <id>` to arm for resuming an
already-in-progress change. `gate-unarmed` still lets you dispatch, but keyless (step 2's fallback)
and can never authorize a re-dispatch.
call) and copy the `<dispatch-context>` and the `<epoch>` into the dispatch prompt. The `<epoch>`
is the run epoch id you thread into `run.cancel --epoch` (below) and every `--run-epoch` dispatch
flag (`agent.enter`, `gate drive start`, `gate drive prepare-scope`). Add `--resume <id>` to arm
for resuming an already-in-progress change. `gate-unarmed` still lets you dispatch, but keyless
(step 2's fallback) and can never authorize a re-dispatch.
2. After the run returns, or its completion notification arrives, run `run.gate-verdict`
with `<key>`; without a key, run it with `--unattributed` plus any change id the notification
names. Obey the resulting `gate-*` report line exactly, never its exit code or the child's prose.
Expand Down
5 changes: 4 additions & 1 deletion docs/reference/glossary.md
Original file line number Diff line number Diff line change
Expand Up @@ -940,7 +940,10 @@ docket workspace publish --id 412 --head <sha>

**Arming** (`run.gate-before`) mints three values before a dispatch: the **gate key** (ties a finish
to this launch), the **run epoch** (the id of this run, threaded into cancel and drive flags), and
the **dispatch context** (a token copied into the dispatch prompt). It prints
the **dispatch context** (a token). The dispatch context and the run epoch are both copied into the
implement-next dispatch prompt; a scope prepared with `--run-epoch` hands that epoch to every scoped
start under it, so build-task workers never receive it (except the repair worker, for its
build-owned post-fix re-run). It prints
`gate-armed <key> <epoch> <dispatch-context>`; `gate-unarmed` still allows a keyless dispatch that
can never authorise a re-dispatch.

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<!-- docket:backlink:start (generated — do not hand-edit) -->
> ↩ **[Change 0467 — Scoped gate starts inherit the run epoch; thread it through the build chain](https://github.com/danielhanold/docket/blob/docket/docs/changes/active/0467-document-run-epoch-in-the-docket-build-task-gate-drive-start.md)**
<!-- docket:backlink:end -->
# Scoped gate starts inherit the run epoch; thread it through the build chain — Results

**Human action:** None needed to merge. After merging, rebuild the installed `docket` binary (the usual post-merge reinstall), because the installed binary still has the old driver behavior until then.

## Outcome

During change 0461's run, a build worker's test-gate start was refused with `stale-run-epoch`. The worker only got through by guessing that it should pass `--run-epoch`. The cause had two parts. The "run epoch" (the id the parent's run gate prints when it arms a run) never reached the child agents, and the gate driver ignored the epoch pinned on a worker's recovery scope, looking only at the value the caller passed in.

This change fixes both:

- **Driver.** A scoped gate start now inherits the run epoch its scope was prepared with, so a worker that passes no epoch is admitted. A start that presents a *different* epoch is still refused. The build-owner fast-path check in the app layer (`startBudgetedBuild`) now uses the same effective epoch. Before this, it could refuse a start that the real admission check would have allowed.
- **Skill prose.** `docket-implement-next`, `docket-build`, and `docket-build-task` now say where the epoch goes: it is passed as `--run-epoch` to every `prepare-scope` and to every build-owned suite start. Ordinary task workers never handle it. The one exception is the repair worker, which is handed the epoch for its build-owned re-run after a fix.
- **Parent instructions.** The managed run-gate block in `AGENTS.md` (and `cursor-rules/run-gate.md`) now tells the parent to copy the `<epoch>` into the implement-next dispatch prompt. On Codex, the dispatch prompt is the `agent.enter` request file, and that route now carries the epoch too.
- **Guards.** New repoguard tests pin each of these threads, and each one was mutation-tested. The `AGENTS.md` dispatch-block word budget was re-baselined from 1137 to 1153, which is still below its 1156 ceiling.

## Verification performed

- Full suite (`go run ./cmd/docket development test`) passed through the build-owned gate at the Task 3 head: 66/66 files. A final certification run at the PR head is recorded in the PR's build-evidence block.
- Whole-branch deep review returned 1 blocker, 2 important, and 1 minor finding. All four were fixed on the branch (commits `7fb799d08`, `6c9226f54`, `18db4ba15`, `c7a4c8e29`), and each fix's worker ran focused tests. No second review round was run, per policy.
- The budget report printed `PARALLEL-SENSITIVE` / `BUDGET WATCH` screening lines for existing slow integration tests. None of those tests is touched by this change, and no serial-confirmed breach was reported.

## Known issues and follow-ups

### Dispatch-block word budget is nearly full

The `AGENTS.md` dispatch block is now 1153 words against a hard ceiling of 1156. The next change that adds wording to that block will have to trim something first. This is confirmed, has no runtime impact, and only affects authors. Suggested next step: trim the block the next time it is edited.

### Installed binary lags until reinstall

Until the post-merge reinstall, the installed `docket` binary still refuses epoch-less scoped starts. Any run that happens before then needs `--run-epoch` passed explicitly, as this run did. Rebuilding per the repo's post-merge rule removes the issue.
Loading
Loading