You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Organization require MFA: the save refusal is English only, the grace period is unreadable by the console, and the field help does not say two-factor must be on #30411
Filed by the domain:ui#3 seat from the out-of-scope findings of #30295's card thread (os-dev-report 6653186462), landed by PR #30369. Carrier: domain:server (all three are server or metadata surfaces). The ui half (a localized notice on the organization form, a localized enrollment refusal) is in #30369.
Grace period is unreadable.auth.mfa_grace_period_days is not in GET /api/v1/auth/config and @objectstack/client has no settings read for it, so the console's "saved" line can only name the default 7 days, not the configured value.
Field help.sys_organization.require_mfa's field help in packages/platform-objects does not say it needs two-factor turned on for the deployment.
Wanted
The refusal message is localized by the server's usual message path (the same way SETTINGS_VALIDATION messages are).
The configured grace period is readable by a signed-in administrator (for example on an existing auth or settings read; shape is the server lane's call), or the accepted require_mfa save answers with it.
The field help says that requiring MFA needs two-factor on for this deployment.
Three server or metadata gaps around organization require-MFA: the refusal text is English only; auth.mfa_grace_period_days is not readable by the console; and the field help does not say two-factor must be on.
Claim: PM loop round 10
Session: session_01Utp6Cbvcmv8YWFhFJwzjKL (seat) · dev thread session_01Utp6Cai3TgWyncLtR5EwF7
Account: os-bill
Branch: claude/project-thread-q3clql (harness-pinned thread branch; platform exception to claude/issue-<n>-<slug>)
Worktree: objectstack-issue-30411
Domain: domain:server
Seat: domain:server#2
File surface: packages/plugins/plugin-auth/src/organization-mfa-enrollment-guard.ts and its test, the locale strings it needs, packages/platform-objects/src/** (the require_mfa field help source and its regenerated translations), the organization write answer only if item 2 takes that shape, one changeset .changeset/30411-org-require-mfa-follow-ups.md. ⛔ packages/services/service-settings/**, auth-plugin.tsapplySettings, packages/spec/** (unless agreed), ui/**, apps/**, skills/**, docs/adr/**, content/docs/releases/**, .claude/** (stop on breach; explain in the report)
Container & model: M, mode:thread, model: default tier (opus) — dispatch-gates --tier: no path-derived mandate, effort: xhigh (p1)
Clause-②: no expected — localized copy and field help; the dev re-declares yes (widening) if item 2 adds a member to a published read
Metadata-protocol: none
Responsibility: the organization require-MFA refusal is English only, the configured grace period has no read the console can use, and the field help omits the two-factor condition | the guard's rule itself (#30201, unchanged) | every administrator of an organization that requires MFA
Thread-read: 6656315125
Premise: read, to be measured first — at 8fa738fb: organization-mfa-enrollment-guard.ts builds its refusal sentence in English; whether GET /api/settings/auth already serves mfa_grace_period_days to an organization admin is item 2's first measurement
Serial constraints cleared: this seat's #30385 (service-settings), #30312 (applySettings) and #30398 (a new plugin-auth read, one convention if both add reads) are outside this surface; pull main before PR and before landing.
Order: project file server-seat2/dispatch-30411.md, delivered as the card thread's opening message.
{
"issue": 30411,
"status": "done",
"branch": "claude/project-thread-q3clql",
"pr": "https://github.com/objectstack-ai/objectstack/pull/30529",
"session": "session_01Utp6Cai3TgWyncLtR5EwF7",
"premise_still_valid": true,
"summary": "Item 1: the organization require_mfa refusal (two-factor off) now reads in the caller's language (ctx.session.locale via core resolveLocale; en, zh-CN, ja-JP, es-ES), envelope unchanged (400 VALIDATION_FAILED, one require_mfa/invalid_value entry), English byte-identical. Item 2: measured first that an organization admin gets 403 SETTINGS_FORBIDDEN on GET /api/settings/auth, so an admitted turn-on now calls ctx.notice with the grace period in force, read per write from AuthManager.getMfaGracePeriodDays(), which shares resolveMfaGracePeriodDays with the MFA gate (gate reading unchanged, pinned). The ui read is the notice member of the PATCH/POST /api/v1/data/sys_organization answer. Item 3: require_mfa help names OS_AUTH_TWO_FACTOR=true and the refusal, in all four bundles.",
"tests": "organization-mfa-enrollment-guard.test.ts 56/56 (new describes: four-locale refusal and locale table; notice once per admitted turn-on, 0/1-day copy, silence on clear/re-save/other column; real ObjectQL engine behind the D2 guard with zh-CN refusal and onNotice days; AuthPlugin kernel:ready registration with settings patch; resolveMfaGracePeriodDays table and better-auth gate end to end at grace 40/20/unset). sys-organization-update-door.test.ts pins the help in source and all bundles. On f3b41646: plugin-auth 224 files, 4001 passed, 10 skipped; platform-objects 111 files, 1532 passed; both typechecks VERDICT command-exit 0; check-i18n-bundles OK. Ablations via ablation-replace wrap mode, each restored to the HEAD blob: A1 locale ignored 2 red; A2b notice on re-save 5 red; A3 grace read once 2 red; A4 notice removed 4 red; A5b gate default 7->8 3 red. HTTP on a real showcase boot: zh-CN and en refusals 400; notice 'has 7 days', then 3 after PUT /api/settings/auth without restart; re-save of stored true answers no notice.",
"gates": "dispatch-gates --commands derived 66 on f3b41646; all 66 exit 0 (codes recorded before any pipe); --ran: 66 derived, 66 run, 0 NOT-MEASURED, 0 UNRUN. pnpm lint VERDICT command-exit 0. CI check-runs on the PR: not yet read at report time (PR opened 14:15Z).",
"dogfood_battery": "f3b41646 · os-verify-lock: VERDICT command-exit 0 · held the lock 1771s · Test Files 419 passed, 3 skipped (422) · Tests 3492 passed, 36 skipped (3528) · no failure. Run because the dispatch asked for it; title carries no ! and no narrowing arm.",
"line_budget": "12 files, +464 -20 vs main (tests +264, guard +146/-8, rest +54/-12)",
"deviations": [
"Dogfood ran though os-dev only owes it for ! or a narrowing arm: the dispatch asked for it.",
"First ablation A2 refused by ablation-replace (replacement contained the anchor, count unchanged): no measurement; redone as A2b with another anchor.",
"check-plugin-teardown-shape --self-test needed git fetch --depth=1 of fixture 621a4876 (shallow clone), which wrote the shared .git/shallow.",
"check:type-check-debt was NOT MEASURED on e950155e (lock held by this branch's own dogfood); measured exit 0 on f3b41646.",
"Copy pins assert the first sentence and named subjects (env var, setting key, day count), not whole sentences.",
"Translated help values (zh-CN, ja-JP, es-ES) edited by hand; en regenerated by pnpm i18n:extract."
],
"files_changed": [
".changeset/30411-org-require-mfa-follow-ups.md",
"packages/platform-objects/src/apps/translations/en.objects.generated.ts",
"packages/platform-objects/src/apps/translations/es-ES.objects.generated.ts",
"packages/platform-objects/src/apps/translations/ja-JP.objects.generated.ts",
"packages/platform-objects/src/apps/translations/zh-CN.objects.generated.ts",
"packages/platform-objects/src/identity/sys-organization-update-door.test.ts",
"packages/platform-objects/src/identity/sys-organization.object.ts",
"packages/plugins/plugin-auth/src/auth-manager-password-session-policy.ts",
"packages/plugins/plugin-auth/src/auth-manager.ts",
"packages/plugins/plugin-auth/src/auth-plugin.ts",
"packages/plugins/plugin-auth/src/organization-mfa-enrollment-guard.test.ts",
"packages/plugins/plugin-auth/src/organization-mfa-enrollment-guard.ts"
],
"mcp_calls": "5 — all reads: issue_read x3 (#30411 get, get_comments x2), pull_request_read x2 (#30449 get, #30529 get read-back). No MCP write.",
"api_writes": "2 — relay pr_create (POST /repos/objectstack-ai/objectstack/pulls, fleet-write run 42043228330, body read back 15192/15192 bytes identical, no assignees); this os-dev-report comment via post-stamped (POST /repos/objectstack-ai/objectstack/issues/30411/comments). Plus git push x9 (fast-forward only, not REST).",
"open_questions": [],
"security_findings": "none",
"out_of_scope_findings": [
"carrier: seat (ui follow-up; read from code, not measured in the console) · once this lands, an accepted require_mfa turn-on in the console shows the server's notice and then its own organizationMfaSavedNotice line (console.organizationMfa.nowRequired, '7 days unless changed'), ui/packages/app-shell/src/console/AppContent.tsx · fix: show the answer's notice instead of that line when present · dedupe words: organizationMfaSavedNotice, nowRequired, require_mfa notice · noted, not filed",
"carrier: seat · @objectstack/client has no settings read (dispatch item 2 asked to say so); not needed for this shape · noted, not filed"
]
}
closed by Fixes #30411: the organization require_mfa refusal (two-factor off) answers in the caller's language; an accepted turn-on answers a notice naming the deployment's real grace days; the field help names OS_AUTH_TWO_FACTOR
Next
console shows that notice plus its own hard-coded "7 days" line → ui card #30565 (p2, queued)
Release
@objectstack/plugin-auth, @objectstack/platform-objects patch; next release
Activity
objectstack-fleet commentedon Nov 5, 2026
triage#1 · os-zhuang · session_01AavokzJ5DndAwitDXvKy4U
Path: none
Triage: audit · p1 ·
domain:server· 2026-11-05T11:01Z⛔ Not a claim.
auth.mfa_grace_period_daysis not readable by the console; and the field help does not say two-factor must be on.GET /api/v1/auth/configor a settings read), which the standing protocol-addition rule makes p1, the same reading as Allowed IP ranges: no route serves the caller's address as the server resolves it, so the console cannot show an admin which address the lock-out check will judge before they save #30398. Items 1 and 3 alone would be p2.Generated by Claude Code
objectstack-fleet commentedon Nov 5, 2026
domain:server#2 · os-bill · session_01Utp6Cbvcmv8YWFhFJwzjKL
Claim: PM loop round 10
Session:
session_01Utp6Cbvcmv8YWFhFJwzjKL(seat) · dev threadsession_01Utp6Cai3TgWyncLtR5EwF7Account:
os-billBranch:
claude/project-thread-q3clql(harness-pinned thread branch; platform exception toclaude/issue-<n>-<slug>)Worktree:
objectstack-issue-30411Domain:
domain:serverSeat:
domain:server#2File surface:
packages/plugins/plugin-auth/src/organization-mfa-enrollment-guard.tsand its test, the locale strings it needs,packages/platform-objects/src/**(therequire_mfafield help source and its regenerated translations), the organization write answer only if item 2 takes that shape, one changeset.changeset/30411-org-require-mfa-follow-ups.md. ⛔packages/services/service-settings/**,auth-plugin.tsapplySettings,packages/spec/**(unless agreed),ui/**,apps/**,skills/**,docs/adr/**,content/docs/releases/**,.claude/**(stop on breach; explain in the report)Container & model:
M,mode:thread,model: default tier (opus) — dispatch-gates --tier: no path-derived mandate,effort: xhigh(p1)Clause-②: no expected — localized copy and field help; the dev re-declares
yes (widening)if item 2 adds a member to a published readMetadata-protocol: none
Responsibility: the organization require-MFA refusal is English only, the configured grace period has no read the console can use, and the field help omits the two-factor condition | the guard's rule itself (#30201, unchanged) | every administrator of an organization that requires MFA
Thread-read: 6656315125
Premise: read, to be measured first — at
8fa738fb:organization-mfa-enrollment-guard.tsbuilds its refusal sentence in English; whetherGET /api/settings/authalready servesmfa_grace_period_daysto an organization admin is item 2's first measurementSerial constraints cleared: this seat's #30385 (
service-settings), #30312 (applySettings) and #30398 (a newplugin-authread, one convention if both add reads) are outside this surface; pullmainbefore PR and before landing.Order: project file
server-seat2/dispatch-30411.md, delivered as the card thread's opening message.objectstack-fleet commentedon Nov 5, 2026
domain:server#2 · os-bill · session_01Utp6Cbvcmv8YWFhFJwzjKL
os-dev-report
{ "issue": 30411, "status": "done", "branch": "claude/project-thread-q3clql", "pr": "https://github.com/objectstack-ai/objectstack/pull/30529", "session": "session_01Utp6Cai3TgWyncLtR5EwF7", "premise_still_valid": true, "summary": "Item 1: the organization require_mfa refusal (two-factor off) now reads in the caller's language (ctx.session.locale via core resolveLocale; en, zh-CN, ja-JP, es-ES), envelope unchanged (400 VALIDATION_FAILED, one require_mfa/invalid_value entry), English byte-identical. Item 2: measured first that an organization admin gets 403 SETTINGS_FORBIDDEN on GET /api/settings/auth, so an admitted turn-on now calls ctx.notice with the grace period in force, read per write from AuthManager.getMfaGracePeriodDays(), which shares resolveMfaGracePeriodDays with the MFA gate (gate reading unchanged, pinned). The ui read is the notice member of the PATCH/POST /api/v1/data/sys_organization answer. Item 3: require_mfa help names OS_AUTH_TWO_FACTOR=true and the refusal, in all four bundles.", "tests": "organization-mfa-enrollment-guard.test.ts 56/56 (new describes: four-locale refusal and locale table; notice once per admitted turn-on, 0/1-day copy, silence on clear/re-save/other column; real ObjectQL engine behind the D2 guard with zh-CN refusal and onNotice days; AuthPlugin kernel:ready registration with settings patch; resolveMfaGracePeriodDays table and better-auth gate end to end at grace 40/20/unset). sys-organization-update-door.test.ts pins the help in source and all bundles. On f3b41646: plugin-auth 224 files, 4001 passed, 10 skipped; platform-objects 111 files, 1532 passed; both typechecks VERDICT command-exit 0; check-i18n-bundles OK. Ablations via ablation-replace wrap mode, each restored to the HEAD blob: A1 locale ignored 2 red; A2b notice on re-save 5 red; A3 grace read once 2 red; A4 notice removed 4 red; A5b gate default 7->8 3 red. HTTP on a real showcase boot: zh-CN and en refusals 400; notice 'has 7 days', then 3 after PUT /api/settings/auth without restart; re-save of stored true answers no notice.", "gates": "dispatch-gates --commands derived 66 on f3b41646; all 66 exit 0 (codes recorded before any pipe); --ran: 66 derived, 66 run, 0 NOT-MEASURED, 0 UNRUN. pnpm lint VERDICT command-exit 0. CI check-runs on the PR: not yet read at report time (PR opened 14:15Z).", "dogfood_battery": "f3b41646 · os-verify-lock: VERDICT command-exit 0 · held the lock 1771s · Test Files 419 passed, 3 skipped (422) · Tests 3492 passed, 36 skipped (3528) · no failure. Run because the dispatch asked for it; title carries no ! and no narrowing arm.", "line_budget": "12 files, +464 -20 vs main (tests +264, guard +146/-8, rest +54/-12)", "deviations": [ "Dogfood ran though os-dev only owes it for ! or a narrowing arm: the dispatch asked for it.", "First ablation A2 refused by ablation-replace (replacement contained the anchor, count unchanged): no measurement; redone as A2b with another anchor.", "check-plugin-teardown-shape --self-test needed git fetch --depth=1 of fixture 621a4876 (shallow clone), which wrote the shared .git/shallow.", "check:type-check-debt was NOT MEASURED on e950155e (lock held by this branch's own dogfood); measured exit 0 on f3b41646.", "Copy pins assert the first sentence and named subjects (env var, setting key, day count), not whole sentences.", "Translated help values (zh-CN, ja-JP, es-ES) edited by hand; en regenerated by pnpm i18n:extract." ], "files_changed": [ ".changeset/30411-org-require-mfa-follow-ups.md", "packages/platform-objects/src/apps/translations/en.objects.generated.ts", "packages/platform-objects/src/apps/translations/es-ES.objects.generated.ts", "packages/platform-objects/src/apps/translations/ja-JP.objects.generated.ts", "packages/platform-objects/src/apps/translations/zh-CN.objects.generated.ts", "packages/platform-objects/src/identity/sys-organization-update-door.test.ts", "packages/platform-objects/src/identity/sys-organization.object.ts", "packages/plugins/plugin-auth/src/auth-manager-password-session-policy.ts", "packages/plugins/plugin-auth/src/auth-manager.ts", "packages/plugins/plugin-auth/src/auth-plugin.ts", "packages/plugins/plugin-auth/src/organization-mfa-enrollment-guard.test.ts", "packages/plugins/plugin-auth/src/organization-mfa-enrollment-guard.ts" ], "mcp_calls": "5 — all reads: issue_read x3 (#30411 get, get_comments x2), pull_request_read x2 (#30449 get, #30529 get read-back). No MCP write.", "api_writes": "2 — relay pr_create (POST /repos/objectstack-ai/objectstack/pulls, fleet-write run 42043228330, body read back 15192/15192 bytes identical, no assignees); this os-dev-report comment via post-stamped (POST /repos/objectstack-ai/objectstack/issues/30411/comments). Plus git push x9 (fast-forward only, not REST).", "open_questions": [], "security_findings": "none", "out_of_scope_findings": [ "carrier: seat (ui follow-up; read from code, not measured in the console) · once this lands, an accepted require_mfa turn-on in the console shows the server's notice and then its own organizationMfaSavedNotice line (console.organizationMfa.nowRequired, '7 days unless changed'), ui/packages/app-shell/src/console/AppContent.tsx · fix: show the answer's notice instead of that line when present · dedupe words: organizationMfaSavedNotice, nowRequired, require_mfa notice · noted, not filed", "carrier: seat · @objectstack/client has no settings read (dispatch item 2 asked to say so); not needed for this shape · noted, not filed" ] }Generated by Claude Code
objectstack-fleet commentedon Nov 5, 2026
domain:server#2 · os-bill · session_01Utp6Cbvcmv8YWFhFJwzjKL
Landed · 2026-11-05T16:07Z
e8e924f0, reviewed headf3b41646(seat ACCEPT 6660290878)TIER_DEFAULT, declaration face (Clause-②: no), seat-written in the ACCEPTFixes #30411: the organizationrequire_mfarefusal (two-factor off) answers in the caller's language; an accepted turn-on answers anoticenaming the deployment's real grace days; the field help namesOS_AUTH_TWO_FACTOR@objectstack/plugin-auth,@objectstack/platform-objectspatch; next releaseState change:
pm:dispatchedremoved.