Repository navigation
fix(service-settings): Setup → Authentication says what the sign-up and Google toggles do - #24842
Merged
objectstack-fleet[bot] merged 1 commit intoOct 20, 2026
Conversation
…le toggles do signup_enabled is relabelled "Allow email sign-up" and its help states the conjunction with the audience posture: the form admits only what the posture admits, and off closes it under every posture, invitations included. google_enabled's help states that Google is offered only once a client ID and secret resolve, saved here or from GOOGLE_CLIENT_ID / GOOGLE_CLIENT_SECRET. Defaults, visible rules, required flags and options are unchanged; the en, zh-CN, ja-JP and es-ES bundles carry the new label and help. Claude-Session: https://claude.ai/code/session_011TdZ8GjixNZFLz1xJD9zzK Co-authored-by: Claude <noreply@anthropic.com>
Contributor
📓 Docs Drift CheckNothing in this diff resolved to a documentable surface (no symbol, route or SDK anchor derived from 1 changed package(s)), so this run has no opinion about the docs. What this run could not see
Coarse fallback — 9 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): |
Contributor
Author
席位核对 · ACCEPT ·
|
objectstack-fleet
Bot
deleted the
claude/issue-24776-auth-settings-contradictions
branch
October 20, 2026 10:39
This was referenced Oct 20, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #24776
Clause-②: no
What changes
Setup → Authentication showed two controls that read as contradicting the system on a fresh install. Both are still truthful about what the runtime does; what they lacked is the second condition. This PR states it. Only wording changes. No default,
visiblerule,requiredflag, option or stored key moves. The admission matrix below is byte-identical before and after.auth.signup_enabled: relabelled Allow email sign-up (was Allow self-service registration), and it now has help text. The help says the toggle opens the email-and-password sign-up form, and the Self-registration audience decides who that form admits:invite_only: only an address holding a pending invitation;email_domain: the allowlisted domains, plus invited addresses;open: anyone.Off closes the form under every audience, invitations included.
auth.google_enabled: the help says Google sign-in is offered only once a client ID and a client secret both resolve, either saved on the page or fromGOOGLE_CLIENT_IDandGOOGLE_CLIENT_SECRETon the server (the server values win over saved ones). Until both resolve, the login page shows no Google button, even while the toggle is on. Off withdraws Google even when the server sets both.The
en,zh-CN,ja-JPandes-ESbundles carry the new label and help.enmatters too: the console resolvessettings.auth.keys.KEY.label/.helpfrom the served bundle before the manifest literal, so ifenlagged, the English page would keep showing the old text.Files:
packages/services/service-settings/src/manifests/auth.manifest.ts,auth.manifest.test.ts,src/translations/{en,zh-CN,ja-JP,es-ES}.ts,.changeset/24776-auth-settings-signup-google-help.md(patch,@objectstack/service-settings). Nothing underplugin-auth/src,settings-service.ts,settings-service-plugin.ts,packages/specor objectui is written.What was measured (the card's premise holds)
The composition: the real
SettingsServicewith the real auth manifest, the realAuthPluginbooted init → start →kernel:ready, and the real better-auth pipeline over an in-memory engine.bindAuthSettingsreads that service. Each cell boots fresh with one existing human (so the bootstrap bypass is off), a pending invitation forinvitee@elsewhere.org, andmember_defaultas the declared self-registration set. The probes:POST /api/v1/auth/sign-up/emailthroughmanager.handleRequest;getPublicConfig()(what/auth/configserves the login page);SettingsService.get(what the page shows).The instrument was a one-off test file and is not committed.
H2 —
signup_enabled×audience_posture. "unset" is the manifest default, read with sourcedefault. Every cell has zero bind refusals.OS_AUTH_SIGNUP_ENABLED=falseOS_DISABLE_SIGNUP=trueOS_AUTH_AUDIENCE_POSTURE=open(The table folds pairs of cells that read the same. The record has 15 separate rows: 12 stored-or-default, plus 3 env.)
So
signup_enabledis a door of its own, in series with the posture.falsecloses what the posture alone leaves open, and underinvite_onlyit still decides whether an invited address can register through the form. Unset reads astrueand an unset posture reads asinvite_only, so the page's defaults already show the runtime's effective state. The contradiction was only in the wording.H3 — Google. No
GOOGLE_*value is printed anywhere; the instrument set fake values in-process.google_enabledunsetgoogle_enabled: truegoogle_client_id/required,google_client_secret/requiredgoogle_enabled: falseOS_AUTH_GOOGLE_ENABLED=falsegoogle_enabled: truegoogle_enabledunsetgoogle_enabled: falsegoogle_enabledunsetThe env-credential deployment with an unset toggle signs in with Google, both before and after this PR. No default moves.
Before / after. Base
87c09ebb7avs headfbf586d971: the 26-line record is byte-identical (diffexit 0; sha25674e45ec11dd103de…on both sides). A control line from the after-run reads the edited manifest (signup_enabled.label=Allow email sign-up), which proves that run loaded the change it claims to compare.Why this route (decision frame: business need · long-term · AI-proofing · startup scope)
signup_enabled. Chosen: relabel plus help text stating the conjunction.invite_only(visible): rejected. The matrix shows the toggle decides the invitee column there. A storedfalsehidden underinvite_onlywould keep invited people out with the cause off-screen.false: rejected. The runtime's default is open (disableSignUpunset). The page would read OFF over an open form, and the first save that carried the shown value would close the invitee door, which is a narrowing this card may not make.falserow).google_enabled. Chosen: help text stating the conjunction.false: rejected on measurement. It reads OFF on the two shapes that do offer Google (env credentials with the toggle unset; stored credentials with the toggle unset), and itsvisiblerule would hide the stored credentials there. The runtime reads explicit values only, so its behaviour would not move; the page would simply stop telling the truth on those shapes.info_banner: rejected. It is one more specifier and eight more strings, and it cannot see env credentials either, so its text would hedge exactly as the help does.GOOGLE_CLIENT_ID/GOOGLE_CLIENT_SECRETas an env source for the two keys: this would let the page show "Set via env", but it lives insettings-service.tsor the spec. Both are outside this claim. It is raised in the report as an open question, with the save refusal below.Pins and ablation
auth.manifest.test.tsgains three cases:signup_enabledkeeps defaulttrueand itsemail_password_enabled-onlyvisiblerule, and its help names everyaudience_postureoption value (read from the option table) and the select's label.google_enabledkeeps defaulttrue, and its help namesGOOGLE_CLIENT_IDandGOOGLE_CLIENT_SECRET.enbundle carries the manifest label and help verbatim for both keys.Ablation (
scripts/ablation-replace.mjs, one leg per changed declaration, run on the committed headfbf586d971). Each leg was mutated, run red, then restored, with the restore proven by blob == HEAD and an emptygit diff HEAD:under invite_only, …;from thesignup_enabledhelp → 2 failed / 13 passed (cases 1 and 3); restored to blob1fc310c429e5.GOOGLE_CLIENT_ID and GOOGLE_CLIENT_SECRET on the serverwithcredentials on the server→ 2 failed / 13 passed (cases 2 and 3); restored to blob1fc310c429e5.enlabel toAllow self-service registration→ 1 failed / 14 passed (case 3); restored to blob8784d7d80de3.The test imports the manifest and bundle by relative path, so it reads
src/: no build ordist/leg is involved.Verification (head
fbf586d971)pnpm --filter @objectstack/service-settings exec vitest run --maxWorkers=2→ 53 files, 897 tests passed.pnpm --filter @objectstack/service-settings run typecheck→ exit 0.tsc --listFilescountsauth.manifest.test.tsin the program once.node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack, 66 commands): 65 exit 0.--ranreports 66 accounted, 65 run, 1 NOT-MEASURED, 0 UNRUN.pnpm check:dual-build-cjs-loads, reason: PREREQUISITE NOT MET (exit 3). It reads every package'sdist/, and this worktree built only the service-settings / plugin-auth closure. CI runs it.test:repo; plugin-auth's suite, because this diff writes nothing there and changes only manifest strings.mainmoved four commits past the base while this ran; none of them touches service-settings or plugin-auth, so the branch is not re-merged.Acceptance notes
GOOGLE_CLIENT_ID/GOOGLE_CLIENT_SECRET, savinggoogle_enabled: truefrom the console is refused (google_client_id/required,google_client_secret/required) while the login page offers Google. So an admin who switches Google off on the page cannot switch it back on there without re-typing credentials the server already holds. This PR leavesrequiredalone, because that is save-validation territory.signup_enabledbindsemailAndPassword.disableSignUp, which better-auth consults only on the email sign-up route (dist/api/routes/sign-up.mjs). Social sign-up reads the provider's own flag (dist/api/routes/callback.mjs), so Allow self-service registration overstated what the switch closes. The new label names what it actually controls.email_passwordgroup description ("…and self-service registration") and themembershipgroup description ("Pairs with self-service registration above") still use the old phrase. They are outside this claim's specifiers. Carrier: none.Generated by Claude Code