Repository navigation
feat(scripts): report-only census of ${…} authored on keys nothing evaluates (objectui#7851) - #7868
Merged
Merged
Conversation
…ectui#7851) A json fence in `content/docs/**` can author any key at all on a node and no gate objects: `check:doc-types` judges the `type` literal and says so in its own header, `check:doc-snippets` compiles the ts/tsx blocks only. Four cards of that shape reached main under green gates (objectui#7418, #7440, #7444, #7838). `scripts/check-doc-expression-carriage.mjs` answers the expression half — is this key on a channel `SchemaRenderer` evaluates — deriving both halves of the universe rather than typing them: the carriage map from the built `@objectstack/spec` artifact, the four evaluated channels from the renderer's own call sites. It is REPORT-ONLY by ruling (three members of the class are open) and exits 1 only when the instrument itself is broken. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KbJQ1y1J12nZxYzFWhP8Q3
… under --list `0 unparsed` is the sentence that makes "only N sites" mean something, so it is printed on every run rather than only when there is something to report. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KbJQ1y1J12nZxYzFWhP8Q3
…ialect blind spot A `jsonc` spelling is what three of `guide/record-edit-modes.md`'s teaching blocks use, and a gate reading `json` alone cannot see that page at all. Both languages were already scanned; what was missing was the READING that says so. Every run now prints parsed/unparsed per language, and parses every fence OUTSIDE that set purely to report whether it would have been a JSON document holding a typed node — so a missed dialect is a number, not something a human finds by re-reading a page. Also states, in the header and in the output, that a hit is a CANDIDATE: `type` is at least seven vocabularies in this corpus, and one of today's hits is an ActionSchema whose `condition` the action runner evaluates. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KbJQ1y1J12nZxYzFWhP8Q3
This was referenced Sep 6, 2026
This was referenced Sep 6, 2026
baozhoutao
pushed a commit
that referenced
this pull request
Sep 6, 2026
…s' surface (objectui#7878) The report-only census landed (PR #7868) pointed at `content/docs` alone, while its two sibling doc gates had already been widened onto the per-app docs trees (#6600) and the root pages (#7115). That is the #7115 geometry rebuilt one gate over: the root `README.md` fell between two gates' surfaces and taught an unregistered component type four times, for exactly one reason -- nothing read the file. The surface is now imported from `check-doc-component-types.mjs` rather than copied: `APP_DOCS`, `appDocsDirs` and `ROOT_PAGES` are the same objects, so there is nothing to drift. `DOCS_ROOT` stays spelled here (that gate declares it `const`, not `export const`) and is pinned against that file's source text. Report-only is unchanged: exit 0 on findings, exit 1 only when the instrument is broken. No predicate, exit-code or ci.yml change. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FhBNJcLRZLe8M87VcUgpKr
akarma-synetal
pushed a commit
to akarma-synetal/objectui
that referenced
this pull request
Sep 9, 2026
…s' surface (objectui#7878) (objectstack-ai#8105) The report-only census landed (PR objectstack-ai#7868) pointed at `content/docs` alone, while its two sibling doc gates had already been widened onto the per-app docs trees (objectstack-ai#6600) and the root pages (objectstack-ai#7115). That is the objectstack-ai#7115 geometry rebuilt one gate over: the root `README.md` fell between two gates' surfaces and taught an unregistered component type four times, for exactly one reason -- nothing read the file. The surface is now imported from `check-doc-component-types.mjs` rather than copied: `APP_DOCS`, `appDocsDirs` and `ROOT_PAGES` are the same objects, so there is nothing to drift. `DOCS_ROOT` stays spelled here (that gate declares it `const`, not `export const`) and is pinned against that file's source text. Report-only is unchanged: exit 0 on findings, exit 1 only when the instrument is broken. No predicate, exit-code or ci.yml change. Claude-Session: https://claude.ai/code/session_01FhBNJcLRZLe8M87VcUgpKr 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.
Fixes #7851
A json fence in
content/docs/**can author any key at all on a node and no gate objects.check:doc-typesjudges thetypeliteral and states the exclusion in its own header — "NOT in scope, deliberately: whether the snippet's OTHER keys are read by the renderer the type resolves to" — andcheck:doc-snippetscovers these pages but type-checksts/tsxblocks only. So the json fence bodies were read by nothing.This lands the instrument that reads them, report-only, and the census it produces.
The census, on
59df1dab2content/docs/guide/expressions.mdbadge.variantx3,badge.text,card.body,card.className,list.itemsx2content/docs/guide/schema-rendering.mdchart.data,badge.text,badge.variant,alert.variant,alert.messagecontent/docs/guide/architecture.mdbadge.text,badge.variantcontent/docs/api/schema-reference.mdaction.conditioncontent/docs/guide/layout.mdpage.titleThe 8 on
expressions.mdare an independent reproduction of the number objectui#7418's prototype measured on the same tree — its six sites plus the twolist.itemsoccurrences that card deliberately left unclaimed. The other 9, in four further pages, were not in any card's enumeration. ⛔ Nothing outside this PR's four files is touched: the other pages are reported, not repaired.Fence languages, and the dialect blind spot
Asked for after a sibling seat measured objectui#7440's page: its three teaching blocks are fenced
jsonc, notjson.jsoncwas already in the scanned set, socontent/docs/guide/record-edit-modes.md's fourjsoncfences are all counted and judged today (they produce no expression finding, because objectui#7440 is the read-back half, not this one). What was missing was the reading that says so, and it is now printed on every run — per language, both directions — together with a probe that parses every fence outside the scanned set purely to report whether it would have been a JSON document holding a typed node. A missed dialect is now a number rather than something a human finds by re-reading a page. Both are pinned.typeis not one vocabulary in these pages —check:doc-typesmeasured at least seven that all spell that key — so a node from another one is judged here against a carriage map that does not govern it. One of today's 17 is exactly that:content/docs/api/schema-reference.md'sActionSchemaexample authors a${…}oncondition, which the action runner's own gate evaluates, notSchemaRenderer's node channels. ⛔ The obvious fix — classify by enclosing key path — was built and measured by that gate before being rejected as non-convergent, and that ruling is inherited here rather than re-litigated. Report-only is what makes inheriting it safe: a candidate a human reads costs a minute, and nothing is blocked while the corpus is read. The caveat is stated in the script's header and printed under every findings list.Report-only, deliberately
Three members of this class are open (objectui#7440, objectui#7444, objectui#7838). A blocking gate would go red on all of them the day it landed and turn one card into four, so the 2026-09-06 ruling on this card is that the census is the deliverable and the decision it feeds — clean the corpus first, or build a ledger — is not made here.
Same posture as
Changeset Overwrite Report, and the same boundary: report-only means the gate declines to fail on its findings, never that it passes without looking. It exits 1 when the instrument is broken — a derivation that matched nothing, a missing spec artifact, a failed control. There is nocontinue-on-erroron the step, because that would swallow exactly the failure that must be loud.Both halves of the universe are derived, never typed
expressionBindableTextKeysForout of the built@objectstack/spec@17.2.0dist/ui/index.mjs— the lookupSchemaRenderer.tsx:1139itself consumescard->title,description;badge/progress/input/list-> nothingSchemaRenderer.tsx's own call sites —evaluator.evaluate(newSchema.X),isConfigBag(newSchema.X),evaluate{Visibility,Enablement}Predicate(newSchema.X, …)content; bagsproperties,props; 8 condition keysRead from call sites, never from the surrounding prose: that file's comments name
visibleOn,disabledand both bags many times over, and a scan of the raw text would be describing its own docblocks. Either derivation matching nothing is exit 1 — a silently narrowed universe turns correct documentation into findings.The test cross-checks the condition keys against a different source: the two
VISIBILITY_SHOW_KEYS/VISIBILITY_HIDE_KEYSarray literals the same file declares. One source read twice proves nothing.Proving it can see
Built-in controls, run before every census, not once in this PR. The positive fixture is
guide/expressions.md's Status Badge block exactly as it stands onmain—badgecarries nothing, sotextandvariantare both findings. The negative fixture is acardusing only carried channels.The pins sabotage each control too, because a control that cannot fail is not a control: widen the carriage map until the defect disappears and the positive control fails; drop
visibleOnfrom the channels and the negative control fails.On-disk mutation control, on the real corpus. objectui#7418's repair has not merged yet, so the six sites are still on
main— the instrument reports them today, which is the positive direction already live. The remaining direction was measured by applying PR #7847's repair to the Status Badge block on disk and watching the census track it. The implementation was committed before the trap was armed.Restored under
trap … EXIT INT TERMwithgit checkout HEAD -- "$REPO_ROOT/…", and proven by state, not by an exit code:git status --shortempty,git diff HEADempty,git hash-objectback to03d44a90a, the anchor count back to 1.The parse surface is printed on every run
0 unparsedis what makes "only 17 sites" mean something, so both directions are printed. Reaching 0 over the whole tree takes four tolerances beyondJSON.parse, all of them removals of non-data or an envelope around it — comments, raw newlines inside${…}strings, trailing commas, and elision markers in the three spellings the corpus uses — plus one retry for a fence that is an object body rather than an object. None can invent a key, and each is pinned, including the case that must not be treated as an elision ("placeholder": "..."is a real value).The half this does not answer
This is the expression half — is this key evaluated. The wider half — is this key read back by the renderer — is what objectui#7440 and objectui#7444 are, and it needs the per-renderer read-point contract
check:doc-typesnames as its missing piece. Neither is visible here, and objectui#7838's site lives indocs/ARCHITECTURE.md, outsidecontent/docs/**and so outside this census's population. All three are stated in the script's header so a green census is not misread as "the fences are correct".Wiring, and the obligation that comes with it
One report-only step in the
docsjob ofci.yml, and — objectui#3653 pins that table by command — the matching sentence in thedocsrow ofcontent/docs/guide/ci-cd-pipeline.md, in the same change.ci-cd-pipeline-doc.test.tspasses in both directions. The step inherits the job'sshould_runcondition, so on a PR that changes nocontent/orapps/site/file the census does not run; a PR that edits only the gate is covered by the vitest pins instead. Both consequences are written down at the step.node scripts/check-governed-queue-guard.mjs --testover all four changed paths, verbatim:Verification, re-run after the final commit at
59df1dab2Exit codes captured by redirecting first (
cmd > log 2>&1; EXIT=$?), never through a pipe.check:doc-snippetsfirst returned EXIT=2, which its own output declares is "I could not run, NOT I ran and found errors" — read as NOT MEASURED. Its scoped build (turbo run build $(node scripts/check-doc-snippet-types.mjs --build-filter) --concurrency=2, 34/34 tasks) then took it to a real green.node scripts/check-changeset-presence.mjs— EXIT=0, verdict verbatim:Acted on: no changeset added, no label touched.
Not run, said plainly:
pnpm lint(turbo run lintacross all 46 packages) and the repo-wide test suite. Thelint:rootscan above is the eslint population that contains these files — measured from eslint's own config at 249 files, with both new files present in it and clean — and this diff adds no file to any package, so no package's lint or test population moves. CI runs the farm regardless.Session, in prose because a markdown-link footer does not survive an edit:
https://claude.ai/code/session_01KbJQ1y1J12nZxYzFWhP8Q3Generated by Claude Code