Repository navigation
Commit b5d137a
<!-- claude-projects-attribution: {"github_login":"os-steve"} -->
_Requested by **Steve** · [project
thread](https://claude.ai/code/project/chan_01FdL1XeUyvVNxLreh3F4Qi9?thread=cmsg_01FdL1XeUyvVNxLreh3F4Qi9WS2SSi8hVuwcpHdWi5p4oQ)_
Fixes #26238
Clause-②: no
Metadata-protocol: none
## What changed
Test-only. 38 `ui/**` test files pinned an exact count, or the whole
value list or key list, of a schema, enum or constant that
`@objectstack/spec` owns. Each of those pins is now a membership
assertion on what ui actually reads, writes or must refuse. Retirement
guards name the retired key as absent and the successor as present. The
two ObjectSchema corpus guards in app-shell also assert directly that no
accepted key is within two edits of a retired or resolved key. That
check replaces the key count, which unrelated spec adoptions had moved
six times (42 → 48). Exact pins on ui-owned shapes are unchanged. No
product source, no `packages/spec`, no locale pack.
An additive spec change (a new key, enum value or constant member) now
leaves these 38 files green, unless ui really lacks something. The kept
parity guards listed below are the cases where ui does lack something.
## Sweep: patterns and control hits
Scanned at merge-base `df8aac41f`: 1273 `ui/**` test files that name
`@objectstack/spec`, through static imports, `await import`,
`vi.importActual` and `require`.
| # | Pattern | Control hit (at `df8aac41f`) |
|---|---|---|
| P1 | `Object.keys(X.shape)` or a derived variable, then `.size` /
`.length` `toBe(N)` / `toHaveLength(N)` |
`app-shell/src/services/MetadataService.retiredObjectEnabled.test.ts:161`
(`accept.size).toBe(47)`) |
| P2 | `.options` / `.def.entries` of a spec enum, then
`toEqual([literal…])` |
`app-shell/src/utils/__tests__/recordFormModalSize-12803.test.ts:34` |
| P3 | `Object.keys(X.shape).sort()` then `toEqual([literal…])` |
`app-shell/src/views/ObjectView.kanbanLane-8193.test.tsx:227` |
| P4 | any literal 5+ count (`toHaveLength(N)`,
`.size/.length).toBe(N)`) in a spec-reading file, triaged by hand (129
hits) |
`plugin-designer/src/MetadataFieldsPage.storedTypePreserved.test.tsx:228`
(`toHaveLength(49)`, FieldType) |
| P5 | a spec constant array (not a schema) compared with
`toEqual([literal…])` or a count (a broad pass over every spec
identifier, 228 hits, triaged by hand) |
`app-shell/src/services/MetadataService.readDecorationStrip.test.ts:129`
(`METADATA_READ_DECORATIONS`) |
| P6 | `toMatchSnapshot` / `toMatchInlineSnapshot` in a spec-reading
file | 0 hits. The pattern's control:
`components/src/__tests__/snapshot-critical.test.tsx`, which is not
spec-reading |
The scanner was a scratch script. It recognised static named and
namespace imports, destructured dynamic imports, and one level of
derived variables (multi-line declarations too). Pins reached only
through `@object-ui/types` re-exports of spec values are outside it. The
ones met while triaging (`ViewTypeSchema`, `TextSchema`,
`VIEW_ITEM_KEYS`) were read by hand.
## Converted (38 files)
Paths are relative to `ui/packages/` unless they start with `ui/`.
- `app-shell/.../MetadataService.retiredObjectEnabled.test.ts`:
`accept.size` 47 removed. Added: no near-spelling, within two edits, of
`enabled` or `_deleted` (except `enable`, which the next lines refuse by
value). The six-entry re-point history is condensed to one line.
- `app-shell/.../MetadataService.specKeyObjectPayload.test.ts`:
`accept.size` 47 removed. Added: no near-spelling of `group`,
`sortOrder` or `relationships`. History condensed, and the header's "43
keys" dropped.
- `app-shell/.../recordFormModalSize-12803.test.ts`: the whole
`modalSize` enum → each tested size is an allowed value.
- `app-shell/.../ObjectView.kanbanLane-8193.test.tsx`: the 4-key
KanbanConfig list → `groupByField` present; `groupField` and `groupBy`
absent.
- `app-shell/.../plugin-runtime-tier-3846.test.tsx`: the literal tier
list → membership. The derived `RUNTIME_FALLBACK` equality stays (see
Kept).
- `app-shell/.../packageSource-12790.test.ts`: union branch count 2 → a
non-empty floor.
- `app-shell/.../ActionPreview.locations.test.tsx`:
`ACTION_LOCATIONS.length` 6 → a floor. `global_nav` stays absent.
- `app-shell/.../MetadataService.readDecorationStrip.test.ts`,
`data-objectstack/src/draft-envelope.test.ts`: the decoration list →
contains `_diagnostics` and `_draft`.
- `app-shell/.../FlowReferenceField.specDerivation.test.ts`: the spec
source's 3-key list → contains `object`, `source` and `valueField`, and
none of the presentation keys this package owns.
- `core/.../normalize-list-view.foldOutputAuthorable-5435.test.ts`:
count 11 and the key list → the seven toggles the fold emits are
declared.
- `core/.../normalize-list-view.pageResidual-8429.test.ts`: counts
9/11/9/11 and both literal lists → the nine drawn kinds present; `page`
absent; the objectui face is the spec's plus two; the census uses
`toMatchObject` plus the derived "every spec kind resolves to itself".
- `core/.../filter-tokens.recordContext-7297.test.ts`: `['record_id']` →
contains. The compile-time ratchet stays in the type check.
- `core/.../filter-view-rule-arity-8557.test.ts`: the literal array and
scalar class lists → membership. The exact partition stays.
- `data-objectstack/src/listViews.roundTripKeys-11013.test.ts`: the
5-key list → contains each.
- `data-objectstack/src/metadata-client.overlayScope.test.ts`: `['env']`
→ contains. The old spellings are still refused by name.
- `plugin-dashboard` and `plugin-report`
`spec-symbol-dataset-totals-11073.test.ts`: `['groupings']` → contains.
- `plugin-designer/src/MetadataFieldsPage.storedTypePreserved.test.tsx`:
FieldType 49, census 22 and `checked === 22` → the census holds every
measured member, and `checked === CENSUS.length`. `DESIGNER_TYPES` 27
(ui-owned) stays.
- `plugin-detail/.../recordActivityFeed.test.ts`: declared 13 and the
unproduced list → membership plus an exact partition. The produced set
(ui-owned) stays exact.
- `plugin-list/.../UserFilters.tabPresetOperators.test.tsx`:
`VIEW_FILTER_OPERATORS.length` 20 → a floor plus `icontains`.
- `plugin-tree/src/ObjectTree.schemaTyped-8655.test.ts`,
`types/.../calendar-flat-color-allday-8466.test.ts`,
`types/.../related-list-add-picker-filter-mirror-9964.test.ts`: block
key lists → the keys this code reads.
- `sdui-parser/.../dashboard-widget-options-census.test.ts`: the 5-key
list → contains each. The derived consumed/declared parity stays (see
Kept).
- `auth/.../auth-spec-parity.test.ts`: the 6-provider list → contains
`github`, `google` and `local`.
- `fields/.../LocationField.optionalKeys.test.tsx`: the 4-key list →
`lat`, `lng` and `altitude` present; `latitude` and `longitude` absent.
- `fields/.../RegistryRefField.audienceAnchors-12200.test.tsx`: the
anchor list → contains `everyone` and `guest`.
- `ui/apps/console/.../component-input-union-specimens.test.ts`: the
literal accepted-arm lists → `arrayContaining`. `defaultValue` keeps its
no-`object`-arm claim.
- `types/.../export-options-spec-parity.test.ts`,
`types/.../object-grid-export-options-refusal-7762.test.ts`: union arms
2 and the key count or list → a floor plus named keys.
- `types/.../grid-kanban-calendar-members-round8-6152.test.ts`: the
operations key list → named members. The local face is derived as the
row's keys plus the two tombstones.
- `types/.../list-view-options-bag-6152.test.ts`: the literal `KINDS`
list → contains this package's block kinds.
- `types/.../record-highlights-fields-icon-9280.test.ts`,
`types/.../record-highlights-layout-9187.test.ts`: the entry, layout and
props key lists → named members, with `icon` absent.
- `types/.../select-option-form-view-boundary-12736.test.ts`,
`types/.../select-option-spec-extension-7014.test.ts`: the SelectOption
key lists → named members, with `icon` and `disabled` absent.
- `types/.../object-view-unmirrored-keys-7779.test.ts`: the 51-key list,
count 51, the retired list and live count 43 → membership and a floor.
## Kept, with the reason
- **Derived parity, both sides computed** (ui set vs spec set). Red
means ui really lacks a mapping, label, declaration or consumer for a
new spec member, and the fix is ui source, not the test. These are:
`RUNTIME_FALLBACK` = tiers; `PACKAGE_SOURCES` = sources; the
`pageResidual` "no undrawable spec kind"; the `UserFilters` "every view
operator is AST-valid"; the `sdui-parser` consumed ⊇ declared;
`export-options` LOCAL keys = spec keys; `object-view-unmirrored-keys`
"narrower than the protocol is empty" (the maintainer principle stated
in that file); `report-chart-query-spec-parity:614`;
`navigation-spec-parity:316`; `bulk-action-spec-parity:46`;
`filter-operator-protocol-set-9559:105`; `mirror-groups-cd-10286:67`;
`ObjectValidationsPanel.runsOn-11923:134`;
`ObjectMetricWidget.countNotCurrency-10356:114`;
`imported-defaults-8317:637`. #26092 is the half that makes these
visible on the spec PR itself.
- **ui-owned shapes**: `DESIGNER_TYPES` 27; produced feed kinds;
`OBJECTUI` local categories `detail`/`list`; the `metadata-form-i18n`
header children (the ui bundle's rows); the i18n locale and key counts;
fixture and row counts (`plugin-grid`, `plugin-map`,
`deriveMasterDetail`, …); `offline-nav-performance` literal arrays
(typed against spec types, so tsc already checks membership); the
`test-support` spec-tombstones fixture schema; the
`object-view-unmirrored-keys` buckets over ui's own declared and unread
members; `object-view-slot-key-lists` (ui's d.ts members).
- **Required-set pins** (`list-view-blocks-by-reference-6152:122-125`):
an additive optional key cannot move a required set. Adding a required
member is a narrowing, so it is breaking, not additive.
- **Behavioural refusals and parse results** (for example
`unrecognized_keys` naming a key, a refusal path, a parsed value): these
already assert one named key or value.
## Proof: a scratch extra member in the spec, old assertion vs new
25 scratch members were added in one pass to the spec source: keys
`zzScratchKey` and values `zz_scratch_*`, across ObjectSchema,
FormView.modalSize, KanbanConfig, UserActionsConfig,
VIEW_FILTER_OPERATORS, TreeConfig, CalendarConfig, ObjectListView, the
ListView type enum, ACTION_LOCATIONS, PluginRuntime,
METADATA_READ_DECORATIONS, APPROVER_VALUE_SOURCES,
RECORD_CONTEXT_TOKENS, DatasetTotals, FieldType, SelectOption,
FeedItemType, DashboardWidgetOptions, AuthProvider,
AUDIENCE_ANCHOR_POSITIONS, overlayScope, RecordHighlights (key and
layout value), the export-options object branch and the location value.
Then a full `@objectstack/spec` build, the 38 files at this branch, the
same 38 files at `df8aac41f` (written to the tree only), and a restore.
After the restore, `git diff HEAD` was empty on the spec, the rebuilt
dist had 0 markers, and the ui tests matched HEAD.
- **24 files: old red at the converted line, new green.** These are
readDecorationStrip, retiredObjectEnabled (49 vs 47),
specKeyObjectPayload (49 vs 47), recordFormModalSize, kanbanLane,
FlowReferenceField, ActionPreview (7 vs 6), auth-spec-parity,
filter-tokens, filter-view-rule-arity, foldOutputAuthorable (12 vs 11),
draft-envelope, overlayScope, LocationField, audienceAnchors, both
dataset-totals, MetadataFieldsPage (50 vs 49, 23 vs 22),
recordActivityFeed (14 vs 13), ObjectTree, calendar-flat-color,
object-grid-export-options-refusal, record-highlights-layout and
select-option-spec-extension.
- **6 files: old red at the converted line, and new red ONLY at a kept
derived-parity line.** These are plugin-runtime-tier (no label for the
new tier), pageResidual (ListView cannot draw the new kind), UserFilters
(the new operator is not in `VALID_AST_OPERATORS`: the scratch added it
to one spec list only), sdui-parser (DatasetWidget does not consume the
new key), export-options-spec-parity (the TS mirror lacks the new key)
and object-view-unmirrored-keys (objectui does not declare the new live
key). Every converted line in these files was green.
- **8 files: NOT MEASURED by this mutation set.** The members they read
were not mutated: union arm counts, list-view slot kinds, the highlights
entry arm, the picker block, grid operations, `VIEW_ITEM_KEYS`, the
form-view option, and element arms. Their conversions use the same
membership shape.
## Verification
At head `cf00e778` (after merging `origin/main` with #26231 in), with
`@objectstack/{spec,client,formula,lint}` closures rebuilt, all under
`scripts/pm/os-verify-lock.sh`:
- The 38 changed files: `Test Files 38 passed (38) · Tests 891 passed
(891)`, VERDICT command-exit 0.
- Before the merge, at `402e830c`, the full suites of the 12 touched
packages: `auth core data-objectstack fields plugin-dashboard
plugin-designer plugin-detail plugin-list plugin-report plugin-tree
sdui-parser types`. Result: `Test Files 1790 passed | 2 skipped (1792) ·
Tests 28011 passed | 65 skipped`, VERDICT command-exit 0, 43m51s.
- Declared narrowing: `app-shell` (about 1725 files) and
`ui/apps/console` ran only their changed files. Their full suites are
left to CI `Test Core` / Test UI.
- Dispatch gates on the final head: `node scripts/pm/dispatch-gates.mjs
--commands` derived 24 families, all 24 run, each exit 0
(`check:type-check-debt` under the lock: VERDICT command-exit 0, 26 raw
tsc errors, none above its recorded number). `--ran` reconciliation: 24
derived, 24 run, 0 NOT-MEASURED, 0 UNRUN.
## Acceptance notes
- Not swept here, a different gate: **type-level literal-union pins**.
At `df8aac41f` there are 51 `Equal` type assertions against a literal
union of names in 31 spec-reading ui test files, for example
`plugin-chatbot/src/__tests__/spec-symbol-batch6.test.ts:251`
(`PendingActionStatus`). Some are on ui-owned types. Those on
spec-derived types red `Type Check UI`, not Test UI, when the spec adds
a member. Converting them needs a per-type ruling (exact type equality
vs `extends`), so they are noted for the seat to card. They are not
carried by this PR.
- The arity pin in `filter-view-rule-arity-8557` was a deliberate review
trigger: a new spec operator lands in the value-requiring class by
default. That default is now held only by the exact partition, not by a
whole-vocabulary list.
- Changeset: none. The diff is test files only, and each touched
package's `files[]` ships `dist` alone, so nothing publishes. Labelled
`skip-changeset` at open.
---
_Generated by [Claude
Code](https://claude.ai/code/session_01HRaa5qRyCQv9YZJCosen4d)_
---------
Co-authored-by: Claude <noreply@anthropic.com>
1 parent 366e4aa commit b5d137a
38 files changed
Lines changed: 256 additions & 217 deletions
File tree
- ui
- apps/console/src/__tests__
- packages
- app-shell/src
- console/marketplace/__tests__
- services
- utils/__tests__
- views
- metadata-admin
- inspectors
- previews/__tests__
- auth/src/__tests__
- core/src/utils/__tests__
- data-objectstack/src
- fields/src
- __tests__
- widgets/__tests__
- plugin-dashboard/src/__tests__
- plugin-designer/src
- plugin-detail/src/renderers/__tests__
- plugin-list/src/__tests__
- plugin-report/src/__tests__
- plugin-tree/src
- sdui-parser/src/__tests__
- types/src/__tests__
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
310 | 310 | | |
311 | 311 | | |
312 | 312 | | |
313 | | - | |
314 | | - | |
| 313 | + | |
| 314 | + | |
| 315 | + | |
| 316 | + | |
315 | 317 | | |
316 | 318 | | |
317 | 319 | | |
| |||
417 | 419 | | |
418 | 420 | | |
419 | 421 | | |
420 | | - | |
421 | | - | |
422 | | - | |
423 | | - | |
424 | | - | |
425 | | - | |
426 | | - | |
427 | | - | |
428 | | - | |
| 422 | + | |
| 423 | + | |
| 424 | + | |
| 425 | + | |
429 | 426 | | |
430 | 427 | | |
431 | 428 | | |
432 | 429 | | |
433 | 430 | | |
434 | 431 | | |
435 | 432 | | |
436 | | - | |
437 | | - | |
438 | | - | |
439 | | - | |
| 433 | + | |
| 434 | + | |
| 435 | + | |
440 | 436 | | |
441 | 437 | | |
442 | 438 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
57 | 57 | | |
58 | 58 | | |
59 | 59 | | |
60 | | - | |
| 60 | + | |
61 | 61 | | |
62 | 62 | | |
63 | 63 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
123 | 123 | | |
124 | 124 | | |
125 | 125 | | |
126 | | - | |
| 126 | + | |
127 | 127 | | |
128 | | - | |
129 | | - | |
| 128 | + | |
| 129 | + | |
| 130 | + | |
130 | 131 | | |
131 | 132 | | |
132 | 133 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
101 | 101 | | |
102 | 102 | | |
103 | 103 | | |
| 104 | + | |
| 105 | + | |
| 106 | + | |
| 107 | + | |
| 108 | + | |
| 109 | + | |
| 110 | + | |
| 111 | + | |
| 112 | + | |
| 113 | + | |
| 114 | + | |
| 115 | + | |
| 116 | + | |
| 117 | + | |
| 118 | + | |
| 119 | + | |
| 120 | + | |
| 121 | + | |
| 122 | + | |
| 123 | + | |
104 | 124 | | |
105 | 125 | | |
106 | 126 | | |
| |||
137 | 157 | | |
138 | 158 | | |
139 | 159 | | |
140 | | - | |
141 | | - | |
142 | | - | |
143 | | - | |
144 | | - | |
145 | | - | |
146 | | - | |
147 | | - | |
148 | | - | |
149 | | - | |
150 | | - | |
151 | | - | |
152 | | - | |
153 | | - | |
154 | | - | |
155 | | - | |
156 | | - | |
157 | | - | |
158 | | - | |
159 | | - | |
160 | | - | |
161 | | - | |
162 | | - | |
| 160 | + | |
| 161 | + | |
| 162 | + | |
163 | 163 | | |
164 | | - | |
165 | 164 | | |
166 | 165 | | |
167 | 166 | | |
168 | 167 | | |
169 | 168 | | |
170 | 169 | | |
| 170 | + | |
| 171 | + | |
| 172 | + | |
| 173 | + | |
| 174 | + | |
| 175 | + | |
171 | 176 | | |
172 | 177 | | |
173 | 178 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
19 | 19 | | |
20 | 20 | | |
21 | 21 | | |
22 | | - | |
23 | | - | |
24 | | - | |
| 22 | + | |
| 23 | + | |
25 | 24 | | |
26 | 25 | | |
27 | 26 | | |
| |||
57 | 56 | | |
58 | 57 | | |
59 | 58 | | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
60 | 79 | | |
61 | 80 | | |
62 | 81 | | |
| |||
153 | 172 | | |
154 | 173 | | |
155 | 174 | | |
156 | | - | |
157 | | - | |
158 | | - | |
159 | | - | |
160 | | - | |
161 | | - | |
162 | | - | |
163 | | - | |
164 | | - | |
165 | | - | |
166 | | - | |
167 | | - | |
168 | | - | |
169 | | - | |
170 | | - | |
171 | | - | |
172 | | - | |
173 | | - | |
174 | | - | |
175 | | - | |
176 | | - | |
| 175 | + | |
| 176 | + | |
| 177 | + | |
177 | 178 | | |
178 | | - | |
179 | 179 | | |
180 | 180 | | |
181 | 181 | | |
182 | 182 | | |
183 | 183 | | |
184 | 184 | | |
185 | 185 | | |
| 186 | + | |
| 187 | + | |
| 188 | + | |
| 189 | + | |
| 190 | + | |
| 191 | + | |
186 | 192 | | |
187 | 193 | | |
188 | 194 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
30 | 30 | | |
31 | 31 | | |
32 | 32 | | |
33 | | - | |
34 | | - | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
35 | 38 | | |
36 | 39 | | |
37 | 40 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
216 | 216 | | |
217 | 217 | | |
218 | 218 | | |
219 | | - | |
| 219 | + | |
220 | 220 | | |
221 | | - | |
222 | | - | |
223 | | - | |
224 | | - | |
225 | | - | |
226 | | - | |
227 | | - | |
228 | | - | |
229 | | - | |
230 | | - | |
231 | | - | |
232 | | - | |
| 221 | + | |
| 222 | + | |
| 223 | + | |
| 224 | + | |
| 225 | + | |
| 226 | + | |
| 227 | + | |
| 228 | + | |
233 | 229 | | |
234 | 230 | | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
62 | 62 | | |
63 | 63 | | |
64 | 64 | | |
65 | | - | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
66 | 72 | | |
67 | 73 | | |
68 | 74 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
45 | 45 | | |
46 | 46 | | |
47 | 47 | | |
48 | | - | |
| 48 | + | |
| 49 | + | |
49 | 50 | | |
50 | 51 | | |
51 | 52 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
108 | 108 | | |
109 | 109 | | |
110 | 110 | | |
111 | | - | |
| 111 | + | |
| 112 | + | |
112 | 113 | | |
113 | 114 | | |
0 commit comments