docs(spec): AnchorBindingContext's boot half names the stack's capability DECLARATIONS, not the not-yet-seeded sys_capability rows - #18767
Merged
os-bill merged 2 commits intoSep 17, 2026
Conversation
…lity DECLARATIONS, not the not-yet-seeded sys_capability rows The docblock named two sources for `declaredCapabilities`: at boot the `sys_capability` rows carrying `managed_by: 'package'` provenance, at authoring time the stack's own `capabilities` array. The boot half has an ordering precondition the sentence never stated. The ADR-0090 D5 anchor binding (`bindBaselineToEveryone`) runs BEFORE `bootstrapDeclaredCapabilities`, the seeder that writes those rows, so on a first boot the table is empty at exactly the moment the docblock said to read it — and this docblock's own "omission refuses" property then turns that emptiness into a silent refusal of every declared token, the defect #18535 removed, reproduced one layer in. The boot half now names the DECLARATIONS, read through the seeder's own two-step (the ObjectQL registry first, the metadata service as the fallback) — the same source the authoring-time half already named, and the read `readDeclaredCapabilityContext` in `@objectstack/plugin-security` already implements. The `sys_capability` rows stay a valid source, qualified: only once the seeder has written them. Comment text only. No predicate, type, export or behaviour changes. Claude-Session: https://claude.ai/code/session_01JbZnqu8bt6YqfJsr9vaFb3 Co-authored-by: Claude <noreply@anthropic.com>
…t boot-source clause The docblock's published reach is the emitted declarations, not the source: `src/security/high-privilege.ts` is not a `.zod.ts`, so `files[]` does not ship it, but `dist/security/index.d.ts` and `dist/security/index.d.mts` are shipped and carry the TSDoc — measured with `npm pack --dry-run`. Published content moves, so this is a `patch`, not `skip-changeset`. Claude-Session: https://claude.ai/code/session_01JbZnqu8bt6YqfJsr9vaFb3 Co-authored-by: Claude <noreply@anthropic.com>
Contributor
📓 Docs Drift Check
What this run could not see
Coarse fallback — 136 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): |
This was referenced Sep 17, 2026
os-bill
marked this pull request as ready for review
September 17, 2026 20:24
This was referenced Sep 17, 2026
os-bill
deleted the
claude/issue-18603-anchor-binding-capability-source
branch
September 17, 2026 20:52
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Clause-②: no
Fixes #18603
Comment text only, in one file: the
AnchorBindingContextdocblock inpackages/spec/src/security/high-privilege.ts. No predicate, type, export or accept set moves.What the sentence said, and why a literal follower is refused
The docblock named two sources for
declaredCapabilities: at boot 「thesys_capabilityrows carryingmanaged_by: 'package'provenance」, at authoring time the stack's owncapabilitiesarray. The boot half carried an ordering precondition the sentence never stated. The ADR-0090 D5 anchor binding runs BEFORE the seeder that writes those rows, so on a first boot the table is empty at exactly the moment the docblock said to read it — and this docblock's own 「omission refuses」 property then turns that emptiness into a silent refusal of every declared token: the app's ownisDefaultset unbindable at theeveryoneanchor, which is the defect #17811 introduced the input to remove, reproduced one layer in.The boot half now names the DECLARATIONS, read through the seeder's own two-step — the ObjectQL registry first, the metadata service as the fallback — which is exactly what
readDeclaredCapabilityContext(@objectstack/plugin-security, PR #18602) already implements, so the contract text and its one runtime consumer corroborate each other instead of contradicting. Thesys_capabilityrows stay a valid source, qualified: only once the seeder has written them.LIT — the ordering was READ, by symbol, on this branch's base
The card's line numbers were taken on PR #18602's head and were carried forward unverified. They were re-derived here by SYMBOL on
origin/main95b21b33be(this branch's merge base),packages/plugins/plugin-security/src/security-plugin.ts:const runBootstrap:3655await seedCatalogBuiltins(...):3866runBootstrap— reachesbootstrapBuiltinRolesat:3572(defined inseedCatalogBuiltins,:3570), which seeds theeveryoneanchorawait bindBaselineToEveryone(...):3888runBootstrap— the ADR-0090 D5 bind; defined at:3583, consultsdescribeHighPrivilegeBitsat:3595await reconcileAudienceBindingSuggestions(...):3905runBootstrapawait bootstrapDeclaredCapabilities(...):3927runBootstrap— the seeder that WRITES themanaged_by: 'package'rows:3888and:3927sit in one straight-linetrybody of one function with no branch between them, so the bind precedes the seeder. The card's conclusion holds. Three line attributions in the card's table are worth correcting for the next reader, and none of them moves the conclusion::3572isbootstrapBuiltinRoles's call site inside the helperseedCatalogBuiltins(:3570), not a line ofrunBootstrap;runBootstrapreaches it at:3866.:3639is a SECONDbindBaselineToEveryonecall, insideseedCatalogForOrganization(:3635) — the organization-creation hook, not the boot sweep. Only:3888isrunBootstrap's.:3742isreconcileAudienceBindingSuggestionsinside the publish-materializer callbackrunBootstrapregisters — a runtime publish path, not a boot step. The boot step is:3905.DARK — a reading that must be ZERO, with a control proving it fires
Predicate: take
git diff -U0overpackages/spec/src/security/high-privilege.ts, keep the+/-lines that are not the+++/---headers, and drop every one that is blank or begins with*,//or/*. What remains is CODE.git diff -U0 95b21b33be HEAD -- packages/spec/src/security/high-privilege.tsNON_COMMENT_CHANGED_LINES=0d5c91dd681(#17811), same predicate, same input shapeNON_COMMENT_CHANGED_LINES=33— it names the addedimport, theexport interface AnchorBindingContext, its member and the whole ofappDeclaredCapabilityNamesThe zero is a measurement, not an absence of input: the same instrument reads 33 on a real code change to the same file.
git diff --statfor this change is 17 insertions / 2 deletions, all of them comment.Changeset — measured, not assumed
skip-changesetwould be wrong: published content moves.packages/spec/src/security/high-privilege.tsis NOT shipped as source.@objectstack/spec'sfiles[]takessrc/**/*.zod.tsand this file is not one —npm pack --dry-run --jsonlists 2021 shipped paths and does not include it, with the siblingsrc/security/permission.zod.tspresent in the same listing as the lit control.pnpm --filter @objectstack/spec build, the new clause is present indist/security/index.d.tsanddist/security/index.d.mts— both in that same shipped listing — the superseded spelling is absent from every built declaration file (0 files), and the docblock's unchanged neighbouring sentence (「Never synthesize this from the set under test」) is present in the same two files as the lit control.Hence
.changeset/18603-anchor-binding-declared-capabilities.md,@objectstack/spec: patch.Verification, at
2387ad9a5cpnpm --filter @objectstack/spec build— green.pnpm --filter @objectstack/spec test— 486 test files, 14017 tests, all passed.pnpm --filter @objectstack/spec typecheck— green.pnpm --filter @objectstack/spec check:generated— all 15 generated artifacts up to date; nothing needed regenerating.pnpm build— 73/73 tasks successful.pnpm lint(eslint . --no-inline-config, the repo-wide population) — green, exit 0.node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack: all 75 run, all exit 0, reconciled with--ran(75 derived / 75 run / 0 NOT-MEASURED, derived from recorded exit codes). Three of them (check:doc-formula-expressions,check:dual-build-cjs-loads,check:lean-entry-closure) first answeredexit 3PREREQUISITE NOT MET on an unbuilt tree, which is not a finding; they were re-run green afterpnpm build.Acceptance notes
Nothing filable was found alongside this change. The three line-attribution corrections above are reported here rather than filed: they are a nuance in a card's evidence table, not a defect in the code, and the ordering they describe is correct.
Landing is the owning seat's — left as a draft, auto-merge not armed.
Generated by Claude Code