Repository navigation
Commit 2df3d13
feat(spec): offer object.imageField in Studio's object form beside nameField (#21854)
Fixes #21765
Clause-②: no
Item 3 of the card, under the director seat's ruling A (`5989738766`):
Studio's object form now offers `imageField`, the record's picture, as a
plain `text` row beside `nameField`. Items 1 and 2 landed in PR #21824.
With this PR, the card's last open item is done.
## What changed
- **The form row** (`packages/spec/src/data/object.form.ts`): one `{
field: 'imageField', type: 'text', colSpan: 1, helpText }` row directly
after `nameField`. It has the same face as `nameField`, for the same
reason: the value names one of the object's own fields, and the registry
has no own-field picker. The row adds no picker and no validator.
`refuseNonPictureImageField` at parse stays the one judge, and its
refusal at save is what an author sees. The helpText says what the parse
accepts: a field of this object whose type is `image` or `avatar`. Left
empty, there is no record picture and no placeholder. The metadata
form's text input writes no key when cleared (objectui `SchemaForm.tsx`
at the pin `0abd4f9f8769`: `onChange(e.target.value || undefined)`), so
"empty" in the helpText means the key is unset, which the parse reads as
no picture.
- **The stale ledger row** (`metadata-form-zod-reconciliation.test.ts`):
the `imageField` `omit` row in the declared-not-enforced group is
deleted. No other row moves.
- **The catalogs**: the four
`packages/platform-objects/src/apps/translations/*.metadata-forms.generated.ts`
files were regenerated with `node scripts/check-i18n-bundles.mjs
--write`. The zh-CN / ja-JP / es-ES `label` and `helpText` leaves were
then written in place, since translated-locale values are hand-written
in those files (AGENTS.md, Documentation Guardrails). A second `--write`
kept them and dropped the six provenance entries the first extract had
added to the three `*.source-hashes.generated.ts` companions. Those
companions are byte-unchanged in this diff.
- **The pin** (`metadata-form-declared-rows.pin.test.ts`): three tests.
A lit and dark control for the locator. The key is offered once, as a
`text` row with no widget. It sits directly after `nameField`, in the
same section, at the same `colSpan`. The reconciliation test proves only
that the key is offered somewhere on the form; it reads neither the
control nor the position, so this pin covers what it misses. No test
title or string carries a tracker id.
- **Two measured counts in `platform-objects` were re-taken**, both
forced by the new row:
- the object form's open-section leaf population: 114 → 116
(`object-collapsed-sections-echo-decisions.test.ts`);
- the catalog-wide translated-label control: 659 → 660 per locale
(`object-lifecycle-panel-echo-decisions.test.ts`).
The `openEchoes` reading stays at zero.
- **Changeset**: `@objectstack/spec` patch and
`@objectstack/platform-objects` patch (below).
⛔ No Zod change, no liveness change, no new gate or ledger class.
## The reconciliation test: predicted, then measured
Predicted before writing: red without the form row, green with it.
Measured on the committed state, with `scripts/ablation-replace.mjs` in
wrap mode and a `trap` restore proven by blob equal to HEAD:
| state | reading |
|---|---|
| row deleted, form row present (this PR, `c730a8c598`) | 2 files, **87
passed (87)** |
| row deleted, form row removed (anchor 1 → 0, blob `d867e358e5e5` →
`a67cdaed2b22`) | **3 failed / 84 passed**: `object.(root): accepted by
the Zod but unauthorable in the form … expected [ 'imageField' ] to
deeply equal []`, plus the two new pin tests. Restored: blob
`d867e358e5e5` == HEAD, `git diff HEAD` empty |
| control: the stale row planted back beside the form row | **1 failed /
75 passed**: `object.(root).imageField: the form offers it now — drop
the ledger entry`. Restored: blob `2a7c49dca958` == HEAD |
The first attempt at the control leg was a no-op. The tool refused it
before running anything, because the replacement text contained its own
anchor. It was redone with a non-overlapping replacement, which is the
reading above.
## What ships
Each package was built and its `dist/` grepped, with a positive control:
- `@objectstack/spec`: the new helpText is in 8 dist files; the control,
`nameField`'s helpText, is in 8.
- `@objectstack/platform-objects`: the new en helpText is in 6 dist
files, the control in 6. The zh-CN, ja-JP and es-ES labels are in 6
each, matched on literal or unicode-escaped text.
Both packages publish the change, so both get `patch`. `skip-changeset`
does not apply.
## Verification (final head `9f6b177875`)
- `pnpm --filter @objectstack/spec exec vitest run --project local
--maxWorkers=2`: Test Files 614 passed | 1 skipped (615), Tests 18385
passed | 1 skipped | 1 todo. The skipped file is
`scripts/root-entry-type-nameability.pin.test.ts`, which is gated by
`OS_EXPECT_ROOT_NAMEABILITY`.
- `pnpm --filter @objectstack/spec run typecheck`: exit 0. `tsc -p
tsconfig.test.json --listFilesOnly` compiles `object.form.ts` and both
changed spec tests.
- `pnpm --filter @objectstack/platform-objects exec vitest run
--maxWorkers=2`: 59 files, **949 passed**. Run before the two counts
were re-taken, it gave exactly two failures: `expected 116 to be 114`
and `zh-CN positive control: expected 660 to be 659`. Typecheck: exit 0.
- `metadata-forms-vocabulary.test.ts`: 5 passed. `pnpm check:i18n`: exit
0, `platform-objects in sync (11 bundle(s))`. `pnpm
check:i18n-coverage`: exit 0, `13 config(s), 621 baselined untranslated
string(s), none new`.
- `pnpm --filter @objectstack/spec run check:generated`: exit 0 (15
artifacts).
- Gates: `node scripts/pm/dispatch-gates.mjs --commands --repo
objectstack-ai/objectstack` derived 87 commands from 10 paths against
the merge base `8832655af`. All 87 were run on `9f6b177875`. `--ran`
reconciliation: `87 derived famil(ies) accounted for — 87 run, 0
NOT-MEASURED`. Four spec gates first exited 3 (`PREREQUISITE NOT MET`:
the dist predated a test-title edit). They exited 0 after `pnpm --filter
@objectstack/spec build`, and the record keeps that last reading.
- eslint `--no-inline-config --format json` on the 9 changed TS files: 9
files, 0 errors, 0 warnings. The population is `eslint.config.mjs:971`
(`**/*.{ts,tsx,mts,cts,js,jsx,mjs,cjs}`). Linting is not type-aware (no
`parserOptions.project`), so untouched files' verdicts cannot move.
## Acceptance notes
- **Surface, stated.** The claim named `object.form.ts`, the
reconciliation test, the four catalogs and a changeset. Three more files
changed:
- `metadata-form-declared-rows.pin.test.ts` holds the pin the dispatch
asked for (item 4).
- The two `platform-objects` echo-decision tests carry the counts the
row moves. Those count lines are the ones PR #19673 moved when it added
rows to the same section. A reviewer who reads them as outside the
surface can say so.
- No `platform-objects` source or object file moved, and no other
catalog key changed.
- The authored leaves live in the generated catalogs themselves, so no
further file joins the surface for them.
- `origin/main` gained one commit after the branch point (`2799155678`,
test titles in `packages/spec/src/data/`). It touches none of this PR's
paths.
---
_Generated by [Claude
Code](https://claude.ai/code/session_01T9u38rswFp5Rw8DswRUReJ)_
---------
Co-authored-by: Claude <noreply@anthropic.com>1 parent 07e933b commit 2df3d13
10 files changed
Lines changed: 97 additions & 9 deletions
File tree
- .changeset
- packages
- platform-objects/src/apps/translations
- spec/src
- data
- system
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
Lines changed: 4 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
60 | 60 | | |
61 | 61 | | |
62 | 62 | | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
63 | 67 | | |
64 | 68 | | |
65 | 69 | | |
| |||
Lines changed: 4 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
60 | 60 | | |
61 | 61 | | |
62 | 62 | | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
63 | 67 | | |
64 | 68 | | |
65 | 69 | | |
| |||
Lines changed: 4 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
60 | 60 | | |
61 | 61 | | |
62 | 62 | | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
63 | 67 | | |
64 | 68 | | |
65 | 69 | | |
| |||
Lines changed: 4 additions & 1 deletion
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
938 | 938 | | |
939 | 939 | | |
940 | 940 | | |
941 | | - | |
| 941 | + | |
| 942 | + | |
| 943 | + | |
| 944 | + | |
942 | 945 | | |
943 | 946 | | |
944 | 947 | | |
| |||
Lines changed: 3 additions & 1 deletion
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1167 | 1167 | | |
1168 | 1168 | | |
1169 | 1169 | | |
1170 | | - | |
| 1170 | + | |
| 1171 | + | |
| 1172 | + | |
1171 | 1173 | | |
1172 | 1174 | | |
1173 | 1175 | | |
| |||
Lines changed: 4 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
60 | 60 | | |
61 | 61 | | |
62 | 62 | | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
63 | 67 | | |
64 | 68 | | |
65 | 69 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
47 | 47 | | |
48 | 48 | | |
49 | 49 | | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
50 | 60 | | |
51 | 61 | | |
52 | 62 | | |
| |||
Lines changed: 50 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
48 | 48 | | |
49 | 49 | | |
50 | 50 | | |
| 51 | + | |
51 | 52 | | |
52 | 53 | | |
53 | 54 | | |
| |||
170 | 171 | | |
171 | 172 | | |
172 | 173 | | |
| 174 | + | |
| 175 | + | |
| 176 | + | |
| 177 | + | |
| 178 | + | |
| 179 | + | |
| 180 | + | |
| 181 | + | |
| 182 | + | |
| 183 | + | |
| 184 | + | |
| 185 | + | |
| 186 | + | |
| 187 | + | |
| 188 | + | |
| 189 | + | |
| 190 | + | |
| 191 | + | |
| 192 | + | |
| 193 | + | |
| 194 | + | |
| 195 | + | |
| 196 | + | |
| 197 | + | |
| 198 | + | |
| 199 | + | |
| 200 | + | |
| 201 | + | |
| 202 | + | |
| 203 | + | |
| 204 | + | |
| 205 | + | |
| 206 | + | |
| 207 | + | |
| 208 | + | |
| 209 | + | |
| 210 | + | |
| 211 | + | |
| 212 | + | |
| 213 | + | |
| 214 | + | |
| 215 | + | |
| 216 | + | |
| 217 | + | |
| 218 | + | |
| 219 | + | |
| 220 | + | |
| 221 | + | |
| 222 | + | |
173 | 223 | | |
174 | 224 | | |
175 | 225 | | |
| |||
Lines changed: 0 additions & 7 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
391 | 391 | | |
392 | 392 | | |
393 | 393 | | |
394 | | - | |
395 | | - | |
396 | | - | |
397 | | - | |
398 | | - | |
399 | | - | |
400 | | - | |
401 | 394 | | |
402 | 395 | | |
403 | 396 | | |
| |||
0 commit comments