Repository navigation
Commit abdc7f2
<!-- 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. 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 two declarations this cut exports in place inside the package,
`buildPluginList` and `PluginListHost` 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
eighth cut it applies to.
Cut 16 of the `auth-manager.ts` split, and the series' last: **the rest
of `buildPluginList`, which is its whole body**. It is the second of the
two `buildPluginList` cuts the seat set at 02:10Z (the `organization`
factory in cut 15, #25594, then the rest of the method). The series ends
after this cut; once it lands, the final report goes on #25224.
This follows the amended claim `6383249105`, which amends `6379187398`
on the file cut 15 left (#25594, landed note `6382750527`). The shape is
the #23050 method move cuts 1 to 11 and 14 used, with cut 10's get/set
pair (#25508) for the two fields the body writes.
Branch: `claude/project-thread-lg3wrj`, the harness-pinned branch for
this session, restarted from `origin/main` after #25594 merged. It names
no issue, so the card relation is this body's first line.
`auth-manager.ts` goes from 6,556 to 5,789 lines. The cut is +961 / −813
over 5 files: 1,774 changed lines, under the 3,000-line line. Two of the
five files are path readers outside the move and one carries two
comments, so `check-governed-merges.mjs` ran on the trial file list
before the cut: NOT governed (0 of 5 paths hit the register), and
`--branch HEAD` agrees. One commit: `a2413e05ce` `refactor(plugin-auth):
move the buildPluginList body into auth-manager-plugin-list.ts`.
## The move
| moved | base lines | proof lines | tokens | members it reads |
|---|---|---:|---:|---:|
| the body of `buildPluginList` | `:1876`–`:2666` | 793 | 2,096 | 18
methods, 4 fields |
The lines are base `10b8250ad5`. The 793 proof lines are the body with
its braces (the method's `{` on `:1875` to its `}` on `:2667`).
- **What it is:** `buildPluginList` (`:1875`, `private async`, annotated
`Promise<any[]>`) builds better-auth's plugin list. `createAuthInstance`
calls it once per build, as `await this.buildPluginList()`, through its
host's closure since cut 14.
- **What the body does, in order** (all of it moves, with its comments):
the reset of the degraded-feature record and of the JWT signing verdict;
the `enabled` table (the env and config precedence it documents and the
SCIM coherence re-check); and every plugin in the same order: `bearer`,
the `organization` factory's arrow (whose body cut 15 moved),
`twoFactor`, breached-password rejection, `admin`, `phoneNumber`,
`magicLink`, the generic OAuth providers, the OIDC provider with its
`jwt` plugin, `sso`, `scim`, device authorization and the custom
session, then `return plugins`.
- **Where it goes:** a new module,
`packages/plugins/plugin-auth/src/auth-manager-plugin-list.ts` (913
lines). The body becomes the body of `export async function
buildPluginList(this: PluginListHost): Promise<any[]>`, re-indented two
spaces (one level) and otherwise unedited. The module header gives the
reasoning, in the form the fifteen earlier `auth-manager-*.ts` modules
use.
- **What stays:** `buildPluginList` keeps its place, its docblock, its
`private` modifier, its (empty) parameter list and its return
annotation. Its body is now:
```ts
private buildPluginList(): Promise<any[]> {
// [#25224 cut 16] The body moved to `auth-manager-plugin-list.ts` (see
`PluginListHost`).
const readConfig = () => this.config;
const readDegradedFeatures = () => this.degradedFeatures;
const readJwtSigningFailureReported = () =>
this.jwtSigningFailureReported;
const writeJwtSigningFailureReported = (v:
AuthManager['jwtSigningFailureReported']) => {
this.jwtSigningFailureReported = v; };
const readOrgRolesMap = () => this.orgRolesMap;
const writeOrgRolesMap = (v: AuthManager['orgRolesMap']) => {
this.orgRolesMap = v; };
const host: PluginListHost = {
addOptionalPlugin: (...a) => this.addOptionalPlugin(...a),
buildJwtPlugin: (...a) => this.buildJwtPlugin(...a),
computeAuthGate: (...a) => this.computeAuthGate(...a),
get config() { return readConfig(); },
get degradedFeatures() { return readDegradedFeatures(); },
// … one closure per method, alphabetical, 18 in all, and:
get jwtSigningFailureReported() { return
readJwtSigningFailureReported(); },
set jwtSigningFailureReported(v) { writeJwtSigningFailureReported(v); },
get orgRolesMap() { return readOrgRolesMap(); },
set orgRolesMap(v) { writeOrgRolesMap(v); },
};
return buildPluginList.call(host);
}
```
## The seat's bars
**Body.**
- The body is the same TypeScript token sequence at base and in the
module function: 793 lines with its braces, 2,096 tokens. Every one of
the 793 lines is the base line minus exactly two spaces.
- **`async` moves from the method to the function.** The stub is not
`async`, and it returns `buildPluginList.call(host)`, the function's own
promise, so `createAuthInstance`'s `await this.buildPluginList()` awaits
the same promise the body settles. The readers, the writers, the host
literal and the `.call` cannot throw before the promise exists, and a
throw inside the body is still a rejection of it.
- **Same parameters, same annotation.** The base method, the stub and
the function take no parameter and carry the same return annotation,
`Promise<any[]>`. The body uses no `arguments`, `new.target` or `super`
(0 of each), no bare `this`, and no `this` under a non-arrow function
(its only non-arrow function nodes are the getter and the setter in the
`organization` arrow's host literal, which read and write through their
closures and name no `this`).
**Receiver.**
- The body's `this` was the `AuthManager` instance. It is now the host.
- `PluginListHost` names exactly the 22 members the body reads, no more,
each typed as the class member (`AuthManager['x']`).
- 18 are methods, so each goes as a late-bound closure, `(...a) =>
this.x(...a)`: `addOptionalPlugin`, `buildJwtPlugin`, `computeAuthGate`,
`deliverPhoneOtp`, `emailLocaleArg`, `enforceSessionControls`,
`getAppName`, `getConsolePageUrl`, `getDataEngine`, `getEmailService`,
`getMcpResourceUrl`, `isPlatformAdminUserId`,
`multiOrgPostureEffective`, `reconcileScimUserLifecycle` (which stays in
the class, per ruling A), `resolveAuthSecret`, `resolveMembershipRole`,
`resolveTwoFactorAccountLockout` 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 callbacks it hands better-auth (the phone OTP senders, the
magic-link sender and the custom session among them), which run long
after the function returns. Every method read is a direct call.
- Four are fields:
- `config`, which the class reassigns after construction
(`setRuntimeBaseUrl` and `applyConfigPatch`), and `degradedFeatures`, as
every field this series carries goes, go as getters over reader
closures, `readonly` on the interface. The body reads `config` 7 times
and writes neither.
- **`jwtSigningFailureReported` and `orgRolesMap` go as get/set pairs**,
the shape the seat set for a moved body that writes a field (cut 10,
#25508; cut 6's `reportJwtSigningFailure` stub carries the first the
same way, and cut 15 carried `orgRolesMap` so). The body resets
`jwtSigningFailureReported` once (`:1881`, `= false`) and never reads
it. It reads and writes `orgRolesMap` only through the `organization`
arrow's reader and writer (`:1978`, `:1979`). Each setter writes the
manager's own field through its writer closure, so
`reportJwtSigningFailure`, which reads the flag back, and the actor
guards, which read the roles map back, read the same field, written at
the same moment, as before. Neither is `readonly` on the interface.
- **Function-valued reads, disclosed** (the way #25516 disclosed
`resolveKernelService`): the body calls `this.degradedFeatures.clear()`
(`:1876`) on the object the getter returns, the manager's own `Map`, at
the same moment as before. Its `this.config` reads are data (`plugins`,
`phoneOtp`, `oidcProviders`, `dataEngine`); none is called.
- The body reads no `AuthManager.X`, so the module imports the class as
a type only. Its one read of the class is a type position
(`AuthManager['orgRolesMap']`, `:1979`, in the `organization` arrow's
writer).
**The `organization` arrow.** It moves with the body, unedited, and
builds its host from `this`, which is now this host: each of its eight
closures calls this host's closure, which calls the manager's method;
its `config` getter reads this host's getter; its `orgRolesMap` reader
and writer read and write this host's pair, which read and write the
manager's field. So it reaches the same members, and the same field, at
the same moment as before (cut 14's precedent for a moved body holding
an earlier cut's stub). Its import (`buildOrganizationPlugin` and
`OrganizationPluginHost`) moves to the new module with it.
**Two top-level declarations, exported in place, and five already
exported.**
- The body reads seven top-level declarations of `auth-manager.ts`:
`readBooleanEnv` (`:347`, 4 reads) and `consentOrganizationOf` (`:1453`,
once), which were not exported, and `resolveScimEnabled`,
`assertScimAdminCoherence`, `resolveOidcProviderEnabled`,
`resolveDcrEnabled` and `OAUTH_ORGANIZATION_CLAIM`, which were.
- Per ruling `6364006498` (A), the two get `export` in place, in this
cut, the first whose body reads them, and the module imports all seven
by value from `./auth-manager.js`, with the class as a type. 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.
- `src/index.ts` names its `auth-manager.ts` exports one by one and
names neither, so nothing new is published.
**Host lifetime.** The host is built each time `buildPluginList` is
called, which `createAuthInstance` 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 getters and the get/set pairs read and write the fields when the
body, or a callback it handed better-auth, does.
**Readers.** The decision letters are read on the merge base and on the
head below: 19 leave the anchored surface, disclosed. Tenant census and
symbol-anchor output are byte-identical at both ends, and the full
plugin-auth suite passes at both ends. The three readers whose lists or
comments name where the moved lines live are migrated in this commit.
## Imports and evaluation order
Nine imported names leave `auth-manager.ts`, because the body was their
last reader there:
- `resolveUserAuthzGrants` (the `@objectstack/core` block keeps its
other names);
- the whole `./admin-impersonate-endpoint.js` block
(`applyPlatformAdminImpersonation`);
- the whole `./auth-schema-config.js` block
(`buildTwoFactorPluginSchema`, `buildOauthProviderPluginSchema`,
`buildDeviceAuthorizationPluginSchema`, `buildAdminPluginSchema`,
`buildPhoneNumberPluginSchema`);
- cut 15's `./auth-manager-organization-plugin.js` line
(`buildOrganizationPlugin`, `type OrganizationPluginHost`) with its
three comment lines.
One comment and one line replace cut 15's: `import { buildPluginList,
type PluginListHost } from './auth-manager-plugin-list.js'`.
`AuthPluginConfig` (a type), `MCP_OAUTH_SCOPES` and `isPlaceholderEmail`
have other readers, so both files import them.
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.
- **The CommonJS entry.** A `Module._load` log for `dist/index.js` gives
127 first loads at both, in the same order.
- **plugin-auth's own modules.** A walk of the bundle's top level and
its eager `init_*` calls finds three that run later at both entries,
whose last value import from `auth-manager.ts` left with the body:
`auth-schema-config.ts`, `admin-impersonate-endpoint.ts` and
`impersonation-bearer-rotation.ts` (which
`admin-impersonate-endpoint.ts` imports). At the CommonJS entry
`platform-admin-gate.ts` also moves, by two places: it ran two modules
before `principal-session-mint.ts` at base and runs right after it at
head; `principal-session-mint.ts` imports `judgeHeldSession` from it and
reads it inside a function only. The top levels of all five are imports,
types, constants and function declarations (`principal-session-mint.ts`
adds one `extends Error` class), with no load-time call, apart from
`admin-impersonate-endpoint.ts`'s `VENDOR_ROLE_SCALAR_ADMIN_PATHS`, a
`new Set` of string literals (`:191`). No importer reads any of their
bindings at load time: all 41 references in the 16 files that import one
of these five or the new module (`auth-manager.ts` among them) are
inside functions, and `index.ts` re-exports `platform-admin-gate.ts` and
`auth-schema-config.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
seven declarations, and `auth-manager.ts`'s import of it form a cycle
with nothing read at load time, as cut 14's and cut 15's do.
## The decision-letter layer: 19 drop, disclosed
`check-adr-anchors`, measured on the merge base and on the head. The
gate exits 0 at both, and every citation still resolves.
| point | anchored files | citations | files | decision letters |
|---|---:|---:|---:|---:|
| merge base `10b8250ad5` | 85 | 52,467 | 6,589 | 1,872 |
| head `a2413e05ce` | 85 | 52,467 | 6,590 | 1,853 |
- **No anchor entry; 19 letters leave the anchored surface, disclosed.**
By the gate's count the body carries 19 decision-letter citations, at
these sites: ADR-0057 D4 (`:2532`, `:2569`, `:2594`), ADR-0068 D1/D2
(`:2526`, `:2555`), ADR-0068 D2 (`:2032`, `:2595`, `:2603`), ADR-0069 D1
(`:2007`), D2 (`:2001`), D3 (`:2046`) and D4 (`:2643`), ADR-0090 D3
(`:2526`, `:2555`) and D5 (`:2533`), ADR-0131 D7 (`:2196`) and ADR-0135
D6 (`:1913`, `:2404`, `:2435`). They leave `auth-manager.ts`, which is
anchored, for a module that is not, so the count drops by 19 while the
gate stays green and every citation still resolves. The
`auth-manager.ts` entry carries two paragraphs: ADR-0093 D2 (the
membership reconciler, which stays) and ADR-0108 (the organization roles
map, whose mechanism cut 15 moved to
`auth-manager-organization-plugin.ts`, anchored by its own entry).
Neither describes this body, so no entry is owed, per the seat's ruling
after cut 5 (an entry would need new invariant text, which a move-only
cut must not add; the drop is recorded in the ACCEPT), as cut 14
recorded its 8.
## Path readers
Three readers outside the move follow it, in this commit:
- **`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-plugin-list.ts` (`:324` and `:634`). The body holds
13 such imports, all of `auth-manager.ts`'s (13 → 0). At base the scan
finds 16 factories; at head without the new entry it would find 3
(`organization` from the cut 15 module and the two in
`auth-manager-actor-guards.ts`), missing 13, 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 `:863` and the in-test note at `:1130`, head numbering) that
name the files the five `sendTemplate` sites live in now name
`auth-manager-plugin-list.ts` (the body of `buildPluginList`) among
them; the magic-link send moved with the body, and `auth-manager.ts`
keeps one. No assertion, count or pattern changes.
Read, and not edited:
- **`api-error-code.pin.test.ts`**: the body carries no `new APIError(`
site, so `authManagerFiles` is not owed the new module. Its sum stays
30, as at base.
- **`scripts/check-dispatcher-error-vocabulary.mjs`**: the body carries
no code-stamping site (no `code:` and no `new APIError(`), 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 its output is
identical apart from its scanned-file count (3,444 → 3,445). Its
`--self-test` runs inside the derived `pnpm
check:dispatcher-error-vocabulary`.
- **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` (762 → 763)
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 767 lines up with the cut's net: `:3876` → `:3109`). Every
statistic is the same apart from `files` (3,494 → 3,495):
`tryStatements` 3,647 and `droppedNotAwaited` 230 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 has none in code.
**`check-cross-package-test-inputs.mjs`** names `auth-manager.ts` in a
self-test fixture only.
- **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.
Seven of their symbols occur as a token on a line of the body, and each
one's declaration stays where it was: `resolveScimEnabled` (ADR-0134
`:90`, `:127`), `reconcileScimUserLifecycle` (`:158`, `:263`; the
method, which stays per ruling A), `assertScimAdminCoherence` (`:171`),
`AuthManager` (ADR-0135 `:104`, the class), `resolveOidcProviderEnabled`
(the ai checklist area `:737`, identity-auth `:1166`), `computeAuthGate`
(identity-auth `:1718`, the method) and `twoFactor` (identity-auth
`:1429`, which resolves to `getPublicConfig`'s `features.twoFactor`,
`:5301` at base, which stays). Each resolves to its declaration at all
three readings.
- **Prose that now points one file early, disclosed, not edited** (cut
14's precedent: a comment that reads no file is not a path reader):
`scripts/publish-smoke.sh:1131` names `auth-manager.ts` for the `admin:
pluginConfig.admin ?? scimEffective` line, which now sits in the module;
the `why` of the `deliverPhoneOtp` row in
`packages/runtime/src/dispatcher-error-vocabulary.ts` (`:1359`) says its
two callers are `sendOTP` hooks in `auth-manager.ts`, which now sit in
the module (the row's `file` field, which the gate reads, names
`auth-manager-email-sms-delivery.ts` and is unchanged); and
`auth-manager-organization-plugin.ts`'s header describes the
`organization` call in `buildPluginList`, which is now the module
function's. If the seat wants any of them re-pointed, it is a comment
edit in this PR.
## Proof
Builds and suites ran through `os-verify-lock`, and every exit code was
captured before any pipe. Base `10b8250ad5`. 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 method 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): 793 lines and 2,096 tokens, each line the base line
minus two spaces.
- **The stub's shape**, checked by the same run: the stub is not
`async`, takes no parameter and keeps the docblock, `private` and
`Promise<any[]>`; it opens with the six reader and writer closures (one
reader per field, one writer per get/set field), then one host literal
whose keys are exactly `PluginListHost`'s, alphabetical, whose 18 method
values are each `(...a) => this.<key>(...a)`, whose `config` and
`degradedFeatures` are getters over their readers and whose
`jwtSigningFailureReported` and `orgRolesMap` are getters over their
readers and setters over their writers, then `return
buildPluginList.call(host)`, and nothing else. The interface types every
member `AuthManager['x']`, and exactly the two getter-only fields are
`readonly`. The run also checks that the body writes exactly the two
get/set fields.
- **Binding identity:** a second proof walks all 500 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 500 resolve the same
way at both ends:
- 338 to a declaration inside the body, the same declaring identifier by
position;
- 48 to receiver members (`AuthManager` at base, `PluginListHost` at
head);
- 23 reads of 20 imported names, with the same specifier and imported
name, the eight `./auth-manager.js` names among them;
- 10 to the same declaration in `auth-manager.ts`: six
`AuthManagerOptions` members read through `this.config` (`dataEngine`,
`oidcProviders`, and `phoneOtp` with its `allowedAttempts`, `expiresIn`
and `otpLength`);
- 81 to no declaration: globals and property names on untyped values.
None resolves to an unexported top-level declaration of
`auth-manager.ts` or to a top-level declaration of the module. A read of
the class itself would have to be in a type position: the one there is
(`:1979`) is.
- **Negative controls:** each proof reads the module text, and each
control changes it, or the proof's input, in memory only; the file is
untouched.
- Token proof: `plugins.push(bearer());` changed to
`plugins.push(bearer?.());` fails the token and line checks (2
failures), and the run exits 1. Declaring the get/set fields without
`jwtSigningFailureReported` fails the write check and the stub-shape
checks (4 failures), and the run exits 1.
- Binding proof: the module's `admin-impersonate-endpoint` 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 two unexported declarations (5 reads), and exits 1.
- **An independent reading:** `git diff --color-moved=plain
--color-moved-ws=allow-indentation-change 10b8250 a2413e0` over
the two source files marks 799 of the 808 deleted lines and 820 of the
954 added lines as moved.
- The 9 unmoved deletions are 3 import lines (`resolveUserAuthzGrants`,
`applyPlatformAdminImpersonation` and the
`./admin-impersonate-endpoint.js` closer), cut 15's three import comment
lines, the first lines of the two declarations (now with `export`) and
the method'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, writers, host literal and `return`, the two
`export` lines, and the new import comment and line. Of the 820, 14 are
stub lines in `auth-manager.ts` that git pairs with the `organization`
arrow's own host lines, which have the same text.
**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. They are also the bytes
cut 15 measured, since a private method's body is not in the
declarations.
- **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). Neither in-place
export, `buildPluginList` nor `PluginListHost` is among them.
`dist/index.d.ts` names neither in-place export nor `PluginListHost`;
its 7 `buildPluginList` lines are `private buildPluginList;` and
docblock text, the same 7 at both ends.
- **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 5 changed 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 file count and the
decision letters, as in the table above.
**5. Gates.**
- `node scripts/pm/dispatch-gates.mjs --commands --repo
objectstack-ai/objectstack` derives 61 commands for the 5 paths. All 61
ran at head after the full build, and all 61 exited 0.
- `--ran` over the record with each exit code: 61 derived, 61 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 5 paths
hit the register), 1,774 changed lines.
- **Docs drift** (`node scripts/docs-audit/affected-docs.mjs --json
10b8250`, exit 0): 21 pages, all name matches of names the moved code
carries (the `PLATFORM_ADMIN`, `platform_admin`, `OS_AUTH_TWO_FACTOR`
and `OS_SSO_DOMAIN_VERIFICATION` literals, the plugin names
`phoneNumber`, `magicLink`, `oidcProvider` and `deviceAuthorization`,
and `AuthManager` and `getMcpResourceUrl`). 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. 7 of the 21 are
release notes, release-owned and not edited.
- **Serial constraints** (in the claim, re-read at 10:40Z before this
PR): 12 PRs are open. One touches `auth-manager.ts`: #25621, whose only
hunk there is `:1320`–`:1331` (the docblock of `acceptLanguageHeader`
and an `export` in place on it), a region this cut does not touch and
the body does not read; `git merge-tree` merges this head with its head
cleanly. None of the others touches `plugin-auth`, the new module's
path, a reader edited above or `scripts/adr-anchors/`. `origin/main` has
moved 5 merges past this base, to `f7b0298968`; none touches
`plugin-auth`, `scripts/adr-anchors/` or a reader named above, and `git
merge-tree` merges this head with it cleanly.
## 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 9d9a06e commit abdc7f2
5 files changed
Lines changed: 961 additions & 813 deletions
File tree
- packages/plugins/plugin-auth/src
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
860 | 860 | | |
861 | 861 | | |
862 | 862 | | |
863 | | - | |
| 863 | + | |
| 864 | + | |
864 | 865 | | |
865 | 866 | | |
866 | 867 | | |
| |||
1125 | 1126 | | |
1126 | 1127 | | |
1127 | 1128 | | |
1128 | | - | |
1129 | | - | |
| 1129 | + | |
| 1130 | + | |
| 1131 | + | |
1130 | 1132 | | |
1131 | 1133 | | |
1132 | 1134 | | |
| |||
0 commit comments