Repository navigation
fix(gates): judge spec member citations in published prose, not only in comments (objectui#7995) - #8370
Conversation
…in comments (objectui#7995) `check-spec-symbol-derivation` read only the comments of `packages/*/src`, so a false `@objectstack/spec` attribution written as prose in `content/docs/**` was judged by nothing. objectui#7537 is the receipt: PR #7510 corrected three JSDoc copies of one such claim and a fourth copy in `content/docs/fields/lookup.mdx` shipped untouched, because no gate reads it. Rule 4 at member granularity asks only whether a name the prose spells exists in the spec, which needs no declaration, no tie and no claim phrase. So its scan surface widens to `content/docs/**` and the rule itself does not move: the citation grammar is factored into one `memberCitationsIn`, and the TypeScript comment scanner was refactored ONTO it rather than having a second copy written beside it. A comment BLOCK is the scope on one side, a markdown PARAGRAPH on the other; everything that decides a verdict is shared. Census taken BEFORE enforcement, on 411a132 against `@objectstack/spec@17.3.0`: 184 documentation pages, 32 mentioning the spec, 183 raw `Symbol.member` citations, 5 naming a spec export with a knowable member set, 3 surviving proximity and same-sentence, 3 resolving, 0 dangling. Zero corrections, zero waivers, no ledger. Skipping fenced code moves the raw count 183 -> 128 and leaves the judged population identical, so there is no fence rule. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FhBNJcLRZLe8M87VcUgpKr
…jectui#7995) The count line read "1 passage cite"; the singular arm now carries the verb. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FhBNJcLRZLe8M87VcUgpKr
|
ACCEPT (#7995) — reviewed on the tree at head Property 1 — closed, and the probe is the proof. A false prose citation planted in Property 2 — FALSIFIED, and the seat verified it independently. The card says the gate drops the member tail. It does not, and has not since Census before enforcement, and the honest consequence: 184 pages, 32 mentioning the spec, 183 raw citations narrowing to 3 that resolve — and zero dangling. So the widening lands with zero corrections, zero waivers and NO ledger. The reasoning for refusing a seventh empty ledger is right on every axis: a ledger with no rows is a name reserved for a future waiver, which is the opposite of a tightening. Ablation discriminates rather than merely reds. Seven legs, including a CORRECT prose citation that must stay GREEN, plus two legs (vi, vii) whose only job is to prove the PINS bite rather than the wiring — because ablating the call site alone leaves the unit pins green and would have proved nothing about them. On the dev's routing question: Two things carried out of this run: the gate's rule reads a SPELLING, not an assertion, so a page explaining that the spec REFUSES a key reads like one claiming it declares it — an inherited property of the comment transport, now documented in the header, with a measured population of zero and the escape being the wording the repaired comments already use. And #8369 is filed against Next: CI convergence → flip ready → post-flip guard → auto-merge SQUASH → queue confirmation → landing probe (the prose scan reaching Generated by Claude Code |
|
Armed: PR #8370 flipped ready at 2026-09-07T15:01:24Z on head Generated by Claude Code |
|
LANDED: merged at 2026-09-07T15:16:54Z as Generated by Claude Code |
Fixes #7995
Both properties objectui#7995 names are closed. One of them this PR closes; the other was already closed two days before the card was filed, and that half is a measurement, not an implementation. Everything below is a reading taken on this branch, and every number is reproducible from the commands quoted.
Property 1 — prose in
content/docs/**is judged by nothing. CLOSED HERE.Probe before, on base
411a132c0, using the gate own machinery rather than a regex — a false spec attribution planted as prose incontent/docs/fields/lookup.mdx:SelectOptionSchemais a live export andiconis refused by name (unrecognized_keys, probed against the installed 17.3.0), so the sentence is false at the member — and the gate had nothing to say, becausesourceFiles()walkspackages/*/srcand nothing else.Probe after, same plant on this branch:
How. Rule 4 at member granularity asks only whether a NAME the prose spells exists in the spec — no declaration, no compile-time tie, no claim phrase. That question is transport-free, so its scan surface widens to
content/docs/**and the rule itself does not move: the citation grammar is factored into a singlememberCitationsIn, and the TypeScript comment scanner was refactored ONTO it rather than having a second copy written beside it. Two dialects of one rule is exactly what commandment 0.1 (contract-first) forbids, and a gate is not exempt. What stays transport-specific decides nothing: a comment BLOCK is the scope on one side, a markdown PARAGRAPH on the other. That analogue is load-bearing — a markdown heading carries no sentence terminator, so without blank lines as hard boundaries the same-sentence test would measure across a heading into an unrelated section (pinned).Census, taken BEFORE enforcement
A gate written against an unknown population is how a scan-surface widening lands as a wall of reds. Measured on
411a132c0against@objectstack/spec@17.3.0, overcontent/docs/**, with an instrumented copy:The three survivors are
FormViewSchema.type,DashboardWidgetSchema.filterBindingsandPageHeaderProps.icon, and all three are correct.Fix-or-ledger decision: neither is needed — the false set is EMPTY. No prose correction, no waiver, no ledger, no allowlist. Under the four axes that is the only defensible outcome: 实际业务需求 — there is no measured debt to serve, so a ledger would be a declaration with nothing behind it; 项目长远合理性 — this repo has landed the shrink-only ledger idiom six times this shift and a seventh with zero rows would dilute the idiom, not extend it; 防 AI 犯错 — an empty ledger block is a name reserved for a future waiver, which is the opposite of a tightening; 创业阶段不扩散 — the widening stops at
content/docs/**, the surface the card demonstrated, and does not reach package READMEs ordocs/adr/**.Also measured: skipping fenced code moves the raw count 183 to 128 and leaves the judged 5 / 3 / 0 identical, so there is no fence rule. A fence rule would have been a precision claim with nothing behind it.
Property 2 — the dangling member tail. ALREADY CLOSED; the card premise is stale.
Probe before, on base
411a132c0, a dangling member citation planted in a scanned source (packages/types/src/select-option.ts):The gate already judges the member tail. It has since
d28d87bf4(PR #7617, objectui#7513, merged 2026-09-04) — two days before objectui#7995 was filed on 2026-09-06. The card sentence "It validates a citation at symbol granularity" describes the gate as it was before that commit.Second, and independently: the two specimens the card names are no longer dangling at all. Resolved against the installed
@objectstack/spec@17.3.0through the gate own resolver:17.3.0 executes the maintainer 2026-08-25 ruling on objectui#6140 / objectui#6153 and declares both keys;
packages/types/src/__tests__/select-option-spec-extension-7014.test.tsalready pins that boundary in both directions. So a PR that "corrected" those two citations today would be writing a new false claim in the opposite direction.Residue declared: this PR implements nothing for property 2. It measures it, and it keeps the property under test through the shared grammar — the probe above is a leg of the ablation, and the pin asserts a comment and a page are judged identically on the same sentence.
Ablation, on the committed tree
Every leg: trap plus restore, mutation proven on disk by a
grep -con the exact injected text before any result is read, restore proven bygit hash-objectequal to theHEADblob AND an emptygit diff HEAD. No build is involved — this gate is ascripts/entry point that reads sources directly and resolves the spec fromnode_modules, so there is nodist/for a stale artifact to hide in.Legs (vi) and (vii) exist because (v) alone does not discriminate: (v) proves the WIRING in
main()does the work, and the unit pins stay green under it because they call the scanner directly. (vi) and (vii) are what prove the PINS bite.Gates, each captured by redirect and read from the gate own verdict line
check:doc-snippets,check:doc-examplesandcheck:skill-examplesfirst returned exit 2, PRECONDITION NOT MET (unbuilt packages) — read as NOT MEASURED, never as a failure. They were re-run afterturbo run buildand are the exit 0 above.pnpm lint:rootis the repository-wide root run, not a narrowed one, so no narrowing needs declaring for it. The three package-level farms (pnpm lint,pnpm test,pnpm type-checkthrough turbo) are CI-owned; this diff is two files underscripts/, which no package build or package test reads.Filed while here
objectui#8369 —
check-lint-rule-coveragewalks gitignored build output (apps/console/plugin.js), so the gate and its pin both turn red after any local build and green again when the artifact is removed, with nothing else changed. Hit on this branch and confirmed independent of this diff by that control. Not touched here.Files
No changeset is owed: neither path is published source of a released package (verified by
check-changeset-presence.mjs, exit 0).Draft, per the dispatch. The seat did not flip it ready and did not queue it.
🤖 Generated with Claude Code
https://claude.ai/code/session_01FhBNJcLRZLe8M87VcUgpKr
Generated by Claude Code