|
| 1 | +--- |
| 2 | +'@objectstack/spec': patch |
| 3 | +--- |
| 4 | + |
| 5 | +`AnchorBindingContext`'s boot half names the stack's capability DECLARATIONS, not the `sys_capability` rows the seeder has not written yet |
| 6 | + |
| 7 | +The docblock named two sources for `declaredCapabilities`: at boot 「the |
| 8 | +`sys_capability` rows carrying `managed_by: 'package'` provenance」, at authoring |
| 9 | +time the stack's own `capabilities` array. The boot half carried an ordering |
| 10 | +precondition the sentence never stated, and a caller following it literally |
| 11 | +lands on the defect the input exists to remove. |
| 12 | + |
| 13 | +`runBootstrap` (`@objectstack/plugin-security`) awaits `bindBaselineToEveryone` |
| 14 | +— the ADR-0090 D5 anchor binding, the boot call site that consults |
| 15 | +`describeHighPrivilegeBits` — BEFORE it calls `bootstrapDeclaredCapabilities`, |
| 16 | +the seeder that WRITES those `managed_by: 'package'` rows. The order is fixed by |
| 17 | +two other constraints stated at that call site: the binding must follow the |
| 18 | +seeding of the `everyone` anchor it binds to, and precede the audience-binding |
| 19 | +suggestion reconciliation. So on a first boot the table is EMPTY at exactly the |
| 20 | +moment the docblock said to read it, and this docblock's own 「omission refuses」 |
| 21 | +property turns that emptiness into a silent refusal of every declared token — |
| 22 | +the app's own `isDefault` set unbindable at the `everyone` anchor, which is the |
| 23 | +defect #17811 introduced the input to remove. |
| 24 | + |
| 25 | +The boot half now names the DECLARATIONS, read through the seeder's own two-step |
| 26 | +— the ObjectQL registry first, the metadata service as the fallback — which is |
| 27 | +what `readDeclaredCapabilityContext` (`@objectstack/plugin-security`, #18535) |
| 28 | +already implements, so the contract text and its one runtime consumer now |
| 29 | +corroborate each other instead of contradicting. The `sys_capability` rows stay |
| 30 | +a valid source, qualified: only once the seeder has written them, which is where |
| 31 | +an admin-surface or post-boot caller reads them. |
| 32 | + |
| 33 | +⛔ No behaviour changes. The diff is comment text: `git diff` against the branch |
| 34 | +point over `src/security/high-privilege.ts` changes **0** non-comment lines (the |
| 35 | +same predicate reads 33 on that file's own #17811 commit, which is the control |
| 36 | +proving it fires). No predicate, no type, no export, no accept set moves. |
| 37 | + |
| 38 | +**This is shipped, which is why it carries a changeset rather than |
| 39 | +`skip-changeset`.** `src/security/high-privilege.ts` is NOT shipped as source — |
| 40 | +`@objectstack/spec`'s published `files[]` takes `src/**/*.zod.ts`, and this file |
| 41 | +is not one (`npm pack --dry-run` lists 2021 files and excludes it, with the |
| 42 | +sibling `src/security/permission.zod.ts` present as the lit control). Its |
| 43 | +published reach is the emitted declarations, and they move: the new clause is |
| 44 | +present in `dist/security/index.d.ts` and `dist/security/index.d.mts`, both in |
| 45 | +that same shipped list, with the superseded spelling absent from every built |
| 46 | +declaration file and the docblock's unchanged neighbouring sentence present in |
| 47 | +the same two as the lit control. |
0 commit comments