Repository navigation
feat(scripts): bound snippet resolution at the repository root manifest - #7554
Merged
Merged
Conversation
A bare specifier that neither the workspace map nor the declared-dependency map covers still resolved in the shared snippet harness, because pnpm symlinks the repository ROOT's own devDependencies into `/node_modules`, one directory above where every block is compiled. Measured: `vitest` and `@playwright/test`. A guide could import a test runner its reader was never told to install and stay green on this workspace's copy. `compileSnippets` now refuses such a specifier, unconditionally for both consumers, and keeps the block importing it out of the semantic program the way an unparseable block is kept out — so the coverage count says what was judged instead of counting it as checked. One predicate, two enforcement points: the resolver (the regime, proven live on every run by a new ROOT-DECLARED control) and a per-block AST walk (the attribution). The JSX factory module is the single exemption, because the compiler imports it on the author's behalf. The one docs snippet the bound reds is declared, with the guide now naming the install the reader needs. The four marked skill fences it reds are carried in a shrink-only `KNOWN_ROOT_DEVDEP_EXAMPLES`, so the bound lands with zero new red; retiring a row is a skills judgement over a governed surface, not this change's to make. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019RfFHiRCSs3JXLK4cwcfox
This was referenced Sep 3, 2026
os-steve
marked this pull request as ready for review
September 3, 2026 21:38
os-steve
enabled auto-merge
September 3, 2026 21:38
objectui#7550's per-category `MARKED_FLOOR` ratchet (PR #7553) landed on the same two files. Both behaviours are kept whole: - `scripts/check-skill-examples.mjs` auto-merged. The summary now carries the floors on its `Marked:` line and the root bound's refused count on its own `Root bound:` line, and the exit path reads both — the floor breach check and the undeclared/stale root-bound rows. - The one conflict was this suite's import list, resolved by keeping both sides' symbols. - The two docblocks now name each other, which is the interaction neither PR could state alone: the floor counts MARKS, so a fence the root bound refuses stays inside it while being type-checked by nothing, and unmarking one to silence a refusal would breach the floor. Two ratchets, counting different things, neither substituting for the other. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019RfFHiRCSs3JXLK4cwcfox
os-steve
pushed a commit
that referenced
this pull request
Sep 3, 2026
…es (#7557) The root-manifest bound (#7554) refused four MARKED fences in skills/objectui/guides/testing.md and carried them as shrink-only debt in KNOWN_ROOT_DEVDEP_EXAMPLES. A declared row is uncovered debt, not a green: every run printed "13 of 17 ts fence(s) judged". Measured first, per the card's two options. check-skill-examples.mjs reads exactly ONE declaration on a fence -- MARKER, an exact-string match on the whole line, with no reason field, no install field and no capture group -- and check-doc-snippet-types.mjs's FRAGMENT_MARKER is not read by it at all (the word appears twice in the file, both times in prose about the docs gate's opposite opt-OUT design, never in code). The bound itself, resolvesOnlyThroughRootManifest, is a pure function of the specifier and two repository-wide maps with no per-block parameter to declare into. So there is no form in which a fence keeps its mark and names its install, and even the docs gate's fragment form routes a block AWAY from the compiled set -- the same coverage loss as the row, under a different name. That selects option 2. - unmark the four fences, reason written beside each: vitest and @playwright/test are the reader's own installs, not packages this repository publishes; - delete all four rows, leaving KNOWN_ROOT_DEVDEP_EXAMPLES empty, with its docblock recording the measurement and when a NEW row is still right; - lower MARKED_FLOOR ts 17 -> 13, reason beside the row, in this same PR -- the move #7550's ratchet allows only here. Not a precedent for unmarking a red fence: these four were type-checked by nothing at all for the whole of their life as rows. Before: Root bound 4 refused, 4 rows declared; Semantic phase 13 of 17. After: Root bound refuses nothing; Semantic phase 13 of 13; Marked 13 ts (floor 13), 39 json (floor 39). Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019RfFHiRCSs3JXLK4cwcfox
This was referenced Sep 3, 2026
This was referenced Sep 6, 2026
akarma-synetal
pushed a commit
to akarma-synetal/objectui
that referenced
this pull request
Sep 9, 2026
…es (objectstack-ai#7557) (objectstack-ai#7568) The root-manifest bound (objectstack-ai#7554) refused four MARKED fences in skills/objectui/guides/testing.md and carried them as shrink-only debt in KNOWN_ROOT_DEVDEP_EXAMPLES. A declared row is uncovered debt, not a green: every run printed "13 of 17 ts fence(s) judged". Measured first, per the card's two options. check-skill-examples.mjs reads exactly ONE declaration on a fence -- MARKER, an exact-string match on the whole line, with no reason field, no install field and no capture group -- and check-doc-snippet-types.mjs's FRAGMENT_MARKER is not read by it at all (the word appears twice in the file, both times in prose about the docs gate's opposite opt-OUT design, never in code). The bound itself, resolvesOnlyThroughRootManifest, is a pure function of the specifier and two repository-wide maps with no per-block parameter to declare into. So there is no form in which a fence keeps its mark and names its install, and even the docs gate's fragment form routes a block AWAY from the compiled set -- the same coverage loss as the row, under a different name. That selects option 2. - unmark the four fences, reason written beside each: vitest and @playwright/test are the reader's own installs, not packages this repository publishes; - delete all four rows, leaving KNOWN_ROOT_DEVDEP_EXAMPLES empty, with its docblock recording the measurement and when a NEW row is still right; - lower MARKED_FLOOR ts 17 -> 13, reason beside the row, in this same PR -- the move objectstack-ai#7550's ratchet allows only here. Not a precedent for unmarking a red fence: these four were type-checked by nothing at all for the whole of their life as rows. Before: Root bound 4 refused, 4 rows declared; Semantic phase 13 of 17. After: Root bound refuses nothing; Semantic phase 13 of 13; Marked 13 ts (floor 13), 39 json (floor 39). Claude-Session: https://claude.ai/code/session_019RfFHiRCSs3JXLK4cwcfox Co-authored-by: Claude <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Part of #7463 — its item 2, the second flight, executing the maintainer ruling of 2026-09-03 (objectstack#14909 item 1, option A: the bound lives in the shared harness, unconditionally, for both consumers).
What resolved before this change, and no longer does
The harness maps two things: every workspace package's own
exports/types, and every specifier the imported packages DECLARE in theirdependencies. Neither says anything about the repository's ownpackage.json— and under pnpm the root's own set is symlinked into/node_modules, one directory above where every block is compiled. So a bare specifier neither map covered still resolved, as long as this repository happened to declare it. The inherited UNDECLARED control never reached that: it bounds TRANSITIVE packages, which pnpm leaves only under.pnpm/.compileSnippetsnow refuses such a specifier and keeps the block importing it OUT of the semantic program, the way an unparseable block is kept out — so the coverage count states what was judged rather than counting it as checked.One predicate (
resolvesOnlyThroughRootManifest), two enforcement points, because a bound has to be both total and attributable:host.resolveModuleNames, scoped to the virtual probe directory — the rule is about what a SNIPPET may import, never about how a declaration file insidenode_modulesresolves its own imports). This is the regime, and the new ROOT-DECLARED control is the probe that it is live.npm install project-nameinside a README example's template literal as an import ofproject-name, and a false refusal reds a document that is correct.⛔ Not a parameter defaulting to off: two resolution regimes behind one function would answer "did resolution stay narrow?" with "depends who is asking".
One exemption, about authorship rather than resolution: the JSX factory module. Every block is compiled as TSX, so the compiler imports
react/jsx-runtimeon the author's behalf. Measured:reactis mapped in the docs corpus only because@object-ui/layoutdeclares it as a real dependency, while the skills corpus imports no package that does — so without the exemption the same JSX tag would be bounded in one gate and not the other, over a line nobody wrote. Exempted at both enforcement points, so they cannot disagree about one specifier.The two known specifiers, before and after
Measured on this branch at
58737af, on a tree built from the gate's own--build-filterclosure; every reading re-run unchanged at the merged head3ca73aa(see the merge section below).Unmapped specifiers@playwright/test, vitest@playwright/test, vitest(the line stays, now as the report of what the bound refuses)--measure, ts candidates passing--build-filterThe one docs block, re-measured at this branch point and matching the ruling's premise exactly:
Nothing else in the 456-block docs corpus and nothing outside
skills/objectui/guides/testing.mdin the skills corpus is touched.The one docs snippet: declared, and the guide now names the install
content/docs/guide/objectos-integration.mdx, the "Integration Tests" fence, is DECLARED through this gate's own mechanism (an MDX-expression fragment marker carrying a written reason and the measured diagnostic, the idiom the same file already uses ten times over) — and, taking the ruling's stated preference for the form a reader can reproduce, the section now tells the reader what to install before the fence:The example is kept intact; nothing was deleted to make a gate green.
The four marked skill fences, and why they are declared in the SCRIPT
The bound also refuses four MARKED fences in
skills/objectui/guides/testing.md(:60,:94,:218onvitest;:258on@playwright/test). The ruling names those two specifiers as the marked population it closes but rules only on the docs snippet, so this is the judgement this flight had to make, and it is the one thing here beyond the ruling's letter:They are carried in a new shrink-only
KNOWN_ROOT_DEVDEP_EXAMPLES, mirroringKNOWN_BARE_ANY_EXAMPLESone flight earlier, because:skills/**is a GOVERNED surface and outside this PR's file surface, so unmarking a fence here is both out of bounds and the "gate weakens the guide to suit itself" move the shrink-only lists exist to prevent;Root boundline counts refusals,Semantic phasedrops to13 of 17, a NOTE spells it out, and the success sentence itself now reads "…the root bound could reach … 4 declared row(s) … were NOT reached, and this line does not speak for them." Retiring a row means giving the example an import the reader provably has, or the guide's owner deciding the fence should not be gated — a skills judgement, in a skills PR.Self-tests, both directions
--self-testgrew by 10 legs, to 52 cases pass; the two vitest suites grew by 15 and 8 cases, to 67 and 73 tests respectively:reactroot-declared and unmapped;Reverse verification
Three legs, each with the fix committed FIRST, mutated under a trap restoring ABSOLUTE paths, the mutation proven on disk by grep counts BEFORE any verdict was read, and the restore proven by
git hash-objectequal to the HEAD blob plus an emptygit diff HEAD. Nodist/is involved: both gates run from source, and the packages they resolve against were unchanged.3115b38e→a6c30eab): docs gate EXIT 1 with[bound] content/docs/guide/objectos-integration.mdx:644 imports '@playwright/test'andSemantic phase: 455 of 456. Restored to3115b38e, count back to 1,git diff HEADempty.99bf34d2→d959bc4d): both gates EXIT 2 (couldNotRun), the ROOT-DECLARED control reportingproduced 0 diagnostic(s)anda specifier only the repository ROOT declares still resolves — the bound is not being applied. That is the whole point of the control: with the bound off the gates refuse to render a verdict instead of going quietly green. Restored to99bf34d2,git diff HEADempty.:258row (row count 1 → 0; blob8c5c5ec2→82e6826d): EXIT 1,[bound] … testing.md:258and1 NOT declared. Added a ghost row (testing.md:9999 vitest, ghost count 0 → 1; blob →617553e3): EXIT 1,[stale-baseline] this row is no longer refused. Restored both times to8c5c5ec2;git diff HEADandgit status --porcelainboth empty.Gates, at head
3ca73aa(the merge commit)Exit codes captured by redirect BEFORE any pipe; each verdict quoted from the gate's own printed line.
pnpm check:doc-snippetsEvery covered documentation snippet compiles against the built types.pnpm check:skill-examplesEvery marked skill example the root bound could reach holds up against the built types — 4 declared row(s) in KNOWN_ROOT_DEVDEP_EXAMPLES were NOT reached, and this line does not speak for them.+Marked: 17 ts fence(s) (floor 17), 39 json fence(s) (floor 39) — the floor is SHRINK-ONLY.check-skill-examples.mjs --self-test52 cases pass (… the ROOT BOUND in both directions with its own shrink-only baseline and control …)check-skill-examples.mjs --measureStarting population — ts: 14/121 pass; json: 39/56 pass.+Root-bound would-be population — 18 refusal(s) over every candidate, of which 4 sit in a MARKED fence.pnpm check:doc-fencesevery TypeScript block in 227 document(s) is fenced ts/tsx/typescript, except 80 declared file(s) … (SHRINK-ONLY)pnpm check:skills-pathscheck-skills-paths: OK (88/89 stated path(s) resolve across 20 guide file(s); 1 baselined).pnpm check:skill-eval-tokensEvery must_contain token is taught by its own skill bundle.pnpm check:doc-typesEvery documented component type is registered.pnpm check:control-bytescheck-control-bytes: OK (scanned 6224 tracked text file(s); skipped 85 binary).pnpm check:pre-install-import-graphOK — 23 pre-install step(s) in 18 job(s) run 21 scripts/ gate(s)check-changeset-presence.mjsNo source or published contract of a released package changed in this range, so no changeset is owed.check-governed-queue-guard.mjs --testover all 5 changed pathsNOT GOVERNED — 5 path(s) checked against 5 governed surface(s); none matched.tsc -p tsconfig.scripts.json --noEmitvitest runover the 11 suites that reference either scriptTest Files 11 passed (11)·Tests 402 passed (402)(394 before the merge; +8 are objectui#7550's floor pins)pnpm lint(repo-wide, no narrowing claimed)Tasks: 47 successful, 47 total— 0 errorsNOT MEASURED, stated rather than implied:
tsconfig.scripts.jsonsetsallowJswithcheckJsFALSE on purpose, so errors inside the two.mjsBODIES are not reported —--listFilesconfirms both modules and both edited test files are in the program, which makes the cleantsca statement about the callers, not about the module bodies. CI convergence is likewise not measured here; this report is filed at draft-PR time per the dispatch contract.Merge with objectui#7550's floors (
3ca73aa)PR #7553 (objectui#7550, the per-category
MARKED_FLOORratchet) landed on the same two files while this PR was in draft, and GitHub read this branchmergeable_state: dirty. Mergedorigin/mainat34ea56dinto the branch — a merge commit, no rebase, no force. Both behaviours are kept whole:scripts/check-skill-examples.mjsauto-merged. The summary carries both:Marked: 17 ts fence(s) (floor 17), 39 json fence(s) (floor 39) — the floor is SHRINK-ONLY.on the floors' line, andRoot bound: 4 fence(s) refused … 4 row(s) declared … 0 NOT declared, 0 declared row(s) no longer refused.on this PR's. The exit path reads both — the floor-breach check and the undeclared/stale root-bound rows.scripts/__tests__/check-skill-examples.test.ts: the import list, where the two PRs each added symbols. Resolved by keeping both sides (KNOWN_ROOT_DEVDEP_EXAMPLESandMARKED_FLOOR,rootDevDepRowKeyandreconcileFloors). No test from either side was dropped: the merged suite runs 73 + 8 cases and the union is green.MARKED_FLOORcounts MARKS, not verifications: a fence the root bound refuses keeps its marker and stays inside the floor while being type-checked by nothing, so the floor's number is not coverage and theRoot bound/Semantic phaselines are what say how many marked fences were reached. And unmarking a fence to silence a root-bound refusal would breach that floor — two ratchets, counting different things, neither substituting for the other.Re-run at the merged head
3ca73aa, all green:pnpm check:skill-examples,pnpm check:doc-snippets,check-skill-examples.mjs --self-test(52 cases pass),pnpm check:doc-fences,pnpm check:skills-paths,pnpm check:skill-eval-tokens,pnpm check:control-bytes,check-changeset-presence.mjs(no changeset is owed, now compared against34ea56d),check-governed-queue-guard.mjs --test(NOT GOVERNED — 5 path(s)),tsc -p tsconfig.scripts.json --noEmit, the 11-suite vitest union (402 passed), and repo-widepnpm lint(Tasks: 47 successful, 47 total, 0 errors).Session for this and every earlier revision:
https://claude.ai/code/session_019RfFHiRCSs3JXLK4cwcfox.Posture
Not governed (verdict above), no changeset owed (verdict above, and no
skip-changesetlabel is applied — that label is a phantom in this repository). Draft, for the seat to review and land.