Uh oh!
There was an error while loading. Please reload this page.
refactor(plugin-auth): remove the inert AUTH_SCIM_PROVIDER_SCHEMA export (enforce-or-remove) - #12008
Conversation
`AUTH_SCIM_PROVIDER_SCHEMA` was a publicly exported `scimProvider` column mapping with zero consumers -- exactly one repo-wide hit, its own declaration -- and inert by construction: `@better-auth/scim` hardcodes its model and exposes no `schema` option (still true of the installed `@better-auth/scim@1.7.0-rc.1`, whose `SCIMOptions` declares no `schema` / `modelName` / `fields` member), so there was nowhere to hand it. Removed under ADR-0049 enforce-or-remove: it was a second source of truth for the four SCIM column names, where the load-bearing one is the adapter layer (`AUTH_MODEL_TO_PROTOCOL` + camelCase-to-snake_case field resolution in `objectql-adapter.ts`) over the `sys_scim_provider` platform object. A dead copy cannot fail when it drifts, and the next reader cannot tell which of the two is authoritative. A NOTE in its place records why no mapping exists and what owns the names instead, following the sibling sso NOTE in the same file. Fixes#11777 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01APWX2AwT3a4xDcjPCe8bk4
📓 Docs Drift CheckThis PR changes 1 package(s): 29 hand-written doc(s) name something this change touched — list omitted above 15 rows. Re-derive on the tree named below: ⛔ 4 release-owned page(s) also affected — read-only, see AGENTS.md Documentation Guardrails. What this run could not see
Coarse fallback — 11 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): Which tree this was computed onThis run read A worktree cut from an older # while this PR is open — GitHub drops the merge commit once it closes
git fetch origin 3567bde3f55cc97b5346bc5c51ce559686854450 && git checkout 3567bde3f55cc97b5346bc5c51ce559686854450
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin 227c1788d55da8f94127137bcf75ba2bf08b15d8 b537844aa40467248154b5a0982d40853ea3cc7b && git checkout -B drift-repro 227c1788d55da8f94127137bcf75ba2bf08b15d8 && git merge --no-ff b537844aa40467248154b5a0982d40853ea3cc7b
node scripts/docs-audit/affected-docs.mjs --json 227c1788d55da8f94127137bcf75ba2bf08b15d8
|
os-trump
commented
Aug 25, 2026
Contract review PASS at Generated by Claude Code |
Uh oh!
There was an error while loading. Please reload this page.
Fixes#11777
Deletes
AUTH_SCIM_PROVIDER_SCHEMAfrompackages/plugins/plugin-auth/src/auth-schema-config.tsunder ADR-0049 enforce-or-remove. It was a publicly exportedscimProvidercolumn mapping that nothing read and nothing could ever hand to a plugin — a dead second source of truth for four column names whose live owner is the adapter layer.⭐ Clause-② — declared, and this PR carries the gate
Clause-② applies: YES.
needs:contract-reviewis on the card and is set on this PR from the moment it exists (dual carrier). The reasoning, since triage did not assert it: the gate is judged from content, and a tightening counts as much as a widening. Deleting a publicly exported symbol NARROWS this published package's public surface — a public-surface change in the direction people forget to count.⛔ Not cleared here, not flipped ready, no auto-merge armed: the contract-review tier gates enqueueing and the floor only goes one way.
The zero, re-measured on this branch — with a positive control
A search tool's silence is an instrument reading, not evidence, so the count was taken against a ref (never the shared checkout, which is hundreds of commits behind) and controlled against a symbol known live in the same file.
git grep -n AUTH_SCIM_PROVIDER_SCHEMA origin/main -- .auth-schema-config.ts:1005), exit0git grep -n buildOrganizationPluginSchema origin/main -- .auth-manager.ts, and 4 test files, exit0grep -ninauth-schema-config.tsAUTH_SCIM_PROVIDER_SCHEMA org:objectstack-aigrep -rnoverobjectstack-ai/hotcrm@5eee1bd361origin/mainwas at497ded7801for every reading. The control returning 15 hits is what makes the target's 1 a measurement rather than a broken channel.Why it was inert by construction, not merely unused yet
Its own doc comment stated the reason it could never be applied:
@better-auth/scimhardcodes its model and exposes noschemaoption — still true of the installed@better-auth/scim@1.7.0-rc.1, whoseSCIMOptionsdeclares noschema,modelNameorfieldsmember at all. There was nowhere to pass it. Its siblings in the same file (buildOrganizationPluginSchema,buildDeviceAuthorizationPluginSchema, …) are all genuinely handed to their plugins asschemaoptions; this one was the odd member.The mapping that actually governs those writes is the adapter layer —
AUTH_MODEL_TO_PROTOCOL(objectql-adapter.ts:57,scimProvider: 'sys_scim_provider') plus the mechanical camelCase-to-snake_case field resolution — over thesys_scim_providerplatform object, which is where the four column names are really declared (packages/platform-objects/src/identity/sys-scim-provider.object.ts). That route is pinned by the dedicated sso/scim block inbetter-auth-schema-parity.test.ts. The deleted copy could drift from it with every gate green, and the next reader could not tell which of the two was authoritative.What replaces it
A NOTE, following the sibling
ssoNOTE already in this file, which records the same class of fact forbuildSsoPluginSchema(). It states why no scim mapping exists, what owns the column names instead, what pins that owner, and the condition under which one could legitimately return (the plugin grows aschemaoption AND it is passed). It deliberately does not restate the four column names — a note that repeated them would re-create the second source of truth this PR removes.Net: 31 lines deleted, 17 added, one file.
Changeset tier
minor, notmajor. Removing a public export is breaking in the semver sense, and the launch-window convention ships breaking asminor(scripts/check-changeset-no-major.mjs: every publishable package is in the Changesetsfixedgroup, so onemajorpromotes ~70 packages). The changeset declares**BREAKING (public export removed)**in the body so the declaration is not lost by the tier, which is exactly the spellingcheck-adr-0087-registrationreads. No tier was forced and nothing needed to stop.ADR-0087 disposition:
not-required (no-migration-prescription)— no consumer exists to rewrite, and the constant is not a metadata surface (no Zod schema, nopackages/specdeclaration, no authorable key, no stored representation), soobjectstack migrate metahas nothing to visit.runtime-interface-onlywas considered and does not apply: it requires the named symbol to resolve at HEAD, and this one is deleted.Serial note — discharged, not deferred
Triage asked to check the SCIM stable migration's in-flight legs for collision. #11632 is
pm:blockedwith nothing cuttable (leg 1b cannot precede the pin move; the pin move is #3653, also blocked), so no in-flight branch exists in that family to collide with. If that migration's future design resurrects a mapping seam, that is its card's business — not a reason to keep this dead one alive now.Verification
All readings below were taken on the final commit,
b537844aa4(git rev-parse --short HEADfrom the same runs). Every exit code was captured before any pipe, and each line quotes the gate's OWN verdict rather than a bare$?.Consumer-direction reverse verification — the control that actually proves the export is gone from what a consumer reads. A probe file was added to a REAL direct consumer (
@objectstack/service-sms) importing the deleted symbol and a live sibling in one statement, then removed by the script'strap … EXIT INT TERM. The probe was confirmed on disk before tsc ran (control_mentions=2 target_mentions=2), andgit statuswas clean afterwards.The differential is what makes it a measurement: the target is refused, the sibling imported in the same statement is not, and the compiler proposes the sibling by name — so it read the REBUILT surface, not a cached one.
total tsc errors: 1also says the consumer package is otherwise clean: the only error in it is the one deliberately introduced.The built type surface, read after the rebuild (
dist/index.d.ts, mtime 04:39, after the edit):AUTH_SCIM_PROVIDER_SCHEMA0 occurrences,AUTH_SSO_PROVIDER_SCHEMA2 — same positive-control shape.os-verify-lock.sh -c "pnpm --workspace-concurrency=2 --filter '@objectstack/plugin-auth...' build"VERDICT command-exit 0 · held the lock 202spnpm --filter @objectstack/plugin-auth typecheck(tsc --noEmit+tsconfig.examples.json)VERDICT command-exit 0 · held the lock 10s— no diagnosticspnpm --filter @objectstack/plugin-auth test -- --maxWorkers=2Test Files 74 passed (74)·Tests 1519 passed (1519)pnpm lint(=eslint . --no-inline-config)VERDICT command-exit 0 · held the lock 80s— the whole farm, not a narrowed subsetcheck:changeset-gate-self-tests✓×3 self-tests (118 + 212 + 116 assertions)check-adr-0087-registration --base origin/main✓ … 1 declared-breaking changeset(s), each carrying an ADR-0087 dispositioncheck-changeset-no-major --base origin/main✓ This diff introduces no 'major' bump.check-empty-changeset✓ No empty-frontmatter changeset introduced by this diffcheck:objectui-changeset✓ objectui-range --self-test: all checks passedcheck:published-files✓ … 69 publishable package(s) … declare a 'files' whitelistcheck:slot-lookup✓ slot-lookup ratchet holds … none new·baseline key set verified against 497ded7: no files addedcheck:test-source-aliascheck-test-source-alias OK — 72 packages with tests scannedcheck:type-source-resolutioncheck-type-source-resolution OK — 93 tsc program(s) across 77 packagescheck-plugin-teardown-shape✓ … 63 Plugin implementation(s) across 4647 source(s)check:type-check-coveragecheck-type-check-coverage: OK — 65/78 workspace packages type-checkeddocs-audit/check-affected-docs✓ affected-docs self-test: 437 cases pass.release-rehearsal-clone --self-test✓ self-test passedcheck-nul-bytescheck-nul-bytes: OK (scanned 6663 text file(s) … no raw ASCII control bytes)Both changed files were also swept directly for control bytes (
grep -naP '[\x00-\x08\x0b\x0c\x0e-\x1f\x7f]', exit 1 — clean).NOT MEASURED locally, and not reported as passes. Two gates refused to run for want of a full-workspace build, and each says so in its own words. CI builds the closure before these steps, so both are left to CI:
check:type-check-debt— "--re-measure cannot run: 30 workspace dependenc(ies) of the ledgered packages have no built type entry point on disk … Build the closure first, exactly as lint.yml does before this step." A declared refusal, not a verdict.check:published-readme-exports— "✗ check:published-readme-exports — 64 package(s) are not built, so this …". Every one of its 64 lines isdoes not exist. Build first; the count of findings that are NOT that is 0, and the count namingplugin-auth— the package this PR touches, which IS built here — is also 0.The gate list was derived, not recalled:
node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack(no paths — the script takes the change set from the merge base itself), re-run against the final commit, and it names 13 families for this card's 2 paths. Twelve are above; the thirteenth,docs-audit/check-drift-comment.mjs, reads a comment on the PR and cannot run before the PR exists.Out of scope
Filed as #12009 (unassigned,
finding, nopm:queue):AUTH_SSO_PROVIDER_SCHEMA, in the same file, is referenced only from one comment and two frozen CHANGELOG lines — the same shape, measured with the same positive control. The file's own NOTE routes it to #8224, but that card is closed, and the follow-up that owned the remaining half, #10074, is closednot_plannedon ruling A — do not rewire the seam. Ruling A settles where the mapping lives; it never ruled on the exported constant that copies the names alongside it, so the question is genuinely untracked rather than answered. Not touched here: it differs from the scim case in ways that could change its disposition (the ssoschemaoption is real on@better-auth/sso@1.7.1, so it is unused by choice rather than inert by construction), and #11777's scope is one symbol.AUTH_JWKS_SCHEMAlooked similar on a per-file hit count and is not dead — it is consumed in-file atauth-schema-config.ts:868. Recorded here so the next reader does not re-derive it.Generated by Claude Code
Generated by Claude Code