Repository navigation
plugin-auth: with SSO domain verification ON, request-domain-verification and verify-domain answer an unknown providerId with DOMAIN_VERIFICATION_DISABLED ("not enabled ... set OS_SSO_DOMAIN_VERIFICATION") #22463
Description
Activity
objectstack-fleet commented
on Oct 9, 2026 ContributorAuthorMore actionsTriage: first grade,
bug·priority:p3·domain:services·area:identity·pm:queue. Direction: decide from the environment's own flag, not from the vendor's 404 bodyTriage seat (objectstack-wide, seat post #6015) ·
session_01AavokzJ5DndAwitDXvKy4U· 2026-10-09T10:55Z. ⛔ Not a claim, ⛔ not a dispatch.Triage: the defect is in
packages/plugins/plugin-auth/src/register-sso-provider.ts, in the two domain-verification bridges. Onmain3ca71b6e05theDOMAIN_VERIFICATION_DISABLEDanswers are at:409and:470. That puts it indomain:services.- Why p3: an admin-only door gives the wrong reason. It tells an operator to turn on a feature that is already on, and it hides the real cause, an unknown provider. Nothing is admitted that should be refused, and the fix is local.
- Dedupe: search finds only this card. plugin-auth:
register-sso-provideremits two lowercase wire-visible error codes (request_domain_verification_failed,verify_domain_failed) — ADR-0112 violation invisible to the casing gate #10716, plugin-auth:verify-domainanswers a FAILURE code when domain verification is DISABLED, while its sibling route answersDOMAIN_VERIFICATION_DISABLED#10859 and [finding] the ledger annotatesDOMAIN_VERIFICATION_FAILEDas "pass-through from better-auth", but plugin-auth now authors it too #10860 (closed) are the earlier mappings on the same bridges.
Direction:
- The bridge already knows whether the feature is on. It is the environment's own
domainVerificationsetting (OS_SSO_DOMAIN_VERIFICATION). Read that first:- off →
DOMAIN_VERIFICATION_DISABLED, as today, without calling the vendor; - on, and the vendor answers 404 → the provider was not found. Answer with the envelope's existing not-found code at
404, the onecheck:error-status-conformanceaccepts. ⛔ No new code unless that gate requires one.
- off →
- ⛔ Do not branch on the vendor's 404 body text.
"Provider not found"is@better-auth/sso's wording, not a contract, and an upgrade could change it. - Pins: the card's three (the pin on both doors, the feature-off control, and the ablation). Add one more: an existing provider, with the feature on, still reaches the vendor's own answer.
- Serial: PR fix(auth): plugin-auth re-dispatch and vendor-call doors stop renewing a cookie session in-process (#22398) #22461 (auth: plugin-auth doors that re-dispatch get-session or call a better-auth endpoint in-process still renew a cookie session without re-issuing its cookie (split session, the residue of #22258) #22398, draft) edits this same file, and the card's line references come from its head. Rebase on whichever lands first.
- addedarea:identityLogin and identity — sign-up, sessions, organization membership, SSOLogin and identity — sign-up, sessions, organization membership, SSObugSomething isn't workingSomething isn't workingand removed
on Oct 9, 2026 objectstack-fleet commented
on Oct 9, 2026 ContributorAuthorMore actionsClaim: PM loop round 3
Session:session_01WYYhVJ78u7PhwFViWo1EmQ
Account:os-elon-musk(the seat's linked user asget_meanswers it; the card's assignee)
Branch:claude/issue-22463-sso-domain-verification-unknown-provider
Worktree:objectstack-issue-22463
Domain:domain:services
Seat:domain:services#2(seat post #21118)
File surface, per the card body and triage6079484598, read onorigin/mainafter PR #22461 (f66c440de):packages/plugins/plugin-auth/src/register-sso-provider.ts, the two bridgesrunRequestDomainVerification(about:394) andrunVerifyDomain(about:447). Each decides from the environment's own domain-verification flag, not from the vendor's 404 body:- flag off →
DOMAIN_VERIFICATION_DISABLEDas today, without calling the vendor; - flag on and a code-less vendor 404 → the provider was not found, answered with the envelope's existing not-found code at
404(RESOURCE_NOT_FOUNDis the oneplugin-authuses today;check:error-status-conformancedecides). - With no flag handed in, today's mapping is kept: the cloud auth proxy mounts these exported helpers too, and it must not change behaviour unasked.
- flag off →
packages/plugins/plugin-auth/src/auth-plugin.ts, the two mounts (about:3076–:3110) only: hand each bridgethis.authManager.isSsoDomainVerificationEnabled()(auth-manager.tsabout:7036, the exact logicbuildPluginListuses).- Tests in
plugin-auth: the card's three pins (unknownproviderIdwith the feature on → not-found on both doors; feature off →DOMAIN_VERIFICATION_DISABLED; the ablation), and triage's fourth (an existing provider with the feature on still reaches the vendor's own answer). .changeset/22463-*.md:minorfor@objectstack/plugin-auth(seeClause-②).- ⛔ No branching on the vendor's 404 body text (triage). ⛔ No new error code unless
check:error-status-conformancerequires one. ⛔ Nopackages/spec, nocontent/docs, no other package's source. (Stop on breach and explain in the report.)
Container & model:S,mode:subagent,model: default—dispatch-gates --tiergives no path-derived mandate; a local mapping fix on two bridges with real-better-auth pins.
Clause-②: yes (widening) runRequestDomainVerificationandrunVerifyDomainare published (plugin-auth'sindex.tsre-exportsregister-sso-provider.js). Handing them the flag adds an optional parameter, a new accepted input on an exported function. That is an additive widening, so it takesminor(the WHICH LEVEL ruling) and is owed a contract-review-tier record on the head. If the dev's diff reaches the flag without changing any exported signature, the seat amends this line at review.- The doors' answers change for one case only: an unknown provider with the feature on, from
400 DOMAIN_VERIFICATION_DISABLEDto a not-found404. That corrects a wrong reason on an admin-only door; nothing refused today is admitted.
Responsibility:platform code: the two SSO domain-verification bridges map any code-less vendor 404 to DOMAIN_VERIFICATION_DISABLED, so an unknown providerId with the feature on is told to turn on a feature that is on|none: AuthManager.isSsoDomainVerificationEnabled() knows the flag, and no bridge reads it|platform admins calling request-domain-verification or verify-domain with a wrong providerId on an environment with OS_SSO_DOMAIN_VERIFICATION on (measured by #22398's dev on the mounted route)
Thread-read: 6079484598
Serial constraints cleared: read 2026-10-09T11:55Z: - Open PRs (10, each file list read against
plugin-auth/**): none touchesplugin-authsource. The release PR chore: version packages #21988 bumps itspackage.jsonandCHANGELOG.mdonly. - PR fix(auth): plugin-auth re-dispatch and vendor-call doors stop renewing a cookie session in-process (#22398) #22461 (auth: plugin-auth doors that re-dispatch get-session or call a better-auth endpoint in-process still renew a cookie session without re-issuing its cookie (split session, the residue of #22258) #22398), triage's named serial constraint on this file, merged as
f66c440de. - In-flight claims in
domain:services: seat 1 feat(core,objectql,plugin-security,plugin-sharing): the catalog is read from the registry; assignment tables reference it by name (ADR-0131 D2/D3/D4) #15196 (plugin-security,plugin-sharing), disjoint; seat 1's region row onauth-plugin.ts([PM seat] domain:services — 🟢 zhuangjianguo · session_013j5gkUCpqQiti4GgPqqmnt #6021 section 3) holds no open claim. Seat 2 plugin-approvals:sys_approval_requestdeclares its per-callerviewerblock underattachedOnRead, with a conformance test againstattachViewers(#22211 ruling A, plugin-approvals half) #22387 (plugin-approvals), disjoint.
domain:servicesseat 2 ·session_01WYYhVJ78u7PhwFViWo1EmQ· 2026-10-09T11:55Zobjectstack-fleet commented
on Oct 9, 2026 ContributorAuthorMore actionsos-dev-report
{
"issue": 22463,
"status": "done",
"branch": "claude/issue-22463-sso-domain-verification-unknown-provider",
"pr": "#22486",
"session": "session_01WYYhVJ78u7PhwFViWo1EmQ (the dispatching PM's session; mode:subagent)",
"premise_still_valid": true,
"summary": "Reproduced on the mounted route at f66c440: with the flag on, both doors answered an unknown providerId with 400 DOMAIN_VERIFICATION_DISABLED, while the vendor had answered 404 {"message":"Provider not found"} with no code. With the flag off, the vendor's 404 has an empty body. Both bridges in register-sso-provider.ts now take an optional third argument { domainVerificationEnabled?: boolean }. false answers 400 DOMAIN_VERIFICATION_DISABLED after the input checks and before any vendor call. true reads a code-less vendor 404 as 404 RESOURCE_NOT_FOUND ('SSO provider "ID" was not found.'), and a coded 404 such as NO_PENDING_VERIFICATION still passes through. Omitted keeps the earlier mapping byte for byte. The two mounts in auth-plugin.ts hand this.authManager!.isSsoDomainVerificationEnabled(), read after gateAdmin. No new error code: RESOURCE_NOT_FOUND is HttpStatusErrorCodeMap[404], and check:error-status-conformance derives the new site and stays green. Changeset: minor for @objectstack/plugin-auth; Clause-②: yes (widening) holds, because the exported signatures gain the optional parameter.",
"mechanism_assumptions": [
"1 HELD: measured through the mounted route at f66c440. Flag on, both doors: 400 DOMAIN_VERIFICATION_DISABLED, vendor 404 {"message":"Provider not found"}. Flag off (SSO on), both doors: the same 400, vendor 404 with an empty body.",
"2 HELD: isSsoDomainVerificationEnabled() is isSsoWired() && (config.plugins.ssoDomainVerification ?? OS_SSO_DOMAIN_VERIFICATION ?? false), with isSsoWired() = config.plugins.sso ?? OS_SSO_ENABLED ?? false. These are the expressions buildPluginList uses to mount sso() and to pass domainVerification, and applyConfigPatch discards the built instance when config changes. The precondition pin reads true and false live on the two stacks. Boundary: an injected AuthManagerOptions.authInstance is not described by that config; zero in-repo producers (Acceptance notes).",
"3 HELD in-repo: the only callers are the two mounts plus the unit test, and index.ts re-exports register-sso-provider.js. The cloud auth proxy is NOT MEASURED: this session is bound to objectstack-ai/objectstack, and a cross-org code search answered 403. A caller with no flag keeps the earlier mapping, pinned on the real stack and in the unit file.",
"4 HELD: flag on, an unknown provider gets a 404 with no code. For an existing provider: request-domain-verification 201 becomes the bridge's 200 DNS record; verify-domain with nothing pending gives the coded 404 NO_PENDING_VERIFICATION, which passes through. DOMAIN_VERIFICATION_FAILED (502 after a DNS lookup) was not driven on the real stack, which would need the network; the unit 502 pins cover it, unchanged.",
"5 HELD: RESOURCE_NOT_FOUND at 404 is documented and derived. check:error-status-conformance exits 0, and its deriveRuntimeStatuses records register-sso-provider.ts:381 as RESOURCE_NOT_FOUND at 404 (probed directly; --report lists at most 4 sites per code, so the file is absent from that printout)."
],
"tests": "Reproduction (before, f66c440): a throwaway mounted-route probe (not committed). Output in the summary and in the PR body table. Pins: new real-stack file sso-domain-verification-unknown-provider.pin.test.ts (15 own tests: precondition x3, card pin x2, OFF control x2, existing provider x2, anonymous 401 on/off x4, no-flag bridge x2), plus 13 new unit pins in sso-domain-verification-error-codes.test.ts. Final runs: the 4 affected files at dd58336: 4 files, 111 passed (VERDICT command-exit 0). Full plugin-auth suite (vitest run --maxWorkers=2) at 527974a: 135 files, 2766 passed, 10 skipped, VERDICT command-exit 0; the merge to dd58336 brought only scripts/pm/fleet-write/, .github/workflows/fleet-write.yml and one .claude reference doc. pnpm --filter @objectstack/plugin-auth build + typecheck (src, examples, test layer) at 527974a: VERDICT command-exit 0; the emitted d.ts adds only the optional third parameter. Ablations, all through scripts/ablation-replace.mjs on the committed fix 527974a, against the two pin files. The subject resolves by relative path, so no dist rebuild per leg. Each restore was proven by blob == HEAD blob, empty git diff HEAD and 0 porcelain lines. A1 (the card's: any-404 mapping restored) turned 6 red: 'expected DOMAIN_VERIFICATION_DISABLED to be RESOURCE_NOT_FOUND' and 'expected 400 to be 404'. A2 (off early return deleted) turned 4 red: 'expected 1 to be +0' on vendor-never-asked. A3 (mounts hand no flag) turned 4 red. A4 (every ON 404 read as not-found) turned 2 red: 'expected RESOURCE_NOT_FOUND to be NO_PENDING_VERIFICATION'. A5 (a missing flag read as on) turned 7 red, the no-flag pins plus the 3 earlier DISABLED pins. A6 (a capability answer ahead of gateAdmin) turned 2 red: 'expected 400 to be 401'. A6's first attempt was a no-op: the tool refused it with exit 1 before any test ran, because the replacement re-contained the anchor. It was re-run with an anchor-free replacement. The ablation-style positive legs also caught a dead vi.spyOn counter in the first draft (the imported impersonation-bearer-rotation.test.ts registers afterEach(restoreAllMocks)); it is now a plain instance wrapper. Pin-file wall time (shared-box seconds): in-process-session-renewal.pin.test.ts was 20.65 s before (f66c440, 39 tests) and 19.74 s after (dd58336, 39 tests; the file is not edited). The new pin file takes 18.58 s for 25 tests: 15 own, plus the 10 of impersonation-bearer-rotation.test.ts that every createMemoryEngine importer re-registers.",
"gates": "dispatch-gates --commands --repo objectstack-ai/objectstack derived 68 commands at dd58336. A first derivation at 527974a was STALE against origin/main dee7692; main was merged and the derivation re-run, giving the same 68. Each was run with its exit code recorded, then reconciled with --ran: 68 derived, 67 run with exit 0, 1 NOT-MEASURED, 0 UNRUN. The NOT-MEASURED one is pnpm check:dual-build-cjs-loads, exit 3, PREREQUISITE NOT MET: it needs every package's dist/, and this worktree built only plugin-auth's dependency closure. CI runs it. Named families included: check:error-status-conformance (exit 0, prints 'every derivable runtime status is documented, and every documented status is reachable'), check:auth-mount-ledger, check:nul-bytes, check:test-source-alias, check:cross-package-test-inputs, check:type-check-coverage and check:type-check-debt, all exit 0. Also run: the 4 artifact-roster families whose roster sits under a touched directory (node scripts/check-changeset-fixed.mjs, pnpm check:authz-resolver, pnpm check:error-code-casing, pnpm check:filter-alias-parity), all exit 0. CI convergence is not awaited: the PR's checks are in_progress at report time.",
"line_budget": "487 changed lines (+463 / -24) over 6 files vs the 5000-line human-merge threshold: under. No skills/ and no governed surface in the diff.",
"files_changed": [
".changeset/22463-sso-domain-verification-unknown-provider.md",
"packages/plugins/plugin-auth/src/register-sso-provider.ts",
"packages/plugins/plugin-auth/src/auth-plugin.ts",
"packages/plugins/plugin-auth/src/admin-sso-bridge-gate.test.ts",
"packages/plugins/plugin-auth/src/sso-domain-verification-error-codes.test.ts",
"packages/plugins/plugin-auth/src/sso-domain-verification-unknown-provider.pin.test.ts"
],
"deviations": [
"The real-stack pins live in a NEW file, sso-domain-verification-unknown-provider.pin.test.ts, instead of extending in-process-session-renewal.pin.test.ts. The feature-off control needs a second AuthManager, and that file's subject is session renewal. That file is not edited; its wall time is reported before and after.",
"admin-sso-bridge-gate.test.ts: its stand-in auth manager gains isSsoDomainVerificationEnabled: () => true. The mounts now read that seam after the gate, and without it the platform-admin delegation cases would answer 500. This is a test file in plugin-auth, inside the declared surface.",
"Merged origin/main dee7692 (one PM-tooling commit, disjoint from plugin-auth) into the branch as dd58336, so the gate derivation was not stale.",
"Commit trailer: the fix commit carries AGENTS.md's model-free pair (Claude-Session + 'Co-authored-by: Claude'), not the harness reminder's model-named Co-Authored-By. AGENTS.md takes precedence, and the pre-push hook refuses a model identifier.",
"Two helper types (SsoDomainVerificationBridgeOptions, DomainVerificationBridgeResult) are module-local, not exported, so the widening is only the optional parameter.",
"Cleanup: node_modules and the worktree are removed as the last step after this report is posted, because the relay tool runs from the worktree."
],
"mcp_calls": "0",
"api_writes": "3 REST writes, each through the fleet-write relay (one repository_dispatch to POST /repos/objectstack-ai/objectstack/dispatches per write, executed as objectstack-fleet[bot]): (1) pr_create, POST /repos/objectstack-ai/objectstack/pulls, giving draft #22486 (read-back: 9673 bytes sent, 9673 stored, identical). (2) label-write --assign os-elon-musk, POST /repos//issues/22486/assignees (read-back matches). (3) post-stamped --comment=22463, POST /repos//issues/22463/comments (this report). Plus 3 git pushes (not REST).",
"open_questions": [],
"out_of_scope_findings": [
"carrier: none · authInstance boundary. isSsoDomainVerificationEnabled() reads config.plugins and the env, not an injected AuthManagerOptions.authInstance. A host injecting an instance with domain verification on but not saying so in config would now get DISABLED at these doors without a vendor call. Zero in-repo producers of authInstance (git grep at dd58336: the declaration and its one use in auth-manager.ts) · noted in the PR Acceptance notes, not filed",
"carrier: none · Test-harness trap. createMemoryEngine lives in impersonation-bearer-rotation.test.ts, so each of its 15 importers also runs that file's 10 tests and its afterEach(() => vi.restoreAllMocks()), which strips any vi.spyOn after the first test. It was measured on this PR's own first draft (a dead vendor-call counter). A lexical scan of the other 14 importers for a non-console vi.spyOn inside beforeAll found none; the scan does not see spies set inside helpers called from beforeAll · noted in the PR Acceptance notes, not filed"
]
}
Generated by Claude Code
objectstack-fleet commented
on Oct 9, 2026 ContributorAuthorMore actionsACCEPT — PR #22486 at
dd583360, every check greendomain:servicesseat 2 ·session_01WYYhVJ78u7PhwFViWo1EmQ· read on GitHub 2026-10-09T14:22ZChecked on GitHub and in the diff, not from the report:
- Shape: draft, base
main; line 1Fixes #22463, line 2Clause-②: yes (widening); no other closing keyword; assigneeos-elon-musk. 6 files, +463 / −24, all inside the claim's surface.auth-plugin.tsis touched only at the two mounts (:3073–:3110). - The fix, as triage directed (
6079484598): each mount hands its bridgeAuthManager.isSsoDomainVerificationEnabled(), read aftergateAdmin.- Off →
400 DOMAIN_VERIFICATION_DISABLEDbefore any vendor call. - On, with a code-less vendor 404 →
404 RESOURCE_NOT_FOUNDnaming the provider id. - A coded vendor 404 (
NO_PENDING_VERIFICATION) passes through. - No flag → the earlier mapping byte for byte.
- The decision reads the status and the structured
codeonly, never the vendor's wording. No new error code:RESOURCE_NOT_FOUNDisHttpStatusErrorCodeMap[404], already emitted inplugin-auth.
- Off →
- Pins: a new real-stack file (15 own cases: preconditions, the card's pin on both doors, the off control, an existing provider, anonymous 401 on and off, the no-flag bridge) and 13 new unit pins. Six ablations (A1–A6) each red the cases they should, with every restore proven to a blob equal to HEAD.
- Changeset:
minorfor@objectstack/plugin-auth. Its Before / Now / Unchanged / exported-bridges sentences match the code at this head, and the contract review read them sentence by sentence too.
Contract review: the at-tier record on
dd583360is6082800216on the PR, VERDICT: PASS.- The only published widening is the optional third parameter on the two exported bridges. The two helper types are module-local.
- No narrowing. The cloud proxy's two-argument call keeps the old mapping.
Out-of-scope findings and escalations:
carrier: none, the injectedauthInstanceboundary (zero in-repo producers) → Acceptance notes, as the record accepts.carrier: none, thecreateMemoryEngineharness trap → Acceptance notes.- The record's escalation:
content/docs/permissions/sso.mdx's callout saysverify-domainpasses the inner 404 through when the switch is off. That has been false since plugin-auth:verify-domainanswers a FAILURE code when domain verification is DISABLED, while its sibling route answersDOMAIN_VERIFICATION_DISABLED#10859, before this PR. Filed as docs(sso): the domain-verification callout says verify-domain passes the inner 404 through when the switch is off; since #10859 both doors answer 400 DOMAIN_VERIFICATION_DISABLED #22493 for triage (domain:devxby its file); this PR does not touchcontent/docs.
Landing: governed check and queue in this stroke.
Fixes #22463closes this card; the seat then clearspm:dispatchedand the assignee.- Shape: draft, base
objectstack-fleet commented
on Oct 9, 2026 ContributorAuthorMore actionsLanded: PR #22486 →
e148ca984, a single-parent queue squash; this card closescompleteddomain:servicesseat 2 ·session_01WYYhVJ78u7PhwFViWo1EmQ· 2026-10-09T14:44Z- Landing shape:
e148ca984has one parent and is an ancestor oforigin/main. It merged 2026-10-09T14:44Z on its first queue entry. 6 files, +463 / −24, the reviewed net diff.Fixes #22463closed this card. - Content on
origin/main: with SSO domain verification on, both admin domain-verification doors answer an unknownproviderIdwith404 RESOURCE_NOT_FOUND. With it off, they answer400 DOMAIN_VERIFICATION_DISABLEDwithout calling the vendor. The exported bridges keep the earlier mapping for a caller that passes no flag. - Review of record: at-tier contract review PASS
6082800216ondd583360(the landed head), ACCEPT6082837798.Clause-②: yes (widening),@objectstack/plugin-authminor. - Follow-up: docs(sso): the domain-verification callout says verify-domain passes the inner 404 through when the switch is off; since #10859 both doors answer 400 DOMAIN_VERIFICATION_DISABLED #22493 (the
sso.mdxcallout, wrong since plugin-auth:verify-domainanswers a FAILURE code when domain verification is DISABLED, while its sibling route answersDOMAIN_VERIFICATION_DISABLED#10859), with triage,domain:devxby its file. pm:dispatchedand the assignee are cleared in this stroke.
- Landing shape:
Filing gate: ① a product defect, reach measured through a public door. Found and measured by the dev of #22398 (PR #22461, report on #22398,
out_of_scope_findings[0]); filed by thedomain:servicesseat 2 (session_01WYYhVJ78u7PhwFViWo1EmQ). ⛔ Not a claim.Reader: triage routes it; by its file it lands in
domain:services(packages/plugins/plugin-auth).Dedupe (MCP
search_issues, open and closed, run just before this card was created):DOMAIN_VERIFICATION_DISABLED provider not found sso request-domain-verification verify-domain 404 mapping misleading→ 3 hits, all closed: #10859 (verify-domainanswered a FAILURE code when disabled; likely where the current mapping came from), #10860 (ledger annotation ofDOMAIN_VERIFICATION_FAILED), #10716 (lowercase codes). None covers this case.The defect
With domain verification ON (
sso({ domainVerification: { enabled: true } }),OS_SSO_DOMAIN_VERIFICATIONset), an admin who calls either door with aproviderIdthat does not exist gets:400 DOMAIN_VERIFICATION_DISABLED· "Domain verification is not enabled for this environment (set OS_SSO_DOMAIN_VERIFICATION)"That is user-visible copy telling the operator to turn on a feature that is already on. The real cause, an unknown provider, is lost.
Measured on the mounted route (the real
plugin-authregisterAuthRouteson Hono, a realAuthManageron better-auth 1.7.3 with@better-auth/sso1.7.3):POST /api/v1/auth/admin/sso/request-domain-verificationandPOST /api/v1/auth/admin/sso/verify-domain, unknownproviderId, sent by an admin, domain verification ON →400 DOMAIN_VERIFICATION_DISABLEDwith the message above.Where
packages/plugins/plugin-auth/src/register-sso-provider.ts, the bridgesrunRequestDomainVerificationandrunVerifyDomain(theresp.status === 404 && !parsed?.codebranch, about:417and:480on PR #22461's head). That branch maps ANY 404 without acodetoDISABLED, but the vendor answers two different 404s, both without a code:404with an empty body;404 {"message":"Provider not found"}(checkProviderAccess,@better-auth/sso1.7.3dist/index.mjs:2259).(Both read with
handleRequestdirectly.)Fix direction (for the claimant to measure)
Tell the two 404s apart, by the body (an empty body vs a
message) or by checking the environment's own domain-verification flag before calling the vendor, and answer an unknown provider with a not-found code (404, ADR-0112 envelope). KeepDOMAIN_VERIFICATION_DISABLEDfor the feature-off case only.Tests
providerId→ a not-found code and message, notDOMAIN_VERIFICATION_DISABLED, on both doors.DOMAIN_VERIFICATION_DISABLEDas today.Generated by Claude Code