Skip to content

docs(spec): the liveness README's authorWarn pointer names the lint's real home - #19659

Merged
os-support-ai merged 2 commits into
mainfrom
claude/issue-19269-liveness-readme-lint-path
Sep 22, 2026
Merged

os-support-ai merged 2 commits into
mainfrom
claude/issue-19269-liveness-readme-lint-path

Conversation

@os-support-ai

Copy link
Copy Markdown
Collaborator

Fixes #19269

Clause-②: no

packages/spec/liveness/README.md told the reader that the lint which emits author warnings lives at packages/cli/src/utils/lint-liveness-properties.ts. That path does not exist. One line, repointed at the module's real home.

Measured in this worktree, not carried from the card

Base 5ce3705. The card's line numbers were re-derived by text, because the file was touched by #19594 after the card was written:

probe : packages/cli/src/utils/lint-liveness-properties.ts
        ls: cannot access ...: No such file or directory

LIT CONTROL (same listing, same corpus):
        packages/lint/src/lint-liveness-properties.ts        35926 bytes
        packages/lint/src/lint-liveness-properties.test.ts   83518 bytes

Both pointers still sit where the card and the dispatch put them — :548 (the stale full path) and :948 (a bare filename) — so #19594 moved neither.

Why packages/lint/src/lint-liveness-properties.ts is the right referent

A path that exists is not automatically the one the sentence means. Four readings say this one is:

  • The module's own header describes exactly what :548 describes: it reads the liveness/*.json ledgers, opts in per entry via authorWarn, emits an advisory warning with a hint, and "NEVER fails the build".
  • The sentence at :948 names TYPE_COLLECTIONS; that constant is declared in this module, at :485.
  • The rule registration carries the answer as data: packages/lint/src/authoring-rules.ts registers { name: 'lintLivenessProperties', tier: 'advisory', source: 'packages/lint/src/lint-liveness-properties.ts' }. The repointed prose now agrees with a machine-readable field rather than with a second piece of prose.
  • The adjacent words "The CLI compile lint" stay true after the repoint: packages/cli/src/commands/compile.ts imports runAuthoringRules / authoringRulesFor from @objectstack/lint and the rule declares commands: ALL, so os compile is still a door this lint runs behind.

Nothing else in the sentence changed, and no ledger entry, verdict, schema, export or runtime behaviour moved.

Why the second pointer is deliberately NOT changed

:948 reads "see lint-liveness-properties.ts" — a bare filename with no directory. Leaving it is a decision, not an oversight:

  • It is not stale. The basename resolves uniquely in the tree today (the module plus its .test.ts), so a reader who follows it lands on the module.
  • A bare filename has no directory to rot. Giving it one would convert a rot-proof pointer into a rot-prone one — manufacturing the exact defect class this card exists to close, for a cosmetic gain.
  • The cost is asymmetric. A wrong full path actively misleads (the reader lands on nothing and may conclude the lint does not exist); a bare filename costs one git grep. The durable form wins where the defect class is this one.
  • The full path is stated once, at :548, which is where a reader who needs the directory gets it.

Changeset: patch, measured rather than assumed

liveness/ is in @objectstack/spec's files[], and the package is published (not private, currently 17.4.0), so this README ships inside the npm tarball. Measured with npm pack --dry-run --json in packages/spec:

  • 277 files in the tarball; liveness/README.md present; 42 liveness/* entries
  • negative controls on the same listing: no scripts/ entry, no *.test.ts entry

So the edited bytes are published bytes. skip-changeset would be false, and a patch changeset is owed. Precedent on the same file: the #14640 changeset states the same fact in the same words ("The ledgers ship inside this package (files[] includes liveness)").

Verification

Gate families derived in this worktree with node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --commands over the real changed paths, then reconciled with --ran carrying each command's exit code captured before any pipe.

  • 57 derived, 53 run green, 4 NOT MEASURED, 0 UNRUN at 5ac6291.
  • The 4 NOT MEASURED all exit 3 with their own PREREQUISITE NOT MET line, which is "nothing was swept", not a finding: check:dts-closure, check:dual-build-cjs-loads, check:lean-entry-closure, check:sourcemap-no-sources-content. Each reads built dist/ across the workspace and needs a full pnpm build first. This diff contains no TypeScript and no published bytes outside one Markdown file, so it cannot move any of them; CI runs them on a built tree.
  • check:plugin-teardown-shape --self-test first exited 3 on a shallow checkout ("cannot read the positive control at 621a487"). After git fetch --unshallow it passes, 48 cases. Its PR-verdict run (no --self-test) was green both times.
  • The five roster gates whose allowlists sit under a directory this diff is in were run rather than read as silence: check-changeset-fixed, check:spec-changes, check:authz-resolver, check:error-code-casing, check:filter-alias-parity — all exit 0.
  • The one test file that reads this README, packages/spec/scripts/liveness/check-liveness.test.ts: 64 tests pass.
  • Control-byte self-scan over both changed files: no match.
  • pnpm lint was narrowed, and the narrowing is measured rather than claimed: eslint's own declared population is source extensions only (files: ['**/*.{ts,tsx,mts,cts,js,jsx,mjs,cjs}'] and four TypeScript-only globs; no Markdown glob), --format json over both changed paths returns 2 entries, each "File ignored because no matching configuration was supplied" with errorCount: 0, and the config enables no type-aware linting (no parserOptions.project), so this diff cannot move the verdict on any file it does not touch. Count of changed files inside eslint's population: 0. The repo-wide sweep is CI's.

Acceptance notes

Noted, not filed, and deliberately not fixed here — the file surface for this card is packages/spec/liveness/README.md and this observation is larger than the repoint:


Generated by Claude Code

… real home

`packages/spec/liveness/README.md` told the reader the author-warning lint
lives at `packages/cli/src/utils/lint-liveness-properties.ts`. That path
returns zero in a full tree listing; the module is at
`packages/lint/src/lint-liveness-properties.ts`, which is also what the rule
registration in `packages/lint/src/authoring-rules.ts` carries as data
(`source:`). This grid has no mechanical reader — `check:liveness` resolves
the `evidence` paths inside ledger entries, never a path in README prose — so
the pointer survived the move with every gate green.

Claude-Session: https://claude.ai/code/session_013RDBh5DqXd2xnLwvHLgLFr
Co-authored-by: Claude <noreply@anthropic.com>
@github-actions github-actions Bot added size/s documentation Improvements or additions to documentation tooling labels Sep 22, 2026
@github-actions

github-actions Bot commented Sep 22, 2026 •

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

⚠️ 1 changed file(s) yielded no anchor (packages/spec/liveness/README.md), so the pages documenting them are NOT COVERED by this run — this is not a clean bill of health for those files. Nothing else in this diff resolved to a documentable surface (no symbol, route or SDK anchor derived from 1 changed package(s)).

What this run could not see
  • 1 changed file(s) yielded no anchor (packages/spec/liveness/README.md) — pages documenting those are invisible to this run
  • 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 — 136 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 fb7b74691f7d192430f6b3b457a858dc442ad0e0 → packageMentionDocs.

Copy link
Copy Markdown
Collaborator Author

Test Core (1/6) is red, it is ⛔ NOT this PR's, and it is a NEW signature — 2026-09-22T05:37Z

Seat note from domain:spec seat 1 (session_013RDBh5DqXd2xnLwvHLgLFr). Read from the job log first-hand.

Full signature, job 106625053057:

::error file=scripts/check-error-status-conformance.mjs, title=[repo] src/api/error-catalog-docs.test.ts, line=1802 — Error: ENOENT: no such file or directory, stat 'packages/spec/tsup.config.bundled_mz2es9op0s7.mjs'
❯ walk :1802 ❯ scanSources :1817 ❯ deriveWireFace :1862 ❯ src/api/error-catalog-docs.test.ts:55
Test Files 1 failed | 33 passed · ⭐ Tests 580 passed (580)

Initial judgment. ⛔ Not this PR's, and ⛔ not a timeout: no assertion failed — the file died during collection. walk() stats every readdirSync entry unguarded, and tsup.config.bundled_<hash>.mjs is the temp config tsup writes and deletes around a bundle (.gitignore:94 already declares *.bundled_*.mjs transient). A concurrent package build in the same workspace is the whole cause.

⭐ The sharpest part: the filter one line below statSync keeps only /\.tsx?$/, so that .mjs would have been discarded anyway — the run died on a file it did not want.

Why not this PR's, by file list rather than argument: this diff is packages/spec/liveness/README.md (one line) plus a changeset. It touches no code path this trace names.

⇒ Filed as #19667 with the code reading and the blast radius.

⛔ Deliberately NOT re-submitted

「新签名 ⇒ ⛔ 不重投」 — a new signature is not re-run on a hunch, it is recorded with its full trace and its initial judgment, on the PR and on its card. Both are now done. ⚠️ And this seat could not have re-run it regardless: 403 on both rerun endpoints, recorded rather than glossed.

⛔ No fix ported — #19667 is minutes old and nothing has landed to carry. ⛔ No test skipped, disabled or quarantined. ⛔ No empty commit, ⛔ no base merge used as a pretext to kick CI.

⇒ This PR stays watched until green, merged or closed. ⚠️ Note for whoever lands it: this signature can hit any PR whose CI overlaps a tsup bundle, so a second red here is ⛔ not evidence about this diff either.


Generated by Claude Code

Bring the branch onto the current green main so CI re-measures against it.
The previous run reddened on two failures in code this two-file docs diff does
not touch.

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013RDBh5DqXd2xnLwvHLgLFr

Copy link
Copy Markdown
Collaborator Author

Why this PR sat red for seven hours — and what actually failed

Measured at 2026-09-22T12:55Z on run 35690079389, attempt 1, head 5ac6291a99. Newest run per check name; no later run of that name existed.

The failing check is Test Core (1/6), and no test assertion failed in it:

Test Files  1 failed | 33 passed (34)
Tests       580 passed (580)

The failure is in a repo-scan step, not a test body:

Error: ENOENT: no such file or directory, stat
  '…/packages/spec/tsup.config.bundled_mz2es9op0s7.mjs'
  at walk → scanSources → deriveWireFace
  scripts/check-error-status-conformance.mjs:1802

tsup writes packages/spec/tsup.config.bundled_<random>.mjs, reads it, and deletes it. The conformance scan walks the tree concurrently and stats every entry it enumerated. When the delete lands between the readdir and the stat, the scan throws on a file that is supposed to be gone. The random infix in the filename is itself the tell: nothing in a diff can name that path, and no two runs produce the same one.

Not this PR's. The diff is two files — .changeset/19269-liveness-readme-lint-path.md and packages/spec/liveness/README.md. No TypeScript, no published bytes outside one Markdown file. main was measured green at fb7b7469 (ci.yml and lint.yml both completed/success), so this is not inherited breakage either.

Why it stayed red. Not CI — me. The seat recorded this PR as "watched" at 2026-09-22T05:51Z and did not come back to it. The seat's own patrol routine listed only the cards it was actively dispatching, so this PR was never re-read. The list was hand-written; that is the root cause, and the routine is being changed to query GitHub for every open PR under this identity instead of reading a list the seat wrote down. Writing a value into a note and then reading the note instead of the world is the same failure shape twice in one session.

Why it was not simply re-run. The fleet App identity cannot mint a token through this container's proxy — POST /app/installations/163654544/access_tokens answers 403 Access to this GitHub API path is not permitted through this proxy, re-measured at 2026-09-22T12:55Z. A re-run under the seat's ordinary account identity is not one of the three uses that account is permitted, so that route is ⛔ closed rather than merely inconvenient.

What was done instead. origin/main merged into this branch at d1c22352aa, so CI re-measures the same two-file diff against the current green main. The merge is clean and the PR's own contribution is byte-unchanged — git diff against the new merge-base is still exactly those two files. ⛔ No rebase, no force-push, no empty commit, and no test skipped, disabled or quarantined.

Filed, not buried. The scan/tsup race is a real defect in shared CI infrastructure that can redden any PR in the repo, so it gets its own card rather than a shrug — whoever finds a flake fixes it or files it.


Generated by Claude Code

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/s tooling

Projects

None yet

2 participants