test(console): pin the four object-metric query members (objectui#8071 slice 8) - #8955
Merged
Merged
Conversation
…1 slice 8) Slice 8 of objectui#8071 takes the first PARTIAL bite of a multi-key block. The batch is a rule, not a pick: every `object-metric` member that shapes the aggregate query behind the NUMBER the tile paints — the four that reach `ObjectMetricWidget`'s `fetchMetric`/`computeOne` (`dataSource` gates the effect; `aggregateKey`, `resolvedFilterKey`, `compareToKey` are its other dependencies). `trend` and `drillDown` reach neither: they shape what is drawn around the number once it exists, and stay exempt for the next slice. MEMBER_PIN_EXEMPTIONS 37 -> 33, MEMBER_PIN_EXEMPTION_CEILING 37 -> 33 and MEMBER_PINS 53 -> 57, in this one commit. NEWLY_JUDGED_UNPINNED_MEMBERS is unchanged — no block it names was touched. Two pins promote pre-existing files, each read end to end and each given the one row it was missing: `ObjectMetric.elementDataSource.test.tsx` gains the negative direction (the view's `columns`/`sort`/`pagination` asserted OUT of the aggregate call, so the pin cannot be satisfied by a mapping that forwards everything), and `ObjectMetricWidget.compareTo.test.tsx` gains the row that mounts `type: 'object-metric'` through SchemaRenderer, so the claim that the block's gate forwards the key untouched is asserted rather than assumed. `aggregate` and `filter` share one new file, written so the aggregate rows author no filter and stay independent of the filter spelling. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Jmxdo7bmeqCQHLSfmLVX9w
Contributor
✅ 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
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Refs #8071
Slice 8 of the per-block member-pin transition, and the first that takes a partial bite of a multi-key block — slice 7 exhausted the "close a block by taking its last key" shape.
The batch, stated as a rule
Four qualify:
dataSource,aggregate,filter,compareTo. The rule is mechanical, not editorial — those four are exactly the members that reachObjectMetricWidget'sfetchMetric/computeOne:dataSourcegates the effect, andaggregateKey/resolvedFilterKey/compareToKeyare its other dependencies. The two left,trendanddrillDown, reach neither. They shape what is drawn around the number once it exists — a static badge beside it, a drawer opened by clicking it — and neither can change the number.⇒ What slice 9 inherits is cheap to state: the two presentation members of
object-metric. They were deliberately left as a pair rather than one being swept in:drillDowndoes issue a query of its own (the drawer's record list, off the same resolved filter), so "reaches an adapter" would have been the wrong cut. That is recorded in the ceiling docblock so the next reader does not re-derive it.Ledger, AST-measured on this branch's own head
TypeScript AST walk —
ts.createSourceFile,VariableDeclaration, initializer unwrapped throughas/satisfies/ parens, directPropertyAssignmentchildren, boundaries from AST node spans.aeaa0f64c)04ee89741)MEMBER_PIN_EXEMPTIONSMEMBER_PIN_EXEMPTION_CEILINGMEMBER_PINSNEWLY_JUDGED_UNPINNED_MEMBERSobject-metric.exemptionsThe delta balances on one instrument: −4 exemptions, −4 ceiling, +4 pins. Both initializers are plain object literals with zero non-
PropertyAssignmentmembers and zero keys lacking a., so the prefix breakdown is the whole population.Remaining 33:
object-grid.15 ·object-form.7 ·object-master-detail-form.6 ·object-kanban.2 (held, unruled on #8913) ·object-metric.2 ·record:related_list.1 (theNO_READ_SITE_TO_PINsentinel).Instrument cross-check. A key-anchored regex bounded to top-level indentation inside the AST span agrees exactly on both objects: 33 = 33 and 57 = 57. The value-anchored variants still disagree, as documented:
AWAITING_A_PINreads 38 andAWAITING_A_PIN\breads 34 against a true 30 value-uses (the exemption values decompose 30 / 1NO_READ_SITE_TO_PIN/ 2AWAITING_A_PIN_NEWLY_JUDGED= 33). The AST is what the numbers above come from.The four pins
Two promote pre-existing files, each read end to end and each given the one row it was missing.
object-metric.dataSource—packages/plugin-dashboard/src/ObjectMetric.elementDataSource.test.tsx. It already drove the binding'sobjectandviewmembers through the real renderer, with an unresolvableviewreporting rather than aggregating the whole object. What it lacked was the negative direction, added here: the view fixture'scolumns,sortandpaginationare asserted out of the aggregate call. Without that, the pin would have been satisfied by a mapping that forwarded everything — which for a metric means one silently ordered and paged by a list view's presentation settings.object-metric.compareTo—packages/plugin-dashboard/src/__tests__/ObjectMetricWidget.compareTo.test.tsx. It already asserted the{ kind, dimension? }member set on a quarter-scoped fixture where the twokindvalues disagree about both window and label, plus the no-compareTosingle-pass control. It drove the widget directly, so this PR adds the row that mountstype: 'object-metric'throughSchemaRenderer. That row is why the file names the block at all: the locator requires it, and a docblock mention alone would have been the locator satisfied by prose rather than by behaviour. Ablation B4 confirms the row is load-bearing, not decorative.Two are new, sharing one file —
packages/plugin-dashboard/src/__tests__/objectMetricQueryMembers-8071.test.tsx, the shape slice 3 used for the record-picker label/placeholder pair and slice 6 for chatter/discussion:object-metric.aggregate— a three-member options bag whose members are read twice: into the call (field/function/groupBy, withgroupByoptional and defaulting to one bucket, an authored value outranking it, the bag asserted whole) and back out of the response (countsumsFIELD_countacross every row; any other function reads the first row'sFIELD_FUNCTION). Both arms run on the same two-row response, so only a readback reading both members can answer 120 on one and 7 on the other. The key's absence is a member semantic too, and the file's non-vacuity floor: with noaggregate, the query verb changes tofind()and the value becomes the row count.object-metric.filter— no named member set, so the member shape is the spelling, and there are two: flat under its own name inside the aggregate bag, and wrapped as an OData-style$filteron the no-aggregate()fallback. Plus placeholders resolved before the query, and the predicate read by value (a deep-equal rebuild must not re-probe; a changed comparand must, and must carry the new predicate).The aggregate rows author no filter on purpose, so the bag comparison is blind to the filter spelling and the two ablations fail for their own reasons rather than as a pair.
Candidates read and rejected, per file
Twelve collected test files name
object-metric— the locator's own precondition — and every one was read end to end.public-block-binding-reach.test.tsxaggregateonly as a plausible sample value.widget-dom-leak-sweep.test.tsxaggregateis a stub returning[];object-metricis one render target among many.ObjectMetricWidget.i18nLabel.test.tsxaggregate,trendanddrillDownpurely to make the drill-down reachable; its subject isI18nLabelresolution. Crediting it fortrendordrillDownwould repeat slice 7'saction-bodyShape-forward.test.tsxmistake in a new place.ObjectPivot.elementDataSource.test.tsxobject-metriconce, in prose, as the sibling shape. Its subject isobject-pivot.ElementDataSourceGate.test.tsxobject-metriconce, in prose, listing which wirings share the gate.public-contract.test.tsdashboardComponents.mapParity.test.tsfilterIsDeclaredInput-7712.test.tsobject-calendar.PageBlockInspector.colorLabelling.test.tsx,PageBlockInspector.i18n.test.tsx,block-config-i18n.test.tsregistry-inputs-spec-parity.test.tsAblations
Every leg proved the mutation on disk before any result was read — anchor grep counts on injected and removed text, plus a
git hash-objectdiffering from the HEAD blob — and restored withgit checkout HEAD -- ABSOLUTE_PATHfrom atrap … EXIT INT TERM, with restoration proved by blob hash, never by an exit code.A0 — the gate mechanism. One deleted exemption re-added, ceiling untouched.
apps/console/src/__tests__/registry-inputs-spec-parity.test.ts, head blob8102fd30b, mutatedba6e07fea; removed anchor 1 to 0, injected anchor 0 to 1. 3 rows red (198 tests, 3 failed): the total-and-disjoint member-shape census, "carries no stale member-pin exemption", and "the member-pin exemption list only ratchets DOWN". Restored to8102fd30b,git diff HEADempty.One ablation per new pin, the whole new pin set run together so neighbour independence is observed rather than asserted (19 tests across the three pin files):
aggregategroupBy: aggregate.groupBy || '_all'becomes a hard-coded'_all'a2da27d14tob08defb10groupByoutrank that default". 18 green.filterfilterbecomes$filtera2da27d14to3063e6ff9filterfind()fallback's$filterbecomes flatfiltera2da27d14to8e1527b57find()fallback WRAPPED as$filter". 18 green.dataSource1479e50aatoddf23632fdataSourcerows. 17 green.compareTo.kindis ignored: every comparison forced topreviousPerioda2da27d14toa1248b0abpreviousYear-reading rows plus the new registry row. ThepreviousPeriodrow and the no-compareTocontrol stay green, which is the discrimination. 16 green.B2 is the one to read carefully, and it is reported as observed rather than smoothed. Collapsing the two wire spellings is precisely the defect this pin exists for, and its blast radius is wide: 10 of 19 rows, spanning all three pin files, because the flat
filterspelling is what every metric fixture in this family reads through. What it did not touch is the finding: all sixaggregaterows stayed green (they author no filter, by design), and so didreaches the find() fallback WRAPPED as $filter. B2b is the other direction of the same pair and fails narrowly — exactly one row — which is what shows the two spellings are separately pinned rather than jointly.0 -> 0; the mutation itself was still proven (injected anchor 0 to 1, blob differing), but a malformed anchor reading is not a reading, so the leg was re-run with a correctly escaped pattern. It reproduced identically — same mutated blob8e1527b57, same single red row — and the corrected counts are1 -> 0and0 -> 1.Verification
Every exit code captured into a variable before any pipe.
pnpm exec vitest run apps/console/src/__tests__/registry-inputs-spec-parity.test.ts— exit 0, 198 passed (198). Baseline onaeaa0f64cwas also 198 passed, so the count is unchanged and the population moved inside it.pnpm exec vitest run packages/plugin-dashboard/ apps/console/— exit 0, 202 files / 2068 tests passed.git status --porcelainempty at04ee89741.pnpm --filter @object-ui/console --filter @object-ui/plugin-dashboard type-check— exit 0. The log echoes both scripts (tsc --noEmit && tsc -p tsconfig.test.json;tsc --noEmit && tsc -b tsconfig.node.json --force), so the test files are type-checked, not merely collected.TS2307 Cannot find module '@object-ui/…'; that was the unbuilt workspace closure, not this diff — it cleared afterpnpm --workspace-concurrency=2 --filter '@object-ui/console^...' --filter '@object-ui/plugin-dashboard^...' buildand the only errors that remained were five in the new file, which are fixed here.pnpm --filter @object-ui/console --filter @object-ui/plugin-dashboard lint— exit 0, and read for the literal word rather than trusted to the exit code:packages/plugin-dashboard lint: ✖ 451 problems (0 errors, 451 warnings)andapps/console lint: ✖ 212 problems (0 errors, 212 warnings). The log echoesScope: 2 of 47 workspace projectsand both script names, so "the filter matched no script" cannot read as a pass. The new file draws no rows at all; the rows on the two edited files are the pre-existingno-explicit-anywarnings they already carried.node scripts/check-changeset-presence.mjs— exit 0: 4 source files of 2 released packages changed, 1 changeset declared, empty frontmatter (test-only, nothing released).node scripts/check-governed-queue-guard.mjs --test …— exit 0, NOT GOVERNED. The PR still stays draft per dispatch; the PM lands it.grep -naP '[\x00-\x08\x0b\x0c\x0e-\x1f\x7f]'over all five touched paths — no matches.Scope
Nothing here touches
packages/plugin-kanban/**,packages/plugin-gantt/**,packages/types/src/complex.ts,zod/complex.zod.ts,packages/sdui-parser/src/kanban-quick-add.tsor the kanban/gantt docs — the live surface of #8865.object-kanban.columns/object-kanban.dataSourcestay exempt on the ruling ground (#8913 unruled), andrecord:related_list.actionswas not re-measured here because this slice took a different block: slice 7's measurement stands as the last one taken.验收备注
noted, not filed—ObjectMetricWidget.computeOne'sfind()fallback returnsrecords.length, so on a page-limited adapter the tile would paint the page size rather than the total. Not filed: no reproduction was measured, and it is a design question about the fallback rather than a defect with a named failing probe. Successor: slice 9, which takes this block's remaining two keys, and anyone editingObjectMetricWidget.tsx.noted, not filed—ObjectMetricWidget.i18nLabel.test.tsxmentions both of the keys slice 9 will take (trendas a props bag whose subject is the label inside it,drillDownas{ enabled: true }to make the drawer reachable). It satisfies any mechanical locator for either and asserts nothing about either member set. Not filed: it is a warning for one specific future slice, not a defect. It is written into the ceiling docblock, where that slice will read it. Successor: slice 9.🤖 Generated with Claude Code
https://claude.ai/code/session_01Jmxdo7bmeqCQHLSfmLVX9w
Generated by Claude Code