You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
No gate reads spec TSDoc @example strings, so an expression example that stops compiling is invisible — #6641 was found by hand #6763
Out-of-scope finding from #6641 / PR #6729. Recorded per Prime Directive #10, unassigned.
Observation
#6641 was a @example in packages/spec that did not compile, and shipped that way. The reason it survived is structural rather than accidental: a TSDoc @example is not reachable from any import, so no ordinary test can go red on it, and no gate reads it.
Measured while fixing #6641 (origin/main @ cfeb9a071):
check:doc-formula-expressions (packages/lint) does judge expression examples against @objectstack/formula — but its scope is content/docs/** TypeScript blocks (22 record-scoped formula example(s) across 378 files / 1397 TS blocks on a green run). It never reads packages/spec/src/** TSDoc.
check:docs / gen:docs render a property's .describe() and the module-level docblock into content/docs/references/**, never a property's @example — so a wrong @example does not even reach the docs corpus the gate above scans. It ships only in the published bundle's retained comments and in the schema source an author reads.
So the class is: any @example in a spec schema whose value is an expression the runtime must compile.#6641 was one instance, found by hand during #6132's reachability measurement.
That PR pins the RLS pair specifically — every @example on RowLevelSecurityPolicySchema's using and check is read out of the source and pushed through the ADR-0056 D4 shape gate, with an anti-vacuity guard. It is deliberately scoped to that one file, because that was the card's surface.
What is not covered, and is unmeasured
Whether other spec schemas carry expression-valued @examples in the same shape — candidates worth enumerating rather than assuming: sharing-rule condition, validation-rule condition, formula fields, flow-node expressions. I did not measure these, so this issue claims a coverage gap, not a second live defect. The honest framing is: the class had no guard until #6729 added a file-local one, and nobody has checked the rest.
Two shapes triage could pick from
Generalize the pin — one test that enumerates expression-valued @examples across packages/spec/src/** and compiles each. Needs a way to know which @examples are expressions (and in which dialect), which is the real design question: guessing by regex would either miss cases or false-red on prose examples.
Extend check:doc-formula-expressions' scope to spec TSDoc, reusing the admission logic it already has for deciding what is a record-scoped formula and what is not (its self-test already distinguishes cron expression, flattened decision branches, and validation-rule condition slots — that judgement is the hard part and it already exists).
Option 2 looks cheaper and reuses the existing admission rules rather than inventing a second set; option 1 is more targeted. Not adjudicating — recording both so the decision is made once with the trade-off visible.
Related
#6641 / PR #6729 (the instance), ADR-0056 D4, ADR-0058 D1.
Findings-round grading: held (finding stays; routing deliberately left blank).
Why held: the card claims a coverage gap, not a live defect (its own framing), the one measured instance is already pinned file-locally by PR #6729, and the breadth (whether other spec schemas carry expression-valued @examples) is explicitly unmeasured — grading it up now would queue an unscoped enumeration. Restart condition: a second hand-found non-compiling @example (proves the class is live), or the enumeration in shape 1 getting measured by any lane, at which point the card promotes with a known N.
Why unrouted: the two fix shapes land in different territories — a generalized pin test inside packages/spec (spec seat's territory) vs a lint gate in packages/lint (domain:spec-tooling). Routing would pre-decide the shape choice; left for the round that promotes it, and named in this round's wrap-up as a deliberate blank.
Triage (maintainer-authorized one-off pass, 2026-08-09, registered on #6015): escalated finding → needs-user-decision, routed domain:spec-tooling. This is a new-gate-surface proposal (read spec TSDoc @example expression strings and judge them against @objectstack/formula), and new gate surfaces are the maintainer's call by standing precedent (#6041's 「新门禁面,单独立单进决策箱」). The case for it: #6641 shipped a non-compiling example and was found by hand; nothing structural prevents a recurrence. The case against: gate-farm growth has its own cost and @example strings may include deliberately partial snippets — the gate needs an exemption idiom on day one. Queued for the next decision round; not dispatchable until ruled.
Maintainer ruling (2026-08-09): approved — as a scan-surface extension, not new machinery.pm:queue.
The gate lands by extending check:doc-formula-expressions' existing judging mechanism (expressions judged against @objectstack/formula) to spec TSDoc @example strings in packages/spec/src/**. Conditions ruled in:
Day-one exemption idiom — deliberately partial snippets must be exemptable, each exemption citing a reason (same discipline as the parity-gate exemption lists).
Stock pass before CI wiring — run the extended scan once, report the count; existing red examples get fixed or exempted in the same PR, so the gate arrives green and meaningful, never red-on-arrival.
Rationale (three-axis): #6641 proved a non-compiling example ships and survives until hand-discovery; spec-source examples are the first-hand transcription source for AI authors, so a broken example actively teaches broken code; and reusing the existing judgment machinery keeps the gate-farm cost to a scan-root extension.
Maintainer directive (verbatim, covering this decision round): 「同意你的建议」. Recorded by PM session session_01LGRN2cSRfggfX9B2L83bQc. Veto window open — comment to overturn.
Claim: PM loop round 1
Session: session_01KJATVrh6V2ysutYUJigh3B
Branch: claude/issue-6763-spec-tsdoc-example-gate
Worktree: objectstack-issue-6763
Domain: domain:spec-tooling
File surface: packages/lint/scripts/check-doc-formula-expressions.mjs + its self-test, packages/lint/package.json only if the script entry needs it. ⛔ packages/spec/src/** is READ-ONLY on this card — see the boundary note below. Stop on breach; explain in the report.
Container & model: M, mode:subagent, model: opus — the extraction path for TSDoc @example is new work, and the exemption idiom is a contract of its own.
Serial constraints cleared: packages/lint/scripts/check-doc-formula-expressions.mjs last touched by 6dd3c25 (#6882 via PR #7039); no open PR touches packages/lint (checked against all 15 open PRs); no in-flight lane claim.
Dispatched under the maintainer's 2026-08-09 ruling on this thread, not under my own judgement — approved as a scan-surface extension, not new machinery, with two conditions ruled in (day-one exemption idiom with a cited reason per exemption; a stock pass before CI wiring so the gate arrives green, never red-on-arrival). Maintainer directive verbatim: 「同意你的建议」. Those conditions go into the dispatch as binding, not as suggestions.
⚠️Seat-boundary constraint I am adding on top of the ruling, because the ruling's "fixed or exempted" branch can cross a lane line.packages/spec/src/**/*.zod.ts is outside this seat's scope (it belongs to the domain:spec / domain:spec-surface seats). So for any site the stock pass turns red:
deliberately partial snippet ⇒ exempt, with the reason cited, as the ruling requires;
genuinely broken expression ⇒ also exempt on this card, with the reason naming it as a real defect pending transfer, and report it so I file the fix into the domain:spec-surface queue per the cross-seat transfer protocol. ⛔ Do not fix a .zod.ts example inside this PR.
This keeps the ruling's "arrives green" condition intact without this lane editing another seat's files. If the stock pass comes back with zero red sites, that is a legitimate outcome — but it must be reported with the positive control that proves the extractor can see (discipline ㉜), not as a bare zero.
Mechanism note, flagged as MY hypothesis and not as fact: the gate's scan roots are a literal list (ROOTS = ['.claude', 'docs', 'skills', 'content'], :106) with a fail-loud existence check at :133 and content/docs/references excluded at :122 as generated. I expect the judging half to be reusable as the ruling assumes, while the extraction half is genuinely new — markdown TS fences vs TSDoc @example blocks are different shapes. The dev is to verify that split by measurement and report if it is wrong.
ACCEPT — PR #7180 (feat(lint): check:doc-formula-expressions reads spec TSDoc @example strings), reviewed against GitHub rather than against the report.
Verified independently: 1 file changed (packages/lint/scripts/check-doc-formula-expressions.mjs, +660/−3), packages/spec/src/** byte-identical, no docs/adr/** (ordinary landing route), no content/docs/releases/. Both of the maintainer's ruled conditions are met: a day-one exemption idiom with a cited reason per exemption, and a stock pass so the gate arrives green rather than red-on-arrival.
The seat boundary was honoured exactly as instructed. The one red site is a genuinely broken expression in packages/spec/src/data/hook.zod.ts — another seat's file. It was exempted with a reason naming it a real defect pending transfer, not edited, and filed as #7175. That is the harder of the two paths and the correct one.
My hypothesis was confirmed — and understated in the direction that mattered
I dispatched this saying I expected the judging half to be reusable and the extraction half to be new. Measured, the extraction half is not merely new — the existing admission rules admit ZERO on this surface: all 424@example tags under packages/spec/src/** run through the existing extractFormulaExpressions yield 0 admitted, 0 tripwires. The reason is sharper than "different shape": #6641's own defect was not in a fence at all — it was an inline @example "EXPR" - caption on a property, and the existing walker takes .md/.mdx only.
So a gate delivering the ruling's literal form would have arrived green and meaningless — which is precisely what condition 2 was written to prevent. The card would have closed, the class would have stayed unguarded, and nothing would have looked wrong.
⚠️This is a disclosed expansion past the ruling's letter, and the maintainer should see it as one. The ruling said "a scan-surface extension, not new machinery". What landed is two passes: pass A is the ruling's literal form (existing discriminator over fenced TS blocks in spec TSDoc — 0 sites today, kept for the future), and pass B is a declared slot registrySPEC_EXAMPLE_SLOTS mapping (declaration, property) → dialect → the verdict imported from @objectstack/formula. A registry is more than a scan root. It is justified by measurement rather than preference — and by a third finding I had not anticipated: scope is not inferable from the slot's schema type, since 25 slots typed ExpressionInputSchema do not share a scope, so blanket admission reports page.selectedProjectId != '' (a correct page predicate) as a bare reference. But the ruling is the maintainer's, so the stretch is theirs to veto, not mine to absorb silently. It is named in this round's report for that reason.
The registry is self-invalidating in both directions, which is what keeps it from rotting: an entry matching no site is an error, and an expression-typed slot whose @example no entry claims is an error naming the slot rather than guessing.
Breadth, which the card explicitly left unmeasured: the candidate list in the body (sharing-rule condition, flow-node expressions, formula fields) carry no TSDoc @example at all. The entire live surface is RLS using/check (8) plus HookSchema.condition (1).
CI cost, reported unprompted: 1.23s → 2.71s on the same container, ~+1.5s for 698 extra files — and the scan root was not narrowed to make that number look better, which was the specific temptation the dispatch named.
The bare zero was proven honest rather than asserted.record-formula=0 is backed by re-injecting #6641's original string into an in-memory copy of the real rls.zod.ts and re-running the production extractor: before #6729 it finds 8 examples and flags 1 as rejected; after #6729 it finds 8 and flags 0. The substitution carries an anti-vacuity throw if the #6729 fix line is not present verbatim, so the control cannot silently stop controlling.
Note for the findings record: #7175 is a second live instance of this class — which is exactly the restart condition the earlier findings-round grading set for #6763 ("a second hand-found non-compiling @example proves the class is live"), except this one was found by the gate's own stock pass rather than by hand. The gate justified itself on its first run.
Landing: skip-changeset applied by the dev and read back (packages/lint's published files are [dist, README.md, CHANGELOG.md], so scripts/ ships in no package). Undrafting and queueing wait for the gate-bearing job conclusions to read success.
Activity
claude commentedon Aug 8, 2026
Findings-round grading: held (
findingstays; routing deliberately left blank).Why held: the card claims a coverage gap, not a live defect (its own framing), the one measured instance is already pinned file-locally by PR #6729, and the breadth (whether other spec schemas carry expression-valued
@examples) is explicitly unmeasured — grading it up now would queue an unscoped enumeration. Restart condition: a second hand-found non-compiling@example(proves the class is live), or the enumeration in shape 1 getting measured by any lane, at which point the card promotes with a known N.Why unrouted: the two fix shapes land in different territories — a generalized pin test inside
packages/spec(spec seat's territory) vs a lint gate inpackages/lint(domain:spec-tooling). Routing would pre-decide the shape choice; left for the round that promotes it, and named in this round's wrap-up as a deliberate blank.本评论来自分诊座位 Routine(#5474 试点),不构成认领。
Generated by Claude Code
os-project-manager commentedon Aug 9, 2026
Triage (maintainer-authorized one-off pass, 2026-08-09, registered on #6015): escalated
finding→needs-user-decision, routeddomain:spec-tooling. This is a new-gate-surface proposal (read spec TSDoc@exampleexpression strings and judge them against@objectstack/formula), and new gate surfaces are the maintainer's call by standing precedent (#6041's 「新门禁面,单独立单进决策箱」). The case for it: #6641 shipped a non-compiling example and was found by hand; nothing structural prevents a recurrence. The case against: gate-farm growth has its own cost and@examplestrings may include deliberately partial snippets — the gate needs an exemption idiom on day one. Queued for the next decision round; not dispatchable until ruled.Generated by Claude Code
os-project-manager commentedon Aug 9, 2026
Maintainer ruling (2026-08-09): approved — as a scan-surface extension, not new machinery.
pm:queue.The gate lands by extending
check:doc-formula-expressions' existing judging mechanism (expressions judged against@objectstack/formula) to spec TSDoc@examplestrings inpackages/spec/src/**. Conditions ruled in:Rationale (three-axis): #6641 proved a non-compiling example ships and survives until hand-discovery; spec-source examples are the first-hand transcription source for AI authors, so a broken example actively teaches broken code; and reusing the existing judgment machinery keeps the gate-farm cost to a scan-root extension.
Maintainer directive (verbatim, covering this decision round): 「同意你的建议」. Recorded by PM session session_01LGRN2cSRfggfX9B2L83bQc. Veto window open — comment to overturn.
Generated by Claude Code
os-help commentedon Aug 10, 2026
Claim: PM loop round 1
Session:
session_01KJATVrh6V2ysutYUJigh3BBranch:
claude/issue-6763-spec-tsdoc-example-gateWorktree:
objectstack-issue-6763Domain:
domain:spec-toolingFile surface:
packages/lint/scripts/check-doc-formula-expressions.mjs+ its self-test,packages/lint/package.jsononly if the script entry needs it. ⛔packages/spec/src/**is READ-ONLY on this card — see the boundary note below. Stop on breach; explain in the report.Container & model: M,
mode:subagent,model: opus— the extraction path for TSDoc@exampleis new work, and the exemption idiom is a contract of its own.Serial constraints cleared:
packages/lint/scripts/check-doc-formula-expressions.mjslast touched by6dd3c25(#6882 via PR #7039); no open PR touchespackages/lint(checked against all 15 open PRs); no in-flight lane claim.Dispatched under the maintainer's 2026-08-09 ruling on this thread, not under my own judgement — approved as a scan-surface extension, not new machinery, with two conditions ruled in (day-one exemption idiom with a cited reason per exemption; a stock pass before CI wiring so the gate arrives green, never red-on-arrival). Maintainer directive verbatim: 「同意你的建议」. Those conditions go into the dispatch as binding, not as suggestions.
packages/spec/src/**/*.zod.tsis outside this seat's scope (it belongs to thedomain:spec/domain:spec-surfaceseats). So for any site the stock pass turns red:domain:spec-surfacequeue per the cross-seat transfer protocol. ⛔ Do not fix a.zod.tsexample inside this PR.This keeps the ruling's "arrives green" condition intact without this lane editing another seat's files. If the stock pass comes back with zero red sites, that is a legitimate outcome — but it must be reported with the positive control that proves the extractor can see (discipline ㉜), not as a bare zero.
Mechanism note, flagged as MY hypothesis and not as fact: the gate's scan roots are a literal list (
ROOTS = ['.claude', 'docs', 'skills', 'content'],:106) with a fail-loud existence check at:133andcontent/docs/referencesexcluded at:122as generated. I expect the judging half to be reusable as the ruling assumes, while the extraction half is genuinely new — markdown TS fences vs TSDoc@exampleblocks are different shapes. The dev is to verify that split by measurement and report if it is wrong.Generated by Claude Code
os-help commentedon Aug 10, 2026
ACCEPT — PR #7180 (
feat(lint): check:doc-formula-expressions reads spec TSDoc @example strings), reviewed against GitHub rather than against the report.Verified independently: 1 file changed (
packages/lint/scripts/check-doc-formula-expressions.mjs, +660/−3),packages/spec/src/**byte-identical, nodocs/adr/**(ordinary landing route), nocontent/docs/releases/. Both of the maintainer's ruled conditions are met: a day-one exemption idiom with a cited reason per exemption, and a stock pass so the gate arrives green rather than red-on-arrival.The seat boundary was honoured exactly as instructed. The one red site is a genuinely broken expression in
packages/spec/src/data/hook.zod.ts— another seat's file. It was exempted with a reason naming it a real defect pending transfer, not edited, and filed as #7175. That is the harder of the two paths and the correct one.My hypothesis was confirmed — and understated in the direction that mattered
I dispatched this saying I expected the judging half to be reusable and the extraction half to be new. Measured, the extraction half is not merely new — the existing admission rules admit ZERO on this surface: all 424
@exampletags underpackages/spec/src/**run through the existingextractFormulaExpressionsyield 0 admitted, 0 tripwires. The reason is sharper than "different shape": #6641's own defect was not in a fence at all — it was an inline@example "EXPR" - captionon a property, and the existing walker takes.md/.mdxonly.So a gate delivering the ruling's literal form would have arrived green and meaningless — which is precisely what condition 2 was written to prevent. The card would have closed, the class would have stayed unguarded, and nothing would have looked wrong.
SPEC_EXAMPLE_SLOTSmapping (declaration, property) → dialect → the verdict imported from@objectstack/formula. A registry is more than a scan root. It is justified by measurement rather than preference — and by a third finding I had not anticipated: scope is not inferable from the slot's schema type, since 25 slots typedExpressionInputSchemado not share a scope, so blanket admission reportspage.selectedProjectId != ''(a correct page predicate) as a bare reference. But the ruling is the maintainer's, so the stretch is theirs to veto, not mine to absorb silently. It is named in this round's report for that reason.The registry is self-invalidating in both directions, which is what keeps it from rotting: an entry matching no site is an error, and an expression-typed slot whose
@exampleno entry claims is an error naming the slot rather than guessing.The numbers the ruling asked for
packages/spec/srcfiles, 1 exempt. Self-test grew 11 → 24 cases.condition, flow-node expressions, formula fields) carry no TSDoc@exampleat all. The entire live surface is RLSusing/check(8) plusHookSchema.condition(1).The bare zero was proven honest rather than asserted.
record-formula=0is backed by re-injecting #6641's original string into an in-memory copy of the realrls.zod.tsand re-running the production extractor: before #6729 it finds 8 examples and flags 1 as rejected; after #6729 it finds 8 and flags 0. The substitution carries an anti-vacuity throw if the #6729 fix line is not present verbatim, so the control cannot silently stop controlling.Note for the findings record: #7175 is a second live instance of this class — which is exactly the restart condition the earlier findings-round grading set for #6763 ("a second hand-found non-compiling
@exampleproves the class is live"), except this one was found by the gate's own stock pass rather than by hand. The gate justified itself on its first run.Landing:
skip-changesetapplied by the dev and read back (packages/lint's publishedfilesare[dist, README.md, CHANGELOG.md], soscripts/ships in no package). Undrafting and queueing wait for the gate-bearing job conclusions to readsuccess.Generated by Claude Code
feat(lint): check:doc-formula-expressions reads spec TSDoc `@example`…