Repository navigation
Commit 681868c
Part of #19920
Clause-②: yes (narrowing)
This PR takes the four remainder items that seat 1's release on #19920
(comment 5858219255) lists, plus remainder 5 (the flattened list
overlay's `type` and `columns`), on `main` after PR #20286. #19920
remains open because this round's census and probes found three more
sites of the same family, outside this PR's surface. See "What stays on
#19920" below.
## What changed
Only types change. The runtime accept set does not move: no schema's
parse, no value, and no removed or renamed export. The FROM column was
probed on the base `c5dcb3ba0`, both against the source (compiler API,
`tsconfig.test.json` options) and against the built `dist`.
| item | FROM | TO |
|:--|:--|:--|
| 1. `JoinedReportBlock` (`ui/report.zod.ts`) | `unknown`, because
`JoinedReportBlockSchema` was annotated `z.ZodTypeAny`. Each `blocks[]`
element of `Report` / `ReportParsed` (and so of `defineReport`'s
parameter) was `unknown` for the same reason. | The schema's own input
type: the annotation is removed. `blocks[]` elements are blocks. |
| 2. A ViewItem's `config` (`ui/view.zod.ts`) | `unknown` on both arms
of `ViewItem` and `ViewItemWire`, because `viewItemArmShape(viewKind,
config)` typed `config` as `z.ZodTypeAny`. The same `unknown` reached
`defineViewItem` and the `viewItem` member of `ViewMetadata`,
`ViewMetadataParsed`, `AssembledViewArtifact` and
`AssembledViewArtifactParsed`. | The arm's config type: a `ListView`
config under `viewKind: 'list'`, a `FormView` config under `viewKind:
'form'`. `config` is a generic parameter now, beside `viewKind`. |
| 3. The flattened overlay members' `viewKind` | The union of `'list'`
and `'form'` on both members, because `flattenedViewOverlayFields(kind)`
was not generic, so `z.enum([kind])` widened. `{ type: 'grid', columns:
['name'], object, viewKind: 'form' }` type-checked, through the list
member, as all four union types above, while both doors refuse it. |
`'list'` on the list overlay member, `'form'` on the form overlay
member: the function is generic in the kind. |
| 4. The list overlay's `type` default | Not named anywhere. | One TSDoc
paragraph on `ViewMetadataParsed`, and the same on
`AssembledViewArtifactParsed`. It says, from the code, that the member
declares `type` without `.default('grid')` and re-applies it in
`.overwrite(applyListOverlayTypeDefault)`. An `.overwrite()` returns the
member's own output type, so `type` stays optional in the output type
while every parse through that member returns it (`'grid'` when the body
named none). On that member `type` is typed as the list shape's `type`
enum. |
| 5. The flattened list overlay's `type` and `columns`
(`ui/view.zod.ts`) | `unknown` on the list overlay member of
`ViewMetadata`, `ViewMetadataParsed`, `AssembledViewArtifact` and
`AssembledViewArtifactParsed`, on input and on output, because
`listOverlayPatchFields()` read both keys off `ListViewShapeSchema`
through a cast of its shape to a record of `z.ZodTypeAny`. `{ object,
viewKind: 'list', columns: 42 }` type-checked as all four while that
member refuses it. | The list shape's own types, both optional: `type`
the list view type enum, `columns` the field list. The shape is read as
typed; the schemas are the same objects, so no parse moves. |
### Changes beyond the five items, each forced, with what forced it
1. **Declaration size (item 2).** With only the generic parameter,
`view.zod.d.ts` grows by +170,655 B (500,535 to 671,190, +34%), with 0
TS7056. The cause is that `ViewItemSchema`, `ViewItemWireSchema` and
`VIEW_METADATA_MEMBERS.viewItem` each spell both config types out in
full, at 58,764 B, 59,326 B and +60,108 B.
- **What this PR does instead.** Both schemas carry an explicit type
annotation through two non-exported aliases read off `viewItemArmShape`
itself. `ViewItemArmShape` is the ReturnType of `typeof
viewItemArmShape`, instantiated. `ViewItemWireArmShape` is that plus
`viewItemWireFields()`, written as one mapped type. The `viewItem` entry
of `VIEW_METADATA_MEMBERS` is spelled `ViewItemWireSchema as typeof
ViewItemWireSchema`, an assertion to the schema's own type, so the
emitter names the schema instead of copying it.
- **Result.** `view.zod.d.ts` is 496,008 B, 4,527 B smaller than on the
base.
- **Identity proof.** Measured with an `Equal` probe (the
mutual-conditional form) against in-memory inferred twins of both
schemas. It holds for each schema, for its z.input and z.output, and for
the member. A control pair answers false.
- **A spelling I measured and did not take.** A first spelling of the
wire annotation used an intersection. It was assignable but not
identical (Equal false), so it was replaced by the mapped form.
- **The deviation.** No TS error forced this assertion. Declaration size
forced it. So it deviates from the dispatch's mechanism assumption 2,
which allowed assertions only where a TS error forces them.
2. **ADR-0122 (items 1 and 2).** Three isomorphism pins in
`type-alias-convention.pin.test.ts` turned into TS2344 ×3:
`Iso_ui_report__JoinedReportBlockSchema`, `Iso_ui_view__ViewItemSchema`
and `Iso_ui_view__ViewItemWireSchema`. They had held only because input
and infer were the same erased `unknown`; typed, each schema carries
defaults. The pins are deleted. Per `check:spec-parsed-alias` rule 2,
three parsed-state aliases are added: `JoinedReportBlockParsed`,
`ViewItemParsed` and `ViewItemWireParsed`. These are three new type
exports on the `ui` entry; `api-surface/ui.json` and
`export-origins/ui.json` were regenerated. The pin count is restated
from 786 to 783 in the file's two prose places and its count history.
3. **`test-typecheck-debt.json`.** The `report.test.ts` entry shrinks by
two signatures (TS18046 "'b' is of type 'unknown'" and TS2571), because
`blocks[]` is typed now. It was regenerated with
`gen:test-typecheck-debt`.
4. **A pending release note corrected on purpose.** See the next
section.
## Confirmation needed: a pending release note is corrected on purpose
(`Check Changeset` stays red)
- **The note.** `.changeset/19920-exported-types-not-unknown.md` is PR
#20260's pending entry for this card. It ended "`JoinedReportBlock` is
not changed by this change, and still resolves to `unknown`."
- **What this PR changes under it.** Item 1 makes the second half of
that sentence false in any release that carries both entries.
- **The rewrite.** The sentence now reads "`JoinedReportBlock` is not
changed by this change. It stops resolving to `unknown` in its own entry
(#19920)." That holds whichever release carries either entry. Nothing
else in the note moves.
- **What the gate says.** `node scripts/check-empty-changeset.mjs --base
origin/main` exits 1, naming exactly this file, in its DELIBERATE
CORRECTION class. Following the gate's prescription, the file is not
restored from the base, which would put the false sentence back.
- **What happens next.** It stays red until someone confirms the
correction here. If a release consumes that entry before this PR lands,
the merge keeps `main`'s deletion and the correction is moot.
The new entry is `.changeset/19920-exported-types-remainder.md`:
`@objectstack/spec` `minor`, `Clause-②: yes (narrowing)` (the diff
narrows published types and also adds three exported type names, per the
at-tier record 5863387565), a BREAKING banner naming every type that
narrows, FROM and TO per item (four bullets, remainder 5 included), a
banner and ADR-0087 reason saying that no EXISTING export changes, and
the ADR-0087 marker `not-required (no-migration-prescription)`.
## Measurements
- **TS7056**: 0 in every spec build of this round: origin/main
`5049a3cf`, the pre-remainder-5 head `406335af` and the head `777b5097`.
- **Remainder 5's cost** (`406335af` to `777b5097`): the `view.zod`
chunk grows 495,664 to 498,393 B (+2,729, the same for `.d.mts`); the
`page.zod` chunk moves -3 B; every other declaration file is
byte-identical; all 128 files +5,452 B.
- **The whole PR** (`5049a3cf` to `777b5097`):
| module | base | head | delta |
|:--|--:|--:|--:|
| `view.zod` chunk (`.d.ts`, and the same for `.d.mts`) | 500,191 |
498,393 | -1,798 |
| `page.zod` chunk (report and assembled views) | 306,012 | 311,003 |
+4,991 |
| `index.d.ts` | 3,277,798 | 3,283,480 | +5,682 |
| `system/index.d.ts` | 3,644,976 | 3,647,050 | +2,074 |
| `ui/index.d.ts` | 524,900 | 524,978 | +78 |
| all 128 `.d.ts` / `.d.mts` files | 30,888,091 | 30,910,145 | +22,054
(+0.071%) |
- Item 1's in-memory emit figures (+3,542 B of `report.zod`) are the
previous run's and were not re-measured; the chunk table above
supersedes them.
## Reverse verification (on disk, from committed state, via
`scripts/ablation-replace.mjs`)
All five legs re-run at `777b5097`, from committed state, through
`scripts/ablation-replace.mjs` in wrap mode; each pin file compiled
under `tsconfig.test.json`'s options:
| leg | reverted to | pin file | result |
|:--|:--|:--|:--|
| item 1 | `JoinedReportBlockSchema: z.ZodTypeAny` |
`joined-report-block-type.test.ts` | 7 x TS2578, 2 x TS18046 |
| item 2 | `config: z.ZodTypeAny` in `viewItemArmShape` |
`view-item-config-type.test.ts` | 8 x TS2578, 1 x TS18046 |
| item 3 | non-generic `flattenedViewOverlayFields` |
`view-overlay-viewkind-type.test.ts` | 11 x TS2578 |
| item 4 | the list overlay's `type` keeping the list default |
`view-overlay-viewkind-type.test.ts` | 1 x TS2322 |
| remainder 5 | the cast of the shape to a record of `z.ZodTypeAny` |
`view-overlay-viewkind-type.test.ts` | 6 x TS2578, 4 x TS2322 |
Every leg: the tool reports the mutation landed and the restore proven
(blob after restore equals the HEAD blob, `git diff HEAD` empty), and a
second check re-reads `git hash-object`. Control, no mutation: the three
pin files compile with 0 diagnostics; `git status --porcelain` empty.
## Tests and gates, at `777b5097`
At `777b5097`: spec build exit 0 (TS7056 x0); spec typecheck exit 0
(check:test-typecheck OK, 53 files / 253 errors / 140 signatures); spec
check:generated exit 0; spec vitest local 560 files, 16,493 passed, 1
todo; spec test:repo 34 files, 620 passed; consumer typechecks exit 0
for lint, metadata, metadata-protocol and objectql after building their
12-package closure (rest NOT MEASURED locally, 26-package closure).
dispatch-gates derived 86: 83 exit 0, check-empty-changeset exit 1 (the
deliberate correction), 2 NOT MEASURED (check:dual-build-cjs-loads,
check:type-check-debt, exit 3); `--ran`: 86 derived, 84 run, 2
NOT-MEASURED, 0 UNRUN. Lint narrowed and proven: 7 changed `.ts` files,
0 errors, 0 warnings; the 5 other changed files are outside eslint's
configuration; no type-aware linting (`eslint.config.mjs`:327).
## Consumer census
- **This repo.** Outside `packages/spec`, the code that imports any
narrowed name is:
- `defineReport` in the two example report files above;
- `Report` in `qa/downstream-contract/src/pipeline.report.ts`;
- `ReportSchema` in one platform-objects test and one
downstream-contract test;
- `ViewMetadataSchema` in two metadata-protocol tests;
- `AssembledViewArtifactSchema` in objectql's `engine.ts` and one
objectql test (its own static type does not move).
- Nothing outside spec names `viewItemArmShape` or
`flattenedViewOverlayFields`, which are not exported. All consumer
typechecks above are green.
- **objectui at the pin `f8a9d0fb`: one break, by design, for the seat
to carry.**
`packages/types/src/__tests__/report-chart-query-spec-parity.test.ts`:725
is the inverted tripwire `true satisfies IsUnknown` of the spec's
`JoinedReportBlock`. Compiled with that file's own two type definitions
against this head's dist, it gives TS1360 ("Type 'true' does not satisfy
the expected type 'false'"); line 726 (`IsAny`) still holds.
- Its docblock says this failure is the instruction to re-run the triage
and burn the local interface down, together with the ledger entry at
`scripts/check-spec-symbol-derivation.mjs`:636.
- It reds objectui's own `type-check` (`tsc -p tsconfig.test.json`) on
its next spec bump. It does not red this repo's Console Pin Gate, which
builds objectui without `__tests__`.
- **objectui's other hits.** Five other objectui files reference
`ViewItemSchema` / `ViewMetadataSchema` in code; every other census hit
is a comment or objectui's own local `JoinedReportBlock` interface. From
reading them, not from compiling them: they read `.success` / `.error`
of a `safeParse`, or cast the schema `as unknown as` a local interface.
None reads a typed `config` off a parse result.
- **Remainder 5 at objectui's pin `f8a9d0fb`.** Six calls in four test
files parse a body with `ViewMetadataSchema`, and none reads `.data` off
the verdict, so the now-typed list-overlay `type` / `columns` reach no
objectui read (from reading, not compiling).
## What stays on #19920
A compiler-API census of the 2,337 non-generic exported aliases of
`packages/spec/src`, excluding tests, with a control that must read lit:
6 aliases resolve to `unknown` before and after this PR, and none
belongs to this family (`FlowValueSlot`, `AssignmentValue` and their
`Parsed`, value slots; `GetPublishedMetaItemResponse` and its `Parsed`,
opaque by ruling). At top-level-key level it counts 210 keys typed
`unknown` before remainder 5 and 202 after; the 8 that left are
remainder 5. Three sites of the family remain, outside this PR's
surface:
- `ApiError.code` (input): `ErrorCode` is cast to a one-argument
`z.ZodType`, whose input defaults to `unknown`, and `makeApiErrorSchema`
repeats the cast. `{ code: 42, message: 'x' }` compiles as `ApiError`
while `ApiErrorSchema` refuses it at `code`.
- `ViewFilterRule.operator` (input): a `z.preprocess`, whose input is
`unknown` (the cause `InlineAction` had). `{ field: 'status', operator:
42 }` compiles while the door refuses it.
- The list overlay's `options` bag: `listViewKindBlocks()` returns a
record of `z.ZodTypeAny`, so the bag is typed as a string-keyed record
of `unknown`. `options: { foo: 1, kanban: 42 }` compiles as
`ViewMetadata` while the door refuses it. The census does not scan
nested keys; a probe found this one.
## Acceptance notes
- **The pin count holds at 783** (`check:spec-parsed-alias`: 1,442 bare
`z.input` aliases, 783 pinned isomorphic, 659 paired).
- **objectui tripwire, carried by the seat.**
`packages/types/src/__tests__/report-chart-query-spec-parity.test.ts` at
objectui pin `f8a9d0fb` asserts that `JoinedReportBlock` is `unknown`
(line 725). It goes red at the next objectui spec-pin bump, and its
docblock says that failure is the instruction to re-run the triage and
burn down the local interface. Carrier: the next objectui spec-pin bump.
It cannot red this repo: the Console Pin Gate builds objectui without
its `__tests__`.
- **Fence held.** `FormViewSchema.layout` (#20221),
`ListViewShapeSchema.tabs` and the view container's body `name` (#20301)
are untouched. `origin/main` `5049a3cf` was merged once, at `1161545d`,
with no conflict; commits that landed on `main` later touch none of this
PR's files.
---
_Generated by [Claude
Code](https://claude.ai/code/session_01CiCTczDo7tGhafXjf61dUJ)_
---------
Co-authored-by: Claude <noreply@anthropic.com>
1 parent 2f122b6 commit 681868c
12 files changed
Lines changed: 482 additions & 20 deletions
File tree
- .changeset
- packages/spec
- api-surface
- export-origins
- src
- ui
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
18 | 18 | | |
19 | 19 | | |
20 | 20 | | |
21 | | - | |
| 21 | + | |
22 | 22 | | |
23 | 23 | | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
216 | 216 | | |
217 | 217 | | |
218 | 218 | | |
| 219 | + | |
219 | 220 | | |
220 | 221 | | |
221 | 222 | | |
| |||
420 | 421 | | |
421 | 422 | | |
422 | 423 | | |
| 424 | + | |
423 | 425 | | |
424 | 426 | | |
| 427 | + | |
425 | 428 | | |
426 | 429 | | |
427 | 430 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
212 | 212 | | |
213 | 213 | | |
214 | 214 | | |
| 215 | + | |
215 | 216 | | |
216 | 217 | | |
217 | 218 | | |
| |||
406 | 407 | | |
407 | 408 | | |
408 | 409 | | |
| 410 | + | |
409 | 411 | | |
410 | 412 | | |
| 413 | + | |
411 | 414 | | |
412 | 415 | | |
413 | 416 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
275 | 275 | | |
276 | 276 | | |
277 | 277 | | |
278 | | - | |
| 278 | + | |
279 | 279 | | |
280 | 280 | | |
281 | 281 | | |
| |||
1551 | 1551 | | |
1552 | 1552 | | |
1553 | 1553 | | |
1554 | | - | |
| 1554 | + | |
| 1555 | + | |
| 1556 | + | |
| 1557 | + | |
1555 | 1558 | | |
1556 | 1559 | | |
1557 | 1560 | | |
| |||
1566 | 1569 | | |
1567 | 1570 | | |
1568 | 1571 | | |
| 1572 | + | |
| 1573 | + | |
| 1574 | + | |
| 1575 | + | |
1569 | 1576 | | |
1570 | 1577 | | |
1571 | 1578 | | |
| |||
1584 | 1591 | | |
1585 | 1592 | | |
1586 | 1593 | | |
1587 | | - | |
1588 | | - | |
1589 | 1594 | | |
1590 | 1595 | | |
1591 | 1596 | | |
| |||
1658 | 1663 | | |
1659 | 1664 | | |
1660 | 1665 | | |
1661 | | - | |
| 1666 | + | |
1662 | 1667 | | |
1663 | 1668 | | |
1664 | 1669 | | |
| |||
2305 | 2310 | | |
2306 | 2311 | | |
2307 | 2312 | | |
2308 | | - | |
| 2313 | + | |
| 2314 | + | |
| 2315 | + | |
| 2316 | + | |
| 2317 | + | |
| 2318 | + | |
| 2319 | + | |
| 2320 | + | |
| 2321 | + | |
| 2322 | + | |
2309 | 2323 | | |
2310 | 2324 | | |
2311 | 2325 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
118 | 118 | | |
119 | 119 | | |
120 | 120 | | |
| 121 | + | |
| 122 | + | |
| 123 | + | |
| 124 | + | |
| 125 | + | |
| 126 | + | |
| 127 | + | |
121 | 128 | | |
122 | 129 | | |
123 | 130 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
203 | 203 | | |
204 | 204 | | |
205 | 205 | | |
| 206 | + | |
| 207 | + | |
| 208 | + | |
| 209 | + | |
| 210 | + | |
| 211 | + | |
| 212 | + | |
206 | 213 | | |
207 | | - | |
| 214 | + | |
208 | 215 | | |
209 | 216 | | |
210 | 217 | | |
| |||
543 | 550 | | |
544 | 551 | | |
545 | 552 | | |
| 553 | + | |
| 554 | + | |
| 555 | + | |
| 556 | + | |
| 557 | + | |
| 558 | + | |
| 559 | + | |
| 560 | + | |
| 561 | + | |
| 562 | + | |
546 | 563 | | |
| 564 | + | |
| 565 | + | |
547 | 566 | | |
548 | 567 | | |
549 | 568 | | |
| |||
0 commit comments