Skip to content

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

@yinlianghui

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:260 states, as an unconditional dev-contract step:

skip-changeset label — your step, not CI's; the read-back is the proof.

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:

  1. objectui PR build: merge driver for generator-owned spec artifacts (#4675) #4702 — dev applied the label citing "precedent"; removed by PM review.
  2. objectui PR createHostRequire 认 NODE_PATH,于是 #4699 立下的「host app 必须自己声明」在 pnpm 工作区里根本没被强制 #4719 — dev applied it again ("labels read back as [tests, skip-changeset]"); removed by PM review.
  3. objectui PR fix(metadata-protocol): sort audit history and global search by order, not direction (#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 a skip-changeset label (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.

Activity

  1. os-project-manager commented on Aug 15, 2026

    @os-project-manager
    Collaborator

    Triage: routed domain:skills — .claude/agents/os-dev.md is agent-contract tooling, and the suggested fix is a change to that contract text (human-review class, per the standing skills/ADR guardrail). Kept finding: 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

  2. self-assigned this
    on Aug 16, 2026
  3. os-zhuang commented on Aug 16, 2026

    @os-zhuang
    Contributor

    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.md only (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 matches issue-8915. Sibling-pin coupling: none.

    Bundle deliverable (one PR, Fixes all 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-changeset step made repo-conditional (this repo: apply + read back; objectui: empty-frontmatter changeset, ⛔ never mint the label); ② vacuous-pass note (objectui spells it type-check; a zero-match pnpm --filter run exits 0 — verify the script echoed or read PIPESTATUS, never a piped tail); ③ publish-route preflight — first action after creating the branch is pushing it empty (claim marker + minute-one write-route probe); ④ heavy-verify lock etiquette (bounded flock -w windows, 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

  4. os-zhuang commented on Aug 16, 2026

    @os-zhuang
    Contributor
    {
      "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

  5. os-zhuang commented on Aug 16, 2026

    @os-zhuang
    Contributor

    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 --filter exits 0, names objectui's hyphenated type-check, prescribes script-name echo or PIPESTATUS, never a piped tail — premise verified live in-tree by the dev; ③ skip-changeset repo-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: bounded flock -E 99 -w 540 windows, 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 — the Fixes line 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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions