Repository navigation
Commit 66d2757
feat(spec): the installed-package row declares its origin, a closed source (code / marketplace / authored), and the served writable verdict (#24010)
Fixes #23972
Clause-②: yes (narrowing)
## What this does
Every installed-package row says where it came from.
`InstalledPackageSchema` declares a required, closed `source: 'code' |
'marketplace' | 'authored'` (`InstalledPackageSourceSchema`), which is
the set ruling B on #23892 (`6216295104`) names for the Packages Source
column. The `GET /packages` and `GET /packages/:id` rows also declare
`writable`, the verdict they have served since #14375.
- The door that registers a package stamps `source` on the registry row.
`GET /packages` reads it off the record (`'source'` joins the response
projection). ⛔ It is never derived from `writable` or from a second
list.
- `writable` is declared on the SERVED row, the two branches of
`InstalledPackageAtEitherStageSchema`, and not on the record. The
registry never stores it, because it is recomputed per read by
`isWritablePackage`. The two keys are separate declarations, and neither
derives the other.
- `SchemaRegistry.installPackage(manifest, source, settings?, scope?)`
takes the origin as a required argument. A missing or unknown value
throws a `TypeError` before any check or mutation, so no row is
recorded. `ObjectQL.registerApp(body, scope?, source = 'code')` and the
`manifest` service's `register(artifact, { source })` accept `'code' |
'marketplace'` and refuse `'authored'`.
## Where each origin is decided (measured, this branch)
| path | file:line | value | pin |
| --- | --- | --- | --- |
| code / kernel: `ObjectQL.registerApp`, the `manifest` service default
| `packages/objectql/src/engine.ts:7877`, `:7922`;
`packages/objectql/src/plugin.ts:675`, `:742` | `code` |
`package-source-stamp.test.ts` › "a package registered by code, with no
source stated, records source code" |
| marketplace install (hot-register) |
`packages/cloud-connection/src/marketplace-install-local-plugin.ts:1559`
| `marketplace` | `marketplace-install-local-hot-loaded.test.ts` ›
"states marketplace on the install register and on the rehydrate after a
restart" |
| marketplace boot rehydrate from the ledger |
`marketplace-install-local-plugin.ts:783` | `marketplace` | same pin
(second boot over the same ledger) |
| multi-package marketplace artifact | `plugin.ts:742` (each body) |
`marketplace` | `package-source-stamp.test.ts` › "every package of a
multi-package marketplace artifact records source marketplace" |
| install-local's own Installed Apps UI bundle |
`marketplace-install-local-plugin.ts:677` | `code` (the plugin's code,
no source stated) | the marketplace pin's CONTROL leg |
| authored: `installPackage` in `@objectstack/metadata-protocol` (Studio
base, `duplicatePackage`, base creation) |
`packages/metadata-protocol/src/protocol.ts:31395` | `authored` |
`protocol-install-package-enable-on-install.test.ts` › "installs the row
with source authored, in both records" |
| authored: the `POST /packages` no-protocol fallback |
`packages/runtime/src/domains/packages.ts:1414` | `authored` |
`packages-install-manifest-id.test.ts` / `-version.test.ts` /
`http-dispatcher.test.ts` fallback limbs |
| authored: the `sys_packages` boot rehydrate |
`packages/services/service-package/src/index.ts:718` | `authored` |
`hydration.test.ts` › "rehydrates a sys_packages row as source authored"
|
| the record seam | `packages/objectql/src/registry.ts:5455` (refusal),
`:5588` (stamp) | the argument | `package-source-stamp.test.ts` ›
"refuses a call that states no source, or a value outside the closed
set, and records no row" |
| the read door | `packages/runtime/src/domains/packages.ts:273` | read
off the record | `packages-writable-verdict.test.ts` › "serves each
row's source as recorded…" and "the served body parses through its
declared contract…" |
Schema pins: `package-registry.test.ts` ›
`InstalledPackageSchema.source` (three origins accepted; `'cloud'`
refused at `source` with `invalid_value`; a row without `source`
refused). `package-api.test.ts` › "the served installed-package row
declares `writable`" (required boolean on both stages; kept on the
served parse; stripped by the record schemas). `objectql-engine.test.ts`
holds the contract's spelled union equal to `InstalledPackageSource`.
**Persistence.** No new storage surface. Both restart paths re-stamp
from facts they already hold. The `sys_packages` rehydrate stamps
`authored`, because that table holds only what `installPackage`
persisted. The install-local ledger rehydrate stamps `marketplace`,
because every ledger entry is a marketplace install. Code packages
re-register at every boot. Install-local does not write `sys_packages`,
so a marketplace row cannot come back through the authored path.
**`source` against `writable` (assumption 2).** Measured per path: code
⇒ `writable: false` (`engine.manifests` holds it), marketplace ⇒ `false`
(registered through `registerApp`), authored ⇒ `true`. Two divergences
were read from code. Neither is fixed here, and both are in the
acceptance notes: an authored install whose manifest says `scope:
'system' | 'cloud'`, and a `POST /packages?overwrite=true` over an id
that code registered. Both read `authored` with `writable: false`.
## Ablation (both rebuilt from source; each subject is resolved through
a relative import)
- Marketplace: `node scripts/ablation-replace.mjs` replaced
`register(manifest, { source: 'marketplace' })` with
`register(manifest)` (anchor 1 → 0, blob `1e6d446df04f` →
`546d2bbefdd7`). The marketplace pin went red with `expected [ [
'com.example.crm', undefined ] ] to deeply equal …`, 1 failed / 3
passed. On restore, the blob equals HEAD and `git diff HEAD` is empty.
The green run is on the same blob.
- Authored: the `sys_packages` rehydrate's `'authored'` was replaced
with `'code'` (blob `11e28de72ae1` → `caac9ee3e4f4`). Two hydration pins
went red. On restore, the blob equals HEAD and `git diff HEAD` is empty.
## Verification
- Full `pnpm test`, merge base `adce192`: spec 690 files / 20940 tests
green; objectql 437 files; metadata-protocol 245 files / 20612 tests
green; service-package 7 / 114 green; cloud-connection 46 / 556 green;
client 52 / 671 green; runtime 403 files. The first objectql and runtime
runs failed only on pins that encoded the old state: the two-argument
fallback call, "no source stamp", and "undeclared residue is exactly
`writable`". Those 11 tests were updated to read the declared keys, and
their files re-run green (8 runtime files / 371 tests; 3 objectql
files).
- After merging `origin/main` (`92fd343b`, which touches `packages/spec`
and `packages/core`): `pnpm --filter @objectstack/spec test` 689 / 690
files. The one red was ADR-0122's hand-kept isomorphism count (788 → 789
for the new alias), corrected in `410897be` and re-run green.
- `pnpm typecheck` green for spec, objectql, metadata-protocol, runtime,
service-package, cloud-connection and client, test layers included.
- `pnpm --filter @objectstack/spec check:generated`: all 14 artifacts
current after the merge of `origin/main` `92fd343b`, measured against a
dist that run built.
- Derived gates (`dispatch-gates --commands`) are run locally at the
final head. Readings are in the report on #23972.
## Acceptance notes
- **Out of the file surface the claim listed, and why:**
`packages/client/src/index.ts` docblocks said `source` and `writable`
"stay undeclared", which is false after this change, and
`return-type-precision.test.ts` assigns a record row to the served type,
which now needs `writable`.
`packages/spec/src/contracts/objectql-engine.ts` declares the registry
contract the runtime fallback calls.
`packages/spec/src/type-alias-convention.pin.test.ts` carries ADR-0122's
isomorphism pin for the new alias.
- **The contract spells the union.** Importing `InstalledPackageSource`
into `contracts/objectql-engine.ts` pulled `package-registry.zod` and
the manifest graph into the `objectstack-data` skill's reference
closure, and `gen:skill-refs` then wanted to rewrite
`skills/objectstack-data/references/_index.md`, which is a governed
surface outside this card. The contract spells `'code' | 'marketplace' |
'authored'` instead, and a type-level pin holds it equal to the
declaration.
- **API change (`@objectstack/objectql`, minor):** `installPackage`'s
second positional argument is now `source`. In-repo callers and fixtures
are updated, and the changeset carries FROM → TO.
- **Not addressed:** #23974's conversion gap at the same two seams
(`service-package` hydration, `protocol.installPackage`) is untouched.
This PR only stamps `source` there.
- **`source` / `writable` divergences** (read, not fixed): ① `POST
/packages` with `manifest.scope: 'system' | 'cloud'` installs an
authored row that serves `writable: false`. ② `POST
/packages?overwrite=true` over an id in `engine.manifests` replaces the
row with `source: 'authored'` while the boot map keeps it read-only.
- A hosted kernel outside this repository that registers control-plane
installs through the `manifest` service without `{ source: 'marketplace'
}` records them as `code`. Every in-repo producer is stamped.
- **Round 2 (`7c45b88c`), the direction is `(narrowing)`.**
`InstalledPackageSchema` requires `source`, the served-row union
requires `writable`, and `installPackage` takes `source` second. These
are registered as ADR-0087 semantic entries
`installed-package-row-source-required` and
`registry-install-package-source-argument`; neither is mechanically
convertible. `check:adr-0087-registration` is green. This line and line
2 were edited by the seat (`domain:spec` seat 2, session
`session_01LFqdRsuM5nkqoJdHd5ztVk`) after contract review `6222834057`.
Follow-up (objectui, filed by the seat after landing): the Packages
Source column reads `row.source` and drops the two-read join.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
https://claude.ai/code/session_01RGdjFAX2oq1VdGNT5WGdKN
---
_Generated by [Claude
Code](https://claude.ai/code/session_01RGdjFAX2oq1VdGNT5WGdKN)_
---------
Co-authored-by: Claude <noreply@anthropic.com>1 parent 2b27460 commit 66d2757
77 files changed
Lines changed: 807 additions & 241 deletions
File tree
- .changeset
- content/docs/references
- api
- kernel
- packages
- client/src
- cloud-connection/src
- metadata-protocol/src
- objectql/src
- runtime/src
- domains
- services/service-package/src
- spec
- api-surface
- authorable-surface
- declaration-map
- export-origins
- json-schema.manifest
- src
- api
- contracts
- kernel
- migrations/entries/semantic
Some content is hidden
Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
| 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 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
67 | 67 | | |
68 | 68 | | |
69 | 69 | | |
| 70 | + | |
70 | 71 | | |
71 | 72 | | |
72 | 73 | | |
| |||
166 | 167 | | |
167 | 168 | | |
168 | 169 | | |
169 | | - | |
| 170 | + | |
170 | 171 | | |
171 | 172 | | |
172 | 173 | | |
| |||
193 | 194 | | |
194 | 195 | | |
195 | 196 | | |
196 | | - | |
197 | | - | |
198 | 197 | | |
199 | 198 | | |
200 | 199 | | |
| 200 | + | |
201 | 201 | | |
202 | 202 | | |
203 | 203 | | |
| |||
209 | 209 | | |
210 | 210 | | |
211 | 211 | | |
| 212 | + | |
212 | 213 | | |
213 | 214 | | |
214 | 215 | | |
215 | | - | |
216 | | - | |
217 | 216 | | |
218 | 217 | | |
219 | 218 | | |
| 219 | + | |
220 | 220 | | |
221 | 221 | | |
222 | 222 | | |
| |||
228 | 228 | | |
229 | 229 | | |
230 | 230 | | |
| 231 | + | |
231 | 232 | | |
232 | 233 | | |
233 | 234 | | |
| |||
242 | 243 | | |
243 | 244 | | |
244 | 245 | | |
245 | | - | |
246 | | - | |
247 | 246 | | |
248 | 247 | | |
249 | 248 | | |
250 | 249 | | |
251 | 250 | | |
| 251 | + | |
252 | 252 | | |
253 | 253 | | |
254 | 254 | | |
| |||
260 | 260 | | |
261 | 261 | | |
262 | 262 | | |
| 263 | + | |
263 | 264 | | |
264 | 265 | | |
265 | 266 | | |
| |||
306 | 307 | | |
307 | 308 | | |
308 | 309 | | |
309 | | - | |
310 | | - | |
311 | 310 | | |
312 | 311 | | |
313 | 312 | | |
314 | 313 | | |
315 | 314 | | |
| 315 | + | |
316 | 316 | | |
317 | 317 | | |
318 | 318 | | |
| |||
324 | 324 | | |
325 | 325 | | |
326 | 326 | | |
| 327 | + | |
327 | 328 | | |
328 | 329 | | |
329 | 330 | | |
| |||
443 | 444 | | |
444 | 445 | | |
445 | 446 | | |
446 | | - | |
| 447 | + | |
447 | 448 | | |
448 | 449 | | |
449 | 450 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
383 | 383 | | |
384 | 384 | | |
385 | 385 | | |
386 | | - | |
| 386 | + | |
387 | 387 | | |
388 | 388 | | |
389 | 389 | | |
| |||
0 commit comments