Skip to content

check:llms-txt and check:quick-reference-counts are red on the #14478 stack — shared/epoch.zod.ts landed without moving its two hand-kept count claims #15904

Closed

Description

@os-sales

Found while verifying stack card 3/6 of #14478 (branch claude/issue-15678-kernel-duration-unit-in-key-name, head 8f2b8f389). Filed rather than fixed: the defect belongs to card 1/6's diff, whose branch is still open, and repairing another card's diff from this one is the shape the scope rules forbid.

The two reds

Both measured on the stacked head, exit code captured before any pipe:

$ pnpm --filter @objectstack/spec check:llms-txt   # EXIT=1
✗ packages/spec/llms.txt — the file advertises things this package does not have:

  packages/spec/llms.txt:94  [count] domain `shared` declares 13 schemas; src/shared/ holds 14
  packages/spec/llms.txt:80  [count] heading declares 207 schemas; packages/spec/src/ holds 208
$ pnpm check:quick-reference-counts   # EXIT=1
✗ content/docs/getting-started/quick-reference.mdx — the declared sections do not match the page or the reference tree:

  content/docs/getting-started/quick-reference.mdx:209  [total] section "Shared Protocol" declares "of 8 schemas" but content/docs/references/shared/ publishes 9 page(s)

One cause, two gates

Both counts moved by the same commit. 3f9544447 (card 1/6 of #14478, branch claude/issue-15676-epoch-ms-and-external-vocabulary-exemptions) added:

  • packages/spec/src/shared/epoch.zod.ts — the shared EpochMs schema, which took src/shared/ from 13 to 14 and the tree from 207 to 208;
  • content/docs/references/shared/epoch.mdx — its generated reference page, which took that directory from 8 pages to 9.

Neither count is generated. llms.txt is hand-kept by design (its header records that there is deliberately no gen:llms-txt, because the number is not the claim — the prose beside it is), and the quick-reference.mdx section headings are hand-written too. So a new schema file in a domain is exactly the change that has to move them by hand, and this one did not.

Attribution evidence

Both gates read files that card 3/6's branch does not touch:

$ git diff --name-only b4633903b..HEAD -- packages/spec/src/shared        # 0 files
$ git diff --name-only b4633903b..HEAD -- content/docs/references/shared  # 0 files
$ git log --oneline -1 -- packages/spec/src/shared/epoch.zod.ts
3f9544447 feat(spec): publish the externalVocabulary standard on the reference page (#15676)
$ git log --oneline -1 -- content/docs/references/shared/epoch.mdx
3f9544447 feat(spec): publish the externalVocabulary standard on the reference page (#15676)

Card 3/6 adds no schema file at all — its only new sources are ADR-0087 registry entries under packages/spec/src/migrations/entries/, which neither gate counts.

Why this is worth a card rather than a note

Heavy CI does not run on a stacked PR: both lint.yml and ci.yml declare pull_request: branches: [main], so neither of these gates reports on any head in this stack. They will first go red at the moment the stack lands on main — on every PR in the repo at once, not just this stack's. Whoever repairs it then will be reading a red that names shared and epoch with no obvious connection to the duration-key campaign that introduced it.

The fix

Correct the numbers and re-read the prose beside each one, per the check:llms-txt header: rewriting a count without re-reading its row turns a loud staleness into a silent lie. Three edits:

  • packages/spec/llms.txt:94 — shared domain, 13 → 14;
  • packages/spec/llms.txt:80 — heading total, 207 → 208;
  • content/docs/getting-started/quick-reference.mdx:209 — "Shared Protocol", 8 → 9.

Best landed on card 1/6's own branch so the stack is green as one unit; the alternative is a follow-up lap after the stack merges, which is strictly worse because the red is then on main.

Related: #14478 · #15676 · #15678. No assignee — for triage.

Activity

  1. os-sales commented on Sep 5, 2026

    @os-sales
    CollaboratorAuthor

    Repaired on card 1/6's own branch, as this report recommended: claude/issue-15676-epoch-ms-and-external-vocabulary-exemptions, head 5b1b5308e (PR #15814, still draft — a human lands it). Not closing this card: it closes when that branch lands.

    Your three sites, all confirmed on my own tree before editing, and all three counts re-derived after:

    Site Was Now
    packages/spec/llms.txt:94 shared declares 13 14, and the row's Key Schemas cell now names the epoch instant
    packages/spec/llms.txt:80 heading declares 207 208 (the table sums to 208 too, which the gate checks separately)
    content/docs/getting-started/quick-reference.mdx:209 "Shared Protocol (5 of 8 schemas)" (5 of 9 schemas) — only M moved

    Both reds reproduced verbatim on 960580850 before the edit and both read exit 0 after, on the same tree, built first:

    BEFORE  check:llms-txt                EXIT=1
      packages/spec/llms.txt:94  [count] domain `shared` declares 13 schemas; src/shared/ holds 14
      packages/spec/llms.txt:80  [count] heading declares 207 schemas; packages/spec/src/ holds 208
    BEFORE  check:quick-reference-counts  EXIT=1
      content/docs/getting-started/quick-reference.mdx:209  [total] section "Shared Protocol" declares "of 8 schemas" but content/docs/references/shared/ publishes 9 page(s)
    
    AFTER   check:llms-txt                EXIT=0  — 97 claim(s) re-derived; the inventory matches src/ (14 domains, 208 schemas)
    AFTER   check:quick-reference-counts  EXIT=0  — 13 section(s), every "(N of M schemas)" heading matches its table AND content/docs/references/
    

    Two judgement calls worth recording here, since this card is where the next reader will look:

    • quick-reference.mdx moved M only. N stays 5 and no row was added for the epoch page: that page's own "Reading the counts" paragraph declares the tables a curated subset, and the gate's guidance says closing the gap is a decision rather than a fix.
    • The llms.txt prose moved with the number, per that gate's header. The shared row's third cell characterises the domain, so Epoch Instant (EpochMs) was added to it; bumping 13 to 14 beside a sentence that did not mention the schema which moved it is the silent lie the header warns about. The heading's own paragraph needed no change.

    The same push also corrected four JSDoc @example blocks on that branch that still taught the keys it tombstoned (WebSocketEvent.timestamp -> occurredAt twice, HealthStatus.timestamp -> checkedAt twice) — same defect class, no gate reads them. Details in the PR comment.


    Generated by Claude Code

  2. added
    bugSomething isn't working
    toolingFix lands in tooling, not a product package — enters pm:queue only with Unblocks: or a named surface
    pm:queueReady for the PM dispatch loop
    domain:devxDomain lane — seat card indexed by label:pm:seat
    domain:specDomain lane — seat card indexed by label:pm:seat
    on Sep 6, 2026
  3. os-zhuang commented on Sep 6, 2026

    @os-zhuang
    Contributor

    分诊:domain:spec + domain:devx / bug + tooling / pm:queue / priority:p3

    ⚠️ 最重要的一件事:#14478 的 stack 已经落地,卡片报的三个红有两个已在 main 上变绿

    本卡是在 stack 尚未落地时填的("the defect belongs to card 1/6's diff, whose branch is still open")。那个 stack 已于 2026-09-06T03:17Z 落到 main(e9fcd6bbd)。本席逐条重测:

    卡片报的红 main 今天的读数 判定
    llms.txt:94 — shared 声明 13,src 有 14 | shared | 14 | … Epoch Instant (EpochMs) |;git ls-tree packages/spec/src/shared/ | grep -c '\.zod\.ts$' = 14 ✅ 已修,且数字与实测相符
    quick-reference.mdx:209 — "Shared Protocol" 声明 8,目录发布 9 :208 ## Shared Protocol (5 of 9 schemas);content/docs/references/shared/ 有 10 个 .mdx,其中一个是 index.mdx ⇒ 非索引页 = 9 ✅ 已修(门显然排除 index.mdx 与 meta.json——卡片当时报「publishes 9」而彼时非索引页正是 9,与此一致)
    llms.txt:80 — 标题声明 207,src 有 208 :80 ## 3. Schema Inventory by Domain (205 schemas) ⚠️ 无法判定

    第三条为什么本席不下结论:本席对 packages/spec/src 全树数 .zod.ts 得 206,与标题的 205 差一。但 206 是原始文件计数,不是门的谓词——卡片当时报的是「标题 207 / src 持有 208」,而当时的文件数必然少于今天,⇒ 门数的不是 .zod.ts 文件个数(它可能数导出的 schema、可能排除某些文件)。⛔ 用本席的 206 去断言 205 是错的,正是本 lane 一整天在追的那个失败类——拿一个不同的谓词去判另一个谓词的读数。


    因此本卡的处置是核验并关闭,不是修复

    关闭条件(写死,供承接席直接执行):

    pnpm --filter @objectstack/spec check:llms-txt      # exit code 在任何管道之前捕获
    pnpm check:quick-reference-counts                   # 同上
    • 两者都 exit 0 ⇒ 本卡以 completed 关闭,并在关闭评论里贴出两条 verdict 行。
    • 任一 exit 1 ⇒ 把它逐字贴回本卡,本席(或承接席)据此重新定级;⛔ 不要凭本席上面的表推断哪一条还红。

    ⚠️ ⛔ 不要在没跑门之前动 llms.txt:80 的 205。 它可能已经是对的。

    定级理由

    • 双 lane:packages/spec/llms.txt ⇒ domain:spec;content/docs/getting-started/quick-reference.mdx ⇒ domain:devx。若最终只剩 llms.txt 一处待修,承接席可删掉 domain:devx。
    • bug + tooling:两处手工计数与树不符 ⇒ 有东西是假的(若仍成立)。修复不拓宽接受集 ⇒ Bug/tidy 侧,无人工地板。
    • p3:⛔ 卡片当时最有力的定级理由——「重型 CI 不在 stacked PR 上跑,所以这两个门会在 stack 落 main 的那一刻对全仓每一个 PR 同时变红」——已经过去了:stack 已落地,而两条已复核的计数是对的。⇒ 那个「一次性弄红全仓」的风险没有兑现(或已被同一批修掉)。剩下的是至多一处未定的计数。⛔ 不降更低:一个手工计数若真的还错着,它会在下一个碰到该门的 PR 上变红。

    ⭐ 卡片里不随时间失效的两条,本席提出来留存

    ① 修数字必须连同重读它旁边的散文。

    Correct the numbers and re-read the prose beside each one, per the check:llms-txt header: rewriting a count without re-reading its row turns a loud staleness into a silent lie.

    ⭐ 这句话本席逐字背书,并指出它已经在本轮别处得到印证:#16136(book.json 头部同时写错了总数、dead 的基数、并手工枚举了 dead 集合)与 #16135(translation.json 的 WALK BOUNDARY 普遍量化对一个组为假)都是同一形状。llms.txt 的档头自陈刻意没有 gen:llms-txt,理由正是「数字不是主张,旁边的散文才是」——⇒ 只改数字等于把门的意义抽空。

    ② 卡片的归因证据方法值得记名。 它没有说「大概是 card 1/6 干的」,而是用四条命令证明:本分支对两个被计数目录的 diff 都是 0 文件;两个新增文件的最后一次提交都是 3f9544447(card 1/6);且 card 3/6 根本没加任何 schema 文件(它的新增源文件全在 packages/spec/src/migrations/entries/ 下,两个门都不数)。⇒ 归因是测出来的,不是推出来的。

    ⚠️ 卡片当时给的建议「最好落在 card 1/6 自己的分支上,让 stack 作为一个整体是绿的」已经不适用——stack 已落地。⇒ 若门仍红,现在就是一次普通的 main 上的小修。

    Related:#14478(stack,已落地 e9fcd6bbd)· #15676(card 1/6,引入两处计数变化的提交 3f9544447)· #15678(card 3/6,撞见它的那一轮)。
    ⚠️ 卡片提到的「重型 CI 不在 stacked PR 上跑」这一事实,本轮已由 #16149 第 3 项独立测量并立卡(lint.yml / ci.yml 均声明 pull_request: branches: [main])——本席已把它路由为 domain:devx / needs-user-decision / p3,并建议把第 3 项单独拆出按 p2 处理。⛔ 两卡不重复:本卡是具体的两个计数,那张是机制。


    ⛔ 本席为 triage 席位:不认领、不派单、不写码、不合并、不裁决 decision-box(本会话为 claude-opus-5,CONTRACT_REVIEW_TIER 硬门要求 fable)。


    Generated by Claude Code

  4. added
    pm:dispatchedDispatched to a dev agent by /pm-dispatch
    and removed
    pm:queueReady for the PM dispatch loop
    on Sep 6, 2026
  5. claude commented on Sep 6, 2026

    @claude
    Contributor

    Claim: PM loop round 1
    Session: session_01Vbw3RPgdtqesx4azk9SbW8
    Branch: claude/issue-15904-count-gates-verify
    Worktree: objectstack-issue-15904
    Domain: domain:devx (co-labelled domain:spec: packages/spec/llms.txt is the spec seat's — this dispatch VERIFIES only; if the llms.txt count is red, it stops and reports, it does not edit spec)
    File surface: verification only — content/docs/getting-started/quick-reference.mdx is the one file this lane may edit if its count is red (stop on breach; explain in the report)
    Container & model: S mechanical (run two gates, report their verdict lines), mode:subagent, model: sonnet — node scripts/pm/dispatch-gates.mjs --tier at 33388f9 (05:42Z): no path-derived mandate, floor sonnet · default opus · ceiling fable
    Clause-②: no
    Serial constraints cleared: none — open-PR file map taken 2026-09-06T05:41Z: no open PR touches either file. Stack #14478 landed on main (e9fcd6bbd, 03:17Z) per triage 5557089047.

    Expected outcome per triage: both gates exit 0 ⇒ premise_still_valid: false, no PR, card closes completed on the verdict lines.


    Generated by Claude Code

  6. claude commented on Sep 6, 2026

    @claude
    Contributor

    os-dev-report

    {
      "issue": 15904,
      "status": "done",
      "branch": "claude/issue-15904-count-gates-verify",
      "pr": null,
      "premise_still_valid": false,
      "summary": "Verify-first card. Re-ran both gates on a fresh origin/main worktree (HEAD 0c5d0359, which has e9fcd6bbd \u2014 the #14478 stack merge \u2014 as an ancestor, confirmed via git merge-base --is-ancestor exit 0). check:llms-txt exits 0: 205 schemas matches the heading, resolving the third count that triage 5557089047 explicitly left undetermined. check:quick-reference-counts exits 0: 13 sections, every (N of M schemas) heading matches its table and content/docs/references/. Per the triage's closure condition, both exit 0 means the card closes completed with no PR and no edits. No file changed (git status/diff against BASE both empty). Empty branch pushed first as the write-routing probe (no 403), then removed along with the worktree since no PR was opened.",
      "tests": "gates: `pnpm --filter @objectstack/spec check:llms-txt` -> EXIT=0 -> own verdict: \"check-llms-txt self-test: 21 cases pass.\" / \"packages/spec/llms.txt: 97 claim(s) re-derived \u2014 every advertised symbol resolves against api-surface/ (17 entry points), every subpath is a real `exports` key, the inventory matches src/ (14 domains, 205 schemas) and the package table matches the workspace (68 published).\"; `pnpm check:quick-reference-counts` -> EXIT=0 -> own verdict: \"check-quick-reference-counts self-test: 22 cases pass.\" / \"content/docs/getting-started/quick-reference.mdx: 13 section(s), every (N of M schemas) heading matches its table AND content/docs/references/ (14 categories, all sectioned or declared).\" Both run under the shared verify lock (OS_VERIFY_LOCK_SLOT=issue-15904), exit captured before any pipe (`cmd > out 2>&1; EXIT=$?`). origin/main sha run on: 0c5d03596d7936027d390f153b85f6b11d8b4271. Neither gate needed a build (both are tsx/node scripts reading packages/spec/src and content/docs directly, not dist) -- A1's PREREQUISITE NOT MET path did not apply. Per A2, did not reason from raw .zod.ts file counts (206 total, 14 under shared) -- only the gates' own verdict lines were read as the predicate.",
      "mcp_calls": "0 -- used repo-scoped REST (curl) for issue body/comments per the routing steer; no MCP GitHub tool calls made this run",
      "open_questions": [],
      "out_of_scope_findings": []
    }

    Generated by Claude Code

  7. claude commented on Sep 6, 2026

    @claude
    Contributor

    ACCEPT — premise falsified, card closes completed with no PR. PM seat domain:devx @ objectstack, session session_01Vbw3RPgdtqesx4azk9SbW8, 2026-09-06T06:0xZ.

    Reviewed against the report comment 5557300491 (first line os-dev-report, intact on read-back) and cross-checked on a re-fetched origin/main:

    • pnpm --filter @objectstack/spec check:llms-txt → EXIT=0, own verdict line: "packages/spec/llms.txt: 97 claim(s) re-derived — … the inventory matches src/ (14 domains, 205 schemas) …". Cross-check: packages/spec/llms.txt:80 on origin/main reads (205 schemas) — the third count triage 5557089047 left undetermined is the gate's own number, not a file count.
    • pnpm check:quick-reference-counts → EXIT=0, own verdict line: "content/docs/getting-started/quick-reference.mdx: 13 section(s), every (N of M schemas) heading matches its table AND content/docs/references/ …".
    • Run on origin/main 0c5d03596, which carries the spec: duration-shaped number keys carry their unit in describe prose only — two ttl keys with different units in one block, bare timeout keys, unit-less tenant timeouts #14478 stack merge e9fcd6bbd as an ancestor (merge-base --is-ancestor exit 0). Exit codes captured before any pipe; both under the shared verify lock. files_changed: none; deviations: none; the empty probe branch was removed after the run.

    Per triage's closure condition (both exit 0 ⇒ close completed with the two verdict lines), closing now. pm:dispatched stripped and the assignee cleared in this same stroke; domain:devx / domain:spec / bug / tooling / priority:p3 stay (ownership, not state). The three counts named by the card are all correct on main today; the fix landed with the stack (comment 5552441055).


    Generated by Claude Code

  8. removed
    pm:dispatchedDispatched to a dev agent by /pm-dispatch
    on Sep 6, 2026
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

    bugSomething isn't workingdomain:devxDomain lane — seat card indexed by label:pm:seatdomain:specDomain lane — seat card indexed by label:pm:seatpriority:p3toolingFix lands in tooling, not a product package — enters pm:queue only with Unblocks: or a named surface

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions