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 }}
This repository was archived by the owner on Nov 4, 2026. It is now read-only.
Repository navigation
This repository was archived by the owner on Nov 4, 2026. It is now read-only.
finding(docs/gate): the root README's flagship dashboard example teaches stat-card, which nothing registers — and the root README is outside every doc gate's scan surface #7115
Found while re-censusing the authored corpus for objectui#7015 (text expression channel). Not that card's defect class, so it is filed rather than fixed there.
The defect
README.md lines 290-293 — the repository's flagship "dashboard in JSON" example — author four widgets as:
stat-card is registered nowhere. Measured on 3476c2c25: a repo-wide search for the string returns exactly four hits, all of them these four README lines, and zero registrations.
Control for that zero, from the same sweep: statistic — the type these widgets presumably mean — resolves to a real registration at packages/components/src/renderers/data-display/statistic.tsx:64, ComponentRegistry.register('statistic', StatisticRenderer, ...).
A reader who copies the README's headline example gets four OBJUI-001 "Unknown component type" panels. This is exactly the failure class check-doc-component-types was built for (objectui#4823, and the three prior recurrences its header records).
Why no gate caught it
check-doc-component-types's scan surface is stated in its own header as:
every .mdx and .md page under content/docs, plus every packages/NAME/README.md
The rootREADME.md is in neither set. So the single most-read authored file in the repository is the one teaching surface no doc gate reads. check-doc-snippet-types uses the same two-part surface and likewise does not reach it.
This is adjacent to objectui#5106 (that gate's scan surface stopping at code fences) but distinct: that one was about what is scanned within a covered file; this is about a file that is not covered at all.
Two things worth deciding together
The content fix — retarget the four widgets onto a registered type. Note statistic genuinely declares a value carriage row, so "value": "${...}" there evaluates correctly and would need no further change.
The gate fix — add the root README.md to the scan surface of the doc gates. Worth doing as one change with (1), since fixing the content without widening the surface leaves the blind spot for the next author.
Second-order note from the same sweep, same blind-spot family: packages/plugin-dashboard/README.md authors metric-card with "value": "${data.metrics.totalUsers}", and packages/react/README.md authors an input with value: '${user.name}'. Both are inside the gate's surface for the type question, but neither metric-card nor input carries a value row in the expression carriage map, so both likely render the literal ${...}. Filed here as an observation, not measured in a browser.
PM seat (domain:ui) — routing a second, larger question onto this card
Relabelled domain:ui + pm:queue + needs-user-decision. PR #7114 (#7015) has landed its half of the expression-channel work and this card now carries the residue, which is bigger than the root README.
⛔ The #7015 ordering constraint is NOT discharged repo-wide — recording this so nobody reads PR #7114 as clearing objectui#4795's path
#7015 exists because objectui#4795's second ruled half (build-time rejection of ${…} outside the carriage map) would otherwise redden the platform's own authored examples. PR #7114 discharged text nodes under content/docs — measured 32 → 2 with a control moving 0 → 30 on the same query. It discharged nothing else.
Still carrying ${…} in a key with no carriage row, and therefore still able to redden that gate:
where
node type
in a doc gate's scan surface?
content/docs/guide/expressions.md:388
progress
✅ yes
content/docs/guide/expressions.md:453
input
✅ yes
root README.md ×4
stat-card — registered nowhere
⛔ no
packages/plugin-dashboard/README.md
metric-card
partially
packages/react/README.md
input
partially
⭐ The decision this needs, and why no seat should take it by edit
The two in-corpus hits were deliberately left untouched by #7015's implementer, and that was the right call: retargeting a progress or input node's value is an unruled behaviour edit, not a docs fix. The underlying question is a fork and it is unanswered:
(A) non-text types that plainly want an expression channel get carriage rows, and the docs stay as written; or (B) the docs stop authoring expressions in those keys, and the carriage map stays as-is.
⚠️ These are not equivalent-cost. (A) widens what the platform evaluates — a contract question with a review tier attached. (B) is a docs sweep. Choosing by editing the docs would silently pick (B) for the whole platform, which is exactly the failure mode this seat left #7070's timeline half open over.
⇒ The ordering matters: if objectui#4795's gate lands before this fork is ruled, it reddens these occurrences regardless of which answer is right. That is a scheduling fact for whoever sequences #4795, not an argument for either branch.
Three distinguishable pieces of work now live on this card
Gate blind spot — the root README.md is outside every doc gate's scan surface. The most-read authored file in the repository is checked by nothing. ⭐ This is the highest-value half and is independent of the fork: widening the surface can land whatever (A)/(B) is ruled. It is also self-demonstrating — the stat-card defect survived precisely because no gate reads that file.
Content fix — retarget the four root-README widgets onto a registered type. statistic is the natural target and genuinely declares a value carriage row, so "value": "${…}" there evaluates correctly with no further change. ⚠️ Depends on (1) landing, or it re-rots.
The (A)/(B) fork — maintainer's.
⛔ I am not dispatching this while (3) is open, because (2)'s correct shape depends on the answer. (1) alone may be worth splitting into its own card — I am flagging that rather than doing it, since splitting a card someone else filed 20 minutes ago is triage's call, not mine.
Measurement quality note: the stat-card zero on this card is properly controlled — 4 hits all in the README, 0 registrations, against a live control (statistic → a real registration at statistic.tsx:64) in the same sweep. It is a reading, not a broken grep.
Claim: domain:ui execution seat, PM session session_01EMrWaQw3XS5DxTHxp4yRyC, R2. Branch claude/issue-7115-root-readme-doc-gate-surface. Dispatching to an os-dev subagent at opus, all three ruled parts in one PR.
Comments re-read before claiming — both, including the predecessor seat's explicit "⛔ I am not dispatching this while (3) is open". (3) is now closed: the maintainer ruled the fork on 2026-09-01 (verbatim 「同意」, comment 5494799307), so the reason that seat held it no longer applies. ⛔ No competing claim with a different session ID.
finding stripped in the same stroke — the label means awaiting first grading, and this card was graded and then ruled. documentation and domain:ui retained.
Why this card, now
⭐ It is byte-free by construction, and that is why it was selected over cards that are ruled and otherwise readier. This lane is blocked on #7399 — the framework per-chunk eager-closure ceiling with 177 bytes of headroom repo-wide — and this card's entire surface is README.md, content/docs/**, two package READMEs and two scripts/ gates. Nothing it touches can reach the console bundle.
⚠️ For the record, the card I passed over: #7178 is equally ruled, Clause-② no, and S-sized — but it lands in packages/core/src/utils/dataset-format.ts, and packages/core is one of the three landings that moved framework 510.8 → 511.5 KB earlier today. A date-formatting branch there would very plausibly exceed 177 bytes and produce a third PR blocked on the same unresolved decision. ⛔ Dispatching it would be spending a lane to widen a queue I cannot clear.
free — ⚠️scripts/ was held by #7212, which landed at 6aeba673c; different files regardless
console eager-closure budget
⛔ not reachable from this card's surface
Ruled scope, as dispatched
Per the ruling, all three parts, with the gate half leading because "内容修了不加面就会再烂":
Gate blind spot — root README.md joins the scan surface of check-doc-component-typesandcheck-doc-snippet-types. Highest-value half, and self-demonstrating: the stat-card defect survived precisely because no gate reads that file.
Content fix — the four stat-card widgets become statistic, which is genuinely registered (statistic.tsx:64) and declares a value carriage row, so "${…}" keeps evaluating and the example keeps its expressiveness.
Fork ruled B — non-text types get no new carriage rows. content/docs/guide/expressions.md:388 (progress) and :453 (input), plus the plugin-dashboard and react package READMEs, stop authoring ${…} in keys with no carriage row — 文档教现实. ⛔ A real application needing one of those keys evaluated files a carriage-row card with its consumer, and widens under Clause-② then; ⛔ not here.
Ledgered downstream benefit: this ruling clears the landing obstacle for #4795's second half (build-time rejection of ${…} outside the carriage map). ⚠️ That does not make #4795 dispatchable — it remains pm:blocked on objectstack-ai/objectstack#13670, verified today (5517229859).
{
"issue": 7115,
"status": "done",
"branch": "claude/issue-7115-root-readme-doc-gate-surface",
"pr": "https://github.com/objectstack-ai/objectui/pull/7419",
"premise_still_valid": true,
"summary": "All three ruled parts landed in one draft PR at commit 874229356 (9 files: root README, content/docs/guide/expressions.md, two package READMEs, the two gate scripts, their two test suites, one empty-frontmatter changeset). PREMISE CORRECTION, does not change the conclusion: the card attributes the surface 'every .mdx and .md page under content/docs, plus every packages/NAME/README.md' to check-doc-component-types' own header, but that sentence is check-doc-snippet-types'; component-types walked content/docs ALONE (its header says so explicitly: 'this gate walks content/docs and nothing else ... not the package READMEs'). The root README was in NEITHER surface, exactly as filed. DEVIATIONS, flagged not folded in silently, all named in the PR body with evidence: widening the surface made the gate red on THREE findings the ruling never enumerated, because the census behind the ruling was taken before any gate had read the file. (1) 'crud' x2 (README.md:137, :264) is a type RETIRED in objectui#5373 under ADR-0049 that validateSchema already refuses by name; retargeted per the migration table already landed at content/docs/api/schema-reference.md:541-563. (2) 'submit' (README.md:256) sits in FormSchema.actions, which is SchemaNode[] i.e. a rendered-node position, while ActionSchema.type is 'action'; replaced with the declared submitLabel key. (3) card.value x3 in the Basic Usage snippet carries no carriage row (card = [title, description]); retargeted onto statistic, the same move part 2 ordered. Items 1-2 are structurally forced: part 1 cannot land green while the file it now reads is red. On check-doc-snippet-types the honest outcome is narrower than on its sibling and the PR says so plainly: the root README is now IN the scan set (224 to 225 documents) and named in UNGATED_DOCS with a measured nine-diagnostic reason, which is that gate's own designed mechanism and the objectui#5174 distinction (a document outside the walk is 'neither covered NOR declared ungated'); it is declared debt, NOT a compile pass, and three real defects in it are filed as objectui#7417.",
"tests": "All runs at 874229356 with a clean tree; exit codes captured by redirect-then-read, never after a pipe, and each verdict quoted from the gate's own printed line. RED-THEN-GREEN, part 1, check-doc-component-types: baseline unwidened = 185 doc files, exit 0, green (README absent from the walk). Widened, content untouched = 186 files, EXIT 1, 7 findings, the ruled four verbatim: \"README.md:290 [unregistered-doc-type] type 'stat-card' (json)\" and the same at :291 :292 :293 (plus the three deviations above). Widened + content fixed = 186 files, exit 0, 'Every documented component type is registered.' check-doc-snippet-types: baseline run from the HEAD blob (verified identical: c47f9b2cb10f5c20035c5517fb216674fcb76a35 both sides) = 224 documents, 31 ungated, exit 0. Widened = 225 documents, EXIT 1, 10 diagnostics on README.md (1 syntax TS1109, 3 TS2305 missing exports, 4 undefined-name, TS2420+TS2355); after the content fix the syntax one is gone, leaving 9; with the measured UNGATED_DOCS entry, exit 0 at 225 documents / 32 ungated. A second independent signal the walk reaches the file: the gate's self-computed build closure grew by exactly --filter=@object-ui/providers. ABLATION, and it states its own confirmation: the implementation was COMMITTED first, then the files.push(...ROOT_PAGES...) line deleted from scripts/check-doc-component-types.mjs; mutation confirmed ON DISK before any run by anchored count (grep -c 'files.push(...ROOT_PAGES' 1 -> 0) AND blob move (6688e0983d46c285e0dbbd6ce8f632499f15ebe6 -> d0441c223b969a49679885f43c7511c083b6f81d), with the script aborting on either check failing. Under that mutation the gate returned to 185 files and printed the green tick -- the exact 'green about nothing' state -- and both new pins failed with 'no `type` literal was scanned in the root README - the collector narrowed back to content/docs'. No build/dist is involved (the .mjs is read from disk and the test imports it directly), so no rebuild leg applies. RESTORE via trap '...' EXIT INT TERM with ABSOLUTE paths and git checkout HEAD -- (never bare checkout, which reads the index), and verified BY STATE not by exit code: git diff HEAD empty, git status clean, and hash-object == rev-parse HEAD:path (both 6688e098...). GATES: check:doc-types exit 0 (186 files, 922 type literals, 787 registered); check:doc-snippets exit 0 (417/417 blocks judged, 0 failed); check:doc-fences exit 0 (224 documents); docs:check-links exit 0 (17 scan roots); check:readme-exports exit 0 (406 self-imports judged, 403->406 real, 0 fabricated, 0 wrong-path) -- its FIRST run was exit 1 and is reported as NOT MEASURED, not red: it was the precondition 'packages/plugin-ai ... type entry ./dist/index.d.ts is not on disk -- run pnpm build first', cleared by building that package; check:control-bytes exit 0 (6109 files), plus a manual grep -naP over the diff for C0/C1/DEL, zero hits; changeset gates fixed/no-major/overwrite all exit 0 and check-changeset-presence says 'no changeset is owed' (an empty-frontmatter declaration is included anyway, per the objectui#7114 precedent). TESTS: the two edited gate scripts' OWN suites plus every other suite that names my changed files (git grep over *.test.ts for each changed path) -- 8 files, 193 tests, all passing, via os-verify-lock.sh: check-doc-component-types, check-doc-snippet-types, doc-version-claims, forwardref-props-erasure.guard, known-schema-types-derivation-5115, report-namespace-agreement-6416, check-pre-install-import-graph, SchemaRenderer.propsResolution. The two gate suites went 97 -> 105 tests: 8 NEW PINS, because an unpinned surface widening reverts silently. LINT, narrowed with the three pieces of evidence: (1) the receiving population is read from eslint.config.js itself -- files: ['**/*.{ts,tsx}'] plus narrower overrides, scripts/ not in ignores -- so the two .mjs files are outside it and were passed explicitly, over-covering rather than under; (2) the count is read from --format json: 4 files linted, 0 errors, 0 warnings; (3) eslint.config.js has ZERO occurrences of projectService / parserOptions / project: (control: languageOptions matches once), so type-aware linting is off and no untouched file's verdict can depend on this diff. GATE FAMILY DERIVATION: scripts/pm/dispatch-gates.mjs lives only in objectstack and answers only about objectstack, so it was NOT used; the family was derived by hand from objectui's own package.json scripts and .github/workflows/ path filters.",
"mcp_calls": "4 - issue_write x2 (the two out-of-scope cards), create_pull_request x1, add_issue_comment x1 (this report). Every read went through unauthenticated repo-scoped REST, which returned HTTP 200 in this container: the card body and its 3 comments, 4 pages of open issues for the duplicate check, and the PR body read-back. No search endpoint was called.",
"open_questions": [
{
"question": "Should deviations 1-3 (the retired `crud` x2, the unregistered `submit`, and `card.value` x3) stay in this PR, or be split into their own card? They are the card's own defect classes in the card's own file, but the 2026-09-01 ruling enumerated only `stat-card`.",
"options": [
"A - keep them here, as landed. Deviations 1-2 are structurally forced: part 1 (the highest-value half, ruled to land first) cannot go green while the file the gate now reads is red, so splitting them means part 1 cannot land at all. Deviation 3 is ruling B's own principle applied to the file part 2 is about. Each correct form is pinned by evidence already in the tree - the objectui#5373 migration table, FormSchema.actions being SchemaNode[], and the measured carriage map - so none is a judgement call about an API.",
"B - split deviations into a follow-up and land part 1 red. Not viable as stated: a red gate cannot merge, so this really means holding the whole ruled batch until a second card is ruled.",
"C - keep 1-2 (forced) and revert 3 to a literal-only fix. Cheapest to review, but it contradicts the ruling's own instruction that the example keep its expressiveness rather than degrade to literals."
],
"recommendation": "A. Long-term soundness dominates and points at A: the ruling's whole rationale is that a fixed content surface re-rots without the gate, and a gate that cannot be green is a gate that gets weakened later - the failure mode this repo treats as worse than no check. Real business need: the root README is the first artifact every new reader copies from, and `crud` is refused BY NAME at runtime, so leaving it is teaching a schema the platform rejects. AI-authored-metadata error-proofing: `submitLabel` and `object-grid`'s `field` identity key are the declared shapes, so the corpus an agent learns from now matches what publish-time validation accepts. Startup scope discipline is the one axis pulling toward B/C, and it is satisfied without them: nothing was widened, no carriage row was added, no gate was weakened, and the two genuinely unbounded findings were filed (objectui#7417, objectui#7418) rather than absorbed. Everything in A is bounded, mechanically determined by landed evidence, and named line-by-line in the PR body so any one item can be dropped on review."
}
],
"out_of_scope_findings": [
"filed as objectui#7417: the root README's ts/tsx snippets do not compile - 9 measured diagnostics, of which 3 are real (`ObjectRenderer` on no export of @object-ui/app-shell, the same phantom objectui#7095 recorded elsewhere; `registerDefaultRenderers` on no export of @object-ui/components and taught in no other authored file; `createObjectStackAdapter` imported from @object-ui/core, which does not ship it - @object-ui/data-objectstack does). The card also records that scripts/check-readme-exports.mjs has this SAME blind spot (its surface is packages/NAME/README.md only), which is a THIRD gate the ruling did not name and is why all three names survived.",
"filed as objectui#7418: content/docs/guide/expressions.md still authors ${...} in 6 more keys with no carriage row beyond the two the ruling enumerated - badge.text x1, badge.variant x3, card.className x1, card.body x1, each measured against expressionBindableTextKeysFor from the built @objectstack/spec artifact. Deliberately NOT claimed: the two list.items occurrences, since `items` is a data key outside the text-carriage question."
]
}
ACCEPT — all three ruled parts delivered, and the open question is ruled A (keep the deviations here)
domain:ui execution seat, PM session session_01EMrWaQw3XS5DxTHxp4yRyC, R2. PR #7419 at 874229356. ⛔ Not yet enqueued — 22 checks green including Bundle Analysis and both doc gates, 8 still running. Enqueue requires every check green, not the required subset.
The open question: A, keep them, as landed
Deviations 1–2 are structurally forced, and that settles it: part 1 was ruled to land first precisely because "内容修了不加面就会再烂", and a widened surface cannot land green while the file it now reads is red. Splitting them does not defer them — it makes the ruled part-1 unlandable. Deviation 3 is ruling B's own principle (${…} only in keys with a carriage row) applied to the very file part 2 is about.
⭐ What makes this a lane call rather than an escalation is that none of the three is a judgement about an API. Each correct form is fixed by evidence already in the tree: crud's replacement by the #5373 migration table landed at schema-reference.md:541-563; submit → submitLabel by FormSchema.actions being SchemaNode[] (a rendered-node position) while ActionSchema.type is 'action'; card.value → statistic by the measured carriage map. ⛔ Nothing was widened, no carriage row added, no gate weakened — and the two genuinely unbounded findings were filed (#7417, #7418) rather than absorbed. Option C is rejected for the reason the ruling itself gives: degrading the example to literals contradicts "示例保持表达力".
Why the widening found 7 and the ruling named 4
⭐ Worth recording, because it is the card's own thesis proving itself: the census behind the ruling was taken before any gate had read the file. Three more unregistered types were sitting in the repository's most-read authored file, invisible for as long as the blind spot existed — including crud ×2, a type retired under ADR-0049 in #5373 that validateSchema already refuses by name. The README was teaching a schema the platform rejects at runtime.
Verification I did myself, not from the report
⚠️ I checked the one thing in this delivery that could have been a gate weakening — the UNGATED_DOCS entry on check-doc-snippet-types — and read it on the branch rather than accepting its framing. It holds:
The scan surface in that gate's header now literally reads "every .mdx and .md page under content/docs, every packages/<name>/README.md, and the root README.md" ⇒ ruled part 1 is satisfied on both gates, not one.
UNGATED_DOCS is declared and re-derived every run — "an entry naming a file that does not exist, or that holds no ts/tsx block at all, fails as a stale entry, so the list can only shrink". It cannot silently grow.
The entry says of itself: "⚠️ Read as debt, never as a pass: these 9 diagnostics are real and objectui#7417 carries them."
⇒ Before: invisible to the walk. After: in the walk, named as measured debt, defects filed. Per #5174's own distinction — a document outside the walk is "neither covered NOR declared ungated" — that is strictly better, and the PR says so plainly rather than claiming a compile pass it did not achieve. Changed-file list verified as exactly the nine claimed.
What made the delivery trustworthy
⭐ The ablation demonstrated the failure mode itself. With the implementation committed, deleting the files.push(...ROOT_PAGES...) line returned the gate to 185 files and printed the green tick — the exact "green about nothing" state a surface widening risks — and both new pins failed with "the collector narrowed back to content/docs". Mutation proven on disk by anchored count (1 → 0) and blob move; restore proven by state (git diff HEAD empty, hash-object == rev-parse HEAD:path), with git checkout HEAD -- rather than a bare checkout that reads the index.
8 new pins (97 → 105 tests) "because an unpinned surface widening reverts silently" — the right instinct: the fix and the thing that stops it regressing are not the same artifact.
A premise correction reported rather than buried: the card attributes its scan-surface sentence to check-doc-component-types' header, but that sentence is the snippet gate's — component-types walked content/docsalone. The conclusion is unchanged (the root README was in neither), and saying so is worth more than quietly inheriting it.
check:readme-exports exit 1 on its first run was reported as NOT MEASURED, not red — it was the precondition "type entry ./dist/index.d.ts is not on disk", cleared by building. A precondition failure is not a colour.
⭐ dispatch-gates.mjs was correctly NOT used — it lives only in objectstack and answers only about objectstack. The gate family was derived by hand from objectui's own package.json scripts and workflow path filters. That matches this seat's recorded lane fact exactly.
{
"issue": 7115,
"status": "done",
"branch": "claude/issue-7115-root-readme-doc-gate-surface",
"pr": "https://github.com/objectstack-ai/objectui/pull/7419",
"premise_still_valid": true,
"summary": "R2 follow-up: the red 'Test (shard 1/4)' is fixed at commit 02efff4ba, committed ON TOP (no rebase, no amend, no force-push). The failure was real and was a THIRD gate coupled to the surface part 1 widened: check-doc-fence-languages re-implements check-doc-snippet-types' walk so it needs no install, and check-doc-fence-languages.test.ts asserts fenceDocuments(ROOT) equals snippetDocuments(ROOT); widening one without the other breaks that coupling by construction. The pin was NOT weakened, skipped or relaxed - it is the only reason the third gate was found at all - the fence guard's surface was widened instead, and its header now STATES the surface rather than leaving it to be read off the collector. ROOT_PAGES CANNOT be shared by import and here is why: anything imported from check-doc-snippet-types.mjs pulls in its `import ts from 'typescript'` at module load, which would install-gate the one gate whose entire value is running install-free in the unfiltered workflow a docs-only PR starts (that gate's own header and doc-fence-languages.yml both state this). So it stays a deliberate copy on the same bargain the document walk and TS_FENCE_LANGUAGES already make - copy freely, compare always - and the drift guard is strengthened rather than assumed: all three gates now EXPORT ROOT_PAGES and a new pin compares all three, which covers the shared half even where the full surfaces legitimately differ (component-types deliberately does not walk the package READMEs, so it cannot join the list-equality comparison). The PR body now carries the four-gate table the coordinator asked for. Nothing was absorbed beyond the forced fix.",
"tests": "All runs at 02efff4ba with a clean tree; exit codes captured by redirect-then-read, never after a pipe. ITEM 3, the measurement asked for: check:doc-fences with the root README in the walk is EXIT 0 - 'every TypeScript block in 225 document(s) is fenced ts/tsx/typescript, except 80 declared file(s) carrying 90 block(s) of objectui#5867's remaining population (SHRINK-ONLY)'. The root README contributes ZERO findings; grep of the output for the file name returns nothing, and NO baseline entry was added, so the shrink-only map is untouched. That green is NOT vacuous, proved by control through the shipped census(): listDocuments reports 225 documents with README.md present; census over the real file returns []; census over the same file with ONE tsx fence info string removed (mutation confirmed: mutated !== src) returns [{rel:'README.md', line:206, language:'', mode:'synonym'}]. So the file is in the walk, is parsed, and WOULD be flagged - it simply has nothing to flag. ITEM 4: pnpm exec vitest run --maxWorkers=2 over the previously failing file plus the two already touched = 3 files, 127 tests, all passing. Final union, same commit, 10 files / 226 tests all passing: check-doc-fence-languages, check-doc-component-types, check-doc-snippet-types, one-authority-per-exported-name-6273, check-pre-install-import-graph, doc-version-claims, forwardref-props-erasure.guard, known-schema-types-derivation-5115, report-namespace-agreement-6416, SchemaRenderer.propsResolution. Two of those were run specifically because of THIS round's change: one-authority-per-exported-name-6273 (I added a third `export ROOT_PAGES`) and check-pre-install-import-graph (the fence guard must stay install-free) - both green. GATE UNION re-run at the final commit after a fresh 35-task build, because the worktree had been torn down after delivery and packages/*/dist went with it: check:doc-types exit 0 (186 files, 922 type literals, 787 registered); check:doc-snippets exit 0 (225 documents, 417/417 blocks judged, 0 failed); check:doc-fences exit 0 (225 documents); docs:check-links exit 0 (17 scan roots); check:readme-exports exit 0 (406 self-imports, 0 fabricated); check:control-bytes exit 0 (6109 files) plus a manual grep -naP over the round-2 diff, zero hits; check:pre-install-import-graph exit 0 (22 modules walked, every non-relative leaf a node builtin). eslint --no-inline-config --format json over the 4 changed lintable files: 0 errors, 0 warnings.",
"mcp_calls": "6 cumulative - issue_write x2, create_pull_request x1, add_issue_comment x2 (both reports), update_pull_request x1. Reads continued through unauthenticated repo-scoped REST (HTTP 200), including both PR body read-backs.",
"open_questions": [],
"out_of_scope_findings": [
"no new cards this round. The third gate was NOT filed as a finding because it is structurally forced inside this PR - a pin asserts the two surfaces are identical, so part 1 cannot be green while they differ - which is the same shape as the crud/submit deviations already landed. objectui#7417 and objectui#7418 stand as filed; objectui#7417 already records check-readme-exports as the fourth surface with this blind spot, and the PR body now names all four in one table."
]
}
Landed — verified BY CONTENT on origin/main, with controls
PR #7419 merged through the queue at 2026-09-03T01:21:35Z. mainbf244f400 → 75e743638. pm:dispatched stripped in the same pass.
⭐ Verified by reading the landed content, ⛔ not by the PR's head SHA — a head SHA says what was pushed, never what reached main. The baseline was measured on bf244f400before the merge, so both sides of each delta are real readings:
probe
on bf244f400
on 75e743638
ROOT_PAGES — check-doc-component-types.mjs
0
4
ROOT_PAGES — check-doc-snippet-types.mjs
0
5
ROOT_PAGES — check-doc-fence-languages.mjs
0
2
stat-card in root README.md
4
0
Both zeros are readings rather than broken queries, which is the whole point of taking controls on the same query and the same paths:
The gate-script control (scanDocs|Documents over the same three files) reads 3 / 4 / 2 on both sides — unchanged, so the query mechanism is identical across the two refs and the ROOT_PAGES movement is the diff, not an artefact. ⚠️ Recorded because the pre-landing baseline for this card was itself first taken with a pattern (^(const|import).*ROOT_PAGES) that structurally could not match export const and returned a false zero on all three; it was caught only by re-probing with a firing control.
The README control on the same file reads 35 → 29. Non-zero on both sides, so the file is genuinely being read; it moved because the landed diff also retargeted crud, submit and the card.value sites, which is expected rather than surprising.
The declaration is present and is the shared-by-copy form the PR argued for, not an import:
scripts/check-doc-fence-languages.mjs:168: export const ROOT_PAGES = ['README.md'];
scripts/check-doc-fence-languages.mjs:191: for (const name of ROOT_PAGES) {
Carried forward, open and unclosed by this card: #7417 (the root README's nine snippet diagnostics, declared as debt in UNGATED_DOCS rather than fixed, plus check-readme-exports' identical blind spot) and #7418 (six more non-carriage ${…} in guide/expressions.md). ⚠️ The UNGATED_DOCS entry is debt, never a pass — the gate now counts and re-derives it every run, which is the difference from a file outside the walk.
Activity
os-warren commentedon Sep 1, 2026
PM seat (
domain:ui) — routing a second, larger question onto this cardRelabelled
domain:ui+pm:queue+needs-user-decision. PR #7114 (#7015) has landed its half of the expression-channel work and this card now carries the residue, which is bigger than the root README.⛔ The #7015 ordering constraint is NOT discharged repo-wide — recording this so nobody reads PR #7114 as clearing objectui#4795's path
#7015 exists because objectui#4795's second ruled half (build-time rejection of
${…}outside the carriage map) would otherwise redden the platform's own authored examples. PR #7114 dischargedtextnodes undercontent/docs— measured 32 → 2 with a control moving 0 → 30 on the same query. It discharged nothing else.Still carrying
${…}in a key with no carriage row, and therefore still able to redden that gate:content/docs/guide/expressions.md:388progresscontent/docs/guide/expressions.md:453inputREADME.md×4stat-card— registered nowherepackages/plugin-dashboard/README.mdmetric-cardpackages/react/README.mdinput⭐ The decision this needs, and why no seat should take it by edit
The two in-corpus hits were deliberately left untouched by #7015's implementer, and that was the right call: retargeting a
progressorinputnode'svalueis an unruled behaviour edit, not a docs fix. The underlying question is a fork and it is unanswered:(A) non-
texttypes that plainly want an expression channel get carriage rows, and the docs stay as written; or(B) the docs stop authoring expressions in those keys, and the carriage map stays as-is.
⇒ The ordering matters: if objectui#4795's gate lands before this fork is ruled, it reddens these occurrences regardless of which answer is right. That is a scheduling fact for whoever sequences #4795, not an argument for either branch.
Three distinguishable pieces of work now live on this card
README.mdis outside every doc gate's scan surface. The most-read authored file in the repository is checked by nothing. ⭐ This is the highest-value half and is independent of the fork: widening the surface can land whatever (A)/(B) is ruled. It is also self-demonstrating — thestat-carddefect survived precisely because no gate reads that file.statisticis the natural target and genuinely declares avaluecarriage row, so"value": "${…}"there evaluates correctly with no further change.⛔ I am not dispatching this while (3) is open, because (2)'s correct shape depends on the answer. (1) alone may be worth splitting into its own card — I am flagging that rather than doing it, since splitting a card someone else filed 20 minutes ago is triage's call, not mine.
Measurement quality note: the
stat-cardzero on this card is properly controlled — 4 hits all in the README, 0 registrations, against a live control (statistic→ a real registration atstatistic.tsx:64) in the same sweep. It is a reading, not a broken grep.Generated by Claude Code
huangyiirene commentedon Sep 1, 2026
裁决:三件一批;(A)/(B) 叉裁 B(维护者 2026-09-01,总监批 #28)
项目总监席 · session
session_01KGtaLpkW1mycWgkbSb3H6t· 维护者对本批逐字:「同意」。README.md加进check-doc-component-types与check-doc-snippet-types的扫描面(最高价值半边,先落——内容修了不加面就会再烂);stat-cardwidget 改statistic(真实注册且有value运送行,"${…}"照常求值,示例保持表达力);content/docs/guide/expressions.md:388/:453(progress/input)与plugin-dashboard/react两个包 README 停止在无运送行的键上编写${…}(文档教现实);真实应用要哪个键求值 ⇒ 带消费者立 carriage-row 卡,届时按条款②扩;content外没有任何文本键既被求值又被读回 ——statistic.value/card.title/button.label无法绑定表达式 #4795 第二半(build 期拒绝 map 外${…})的落地障碍 —— 其排期归车道;状态转移(同笔)
摘
needs-user-decision(矛盾对修正),pm:queuedocumentationfindingdomain:ui留。Generated by Claude Code
os-project-manager commentedon Sep 2, 2026
Claim:
domain:uiexecution seat, PM sessionsession_01EMrWaQw3XS5DxTHxp4yRyC, R2. Branchclaude/issue-7115-root-readme-doc-gate-surface. Dispatching to anos-devsubagent at opus, all three ruled parts in one PR.Comments re-read before claiming — both, including the predecessor seat's explicit "⛔ I am not dispatching this while (3) is open". (3) is now closed: the maintainer ruled the fork on 2026-09-01 (verbatim 「同意」, comment 5494799307), so the reason that seat held it no longer applies. ⛔ No competing claim with a different session ID.
findingstripped in the same stroke — the label means awaiting first grading, and this card was graded and then ruled.documentationanddomain:uiretained.Why this card, now
⭐ It is byte-free by construction, and that is why it was selected over cards that are ruled and otherwise readier. This lane is blocked on #7399 — the
frameworkper-chunk eager-closure ceiling with 177 bytes of headroom repo-wide — and this card's entire surface isREADME.md,content/docs/**, two package READMEs and twoscripts/gates. Nothing it touches can reach the console bundle.packages/core/src/utils/dataset-format.ts, andpackages/coreis one of the three landings that movedframework510.8 → 511.5 KB earlier today. A date-formatting branch there would very plausibly exceed 177 bytes and produce a third PR blocked on the same unresolved decision. ⛔ Dispatching it would be spending a lane to widen a queue I cannot clear.Serial constraints cleared
README.md,content/docs/guide/expressions.md,packages/{plugin-dashboard,react}/README.mdscripts/check-doc-component-types.*,scripts/check-doc-snippet-types.*scripts/was held by #7212, which landed at6aeba673c; different files regardlessRuled scope, as dispatched
Per the ruling, all three parts, with the gate half leading because "内容修了不加面就会再烂":
README.mdjoins the scan surface ofcheck-doc-component-typesandcheck-doc-snippet-types. Highest-value half, and self-demonstrating: thestat-carddefect survived precisely because no gate reads that file.stat-cardwidgets becomestatistic, which is genuinely registered (statistic.tsx:64) and declares avaluecarriage row, so"${…}"keeps evaluating and the example keeps its expressiveness.texttypes get no new carriage rows.content/docs/guide/expressions.md:388(progress) and:453(input), plus theplugin-dashboardandreactpackage READMEs, stop authoring${…}in keys with no carriage row — 文档教现实. ⛔ A real application needing one of those keys evaluated files a carriage-row card with its consumer, and widens under Clause-② then; ⛔ not here.Ledgered downstream benefit: this ruling clears the landing obstacle for #4795's second half (build-time rejection of⚠️ That does not make #4795 dispatchable — it remains
${…}outside the carriage map).pm:blockedonobjectstack-ai/objectstack#13670, verified today (5517229859).Generated by Claude Code
fix(docs,gates): the root README joins both doc gates' scan surface, …
os-project-manager commentedon Sep 3, 2026
os-dev-report
{ "issue": 7115, "status": "done", "branch": "claude/issue-7115-root-readme-doc-gate-surface", "pr": "https://github.com/objectstack-ai/objectui/pull/7419", "premise_still_valid": true, "summary": "All three ruled parts landed in one draft PR at commit 874229356 (9 files: root README, content/docs/guide/expressions.md, two package READMEs, the two gate scripts, their two test suites, one empty-frontmatter changeset). PREMISE CORRECTION, does not change the conclusion: the card attributes the surface 'every .mdx and .md page under content/docs, plus every packages/NAME/README.md' to check-doc-component-types' own header, but that sentence is check-doc-snippet-types'; component-types walked content/docs ALONE (its header says so explicitly: 'this gate walks content/docs and nothing else ... not the package READMEs'). The root README was in NEITHER surface, exactly as filed. DEVIATIONS, flagged not folded in silently, all named in the PR body with evidence: widening the surface made the gate red on THREE findings the ruling never enumerated, because the census behind the ruling was taken before any gate had read the file. (1) 'crud' x2 (README.md:137, :264) is a type RETIRED in objectui#5373 under ADR-0049 that validateSchema already refuses by name; retargeted per the migration table already landed at content/docs/api/schema-reference.md:541-563. (2) 'submit' (README.md:256) sits in FormSchema.actions, which is SchemaNode[] i.e. a rendered-node position, while ActionSchema.type is 'action'; replaced with the declared submitLabel key. (3) card.value x3 in the Basic Usage snippet carries no carriage row (card = [title, description]); retargeted onto statistic, the same move part 2 ordered. Items 1-2 are structurally forced: part 1 cannot land green while the file it now reads is red. On check-doc-snippet-types the honest outcome is narrower than on its sibling and the PR says so plainly: the root README is now IN the scan set (224 to 225 documents) and named in UNGATED_DOCS with a measured nine-diagnostic reason, which is that gate's own designed mechanism and the objectui#5174 distinction (a document outside the walk is 'neither covered NOR declared ungated'); it is declared debt, NOT a compile pass, and three real defects in it are filed as objectui#7417.", "tests": "All runs at 874229356 with a clean tree; exit codes captured by redirect-then-read, never after a pipe, and each verdict quoted from the gate's own printed line. RED-THEN-GREEN, part 1, check-doc-component-types: baseline unwidened = 185 doc files, exit 0, green (README absent from the walk). Widened, content untouched = 186 files, EXIT 1, 7 findings, the ruled four verbatim: \"README.md:290 [unregistered-doc-type] type 'stat-card' (json)\" and the same at :291 :292 :293 (plus the three deviations above). Widened + content fixed = 186 files, exit 0, 'Every documented component type is registered.' check-doc-snippet-types: baseline run from the HEAD blob (verified identical: c47f9b2cb10f5c20035c5517fb216674fcb76a35 both sides) = 224 documents, 31 ungated, exit 0. Widened = 225 documents, EXIT 1, 10 diagnostics on README.md (1 syntax TS1109, 3 TS2305 missing exports, 4 undefined-name, TS2420+TS2355); after the content fix the syntax one is gone, leaving 9; with the measured UNGATED_DOCS entry, exit 0 at 225 documents / 32 ungated. A second independent signal the walk reaches the file: the gate's self-computed build closure grew by exactly --filter=@object-ui/providers. ABLATION, and it states its own confirmation: the implementation was COMMITTED first, then the files.push(...ROOT_PAGES...) line deleted from scripts/check-doc-component-types.mjs; mutation confirmed ON DISK before any run by anchored count (grep -c 'files.push(...ROOT_PAGES' 1 -> 0) AND blob move (6688e0983d46c285e0dbbd6ce8f632499f15ebe6 -> d0441c223b969a49679885f43c7511c083b6f81d), with the script aborting on either check failing. Under that mutation the gate returned to 185 files and printed the green tick -- the exact 'green about nothing' state -- and both new pins failed with 'no `type` literal was scanned in the root README - the collector narrowed back to content/docs'. No build/dist is involved (the .mjs is read from disk and the test imports it directly), so no rebuild leg applies. RESTORE via trap '...' EXIT INT TERM with ABSOLUTE paths and git checkout HEAD -- (never bare checkout, which reads the index), and verified BY STATE not by exit code: git diff HEAD empty, git status clean, and hash-object == rev-parse HEAD:path (both 6688e098...). GATES: check:doc-types exit 0 (186 files, 922 type literals, 787 registered); check:doc-snippets exit 0 (417/417 blocks judged, 0 failed); check:doc-fences exit 0 (224 documents); docs:check-links exit 0 (17 scan roots); check:readme-exports exit 0 (406 self-imports judged, 403->406 real, 0 fabricated, 0 wrong-path) -- its FIRST run was exit 1 and is reported as NOT MEASURED, not red: it was the precondition 'packages/plugin-ai ... type entry ./dist/index.d.ts is not on disk -- run pnpm build first', cleared by building that package; check:control-bytes exit 0 (6109 files), plus a manual grep -naP over the diff for C0/C1/DEL, zero hits; changeset gates fixed/no-major/overwrite all exit 0 and check-changeset-presence says 'no changeset is owed' (an empty-frontmatter declaration is included anyway, per the objectui#7114 precedent). TESTS: the two edited gate scripts' OWN suites plus every other suite that names my changed files (git grep over *.test.ts for each changed path) -- 8 files, 193 tests, all passing, via os-verify-lock.sh: check-doc-component-types, check-doc-snippet-types, doc-version-claims, forwardref-props-erasure.guard, known-schema-types-derivation-5115, report-namespace-agreement-6416, check-pre-install-import-graph, SchemaRenderer.propsResolution. The two gate suites went 97 -> 105 tests: 8 NEW PINS, because an unpinned surface widening reverts silently. LINT, narrowed with the three pieces of evidence: (1) the receiving population is read from eslint.config.js itself -- files: ['**/*.{ts,tsx}'] plus narrower overrides, scripts/ not in ignores -- so the two .mjs files are outside it and were passed explicitly, over-covering rather than under; (2) the count is read from --format json: 4 files linted, 0 errors, 0 warnings; (3) eslint.config.js has ZERO occurrences of projectService / parserOptions / project: (control: languageOptions matches once), so type-aware linting is off and no untouched file's verdict can depend on this diff. GATE FAMILY DERIVATION: scripts/pm/dispatch-gates.mjs lives only in objectstack and answers only about objectstack, so it was NOT used; the family was derived by hand from objectui's own package.json scripts and .github/workflows/ path filters.", "mcp_calls": "4 - issue_write x2 (the two out-of-scope cards), create_pull_request x1, add_issue_comment x1 (this report). Every read went through unauthenticated repo-scoped REST, which returned HTTP 200 in this container: the card body and its 3 comments, 4 pages of open issues for the duplicate check, and the PR body read-back. No search endpoint was called.", "open_questions": [ { "question": "Should deviations 1-3 (the retired `crud` x2, the unregistered `submit`, and `card.value` x3) stay in this PR, or be split into their own card? They are the card's own defect classes in the card's own file, but the 2026-09-01 ruling enumerated only `stat-card`.", "options": [ "A - keep them here, as landed. Deviations 1-2 are structurally forced: part 1 (the highest-value half, ruled to land first) cannot go green while the file the gate now reads is red, so splitting them means part 1 cannot land at all. Deviation 3 is ruling B's own principle applied to the file part 2 is about. Each correct form is pinned by evidence already in the tree - the objectui#5373 migration table, FormSchema.actions being SchemaNode[], and the measured carriage map - so none is a judgement call about an API.", "B - split deviations into a follow-up and land part 1 red. Not viable as stated: a red gate cannot merge, so this really means holding the whole ruled batch until a second card is ruled.", "C - keep 1-2 (forced) and revert 3 to a literal-only fix. Cheapest to review, but it contradicts the ruling's own instruction that the example keep its expressiveness rather than degrade to literals." ], "recommendation": "A. Long-term soundness dominates and points at A: the ruling's whole rationale is that a fixed content surface re-rots without the gate, and a gate that cannot be green is a gate that gets weakened later - the failure mode this repo treats as worse than no check. Real business need: the root README is the first artifact every new reader copies from, and `crud` is refused BY NAME at runtime, so leaving it is teaching a schema the platform rejects. AI-authored-metadata error-proofing: `submitLabel` and `object-grid`'s `field` identity key are the declared shapes, so the corpus an agent learns from now matches what publish-time validation accepts. Startup scope discipline is the one axis pulling toward B/C, and it is satisfied without them: nothing was widened, no carriage row was added, no gate was weakened, and the two genuinely unbounded findings were filed (objectui#7417, objectui#7418) rather than absorbed. Everything in A is bounded, mechanically determined by landed evidence, and named line-by-line in the PR body so any one item can be dropped on review." } ], "out_of_scope_findings": [ "filed as objectui#7417: the root README's ts/tsx snippets do not compile - 9 measured diagnostics, of which 3 are real (`ObjectRenderer` on no export of @object-ui/app-shell, the same phantom objectui#7095 recorded elsewhere; `registerDefaultRenderers` on no export of @object-ui/components and taught in no other authored file; `createObjectStackAdapter` imported from @object-ui/core, which does not ship it - @object-ui/data-objectstack does). The card also records that scripts/check-readme-exports.mjs has this SAME blind spot (its surface is packages/NAME/README.md only), which is a THIRD gate the ruling did not name and is why all three names survived.", "filed as objectui#7418: content/docs/guide/expressions.md still authors ${...} in 6 more keys with no carriage row beyond the two the ruling enumerated - badge.text x1, badge.variant x3, card.className x1, card.body x1, each measured against expressionBindableTextKeysFor from the built @objectstack/spec artifact. Deliberately NOT claimed: the two list.items occurrences, since `items` is a data key outside the text-carriage question." ] }Generated by Claude Code
os-project-manager commentedon Sep 3, 2026
ACCEPT — all three ruled parts delivered, and the open question is ruled A (keep the deviations here)
domain:uiexecution seat, PM sessionsession_01EMrWaQw3XS5DxTHxp4yRyC, R2. PR #7419 at874229356. ⛔ Not yet enqueued — 22 checks green includingBundle Analysisand both doc gates, 8 still running. Enqueue requires every check green, not the required subset.The open question: A, keep them, as landed
Deviations 1–2 are structurally forced, and that settles it: part 1 was ruled to land first precisely because "内容修了不加面就会再烂", and a widened surface cannot land green while the file it now reads is red. Splitting them does not defer them — it makes the ruled part-1 unlandable. Deviation 3 is ruling B's own principle (
${…}only in keys with a carriage row) applied to the very file part 2 is about.⭐ What makes this a lane call rather than an escalation is that none of the three is a judgement about an API. Each correct form is fixed by evidence already in the tree:
crud's replacement by the #5373 migration table landed atschema-reference.md:541-563;submit→submitLabelbyFormSchema.actionsbeingSchemaNode[](a rendered-node position) whileActionSchema.typeis'action';card.value→statisticby the measured carriage map. ⛔ Nothing was widened, no carriage row added, no gate weakened — and the two genuinely unbounded findings were filed (#7417, #7418) rather than absorbed. Option C is rejected for the reason the ruling itself gives: degrading the example to literals contradicts "示例保持表达力".Why the widening found 7 and the ruling named 4
⭐ Worth recording, because it is the card's own thesis proving itself: the census behind the ruling was taken before any gate had read the file. Three more unregistered types were sitting in the repository's most-read authored file, invisible for as long as the blind spot existed — including
crud×2, a type retired under ADR-0049 in #5373 thatvalidateSchemaalready refuses by name. The README was teaching a schema the platform rejects at runtime.Verification I did myself, not from the report
UNGATED_DOCSentry oncheck-doc-snippet-types— and read it on the branch rather than accepting its framing. It holds:.mdxand.mdpage undercontent/docs, everypackages/<name>/README.md, and the rootREADME.md" ⇒ ruled part 1 is satisfied on both gates, not one.UNGATED_DOCSis declared and re-derived every run — "an entry naming a file that does not exist, or that holds nots/tsxblock at all, fails as a stale entry, so the list can only shrink". It cannot silently grow.⇒ Before: invisible to the walk. After: in the walk, named as measured debt, defects filed. Per #5174's own distinction — a document outside the walk is "neither covered NOR declared ungated" — that is strictly better, and the PR says so plainly rather than claiming a compile pass it did not achieve. Changed-file list verified as exactly the nine claimed.
What made the delivery trustworthy
files.push(...ROOT_PAGES...)line returned the gate to 185 files and printed the green tick — the exact "green about nothing" state a surface widening risks — and both new pins failed with "the collector narrowed back tocontent/docs". Mutation proven on disk by anchored count (1 → 0) and blob move; restore proven by state (git diff HEADempty,hash-object==rev-parse HEAD:path), withgit checkout HEAD --rather than a bare checkout that reads the index.check-doc-component-types' header, but that sentence is the snippet gate's — component-types walkedcontent/docsalone. The conclusion is unchanged (the root README was in neither), and saying so is worth more than quietly inheriting it.check:readme-exportsexit 1 on its first run was reported as NOT MEASURED, not red — it was the precondition "type entry ./dist/index.d.ts is not on disk", cleared by building. A precondition failure is not a colour.dispatch-gates.mjswas correctly NOT used — it lives only in objectstack and answers only about objectstack. The gate family was derived by hand from objectui's ownpackage.jsonscripts and workflow path filters. That matches this seat's recorded lane fact exactly.Filed out of scope
dist/index.d.ts, incl.createObjectStackAdapterattributed to the wrong package #7417 — the root README's ts/tsx snippets do not compile: 9 diagnostics, 3 real.scripts/check-readme-exports.mjshas the same blind spot (its surface ispackages/<name>/README.mdonly) — a third gate the ruling did not name, and why all three phantom names survived.guide/expressions.mdstill authors${…}in 6 more keys with no carriage row —badge.text/badge.variant/card.className/card.body, beyond the two the 2026-09-01 ruling named #7418 —expressions.mdauthors${…}in 6 more keys with no carriage row beyond the two the ruling enumerated, each measured againstexpressionBindableTextKeysForfrom the built spec artifact. The twolist.itemsoccurrences were deliberately not claimed —itemsis a data key, outside the text-carriage question.Both filed unassigned with no
domain:*or priority. ⛔ Grading is the triage seat's.Generated by Claude Code
fix(gates): the root README joins `check-doc-fence-languages` too — t…
os-project-manager commentedon Sep 3, 2026
os-dev-report
{ "issue": 7115, "status": "done", "branch": "claude/issue-7115-root-readme-doc-gate-surface", "pr": "https://github.com/objectstack-ai/objectui/pull/7419", "premise_still_valid": true, "summary": "R2 follow-up: the red 'Test (shard 1/4)' is fixed at commit 02efff4ba, committed ON TOP (no rebase, no amend, no force-push). The failure was real and was a THIRD gate coupled to the surface part 1 widened: check-doc-fence-languages re-implements check-doc-snippet-types' walk so it needs no install, and check-doc-fence-languages.test.ts asserts fenceDocuments(ROOT) equals snippetDocuments(ROOT); widening one without the other breaks that coupling by construction. The pin was NOT weakened, skipped or relaxed - it is the only reason the third gate was found at all - the fence guard's surface was widened instead, and its header now STATES the surface rather than leaving it to be read off the collector. ROOT_PAGES CANNOT be shared by import and here is why: anything imported from check-doc-snippet-types.mjs pulls in its `import ts from 'typescript'` at module load, which would install-gate the one gate whose entire value is running install-free in the unfiltered workflow a docs-only PR starts (that gate's own header and doc-fence-languages.yml both state this). So it stays a deliberate copy on the same bargain the document walk and TS_FENCE_LANGUAGES already make - copy freely, compare always - and the drift guard is strengthened rather than assumed: all three gates now EXPORT ROOT_PAGES and a new pin compares all three, which covers the shared half even where the full surfaces legitimately differ (component-types deliberately does not walk the package READMEs, so it cannot join the list-equality comparison). The PR body now carries the four-gate table the coordinator asked for. Nothing was absorbed beyond the forced fix.", "tests": "All runs at 02efff4ba with a clean tree; exit codes captured by redirect-then-read, never after a pipe. ITEM 3, the measurement asked for: check:doc-fences with the root README in the walk is EXIT 0 - 'every TypeScript block in 225 document(s) is fenced ts/tsx/typescript, except 80 declared file(s) carrying 90 block(s) of objectui#5867's remaining population (SHRINK-ONLY)'. The root README contributes ZERO findings; grep of the output for the file name returns nothing, and NO baseline entry was added, so the shrink-only map is untouched. That green is NOT vacuous, proved by control through the shipped census(): listDocuments reports 225 documents with README.md present; census over the real file returns []; census over the same file with ONE tsx fence info string removed (mutation confirmed: mutated !== src) returns [{rel:'README.md', line:206, language:'', mode:'synonym'}]. So the file is in the walk, is parsed, and WOULD be flagged - it simply has nothing to flag. ITEM 4: pnpm exec vitest run --maxWorkers=2 over the previously failing file plus the two already touched = 3 files, 127 tests, all passing. Final union, same commit, 10 files / 226 tests all passing: check-doc-fence-languages, check-doc-component-types, check-doc-snippet-types, one-authority-per-exported-name-6273, check-pre-install-import-graph, doc-version-claims, forwardref-props-erasure.guard, known-schema-types-derivation-5115, report-namespace-agreement-6416, SchemaRenderer.propsResolution. Two of those were run specifically because of THIS round's change: one-authority-per-exported-name-6273 (I added a third `export ROOT_PAGES`) and check-pre-install-import-graph (the fence guard must stay install-free) - both green. GATE UNION re-run at the final commit after a fresh 35-task build, because the worktree had been torn down after delivery and packages/*/dist went with it: check:doc-types exit 0 (186 files, 922 type literals, 787 registered); check:doc-snippets exit 0 (225 documents, 417/417 blocks judged, 0 failed); check:doc-fences exit 0 (225 documents); docs:check-links exit 0 (17 scan roots); check:readme-exports exit 0 (406 self-imports, 0 fabricated); check:control-bytes exit 0 (6109 files) plus a manual grep -naP over the round-2 diff, zero hits; check:pre-install-import-graph exit 0 (22 modules walked, every non-relative leaf a node builtin). eslint --no-inline-config --format json over the 4 changed lintable files: 0 errors, 0 warnings.", "mcp_calls": "6 cumulative - issue_write x2, create_pull_request x1, add_issue_comment x2 (both reports), update_pull_request x1. Reads continued through unauthenticated repo-scoped REST (HTTP 200), including both PR body read-backs.", "open_questions": [], "out_of_scope_findings": [ "no new cards this round. The third gate was NOT filed as a finding because it is structurally forced inside this PR - a pin asserts the two surfaces are identical, so part 1 cannot be green while they differ - which is the same shape as the crud/submit deviations already landed. objectui#7417 and objectui#7418 stand as filed; objectui#7417 already records check-readme-exports as the fourth surface with this blind spot, and the PR body now names all four in one table." ] }Generated by Claude Code
os-project-manager commentedon Sep 3, 2026
Landed — verified BY CONTENT on
origin/main, with controlsPR #7419 merged through the queue at 2026-09-03T01:21:35Z.
mainbf244f400→75e743638.pm:dispatchedstripped in the same pass.⭐ Verified by reading the landed content, ⛔ not by the PR's head SHA — a head SHA says what was pushed, never what reached
main. The baseline was measured onbf244f400before the merge, so both sides of each delta are real readings:bf244f40075e743638ROOT_PAGES—check-doc-component-types.mjsROOT_PAGES—check-doc-snippet-types.mjsROOT_PAGES—check-doc-fence-languages.mjsstat-cardin rootREADME.mdBoth zeros are readings rather than broken queries, which is the whole point of taking controls on the same query and the same paths:
scanDocs|Documentsover the same three files) reads 3 / 4 / 2 on both sides — unchanged, so the query mechanism is identical across the two refs and theROOT_PAGESmovement is the diff, not an artefact.^(const|import).*ROOT_PAGES) that structurally could not matchexport constand returned a false zero on all three; it was caught only by re-probing with a firing control.crud,submitand thecard.valuesites, which is expected rather than surprising.The declaration is present and is the shared-by-copy form the PR argued for, not an import:
Carried forward, open and unclosed by this card: #7417 (the root README's nine snippet diagnostics, declared as debt in⚠️ The
UNGATED_DOCSrather than fixed, pluscheck-readme-exports' identical blind spot) and #7418 (six more non-carriage${…}inguide/expressions.md).UNGATED_DOCSentry is debt, never a pass — the gate now counts and re-derives it every run, which is the difference from a file outside the walk.Generated by Claude Code
feat(scripts): widen the expression-carriage census to check:doc-type…
fix(docs,gates): the root README joins both doc gates' scan surface, …
feat(scripts): widen the expression-carriage census to check:doc-type…
gate(doc-types): walk packages/NAME/README.md, with its ruled DOC_TYP…