Repository navigation
Commit c6b3a01
Part of #20901
Clause-②: no
The follow-up the contract review of PR #20927 owes (review record
`5919009567`, items 5, 6 and 9, and the ① text findings), dispatched by
landing record `5919493523`. #20901 stays open for the seat to close by
hand.
## What changed
1. **Review item 5, the step-18 entry
`inline-grid-column-currency-scale-refused`.** Its surface said a column
that declares no `type` "is untouched", and its acceptance said such
columns "keep their `scale`". Since `bee75cebe6` that is false for an
identity-only column over a `currency` child field, which `defineStack`
refuses. The surface, the reach sentence of the reason and the
acceptance now say so, and each names the sibling entry
`inline-grid-column-identity-only-currency-scale-refused`. The registry
was regenerated with `gen:migration-registry`.
2. **Review item 6, ruled WIDEN: the `field` → `name` respelling is now
an ADR-0087 chain step on the form-view carrier.** New D2 conversion
`form-view-subform-columns-canonicalized` (protocol 18,
`retiredFromLoadPath: true`, `retiredAfter: '17.5.0'`). It walks every
FORM payload `mapViewPayloads` reaches, which is `form`, each
`formViews` entry, a form view item's `config` and a flattened form
overlay (the stored-row seam wraps a `view` row as `{ views: [row] }` in
any of those spellings). It also walks the assembled `viewItems`
channel. It uses the same respelling rule as
`field-column-lists-canonicalized`, now one shared function
(`respellInlineGridColumns`) called by both entries. An entry already
spelled `name` is left alone, and so is one carrying both keys, exactly
as the existing walk behaves. The D3 entry
`form-view-subform-columns-closed` said "NOT mechanically converted". It
now names this conversion, and its comment no longer says a stored row
is "refused": a stored row is diagnosed at rehydration.
3. **Review item 9.** A pin in `inline-grid-column-carriers.test.ts`
probes `InlineGridColumnSchema` for every (type, key, value) that parses
with the key alone and with the type alone but not with both. Today it
finds exactly `currency` + `scale` (at `0` and `2`), and it asserts that
`defineStack` refuses each such rule on an identity-only column over a
field of that type. A new type-conditional rule without a
`HYDRATED_INLINE_COLUMN_TYPE` row goes red, and the failure message
names the table. `stack.zod.ts` itself is unchanged apart from comments.
4. **The ① text findings, in the files touched above.** `stack.zod.ts`:
the objectui `hydrateColumns` / `fieldTypeToColumnType` claim is now a
historical pin citation (`.objectui-sha` pin `db11afd4967c`, re-read at
that sha: `hydrateColumns` leaves a typed column alone, and
`fieldTypeToColumnType`'s only `currency` arm is `case 'currency'`), and
`check:objectui-pin-citations` lists it. The over-broad "like the view
data-source check" is cut. The instruction "adds its row here" now names
the pin that holds it.
## Route change on item 6: its own entry, not a wider walk inside
`field-column-lists-canonicalized`
The ruling's intent is carried out exactly: a lossless respelling on the
new carrier, landed as a `retiredFromLoadPath` chain step in the same
release. The vehicle differs from the ruling's wording, for one ledger
fact the gates cannot see. `retiredAfter` is one value per entry: "the
last published `@objectstack/spec` whose authoring surface still
accepted the old shape" (ADR-0087 amendment of 2026-09-30, maintainer
ruling A on #20390). `field-column-lists-canonicalized` is published
with `17.0.0`, and `retired-after.census.test.ts` pins that value, while
the form-view carrier accepted `field` through 17.5.0. The
artifact-ingestion door opens its window per entry by that value.
Measured at this head, with `applyArtifactForwardConversions`, an
artifact declaring `engines.protocol: ^17.5.0`, and runtime label
`17.5.0`:
- verdict `converted-retired-after`;
- the subform column `{ field: 'quantity' }` became `{ name: 'quantity'
}` through the new entry (listed in `replayedRetirements` with
`retiredAfter` `17.5.0`);
- the same `{ field: 'quantity' }` on a relationship field's
`inlineColumns` stayed as authored, because
`field-column-lists-canonicalized` (`17.0.0`) stays closed at that
floor. That is correct for that carrier, and it is what a folded-in
subform walk would have done to the new carrier: the refusal instead of
the rewrite.
A second, smaller reason: the per-release section of `spec-changes.json`
reports conversion ids that are new in a release, so a widened,
already-published id would be invisible there. If the seat still wants
one id, the fold-in is mechanical: move the `mapViewPayloads` walk into
`field-column-lists-canonicalized` and delete the sibling. The cost is
the artifact-door gap above.
## Verification (at `06f079864a`, which carries `origin/main`
`3fbf3ca617`)
- **Pins** `packages/spec/src/inline-grid-column-carriers.test.ts`: 21
passed (13 existing + 8 new).
- **Ablation 1** (`scripts/ablation-replace.mjs`, `registry.ts`: the new
entry's `respellInlineGridColumns(subform.columns, …)` call replaced by
`subform.columns`; anchor x1 → x0; blob `909148b74725` →
`3b07d9f2d145`), run over the pins plus `conversions.test.ts`: `Tests 4
failed | 251 passed (255)`. The red ones are the fixture pair of
`form-view-subform-columns-canonicalized`, the stored-row test in all
three `view` spellings, the `os migrate meta` chain test, and the
two-carriers-one-rule test. The controls (an entry spelled `name`, one
carrying both keys, and the authoring funnel's refusal) stayed green.
Restored: blob == HEAD, `git diff HEAD` empty.
- **Ablation 2** (`stack.zod.ts`: the `currency` row deleted from
`HYDRATED_INLINE_COLUMN_TYPE`; blob `f93870ec6a88` → `d3aca2ec1d38`):
`Tests 4 failed | 17 passed (21)`. The new table pin is red with "…add
the row to HYDRATED_INLINE_COLUMN_TYPE in stack.zod.ts", and so are the
three existing hydrated refusals. Restored: blob == HEAD.
- Both ablations ran from committed state (`ca5ad202a9`). The subject
resolves to `src` through relative imports, so no dist leg was owed.
- **Spec suite** `vitest run --project local`: `Test Files 584 passed
(584) / Tests 17200 passed | 1 todo`. **Typecheck** `pnpm --filter
@objectstack/spec typecheck`: exit 0 (`check:test-typecheck: OK`;
`tsconfig.test.json --listFiles` includes the pin file). **Repo-project
subset** (major-18 merge, step-18 rationale merge, retired-key migrate
sentence, two view retirement pins): 82 passed. The full `test:repo`
project is left to CI.
- **`check:generated`**: all 15 artifacts up to date after a fresh `pnpm
--filter @objectstack/spec build`.
- **Derived gates** `node scripts/pm/dispatch-gates.mjs --commands
--repo objectstack-ai/objectstack`: 90 derived, 90 run, all exit 0.
`--ran` reconciliation reports "0 NOT-MEASURED (a DERIVED zero — all 90
recorded an exit code)". Four first exited 3 (PREREQUISITE NOT MET:
`lint check:doc-formula-expressions`, `check:dual-build-cjs-loads`,
`check:lean-entry-closure`, `check:type-check-debt`) and were green on a
re-run after `turbo run build` over `./packages/*` and `./packages/*/*`.
- **ESLint** (a narrowed run, stated as such): `eslint
--no-inline-config --format json` over the 7 changed `.ts` files reports
files 7, errors 0, warnings 0. The population is `eslint.config.mjs`'s
`**/*.{ts,tsx,mts,cts,js,jsx,mjs,cjs}`. That config never enables
type-aware linting (its own comment: no `parserOptions.project`, no
typed rules), so this diff cannot move the verdict on any untouched
file.
## One test touched outside the dispatched files
`packages/spec/scripts/conversions-major18-merge.test.ts` went red on
this diff. It builds its synthetic retirement pair beside the entry at
the middle of `MAJOR_18_CONVERSIONS`. At the base that neighbour was
`hookTimeoutToTimeoutMs`, which predates the placement rule. With this
entry added, the neighbour is `formViewSubformColumnsCanonicalized`,
which is placed by the rule. The "defined after every other conversion"
variant then reports the neighbour too, because its entry is now
followed by the synthetic one. The expectation now derives that
neighbour finding when, and only when, the neighbour is not exempt. At
the base it reduces to the old single-element list. 12/12 pass.
## Changeset
`@objectstack/spec: patch`. The act adds no exported symbol
(`check:api-surface` green) and no accepted key or value on an authoring
surface: authored sources are refused exactly as before. It rewrites
stored and assembled data that the contract already names (`name`), so
under the "WHICH LEVEL" rule it is a fix and stays `patch`. `Clause-②:
no`, per the gate's definition (a new key on a published payload): the
conversion adds no key, and the step-18 edits are prose. It is not a
narrowing either, since the data-at-rest seams now accept strictly more.
## Acceptance notes
- `retiredAfter: '17.5.0'` is the package label, as
`retired-after.census.test.ts` requires for an unpublished entry. The
census is refreshed after the next publish.
- Step 18's `rationale` gains no fragment. PR #20927 added none for its
two D3 entries either, and no gate requires one per entry.
- Not changed here: the PR #20927 body sentence "No check read
`subforms[].childObject`", recorded by the adoption for its next touch;
`packages/spec/src/data/field.zod.ts`, which the dispatch keeps out of
scope; #20928 and #20929; and objectui#11266.
---
_Generated by [Claude
Code](https://claude.ai/code/session_01Sfe5YjBLwB9J3y8fvm2xq1)_
---------
Co-authored-by: Claude <noreply@anthropic.com>
1 parent c1602ba commit c6b3a01
8 files changed
Lines changed: 427 additions & 58 deletions
File tree
- .changeset
- packages/spec
- scripts
- src
- conversions
- migrations
- entries/semantic
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
355 | 355 | | |
356 | 356 | | |
357 | 357 | | |
| 358 | + | |
| 359 | + | |
| 360 | + | |
358 | 361 | | |
| 362 | + | |
| 363 | + | |
| 364 | + | |
359 | 365 | | |
360 | 366 | | |
361 | 367 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
7623 | 7623 | | |
7624 | 7624 | | |
7625 | 7625 | | |
| 7626 | + | |
| 7627 | + | |
| 7628 | + | |
| 7629 | + | |
| 7630 | + | |
| 7631 | + | |
| 7632 | + | |
| 7633 | + | |
| 7634 | + | |
| 7635 | + | |
| 7636 | + | |
| 7637 | + | |
| 7638 | + | |
| 7639 | + | |
| 7640 | + | |
| 7641 | + | |
| 7642 | + | |
| 7643 | + | |
| 7644 | + | |
| 7645 | + | |
| 7646 | + | |
| 7647 | + | |
| 7648 | + | |
| 7649 | + | |
| 7650 | + | |
| 7651 | + | |
| 7652 | + | |
| 7653 | + | |
| 7654 | + | |
| 7655 | + | |
7626 | 7656 | | |
7627 | 7657 | | |
7628 | 7658 | | |
| |||
7667 | 7697 | | |
7668 | 7698 | | |
7669 | 7699 | | |
7670 | | - | |
7671 | | - | |
7672 | | - | |
7673 | | - | |
7674 | | - | |
7675 | | - | |
7676 | | - | |
7677 | | - | |
7678 | | - | |
7679 | | - | |
| 7700 | + | |
| 7701 | + | |
7680 | 7702 | | |
7681 | 7703 | | |
7682 | 7704 | | |
| |||
9820 | 9842 | | |
9821 | 9843 | | |
9822 | 9844 | | |
| 9845 | + | |
| 9846 | + | |
| 9847 | + | |
| 9848 | + | |
| 9849 | + | |
| 9850 | + | |
| 9851 | + | |
| 9852 | + | |
| 9853 | + | |
| 9854 | + | |
| 9855 | + | |
| 9856 | + | |
| 9857 | + | |
| 9858 | + | |
| 9859 | + | |
| 9860 | + | |
| 9861 | + | |
| 9862 | + | |
| 9863 | + | |
| 9864 | + | |
| 9865 | + | |
| 9866 | + | |
| 9867 | + | |
| 9868 | + | |
| 9869 | + | |
| 9870 | + | |
| 9871 | + | |
| 9872 | + | |
| 9873 | + | |
| 9874 | + | |
| 9875 | + | |
| 9876 | + | |
| 9877 | + | |
| 9878 | + | |
| 9879 | + | |
| 9880 | + | |
| 9881 | + | |
| 9882 | + | |
| 9883 | + | |
| 9884 | + | |
| 9885 | + | |
| 9886 | + | |
| 9887 | + | |
| 9888 | + | |
| 9889 | + | |
| 9890 | + | |
| 9891 | + | |
| 9892 | + | |
| 9893 | + | |
| 9894 | + | |
| 9895 | + | |
| 9896 | + | |
| 9897 | + | |
| 9898 | + | |
| 9899 | + | |
| 9900 | + | |
| 9901 | + | |
| 9902 | + | |
| 9903 | + | |
| 9904 | + | |
| 9905 | + | |
| 9906 | + | |
| 9907 | + | |
| 9908 | + | |
| 9909 | + | |
| 9910 | + | |
| 9911 | + | |
| 9912 | + | |
| 9913 | + | |
| 9914 | + | |
| 9915 | + | |
| 9916 | + | |
| 9917 | + | |
| 9918 | + | |
| 9919 | + | |
| 9920 | + | |
| 9921 | + | |
| 9922 | + | |
| 9923 | + | |
| 9924 | + | |
| 9925 | + | |
| 9926 | + | |
| 9927 | + | |
| 9928 | + | |
| 9929 | + | |
| 9930 | + | |
| 9931 | + | |
| 9932 | + | |
| 9933 | + | |
| 9934 | + | |
| 9935 | + | |
| 9936 | + | |
| 9937 | + | |
| 9938 | + | |
| 9939 | + | |
| 9940 | + | |
| 9941 | + | |
| 9942 | + | |
| 9943 | + | |
| 9944 | + | |
| 9945 | + | |
| 9946 | + | |
| 9947 | + | |
| 9948 | + | |
| 9949 | + | |
| 9950 | + | |
| 9951 | + | |
| 9952 | + | |
| 9953 | + | |
| 9954 | + | |
| 9955 | + | |
| 9956 | + | |
| 9957 | + | |
| 9958 | + | |
| 9959 | + | |
| 9960 | + | |
| 9961 | + | |
| 9962 | + | |
| 9963 | + | |
| 9964 | + | |
| 9965 | + | |
| 9966 | + | |
| 9967 | + | |
| 9968 | + | |
| 9969 | + | |
| 9970 | + | |
| 9971 | + | |
| 9972 | + | |
| 9973 | + | |
| 9974 | + | |
| 9975 | + | |
| 9976 | + | |
| 9977 | + | |
| 9978 | + | |
| 9979 | + | |
| 9980 | + | |
| 9981 | + | |
| 9982 | + | |
| 9983 | + | |
| 9984 | + | |
| 9985 | + | |
| 9986 | + | |
| 9987 | + | |
| 9988 | + | |
| 9989 | + | |
| 9990 | + | |
| 9991 | + | |
| 9992 | + | |
| 9993 | + | |
| 9994 | + | |
| 9995 | + | |
| 9996 | + | |
| 9997 | + | |
| 9998 | + | |
| 9999 | + | |
| 10000 | + | |
| 10001 | + | |
9823 | 10002 | | |
9824 | 10003 | | |
9825 | 10004 | | |
| |||
13074 | 13253 | | |
13075 | 13254 | | |
13076 | 13255 | | |
| 13256 | + | |
13077 | 13257 | | |
13078 | 13258 | | |
13079 | 13259 | | |
| |||
0 commit comments