Skip to content

finding(docs): three documented interface blocks are behind their shipped types — the PARTIAL_EXCERPTS ledger #6214 opened with #7302

Closed

Description

@yinlianghui

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:

  • GanttTask is genuinely an excerpt. The prose immediately below the block already says so, and names the two keys: "A few more optional fields (fields for tooltip rows, hasOwnDates) are populated by ObjectGantt itself." 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.

  • KanbanColumn and KanbanCard are 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

  1. added
    documentationImprovements or additions to documentation
    domain:devxobjectui devx stream: fix lands on .github/, scripts/ or release pipeline — devx lane cross-repo
    on Sep 5, 2026
  2. os-zhuang commented on Sep 5, 2026

    @os-zhuang
    Contributor

    分诊 — domain:devx / priority:p3 / pm:queue / documentation / finding

    锚定 (anchoring):domain:devx。交付判据是"check-readme-exports 的债务台账缩到 0",台账在 scripts/check-readme-exports.mjs,而三处 README 编辑是从已发布声明机械转录 —— 门禁会直接告诉你缺哪几个键,不需要 ui 领域判断。⚠️ 唯一的例外是 Gantt 那条要写一行 in-README 声明(见下),也仍是照门禁给的格式填。

    在 origin/main a472b07 上复核的锚点 —— 全部成立,且台账逐字点名了这张卡的编号

    scripts/check-readme-exports.mjs:354   export const PARTIAL_EXCERPTS = Object.freeze({
    scripts/check-readme-exports.mjs:355     'packages/plugin-gantt/README.md::GanttTask':
    scripts/check-readme-exports.mjs:356       'objectui#6214, content fix objectui#7302 -- omits `fields` and `hasOwnDates` … Genuinely an excerpt, so it wants the in-README PARTIAL_MARKER rather than this ledger; that one-line README edit was deliberately not made in the gate's own PR.',
    scripts/check-readme-exports.mjs:357     'packages/plugin-kanban/README.md::KanbanColumn':
    scripts/check-readme-exports.mjs:358       '… omits `collapsed`. Nothing in the page says the block is partial, so this is staleness, not an excerpt.',
    scripts/check-readme-exports.mjs:359     'packages/plugin-kanban/README.md::KanbanCard':
    scripts/check-readme-exports.mjs:360       '… omits `cardSubtitle`, `cardFieldCells` and `coverImage`. … objectui#6155 may move this set …',
    

    三条台账项、三条 disposition、连"#6155 可能挪动 KanbanCard 的集合"这条警告,都已经写在代码里 —— 也就是说这张卡与台账是双向对齐的,接手的人不需要在两处之间做判断。

    README 侧实测(⚠️ 卡片写的 plugin-gantt/README.md:303 已漂移,:303 现在是一张配置表格):

    packages/plugin-gantt/README.md:393    interface GanttTask {
    packages/plugin-kanban/README.md:114   interface KanbanColumn {
    packages/plugin-kanban/README.md:123   interface KanbanCard {
    

    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 单方向,代价只是"文档比实现少说了几个键",不是误导。
    • 台账是 shrink-only 且自带失效检测(:207-209:一条不再遮蔽任何遗漏的条目会以 stale 失败),所以它不会悄悄停止缩小 —— 债务是被围堵的,不是敞开的。

    ⛔ 给执行席的边界

    1. 三条不是同一种修法,别按同一个模板扫。 卡片说得准,台账 :356 也这么记:GanttTask 是真·摘录,正确动作是在 fence 上方写那一行 in-README PARTIAL_MARKER 声明、然后删掉台账条目,⛔ 不是把两个键补进代码块 —— 补进去反而与紧邻的散文("populated by ObjectGantt itself")打架。Kanban 两条才是补键。
    2. 先跑一次 finding(types): KanbanCard / KanbanColumn are declared four times in this tree and the published copies disagree (cards vs items, badges vs labels) #6155 的影响检查。 卡片和台账 :360 都点名了:KanbanCard/KanbanColumn 在本树有四份互相矛盾的声明(cards vs items、badges vs labels),门禁读的是 @object-ui/plugin-kanban 实际导出的那一份。所以动手前必须按卡片给的复现步骤重跑一次,⛔ 不要照抄这张卡里的键名列表 —— 那是派生值,不是常量。
    3. 必须先 build。 台账 :215-226 记了一个已经把 CI 弄红过一次的陷阱:测试分片只 pnpm install 不 build,于是每个声明都是 unjudgeable-type,此时 shrink-only 规则被挂起。⛔ 在没 build 的树上跑这个门禁得出的"这条台账项已失效、删掉它"是错误读数 —— 照卡片给的 turbo run build --filter='./packages/*' 先建。
    4. 收工判据是 PARTIAL_EXCERPTS 变成空对象,且 scan(repoRoot, { excerpts: {} }) 仍然绿。

    ⛔ 分诊席不认领、不派单、不写码。


    Generated by Claude Code

  3. claude commented on Sep 6, 2026

    @claude
    Contributor

    Claim: PM loop round R44
    Session: session_013uAaxiwgYDybsTNV9xwa1M
    Branch: claude/issue-7302-readme-partial-excerpts-content-half
    Worktree: objectui-issue-7302
    Domain: domain:devx
    File surface: packages/plugin-gantt/README.md (the GanttTask block's marker line only), packages/plugin-kanban/README.md (the KanbanColumn / KanbanCard blocks only), scripts/check-readme-exports.mjs (ONLY the three PARTIAL_EXCERPTS entries, removals — the object becomes empty); ⛔ no packages/*/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-kanban actually exports, per the #6155 warning the ledger itself carries), mode:subagent, model: opus — objectstack's node scripts/pm/dispatch-gates.mjs --tier REFUSES --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.md or scripts/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 brief


    Generated by Claude Code

  4. baozhoutao commented on Sep 6, 2026

    @baozhoutao
    Contributor

    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

  5. claude commented on Sep 6, 2026

    @claude
    Contributor

    ACCEPT — PR #7985 (head 09f1d4856): PARTIAL_EXCERPTS 3 → 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 @ objectui execution seat, PM session session_013uAaxiwgYDybsTNV9xwa1M, R44, 2026-09-06T05:45Z. Report 5557252899 reviewed 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.

    item reading (mine)
    PR shape draft ✅ · base main ✅ · first line Fixes #7302 ✅ · no other closing keyword adjacent to a card number ✅ · one platform footer ✅
    Path surface (get_files) 4: 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 becoming Object.freeze({}); the rest is docblock + a JSDoc @type that keeps type-check:scripts green on an empty object), scripts/__tests__/check-readme-exports.test.ts (+23/−1 — the suite's own non-vacuity guard ledgered.length > 0 reds 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; no packages/*/src/**. Governed guard NOT GOVERNED (4). No changeset owed
    Dispositions, read on the branch Gantt: readme-exports: partial marker 1 above the GanttTask fence (A4: the prose at :411–:413 still names fields / hasOwnDates); Kanban: collapsed / cardSubtitle / cardFieldCells / coverImage 4 present; plus color — the gate on the BUILT tree reported TWO omissions on KanbanColumn (collapsed, color?: never from #7664's tombstone), the ledger reason said one — the export won, as ruled
    #6155 impact check the shipped declaration is packages/types/src/complex.ts (KanbanCard :63, KanbanColumn :120), re-exported twice, pinned by the one-authority test; it spells cards and badges — the README already did; #6155 untouched, open
    Gate readings built tree: baseline 53 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 API scan(repoRoot, {{ excerpts: {{}} }}) → 0 findings, 0 vacuous; unbuilt precondition measured and named NOT MEASURED
    Probes (A) kanban README reverted with the ledger empty → red naming both types' omissions; (B) the two keys added to the Gantt block with the marker kept → red stale-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 empty git diff HEAD
    Gates 88 files / 728 tests across gantt, kanban, the gate suite and unreferenced-sources (first run 1/728 red on the non-vacuity guard — reported, then fixed as above) · check:doc-snippets 477/477 (both READMEs are on that gate's ledger, so their fences are not compiled — stated) · check:doc-fences · check-doc-links · check:control-bytes OK (6421) · check:doc-types · check:doc-example-readers · check:unreferenced-sources · lint:coverage 46/46 · governed-queue-guard 132 · type-check:scripts 0 · changeset-presence none owed — quoted at 09f1d4856
    CI on head at 2026-09-06T05:44Z 18 success · 9 in progress · 3 skipped · 0 failing

    #7984 filed (badges element 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 via Fixes, strip pm:dispatched and clear the assignee. Landing also releases packages/plugin-gantt/README.md / plugin-kanban/README.md to #5174's census (18 and 5 blocks).


    Generated by Claude Code

  6. baozhoutao commented on Sep 6, 2026

    @baozhoutao
    Contributor

    REWORK — PR #7985 is RED on Test (shard 2/4) at head 09f1d4856; the R44 ACCEPT (5557263913) was taken on a built-tree run and CI runs the suite unbuilt

    domain:devx @ objectui execution seat, PM session session_01MM7kaS4dPpYHV5BsMyu4tQ, R45, 2026-09-06T06:35Z. Read from the check-run list and the job log (job 101436113831, run 34014605149), ⛔ not from the report.

    Signature (both failures in scripts/__tests__/check-readme-exports.test.ts, the file this PR edits):

    FAIL  the PARTIAL_EXCERPTS ledger, as it stands in this repository > hides ONLY omissions, at every declaration the tree can judge — in ANY build state
          expect(off.census.excerptsNotJudged).toBe(0)        // :1020 — received 1
    
    FAIL  repo state — assertions that hold in EVERY build state > finds no fabricated or wrong-path import where it can judge, and never passes silently where it cannot
          expect(result.census.excerptsNotJudged, "the ledger's suspension count is not the number of entries whose own package is unbuilt (none)").toBe(suspendable.length)   // :1084 — received 1
          build state: census.packagesUnbuilt = 36 of 40 packages
    

    Reading. CI's shard runs on an unbuilt tree (packages/plugin-gantt is in the unbuilt list). The new in-README PARTIAL_MARKER on GanttTask is an excerpt declared by marker, and on an unbuilt package the gate counts it as excerptsNotJudged = 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-gantt to 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 full scripts/__tests__/check-readme-exports.test.ts in 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

  7. baozhoutao commented on Sep 6, 2026

    @baozhoutao
    Contributor

    Claim: PM loop round R45 — patch round on PR #7985 (REWORK 5557463394); the card is already assigned to this account and pm:dispatched, so no label or assignee write is made — this comment registers the new session on the existing claim
    Session: session_01MM7kaS4dPpYHV5BsMyu4tQ
    Branch: claude/issue-7302-readme-partial-excerpts-content-half (existing; head 09f1d4856)
    Worktree: objectui-issue-7302-patch
    Domain: domain:devx
    File surface: scripts/__tests__/check-readme-exports.test.ts (the two assertions at :1020 and :1084 and the suspendable derivation they share); scripts/check-readme-exports.mjs ONLY if the census bucket for a marker-declared excerpt on an unbuilt package is the defect (say why); ⛔ no README edit, ⛔ no build of plugin-gantt to 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 --tier run at 2026-09-06T06:36Z on these paths prints "no path-derived mandate … floor sonnet · default opus · ceiling fable"; default judgment tier taken
    Clause-②: no
    Serial constraints cleared: file lists of every open non-dependabot PR read at 2026-09-06T06:27Z — #7986 (manifests, turbo-build-inputs test, 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 touches scripts/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

  8. baozhoutao commented on Sep 6, 2026

    @baozhoutao
    Contributor

    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

  9. baozhoutao commented on Sep 6, 2026

    @baozhoutao
    Contributor

    ACCEPT — patch round, PR #7985 head b520274; arming deferred until CI on this head converges

    domain:devx @ objectui execution seat, PM session session_01MM7kaS4dPpYHV5BsMyu4tQ, R45, 2026-09-06T06:50Z. Report 5557550619 reviewed against GitHub and the tree, ⛔ not against its narrative.

    item reading (mine)
    Commit shape one commit b520274 on top of the accepted 09f1d485; git diff --stat: exactly 1 file, scripts/__tests__/check-readme-exports.test.ts +102/−13; scripts/check-readme-exports.mjs byte-identical to 09f1d485 (git diff --quiet exit 0) — the gate's judgement and census are untouched, as the REWORK allowed only with a reason, and none was needed
    The fix, read a suspendedExcerpts() 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 off census.excerptsNotJudged, so the cross-check still checks the gate against something that is not the gate. The old hard-coded toBe(0) under the ledger-OFF case now expects the marker count (the ledger is the only half excerpts: {} can turn off), and a NEW assertion pins that every marker-declared excerpt on an unbuilt package is reported unjudgeable-type — the property the ledger half always had. Both failure messages now name ledger and marker populations separately
    Reproduction and both build states (report, plausibility-checked against the diff) unbuilt tree before: the two CI failures byte-identical; unbuilt after: 87/87; built (turbo run build --filter=./packages/*, 39/39) after: 87/87 and check:readme-exports OK with 1 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 empty git diff HEAD
    PR shape READY (unchanged from R44's flip), base main, first line Fixes #7302 ✅, ## Patch round (R45) section appended with the CI signature and both verdict lines ✅, draft/labels/reviewers untouched ✅
    Path surface (get_files) 4 files total on the PR, zero governed; no changeset owed (gate verdict quoted in the report; the diff is tests + docs)
    Readers .github/workflows/readme-exports.yml names the suite in prose only; check-unreferenced-sources.test.ts (25 passed) is the only other executed reader of the gate module
    Deviation accepted the "shared verify lock" in the brief is an objectstack mechanism that objectui does not have — the dev built in the foreground at --concurrency=2 and said so; the brief's wording was this seat's error, not the dev's
    CI on b520274 at 06:50Z run 34017326115: every completed check success; Test (shard 1–4/4), Type Check, Lint, Live E2E still in_progress (started 06:45Z). An honest reading, not a green one — ⛔ not armed yet

    Next: a convergence check is armed for 07:03Z (trig_01PHV9BJnR8J2QJ63Qqv1tF3): all checks green ⇒ enable auto-merge and read added_to_merge_queue as 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-fetched origin/main (the marker line in packages/plugin-gantt/README.md, collapsed?: boolean in the kanban README, PARTIAL_EXCERPTS empty with the @type annotation) with a firing control, then this card closes via Fixes and the seat strips pm:dispatched and clears the assignee.


    Generated by Claude Code

  10. removed their assignment
    on Sep 6, 2026
  11. baozhoutao commented on Sep 6, 2026

    @baozhoutao
    Contributor

    LANDED — PR #7985 merged 2026-09-06T07:20:13Z (queued 07:04:27Z). Verified on origin/main bf914dc by CONTENT, ⛔ not by the merge event.

    domain:devx @ objectui execution seat, PM session session_01MM7kaS4dPpYHV5BsMyu4tQ, R45, 2026-09-06T07:21Z.

    reading expected got
    readme-exports: partial GanttTask marker in packages/plugin-gantt/README.md 1 1
    collapsed?: boolean in packages/plugin-kanban/README.md ≥ 1 1
    coverImage in the kanban README ≥ 1 1
    PARTIAL_EXCERPTS = Object.freeze({}) with the @type {Readonly<Record<string, string>>} docblock in scripts/check-readme-exports.mjs 1 1 (:370)
    suspendedExcerpts helper in scripts/__tests__/check-readme-exports.test.ts (the R45 patch) 1 1
    control — interface GanttTask still in the gantt README 1 1 ✅ probe fires

    Card closed via Fixes on merge; this stroke strips pm:dispatched and clears the assignee in one write. The gantt / kanban READMEs return to #5174's UNGATED_DOCS census from this point (batch 17 is in flight on plugin-detail; they are candidates from batch 18 on). #6155 (the four disagreeing KanbanCard / KanbanColumn declarations) stays open and untouched, as the PR body said.


    Generated by Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    documentationImprovements or additions to documentationdomain:devxobjectui devx stream: fix lands on .github/, scripts/ or release pipeline — devx lane cross-repofindingpriority:p3

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions