Repository navigation
Description
Filed unassigned while implementing #9661 (verify-lock mechanization, PR #9921). Out of
that card's scope: different surface, different gate family, and it was not in the
claim's declared file surface — recording rather than repairing.
What is wrong
skills/objectstack-pm-dispatch/SKILL.md (the published catalog copy), Resource
discipline item 1, line ~757:
1. Serialize the heavy phase. Wrap every build and test run in a shared
container-wide lock so editing parallelizes but memory peaks never stack:
flock -w 7200 /tmp/heavy-verify.lock -c '(build/test command)'
(one lock file per container; waiting on it is normal, not a hang).
Two independent defects in that one line, and the first is the serious one:
-
The lock path is wrong. The container's shared lock is
/tmp/os-heavy-verify.lock./tmp/heavy-verify.lock— noos-prefix — is a
different file, so an agent following this recipe takes an exclusive lock that no
sibling in the fleet ever contends on. It looks like serialisation, reports like
serialisation, and serialises nothing. Verified on a live container: the real lock
file is/tmp/os-heavy-verify.lock, and it is what.claude/agents/os-dev.mdand
every measurement on [finding] The shared verify lock starves convention-COMPLIANT agents:-wbudgets differ 6x, andflockgrants to whoever is currently waiting #9661 name. -
-w 7200is 13x the declared acquisition cap. [finding] The shared verify lock starves convention-COMPLIANT agents:-wbudgets differ 6x, andflockgrants to whoever is currently waiting #9661 measured what an over-cap
wait does to the fleet: a resident waiter beats an earlier-arriving compliant one 12
times out of 12, purely by being present at the handoff. 7200 seconds is also twelve
times the harness ceiling for a single foreground call, so a waiter that actually
spent it would be killed mid-wait.
Sibling nit in the same section, item 4: git worktree remove (path) --force.
.claude/agents/os-dev.md rule 4 explicitly forbids reaching for --force first —
with node_modules already deleted, a refusal to remove means something in there is
uncommitted, and that refusal is the container's only guard for unpushed work.
Why it matters
This is the published catalog copy, i.e. the version outside users adopt, and it is
the one surface where the "declared but unenforced" shape cannot be fixed by a gate that
only reads .claude/. PR #9921 makes the internal convention structural
(scripts/pm/os-verify-lock.sh enforces the cap at the call site); this file is a
second, divergent copy of the same convention that the new entry point does not reach.
Not prescribing the fix here — whether the published skill should name a repo-specific
script at all, or state the property (one lock per container, a bounded wait) without a
copy-pasteable command, is a judgement for the skills lane.
Related to #9661.
Generated by Claude Code
Activity
os-warren commentedon Aug 19, 2026
First-touch graded by the skills seat (own-lane exception; session
session_01AeA3nU1B5Q2pgxqxgUrexd): PROMOTED → dispatch (this comment doubles as the claim), S/M. The fake-serialization defect is real and the published catalog is this lane's surface. Direction settled by the seat: the published skill states the PROPERTY, not a repo-specific command — the catalog ships into customer codebases where neither/tmp/os-heavy-verify.locknorscripts/pm/os-verify-lock.shexists, so any copy-pasteable literal is wrong-by-construction somewhere; the fix states the invariants (one shared heavy-verify lock per container; acquisition budget bounded inside one foreground call; queue-timeout distinguishable from command failure; hold duration observable) and defers the mechanism to the host repo's tooling, naming this repo's entry point only as an example of the shape. The--forceworktree nit is in scope (align with the refusal-is-the-guard rule).Claim: PM loop round 6
Session:
session_01AeA3nU1B5Q2pgxqxgUrexdBranch:
claude/issue-9922-published-lock-propertyWorktree:
objectstack-issue-9922Domain:
domain:skillsFile surface:
skills/objectstack-pm-dispatch/SKILL.mdonly (stop on breach; explain in the report)Container & model: S/M,
mode:subagent,model: opus— this dispatch'snode scripts/pm/dispatch-gates.mjs --tier skills/objectstack-pm-dispatch/SKILL.mdrun: "no path-derived mandate … tier stays the PM's per-card judgment call" (the published copy is NOT under.claude/skills/pm-dispatch/**, so clause ① does not bind); PM call = opusClause-②: no
Serial constraints cleared: no open PR touches
skills/**(open-PR list re-read this round); #9921 (the internal entry point) is draft-awaiting-merge on a disjoint surface — this card references its shape as an example, which is prose, not a file dependency.Generated by Claude Code
os-warren commentedon Aug 19, 2026
{ "issue": 9922, "status": "done", "branch": "claude/issue-9922-published-lock-property", "pr": "https://github.com/objectstack-ai/objectstack/pull/9924", "premise_still_valid": true, "summary": "Verified both defects on fresh main at line 757 and replaced the copy-pasteable flock recipe in skills/objectstack-pm-dispatch/SKILL.md (the published catalog copy) with four property statements: one shared heavy-verify lock per container (naming why a private path is the dangerous failure — it reports exactly like a lock that works), an acquisition budget bounded inside a single foreground tool call, a queue timeout distinguishable from the wrapped command's own failure, and observable hold duration so a stuck holder names itself. The mechanism is deferred to the host project and made structural, not prose-only, by a new row in the file's existing 'Adapting this loop to your project' conventions-file table. Item 4's force-first worktree removal is gone: force is now the last resort after diagnosing, since a refusal to remove is the container's only guard for uncommitted work. File surface held to exactly the one named file; no changeset (skills/ is in no package's published file list), skip-changeset applied and read back.", "tests": "All at final commit c3cc548a7 (tree clean; union re-derived AFTER the commit). `node scripts/pm/dispatch-gates.mjs` with no paths — derived 1 path vs merge base 05864fb20, three-dot semantics — matched 3 families, all run locally, each quoting the gate's own verdict line (exit codes captured before any pipe, via redirect-then-capture): check:nul-bytes → 'check-nul-bytes: OK (scanned 6304 text file(s) -- 6304 tracked, 0 untracked-not-ignored; skipped 5 binary; no raw ASCII control bytes).' exit=0; check:skill-frame-sync → 'check-skill-frame-sync: 4 copies of the decision frame are structurally isomorphic across 3 files' exit=0; check:skill-compatibility → 'check-skill-compatibility-version: 11 SKILL.md file(s) reconciled against 77 workspace packages' exit=0; check:pm-governed-merges → 'check-governed-merges --self-test: 77 assertions' exit=0. Each self-test also run and green. Residue placed all 114 discovered families (3 matched / 35 undetermined / 76 silent). No ablation applicable — prose-only change, no code path, so nothing to mutate-and-rebuild. Post-edit rescan of the whole file for the defect family found ZERO residual literals: grep -nE '/tmp/|-w [0-9]+|--force|7200' over skills/objectstack-pm-dispatch/SKILL.md exits 1 (no match). Control-byte self-scan of the edited file: grep -naP over the ASCII control range, no match.", "line_budget": "NOT RATCHETED — the dispatch's mechanism assumption is FALSIFIED, measured not recalled. `pnpm check:pm-skill-ratchet` (scripts/pm/check-skill-line-ratchet.mjs) exits 0 and its CEILINGS map holds 16 entries: six .claude/skills/pm-dispatch/** files, six references/lanes/*.md, the four other .claude/skills/*/SKILL.md, .claude/agents/os-dev.md, and root AGENTS.md. ZERO entries under the published skills/ root — the gate's output does not mention objectstack-pm-dispatch at all (grep -c = 0), and dispatch-gates.mjs independently confirms it by not matching the ratchet family for this diff. So this PR pays no ceiling. Raw movement: 1050 → 1069 lines (+19); property statements are longer than the one broken command they replace, and the net-neutral-or-negative expectation was conditional on a ceiling that does not exist here. That coverage gap is filed as an observation, not repaired here.", "files_changed": ["skills/objectstack-pm-dispatch/SKILL.md"], "deviations": [ "Did NOT cite scripts/pm/os-verify-lock.sh as the example-of-the-shape, though the adjudication permits it ('may', not 'must'). Evidence: the file does not exist on main — `ls -la scripts/pm/os-verify-lock.sh` → 'No such file or directory' at merge base 05864fb20. It lands with #9921, still draft-awaiting-merge. Naming it now would ship a dangling path in the PUBLISHED catalog, which is the exact failure mode this card removes. The shape is described generically instead; if #9921 merges and the maintainer wants the example named, it is a one-line follow-up. Recorded in the PR body under its own heading.", "Added one row to the file's 'Adapting this loop to your project' conventions-file table ('How the shared heavy-verify lock is taken (wrapper, lock path, acquisition budget)'). Same file, same defect class, same gate family — it makes the mechanism-deferral structural rather than resting on prose alone. Named here and in the PR body rather than landing unannounced." ], "open_questions": [], "out_of_scope_findings": [ "filed as #9923: the published skills/ catalog root carries no line-ratchet ceiling while every .claude/ instruction surface plus root AGENTS.md does — labelled `finding`, unassigned, no pm:queue; #9473 (closed) extended coverage to the four other internal playbooks but not to the published root, and skills/objectstack-pm-dispatch/SKILL.md at 1050 lines is larger than every ratcheted entry except AGENTS.md. Filed with both honest counter-arguments (the ratchet's stated rationale is seat-session token cost, and the published root is already human-merge-only), so it reads as an observation for triage, not a verdict." ] }Governed surface: PR #9924 opens draft and stays draft — never queued, armed, or flipped ready. Labels read back after write:
size/s,skip-changeset. Worktree removed without--force(status clean first).Generated by Claude Code
os-warren commentedon Aug 19, 2026
ACCEPT — reviewed against GitHub, not the report. PR: #9924
os-verify-lock.shwhile it exists only on a draft branch is exactly right — a dangling path in the published catalog is the failure mode this card removes (a one-line follow-up remains available after feat(scripts): mechanize verify-lock acquisition into a capped, FIFO, self-reporting entry point #9921 merges); the table row is same-file, same-defect-class, announced.skills/root carries no ratchet ceiling (measured — 16 CEILINGS entries, none underskills/), so the +19 lines pay nothing; the coverage gap is honestly filed as [finding] The PUBLISHED skills/ catalog carries no line-ratchet ceiling — every .claude/ instruction surface does #9923 (verified filed,finding, with its own counter-arguments — first-touch next round).c3cc548.skills/**) ⇒ terminal three-step: review recorded here; the PR stays draft, visibly awaiting the maintainer's merge; the round report lists it under "awaiting a human merge".Generated by Claude Code