Repository navigation
Commit c199772
fix(spec): title
Fixes #17506
Clause-②: no
Studio renders a `type: 'repeater'` form field as a table whose column
headers read `items.properties[k].title ?? k` off the JSON Schema
derived from the metadata type schema. `SelectOptionSchema`
(`packages/spec/src/data/field.zod.ts`) carried no `title` on any of its
six row properties, so the fallback arm ran and the maker saw `label` /
`value` / `description` / `color` / `default` / `visibleWhen` inside an
otherwise translated panel — in every locale, English included. Titles
are hard-coded English by design: `system/translation.zod.ts` states
that a row property renders from `items.properties[k].title`, and
`resolveMetadataFormSchemaTitles` only ever REPLACES a title that is
already there, so an untitled property has no layer for a translation to
overlay. Triage refused the i18n route by name; this is not routed
through translations.
Two halves, both here:
1. `.meta({ title })` on each of the six row properties — `Label`,
`Value`, `Description`, `Color`, `Default`, `Visible When`.
2. Both of this carrier's entries deleted from the shrink-only ledger in
`packages/spec/src/kernel/repeater-item-titles.test.ts`.
## One schema, two carriers — verified, not assumed
`field:options` and `object:fields.options` resolve to the **same**
`SelectOptionSchema` object. Measured by object identity (`===`) against
the schemas the ledger itself derives from, not by structural
resemblance:
```
LEG1 FieldSchema.shape.options element === SelectOptionSchema : true
LEG2a getMetadataTypeSchema("field").options element === SelectOptionSchema : true
object.fields is a record ; its value schema === FieldSchema : true
LEG2b getMetadataTypeSchema("object").fields[*].options element === SelectOptionSchema : true
SAME OBJECT both carriers : true
CONTROL FormSelectOptionSchema === SelectOptionSchema (expect false) : false
```
The last line is the firing control: the probe can tell two schemas
apart, so the four `true` readings are readings and not a stuck
predicate. ⇒ **`packages/spec/src/data/object.zod.ts` needed no edit**
and was not touched; it reaches the option shape only through its
`FieldSchema` import. The declared file surface held.
## Re-derived on today's `origin/main`, not inherited from the card
The ledger's own derivation, replayed over all 15 `*.form.ts` exports
(22 carriers):
| reading | before | after |
|---|---|---|
| `field:options` row properties | 6 — `label`, `value`, `description`,
`color`, `default`, `visibleWhen`; all 6 untitled | all 6 titled |
| `object:fields.options` row properties | the same 6, all untitled |
all 6 titled |
| other carriers with untitled rows | `view:columns` (14), `view:sort`
(2), `view:tabs` (9) | unchanged — untouched |
| carriers with zero untitled rows | 17 of 22 | 19 of 22 |
The 17 already-green carriers are the lit control beside the zeros, and
the three `view:*` carriers are the dark control: they stay exactly as
untitled as they were, which is what an edit scoped to
`SelectOptionSchema` must look like.
## The ledger was not weakened — both of its arms were made to fire
Fix committed first, then mutated on disk through
`scripts/ablation-replace.mjs` (anchor must hit; the write is proven by
blob-hash change, never by an exit code), and restored with the restore
proven by blob hash against `HEAD` plus an empty `git diff HEAD`.
**Ablation 1 — delete one title.** `.meta({ title: 'Color' })` removed
from `field.zod.ts`; blob `7bee63cfd9b6` → `5c4d8131a8a9`. Predicted
direction: both carriers red on exactly `color`, because neither sits in
the ledger any more. Observed:
```
× field:options expected [ 'color' ] to deeply equal []
× object:fields.options
Tests 2 failed | 24 passed (26)
restored: blob == HEAD (7bee63c) and `git diff HEAD` is empty
```
**Ablation 2 — put a paid entry back.** `'view:columns'` in `LEDGER`
replaced with `'field:options'`; blob `c6579a27080a` → `2c450c99382c`.
This fires **both** directions of the exact ratchet at once:
```
× field:options (ledger: still owed titles)
AssertionError: field:options is fully titled now — delete its LEDGER entry in this file
× view:columns
AssertionError: view:columns: these row properties have no `.meta({ title })` …
Tests 2 failed | 24 passed (26)
restored: blob == HEAD (c6579a2) and `git diff HEAD` is empty
```
A ledger nobody has seen red on this carrier would not be evidence it is
holding; it has now been seen red on this carrier, in both directions.
## Clause-② — `no`, and measured
`.meta({ title })` is JSON-Schema presentation metadata and a ledger row
is a test; neither moves what any schema accepts. Two independent
readings agree:
- `check:authorable-surface` is green with the generated
`authorable-surface/` artifacts **byte-identical** — that artifact set
IS "what the schema accepts", and it did not move. All 16 generated
artifacts report up to date.
- The pinned accept/refuse suites for this exact shape pass unchanged:
`editability-boundary`, `visible-when-alias-guidance`,
`form-select-option`, `evaluated-slot-population` (254 tests over 5
files).
## Changeset — owed, and why
`@objectstack/spec` publishes `dist` **and** `src/**/*.zod.ts` (its
`files[]`), and both carry the six new calls — `dist/data/index.mjs`
reads `Color code for badges/charts").meta({ title: "Color" …`, with a
nonsense title string as the negative control reading 0. Published bytes
move ⇒ a `patch` changeset, not `skip-changeset`.
## Verification
Run at `cff031c8db` unless stated:
- `pnpm --filter @objectstack/spec test` — **500 files / 14642 tests
passed**.
- `pnpm --filter @objectstack/spec typecheck` — green.
- `pnpm --filter @objectstack/spec check:generated` — 16 of 16 artifacts
up to date.
- `pnpm --filter @objectstack/spec build` then `check:api-surface` /
`check:api-surface-declarations` — green (5364 declarations, text
unchanged).
- Consumers of the wire shape: `@objectstack/metadata-protocol`
meta-types derivation tests (3 files / 35 tests) and `@objectstack/rest`
`meta-types-schema-titles.test.ts` (3 tests) — green.
- `scripts/pm/dispatch-gates.mjs --ran` over this diff: **81 derived, 78
run, 3 NOT MEASURED, 0 unrun**. The three are
`check:dual-build-cjs-loads`, `check:lean-entry-closure` and
`check:type-check-debt`, each exiting 3 (PREREQUISITE NOT MET — they
need a whole-workspace build). Those are CI's farm, not a pass and not a
finding.
- `pnpm exec eslint --no-inline-config` over the two changed source
files: 2 files linted, 0 errors, 0 warnings. The narrowing is measured,
not assumed: this repo runs one `eslint.config.mjs` which never enables
type-aware linting for any file (no `parserOptions.project`, no typed
rules — stated and positively controlled in that file's own header), so
this diff cannot move the verdict on a file it does not touch.
## Acceptance notes
- **Out of scope, noted only.** `repeater-item-titles.test.ts` derives
with `io: 'input'` while the server's `toJsonSchemaSafe` takes zod's
default `'output'`, and the two part on `action`, whose output
derivation is `{}`. The file documents this itself and calls the
output-side hole a separate defect; nothing here changes it.
- **Out of scope, noted only.** `view:columns`, `view:sort` and
`view:tabs` stay in the ledger. They are `view.zod.ts`'s debt and that
file is held by another PR.
- **Observation, one reading, not isolated.**
`check:api-surface-declarations` reported "0 removed, 0 added, 140
reshaped" against a `packages/spec/dist` produced by a 13-package `pnpm
--filter '…^...' build` run, and reported "declaration text unchanged
(5364 declarations)" against a dist produced by a standalone `pnpm
--filter @objectstack/spec build` of the identical source. The
standalone reading is the one quoted above. The variable was not
isolated, so this is recorded as an observation rather than filed.
- **Surface note.** The declared file surface was the two paths above;
the third file in this PR is the changeset the publish rule requires.
---
_Generated by [Claude
Code](https://claude.ai/code/session_01AmH9bKvGoLjiY86Q4Z3og2)_
---------
Co-authored-by: Claude <noreply@anthropic.com>SelectOptionSchema's six row properties — clears both repeater ledger carriers (#19257)1 parent 7d0f911 commit c199772
3 files changed
Lines changed: 29 additions & 16 deletions
File tree
- .changeset
- packages/spec/src
- data
- kernel
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
335 | 335 | | |
336 | 336 | | |
337 | 337 | | |
338 | | - | |
339 | | - | |
| 338 | + | |
| 339 | + | |
340 | 340 | | |
341 | 341 | | |
342 | 342 | | |
| |||
356 | 356 | | |
357 | 357 | | |
358 | 358 | | |
359 | | - | |
360 | | - | |
361 | | - | |
| 359 | + | |
| 360 | + | |
| 361 | + | |
362 | 362 | | |
363 | 363 | | |
364 | 364 | | |
| |||
384 | 384 | | |
385 | 385 | | |
386 | 386 | | |
387 | | - | |
| 387 | + | |
388 | 388 | | |
389 | 389 | | |
390 | 390 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
84 | 84 | | |
85 | 85 | | |
86 | 86 | | |
87 | | - | |
88 | | - | |
89 | | - | |
90 | | - | |
91 | | - | |
92 | | - | |
| 87 | + | |
| 88 | + | |
| 89 | + | |
| 90 | + | |
93 | 91 | | |
94 | | - | |
95 | | - | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
| 95 | + | |
| 96 | + | |
| 97 | + | |
96 | 98 | | |
97 | 99 | | |
98 | | - | |
99 | | - | |
100 | 100 | | |
101 | 101 | | |
102 | 102 | | |
| |||
0 commit comments