Skip to content

fix(lint): one-line fix lines for 16 more author-time rule ids; os explain RULE_ID carries what they enumerated - #22909

Merged
objectstack-fleet[bot] merged 5 commits into
mainfrom
claude/issue-22161-s2-lint-slice-12-hints
Oct 12, 2026
Merged

objectstack-fleet[bot] merged 5 commits into
mainfrom
claude/issue-22161-s2-lint-slice-12-hints

Conversation

@objectstack-fleet

Copy link
Copy Markdown
Contributor

Part of #22161
Clause-②: no

Stage 2 of the card, slice 12: the over-long fix: lines, continued in slice 11's shape. Each finding's hint (the CLI's fix: line, the runtime issue's hint) of 16 more packages/lint rule ids, in ten whole rule files, is now one remedy line of at most 200 characters, and what the lines used to enumerate or explain is each id's RULE_EXPLANATIONS entry behind os explain RULE_ID. The card stays open: 91 author-time ids still carry a hint over 200 characters (the last section).

What changes

  • One remedy line per finding. The 16 ids, every hint the lint suite fires, before → after:
rule id file lint suite: hints · range, before → after runtime door
validation-rule-json-schema-unknown-format validate-rule-schema-formats.ts 10 · 606–646 → 10 · 143–183 object write, 422
measure-aggregate-field-type-refused validate-dataset-measure-aggregates.ts 694 · 574–645 → 694 · 111–178 dataset write, 422
dimension-json-stored-field-refused same 5 · 177–262 → 5 · 161–177 dataset write, 422
predicate-rhs-path-shaped validate-predicate-path-refs.ts 12 · 381–643 → 12 · 153–184 view write, 422 (dotted) / 2xx advisory (bare word)
predicate-path-unrooted same 1 · 214 → 1 · 122 view write, 422
predicate-path-unresolved same 10 · 84–201 → 10 · 20–153 view write, 422
rls-predicate-unknown-user-variable validate-rls-predicate-enforceability.ts 6 · 566–618 → 3 · 158–193 permission write, 422
rls-predicate-unparseable same 1 · 523 → 1 · 171 permission write, 422
hook-api-update-readonly-when-field validate-readonly-hook-writes.ts 1 · 607 → 1 · 173 CLI only
action-name-undefined validate-action-name-refs.ts 32 · 181–560 → 29 · 91–195 CLI only
ai-skill-tool-unresolved validate-ai-tool-references.ts 22 · 308–548 → 22 · 150–189 CLI only
org-axis-permission-inheritance validate-org-axis-red-lines.ts 1 · 542 → 1 · 145 CLI only
org-axis-cross-org-bu-grant same 1 · 315 → 1 · 141 CLI only
object-reference-unknown validate-object-references.ts 23 · 254–522 → 2 · 123–134 dataset write (its object), 422
object-reference-unregistered-platform same 8 · 366–500 → 1 · 187 dataset write (its object), 2xx advisory
filter-empty-node validate-empty-combinators.ts 3 · 170–515 → 3 · 69–113 flow / report write, 422

A count that falls is several old hints that differed only in what the new line no longer carries: the stack's object or action list, the site's consequence sentence, the kernel key list's position against the suggestion.

  • Lists are no longer echoed. object-reference-unknown drops "Defined objects: …" and action-name-undefined drops "Defined actions: …" and the related object's action list: the verdict's "Did you mean" already names the nearest one. validation-rule-json-schema-unknown-format names the nearest registered format and moves the full registered set (26 names) into its explanation, written out there and held to registeredFormatNames() by the rule's test. ai-skill-tool-unresolved moves the family prefixes into its explanation, held to PLATFORM_TOOL_FAMILY_PREFIXES. rls-predicate-unknown-user-variable keeps the six kernel keys and the nearest one, so its line holds no author text at all (a test holds the worst-case suggestion under 200).
  • The reasoning moves, the remedy stays.
    • object-reference-*: each check() site passed a consequence sentence that closed every hint (the record picker, the view container's index, the dashboard filter, the dataset's reports, the nav gate). Those are now one paragraph in both ids' explanations; the check() argument is a remedy, which only the view-container site passes (the namespace-prefixed spelling, which is then the whole line).
    • measure-aggregate-field-type-refused: the line names the aggregates the declaration accepts (the "accepts: count." pins hold); why count / count_distinct reach further, the stored-numeric route and the two doors that refuse the pair later (DATASET_COMPILE_DOOR / CUBE_QUERY_DOOR, now deleted with the door parameter) are the explanation's.
    • hook-api-update-readonly-when-field: the two routes and "runAs: 'system' and sudo() do not waive this lock"; why (the system context, the sandbox), the drop-the-field alternative and "never blocks a build" are the explanation's.
    • rls-predicate-unparseable: the SQL-to-CEL translations in one line; the subquery route (ADR-0055, ADR-0105 D11) is the explanation's.
    • predicate-rhs-path-shaped: both spellings in one line, and the bare-word arm keeps "Do NOT simply add the root in place" (pinned by runtime-gate.test.ts); why quoting changes nothing today and why two paths cannot be compared are the explanation's.
    • filter-empty-node: OMIT_THE_KEY / MATCH_NONE_SPELLING are deleted from the rule and their text is the explanation's.
    • org-axis-*, ai-skill-tool-unresolved, action-name-undefined, the two other predicate ids, dimension-json-stored-field-refused (multi-value arm) and validation-rule-json-schema-unknown-format: likewise, one line each.
  • Two ids gain an explanation entry, because their reasoning had no entry to move into: object-reference-unknown ("how an object name resolves, and what a miss costs") and org-axis-permission-inheritance ("why access never walks the organization tree"). Their rule: line now ends with the os explain pointer, which explainPointer prints for every id the table holds. The two object-reference entries share the sites, the ladder and the per-site cost paragraphs; the two org-axis entries share the ADR-0105 D6 opening. The other 14 entries gain paragraphs.
  • Nothing else moves. Every message, rule id, severity and path, and what each rule accepts or refuses, is unchanged: every hunk in the ten rule files is a hint expression, a comment, a deleted hint constant, or (two places) a parameter that only fed a hint (door, and fix renamed remedy with a default). No condition, branch, skip or dedupe moved.
  • .changeset/22161-lint-slice-12-one-line-fix.md: @objectstack/lint patch, Clause-②: no, naming every door that prints fix: and the runtime hint FROM → TO.

The runtime wire (Zone 2 item 3)

Measured at the door with runRuntimeAuthoringRules on the base dist and on the rebuilt one (a scratch probe, 28 writes):

  • an object write: validation-rule-json-schema-unknown-format (422 issues[].hint, 638 / 606 → 175 / 143, with and without a nearest name);
  • a dataset write: measure-aggregate-field-type-refused (422, 606 / 581 → 147 / 122), dimension-json-stored-field-refused (422, multi-value 259 → 166, structured JSON 177 unchanged), object-reference-unknown on the dataset's object (422, 331 → 134) and object-reference-unregistered-platform (2xx advisories[].hint and the [Protocol] authoring advisory log line, 449 → 187);
  • a view write of a schema-bound metadata form: predicate-rhs-path-shaped (422 dotted 384 → 156; 2xx advisory bare word 631 → 180), predicate-path-unrooted (422, 214 → 122), predicate-path-unresolved (422, 100 → 36 with a nearest key);
  • a permission write: rls-predicate-unparseable (422, 523 → 171), rls-predicate-unknown-user-variable (422, 566 / 590 / 634 → 158 / 180 / 190, without a nearest key, with email, with organization_id);
  • a flow or report write: filter-empty-node (422, 515 / 278 / 170 → 113 / 107 / 69);
  • no write reaches hook-api-update-readonly-when-field, action-name-undefined, ai-skill-tool-unresolved or the two org-axis-* ids (a hook, skill, page, sharing_rule, view bulk-action and permission write were probed), nor the object-reference ids on an object or view write.

Readers of hint, read-only against objectui main at f3d5408141 (fetched into a ref of its own, git grep, no edit): Studio's saveAdvisoryToast.ts formatFinding renders [rule] where — message hint for every 2xx advisory; DraftChangesPanel.tsx renders p.hint || p.message for the in-browser security-posture lint (none of the 16); metadata-client.ts readSaveAdvisories checks only that hint is a string; the 422 issues renderers read path and message. REST (PUT /api/v1/meta, SaveMetaItemResponseSchema.advisories, the error envelope's issues) forwards the array as JSON; packages/mcp has no metadata write tool, so an MCP or AI author reaches the gate through REST. In this repository toIssue forwards hint verbatim, the advisory log line prints it, and build-probes.ts reads hint only for object-field-ref-unknown (not one of the 16). No reader in either repository matches on hint text.

check:watch-hint-literal guards something else of the same name (every *_WATCH_HINTS population declaration in a gate script is a literal array): exit 0, 72 declarations across 4 rostered names, standalone and inside the gate set.

Census (taken first, before any edit, at the base 63739521d8)

Method: slices 4 to 11's scratch preload (NODE_OPTIONS=--import, never committed) patching Array.prototype.push to record every finding-shaped object, deduped by (rule, hint) per process, with its push site. Lengths are the hint alone. Runs, each before and after:

  • packages/lint suite (137 files, 6,497 tests at the base): 240 ids fire, 131 carry a hint over 200 = 21 of the 26 fenced ids, 3 repo-gate ids (lint-startup-registry-verdict.ts) and 107 author-time ids; the 16 here match slice 11's census lengths exactly. After, at the merged head 26fe94f3e1 with the lint dist rebuilt: 115 over 200 = 21 fenced + 3 repo-gate + 91 author-time.
  • Runtime publish gate, the whole @objectstack/metadata-protocol suite reading @objectstack/lint from its built dist (base dist before, rebuilt after): fires measure-aggregate-field-type-refused (588 → 129) and rls-predicate-unparseable (523 → 171) of the 16.
  • packages/cli unit tier (283 files): fires hook-api-update-readonly-when-field (604 → 170) and object-reference-unknown (7 hints · 242–348 → 1 · 134).
  • os validate (the built CLI) on app-crm, app-todo, app-showcase, app-multi-package, exit 0 each, before and after: none of the 16 fires on any of them; each app prints the same 9 / 7 / 70 / 3 rule: lines, and the printed output is byte-identical before and after.

Tests

Every heavy run went through scripts/pm/os-verify-lock.sh (slot issue-22161-s12); its VERDICT lines are in the report.

  • Each rule's own suite pins the new shape. Every touched suite already records what its cases fire; a new last block per file holds every recorded fix: line of its converted ids to one line of at most 200 characters behind a coverage control (each arm fired: both format arms; the measure id on a type row and a flagged declaration and the dimension id on both classes; both unresolved arms and both right-hand arms; the variable id with and without a nearest key; the generic action arm with both placements and both related-list arms; both ai-skill arms; both org-axis ids; the object-reference id with and without the namespace remedy; all three empty-node positions), plus a check per id that explainRule(id) holds what the line stopped saying. The three RLS sibling files' bounds now cover every rls-predicate-* id. Pins that read the old hint text moved to the explanation, text-only, except two that needed a new reading: the related-list drawn-locations pin now reads its own paragraph (the new fix paragraph names the header's record_header / record_more), and the artifact-context pin reads the verdict's "Did you mean" on a near miss instead of the dropped object list.
  • Lint suite at the merged head 26fe94f3e1: Test Files 137 passed (137), Tests 6,528 passed (6,528); VERDICT command-exit 0 (6,518 before the merge of origin/main).
  • Lint build + typecheck: pnpm --filter @objectstack/lint build (check-dts-emitted 6/6), rebuilt with its closure after the merge, and run typecheck at 9d56f0f431 (check:test-typecheck OK, 2 files / 6 errors / 2 pinned signatures held), VERDICT command-exit 0 each. The rebuilt dist carries the new text (constraint with \pattern`, which is enforcedandtest an app-staged membership1 hit each inindex.js, index.cjs, runtime.js, runtime.cjs; the old The registered names are: ${` 0).
  • CLI unit tier on the rebuilt dist: Test Files 283 passed (283), Tests 4,265 passed (4,265); VERDICT command-exit 0. No packages/cli or packages/metadata-protocol test asserts these ids' hint text, so the declared rider went unused.
  • Runtime gate: the whole @objectstack/metadata-protocol suite, after: Test Files 226 passed, 3 skipped (229), Tests 28,171 passed, 19 skipped; VERDICT command-exit 0.
  • Ablation (one-shot, from the committed head 9d56f0f431, through scripts/ablation-replace.mjs under the lock, with a shell trap restoring HEAD by absolute path). The rule suites import the rule source, so there is no dist leg. rls-predicate-unparseable's pre-slice line was restored: hint: UNPARSEABLE_FIX, → the 523-character SQL-to-CEL hint as one literal (anchor x1 → x0, blob 1e997b3fc7cc → 371d8e008841). Predicted before the run: exactly the new bound pin goes red, and the older canonical CEL / && pins stay green. Observed: src/validate-rls-predicate-enforceability.test.ts Tests 1 failed, 132 passed (133), exactly that pin, which read 523. Restored: blob 1e997b3fc7cc == HEAD, git diff HEAD empty, git status --porcelain empty.
  • Corpus pins over packages/lint/src: pnpm --filter @objectstack/spec test:repo at 9d56f0f431: Test Files 55 passed (55), Tests 971 passed (971); VERDICT command-exit 0. No new text carries an os migrate meta --from sentence, and no tracker id is in a printed hint or explanation (citations stay in comments and test names).
  • ESLint, narrowed: npx eslint --no-inline-config --format json over the 24 changed .ts files: 24 files in the report, 0 errors, 0 warnings. The population is eslint.config.mjs's **/*.{ts,…} block plus its packages/** blocks; the config never enables type-aware linting (no parserOptions.project), so no untouched file's verdict can move. A control-character scan of every changed file found no match.
  • Gates: one merge of origin/main through scripts/pm/os-regen-merge.sh (0cc2194a2b → 26fe94f3e1, onto 9fdb12752c; no conflict, and the branch edits no generated artifact). node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack with no paths at the final head 9d56f0f431 (25 paths vs the merge base) derived 62 commands; 60 ran, each exit code captured before any pipe, all 0 (longest: check:query-options-erasure 348s, check:slot-lookup 175s, check-comment-mask-corpus 142s). NOT MEASURED, as dispatched: check:dual-build-cjs-loads (needs every package's dist) and check:type-check-debt (its script is --re-measure; check:type-check-coverage ran). --ran: Run reconciliation — 62 derived, 60 run, 2 NOT-MEASURED, 0 UNRUN. The artifact-roster block (51 families): the 48 that need no pull request exited 0 at 9d56f0f431, check:published-readme-exports after building its four missing dists (client-react, embedder-openai, knowledge-ragflow, organizations, 54 tasks) under the lock (its first answer was the exit-3 prerequisite refusal, not a verdict); the three PR-context guards run against this PR and report on the card.
  • Which tree each reading is from: the lint suite and the census at 26fe94f3e1 (the merge; 9d56f0f431 adds one changeset figure only); the CLI unit tier, the metadata-protocol suite, os validate and the runtime probe on the pre-merge head 0cc2194a2b, whose hint text the merge did not touch (main brought no change to the ten rule files or rule-explanations.ts).

Acceptance notes

  • A long name can still lengthen a line. The bound holds on every variant the suites, the runtime probe and the four example apps fire; the names in a hint (the measure's column, the dimension's object and field, the right-hand text, the action and related-object names, the readonlyWhen field and object) are the author's. The closest measured case is action-name-undefined at 195. rls-predicate-unknown-user-variable and rls-predicate-unparseable carry no author text at all.
  • The dropped lists now print nowhere on the CLI. A near miss still gets the verdict's "Did you mean"; a far miss of an object or action name no longer sees the stack's whole list on the fix: line. The card's "Asked for" names no list, and slice 11 made the same call for rls-predicate-unknown-field's field list.
  • Two rule: lines gain the os explain pointer (object-reference-unknown, org-axis-permission-inheritance), through the new entries. That is the printer's own rule for an id the table holds, not a printer change.
  • The bare-word right-hand line is two sentences: the remedy, then "Do NOT simply add the root in place", kept verbatim because runtime-gate.test.ts (outside this slice's files) pins it.
  • The namespace remedy replaces the generic line on both object-reference arms. A platform-prefixed short name whose namespaced spelling the stack declares gets that spelling alone, where it used to get the generic platform text and then the spelling.

Remaining for this card

91 author-time packages/lint ids still carry a hint over 200 characters in the final lint census (at 26fe94f3e1: 115 over 200 = 91 + 21 fenced + 3 repo-gate), by file, longest first:

  • lint-flow-patterns.ts (2): flow-double-brace-interpolation 1339, flow-bare-dollar-reference 1231
  • lint-flow-credential-literals.ts (1): flow-credential-literal 646
  • data-model-rules.ts (6): unique/legacy-organization-composite 578, unique/unscoped-declared-index 380, object/missing-name-field 327, rollup/non-numeric-aggregand 282, unique/double-declaration 279, field/select-missing-options 207
  • validate-widget-bindings.ts (11): dashboard-filter-field-unprovisioned 561, chart-field-unknown 415, dashboard-filter-field-unknown 403, chart-measures-missing 369, widget-legacy-analytics-shape 338, widget-measures-missing 330, widget-filter-field-unknown 322, widget-legacy-analytics-unrenderable 320, table-count-only 311, chart-dimensions-missing 291, dashboard-filter-field-not-included 218
  • validate-readonly-flow-writes.ts (2): flow-update-readonly-when-field 549, flow-update-readonly-field 400
  • validate-action-dispatch-contract.ts (1): action-dispatch-contract-mismatch 514
  • validate-security-posture.ts (5): security-controlled-by-parent-ambiguous-relation 496, security-master-detail-ungranted 314, security-controlled-by-parent-no-relation 294, security-fls-unknown-field 293, security-wildcard-vama 218
  • validate-sharing-rule-enforceability.ts (2): sharing-rule-object-not-shareable 482, sharing-rule-object-controlled-by-parent 395
  • validate-page-visualization-bindings.ts (1): page/visualization-without-binding 480
  • validate-readonly-action-writes.ts (1): action-api-update-readonly-when-field 470
  • validate-flow-trigger-readiness.ts (5): flow-api-trigger-secret-missing 461, flow-time-relative-descriptor-unroutable 441, flow-trigger-unroutable 295, flow-trigger-unknown-event 268, flow-trigger-unknown-object 210
  • validate-searchable-fields.ts (3): searchable-field-unknown 448, searchable-field-unprovisioned 362, searchable-field-unsearchable 328
  • validate-flow-filter-tokens.ts (1): flow-filter-token-unknown 427
  • validate-action-locations.ts (1): action-no-placement 424
  • validate-mapping-target-fields.ts (1): mapping-target-field-unknown 405
  • validate-dashboard-widget-options.ts (1): unconsumed-widget-option 396
  • validate-sortable-fields.ts (3): sort-field-unprovisioned 378, sort-field-unsortable 332, sort-field-unknown 301
  • validate-visibility-predicates.ts (3): visibility-predicate-unknown-function 375, visibility-bare-identifier 221, visibility-predicate-syntax 214
  • validate-nav-access.ts (1): nav-object-ungranted 370
  • validate-hook-body-writes.ts (3): hook-body-write-unprovisioned-anchor 365, hook-body-write-unknown-field 275, hook-body-source-unparseable 254
  • validate-ai-agent-authoring.ts (2): agent-authoring-withdrawn 363, default-agent-outside-roster 237
  • validate-react-page-props.ts (4): react-chart-field-unprovisioned 362, react-prop-missing-required 277, react-page-source-unparseable 254, react-block-needs-record-context 228
  • validate-translatable-sections.ts (1): translation-section-name-missing 359
  • validate-action-body-writes.ts (4): action-body-write-unprovisioned-anchor 358, action-body-write-unknown-field 323, action-record-write-discarded 309, action-body-source-unparseable 254
  • validate-flow-node-writes.ts (2): flow-node-write-unprovisioned-anchor 358, flow-node-write-unknown-field 289
  • validate-managed-api-methods.ts (1): object/managed-api-method-unaffordable 357
  • validate-nav-object-servability.ts (1): nav-object-unservable 348
  • validate-rule-compilability.ts (2): validation-rule-json-schema-uncompilable 341, validation-rule-regex-uncompilable 300
  • validate-dataset-references.ts (2): dataset-include-unknown 336, dataset-field-unknown 206
  • validate-translation-references.ts (1): translation-target-unknown 317
  • validate-approval-approvers.ts (3): approval-approver-not-membership-tier 313, approval-expression-no-empty-policy 294, approval-expression-invalid 292
  • validate-seed-replay-safety.ts (1): seed-insert-mode-duplicates-on-replay 309
  • validate-chart-bindings.ts (1): chart-measure-unknown 285
  • validate-object-field-refs.ts (1): object-field-ref-unknown 284
  • validate-capability-references.ts (1): capability-reference-unknown 273
  • validate-record-title.ts (2): title-format-retired 267, title-unresolvable 237
  • validate-list-view-field-refs.ts (2): list-view-field-unknown 258, list-view-field-dotted 233
  • validate-view-containers.ts (1): view-container-shape 256
  • validate-seed-state-machine.ts (1): seed-value-outside-state-machine 251
  • validate-ai-surface-affinity.ts (1): ai-skill-surface-mismatch 235
  • validate-page-source-styling.ts (1): page-source-className-tailwind 231
  • lint-liveness-properties.ts (1): liveness-planned-property 230
  • validate-list-view-mode.ts (1): list-view-filters-in-views-mode 219

Not in the 91: the 26 fenced ids as PR #22448 lists them (21 fire a hint over 200), the 3 repo-gate ids (startup-open-vocabulary-verdict, startup-source-unparseable, startup-verdict-assertive-wording), and the packages/cli ids on #22841.


Generated by Claude Code

Part of the #22161 slice 12 work: each hint of the ten claimed rule files
becomes one remedy line, and what it enumerated moves into the ids'
RULE_EXPLANATIONS entries.

Claude-Session: https://claude.ai/code/session_01KNKBCRDJCu5tGy3TEbvtrF
Co-authored-by: Claude <noreply@anthropic.com>
@github-actions github-actions Bot added size/l documentation Improvements or additions to documentation tests tooling labels Oct 12, 2026
@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 1 package(s): @objectstack/lint, touching 30 documentable anchor(s).

6 hand-written doc(s) NAME something this change touched and may need an implementation-accuracy re-verification:

  • content/docs/automation/approvals.mdx (via sys_approval_request (literal, a string literal in validateObjectReferences))
  • content/docs/automation/flows.mdx (via sys_approval_request (literal, a string literal in validateObjectReferences))
  • content/docs/automation/workflows.mdx (via sys_approval_request (literal, a string literal in validateObjectReferences))
  • content/docs/deployment/validating-metadata.mdx (via validateRlsPredicateEnforceability (symbol, a top-level function), validateRuleSchemaFormats (symbol, a top-level function), sys_approval_process (literal, a string literal in validateObjectReferences))
  • content/docs/plugins/packages.mdx (via sys_approval_request (literal, a string literal in validateObjectReferences))
  • content/docs/ui/translations.mdx (via sys_approval_request (literal, a string literal in validateObjectReferences))

⛔ 2 release-owned page(s) also name something this change touched. These are read-only:

  • content/docs/releases/v16.mdx (via sys_approval_request (literal, a string literal in validateObjectReferences))
  • content/docs/releases/v17/17-6.mdx (via sys_approval_request (literal, a string literal in validateObjectReferences))

content/docs/releases/ is RELEASE-OWNED (AGENTS.md "Documentation Guardrails"): release
notes are written centrally at release time, and a code PR that edits them is the exact PR
that guardrail exists to stop. They are still audited — read-only. If one of them is actually
wrong, file an issue or open a dedicated docs-only PR; do not edit it here.

What this run could not see
  • 1 anchor(s) matched too much of the corpus to be a work list: sys_user (literal, 40 pages)
  • 3 name(s) were too generic to anchor anything (single lowercase words)
  • the SDK route bridge reached 54 of 206 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 eb20c33c456f4b9fdeafd0e7a5b5de274888848e → packageMentionDocs.

Which tree this was computed on

This run read content/docs from d8096e2c5d162fea8007fc5aa7c1cb9620f2c3ca — the merge of head 9d56f0f4310049e79805aa54afc9b78a9180805a into base eb20c33c456f4b9fdeafd0e7a5b5de274888848e, 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 d8096e2c5d162fea8007fc5aa7c1cb9620f2c3ca && git checkout d8096e2c5d162fea8007fc5aa7c1cb9620f2c3ca
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin eb20c33c456f4b9fdeafd0e7a5b5de274888848e 9d56f0f4310049e79805aa54afc9b78a9180805a && git checkout -B drift-repro eb20c33c456f4b9fdeafd0e7a5b5de274888848e && git merge --no-ff 9d56f0f4310049e79805aa54afc9b78a9180805a

node scripts/docs-audit/affected-docs.mjs --json eb20c33c456f4b9fdeafd0e7a5b5de274888848e

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

Advisory only, and a precision-first one (#9192): a page is listed because it names a
symbol, wire route or SDK method this diff touched — not because it mentions a changed
package. Each row says which anchor put it there, so a wrong row is reportable rather than
merely annoying. To re-verify, run the docs-accuracy-audit workflow scoped to these files:
node scripts/docs-audit/affected-docs.mjs eb20c33c456f4b9fdeafd0e7a5b5de274888848e → pass the list as
args.docs, on the commit named under Which tree this was computed on.

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

Landing pre-checks at 9d56f0f431, by the owning seat: all green, queued

domain:spec seat 3 (#18883) · zhuangjianguo · session session_01KNKBCRDJCu5tGy3TEbvtrF · 2026-10-12T00:56Z · holder of claim 6114361143 on #22161.

pr_ready and automerge_enable follow.


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/l tests tooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants