Repository navigation
AGENTS.md: make "push a WIP commit before any minutes-long step" an ordering rule — the one lesson from the 2026-08-25 restart that is not already covered #12024
Description
Activity
Skills-lane self-triage:
finding→ promotedpm:queue, folded with #12077 as one compression-paidAGENTS.mdedit (chain head to be named at claim time; the five fold gates get answered in that claim). The ordering rule as proposed — the trigger is "before anything that is not the next edit", not "before you wait" — with the card's own rationale kept: the population that most needs it is the one working hardest.⚠️ Both constraints stand as filed: AGENTS.md is at ceiling (headroom 0), payment is in-place compression with each cut verified to survive somewhere; if compression cannot pay, this converts toneeds-user-decisionon the ceiling family TOGETHER with open #11910 (the implementing dev reads #11910 first, per triage's carried note) rather than raising quietly.
Generated by Claude Code
Claim: PM loop round R1 W2 — family dispatch chain head (members: this card + #12077)
Session:session_01JANH3y7qe3MD8aLaLXci8N
Branch:claude/issue-12024-agents-doctrine-pair(shared, named by this chain head)
Worktree:objectstack-issue-12024
Domain:domain:skills
File surface:AGENTS.mdonly (stop on breach; explain in the report)
Container & model: S+S folded,mode:subagent,model: claude-opus-5— this round'snode scripts/pm/dispatch-gates.mjs --tier AGENTS.md(fresh treec026b0d2): "no path-derived mandate … the tier stays the PM's per-card judgment call"; compression-paid doctrine writing = judgment tier, compensated by this seat's fable-tier skill-face review
Clause-②: no — internal doctrine text
Fold-or-serial answered — the five gates: ① same defect form (a measured container fact missing from AGENTS.md doctrine) and same fix form (one doctrine line each, paid by in-place compression); ② same file, one worktree, one changeset-free PR, one queue slot; ③ both members graded by this seat this round (bothpm:queue); ④ independently verifiable — each member has its own named line and its own acceptance reading (WIP-commit ordering rule present for #12024; cache-sharing carve-out beside the stash rule for #12077); ⑤ exclusion list — #12204 (os-dev.md ablation clause, different file), #12188/#12341 (os-dev/verify-lock family), and #11910 is NOT a member: it is the open ceiling-family decision the dev must READ FIRST — if compression cannot pay, this dispatch converts toneeds-user-decisionalongside it rather than raising the ceiling.
Serial constraints cleared: zero open PRs touchAGENTS.md(PR #12386 merged; this seat's three wave-1 PRs hold os-dev.md / pm-dispatch files / check-half-states.mjs — all disjoint). Ratchet live reading THIS round on the fresh tree: AGENTS.md 1158/1158, widest-row pin 1081 — headroom 0 (the card's 1149 figure is stale; ceiling has moved). Premise re-verified onc026b0d2: zero WIP-commit-rule hits (controlgit stash= 2), all fiveturbomentions are build-command/hashing references — no cache carve-out exists.
Generated by Claude Code
Dev claim (implementing seat, family chain head) — session
session_01JANH3y7qe3MD8aLaLXci8N
Branch:claude/issue-12024-agents-doctrine-pair(shared; members: this card + #12077)
Worktree:/home/user/objectstack-issue-12024· File surface:AGENTS.mdonly — held, no breach.
Read in full before the first edit: #11910 (the open ceiling-family decision, per the dispatch's first-action clause), both member cards, and all comments on each.
Premise re-verified on my own fetch ofc026b0d2: zero WIP-commit-rule hits inAGENTS.md, controlgit stash= 2 hits; all fiveturbomentions are build-command/hashing references with no cache clause. Both premises hold.
Ceiling: compression paid for both additions in full (+10 / −10, net 0 at 1158/1158) — no ceiling raise, so the escalation clause to a ceiling decision alongside #11910 was not reached. #11910 remains open and untouched.
Draft PR: #12420 — governed surface, draft, human merge only.
Generated by Claude Code
os-dev-report
{ "issue": 12024, "status": "done", "branch": "claude/issue-12024-agents-doctrine-pair", "pr": "https://github.com/objectstack-ai/objectstack/pull/12420", "premise_still_valid": true, "summary": "Family of two, one branch, one draft PR, one commit per member, all in AGENTS.md only (declared surface held, no breach). #12024 adds the WIP-commit ordering rule at the head of Build and Test, triggered on the STEP (a build, a full test run, a gate sweep, an ablation) rather than on waiting, keeping the card's inverse-cost rationale and the 2,081-line measurement. #12077 adds the build-cache carve-out beside the stash rule in the isolation-promise section: turbo resolves the repo root through the git COMMON dir so every worktree replays one .turbo/cache, with the symptom (a typecheck failing on a package your diff never touched, unrepaired by a plain rebuild because the rebuild is a cache HIT), the remedy (a forced rebuild), and ablation named as a sanctioned producer. Both additions were paid IN PLACE against the zero-headroom ceiling: +10 added, -10 cut, net 0 at 1158/1158, NO ceiling raise and no re-wrap, so the escalation clause to a ceiling decision alongside #11910 was never reached; #11910 was read in full first and remains open and untouched. Four cuts, each with a named surviving home, all listed in the PR body: three named-example docs rows (home: the generic per-tree row above them, which called them examples), the Skills governed-surface paragraph 4->2 (home: Prime Directive #14, which carries every clause), Prime Directive #11's stash tail 3->2 (home: the Multi-agent stash paragraphs), and the Multi-agent section opener 6->2 (home: Prime Directive #11, which it restated clause for clause). One cut did double duty: PD #11 claimed the stash was 'the one thing a worktree does not isolate', already false against the Multi-agent section's own 'the stash is one CASE' paragraph, and it now reads 'neither the stash nor the build cache' - the bounded in-place fix is same-defect-class, mechanical, pinned by existing in-file evidence, same gate family, and is named with its evidence in the PR body. PM note, no action needed from me: #11910's authorized raise (961 -> 969) has been overtaken by later raises (the ceiling now reads 1158), so that card's stated one-line follow-up is stale and may want re-triage on its own thread.", "tests": "Gate families derived from the ACTUAL diff, not recalled: `node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack` (no paths; the script took its own change set from the merge base c026b0d2d - 'committed 1, working tree 0, untracked 0'), which named 8 families for the single-path surface AGENTS.md and printed 'gate list derived from the tree of objectstack-ai/objectstack at commit 26e7c579' with the --repo assertion holding against this checkout's origin. UNION re-run at the FINAL commit `git rev-parse --short HEAD` = 26e7c579, all 8 plus check:nul-bytes, exit codes captured BEFORE any pipe (redirect to file first, then tail) so these are the gates' own verdicts and not a pipeline's status. Verdict lines as printed: '+ check-skill-line-ratchet: AGENTS.md is 1158 lines (ceiling 1158; headroom 0).' / '+ check-skill-line-ratchet: AGENTS.md: widest table row is 1081 bytes (pin 1081; headroom 0).' / '+ check-governed-prose: 2 instruction surface(s) name all 5 registered governed surfaces (docs/adr/** . .claude/** . skills/** . AGENTS.md . CLAUDE.md) and claim no others.' / '+ check-skill-id-lint: 22 file(s) clean (pattern /#[0-9]{3,}/g)' - this is the id-lint population that covers AGENTS.md, confirming both new lines are self-contained with no issue-number references in operative text. / '+ check-required-contexts: 6 required context name(s) pinned across 2 workflow(s); 5 instruction surface(s) scanned against 2 retired name(s).' / '+ check-agent-test-spelling: 0 violations - 386 file(s).' / '+ docs-accuracy-audit scope is in sync with content/docs/: 189 hand-written doc(s).' / '+ check-nul-bytes: OK (scanned 6871 text file(s); no raw ASCII control bytes).' / check:pm-governed-merges exit 0. NOT MEASURED, recorded as such and not as a red: check:required-contexts first returned 'PREREQUISITE NOT MET - the dependency yaml is not installed' (fresh worktree, exit 1 but nothing measured); pnpm install then ran through the shared entry point `bash scripts/pm/os-verify-lock.sh -c ...` (VERDICT command-exit 0, held the lock 8s, waited 0s) and the verdict line above is from the real run afterwards. Two intermediate reds were found and fixed before the final commit rather than reported as green: a 122-byte line over the 120-byte budget (L243) and a +1 line count at 1159/1158. No ablation was performed and none is claimed: the change is doctrine prose with no build artifact and no executable behaviour to mutate, so there is no rebuild or on-disk mutation evidence to state. Control-char self-scan of AGENTS.md beyond the gate: grep -naP over the C0 range plus DEL returned no matches. PR body verified byte-complete after creation by reading it back through the API (7149 bytes, identical to the local source modulo one trailing newline); both 'Fixes' lines survived as the first two lines and the session-URL footer survived verbatim.", "open_questions": [], "out_of_scope_findings": [] }
Generated by Claude Code
ACCEPT (family: this card + #12077) — PR #12420 reviewed on its actual diff at head
26e7c579(reviewer of record: skills seat,session_01JANH3y7qe3MD8aLaLXci8N, contract-review tier per the skill-face requirement).Checklist conclusion: draft ✓ · base
main✓ · bothFixeslines lead the body ✓ · one file (AGENTS.md, declared surface held) ✓ · one commit per member ✓ · net 0 lines at 1158/1158 with the widest-row pin intact — no ceiling raise, no re-wrap, so the #11910 escalation clause was correctly never reached (and #11910 was read first as instructed). Cut audit against the diff: all four cuts have live surviving homes (the generic docs-table row absorbs its own named examples; PD#14 carries the skills-paragraph clauses; PD#11 and the Multi-agent section de-duplicate each other with the pointer retained both ways). The double-duty repair is the right call and self-evidencing: PD#11's "the ONE thing a worktree does not isolate" was already false against the file's own stash-is-one-CASE paragraph, and "neither the stash nor the build cache" fixes the falsehood in the same stroke that pays for #12077's line. Member deliverables verified present: the WIP-commit rule triggers on the STEP with the inverse-cost rationale and the 2,081-line measurement, id-lint clean; the cache carve-out carries symptom (cache-HIT rebuild), remedy (forced rebuild), and ablation-as-sanctioned-producer. Two intermediate reds (122-byte line, 1159/1158) fixed before final commit rather than reported green — correct posture.Governed-surface ending: PR stays draft — ⛔ never ready/queued/auto-merge from a seat; review requested from
os-zhuangwithdraft: trueexplicit; the human merge is the review record. Listed under "awaiting a human merge". PM note accepted into the round report: #11910's authorized-raise text is stale (ceiling has moved 961→1158 under later authorized raises) — flagged for that card's own thread, not touched here.
Generated by Claude Code
Filed unassigned, recording only.
A container restart on 2026-08-25 killed five in-flight
os-devagents. Four of tonight's five lessons turned out to be instances of rules the repo already has, and are recorded as findings rather than as new doctrine. This card is the one that is genuinely missing.The gap, measured
AGENTS.mdcarries no rule about committing before a long-running step. Verified with a working control:The nearest thing that exists is #11463, whose framing is parking: an agent that decides to wait should commit first. The restart showed that framing is too narrow — the rule has nothing to do with parking.
What the restart measured
lint.yml+22,package.json+1Only luck saved #11525: the worktrees outlived the processes, so a rescue dispatch could commit and push the work (
f7e038cda). This environment documents that it reclaims the filesystem — so that luck is not repeatable.⭐ Why the current phrasing cannot reach the agents that need it
The cost of not committing is inversely related to how well the agent is behaving. An agent that finishes fast commits soon and risks little. An agent deep in a hard card — measuring, ablating, re-deriving — defers committing because it is not done yet, and so accumulates the largest uncommitted surface exactly where the work is most expensive to reproduce. #11694 and #11942 lost 14 minutes each. #11525 lost hours because it was doing the card properly.
So the population that most needs the rule is the population least likely to be reached by it: "commit before you wait" does not fire for an agent that is not waiting — it is working.
The proposed rule
Change the trigger from "before you wait" to "before anything that is not the next edit" — before a build, a full test run, a gate sweep, an ablation, any step measured in minutes.
#11463 already establishes that ordering rules are the instructable kind (do-not-end-the-turn survived three escalating strengths; commit-before-you-wait did not need to). Tonight's rescue is a second confirmation: told "commit and push before reading anything else," the agent did exactly that, and 2081 lines were safe on
originbefore it began verifying anything.AGENTS.mdis 1149 lines against a ceiling of 1149 — headroom 0, andscripts/pm/check-skill-line-ratchet.mjsis shrink-only: raising a ceiling "requires a maintainer ruling quoted in the raising PR's body" and wants "its own card".So this is not a one-line edit. Two routes, and the first is preferred:
needs-user-decisionrather than raising the ceiling quietly.Deliberately NOT filed as cards — already covered
Recording these so nobody re-files them as new doctrine. Each is a worked example of a rule the repo already has, and paying compression to restate an existing rule is negative value:
scripts/ci-failure.mjs,scripts/affected-docs.mjs; real:scripts/pm/,scripts/docs-audit/).dispatch-gates.mjsprinting "absent from this tree" is the tell. → instance of a zero needs a positive control.list_issuestreatslabelsas OR, not AND → already [finding]mcp__github__list_issuestreatslabelsas OR, not AND — any seat computing "pm:queue ∩ domain:X" from one query gets an inflated count that looks plausible #11559.Related