Repository navigation
[finding] two prose statements of the governed REPO set live outside the register and go stale when #14867 lands — pm-dispatch/SKILL.md:723 and guard-governed-enqueue.sh:54, with no gate on either #14984
Description
Filed by the os-dev seat while implementing #14867 (session session_019RfFHiRCSs3JXLK4cwcfox, branch claude/issue-14867-governed-repos-hotcrm). ⛔ Observation-level, unassigned, no domain:* / type — routing and grading belong to central triage. Out of scope for the #14867 PR by construction: both sites are inside .claude/**, a governed surface, so folding them into that pure-scripts/pm/** diff would fork the PR under Prime Directive #14.
What is wrong
#14867 adds hotcrm to GOVERNED_REPOS in scripts/pm/check-governed-merges.mjs, taking the audited set from four repos to five. Two places outside that file state the set — or its size — in prose, and neither is reached by any gate. Both go stale the moment #14867 lands.
-
.claude/skills/pm-dispatch/SKILL.md:723`CLAUDE.md`;agent 指令文件按此跨仓同判 —— objectui、cloud、objectos 一并在内(2026-08-18 裁定)This is the PM's own operating text for the ACCEPT path-fork. It enumerates the sibling repos in which agent-instruction files are judged governed, and after check-governed-merges has no coverage for
hotcrm, a repo whose AGENTS.md is hand-merged as governed — the audit cannot report a gap it was never pointed at #14867 that enumeration is short by one. The line is the same shape the check-governed-merges has no coverage forhotcrm, a repo whose AGENTS.md is hand-merged as governed — the audit cannot report a gap it was never pointed at #14867 card criticised in the script's header: a derived statement of the set, presented as if it were the register. -
.claude/hooks/guard-governed-enqueue.sh:54# the same call answers for all four governed repos.A count, in a hook's header, of the repos one call covers. Five after check-governed-merges has no coverage for
hotcrm, a repo whose AGENTS.md is hand-merged as governed — the audit cannot report a gap it was never pointed at #14867.
Why it matters
The register is GOVERNED_REPOS and GOVERNED_SURFACES in scripts/pm/check-governed-merges.mjs — AGENTS.md Prime Directive #14 says so explicitly for surfaces, and #14867's ruling establishes the same for repos. pnpm check:pm-governed-prose already reds when the instruction files' surface list drifts from the register, in both directions. There is no equivalent for the repo set: I ran that gate on the #14867 branch and it passes, correctly — its scope is GOVERNED_SURFACES only (scripts/pm/check-governed-prose.mjs:190 maps surfaces to globs, and nothing there reads GOVERNED_REPOS).
So the failure mode is the one this family keeps producing: a seat reads a prose enumeration, treats it as the register, and acts on a set that is one repo short — the exact reading error #14867's own header now warns about for the 2026-08-18 quotation. A PM seat that reads SKILL.md:723 and concludes hotcrm's instruction-file PRs are not on the governed path would reverse the 2026-09-03 ruling by inference.
Two shapes of remedy, not ruled here
- Correct the two lines. Cheap, and it is a governed-surface edit, so it needs the human-merge path. Leaves the drift class open — this is the second time the set has grown.
- Extend
check-governed-proseto the repo set, so the instruction surfaces that enumerate repos are held equal toGOVERNED_REPOSthe way they are already held equal toGOVERNED_SURFACES. Needs a decision on which prose statements are in scope — a Chinese enumeration inside a sentence is harder to parse than the glob list the gate reads today, and a parser that guesses wrong reds on correct text.
Duplicate check
Enumerated every open issue in this repo through the REST list endpoint with completeness self-proof (state=open&per_page=100, pages 1–6, last page 18 rows; 499 open non-PR issues) and grepped the titles locally. Positive control in the same reading: governed returns 4 rows including the known-must-hit #14867, so the channel is live and a zero would have been a reading. No open card covers either site. Nearest neighbours, both distinct: #14870 (gate-script comments saying the decision frame has "four" copies — same shape, unrelated subject) and #14967 (governed-PR review requests).
Blocked-by: #14867 — both lines are correct until it lands.
Generated by Claude Code
Generated by Claude Code
Activity
os-steve commentedon Sep 3, 2026
Triage — skills seat (session
session_019RfFHiRCSs3JXLK4cwcfox, os-steve), 2026-09-03T17:40Z. Gradedpriority:p3,findingwas never set (filed bare),domain:skills(both sites are this lane's operating text and hook),tooling, statepm:queue→ claimed in the same minute (below), type Task. Applied and read back after this comment.The blocker is cleared: PR #14987 (#14867) merged
5d4d55ae17:37Z, soGOVERNED_REPOSholds five repos and both prose sites are stale as of that minute.Remedy chosen by the seat, on the four axes: neither of the card's two shapes as written. Shape 1 (rewrite the enumeration to five names) keeps a mirror that goes stale the next time the set grows — this is already the second time. Shape 2 (teach
check-governed-proseto parse a Chinese enumeration inside a sentence) is a parser that reds on correct text when it guesses wrong, for a set that changes twice a month. The shape that shrinks the special case: remove the mirrors and point at the register —SKILL.md:723says the cross-repo judgement followsGOVERNED_REPOSinscripts/pm/check-governed-merges.mjs(keeping its 2026-08-18 ruling date pointer per the X0 quote policy) without naming any repo; the hook comment atguard-governed-enqueue.sh:54says the one call answers for every configured governed repo, without a count. No repo name and no count outside the register ⇒ nothing to drift and nothing to parse. If the maintainer prefers a spelled-out list in the operating text, that is a one-line change on the same PR.XS; governed (
.claude/**×2) ⇒ draft PR, in-seat review, reviewersos-zhuang+hotlong, human merge.Generated by Claude Code
os-steve commentedon Sep 3, 2026
Claim: PM loop round 3
Session:
session_019RfFHiRCSs3JXLK4cwcfoxBranch:
claude/issue-14984-governed-repo-set-mirrorsWorktree:
objectstack-issue-14984Domain:
domain:skillsFile surface:
.claude/skills/pm-dispatch/SKILL.md(the one line at:723atorigin/main5d4d55ae) +.claude/hooks/guard-governed-enqueue.sh(the one comment line at:54) (stop on breach; explain in the report). ⛔ No gate, no script, no third file.Container & model: XS prose (two one-line edits),
mode:subagent,model: fable(tier:node scripts/pm/dispatch-gates.mjs --tier .claude/skills/pm-dispatch/SKILL.mdatorigin/main5d4d55ae, 17:39Z: "MANDATORY: claude-fable-5-1 (derived from the file surface)"; the hook has no path mandate; the mandate face sets the flight)Clause-②: no
Serial constraints cleared:
.claude/skills/pm-dispatch/SKILL.mdand.claude/hooks/**are free on the seat post's hot-file queue; no in-flight claim names them; no open PR touches them. Governed ⇒ draft + reviewers, human merge. SKILL.md line ratchet at5d4d55ae: 970 / 1005 (headroom 35) — the edit is a rewrite within the line, net 0.Decision re-read (17:40Z): no maintainer ruling on the card; the seat's triage comment above fixes the remedy shape (remove the mirrors, point at the register; no repo name, no count outside
GOVERNED_REPOS).check:pm-governed-prosecovers surfaces only and stays green either way — measured at5d4d55ae(2 instruction surfaces, 5 registered surfaces); the flight re-runs it andcheck:skill-frame-syncat the head.Generated by Claude Code
os-steve commentedon Sep 3, 2026
os-dev-report
{ "issue": 14984, "status": "done", "branch": "claude/issue-14984-governed-repo-set-mirrors", "pr": "https://github.com/objectstack-ai/objectstack/pull/15031", "premise_still_valid": true, "summary": "Premise verified on the branch (BASE fddfc8db, which already contains 5d4d55ae): both mirrors were at the quoted positions, and the third-mirror grep over .claude, AGENTS.md, CLAUDE.md and skills hit only the two target lines (seven other hits are unrelated 五个 prose; a repo-wide grep for the two literal strings finds no test pin). Rewrote exactly the two lines per the triage ruling: SKILL.md:723 now reads `CLAUDE.md`;agent 指令文件按此跨仓同判 —— 仓集读 `GOVERNED_REPOS`,此处不列(2026-08-18 裁定) (118 bytes, date pointer verbatim, no repo name, no count, no issue id); guard-governed-enqueue.sh:54 now reads `the same call answers for every repo configured in GOVERNED_REPOS.` (75 cols, no count). One measured deviation from the dispatch word: it asked line 723 to name both GOVERNED_REPOS and scripts/pm/check-governed-merges.mjs at net 0 lines, but check:pm-skill-ratchet also holds a 120-byte per-line budget — my first cut (0931bc0b) went red with `L723 (180B)`; 79 bytes of the line are fixed (prefix + date pointer), the path alone is 38, so both names cannot fit on one line and wrapping would spend a line. The line names GOVERNED_REPOS alone; the script is already named in the same file at lines 264, 791 and 964. Draft PR #15031 (Fixes #14984, single commit 16bd3e51, no reviewers requested, no ready flip, no auto-merge), skip-changeset applied over REST (additive POST, HTTP 200) and read back; PR body read back byte-identical. The issue page payload listed no assignee at hand-off (PM-side state, not acted on). Nothing else touched; no changeset (nothing published).", "tests": "Gate union on the pushed head 16bd3e51, each exit captured before any pipe, list re-derived by `node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack` with no paths (change set from the merge base: the two files; 14 families, one beyond the dispatch word: check:bash32-floor, run and green). All exit 0 with the gate's own verdict lines quoted in the PR body: check-closing-keyword-parity OK (8178 tracked files); comment-mask corpus sweep 5833 files, 0 disagree; check:doc-formula-expressions 22 record-scoped formula example(s) judged clean (two earlier runs exited 3 = PREREQUISITE NOT MET for unbuilt @objectstack/formula then @objectstack/lint — NOT MEASURED; both built under os-verify-lock.sh, VERDICT command-exit 0, then measured); check-agent-test-spelling 0 violations; doc authoring guard 393 files clean; check-nul-bytes OK (8171 text files, no raw control bytes); check-governed-merges --self-test 245 assertions; check-governed-prose 2 instruction surface(s) name all 5 registered governed surfaces and claim no others; check-skill-id-lint 23 file(s) clean; check-skill-line-ratchet .claude/skills/pm-dispatch/SKILL.md is 970 lines (ceiling 1005; headroom 35) — net 0, L723 118 bytes (was 119); check-refd-timer-probe 5828 files swept; check-skill-frame-sync 2 copies isomorphic; check-watch-hint-literal 48 declarations; check-bash32-floor 26 shell files clean; `bash -n` on the hook exit 0; guard-governed-enqueue.selftest.sh `49 passed, 0 failed`. Both edits proved on disk by anchored counts before commit (old text 0, new text 1 per file), not by editor exit code. check-governed-queue-guard is CI-measured only. No ablation (prose-only diff).", "mcp_calls": "2 — create_pull_request and add_issue_comment (this report); everything else went through the zero-quota page payload (issue body + comments) or repo-scoped REST (label POST + read-back, PR read-back), which was reachable from this seat", "open_questions": [ { "question": "Line 723 names GOVERNED_REPOS without the script path, because both names do not fit the ratchet's 120-byte line budget at net 0 lines. Keep as landed, or add the path and wrap?", "options": [ "A — keep as landed: `仓集读 GOVERNED_REPOS,此处不列`, 118 bytes, net 0 lines; the constant is unique in the tree and the script is named three times elsewhere in the same file", "B — name both and wrap line 723 into two lines (970 → 971 lines, ceiling 1005): a one-line change on this PR" ], "recommendation": "A — real need: a seat resolves GOVERNED_REPOS in one grep and the same file already names the script; long-term: one identifier drifts less than an identifier plus a path; AI-error prevention: equal either way, the pointer is unambiguous; startup focus: spends no ratchet headroom on a duplicate address" } ], "out_of_scope_findings": [ "not filed (informational, already surfaced by the gate on every run): check:pm-skill-ratchet prints that two max-table-row-bytes pins could be lowered opportunistically (pm-dispatch/SKILL.md pin 642 → 555; spec-property-retirement/SKILL.md pin 328 → 326) — pin-map rows in scripts/pm/check-skill-line-ratchet.mjs, outside this card's two-line surface" ] }Generated by Claude Code
Generated by Claude Code
os-steve commentedon Sep 3, 2026
ACCEPT — skills seat (session
session_019RfFHiRCSs3JXLK4cwcfox), reviewer of record, 2026-09-03T17:59Z, verified against GitHub and a compare worktree at the PR head, not against the report.PR #15031 @
16bd3e51— draft, basemain, first lineFixes #14984, two files, two lines,+2/-2,skip-changeset, no other closing keyword, no model name, one footer, no control bytes.Content against the triage shape (comment 5529676559):
SKILL.md:723now says the cross-repo judgement readsGOVERNED_REPOSand lists nothing here, with the(2026-08-18 裁定)date pointer verbatim — 118 bytes, no repo name, no count, no issue id; the hook comment says the one call answers for every repo configured inGOVERNED_REPOS— no count. Seat's re-run at the head:check-skill-line-ratchet970 / 1005 (net 0),check-skill-id-lintclean,check-governed-merges --testGOVERNED ×2,bash -nclean, the hook's own self-test49 passed, 0 failed; a grep for either old mirror over.claude,AGENTS.md,CLAUDE.md,skillsreturns nothing. The dev's third-mirror sweep found no other site; accepted.Open question: A — the constant alone is the pointer; the script is already named three times in the same file, and the 120-byte line budget would have made the second name cost a line. The deviation from the brief's wording is a measured one, recorded as a good run.
Deviations: none otherwise. Report
mcp_calls: 2 — within contract.CI at 17:58Z on
16bd3e51: 28 check runs, 11success+ 12skipped, fivein_progress(Lint & Repo Gates, fourType Checklegs); nothing red; re-read at the next patrol and recorded here.Terminal: governed surface (
.claude/**×2) ⇒ the PR stays draft and lands by an approver's hand; review requested fromos-zhuangandhotlongover the REST reviewers endpoint (draft bit untouched), read back. Card stayspm:dispatcheduntil the merge closes it.Generated by Claude Code