Skip to content

fix(spec): chart drillDown mode guidance names object-data-table, not TABLE/PIVOT/METRIC - #20211

Merged
objectstack-fleet[bot] merged 2 commits into
mainfrom
claude/issue-20152-chart-drilldown-mode-guidance
Sep 27, 2026
Merged

objectstack-fleet[bot] merged 2 commits into
mainfrom
claude/issue-20152-chart-drilldown-mode-guidance

Conversation

@objectstack-fleet

Copy link
Copy Markdown
Contributor

Fixes #20152
Clause-②: no

What changed

ChartDrillDownSchema's guidance entry for mode (packages/spec/src/ui/chart.zod.ts) told an author who wrote drillDown.mode on a chart that the key belonged on a "TABLE / PIVOT / METRIC" widget. Two of those three blocks now refuse the same key on arrival:

  • object-metric refuses drillDown.mode at its TypeScript door since objectui#9002 (PR objectui#10681, merged) — the ruling this card follows (objectui#9002 comment 5643445104, B).
  • object-pivot refuses it at its TypeScript door since objectui#10685 (PR objectui#10710, merged).

Measured on objectui origin/main (0896838): neither object-metric's nor object-pivot's renderer ever read mode; only object-data-table does (ObjectDataTableSchema.drillDown / plugin-dashboard/src/ObjectDataTable.tsx). So the old sentence sent an author straight into a second refusal on two of the three blocks it named, and a stored config that lands on object-pivot (no zod mirror there) is silently ignored with no diagnostic.

The guidance now names the one block that actually reads mode:

mode ('filter' | 'record') is objectui's object-data-table drill key, not a chart one: …

The reasoning clause and "Delete the key" are unchanged. Its pin at packages/spec/src/ui/chart.test.ts:707 and the mirror pin at packages/lint/src/validate-react-page-props.test.ts:1033 moved with the wording.

Out of scope on this card's own evidence (triage note 3, comment 5851546523): the neighbouring report guidance entry ("a METRIC / PIVOT widget capability") is left untouched — its blocks were not remeasured here.

Premise check (H1)

Re-verified on objectui origin/main (0896838, PR objectui#10710 merged): ObjectMetricDrillDownConfig and the new ObjectPivotDrillDownConfig both carry mode?: never tombstones; object-data-table is the sole reader (isDrillEnabled guards it, 'record' opens the row, 'filter' turns the drill off). Premise holds in both the pre- and post-#10710 state, so premise_still_valid: true.

Ships, so this carries a changeset

@objectstack/spec's published files[] includes both dist and src/**/*.zod.ts; chart.zod.ts ships as source verbatim, and the sentence is also a runtime string in dist/ui/index.js / dist/ui/index.mjs (measured after a rebuild: 1 occurrence of the new wording in each, 0 of the old "TABLE / PIVOT / METRIC" spelling). .changeset/20152-chart-drilldown-mode-guidance.md — patch, no accept/reject behaviour changes.

Verification

  • pnpm --filter @objectstack/spec build — clean; new wording present in dist/ui/index.{js,mjs}, old wording absent.
  • pnpm --filter @objectstack/spec check:generated — all 15 generated artifacts up to date (no regeneration needed for a guidance-text-only change).
  • pnpm --filter @objectstack/spec test — 541 test files / 15896 tests passed.
  • pnpm --filter @objectstack/spec typecheck — clean.
  • pnpm --filter @objectstack/lint test — 108 test files / 4169 tests passed, after building lint's workspace dependency closure (@objectstack/formula, @objectstack/spec, @objectstack/sdui-parser — none were built in the fresh worktree).
  • pnpm --filter @objectstack/lint typecheck — clean.
  • node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --commands, re-derived after adding the changeset → 83 derived families; ran all 83 and reconciled with --ran: 78 run (all green), 5 NOT MEASURED, 0 UNRUN. The 5 NOT MEASURED (check:doc-formula-expressions, check:docs-transcript-drift, check:dual-build-cjs-loads, check:lean-entry-closure, check:type-check-debt) each exit 3 PREREQUISITE NOT MET — they read a whole-tree pnpm build this local verification's scope does not owe (CI's Build Core job covers it).
  • Six silent-verdict rosters whose scan directory this diff sits in were read directly rather than trusted on silence: check-changeset-fixed, check:meta-url-spelling, check:spec-changes, check:authz-resolver, check:error-code-casing, check:filter-alias-parity — all green.

Generated by Claude Code

… TABLE/PIVOT/METRIC

object-metric (objectui#9002/PR objectui#10681, merged) and object-pivot
(objectui#10685/PR objectui#10710, merged) both refuse drillDown.mode at
their TypeScript door now. Only object-data-table still reads it. The
published refusal text an author sees for drillDown.mode on a chart sent
them to all three blocks, two of which now refuse the same key on arrival.

Reword the guidance to name the one block that actually reads mode, and
move its pin. The neighbouring `report` guidance entry is left alone —
out of scope for this card.

Co-authored-by: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QcAS3qiYYZNezaxZxaUdMV
patch — the guidance sentence ships as source (chart.zod.ts is in
@objectstack/spec's published src/**/*.zod.ts) and as a runtime string in
dist/ui/index.{js,mjs}; no accept/reject behaviour moves.

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

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

1 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 54 of 207 client-bound route-ledger rows — the other 153 have no registrar path: tail to select them, so pages documenting THEIR client methods cannot appear above, on this or any run. Of those 153: 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; 98 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 — 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 1c8b320a894b31dcfc76c33c8e7a62b8986d893a → packageMentionDocs.

Which tree this was computed on

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

node scripts/docs-audit/affected-docs.mjs --json 1c8b320a894b31dcfc76c33c8e7a62b8986d893a

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

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

Contract review

Served-tier: 111/111 CONTRACT_REVIEW_TIER
Head-sha: 8c243371dc73f932ed9bba532b86e22b6426c49a

① Derived judgments

  1. Head unchanged at 8c24337 (2 commits over merge-base d7c0241; 4 files, +44/-3) and matches the four named files.
  2. Premise, measured on objectui origin/main 25c7d58 (moved past the PR's 0896838; objectui 2FA backup-code regeneration on the navigable surface is a lockout path (sys_user.generate_backup_codes has no resultDialog) #10681 and [finding] GraphQL residue outside #10583's site list: api/index.mdx still documents a /graphql route that the dispatcher removed #10710 both merged=true, merge commits 526fc11 and 5ad3b88 are ancestors): the sole runtime reader of drillDown.mode is plugin-dashboard/src/ObjectDataTable.tsx:644 ((drillDown?.mode ?? 'record') === 'record'). ObjectMetricWidget.tsx:193 types drillDown as ObjectMetricDrillDownConfig and ObjectPivotTable.tsx:105 as ObjectPivotDrillDownConfig; both carry mode?: never (types/src/data-display.ts:2442-2461, 2485-2495). Every other mode hit is a writer (ObjectChart.tsx:1526, DashboardGridLayout.tsx:401, DashboardRenderer.tsx:815, DrillDownDrawer.tsx:130), a registration string, or a declaration; plain PivotTable.tsx:186 reads drillDown only via isDrillEnabled. No second reader, so "the one block" holds.
  3. New sentence TRUE: object-data-table is the registered block name (objectql.zod.ts:2771) and its schema keeps mode (objectql.ts:4835). Reason clause and "Delete the key" are byte-identical; the chart-side reason (a segment is always an aggregate) still holds. Accepted set unchanged: the diff touches one string in the guidance map and no shape member.
  4. Pins: chart.test.ts:707 asserts toContain('object-data-table') and that no rename is suggested; validate-react-page-props.test.ts:1033 asserts the same substance through the lint gate. Both name the block, not merely the old phrase's absence. Whole-repo grep on the head for TABLE / PIVOT / METRIC (exact and loose TABLE.{0,4}PIVOT.{0,4}METRIC) hits only the changeset's own quotation; on origin/main the phrase lived in exactly the three moved files, so no doc, skill or generated artefact was missed.
  5. Changeset sentences measured TRUE: packages/spec/package.json files[] holds dist and src/**/*.zod.ts; src/ui/index.ts:13 re-exports ./chart.zod; tsup.config.ts:85,208 builds src/ui/index.ts as ['esm','cjs'], and exports["./ui"] resolves to dist/ui/index.mjs / dist/ui/index.js. The "1 occurrence each" count was not re-measured here (no rebuild), but the string is a runtime argument of an exported strictObject, so it cannot be shaken out. The objectui validate / safeValidateSchema claim holds: objectui objectql.zod.ts:2573 mounts stripImportedDefaults(SpecChartDrillDownSchema), and that walker clones by patching each node's own def, so the strict guidance map survives. "Silently ignored" holds for both blocks: objectui has no object-metric zod mirror and object-pivot has none by its own docblock. No garbled or self-contradicting sentence; "not all three it used to" is elliptical but unambiguous.
  6. CI on the head: 39 check-runs, 33 success, 6 skipped, 0 failed, 0 pending.

② Semver level

patch is right: AGENTS.md §3 (lines 1073-1075) gives a fix in a released package a patch changeset, never skip-changeset. Clause-②: no is right: no key enters or leaves ChartDrillDownSchema. No BREAKING marker or ADR-0087 line is owed for no with no arm, and none is present. @objectstack/spec is in the fixed group, so a single spec entry is the correct shape.

③ Boundary flags

  • report entry ("a METRIC / PIVOT widget capability") untouched per triage note 3; my reading on objectui origin/main: still true, ObjectMetricWidget.tsx:584 and ObjectPivotTable.tsx:361 both hand drillDown.report to DrillDownDrawer, which renders it (DrillDownDrawer.tsx:77).
  • chart.zod.ts:440-443 docblock above the schema still says "shared by its table / pivot / metric widgets (mode, report)"; it describes objectui's shared DrillDownConfig, which does still carry both, and does not quote this entry, so not a leftover; a follow-up could tighten it.
  • Reason-clause nuance: on object-data-table, mode: 'filter' turns the row drill off rather than drilling through (objectui data-display.ts:2345-2351); the clause states the key's declared vocabulary, which the shared type documents identically, so not a defect of this card.

Implemented-by: claude/issue-20152-chart-drilldown-mode-guidance
Reviewed-by: session_01QcAS3qiYYZNezaxZxaUdMV

VERDICT: PASS

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

Projects

None yet

2 participants