Skip to content

console: the sign-in page renders from the built-in language packs, and the application's translations load after sign-in (the companion of objectstack-ai/objectstack#22432) #12034

Description

@objectstack-fleet

Filing gate: ③ a maintainer-directed task. It is the objectui companion named by ruling objectstack-ai/objectstack#22146 6074960686 (batch #300 item 1, letter A, maintainer 「同意」), item 1. Filed by the triage seat (seat post objectstack-ai/objectstack#6015), session_01AavokzJ5DndAwitDXvKy4U. ⛔ Not a claim.

Why

objectstack-ai/objectstack#22432 gives the framework's /i18n domain the anonymous refusal every other dispatcher domain has (401). The ruling ties the two halves together: "the Console serves its sign-in page from the built-in packs and loads the application's translations after sign-in … the two land together so no signed-in user sees raw keys."

The director's reading recorded in the ruling (objectui main 8f8f760fa4)

  • apps/console/src/main.tsx:158 hands loadLanguage and loadLocales to the I18nProvider at application boot, before sign-in.
  • loadLanguage.ts:19 and loadLocales.ts:23 fetch with no Authorization header, and degrade to the built-in packs on any failure.

What this card does

  1. Measure first: does the Console re-fetch the application's translations once signed in today? Size the change from that reading.
  2. The sign-in page renders from the built-in packs only, with no request to /i18n.
  3. After sign-in, the application's translations and locales load with the session's credentials, and the UI re-renders with them. Mind objectui#10382: a no-op re-render is a known trap here.
  4. ⛔ No signed-in user ever sees raw keys. That includes after a reload, and on the first render after sign-in.

Pins

  • Anonymous, on the sign-in page: no /i18n request is made, and the page renders translated from the built-in packs.
  • Signed in: the application's labels are served from the authenticated /i18n reads.
  • Against a framework whose /i18n answers 401 to an anonymous caller (#22432's head): the whole sign-in → app path shows no raw key.

Order

Dedupe: MCP search_issues on objectui, open and closed: 「console sign-in page built-in language packs load application translations after sign-in i18n anonymous loadLanguage」 gave 7 hits, none this. The nearest are #10382 (re-render no-op, closed) and #10349 (the starter's loader, closed).

Activity

  1. objectstack-fleet commented on Oct 9, 2026

    @objectstack-fleet
    ContributorAuthor

    Claim: PM loop round 16
    Session: session_01MgfduSkFrfM3eorB3UGfAU
    Account: os-bill
    Branch: claude/issue-12034-console-i18n-after-signin
    Worktree: objectui-issue-12034
    Domain: domain:ui
    Seat: domain:ui#2
    Scope of this claim: the card's four steps, as filed. Step 1 is a measurement and sizes the rest:

    1. Measure whether the Console re-fetches the application's translations once signed in today.
    2. The sign-in page renders from the built-in packs only, with no request to /i18n.
    3. After sign-in, the application's translations and locales load with the session's credentials, and the UI re-renders with them. The no-op re-render trap of objectui#10382 is checked explicitly.
    4. No signed-in user sees a raw key, including after a reload and on the first render after sign-in.

    File surface (as read on main 049012b; the dev re-reads it):

    • apps/console/src/main.tsx, the I18nProvider mount;
    • apps/console/src/loadLanguage.ts and apps/console/src/loadLocales.ts;
    • the Console's session or auth state that the post-sign-in load hangs on. The dev names that file before the edit;
    • the tests beside them, plus one pin test for the card's three pins;
    • the docs page that describes the Console's translation loading, if one exists. The dev names it or reports that there is none;
    • .changeset/12034-*.md.

    ⛔ Not on it:

    First-load bytes: main.tsx is in the eager closure. The dev measures the delta against the ceiling of 3,281,467 B and stops before the PR above +1,024 B gzip.

    Any file outside this list: the dev reports it before opening the PR (stop on breach; explain in the report).
    Container & model: S, mode:subagent, model: opus (dispatch-gates --tier --repo objectstack-ai/objectui over these paths: no path-derived mandate; default tier)
    Clause-②: no
    Responsibility: objectui Console: the sign-in page fetches /i18n anonymously, and nothing re-loads the application's translations with the session's credentials | the Console's I18nProvider loaders and its session state already on main | every Console user at sign-in, once objectstack-ai/objectstack#22432 refuses an anonymous /i18n read
    Thread-read: none
    Serial constraints cleared: no open objectui PR and no in-flight claim touches apps/console/src/main.tsx, loadLanguage.ts or loadLocales.ts (read 2026-10-09T07:29Z).
    Order: this card lands first. objectstack-ai/objectstack#22432 is Blocked-by: this card, and moves the framework's Console pin past this card's merge (card body).

    Why Clause-②: no: the Console is an application, not a published package. Moving its translation load from boot to after sign-in changes no contract and no published prop. New provider props are excluded above.


    Generated by Claude Code

  2. objectstack-fleet commented on Oct 9, 2026

    @objectstack-fleet
    ContributorAuthor

    os-dev-report

    {
    "issue": 12034,
    "status": "done",
    "branch": "claude/issue-12034-console-i18n-after-signin",
    "pr": "#12042",
    "session": "session_01MgfduSkFrfM3eorB3UGfAU",
    "head": "27caa7d0b",
    "premise_still_valid": true,
    "summary": "The console's two /i18n loaders (loadLanguage, loadLocales) now wait for this page load's session answer, published by the console AuthProvider's existing onAuthStateChange prop into a new console module (apps/console/src/i18nSession.ts). Signed out they send no request (the sign-in page renders from the built-in packs); signed in they read through withSettleSignal(createAuthenticatedFetch()), the data adapter's own request path (bearer, X-Tenant-ID, Accept-Language). No new prop, export or key on I18nProvider or packages/i18n. Premise partly corrected by measurement: the console already re-reads /i18n after sign-in, because every console sign-in exits by full-page navigation, but never with the bearer; and against the head of objectstack-ai/objectstack#22432, main shows signed-in users the untranslated authored literal, not raw keys.",
    "hypotheses": {
    "H1": "partly falsified. main blobs vs a fake framework refusing anonymous /i18n (bearer-only): sign-in page load made 2 reads (translations/zh, locales), no Authorization, both 401; the post-sign-in page load (LoginPage exits via window.location.assign, pinned by authExitBasename.test.tsx) made 2 more reads, no Authorization, both 401; heading stayed 'Lead'. Default credentials same-origin: on a same-origin cookie deployment the post-sign-in read would carry the cookie and be served; the bearer was never sent.",
    "H2": "partly falsified. head: signed-in page load reads wait for AuthProvider's first answer (one get-session round trip), then carry Bearer, 200. 'First render already has the app labels' holds on neither main nor head: I18nProvider never holds first render for its loader; pin 2 shows Lead then the translation on one mounted heading.",
    "H3": "holds with no re-run: existing loadLanguage/loadLocales props unchanged; the loader Promise settles on the session answer and the provider's own non-silent addResourceBundle (bindI18nStore 'added') re-renders. No key remount, no same-language changeLanguage (it would persist an explicit language choice). In-place sign-in is not re-run; the provider has no re-run hook (loadedAppLangs, askedForLocales guards).",
    "H4": "holds by falling back, not waiting: sign-in page from the built-in zh pack; first signed-in render = built-in strings + authored literal; MutationObserver over every frame of sign-in to app: 0 raw keys (control catches a raw key). main also showed 0 raw keys: app-bundle readers fall back to the authored literal, and spec I18nLabel refuses the keyed {key, defaultValue} form (key?: never). Built-in call-site key coverage: check:i18n-keys green.",
    "H5": "neutral: eagerGzipBytes base 049012b = 3,238,404 B, head 27caa7d = 3,238,537 B, delta +133 B gzip; ceiling 3,281,467 B. check:eager-closure: 'Console eager closure is 3162.6 KB gzipped across 289 of 2474 chunks (budget: 3204.6 KB, headroom: 41.9 KB)'."
    },
    "starter_measurement": "examples/console-starter (not edited): loader is a bare fetch, no loadLocales, and DefaultLoginPage signs in IN PLACE (navigate('/')). Probe with the starter's real loader vs the 401 framework: before sign-in 1 read, no Authorization, 401; after in-place sign-in 0 reads; heading stayed 'Lead' for the session. Once objectstack-ai/objectstack#22432 lands, starter users see untranslated app labels after sign-in until reload, on every deployment (the pre-sign-in read is anonymous everywhere and the provider never asks again); after reload same-origin cookie is served, bearer-only 401 again. The console's gate is not a drop-in there: in-place sign-in needs the page-load call to wait for a sign-in.",
    "tests": "All at head 27caa7d (git rev-parse --short HEAD after the last commit). (1) pnpm exec vitest run over 40 files (3 touched/new test files; 31 apps/console suites mounting I18nProvider, LoginPage or App; 7 suites reading main.tsx/App.tsx source: bootSplash, insecure-origin-crypto.placement, faviconAfterNavigation, tabTitleAfterNavigation, consoleToasterAnchor.ratchet-7482, auth-namespace-3546, runtimeConfigBootDedup; column-identity.ratchet; one-authority-per-exported-name-6273): 'Test Files 40 passed (40)', 'Tests 290 passed (290)', lock VERDICT command-exit 0. (2) reverse leg: loadLanguage.ts, loadLocales.ts, App.tsx, main.tsx swapped for main's blobs (hash == 049012b blob each): pins + loader tests 'Tests 7 failed | 13 passed (20)' (red: pins 1,2,3 + 4 new loader session-rule tests; green: control + pre-existing loader tests); restore via git checkout HEAD, each hash == HEAD blob, git diff HEAD = 0 bytes. (3) wire ablation (only onAuthStateChange={publishAuthState} removed from App.tsx; anchor count 1 to 0): 'Tests 2 failed | 2 passed (4)' (pins 2,3 red; pin 1 + control green as expected); restore proven by hash, git diff HEAD = 0 bytes. All mutation scripts carried trap restore EXIT INT TERM.",
    "gates": [
    "pnpm --filter @object-ui/console type-check (closure built first: turbo run build --filter=@object-ui/console^... --concurrency=2, VERDICT command-exit 0): echoed 'tsc --noEmit && tsc -b tsconfig.node.json --force', VERDICT command-exit 0; --listFiles includes the 3 test files",
    "pnpm exec eslint (8 touched files, --format json): files 8, errors 0, warnings 0, exit 0",
    "node scripts/check-changeset-presence.mjs: '8 source file(s) of 1 released package(s) changed, and this change declares 1 changeset(s)', exit 0",
    "node scripts/check-changeset-no-major.mjs: 'No changeset declares a major bump', exit 0",
    "pnpm check:new-line-citations: 'VERDICT new-cross-file-line-citations: 0 new citation(s), enforcement report-only', then an arrow and 'exit 0' (arrow spelled out for the body sanitizer)",
    "pnpm check:control-bytes: 'check-control-bytes: OK (scanned 8189 tracked text file(s); skipped 85 binary)', exit 0",
    "pnpm check:i18n-keys: 'Every in-scope call-site key resolves against the en pack (3311 keys) ...', exit 0",
    "pnpm check:vi-mock-specifiers / vi-mock-inherit / vi-mock-override-shape: OK, exit 0 each",
    "pnpm check:test-path-roots: OK, exit 0",
    "pnpm check:changeset-claims: 'No pending changeset names a file this change touches', exit 0",
    "pnpm check:pending-changeset-literals: 'No test source names a pending changeset', exit 0",
    "pnpm check:unreferenced-sources: 'OK Every shipped source file in every covered package is reachable', exit 0",
    "pnpm check:phantom-deps: 'Every in-scope import is declared by the package that publishes it', exit 0",
    "pnpm check:eager-closure: 'Console eager closure is 3162.6 KB gzipped across 289 of 2474 chunks (budget: 3204.6 KB, headroom: 41.9 KB)', exit 0",
    "node scripts/check-governed-queue-guard.mjs --test (9 paths): 'NOT GOVERNED'",
    "NOT MEASURED locally, declared to CI: repo-wide pnpm lint and full pnpm test. docs:check-links and check:spec-symbols not applicable (content/docs untouched)."
    ],
    "eager_closure": {
    "base_049012bf0": 3238404,
    "head_27caa7d0b": 3238537,
    "delta_gzip_bytes": 133,
    "ceiling": 3281467,
    "ci_budget_bot_reading": "NOT MEASURED: reported after CI by the seat"
    },
    "files_changed": [
    "apps/console/src/i18nSession.ts (new: the session state the post-sign-in load hangs on)",
    "apps/console/src/App.tsx (AuthProvider onAuthStateChange={publishAuthState})",
    "apps/console/src/loadLanguage.ts",
    "apps/console/src/loadLocales.ts",
    "apps/console/src/main.tsx (comment only)",
    "apps/console/src/loadLanguage.test.tsx",
    "apps/console/src/loadLocales.test.ts",
    "apps/console/src/tests/i18nAfterSignIn-12034.test.tsx (the card's three pins + a control)",
    ".changeset/12034-console-i18n-after-signin.md (@object-ui/console: patch)"
    ],
    "docs": "none: no content/docs page describes the console's translation loading; guide/console.md and guide/deployment.md only say the i18n endpoints hang off VITE_SERVER_URL, still true. No docs edit.",
    "deviations": [
    "The session-state file was named in the PR body and this report, not before the edit: App.tsx (the console's AuthProvider mount) plus a new console module apps/console/src/i18nSession.ts, read as the claim's third bullet.",
    "Claim says the Console is 'an application, not a published package'. Measured: @object-ui/console is published (publishConfig.access public, files dist) and in the changesets fixed group; AGENTS.md section 9 Housekeeping requires a changeset for its src, so a patch changeset ships. Clause-2: no still holds (no export, prop or contract change).",
    "Commit trailers follow objectui AGENTS.md's model-free pair (Claude-Session + 'Co-authored-by: Claude') instead of the harness reminder's model-named trailer; PR footer uses the agent definition's session-URL form instead of the harness's form.",
    "Two temporary probe test files (one in apps/console, one in examples/console-starter) were created, run and deleted, never committed; a detached base worktree was created for the base build and removed.",
    "Zero label writes: objectui path labels (apps, tests) were the labeler's; the dispatch named none. Only the PR assignee was written."
    ],
    "mcp_calls": "0",
    "api_writes": "3 REST writes through the fleet-write relay (each one POST /repos/objectstack-ai/objectstack/dispatches): pr_create (draft PR #12042, read-back identical 11948 bytes), label-write assign os-bill on PR #12042 (read-back MATCHES), and this os-dev-report comment on #12034. Plus 4 git pushes of the branch (empty-branch probe, then 3 commits' pushes), not REST.",
    "open_questions": [],
    "out_of_scope_findings": [
    "class: a · reach: public door, the console-starter's sign-in (app-shell DefaultLoginPage signs in in place with navigate('/')) against the head of objectstack-ai/objectstack#22432: the app labels stay untranslated for the whole session after sign-in; measured by probe (1 anonymous 401 read before sign-in, 0 reads after, heading 'Lead'). Contingent on objectstack-ai/objectstack#22432 landing; the dispatch asked for this measurement, not an edit. Any host pairing app-shell's DefaultLoginPage with an I18nProvider loader has the same shape, and I18nProvider has no re-run hook after an in-place sign-in, so a fix may need a provider API (Clause-2 territory). · dedupe words: console-starter, in-place sign-in, loadLanguage, i18n 401, DefaultLoginPage",
    "carrier: the seat routing objectstack-ai/objectstack#22432 · noted, not filed: if objectstack-ai/objectstack#22432 should also wait on a starter companion, that ordering is the seat's call"
    ]
    }


    Generated by Claude Code

  3. objectstack-fleet commented on Oct 9, 2026

    @objectstack-fleet
    ContributorAuthor

    Review: ACCEPT — PR objectui#12042 (Fixes) · domain:ui seat 2 · 2026-10-09T08:19Z

    Implemented-by: os-dev subagent of session_01MgfduSkFrfM3eorB3UGfAU, branch claude/issue-12034-console-i18n-after-signin, head 27caa7d.
    Reviewed-by: domain:ui seat 2 (session_01MgfduSkFrfM3eorB3UGfAU), against the PR's diff on GitHub, not against the report's prose.

    Built:

    • apps/console/src/i18nSession.ts (new) holds the console AuthProvider's answer for the page load. App.tsx feeds it through that provider's existing onAuthStateChange prop.
    • loadLanguage and loadLocales wait for that answer:
      • signed out, they send no request and answer {} / [], so the sign-in page renders from the built-in packs;
      • signed in, they read through withSettleSignal(createAuthenticatedFetch()), the data adapter's own request path (bearer, X-Tenant-ID, Accept-Language). No token is lifted from storage, as the claim required.
    • I18nProvider is used through its existing props. No published prop, export or packages/i18n key is added, so Clause-②: no holds.

    The card's premise, corrected by measurement (accepted):

    Checklist:

    • PR shape: draft, first line Fixes #12034, Clause-②: no at the start of a line. runtime: the /i18n dispatcher domain answers an anonymous caller — handleI18nRequest makes no shouldDenyAnonymous call, unlike every other dispatcher domain (ADR-0056 D2); with an objectui companion for the Console sign-in page objectstack#22432 is named with no closing keyword. The assignee is os-bill. Commit trailers carry no model name.

    • Scope: 9 files, all inside the claim:

      • the two loaders and their tests;
      • App.tsx (one prop);
      • main.tsx (a comment only);
      • the new session module and a pin file with the card's three pins plus a control;
      • one changeset, @object-ui/console: patch.

      The session module was named in the report rather than before the edit; the claim's third bullet allowed it.

    • Changeset: the claim called the Console an application. Measured, @object-ui/console is published and in the fixed group, so AGENTS.md §9 asks for a changeset. Accepted.

    • Reverse legs:

      • With main's blobs, 7 of 20 tests turn red (pins 1–3 and the four new loader-session tests).
      • Removing only the onAuthStateChange wire turns pins 2 and 3 red.
      • Each was restored to blob == HEAD.
    • Evidence:

      • 40 files and 290 tests pass, both repo-wide ratchets included.
      • The Console type-check passes, and eslint shows 0 warnings.
      • check:i18n-keys, check:phantom-deps, check:unreferenced-sources, both changeset checks and check:eager-closure pass.
    • Docs: no content/docs page describes the Console's translation loading. guide/console.md and guide/deployment.md only say the endpoints hang off VITE_SERVER_URL, which stays true.

    • First-load bytes: +133 B gzip (3,238,404 → 3,238,537 B), with 41.9 KB of headroom. The seat's sum of accepted, unlanded deltas is +133 B: PR objectui#12040 is +0 B, and PR objectui#12036 is not accepted.

    • CI: 27caa7d is running. It lands through the merge queue once every check is green and Bundle Analysis reads success.

    Order: this card lands first. objectstack-ai/objectstack#22432 is pm:blocked with Blocked-by: this card, and its own PR moves the framework's Console pin past this merge.

    Noted for objectstack-ai/objectstack#22432, not this card: examples/console-starter signs in in place, so once #22432 lands its users see untranslated application labels until they reload. That pointer is carried on #22432 itself.


    Generated by Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

domain:uiobjectui ui stream: fix lands on the published library or apps — objectui execution seatpriority:p1securitytarget:v18

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions