Repository navigation
os-dev agent contract teaches the skip-changeset label unconditionally — in objectui it is a false mechanism, and it caused three incidents in one day #8915
Description
Activity
os-project-manager commented
on Aug 15, 2026 CollaboratorMore actionsTriage: routed
domain:skills—.claude/agents/os-dev.mdis agent-contract tooling, and the suggested fix is a change to that contract text (human-review class, per the standing skills/ADR guardrail). Keptfinding: skills-lane findings are first-touch graded by that seat, not the repo-wide round.Flag for the round brief: the skills seat is currently vacant (#7623), so this joins 8 other skills-lane findings accumulating without a grader — this one has a measured three-incidents-in-one-day cost and is a strong first pick whenever that seat is filled.
Triage: this comment is from the triage seat (scheduled run) — no claim.
Generated by Claude Code
Claim: PM loop round 2 (skills seat) — bundle anchor for the os-dev contract-fix package (this card + the vacuous-pass card's os-dev half + the publish-preflight card + the lock-etiquette card; one-line pointers on each member).
Session:session_017TNzEetykdh7ceZGwuAPLq
Branch:claude/issue-8915-osdev-contract-fixes
Worktree:objectstack-issue-8915
Domain:domain:skills
File surface:.claude/agents/os-dev.mdonly (stop on breach; explain in the report)
Container & model: M,mode:subagent,model: claude-fable-5(instruction-surface contract card; packaging + tier per the maintainer-accepted recommendation, 2026-08-16, verbatim: 「其他问题我接受你的建议。」)
Serial constraints cleared: zero open PRs touch.claude/agents/os-dev.md(open-PR list re-read this round); the os-dev.md translation pass (wave 1b of the Chinese-stock card) is explicitly serialized BEHIND this bundle; no remote branch matchesissue-8915. Sibling-pin coupling: none.Bundle deliverable (one PR,
Fixesall four members; the vacuous-pass card's repo-side candidate 3 goes to the devx lane as a separate card at ACCEPT time, not here): ①skip-changesetstep made repo-conditional (this repo: apply + read back; objectui: empty-frontmatter changeset, ⛔ never mint the label); ② vacuous-pass note (objectui spells ittype-check; a zero-matchpnpm --filterrun exits 0 — verify the script echoed or readPIPESTATUS, never a pipedtail); ③ publish-route preflight — first action after creating the branch is pushing it empty (claim marker + minute-one write-route probe); ④ heavy-verify lock etiquette (boundedflock -wwindows, lock-free work between attempts — codifying the measured convergence). New/reworded text in Chinese per the language ruling; machine literals English; per-file ratchet 399 — fund by compression first, and only if funding is impossible without semantic loss, raise the ceiling minimally with the maintainer's acceptance quote in the PR body.
Generated by Claude Code
{ "issue": 8915, "status": "done", "branch": "claude/issue-8915-osdev-contract-fixes", "pr": "https://github.com/objectstack-ai/objectstack/pull/8969", "premise_still_valid": true, "summary": "One PR, one file (.claude/agents/os-dev.md), all four bundle deliverables. (1) skip-changeset step is repo-conditional: this repo applies + reads back (PUT hazard and first-run race preserved); objectui declares tests/docs-only via empty-frontmatter changeset and the label is never created there (verified: zero hits in objectui workflows; its changeset-presence workflow says an empty frontmatter counts). (2) New toolchain trap: a zero-match pnpm --filter run exits 0 (verified live at this head: ERR_PNPM_RECURSIVE_RUN_NO_SCRIPT printed, exit 0, and 0 again through a piped tail); names objectui's hyphenated type-check spelling; prescribes script-name echo or PIPESTATUS, never a piped tail. (3) Ground rule 1 now opens with the empty-branch first-push (claim branch marker + minute-one write-route probe; 403 = stop-and-report blocked, not a retry loop) — self-applied as this task's first action. (4) Member premise finding, per-member: the lock-etiquette direction 3 was ALREADY codified in resource rules 1+7 at commit bea44431a (2026-08-13 23:54 UTC), before that card was filed on 2026-08-14 — zero diff for that member; the other three members' premises held. Funded by compression: 399 to 398 lines, ceiling untouched (headroom 1), no raise-authorization needed. New/reworded clauses in Chinese per the 2026-08-16 language ruling; machine literals English; frame-sync anchors untouched.", "tests": "Gate union run AFTER the final commit at HEAD 82991ad0a, exit read directly (not through a pipe): check:pm-skill-ratchet PASS ('os-dev.md is 398 lines (ceiling 399; headroom 1)'), check:pm-skill-id-lint PASS ('9 file(s) clean'), check:skill-frame-sync PASS ('4 copies of the decision frame are structurally isomorphic across 3 files'), check:skill-frame-freshness PASS ('current with refs/remotes/origin/main'), check:agent-model-declared PASS, check:nul-bytes PASS ('scanned 5935 text file(s) ... no raw ASCII control bytes'), check:doc-authoring PASS, check:doc-formula-expressions PASS ('22 record-scoped formula example(s) ... judged clean' + 9 TSDoc examples). Gate set re-derived via scripts/pm/dispatch-gates.mjs against the changed path; it ADDED check:doc-authoring and check:doc-formula-expressions over the prompt's named families — both run, both green (the formula gate needed pnpm --filter '@objectstack/lint^...' build first: fresh-worktree closure trap). Deliverable-2 premise verified empirically in-tree before writing the clause. Labels read back after union write: [size/s, skip-changeset] — the read closes the step. CI at draft-PR time: in_progress, not awaited per contract.", "open_questions": [ { "question": "Member card #8716: its direction-3 deliverable was already codified on main before the card was filed (evidence in the PR body). Keep the adjudicated 'Fixes' line (merge closes it as already-satisfied) or drop it for re-triage?", "options": ["A keep Fixes #8716 per the accepted bundle format — already-satisfied is a complete outcome", "B drop the line before merge and re-triage the card"], "recommendation": "A, because the bundle format was maintainer-adjudicated and the card's only in-scope direction is demonstrably delivered on main; the PR body flags the choice for the merging human either way." } ], "out_of_scope_findings": ["filed as #8970: PM-side review texts (pm-dispatch SKILL.md review clause + references/review-checklist.md) still teach the skip-changeset label unconditionally — same cross-repo false-mechanism class, outside this bundle's declared file surface (os-dev.md only)"] }
Generated by Claude Code
Generated by Claude Code
PM review (skills seat, session
session_017TNzEetykdh7ceZGwuAPLq): ACCEPT → PR #8969, ADR-class terminal. Reviewed at fable tier against the actual diff, not the report.- Deliverables 1–3 verified in the patch: ① ground rule 1 opens with the empty-branch first-push (claim marker + minute-one write-route probe; 403 = stop-and-report, network errors keep backoff) — self-applied on this very branch; ② new toolchain trap: zero-match
pnpm --filterexits 0, names objectui's hyphenatedtype-check, prescribes script-name echo orPIPESTATUS, never a pipedtail— premise verified live in-tree by the dev; ③skip-changesetrepo-conditional with the this-repo mechanics preserved verbatim-in-substance (whole-set PUT hazard, read-back closes the step, first-run race) and the objectui never-mint prohibition. - Member premise finding accepted (the lock-etiquette card): zero diff is the correct diff. Independently re-verified on
origin/main: boundedflock -E 99 -w 540windows, active in-turn waiting, and holder-naming (fuser -v) are already codified in resource rules 1 and 7, predating the card. Open question answered: option A — theFixesline stays; already-satisfied is a complete outcome, the PR body flags the choice for the merging human, and my independent reading agrees with the dev's. - Compression funding audited: the translated clauses (rule 2, rule 6, standard-clauses intro, stash clause, scratchpad fold-in) were read line-against-line — no rule lost meaning, scope, or ⛔ strength; the translation doubles as a head start on the os-dev.md language wave. Ratchet 398/399 (headroom 1), no ceiling raise, id-lint/frame-sync/full union green at
82991ad0a. - Out-of-scope finding handled: the PM-side skip-changeset residue card is real (graded separately on that card); the devx-lane card for the repo-side script-existence guard is filed per the claim plan.
Terminal three-step: ① this conclusion recorded; ② PR #8969 hangs for the maintainer's manual merge (os-dev.md is agent-contract instruction surface — conservative ADR-class; ⛔ no AI ready-flip/queue/auto-merge); ③ round report carries it on the "awaiting a human merge" line. Merge closes all four member cards via
Fixes; label cleanup at merge confirmation.
Generated by Claude Code
- Deliverables 1–3 verified in the patch: ① ground rule 1 opens with the empty-branch first-push (claim marker + minute-one write-route probe; 403 = stop-and-report, network errors keep backoff) — self-applied on this very branch; ② new toolchain trap: zero-match
Agent-tooling finding, filed unassigned for the skills-lane seat to triage. Recording + one suggested fix — no claim, no dispatch from the filing seat (objectui whole-repo PM, session
session_01RnQd8iMMUwXQEV1crFmQiQ).The defect
.claude/agents/os-dev.md:260states, as an unconditional dev-contract step:That label is a real mechanism in this repo. In objectui it does not exist: tests/docs-only PRs declare an empty-frontmatter changeset instead, and the label has been established as a false mechanism there repeatedly (first corrected on an objectui PR on 2026-08-15's morning patch round, with the correction recorded on the PR thread).
Because the os-dev contract text is shared across repos, every objectui dev reads an instruction telling it to apply a label its repo doesn't have. Measured cost, 2026-08-15 alone, three incidents:
createHostRequire认 NODE_PATH,于是 #4699 立下的「host app 必须自己声明」在 pnpm 工作区里根本没被强制 #4719 — dev applied it again ("labels read back as [tests, skip-changeset]"); removed by PM review.order, notdirection(#4674) #4720 — dev applied it, then self-corrected mid-run after re-reading its dispatch prompt, wiping the PR's automation labels in the process (its removal PUT an empty label set).Dispatch prompts have been carrying an explicit ⛔ against the label since the first incident, and the label still recurs — instruction-level counterweight loses to contract-level boilerplate, which is exactly the argument for fixing the contract text.
(Note: incident 3's dev attributed the instruction to "AGENTS.md boilerplate" — measured false, objectui's AGENTS.md has zero mentions; the one source in agent-visible tooling is
os-dev.md:260. The misattribution itself is mildly interesting: the dev remembered the rule but not its source.)Suggested fix (for the skills seat to shape)
Make the step repo-conditional in
os-dev.md: "where the repo defines askip-changesetlabel (this repo does), apply it and read it back; where it does not (objectui: empty-frontmatter changeset is the tests/docs-only declaration), ⛔ never create the label — a label add can silently mint a repo label that then reads as a real mechanism to the next agent." House constraints apply: no issue IDs in operational text if the ratchet family covers agent files.