Repository navigation
Commit be7382d
Fixes #17536
Clause-②: yes
The four `packages` READ members of `@objectstack/client` —
`ObjectStackClient.packages.list` / `.get` and their
`ScopedEnvironmentClient` twins — returned `InstalledPackage`, the
AUTHORING manifest stage, while both read doors have been declared at
EITHER stage since PR #17517. A response the server is declared able to
send was one this SDK's own types said could not arrive.
`packages/spec` is the one contract between producers and consumers
(Prime Directive #12) and `packages/client` is a consumer of it, so the
consumer's declaration is what moves. All four now declare
`InstalledPackageAtEitherStage` from `@objectstack/spec/api`.
Direction ruled by triage at
[`5735293092`](#17536 (comment)),
taking ① widen the client. ⛔ Narrowing the read door was excluded by
rule, not by preference: AGENTS.md rule 13 makes reversing PR #17517's
landed decision a new ADR, which is `domain:spec`'s work and not this
card's. ⛔ Nothing under `packages/spec` is touched here.
## The semver level, and the reading behind it
⚠️ The dispatch carried a reserved exit: **measure the level honestly,
and if it needs `major`, stop and report rather than land.** It was
measured, both legs, on this branch.
| leg | command | exit | what it says |
|---|---|---|---|
| `major` on `@objectstack/client` | `node
scripts/check-changeset-no-major.mjs --base origin/main` | **1** | ⛔
REFUSED — "Every publishable package is in the Changesets `fixed`
(lockstep) group, so a single `major` promotes the ENTIRE monorepo…
During the launch window ship breaking changes as `minor` instead." |
| `minor` on `@objectstack/client` (what this PR carries) | same command
| **0** | accepted |
⇒ **This does not need a `major`; it needs a `minor` plus the two
carriers that stand in for the level during the launch window.**
`check-changeset-no-major.mjs`'s own header states the convention and
its end condition: *"During the launch window it is NOT the carrier… The
mandatory information carriers for breaking-ness in the meantime are the
BREAKING banner the author writes in the changeset body and the ADR-0087
migration-ledger disposition… THIS GUARD IS WHAT GETS DISARMED AT GA."*
The window is open on this tree: there is no `.changeset/pre.json`, so
the RC exemption is not in force and the guard is armed — which is what
the exit-1 leg above demonstrates rather than assumes.
⛔ The level was not lowered to quiet a gate, and the breaking-ness was
not dropped to reach a lower level. Both carriers are present and both
were driven:
- the changeset body carries a **BREAKING** banner;
- `node scripts/check-adr-0087-registration.mjs --base origin/main`
exits **0** and reports `[BREAKING] not-required
(no-migration-prescription)`. `type-surface-only` is deliberately NOT
claimed, and the changeset writes out why it is unavailable on the
merits: that category is for a published TYPE-surface NARROWING moving
off an erased type, and at the merge base all four members carried a
concrete annotation.
**Under strict semver this is breaking, and the changeset says so in
words.** What the launch-window convention decides is only which field
carries that fact.
## What a consumer pays, measured
The element is a union of two whole, CLOSED stages that differ in
exactly one key, `manifest`. Every other member of the row — `id`,
`name`, `version`, `status`, `enabled`, `installedAt`, … — is common to
both branches and reads exactly as before, so code that touches only
those needs no change. Code that reaches INTO `manifest` separates the
stages first: the authoring stage's `objects` are glob STRINGS, the
assembled stage's are object DEFINITIONS, and the compiler now says so
at the call site instead of letting a glob-shaped read compile against a
row carrying definitions.
In this repository the consumer cost is **zero sites outside
`packages/client` itself**. No other workspace package calls either read
member; the only in-tree mentions are `packages/client/README.md` (a
bare `await client.packages.list();` with no member read, type-checked
green by `check:skill-examples` against the rebuilt declarations) and
the pins in this PR.
**The three WRITE members did not move.** `install` / `enable` /
`disable` answer the row their own request contract produced —
`PackageInstallRequestSchema` declares `manifest: ManifestSchema` — and
PR #17517 moved the read doors alone. That asymmetry is a measurement,
not an oversight, and it is pinned.
## Tests — type-level, with a control that can fail
`packages/client/src/return-type-precision.test.ts` is the only place a
return-type move CAN be pinned: nothing about the runtime values
changed, so a runtime test is green either way.
- **direction 1** — all four read members now ADMIT an assembled-stage
row;
- **the control** — the same assignment against the unmoved
`packages.install` is a used `@ts-expect-error`. If
`AssembledInstalledPackage` were assignable to `InstalledPackage` after
all, that suppression would go unused (TS2578) and direction 1 would be
exposed as passing vacuously;
- **direction 2** — a `manifest` belonging to NEITHER stage is still
refused, so this line reddens if anyone ever "widens" these members to
`any`, `unknown` or an open shape.
**Ablation** (restore `packages/client/src/index.ts` to blob
`c12b554d20` — the blob it carried before `21e6b9887c`, a **fixed**
anchor rather than the moving `origin/main`, keep the test file, run
`tsc --noEmit -p tsconfig.test.json`): exit **2**, **ten** errors — the
five `toEqualTypeOf` pins naming the union (TS2344) and **five** TS2322:
the four direction-1 assignments plus the new #19324 gap pin. Zero
TS2578 — both controls stay USED in both states. The restore was
verified by blob identity against `HEAD` with `git diff HEAD` empty;
both `@ts-expect-error` controls stay USED in the ablated run, which is
why they are labelled GREEN IN BOTH STATES rather than offered as
evidence.
## Gates
Derived from the actual diff with `node scripts/pm/dispatch-gates.mjs
--commands --repo objectstack-ai/objectstack` on the merged head, every
exit code captured to disk before any pipe, and reconciled with `--ran`:
```
58 derived, 58 run, 0 NOT-MEASURED, 0 UNRUN — all 58 exit 0
pnpm --filter '@objectstack/client^...' build :: exit 0
pnpm --filter @objectstack/client typecheck :: exit 0 (tsc + check:test-typecheck, 0 errors)
pnpm --filter @objectstack/client test :: exit 0 (48 files / 566 tests)
pnpm lint :: exit 0 — the FULL unnarrowed repo union, at 4fe43c0
```
Two of the 58 first answered `PREREQUISITE NOT MET`
(`check:skill-examples`, `check:dual-build-cjs-loads`), which is NOT
MEASURED and not a pass: both read built output and the packages had no
`dist`. They were built and re-run, and both then exited 0 on the merits
— `check:skill-examples` type-checks 258 prose examples across three
surfaces, including the client SDK's 23 blocks, against the rebuilt
declarations.
`origin/main` was merged once (`e3b3cdd2df`) before this PR opened;
build state was refreshed and the whole derived set plus the lint union
were re-run on the merged head.
## Acceptance notes
⚠️ **One finding, in `packages/spec`, reported rather than filed or
fixed** — this lane does not touch that package and does not file cards.
Measured on this branch, and it bears on how much the union actually
buys a consumer:
`AssembledInstalledPackage`'s `manifest` resolves to an index-signature
type (`Record` of `string` to `unknown`) in the PUBLISHED TypeScript
type, not to the assembled body's declared shape. The cause is the cast
in `packages/spec/src/api/package-api.zod.ts`:
`AssembledPackageRecordBodySchema` is built on
`(AssembledPackageBodySchema as unknown as z.ZodObject(z.ZodRawShape))`,
whose `z.input` is an index signature. Driven with `tsc`:
`InstalledPackage` IS assignable to `AssembledInstalledPackage` (an
authoring manifest satisfies an index signature), so the assembled arm
absorbs the authoring arm at the type level, and a member read off the
assembled stage's `manifest` arrives as `unknown` rather than its
declared type. The runtime Zod parse is unaffected — the schema still
checks the assembled body member by member, exactly as its own docblock
says. This is the same failure family `check:exported-any` exists for
("the snapshot records that an export exists, never what it resolves
to"), reached by a different spelling. Dedupe words:
`AssembledPackageRecordBodySchema`, `ZodRawShape`, `package-api.zod`,
`assembled manifest type erosion`, `z.input index signature`.
noted, not filed: `@objectstack/client` re-exports neither
`InstalledPackage` nor `InstalledPackageAtEitherStage`, so a consumer
writing an explicit annotation reaches into `@objectstack/spec/api` for
it. That is unchanged by this PR — the SDK has never re-exported the
package row — and adding a re-export would be a new published export on
a package this card is only correcting. Carrier: none; no queued PR or
lane touches this surface.
noted, not filed: the stale comment triage measured on `packages.get`
(it claimed `GetInstalledPackageResponseSchema` is `data:
InstalledPackageSchema`) is corrected in this PR rather than filed, per
that ruling's explicit instruction. It is corrected in place with the
reading that falsified it, not deleted.
---
_Generated by [Claude
Code](https://claude.ai/code/session_01QCdUBjM47SxioST9z5Zwdf)_
---
_Generated by [Claude Code](https://claude.ai/code)_
---------
Co-authored-by: Claude <noreply@anthropic.com>
1 parent e56112c commit be7382d
3 files changed
Lines changed: 350 additions & 25 deletions
File tree
- .changeset
- packages/client/src
| 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 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
123 | 123 | | |
124 | 124 | | |
125 | 125 | | |
| 126 | + | |
| 127 | + | |
| 128 | + | |
| 129 | + | |
| 130 | + | |
| 131 | + | |
| 132 | + | |
| 133 | + | |
| 134 | + | |
| 135 | + | |
| 136 | + | |
| 137 | + | |
| 138 | + | |
| 139 | + | |
126 | 140 | | |
127 | 141 | | |
128 | 142 | | |
| |||
2453 | 2467 | | |
2454 | 2468 | | |
2455 | 2469 | | |
2456 | | - | |
2457 | | - | |
| 2470 | + | |
| 2471 | + | |
| 2472 | + | |
| 2473 | + | |
| 2474 | + | |
| 2475 | + | |
| 2476 | + | |
| 2477 | + | |
| 2478 | + | |
| 2479 | + | |
| 2480 | + | |
| 2481 | + | |
| 2482 | + | |
| 2483 | + | |
| 2484 | + | |
| 2485 | + | |
| 2486 | + | |
| 2487 | + | |
| 2488 | + | |
| 2489 | + | |
| 2490 | + | |
| 2491 | + | |
| 2492 | + | |
| 2493 | + | |
| 2494 | + | |
| 2495 | + | |
| 2496 | + | |
| 2497 | + | |
| 2498 | + | |
| 2499 | + | |
| 2500 | + | |
| 2501 | + | |
| 2502 | + | |
| 2503 | + | |
| 2504 | + | |
| 2505 | + | |
| 2506 | + | |
| 2507 | + | |
| 2508 | + | |
| 2509 | + | |
| 2510 | + | |
| 2511 | + | |
| 2512 | + | |
| 2513 | + | |
| 2514 | + | |
| 2515 | + | |
| 2516 | + | |
| 2517 | + | |
| 2518 | + | |
| 2519 | + | |
| 2520 | + | |
| 2521 | + | |
| 2522 | + | |
| 2523 | + | |
| 2524 | + | |
2458 | 2525 | | |
2459 | 2526 | | |
2460 | 2527 | | |
| |||
2463 | 2530 | | |
2464 | 2531 | | |
2465 | 2532 | | |
2466 | | - | |
| 2533 | + | |
2467 | 2534 | | |
2468 | 2535 | | |
2469 | 2536 | | |
| |||
2489 | 2556 | | |
2490 | 2557 | | |
2491 | 2558 | | |
2492 | | - | |
2493 | | - | |
2494 | | - | |
2495 | | - | |
2496 | | - | |
2497 | | - | |
| 2559 | + | |
| 2560 | + | |
| 2561 | + | |
| 2562 | + | |
| 2563 | + | |
| 2564 | + | |
| 2565 | + | |
| 2566 | + | |
| 2567 | + | |
| 2568 | + | |
| 2569 | + | |
| 2570 | + | |
| 2571 | + | |
| 2572 | + | |
| 2573 | + | |
2498 | 2574 | | |
2499 | 2575 | | |
2500 | 2576 | | |
2501 | 2577 | | |
2502 | 2578 | | |
2503 | | - | |
| 2579 | + | |
2504 | 2580 | | |
2505 | 2581 | | |
2506 | 2582 | | |
2507 | 2583 | | |
2508 | 2584 | | |
2509 | 2585 | | |
| 2586 | + | |
| 2587 | + | |
| 2588 | + | |
| 2589 | + | |
| 2590 | + | |
| 2591 | + | |
2510 | 2592 | | |
2511 | | - | |
| 2593 | + | |
2512 | 2594 | | |
2513 | 2595 | | |
2514 | | - | |
| 2596 | + | |
2515 | 2597 | | |
2516 | 2598 | | |
2517 | 2599 | | |
| |||
7896 | 7978 | | |
7897 | 7979 | | |
7898 | 7980 | | |
7899 | | - | |
| 7981 | + | |
| 7982 | + | |
| 7983 | + | |
| 7984 | + | |
| 7985 | + | |
| 7986 | + | |
| 7987 | + | |
| 7988 | + | |
| 7989 | + | |
| 7990 | + | |
| 7991 | + | |
7900 | 7992 | | |
7901 | | - | |
| 7993 | + | |
7902 | 7994 | | |
7903 | 7995 | | |
7904 | 7996 | | |
| |||
7926 | 8018 | | |
7927 | 8019 | | |
7928 | 8020 | | |
7929 | | - | |
| 8021 | + | |
7930 | 8022 | | |
7931 | 8023 | | |
7932 | | - | |
7933 | | - | |
| 8024 | + | |
| 8025 | + | |
7934 | 8026 | | |
7935 | 8027 | | |
7936 | 8028 | | |
| 8029 | + | |
| 8030 | + | |
| 8031 | + | |
| 8032 | + | |
| 8033 | + | |
| 8034 | + | |
| 8035 | + | |
7937 | 8036 | | |
7938 | 8037 | | |
7939 | 8038 | | |
7940 | 8039 | | |
7941 | | - | |
| 8040 | + | |
7942 | 8041 | | |
7943 | 8042 | | |
7944 | | - | |
| 8043 | + | |
7945 | 8044 | | |
7946 | 8045 | | |
7947 | 8046 | | |
| |||
0 commit comments