Skip to content

fix(lint): liveness author warnings and the status census read ledger rows at every depth - #26379

Merged
objectstack-fleet[bot] merged 2 commits into
mainfrom
claude/project-thread-smn79b
Oct 27, 2026
Merged

objectstack-fleet[bot] merged 2 commits into
mainfrom
claude/project-thread-smn79b

Conversation

@objectstack-fleet

Copy link
Copy Markdown
Contributor

Requested by Yibo Wang · project thread

Fixes #26146

Clause-②: no
Metadata-protocol: none

维护者速读

  • 改了什么:liveness 作者告警(os lint)与状态词普查,原来只读台账顶层加一层 children,现在读到任意深度。
  • 为什么改:台账已有 41 行在第二层、2 行在第三层带 status,从未被评级;一个深层 dead 行或新状态词会悄悄漏过。
  • 风险与回滚:今天唯一新出现的告警是仪表盘 widgets[].chartConfig 的 5 个已退役键(schema 本就拒收);回滚即 revert 本 PR。
  • 先看:packages/lint/src/lint-liveness-properties.ts 的 ledgerRows(两处遍历共用它),再看测试文件末尾的 lint: liveness-properties flattens one level of children, but 40 grandchild ledger rows carry a status (e.g. dashboard/widgets.chartConfig.*), so they are never graded #26146 块。
  • 两分钟验证:pnpm --filter @objectstack/lint exec vitest run src/lint-liveness-properties.test.ts,预期 106 个用例全绿。
  • 需要你做的:无,席位落地。

What changes

  • packages/lint/src/lint-liveness-properties.ts: one walk, ledgerRows, yields every ledger row at every depth of children as a dotted path, descendants before the row (the order the warn map was always filled in, so finding order at depth 0 and 1 is unchanged). loadWarnMap and the status census both read it, so they cannot disagree about depth again.
  • The census gains a directory seam, ledgerStatusesIn(dir) (module export only, the same posture as lintLivenessPropertiesFromLedgerDir); shippedLedgerStatuses() is that census over the shipped directory.
  • Docblocks re-measured. The :303-306 count read "423 top-level and 285 child rows carry a status, zero grandchildren do". On origin/main 6390fe52 it is 528 top-level, 419 child, 41 grandchild, 2 great-grandchild. The WarnMap, loadWarnMap and authorWarnedProperties docblocks now say every depth.
  • Changeset: @objectstack/lint patch.

Tests

  • New block at the end of lint-liveness-properties.test.ts:
    • REAL LEDGER: widgets.chartConfig.type / .xAxis / .yAxis / .series (dead, two levels down) are in authorWarnedProperties('dashboard') and graded liveness-dead-property on an unparsed stack, through the array fan-out (the second widget authors them). The live chartConfig.title in the same call stays silent.
    • PLANTED: a dead + authorWarn row two levels down warns; a planned + authorWarn row three levels down warns, while its planned sibling without the opt-in stays silent (so the opt-in itself reaches depth 3, not only the verdict).
    • PLANTED: status words used only at depth 2 and depth 3 reach ledgerStatusesIn; the shipped census equals ledgerStatusesIn(shippedLedgerDir()) and carries neither word.
  • The #16094 hint pins' shippedRows() / itemAuthoring now walk every depth, so the newly warned deep rows are held to the same "never the note, no tracker id" rule.
Test runs (head bec9f05)
  • pnpm --filter @objectstack/lint exec vitest run --maxWorkers=2 src/lint-liveness-properties.test.ts: Test Files 1 passed, Tests 106 passed.
  • pnpm --filter @objectstack/lint typecheck && pnpm --filter @objectstack/lint test: exit 0, Test Files 165 passed, Tests 7383 passed, 5 skipped.
  • Ablation (scripts/ablation-replace.mjs, mutation landed: anchor 1 to 0, blob 60014c1e09ed to d39fa40b0098): ledgerRows limited to one children level reds exactly the three new tests (3 failed, 103 passed). Restored: blob back to 60014c1e09ed, equal to the HEAD blob, git diff HEAD empty.

Acceptance notes

Verification

Dispatch gates (head bec9f05)
  • node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack: 64 commands; 3 paths, 206 changed lines.
  • 63 exit 0. Three first answered exit 3 PREREQUISITE NOT MET (check-plugin-teardown-shape --self-test on the shallow clone; check:docs-transcript-drift and check:lean-entry-closure without built lint / objectql); after git fetch --unshallow and pnpm --filter '@objectstack/lint...' --filter '@objectstack/objectql...' build each re-ran exit 0.
  • NOT MEASURED: check:dual-build-cjs-loads, reason: it needs every package's dist (a full pnpm build, 88 packages absent); CI's Lint & Repo Gates runs it.
  • --ran reconciliation: exit 0, "64 derived famil(ies) accounted for — 63 run, 1 NOT-MEASURED".

Generated by Claude Code

@github-actions github-actions Bot added size/m documentation Improvements or additions to documentation tests tooling labels Oct 27, 2026
@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

4 anchor(s) derived from 1 changed package(s); no hand-written page names any of them, so this run has nothing to list — not a clean bill of health. This check sees only pages that NAME a derived anchor: one that documents this change in prose, or enumerates it in an authoring dialect, names none and stays invisible to it on every run.

What this run could not see
  • the SDK route bridge reached 55 of 207 client-bound route-ledger rows — the other 152 have no registrar path: tail to select them, so pages documenting THEIR client methods cannot appear above, on this or any run. Of those 152: 0 are remediable by widening that discovery convention (an in-repo file declares the path; the convention did not scan it); 55 are structural — on a ledger where NOT ONE row is declared in-repo, so no discovery change reaches them at any price; 97 are undecided (no in-repo declaration, on a ledger that has other in-repo registrars — absence and an unreadable spelling are not distinguishable here). The rows themselves: node scripts/docs-audit/affected-docs.mjs --bridge-coverage
  • a page that states a rule by its inputs shares no identifier with the emitter that implements the rule, so an emitter-only diff cannot list it — not on this run and not on any run. Measured on fix(driver-sql): emit varchar(maxLength) for a text field a declared index keys on #11430: content/docs/protocol/objectql/types.mdx documents the text-family column mapping by the ObjectQL type names it maps FROM (text / textarea / html) while the diff changed createColumn; it went unlisted, and it was the page that diff falsified, in four places. No shared token exists to detect this on, so a rule your change carries has to be re-read by hand in the pages that restate it.
  • a key NAME is not a key, so the hand re-read the line above prescribes can land on the wrong schema. The same spelling is authorable on one governed type and a [REMOVED] tombstone on another for each of active, aria, joins, objects, template, tools and version (censused on [finding] tools is a key on BOTH AgentSchema (tombstoned, dead) and SkillSchema (live, cloud-attested), so a name-based search attributes skill examples to the agent key — it produced a false stop-the-line alarm on PR #19059 #19093 over the liveness ledger's governed types, top-level keys); nothing in a search result distinguishes the two, so a grep hit on a LIVE example reads as evidence about the DEAD key. Measured on fix(spec): the agent.tools liveness row says dead — it claimed live on a key the schema tombstoned #19059: content/docs/ai/agents.mdx was reported as contradicting the agent.tools tombstone over its tools: example at :161, which is inside the defineSkill({ block opened at :155 — the page was already correct. Settle ownership by PARSING the value against both schemas, never by the name: that literal PASSES SkillSchema, and as an AgentSchema it FAILS at tools with the tombstone prescription. ⛔ These names are not the whole class — a key retired through a .strict() guidance map leaves no tombstone in the walked shape and none of them here (tool.category, live as AIToolDefinition.category).

Coarse fallback — 4 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): node scripts/docs-audit/affected-docs.mjs --json 61c079862ac726a1e16fcd73a04122567f475c4a → packageMentionDocs.

Which tree this was computed on

This run read content/docs from 804ebf15bfbd22b8e93bcc70a27af9b1d81e9590 — the merge of head bec9f0584657401fbc1542f4bfab1b0ea34b3475 into base 61c079862ac726a1e16fcd73a04122567f475c4a, which is what actions/checkout gives a pull_request run. Not the PR head.

A worktree cut from an older main holds a different content/docs, so re-deriving there can legitimately return a different list — that is a different tree, not a wrong row. To answer on the same tree:

# while this PR is open — GitHub drops the merge commit once it closes
git fetch origin 804ebf15bfbd22b8e93bcc70a27af9b1d81e9590 && git checkout 804ebf15bfbd22b8e93bcc70a27af9b1d81e9590
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin 61c079862ac726a1e16fcd73a04122567f475c4a bec9f0584657401fbc1542f4bfab1b0ea34b3475 && git checkout -B drift-repro 61c079862ac726a1e16fcd73a04122567f475c4a && git merge --no-ff bec9f0584657401fbc1542f4bfab1b0ea34b3475

node scripts/docs-audit/affected-docs.mjs --json 61c079862ac726a1e16fcd73a04122567f475c4a

⚠️ That checkout carried uncommitted changes, so the commit above does not fully identify what was read.

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

席位核对 · ACCEPT · domain:spec seat 1 (#6017) · session session_01WGufzfhobWEgUUrjz4rrbh · 2026-10-27T01:36Z

Head bec9f0584657401fbc1542f4bfab1b0ea34b3475. Card #26146, claim 6430852060, dev report 6431253092.

  • Shape: draft, base main, Fixes #26146 on its own line; 3 files (packages/lint/src/lint-liveness-properties.ts, its test, .changeset/26146-liveness-every-depth.md), all inside the claim's file surface. check-governed-merges --pr 26379: NOT governed, 206 changed lines.
  • Contract faces: none. No packages/spec/src/**, no governed path, Clause-②: no on body and changeset; ledgerStatusesIn is a module export only, not re-exported from packages/lint/src/index.ts (named re-exports at :936-964 do not include it). So no at-tier record is owed; CI plus this seat's read.
  • Diff read: one generator ledgerRows replaces both one-level walks (loadWarnMap, the status census); descendants are yielded before the row, so depth-0/1 finding order is unchanged. shouldWarn (:173-176) is untouched: a row warns on a verdict in VERDICTS_THAT_WARN or on authorWarn.
  • Changeset sentences checked against the diff: "A row at any depth now warns under the same rules as a shallower one" (matches ledgerRows feeding loadWarnMap); "The only rows this reaches today are the dashboard's widgets[].chartConfig.type, .xAxis, .yAxis, .series and .aria, all dead" (matches the seat premise reading 6430781250: five dead grandchildren in dashboard.json, no authorWarn at depth 2+); "A status word used only at depth 2 or deeper now reaches the vocabulary check" (matches ledgerStatusesIn). @objectstack/lint patch: right for a lint-reach fix with no published shape change.
  • Gates: check-runs on the head: 39 success, 8 skipped (the UI, docs, temporal, dogfood and opt-in lanes a lint-only diff does not trigger), 0 red; Lint & Repo Gates and TypeScript Type Check both success. The dev's local set: 63 of 64 derived commands exit 0, check:dual-build-cjs-loads NOT MEASURED locally and covered by CI's Lint & Repo Gates.
  • Tests: the three new cases are proven to bite by the dev's ablation (a one-level ledgerRows reds exactly them); real-ledger case plus planted depth-2 and depth-3 rows.
  • Accepted deviations: none from the claim. The five newly-warned rows are already schema-refused keys, so only an unparsed stack (os lint) sees them; per triage 6417914269 no ledger row is regraded here.
  • Out of scope: PR feat(spec,cli)!: retire the ≤16.x retirement kits; the strict unknown-key refusal names the protocol upgrade guide #26138 (draft) carries a test comment that this PR makes false ("sit two down and were never graded"); the second lander merges main and re-measures. Noted, not filed.
  • Landing: Tier S path, not governed: pr_ready + automerge_enable in this act.

@objectstack-fleet
objectstack-fleet Bot marked this pull request as ready for review October 27, 2026 01:38
@objectstack-fleet
objectstack-fleet Bot enabled auto-merge October 27, 2026 01:38
@objectstack-fleet
objectstack-fleet Bot added this pull request to the merge queue Oct 27, 2026
Merged via the queue into main with commit 13136f7 Oct 27, 2026
48 checks passed
@objectstack-fleet
objectstack-fleet Bot deleted the claude/project-thread-smn79b branch October 27, 2026 02:00
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation size/m tests tooling

Projects

None yet

2 participants