Repository navigation
Commit f192123
<!-- claude-projects-attribution: {"github_login":"os-sales"} -->
_Requested by **Sales** · [project
thread](https://claude.ai/code/project/chan_01D5bWFY3rFzgJcytD5gD4Uu?thread=cmsg_01D5bWFY3rFzgJcytD5gD4UuMjbPDrsigsyqoKsV4WZQMz)_
Part of #25224
Clause-②: no
Metadata-protocol: none
Ruling-ref: 6348891160, 6364006498
The basis for the `Clause-②: no` line: this is a move plus reader
migrations and one anchor entry. No accept set, route, refusal, code or
answer changes, and the published surface is measured unchanged:
- `@objectstack/plugin-auth`'s `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). The positive control is the one ruling
`6348891160` asks for.
- Its ESM and CJS entries export the same 159 names at base and at head.
The eight declarations this cut exports in place inside the package,
`buildOrganizationPlugin` and `OrganizationPluginHost` are not among
them.
The `.d.ts` bar is ruling `6348891160` item 1 (on #25222, covering this
card). Ruling `6364006498` is Sales's ruling A on this card. This is the
seventh cut it applies to.
Cut 15 of the `auth-manager.ts` split: **the `organization` plugin's
factory inside `buildPluginList`**. It is the first of the two
`buildPluginList` cuts the seat set at 02:10Z (this factory, then the
rest of the method); the series ends after cut 16, and #25224 stays open
for it.
This follows the amended claim `6379187398`, which amends `6377759458`
on the file cut 14 left (#25566, landed note `6378561924`). The shape is
the closure move cuts 12 and 13 used (a factory arrow's body into a
module function called on a host), with cut 10's get/set pair (#25508)
for the one field the body writes.
Branch: `claude/project-thread-lg3wrj`, the harness-pinned branch for
this session, restarted from `origin/main` after #25566 merged. It names
no issue, so the card relation is this body's first line.
`auth-manager.ts` goes from 7,122 to 6,556 lines. The cut is +734 / −608
over 7 files: 1,342 changed lines, under the 3,000-line line. Four of
the seven files are path readers outside the move and one is a new
anchor entry, so `check-governed-merges.mjs` ran on the trial file list
before the cut: NOT governed (0 of 7 paths hit the register), and
`--branch HEAD` agrees. One commit: `361581a546` `refactor(plugin-auth):
move the organization plugin factory into
auth-manager-organization-plugin.ts`.
## The move
| moved | base lines | proof lines | tokens | members it reads |
|---|---|---:|---:|---:|
| the body of the `organization` factory arrow in `buildPluginList` |
`:1991`–`:2559` | 571 | 1,854 | 8 methods, 2 fields |
The lines are base `ba9e0c3749`. The 571 proof lines are the body with
its braces (the arrow's `{` on `:1990` to its `}` on `:2560`).
- **What it is:** `buildPluginList` (`:1892`, `private async`, annotated
`Promise<any[]>`) builds better-auth's plugin list. For each optional
plugin it calls `await this.addOptionalPlugin(plugins, name, async () =>
{…})`, whose arrow loads the plugin and builds it. The `organization`
call is at `:1990`, inside `if (enabled.organization)`.
- **What the body does, in order** (all of it moves, with its comments):
the deferred `better-auth/plugins/organization` import; the closed
organization-role vocabulary and the roles map built from it
(`better-auth/plugins/organization/access`), stored on the manager as
`orgRolesMap`; one options object (the schema, teams, the
`requireEmailVerificationOnInvitation: false` declaration, the
organization limit, the membership limit, the organization hooks for
creation, invitation, acceptance, slug change and deletion with their
refusal codes, and the invitation e-mail); the vendor plugin built from
it; and the rebuilt `/organization/list-user-invitations` listing, with
its warning when the vendor no longer exposes it.
- **Where it goes:** a new module,
`packages/plugins/plugin-auth/src/auth-manager-organization-plugin.ts`
(683 lines). The body becomes the body of `export async function
buildOrganizationPlugin(this: OrganizationPluginHost)`, re-indented four
spaces (two levels) and otherwise unedited. The module header gives the
reasoning, in the form the fourteen earlier `auth-manager-*.ts` modules
use.
- **What stays:** `buildPluginList` keeps its place, its docblock, its
signature and every other line. The `organization` call keeps its place
in it, and its arrow is now:
```ts
// [#25224 cut 15] The body of this factory moved to
// `auth-manager-organization-plugin.ts`; this arrow hands it the
members
// it reads (`OrganizationPluginHost`).
await this.addOptionalPlugin(plugins, 'organization', () => {
const readConfig = () => this.config;
const readOrgRolesMap = () => this.orgRolesMap;
const writeOrgRolesMap = (v: AuthManager['orgRolesMap']) => {
this.orgRolesMap = v; };
const host: OrganizationPluginHost = {
get config() { return readConfig(); },
emailLocaleArg: (...a) => this.emailLocaleArg(...a),
// … one closure per method, alphabetical, 8 in all, and:
get orgRolesMap() { return readOrgRolesMap(); },
set orgRolesMap(v) { writeOrgRolesMap(v); },
};
return buildOrganizationPlugin.call(host);
});
```
## The seat's bars
**Body.**
- The body is the same TypeScript token sequence at base and in the
module function: 571 lines with its braces, 1,854 tokens. Each of the
569 lines between the braces is the base line minus exactly four spaces.
The closing brace is the one line that moves further: at base the body
sat at the arrow line's own column, so its `}` was at column 6, and in
the module it is at column 0.
- **`async` moves from the arrow to the function.** The arrow is not
`async`, and it returns `buildOrganizationPlugin.call(host)`, the
function's own promise, so `addOptionalPlugin` awaits the same promise
the body settles. The readers, the writer, the host literal and the
`.call` cannot throw before the promise exists, and a throw inside the
body is still a rejection of it.
- **No parameter, no annotation, no captured local.** The arrow and the
function take no parameter, and neither carries a return annotation. The
body uses no `arguments`, `new.target` or `super` (0 of each), no bare
`this`, and no `this` under a non-arrow function (its one non-arrow
function node is a function type). It reads no local of
`buildPluginList`: `enabled` and `plugins` appear only in the `if` and
in the call's own arguments, and the body's `dataEngine` is its own
local.
- `buildPluginList` is byte-identical at base and at head outside the
arrow, apart from the three comment lines above the call (772 lines at
base, checked by the same run).
**Receiver.**
- The body's `this` was the `AuthManager` instance, the arrow's lexical
receiver. It is now the host.
- `OrganizationPluginHost` names exactly the 10 members the body reads,
no more, each typed as the class member (`AuthManager['x']`).
- 8 are methods, so each goes as a late-bound closure, `(...a) =>
this.x(...a)`: `emailLocaleArg`, `getAppName`, `getConsolePageUrl`,
`getDataEngine`, `getEmailService`, `multiOrgPostureEffective`,
`resolveMembershipRole` and `storedRecipientLocale`. The method runs on
the manager and is looked up when the body calls it, so a spy or double
set on the manager is still the one the body reaches, including from the
organization hooks and the invitation e-mail, which better-auth runs
long after the function returns.
- Two are fields:
- `config`, which the class reassigns after construction
(`setRuntimeBaseUrl` and `applyConfigPatch`), goes as a getter over a
reader closure, `readonly` on the interface. The body reads it 9 times
and never writes it.
- **`orgRolesMap` goes as a get/set pair**, the shape the seat set for a
moved body that writes a field (cut 10, #25508, `routeOwnership` and
`routeOwnershipFor`). The body writes it once (`:2050`,
`this.orgRolesMap = customOrgRoles`) and never reads it. The setter
writes the manager's own field through the writer closure, so the field
the actor guards read back (`assertRemoveMemberPermitted` and
`assertOrganizationDeletable`, through their own getters) is the same
field, written at the same moment, as before. It is not `readonly` on
the interface.
- **Function-valued reads, disclosed** (the way #25516 disclosed
`resolveKernelService`): the body reads five function-valued members off
`this.config`. It calls `this.config.invitationPlacement?.()` (twice,
`:2245` and `:2290`) and `this.config.logger.warn(msg, meta)` (`:2487`)
on their own objects; it reads `onOrganizationCreated` (`:2178`) and
`onInvitationAccepted` (`:2307`) into a local `cb` and calls that; and
it hands `getI18n` on as a value (`:2485`). Each is read off the object
the getter returns, the manager's current `config`, at the same moment
as before, so every call has the same callee and the same `this`.
- The body reads no `AuthManager.X`, so the module imports the class as
a type only.
**Eight top-level declarations, exported in place, and one already
exported.**
- The body reads nine top-level declarations of `auth-manager.ts`:
- the five organization hook refusal codes:
`ORGANIZATION_RESERVED_IDENTIFIER_CODE`,
`ORGANIZATION_CREATION_DISABLED_CODE`,
`INVITE_PLACEMENT_UNSUPPORTED_CODE`,
`INVITE_PLACEMENT_OUTSIDE_ISSUER_SCOPE_CODE` and
`ORGANIZATION_SLUG_LOCKED_CODE`;
- the slug guard's and the placement check's read-fault answers,
`slugGuardReadFaultApiError` and `invitationPlacementReadFaultApiError`;
- the placement gate's refusal test, `isInvitationPlacementGateRefusal`;
- `readInvitationPlacementIntent`, which is already exported.
- Per ruling `6364006498` (A), the eight unexported ones get `export` in
place, in this cut, the first whose body reads them, and the module
imports all nine by value from `./auth-manager.js`. The binding proof
checks that each head declaration is the base one with `export ` in
front and nothing else changed, and that the base and head reads resolve
to it.
- They stay where they are, so the two read-fault answers and their `new
APIError(` sites stay in `auth-manager.ts`.
- `src/index.ts` names its `auth-manager.ts` exports one by one and
names none of them, so nothing new is published.
`readInvitationPlacementIntent` was exported and published at base, and
is in both export lists and in `dist/index.d.ts` at both ends,
unchanged.
**Host lifetime.** The host is built each time `addOptionalPlugin` runs
the factory, which `buildPluginList` does once per build, as every stub
in this series builds its host per call. Nothing the body reads is
captured early: the closures look each method up on the manager at call
time, and the getter and the get/set pair read and write the fields when
the body, or a hook it handed better-auth, does.
**Readers.** The decision letters are read on the merge base and on the
head below: none drop, and the new module is anchored by the entry under
Path readers. Tenant census and symbol-anchor output are byte-identical
at both ends, and the full plugin-auth suite passes at both ends. The
four path readers whose text or lists name where the moved lines live
are migrated in this commit.
## Imports and evaluation order
Fifteen imported names leave `auth-manager.ts`, because the body was
their last reader there:
- the type `OrganizationOptions` (its whole
`better-auth/plugins/organization` line);
- the whole `./cloud-managed.js` line (`CLOUD_MANAGED_REFUSAL_CODE`,
`CLOUD_MANAGED_REFUSAL_MESSAGES`);
- `resolveOrgLimit` (the `@objectstack/types` block keeps
`resolveTenancyPosture` and `isMcpServerEnabled`);
- the whole `./membership-limit.js` line
(`resolveMembershipLimitOption`);
- the whole `@objectstack/spec` block
(`MEMBERSHIP_ROLE_DELEGATED_ADMIN`, `MEMBERSHIP_ROLE_EXTERNAL`);
- `withSystemContext` (the `./objectql-adapter.js` line keeps
`createObjectQLAdapterFactory` and `withSystemReadContext`);
- the whole `./list-user-invitations-verification.js`,
`./invitation-role-cap.js`, `./invitation-role-label.js` and
`./organization-delete.js` blocks
(`applyDeclaredInvitationVerificationToListing`,
`invitationRoleCapFailure`, `isPlainMemberInvitation`,
`invitationRoleLabel`, `isDefaultOrganizationTarget`,
`removeOrganizationAuthStructure`);
- `buildOrganizationPluginSchema` (the `./auth-schema-config.js` block
keeps its other names).
One comment and one line are added after cut 14's: `import {
buildOrganizationPlugin, type OrganizationPluginHost } from
'./auth-manager-organization-plugin.js'`. `isCloudManaged`,
`postureEnforcesWall`, `resolveTenancyPosture`, `withSystemReadContext`
and `isPlaceholderEmail` have other readers, so both files import them.
One prose mention of `withSystemContext` stays in a docblock (`:892` at
head, in backticks, not a `{@link}`), so nothing dangles.
esbuild drops a type-only import, so a module whose last value import
leaves `auth-manager.ts` can now be evaluated later. The order was
measured rather than argued:
- **The ES modules, at run time.** A loader hook logged each ES module
as its body ran while `dist/index.mjs` loaded, at base and at head. 171
modules evaluate at both, in the same order apart from one adjacent pair
just before the bundle's own body:
`@objectstack/platform-objects/identity` and
`@better-auth/core/utils/ip` swap places (169 and 170). The bundle's
first `platform-objects/identity` import is `invitation-role-label.ts`'s
(`SysMember`), and that module's segment now sits later in the bundle
(line 4,828 at base, 8,522 at head), after the first `utils/ip` import.
Neither module imports the other. `utils/ip`'s top level imports
`@better-auth/core`'s env module and `zod`, builds two `zod` schemas and
declares constants and functions; `platform-objects/identity` imports
three `@objectstack/spec` entries, all evaluated earlier at both, and
builds object schemas. Neither writes `process.env` or a global.
- **The CommonJS entry.** A `Module._load` log for `dist/index.js` gives
127 first loads at both. Two move earlier:
`@better-auth/core/dist/utils/ip.mjs` and
`@better-auth/core/dist/context/index.mjs` were the last two loads at
base and now come right after `@objectstack/spec/identity`, ahead of
`platform-objects/identity`, `rest`, `observability`, `metadata-core`,
node's `module` and `metadata/view-container`. Their top levels are the
ones above and the inert `context` chain cut 14 measured (its only
load-time reads are of `process.env`), and none of those five package
entries writes `process.env` or a global anywhere in its file (`module`
is node's own).
- **plugin-auth's own modules.** A walk of the bundle's top level and
its eager `init_*` calls finds six that run later at both entries:
`cloud-managed.ts`, `membership-limit.ts`,
`list-user-invitations-verification.ts`, `invitation-role-label.ts`,
`organization-delete.ts` and `grant-set-name.ts`, whose last value
import from `auth-manager.ts` left with the body (`grant-set-name.ts`
moves with `organization-delete.ts`, which imports it). Their top levels
are imports, constants with no call in their initializers, types and
function declarations: no load-time call at all. No importer reads any
of their bindings at load time: all 35 references in the 11 importing
files are inside functions, and `index.ts` re-exports `cloud-managed.ts`
with `export *`, which reads nothing.
- The new module's own top level is imports, one interface and one
function declaration. Its value import of `auth-manager.ts`, for the
nine declarations, and `auth-manager.ts`'s import of it form a cycle
with nothing read at load time, as cut 14's does.
## The decision-letter layer: 0 drop
`check-adr-anchors`, measured on the merge base and on the head. The
gate exits 0 at both.
| point | anchored files | citations | files | decision letters |
|---|---:|---:|---:|---:|
| merge base `ba9e0c3749` | 84 | 52,305 | 6,698 | 1,939 |
| head `361581a546` | 85 | 52,307 | 6,700 | 1,939 |
- The body's letters leave `auth-manager.ts`, which is anchored, for the
new module, which the new entry below anchors, so the count does not
move.
- The two new citations are the entry's two `ADR-0108` mentions; the two
new files are the module and the entry.
## Path readers
Four readers outside the move follow it, in this commit, and one anchor
entry is added:
- **`api-error-code.pin.test.ts`**: `authManagerFiles`, the files
`AuthManager`'s throws are counted over, gains
`auth-manager-organization-plugin.ts`. The body carries 7 `new
APIError(` sites, so the sum over the list is 30 at head, as at base (7
in the module; `auth-manager.ts` goes 9 → 2, the two read-fault answers
that stay). Without the new entry the sum would be 23, under the floor
of 24, and the pin would fail: it is a floor over a list, not a silent
zero.
- **`better-auth-schema-parity.test.ts` and
`managed-extension-fields.test.ts`**: each one's
`authManagerPluginFactories()` scans a list of files for `const { X } =
await import('better-auth/plugins…' | '@better-auth/…')`, and both lists
gain `auth-manager-organization-plugin.ts` (the comment above each list
now says "any of them" for "either"). The body holds one such import,
`organization`. At base the scan finds 16 factories; at head without the
new entry it would find 15, missing `organization`, which each test's
stale-entry check fails on; with it the scan finds the same 16 as base.
- **`auth-email-locale.test.ts`**: the two population comments (the
docblock at `:861` and the in-test note at `:1127`, head numbering) that
name the files the five `sendTemplate` sites live in now name
`auth-manager-organization-plugin.ts` (the body of the organization
plugin's factory) among them; the invitation send moved with the body.
No assertion, count or pattern changes.
- **The anchor entry**:
`scripts/adr-anchors/packages__plugins__plugin-auth__src__auth-manager-organization-plugin.ts.json`
(new), with `adrs: ["ADR-0108"]` and the `auth-manager.ts` entry's
ADR-0108 paragraph verbatim ("better-auth's organization roles map
registers the closed framework vocabulary ONLY…"). The body is that
mechanism: it builds the roles map from the closed vocabulary and stores
it. This is cut 4's precedent (an entry for the new module carrying the
paragraph verbatim; the old entry stays unchanged), and ruling
`6353073966` item 1 says `scripts/adr-anchors/` is not a
governed-register row. The `auth-manager.ts` entry is not edited: it
keeps ADR-0108, which the file still cites (`:771`, the
`additionalOrgRoles` removal note), and its ADR-0093 D2 paragraph.
Read, and not edited:
- **`scripts/check-dispatcher-error-vocabulary.mjs`**: the body's 7 `new
APIError(` sites each carry a registered or standard code, and the
gate's only per-file `plugin-auth` key is `liveMemberFile`
(`auth-manager-before-hook.ts`), which the cut does not touch. It exits
0 at both, 56 sites found and 56 classified at both, and only its
scanned-file count moves (3,434 → 3,435). `--self-test` is among the
derived gates.
- **The tenant-audit census.** No census site moves: the body's engine
calls are reads. `check-tenant-audit-census` exits 0 at both with no
`--write`, with byte-identical output. Its `--json` document has 238
sites at both and 0 per-site differences with line numbers ignored. 2
sites are in `auth-manager.ts` at both, 0 are in the new module, and 0
are unresolved or unledgered at both. Only `scannedSources` (753 → 754)
and `measuredAt` move, so neither census document is edited.
- **`scripts/measure-durability-swallow-family.mjs`** (a measurement,
not a gate): 77 members and 84 quiet rows at both, identical with line
numbers ignored (one member, in `observeFirstMemberships`, which stays,
moves 566 lines up with the cut's net: `:4442` → `:3876`). Every
statistic is the same apart from `files` (3,484 → 3,485):
`tryStatements` 3,646 and `droppedNotAwaited` 234 at both.
- **`check-auth-mount-ledger.mjs`** reads only the `basePath`
declaration in `auth-manager.ts`, which stays.
**`auth-manager-base-path.test.ts`** reads `auth-manager.ts` for code
lines carrying `'/api/v1/auth'`; the body has none.
- **`rate-limit-storage-isolation.test.ts`** walks the import graph from
`rate-limit-storage.ts`, which reaches neither file. It passes at head.
- **`check-system-context-census.mjs`** tracks reads of
`ExecutionContext.isSystem`; the body names it once, in a comment.
**`scripts/publish-smoke.sh`** names `auth-manager.ts` for the `admin:
pluginConfig.admin ?? scimEffective` line, in the `enabled` literal,
which stays.
- **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, at base with the body blanked, and at head.
Two of their symbols occur as a token on a line of the body:
`AuthManager` (ADR-0135 `:104`), whose declaration is the class, which
stays, and `ORGANIZATION_CREATION_DISABLED_CODE` (the
attachments-storage checklist area `:1116`), whose declaration (`:1403`
at base) stays and gains only `export`. Each resolves to its declaration
at all three readings.
## Proof
Builds and suites ran through `os-verify-lock`, and every exit code was
captured before any pipe. Base `ba9e0c3749`. A full `turbo run build`
ran first. Then `plugin-auth` was built and its suite run at base, and
built and run again at head, on the same dependency dists.
**1. The moved text.**
- **Token identity:** the base arrow body and the module 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): 571 lines and 1,854 tokens, each line between the
braces the base line minus four spaces.
- **The stub's shape**, checked by the same run: the arrow is not
`async` and takes no parameter; it holds the two reader closures and the
writer closure, one host literal whose keys are exactly
`OrganizationPluginHost`'s, alphabetical, whose 8 method values are each
`(...a) => this.<key>(...a)`, whose `config` is a getter over its reader
and whose `orgRolesMap` is a getter over its reader and a setter over
the writer, then `return buildOrganizationPlugin.call(host)`, and
nothing else. The interface types every member `AuthManager['x']`, and
exactly the getter-only field is `readonly`. `buildPluginList` outside
the arrow is byte-identical apart from the three comment lines.
- **Binding identity:** a second proof walks all 496 identifiers of the
body at base and in the module, in order, and resolves each with the
TypeScript checker (the module's `./auth-manager.js` resolved to the
head file, where the in-place exports live). All 496 resolve the same
way at both ends:
- 324 to a declaration inside the body, the same declaring identifier by
position;
- 18 to receiver members (`AuthManager` at base,
`OrganizationPluginHost` at head);
- 31 reads of 29 imported names, with the same specifier and imported
name, the nine `./auth-manager.js` names among them;
- 11 to the same declaration in `auth-manager.ts`: seven
`AuthManagerOptions` members read through `this.config` (`dataEngine`,
`getI18n`, `invitationPlacement`, `logger` and its `warn`,
`onInvitationAccepted` and `onOrganizationCreated`), and the `locale` of
`emailLocaleArg`'s answer;
- 112 to no declaration: globals and property names on untyped values.
None resolves to a local of `buildPluginList`, to an unexported
top-level declaration of `auth-manager.ts` or to a top-level declaration
of the module.
- **Negative controls:** each proof reads the module text, and each
control changes it in memory only; the file is untouched.
- Token proof: `organization(organizationOptions)` changed to
`organization?.(organizationOptions)` fails the token and line checks,
and the run exits 1.
- Binding proof: the module's `membership-limit` import pointed at
another specifier gives 1 difference, and the run exits 1. The
`placeholder-email` import shadowed by a module-level `const` gives 1
difference and reports the module top-level read, and exits 1. Run
without being told about the in-place exports, it reports the base reads
of the eight unexported declarations, and exits 1.
- **An independent reading:** `git diff --color-moved=plain
--color-moved-ws=allow-indentation-change ba9e0c3 361581a` over
the two source files marks 577 of the 600 deleted lines and 580 of the
717 added lines as moved.
- The 23 unmoved deletions are 14 import lines (the import names and
block closers listed under Imports, and the `./objectql-adapter.js`
line, rewritten without `withSystemContext`), the first lines of the
eight declarations (now with `export`) and the arrow's own line (now
without `async`).
- The other added lines are the module header, its import lines, the
host interface and its docblock, the function signature and docblock,
the stub's comment, readers, writer, host literal and `return`, the
eight `export` lines, the rewritten `./objectql-adapter.js` line, and
the new import comment and line.
**2. `.d.ts` and exports (ruling `6348891160` items 1 and 2).**
| file | base and head | raw diff lines |
|---|---|---:|
| `dist/index.d.ts` raw |
`1b3a48357d137155de33104277667a922aab62df73b418b03894c56faaacd0ba` | 0 |
| `dist/index.d.ts` normalised |
`cee7303ccdfe72794efd588c85b628419d4253d730b5a0c5a3f1cdb8dddb4443` | |
| `dist/index.d.mts` raw |
`b5e8dc982b634f0a5108b1b533626a68767f2da5a56f72dba801059b149e2872` | 0 |
| `dist/index.d.mts` normalised |
`562d0a4ce656f97aeb937541482cdf531b61d7c75a005918784bf0a52d032dfc` | |
- 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 byte-identical, so no union-order swap occurs: 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 buildPluginList;` → `buildPluginList;`,
line 1829, a one-line change) hashes raw
`f8ff1470cbc34cd34a441c67b8763c5adde86fa408a4bcecf1590c60d30bce57` and
normalised
`fe48a6a7f320e626e941a422a27571c28fbdc47a73bbbdaa0d5048d7307cae55`. 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). None of the eight
declarations exported in place, `buildOrganizationPlugin` or
`OrganizationPluginHost` is among them, and `dist/index.d.ts` names none
of them.
- **The bundle:** `tsup` bundles the new module into the root entry
(`splitting: false`). The dist has the same 18 files at base and at
head, plus the two `.build-input-hash` stamps the build writes from its
inputs. Only `index.js`, `index.mjs` and their maps differ.
**3. Tests and lint.**
- `pnpm exec vitest run --maxWorkers=3` in
`packages/plugins/plugin-auth`: base `Test Files 191 passed (191)`,
`Tests 3626 passed | 10 skipped (3636)`, 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` over the 6 TypeScript files: exit 0.
**4. The censuses, the measurement and the anchors, at base and at
head.**
- The tenant-audit census, as above: byte-identical gate output, 238
sites at both, 0 per-site differences line-blind, 0 unresolved and 0
unledgered at both.
- The durability measurement, as above, with its one moved statistic
traced.
- 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.
Five print byte-identical output at both (`cmp` clean):
- `check-adr-symbol-anchors`: 2,384 anchors across 142 records, 466
symbol (440 declaration, 26 literal);
- `check-scripts-symbol-anchors`: 4,070 anchors;
- `check-spec-docblock-symbol-anchors`: 5,076 anchors;
- `check-system-context-census`: 149 elevation read sites;
- `check-platform-checklist`: 16 areas, 329 items.
The sixth, `check-adr-anchors`, differs only in the anchored-file,
citation and file counts, as in the table above, with the decision
letters equal.
**5. Gates.**
- `node scripts/pm/dispatch-gates.mjs --commands --repo
objectstack-ai/objectstack` derives 71 commands for the 7 paths. All 71
ran at head after the full build, and all 71 exited 0.
- `--ran` over the record with each exit code: 71 derived, 71 run, 0
NOT-MEASURED, a derived zero. `--tier`: no path-derived mandate.
- `check-governed-merges.mjs`: on the trial file list before the cut and
`--branch HEAD` after the commit, both read NOT governed (0 of 7 paths
hit the register), 1,342 changed lines.
- **Docs drift** (`node scripts/docs-audit/affected-docs.mjs --json
ba9e0c3`, exit 0): 41 pages, all name matches of names the moved code
carries (the `VALIDATION_ERROR`, `sys_member`, `sys_organization`,
`sys_invitation` and `sys_environment` literals, and `AuthManager`). One
names `auth-manager.ts`: `content/docs/kernel/services-checklist.mdx`
(`:314`), for the identity provider service as a whole, which still
holds. The code that reads those names is unchanged, so no doc edit is
owed. 11 of the 41 are release-owned (the release notes and
`releases/implementation-status.mdx`) and not edited.
- **Serial constraints** (in the claim, and re-read at 03:13Z before
this PR): 8 PRs are open, and none touches `auth-manager.ts`, the new
module's path, a reader edited above or `scripts/adr-anchors/`. The
Version Packages PR #24876 touches `plugin-auth`'s `package.json`, its
`CHANGELOG.md` and changesets only. `origin/main` has moved 8 merges
past this base, to `e073455929`; none touches `plugin-auth`,
`scripts/adr-anchors/` or a reader named above.
## 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](https://claude.ai/code/session_01LSXBc2GCBwiAL7vV4kWkyr)_
🤖 Generated with [Claude Code](https://claude.com/claude-code)
https://claude.ai/code/session_01LSXBc2GCBwiAL7vV4kWkyr
Co-authored-by: Claude <noreply@anthropic.com>
1 parent e57a4c3 commit f192123
7 files changed
Lines changed: 734 additions & 608 deletions
File tree
- packages/plugins/plugin-auth/src
- scripts/adr-anchors
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
182 | 182 | | |
183 | 183 | | |
184 | 184 | | |
| 185 | + | |
185 | 186 | | |
186 | 187 | | |
187 | 188 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
859 | 859 | | |
860 | 860 | | |
861 | 861 | | |
862 | | - | |
863 | | - | |
| 862 | + | |
| 863 | + | |
| 864 | + | |
864 | 865 | | |
865 | 866 | | |
866 | 867 | | |
| |||
1124 | 1125 | | |
1125 | 1126 | | |
1126 | 1127 | | |
1127 | | - | |
1128 | | - | |
| 1128 | + | |
| 1129 | + | |
1129 | 1130 | | |
1130 | 1131 | | |
1131 | 1132 | | |
| |||
Large diffs are not rendered by default.
Large diffs are not rendered by default.
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
320 | 320 | | |
321 | 321 | | |
322 | 322 | | |
323 | | - | |
324 | | - | |
| 323 | + | |
| 324 | + | |
325 | 325 | | |
326 | 326 | | |
327 | 327 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
630 | 630 | | |
631 | 631 | | |
632 | 632 | | |
633 | | - | |
634 | | - | |
| 633 | + | |
| 634 | + | |
635 | 635 | | |
636 | 636 | | |
637 | 637 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
0 commit comments