Repository navigation
feat(plugin-timeline,plugin-list): retire the undeclared timeline metaFields reads (objectui#10222) - #10430
Conversation
…taFields` reads (objectui#10222) Ruling batch #223 item 5b, letter A. The spec's TimelineConfigSchema is a strict object that declares no `metaFields` member, yet ObjectTimeline read it to pick the chip fields and ListView read it three times (the expand collector, the select collector, and the switch that skipped the status / priority auto-projection). All four reads are deleted. - ObjectTimeline: chips are always the built-in status / priority pair, limited to the fields the object declares. - ListView: status / priority are projected for every timeline view, so a view without the key fetches exactly what it did before. - ListView.speculativeFls-7216 PIN 4 rewritten with the reason (its permitted binding is now `endDateField`; the old `region` control rode the column path). - New pins: render (chips identical with and without the key), projection (the key adds nothing to $select / $expand), and a source scan with firing controls in both packages. - Changeset: minor on both packages, naming the behaviour change for a stored interface-page view carrying `options.timeline.metaFields`. Claude-Session: https://claude.ai/code/session_01BA3nKVUwKQJf8DBxrSVtNC
…in the retirement comments (objectui#10222) So a reader who greps for the key lands on the explanation. Comments only; the source pins read code tokens, not comments. Claude-Session: https://claude.ai/code/session_01BA3nKVUwKQJf8DBxrSVtNC
…n beside the plugin-list one (objectui#10222) plugin-timeline's tsconfig.test.json names no `node` types (TypeScript 6 includes none by default), so a `node:fs` import in that package's test does not type-check. The two-package source scan now lives in the plugin-list file, whose test config names them; the plugin-timeline file keeps the render pin only. Claude-Session: https://claude.ai/code/session_01BA3nKVUwKQJf8DBxrSVtNC
… explicit `any` Casts at the props instead; the file lints with zero eslint messages. Claude-Session: https://claude.ai/code/session_01BA3nKVUwKQJf8DBxrSVtNC
|
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
|
Fixes #10222
Clause-②: no
Ruling batch #223 item 5b, letter A (card comment 5824012155, maintainer 「其他同意」): delete every undeclared
metaFieldsread in both packages.cardFieldsstays the reserved spelling; nothing is declared, andpackages/typesand the spec are untouched. The bypass that delivered the key (a stored view's unjudgedoptionsbag) belongs to objectui#10380 and is not touched here; this card does not wait on it.What changed
plugin-timelineObjectTimeline.tsx: the(timelineConfig as any).metaFieldsread and its docblock line 「Spec config:timeline.metaFields: string[]」 are deleted. The chips beside each title are always the built-instatus/prioritypair, limited to the fields the object declares (the default did not change).plugin-listListView.tsx: three reads deleted.metaFieldsspread in theexpandFieldscollector;$selectcollector;!Array.isArray(tCfg.metaFields)condition on the status / priority auto-projection, which is nowif (tCfg): unconditional for any configured timeline block. Each site's comment names the retired key and the ruling. ThetCfg: anyannotation lost its purpose and is dropped.ListView.speculativeFls-7216.test.tsxPIN 4 is rewritten with the reason, not deleted. It still pins what it guards, a DENIEDdateFieldbinding kept out of$select. Its fixture carriedmetaFields: ['region']as the permitted control. That key is retired, and it was never a discriminating control anyway:regionis in that file'sCOLUMNS, so it reached$selectthrough the column path whatever the binding did. The permitted binding is nowendDateField: 'end_date', which only the timeline binding can project (the same shape PIN 3 uses for gantt). The PIN 8 comment (「when a timeline is configured with no explicitmetaFields」) was re-read and updated the same way..changeset/10222-retire-timeline-metafields-reads.md:minoron@object-ui/plugin-timelineand@object-ui/plugin-list. It names the behaviour change in the ruling's words: a stored interface-page view carryingoptions.timeline.metaFieldsfalls back to the default card labels. No such view has been found, and the stored rows are not censused.Zone 2 measurements (base
378a4f6ca, then the branch)git grep -n metaFields 378a4f6caover the whole tree found 12 hits in 4 files, all underpackages/(none inapps,contentorexamples). Classified:ObjectTimeline.tsx: the docblock line and the two-line read. Deleted.ListView.tsx: theexpandFieldsspread, the$selectspread, the auto-projection comment and its!Array.isArray(tCfg.metaFields)switch. Deleted or rewritten.ListView.speculativeFls-7216.test.tsx: the PIN 4 fixture and the PIN 8 comment. Rewritten.plugin-gridObjectGrid.tsx: 3 hits, one more than the dispatch listed. All three are the same LOCAL variable (the record panel's system-field list): its declaration and two uses in the JSX. It is not this key. Left alone; that file is held by objectui#10354.No other hit.
$selectfor a timeline view with nometaFieldsis IDENTICAL before and after:['id', 'name', 'start_date', 'status', 'priority']. The pinIDENTICALasserts that exact array. It is green with the reads restored (the ablation leg, which is behaviour-equivalent to base in these files) and green on the fix. The auto-projection is now unconditional for a timeline block rather than dropped.PIN 4: see above. The retired key was removed from its fixture, and the new projection pin carries the proof that it is ignored.
A block WITH
metaFields: ['region']renders the SAME chips as one without (['Open', 'High']).regionis not projected byListView.Pins
(b) render,
plugin-timeline/src/ObjectTimeline.metaFieldsRetired-10222.test.tsx, against the realTimelineRenderer(not mocked):['Open', 'High'];metaFields: ['region'], the chips are identical and contain noEMEA.(c) projection,
plugin-list/src/__tests__/ListView.timelineMetaFieldsRetired-10222.test.tsx.regionis deliberately not a column here.metaFields: ['region']adds nothing, and status / priority are still projected.options.timelinespelling, both beside atimelineblock and on its own. On its own was the shape that fetched no status / priority at all at base.metaFieldsis neither expanded nor selected, with a control proving the same lookup IS expanded as a column.(a) source, in the same
plugin-listfile: a TypeScript-AST scan of every non-test.ts/.tsxunderpackages/plugin-list/srcANDpackages/plugin-timeline/src. It counts identifiers and string literals; comments are trivia, so prose naming the key is not a read. It asserts zerometaFieldsuses. Controls:ListView.tsx/ObjectTimeline.tsx;cardFields/colorFieldbeside them;The
plugin-timelinehalf lives in theplugin-listfile becauseplugin-timeline'stsconfig.test.jsonnames nonodetypes, and TypeScript 6 includes none by default. A first draft that read disk from theplugin-timelinetest failed that package's type-check with TS2591. Changing that tsconfig was outside the claimed file surface.Ablation (restore all four reads; on-disk proof)
The tool is
node ../objectstack/scripts/ablation-replace.mjs, run in--holdmode for four anchored mutations: 1 inObjectTimeline.tsxand 3 inListView.tsx. Every anchor hit exactly once and every blob moved. The script arms atraprestore on EXIT, INT and TERM, and it ran inside the verify lock. Final run on HEAD8659b926e:grep -c 'Array.isArray.*metaFields'went fromTL=0 LV=0toTL=1 LV=3;Tests 7 failed | 22 passed (29), exit 1. The 7 reds are all expected:expected [ 'EMEA' ] to deeply equal [ 'Open', 'High' ];regionin$select) and EXPAND (accountin$expand);ListView.speculativeFls-7216(the rewritten PIN 4 does not lean on the key).ablation-replace --restoreput both files back with blob == HEAD blob (6b21ccaf9625,37d5565ca83d), andgit diff HEADplusgit status --shortwere empty. Re-checked by hand afterwards withgit hash-objectagainstgit rev-parse HEAD:path: equal.Gates (HEAD
8659b926eunless stated)Dependency closure:
turbo run build --filter='@object-ui/plugin-list^...' --filter='@object-ui/plugin-timeline^...' --concurrency=2⇒Tasks: 12 successful, 12 total(all served from the shared worktree cache:FULL TURBO).type-check:
pnpm --filter @object-ui/plugin-timeline --filter @object-ui/plugin-list run type-check(bothtsc --noEmitandtsc -p tsconfig.test.json) ⇒Done/Doneat4c7fc8bf8. After that, only the new plugin-list test changed; the plugin-list type-check re-ran green on those exact bytes.--listFilesconfirms both test programs compile the new test files.pnpm exec vitest run packages/plugin-timeline/ packages/plugin-list/from the repo root ⇒Test Files 117 passed (117)/Tests 1389 passed (1389).Tests that read the touched sources as TEXT: a
git grepover test files for file-reading calls, plus the touched file names, found 68 files outside these two packages (census, ratchet and docblock-quote suites among them). Run from the root at4c7fc8bf8⇒Test Files 68 passed (68)/Tests 2633 passed (2633).ObjectTimeline.tsxandListView.tsxare byte-identical between4c7fc8bf8and HEAD.pnpm check:control-bytes⇒ OK.pnpm check:new-line-citations⇒0 new citation(s).node scripts/check-changeset-presence.mjs⇒5 source file(s) of 2 released package(s) changed, and this change declares 1 changeset(s).pnpm check:changeset-claims: the self-contradiction and born-false readings are clean. It flags 7 pending changesets that nameListView.tsx: 7070, 7499, 7773, 7780, 8990, list-user-actions-collision-5398 and listview-comment-pair-4559. Each flagged paragraph was read. They cover the gantt branch, kanbangroupField/groupBy,userActionsand two comment corrections, and none describes the timeline collectors or the auto-projection this diff edits. None went false.eslint over the 5 touched files, by rule, base ⇒ head. All messages are warnings; there are 0 errors on both sides.
ListView.tsx:no-explicit-any137 ⇒ 136; every other rule unchanged (12 / 6 / 12 / 8 / 9).ObjectTimeline.tsx:no-explicit-any28 ⇒ 25, andreact-hooks/exhaustive-deps1 ⇒ 0. The chip memo readtimelineConfigwithout listing it.This is a narrowed run and still a measurement. The population is the 5 files, and eslint's own
--format jsonreturned 5 results. The config is not type-aware:--print-configshows noparserOptions, and no rule undereslint-rules/reads other files. So this diff cannot move a verdict in an untouched file.Acceptance notes
ListViewstill mergesoptions.timelineinto the timeline node verbatim, so a storedmetaFieldsstill ARRIVES atObjectTimeline. Nothing reads it now. That door belongs to objectui#10380.ListViewTimelineConfig(packages/types) carries a[key: string]: anyindex signature and a deprecateddateFieldalias, andObjectTimelinestill readstimelineConfig?.dateFieldas a fallback. That is an objectui-declared legacy alias, not an undeclared read.packages/typesis outside this card, and this is noted, not filed (carrier: none).content/; the base whole-tree grep had no hits outsidepackages/. So there is nothing to update there.Generated by Claude Code