docs(plugins): bring three documented interface blocks up to their shipped types - #7985
Merged
baozhoutao merged 2 commits intoSep 6, 2026
Merged
Conversation
…ipped types `PARTIAL_EXCERPTS` in `scripts/check-readme-exports.mjs` opened with three entries, each recording drift objectui#6214 was not allowed to fix in the gate's own PR. All three are paid off here and the ledger is now empty. The three are NOT one fix: - `packages/plugin-gantt/README.md::GanttTask` is a genuine excerpt -- the paragraph directly below the block already says `fields` and `hasOwnDates` are populated by `ObjectGantt` itself. It moves to the in-README `PARTIAL_MARKER` above the fence, which is the declaration that means "deliberate"; adding the two keys to the block would contradict that prose. - `packages/plugin-kanban/README.md::KanbanColumn` and `::KanbanCard` are staleness, so the blocks are brought up to the shipped declarations. The key sets are re-derived from what `@object-ui/plugin-kanban` actually exports on a built tree, not copied from the ledger reasons: the column is two keys behind (`collapsed` and the `color` tombstone), not the one the ledger recorded. The ledger's own test case is updated with it. Its non-vacuity guard (`expect(ledgered.length).toBeGreaterThan(0)`) went red on the empty ledger, correctly: the per-ENTRY leg stops asserting. The case does not go vacuous -- `judgeable` becomes the empty set and the equality then reads "no declaration in this tree reds as a stale omission with the ledger off" -- so the guard is replaced by the empty state asserted as a fact, and the per-entry property stays pinned on the fixture tree, which carries an entry by construction. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013uAaxiwgYDybsTNV9xwa1M
Contributor
✅ Console Performance Budget
The eager closure is every chunk the entry reaches through static imports — what the browser fetches and parses before the app renders. The entry chunk on its own is a small fraction of it. 📦 Bundle Size Report
Size Limits
|
baozhoutao
marked this pull request as ready for review
September 6, 2026 05:45
This was referenced Sep 6, 2026
…n expectation `Test (shard 2/4)` went red at head 09f1d48 with two assertions in this file expecting 0 and receiving 1. CI's shards run `pnpm install` then `pnpm test` and never build, so the tree they judge is unbuilt -- and an unbuilt tree is the only state in which this can fire. The PR's own verification ran on a built tree, where it cannot. The gate counts BOTH excerpt mechanisms in one census counter, deliberately and in one sentence of its header: a declaration that comes back `unjudgeable-type` suspends the shrink-only rule for its ledger entry AND for its in-README `PARTIAL_MARKER`, and "both are counted as `not judged` in the census". The two assertions derived their expected value from the LEDGER alone -- `Object.keys(PARTIAL_EXCERPTS)` filtered by build state -- which was complete only while every excerpt in the tree was a ledger entry. Moving `GanttTask` to the marker, which is the disposition a genuine excerpt is meant to end at, produced a count neither assertion modelled. So the expectation is widened to the population the counter actually counts, under the same per-PACKAGE rule: `suspendedExcerpts()` returns the ledger entries and the bound markers whose OWN package is unbuilt. The gate is unchanged -- no judgement byte and no census byte moves. Derived from the READMEs, not from the counter under test: the ledger half from the exported literal, the marker half by re-reading each README of an unbuilt package through the gate's own exported grammar (`extractCodeBlocks` + `findPartialMarkers`, keyed `<fence>::<Name>` per README exactly as the gate keys `excerptFor`). It does not re-parse the block to confirm the named type is declared inside it, because a bound marker whose fence declares no such type is reported `stale-partial-marker` in every build state and the same case asserts there are none. The property both assertions exist for is kept and extended, not relaxed: an unbuilt package is still REPORTED and never silently skipped, and a new line asserts that for the marker route too -- every marker-declared excerpt on an unbuilt package must carry its own `unjudgeable-type` finding, the same requirement the ledger half has always had. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MM7kaS4dPpYHV5BsMyu4tQ
Contributor
✅ Console Performance Budget
The eager closure is every chunk the entry reaches through static imports — what the browser fetches and parses before the app renders. The entry chunk on its own is a small fraction of it. 📦 Bundle Size Report
Size Limits
|
Contributor
Author
|
Standing down on
Proceeding: arming auto-merge (ACCEPT Generated by Claude Code |
baozhoutao
deleted the
claude/issue-7302-readme-partial-excerpts-content-half
branch
September 6, 2026 07:20
This was referenced Sep 6, 2026
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 #7302
PARTIAL_EXCERPTSinscripts/check-readme-exports.mjsopened with exactly three entries: objectui#6214 wired the interface pin and was deliberately not allowed to edit README CONTENT, so the drift its first run found was written down there instead of being inherited silently. All three are paid off here.Ledger before: 3 entries. Ledger after: 0 —
Object.freeze({}), with the docblock kept and extended, because the list must be able to fill again.Three entries, three dispositions — deliberately not one template
packages/plugin-gantt/README.md::GanttTaskPARTIAL_MARKERabove the fencefieldsandhasOwnDatesare populated byObjectGanttitself — verified still present on this base. Adding the two keys to the block would contradict that prose.packages/plugin-kanban/README.md::KanbanColumnpackages/plugin-kanban/README.md::KanbanCardThe marker grammar used
One marker silences one TYPE, and it binds to the next fenced block whose opening fence is the first following line that is neither blank nor another marker. Placed at
packages/plugin-gantt/README.md:392, immediately above the fence at :393:(spelled without its HTML-comment delimiters here, because a comment-shaped fragment does not survive being written into a GitHub body — see the read-back rule in
AGENTS.md. The delimiters are present in the file, and the gate parses it: the run below reports1 excerpt(s) declared by marker.)The #6155 impact check (Zone 2 A3) — asked for, and the answer moved a key set
The key sets were re-derived from the gate's own reading of the built tree, not copied from the ledger reasons, exactly as objectui#6155's warning in the ledger asked.
Which declaration
@object-ui/plugin-kanbanactually exports today:packages/plugin-kanban/src/index.tsx:111re-exportsKanbanCard/KanbanColumnfromsrc/types.ts, andsrc/types.ts:35is itself a plain re-export from@object-ui/types. So the shipped declaration is the ONE inpackages/types/src/complex.ts—KanbanCardat :63,KanbanColumnat :120 — which objectui#7664 made authoritative and which that file's own header pins against re-declaration (one-authority-per-exported-name-6273.test.ts). Of objectui#6155's four disagreeing declarations, this is the one that spells the lane's arraycards(objectui#6939 retireditems, a spelling with zero read sites) and the card's arraybadges. Both spellings the README already used are therefore correct against the export; neither was touched. objectui#6155 is not addressed here and remains open.Where the derived answer disagreed with the ledger's prose: the ledger reason for
KanbanColumnrecorded ONE omitted key,collapsed. The gate on a built tree reports two —collapsedandcolor:colorarrived after that reason was written: objectui#7664 retired it ascolor?: never, a deliberate tombstone whose own JSDoc gives prong 2 as "keep loud a key the docs taught as working". The README now documents it as such rather than dropping it — which is what the tombstone exists for. The reason string was a derived value, and it was stale; the export won.Diff, in full
packages/plugin-gantt/README.md— one marker line. The block is unchanged.packages/plugin-kanban/README.md—collapsed?: booleanandcolor?: neverontoKanbanColumn;cardSubtitle?,cardFieldCells?,coverImage?ontoKanbanCard, with a one-line comment each in the block's existing trailing-comment style.limit's comment corrected from "Maximum cards allowed" to the WIP-limit wording the shipped JSDoc uses.scripts/check-readme-exports.mjs— the only non-comment change in this file is the ledger literal (three entries becoming{}); verified by filtering the diff. Everything else is docblock: a paragraph recording that empty is a state and not a retirement, and a@typeannotation (see below).scripts/__tests__/check-readme-exports.test.ts— see the declared deviation below.Two things the dispatch did not predict — both declared
1. The gate's own suite has a non-vacuity guard on the ledger, and it fired.
expect(ledgered.length, 'the ledger is empty, so this case asserts nothing').toBeGreaterThan(0)went red the moment the ledger emptied. It was right to: the per-ENTRY leg of that case does stop asserting. But the case does not go vacuous with it —judgeablebecomes the empty set, so the equality below it then reads "NO declaration in this tree reds as a stale omission with the ledger off", which reds on the next README that drifts. So the guard is replaced by the empty state asserted as a fact, with a comment saying that an entry arriving flips that line, and that the per-entry property never depended on the repository carrying an entry — it is pinned on the fixture tree in the same file (the LEDGER suppresses the omission it records,the LEDGER does NOT suppress a fabricated key either, and the two stale-entry cases), which carries an entry by construction.2.
pnpm type-check:scriptsfailed TS18046 on the empty ledger.Object.freeze({})infersReadonlyof the empty object type, soObject.entrieshands the test suiteunknownvalues and the case that reads each reason stops compiling. Fixed with a@type {Readonly<Record<string, string>>}JSDoc annotation on the export — the same spelling, and the same reason, ascheck-doc-snippet-types.mjs'sUNGATED_DOCS. It is a comment, so it changes no runtime byte.Probes — every mutation proven on disk, every restore proven
Run on the COMMITTED tree, one script with
trap ... EXIT INT TERMand absolute paths. Each mutation is proven by comparinggit hash-objectagainst the path's HEAD blob (an empty or equal hash aborts loudly), and each restore bygit checkout HEAD -- pathfollowed by an emptygit diff HEAD.5d17050cvs HEAD97296226; anchor countscollapsed=0,coverImage=02 documented type(s) are behind the shipped declaration:KanbanColumn omits collapsed, color;KanbanCard omits cardSubtitle, cardFieldCells, coverImagegit diff HEADEMPTY8e2a2736vs HEAD17b504eb; injected anchorhasOwnDates=1, marker still11 partial-excerpt marker(s) declare nothing:GanttTask declares an excerpt that omits nothing any more -- delete the markergit diff HEADEMPTYfabricated-keypositive controlKanbanCardblock9e149d23vs HEAD97296226; anchor count11 documented type(s) declare a key the shipped type does NOT have:documents totallyMadeUpKey, not on the shipped typegit diff HEADEMPTYB is the one that earns the marker route: the marker is checked, so it cannot outlive the fact it declares.
Verification — at
09f1d4856, on a BUILT treeAn unbuilt tree reports every declaration
unjudgeable-typeand SUSPENDS the shrink-only rule, so it is a precondition and not a red. Measured both ways here: before building,426 self-import(s) could not be judgedand3 not judged; the build (turbo run build --filter=./packages/*, through the shared verify lock) reportedVERDICT command-exit 0,Tasks: 39 successful, 39 total.pnpm check:readme-exports— exit 0,✅ check-readme-exports: OK (... 58 key(s) compared both ways (0 fabricated, 0 stale omission(s); 1 excerpt(s) declared by marker, 0 by ledger, 0 not judged ...)). Baseline before the change on the same built tree:53 key(s) ... 0 by marker, 3 by ledger.scan(repoRoot, { excerpts: {} })returnsfindings: 0 vacuous: 0withPARTIAL_EXCERPTS keys: [].--listnow reportspartial-markeronGanttTaskandmatches doc 7 key(s) vs own 7 of 7on both kanban declarations.pnpm exec vitest run packages/plugin-gantt/ packages/plugin-kanban/ scripts/__tests__/check-readme-exports.test.ts scripts/__tests__/check-unreferenced-sources.test.ts→Test Files 88 passed (88),Tests 728 passed (728), lockVERDICT command-exit 0. The reader sweep (git grep -lfor both README paths overscripts/ packages/ examples/ apps/) namespackages/plugin-gantt/src/readme-navigation-example.test.ts,scripts/__tests__/check-readme-exports.test.tsandscripts/check-doc-snippet-types.mjs; all three are covered above.pnpm check:doc-snippets— exit 0,Semantic phase: 477 of 477 block(s) judged, 0 failed.Both READMEs are on that gate'sUNGATED_DOCSledger (gantt: 9 parse + 12 undefined-name; kanban: 6 parse), so their fences are NOT compiled; the ledger's counts are prose and are not re-derived, so these edits cannot move that verdict.pnpm check:doc-fencesexit 0 ·check-doc-linksexit 0 ·pnpm check:control-bytesexit 0 (6421 tracked text file(s)) ·pnpm check:doc-typesexit 0 ·pnpm check:doc-example-readersexit 0 ·check-unreferenced-sourcesexit 0 ·pnpm lint:coverageexit 0 (46/46 packages) ·pnpm check:governed-queue-guardexit 0 (132 cases pass).pnpm type-check:scripts— exit 0.node scripts/check-changeset-presence.mjs— exit 0, verdict quoted literally:✅ No source or published contract of a released package changed in this range, so no changeset is owed.(0 of them published source of a package the release covers).node scripts/check-governed-queue-guard.mjs --testover all four changed paths —✅ NOT GOVERNED — 4 path(s) checked against 5 governed surface(s); none matched.grep -naPfor the control range over all four files → no hits.eslint.config.js'sfilesglobs are**/*.{ts,tsx}and narrower, with no markdown processor, so the two READMEs and the.mjsare outside eslint's population entirely and the linted half of this diff is one file; ②--format jsoncountedfiles linted: 2, errors: 0, warnings: 0; ③ invariance — the config declares noproject/projectService, so type-aware linting is off and this diff cannot move the verdict on any untouched file. The repo-wideeslint . --no-inline-configrun belongs to CI.Out of scope, filed
#7984 — the same README's
badgeselement documents 2 of the shipped 4 members (colorClass/colorStyleare missing). It sits inside a nested object literal, which this gate compares in neither direction by design, and the page's fences are not compiled either. Not touched here.Patch round (R45) —
Test (shard 2/4)was red at09f1d485, and the fix is test-sideTest (shard 2/4)(run34014605149, job101436113831) failed at the previous head with two assertions inscripts/__tests__/check-readme-exports.test.ts, the file this PR already edits:Why it was green here and red there
The test shards run
pnpm installthenpnpm testand never build, so CI judges an unbuilt tree —packages/plugin-ganttamong the 36 unbuilt packages. On an unbuilt package every declaration comes backunjudgeable-type, and the gate then suspends the shrink-only rule for whatever declared that declaration an excerpt, counting it incensus.excerptsNotJudged. It counts both mechanisms there, deliberately and in one sentence of its own header: "BOTH suppressstale-omission... both are counted asnot judgedin the census".The two assertions derived their expected value from the ledger only —
Object.keys(PARTIAL_EXCERPTS)filtered by build state. That was complete while every excerpt in the tree was a ledger entry. This PR movedGanttTaskto the in-READMEPARTIAL_MARKER(the disposition the ledger's own reason prescribed), which produced a marker-declared excerpt on an unbuilt package — a count neither assertion modelled: expected 0, gate reported 1. Verification for R44 ran on a BUILT tree, which is exactly the state in which this cannot fire.Which side owns the count
The test. The gate's behaviour is the one its header specifies, and the census already attributes the suspension correctly — so nothing in
scripts/check-readme-exports.mjschanged in this round. No judgement byte and no census byte moves. The whole patch is one file.suspendedExcerpts(result, excerpts?)returns the declared excerpts whose OWN package is unbuilt, under the same per-package rule the rest of these cases use since objectui#7460:PARTIAL_EXCERPTSliteral, as before;extractCodeBlocks+findPartialMarkers), keyedfence::Nameper README exactly as the gate keys itsexcerptFormap.Derived from the README bytes, never read back off the counter under test, so both assertions still cross-check the gate against something that is not the gate's own count. The marker half deliberately does not re-parse the block to confirm the named type is declared inside it: a bound marker whose fence declares no such type is reported
stale-partial-markerin every build state, and the same case asserts there are none of those.The property both assertions exist for is kept and extended, not relaxed: an unbuilt package must be REPORTED and never silently skipped, and a new line now asserts that for the marker route too — every marker-declared excerpt on an unbuilt package must carry its own
unjudgeable-typefinding, the requirement the ledger half has always had. The:1020line is likewise no longer a hard-coded 0:excerpts: {}turns the ledger off and the ledger is the only half it can turn off, so that line was quietly asserting "this repository declares no excerpt by marker" under a title about the ledger.Verdict lines — both build states
dist/present)pnpm exec vitest run scripts/__tests__/check-readme-exports.test.tsTests 2 failed | 85 passed (87), byte-identical to the CI signature at:1020and:1084Test Files 1 passed (1),Tests 87 passed (87)turbo run build --filter=./packages/* --concurrency=2→Tasks: 39 successful, 39 total), after the fixTests 87 passed (87)pnpm check:readme-exportscheck-readme-exports: OK (... 58 key(s) compared both ways (0 fabricated, 0 stale omission(s); 1 excerpt(s) declared by marker, 0 by ledger, 0 not judged ...))Ablation
On the committed tree, unbuilt, one script with
trap ... EXIT INT TERMand absolute paths: the test-side change alone reverted to the pre-fix blob (git checkout 09f1d485 -- scripts/__tests__/check-readme-exports.test.ts).ddae340evs HEADe64cd41b; anchorsuspendedExcerptscount0after the revert, the oldexpect(off.census.excerptsNotJudged).toBe(0);line back at count1;Tests 2 failed | 85 passed (87)— the same two assertions, the predicted direction (turns red);git checkout HEAD -- path, blob back toe64cd41b,git diff HEADon that path empty andgit status --porcelainempty.Gates, at
b520274pnpm type-check:scriptsexit 0 ·node scripts/check-governed-queue-guard.mjs --testover all four changed paths —NOT GOVERNED — 4 path(s) checked against 5 governed surface(s); none matched·node scripts/check-changeset-presence.mjsexit 0,No source or published contract of a released package changed in this range, so no changeset is owed·pnpm check:control-bytesexit 0 (scanned 6421 tracked text file(s)) plus agrep -naPself-scan of the changed file, no hits ·pnpm check:unreferenced-sourcesexit 0.Readers of the changed file (
git grep -loverscripts/ packages/ .github/, unpiped, exit 0):.github/workflows/readme-exports.yml, which names it in prose as the pin that fails if apathsfilter is ever added to that workflow — no code reads it. Readers of the module it imports:scripts/__tests__/check-unreferenced-sources.test.ts(run:Tests 25 passed (25)), plus prose references inscripts/check-unreferenced-sources.mjs,scripts/check-doc-snippet-types.mjsand.github/workflows/ci.yml.Lint, as a declared narrowing with its three readings: ① the changed file is a
.tsand therefore inside eslint's own population (filesglobs**/*.{ts,tsx}); ②--format jsoncountedfiles linted: 1, errors: 0, warnings: 0; ③ invariance — the config declares noproject/projectService, so type-aware linting is off and this diff cannot move the verdict on any untouched file. The repo-wide run belongs to CI.One deviation from the dispatch's wording: it asked for the build to go through "the repo's shared verify lock". There is no such entry point in this repository (no
scripts/pm/os-verify-lock.sh, nothing inAGENTS.md); the build was run in the foreground at--concurrency=2as written.Generated by Claude Code
Generated by Claude Code