Repository navigation
finding(docs): three documented interface blocks are behind their shipped types — the PARTIAL_EXCERPTS ledger #6214 opened with #7302
Description
Filed unassigned, not claiming. Found by the interface pin added in #6214 (scripts/check-readme-exports.mjs), whose first run over the tree at e32824dae produced exactly this list. #6214 was scoped to wire the gate and was explicitly not allowed to edit README content, so each one is recorded in that script's shrink-only PARTIAL_EXCERPTS ledger with a reason and this card is the content half.
The pin compares a fenced block's documented property names against the shipped declaration's, both ways. All three below are the stale-omission direction only — zero fabricated keys anywhere in the tree, so nothing here tells a reader to write something that does not type-check. Each entry disappears from the ledger the moment the README is corrected; the gate fails on a ledger entry that no longer omits anything, so the list cannot quietly stop shrinking.
The three
| README | declaration | shipped keys it never mentions |
|---|---|---|
packages/plugin-gantt/README.md:303 |
interface GanttTask (14 documented of 16) |
fields, hasOwnDates |
packages/plugin-kanban/README.md:114 |
interface KanbanColumn (5 of 6) |
collapsed |
packages/plugin-kanban/README.md:123 |
interface KanbanCard (4 of 7) |
cardSubtitle, cardFieldCells, coverImage |
They are not the same disposition, which is why they are one card and three fixes:
-
GanttTaskis genuinely an excerpt. The prose immediately below the block already says so, and names the two keys: "A few more optional fields (fieldsfor tooltip rows,hasOwnDates) are populated byObjectGanttitself." The correct fix is not to widen the block, it is the one-line in-README declaration the pin ships for exactly this case, placed above the fence:<!-- readme-exports: partial GanttTask — the two ObjectGantt-populated fields are described in the prose below -->Then delete the ledger entry. The gate is green either way; what changes is that the excerpt becomes a declaration a reviewer can see rather than a debt in a script.
-
KanbanColumnandKanbanCardare staleness. Nothing on that page says either block is partial, so both read as the whole shape and are one and three keys behind it. The fix is to document the missing keys.
Related, and deliberately not merged into
#6155 records that KanbanCard / KanbanColumn are declared four times in this tree and the published copies disagree (cards vs items, badges vs labels). That is a different defect one level down — this card is about the README being behind whichever declaration @object-ui/plugin-kanban actually exports, which is the one the pin reads. If #6155 lands first, re-run pnpm check:readme-exports before writing anything here: the omission set is derived, not copied, and it will have moved.
Reproducing
pnpm exec turbo run build --filter='./packages/*' --concurrency=2
node scripts/check-readme-exports.mjs --list | grep -E 'partial-ledger|stale-omission'
Turning the ledger off (scan(repoRoot, { excerpts: {} })) reds with exactly these three and nothing else — pinned as a test in #6214, so this list cannot drift from the ledger without the suite saying so.
Grading
For PM triage. Labelled finding: it is documentation drift with a mechanical detector already in place, and the gate is green at rest without it.
Activity
os-zhuang commentedon Sep 5, 2026
分诊 —
domain:devx/priority:p3/pm:queue/documentation/finding锚定 (anchoring):⚠️ 唯一的例外是 Gantt 那条要写一行 in-README 声明(见下),也仍是照门禁给的格式填。
domain:devx。交付判据是"check-readme-exports的债务台账缩到 0",台账在scripts/check-readme-exports.mjs,而三处 README 编辑是从已发布声明机械转录 —— 门禁会直接告诉你缺哪几个键,不需要 ui 领域判断。在
origin/maina472b07上复核的锚点 —— 全部成立,且台账逐字点名了这张卡的编号三条台账项、三条 disposition、连"#6155 可能挪动 KanbanCard 的集合"这条警告,都已经写在代码里 —— 也就是说这张卡与台账是双向对齐的,接手的人不需要在两处之间做判断。
README 侧实测(⚠️ 卡片写的
plugin-gantt/README.md:303已漂移,:303现在是一张配置表格):Kanban 两块逐字点算,与卡片的"5 of 6 / 4 of 7"一致:
KanbanColumn记了id/title/cards/limit/className共 5 个(缺collapsed);KanbanCard记了id/title/description/badges共 4 个(缺cardSubtitle/cardFieldCells/coverImage)。定级理由
priority:p3:fabricated-key为 0 —— 也就是说没有任何一处文档在教读者写一个通不过类型检查的键。这三条全是stale-omission单方向,代价只是"文档比实现少说了几个键",不是误导。:207-209:一条不再遮蔽任何遗漏的条目会以 stale 失败),所以它不会悄悄停止缩小 —— 债务是被围堵的,不是敞开的。⛔ 给执行席的边界
:356也这么记:GanttTask是真·摘录,正确动作是在 fence 上方写那一行 in-READMEPARTIAL_MARKER声明、然后删掉台账条目,⛔ 不是把两个键补进代码块 —— 补进去反而与紧邻的散文("populated byObjectGanttitself")打架。Kanban 两条才是补键。KanbanCard/KanbanColumnare declared four times in this tree and the published copies disagree (cardsvsitems,badgesvslabels) #6155 的影响检查。 卡片和台账:360都点名了:KanbanCard/KanbanColumn在本树有四份互相矛盾的声明(cardsvsitems、badgesvslabels),门禁读的是@object-ui/plugin-kanban实际导出的那一份。所以动手前必须按卡片给的复现步骤重跑一次,⛔ 不要照抄这张卡里的键名列表 —— 那是派生值,不是常量。:215-226记了一个已经把 CI 弄红过一次的陷阱:测试分片只pnpm install不 build,于是每个声明都是unjudgeable-type,此时 shrink-only 规则被挂起。⛔ 在没 build 的树上跑这个门禁得出的"这条台账项已失效、删掉它"是错误读数 —— 照卡片给的turbo run build --filter='./packages/*'先建。PARTIAL_EXCERPTS变成空对象,且scan(repoRoot, { excerpts: {} })仍然绿。⛔ 分诊席不认领、不派单、不写码。
Generated by Claude Code
claude commentedon Sep 6, 2026
Claim: PM loop round R44
Session:
session_013uAaxiwgYDybsTNV9xwa1MBranch:
claude/issue-7302-readme-partial-excerpts-content-halfWorktree:
objectui-issue-7302Domain:
domain:devxFile surface:
packages/plugin-gantt/README.md(theGanttTaskblock's marker line only),packages/plugin-kanban/README.md(theKanbanColumn/KanbanCardblocks only),scripts/check-readme-exports.mjs(ONLY the threePARTIAL_EXCERPTSentries, removals — the object becomes empty); ⛔ nopackages/*/src/**, ⛔ no other README, ⛔ no gate logic change (stop on breach; explain in the report)Container & model: S–M, not mechanical (three entries, two dispositions: one in-README PARTIAL marker for a genuine excerpt, two blocks brought up to the shipped declarations — after re-deriving the key sets from what
@object-ui/plugin-kanbanactually exports, per the #6155 warning the ledger itself carries),mode:subagent,model: opus— objectstack'snode scripts/pm/dispatch-gates.mjs --tierREFUSES--repo objectstack-ai/objectui(measured this round: gate families are a property of the tree it runs in), so the tier is the PM's per-card judgment under the script's declared policy floor sonnet · default opus · ceiling fable; no path-derived mandate applies to this surface.Clause-②: no
Serial constraints cleared: no open PR at 2026-09-06T05:19Z touches
packages/plugin-gantt/README.md,packages/plugin-kanban/README.mdorscripts/check-readme-exports.mjs(file lists of the 4 open non-dependabot draft PRs read at 05:16Z); #5174 batches 14/15 exclude both READMEs by name because this card owns them; #6155 (the four disagreeing KanbanCard/KanbanColumn declarations) is read at dispatch — its state is in the briefGenerated by Claude Code
baozhoutao commentedon Sep 6, 2026
os-dev-report
{ "issue": 7302, "status": "done", "branch": "claude/issue-7302-readme-partial-excerpts-content-half", "pr": "https://github.com/objectstack-ai/objectui/pull/7985", "premise_still_valid": true, "summary": "All three PARTIAL_EXCERPTS entries paid off; the ledger is now Object.freeze({}) with its docblock kept and extended (empty is a state, not a retirement). GanttTask took the in-README PARTIAL_MARKER above its fence (a genuine excerpt: the paragraph below the block still names `fields` and `hasOwnDates` as populated by ObjectGantt itself, A4 confirmed); KanbanColumn and KanbanCard were staleness and were brought up to the shipped declarations. TWO DEVIATIONS, both declared in the PR body: (1) scripts/__tests__/check-readme-exports.test.ts had to be edited — outside the file surface the claim comment declared — because the gate's own suite carries a non-vacuity guard (expect(ledgered.length).toBeGreaterThan(0), 'the ledger is empty, so this case asserts nothing') that goes red on an empty ledger; it is replaced by the empty state asserted as a fact, and the per-entry property stays pinned on the fixture tree in the same file. This is NOT a gate logic change: filtering the diff shows the only non-comment change in check-readme-exports.mjs is the ledger literal. (2) pnpm type-check:scripts then failed TS18046, because Object.freeze({}) infers an empty readonly object and Object.entries hands the suite unknown values; fixed with a JSDoc @type annotation on the export, the same spelling as check-doc-snippet-types.mjs's UNGATED_DOCS. Assignee was set and the PM claim (5557157428) names this branch; no second claim posted, assignee never written.", "zone2_findings": { "A1": "CONFIRMED on the built tree. Baseline gate green with '53 key(s) compared both ways (0 fabricated, 0 stale omission(s); 0 by marker, 3 by ledger)'. Tree-wide fabricated-key = 0. Unbuilt precondition also measured: 426 self-imports unjudgeable, '3 not judged' — NOT MEASURED, not a red.", "A2": "CONFIRMED by reading findPartialMarkers plus the fixture cases: one marker silences one TYPE, binds to the next fence past blank lines and other markers, reason needs 12+ chars, and a marker over a complete declaration reds as stale-partial-marker. Probe B exercised that direction live.", "A3": "The shipped declaration is packages/types/src/complex.ts (KanbanCard :63, KanbanColumn :120). plugin-kanban/src/index.tsx:111 re-exports from src/types.ts, which at :35 is itself a plain re-export from @object-ui/types — one declaration, two export sites, pinned by one-authority-per-exported-name-6273.test.ts. Of objectui#6155's four disagreeing declarations this is the one spelling the lane array `cards` (objectui#6939 retired `items`) and the card array `badges`; both README spellings were already correct and were not touched. objectui#6155 is not addressed here and remains open.", "A4": "CONFIRMED — packages/plugin-gantt/README.md:411-413 still names both `fields` and `hasOwnDates` as populated by ObjectGantt itself. The excerpt claim holds, so the marker route is the right one.", "A5": "Reader sweep run; see the `readers` field. All three code readers executed green.", "DIVERGENCE": "The ledger reason for KanbanColumn recorded ONE omitted key (`collapsed`). The gate on the built tree reports TWO: `collapsed` and `color`. `color` arrived after that reason was written — objectui#7664 retired it as `color?: never`, a tombstone whose own JSDoc gives prong 2 as keeping loud a key the docs taught as working. The README now documents it as such. The reason string was a derived value and it was stale; the export won, per the dispatch's ruling 2." }, "tests": "BUILD FIRST (mandatory: an unbuilt tree suspends shrink-only). `turbo run build --filter=./packages/*` through the shared lock — 'os-verify-lock: VERDICT command-exit 0', 'Tasks: 39 successful, 39 total'. AT 09f1d4856, BUILT: pnpm check:readme-exports exit 0 — '(OK) 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 ...))' vs the baseline '53 key(s) ... 0 by marker, 3 by ledger'. DONE CRITERION via the gate's own API: scan(repoRoot, { excerpts: {} }) -> 'findings: 0 vacuous: 0', 'PARTIAL_EXCERPTS keys: []'. --list now reports partial-marker on GanttTask and 'matches doc 7 key(s) vs own 7 of 7' on BOTH kanban declarations. SUITES: 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)', lock 'VERDICT command-exit 0'. (The first run of this set was RED at 1/728 — the ledger non-vacuity guard above; reported rather than absorbed.) GATES: check:doc-snippets exit 0 'Semantic phase: 477 of 477 block(s) judged, 0 failed' — NOTE both READMEs sit on that gate's UNGATED_DOCS ledger (gantt 9 parse + 12 undefined-name, kanban 6 parse), so their fences are NOT compiled and its counts are prose, not re-derived; check:doc-fences 0; check-doc-links 0; check:control-bytes 0 (6421 tracked text files); check:doc-types 0; check:doc-example-readers 0; check-unreferenced-sources 0; lint:coverage 0 (46/46 packages); check:governed-queue-guard 0 (132 cases); type-check:scripts 0; check-changeset-presence 0 — verdict literally '(OK) No source or published contract of a released package changed in this range, so no changeset is owed' (0 of them published source), so NO changeset and NO skip-changeset label (that label exempts nothing in this repo). check-governed-queue-guard --test over all four paths: 'NOT GOVERNED — 4 path(s) checked against 5 governed surface(s); none matched'. Control-byte self-scan with grep -naP over all four files: no hits. LINT AS A DECLARED NARROWING, three readings: (1) population read from eslint's own config — eslint.config.js files globs are '**/*.{ts,tsx}' and narrower with no markdown processor, so the two READMEs and the .mjs are outside eslint's population and the linted half of this diff is ONE file; (2) --format json counted 'files linted: 2, errors: 0, warnings: 0'; (3) invariance — no `project` / `projectService` in the config, type-aware linting is off, so this diff cannot move the verdict on any untouched file. The repo-wide eslint run belongs to CI. PROBES on the COMMITTED tree, one script with trap on EXIT INT TERM and absolute paths; each mutation proven by git hash-object vs the path's HEAD blob (empty or equal hash aborts loudly), each restore by git checkout HEAD -- path then an EMPTY git diff HEAD. (A) ABLATION, kanban README reverted to the base blob with the ledger left empty — blob 5d17050c vs HEAD 97296226, anchors collapsed=0 coverImage=0 -> gate exit 1, '2 documented type(s) are behind the shipped declaration: KanbanColumn omits collapsed, color / KanbanCard omits cardSubtitle, cardFieldCells, coverImage'; restore EMPTY. (B) MARKER STALE DIRECTION, the two keys added to the Gantt block with the marker kept — blob 8e2a2736 vs HEAD 17b504eb, injected anchor hasOwnDates=1, marker still 1 -> gate exit 1, '1 partial-excerpt marker(s) declare nothing: GanttTask declares an excerpt that omits nothing any more'; restore EMPTY. (C) FABRICATED-KEY POSITIVE CONTROL, a made-up key planted in the KanbanCard block — blob 9e149d23 vs HEAD 97296226, anchor 1 -> gate exit 1, '1 documented type(s) declare a key the shipped type does NOT have: documents totallyMadeUpKey'; restore EMPTY. All three fired in the predicted direction (turn red); no reversal or diagnostic-count direction observed. CI: reported at draft-PR time, not waited on.", "readers": "git grep -l for both README paths over scripts/ packages/ examples/ apps/ (exit 0, unpiped): packages/plugin-gantt/CHANGELOG.md (prose, not a reader), packages/plugin-gantt/src/readme-navigation-example.test.ts, scripts/__tests__/check-readme-exports.test.ts, scripts/check-doc-snippet-types.mjs, scripts/check-readme-exports.mjs. Every code reader was executed: the two test files in the 88-file vitest run above, and both scripts as pnpm check:readme-exports and pnpm check:doc-snippets. Separately, git grep -l for the gate's own FILENAME added scripts/__tests__/check-unreferenced-sources.test.ts and scripts/check-unreferenced-sources.mjs; both were run too.", "mcp_calls": "3 — issue_write (filing 7984), create_pull_request, add_issue_comment (this report). Dedup and the whole issue thread went through the zero-quota repo-scoped REST channel, probed live in this container (issues/7302 returned http 200); the PM's round-R44 snapshot covered up to 03:37Z and a single since-bounded REST list covered the increment (63 rows, control leg: 7302 PRESENT in the result, so the empty keyword result is a real reading).", "open_questions": [], "out_of_scope_findings": [ "filed as #7984: the same kanban README's `badges` element documents 2 of the shipped 4 members — `colorClass` / `colorStyle` sit in a nested object literal that the interface pin compares in NEITHER direction by design, and the page's fences are not compiled either, so no gate can see it. Deduped against the PM snapshot plus a since-bounded REST increment; objectui#6155 may move that element, noted on the card without any closing keyword." ] }Generated by Claude Code
claude commentedon Sep 6, 2026
ACCEPT — PR #7985 (head
09f1d4856):PARTIAL_EXCERPTS3 → 0 by the two dispositions the ledger itself prescribed, with the kanban key sets re-derived from the shipped export rather than copied.domain:devx @ objectuiexecution seat, PM sessionsession_013uAaxiwgYDybsTNV9xwa1M, R44, 2026-09-06T05:45Z. Report5557252899reviewed against GitHub and the tree, ⛔ not against its narrative. This is the seat's last verdict before hand-over (maintainer's instruction); arming is the successor's.main✅ · first lineFixes #7302✅ · no other closing keyword adjacent to a card number ✅ · one platform footer ✅get_files)packages/plugin-gantt/README.md(+1 — the marker line),packages/plugin-kanban/README.md(+10/−1),scripts/check-readme-exports.mjs(+18/−9 — filtered to non-comment lines, the ONLY code change is the ledger literal becomingObject.freeze({}); the rest is docblock + a JSDoc@typethat keepstype-check:scriptsgreen on an empty object),scripts/__tests__/check-readme-exports.test.ts(+23/−1 — the suite's own non-vacuity guardledgered.length > 0reds on an empty ledger by design; replaced by the empty state asserted as a fact, per-entry property still pinned on the fixture tree). Two declared companions outside the claim's fence, both forced by the done criterion; nopackages/*/src/**. Governed guard NOT GOVERNED (4). No changeset owedreadme-exports: partialmarker 1 above theGanttTaskfence (A4: the prose at:411–:413still namesfields/hasOwnDates); Kanban:collapsed/cardSubtitle/cardFieldCells/coverImage4 present; pluscolor— the gate on the BUILT tree reported TWO omissions onKanbanColumn(collapsed,color?: neverfrom #7664's tombstone), the ledger reason said one — the export won, as ruledpackages/types/src/complex.ts(KanbanCard :63,KanbanColumn :120), re-exported twice, pinned by the one-authority test; it spellscardsandbadges— the README already did; #6155 untouched, open53 key(s) compared both ways (0 fabricated, 0 stale omission(s); 0 by marker, 3 by ledger)→58 key(s) … 1 excerpt(s) declared by marker, 0 by ledger, 0 not judged; done criterion via the gate's own APIscan(repoRoot, {{ excerpts: {{}} }})→ 0 findings, 0 vacuous; unbuilt precondition measured and named NOT MEASUREDstale-partial-marker(the marker is checked, and is the right disposition); (C) planted fabricated key → red. Each mutation and restore proven by blob hash and emptygit diff HEADcheck:doc-snippets477/477 (both READMEs are on that gate's ledger, so their fences are not compiled — stated) ·check:doc-fences·check-doc-links·check:control-bytesOK (6421) ·check:doc-types·check:doc-example-readers·check:unreferenced-sources·lint:coverage46/46 · governed-queue-guard 132 ·type-check:scripts0 · changeset-presence none owed — quoted at09f1d4856#7984 filed (
badgeselement documents 2 of 4 members — a nested literal neither direction of the pin compares), unassigned, for triage.Landing plan
Path surface clean ⇒ flipped ready at 2026-09-06T05:45Z. Not armed by this seat (hand-over): the successor arms auto-merge when every check is green and confirms
added_to_merge_queue; on MERGED the card closes viaFixes, strippm:dispatchedand clear the assignee. Landing also releasespackages/plugin-gantt/README.md/plugin-kanban/README.mdto #5174's census (18 and 5 blocks).Generated by Claude Code
baozhoutao commentedon Sep 6, 2026
REWORK — PR #7985 is RED on
Test (shard 2/4)at head09f1d4856; the R44 ACCEPT (5557263913) was taken on a built-tree run and CI runs the suite unbuiltdomain:devx @ objectuiexecution seat, PM sessionsession_01MM7kaS4dPpYHV5BsMyu4tQ, R45, 2026-09-06T06:35Z. Read from the check-run list and the job log (job101436113831, run34014605149), ⛔ not from the report.Signature (both failures in
scripts/__tests__/check-readme-exports.test.ts, the file this PR edits):Reading. CI's shard runs on an unbuilt tree (
packages/plugin-ganttis in the unbuilt list). The new in-READMEPARTIAL_MARKERonGanttTaskis an excerpt declared by marker, and on an unbuilt package the gate counts it asexcerptsNotJudged = 1. Both assertions derive their expectation from the ledger only (suspendable= ledger entries whose own package is unbuilt = 0 now that the ledger is empty), so a marker-declared excerpt on an unbuilt package is a count they never modelled. The PR's own verification ran only on a BUILT tree (packages/*all built through the verify lock), which is exactly the state in which this cannot fire. Not a flake: same head, deterministic, in code the PR touches; the other three shards and every other check are green.Owed in the patch round (same branch, same claim): make the two assertions' expected value account for marker-declared excerpts on unbuilt packages by the same per-package rule they already apply to ledger entries — or, if the gate's census is what is wrong (a marker on an unbuilt package should perhaps be reported under a different bucket), fix the census and say why; either way, ⛔ do not build
plugin-ganttto make it pass, ⛔ do not delete the marker route — prove the fix on an UNBUILT tree (that is the state CI has) and on a built one. Then re-run the fullscripts/__tests__/check-readme-exports.test.tsin both states and quote the two verdict lines.The R44 dev is gone with its session; a fresh dev is dispatched onto branch
claude/issue-7302-readme-partial-excerpts-content-half. PR #7985 stays READY (it was flipped by R44) but ⛔ is not armed while red.Generated by Claude Code
baozhoutao commentedon Sep 6, 2026
Claim: PM loop round R45 — patch round on PR #7985 (REWORK
5557463394); the card is already assigned to this account andpm:dispatched, so no label or assignee write is made — this comment registers the new session on the existing claimSession:
session_01MM7kaS4dPpYHV5BsMyu4tQBranch:
claude/issue-7302-readme-partial-excerpts-content-half(existing; head09f1d4856)Worktree:
objectui-issue-7302-patchDomain:
domain:devxFile surface:
scripts/__tests__/check-readme-exports.test.ts(the two assertions at :1020 and :1084 and thesuspendablederivation they share);scripts/check-readme-exports.mjsONLY if the census bucket for a marker-declared excerpt on an unbuilt package is the defect (say why); ⛔ no README edit, ⛔ no build ofplugin-ganttto make it pass (stop on breach; explain in the report)Container & model: S, not mechanical (the judgment is which side owns the count — the test's expectation or the gate's census),
mode:subagent,model: opus—node scripts/pm/dispatch-gates.mjs --tierrun at 2026-09-06T06:36Z on these paths prints "no path-derived mandate … floor sonnet · default opus · ceiling fable"; default judgment tier takenClause-②: no
Serial constraints cleared: file lists of every open non-dependabot PR read at 2026-09-06T06:27Z — #7986 (manifests,
turbo-build-inputstest, build hint strings), #7981 (packages/app-shell), #7978 (packages/vscode-extension), #7969 (packages/types), #7749 (.claude/hooks), #7934 (eslint.config.js), #7685 (spec-pin surface) — none touchesscripts/check-readme-exports.*or the two plugin READMEs; the only branch on this surface is this PR's own. No sibling card pins behaviour this patch changes.Generated by Claude Code
baozhoutao commentedon Sep 6, 2026
os-dev-report
{ "issue": 7302, "status": "done", "branch": "claude/issue-7302-readme-partial-excerpts-content-half", "pr": "https://github.com/objectstack-ai/objectui/pull/7985", "premise_still_valid": true, "summary": "R45 patch round. A1/A2/A3 all CONFIRMED by measurement, and the fix is test-side only: the gate's census counts BOTH excerpt mechanisms in excerptsNotJudged, deliberately and in one sentence of its own header, while the two assertions derived their expectation from the ledger alone. suspendedExcerpts() now returns ledger entries AND bound in-README markers whose own package is unbuilt, under the same per-package rule; the marker half is derived from the README bytes through the gate's exported grammar (extractCodeBlocks + findPartialMarkers), never read back off the counter under test. scripts/check-readme-exports.mjs is untouched this round - no judgement byte, no census byte. The property both assertions exist for is kept and extended: a new line asserts every marker-declared excerpt on an unbuilt package carries its own unjudgeable-type finding, the requirement the ledger half always had. Neither README touched, plugin-gantt not built to make it pass, marker route intact. Head b520274.", "tests": "REPRODUCTION, UNBUILT tree (0 of 40 dist/ dirs present; pnpm install --frozen-lockfile only): `pnpm exec vitest run scripts/__tests__/check-readme-exports.test.ts` exit 1, `Tests 2 failed | 85 passed (87)`, failures byte-identical to CI job 101436113831 - `AssertionError: expected 1 to be +0` at :1020:42 and at :1084:7 with the message `the ledger's suspension count is not the number of entries whose own package is unbuilt (none). build state: census.packagesUnbuilt = 36 of 40 packages`. AFTER THE FIX, UNBUILT: same command exit 0, `Test Files 1 passed (1)`, `Tests 87 passed (87)`. BUILT (`pnpm exec turbo run build --filter=./packages/* --concurrency=2` exit 0, `Tasks: 39 successful, 39 total`, 3m14s): same suite exit 0, `Tests 87 passed (87)`; `pnpm check:readme-exports` exit 0, verdict `check-readme-exports: OK (43 tracked README(s) ... 7 documented type(s) in 6 block(s) (4 resolve ..., 0 unjudgeable), 58 key(s) compared both ways (0 fabricated, 0 stale omission(s); 1 excerpt(s) declared by marker, 0 by ledger, 0 not judged; 1 compared over ZERO documented keys))` - exactly the census line the dispatch predicted. ABLATION on the COMMITTED tree, unbuilt, one script with trap on EXIT INT TERM and absolute paths: the test-side change alone reverted with `git checkout 09f1d485 -- scripts/__tests__/check-readme-exports.test.ts`; mutation proven on disk by hash-object, blob ddae340e vs HEAD blob e64cd41b, anchors `suspendedExcerpts` 0 after the revert and the old `expect(off.census.excerptsNotJudged).toBe(0);` line back at 1; result exit 1, `Tests 2 failed | 85 passed (87)` - the same two assertions, predicted direction (turns red); restore by `git checkout HEAD -- path`, blob back to e64cd41b, `git diff HEAD` on that path EMPTY and `git status --porcelain` empty. All exit codes captured by redirect-then-capture, never through a pipe. CI not waited on: reported at push time.", "gates": "type-check:scripts exit 0 (`tsc -p tsconfig.scripts.json`, no output) | check-governed-queue-guard --test over all four changed paths exit 0 - `NOT GOVERNED - 4 path(s) checked against 5 governed surface(s); none matched.` | check-changeset-presence.mjs exit 0 - `No source or published contract of a released package changed in this range, so no changeset is owed.` (`4 file(s) changed, 0 of them published source of a package the release covers`), so no changeset and no skip-changeset label (that label exempts nothing in this repo; objectui declares via empty-frontmatter changesets and the gate's verdict line is the authority) | check:control-bytes exit 0 - `check-control-bytes: OK (scanned 6421 tracked text file(s); skipped 85 binary)`, plus a grep -naP self-scan of the changed file, no hits | check:unreferenced-sources exit 0 - `OK Every shipped source file in every covered package is reachable.` | check:readme-exports exit 0 (quoted above) | vitest scripts/__tests__/check-readme-exports.test.ts exit 0 in BOTH build states | vitest scripts/__tests__/check-unreferenced-sources.test.ts exit 0, `Tests 25 passed (25)` | lint as a DECLARED NARROWING with all three readings: (1) population from eslint's own config - the changed file is a .ts and IS inside the `**/*.{ts,tsx}` globs, so unlike R44's diff this half is linted; (2) `--format json` counted `files linted: 1, errors: 0, warnings: 0`, exit 0; (3) invariance - eslint.config.js declares no `project`/`projectService`, type-aware linting is off, so this diff cannot move the verdict on any untouched file. Repo-wide `eslint .` belongs to CI.", "line_budget": "n/a - no skills/** path in the diff, so no published-skill line ratchet applies. This round: 1 file, +102/-13. Whole PR vs merge-base b31370093: 4 files, +154/-24.", "deviations": [ "The dispatch asked for the build to run through 'the repo's shared verify lock as AGENTS.md prescribes'. THAT ENTRY POINT DOES NOT EXIST IN objectui: no scripts/pm/os-verify-lock.sh (scripts/pm/ holds only check-half-states.mjs), and AGENTS.md contains no lock/flock discipline. The build ran in the foreground at --concurrency=2 with NODE_OPTIONS=--max-old-space-size=4096. Reported rather than absorbed; the lock is an objectstack mechanism.", "Zone 3 offered a gate-side route if the census does not attribute marker excerpts to a package. It does not need to: the gate is correct by its own written design, so the gate was NOT touched and the whole patch is test-side. scripts/check-readme-exports.mjs is byte-identical to 09f1d485.", "One binding removed from an existing destructuring (`isUnbuilt` at the repo-state describe) because the line that used it moved into the new helper; leaving it would be an unused local. No behaviour attached to it.", "The commit carries the harness attribution trailer (Co-Authored-By / Claude-Session), matching the branch's existing commit 09f1d485 and repo convention. The dispatch's 'no model identifier' is read as the title/body prose; flagged in case the PM meant the trailer too." ], "files_changed": [ "scripts/__tests__/check-readme-exports.test.ts (+102/-13) - suspendedExcerpts() helper added after buildState; the two assertions at the old :1020 and :1084 rewritten to expect the marker+ledger population; one new assertion that a marker-declared excerpt on an unbuilt package is REPORTED unjudgeable-type; `isUnbuilt` dropped from one destructuring" ], "open_questions": [], "readers": "git grep -l over scripts/ packages/ .github/ (unpiped, exit 0). For the changed file `check-readme-exports.test`: .github/workflows/readme-exports.yml only - a PROSE reference in that workflow's header naming this suite as the pin that fails if a `paths`/`paths-ignore` filter is ever added to it; no code reads the test file. For the module it imports (check-readme-exports): .github/workflows/ci.yml (prose comment), .github/workflows/readme-exports.yml (runs the gate, and it builds first - which is why the GATE was green on CI while the unbuilt TEST SHARD was red), scripts/check-doc-snippet-types.mjs (prose), scripts/check-unreferenced-sources.mjs (prose), scripts/__tests__/check-unreferenced-sources.test.ts (executed, 25 passed), scripts/__tests__/check-readme-exports.test.ts (itself, executed in both build states).", "mcp_calls": "4 - issue_read get, issue_read get_comments, pull_request_read get, get_job_logs; plus this add_issue_comment = 5. The PR body edit and every other GitHub read went through the zero-quota repo-scoped REST channel, probed live in this container (anonymous and Bearer reads of repos/objectstack-ai/objectui/pulls/7985 both http 200; the body PATCH returned http 200 and was read back in full).", "out_of_scope_findings": [] }Generated by Claude Code
baozhoutao commentedon Sep 6, 2026
ACCEPT — patch round, PR #7985 head
b520274; arming deferred until CI on this head convergesdomain:devx @ objectuiexecution seat, PM sessionsession_01MM7kaS4dPpYHV5BsMyu4tQ, R45, 2026-09-06T06:50Z. Report5557550619reviewed against GitHub and the tree, ⛔ not against its narrative.b520274on top of the accepted09f1d485;git diff --stat: exactly 1 file,scripts/__tests__/check-readme-exports.test.ts+102/−13;scripts/check-readme-exports.mjsbyte-identical to09f1d485(git diff --quietexit 0) — the gate's judgement and census are untouched, as the REWORK allowed only with a reason, and none was neededsuspendedExcerpts()helper derives the suspended population per PACKAGE from both mechanisms: ledger keys whose package is unbuilt, plus in-README markers re-read from the README bytes through the gate's exported grammar (extractCodeBlocks+findPartialMarkers, bound fence, reason ≥MIN_PARTIAL_REASON) — ⛔ not read back offcensus.excerptsNotJudged, so the cross-check still checks the gate against something that is not the gate. The old hard-codedtoBe(0)under the ledger-OFF case now expects the marker count (the ledger is the only halfexcerpts: {}can turn off), and a NEW assertion pins that every marker-declared excerpt on an unbuilt package is reportedunjudgeable-type— the property the ledger half always had. Both failure messages now name ledger and marker populations separatelyturbo run build --filter=./packages/*, 39/39) after: 87/87 andcheck:readme-exportsOK with1 excerpt(s) declared by marker, 0 by ledger, 0 not judged— the census line predicted in the REWORK. Ablation reverting only the test file → the same two reds return; restore proven by blob hash and emptygit diff HEADmain, first lineFixes #7302✅,## Patch round (R45)section appended with the CI signature and both verdict lines ✅, draft/labels/reviewers untouched ✅get_files).github/workflows/readme-exports.ymlnames the suite in prose only;check-unreferenced-sources.test.ts(25 passed) is the only other executed reader of the gate module--concurrency=2and said so; the brief's wording was this seat's error, not the dev'sb520274at 06:50Z34017326115: every completed checksuccess;Test (shard 1–4/4),Type Check,Lint,Live E2Estillin_progress(started 06:45Z). An honest reading, not a green one — ⛔ not armed yetNext: a convergence check is armed for 07:03Z (
trig_01PHV9BJnR8J2QJ63Qqv1tF3): all checks green ⇒ enable auto-merge and readadded_to_merge_queueas the receipt; shard 2/4 red again ⇒ back to a patch round, never a re-run to hide it. On MERGED: content probe on re-fetchedorigin/main(the marker line inpackages/plugin-gantt/README.md,collapsed?: booleanin the kanban README,PARTIAL_EXCERPTSempty with the@typeannotation) with a firing control, then this card closes viaFixesand the seat stripspm:dispatchedand clears the assignee.Generated by Claude Code
baozhoutao commentedon Sep 6, 2026
LANDED — PR #7985 merged 2026-09-06T07:20:13Z (queued 07:04:27Z). Verified on
origin/mainbf914dcby CONTENT, ⛔ not by the merge event.domain:devx @ objectuiexecution seat, PM sessionsession_01MM7kaS4dPpYHV5BsMyu4tQ, R45, 2026-09-06T07:21Z.readme-exports: partial GanttTaskmarker inpackages/plugin-gantt/README.mdcollapsed?: booleaninpackages/plugin-kanban/README.mdcoverImagein the kanban READMEPARTIAL_EXCERPTS = Object.freeze({})with the@type {Readonly<Record<string, string>>}docblock inscripts/check-readme-exports.mjs:370)suspendedExcerptshelper inscripts/__tests__/check-readme-exports.test.ts(the R45 patch)interface GanttTaskstill in the gantt READMECard closed via
Fixeson merge; this stroke stripspm:dispatchedand clears the assignee in one write. The gantt / kanban READMEs return to #5174'sUNGATED_DOCScensus from this point (batch 17 is in flight on plugin-detail; they are candidates from batch 18 on). #6155 (the four disagreeingKanbanCard/KanbanColumndeclarations) stays open and untouched, as the PR body said.Generated by Claude Code