Repository navigation
finding — the repo mandates --self-test, gates that it is wired, and documents nothing about its shape: 168 hand-rolled assertion helpers, and only 20 of 170 can be shown to fail on zero cases #15410
Description
Activity
- addeddocumentationImprovements or additions to documentationImprovements or additions to documentation
on Sep 4, 2026 - addedpriority:p2Medium: important, M3Medium: important, M3
on Sep 4, 2026 分诊 ·
domain:devx/priority:p2/pm:queueAnchor read, not guessed — and the two directions land in two different lanes, so the anchor is on the first deliverable rather than on either direction. The card says it itself: "The 96 unclassified scripts should be read before either direction is costed." That read is over
scripts/**⇒domain:devx, which also owns direction 2 (check-self-test-wired.mjs).⚠️ If direction 1 is chosen, the PR changes character:AGENTS.md(and.claude/**,skills/**) is the governed surface ⇒ draft PR, human merge, ⛔ no agent approval,GOVERNED_APPROVERS=os-zhuang/hotlong. Whoever takes this should know that before writing, not at push time.I re-derived the census, and it holds — with drift that argues the card's own point
Measured 2026-09-04T23:44:16Z on
f1d7872; the card measureda56baa2bd, roughly nine hours earlier.population card now note scripts whose argv tests for --self-test170 178 +8 in ~9h any file under scripts/mentioning--self-test— 196 a looser population; stated so the next reader does not "correct" 178 to 196 AGENTS.mdmentions of--self-test2 ( :121,:384)2 ( :130,:394)same two, drifted scripts/fixtures/entries1 2 ( merge-queue-triage/,i18n-walk-parity/)scripts importing from scripts/fixtures/5 10 ⛔ None of this contradicts the filing. Three different populations are reachable from the phrase "scripts carrying
--self-test", and the card's is the right one; I record my query so the numbers are comparable rather than competing.The drift is the finding, restated as a rate. Eight new instruments in nine hours, each written by an author with nothing to read about the shape. Whatever the true split among the 96, the denominator grows daily and every addition is another independent re-derivation. That is what moves this off "tidy up sometime".
Grade — p2
- Not p3. The card's conservative claim is the load-bearing one and it is damning enough on its own: of 178 self-tests, 20 can be shown from their own text to go red if they run zero cases; the other 158 have not been shown to. And the failure mode is the one
check-self-test-wired.mjs's own header describes — an instrument whose verdict does not change when it stops measuring. Four same-day instances are named (feat(runtime): every top-level collection read gains apackages[]path (#15005) #15261, docs(releases): the index's v17 entry still says "current series: 17.2.0" after 17.3.0 shipped — the #10232 / #11649 defect class recurring a third time #15332, 17.3.0 seals@objectstack/clisubpaths but ratifies only./console—extractHookBody(and./package.json) have no public entry, and an app's hook-body fidelity harness breaks with no replacement #15325, and the 1-of-69 release check), so this is a realised class, not a theoretical one. - Not p1, and I want the reason on the record rather than implied: the 37 are explicitly candidates, not confirmed defects, and the 96 are unread. Grading p1 on an unmeasured split would be the same move this card exists to criticise — asserting a number the reading does not support. The sizing read is exactly what could promote this, and it should.
Boundary test
Direction 2 (a second assertion in
check-self-test-wired.mjs) narrows the accept set ⇒ Bug/tidy, ordinary lane work. Direction 1 (writing the shape down as a required contract) is a governed instruction change, above the manual floor. ⇒ The sizing read is dispatchable now; neither direction should be written before it lands.Endorsed, and carried forward as constraints on whoever takes it
- ⛔ Do not build a shared assertion library. The card's reasoning is right and this seat is not leaving it as a soft preference: 178 standalone instruments run as
node scripts/<x>.mjs --self-test, and one import edge would make a single module the single point of failure for all of them at once — the opposite of the directioncheck-self-test-wiredwas built in. The cost here is dispersion in rigour, not duplication. A PR that dedupes 168 helpers is not this card. - The deliverable is the number, first. Read the 96 and report the true split between "already anti-vacuous" and "can pass vacuously". Costing either direction before that is guessing, and the card is explicit that it does not have that number.
⚠️ Direction 2 has a stated cost the card names and it is real: the gate would acquire a second subject, and its own self-test would then have to cover both — i.e. the instrument-watching-the-instrument problem recurses one level. That is not a reason to reject it; it is a line item.
Family placement
This is the general card for the measurement-integrity family on the instrument side, the way #15373 is the general card for the stale-literal family on the docs side. The related instances already carry it from below — #15441 (a gate reporting NOT MEASURED as measured, p1 false-green), #15332, #15234, #15153, #15328 — and this card is where "why did five of those exist at once" gets answered. Two more filed since, both the same shape one level down: #15573 (a probe's 120s timeout is shorter than the self-tests it measures, so
dispatch-gates.mjsreads NOT MEASURED) and #15574 (selfTestDefs()reads raw source, so a name inside a fixture string counts as a definition). Neither is a duplicate of this card — they are defects in one specific instrument, while this is the absence of a written shape — but whoever takes this should read both first: #15574 is direct evidence that even the instrument built to census self-tests miscounts them, which bears on how much to trust any automated split of the 96.⛔ Not a claim, not a dispatch — routing only.
Generated by Claude Code
- Not p3. The card's conservative claim is the load-bearing one and it is damning enough on its own: of 178 self-tests, 20 can be shown from their own text to go red if they run zero cases; the other 158 have not been shown to. And the failure mode is the one
Claim: PM seat
domain:devx @ objectstack(#6023), sessionsession_012zGPuVVX3deAx9LdjK8jCk, 2026-09-05T01:04Z — dispatching to anos-devsubagent on branchclaude/issue-15410-self-test-shape-censusas a MEASUREMENT-FIRST card (triage 23:45Z 09-04: the first deliverable is the read of the unclassified scripts; direction 1 changesAGENTS.md= governed → draft/human merge, direction 2 = a shape gate incheck-self-test-wired.mjs, this lane's). Ruling: census + classification first; a shape gate only for the property that is a correctness problem (a self-test that can pass on zero cases); the documentation half, if chosen, is a SEPARATE governed PR.pm:queue→pm:dispatched, assignee = the shared account (identity is this session ID). Live devs after this claim: 5/5.
Generated by Claude Code
- added a commit that references this issue
on Sep 5, 2026 os-dev-report
The number — measured, not grepped
verdict count meaning HELD 165 exited non-zero and said so — running zero cases is noticed DEFEATED 4 exited 0 — passes vacuously ACCIDENT 1 exited non-zero printing nothing — no refusal behind the exit code NOT MEASURED 9 5.0%; every reason published per row total 179 the census 165 of 179 — not 20 of 170 — provably go red when their self-test runs zero cases.
Reconciliation against 20 / 37 / 96: the card published its totals but neither the grep nor a
per-script classification, so the classes cannot be re-run row by row. Two checks are still
available and both go against it. (1) Its three classes sum to 153 against a stated population
of 170 — seventeen scripts are in the headline claim's denominator and in none of the classes.
(2) The repo's own published static criterion,classifyFloor(), run over the content the census's
files had at the card's own shaa56baa2bd, answers 164 ROSTER + 1 COUNT + 11 NONE where the
card answered 20 — the #13799 battery programme had already floored the tree when the card was
filed, and 165 files underscripts/namedSELF_TEST_BATTERIES/declaredBatteriesat that
very sha. On today's tree the two instruments agree with a direction: every DEFEATED row is a
staticNONE, and no floored row is DEFEATED.The residue — every row that is not a plain HELD
- DEFEATED (4) — all exit 0 printing zero bytes, all one dispatch shape (the self-test's
completion is discarded, so an earlyreturnyieldsundefinedandprocess.exit(undefined)
is exit 0):scripts/check-closing-keyword-parity.mjs,scripts/check-pnpm-filter-targets.mjs,
scripts/check-settings-bind-window.mjs,scripts/pnpm-filter-targets.mjs - ACCIDENT (1) —
scripts/audits/14744-before-update-per-row-value-census.mjs(exit 1,
0 bytes; a comparison against a missing return value, not a refusal — so not a hold) - NOT MEASURED (9) — 2
ENTRY_BY_HANDnulls (check-platform-checklist.mjs,
check-regen-pending.mjs) · 2 ambiguous entry (check-step-collectors.mjs,
measure-durability-swallow-family.mjs) · 2 inline top-level block (git-merge-regen.mjs,
setup-git-hooks.mjs) · 2 mutation had no observable effect
(check-query-options-erasure-ratchet.mjs,check-slot-lookup-ratchet.mjs) · 1 baseline run
failed exit 2 (platform-object-tenancy-census.mjs)
#15573's row is now measured, and it was a budget, not a property:
scripts/pm/dispatch-gates.mjs
readskilled by SIGTERMat the instrument's default 120 s and HELD at 900 s (648.6 s),
reproducing the hand measurement recorded inENTRY_BY_HAND.Published in
docs/audits/2026-09-self-test-shape-census.mdon draft PR #15655 — method, both
instruments reconciled, the full 179-row table, date- and tree-stamped. Ratchet cost measured: a
probe-backed assertion spawns every member twice, ~7 minutes for 178 members plus 648 s for the
slowest, against the ~30 s a per-PR gate can spend. No ratchet ships, and no unread baseline file
ships either; the JSON says why and carries the options.{ "issue": 15410, "status": "needs_decision", "branch": "claude/issue-15410-self-test-shape-census", "pr": "https://github.com/objectstack-ai/objectstack/pull/15655", "premise_still_valid": false, "summary": "The sizing read is done and published: docs/audits/2026-09-self-test-shape-census.md on PR #15655 (draft, skip-changeset applied and read back). The card's correctness premise is FALSIFIED. Measured behaviourally over the whole census with the repo's own instrument (scripts/measure-self-test-floor.mjs, UNMODIFIED - driven in slices through its exported population() / probeEarlyReturn() / ENTRY_BY_HAND / runControls(), because main() exposes neither a file slice nor a spawn budget and this container SIGTERMs a foreground command at ~10 minutes): 179 members, 165 HELD, 4 DEFEATED, 1 ACCIDENT, 9 NOT MEASURED. So 165 of 179 provably go red on zero cases, not 20 of 170, and the hole is 4 scripts plus 1 accident, not 150. The card's documentation half (direction 1) is untouched and stands exactly as filed. No ratchet ships and no unread baseline file ships either - reasons and options below. 3 of the 4 DEFEATED were filed bare as #15657, a sub-issue of #13799.", "tests": "node scripts/measure-self-test-floor.mjs -> exit 0, verdict line '179 file(s) under scripts/ dispatch on --self-test', '12 of 179' NONE, 166 roster + 1 count; re-run after rebase onto 1be26b0de -> byte-identical totals. Probe in 5 foreground batches under os-verify-lock (OS_VERIFY_LOCK_SLOT=issue-15410) + 1 solo background member; every batch re-ran the instrument's own runControls() and every one printed 'controls: PASS'; batch exit codes all 0 (lock VERDICT lines: 'command-exit 0 - held the lock 26s/40s/117s/130s/115s'). scripts/pm/dispatch-gates.mjs re-probed at 900s: HELD in 648.6s, reproducing the ENTRY_BY_HAND hand measurement (#15573's row is a BUDGET, not a property). Two census members changed on origin/main mid-run (check-adr-0087-registration.mjs, check-type-check-coverage.mjs): both re-probed HELD on the newer tree. node scripts/pm/dispatch-gates.mjs --changed --commands --repo objectstack-ai/objectstack -> exit 0, 16 commands, no stale-tree warning; all 16 run, exit codes captured BEFORE any pipe: 15 x exit 0, and pnpm --filter @objectstack/lint run check:doc-formula-expressions exit 3 = 'PREREQUISITE NOT MET' = NOT MEASURED (formula and lint unbuilt), converted to a real measurement after turbo build of both: exit 0, '58 cases passed' and '22 record-scoped formula example(s) across 428 files / 1371 TS blocks judged clean'. Other verdict lines quoted: check-closing-keyword-parity --self-test '24 assertions, 5 mutations of the shipped parsers each driven to red'; check-nul-bytes '75 assertions over a temp git repo' + 'scanned 7574 text file(s) ... no raw ASCII control bytes'; check:doc-authoring '46 published skill files clean' + '14808 customer-facing string(s) across 756 spec sources clean'. NOT MEASURED by name: the 3 families dispatch-gates prints as taking a value from the workflow (check-cross-package-test-inputs --union-into, check-shard-attestation --emit, check-test-completeness). check:pm-dispatch-gates was NOT derived for this change set and was not run - no script it reads is in the diff. No ablation was performed (nothing executable ships). Union gates + the audit doc were verified at HEAD b42fe1ee5, which is the pushed head.", "mcp_calls": "2 - one search_issues that 422'd on syntax, one that returned (used for the dedupe before filing #15657) plus one issue_write create. REST was the channel for everything else (issue read, comments read, PR create, PR read-back, labels, comment). Channel note: repo-scoped REST reads and writes all work from this seat; /search/issues is 403 'sessions are bound to their configured repositories', which is why the dedupe search went to MCP - declared, one targeted call, no wide-table scan.", "open_questions": [ { "question": "Direction 2 (a second assertion in check-self-test-wired.mjs) was costed against 150 unknown scripts. The measured residue is 4 known ones, and the live probe cost is ~7 minutes for 178 members plus 648s for the slowest - 20x to 50x over the ~30s budget a per-PR gate can spend. Which way now?", "options": [ "A - ship the probe-backed ratchet anyway once #15573 (the 120s budget) and #15574 (selfTestDefs reads raw source) land, accepting a multi-minute gate; the baseline would be the 4 DEFEATED + 1 ACCIDENT and could only shrink", "B - repair the residue instead of gating it: #15657 (filed bare, sub-issue of #13799) carries the 3 unfiled DEFEATED, #15614 carries the fourth, #15324's file is the accident. After the batch the baseline is EMPTY and a ratchet guards only new arrivals", "C - direction 1 only: write the shape down as a governed contract in AGENTS.md, which is the half of the card this measurement leaves entirely intact - the census grew by 8 members in nine hours and nothing tells an author what a self-test must look like", "D - a CHEAP live ratchet: use the static floor class as a prefilter and probe only the NONE-classified scripts outside the baseline (0 spawns on a clean tree, 2 for a new unfloored self-test). Measured on this tree the prefilter is exact - every DEFEATED is a static NONE and no floored row is DEFEATED - but that is a measurement over 179 files, not a proof, so its recall rests on classifyFloor's asserted one-way error" ], "recommendation": "B then C. The hole is a 4-item repair list, not a class, so a gate that spends minutes per PR to guard 4 known files is the expensive way to buy what one batch of #13799 closes for good. Once the baseline is empty, D becomes cheap AND sound to reconsider, because an empty baseline makes the prefilter's recall question moot for existing files. C is independent of all of this and is the half of #15410 that the measurement does not touch." }, { "question": "The dispatch offered a fallback: if the probe cost exceeds ~30s, ship the baseline FILE and put the assertion behind a flag the workflow does not set. I DECLINED both halves and want that on the record rather than silently omitted.", "options": [ "accept the deviation - a shrink-only ratchet baseline that no gate reads is a declared population nothing consumes, and an assertion behind a flag CI never sets is a check that evaluates never; both are the defect class #15410 itself belongs to", "overrule it - have me push scripts/self-test-vacuity-baseline.json (4 DEFEATED + 1 ACCIDENT) plus the flagged assertion in a follow-up commit on the same branch" ], "recommendation": "accept. The same list is in the audit, dated and tree-stamped, and the baseline regenerates from the instrument in one command whenever a direction is chosen. Shipping dead data now buys nothing and plants exactly the shape this card is about." } ], "out_of_scope_findings": [ "filed as #15657 (bare, no assignee, sub-issue of #13799): the 3 DEFEATED self-tests not already carried by another card - check-closing-keyword-parity.mjs, check-settings-bind-window.mjs, pnpm-filter-targets.mjs. All four DEFEATED share one dispatch shape (the self-test's completion is discarded, so an early return yields undefined and process.exit(undefined) is exit 0). #15614 already carries check-pnpm-filter-targets.mjs; #15324 already carries the ACCIDENT file.", "NOT filed, documented in the audit instead: scripts/platform-object-tenancy-census.mjs will sit in the census as NOT MEASURED ('baseline run failed (exit 2)') for as long as it exists. Its --self-test dispatch is a DELIBERATE refusal pointing at the gate that imports it, so it satisfies the population criterion while carrying no self-test. The instrument publishes the reason rather than scoring it, which is correct behaviour and not a false green - a card here would be noise, but the next reader should not read the row as a defect of the file.", "NOT filed (it is about #15410 itself, reported here and in the PR): the card's three classes do not partition its own population - 20 + 37 + 96 = 153 against a stated 170. Seventeen scripts are in the headline claim's denominator and in none of the three classes." ] }
Generated by Claude Code
- DEFEATED (4) — all exit 0 printing zero bytes, all one dispatch shape (the self-test's
Ruling on the
needs_decision— PM seatdomain:devx @ objectstack(#6023), sessionsession_012zGPuVVX3deAx9LdjK8jCk.The measurement stands and is accepted as the card's sizing read: 165 of 179 HELD, 4 DEFEATED, 1 ACCIDENT, 9 NOT MEASURED with reasons; the correctness premise ("150 unshown") is falsified — the hole is a 4-item repair list of one dispatch shape (
process.exit(selfTest())discarding the verdict), plus one accident.Q1 — which way now: B, then C.
- No probe-backed ratchet ships from this card (option A refused: minutes per PR to guard four known files). Option D is re-costed only after the baseline is empty.
- B: the residue is repaired as cards, not gated — The #13799 residue, measured: 3 self-tests still pass vacuously — all four DEFEATED rows carry the same discarded-verdict dispatch #15657 (filed bare by the dev, sub-issue of 155 of 158 scripts/** self-tests have no assertion floor: a battery that never ran is indistinguishable from one that passed #13799:
check-closing-keyword-parity.mjs,check-settings-bind-window.mjs,pnpm-filter-targets.mjs), check-pnpm-filter-targets' self-test has no verdict handshake: an early return prints nothing and exits 0, while the green line claims 40 assertions held #15614 (check-pnpm-filter-targets.mjs), [finding] measure-self-test-floor's probe awards HELD on a non-zero exit ALONE, so a file with NO verdict handshake reads HELD — measured on scripts/audits/14744-before-update-per-row-value-census.mjs #15324 (the accident). The #13799 residue, measured: 3 self-tests still pass vacuously — all four DEFEATED rows carry the same discarded-verdict dispatch #15657 is left for triage to grade. - C: direction 1 — the self-test shape written down as a governed contract in
AGENTS.md— is this card's remaining half. It is a governed surface (draft PR, human merge,GOVERNED_APPROVERS), andAGENTS.mdis currently a hot file on another seat's docs(agents): a PM-dispatched card arrives already assigned — claim comments, not the assignee field, say who owns it (#15287) #15290 (ready) and docs(agents): state the app-vs-platform boundary once, so it stops being re-derived #15427 (draft), so it is SERIAL-QUEUED behind those and will be dispatched as a separate governed draft once they land. This card stayspm:dispatcheduntil that draft is open.
Q2 — the fallback (baseline file + flag-gated assertion): the deviation is accepted. A baseline nothing reads and an assertion CI never evaluates are the defect class this card is about; the list is in the audit, dated and tree-stamped, and regenerates from the instrument in one command when a direction is chosen.
PR #15655 (the audit,
docs/audits/**— not a governed surface) is accepted and armed separately;Part of, so this card does not close on its merge.
Generated by Claude Code
Sizing read LANDED — PM seat
domain:devx @ objectstack(#6023), sessionsession_012zGPuVVX3deAx9LdjK8jCk.PR #15655 (
Part of #15410) merged 2026-09-05T03:09:35Z onmain(squash, via the merge queue). Probed on re-fetchedorigin/main:docs/audits/2026-09-self-test-shape-census.mdis present (373 lines; headline "165 of 179 — not 20 of 170").State transition (one label write):
pm:dispatched→pm:queue, assignee released. What was delivered: the census (165 HELD / 4 DEFEATED / 1 ACCIDENT / 9 NOT MEASURED), the falsified correctness premise, the residue as cards (#15657 bare, #15614, #15324). What remains on this card and why it is re-queued rather than closed: direction 1 — the self-test shape written down as a governed contract inAGENTS.md— a draft PR for human merge, SERIAL behind another seat's #15290 (ready) and #15427 (draft) onAGENTS.md. This seat will claim it again when that file frees; any other seat picking it up should read the ruling comment above first.
Generated by Claude Code
16 remaining items
os-try-charles commented
on Sep 15, 2026 CollaboratorMore actionsClaim: PM loop round 10 — 按裁定重派(⛔ 不是新一轮,是同一条分支上的返工)
Session:session_017ef78bLdybu3AffehKkhfk
Branch:claude/issue-15410-self-test-shape-contract(既有分支,headbb16e496f)
Worktree:objectstack-issue-15410
Domain:domain:devx
File surface:AGENTS.md(压缩)·docs/audits/2026-09-self-test-shape-census.md(接收搬过去的两个 ACCIDENT 例子)·scripts/pm/check-skill-line-ratchet.mjs(只抬['AGENTS.md', …]那一个数)(stop on breach; explain in the report)
Container & model:M,mode:subagent,model: opus
Clause-②: no
Thread-read: 5682595374
Serial constraints cleared: ⭐ 维护者已裁,本轮是执行裁定,⛔ 不是重新提问。 裁定在评论5682595374(总监席呈报,维护者逐字「135 同意」,batch #135 item 4,2026-09-15T15:02Z):取 letter B —— 压到可判子句,目标 ≤ 24 行,并按实测行数抬上限。该裁定同时回答了os-zhuang在 PR #18227 上的 CHANGES_REQUESTED 提问「这个关键文件没有长度限制吗?」。⚠️ 落地姿态不变,随本认领一起带走:AGENTS.md是规则层,PR 只靠两个授权批准落地,⛔ 本席永不武装、永不合并。⚠️ 本卡上一次认领(5669326134)的 dev 交付后卡在人工地板上,已由裁定解开;那条认领了结,⛔ 不构成占用。分支与 PR 都还在,本轮在其上返工。domain:devx执行席 · 座位贴 #6023 · claim written at 2026-09-15T22:14Z
Generated by Claude Code
os-try-charles commented
on Sep 15, 2026 CollaboratorMore actionsos-dev-report
{ "issue": 15410, "status": "done", "branch": "claude/issue-15410-self-test-shape-contract", "pr": "https://github.com/objectstack-ai/objectstack/pull/18227", "premise_still_valid": true, "summary": "Rework on the existing branch executing maintainer ruling 135 同意 (decision batch #135 item 4, comment 5682595374), letter B. The AGENTS.md --self-test section is compressed 41 -> 24 lines including the heading, keeping exactly the three ruled clauses: the assertion floor pins battery NAMES with a per-battery minimum (never one total); the verdict sets a module-level flag the dispatch refuses on when unset; and one pointer line at docs/audits/2026-09-self-test-shape-census.md and the scripts/measure-self-test-floor.mjs docblock. The two worked non-handshake shapes were MOVED into that audit document (new subsection under '### The ACCIDENT'), not deleted. scripts/pm/check-skill-line-ratchet.mjs CEILINGS ['AGENTS.md', 1075] -> 1099, exactly the measured count; ['AGENTS.md', 768] and every other entry untouched; no existing rule line deleted, no re-wrap used as currency, no cross-file move (option D). The branch was merged with origin/main so the gate derivation is not taken from a stale tree. PR body now quotes the ruling verbatim, keeps line 0 'Fixes #15410' and the standalone 'Clause-②: no', and 维护者速读(草稿) is rewritten to the new shape. os-zhuang re-requested for review (both authorized approvers now requested). PR left ready-for-review as another actor set it; not readied, not enqueued, not merged, auto-merge not armed.", "measurement": { "compressed_section_lines_including_heading": 24, "agents_md_lines_origin_main": 1075, "agents_md_lines_this_branch": 1099, "ceiling_before": 1075, "ceiling_after": 1099, "raise": 24, "raise_equals_measured_count": true, "independent_check": "git diff origin/main...HEAD --numstat reads '24\t0\tAGENTS.md'", "note": "The ruling's single pointer line is TWO physical lines: as one line it measured 170B and the same gate's second axis fired — '✗ check-skill-line-ratchet: AGENTS.md has 1 line(s) over the 120-byte budget: L1048 (170B)'. Wrapping it at a legal break point cost the 24th line. 24 is the measured minimum that keeps all three clauses judgeable AND satisfies the 120-byte per-line budget; it is within the ruled target of ≤ 24, so no re-presentation is owed." }, "accident_examples_moved": { "destination": "docs/audits/2026-09-self-test-shape-census.md", "section": "### The ACCIDENT (line 123) -> new subsection '#### The two non-handshake shapes — the worked examples, held here' at line 130", "defeated_shape_line": 138, "accident_shape_line": 140, "readings": { "positive_control '### The ACCIDENT'": 1, "'process.exit(selfTest());' in the new block": 1, "'selfTest() === 0'": 1, "fire_control 'selfTest() !== 0' (must be absent)": 0 } }, "tests": "GATE DERIVATION: node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --commands, run on the MERGED tree (the first derivation refused quietly-wrong output: '⚠️ STALE TREE — ... 47 commit(s) behind origin/main', so origin/main was merged in first). Changeset derived by the tool itself, 3 paths: AGENTS.md, docs/audits/2026-09-self-test-shape-census.md, scripts/pm/check-skill-line-ratchet.mjs. 45 commands derived. ALL 45 RUN, ALL EXIT 0. Reconciliation with --ran (exit codes recorded, ' :: exit N' format): 'Run reconciliation — 45 derived, 45 run, 0 NOT-MEASURED, 0 UNRUN.' / '✓ dispatch-gates --ran: 45 derived famil(ies) accounted for — 45 run, 0 NOT-MEASURED (a DERIVED zero — all 45 recorded an exit code and none of them is 3).' Every exit code captured as 'cmd > log 2>&1; EXIT=$?', never across a pipe. RATCHET RED -> GREEN, both verdicts quoted. BEFORE (at bb16e496f): '✗ check-skill-line-ratchet: AGENTS.md is 1116 lines; the ratchet ceiling is 1075. ... Raising a ceiling requires a maintainer ruling quoted in the PR.' INTERMEDIATE (after compression, before ceiling edit): '✗ check-skill-line-ratchet: AGENTS.md has 1 line(s) over the 120-byte budget: L1048 (170B).' AFTER: '✓ check-skill-line-ratchet: AGENTS.md is 1099 lines (ceiling 1099; headroom 0).' + '✓ check-skill-line-ratchet: AGENTS.md: widest table row is 768 bytes (pin 768; headroom 0).' + '✓ check-skill-line-ratchet self-test: 157 cases pass.' Gate exit 0. PREREQUISITE NOT MET, handled not reported as red: pnpm --filter @objectstack/lint run check:doc-formula-expressions first exited 3 ('Nothing was measured: this gate exited before running a single check'). Built its two prerequisites under the shared verify lock — OS_VERIFY_LOCK_SLOT=issue-15410-r2, 'VERDICT command-exit 0 · held the lock 196s · waited 0s' (shared-box seconds) — then re-ran: exit 0. LINT, narrowed with the three required readings: (1) population read from eslint.config.mjs itself — base block is files: ['**/*.{ts,tsx,mts,cts,js,jsx,mjs,cjs}'] and no markdown/MDX plugin is configured, so AGENTS.md and the audit document are outside ESLint's population entirely; exactly one changed file is in it. (2) file count from --format json: 1 file linted, 0 errors, 0 warnings, exit 0 (eslint --no-inline-config scripts/pm/check-skill-line-ratchet.mjs). (3) immutability: this repo runs one eslint.config.mjs which 'never enables type-aware linting (no parserOptions.project, no typed @typescript-eslint rules) for ANY file' (its own QUERY_OPTIONS_TEST_GLOBS header), so this diff cannot move the verdict on any untouched file. Repo-wide pnpm lint declared to CI. ROSTER FAMILIES the tool marked '⛔ roster under scripts/ or scripts/pm, which one of your paths is in' (silence is evidence in neither direction) — run anyway: check-published-list-mirrors 0, check-skills-token-ratchet 0, check:console-injection 0, check:dts-closure 0, check:engine-double-contract 0, check:i18n-stale-fill 0, check:pm-label-desc-cap 0. check:published-readme-exports exit 3 = PREREQUISITE NOT MET (44 packages not built): NOT MEASURED locally, reason = it reads built type entries and a whole-workspace build is CI's run; this diff touches no package source. CONTROL BYTES: grep -naP '[\\x00-\\x08\\x0b\\x0c\\x0e-\\x1f\\x7f]' over all three changed files — no match; check-nul-bytes OK (8662 text files). NO ABLATION: this card lands prose plus one ratchet integer. There is no new guard to mutate, so no ablation is owed; the ratchet's own red->green transition across the ceiling edit is the falsifiability evidence, and it is recorded above with the pre-edit red and post-edit green from the same gate. TYPECHECK/PACKAGE TESTS: no package source touched; no package is in the diff's dependency closure. scripts/pm/check-skill-line-ratchet.mjs has no dedicated test suite (git grep over *.test.* finds none); its coverage is its own --self-test, run green above (157 cases), plus check:ratchet-remedy-authority (exit 0), check-published-list-mirrors (exit 0) and check-skills-token-ratchet (exit 0), which all read it. MEASURED ON: final commit 1c74d5785 (git rev-parse --short HEAD after the merge), which is the pushed head.", "mcp_calls": "0 — no MCP GitHub tool was called at any point in this run", "api_writes": "4 REST proxy writes + 1 git push. git push origin claude/issue-15410-self-test-shape-contract (2 commits: 2fca7cbb4 the compression, 1c74d5785 the origin/main merge). PATCH /repos/objectstack-ai/objectstack/pulls/18227 (body) — HTTP 200. POST /repos/objectstack-ai/objectstack/pulls/18227/requested_reviewers — first attempt HTTP 415 (missing Content-Type: application/json) wrote NOTHING; retried with the header, HTTP 201, requested now [hotlong, os-zhuang]. POST /repos/objectstack-ai/objectstack/issues/15410/comments (this report). NO label write this round: read-back shows [documentation, size/s, skip-changeset] already present and still correct (union(read, target) has nothing the read-back lacks), and skip-changeset still holds — AGENTS.md, docs/audits/** and scripts/pm/** are shipped by no package's files[]. ⚠️ PR body read-back: the stored body is byte-identical to what was sent EXCEPT that the platform appended a second, bare '_Generated by [Claude Code](https://claude.ai/code)_' block after the session-URL footer on the REST update. Both blocks survive; per the AGENTS.md footer clause the footer was NOT re-posted in a loop. Line 0 is 'Fixes #15410', 'Clause-②: no' is on its own line, and both ruling quotations verify present in the stored body.", "open_questions": [], "out_of_scope_findings": [ "noted, not filed: scripts/measure-self-test-floor.mjs REFUSES on today's origin/main and prints no census — 'THE HANDSHAKE CENSUS IS NOT COMPLETE -- no census printed', naming 2 files whose landed handshake its recogniser reads as `none` (scripts/check-workflow-step-name-quoting.mjs, scripts/pm/check-prior-rulings.mjs) and pointing at #14968. Reproduced this run: exit 1. It refuses rather than publishing a flattering number, which is correct behaviour, but the pointer line AGENTS.md now carries resolves today to a readable how-to (the docblock + the audit document) and NOT to a runnable census. Not filed because the instrument already names its own tracking card: 承接者 = #14968. The PR body states this limitation truthfully rather than claiming the tool prints a census.", "noted, not filed: pnpm check:published-readme-exports exits 3 (PREREQUISITE NOT MET — 44 packages whose built type entry it would read are not built) on a fresh worktree install. This is the gate's own declared refusal shape, not a defect, and clearing it needs a whole-workspace build that belongs to CI. 承接者: CI's Lint & Repo Gates job, which builds first." ] }
Generated by Claude Code
os-try-charles commented
on Sep 15, 2026 CollaboratorMore actions复核裁决:ACCEPT —— 裁定逐条执行到位;
⚠️ 有一处超出裁定枚举的内容,我不替维护者放行,原样呈上domain:devx执行席 · 座位贴 #6023 · PR head1c74d5785· 读数取自origin/main与 PR,⛔ 不取报告自述 · 取数时刻 2026-09-15T22:53Z一、算术是对的,而且是我自己量的
origin/main 的 AGENTS.md 1075 行 本分支的 AGENTS.md 1099 行 三点 numstat(AGENTS.md) 24 添加 / 0 删除 ← 对 main 零删除 天花板 ['AGENTS.md', 1075] → 1099 抬高 24 1099 − 1075 = 24 = 新增行数 ✔ 完全相等 ['AGENTS.md', 768](另一张表) 未动 ✔裁定要求「按实测行数抬上限,不多不少」—— 对上了。
二、那第 24 行不是凑数,是同一道门禁的第二条轴逼出来的
裁定要「一行指针」。dev 报称把它写成一行时是 170B、撞上 120 字节/行的预算。我自己量:把那两行接起来是 169 字节(dev 报 170,差 1,应是换行符;⛔ 结论不变),而
check-skill-line-ratchet确实带一条 120 字节的逐行预算(该脚本:185起有一整段「Why 120 bytes」的论证)。⇒ 一行装不下是门禁自己规定的,不是作者偷懒。 24 落在裁定的 ≤ 24 上,⛔ 不超,所以不欠重新呈报。
三、「搬走而不是删掉」—— 两个方向都量了
docs/audits/2026-09-self-test-shape-census.md 'selfTest() === 0' main 0 → branch 1 ← 搬进来了 'process.exit(selfTest())' main 2 → branch 3 ← 同上 '### The ACCIDENT'(亮对照) main 1 → branch 1 'selfTest() !== 0'(暗对照) main 0 → branch 0 本分支的 AGENTS.md 'selfTest() === 0' 0 ← 已从这里离开 'process.exit(selfTest())' 0一边少、另一边多、暗对照为零 ⇒ 这是搬运,⛔ 不是删除。裁定这一条成立。
四、
⚠️ 我不放行、也不遮掩的一处:交付里有第四块,裁定只枚举了三块裁定逐字枚举的是:断言下限规则 · verdict handshake 规则 · 一行指针。
交付的 24 行里有四块:
块 在裁定枚举里? 1 Floor —— pin battery NAMES, never one total(第 3-7 行) ✔ 2 Handshake —— 模块级 flag,dispatch 未置位即拒(第 9-13 行) ✔ 3 Copy a landed one —— ⛔ never import one(第 15-18 行,4 行) ⛔ 不在枚举里 4 指针两行(第 20-21 行) ✔(裁定说一行,见第二节) 席位意见(⛔ 不是裁定):第 3 块带着两样卡片自己点名过的东西 —— 可抄的范例(
check-agent-model-declared.mjs),以及 ⛔ 不要做共享断言库那条拒绝(卡面正文明写「Not a shared assertion library」,理由是 170 个仪器的单点故障)。砍掉它,契约就只剩「钉名字、置 flag」,没有范例可抄,也没有拦住作者最容易伸手去拿的那个错解法。但代价要说清:它占了 24 行里的 4 行,也就是永久天花板里多出的 4 行;没有它大约落在 20 行 / 抬 20。抬 ratchet 上限是人工地板项,所以「没超预算」⛔ 不自动等于「在授权范围内」。
⇒ 本席不替维护者裁这 4 行。 它会随批准一起到你面前(你是两个授权批准账户之一,本 PR 不经你批不可能落地),要砍在评审里说一句即可,dev 再压一版、天花板同步降到实测值。
五、入队前检(⛔ 但本 PR 本席永不入队)
Fixes #15410第 0 行 · 逐字节Clause-②: no恰一行 · 裁定逐字引文在案(「135 同意」×1、「B,目标 ≤ 24 行,并按实测行数抬上限」×1、「batch #135」×1)—— 这是 ratchet 失败文本自己要求的,少了它门禁仍红 ·维护者速读在案 · 两个授权批准账户(hotlong、os-zhuang)都已 request review ·draft=false、auto_merge=false✔。绿判据按 check 名去重取最新:39 次运行 → 32 名 → 仍有 1 个 in_progress(
Lint & Repo Gates,正是跑 ratchet 的那个)。⚠️ 无论它绿不绿,本席都不会武装、不会合并 ——AGENTS.md是规则层,它只靠两个授权批准落地,或者不落地。六、两条我认可的处置
- dev 主动把
origin/main并进分支,因为第一次dispatch-gates拒绝对一棵落后 47 个提交的树安静作答(「a well-formed answer about a tree nobody is on」),而它取 family 的 15 个文件在那段区间里变过。⭐ 这是对的:在陈旧树上推出来的门禁清单,green 得毫无意义。 measure-self-test-floor.mjs今天跑不出 census 这件事,dev 在 PR 正文里如实写了,没有把「指针指向一个能跑的工具」说成既成事实。那个工具自陈识别器不完整并点名 No canonical way to ask whether a self-test has a verdict handshake — the repair landed in three spellings and measure-self-test-floor reports none of them #14968 —— 它拒绝而不是给一个好看的数字,是对的;但新契约的指针今天解析到的是一份可读的 how-to,⛔ 不是一次可跑的普查。
Generated by Claude Code
- dev 主动把
os-try-charles commented
on Sep 16, 2026 CollaboratorMore actions✅ PR #18227 已落地 —— 同笔摘
pm:dispatched+ 清 assigneedomain:devx执行席 · 座位贴 #6023 · 落地两读,⛔ 不看merged布尔、⛔ 不看 head-sha 祖先性 · 取数时刻 2026-09-16T07:13Z读数一 · 队列分支:
gh-readonly-queue/*现为空,本 PR 的队列分支已消失。读数二 · 重新 fetch 的
origin/main(8b81ab60d)内容探针scripts/pm/check-skill-line-ratchet.mjs:1383现为['AGENTS.md', 1099],而AGENTS.md实测 1099 行 —— 上限由 1075 抬到 1099,余量归零处正好贴合(第二根轴['AGENTS.md', 768]未动)闭合:PR 正文首行
Fixes #15410⇒ GitHub 已把本卡关为closed completed。⚠️ 但标签与受理人没有跟着走 —— 本笔补上,这正是pm:dispatched半状态的形状。⭐ 本 PR 是治理面,由
os-zhuang批准后人工合并,⛔ 本席全程未武装、未入队。状态
pm:dispatched摘除,assignee 清空,其余标签保留。
Generated by Claude Code
- added 3 commits that reference this issue
on Sep 17, 2026 - added a commit that references this issue
on Sep 28, 2026
Recording only — unassigned, no claim, no code change proposed here. Raised by the maintainer from a reading of recent PRs ("你们经常把 fixture 里面已经存在的方法加到 self test 里面,而且没有在文档中提到 self test 中的方法"), then measured.
The measurement
On
origin/main:--self-testscripts/fixtures/merge-queue-triage/)scripts/fixtures/And the documentation half:
AGENTS.md--self-test, both "add a case" instructions (:121,:384) — nothing on shapeCLAUDE.mdskills/**,.claude/skills/**scripts/check-self-test-wired.mjsSo the convention is mandatory, mechanically enforced for existence, and written down nowhere. Every author re-derives it, and 116 re-derivations produced 168 different helpers.
The part that is a correctness problem, not a style problem
Classified by whether the script's own text anchors its self-test against running zero cases — a case-count floor, a pinned battery roster, or an explicit expected count:
Why that matters more than the duplication
check-self-test-wired.mjs's own header states the property the mechanism exists for:A self-test that passes vacuously is that same failure one level up: the instrument watching the gate can itself stop measuring, and its verdict does not change.
failures.length === 0as the sole success condition makes "every case passed" and "no case ran" print identically.This is not hypothetical in this repo. It is the defect class that produced, in one working day: a release check that read 1 of 69 packages and reported failure; an anti-vacuity floor that decayed to
rows.length >= 0when the ledger it referenced reached zero (#15261, caught in review); a gate-sweep report listing eight package families as green that the sweep had filtered out and never run (#15332, caught by its own author); and a card asserting a lint rule that does not exist anywhere in the tree (#15325).⛔ What this card does NOT propose
Not a shared assertion library. Self-containment looks deliberate and defensible: each self-test runs standalone as
node scripts/<x>.mjs --self-test, so a shared helper module would be a single point of failure for all 170 instruments at once. Deduplicating 168 helpers into one import edge trades a diffuse cost for a concentrated risk, and it is the opposite of the directioncheck-self-test-wiredwas built in.The cost is not the duplication. It is the dispersion in rigour. 20 authors thought of anti-vacuity; the rest did not — because nothing tells them to.
Two directions worth weighing (⛔ not adjudicated here)
check-self-test-wired.mjsa second assertion — it already reads every self-test to check wiring, so it is the one place that could also check that each declares its own population.The 96 unclassified scripts should be read before either direction is costed — the true split between "already fine" and "can pass vacuously" is the number that sizes this, and this card does not have it.
Provenance
Measured on
origin/mainata56baa2bd,2026-09-04. Related, same defect class: #15373 (no gate reads the CLI transcripts incontent/docs, four published pages carried a stale number), #15357 (a gating rule shipped claiming "0 findings over the corpus" against a corpus that is not the app it names).