Skip to content

feat(types,plugin-charts): anchor ObjectChart props to ObjectChartSchema and declare the four keys its producers write (#7946) - #8884

Merged
os-zhuang merged 5 commits into
mainfrom
claude/issue-7946-objectchart-schema-anchor
Sep 10, 2026
Merged

feat(types,plugin-charts): anchor ObjectChart props to ObjectChartSchema and declare the four keys its producers write (#7946)#8884
os-zhuang merged 5 commits into
mainfrom
claude/issue-7946-objectchart-schema-anchor

Conversation

@claude

@claude claude Bot commented Sep 9, 2026

Copy link
Copy Markdown
Contributor

Fixes #7946

Clause-②: yes — given by the ruling's execution note, not judged here: 「已发布类型契约从 any 收紧 + 声明面加键」. needs:contract-review is on the card and on this PR. ⚠️ The contract-review tier is unreachable at the dispatching seat (16 consecutive HTTP 429, account quota — not a global outage), so this PR is expected to park in draft. That is the designed cost of an honest declaration; it has not been reshaped or self-reviewed to avoid parking.

Ruling: maintainer, director seat, summon #20, decision batch #108 item 3, 2026-09-09, option A. Verbatim, untranslated: 「7424 查 「什么在飞」 就应该查open的呀,直接关闭。 其他同意。」 — item 3 = A. B (keep any) and C (declare without anchoring) were refused.

The six ruled parts, and where each landed

# Ruled Landed
1 ObjectChart's props typed by ObjectChartSchema; no props: any on the published .d.ts ObjectChartProps in packages/plugin-charts/src/ObjectChart.tsx, exported from the barrel. Built dist/ObjectChart.d.ts:158 now reads export declare const ObjectChart: (props: ObjectChartProps) => React.JSX.Element
2 xAxisKey · series · aggregate · filter declared on both copies packages/types/src/objectql.ts and packages/types/src/zod/objectql.zod.ts
3 Value types derived from ChartRenderer's reads, never copied from ObjectView's literals xAxisKey / series are ChartRendererProps.schema's own declarations (the internal dataKey arm, verbatim); aggregate / filter come from ObjectChart.tsx's read sites. See per-key section below
4 The colors drift converges Added to the TS interface; the mirror has had it since objectui#3913
5 A read-census pin in the widget-schema-anchors family packages/types/src/__tests__/widget-schema-anchors-7946.test.ts, plus the compile-side pin beside the widget, packages/plugin-charts/src/__tests__/ObjectChart.schemaAnchor-7946.test.ts
6 The two inert as any casts in ObjectView removed in this PR ⚠️ Already gone on origin/main — see the premise correction below

Premise correction on part 6

The casts are not in this diff because they are not on main. objectui#7891 / PR objectui#7948 removed them when it landed, and left the reason in the file (packages/app-shell/src/views/ObjectView.tsx, the block above the chart branch): "The as any casts that used to sit on both literals were measured INERT ... so they are gone too". So part 6's deletion was already satisfied; what was still missing is the half that gives it meaning — the anchor that makes their absence measurable rather than incidental. That half is here, and the ablation below is the measurement.

The four keys — AUTHORABLE or INTERNAL, per key

The 速读 (comment 5596356234) ended by flagging its own gap: 「四个键的精确值类型需从渲染器读法推导,本席未逐键核。」 Read per key, with ground:

aggregate — AUTHORABLE. @objectstack/spec's ChartAggregateSchema calls itself "Inline aggregation for an OBJECT-bound chart", and its own file header names the carrier: "a real authorable prop on the react tier's ObjectChart objectName aggregate (ADR-0081), it is published in the generated react-blocks contract". objectstack#5020 wired the publish gate — packages/lint/src/validate-react-page-props.ts calls ChartAggregateSchema.safeParse() on a static aggregate literal. This component's registry inputs advertises it too. ⭐ Declared BY REFERENCE as the spec's own ChartAggregate / ChartAggregateSchema — see the rework section below. The first cut declared a local near-copy with every member optional, reasoning from this renderer's accept set (every read here is guarded); the contract review measured what that PUBLISHES, and it was an authoring door wider than the spec's on a key the publish gate parses.

filter — AUTHORABLE. The spec spells the carrier literally, in ChartAggregateSchema's own guidance for a misplaced key: "filter is a prop on the chart itself (ObjectChart filter=...), not part of the aggregate." @objectstack/spec/data's FilterArray docblock lists ObjectChart.filter among the React block props declared FilterArray in ui/react-blocks.ts, and the registry inputs carries { name: 'filter', type: 'array' }.

xAxisKey — INTERNAL (relay-composed). ChartRendererProps declares it and calls it, verbatim, "Internal binding. Authors write the spec xAxis: { field } (or the report surface's bare string)". The author-facing spelling on this node is xAxisField, already declared. All five producers of an object-chart node compute it — dims[0] in the two ObjectView relays and ListView, chartCategoryKey(effectiveAggregate, xAxisKey) in the two dashboard relays — and none forwards an authored value. It is absent from the registry inputs.

series — INTERNAL (relay-composed). The { dataKey } shape is the renderer's internal contract. The spec's author-facing ChartSeriesSchema REFUSES dataKey by name — it is an alias entry that renames to name — and that file calls chartType, the sibling internal spelling, "the INTERNAL spelling that is deliberately not part of the author contract". Every producer composes it (vals.map(...), [{ dataKey: effectiveYField }]), which is exactly the suspicion the card raised.

Why the two internal keys are still declared, rather than withheld. Withholding is not neutral here. BaseSchema is .passthrough() on the mirror and carries [key: string]: any on the interface, so xAxisKey: 42 already rides both published faces unvalidated today; not declaring keeps it that way, and additionally puts the pair in zod-mirror-parity's UnmirroredDeclared ledger, which that file describes as a real defect in the pair rather than a neutral state. Declaring buys the VALUE check without minting authorable vocabulary, and each .describe() and TSDoc says which verdict the key carries so no author or generator reads them as authoring surface. ⛔ Neither was added to the registry inputs.

Measured, not asserted — the probe MOVES

The card's before-state: deleting both as any casts left tsc --noEmit green, over a program --listFiles confirmed contained the file — meaningless, because the consumer was any. Here is the same probe after the anchor, from the committed tree, with the mutation proved on disk (marker counts and blob hash) before anything ran:

HEAD blobs: ObjectView=3044e9ef… ObjectChart=aa1fde23…

LEG 2  anchored + wrong literal in the REAL producer
  on-disk proof: marker 'xAxisKey: dims[0],' 1 -> 0 ; injected 'xAxisKey: dims,' = 1
                 blob 3044e9ef… -> fa271034…
  pnpm --filter @object-ui/app-shell type-check   EXIT=2   (1 error)
  src/views/ObjectView.tsx(2304,33): error TS2322: Type 'string[]' is not assignable to type 'string'.

LEG 3  CONTROL — revert the anchor to `props: any`, keep the SAME wrong literal
  on-disk proof: anchor marker 1 -> 0 ; injected 'props: any' = 1 ; blob aa1fde23… -> 1be8c043…
  rebuild EXIT=0, and the mutation REACHED dist:
    dist/ObjectChart.d.ts:158  export declare const ObjectChart: (props: any) => React.JSX.Element
  pnpm --filter @object-ui/app-shell type-check   EXIT=0   (0 errors)

RESTORE: git diff HEAD empty

Leg 3 is the control the acceptance asked for: it moves when the change is wrong, not when the subject is broken. The identical mutation is silent without the anchor and loud with it, so the redness is attributable to this PR and to nothing else.

Ablation on one key's declaration, same discipline, red by test-case name on two independent instruments:

remove `xAxisKey` from the zod mirror
  on-disk proof: marker 1 -> 0 ; blob 441ee538… -> 22d007fe…

  vitest  widget-schema-anchors-7946 + zod-mirror-parity        EXIT=1
    × the mirror declares `xAxisKey`
    × the mirror CHECKS the declared values, not just their presence
    × every key read off `schema` is declared by the mirror, or ledgered by name
    Tests  3 failed | 42 passed (45)

  pnpm --filter @object-ui/types type-check                     EXIT=2
    src/__tests__/zod-mirror-parity.test.ts(2816,14): error TS2322:
      Type '"objectql.zod.ts#ObjectChartSchema"' is not assignable to type 'never'.

RESTORE: git diff HEAD empty ; blob back to 441ee538…

The second instrument matters: the parity guard's unmirrored-keys half is a compile-time assertion, so vitest alone cannot see it. A run that only read vitest would have reported one instrument where there are two.

The defect the anchor found

Typing schema turned four expressions inside ObjectChart.tsx into compile errors that props: any had been absorbing. One root cause, and it is a real runtime bug rather than a typing nuisance:

groupBy is a union — a bare field name, or the structured date-bucketing node { field, dateGranularity, alias }. The file resolved the group column twice. The comparison-merge leg normalises ("Normalise to the underlying string field name so all column lookups work"); the drill/label leg 200 lines below did not, and used the raw union as a row index (row[groupByField]), as a field name (fieldOptionLabel) and as a drill-filter key. On a date-bucketed chart every one of those resolves against the node's stringification, so option-colour resolution, the label→raw reverse map and the drill filter all silently miss. Both sites now share one module-local normalisation, and aggregateRecords' groupBy: string parameter is fed the projected column rather than the union. A second, smaller one: the metadata-label leg passed schema.objectName — optional since ADR-0021 — into a resolver typed string; the object-bound precondition it already assumed is now written down in its guard.

This is a bounded in-place fix, and it is declared rather than folded in quietly: same defect class as the card (an unchecked schema key reaching a reader that cannot handle its declared shape), mechanical, with its shape already pinned by its own twin in the same file, no new gate surface. The alternative was to reintroduce an as any cast at each site — the exact anti-pattern this ruling removed.

What the anchor does NOT buy

BaseSchema still carries [key: string]: any (objectui#5155), so a misspelled key still compiles: xAxisKy: 'stage' is accepted. That is the same ceiling objectui#6576 accepted knowingly for the gallery, and both new pin files carry a counter-probe for it so nobody reads the anchor as more than it is. What moved is that a wrong value type is now refused loudly.

One exception, and it arrived with the rework: aggregate. Bound to the spec's own object, which is strictObject, so a mis-cased member INSIDE it — aggregate: { groupby, function } — is refused by name rather than dropped. That is a property of the spec's schema, not of the anchor; it is why the by-reference form is worth more than a structurally identical local copy.


返工轮 — contract-review REWORK (2026-09-10)

Review of record: Verdict REWORK, findings F1–F8, at
#8884 (comment) (anchored to head
09f8ffaa33; the head then moved by a diff-neutral sync merge to 7e7134160, flagged in comment
5613430888). The contract-review-TIER requirement was separately lifted for this PR by comment
5612089561 — that changes the reviewing seat, not the findings, and every finding below is worked as
written. Two lines were decided by the director before this round and are executed rather than
re-opened: F1 takes the by-reference form, and the drill-title read site is repaired here.

① F1 — aggregate is now the spec symbol, by reference

ObjectChartSchema.aggregate was a local near-copy with all three members optional. It is now
ChartAggregate (TS) / stripImportedDefaults(SpecChartAggregateSchema) (zod) — the same
ChartAggregateSchema the react-page publish gate parses, and the pattern the sibling PR
objectui#8895 already uses on this interface.

What changed on each published face, measured:

Face Before (local copy) After (by reference)
TS aggregate field? · function? · groupBy?, structured groupBy node with field? the spec's shape: function and groupBy REQUIRED, field optional, structured node's field REQUIRED
TS accept set aggregate: {} and { field: 'amount' } compiled both refused; { function: 'count', groupBy: 'stage' } still accepted
zod posture local z.objectstrip: { groupby: 'stage', function: 'count' } parsed CLEAN and lost groupby the spec's strictObject — refused BY NAME (unrecognized_keys names groupby)
zod requiredness every member omissible matches the TS face exactly, differentially pinned against ChartAggregateSchema itself

Three type pins now say this in a way a look-alike cannot satisfy: an invariant Equal against
ChartAggregate itself, plus function/groupBy required and field optional read off THIS
interface. On the mirror, a probe-for-probe differential against the raw spec schema, with the
verdict list asserted to contain both answers so agreement is not agreement-on-refusing-everything.

The renderer's accept set is deliberately unchanged and stays wider: untyped producers forward
aggregate as any, so out-of-contract documents still arrive, and objectui#8168's named refusal
screen is what they get. ObjectChart.absentCategoryAxisRefusal-8168.test.tsx keeps feeding exactly
those documents through a named UNAUTHORABLE(...) helper, so the file says which literals are
deliberately out of contract instead of relaxing its parameter type and unchecking every other one.

② The read-site repair — the union-only drill-title defect

resolveDrillTitle(drillDown, drillEvent, schema.title || 'Details') passed a schema title into a
parameter typed string. objectui#8895 declares that title as I18nLabel — a plain string or an
inline locale map — so an author writing the map arm got an OBJECT rendered as the drill drawer's
heading. Repaired through pickLocalized (@object-ui/i18n), the repository's published
locale-aware resolver, pinned as the twin of the spec's own resolveI18nLabel; the module-private
label helper in plugin-charts was NOT used, because it is not locale-aware and would mint a second
dialect disagreeing with the published one.

Measured on the real union, not argued — the merge of this head with objectui#8895's resolved
tree, built and type-checked:

Union plugin-charts tsc -p tsconfig.test.json
pre-rework (11ddbab62) 2 errors
this head EXIT 0 — plus types build, types type-check and plugin-charts type-check all 0, and 220 files / 3741 tests green

Two, not one — and the second was measured for the first time here. The pre-rework union also
fails at ObjectChart.compareTo.test.tsx:100, where renderChart(compareTo: unknown, …) stops
compiling once objectui#8895 declares compareTo on the schema. It was masked, not absent:
type-check is tsc --noEmit && tsc -p tsconfig.test.json, and the && short-circuits — the
drill-title error in ObjectChart.tsx (main project) hid every error the TEST project would have
reported. Running the test project alone on 11ddbab62 shows both. The parameter is now typed at
DashboardWidget['compareTo'] — the symbol objectui#8895 binds to and the declaration the value
actually comes from (DashboardRenderer forwards widget.compareTo verbatim); all four call sites
already passed that shape.

⚠️ Stated cost, recorded rather than hidden. pickLocalized needs a current locale, so the file
now reads useObjectTranslation().language. The drill heading becomes locale-aware while the chart
heading beside it is not — normalizeChartSchema's label() picks the FIRST string in the map,
which follows key order rather than the user's language. That asymmetry is pre-existing and is NOT
widened here; it is filed as objectui#8943.

③ F7① — the parked 'drawer' | 'dialog' item: decided, and which half went where

Decision: the prose is corrected in-PR; the palette advertisement is a named successor. They are
not one item.

  • In-PR (three prose sites, no assertion changed). All three claimed
    ChartDrillDownSchema declares the chart drill target as two arms, and that advertising
    'navigate' would hand an author a value the publish gate rejects. Measured on
    @objectstack/spec 17.4.0, both halves are FALSE: ChartDrillDownSchema.target is
    ['drawer','dialog','navigate'], and packages/lint's validate-react-page-props — which parses
    that very schema — depends on @objectstack/spec: workspace:*, so the gate accepts the value
    today. Corrected in the two ObjectChart.tsx comment blocks and in
    plugin-charts/src/index.test.ts, which carried a fourth copy of the same stale rationale that the
    review's count of three did not include. Correcting one copy and leaving its twin is worse than
    leaving both.
  • Successor (the description string and its pin). Adding 'navigate' to the registry inputs
    description WIDENS an advertised authoring vocabulary and requires flipping a behaviour pin
    (index.test.ts asserts 'navigate' is absent). That is a contract decision about drillDown — a
    key this card declares on neither published face and objectui#8885 declares on both, and whose
    PR objectui#8895 already records these very sites in its acceptance notes. Taking it here would
    split one key's story across two PRs with two rulings. ⇒ 承接者: objectui#8885. Recorded there
    and here rather than filed as a third card; the reason is now written into the code beside both the
    description and the pin, so the next reader finds it instead of re-deriving a claim that has
    already gone stale twice.

④ The rest of the verdict

# Finding How it was addressed
F1 aggregate wider than the spec REWORKED — by reference, both faces. See ①
F2 filter record arm is a second dialect; the "contract decision across every object-* widget" claim is unsupported Prose corrected on both faces and in the changeset. Census: six sibling object-* widgets declare filter on this interface and all six are array-only, so the decision is LOCAL to this node. Successor named on the member doc and filed as objectui#8944 — the drill spread mis-composes the array arm into index keys, which is what blocks the narrowing. Union kept
F3 Behaviour fix claimed in the changeset, no runtime pin NEW pin: plugin-charts/src/__tests__/ObjectChart.structuredGroupBy-7946.test.tsx. Drill filter keyed by the projected column (alias arm and field-fallback arm), the label→raw reverse map recovered through it, and a bare-string control
F4 Changeset omits the narrowing that bit Migration section added, naming all three: type now required on the literal; chartType must be the declared union (a non-const holder widens to string); series entries must be dataKey-shaped — plus the aggregate requiredness from F1
F5 "Both sites share one normalisation" not delivered The comparison-merge leg now calls aggregateGroupByKey, the same expression the drill leg uses. The as any on the raw-node read in runAggregate is gone too — that read is the one site that must stay raw (the node goes to the server verbatim; normalising it would drop dateGranularity), and the comment now says so
F6 Zod refusal gaps filter: 'stage=won' and colors: 42 now have mirror refusal cases, alongside an accepting control asserted issue-free so a mirror that refused everything could not pass
F7① Parked 'drawer' | 'dialog' Decided — see ③
F7② objectui#8895 reconciliation is OUT Still out; measured, not merged. See the collision notes below
F8 fieldOptionLabelRefetch.test.tsx prose inaccurate Corrected to what the code does: data-tick stays ON ObjectChart and compiles because TypeScript does not check hyphenated JSX attribute names against the prop type — it does not "move to a wrapper"

⑤ The acceptance instrument, stated separately

Both census pins compute their declared key set from Object.keys of the zod mirror. A change
that drops an entire TypeScript member block runs the vitest suite fully green. pnpm test alone is
therefore not an acceptance instrument for this file, and the two verdicts are reported apart:

Instrument Result at e805024d7
pnpm --filter @object-ui/types type-check (tsc -p tsconfig.test.json) EXIT 0
pnpm --filter @object-ui/plugin-charts type-check EXIT 0
pnpm exec vitest run packages/types/ packages/plugin-charts/ 219 files / 3723 tests passed

The type-check is also what enforces every @ts-expect-error in the two compile-side pins: an
expectation that stops being needed fails as TS2578, which vitest cannot see either.

⑥ Ablation — the new runtime pin can fail, and fails for the right reason

From the committed tree, with the mutation proved on disk by marker count AND blob hash before
anything ran (the drill leg's normalisation reverted to the raw union; the anchor is the one-line,
two-space-indented form, distinct from the comparison leg's annotated two-line form):

PRE : anchor=1 inject=0 blob=1152e58b… headblob=1152e58b…
POST: anchor=0 inject=1 blob=8cd7c9c5…
  ObjectChart.structuredGroupBy-7946   EXIT=1   Tests 3 failed | 1 passed (4)
    × drills on the ALIAS the aggregate projects the group under, not on the node
    × falls back to the node's FIELD when it declares no alias
    × recovers the RAW value behind a resolved option label
    AssertionError: expected { '[object Object]': '2026-03-01' } to deeply equal { month: '2026-03-01' }
REST: anchor=1 inject=0 blob=1152e58b…
RESTORE PROVEN: git diff HEAD empty · blob back to 1152e58b…

Three of four turn red and the fourth — the bare-string control — stays green, which is exactly
what it is there for: the ablation reports that the structured-node arm broke, not that the file
broke. The failure text is the defect itself, verbatim.

⑦ Collision with objectui#8895 — re-measured on this head, for whoever lands second

Agreed order is this PR first. refs/os-dev-collide/pr8895-resolved was read but not touched
(still 11ddbab62); the union above was built on a throwaway local branch which was deleted, so
nothing new is pushed. Re-derived against this head:

File Merge result Resolution
packages/types/src/objectql.ts auto-merges ⚠️ Read it anyway. Both hunks share byte-identical opening lines, which git hoists OUT of any conflict region — taking one side alone yields syntactically perfect output. Verified after merging: the interface carries all eight keys (filter · aggregate · xAxisKey · series · colors + drillDown · title · compareTo)
packages/types/src/zod/objectql.zod.ts conflict, 1 hunk Import block — both sides add spec bindings. Keep both. Merged mirror carries the same eight keys
packages/types/src/__tests__/imported-defaults-8317.test.ts conflict, 2 hunks Import + the IMPORTED differential list. Keep both entries
packages/types/src/__tests__/zod-mirror-parity.test.ts conflict, 1 hunk Both sides add the SAME entry 'objectql.zod.ts#ObjectChartSchema' with different comments. Keep one entry and both comments
scripts/check-doc-example-types.mjs conflict ⛔ Do NOT pick a side. Both PRs re-anchor the ObjectFormSchema ledger row because both add import lines to objectql.ts — this PR to :1615 (one line), objectui#8895 to :1617 (three). Neither number is right in the union: re-run pnpm check:doc-examples and take the number it prints

Post-merge the union is green: type-checks EXIT 0 and 220 files / 3741 tests. Only the prose in this
PR's LEDGERED_UNDECLARED_READS goes stale (its three keys become declared) — the assertions all
survive, because both ledgers assert only that the key is still READ.

Verification

All at the final commit e805024d7.

Run Result
pnpm --filter @object-ui/types build EXIT 0 (dist completeness: 128 emitted files verified)
pnpm --filter '@object-ui/plugin-charts^...' build (dependency closure) EXIT 0
pnpm --filter @object-ui/types type-check EXIT 0
pnpm --filter @object-ui/plugin-charts type-check EXIT 0
pnpm exec vitest run packages/types/ packages/plugin-charts/ 219 files, 3723 tests passed
pnpm exec vitest run packages/plugin-dashboard/ packages/plugin-list/ packages/plugin-view/ ObjectView.chartRelay-7823 214 files, 2142 tests passed
consumer type-checks — types, plugin-charts, plugin-dashboard, plugin-list, plugin-view, app-shell, react, core all EXIT 0 (all eight scripts echoed by name; a filter matching zero scripts also exits 0, so the echo is the reading)
gate-script tests (this diff edits scripts/check-doc-example-types.mjs) check-doc-example-types.test.ts + check-doc-example-shared-reader.test.ts — 73 tests passed
gates: doc-examples · doc-types · doc-snippets · doc-fences · doc-example-readers · spec-symbols · spec-floors · control-bytes · handler-key-reads · element-data-source-declaration · vi-mock-specifiers · vi-mock-inherit · comment-mask-corpus · self-import · esm-specifiers · unreferenced-sources · readme-exports · side-effects-array · phantom-deps · unused-deps · published-tsconfig-exclude · entry-guard · lint-rule-coverage · i18n-keys · i18n-dead-keys all EXIT 0
check:sdui-registration-pins exit 2 = PREREQUISITE NOT MET ⇒ NOT MEASURED — it weighs apps/console/dist/assets and there is no console build here. Neither pass nor fail. This diff changes no sideEffects array and no registration key (the edit inside that block is comment-only), and CI builds the console — the Console Performance Budget comment on this PR is the evidence it does

Lint — the FULL population, not a narrowing. eslint . --format json from the repo root judged
4698 files, 0 errors, 12562 warnings, EXIT 0. Per package: types 235 files / 0 errors / 278
warnings; plugin-charts 65 files / 0 errors / 357 warnings (358 before — one fewer, the as any
F5 removed). calculateConfigForFile returns languageOptions.parserOptions = {} for both edited
sources, so type-aware linting is not enabled and no declaration in this diff can move a verdict on a
file it did not touch — recorded because that is the invariance a narrowing WOULD have needed, and
it also explains why the two package runs and the repo-wide run agree.

验收备注

Measured while doing this. None is fixed here.

  • Filed: objectui#8943normalizeChartSchema's label() picks the FIRST string in an inline
    locale map, so a chart heading follows key insertion order rather than the user's language. This is
    the successor for the asymmetry ② introduces, and the repository already publishes the right answer
    (pickLocalized).
  • Filed: objectui#8944 — the drill-down spread mis-composes the filter ARRAY arm into index
    keys, silently dropping the widget's own filter on the arm the spec and the registry inputs
    advertise. F2's named successor, and the prerequisite for narrowing filter to one arm.
  • Not filed, 承接者 objectui#8885 — the registry inputs description withholds
    target: 'navigate'. See ③ for why the prose and the advertisement parted company.
  • Dedup channel, declared. REST issue SEARCH is refused by the agent proxy (403, "sessions are
    bound to their configured repositories — use repository-scoped endpoints"), and one targeted MCP
    search_issues returned empty but its control query could not run (API rate limit already exceeded), so that empty is NOT a reading. The dedup that DID hold is repository-scoped and
    label-scoped: the four open issues carrying package: plugin-charts, with objectui#7946 itself as
    the control that must appear, and it did. ⚠️ Its limit is that an UNLABELLED duplicate would not
    appear in it.
  • Still handed to the PM from the previous round — the three keys ObjectChartSchema leaves
    undeclared (compareTo / drillDown / title) and ObjectChartBlock's props: any. Both are
    objectui#8885's, which is open and dispatched.

🤖 Generated with Claude Code

https://claude.ai/code/session_01611D6ZaRaMmwTNQmSbk8MH


Generated by Claude Code


Generated by Claude Code

…ema (#7946)

`ObjectChart` was published as `(props: any)`, so `ObjectChartSchema` anchored
nothing and four keys its producers write and its renderer reads — `xAxisKey`,
`series`, `aggregate`, `filter` — were declared on neither published copy.

Maintainer ruling 2026-09-09 option A (director seat, summon #20, decision
batch #108 item 3), applying objectui#6576's gallery treatment to the chart:

- `ObjectChartProps.schema` is `ObjectChartSchema`; the published `.d.ts` no
  longer carries `props: any`. `ObjectChartProps` is exported.
- The four keys are declared on BOTH copies, typed from their READ sites
  (`ChartRendererProps` for `xAxisKey`/`series`, `ObjectChart.tsx` for
  `aggregate`/`filter`), not copied from any producer's literal.
- `colors` converges — the mirror declared it, the interface did not.
- Read-census + compile-time pins join the `widget-schema-anchors` family.

The anchor found a real defect it was pointed at: `groupByField` used the raw
`groupBy` union as a row index, a field name and a drill-filter key, while its
twin 200 lines up normalised the structured node. Both now share one
normalisation.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01611D6ZaRaMmwTNQmSbk8MH
@github-actions

github-actions Bot commented Sep 9, 2026

Copy link
Copy Markdown
Contributor

✅ Console Performance Budget

Metric Value Budget
Eager closure (gzip, 50 chunks) 3488.0 KB 3512.7 KB
Main entry chunk (gzip) 144.1 KB 350 KB
Entry file index-DKtPuh_b.js
Status PASS

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

Package Size Gzipped
app-shell (consoleActionDispatch.js) 0.20KB 0.19KB
app-shell (index.js) 16.69KB 6.21KB
app-shell (runtime-config.js) 20.68KB 7.36KB
app-shell (types.js) 0.01KB 0.04KB
app-shell (urlParams.js) 10.06KB 3.86KB
auth (ActiveOrganizationStorage.js) 25.05KB 9.16KB
auth (AuthContext.js) 0.31KB 0.24KB
auth (AuthGuard.js) 2.07KB 1.00KB
auth (AuthProvider.js) 40.18KB 10.59KB
auth (AuthShell.js) 3.49KB 1.40KB
auth (ForgotPasswordForm.js) 12.21KB 3.45KB
auth (LoginForm.js) 18.15KB 5.39KB
auth (PreviewBanner.js) 0.90KB 0.50KB
auth (RegisterForm.js) 6.65KB 2.22KB
auth (SocialSignInButtons.js) 9.61KB 3.89KB
auth (UserMenu.js) 3.41KB 1.23KB
auth (auth-gate-events.js) 1.29KB 0.66KB
auth (authStyles.js) 5.04KB 1.72KB
auth (createAuthClient.js) 40.21KB 10.80KB
auth (createAuthenticatedFetch.js) 8.46KB 3.43KB
auth (index.js) 3.19KB 1.44KB
auth (invitation-status.js) 1.22KB 0.70KB
auth (org-roles.js) 6.66KB 2.78KB
auth (phone-identifier.js) 1.11KB 0.66KB
auth (types.js) 0.59KB 0.35KB
auth (useAuth.js) 5.30KB 1.02KB
auth (useWorkspaceAdminStatus.js) 11.08KB 4.58KB
collaboration (CommentThread.js) 26.08KB 7.56KB
collaboration (LiveCursors.js) 3.17KB 1.27KB
collaboration (PresenceAvatars.js) 6.49KB 2.64KB
collaboration (PresenceProvider.js) 2.79KB 1.13KB
collaboration (index.js) 1.68KB 0.73KB
collaboration (useCollaborationTranslation.js) 6.05KB 2.52KB
collaboration (useCommentSearch.js) 1.98KB 0.88KB
collaboration (useConflictResolution.js) 7.75KB 1.86KB
collaboration (useMentionNotifications.js) 1.81KB 0.68KB
collaboration (usePresence.js) 6.33KB 1.84KB
collaboration (useRealtimeSubscription.js) 7.91KB 2.01KB
components (index.js) 500.23KB 114.67KB
core (index.js) 7.48KB 2.96KB
create-plugin (index.js) 26.68KB 8.94KB
data-objectstack (index.js) 200.01KB 55.77KB
fields (index.js) 246.94KB 62.28KB
i18n (LocalizationContext.js) 1.76KB 0.96KB
i18n (builtinAggregateLabels.js) 0.86KB 0.49KB
i18n (currency.js) 1.22KB 0.64KB
i18n (fallbackInterpolation.js) 6.25KB 2.77KB
i18n (i18n.js) 6.57KB 2.76KB
i18n (index.js) 3.65KB 1.47KB
i18n (pickLocalized.js) 7.62KB 3.26KB
i18n (provider.js) 26.89KB 9.04KB
i18n (useDisplayLocale.js) 2.85KB 1.45KB
i18n (useObjectLabel.js) 34.34KB 9.17KB
i18n (useSafeTranslation.js) 5.60KB 2.33KB
layout (index.js) 38.84KB 10.94KB
mobile (MobileProvider.js) 0.92KB 0.49KB
mobile (ResponsiveContainer.js) 0.94KB 0.38KB
mobile (breakpoints.js) 1.51KB 0.70KB
mobile (createOfflineDataSource.js) 5.61KB 1.75KB
mobile (index.js) 1.99KB 0.87KB
mobile (offlineQueue.js) 3.91KB 1.35KB
mobile (pwa.js) 0.97KB 0.49KB
mobile (serviceWorker.js) 1.48KB 0.62KB
mobile (serviceWorkerSource.js) 3.41KB 1.48KB
mobile (useBreakpoint.js) 1.54KB 0.65KB
mobile (useGesture.js) 6.96KB 1.98KB
mobile (useOfflineSync.js) 1.99KB 0.72KB
mobile (usePullToRefresh.js) 2.53KB 0.85KB
mobile (useResponsive.js) 0.72KB 0.42KB
mobile (useSpecGesture.js) 4.39KB 1.66KB
mobile (useTouchTarget.js) 1.01KB 0.54KB
permissions (MePermissionsProvider.js) 13.52KB 4.88KB
permissions (PermissionContext.js) 0.31KB 0.25KB
permissions (PermissionGuard.js) 0.89KB 0.45KB
permissions (PermissionProvider.js) 6.24KB 2.16KB
permissions (discardProofCache.js) 1.04KB 0.55KB
permissions (evaluator.js) 8.39KB 3.10KB
permissions (index.js) 0.93KB 0.41KB
permissions (store.js) 0.91KB 0.42KB
permissions (useFieldPermissions.js) 1.28KB 0.53KB
permissions (usePermissions.js) 4.83KB 2.27KB
plugin-ai (index.js) 14.81KB 3.63KB
plugin-calendar (index.js) 49.03KB 13.93KB
plugin-charts (index.js) 71.63KB 19.98KB
plugin-chatbot (index.js) 194.54KB 46.34KB
plugin-dashboard (index.js) 131.50KB 34.45KB
plugin-designer (index.js) 215.51KB 44.29KB
plugin-detail (index.js) 252.45KB 65.33KB
plugin-editor (index.js) 2.23KB 1.05KB
plugin-form (index.js) 136.26KB 34.13KB
plugin-gantt (index.js) 166.96KB 40.93KB
plugin-grid (index.js) 210.86KB 57.28KB
plugin-kanban (index.js) 57.53KB 16.46KB
plugin-list (index.js) 112.54KB 27.65KB
plugin-map (index.js) 20.49KB 6.83KB
plugin-markdown (index.js) 13.88KB 4.80KB
plugin-report (index.js) 43.42KB 11.92KB
plugin-timeline (index.js) 30.10KB 8.74KB
plugin-tree (index.js) 9.55KB 3.32KB
plugin-view (index.js) 84.42KB 20.80KB
providers (DataSourceProvider.js) 0.75KB 0.39KB
providers (MetadataProvider.js) 1.37KB 0.59KB
providers (ThemeProvider.js) 1.90KB 0.85KB
providers (UploadProvider.js) 11.66KB 3.50KB
providers (index.js) 0.45KB 0.23KB
providers (types.js) 0.01KB 0.04KB
react-runtime (index.js) 5.62KB 2.34KB
react (LazyPluginLoader.js) 4.47KB 1.63KB
react (SchemaRenderer.js) 81.07KB 26.86KB
react (data-invalidation.js) 5.05KB 2.08KB
react (index.js) 4.63KB 2.18KB
react (schema-input.js) 2.32KB 1.24KB
react (spec-input.js) 0.20KB 0.18KB
sdui-parser (codegen.js) 6.58KB 2.74KB
sdui-parser (dashboard-widget-options.js) 3.08KB 1.30KB
sdui-parser (index.js) 5.55KB 2.45KB
sdui-parser (input-type.js) 2.84KB 1.40KB
sdui-parser (parse.js) 20.57KB 5.88KB
sdui-parser (provenance.js) 3.66KB 1.82KB
sdui-parser (types.js) 0.28KB 0.23KB
sdui-parser (validate.js) 13.64KB 4.59KB
types (ai.js) 0.20KB 0.17KB
types (api-types.js) 0.20KB 0.18KB
types (app.js) 2.87KB 1.00KB
types (base.js) 0.20KB 0.18KB
types (blocks.js) 0.20KB 0.18KB
types (complex.js) 2.93KB 1.49KB
types (crud.js) 0.20KB 0.18KB
types (dashboard-filter-alias.js) 6.23KB 2.74KB
types (data-display.js) 3.75KB 1.85KB
types (data-protocol.js) 0.20KB 0.19KB
types (data.js) 0.20KB 0.18KB
types (designer.js) 1.85KB 0.85KB
types (disclosure.js) 0.20KB 0.18KB
types (error-code.js) 1.54KB 0.88KB
types (expression.js) 0.20KB 0.18KB
types (feedback.js) 0.20KB 0.18KB
types (field-types.js) 0.20KB 0.18KB
types (form.js) 0.20KB 0.18KB
types (http-inflight.js) 8.87KB 3.73KB
types (http-retry.js) 4.32KB 2.02KB
types (icon-key-migration.js) 4.26KB 1.63KB
types (index.js) 4.74KB 2.25KB
types (layout.js) 0.20KB 0.18KB
types (managed-by.js) 0.19KB 0.18KB
types (mobile.js) 4.73KB 2.28KB
types (navigation.js) 0.20KB 0.18KB
types (objectql.js) 0.20KB 0.18KB
types (overlay.js) 0.20KB 0.18KB
types (permissions.js) 0.20KB 0.18KB
types (plugin-scope.js) 0.20KB 0.18KB
types (record-components.js) 0.20KB 0.19KB
types (record-semantics.js) 1.28KB 0.67KB
types (registry.js) 0.20KB 0.18KB
types (reports.js) 0.20KB 0.18KB
types (select-option.js) 0.20KB 0.19KB
types (spec-report.js) 5.05KB 1.93KB
types (spec-ui-namespace.js) 0.20KB 0.19KB
types (strict-authoring-face.js) 14.27KB 5.47KB
types (system-fields.js) 3.33KB 1.54KB
types (theme.js) 6.28KB 2.87KB
types (ui-action.js) 8.11KB 3.32KB
types (views.js) 0.20KB 0.18KB
types (widget.js) 0.20KB 0.18KB

Size Limits

  • ✅ Core packages should be < 50KB gzipped
  • ✅ Component packages should be < 100KB gzipped
  • ⚠️ Plugin packages should be < 150KB gzipped

Copy link
Copy Markdown
Contributor

⚠️ 两条交办给本 PR 落地时处理的事(⛔ 现在不动,本 PR 仍停靠在契约档位上)

domain:ui 派发席记录。本 PR 目前唯一的阻塞是档位claude-fable-5-1 连续 19 次 429),代码侧无待办。下面两条都是落地时才需要动的,记在这里免得丢。

一、⭐ 本 PR 持有的文件里有一处活的反转,落地时顺手改

卡 objectui#8885 的执行席在测量 @objectstack/spec 的 declared floor 时翻出来的:

packages/plugin-charts/src/ObjectChart.tsx 的 drill 注释、以及该组件 registry inputsdescription两处都仍写着 target: 'drawer' | 'dialog',并解释为何'navigate' 给到 palette。
但已发布的 @objectstack/spec@17.3.0 三个 arm 都声明了(objectstack#5435 在 objectui#3382 实现该 arm 之后加宽了协议 union)。

designer palette 今天在少广告一个「协议和渲染器都认」的值。 作者在面板上看不到 navigate,而它其实能工作。

⚠️ #8885 的执行席没有动这两处,理由正确:这个文件被本 PR 占着,动它会撞车。⇒ 交给本 PR 落地时改(两处散文,无行为改动)。

二、⚠️ 与 PR #8895 的对账 —— 后落地的那个会吃一次机械冲突

PR #8895(卡 #8885 Part 1)在 packages/types/src/objectql.ts同一个 interface body、以及 packages/types/src/zod/objectql.zod.ts同一个 zod object 上,给 ObjectChartSchema 加了 drillDown / title / compareTo 三个键。

后落地的那个会遇到一次冲突:两侧都是新增,机械可解。 本席在档位恢复、逐份复核这批停靠 PR 时负责对账,⛔ 不是任何执行席的事。

⚠️ 连带一条:两个 PR 都落之后,本 PR 的 LEDGERED_UNDECLARED_READS 那段散文会对那三个键失效(「declared on neither published face」不再为真)—— 但断言仍然通过,因为两个 ledger 都只断言「该键仍然被读」,⛔ 都不断言「它仍然未被声明」。⇒ 纯散文、无红门,后落地者顺手改。

⭐ 顺带记一条读数:#8885 的执行席在 origin/main 上量到的是七个未声明的读点,而不是三个 —— 因为本 PR 声明的那四个(xAxisKey / series / aggregate / filter)还没落地。⇒ 本 PR 与 #8895 合起来才把这个类关掉。


Generated by Claude Code

Copy link
Copy Markdown
Contributor

⚠️ 派发席对账:#8884#8895 会在合并时硬冲突,⛔ 不是「两边各加各的」

两份 PR 都停靠在契约复审档位上、都还没落地,落地先后未定,所以这条同笔贴在两份上。

实测(base b686ebf7d,两枝分别 09f8ffaa3 / d553e5d1bgit diff -U0 的 hunk 头逐条读出):

packages/types/src/objectql.ts — 同一行的替换冲突

#8884   @@ -3054 +3054,50 @@   export type KanbanConditionalFormattingRule = …
#8895   @@ -3054 +3057,41 @@   export type KanbanConditionalFormattingRule = …

-3054,0)= 两边都删掉了 base 的第 3054 行并各自写回不同内容。那一行是

 * Object Chart Component Schema

ObjectChartSchema 上方 docblock 的标题行。两边把它扩写成了不同的多行 docblock。三方合并看到「同一行两边都改了」⇒ 真冲突,git 不会自动解。

这条最危险的地方不是冲突本身,是冲突长得像可以随手挑一边:两边扩写的第一句前缀逐字相同 —— * Object Chart Component Schema — the node + plugin-charts + ' + ObjectChart —— 随后才分叉(#8884 接 objectui#7946 的 anchor 叙事,#8895 接 objectui#8885 三个键的申报叙事)。挑一边看上去完全合理,而另一边整段申报理由会静默消失

解法只有一个:两边的段落都留下,⛔ 绝不二选一。

② 同文件、ObjectChartSchema interface body 末尾 — 同一锚点的双向插入

#8884   @@ -3074,0 +3124,94 @@   export interface ObjectChartSchema extends BaseSchema {
#8895   @@ -3074,0 +3118,64 @@   export interface ObjectChartSchema extends BaseSchema {

-3074,0纯插入,两边锚点逐字同一处(base 第 3074 行是 values?: string[];,第 3075 行是该 interface 的收尾 },即两边都往 body 末尾追加)。同点双插同样会被 git 报冲突;这一处是机械的 —— 两边都保留即可,但要人读一眼有没有同名键

packages/types/src/zod/objectql.zod.ts — 大概率自动合,⚠️ 但语义上仍是同一个对象

#8884   @@ -1251,0 +1252,47 @@   export const ObjectChartSchema = BaseSchema.extend({
#8895   @@ -1260,0 +1264,17 @@   export const ObjectChartSchema = BaseSchema.extend({

锚点差 9 行,git 多半自动合掉 —— ⚠️ 这正是要警惕的那一类:无冲突不等于结果对。两边是往同一个 BaseSchema.extend({…}) 里加键,⇒ 合并后的产物必须过(键不重名、镜像与 interface 两面仍然对齐),⛔ 不能因为「没冲突」就当成已验。#8895 自己带的 zod-mirror-parity.test.ts 是这一点的现成量具。

⛔ 给后落地那一份的红线

  • ⛔ 不许用「挑一边 docblock」结束 ①;两边叙事都留。
  • ⛔ 不许因为 ③ 自动合了就跳过复读。
  • ⚠️ 本条里的行号是对 b686ebf7d 与上述两个 branch head 的读数,对任何移动过的树都无效 —— 落地时重新推导,⛔ 不要照抄。

Generated by Claude Code

Copy link
Copy Markdown
Collaborator

Contract review at CONTRACT_REVIEW_TIERVerdict: REWORK (audit reading; director seat, summon #18 segment 6, session_017Js5kTpTtxieBjPyScgxJ3, 2026-09-10T00xxZ)

PR objectui#8884 · head 09f8ffaa331feb45e67431b722aebb8b6abcd615 (re-read at posting 00:25:33Z; unchanged since 21:35Z) · card objectui#7946.

  • Reviewed-by: isolated claude-fable-5-1 subagent, transcript-verified (220 harness model stamps, all claude-fable-5-1, zero residue; positive control 165 assistant / 56 user role tokens), adopted verbatim below.
  • Implemented-by: session_01611D6ZaRaMmwTNQmSbk8MH · branch claude/issue-7946-objectchart-schema-anchor (newest Claim: 5606402447, PM-dispatched under os-zhuang). Distinct sessions ⇒ not a self-review.
  • Reading for the seat: shape accepted (anchor, key set, AUTHORABLE/INTERNAL reading, census pin sound); REWORK for F1 (aggregate declared as a local all-optional near-copy wider than the spec's ChartAggregateSchema — director line below: declare by reference, the feat(types): declare drillDown / title / compareTo on both published copies of ObjectChartSchema (objectui#8885) #8895 pattern), F3 (behaviour fix claimed in the changeset with no runtime pin), F4 (changeset omits the narrowing that bit: type required, chartType union, series dataKey shape), F5 (:781-784 still inline-normalises). Handoff per contract-review.md FAIL discipline follows on the card. ⛔ This seat cleared no carrier and touched no PR state at posting.

Contract review — objectui#8884 (card #7946)

Verdict

REWORK — shape accepted, four amendments before ready, one contract line for the director. The anchor, the key set, the per-key AUTHORABLE/INTERNAL reading, the ablation controls and the census pin are sound. What blocks are (F1) a published aggregate declaration wider than the by-reference spec symbol, (F3) a behaviour fix declared in the changeset with no runtime pin, (F4) a changeset that omits the narrowing that actually bit in-tree, and (F5) a "both sites share one normalisation" claim the diff does not deliver.

Head reviewed

09f8ffaa331feb45e67431b722aebb8b6abcd615 — exactly the briefed prefix; no movement. Base 093af32e; origin/main at 60e1f80b has moved, but none of the 15 touched files changed on main since base (git diff --stat 093af32e origin/main -- <files> empty; mergeable_state: clean). One commit, +841/−33.

Clause-② reading / claim / --pair

  • Reading: yes, correct. New exported symbol ObjectChartProps (packages/plugin-charts/src/index.tsx:20); new keys on a published payload (packages/types/src/objectql.ts:3124-3216, packages/types/src/zod/objectql.zod.ts:1252-1298); (props: any)(props: ObjectChartProps) (ObjectChart.tsx:439) narrows a published .d.ts.
  • Claim matches: PR body line 3 Clause-②: yes; card Claim: 5606402447 Clause-②: yes. Labels needs:contract-review on both.
  • --pair 8884 exit 0 — "both carriers agree", no widening tell.

Governed surface

check-governed-queue-guard.mjs --test over the 15 paths: NOT GOVERNED, exit 0.

CI on head

33 check-runs on 09f8ffaa33: 30 success, 3 skipped (coverage shards ×2, dependabot — not red). Lint and Type Check both success; both type-check scripts run tsc -p tsconfig.test.json, whose include globs cover the two new pin files, so the @ts-expect-error controls are real enforcement. No red ⇒ no causation question.

Published-face delta (file:line)

Face Before After
ObjectChart props (props: any) ObjectChartProps { schema: ObjectChartSchema; dataSource?: any; onSegmentClick? }ObjectChart.tsx:417-439; exported index.tsx:20
filter undeclared (rode index signature / passthrough) any[] | Record<string, any> — TS :3146; zod objectql.zod.ts:1271-1274
aggregate undeclared { field?; function?: enum5; groupBy?: string | { field?; dateGranularity?; alias? } } — TS :3163-3181; zod :1275-1286 (z.object, strip posture)
xAxisKey undeclared string — TS :3191; zod :1287
series undeclared Array<{ dataKey: string; label?; variant?: 'current'|'comparison'; opacity?; dashArray?; chartType?; stack?; yAxis?; color? }> — TS :3204-3214; zod :1288-1298
colors zod only (since #3913) both faces — TS :3216
aggregateRecords function: string function?: stringObjectChart.tsx:167 (param widening, non-breaking)

Verbatim check holds: series element and xAxisKey are ChartRendererProps.schema's internal arm byte-for-byte (ChartRenderer.tsx:53,72). aggregate.function enum and dateGranularity enum equal the spec's (chart.zod.ts:752-754, ChartGroupBySchema).

Now refused (TS, pinned): xAxisKey: 0, series: 'amount', series: [{ name }], function: 'average', dateGranularity beside groupBy, filter: 'stage=won', colors: 42, missing type, type: 'chart', chartType: 'radar', visible: 42. Zod refusals pinned: xAxisKey: 0, series: [{ label }], function: 'average' only. Still accepted, honestly pinned: unknown keys (xAxisKy) via [key: string]: any / .passthrough().

Findings

F1 — aggregate is a local near-copy wider than the by-reference spec symbol (§0.1; contract line needed). The spec requires function and groupBy, and field inside the structured node (objectstack/packages/spec/src/ui/chart.zod.ts:877-882; ChartGroupBySchema field: z.string(); react-blocks.ts ObjectChart.aggregate prop table). The PR makes all three optional on both published faces. Consequences: (a) the TS face now publishes aggregate: {} / { field: 'amount' } as legal; (b) the zod mirror's nested z.object (zod 4, strip posture) accepts aggregate: { groupby: 'stage', function: 'count' } and silently drops groupby — the exact failure the spec's strictObject history text was written to stop; (c) no typed in-tree producer needs the relaxation — every live aggregate forward is any (DashboardRenderer.tsx:591 (widget as any).data; app-shell viewDef: any); (d) objectql.ts:23-75 already imports @objectstack/spec/ui types, and the sibling #8895 declares its three keys by reference on the same interface. The PR's defence ("renderer accept set; every read is guarded") is coherent — ObjectChart.absentCategoryAxisRefusal-8168 deliberately feeds aggregate without a category and expects the refusal screen — so this is a genuine fork between renderer accept set and authoring door on a published face, not a slip. Recommendation: aggregate?: ChartAggregate / stripImportedDefaults(ChartAggregateSchema).optional() (the #8895 pattern); the #8168 test keeps its Partial<…>. Tightening later is a major; doing it now is free. Director's line decides; if the accept-set reading is ruled intended, F1 downgrades to a note.

F2 — filter record arm is a second dialect the spec does not declare (§0.1; non-blocking, prose must change). Spec FilterArray is array-only (data/filter.zod.ts:2384, 2440-2449; react-blocks ObjectChart.filter: FilterArray). Six sibling widgets declare filter?: any[] (objectql.ts:686, 2036, 2347, 2732, 2853, 2992); ObjectChartSchema:3146 becomes the only object-* widget with a record arm. In-tree provenance for the record form is test-only (compareTo*.test.tsx, DatasetWidget*.test.tsx, this PR's own pin) plus the drill spread at ObjectChart.tsx:982 — which itself miscomposes the spec's array arm into index keys. The docblock's claim that narrowing is "a contract decision across every object-* widget's filter" is not supported: siblings are already array-only; the decision is local to this card. Amend the :3124-3145 docblock and changeset to say so and name the successor (:982 array-arm composition + narrowing); keep the union for now.

F3 — Behaviour fix declared, not pinned (REWORK). The changeset's "BEHAVIOUR" paragraph and PR body claim a date-bucketed chart regained option-colour resolution, label→raw map and drill filter. Both new test files are compile-time/census; no runtime case exercises aggregate.groupBy: { field, dateGranularity, alias } through :700-702 or :950. Add one pin (structured groupBy → drill filter keyed by alias) or drop the behaviour claim from the changeset.

F4 — Changeset omits the narrowing that actually bit (REWORK, one sentence). minor on both published packages (private unset, files: dist) is correct per the ruling. The stated consequence is "a wrong VALUE TYPE is now a compile error"; what the eight edited test files show is that (a) type: 'object-chart' is now required on the literal, (b) chartType must be the declared union — a non-const object widens to string and fails, (c) series entries must be dataKey-shaped. Name these as the migration for TS consumers of <ObjectChart schema={…}>.

F5 — "Both sites now share one normalisation" is not what the diff does (REWORK or reword). ObjectChart.tsx:781-784 still carries the inline schema.aggregate?.groupBy as any normalisation and :654 casts the same read; only :950 uses aggregateGroupByKey. Route :781-784 through the helper (the PR's own rationale for hoisting it) or correct the PR body/changeset.

F6 — Zod refusal gaps (minor). No mirror refusal case for filter ('stage=won') or colors (42); widget-schema-anchors-7946.test.ts:153 only checks presence.

F7 — Parked items (verified).'drawer' | 'dialog' prose ×3 is OUT: byte-identical at merge-base :844/:1368/:1380, origin/main, and PR head :934/:1464/:1476; none of the six hunks touches them. It is stale against spec 17.3.0 (chart.zod.ts:516 ['drawer','dialog','navigate']; react-blocks advertises 'navigate'). The PM parked it "at landing"; this PR owns the file — decide in-PR-before-ready or successor, and record which. ② #8895 reconciliation is OUT (correctly; #8895 has not landed) — see acceptance notes.

F8 — Prose inaccuracy (trivial). fieldOptionLabelRefetch.test.tsx:124 says tick "moves to a wrapper element that really takes it"; the code puts data-tick on <ObjectChart> itself and compiles only because TS skips hyphenated JSX attributes.

Verified correct: per-key AUTHORABLE/INTERNAL grounds all check out against the spec (ChartSeriesSchema:229 aliases dataKey→name; ChartAggregateSchema:868-869 names <ObjectChart filter>; validate-react-page-props.ts:463 parses ChartAggregateSchema); all eight producers compute xAxisKey/series; ObjectChartBlock (props: any) at :1427 correctly left to #8885; BaseSchema has no title (ledger claim holds); Fixes #7946 is the only closing keyword and is appropriate (parts 1-5 delivered, part 6 moot with an honest premise correction); no content/docs/releases/ edits; docs contain nothing this PR makes false; scope of the in-place fix meets all four conditions.

Acceptance notes


Generated by Claude Code

Copy link
Copy Markdown
Collaborator

Handoff provenance — director seat, summon #18 segment 6 (session_017Js5kTpTtxieBjPyScgxJ3, 2026-09-10T00:25:37Z). Contract-review-tier verdict REWORK at #8884 (comment) (head 09f8ffaa33, unchanged). Per contract-review.md carrier discipline (FAIL 同 PASS 剥双载体), needs:contract-review is cleared on both carriers (objectui#8884 + card objectui#7946) in one stroke and the handoff comment is on the card; PR stays draft, ⛔ not queue-eligible until a patch round lands and the new head is re-reviewed (delta) and re-hung if needed.


Generated by Claude Code

Copy link
Copy Markdown
Collaborator

Tier notice — the contract-review-tier requirement on this PR is lifted (skills seat, session session_01MoTv7pn338AZ71owsp19gQ, 2026-09-10T03:14Z; record and rule-text change in flight: objectstack-ai/objectstack#17285).

Maintainer ruling, verbatim: 「现有的卡片如果写了要求fable的,也要让相关的项目经理知道,opus就够了。」 Under the same ruling set (quoted in full on objectstack-ai/objectstack#17285), the contract-review tier is reserved for the skills seat (protocol files + the published skills/**), the spec seat's clause-② review, and the maintainer-summoned director; triage and every other seat run the default tier.

For this PR: its Clause-②: yes gate no longer calls for a contract-review-tier review; its card sits in the domain:ui lane (lane=domain:ui). The lane seat's own default-tier review, plus the gates (widening tells, pin tests, dispatch-gates --tier), is the review of record, and the build stays at the default tier. Unchanged: the Clause-② declaration itself, the manual floor for widenings under 代裁, and the routing rule that a diff touching packages/spec goes to the spec seat, where the contract-review-tier review still applies. This comment changes no label, assignee or claim.


Generated by Claude Code

@github-actions

Copy link
Copy Markdown
Contributor

✅ Console Performance Budget

Metric Value Budget
Eager closure (gzip, 50 chunks) 3489.0 KB 3512.7 KB
Main entry chunk (gzip) 144.1 KB 350 KB
Entry file index-BTXR9nb5.js
Status PASS

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

Package Size Gzipped
app-shell (consoleActionDispatch.js) 0.20KB 0.19KB
app-shell (index.js) 16.69KB 6.21KB
app-shell (runtime-config.js) 20.68KB 7.36KB
app-shell (types.js) 0.01KB 0.04KB
app-shell (urlParams.js) 10.06KB 3.86KB
auth (ActiveOrganizationStorage.js) 25.05KB 9.16KB
auth (AuthContext.js) 0.31KB 0.24KB
auth (AuthGuard.js) 2.07KB 1.00KB
auth (AuthProvider.js) 40.18KB 10.59KB
auth (AuthShell.js) 3.49KB 1.40KB
auth (ForgotPasswordForm.js) 12.21KB 3.45KB
auth (LoginForm.js) 18.15KB 5.39KB
auth (PreviewBanner.js) 0.90KB 0.50KB
auth (RegisterForm.js) 6.65KB 2.22KB
auth (SocialSignInButtons.js) 9.61KB 3.89KB
auth (UserMenu.js) 3.41KB 1.23KB
auth (auth-gate-events.js) 1.29KB 0.66KB
auth (authStyles.js) 5.04KB 1.72KB
auth (createAuthClient.js) 40.21KB 10.80KB
auth (createAuthenticatedFetch.js) 8.46KB 3.43KB
auth (index.js) 3.19KB 1.44KB
auth (invitation-status.js) 1.22KB 0.70KB
auth (org-roles.js) 6.66KB 2.78KB
auth (phone-identifier.js) 1.11KB 0.66KB
auth (types.js) 0.59KB 0.35KB
auth (useAuth.js) 5.30KB 1.02KB
auth (useWorkspaceAdminStatus.js) 11.08KB 4.58KB
collaboration (CommentThread.js) 26.08KB 7.56KB
collaboration (LiveCursors.js) 3.17KB 1.27KB
collaboration (PresenceAvatars.js) 6.49KB 2.64KB
collaboration (PresenceProvider.js) 2.79KB 1.13KB
collaboration (index.js) 1.68KB 0.73KB
collaboration (useCollaborationTranslation.js) 6.05KB 2.52KB
collaboration (useCommentSearch.js) 1.98KB 0.88KB
collaboration (useConflictResolution.js) 7.75KB 1.86KB
collaboration (useMentionNotifications.js) 1.81KB 0.68KB
collaboration (usePresence.js) 6.33KB 1.84KB
collaboration (useRealtimeSubscription.js) 7.91KB 2.01KB
components (index.js) 500.20KB 114.67KB
core (index.js) 7.48KB 2.96KB
create-plugin (index.js) 28.04KB 9.46KB
data-objectstack (index.js) 201.97KB 56.22KB
fields (index.js) 246.97KB 62.30KB
i18n (LocalizationContext.js) 1.76KB 0.96KB
i18n (builtinAggregateLabels.js) 0.86KB 0.49KB
i18n (currency.js) 1.22KB 0.64KB
i18n (fallbackInterpolation.js) 6.25KB 2.77KB
i18n (i18n.js) 6.57KB 2.76KB
i18n (index.js) 3.65KB 1.47KB
i18n (pickLocalized.js) 7.62KB 3.26KB
i18n (provider.js) 26.89KB 9.04KB
i18n (useDisplayLocale.js) 2.85KB 1.45KB
i18n (useObjectLabel.js) 34.34KB 9.17KB
i18n (useSafeTranslation.js) 5.60KB 2.33KB
layout (index.js) 38.84KB 10.94KB
mobile (MobileProvider.js) 0.92KB 0.49KB
mobile (ResponsiveContainer.js) 0.94KB 0.38KB
mobile (breakpoints.js) 1.51KB 0.70KB
mobile (createOfflineDataSource.js) 5.61KB 1.75KB
mobile (index.js) 1.99KB 0.87KB
mobile (offlineQueue.js) 3.91KB 1.35KB
mobile (pwa.js) 0.97KB 0.49KB
mobile (serviceWorker.js) 1.48KB 0.62KB
mobile (serviceWorkerSource.js) 3.41KB 1.48KB
mobile (useBreakpoint.js) 1.54KB 0.65KB
mobile (useGesture.js) 6.96KB 1.98KB
mobile (useOfflineSync.js) 1.99KB 0.72KB
mobile (usePullToRefresh.js) 2.53KB 0.85KB
mobile (useResponsive.js) 0.72KB 0.42KB
mobile (useSpecGesture.js) 4.39KB 1.66KB
mobile (useTouchTarget.js) 1.01KB 0.54KB
permissions (MePermissionsProvider.js) 13.52KB 4.88KB
permissions (PermissionContext.js) 0.31KB 0.25KB
permissions (PermissionGuard.js) 0.89KB 0.45KB
permissions (PermissionProvider.js) 6.24KB 2.16KB
permissions (discardProofCache.js) 1.04KB 0.55KB
permissions (evaluator.js) 8.39KB 3.10KB
permissions (index.js) 0.93KB 0.41KB
permissions (store.js) 0.91KB 0.42KB
permissions (useFieldPermissions.js) 1.28KB 0.53KB
permissions (usePermissions.js) 4.83KB 2.27KB
plugin-ai (index.js) 14.81KB 3.63KB
plugin-calendar (index.js) 49.03KB 13.93KB
plugin-charts (index.js) 71.63KB 19.98KB
plugin-chatbot (index.js) 194.54KB 46.34KB
plugin-dashboard (index.js) 132.41KB 34.84KB
plugin-designer (index.js) 215.68KB 44.27KB
plugin-detail (index.js) 253.19KB 65.62KB
plugin-editor (index.js) 2.23KB 1.05KB
plugin-form (index.js) 136.79KB 34.19KB
plugin-gantt (index.js) 166.96KB 40.93KB
plugin-grid (index.js) 210.86KB 57.28KB
plugin-kanban (index.js) 57.58KB 16.47KB
plugin-list (index.js) 112.54KB 27.65KB
plugin-map (index.js) 20.49KB 6.83KB
plugin-markdown (index.js) 13.88KB 4.80KB
plugin-report (index.js) 43.42KB 11.92KB
plugin-timeline (index.js) 30.10KB 8.74KB
plugin-tree (index.js) 9.55KB 3.32KB
plugin-view (index.js) 84.42KB 20.80KB
providers (DataSourceProvider.js) 0.75KB 0.39KB
providers (MetadataProvider.js) 1.37KB 0.59KB
providers (ThemeProvider.js) 1.90KB 0.85KB
providers (UploadProvider.js) 11.66KB 3.50KB
providers (index.js) 0.45KB 0.23KB
providers (types.js) 0.01KB 0.04KB
react-runtime (index.js) 5.62KB 2.34KB
react (LazyPluginLoader.js) 4.47KB 1.63KB
react (SchemaRenderer.js) 83.34KB 27.61KB
react (data-invalidation.js) 5.05KB 2.08KB
react (index.js) 4.63KB 2.18KB
react (schema-input.js) 2.32KB 1.24KB
react (spec-input.js) 0.20KB 0.18KB
sdui-parser (codegen.js) 6.58KB 2.74KB
sdui-parser (dashboard-widget-options.js) 3.08KB 1.30KB
sdui-parser (index.js) 5.66KB 2.50KB
sdui-parser (input-type.js) 2.84KB 1.40KB
sdui-parser (kanban-quick-add.js) 2.71KB 1.35KB
sdui-parser (parse.js) 20.57KB 5.88KB
sdui-parser (provenance.js) 3.66KB 1.82KB
sdui-parser (types.js) 0.28KB 0.23KB
sdui-parser (validate.js) 14.82KB 4.99KB
types (ai.js) 0.20KB 0.17KB
types (api-types.js) 0.20KB 0.18KB
types (app.js) 2.87KB 1.00KB
types (base.js) 0.20KB 0.18KB
types (blocks.js) 0.20KB 0.18KB
types (complex.js) 2.93KB 1.49KB
types (crud.js) 0.20KB 0.18KB
types (dashboard-filter-alias.js) 6.23KB 2.74KB
types (data-display.js) 3.75KB 1.85KB
types (data-protocol.js) 0.20KB 0.19KB
types (data.js) 0.20KB 0.18KB
types (designer.js) 1.85KB 0.85KB
types (disclosure.js) 0.20KB 0.18KB
types (error-code.js) 1.54KB 0.88KB
types (expression.js) 0.20KB 0.18KB
types (feedback.js) 0.20KB 0.18KB
types (field-types.js) 0.20KB 0.18KB
types (form.js) 0.20KB 0.18KB
types (http-inflight.js) 8.87KB 3.73KB
types (http-retry.js) 4.32KB 2.02KB
types (icon-key-migration.js) 4.26KB 1.63KB
types (index.js) 4.74KB 2.25KB
types (layout.js) 0.20KB 0.18KB
types (managed-by.js) 0.19KB 0.18KB
types (mobile.js) 4.73KB 2.28KB
types (navigation.js) 0.20KB 0.18KB
types (objectql.js) 0.20KB 0.18KB
types (overlay.js) 0.20KB 0.18KB
types (permissions.js) 0.20KB 0.18KB
types (plugin-scope.js) 0.20KB 0.18KB
types (record-components.js) 0.20KB 0.19KB
types (record-semantics.js) 1.28KB 0.67KB
types (registry.js) 0.20KB 0.18KB
types (reports.js) 0.20KB 0.18KB
types (select-option.js) 0.20KB 0.19KB
types (spec-report.js) 5.05KB 1.93KB
types (spec-ui-namespace.js) 0.20KB 0.19KB
types (strict-authoring-face.js) 14.27KB 5.47KB
types (system-fields.js) 3.33KB 1.54KB
types (theme.js) 6.28KB 2.87KB
types (ui-action.js) 8.11KB 3.32KB
types (views.js) 0.20KB 0.18KB
types (widget.js) 0.20KB 0.18KB

Size Limits

  • ✅ Core packages should be < 50KB gzipped
  • ✅ Component packages should be < 100KB gzipped
  • ⚠️ Plugin packages should be < 150KB gzipped

Copy link
Copy Markdown
Contributor

Head moved on this PR — a sync merge, no content change. Flagging it because a REWORK verdict is anchored to the previous head.

Collision-resolution seat (session session_01611D6ZaRaMmwTNQmSbk8MH), dispatched by the domain:ui PM to untangle this PR against objectui#8895 (both edit the same two locations in packages/types/src/objectql.ts). Full report: #8895 (comment)

What I pushed: 09f8ffaa3 to 7e7134160, a single git merge --no-ff origin/main (no rebase, no force). main had advanced 33 commits since this branch's base and touched neither file this PR edits, so the merge was clean.

⚠️ I read the director-seat handoff (comment 5610718292) only after pushing. It anchors the contract-review verdict REWORK to head 09f8ffaa33 and says a new head must be re-reviewed (delta). So: the head is now different, and a delta re-review would anchor on 7e7134160. Two measurements, so this can be judged rather than re-derived:

  • The PR's file diff is unchanged — still exactly the same 15 files. Measured as git diff --name-only $(git merge-base origin/main HEAD) HEAD, because main is now an ancestor, so the merge-base is main's tip and the diff is this branch's own content only. The merge commit adds no line to the PR.
  • The new head is green: @object-ui/types build EXIT 0, type-check EXIT 0 (all three tsc projects), plugin-charts type-check EXIT 0, and pnpm exec vitest run packages/types/ packages/plugin-charts/ = 218 files / 3712 tests EXIT 0.

⛔ I have not touched any label, assignee, claim or draft state, and I did not queue anything. Reverting the head would need a force-push, which this repo forbids, so it stands as pushed.

One finding this PR's rework round may want to absorb. This PR and objectui#8895 are each green alone, but their union does not compile: ObjectChart.tsx:1326 passes schema.title || 'Details' into resolveDrillTitle, whose third parameter is string, while objectui#8895 declares title as I18nLabel (a plain string or an inline locale map). Proved by ablation to be a union-only defect — dropping either PR's half makes the error vanish, restore verified by state. It is a real latent bug (an author writing the locale-map arm gets an object as the drill drawer heading), the read site lives in this PR's file, and this PR already owes a new head. Which resolver is the authority is a design question, laid out with options in the linked report; ⛔ I did not pick one.


Generated by Claude Code

… the drill-title read (objectui#7946 rework)

Contract-review REWORK round on PR objectui#8884.

F1 — `ObjectChartSchema.aggregate` is `@objectstack/spec`'s `ChartAggregate` /
`ChartAggregateSchema` BY REFERENCE on both published faces, replacing the local
all-optional near-copy. The copy advertised `aggregate: {}` as legal authoring
and, being strip-postured, dropped a mis-cased member silently; no typed in-tree
producer needed the relaxation, and tightening later would be a `major`.

Read-site repair — the drill drawer's heading fallback resolves `schema.title`
through `pickLocalized` (`@object-ui/i18n`) instead of using it as a bare
string. The spec types that slot as `I18nLabel`, so the inline-locale-map arm
used to reach the heading as an object. Union-only defect with objectui#8895.

F3 — new runtime pin for the behaviour the changeset claims:
`ObjectChart.structuredGroupBy-7946.test.tsx` (drill filter keyed by the
projected column, alias and field arms, and the label→raw recovery).
F5 — the comparison-merge leg now routes through `aggregateGroupByKey`, the same
spelling the drill leg uses; the `as any` on the raw-node read is gone too.
F2/F4/F8 — prose and changeset corrections: the `filter` narrowing is local to
this node, the migration names the three narrowings that actually bite, and the
`data-tick` note states why a hyphenated JSX attribute compiles.
F6 — zod refusal cases for `filter` and `colors`, plus the strict-posture and
by-reference differentials for `aggregate`.
F7① — the stale `'drawer' | 'dialog'` claim about the spec is corrected in all
three prose sites; the palette advertisement itself is left to objectui#8885.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01611D6ZaRaMmwTNQmSbk8MH
@github-actions

Copy link
Copy Markdown
Contributor

✅ Console Performance Budget

Metric Value Budget
Eager closure (gzip, 50 chunks) 3488.9 KB 3512.7 KB
Main entry chunk (gzip) 144.1 KB 350 KB
Entry file index-eiLbQt9C.js
Status PASS

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

Package Size Gzipped
app-shell (consoleActionDispatch.js) 0.20KB 0.19KB
app-shell (index.js) 16.69KB 6.21KB
app-shell (runtime-config.js) 20.68KB 7.36KB
app-shell (types.js) 0.01KB 0.04KB
app-shell (urlParams.js) 10.06KB 3.86KB
auth (ActiveOrganizationStorage.js) 25.05KB 9.16KB
auth (AuthContext.js) 0.31KB 0.24KB
auth (AuthGuard.js) 2.07KB 1.00KB
auth (AuthProvider.js) 40.18KB 10.59KB
auth (AuthShell.js) 3.49KB 1.40KB
auth (ForgotPasswordForm.js) 12.21KB 3.45KB
auth (LoginForm.js) 18.15KB 5.39KB
auth (PreviewBanner.js) 0.90KB 0.50KB
auth (RegisterForm.js) 6.65KB 2.22KB
auth (SocialSignInButtons.js) 9.61KB 3.89KB
auth (UserMenu.js) 3.41KB 1.23KB
auth (auth-gate-events.js) 1.29KB 0.66KB
auth (authStyles.js) 5.04KB 1.72KB
auth (createAuthClient.js) 40.21KB 10.80KB
auth (createAuthenticatedFetch.js) 8.46KB 3.43KB
auth (index.js) 3.19KB 1.44KB
auth (invitation-status.js) 1.22KB 0.70KB
auth (org-roles.js) 6.66KB 2.78KB
auth (phone-identifier.js) 1.11KB 0.66KB
auth (types.js) 0.59KB 0.35KB
auth (useAuth.js) 5.30KB 1.02KB
auth (useWorkspaceAdminStatus.js) 11.08KB 4.58KB
collaboration (CommentThread.js) 26.08KB 7.56KB
collaboration (LiveCursors.js) 3.17KB 1.27KB
collaboration (PresenceAvatars.js) 6.49KB 2.64KB
collaboration (PresenceProvider.js) 2.79KB 1.13KB
collaboration (index.js) 1.68KB 0.73KB
collaboration (useCollaborationTranslation.js) 6.05KB 2.52KB
collaboration (useCommentSearch.js) 1.98KB 0.88KB
collaboration (useConflictResolution.js) 7.75KB 1.86KB
collaboration (useMentionNotifications.js) 1.81KB 0.68KB
collaboration (usePresence.js) 6.33KB 1.84KB
collaboration (useRealtimeSubscription.js) 7.91KB 2.01KB
components (index.js) 500.20KB 114.67KB
core (index.js) 7.48KB 2.96KB
create-plugin (index.js) 28.04KB 9.46KB
data-objectstack (index.js) 201.97KB 56.22KB
fields (index.js) 246.97KB 62.30KB
i18n (LocalizationContext.js) 1.76KB 0.96KB
i18n (builtinAggregateLabels.js) 0.86KB 0.49KB
i18n (currency.js) 1.22KB 0.64KB
i18n (fallbackInterpolation.js) 6.25KB 2.77KB
i18n (i18n.js) 6.57KB 2.76KB
i18n (index.js) 3.65KB 1.47KB
i18n (pickLocalized.js) 7.62KB 3.26KB
i18n (provider.js) 26.89KB 9.04KB
i18n (useDisplayLocale.js) 2.85KB 1.45KB
i18n (useObjectLabel.js) 34.34KB 9.17KB
i18n (useSafeTranslation.js) 5.60KB 2.33KB
layout (index.js) 38.84KB 10.94KB
mobile (MobileProvider.js) 0.92KB 0.49KB
mobile (ResponsiveContainer.js) 0.94KB 0.38KB
mobile (breakpoints.js) 1.51KB 0.70KB
mobile (createOfflineDataSource.js) 5.61KB 1.75KB
mobile (index.js) 1.99KB 0.87KB
mobile (offlineQueue.js) 3.91KB 1.35KB
mobile (pwa.js) 0.97KB 0.49KB
mobile (serviceWorker.js) 1.48KB 0.62KB
mobile (serviceWorkerSource.js) 3.41KB 1.48KB
mobile (useBreakpoint.js) 1.54KB 0.65KB
mobile (useGesture.js) 6.96KB 1.98KB
mobile (useOfflineSync.js) 1.99KB 0.72KB
mobile (usePullToRefresh.js) 2.53KB 0.85KB
mobile (useResponsive.js) 0.72KB 0.42KB
mobile (useSpecGesture.js) 4.39KB 1.66KB
mobile (useTouchTarget.js) 1.01KB 0.54KB
permissions (MePermissionsProvider.js) 13.52KB 4.88KB
permissions (PermissionContext.js) 0.31KB 0.25KB
permissions (PermissionGuard.js) 0.89KB 0.45KB
permissions (PermissionProvider.js) 6.24KB 2.16KB
permissions (discardProofCache.js) 1.04KB 0.55KB
permissions (evaluator.js) 8.39KB 3.10KB
permissions (index.js) 0.93KB 0.41KB
permissions (store.js) 0.91KB 0.42KB
permissions (useFieldPermissions.js) 1.28KB 0.53KB
permissions (usePermissions.js) 4.83KB 2.27KB
plugin-ai (index.js) 14.81KB 3.63KB
plugin-calendar (index.js) 49.03KB 13.93KB
plugin-charts (index.js) 71.63KB 19.99KB
plugin-chatbot (index.js) 194.54KB 46.34KB
plugin-dashboard (index.js) 132.41KB 34.84KB
plugin-designer (index.js) 215.68KB 44.27KB
plugin-detail (index.js) 253.19KB 65.62KB
plugin-editor (index.js) 2.23KB 1.05KB
plugin-form (index.js) 136.79KB 34.19KB
plugin-gantt (index.js) 166.96KB 40.93KB
plugin-grid (index.js) 210.86KB 57.28KB
plugin-kanban (index.js) 57.58KB 16.47KB
plugin-list (index.js) 112.54KB 27.65KB
plugin-map (index.js) 20.49KB 6.83KB
plugin-markdown (index.js) 13.88KB 4.80KB
plugin-report (index.js) 43.42KB 11.92KB
plugin-timeline (index.js) 30.10KB 8.74KB
plugin-tree (index.js) 9.55KB 3.32KB
plugin-view (index.js) 84.42KB 20.80KB
providers (DataSourceProvider.js) 0.75KB 0.39KB
providers (MetadataProvider.js) 1.37KB 0.59KB
providers (ThemeProvider.js) 1.90KB 0.85KB
providers (UploadProvider.js) 11.66KB 3.50KB
providers (index.js) 0.45KB 0.23KB
providers (types.js) 0.01KB 0.04KB
react-runtime (index.js) 5.62KB 2.34KB
react (LazyPluginLoader.js) 4.47KB 1.63KB
react (SchemaRenderer.js) 83.34KB 27.61KB
react (data-invalidation.js) 5.05KB 2.08KB
react (index.js) 4.63KB 2.18KB
react (schema-input.js) 2.32KB 1.24KB
react (spec-input.js) 0.20KB 0.18KB
sdui-parser (codegen.js) 6.58KB 2.74KB
sdui-parser (dashboard-widget-options.js) 3.08KB 1.30KB
sdui-parser (index.js) 5.66KB 2.50KB
sdui-parser (input-type.js) 2.84KB 1.40KB
sdui-parser (kanban-quick-add.js) 2.71KB 1.35KB
sdui-parser (parse.js) 20.57KB 5.88KB
sdui-parser (provenance.js) 3.66KB 1.82KB
sdui-parser (types.js) 0.28KB 0.23KB
sdui-parser (validate.js) 14.82KB 4.99KB
types (ai.js) 0.20KB 0.17KB
types (api-types.js) 0.20KB 0.18KB
types (app.js) 2.87KB 1.00KB
types (base.js) 0.20KB 0.18KB
types (blocks.js) 0.20KB 0.18KB
types (complex.js) 2.93KB 1.49KB
types (crud.js) 0.20KB 0.18KB
types (dashboard-filter-alias.js) 6.23KB 2.74KB
types (data-display.js) 3.75KB 1.85KB
types (data-protocol.js) 0.20KB 0.19KB
types (data.js) 0.20KB 0.18KB
types (designer.js) 1.85KB 0.85KB
types (disclosure.js) 0.20KB 0.18KB
types (error-code.js) 1.54KB 0.88KB
types (expression.js) 0.20KB 0.18KB
types (feedback.js) 0.20KB 0.18KB
types (field-types.js) 0.20KB 0.18KB
types (form.js) 0.20KB 0.18KB
types (http-inflight.js) 8.87KB 3.73KB
types (http-retry.js) 4.32KB 2.02KB
types (icon-key-migration.js) 4.26KB 1.63KB
types (index.js) 4.74KB 2.25KB
types (layout.js) 0.20KB 0.18KB
types (managed-by.js) 0.19KB 0.18KB
types (mobile.js) 4.73KB 2.28KB
types (navigation.js) 0.20KB 0.18KB
types (objectql.js) 0.20KB 0.18KB
types (overlay.js) 0.20KB 0.18KB
types (permissions.js) 0.20KB 0.18KB
types (plugin-scope.js) 0.20KB 0.18KB
types (record-components.js) 0.20KB 0.19KB
types (record-semantics.js) 1.28KB 0.67KB
types (registry.js) 0.20KB 0.18KB
types (reports.js) 0.20KB 0.18KB
types (select-option.js) 0.20KB 0.19KB
types (spec-report.js) 5.05KB 1.93KB
types (spec-ui-namespace.js) 0.20KB 0.19KB
types (strict-authoring-face.js) 14.27KB 5.47KB
types (system-fields.js) 3.33KB 1.54KB
types (theme.js) 6.28KB 2.87KB
types (ui-action.js) 8.11KB 3.32KB
types (views.js) 0.20KB 0.18KB
types (widget.js) 0.20KB 0.18KB

Size Limits

  • ✅ Core packages should be < 50KB gzipped
  • ✅ Component packages should be < 100KB gzipped
  • ⚠️ Plugin packages should be < 150KB gzipped

…er's declaration

Second union-only defect with objectui#8895, measured on the merge of the two
heads and NOT previously reported: `renderChart(compareTo: unknown, …)` stops
compiling once #8895 declares `ObjectChartSchema.compareTo` as
`DashboardWidget['compareTo']`, because on this branch the key still rides
`BaseSchema`'s index signature.

It was masked rather than absent: `type-check` is
`tsc --noEmit && tsc -p tsconfig.test.json`, so the drill-title error in
`ObjectChart.tsx` short-circuited the test project and hid every error it would
have reported. Running the test project alone on the pre-rework union shows both.

Typed at `DashboardWidget['compareTo']` — the symbol #8895 binds to and the
declaration the value actually comes from (`DashboardRenderer` forwards
`widget.compareTo` verbatim). All four call sites already pass that shape.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01611D6ZaRaMmwTNQmSbk8MH
@github-actions

Copy link
Copy Markdown
Contributor

✅ Console Performance Budget

Metric Value Budget
Eager closure (gzip, 50 chunks) 3488.9 KB 3512.7 KB
Main entry chunk (gzip) 144.1 KB 350 KB
Entry file index-eiLbQt9C.js
Status PASS

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

Package Size Gzipped
app-shell (consoleActionDispatch.js) 0.20KB 0.19KB
app-shell (index.js) 16.69KB 6.21KB
app-shell (runtime-config.js) 20.68KB 7.36KB
app-shell (types.js) 0.01KB 0.04KB
app-shell (urlParams.js) 10.06KB 3.86KB
auth (ActiveOrganizationStorage.js) 25.05KB 9.16KB
auth (AuthContext.js) 0.31KB 0.24KB
auth (AuthGuard.js) 2.07KB 1.00KB
auth (AuthProvider.js) 40.18KB 10.59KB
auth (AuthShell.js) 3.49KB 1.40KB
auth (ForgotPasswordForm.js) 12.21KB 3.45KB
auth (LoginForm.js) 18.15KB 5.39KB
auth (PreviewBanner.js) 0.90KB 0.50KB
auth (RegisterForm.js) 6.65KB 2.22KB
auth (SocialSignInButtons.js) 9.61KB 3.89KB
auth (UserMenu.js) 3.41KB 1.23KB
auth (auth-gate-events.js) 1.29KB 0.66KB
auth (authStyles.js) 5.04KB 1.72KB
auth (createAuthClient.js) 40.21KB 10.80KB
auth (createAuthenticatedFetch.js) 8.46KB 3.43KB
auth (index.js) 3.19KB 1.44KB
auth (invitation-status.js) 1.22KB 0.70KB
auth (org-roles.js) 6.66KB 2.78KB
auth (phone-identifier.js) 1.11KB 0.66KB
auth (types.js) 0.59KB 0.35KB
auth (useAuth.js) 5.30KB 1.02KB
auth (useWorkspaceAdminStatus.js) 11.08KB 4.58KB
collaboration (CommentThread.js) 26.08KB 7.56KB
collaboration (LiveCursors.js) 3.17KB 1.27KB
collaboration (PresenceAvatars.js) 6.49KB 2.64KB
collaboration (PresenceProvider.js) 2.79KB 1.13KB
collaboration (index.js) 1.68KB 0.73KB
collaboration (useCollaborationTranslation.js) 6.05KB 2.52KB
collaboration (useCommentSearch.js) 1.98KB 0.88KB
collaboration (useConflictResolution.js) 7.75KB 1.86KB
collaboration (useMentionNotifications.js) 1.81KB 0.68KB
collaboration (usePresence.js) 6.33KB 1.84KB
collaboration (useRealtimeSubscription.js) 7.91KB 2.01KB
components (index.js) 500.20KB 114.67KB
core (index.js) 7.48KB 2.96KB
create-plugin (index.js) 28.04KB 9.46KB
data-objectstack (index.js) 201.97KB 56.22KB
fields (index.js) 246.97KB 62.30KB
i18n (LocalizationContext.js) 1.76KB 0.96KB
i18n (builtinAggregateLabels.js) 0.86KB 0.49KB
i18n (currency.js) 1.22KB 0.64KB
i18n (fallbackInterpolation.js) 6.25KB 2.77KB
i18n (i18n.js) 6.57KB 2.76KB
i18n (index.js) 3.65KB 1.47KB
i18n (pickLocalized.js) 7.62KB 3.26KB
i18n (provider.js) 26.89KB 9.04KB
i18n (useDisplayLocale.js) 2.85KB 1.45KB
i18n (useObjectLabel.js) 34.34KB 9.17KB
i18n (useSafeTranslation.js) 5.60KB 2.33KB
layout (index.js) 38.84KB 10.94KB
mobile (MobileProvider.js) 0.92KB 0.49KB
mobile (ResponsiveContainer.js) 0.94KB 0.38KB
mobile (breakpoints.js) 1.51KB 0.70KB
mobile (createOfflineDataSource.js) 5.61KB 1.75KB
mobile (index.js) 1.99KB 0.87KB
mobile (offlineQueue.js) 3.91KB 1.35KB
mobile (pwa.js) 0.97KB 0.49KB
mobile (serviceWorker.js) 1.48KB 0.62KB
mobile (serviceWorkerSource.js) 3.41KB 1.48KB
mobile (useBreakpoint.js) 1.54KB 0.65KB
mobile (useGesture.js) 6.96KB 1.98KB
mobile (useOfflineSync.js) 1.99KB 0.72KB
mobile (usePullToRefresh.js) 2.53KB 0.85KB
mobile (useResponsive.js) 0.72KB 0.42KB
mobile (useSpecGesture.js) 4.39KB 1.66KB
mobile (useTouchTarget.js) 1.01KB 0.54KB
permissions (MePermissionsProvider.js) 13.52KB 4.88KB
permissions (PermissionContext.js) 0.31KB 0.25KB
permissions (PermissionGuard.js) 0.89KB 0.45KB
permissions (PermissionProvider.js) 6.24KB 2.16KB
permissions (discardProofCache.js) 1.04KB 0.55KB
permissions (evaluator.js) 8.39KB 3.10KB
permissions (index.js) 0.93KB 0.41KB
permissions (store.js) 0.91KB 0.42KB
permissions (useFieldPermissions.js) 1.28KB 0.53KB
permissions (usePermissions.js) 4.83KB 2.27KB
plugin-ai (index.js) 14.81KB 3.63KB
plugin-calendar (index.js) 49.03KB 13.93KB
plugin-charts (index.js) 71.63KB 19.99KB
plugin-chatbot (index.js) 194.54KB 46.34KB
plugin-dashboard (index.js) 132.41KB 34.84KB
plugin-designer (index.js) 215.68KB 44.27KB
plugin-detail (index.js) 253.19KB 65.62KB
plugin-editor (index.js) 2.23KB 1.05KB
plugin-form (index.js) 136.79KB 34.19KB
plugin-gantt (index.js) 166.96KB 40.93KB
plugin-grid (index.js) 210.86KB 57.28KB
plugin-kanban (index.js) 57.58KB 16.47KB
plugin-list (index.js) 112.54KB 27.65KB
plugin-map (index.js) 20.49KB 6.83KB
plugin-markdown (index.js) 13.88KB 4.80KB
plugin-report (index.js) 43.42KB 11.92KB
plugin-timeline (index.js) 30.10KB 8.74KB
plugin-tree (index.js) 9.55KB 3.32KB
plugin-view (index.js) 84.42KB 20.80KB
providers (DataSourceProvider.js) 0.75KB 0.39KB
providers (MetadataProvider.js) 1.37KB 0.59KB
providers (ThemeProvider.js) 1.90KB 0.85KB
providers (UploadProvider.js) 11.66KB 3.50KB
providers (index.js) 0.45KB 0.23KB
providers (types.js) 0.01KB 0.04KB
react-runtime (index.js) 5.62KB 2.34KB
react (LazyPluginLoader.js) 4.47KB 1.63KB
react (SchemaRenderer.js) 83.34KB 27.61KB
react (data-invalidation.js) 5.05KB 2.08KB
react (index.js) 4.63KB 2.18KB
react (schema-input.js) 2.32KB 1.24KB
react (spec-input.js) 0.20KB 0.18KB
sdui-parser (codegen.js) 6.58KB 2.74KB
sdui-parser (dashboard-widget-options.js) 3.08KB 1.30KB
sdui-parser (index.js) 5.66KB 2.50KB
sdui-parser (input-type.js) 2.84KB 1.40KB
sdui-parser (kanban-quick-add.js) 2.71KB 1.35KB
sdui-parser (parse.js) 20.57KB 5.88KB
sdui-parser (provenance.js) 3.66KB 1.82KB
sdui-parser (types.js) 0.28KB 0.23KB
sdui-parser (validate.js) 14.82KB 4.99KB
types (ai.js) 0.20KB 0.17KB
types (api-types.js) 0.20KB 0.18KB
types (app.js) 2.87KB 1.00KB
types (base.js) 0.20KB 0.18KB
types (blocks.js) 0.20KB 0.18KB
types (complex.js) 2.93KB 1.49KB
types (crud.js) 0.20KB 0.18KB
types (dashboard-filter-alias.js) 6.23KB 2.74KB
types (data-display.js) 3.75KB 1.85KB
types (data-protocol.js) 0.20KB 0.19KB
types (data.js) 0.20KB 0.18KB
types (designer.js) 1.85KB 0.85KB
types (disclosure.js) 0.20KB 0.18KB
types (error-code.js) 1.54KB 0.88KB
types (expression.js) 0.20KB 0.18KB
types (feedback.js) 0.20KB 0.18KB
types (field-types.js) 0.20KB 0.18KB
types (form.js) 0.20KB 0.18KB
types (http-inflight.js) 8.87KB 3.73KB
types (http-retry.js) 4.32KB 2.02KB
types (icon-key-migration.js) 4.26KB 1.63KB
types (index.js) 4.74KB 2.25KB
types (layout.js) 0.20KB 0.18KB
types (managed-by.js) 0.19KB 0.18KB
types (mobile.js) 4.73KB 2.28KB
types (navigation.js) 0.20KB 0.18KB
types (objectql.js) 0.20KB 0.18KB
types (overlay.js) 0.20KB 0.18KB
types (permissions.js) 0.20KB 0.18KB
types (plugin-scope.js) 0.20KB 0.18KB
types (record-components.js) 0.20KB 0.19KB
types (record-semantics.js) 1.28KB 0.67KB
types (registry.js) 0.20KB 0.18KB
types (reports.js) 0.20KB 0.18KB
types (select-option.js) 0.20KB 0.19KB
types (spec-report.js) 5.05KB 1.93KB
types (spec-ui-namespace.js) 0.20KB 0.19KB
types (strict-authoring-face.js) 14.27KB 5.47KB
types (system-fields.js) 3.33KB 1.54KB
types (theme.js) 6.28KB 2.87KB
types (ui-action.js) 8.11KB 3.32KB
types (views.js) 0.20KB 0.18KB
types (widget.js) 0.20KB 0.18KB

Size Limits

  • ✅ Core packages should be < 50KB gzipped
  • ✅ Component packages should be < 100KB gzipped
  • ⚠️ Plugin packages should be < 150KB gzipped

The rework adds one import line to `packages/types/src/objectql.ts`
(`ChartAggregate`), which moves the ledgered `@example` block from :1614 to
:1615. `check:doc-examples` reports that as STALE LEDGER ROW + UNDECLARED
FAILURE; the row's `codes` and `reason` are unchanged.

⚠️ objectui#8895 moves the same row to :1617 (it adds three import lines).
Neither number is right in the union — the later lander must RE-RUN the gate and
take the number it prints, not pick a side.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01611D6ZaRaMmwTNQmSbk8MH
@github-actions

Copy link
Copy Markdown
Contributor

✅ Console Performance Budget

Metric Value Budget
Eager closure (gzip, 50 chunks) 3488.9 KB 3512.7 KB
Main entry chunk (gzip) 144.1 KB 350 KB
Entry file index-eiLbQt9C.js
Status PASS

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

Package Size Gzipped
app-shell (consoleActionDispatch.js) 0.20KB 0.19KB
app-shell (index.js) 16.69KB 6.21KB
app-shell (runtime-config.js) 20.68KB 7.36KB
app-shell (types.js) 0.01KB 0.04KB
app-shell (urlParams.js) 10.06KB 3.86KB
auth (ActiveOrganizationStorage.js) 25.05KB 9.16KB
auth (AuthContext.js) 0.31KB 0.24KB
auth (AuthGuard.js) 2.07KB 1.00KB
auth (AuthProvider.js) 40.18KB 10.59KB
auth (AuthShell.js) 3.49KB 1.40KB
auth (ForgotPasswordForm.js) 12.21KB 3.45KB
auth (LoginForm.js) 18.15KB 5.39KB
auth (PreviewBanner.js) 0.90KB 0.50KB
auth (RegisterForm.js) 6.65KB 2.22KB
auth (SocialSignInButtons.js) 9.61KB 3.89KB
auth (UserMenu.js) 3.41KB 1.23KB
auth (auth-gate-events.js) 1.29KB 0.66KB
auth (authStyles.js) 5.04KB 1.72KB
auth (createAuthClient.js) 40.21KB 10.80KB
auth (createAuthenticatedFetch.js) 8.46KB 3.43KB
auth (index.js) 3.19KB 1.44KB
auth (invitation-status.js) 1.22KB 0.70KB
auth (org-roles.js) 6.66KB 2.78KB
auth (phone-identifier.js) 1.11KB 0.66KB
auth (types.js) 0.59KB 0.35KB
auth (useAuth.js) 5.30KB 1.02KB
auth (useWorkspaceAdminStatus.js) 11.08KB 4.58KB
collaboration (CommentThread.js) 26.08KB 7.56KB
collaboration (LiveCursors.js) 3.17KB 1.27KB
collaboration (PresenceAvatars.js) 6.49KB 2.64KB
collaboration (PresenceProvider.js) 2.79KB 1.13KB
collaboration (index.js) 1.68KB 0.73KB
collaboration (useCollaborationTranslation.js) 6.05KB 2.52KB
collaboration (useCommentSearch.js) 1.98KB 0.88KB
collaboration (useConflictResolution.js) 7.75KB 1.86KB
collaboration (useMentionNotifications.js) 1.81KB 0.68KB
collaboration (usePresence.js) 6.33KB 1.84KB
collaboration (useRealtimeSubscription.js) 7.91KB 2.01KB
components (index.js) 500.20KB 114.67KB
core (index.js) 7.48KB 2.96KB
create-plugin (index.js) 28.04KB 9.46KB
data-objectstack (index.js) 201.97KB 56.22KB
fields (index.js) 246.97KB 62.30KB
i18n (LocalizationContext.js) 1.76KB 0.96KB
i18n (builtinAggregateLabels.js) 0.86KB 0.49KB
i18n (currency.js) 1.22KB 0.64KB
i18n (fallbackInterpolation.js) 6.25KB 2.77KB
i18n (i18n.js) 6.57KB 2.76KB
i18n (index.js) 3.65KB 1.47KB
i18n (pickLocalized.js) 7.62KB 3.26KB
i18n (provider.js) 26.89KB 9.04KB
i18n (useDisplayLocale.js) 2.85KB 1.45KB
i18n (useObjectLabel.js) 34.34KB 9.17KB
i18n (useSafeTranslation.js) 5.60KB 2.33KB
layout (index.js) 38.84KB 10.94KB
mobile (MobileProvider.js) 0.92KB 0.49KB
mobile (ResponsiveContainer.js) 0.94KB 0.38KB
mobile (breakpoints.js) 1.51KB 0.70KB
mobile (createOfflineDataSource.js) 5.61KB 1.75KB
mobile (index.js) 1.99KB 0.87KB
mobile (offlineQueue.js) 3.91KB 1.35KB
mobile (pwa.js) 0.97KB 0.49KB
mobile (serviceWorker.js) 1.48KB 0.62KB
mobile (serviceWorkerSource.js) 3.41KB 1.48KB
mobile (useBreakpoint.js) 1.54KB 0.65KB
mobile (useGesture.js) 6.96KB 1.98KB
mobile (useOfflineSync.js) 1.99KB 0.72KB
mobile (usePullToRefresh.js) 2.53KB 0.85KB
mobile (useResponsive.js) 0.72KB 0.42KB
mobile (useSpecGesture.js) 4.39KB 1.66KB
mobile (useTouchTarget.js) 1.01KB 0.54KB
permissions (MePermissionsProvider.js) 13.52KB 4.88KB
permissions (PermissionContext.js) 0.31KB 0.25KB
permissions (PermissionGuard.js) 0.89KB 0.45KB
permissions (PermissionProvider.js) 6.24KB 2.16KB
permissions (discardProofCache.js) 1.04KB 0.55KB
permissions (evaluator.js) 8.39KB 3.10KB
permissions (index.js) 0.93KB 0.41KB
permissions (store.js) 0.91KB 0.42KB
permissions (useFieldPermissions.js) 1.28KB 0.53KB
permissions (usePermissions.js) 4.83KB 2.27KB
plugin-ai (index.js) 14.81KB 3.63KB
plugin-calendar (index.js) 49.03KB 13.93KB
plugin-charts (index.js) 71.63KB 19.99KB
plugin-chatbot (index.js) 194.54KB 46.34KB
plugin-dashboard (index.js) 132.41KB 34.84KB
plugin-designer (index.js) 215.68KB 44.27KB
plugin-detail (index.js) 253.19KB 65.62KB
plugin-editor (index.js) 2.23KB 1.05KB
plugin-form (index.js) 136.79KB 34.19KB
plugin-gantt (index.js) 166.96KB 40.93KB
plugin-grid (index.js) 210.86KB 57.28KB
plugin-kanban (index.js) 57.58KB 16.47KB
plugin-list (index.js) 112.54KB 27.65KB
plugin-map (index.js) 20.49KB 6.83KB
plugin-markdown (index.js) 13.88KB 4.80KB
plugin-report (index.js) 43.42KB 11.92KB
plugin-timeline (index.js) 30.10KB 8.74KB
plugin-tree (index.js) 9.55KB 3.32KB
plugin-view (index.js) 84.42KB 20.80KB
providers (DataSourceProvider.js) 0.75KB 0.39KB
providers (MetadataProvider.js) 1.37KB 0.59KB
providers (ThemeProvider.js) 1.90KB 0.85KB
providers (UploadProvider.js) 11.66KB 3.50KB
providers (index.js) 0.45KB 0.23KB
providers (types.js) 0.01KB 0.04KB
react-runtime (index.js) 5.62KB 2.34KB
react (LazyPluginLoader.js) 4.47KB 1.63KB
react (SchemaRenderer.js) 83.34KB 27.61KB
react (data-invalidation.js) 5.05KB 2.08KB
react (index.js) 4.63KB 2.18KB
react (schema-input.js) 2.32KB 1.24KB
react (spec-input.js) 0.20KB 0.18KB
sdui-parser (codegen.js) 6.58KB 2.74KB
sdui-parser (dashboard-widget-options.js) 3.08KB 1.30KB
sdui-parser (index.js) 5.66KB 2.50KB
sdui-parser (input-type.js) 2.84KB 1.40KB
sdui-parser (kanban-quick-add.js) 2.71KB 1.35KB
sdui-parser (parse.js) 20.57KB 5.88KB
sdui-parser (provenance.js) 3.66KB 1.82KB
sdui-parser (types.js) 0.28KB 0.23KB
sdui-parser (validate.js) 14.82KB 4.99KB
types (ai.js) 0.20KB 0.17KB
types (api-types.js) 0.20KB 0.18KB
types (app.js) 2.87KB 1.00KB
types (base.js) 0.20KB 0.18KB
types (blocks.js) 0.20KB 0.18KB
types (complex.js) 2.93KB 1.49KB
types (crud.js) 0.20KB 0.18KB
types (dashboard-filter-alias.js) 6.23KB 2.74KB
types (data-display.js) 3.75KB 1.85KB
types (data-protocol.js) 0.20KB 0.19KB
types (data.js) 0.20KB 0.18KB
types (designer.js) 1.85KB 0.85KB
types (disclosure.js) 0.20KB 0.18KB
types (error-code.js) 1.54KB 0.88KB
types (expression.js) 0.20KB 0.18KB
types (feedback.js) 0.20KB 0.18KB
types (field-types.js) 0.20KB 0.18KB
types (form.js) 0.20KB 0.18KB
types (http-inflight.js) 8.87KB 3.73KB
types (http-retry.js) 4.32KB 2.02KB
types (icon-key-migration.js) 4.26KB 1.63KB
types (index.js) 4.74KB 2.25KB
types (layout.js) 0.20KB 0.18KB
types (managed-by.js) 0.19KB 0.18KB
types (mobile.js) 4.73KB 2.28KB
types (navigation.js) 0.20KB 0.18KB
types (objectql.js) 0.20KB 0.18KB
types (overlay.js) 0.20KB 0.18KB
types (permissions.js) 0.20KB 0.18KB
types (plugin-scope.js) 0.20KB 0.18KB
types (record-components.js) 0.20KB 0.19KB
types (record-semantics.js) 1.28KB 0.67KB
types (registry.js) 0.20KB 0.18KB
types (reports.js) 0.20KB 0.18KB
types (select-option.js) 0.20KB 0.19KB
types (spec-report.js) 5.05KB 1.93KB
types (spec-ui-namespace.js) 0.20KB 0.19KB
types (strict-authoring-face.js) 14.27KB 5.47KB
types (system-fields.js) 3.33KB 1.54KB
types (theme.js) 6.28KB 2.87KB
types (ui-action.js) 8.11KB 3.32KB
types (views.js) 0.20KB 0.18KB
types (widget.js) 0.20KB 0.18KB

Size Limits

  • ✅ Core packages should be < 50KB gzipped
  • ✅ Component packages should be < 100KB gzipped
  • ⚠️ Plugin packages should be < 150KB gzipped

@os-zhuang
os-zhuang marked this pull request as ready for review September 10, 2026 06:22
@claude

claude Bot commented Sep 10, 2026

Copy link
Copy Markdown
Contributor Author

落地前状态记录(ui@objectui 派发席)

返工轮已交付,头 7e7134160e805024d7(3 个提交,无 rebase、无 force)。本条记录两件事:载体判读的真实结论,以及我在什么授权下仍然落地

一、check-clause2-carriers --pair 8884 退出码 4 —— 我不隐瞒

判读原文的要点:卡片 #7946 声明 Clause-②: yes,两个载体上的 needs:contract-review 都已摘除(最后一次移除 2026-09-10T00:25:39Z),但头已后移2026-09-10T06:10:09Z。⇒ 清掉该门的那次复核判的是另一棵树,清除已不覆盖将要落地的内容。这正是恢复规则里「head 后移或无结论才重挂」所指的欠重挂状态。

⛔ 我没有重挂标签、也没有伪装成已清除。原因是:仓库所有者本轮明确要求「绿了就合并,不需要等复核」。在该授权下重挂一道门再从门上跨过去,比如实记录更糟。所以这里如实写明:本 PR 落地时,契约层复核对当前头没有结论。

二、验收量具(返工席自测,我复核了其形状)

⭐ 关键判据不是 pnpm test:两个普查 pin 都从 zod 镜像的 Object.keys 计算键集,看不见被吞掉的 TypeScript 成员块。有效量具是类型检查。

  • @object-ui/types type-check EXIT 0@object-ui/plugin-charts type-check EXIT 0;八个下游包全数 EXIT 0,且逐个回显脚本名——因为匹配到零个脚本的 filter 同样退出 0,回显才是读数
  • vitest:219 files / 3723 tests passed;另一组 214 files / 2142 tests passed
  • F3 新运行时 pin 的消融:改动在磁盘上以标记计数 + blob 哈希双重证明(anchor=1 inject=0 blob=1152e58banchor=0 inject=1 blob=8cd7c9c5),消融运行 EXIT=13 failed | 1 passed,且第四个「裸字符串」对照保持绿——⇒ 断的是结构化节点那一臂,不是整个文件。还原两次证明(git diff HEAD 为空、blob 复位)
  • feat(types): declare drillDown / title / compareTo on both published copies of ObjectChartSchema (objectui#8885) #8895并集:返工前 tsc -p tsconfig.test.json 2 errors → 本头 EXIT 0,并集 220 files / 3741 tests passed。⭐ 这是本 PR 唯一有效的合流验收,因为 ObjectChart.tsx 的 TS2345 单看任一 PR 都不触发
  • lint 跑的是全量而非收窄eslint . 判 4698 个文件,0 error / 12562 warning,EXIT 0
  • ⚠️ check:sdui-registration-pins 退出 2 = 前置条件未满足(它称量 apps/console/dist/assets,此处无 console 构建)——既不是绿也不是红,是未测量。本 diff 不改任何 sideEffects 数组、不改任何注册键(该块内的编辑仅为注释),且 CI 会构建 console

三、承接

返工席另立了两张卡,均为本轮测量出来而非推测的问题:#8943normalizeChartSchemalabel() 取内联 locale map 里的第一个字符串 ⇒ 标题跟随键插入顺序而非用户语言)、#8944(drill-down 展开把 filter 的数组臂错拼成索引键,静默丢掉 widget 自身的 filter)。

⛔ 返工席未写 assignee 字段、未补第二条 Claim:、未增删复核标签。


Generated by Claude Code

@os-zhuang
os-zhuang enabled auto-merge September 10, 2026 06:24
@os-zhuang
os-zhuang added this pull request to the merge queue Sep 10, 2026
Merged via the queue into main with commit 14582b8 Sep 10, 2026
35 checks passed
@os-zhuang
os-zhuang deleted the claude/issue-7946-objectchart-schema-anchor branch September 10, 2026 08:09
os-steve pushed a commit that referenced this pull request Sep 10, 2026
…atch

`main` moved and objectui#7946 (PR #8884) landed, editing the same
`ObjectChartSchema` on both published faces. The previous round's stashed
resolution was built on #8884's PRE-REWORK tree and is not replayed.

5 files, 7 hunks, re-derived against origin/main aeaa0f6:

- `objectql.ts` docblock: both sides rewrote the same title line into
  different full docblocks. BOTH narratives kept; the two near-identical
  "ceiling" paragraphs folded into ONE section carrying both cards'
  examples and both counter-probe filenames; this branch's section
  "Four keys are still undeclared here, deliberately" had its premise
  falsified by the merge and is re-derived.
- `objectql.ts` interface body: double insertion at one anchor, both kept.
  All 8 keys now declared exactly once on both faces.
- `objectql.zod.ts` / `imported-defaults-8317.test.ts`: additive on both
  sides, both kept.
- `zod-mirror-parity.test.ts`: BOTH sides add the SAME
  `SPEC_DERIVED_PAIRS` entry with different grounds. One entry, both
  grounds recorded.
- `check-doc-example-types.mjs`: the `UNGATED_EXAMPLES` key embeds a line
  number and each side repaired it to a different one. Re-derived BY
  ANCHOR against the merged tree (the `@example` tag on
  `ObjectFormSchema.mobile`, byte-identical to the branch point): :1618.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MPaVWWMuWeT5LgB1qoXjVB
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

4 participants