feat(types,plugin-form,plugin-charts,app-shell)!: dashboard widgets bind a dataset in the catalog and docs; FormulaFieldMetadata takes the spec's expression; three display-pointer readers read displayField alone (objectui#11070, round 6) - #11333
Conversation
…ind datasets; formula -> expression; display_field legs retired (objectui#11070 round 6) - (i) objectui#11228 ruling C: the six filtered-dashboard catalog fixtures, dashboard-filters.md and the schema-reference DashboardComponentSchema fence move to the ADR-0021 dataset form; the inline dialect is no longer taught (also plugin-dashboard.mdx and the plugin-dashboard README). The strict face is unchanged and keeps refusing the nine keys by name (pinned), and every plugin-dashboard catalog entry parses on it (pinned). - (ii) FormulaFieldMetadata.formula -> expression (FieldSchema's member by reference); formula.mdx follows; sanitizeFormData drops its formula flag read. objectui#6526 ruling B's Studio arm is untouched. - (iii) deriveColumns / hydrateColumns, ObjectChart and resolveActionParams read displayField, then reference_field; the display_field legs and RuntimeField.display_field are retired. Fixtures move to displayField; the fold pins keep the snake spelling as input. - (iv) dated notes on the 7166 and lucky-donkeys-shave changesets. Claude-Session: https://claude.ai/code/session_01TdiauJaVCHuj45EzZGUxHh Co-authored-by: Claude <noreply@anthropic.com>
…d 6 (objectui#11070) Claude-Session: https://claude.ai/code/session_01TdiauJaVCHuj45EzZGUxHh Co-authored-by: Claude <noreply@anthropic.com>
… check:doc-types (objectui#11070 round 6) The DashboardComponentSchema example's `component` chart is now a dataset-bound `area` widget (objectui#11228 ruling C). `area` is a widget family, not a node type, so the page declares it with its reason, the way the dashboard pages already declare `bar` / `line`. Claude-Session: https://claude.ai/code/session_01TdiauJaVCHuj45EzZGUxHh Co-authored-by: Claude <noreply@anthropic.com>
…-round6 Claude-Session: https://claude.ai/code/session_01TdiauJaVCHuj45EzZGUxHh Co-authored-by: Claude <noreply@anthropic.com>
…-round6 Claude-Session: https://claude.ai/code/session_01TdiauJaVCHuj45EzZGUxHh Co-authored-by: Claude <noreply@anthropic.com>
|
changeset-claim-re-read
|
✅ Console Performance Budget
The eager closure is every chunk the entry reaches through static imports — what the browser fetches and parses before the app renders. The entry chunk on its own is a small fraction of it. 📦 Bundle Size Report
Size Limits
|
|
CI red that is not this PR's:
|
✅ Console Performance Budget
The eager closure is every chunk the entry reaches through static imports — what the browser fetches and parses before the app renders. The entry chunk on its own is a small fraction of it. 📦 Bundle Size Report
Size Limits
|
Round 6 (PR #11333) and objectui#10859 batch 6 landed. Two test files conflicted, each resolved by keeping both sides: the 11070 strict-face pin keeps round 6's dashboard-dialect rows and round 7's node-level object-chart binding row (round 6's "refused until declared" row is superseded by the declaration), and the 10872 envelope census names both object-gantt (batch 6) and object-chart (round 7). Claude-Session: https://claude.ai/code/session_01TdiauJaVCHuj45EzZGUxHh Co-authored-by: Claude <noreply@anthropic.com>
Refs #11070 · Refs #11228
Clause-②: yes (narrowing).
FormulaFieldMetadata.formularetires for the spec'sexpression(typed by reference),sanitizeFormDatastops readingformula, and three display-pointer readers (deriveColumns/hydrateColumns,ObjectChart, the action-param resolver, with its internalRuntimeField.display_fieldmember) drop theirdisplay_fieldleg, under the startup no-gradualism rule. Item (i) alone, the dashboard round, was ruledClause-②: no: it moves fixtures and docs only, and the strict face does not change. The break is priced in the changeset.Round 6 of objectui#11070 (claim
5924126483). Four items in one PR: (i) objectui#11228's ruling C (5921018991, intake5921153525); (ii) seat answer A onformula(5923126508); (iii) the threedisplay_fieldconsumer legs (round 5's out-of-scope finding); (iv) dated changeset notes.What changed
(i) Dashboard widgets bind a dataset, everywhere objectui teaches one (objectui#11228 ruling C).
examples/schema-catalog/src/schemas/plugin-dashboard/filtered-dashboard*.jsonfixtures are in the ADR-0021 dataset form: every widget names adatasetwithdimensions/values, and none carries rows. Each demo keeps its filter feature (dateRangepresets,optionsFrom, text / number / lookup filters,targetWidgets,filterBindingsoverrides and opt-outs). No demo was dropped: the docs gallery's no-backend harness (apps/site/app/components/galleryDataSource.ts) answersqueryDatasetwith placeholder rows, and the gallery render pin draws every widget title with zero dataset errors.dataset-widgetsvariant is re-titled incatalog-meta.json("Widgets Over Two Datasets"), because "Dataset + Inline Widgets" became false;index.tsis regenerated from it.content/docs/guide/dashboard-filters.md: the data-surface table becomes one paragraph (a widget binds a dataset) plus a "not an authoring surface" note naming the nine keys; the retired-shape callout, the "Dataset widgets" section, the working-examples note and Known limitations stop offeringoptions.data.content/docs/api/schema-reference.md'sDashboardComponentSchemaexample: the metric, thecomponentchart and thelistwidget become dataset-boundmetric,areaandtablewidgets, and the prose under it says what a widget's data is. The standalonechartcomponent's ownchartType/xAxisKey/seriessection is untouched.strict-face-read-keys-11070.test.tsasserts each of the nine is refused by name (with a dataset-widget control that parses);plugin-dashboard-component-schema.test.tsasserts everyplugin-dashboardcatalog entry parses onStrictAnyComponentSchema.(ii)
FormulaFieldMetadata.expressionreplacesformula(seat answer A).packages/types/src/field-types.ts:expression?: SpecField['expression'](a CEL string or the spec's{ dialect, source, … }envelope). Type-level pins: by-reference identity, andformulajoins the retired-members list.content/docs/fields/formula.mdx: the typed fence, the plaintext examples (rewritten in CEL againstrecord.) and the prose. The backend section's pseudo-code goes; it said nothing true about how the platform evaluates a formula.plugin-form/src/sanitize.ts: theif (fieldDef.formula) continue;guard is removed after measurement (below). A new case pins that aformulakey marks nothing computed. TheformArmsWritePayload-10563fixture's formula column moves toexpression.ObjectFieldInspector's seed and clear,ObjectFormCanvas/FieldStub,object-fields-io.ts,clientValidation.tsandretired-field-keys.tsare not in the diff.(iii) The three
display_fieldconsumer legs.deriveColumns/hydrateColumns(plugin-form):d?.displayField || d?.reference_field. Before this change they had nodisplayFieldleg at all, so a spec-spelled lookup got no display pointer on its master-detail grid column; it does now (probe below).ObjectChart'sresolveGroupByLabels(plugin-charts):displayField, thenreference_field, then'name'.resolveActionParams(app-shell):field.displayField ?? field.reference_field; theRuntimeField.display_fieldmember goes.reference_fieldstays (FieldSchemadeclares no twin the fold could stamp it onto).display_fieldmove todisplayField(deriveMasterDetail.test.ts,resolveActionParams.test.ts,expandableFamily.identity-5874.test.ts). The two "adisplay_field-only def still resolves" pins flip to "no longer resolves", and each consumer gains a pin that keeps the snake spelling as its INPUT and shows the ingestion fold (normalizeSchemaReferenceKeys, objectui#7650 ruling A) delivers it asdisplayField.(iv) Changesets.
.changeset/11070-dashboard-formula-round6.md(minor fortypes,plugin-form,plugin-charts,app-shell; the break measured and stated). Dated, append-only notes:.changeset/7166-retire-inert-fieldmeta-copies.md(itsdisplay_fieldsentence was already false: objectui#7155 retired the cell's leg) and.changeset/lucky-donkeys-shave.md(its KEEP verdicts for these threedisplay_fieldreads are now false).Files beyond the claim's named surface, each forced by the round
packages/plugin-dashboard/README.mdandcontent/docs/plugins/plugin-dashboard.mdxtaught the same inline dialect (options.data/xField/yField) in a TypeScript fence and prose, outside M3's JSON corpus. A bounded in-place fix: the same defect class, a mechanical move to the ruled form, no open PR holds either file, and the README's existing gate (readme-dashboard-examples-spec-valid.test.ts) judges it. The seat should append both to the claim's file surface.scripts/check-doc-component-types.mjs: one exemption entry (areaonschema-reference.md).check:doc-typesrefused the rewritten example'sareawidget kind, which is a widget family and not a node type; the dashboard pages already declarebar/linethis way. The script's own tests and every test that names it ran green (25 files, 1393 tests).examples/schema-catalog/src/catalog-meta.jsonand the regeneratedindex.ts(a title made false); comment-only edits inDashboardGridLayout.legacyRetired.test.tsx(it describedfiltered-dashboard.json's widgets as inline) andpackages/core/src/utils/reference-keys.ts(it namedderiveColumns'display_fieldread as a kept snake read; it now namesreference_field).Fork clause: not triggered
No real producer of the nine keys exists outside objectui's demo corpus.
origin/maind67b94280):xField/yField0 occurrences in the whole tree; the six dashboard files (app-crm, app-showcase ×3, app-todo, platform-objects) carry 60dataset:bindings, and their widgetoptionscarryformat/currency/color/suffix/showLegend/horizontal/showDataLabels, none of the nine (that is objectstack#20960's catchall class, not here).chartType/xAxisKeyhits are chart, view and page-node keys, none on a dashboard widget. Control: the same channel findsdataset:in all six files.options.data. Writers ofoptions: { datain non-test source: 0 (control: the same pattern, 25 in tests). Theprovider: 'object'writers (anchors.ts,runtime-metadata-persistence.ts) build list / form VIEW configs, not dashboard widgets.xField/yFieldin non-test source are renderer and helper reads only.Census, base
0c6f9bb→ headxField/yFieldwrites on authoring surfaces (content,examples,apps,skills,docs, package READMEs)schema-reference.mdexample)display_fieldcode reads inpackages/*/src+apps/*/src(non-test, non-comment)RuntimeFieldmembernevertombstone and a register note)formulacode linessanitize.ts1,field-types.ts1formula:writes informula.mdxexpression:)Probes
Spec, installed
@objectstack/spec17.5.0.FieldSchemarefusesformulaon all 49 field types (unrecognized_keys, with the rename hint toexpression); controls: a baretextdef accepted,zzz_not_realrefused,expressionaccepted both as a string and as{ dialect: 'cel', source }. That is H4: no served definition can carryformulaon a non-formula type, and everytype: 'formula'field is dropped byCOMPUTED_FIELD_TYPESanyway. Producer census: objectstack writesformula:on a field only inmetadata-core's FLS test contract, on atype: 'formula'field.CEL. The nine expressions
formula.mdxnow teaches all parse with@objectstack/formula17.5.0'sparseCelToAst; control: the oldcreated_at + 7 daysdoes not parse.Display pointer (a scratch vitest file, copied into the worktree, run at base and head, removed by trap, never committed). A lookup whose pointer is
title, read byderiveColumns/hydrateColumns,resolveGroupByLabelsandresolveActionParams:display_field, handed in raw (BYO)title· axis label fromtitle·titlename· nonedisplay_field, throughObjectStackAdapter.getObjectSchematitle·title·titletitle·title·titledisplayField, rawtitle·titletitle·title·titledisplayField, through the adaptertitle·titletitle·title·title(Column order: master-detail column, chart axis, action param.) The first row is the BYO break the changeset states; the bold cells are the master-detail fix.
M3,
scripts/measure-strict-authoring-face.mjs --json, plus the PR #11069findUndeclaredKeysport for the pairs0c6f9bb95bd23c2abe905139a491From
main95bd23cto the merged head2abe905, exactly the nine dashboard pairs leave; no pair enters and no other pair moves. The last merge (5262f7d, objectui#11276) moved no M3 reading on this branch. H2 holds.Hypotheses
schema-reference.md's example, notdashboard-filters.md: the guide carried the dialect in a table row and prose, which M3's JSON-fence corpus does not read. The README andplugin-dashboard.mdxtaught it too, outside that corpus (see "Files beyond the claim").type-checkis green intypes,fields(the one importer, whoseFormulaFieldreadsreturnTypealone),plugin-form,plugin-charts,plugin-dashboard,app-shellandexample-schema-catalog, so no typed read existed. The untypedformulareads weresanitize.tsand the Studio arm, as posed.Checks
All at the final head
139a491unless marked. Heavy runs went throughos-verify-lock; exit codes were captured before any pipe.check-doc-snippet-types --build-filter, turbo--concurrency=2): 35 successful, atb126b7d(code identical toeddd18d) and again after the first merge;@object-ui/typesrebuilt after the second.type-check, exit 0:types,fields,plugin-form,plugin-charts,plugin-dashboard,app-shell,example-schema-catalog. Every touched test file is inside its package'stsconfig.test.json(--listFilesOnly).packages/types/ examples/schema-catalog/, the touched plugin tests, and 72 test files outside those packages that name a touched file or symbol: exit 0, 422 files, 12188 tests passed.packages/plugin-form/ packages/plugin-charts/ packages/plugin-dashboard/(at2abe905; the last merge touched none of them): exit 0, 398 files, 4270 tests passed, 16 skipped.packages/app-shell/in full ateddd18d: exit 0, 965 files passed, 1 skipped; 9608 tests passed. After the merges, its 17 test files that name a touched symbol ran green in the first set, and the app-shell test the first merge brought in ran green at2abe905.check:doc-fences,check:doc-snippets(698 of 698 judged, 0 failed),check:doc-types,docs:check-links,check:control-bytes,check:doc-examples,check:spec-symbols,check:doc-example-readers,check:doc-example-ids,check:new-line-citations(0 new),check:test-path-roots,regenerate-catalog-index.py --check.check:changeset-claims(report-only; it names 26 pending changesets that cite a touched file. Each was screened for this round's keys and read where it matched; only7166andlucky-donkeys-shaveare made false, and both carry a dated note),check:pending-changeset-literals,check-changeset-presence(15 source files of 6 released packages, 1 changeset),changeset:check(nomajor). Bump: minor fortypes,plugin-form,plugin-charts,app-shell.core(one comment) andplugin-dashboard(a README and a test comment) publish nothing new and take no bump..ts/.tsx/.mjsfiles, against the merge-base blobs (--stdin): 0 errors at head, warnings equal to base in every file, and 0 errors with--no-inline-configtoo. Population: the diff's changed script and TypeScript files, each matched by the rooteslint.config.js(one result per file in the JSON output). Type-aware linting is off (no parser project in that config), so the diff cannot move an untouched file's verdict.check-governed-queue-guard --testover the 33 paths: NOT GOVERNED.Ablations, re-run at
139a491with the same readings as at2abe905andeddd18d. Each prediction was written first, and each mutation went through objectstack'sablation-replace.mjs(anchor hit once, blob moved, restore blob equal to HEAD,git diff HEADempty):filtered-dashboard.json's first widget goes back to inlineoptions. The catalog schema test has 1 failed and 29 passed, and the red is the strict-face case for that entry. M3 (measured in theeddd18drun): those three pairs re-enter at 1 occurrence each, and strict-refused goes 82 to 83. As predicted.FormulaFieldMetadatadeclaresformula?: stringagain.typestsc ontsconfig.test.jsonexits 2 with one TS2344, onassertionRetiredMembersAreGone'sFormulaFieldMetadatarow. As predicted. (The first attempt was refused by the tool before anything ran, because its replacement contained its anchor. It is not counted.)sanitize.tsreadsformulaagain.sanitize.test.tshas 1 failed and 5 passed ("expected {} to deeply equal { note: 'kept' }"). As predicted.deriveColumnsreadsdisplay_fieldagain behinddisplayField.deriveMasterDetail.test.tshas 1 failed and 39 passed. As predicted.ObjectChart's chain readsdisplay_fieldagain. The display-leg test has 1 failed and 5 passed. As predicted.resolveActionParamsreadsdisplay_fieldagain. The declared-legs test has 1 failed and 11 passed. As predicted.formula.mdx's typed fence writesformula:.check:doc-snippetsexits 1, with 1 of 698 blocks failed against the rebuilt dist. Predicted TS2561; observed TS2353 ("formuladoes not exist in typeFormulaFieldMetadata"). The same refusal, without a did-you-mean.NOT MEASURED:
app-shellsuite after the two merges. It was green in full ateddd18d, and the merges brought noapp-shellsource change.main5262f7don its own. Merging it moved no reading on this branch.DataSources.Acceptance notes
options.descriptionis in ruling C's nine, and the strict face refuses it. ButDatasetWidgetreads it on the dataset path as a metric tile's sub-caption (CONSUMED_WIDGET_OPTION_KEYSinsdui-parser). No producer writes it in either repository. It belongs to objectstack#20960's catchall census (a consumed key the strict face refuses), not to this round. Noted, not filed.options.data ?? widget.data,xField || 'name', …) is untouched, as ruled. It retires on its own card.pm:blockedon this card. It closes with a pointer once this is onmain.Generated by Claude Code