Skip to content

Commit b88f5e8

Browse files
os-zhuangclaude
andauthored
docs(spec): re-anchor two self-descriptions to measured reality (#7056) (#7065)
* docs(spec): re-anchor the `chartConfig` liveness evidence to what was actually measured (#7017) `widgets.children.chartConfig`'s evidence claimed "chart-config bag forwarded to the chart renderer". Nothing ever measured that: the cited lines took the bag out of the widget and the line after them read exactly one key (`showLegend`, #3135), leaving the rest of `ChartConfigSchema` declared and inert. #5175 measured the real state — 1 of 14 keys reaching the renderer — and recorded that this sentence had already mis-steered the #5022 measurement for half its length. Re-anchored to today's objectui main rather than to either older state, because #7016 landed the enforce half in between. At objectui `@230ffd875`, `chartConfigPresentation` lowers NINE keys, one `if` per key, and the caller spreads the result onto the chart schema handed to the renderer; a DOM test pins each forwarded key. The remaining FIVE are named as unforwarded with the reason: `xAxis`/`yAxis`/`series` are derived from the dataset selection, `type` is answered by the widget's own `type` through `CHART_TYPE_MAP`, and `aria` has no reader on that path. The verdict is unchanged (`live`) — #5175's measurements never demanded a different one; they demanded evidence that supports it. No `children` are opened and no key is classified: the narrowing half for the five unforwarded keys is still an open maintainer decision on #5175, and the note says so. `verifiedAt` is stamped 2026-08-09 and `evidenceScope: "cross-repo"` added — the objectui realm was walked, at a pinned commit, which is what those two fields (#7024) exist to record. Co-authored-by: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PoaTe9AqwDvcGiE92dUp5Z * docs(spec): `allowAddTab` describes the session-scoped semantics #5236 A1 shipped (#6961) #5073 promoted `allowAddTab` into `UserFiltersSchema` with a `.describe()` narrowed on purpose to "renders an add-tab affordance": the button objectui shipped carried no click handler, and promising "end users can add presets" would have advertised a capability the runtime did not deliver (PD#10). The maintainer ruled A1 — implement, session-scoped (#5236, 2026-08-06) — and objectui#3926 delivered it (merged, objectui main `cf5be4ec2`). The describe now states what is shipped: the affordance asks for a name and snapshots the filters currently applied as a new tab; the tab is SESSION-SCOPED — it lives only for the current mount and is never written back as metadata (ADR-0047) — and it carries a remove control the authored presets do not. #5073's applicability sentence is kept verbatim (page lists only; object views use `listViews` for named presets). The `⚠️ Scope of the promotion` TSDoc above the schema recorded the dead-button state as current, so it was realigned too: it now records how the narrowing was resolved instead of asserting a state that has not held since objectui#3926. Documentation semantics only — the ruling confirmed renderers do not read this text. `content/docs/references/ui/view.mdx` is the regenerated projection of the new describe (`gen:schema` + `gen:docs`); no schema key, enum member or strictness posture moves, so the acceptance face is byte-identical. Co-authored-by: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PoaTe9AqwDvcGiE92dUp5Z * chore(changeset): two self-descriptions re-anchored to measured reality (#7056) One patch changeset for the sweep — both members land in `@objectstack/spec` and neither changes behaviour. Matches the predecessor of this criterion family (#7024 / PR #7032), whose prose-level spec entries were also patch. Co-authored-by: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PoaTe9AqwDvcGiE92dUp5Z --------- Co-authored-by: Claude <noreply@anthropic.com>
1 parent aa4b90d commit b88f5e8

4 files changed

Lines changed: 74 additions & 11 deletions

File tree

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
---
2+
"@objectstack/spec": patch
3+
---
4+
5+
docs(spec): two self-descriptions re-anchored to measured reality — the `chartConfig` liveness evidence and `allowAddTab`'s `.describe()` (#7017, #6961)
6+
7+
Sweep card #7056. Both members are prose that stopped being answerable to the
8+
code it describes: one **overstated** what a reader delivers, one **understated**
9+
what a renderer now delivers. Zero acceptance-face change — no schema key, no
10+
enum member, no strictness posture moves, and the only generated artifact that
11+
shifts is the `.describe()` row in `content/docs/references/ui/view.mdx`.
12+
13+
**#7017`widgets.children.chartConfig`'s evidence said "chart-config bag
14+
forwarded", which was never measured.** The cited lines took the bag out of the
15+
widget and the line after them read exactly one key (`showLegend`, #3135); the
16+
rest of `ChartConfigSchema` stayed unforwarded. #5175 measured that (1 of 14
17+
keys reaching the renderer) and recorded that the wording had already mis-steered
18+
the #5022 measurement for half its length. Since then #7016 landed the enforce
19+
half in objectui, so the row is re-anchored to today's reality rather than to
20+
either older state: at objectui `@230ffd875`, `chartConfigPresentation` lowers
21+
**nine** keys one `if` per key — `showLegend`, `showDataLabels`, `title`,
22+
`subtitle`, `description`, `height`, `annotations`, `interaction` and `colors`
23+
(split into the positional palette and `categoryColors`) — and the caller spreads
24+
the result onto the chart schema handed to the renderer, with a DOM test pinning
25+
each forwarded key. The remaining **five** are named as unforwarded and why:
26+
`xAxis` / `yAxis` / `series` are derived from the dataset selection, `type` is
27+
answered by the widget's own `type` through `CHART_TYPE_MAP`, and `aria` has no
28+
reader on that path. The entry also gains `verifiedAt: 2026-08-09` and
29+
`evidenceScope: "cross-repo"` (the objectui realm was walked, at a pinned
30+
commit), the two fields #7024 added for exactly this.
31+
32+
The verdict is unchanged — `live`, as it was, now for a reason the evidence
33+
actually supports. No `children` are opened and no key is classified: the
34+
narrowing half for the five unforwarded keys is still an open maintainer decision
35+
on #5175, and the note says so, so this row cannot be read as pre-empting it.
36+
37+
**#6961`UserFiltersSchema.allowAddTab` still described the interim,
38+
deliberately-narrowed contract.** #5073 promoted the key with a `.describe()`
39+
that promised only that the tab bar *renders* an add-tab affordance, because the
40+
button objectui shipped had no click handler — narrowing on purpose rather than
41+
advertising a capability the runtime did not deliver (PD#10). The maintainer then
42+
ruled **A1 — implement, session-scoped** (#5236, 2026-08-06) and objectui#3926
43+
delivered it. The describe now states the semantics that are actually shipped:
44+
the affordance asks for a name and snapshots the filters currently applied as a
45+
new tab; the tab is **session-scoped** — it lives only for the current mount and
46+
is never written back as metadata (ADR-0047, which scopes an end user's filter
47+
choices to the session) — and it carries a remove control the authored presets do
48+
not. The applicability sentence #5073 wrote is kept verbatim: page lists only,
49+
object views use `listViews` for named presets. The `⚠️ Scope of the promotion`
50+
TSDoc above the schema, which recorded the dead-button state as current, now
51+
records how it was resolved instead.
52+
53+
The ruling confirmed renderers do not read this text, so this is documentation
54+
semantics only: no runtime change, and the JSON-Schema baselines and the docs
55+
site are regenerated with the describe.

content/docs/references/ui/view.mdx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -734,7 +734,7 @@ End-user quick-filter configuration (Airtable "User filters" parity)
734734
| **fields** | `{ field: string; label?: string \| Record<string, string>; type?: Enum<'select' \| 'multi-select' \| 'boolean' \| 'date-range' \| 'text'>; options?: object[]; … }[]` | optional | Fields exposed as quick filters (dropdown/toggle elements) |
735735
| **tabs** | `{ name: string; label?: string \| Record<string, string>; icon?: string; view?: string; … }[]` | optional | Named filter presets rendered as tabs (tabs element). Reuses ViewTabSchema |
736736
| **showAllRecords** | `boolean` | optional | Show an "All records" tab before the presets (tabs element) |
737-
| **allowAddTab** | `boolean` | optional | Render an "add tab" affordance after the presets (tabs element). Page lists only — object views use `listViews` for named presets |
737+
| **allowAddTab** | `boolean` | optional | Let end users add their own tab after the presets (tabs element): the affordance asks for a name and snapshots the filters currently applied as a new tab. SESSION-SCOPED — an added tab lives only for the current mount, is never written back as metadata (ADR-0047), and carries a remove control the authored presets do not. Page lists only — object views use `listViews` for named presets |
738738

739739

740740
---

packages/spec/liveness/dashboard.json

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -47,9 +47,10 @@
4747
},
4848
"chartConfig": {
4949
"status": "live",
50-
"verifiedAt": "2026-08-03",
51-
"evidence": "objectui @91757a7: packages/plugin-dashboard/src/DatasetWidget.tsx:602-603 (chart-config bag forwarded to the chart renderer)",
52-
"note": "chart presentation config; read on the dataset-bound chart path."
50+
"verifiedAt": "2026-08-09",
51+
"evidenceScope": "cross-repo",
52+
"evidence": "objectui @230ffd875: packages/plugin-dashboard/src/DatasetWidget.tsx:380-429 — chartConfigPresentation lowers NINE of the declared keys, one `if` per key (:390 showLegend, :391 showDataLabels, :393 title, :395 subtitle, :397 description, :401 height, :403 annotations, :405 interaction, :419 and :425 colors, split into the positional palette and categoryColors); objectui: packages/plugin-dashboard/src/DatasetWidget.tsx:1091 calls it and :1118 spreads the result onto the chart schema handed to the renderer; objectui: packages/plugin-dashboard/src/__tests__/DatasetWidget.chartConfig.dom.test.tsx pins the DOM effect of each forwarded key",
53+
"note": "chart presentation config on the dataset-bound chart path — read PER KEY, not forwarded as a bag. Of the 14 keys ChartConfigSchema declares, 9 reach the renderer (above) and 5 do not: xAxis/yAxis/series are derived from the dataset selection, so an authored value would shadow the derived binding; type is answered by the widget's own `type` through CHART_TYPE_MAP; aria has no reader on this path (AdvancedChartImpl has no `aria` prop and the ARIA injection reads the flat ariaLabel/ariaDescribedBy/role). This entry previously read 'chart-config bag forwarded to the chart renderer', which was never measured: at that time exactly one key (showLegend, #3135) was lowered, and the overstatement mis-steered the #5022 measurement for half its length. #5175 measured the real 1-of-14 state, #7016 forwarded the keys the chart block actually delivers, and the narrowing half for the 5 unforwarded keys is still open on #5175 — do not read this row as classifying them."
5354
},
5455
"colorVariant": {
5556
"status": "dead",

packages/spec/src/ui/view.zod.ts

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -775,12 +775,19 @@ export const UserFilterFieldSchema = lazySchema(() => strictObject({
775775
* `packages/spec` and objectui two sources of truth for one contract — the
776776
* fork #2231's derive-by-reference unification exists to prevent (PD#12).
777777
*
778-
* ⚠️ Scope of the promotion: `allowAddTab` declares that the tab bar RENDERS an
779-
* add-tab affordance. The button objectui renders today carries no click
780-
* handler, so it is presentational — filed against the renderer as #5236, and
781-
* deliberately NOT written into the `.describe()`, because a contract that
782-
* promises "end users can add presets" would be advertising a capability the
783-
* runtime does not deliver (PD#10).
778+
* ⚠️ Scope of the promotion, and its RESOLUTION (#5236 → #6961). At promotion
779+
* time `allowAddTab` was described as declaring only that the tab bar RENDERS
780+
* an add-tab affordance: the button objectui rendered carried no click handler,
781+
* so it was presentational, and the narrower wording was deliberate — a
782+
* contract promising "end users can add presets" would have advertised a
783+
* capability the runtime did not deliver (PD#10). The maintainer then ruled
784+
* **A1 — implement, session-scoped** (#5236, 2026-08-06), objectui#3926
785+
* delivered it (`packages/plugin-list/src/UserFilters.tsx` — naming popover,
786+
* snapshot of the applied filters, component state only, remove affordance on
787+
* the added tab), and the `.describe()` below was upgraded back to the real
788+
* semantics. The narrowing was the interim state the ruling closed, not the
789+
* contract: the key now promises the behaviour, and PD#10 is satisfied by the
790+
* delivery rather than by the hedge.
784791
*
785792
* ## What closing flips, and why that flip is wanted (批 6e's question)
786793
*
@@ -814,7 +821,7 @@ export const UserFiltersSchema = lazySchema(() => strictObject({
814821
showAllRecords: z.boolean().optional()
815822
.describe('Show an "All records" tab before the presets (tabs element)'),
816823
allowAddTab: z.boolean().optional()
817-
.describe('Render an "add tab" affordance after the presets (tabs element). Page lists only — object views use `listViews` for named presets'),
824+
.describe('Let end users add their own tab after the presets (tabs element): the affordance asks for a name and snapshots the filters currently applied as a new tab. SESSION-SCOPED — an added tab lives only for the current mount, is never written back as metadata (ADR-0047), and carries a remove control the authored presets do not. Page lists only — object views use `listViews` for named presets'),
818825
}).describe('End-user quick-filter configuration (Airtable "User filters" parity)'));
819826

820827
/**

0 commit comments

Comments
 (0)