Skip to content

Commit a83dbb6

Browse files
hotlongclaude
andauthored
fix(plugin-security, spec): name the ADR-0025 reading of manifest.permissions when the audience-binding reconciler cannot use it, and make both halves of the key point at each other (#18035)
Fixes #18031 Clause-②: yes `permissions` carries two incompatible readings and `SchemaRegistry.installPackage` records both in one slot. At the AUTHORING stage `ManifestSchema.permissions` is the ADR-0025 §3.2 capability grant a plugin requests — the legacy flat `string[]`, or the structured `{ services, hooks, network, fs }` block. At the ASSEMBLED stage the collection wins and the same key is the ADR-0090 `PermissionSet[]` (`AssembledPackageBodySchema`, ADR-0130 D4). A package declares one of them and the other has nowhere to go. ## What changed **1. The drop is loud (`@objectstack/plugin-security`).** `collectDeclaredSuggestions` source 2 wants the assembled reading. Handed the authoring one it returned an empty list and logged nothing: the structured arm is an object, so `Array.isArray(manifest.permissions)` was false and the value never entered the loop; every member of the legacy arm is a bare string, so `consider`'s `typeof ps !== 'object'` line dropped all of them. No `sys_audience_binding_suggestion` row, no admin prompt, no log — the "absence must be loud" rule in AGENTS.md → Route & surface ownership §3. It now warns, naming which arm it found, how many members were dropped, what is lost if the author meant permission sets (nobody is ever prompted to bind the set, and the deployment goes on looking healthy), and where the sets belong: the package's own `defineStack({ permissions: [ … ] })`. - `warn`, not `error`, deliberately: nothing here claims to have persisted anything, so this is a functional degradation — a prompt that is not offered. Same reading, one step weaker, as the write-refusal report beside it, and the same sink (`SuggestionDeps['logger']`, which declares no `error`; adding one would enrol the published type into `check:optional-error-sink`'s population, a contract call above this repair). - Once per engine per package+arm, through a `WeakMap` keyed on the engine. The pass runs at boot, after every package-door `permission` publish **and on every list call**, while a manifest's shape is fixed for as long as that package is installed — an undeduplicated line would repeat on every console page load and be skimmed past, which is the same silence with extra steps. Keyed on the engine rather than a module `Set` so a process hosting several tenant kernels reports once per kernel. - A partially readable array still registers its readable sets and still names the dropped members. **2. The two halves of the key name each other (`@objectstack/spec`, declaration text only).** `ManifestSchema.permissions` says it describes the AUTHORING stage and names the assembled counterpart; the stack `permissions` collection names the manifest-stage grant; `InstalledPackageSchema.manifest` says it is a STAGE rather than "whatever was stored", pointing at `AssembledInstalledPackageSchema` / `InstalledPackageAtEitherStageSchema` for the stage a `defineStack()` host installs. No key, arm, export or accept set moved. ## Scope item 1 of the card was NOT done, and the evidence says it should not be The card suggested making `InstalledPackageSchema.manifest` "tell the truth (or declare itself a superset)", and flagged that `ManifestSchema` "has no `objects` / `datasources` keys". Two corrections, both measured on `origin/main` at `1e20f816e`: 1. **`ManifestSchema` declares both keys.** `objects` and `datasources` are `z.array(z.string()).optional()` — glob patterns. So the mismatch is of TYPE, not of presence, and it is bigger than the card says: `ManifestSchema` is `strictObject`, so a real assembled record is refused twice over — `invalid_type` on those two keys and `unrecognized_keys` on `apps` / `objectExtensions` / the collections. 2. **The work is already landed, under a maintainer ruling that rejects the suggested road by name.** #14242 recorded three roads and the maintainer took **B** on 2026-09-02 — «declare the assembled stage rather than widen the authoring one» — quoted at `AssembledPackageBodySchema` in `packages/spec/src/stack.zod.ts`. Road **C** (widen a manifest key into a union of both spellings) was REJECTED by name: a union at the key makes neither stage checkable, the tolerate-at-the-consumer shape Prime Directive #12 refuses. The assembled stage therefore already has `AssembledInstalledPackageSchema`, and the read doors already serve `InstalledPackageAtEitherStageSchema`, a union of two whole closed stages (`packages/spec/src/api/package-api.zod.ts`). ⇒ Widening `InstalledPackageSchema.manifest` would reverse a recorded decision — Prime Directive #13 territory, needing an ADR, not a changeset. What was genuinely missing is the one thing this PR adds instead: a reader standing at `package-registry.zod.ts` had no pointer to any of it. The same goes for scope item 3: the assembled side already carries a stage table naming `permissions` beside `objects` and `datasources`, so the missing half was the BACK-pointers from `ManifestSchema.permissions` and from the stack collection, which is what landed. ## Verification ⚠️ **Declared narrowing — verification ran UNLOCKED.** `scripts/pm/os-verify-lock.sh` could not take the shared verify lock on this host: no usable `flock`. The shared verify lock is declared Linux-only (`flock` is util-linux, and a stock macOS does not ship it), so every command below was run directly, without the lock — a declared narrowing, not a silent one. No serialization guarantee held for these runs, nor for any sibling agent in this container while they ran. Named gates, each read from its own verdict line, not from a bare exit code: | command | verdict | |---|---| | `pnpm --filter @objectstack/spec build` | exit 0 | | `pnpm --filter @objectstack/spec test` | 476 files / 13563 tests passed | | `pnpm --filter @objectstack/spec typecheck` | exit 0 — includes `check:test-typecheck` (54 files / 259 errors / 144 pinned signatures held, unchanged) | | `pnpm --filter @objectstack/spec check:generated` | 15 artifacts; `check:docs` was the only stale one, regenerated by `--fix` (`gen:docs`), re-run clean. `check:migration-registry`, `check:upgrade-guide`, `check:spec-changes`, `check:authorable-surface`, `check:api-surface`, `check:liveness` all green with no regeneration owed | | `pnpm --filter @objectstack/plugin-security build` | exit 0 | | `pnpm --filter @objectstack/plugin-security test` | 111 files / 2154 tests passed | | `pnpm --filter @objectstack/plugin-security typecheck` | exit 0 — includes `check:test-typecheck` (0 files / 0 errors) | | `pnpm check:nul-bytes` | OK — 8604 text files, no raw control bytes | | `pnpm check:pm-widening-tells` | self-test 269 cases pass | | `pnpm check:durability-log-level` | 35 durability-critical seams all loud; 68 read seams, none inventing an answer | | `pnpm check:optional-error-sink` | every sink declaring an optional `error` guarantees a `warn` | | `pnpm check:stack-collection-maps` | 8 enumerations reconciled against 31 declared collections | | `pnpm check:startup-registry-verdict` | 43 seams, none recording a verdict the boot can contradict | | `node scripts/check-empty-changeset.mjs --base origin/main` | exit 0 | | `node scripts/check-adr-0087-registration.mjs --base origin/main` | exit 0 — no declared-breaking changeset | | `node scripts/check-changeset-no-major.mjs --base origin/main` | exit 0 — no `major`; the level axis is PR-scoped and has no input on a local run | Repo-wide sweeps (`pnpm lint` first among them) are CI's run, not this seat's; `node scripts/pm/dispatch-gates.mjs --commands` derives 112 commands from this change set and the farm owns the rest. ### Ablation — the new guard can fail Run from the committed state, mutation proved on disk, restore proved by hash. 1. `HEAD` blob for `suggested-audience-bindings.ts` = `2e6a770cd56f678cabd3fee3876d370631c32610`; marker `reportDroppedManifestPermissions(ql, logger, dropped);` present **1×** in source. 2. Mutation deleted that one call. Marker count in source **0** — the mutation landed; `perl -0pi` exit status was not read as evidence. 3. Rebuilt `@objectstack/plugin-security`, then `node scripts/ablation-dist-preflight.mjs @objectstack/plugin-security '…' --absent` → `✓ dist/: marker absent from all 4 built files`. (The suite imports the subject by relative path, so its resolution is source, not `dist` — the dist leg is run anyway rather than argued away.) 4. **Predicted direction: red. Observed: red.** `4 failed | 29 passed (33)` — the four warn-asserting cases. The three that assert *no* noise (readable shape, no logger, steady state) stayed green, which is what distinguishes a discriminating guard from one that fires on everything. 5. Restore leg `git checkout HEAD -- …` (never a bare `git checkout --`), then: marker back to 1, `git status --porcelain` empty across the WHOLE tree, `git hash-object` = the HEAD blob above, byte-identical. `dist/` rebuilt from the restored source and the preflight re-run in its positive direction — `✓ marker present in 2 built files`, so nothing of the ablation survives in the artifact. An incidental reading from the mutation leg: with the call gone, `tsc` refuses the DTS build with `TS6133: 'logger' is declared but its value is never read` — the guard is load-bearing for the type check too. ## Clause ②, both limbs stated separately - **PATH limb HITS** — the diff moves `packages/spec/src/**`. `needs:contract-review` is on both carriers (this PR and the card) and the card waits outside the queue until the in-seat review clears it. - **CONTENT limb does not hit**, and the `yes` above is the conservative direction rather than a claim that it does. Nothing relaxes an accept set: `ManifestSchema` stays `strictObject`, both arms of `ManifestPermissionsSchema` are untouched, `InstalledPackageSchema.manifest` stays `ManifestSchema`. Nothing widens a published surface: `collectDeclaredSuggestions` gains an optional third parameter but is module-exported only — it is not re-exported from `plugin-security/src/index.ts`, so it is not on the package's published API. The spec half is `describe` / TSDoc text. - The level rule is honoured on the package that actually gained something: `@objectstack/plugin-security` is graded `minor` for a new operator-visible diagnostic that did not exist; `@objectstack/spec` is `patch` for declaration text. ## Acceptance notes - **Filed as #18034** — `AppPlugin`'s `SECURITY_FIELDS` loop (`packages/runtime/src/app-plugin.ts`) has the identical silent drop at both arms, on the same key, and is the half that runs at every boot for every stack. Out of scope here: a different package, a different verification surface, and its remedy needs the other four fields in that loop measured first. - **Noted, not filed** — `packages/spec/liveness/manifest.json` grades `permissions` `live` on the strength of this very reader, with the note "it reads the LEGACY arm". It *iterates* that arm and reads no value out of it, which the tests added here now pin. #11333 and #13458 already own that question and its retirement route, so the measurement went on #11333 as evidence rather than into a duplicate card; `liveness/manifest.json` is deliberately untouched by this PR, because moving a liveness `status` is the spec seat's verdict, not a rider on a reader-side repair. Carrier: #11333. - No governed surface is touched (`docs/adr/**`, `.claude/**`, `skills/**`, `AGENTS.md`, `CLAUDE.md` — none in the file list), so this is an ordinary queue candidate once the contract review clears. --- _Generated by [Claude Code](https://claude.ai/code/session_680c1c4e-4867-4565-b594-b5d2662e3e65)_ --------- Co-authored-by: Claude <noreply@anthropic.com>
1 parent 6d64785 commit a83dbb6

11 files changed

Lines changed: 378 additions & 33 deletions

File tree

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
---
2+
"@objectstack/plugin-security": minor
3+
"@objectstack/spec": patch
4+
---
5+
6+
A package whose `manifest.permissions` carries the ADR-0025 capability grant is now NAMED when the audience-binding reconciler skips it, instead of vanishing; and both halves of the `permissions` key now point at each other in the spec (#18031).
7+
8+
`permissions` has two incompatible readings and the package registry stores both in the same slot. At the AUTHORING stage `ManifestSchema.permissions` is the capability grant a plugin requests — the legacy flat `string[]`, or the structured `{ services, hooks, network, fs }` block (ADR-0025 §3.2). At the ASSEMBLED stage the collection wins and the same key is the ADR-0090 `PermissionSet[]` collection (`AssembledPackageBodySchema`, ADR-0130 D4). `SchemaRegistry.installPackage` records whichever stage its caller handed it.
9+
10+
- **`collectDeclaredSuggestions` reports the reading it cannot use.** It wants the assembled one. Handed the authoring one it returned an empty list and logged nothing: the structured arm is an object, so `Array.isArray(manifest.permissions)` was false and the value never entered the loop; every member of the legacy arm is a bare string, so `consider`'s `typeof ps !== 'object'` line dropped all of them. A package declaring the other reading produced no `sys_audience_binding_suggestion` row, no prompt and no log. It now warns once per engine per package and arm, naming which arm it found, what is lost if the author meant permission sets (no admin is ever prompted to bind the set, and the deployment goes on looking healthy), and where the sets belong — the package's own `defineStack({ permissions: [ … ] })`, which is what the assembled body carries.
11+
- **`warn`, not `error`, and deliberately.** Nothing here claims to have persisted anything, so this is a functional degradation — a prompt that is not offered. Same reasoning, one step weaker, as the write-refusal report beside it, and the same sink (`SuggestionDeps['logger']`, which declares no `error`).
12+
- **Reported once per engine per package+arm.** The pass runs at boot, after every package-door `permission` publish and on every list call, while a manifest's shape is fixed for as long as that package is installed; an undeduplicated line would repeat on every console page load and be skimmed past.
13+
- **The spec half is declaration text only — no key, export, arm or accept-set moved.** `ManifestSchema.permissions` now says it describes the AUTHORING stage and names the assembled-stage counterpart; the stack collection `permissions` names the manifest-stage grant; and `InstalledPackageSchema.manifest` says it is the authoring STAGE rather than "whatever was stored", pointing at `AssembledInstalledPackageSchema` / `InstalledPackageAtEitherStageSchema` for the stage a `defineStack()` host installs.
14+
-**The union at the key was NOT widened, and must not be.** Widening a manifest key into a union of both stages is road C of #14242, rejected by name by the maintainer on 2026-09-02 in favour of road B — declare the assembled stage rather than widen the authoring one — because a union at the key makes neither stage checkable (Prime Directive #12). That ruling is why the fix here is a report and a cross-reference rather than a schema change.

content/docs/references/api/package-api.mdx

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ Installed package row whose manifest is the assembled package body
7272
| **scope** | `Enum<'cloud' \| 'system' \| 'project'>` | optional (default: `"project"`) | Deployment scope: cloud \| system \| project |
7373
| **name** | `string` || Human-readable package name |
7474
| **description** | `string` | optional | Package description |
75-
| **permissions** | `{ name: string; label?: string; description?: string; packageId?: string; … }[]` | optional | Permission Sets |
75+
| **permissions** | `{ name: string; label?: string; description?: string; packageId?: string; … }[]` | optional | Permission Sets — the ADR-0090 collection half of `permissions`; at the manifest/authoring stage the same key is the ADR-0025 capability grant instead (`ManifestSchema.permissions`) |
7676
| **objects** | `{ name: string; label?: string; pluralLabel?: string; description?: string; … }[]` | optional | Business Objects definition (owned by this package) |
7777
| **datasources** | `{ name: string; label?: string; driver: string; config: Record<string, any>; … }[]` | optional | External Data Connections |
7878
| **dependencies** | `Record<string, string>` | optional | Package dependencies |
@@ -177,7 +177,7 @@ Installed package with runtime lifecycle state
177177

178178
| Property | Type | Required | Description |
179179
| :--- | :--- | :--- | :--- |
180-
| **manifest** | `{ id: string; namespace?: string; defaultDatasource?: string; version: string; … }` || Full package manifest |
180+
| **manifest** | `{ id: string; namespace?: string; defaultDatasource?: string; version: string; … }` || Package manifest at the AUTHORING stage; a row installed by a `defineStack()` host carries the assembled body instead — see `AssembledInstalledPackageSchema` / `InstalledPackageAtEitherStageSchema` |
181181
| **status** | `Enum<'installed' \| 'disabled' \| 'installing' \| 'upgrading' \| 'uninstalling' \| 'error'>` | optional (default: `"installed"`) | Package state: installed, disabled, installing, upgrading, uninstalling, or error |
182182
| **enabled** | `boolean` | optional (default: `true`) | Whether the package is currently enabled |
183183
| **installedAt** | `string` | optional | Installation timestamp |
@@ -228,7 +228,7 @@ Installed package with runtime lifecycle state
228228

229229
| Property | Type | Required | Description |
230230
| :--- | :--- | :--- | :--- |
231-
| **manifest** | `{ id: string; namespace?: string; defaultDatasource?: string; version: string; … }` || Full package manifest |
231+
| **manifest** | `{ id: string; namespace?: string; defaultDatasource?: string; version: string; … }` || Package manifest at the AUTHORING stage; a row installed by a `defineStack()` host carries the assembled body instead — see `AssembledInstalledPackageSchema` / `InstalledPackageAtEitherStageSchema` |
232232
| **status** | `Enum<'installed' \| 'disabled' \| 'installing' \| 'upgrading' \| 'uninstalling' \| 'error'>` | optional (default: `"installed"`) | Package state: installed, disabled, installing, upgrading, uninstalling, or error |
233233
| **enabled** | `boolean` | optional (default: `true`) | Whether the package is currently enabled |
234234
| **installedAt** | `string` | optional | Installation timestamp |
@@ -253,7 +253,7 @@ Installed package with runtime lifecycle state
253253
| **scope** | `Enum<'cloud' \| 'system' \| 'project'>` | optional (default: `"project"`) | Deployment scope: cloud \| system \| project |
254254
| **name** | `string` || Human-readable package name |
255255
| **description** | `string` | optional | Package description |
256-
| **permissions** | `string[] \| { services?: string[]; hooks?: string[]; network?: string[]; fs?: string[] }` | optional | Required permissions: legacy string[] or structured plugin block (ADR-0025 §3.2) |
256+
| **permissions** | `string[] \| { services?: string[]; hooks?: string[]; network?: string[]; fs?: string[] }` | optional | Required permissions at the AUTHORING stage: legacy string[] or structured plugin block (ADR-0025 §3.2) — at the assembled stage the same key is the ADR-0090 `PermissionSet[]` collection instead (`AssembledPackageBodySchema`) |
257257
| **objects** | `string[]` | optional | Glob patterns for ObjectQL schemas files |
258258
| **datasources** | `string[]` | optional | Glob patterns for Datasource definitions |
259259
| **dependencies** | `Record<string, string>` | optional | Package dependencies |
@@ -316,7 +316,7 @@ Installed package row whose manifest is the assembled package body
316316
| **scope** | `Enum<'cloud' \| 'system' \| 'project'>` | optional (default: `"project"`) | Deployment scope: cloud \| system \| project |
317317
| **name** | `string` || Human-readable package name |
318318
| **description** | `string` | optional | Package description |
319-
| **permissions** | `{ name: string; label?: string; description?: string; packageId?: string; … }[]` | optional | Permission Sets |
319+
| **permissions** | `{ name: string; label?: string; description?: string; packageId?: string; … }[]` | optional | Permission Sets — the ADR-0090 collection half of `permissions`; at the manifest/authoring stage the same key is the ADR-0025 capability grant instead (`ManifestSchema.permissions`) |
320320
| **objects** | `{ name: string; label?: string; pluralLabel?: string; description?: string; … }[]` | optional | Business Objects definition (owned by this package) |
321321
| **datasources** | `{ name: string; label?: string; driver: string; config: Record<string, any>; … }[]` | optional | External Data Connections |
322322
| **dependencies** | `Record<string, string>` | optional | Package dependencies |
@@ -481,7 +481,7 @@ Install package request
481481
| **scope** | `Enum<'cloud' \| 'system' \| 'project'>` | optional (default: `"project"`) | Deployment scope: cloud \| system \| project |
482482
| **name** | `string` || Human-readable package name |
483483
| **description** | `string` | optional | Package description |
484-
| **permissions** | `string[] \| { services?: string[]; hooks?: string[]; network?: string[]; fs?: string[] }` | optional | Required permissions: legacy string[] or structured plugin block (ADR-0025 §3.2) |
484+
| **permissions** | `string[] \| { services?: string[]; hooks?: string[]; network?: string[]; fs?: string[] }` | optional | Required permissions at the AUTHORING stage: legacy string[] or structured plugin block (ADR-0025 §3.2) — at the assembled stage the same key is the ADR-0090 `PermissionSet[]` collection instead (`AssembledPackageBodySchema`) |
485485
| **objects** | `string[]` | optional | Glob patterns for ObjectQL schemas files |
486486
| **datasources** | `string[]` | optional | Glob patterns for Datasource definitions |
487487
| **dependencies** | `Record<string, string>` | optional | Package dependencies |
@@ -605,7 +605,7 @@ Upgrade package request
605605
| **scope** | `Enum<'cloud' \| 'system' \| 'project'>` | optional (default: `"project"`) | Deployment scope: cloud \| system \| project |
606606
| **name** | `string` || Human-readable package name |
607607
| **description** | `string` | optional | Package description |
608-
| **permissions** | `string[] \| { services?: string[]; hooks?: string[]; network?: string[]; fs?: string[] }` | optional | Required permissions: legacy string[] or structured plugin block (ADR-0025 §3.2) |
608+
| **permissions** | `string[] \| { services?: string[]; hooks?: string[]; network?: string[]; fs?: string[] }` | optional | Required permissions at the AUTHORING stage: legacy string[] or structured plugin block (ADR-0025 §3.2) — at the assembled stage the same key is the ADR-0090 `PermissionSet[]` collection instead (`AssembledPackageBodySchema`) |
609609
| **objects** | `string[]` | optional | Glob patterns for ObjectQL schemas files |
610610
| **datasources** | `string[]` | optional | Glob patterns for Datasource definitions |
611611
| **dependencies** | `Record<string, string>` | optional | Package dependencies |
@@ -691,7 +691,7 @@ Resolve dependencies request
691691
| **scope** | `Enum<'cloud' \| 'system' \| 'project'>` | optional (default: `"project"`) | Deployment scope: cloud \| system \| project |
692692
| **name** | `string` || Human-readable package name |
693693
| **description** | `string` | optional | Package description |
694-
| **permissions** | `string[] \| { services?: string[]; hooks?: string[]; network?: string[]; fs?: string[] }` | optional | Required permissions: legacy string[] or structured plugin block (ADR-0025 §3.2) |
694+
| **permissions** | `string[] \| { services?: string[]; hooks?: string[]; network?: string[]; fs?: string[] }` | optional | Required permissions at the AUTHORING stage: legacy string[] or structured plugin block (ADR-0025 §3.2) — at the assembled stage the same key is the ADR-0090 `PermissionSet[]` collection instead (`AssembledPackageBodySchema`) |
695695
| **objects** | `string[]` | optional | Glob patterns for ObjectQL schemas files |
696696
| **datasources** | `string[]` | optional | Glob patterns for Datasource definitions |
697697
| **dependencies** | `Record<string, string>` | optional | Package dependencies |

content/docs/references/api/protocol.mdx

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -782,7 +782,7 @@ Disable package response
782782

783783
| Property | Type | Required | Description |
784784
| :--- | :--- | :--- | :--- |
785-
| **manifest** | `{ id: string; namespace?: string; defaultDatasource?: string; version: string; … }` || Full package manifest |
785+
| **manifest** | `{ id: string; namespace?: string; defaultDatasource?: string; version: string; … }` || Package manifest at the AUTHORING stage; a row installed by a `defineStack()` host carries the assembled body instead — see `AssembledInstalledPackageSchema` / `InstalledPackageAtEitherStageSchema` |
786786
| **status** | `Enum<'installed' \| 'disabled' \| 'installing' \| 'upgrading' \| 'uninstalling' \| 'error'>` | optional (default: `"installed"`) | Package state: installed, disabled, installing, upgrading, uninstalling, or error |
787787
| **enabled** | `boolean` | optional (default: `true`) | Whether the package is currently enabled |
788788
| **installedAt** | `string` | optional | Installation timestamp |
@@ -826,7 +826,7 @@ Enable package response
826826

827827
| Property | Type | Required | Description |
828828
| :--- | :--- | :--- | :--- |
829-
| **manifest** | `{ id: string; namespace?: string; defaultDatasource?: string; version: string; … }` || Full package manifest |
829+
| **manifest** | `{ id: string; namespace?: string; defaultDatasource?: string; version: string; … }` || Package manifest at the AUTHORING stage; a row installed by a `defineStack()` host carries the assembled body instead — see `AssembledInstalledPackageSchema` / `InstalledPackageAtEitherStageSchema` |
830830
| **status** | `Enum<'installed' \| 'disabled' \| 'installing' \| 'upgrading' \| 'uninstalling' \| 'error'>` | optional (default: `"installed"`) | Package state: installed, disabled, installing, upgrading, uninstalling, or error |
831831
| **enabled** | `boolean` | optional (default: `true`) | Whether the package is currently enabled |
832832
| **installedAt** | `string` | optional | Installation timestamp |
@@ -1494,7 +1494,7 @@ Get package response
14941494

14951495
| Property | Type | Required | Description |
14961496
| :--- | :--- | :--- | :--- |
1497-
| **manifest** | `{ id: string; namespace?: string; defaultDatasource?: string; version: string; … }` || Full package manifest |
1497+
| **manifest** | `{ id: string; namespace?: string; defaultDatasource?: string; version: string; … }` || Package manifest at the AUTHORING stage; a row installed by a `defineStack()` host carries the assembled body instead — see `AssembledInstalledPackageSchema` / `InstalledPackageAtEitherStageSchema` |
14981498
| **status** | `Enum<'installed' \| 'disabled' \| 'installing' \| 'upgrading' \| 'uninstalling' \| 'error'>` | optional (default: `"installed"`) | Package state: installed, disabled, installing, upgrading, uninstalling, or error |
14991499
| **enabled** | `boolean` | optional (default: `true`) | Whether the package is currently enabled |
15001500
| **installedAt** | `string` | optional | Installation timestamp |
@@ -1891,7 +1891,7 @@ Install package request
18911891
| **scope** | `Enum<'cloud' \| 'system' \| 'project'>` | optional (default: `"project"`) | Deployment scope: cloud \| system \| project |
18921892
| **name** | `string` || Human-readable package name |
18931893
| **description** | `string` | optional | Package description |
1894-
| **permissions** | `string[] \| { services?: string[]; hooks?: string[]; network?: string[]; fs?: string[] }` | optional | Required permissions: legacy string[] or structured plugin block (ADR-0025 §3.2) |
1894+
| **permissions** | `string[] \| { services?: string[]; hooks?: string[]; network?: string[]; fs?: string[] }` | optional | Required permissions at the AUTHORING stage: legacy string[] or structured plugin block (ADR-0025 §3.2) — at the assembled stage the same key is the ADR-0090 `PermissionSet[]` collection instead (`AssembledPackageBodySchema`) |
18951895
| **objects** | `string[]` | optional | Glob patterns for ObjectQL schemas files |
18961896
| **datasources** | `string[]` | optional | Glob patterns for Datasource definitions |
18971897
| **dependencies** | `Record<string, string>` | optional | Package dependencies |
@@ -1928,7 +1928,7 @@ Install package response
19281928

19291929
| Property | Type | Required | Description |
19301930
| :--- | :--- | :--- | :--- |
1931-
| **manifest** | `{ id: string; namespace?: string; defaultDatasource?: string; version: string; … }` || Full package manifest |
1931+
| **manifest** | `{ id: string; namespace?: string; defaultDatasource?: string; version: string; … }` || Package manifest at the AUTHORING stage; a row installed by a `defineStack()` host carries the assembled body instead — see `AssembledInstalledPackageSchema` / `InstalledPackageAtEitherStageSchema` |
19321932
| **status** | `Enum<'installed' \| 'disabled' \| 'installing' \| 'upgrading' \| 'uninstalling' \| 'error'>` | optional (default: `"installed"`) | Package state: installed, disabled, installing, upgrading, uninstalling, or error |
19331933
| **enabled** | `boolean` | optional (default: `true`) | Whether the package is currently enabled |
19341934
| **installedAt** | `string` | optional | Installation timestamp |
@@ -2130,7 +2130,7 @@ Installed package with runtime lifecycle state
21302130

21312131
| Property | Type | Required | Description |
21322132
| :--- | :--- | :--- | :--- |
2133-
| **manifest** | `{ id: string; namespace?: string; defaultDatasource?: string; version: string; … }` || Full package manifest |
2133+
| **manifest** | `{ id: string; namespace?: string; defaultDatasource?: string; version: string; … }` || Package manifest at the AUTHORING stage; a row installed by a `defineStack()` host carries the assembled body instead — see `AssembledInstalledPackageSchema` / `InstalledPackageAtEitherStageSchema` |
21342134
| **status** | `Enum<'installed' \| 'disabled' \| 'installing' \| 'upgrading' \| 'uninstalling' \| 'error'>` | optional (default: `"installed"`) | Package state: installed, disabled, installing, upgrading, uninstalling, or error |
21352135
| **enabled** | `boolean` | optional (default: `true`) | Whether the package is currently enabled |
21362136
| **installedAt** | `string` | optional | Installation timestamp |

content/docs/references/kernel/manifest.mdx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ const result = ManifestSchema.parse(data);
3535
| **scope** | `Enum<'cloud' \| 'system' \| 'project'>` | optional (default: `"project"`) | Deployment scope: cloud \| system \| project |
3636
| **name** | `string` || Human-readable package name |
3737
| **description** | `string` | optional | Package description |
38-
| **permissions** | `string[] \| { services?: string[]; hooks?: string[]; network?: string[]; fs?: string[] }` | optional | Required permissions: legacy string[] or structured plugin block (ADR-0025 §3.2) |
38+
| **permissions** | `string[] \| { services?: string[]; hooks?: string[]; network?: string[]; fs?: string[] }` | optional | Required permissions at the AUTHORING stage: legacy string[] or structured plugin block (ADR-0025 §3.2) — at the assembled stage the same key is the ADR-0090 `PermissionSet[]` collection instead (`AssembledPackageBodySchema`) |
3939
| **objects** | `string[]` | optional | Glob patterns for ObjectQL schemas files |
4040
| **datasources** | `string[]` | optional | Glob patterns for Datasource definitions |
4141
| **dependencies** | `Record<string, string>` | optional | Package dependencies |

0 commit comments

Comments
 (0)