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
29 changes: 19 additions & 10 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -390,16 +390,25 @@ workflow, not optional conveniences — use them at the point named, every time:
the 2026-08-01 incident this check exists for was a silent worktree-escape
where ~1700 lines of half-finished output had already landed directly in
the coordinator's live tree by the time the lane reported back.
- **Before squash-merging any PR**: `devtools workspace merge-gate record <PR>
--command "devtools verify"` (or a narrower test selection) against the
PR's current head, then `devtools workspace merge-gate check <PR>` —
BLOCKs unless a fresh receipt exists for the exact head sha and no review
comment (inline, issue-level, or review-summary) is newer than the head
commit's timestamp unless explicitly `ack`'d. This replaces "remember to
grace-period-poll and remember to run the broader suite CI skips" with one
command; it is not automatic (a coordinator still has to remember to run
it), so treat it as a required step in the merge checklist below, not an
optional nicety.
- **To squash-merge any PR**: use `devtools workspace merge <PR>` instead of
a bare `gh pr merge --squash` — it wraps `merge-gate record`/`check` at the
actual merge boundary instead of leaving them a step a coordinator must
remember. It auto-records a receipt if none is fresh for the current head
sha (running `--command`, default `devtools verify`), BLOCKs the merge on
any `merge-gate check` failure (no fresh receipt, stale receipt, nonzero
exit, or an unacked review comment newer than the head commit), strips a
doubled `(#N) (#N)` squash-subject suffix, then runs the actual
`gh pr merge --squash`. `--dry-run` runs every check without merging;
`--with-verify` immediately runs and records the merge-train's terminal
full-suite verify after merging. `devtools workspace merge train-status`
reports (exit 1) any PRs merged since the last recorded full-suite verify —
this is the structural stand-in for "a merge-train records the full-suite
verify as its terminal ledger step"; `devtools workspace merge
record-full-verify --command "devtools verify --all"` records that step
directly once per merge-train session boundary. The lower-level
`devtools workspace merge-gate record/check` commands still exist for
ad hoc receipt inspection, but the merge action itself should go through
`workspace merge`.
- Sizing/triage input: `devtools workspace backlog-calibration` for
lead-time/discovery/staleness distributions before deciding batch size.

Expand Down
30 changes: 30 additions & 0 deletions devtools/command_catalog.py
Original file line number Diff line number Diff line change
Expand Up @@ -728,6 +728,36 @@ def to_dict(self) -> dict[str, object]:
'devtools workspace merge-gate ack 3517 123456789 --reason "already fixed upstream, false positive"',
),
),
CommandSpec(
"workspace merge",
"workspace",
"Merge boundary wrapper: refuses `gh pr merge` without a fresh merge-gate receipt.",
"devtools.merge_boundary",
use_when=(
"Replace a bare `gh pr merge --squash` with this at the actual merge boundary "
"(polylogue-ct3r2 / polylogue-t6iga: duplicate filings of the same finding -- "
"`merge-gate record/check` and the one-full-verify-per-train rule both existed but "
"fired only if a coordinator remembered to invoke them). `merge <PR>` auto-records a "
"merge-gate receipt if none is fresh for the current head sha (running `--command`, "
'default "devtools verify"), runs `merge-gate check` and refuses to merge on any '
"BLOCK, strips a doubled `(#N) (#N)` squash-subject suffix (the 2026-07-12/13 "
"incident), then runs the actual `gh pr merge --squash`. `--dry-run` runs every check "
"without merging. `--with-verify` immediately runs and records the merge-train's "
"terminal full-suite verify after merging; otherwise it prints a reminder. "
"`train-status` reports (exit 1) any PRs merged since the last recorded full-suite "
"verify -- the structural stand-in for 'a merge-train records the full-suite verify "
"as its terminal ledger step'. `record-full-verify` runs and records that step "
"directly, e.g. once per merge-train session boundary."
),
examples=(
"devtools workspace merge 3517",
'devtools workspace merge 3517 --command "devtools test tests/unit/foo.py"',
"devtools workspace merge 3517 --dry-run",
'devtools workspace merge 3517 --with-verify --verify-command "devtools verify --all"',
"devtools workspace merge train-status",
'devtools workspace merge record-full-verify --command "devtools verify --all"',
),
),
CommandSpec(
"workspace merge-conductor",
"workspace",
Expand Down
Loading