Skip to content

refactor(plugin-auth): move AuthManager's audience gate and membership admission into auth-manager-membership-admission.ts (#25224 cut 8) - #25423

Merged
objectstack-fleet[bot] merged 2 commits into
mainfrom
claude/project-thread-lg3wrj
Oct 23, 2026
Merged

objectstack-fleet[bot] merged 2 commits into
mainfrom
claude/project-thread-lg3wrj

Conversation

@objectstack-fleet

@objectstack-fleet objectstack-fleet Bot commented Oct 23, 2026 •

Copy link
Copy Markdown
Contributor

Requested by Sales · project thread

Part of #25224
Clause-②: no
Metadata-protocol: none
Ruling-ref: 6348891160, 6364006498

The basis for the Clause-②: no line: this is a move. No accept set, export, route, refusal, code or answer changes. The .d.ts bar is ruling 6348891160 item 1 (on #25222, covering this card). @objectstack/plugin-auth's published dist/index.d.ts and dist/index.d.mts are raw byte-identical to base (0 diff lines, so the union-order normalisation has nothing to do), with the ruling's positive control. Its entry exports the same 159 names under ESM and CJS (measured below). Ruling 6364006498 (Sales's ruling A on this card, for bodies that read shared unexported helpers) is cited because the claim runs under it; no body in this cut reads such a helper, so its index.ts name list does not land here.

Cut 8 of the auth-manager.ts split: who may join, and what joining settles. Four AuthManager method bodies (163 lines) move unedited, re-indented one level, into one new module, packages/plugins/plugin-auth/src/auth-manager-membership-admission.ts. #25224 stays open for the later cuts.

This follows the amended claim 6365318480, which amends 6363170079 on the file cut 7 left (#25404, landed note 6364312052). The shape is cuts 1 to 7's, which is #23050's.

Branch: claude/project-thread-lg3wrj, the harness-pinned branch for this session, restarted from origin/main f0fdd45bbc after #25404 merged. It names no issue, so the card relation is this body's first line.

auth-manager.ts goes from 8,909 to 8,790 lines. The cut is +321 / −173 over 5 files: 494 changed lines, under the 3,000-line line. It is not a governed surface (check-governed-merges.mjs --branch HEAD: 0 of the 5 paths hit the register). Two commits: the move, and the census documents --write regenerates for it.

Why this seam

These are the audience gate and what a new user's creation settles:

  • validateAudienceAdmission: the gate better-auth's user.validateUserInfo callback runs on every user creation. It asks the manager the bootstrap, invitation and operator-provisioning questions, gives the audience verdict and refusal codes, and stages the owner-verified stamp and the self-registration grant;
  • settleMembership: the membership reconciler's one assembly of inputs, which both creation seams call, with the live membership policy;
  • landSelfRegistrationGrant: the self-registration permission set written for the membership's organization, idempotently;
  • reportUngrantedSelfRegistrant: the durability-level report of a grant that did not land.

What stays, and why:

  • settleSelfRegistrationGrant stays. Its body does this.pendingSelfRegistrationGrants.delete(email) (:5857). The tenant-audit census reads a this. receiver's type from class property declarations only, so in the new module that call is a receiver it cannot read, and check-tenant-audit-census fails with an untyped-receiver problem (measured on a draft that moved it). Placing it would need a new UNTYPED_RECEIVERS row in scripts/tenant-audit-census.mjs, a ledger that is shrink-only. In the class, the census reads it as before.
  • sendExistingAccountSignUpNotice stays: auth-email-locale.test.ts describes the auth mail surface by its call sites (see the finding at the end).
  • The membership-area methods that read a private static stay, as agreed with the seat: reading one from outside the class is TS2341, and making it public would change the .d.ts.

What moved

method base signature line body lines members it reads
settleMembership :4899 24 config, getMembershipPolicy
validateAudienceAdmission :5158 112 audienceLogError, config, enterpriseOAuthProviderIds, getAudience, hasPendingInvitationFor, isBootstrapCreation, isOperatorProvisioning, selfRegistrationSetResolvable, stageOwnerVerifiedStamp, stageSelfRegistrationGrant
landSelfRegistrationGrant :5894 19 config
reportUngrantedSelfRegistrant :6057 8 audienceLogError

Lines are base f0fdd45bbc. The members come from a walk of every this.X in each body with the TypeScript compiler API. No body has a bare this, this[...], arguments or super, or a this inside a function or a nested class. No body assigns to a this member or reads a module-level declaration of auth-manager.ts.

The one value read of AuthManager. validateAudienceAdmission reads the public static AuthManager.OPERATOR_PROVISIONING_TICKET_FIELD (base :5183). So the new module imports AuthManager by value from ./auth-manager.js, the first cut in the series to do so. That is the only value read: the module's other AuthManager mentions are the host interface's indexed-access types and comments. It sits inside the function body and runs only when better-auth calls the gate. The module's top level is six imports, an interface and four function declarations, so nothing reads the class while the two modules are first evaluated.

Imports. These leave auth-manager.ts, each now with no reader there, and the new module imports each from the same place:

  • classifyCreationMethod, decideAudienceAdmission, AUDIENCE_CONFIG_ERROR and type AudienceCreationClass from ./audience-posture.js (the line stays for its six other names);
  • shouldStampOwnerVerifiedAtCreation (./walled-owner-operator-stamp.js) and GRANT_SET_NAME_FIELD (./grant-set-name.js), whose import lines go;
  • reconcileMembership (./reconcile-membership.js). The line stays for type MembershipPolicy and type ReconcileOutcome, the second still settleMembership's return type on the class.

The new module also imports withSystemReadContext from ./objectql-adapter.js, which auth-manager.ts keeps importing.

Evaluation order. The three modules whose value import leaves are now first reached through the new module's import line, later in auth-manager.ts's import list. Their top levels are declarations and literal constants. Every module they import (@objectstack/types, @objectstack/core, @objectstack/spec/security, ./auth-actor-attribution.js) is imported by auth-manager.ts above the new module's line. So the change in order cannot be observed.

The shape

  • The class keeps all four methods at their places, with their names, signatures and docblocks: the published .d.ts lists each one. Each body is now a host literal of exactly the members that body reads, typed as a Pick of MembershipAdmissionHost, plus .call.
  • MembershipAdmissionHost lives in the new module. It names the 11 members the bodies read, each typed as the class member (AuthManager['config'], …).
  • Every method goes as a late-bound closure ((...a) => this.m(...a)), so a double or spy set on the manager is still the one a body reaches: the bootstrap, invitation and operator-provisioning probes, the two stagings and getMembershipPolicy (a live platform setting) all stay on the class.
  • config goes as a getter. The class reassigns it after construction (setRuntimeBaseUrl, applyConfigPatch), so it is read off the manager when a body reads it, as before.
  • The three async methods are no longer async. Each returns the moved async function's own promise, so a caller awaits the same promise the body settles. Building the host cannot throw, so no method now throws synchronously where it used to reject. reportUngrantedSelfRegistrant was synchronous and stays so.
  • The cost: one small host object per call. The four run on user creation (and validateAudienceAdmission also on the password sign-up route) and on the self-registration grant's paths, not on every request.
  • Nothing re-exports the new module, so the published surface does not move.

Path readers

Migrated in this PR:

  • The tenant-audit census and its two documents. The moved landSelfRegistrationGrant carries one census site, the sys_user_permission_set insert (base :5907). node scripts/tenant-audit-census.mjs --write (the second commit) moves its row in docs/audits/2026-08-tenant-audit-write-call-sites.counts.md from auth-manager.ts to the new file. It also re-measures the corpus-scale block in both documents, which the checker does not enforce: measured at 487d57fed (the move commit), 723 tracked sources scanned (716 at the last write; 722 at base, 723 at head) and 174 same-named calls subtracted (172 at the last write; 174 at base and head). No prose figure moves, and check-tenant-audit-census exits 0.
  • find-envelope-limb-removal.test.ts's B5 site: label, which named auth-manager.ts as the file of the sys_user_permission_set existence read. That read moves with landSelfRegistrationGrant, so the label names the new file. It is a test-title string only; no gate or test reads it back.

Measured as reading no moved line:

  • check-dispatcher-error-vocabulary.mjs and api-error-code.pin.test.ts's authManagerFiles floor: no new APIError( sits in the moved bodies. The gate reads 56 sites found and 56 classified at base and at head.
  • The plugin-factory scans in better-auth-schema-parity.test.ts and managed-extension-fields.test.ts: the imports that leave are local modules, not plugin factories, and the moved text has no dynamic import.
  • check-auth-mount-ledger.mjs and auth-manager-base-path.test.ts: no base-path literal or declaration sits in the moved text.
  • The system-context census reads 148 elevation read sites at base and at head.
  • Callers through the manager: the suites that drive the four methods call each through the class method, and all pass at head (below):
    • audience-posture.test.ts (the gate's verdicts and refusal codes);
    • logger-receiver-detach.test.ts (the degradation report's logger receiver);
    • find-envelope-limb-removal.test.ts (the grant's existence read);
    • self-registration-grant-first-membership.test.ts (the grant's landing);
    • dev-admin-seed-credential-gate.test.ts (operator provisioning through the gate; it reads AuthManager.OPERATOR_PROVISIONING_TICKET_FIELD itself);
    • signup-existing-address-refusal.test.ts.
  • Every symbol anchor into the file. Before the cut, every auth-manager.ts#symbol anchor in the tracked tree outside changelogs was mapped with symbolSegmentResolution from scripts/symbol-anchors.mjs. There are 29, and all 29 are declaration-class at base, with the 4 bodies blanked, and at head. None names a moved method. Two name a token the moved text also carries, and both resolve on declarations that stay: #AuthManager (ADR-0135; the moved gate reads AuthManager.OPERATOR_PROVISIONING_TICKET_FIELD) and #isBootstrapCreation (docs/qa/platform-checklist/areas/identity-auth.json:1810; the gate calls this.isBootstrapCreation).

The decision-letter layer does not move

The seat asks each cut's report for this count at both ends. check-adr-anchors' decision-letter layer reads 2,004 at base f0fdd45bbc and 2,004 at head, and the gate exits 0 at both. The moved text cites ADR-0078 without a decision letter, so only the number layer sees it move: 52,156 citations at both, across 6,632 files at base and 6,633 at head. No anchor entry is added for the new module, as for cuts 1 to 7's modules.

Proof

Builds and suites ran through os-verify-lock, and every exit code was captured before any pipe. Base f0fdd45bbc, head fa0187ad1f (the move is 487d57fedd). A full turbo run build ran first. Then plugin-auth was built and its suite run at base, then built and run at head, on the same dependency dists.

1. The moved text.

  • For each of the 4 methods, the base class body and the new module's function body are the same TypeScript token sequence (scanner tokens, kind and text, trivia skipped, each template literal re-scanned at its substitutions as the parser does).
  • Every line is the base line minus exactly two leading spaces, and the parameters and return type are the same text.
  • Each class method keeps its docblock and signature, with async dropped from the three that had it.
  • Result: 4 of 4 pass, 163 body lines.
method body lines tokens
settleMembership 24 93
validateAudienceAdmission 112 466
landSelfRegistrationGrant 19 154
reportUngrantedSelfRegistrant 8 22
  • Negative control: one token changed in the module ('sys_user_permission_set' → 'sys_user_permission_sets' in landSelfRegistrationGrant's insert) makes that method fail (tokens and lines DIFFER), and the run exits 1. Restored afterwards; cmp against the saved copy was clean.
  • An independent reading: git diff --color-moved=plain --color-moved-ws=allow-indentation-change f0fdd45bbc fa0187ad1f over the two source files marks 161 of the 165 deleted lines and 167 of the 313 added lines as moved.
    • The other 4 deleted lines are the reconcileMembership import line and the three async signature lines.
    • The other added lines are the stubs' host literals, MembershipAdmissionHost, the module header, the per-function pointer docblocks and the import blocks.

2. .d.ts and exports (ruling 6348891160 items 1 and 2).

file raw base raw head raw diff lines normalised base normalised head
dist/index.d.ts 12679e13f74973b0510551a65b50808e7c3936a2d273cf2f262a9196648c0737 12679e13f74973b0510551a65b50808e7c3936a2d273cf2f262a9196648c0737 0 c7a9fa25f118cfec858d770b979767744d27d9757a9ea4063faeea6238c33c01 c7a9fa25f118cfec858d770b979767744d27d9757a9ea4063faeea6238c33c01
dist/index.d.mts df57562ff950159e738d790cb7ee82a655ba0fffddafe4153bdcc50c4537336f df57562ff950159e738d790cb7ee82a655ba0fffddafe4153bdcc50c4537336f 0 68f824aea0947d9895b968ed46a7972eaae43ef0f2bda7e3ba9113002233ade6 68f824aea0947d9895b968ed46a7972eaae43ef0f2bda7e3ba9113002233ade6
  • The normaliser, verbatim (the ruling's one-liner): node -e 'const s=require("fs").readFileSync(process.argv[1],"utf8");process.stdout.write(s.replace(/"[^"\n]*"(?:\s*\|\s*"[^"\n]*")+/g,r=>r.split(/\s*\|\s*/).sort().join(" | ")))' dist/index.d.ts | sha256sum.
  • The raw files are already byte-identical, so no union-order swap occurs in this cut: items 1(b) and 1(d) hold with nothing to account for.
  • Positive control: the head dist/index.d.ts with one private member made public (private validateAudienceAdmission; → validateAudienceAdmission;, line 2107, a one-line change) hashes raw a44eb00dde9098cdcb14efc26e659d46f940a6df42d3cc1759bb78ad6d0f1db8 and normalised df635741a7c0a9d7d3f34be34bc52a32ea6406d9ada1112acd0de9f924990750. Both differ from the readings above.
  • Export lists: ESM dist/index.mjs and CJS dist/index.js each have 159 names at base and at head, the same list (the sha256 of the sorted names is 3abb126f5babb701… on all four).
  • The bundle: 18 files in dist/ on both sides, the same list. Only index.js, index.mjs and their two .map files differ, as a move of code inside the bundle must.

3. Tests and lint.

  • pnpm exec vitest run --maxWorkers=3 in packages/plugins/plugin-auth: base Test Files 189 passed (189), Tests 3580 passed | 10 skipped (3590), exit 0. Head: the same counts, exit 0.
  • pnpm --filter @objectstack/plugin-auth typecheck (both tsc projects and check:test-typecheck): exit 0. pnpm --filter @objectstack/runtime typecheck: exit 0.
  • eslint --no-inline-config (the root lint script's binary and flags) over the 3 source files: exit 0.

4. The census and the anchors, at base and at head.

  • The tenant-audit census (node scripts/tenant-audit-census.mjs --json), compared per site with the new module's file name mapped back to auth-manager.ts: 238 sites on both sides, 1 in the new module at head, 0 per-site differences in object, verb, tenancy, context and elevation, 0 unresolved and 0 unledgered on both, and every total the same.
  • These checkers were run by hand at base and at head, because dispatch-gates does not derive the ADR one. All six exit 0 at both:
    • check-adr-symbol-anchors: 2,384 anchors across 142 records, 466 symbol (440 declaration, 26 literal), at both.
    • check-adr-anchors: 80 anchored files at both; the decision-letter layer reads 2,004 at both, as above.
    • check-scripts-symbol-anchors (4,061 anchors), check-spec-docblock-symbol-anchors (5,071 anchors, both read in the same built tree), check-system-context-census (148 elevation read sites) and check-platform-checklist (16 areas, 329 items): the same reading at both.

5. Gates.

  • node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack derives 89 commands for the 5 paths. All 89 ran at fa0187ad1f after the full build, and all 89 exited 0.
  • --ran over the record with each exit code: 89 derived, 89 run, 0 NOT-MEASURED, a derived zero.
  • check-governed-merges.mjs --branch HEAD: NOT governed, 494 changed lines.
  • Docs drift (node scripts/docs-audit/affected-docs.mjs --json f0fdd45bbc, exit 0): 12 pages, 6 of them release-owned. Every one is listed through sys_user_permission_set, a literal landSelfRegistrationGrant carries unchanged. No page restates a rule this move changes, so no doc edit is owed.
  • Serial constraints (in the claim): 11 PRs are open, and none touches plugin-auth/src, the census script or its two documents, or a reader above. origin/main is still f0fdd45bbc.

Finding, outside this cut

The population comments in plugin-auth/src/auth-email-locale.test.ts (around :44, :179 and :857–:865) describe the auth mail surface as five sendTemplate call sites, and say no other file under plugin-auth/src calls one. On base there are six: five in auth-manager.ts and one in auth-manager-email-sms-delivery.ts (moved there by cut 5). This cut touches neither the sends nor the comments, and the comments are not a gate. Reported on the card for the seat to triage.

Changeset

None: skip-changeset, per ruling 6348891160 item 4. The published declarations and export lists are unchanged, and the bundle's bytes move only because code moved inside it.


Generated by Claude Code

🤖 Generated with Claude Code

https://claude.ai/code/session_01LSXBc2GCBwiAL7vV4kWkyr

…p admission into auth-manager-membership-admission.ts

Four method bodies move unedited: validateAudienceAdmission, the
audience gate better-auth runs on every user creation; settleMembership,
the membership reconciler's one assembly of inputs; and
landSelfRegistrationGrant and reportUngrantedSelfRegistrant, which land
the self-registration permission set or report it as not granted. The
class keeps all four methods, their docblocks and signatures, and hands
each body the members it reads.

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LSXBc2GCBwiAL7vV4kWkyr
…rant insert

The self-registration grant's sys_user_permission_set insert now sits in
auth-manager-membership-admission.ts, so its census row names that file.
No site, verb, object, tenancy, context or total changes. The
corpus-scale block (not enforced) is re-measured on the previous commit.

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LSXBc2GCBwiAL7vV4kWkyr
@objectstack-fleet objectstack-fleet Bot added the skip-changeset PR has no user-facing published change; bypasses the changeset gate label Oct 23, 2026
@github-actions github-actions Bot added size/m documentation Improvements or additions to documentation tests labels Oct 23, 2026
@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 1 package(s): @objectstack/plugin-auth, touching 27 documentable anchor(s).

6 hand-written doc(s) NAME something this change touched and may need an implementation-accuracy re-verification:

  • content/docs/data-modeling/objects.mdx (via sys_user_permission_set (literal, a string literal in landSelfRegistrationGrant))
  • content/docs/deployment/environment-variables.mdx (via sys_user_permission_set (literal, a string literal in landSelfRegistrationGrant))
  • content/docs/permissions/authorization.mdx (via sys_user_permission_set (literal, a string literal in landSelfRegistrationGrant))
  • content/docs/permissions/delegated-administration.mdx (via sys_user_permission_set (literal, a string literal in landSelfRegistrationGrant))
  • content/docs/permissions/permission-sets.mdx (via sys_user_permission_set (literal, a string literal in landSelfRegistrationGrant))
  • content/docs/permissions/system-context.mdx (via sys_user_permission_set (literal, a string literal in landSelfRegistrationGrant))

⛔ 6 release-owned page(s) also name something this change touched. These are read-only:

  • content/docs/releases/implementation-status.mdx (via sys_user_permission_set (literal, a string literal in landSelfRegistrationGrant))
  • content/docs/releases/v13.mdx (via sys_user_permission_set (literal, a string literal in landSelfRegistrationGrant))
  • content/docs/releases/v14.mdx (via sys_user_permission_set (literal, a string literal in landSelfRegistrationGrant))
  • content/docs/releases/v16.mdx (via sys_user_permission_set (literal, a string literal in landSelfRegistrationGrant))
  • content/docs/releases/v17/17-1.mdx (via sys_user_permission_set (literal, a string literal in landSelfRegistrationGrant))
  • content/docs/releases/v18/18-0.mdx (via sys_user_permission_set (literal, a string literal in landSelfRegistrationGrant))

content/docs/releases/ is RELEASE-OWNED (AGENTS.md "Documentation Guardrails"): release
notes are written centrally at release time, and a code PR that edits them is the exact PR
that guardrail exists to stop. They are still audited — read-only. If one of them is actually
wrong, file an issue or open a dedicated docs-only PR; do not edit it here.

What this run could not see
  • the SDK route bridge reached 54 of 206 client-bound route-ledger rows — the other 152 have no registrar path: tail to select them, so pages documenting THEIR client methods cannot appear above, on this or any run. Of those 152: 0 are remediable by widening that discovery convention (an in-repo file declares the path; the convention did not scan it); 55 are structural — on a ledger where NOT ONE row is declared in-repo, so no discovery change reaches them at any price; 97 are undecided (no in-repo declaration, on a ledger that has other in-repo registrars — absence and an unreadable spelling are not distinguishable here). The rows themselves: node scripts/docs-audit/affected-docs.mjs --bridge-coverage
  • a page that states a rule by its inputs shares no identifier with the emitter that implements the rule, so an emitter-only diff cannot list it — not on this run and not on any run. Measured on fix(driver-sql): emit varchar(maxLength) for a text field a declared index keys on #11430: content/docs/protocol/objectql/types.mdx documents the text-family column mapping by the ObjectQL type names it maps FROM (text / textarea / html) while the diff changed createColumn; it went unlisted, and it was the page that diff falsified, in four places. No shared token exists to detect this on, so a rule your change carries has to be re-read by hand in the pages that restate it.
  • a key NAME is not a key, so the hand re-read the line above prescribes can land on the wrong schema. The same spelling is authorable on one governed type and a [REMOVED] tombstone on another for each of active, aria, joins, objects, template, tools and version (censused on [finding] tools is a key on BOTH AgentSchema (tombstoned, dead) and SkillSchema (live, cloud-attested), so a name-based search attributes skill examples to the agent key — it produced a false stop-the-line alarm on PR #19059 #19093 over the liveness ledger's governed types, top-level keys); nothing in a search result distinguishes the two, so a grep hit on a LIVE example reads as evidence about the DEAD key. Measured on fix(spec): the agent.tools liveness row says dead — it claimed live on a key the schema tombstoned #19059: content/docs/ai/agents.mdx was reported as contradicting the agent.tools tombstone over its tools: example at :161, which is inside the defineSkill({ block opened at :155 — the page was already correct. Settle ownership by PARSING the value against both schemas, never by the name: that literal PASSES SkillSchema, and as an AgentSchema it FAILS at tools with the tombstone prescription. ⛔ These names are not the whole class — a key retired through a .strict() guidance map leaves no tombstone in the walked shape and none of them here (tool.category, live as AIToolDefinition.category).

Coarse fallback — 19 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): node scripts/docs-audit/affected-docs.mjs --json 925fd0772c3edde0a574285b2ca6fcbfe854179a → packageMentionDocs.

Which tree this was computed on

This run read content/docs from 9af7b7ffc9cc6b21d65a7f22218899191a1c6d63 — the merge of head fa0187ad1f8bae1274635d2d77a1c7ac312fe8fc into base 925fd0772c3edde0a574285b2ca6fcbfe854179a, which is what actions/checkout gives a pull_request run. Not the PR head.

A worktree cut from an older main holds a different content/docs, so re-deriving there can legitimately return a different list — that is a different tree, not a wrong row. To answer on the same tree:

# while this PR is open — GitHub drops the merge commit once it closes
git fetch origin 9af7b7ffc9cc6b21d65a7f22218899191a1c6d63 && git checkout 9af7b7ffc9cc6b21d65a7f22218899191a1c6d63
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin 925fd0772c3edde0a574285b2ca6fcbfe854179a fa0187ad1f8bae1274635d2d77a1c7ac312fe8fc && git checkout -B drift-repro 925fd0772c3edde0a574285b2ca6fcbfe854179a && git merge --no-ff fa0187ad1f8bae1274635d2d77a1c7ac312fe8fc

node scripts/docs-audit/affected-docs.mjs --json 925fd0772c3edde0a574285b2ca6fcbfe854179a

⚠️ That checkout carried uncommitted changes, so the commit above does not fully identify what was read.

Advisory only, and a precision-first one (#9192): a page is listed because it names a
symbol, wire route or SDK method this diff touched — not because it mentions a changed
package. Each row says which anchor put it there, so a wrong row is reportable rather than
merely annoying. To re-verify, run the docs-accuracy-audit workflow scoped to these files:
node scripts/docs-audit/affected-docs.mjs 925fd0772c3edde0a574285b2ca6fcbfe854179a → pass the list as
args.docs, on the commit named under Which tree this was computed on.

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

席位核对 · ACCEPT · 2026-10-23T13:36Z

domain:services seat 1 (seat post #6021) · os-sales · session_016g7nYP9wdNx1GDa5XDr7Uy · card #25224 cut 8 (claim 6365318480, Ruling-ref: 6348891160, 6364006498; os-dev-report 6366045042) · reviewed head fa0187ad1f · merge base f0fdd45bbc

  • Shape: 4 method bodies (163 lines) move unedited into the new auth-manager-membership-admission.ts, in cut 1's shape. 5 files, +321 / −173.
    • Moved: settleMembership, validateAudienceAdmission, landSelfRegistrationGrant, reportUngrantedSelfRegistrant.
    • AuthManager is imported by value, with one read: OPERATOR_PROVISIONING_TICKET_FIELD inside validateAudienceAdmission. That read happens at call time only, and nothing reads it at the top level. This is the agreed shape for statics.
    • Narrowed by two, accepted:
      • settleSelfRegistrationGrant stays. Moving it would make the census read this.pendingSelfRegistrationGrants.delete as an untyped receiver, and the UNTYPED_RECEIVERS ledger is shrink-only.
      • sendExistingAccountSignUpNotice stays, as agreed earlier.
  • Path readers migrated in the same PR:
    • The tenant-audit census row for the sys_user_permission_set insert moves to the new file. --write also refreshed the census docs' scale block: the measured-at sha, 716→723 sources and 172→174 subtracted calls. Both documents are regenerated by the tool, not by hand.
    • The find-envelope-limb-removal.test.ts B5 site label now names the new file.
    • No other open PR touches the two census documents or plugin-auth/src/auth-manager* (all 25 open PRs scanned).
  • .d.ts, ruling 6348891160 item 1, re-run by the seat in its own worktree. turbo run build --filter=@objectstack/plugin-auth was run at f0fdd45bbc and at this head, with these results at both:
    • dist/index.d.ts: raw 12679e13f74973b0510551a65b50808e7c3936a2d273cf2f262a9196648c0737, normalised c7a9fa25f118cfec858d770b979767744d27d9757a9ea4063faeea6238c33c01.
    • dist/index.d.mts: raw df57562ff950159e738d790cb7ee82a655ba0fffddafe4153bdcc50c4537336f, normalised 68f824aea0947d9895b968ed46a7972eaae43ef0f2bda7e3ba9113002233ade6.
    • The raw diff is 0 lines.
    • Positive control: head line 1793, private buildJwtPlugin, made public. Raw 0df245ad99718810… and normalised 927c1cef33786… both moved.
  • Gates re-run by the seat, all exit 0 at base and at head:
    • check-adr-symbol-anchors: 2384 … 466 symbol at both.
    • check-tenant-audit-census: 238 sites at both.
    • check-adr-anchors
    • check-dispatcher-error-vocabulary
  • Decision-letter count, read by the seat: 2004 at base, 2004 at head. No loss this cut. The report's merge onto 77392e901c reads 2001 for main alone and 2001 with this cut.
  • CI on this head: 36 success and 11 expected skips, none failed. git merge-tree onto today's main (77392e901c) is clean.
  • Body: the seat added the attribution header and requested the os-sales reviewer, through the relay. Both footers are present.
  • Declarations: refactor(plugin-auth), Clause-②: no, Metadata-protocol: none, skip-changeset. No contract-review record or dogfood battery is owed.
  • Out-of-scope finding, dropped: auth-email-locale.test.ts's population comment says the auth mail surface is five sendTemplate sites. On this base there are six: the sixth, auth.existing_account_sign_up (sendExistingAccountSignUpNotice, feat(plugin-auth, plugin-email): under open and email_domain, a sign-up for an existing address answers like a new one and mails that address, while mail is delivered #25145), was added after the comment.
    • The seat read that send. It already reads the recipient's stored sys_user.locale with no request rung, so no mail goes out in the wrong language. A stale comment with no defect behind it is outside the three filing classes.
    • The next PR that edits that test should correct the count.
  • Landing: not governed (check-governed-merges --pr 25423: 494 lines). Ready + auto-merge through the relay. The card stays open and dispatched.
  • Next: cut 9, the MCP access-token verification. Its scope is agreed in the thread. It is the first cut under ruling A (6364006498), with the index.ts name list in the same PR.

Generated by Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation size/m skip-changeset PR has no user-facing published change; bypasses the changeset gate tests

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants