diff --git a/docs/qa/platform-checklist/areas/identity-auth.json b/docs/qa/platform-checklist/areas/identity-auth.json index 4d00eca34e..f6baec3c23 100644 --- a/docs/qa/platform-checklist/areas/identity-auth.json +++ b/docs/qa/platform-checklist/areas/identity-auth.json @@ -136,7 +136,7 @@ "source": [ "#3358 §6", "#3408", - "examples/app-showcase/src/security/seed-approval-demo.ts#PHONE_DEMO_USER (PHONE_DEMO_USER)", + "examples/app-showcase/src/security/demo-personas.ts#PHONE_DEMO_USER (PHONE_DEMO_USER — re-pointed #18104: seed-approval-demo.ts only IMPORTS this persona and provisions it; the constant, phone_number included, is declared in demo-personas.ts, the one registry the seed and the approval bootstrap share)", "packages/spec/src/system/auth-config.zod.ts#phoneNumber (phoneNumber plugin: unique phone_number + phone_number_verified columns)", "packages/spec/src/kernel/public-auth-features.ts#phoneNumber (phoneNumber gates sys_user.actions.create_user.params.phoneNumber — #2871)" ], @@ -355,7 +355,7 @@ "source": [ "packages/qa/dogfood/test/delegated-admin-invite.dogfood.test.ts (ADR-0105 D8 / #3697; the escalation chain the role cap blocks)", "packages/spec/src/identity/organization.zod.ts#InvitationSchema (InvitationSchema, InvitationStatus enum)", - "packages/rest/src/rest-route-ledger.ts#describeDelegableScope (GET /api/v1/security/my-delegable-scope — security.describeDelegableScope, ADR-0090 D12 / ADR-0105 D8, self-scoped read half of the delegated-admin gate)", + "packages/rest/src/rest-route-ledger.ts#REST_ROUTE_LEDGER (GET /api/v1/security/my-delegable-scope — security.describeDelegableScope, ADR-0090 D12 / ADR-0105 D8, self-scoped read half of the delegated-admin gate — re-pointed #18104: describeDelegableScope is a CLIENT METHOD name, carried in this file only inside a string value)", "packages/spec/src/contracts/security-service.ts#DelegableScope (DelegableScope: isTenantAdmin, scopes, placeableBusinessUnitIds, assignablePositions — no invitation-role field, which is why the scope read cannot be the invite picker's allowlist)", "packages/spec/src/kernel/public-auth-features.ts#sys_invitation (organization feature gates sys_invitation invite/cancel/resend actions)" ], @@ -477,7 +477,7 @@ "packages/spec/src/system/auth-config.zod.ts (admin plugin: endpoint list, sys_user role/banned/ban_reason/ban_expires, sys_session.impersonated_by)", "packages/plugins/plugin-auth/src/auth-route-ledger.ts#BETTER_AUTH_MOUNTED_SURFACE (BETTER_AUTH_MOUNTED_SURFACE admin/* rows: list-users, create-user, set-role, remove-user, revoke-user-session(s))", "packages/plugins/plugin-auth/src/admin-user-endpoints.ts#resolvePassword (create-user resolvePassword: explicit password wins over generatePassword — #3031/#3033; leaves sys_user + credential sys_account)", - "packages/plugins/plugin-security/src/security-plugin.ts#__referentialFieldClear (§A5 #3023 EXEMPTION: __referentialFieldClear owner_id-null cascade rides a server-derived context, the owner-anchor guard must not veto it) + security-plugin.test.ts '[#3023] … engine referential FK clear … is exempt'", + "packages/plugins/plugin-security/src/security-plugin.ts#SecurityPlugin (§A5 #3023 EXEMPTION: __referentialFieldClear owner_id-null cascade rides a server-derived context, the owner-anchor guard must not veto it — re-pointed #18104: __referentialFieldClear is a CONTEXT KEY this file only reads off opCtx.context, a member access; the guard that honours it is in the SecurityPlugin class this file declares) + security-plugin.test.ts '[#3023] … engine referential FK clear … is exempt'", "packages/spec/src/kernel/public-auth-features.ts#sys_user (admin flag gates the sys_user lifecycle actions; SCIM forces it on — ADR-0134)", "packages/qa/dogfood/test/admin-identity-audit-trail.dogfood.test.ts", "packages/plugins/plugin-auth/src/anonymous-session-refusal.ts#ANONYMOUS_SESSION_REFUSAL_STATUS (since #17881 an anonymous or revoked /get-session answers 401 with the ADR-0112 refusal envelope, code UNAUTHENTICATED derived from that status; a live session still answers 200 with { user, session }. Both legs are driven end to end in packages/plugins/plugin-auth/src/anonymous-session-refusal.test.ts, and the body-not-status discipline for a revoke is kept in packages/plugins/plugin-auth/src/session-of-record.test.ts)" @@ -574,7 +574,7 @@ ], "traps": ["wrong-persona", "shared-browser-tab"], "source": [ - "packages/plugins/plugin-auth/src/auth-route-ledger.ts#revokeOthers (GET list-sessions=auth.sessions.list, POST revoke-session=auth.sessions.revoke, revoke-other-sessions=auth.sessions.revokeOthers, revoke-sessions=auth.sessions.revokeAll)", + "packages/plugins/plugin-auth/src/auth-route-ledger.ts#AUTH_ROUTE_LEDGER (GET list-sessions=auth.sessions.list, POST revoke-session=auth.sessions.revoke, revoke-other-sessions=auth.sessions.revokeOthers, revoke-sessions=auth.sessions.revokeAll — re-pointed #18104: revokeOthers is a CLIENT METHOD name, carried in this file only inside a dotted string value)", "packages/platform-objects/src/identity/sys-session.object.ts#user_id (mine view filter user_id={current_user_id}; all_sessions admin view; revoked_at/revoke_reason fields ADR-0069 D4; revoke_session action recordIdParam:'token'; apiMethods ['get','list'] — writes 405 before 403, #1591/ADR-0092 D2)", "packages/platform-objects/src/apps/setup-nav.contributions.ts#nav_sessions (nav_sessions → Setup Sessions, objectName sys_session)" ], @@ -741,7 +741,7 @@ "traps": ["hydration-race", "stale-console-bundle"], "source": [ "objectui apps/console/src/pages/system/ProfilePage.tsx (updateUser name/image; useUpload avatar; PasswordCard changePassword vs setInitialPassword gated on hasLocalPassword; email immutable; data-testids profile-avatar-file/-upload-btn/-remove-btn)", - "packages/plugins/plugin-auth/src/auth-route-ledger.ts#updateUser (POST /api/v1/auth/update-user=auth.updateUser, POST /api/v1/auth/change-password=auth.changePassword, GET /api/v1/auth/get-session=auth.me)", + "packages/plugins/plugin-auth/src/auth-route-ledger.ts#AUTH_ROUTE_LEDGER (POST /api/v1/auth/update-user=auth.updateUser, POST /api/v1/auth/change-password=auth.changePassword, GET /api/v1/auth/get-session=auth.me — re-pointed #18104: updateUser is a CLIENT METHOD name, carried in this file only inside a dotted string value)", "packages/platform-objects/src/identity/sys-account.object.ts#previous_password_hashes (previous_password_hashes ring — ADR-0069 D1 reuse-prevention backs change-password)" ], "history": [ @@ -832,8 +832,8 @@ "packages/plugins/plugin-auth/src/auth-route-ledger.ts (organization family: update-member-role, remove-member, update, create-team, add-team-member, list-members/teams/invitations, get-active-member, get-full-organization)", "packages/spec/src/identity/membership-role.ts#BUILTIN_MEMBERSHIP_ROLES (BUILTIN_MEMBERSHIP_ROLES / BUILTIN_MEMBERSHIP_ROLE_OPTIONS — THE role vocabulary: owner/admin/delegated_admin/member, ADR-0108; 'nothing widens these at boot any more')", "docs/adr/0108-membership-grade-is-not-a-capability-channel.md (why the list is closed: a grade decides what you can REACH, never a bundle of what you may do)", - "packages/qa/dogfood/test/membership-role-vocabulary.dogfood.test.ts#PermissionSet (both enforced selects offer exactly the four; a declared position or PermissionSet name is refused at better-auth's role check — ROLE_NOT_FOUND — before any insert)", - "packages/platform-objects/src/identity/sys-member.object.ts#BUILTIN_MEMBERSHIP_ROLE_OPTIONS + sys-invitation.object.ts (role select options: [...BUILTIN_MEMBERSHIP_ROLE_OPTIONS])", + "packages/qa/dogfood/test/membership-role-vocabulary.dogfood.test.ts#CLOSED_VOCABULARY (both enforced selects offer exactly the four; a declared position or PermissionSet name is refused at better-auth's role check — ROLE_NOT_FOUND — before any insert — re-pointed #18104: PermissionSet survives in this file only inside a comment and an it(...) title; the four this item means are what CLOSED_VOCABULARY declares)", + "packages/platform-objects/src/identity/sys-member.object.ts#SysMember + sys-invitation.object.ts (role select options: [...BUILTIN_MEMBERSHIP_ROLE_OPTIONS] — re-pointed #18104: this file IMPORTS that constant from the spec, which the membership-role.ts citation two rows up already anchors; what sys-member.object.ts declares is the object carrying the select)", "packages/platform-objects/src/identity/sys-team-member.object.ts#team_id (add_team_member/remove_team_member actions → organization/add-team-member; unique team_id+user_id; requiresFeature organization)" ], "history": [ @@ -914,7 +914,7 @@ "packages/platform-objects/src/identity/sys-team-member.object.ts#team_id (add_team_member/remove_team_member → organization/add-team-member|remove-team-member; unique team_id+user_id)", "packages/platform-objects/src/identity/sys-business-unit.object.ts#parent_business_unit_id (canonical BU tree ADR-0057 D2; kind enum; parent_business_unit_id self-ref; org_chart tree view; managedBy 'platform' — writable over the data API)", "packages/platform-objects/src/identity/sys-business-unit-member.object.ts#function_in_business_unit (user↔BU placement: function_in_business_unit member/lead/deputy, is_primary)", - "docs/qa/platform-checklist/areas/access-security.json#access (access-security.scope-depth-asymmetry — the depth matrix this cross-references for the tree-widening geometry)", + "docs/qa/platform-checklist/areas/access-security.json#items (access-security.scope-depth-asymmetry — the depth matrix this cross-references for the tree-widening geometry — re-pointed #18104: access is not a key this JSON declares; a cross-area citation names the items block, and the item id stays in this parenthetical)", "examples/app-showcase/src/security/sharing-rules.ts#share_new_inquiries_with_field_ops (`share_new_inquiries_with_field_ops` — the shipped BU-consuming geometry: expands the bu_field_ops subtree onto showcase_inquiry)", "examples/app-showcase/src/data/seed/index.ts#sys_business_unit (the sys_business_unit tree is seeded with explicit ids; user↔unit membership — sys_business_unit_member — and position assignments are NOT seeded, they stay runtime admin actions)" ], @@ -1088,7 +1088,7 @@ "packages/types/src/env.ts#isMcpServerEnabled (isMcpServerEnabled — unset means TRUE; explicit false/0/off/no opts out)", "objectui apps/console/src/App.tsx (/oauth/consent → OAuthConsentPage) + apps/console/src/pages/auth/OAuthConsentPage.tsx", "packages/platform-objects/src/identity/sys-oauth-consent.object.ts#apiEnabled (row implies consent for listed scopes — consent_given removed; apiEnabled:false so verify via get-consents, not the data API)", - "packages/platform-objects/src/identity/sys-oauth-application.object.ts#OAuth + setup-nav.contributions.ts (nav_oauth_apps → Setup OAuth Applications)" + "packages/platform-objects/src/identity/sys-oauth-application.object.ts#SysOauthApplication + setup-nav.contributions.ts (nav_oauth_apps → Setup OAuth Applications — re-pointed #18104: the bare word OAuth is carried in this file only inside label and description strings)" ], "history": [ { "revision": 1, "date": "2026-08-08", "change": "new item: OAuth client registration (secret once) + authorization-code consent loop (approve mints tokens + consent record, deny mints none, recorded consent short-circuits), mine-view scoped; blocked(fixture) pending a configured oidcProvider flow (PENDING-GAPS §C)", "ref": "claude/platform-test-checklist-ocwugl" }, @@ -1161,7 +1161,7 @@ "traps": ["wrong-persona", "dispatcher-vs-hono-route", "hydration-race"], "source": [ "packages/platform-objects/src/identity/sys-account.object.ts#user_id (link_social type:'url' → /api/v1/auth/sign-in/social?provider=&callbackURL=; unlink_account → /api/v1/auth/unlink-account accountId=row id; mine view user_id={current_user_id} vs all_links; provider options; apiMethods ['get','list'])", - "packages/plugins/plugin-auth/src/auth-route-ledger.ts#linkSocial (POST link-social=auth.accounts.linkSocial, GET list-accounts=auth.accounts.list, POST unlink-account=auth.accounts.unlink)", + "packages/plugins/plugin-auth/src/auth-route-ledger.ts#AUTH_ROUTE_LEDGER (POST link-social=auth.accounts.linkSocial, GET list-accounts=auth.accounts.list, POST unlink-account=auth.accounts.unlink — re-pointed #18104: linkSocial is a CLIENT METHOD name, carried in this file only inside a dotted string value)", "packages/platform-objects/src/apps/setup-nav.contributions.ts#nav_accounts (nav_accounts → 'Identity Links', objectName sys_account)" ], "history": [ @@ -1684,7 +1684,7 @@ "objectui apps/console/src/components/SetupRoute.tsx (one URL, two surfaces — first-run wizard vs platform-admin deep link, objectui#2794) + setupEntry.ts (the latched verdict: fresh only from an unauthenticated probe)", "objectui apps/console/src/pages/auth/SetupPage.tsx (renders only at hasOwner:false; creates owner + names the auto-provisioned personal org) + (why both exits are FULL-PAGE navigations — objectui#4181) + handleSubmit (rename-not-create, refreshOrganizations poll, slug guard)", "packages/plugins/plugin-auth/src/auth-plugin.ts#dataEngine (bootstrap-status exempt from the auth wall) + (the route: hasOwner from dataEngine.count('sys_user'))", - "packages/plugins/plugin-auth/src/auth-route-ledger.ts#bootstrapStatus (GET /api/v1/auth/bootstrap-status = auth.bootstrapStatus, objectstack-mount)", + "packages/plugins/plugin-auth/src/auth-route-ledger.ts#AUTH_ROUTE_LEDGER (GET /api/v1/auth/bootstrap-status = auth.bootstrapStatus, objectstack-mount — re-pointed #18104: bootstrapStatus is a CLIENT METHOD name, carried in this file only inside a dotted string value)", "packages/plugins/plugin-auth/src/auth-manager.ts#isBootstrapCreation (the bypass's contract comment) + (the before-hook: isBootstrapCreation flips disableSignUp for this request — [#11767] fixed the inert probe) + (isBootstrapCreation: human rows, fail-closed on a full page)", "packages/plugins/plugin-auth/src/audience-posture.ts#isHumanUserRow (isHumanUserRow) + (decideAudienceAdmission isBootstrap arm) + (undeclared audience ⇒ invite_only, maintainer ruling 2026-08-24)", "packages/cli/src/commands/dev.ts,339 (seed-admin defaults ON — why a zero-user boot needs --no-seed-admin)" @@ -1863,7 +1863,7 @@ "source": [ "packages/plugins/plugin-auth/src/auth-manager.ts#requireEmailVerification (requireEmailVerification wiring — [#11739]: a self-registration-permitting posture FORCES it on; otherwise config passthrough) + (emailVerification block: sendOnSignUp/sendOnSignIn/autoSignInAfterVerification/expiresIn passthrough; sendVerificationEmail via template auth.verify_email, failures thrown into the log) + (getPublicConfig mirrors the forced flag)", "packages/plugins/plugin-auth/src/audience-posture.ts#entry (entry validation refuses the permitting-posture + explicit-false contradiction)", - "packages/plugins/plugin-auth/src/auth-route-ledger.ts#sendVerificationEmail (POST /api/v1/auth/send-verification-email = auth.sendVerificationEmail) + (GET /api/v1/auth/verify-email = auth.verifyEmail)", + "packages/plugins/plugin-auth/src/auth-route-ledger.ts#AUTH_ROUTE_LEDGER (POST /api/v1/auth/send-verification-email = auth.sendVerificationEmail) + (GET /api/v1/auth/verify-email = auth.verifyEmail) — re-pointed #18104: sendVerificationEmail is a CLIENT METHOD name, carried in this file only inside a dotted string value", "objectui apps/console/src/App.tsx (/verify-email + /verify-email-prompt routes)", "objectui apps/console/src/pages/auth/VerifyEmailPage.tsx (consumes ?token= via the POST variant — GET 302s, POST returns JSON so the SPA controls the post-verify UX)", "objectui apps/console/src/pages/auth/VerifyEmailPromptPage.tsx (shown after sign-up or an EMAIL_NOT_VERIFIED-blocked sign-in; resend via useAuth().sendVerificationEmail)", @@ -1954,7 +1954,7 @@ "objectui packages/app-shell/src/layout/CurrentOrganizationIndicator.tsx (objectui#5287: read-only name for exactly-one membership, gated on postureHasOrgWall — single posture renders nothing by design; no click target)", "objectui packages/app-shell/src/hooks/useTenancyPosture.ts (postureHasOrgWall restated locally for bundle size, spec-parity test-locked)", "objectui packages/app-shell/src/providers/MetadataProvider.tsx (objectui#4486: an org change drops the whole metadata cache — one organization's metadata never survives into another organization's reads; the reloading switch paths and the SPA-internal path both covered)", - "packages/plugins/plugin-auth/src/auth-route-ledger.ts#setActive (POST /api/v1/auth/organization/set-active = organizations.setActive, requires organization)", + "packages/plugins/plugin-auth/src/auth-route-ledger.ts#AUTH_ROUTE_LEDGER (POST /api/v1/auth/organization/set-active = organizations.setActive, requires organization — re-pointed #18104: setActive is a CLIENT METHOD name, carried in this file only inside a dotted string value)", "packages/plugins/plugin-auth/src/auth-manager.ts#multiOrgEnabled (multiOrgEnabled = postureEnforcesWall(effectiveTenancyPosture()) — the SAME call the org-create gate makes, #5233/#5261) + area (features advertised)", "packages/types/src/env.ts#resolveTenancyPosture (resolveTenancyPosture: OS_TENANCY_POSTURE, invalid value refuses boot; unset falls back to `single` unless legacy multi-org env)" ], diff --git a/scripts/check-platform-checklist.mjs b/scripts/check-platform-checklist.mjs index b52b00f365..4ae200e4e2 100644 --- a/scripts/check-platform-checklist.mjs +++ b/scripts/check-platform-checklist.mjs @@ -1867,11 +1867,12 @@ const CORPUS = defineCorpus({ // string-substring the symbol survives only INSIDE a longer string token: // `saveItem` in `client: 'meta.saveItem'`, `:shareId` in a // route pattern, a name inside an `it(...)` title or a -// `.describe(...)` sentence. 21 rows, the largest class. +// `.describe(...)` sentence. 12 rows, still the largest +// class. // import-only the cited file IMPORTS the symbol; the declaration is in -// another file. 8 rows. +// another file. 6 rows. // member-access the symbol survives only as `x.symbol` on some other -// object — `manifest.objectExtensions`. 3 rows. +// object — `manifest.objectExtensions`. 2 rows. // json-value-not-key the `.json` target carries the symbol as a VALUE; the // shared rule reads JSON KEYS. 3 rows. // regex-literal the symbol survives only inside a regex literal. 1 row. @@ -1881,8 +1882,22 @@ const CORPUS = defineCorpus({ // truncated an item-id reference at its first hyphen and // produced a phantom `#access`, which the permissive rule // then resolved against the spelling `access-security`. -// 1 row — the sharpest single illustration of what a -// looser second resolver buys. +// the sharpest single illustration of what a looser second +// resolver buys. 0 rows — DRAINED by the second slice, and +// the reading is kept because the shape is not: its one row +// was `bad-citation` BY VERDICT, and `shape` only ever said +// why the withdrawn rule used to resolve it. ⚠️ A reader who +// takes the shape for the disposition is sent at the +// DETECTOR, which since #18107 is `scripts/symbol-anchors.mjs` +// — the file this card forbids by name. Repaired +// citation-side like the other twelve: the truncation was +// not even happening any more — the citation's fragment +// was followed by a SPACE — so the symbol it named was +// simply a key `areas/access-security.json` does not +// declare. ⚠️ That fragment is spelled in WORDS here and +// not in a code span: a lone fragment span is a +// CONTINUATION anchor, so writing it would file this +// comment as the citation the row was. // // ⭐ THE DRAIN (#18104). The `bad-citation` half is a population with an owner, // and it leaves this ledger ONE WAY: the citation is re-pointed at what the @@ -1900,11 +1915,18 @@ const CORPUS = defineCorpus({ // `areas/api-backend.json` and `areas/automation.json` — 9 rows, all of them // citations naming a route table's client-method names or route path // parameters where the declaration the item means is the ledger export itself. +// Second slice landed (#18104): `areas/identity-auth.json` — 13 rows, the +// largest single-file block, the same reading applied plus three of its own: an +// import-only persona whose constant had MOVED to another file (the path was +// re-pointed, not the symbol), a `.json` cross-area citation re-pointed at the +// `items` block it means, and the `detector-artifact` row above. ⚠️ That file +// still carries its 2 `accept-set` rows and that is CORRECT, not half-done: +// they are #18101's, and reaching them means widening the shared core. // // `verdict` is the classification #16898's acceptance asks for, and there are // exactly two: // -// bad-citation (38 rows) the anchor names a symbol the cited file does not +// bad-citation (25 rows) the anchor names a symbol the cited file does not // declare. The repair is in the LEDGER: re-point the anchor at // what the file carries, or drop to a bare citation. ⚠️ Dropping // costs the file an anchor and most floors have no headroom, so @@ -1930,19 +1952,6 @@ const SHARED_RESOLVER_RESIDUAL = Object.freeze([ { doc: 'areas/cli.json', anchor: 'packages/verify/src/verify.ts#VALIDATION_FAILED', shape: 'regex-literal', verdict: 'bad-citation' }, { doc: 'areas/dashboards.json', anchor: 'examples/app-showcase/src/data/seed/index.ts#sales_region', shape: 'inline-key', verdict: 'accept-set' }, { doc: 'areas/dashboards.json', anchor: 'examples/app-showcase/src/data/seed/index.ts#signed_on', shape: 'inline-key', verdict: 'accept-set' }, - { doc: 'areas/identity-auth.json', anchor: 'docs/qa/platform-checklist/areas/access-security.json#access', shape: 'detector-artifact', verdict: 'bad-citation' }, - { doc: 'areas/identity-auth.json', anchor: 'examples/app-showcase/src/security/seed-approval-demo.ts#PHONE_DEMO_USER', shape: 'import-only', verdict: 'bad-citation' }, - { doc: 'areas/identity-auth.json', anchor: 'packages/platform-objects/src/identity/sys-member.object.ts#BUILTIN_MEMBERSHIP_ROLE_OPTIONS', shape: 'import-only', verdict: 'bad-citation' }, - { doc: 'areas/identity-auth.json', anchor: 'packages/platform-objects/src/identity/sys-oauth-application.object.ts#OAuth', shape: 'string-substring', verdict: 'bad-citation' }, - { doc: 'areas/identity-auth.json', anchor: 'packages/plugins/plugin-auth/src/auth-route-ledger.ts#bootstrapStatus', shape: 'string-substring', verdict: 'bad-citation' }, - { doc: 'areas/identity-auth.json', anchor: 'packages/plugins/plugin-auth/src/auth-route-ledger.ts#linkSocial', shape: 'string-substring', verdict: 'bad-citation' }, - { doc: 'areas/identity-auth.json', anchor: 'packages/plugins/plugin-auth/src/auth-route-ledger.ts#revokeOthers', shape: 'string-substring', verdict: 'bad-citation' }, - { doc: 'areas/identity-auth.json', anchor: 'packages/plugins/plugin-auth/src/auth-route-ledger.ts#sendVerificationEmail', shape: 'string-substring', verdict: 'bad-citation' }, - { doc: 'areas/identity-auth.json', anchor: 'packages/plugins/plugin-auth/src/auth-route-ledger.ts#setActive', shape: 'string-substring', verdict: 'bad-citation' }, - { doc: 'areas/identity-auth.json', anchor: 'packages/plugins/plugin-auth/src/auth-route-ledger.ts#updateUser', shape: 'string-substring', verdict: 'bad-citation' }, - { doc: 'areas/identity-auth.json', anchor: 'packages/plugins/plugin-security/src/security-plugin.ts#__referentialFieldClear', shape: 'member-access', verdict: 'bad-citation' }, - { doc: 'areas/identity-auth.json', anchor: 'packages/qa/dogfood/test/membership-role-vocabulary.dogfood.test.ts#PermissionSet', shape: 'string-substring', verdict: 'bad-citation' }, - { doc: 'areas/identity-auth.json', anchor: 'packages/rest/src/rest-route-ledger.ts#describeDelegableScope', shape: 'string-substring', verdict: 'bad-citation' }, { doc: 'areas/identity-auth.json', anchor: 'packages/spec/src/kernel/public-auth-features.ts#sys_invitation', shape: 'dotted-string-head', verdict: 'accept-set' }, { doc: 'areas/identity-auth.json', anchor: 'packages/spec/src/kernel/public-auth-features.ts#sys_user', shape: 'dotted-string-head', verdict: 'accept-set' }, { doc: 'areas/integration-system.json', anchor: 'examples/app-showcase/objectstack.config.ts#declarativeStdio', shape: 'inline-key', verdict: 'accept-set' }, @@ -1971,7 +1980,7 @@ const SHARED_RESOLVER_RESIDUAL = Object.freeze([ // fail), so this is the belt on the braces: a silent append — the one edit that // would turn a closed ledger back into a permissive rule, one row at a time — // refuses here rather than validating. -const SHARED_RESOLVER_RESIDUAL_CEILING = 46; +const SHARED_RESOLVER_RESIDUAL_CEILING = 33; const residualKey = (doc, anchor) => `${doc}::${anchor}`; const SHARED_RESOLVER_RESIDUAL_INDEX = new Map(