Skip to content

feat(spec)!: object-metric drillDown.report is ReportSchema, object-timeline items the entry kind its variant selects, and action:group / action:menu members a closed inline action (#21464, S-final) - #21764

Merged
objectstack-fleet[bot] merged 4 commits into
mainfrom
claude/issue-21464-s-final
Oct 4, 2026

Conversation

@objectstack-fleet

Copy link
Copy Markdown
Contributor

Fixes #21464
Clause-②: yes (narrowing)

What this does

The S-final stage of the ComponentPropsMap z.unknown() close-out, and its last. It executes the maintainer's rulings on forks 1, 4 and 5 of the decision card #21704: fork 1 letter B (ruling record 5978663135, batch #276), forks 4 and 5 letters B and A (record 5979239990, batch #277), per the claim 5981629450. Read points are at the .objectui-sha pin 2e818d0b51ec, under objectui packages/ unless named. Every cited reader file is byte-identical at objectui main 2abec3a96 (the pin is an ancestor of it; plugin-timeline/src/renderHandoff.ts and types/src/data-display.ts differ there in comments and a typed click slot only, not in either arm).

row · member was now
object-metric · drillDown.report z.unknown() ReportSchema, by reference
object-timeline · items z.array(z.unknown()) a closed entry (module-private, built once) of objectui#6356's two arms, paired with the row's variant by a row refinement
action:group · actions[] z.record(z.string(), z.unknown()) per member a closed inline action (module-private): action:button's keys by type, plus the inline button's size
action:menu · actions[] the same the same member without size

With these three typed, the enumeration pin's fork lines are gone, the fork stage is gone with them, and a new §6 pins the close-out: no stage is declared and no ledger line is staged.

Fork 1 B — drillDown.report is ReportSchema

  • The read. The tile hands report to the shared drawer verbatim (plugin-dashboard/src/ObjectMetricWidget.tsx:742). DrillDownDrawer.tsx draws it as a report node when isDatasetBoundReport holds (:92, used at :115) — a non-empty dataset, or a joined report with a block that binds one — joining the metric's filter into the report's own runtimeFilter (:150-153). Any other value lists the records. objectui types the member as this package's ReportSchema author input (SpecReportInput). Both files are byte-identical from ab1879721595, where the fork was measured.
  • The premise, re-measured: admitted implies drawn. Since [finding] spec(report): a type: 'joined' report whose blocks bind no dataset parses and passes objectstack validate, while ReportSchema's own refinement comment and reports.mdx say "each block dataset-bound" #21702 (ed15448217) the joined arm refuses every block with no dataset, and every other type needs dataset and values. The new pin's §4 restates isDatasetBoundReport from the pin and checks it over 14 candidate reports: every report the member admits is drawn (zero exceptions), and the four writer shapes are admitted (a lit control).
  • The remaining difference runs one way only, and is pinned as such. The drawer also draws four incomplete reports the member refuses: a joined report with only some blocks bound, a joined report with a container dataset, a report with no name / label, and a summary report with no values. No measured writer authors any of them.
  • drillDown's other members, stage 5's. enabled, title, target, columns and maxRows stay the chart drill-down's by reference, and filter / mode stay refused by name. The block's describe and docblocks now say report is ReportSchema. The metric family pin's §3 key set is unchanged.
  • Parsed type. ReportSchema's defaults (type, drilldown) materialize on parse, so ObjectMetricPropsParsed now also differs from the authored type on drillDown.report. Its docblock says so. A page component's properties is not parsed on the way to the renderer, so the drawer still reads the report as written.

Fork 4 B — the timeline entry, both arms closed

  • The arms, read at the pin. The feed branches read time, title, description, variant, icon, content and className (plugin-timeline/src/renderer.tsx:1612-1659 vertical, :1697-1716 horizontal). The gantt branch reads a row's label (:1899-1900) and items (classifyGanttRows, :617-621; drawn at :1908), and each bar's startDate, endDate (:1909), variant (:1916) and title (:1918, :1921). That is exactly objectui's TimelineFeedItem (seven keys) and TimelineGanttItem / TimelineGanttItemBar, taken as ruled.
  • One entry shape, not a union. The entry declares every member of both arms, each optional, closed against anything else — objectui's own TimelineItemSchema shape. A union would fold an off-shape bar's issue into one invalid_union at the entry, as objectui's docblock records.
  • The row refinement (objectTimelineItemsFitVariant, restating objectui's timelineItemsFitVariant) pairs each entry with the arm the row's variant selects (absent means vertical). It refuses, each at the key it names: the arm's required key absent (title on a feed entry, label on a gantt row), or a key only the other arm declares. The arm key lists are read off the two shapes, never restated.
  • content is opaque, by the ruling: z.unknown(), its describe says "Held opaque", and the enumeration pin records it under a new opaque reason naming the ruling record (§2 checks both). It is not a slot position.
  • Gantt-bar dates are a string or a finite number (z.number() refuses Infinity and NaN). The Date arm is left out, by the ruling.
  • The record-composed keys (color, startDate, endDate, group, meta on an entry) are refused, each with what an authored entry writes instead. date is an alias for time.

Fork 5 A — the container members, measured from the reads

  • The read set, measured from action-group.tsx (InlineActionButton :91-174, DropdownActionItem :188-247, handleExecute :306-385), action-menu.tsx (ActionMenuItem :92-150, ActionAutoTrigger :177-191, handleExecute :244-334), static-params.ts (:142-148, :172-183) and auto-trigger.ts (:96). It is not transcribed from UIActionSchema. All four files are byte-identical from ab1879721595 and at objectui main.
    • Drawn: label (or name), icon, variant and tags (separator-before, the one tag read, :224 / :408).
    • Gated: visible and disabled.
    • Placed: locations (actionRendersAt on the group, :304).
    • Forwarded to the runner: type, name, label, description, target, openIn, method, params, bodyExtra, bodyShape, operation, patch, confirmText, successMessage, errorMessage, refreshAfter, locations, toast, resultDialog, onSuccess and objectName.
  • That is action:button's keys by type, with two differences the reads decide, and §3 derives the key set from ActionButtonPropsSchema.shape to pin them. undoable and recordIdField are not forwarded by either container. tags is drawn by both. size is read only by a group's inline button (:124, md drawn as default); an action:menu item reads none and declares none (the action:icon precedent).
  • Value schemas are the rows', key by key. visible / disabled take the rows' own actionCondition(), and §3 checks the same accept set and the same envelope. The runner-forwarded blocks stay z.unknown() with "forwarded to the runner" in their describes, so the enumeration pin's runner reason holds for each.
  • Refused, each with a prescription:
    • actionType → type (the rows' alias table, turned round);
    • endpoint / url / path / href → target (the rows' ACTION_TARGET_ALIASES);
    • enabled (the rows' own text) and autoTrigger (the rows' text on action:menu; on action:group, which never reads it, the text says so);
    • outcomeMessages → successMessage;
    • a member className → variant, or the node's own className;
    • properties → bodyExtra, or the action as its own action:button;
    • undoable / recordIdField;
    • an action:menu member's size.
  • outcomeMessages stays undeclared on all four action blocks. §3 pins that none of action:button, action:icon, action:group, action:menu and neither member shape declares it. The action:button / action:icon rows are not edited.

The census (writers of all three members)

Instrument. This run's TypeScript-AST walk over code and fenced docs, with same-file constants and spreads, .map over a constant list, templates and same-file helper calls evaluated. It reads:

  • object literals naming the block (the type also through a spread constant);
  • typed literals;
  • direct parses through the row (receiver constants resolved);
  • the block's JSX component (schema={…}, or ObjectMetricWidget's own props);
  • helper parameters at every same-file call site, for both member and whole-node positions;
  • a loose pass over every report / items / actions key in a file naming a block.

Every static value was parsed through this branch's rows; each value with a non-static part, and each refusal, was read by hand. Cross-check: it reproduces stage 5's drillDown population exactly (26 values) and the S-objectui-held census's 40 action:group / 19 action:menu values.

  • objectstack at 1289925c0a (the base; main moved 5 commits to 33f97917ac, merged here through os-regen-merge.sh, none touching a census corpus file):
    • one drill report (the metric pin's own), which parses;
    • one timeline items (component-element-navigation-17987.test.ts:213, a feed entry), which parses;
    • three container members (component-action-element-rows-20371.test.ts), which parse, plus that file's two probes the old row already refused;
    • no example, doc or skill writes any of the three.
  • objectui at the pin 2e818d0b51ec and at main 2abec3a96, the same counts at both:
    • drillDown.report: of the 26 drillDown values, 2 carry a report. The drawn one (objectMetricDrillDownMembers-8071.test.tsx:281) parses. The other is that file's it.each pair (:305), the two values the drawer does NOT draw, both refused. The loose pass's 34 report keys: 17 parse (drill-mirror tests and the dashboard guide); 9 are refused, all refusal probes on objectui's own faces ({ name }, { name: 42 }, the matrix with no values in drill-down-report-name-retired-11517.test.ts); 4 are not static and 4 are not report objects (i18n strings).

    • items: 18 values. 15 parse: feed entries, gantt rows and the empty gantt. The 3 refused are the render-time gantt date diagnostic's own probes, an array, false and null bar date (timeline-gantt-date-spelling-6907.test.tsx:338, timeline-gantt-date-type-rule-6781.test.tsx:419, timeline-gantt-null-date-6770.test.tsx:220).

    • Members: action:group 40 values (26 parse, 2 refused, 12 partly non-static) and action:menu 19 (11 parse, 3 refused, 5 partly non-static), all in tests but one run-time hand-off. Every refused member is a probe of a read the ruling refuses:

      • the member pin's className (action-group-menu-inputs-11168.test.tsx:249);
      • the outcomeMessages forward tests (action-outcomeMessages-forward-11344.test.tsx:147, :158);
      • the properties.params static-value tests (action-container-member-params-10290.test.tsx, read by hand);
      • the host's autoTrigger flag (action-overflow-autotrigger.test.tsx:298, and as a test device in action-onSuccess-forward.test.tsx:182, action-objectName-onClick-4202.test.tsx:127 and action-menu-host-disabled-11182.test.tsx).

      The partly non-static members are predicate variables, helper-built members and code-composed onClick functions, read by hand; their static keys parse.

    • The run-time hand-off is action:bar's overflow menu (action-bar.tsx:287). It hands the bar's own members — the registered actions a host passes — to action:menu at run time, never through the component-props gate, and those members are ActionSchema entries (the ruled-out option C). Recorded, not a block writer.

  • hotcrm at 4054ec2680 and cloud at 2205b53010: no writer of any of the three. hotcrm's four object-metric tiles declare no drillDown.
  • No measured working writer is refused, so the stop valve does not trip on any of the three members.

Release

  • .changeset/21464-component-props-report-items-action-members-typed.md: '@objectstack/spec': minor, the BREAKING banner, Clause-②: yes (narrowing), the ADR-0087 registered marker naming the three ids, a FROM → TO table and the census.
  • Three D3 entries in step 18: 18.ui-object-metric-drill-down-report-typed.ts, 18.ui-object-timeline-items-typed.ts and 18.ui-action-group-menu-members-typed.ts. The semantic region was regenerated by gen:migration-registry.
  • Three rationale fragments at orders 80, 81 and 82, the next free after S-forms' 79.
  • No D2 conversion and no RETIRED_KEYS_BY_MAJOR row: page-component properties is not on the save or load path, and no declared key is removed.
  • No export is added or removed: the entry, bar and member builders are module-private.
  • Generated: content/docs/references/ui/component.mdx (two member tables and the timeline entry table) and the strictness counts (ui/ 204 → 208, component.zod.ts 74 → 78: the entry, the bar and the two members).
  • dropped-refinements.baseline.json 670 → 676. ObjectMetricProps gains the five ReportSchema refinement sites carried by reference, the S-forms growth-by-reuse precedent. ObjectTimelineProps gains its root, the new pairing refinement.
  • Dogfood expression-conformance ledger: two rows, cel-action-member-visible (fail-closed) and cel-action-member-disabled (fail-closed), for the two new positions actionContainerMemberShape.visible / .disabled. Each has one evaluation leg, the container's, and no node gate (feat(spec): ComponentPropsMap rows for action:button/group/menu/icon and element:definition-list/repeater #20420 and the S-forms rows are the precedent).

Tests

  • Red first, through the published @objectstack/spec@17.6.0 (npm tarball, ComponentPropsMap[type].safeParse): 33 of the 34 values this branch refuses are ACCEPTED there. The one refused, items: 42, was already refused by the old z.array (a control). On this branch all 34 are refused.
  • The new pin component-report-items-action-members-typed.pin.test.ts:
    • §1: the writer shapes parse — timeline entries and members byte-identical, drill reports to exactly ReportSchema.parse(report);
    • §2: 34 refusals by code and path (the red-first set), plus the prescriptions;
    • §3: the vocabulary pins (the report def identity, the arms' key sets, the member key set derived from the button's, outcomeMessages absent on all six faces, the shared condition);
    • §4: admitted implies drawn;
    • §5: the D3 ids.
  • The enumeration pin: 23 new reasoned lines (the member predicates' ast, the runner-forwarded members, the report's two runtimeFilter positions, the opaque content), the four fork lines gone, and §2 and §6 added. The metric family pin: the drawn report row moves out of the byte-identical table into its own case, asserting the parse equals ReportSchema's answer (no expect removed, no skip).
  • pnpm --filter @objectstack/spec test at b7335d8374: Test Files 615 passed (615); Tests 18358 passed, 1 todo. pnpm --filter @objectstack/spec typecheck at the same head: exit 0, test layer held (52 files / 246 errors / 135 signatures; the touched pins are on tsconfig.test.json). pnpm --filter @objectstack/lint test: 119 files, 5627 tests passed. The showcase validate: passed. Dogfood test/expression-conformance.test.ts: 7 passed.
  • Ablation, one leg per member (two for the timeline), each through scripts/ablation-replace.mjs in a driver with an EXIT / INT / TERM trap, restored and proven by blob hash (HEAD blob b4dcaf34d2, git diff HEAD empty after every leg):
    • report → z.unknown(): 17 red;
    • items element → z.unknown(): 18 red;
    • the pairing refinement dropped: 5 red;
    • the action:group member → an open record: 15 red;
    • the action:menu member → an open record: 13 red.
  • Public door, through built lint's validateComponentProps. Nothing is reported for the drawn report drill, feed entries or group members. component-props-invalid is reported at drillDown.report.dataset / drillDown.report and at items.0.title / .label / .items. component-props-unknown-key is reported for an entry's color, a member's actionType and a menu member's outcomeMessages.
  • Derived gates: node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --commands gives 114 commands (merge base 33f97917a, 14 paths, 1705 changed lines). All 114 exit 0 at b7335d8374, and the --ran reconciliation reads 114 derived, 114 run, 0 NOT-MEASURED, 0 UNRUN. Two first ran as PREREQUISITE NOT MET (check:skill-examples, check:dual-build-cjs-loads) and were re-run green after turbo run build --filter=!@objectstack/docs (72 successful).
  • The changeset gates with this body as the pull_request payload (--event): check-changeset-no-major (LEVEL AXIS: yes (narrowing), no moved package graded patch), check-adr-0087-registration (one declared-breaking changeset, registered with the three ids) and check-empty-changeset, each exit 0.
  • eslint, a proven narrowing of pnpm lint: eslint --no-inline-config --format json over the 10 changed .ts files reads 10 files, 0 errors, 0 warnings. The population is the repo's one eslint.config.mjs, which ignored none of the 10. The narrowing excludes nothing: that config never enables type-aware linting (eslint.config.mjs:327-328, no parserOptions.project), so this diff cannot move a verdict on an untouched file.
  • NOT MEASURED: the Console Pin Gate, the Dogfood Regression Gate's full suite and the full pnpm lint, reason: CI-owned. objectui was read at the pin and at main, not built against this spec.

Acceptance notes

Noted, not filed:

  • A member's object params is forwarded as the request payload of a type: 'api' member only. On any other type the container drops it with a development warning (static-params.ts:172-183). The member keeps params as the rows do (z.unknown(), runner-forwarded), and its describe says so.
  • The action:bar hand-off above composes action:menu members from the host's registered actions at run time. Those carry ActionSchema keys (outcomeMessages, order, component, …) the member shape refuses. No gate judges that composition, and the action:button row's docblock already records the same member path for outcomeMessages.
  • The D2 conversion action-block-endpoint-to-target rewrites a stored endpoint on action:button / action:icon nodes only. A stored member endpoint is not rewritten. The census found no writer of one, and the refusal carries the rename.
  • Earlier step-18 rationale fragments (ui-object-metric-drill-down-typed, ui-object-timeline-mapping-typed) still say these members "stay open". The new fragments (orders 80-82) follow them and say they are now typed, so the joined text reads in order. The older fragments are not edited, the S-forms precedent.
  • The grid widget's camelCase keys (objectui#11610, landed on objectui main as 2abec3a9, not yet at the .objectui-sha pin) are not declared on the S-forms runtime form field here. That is fork 2's follow-up, outside this claim's file surface; its carrier is the next pin bump.

Not in this PR

  • No action:button / action:icon row edit, and no view.zod.ts / report.zod.ts edit.
  • No objectui change and no pin bump.

Generated by Claude Code

@github-actions github-actions Bot added size/xl documentation Improvements or additions to documentation protocol:ui tests tooling labels Oct 4, 2026
@github-actions

github-actions Bot commented Oct 4, 2026

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 1 package(s): @objectstack/spec, touching 31 documentable anchor(s). ⚠️ 1 changed file(s) yielded no anchor (packages/spec/dropped-refinements.baseline.json), so the pages documenting them are NOT COVERED by this run — this is not a clean bill of health for those files.

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

  • content/docs/ai/skills-reference.mdx (via visibleWhen (symbol, a field of const object ACTION_CONTAINER_MEMBER_ALIASES))
  • content/docs/automation/flows.mdx (via actionType (symbol, a field of const object ACTION_CONTAINER_MEMBER_ALIASES), visibleWhen (symbol, a field of const object ACTION_CONTAINER_MEMBER_ALIASES))
  • content/docs/data-modeling/field-types.mdx (via visibleWhen (symbol, a field of const object ACTION_CONTAINER_MEMBER_ALIASES))
  • content/docs/data-modeling/fields.mdx (via visibleWhen (symbol, a field of const object ACTION_CONTAINER_MEMBER_ALIASES))
  • content/docs/data-modeling/formulas.mdx (via visibleWhen (symbol, a field of const object ACTION_CONTAINER_MEMBER_ALIASES))
  • content/docs/data-modeling/schema-design.mdx (via visibleWhen (symbol, a field of const object ACTION_CONTAINER_MEMBER_ALIASES))
  • content/docs/data-modeling/validation-rules.mdx (via visibleWhen (symbol, a field of const object ACTION_CONTAINER_MEMBER_ALIASES))
  • content/docs/deployment/environment-variables.mdx (via visibleWhen (symbol, a field of const object ACTION_CONTAINER_MEMBER_ALIASES))
  • content/docs/deployment/validating-metadata.mdx (via actionType (symbol, a field of const object ACTION_CONTAINER_MEMBER_ALIASES))
  • content/docs/protocol/objectui/concept.mdx (via visibleWhen (symbol, a field of const object ACTION_CONTAINER_MEMBER_ALIASES))
  • content/docs/protocol/objectui/layout-dsl.mdx (via visibleWhen (symbol, a field of const object ACTION_CONTAINER_MEMBER_ALIASES))
  • content/docs/ui/pages.mdx (via visibleWhen (symbol, a field of const object ACTION_CONTAINER_MEMBER_ALIASES))
  • content/docs/ui/views.mdx (via visibleWhen (symbol, a field of const object ACTION_CONTAINER_MEMBER_ALIASES))

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

  • content/docs/releases/implementation-status.mdx (via visibleWhen (symbol, a field of const object ACTION_CONTAINER_MEMBER_ALIASES))
  • content/docs/releases/v12.mdx (via visibleWhen (symbol, a field of const object ACTION_CONTAINER_MEMBER_ALIASES))
  • content/docs/releases/v15.mdx (via visibleWhen (symbol, a field of const object ACTION_CONTAINER_MEMBER_ALIASES))
  • content/docs/releases/v16.mdx (via actionType (symbol, a field of const object ACTION_CONTAINER_MEMBER_ALIASES), visibleWhen (symbol, a field of const object ACTION_CONTAINER_MEMBER_ALIASES))
  • content/docs/releases/v17/17-0.mdx (via actionType (symbol, a field of const object ACTION_CONTAINER_MEMBER_ALIASES), visibleWhen (symbol, a field of const object ACTION_CONTAINER_MEMBER_ALIASES))
  • content/docs/releases/v17/17-2.mdx (via visibleWhen (symbol, a field of const object ACTION_CONTAINER_MEMBER_ALIASES))
  • content/docs/releases/v17/17-4.mdx (via visibleWhen (symbol, a field of const object ACTION_CONTAINER_MEMBER_ALIASES))
  • content/docs/releases/v17/17-5.mdx (via visibleWhen (symbol, a field of const object ACTION_CONTAINER_MEMBER_ALIASES))
  • content/docs/releases/v17/17-6.mdx (via actionType (symbol, a field of const object ACTION_CONTAINER_MEMBER_ALIASES), visibleWhen (symbol, a field of const object ACTION_CONTAINER_MEMBER_ALIASES))

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 changed file(s) yielded no anchor (packages/spec/dropped-refinements.baseline.json) — pages documenting those are invisible to this run
  • 7 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 — 138 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 a6a7547074d2f705f7a2c3f525250099c42b6b72 → packageMentionDocs.

Which tree this was computed on

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

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

⚠️ 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 a6a7547074d2f705f7a2c3f525250099c42b6b72 → pass the list as
args.docs, on the commit named under Which tree this was computed on.

@objectstack-fleet
objectstack-fleet Bot marked this pull request as ready for review October 4, 2026 17:22
@objectstack-fleet
objectstack-fleet Bot enabled auto-merge October 4, 2026 17:22
@objectstack-fleet
objectstack-fleet Bot added this pull request to the merge queue Oct 4, 2026
Merged via the queue into main with commit 4331a6b Oct 4, 2026
37 checks passed
@objectstack-fleet
objectstack-fleet Bot deleted the claude/issue-21464-s-final branch October 4, 2026 18:04
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 protocol:ui size/xl tests tooling

Projects

None yet

2 participants