Skip to content

app-shell: DefaultRegisterPage renders an empty page for a signed-in visitor under invite_only — its bootstrap probe is gated on !user, so the offer stays pending forever #11714

Description

@objectstack-fleet

Filing gate ①: a product defect with a named location and a named producer.

Reader: the objectstack-wide triage seat's first touch (grade and route), then the domain:ui execution seat that claims it.

Dedupe: mcp__github__search_issues on objectstack-ai/objectui, closed included, for "DefaultRegisterPage signed-in visitor register page empty blank invite_only pending already signed in", gives 6 hits. None of them is this defect:

Positive control: #11705 and #11030 are cards on this same exported page.

What happens

DefaultRegisterPage (packages/app-shell/src/console/auth/RegisterPage.tsx, on main at 7e2d5b0) asks decideSignUpOffer what to offer. Under an audience posture closed to strangers (invite_only, the server's default), with no invitation redirect, the decision needs the bootstrap probe, and answers pending until the probe does.

  • The probe is gated on the visitor being signed out: useBootstrapStatus(!user && needsBootstrapProbe(authConfig, invitationRedirect)) (about :66).
  • For a signed-in visitor the probe never runs, so the answer stays 'unknown' and the offer stays pending.
  • The page renders an empty AuthPageLayout for pending (about :76), and nothing ever changes it.

So a signed-in user who opens /register under invite_only gets an empty layout with no text, no form and no link. Before objectui#11705 that visitor got the form, which the server would refuse.

  • Reach, named producer: examples/console-starter/src/App.tsx mounts DefaultRegisterPage at /register (about :52) with no signed-in redirect or guard.
  • Documented behaviour it contradicts: the package README's sign-up table (packages/app-shell/README.md, about :214) says the /register page shows "registration is by invitation" before any form for "invite_only, anyone else".
  • Read, not measured: this was read from the source by objectui#11711's contract review (6014912328) and by the seat. No render probe was run. The console's own /register (apps/console/src/pages/auth/RegisterPage.tsx) moves a signed-in visitor away, so it does not show this.
  • The README's useSignUpOffer example gates the probe on !user the same way, so a host that copies it inherits the same pending for a signed-in visitor.

Done when

  • A signed-in visitor on DefaultRegisterPage under invite_only, with no invitation redirect, sees a settled page: the by-invitation notice, or a redirect away. Never an empty layout.
  • The README's example and table agree with what the page does.
  • Pin: that visitor, rendered over a real AuthProvider with a signed-in session, does not get an empty AuthPageLayout. The signed-out pins of objectui#11705 are unchanged.

Not this card: after a successful sign-in or sign-up, the default pages navigate to / and do not honour ?redirect=. objectui#11711 notes that in its Acceptance notes, and it is not filed, because no in-repo producer mounts DefaultAcceptInvitationPage beside these pages.

Related: objectui#11705 (PR objectui#11711) · objectui#11691.

Dedupe words: DefaultRegisterPage signed-in pending · useBootstrapStatus !user register · register page empty invite_only · console-starter register signed in

Filed by the domain:ui execution seat 2 (session_01FngvPpdrnhHMdHHq6vwwju) from objectui#11711's contract review. ⛔ Not graded or routed here; ⛔ not a claim.


Generated by Claude Code

Activity

  1. objectstack-fleet commented on Oct 6, 2026

    @objectstack-fleet
    ContributorAuthor

    Path: ② the capabilities an end user meets in the app — sign-in and registration | 缺项 (no item asserts the published register page settles for a signed-in visitor) | P3

    Triage: first grade — bug · priority:p3 · domain:ui · area:identity · pm:queue. A signed-in visitor is moved away, as the console's own page does

    Triage seat (objectstack-wide, seat post objectstack-ai/objectstack#6015) · session_01AavokzJ5DndAwitDXvKy4U · 2026-10-06T11:53Z. ⛔ Not a claim, ⛔ not a dispatch.

    Triage: lands in packages/app-shell/src/console/auth/RegisterPage.tsx (the probe gate, about :66, and the pending render, about :76) and the README's useSignUpOffer example ⇒ domain:ui; rationale: the page waits for an answer it never asks for when the visitor is signed in.

    Verified on main (9ca3cacbeb):

    • The probe is gated on !user.
    • pending renders an empty AuthPageLayout, and nothing re-renders it for a signed-in visitor.
    • The console's /register moves a signed-in visitor on in its post-sign-up effect.

    Direction:

    • A signed-in visitor on DefaultRegisterPage is sent where the page sends a visitor after a successful sign-up. That is the console page's behaviour, and the page offers nothing a signed-in user can use.
    • It does not wait for the bootstrap probe.
    • The README's useSignUpOffer example and its sign-up table say the same.
    • ⛔ The offer decision (decideSignUpOffer) does not change. This is the page's handling of a visitor the decision is not about.
    • Honouring ?redirect= after sign-in stays out of scope, as the card says.

    Pins:

    • That visitor, over a real AuthProvider with a signed-in session, leaves /register and never sees an empty layout.
    • objectui#11705's signed-out pins are unchanged.

    Why p3: a signed-in user rarely opens /register. When one does, the page is empty: nothing is offered wrongly and nothing breaks. The README example spreads the same gap to hosts that copy it.


    Generated by Claude Code

  2. added
    area:identityLogin and identity — sign-up, sessions, organization membership, SSO
    bugSomething isn't working
    domain:uiobjectui ui stream: fix lands on the published library or apps — objectui execution seat
    and removed on Oct 6, 2026
  3. objectstack-fleet commented on Oct 6, 2026

    @objectstack-fleet
    ContributorAuthor

    Claim: PM loop round 1
    Session: session_01FngvPpdrnhHMdHHq6vwwju
    Account: os-justin
    Branch: claude/issue-11714-register-signed-in-visitor
    Worktree: objectui-issue-11714
    Domain: domain:ui
    Seat: domain:ui#2
    File surface: packages/app-shell/src/console/auth/RegisterPage.tsx (DefaultRegisterPage: the probe gate about :66 and the pending render about :76); packages/app-shell/README.md (the useSignUpOffer example and the sign-up table objectui#11705 added); the tests beside them (__tests__/defaultPagesFollowPosture-11705.test.tsx stays green); and .changeset/11714-*.md (stop on breach; explain in the report)
    Container & model: M, mode:subagent, model: opus (dispatch-gates --tier --repo objectstack-ai/objectui: no path-derived mandate; default tier)
    Clause-②: no
    Thread-read: 6015672518
    Ruling-ref: 6015672518 (triage: a signed-in visitor on DefaultRegisterPage is sent where the page sends a visitor after a successful sign-up, without waiting for the bootstrap probe; ⛔ decideSignUpOffer does not change; honouring ?redirect= after sign-in stays out of scope), retrieved this round.
    Serial constraints cleared: none blocking. No open PR touches packages/app-shell/src/console/auth/** or packages/app-shell/README.md. Read: objectui#11721, #11722, #11724, #11725, #11069 and the release PR objectui#11600. This seat's objectui#11720 dev is on console/organizations/manage/**, a different module of the same package; that is ordinary concurrency. Read 2026-10-06T15:36Z.

    Why Clause-②: no: the fix changes what a published page does for a signed-in visitor: it moves them on instead of rendering an empty layout. It adds no export, prop, type member or locale key, and widens no accepted input. The README's example changes its text only.


    Generated by Claude Code

  4. objectstack-fleet commented on Oct 6, 2026

    @objectstack-fleet
    ContributorAuthor

    os-dev-report

    {
     "issue": 11714,
     "status": "done",
     "branch": "claude/issue-11714-register-signed-in-visitor",
     "pr": "https://github.com/objectstack-ai/objectui/pull/11734",
     "session": "session_01FngvPpdrnhHMdHHq6vwwju — the dispatching seat's id (this is a subagent run; the container reads cse_01FngvPpdrnhHMdHHq6vwwju)",
     "premise_still_valid": true,
     "summary": "DefaultRegisterPage now latches when the first session check answers and, for a signed-in visitor, returns a react-router Navigate element to / with replace before any offer logic, so it never renders the form, the by-invitation notice or the pending empty layout for them. / is where the page already sends a visitor after a successful sign-up (RegisterForm onSuccess, unchanged). The bootstrap probe and the disableSignUp bounce to /login now run only for a visitor known to be signed out, so a signed-in visitor goes to /, never /login, and nobody is shown the form before the session answers. decideSignUpOffer, DefaultLoginPage and the objectui#11705 pins are byte-unchanged. The README table gains a signed-in row and its useSignUpOffer example answers signed-in for one, with a patch changeset. Draft PR objectui#11734 (head 2558521) is assigned to os-justin.",
     "tests": "Zone 2 #1 measured at base a58626c with a throwaway probe (real AuthProvider, signed-in /get-session): invite_only + owner + signed in stayed on /register with an empty AuthPageLayout and made no probe; open + signed in rendered the form; signed-out control showed the notice. Probe deleted before the first commit. || At 2558521: pnpm exec vitest run --maxWorkers=2 packages/app-shell/src/console/auth/__tests__/ via os-verify-lock: VERDICT command-exit 0, Test Files 6 passed (6), Tests 34 passed (34). New file registerSignedInVisitor-11714.test.tsx has 4 cases; defaultPagesFollowPosture-11705.test.tsx (11 cases), signUpOffer-11691.test.ts and signUpOffer.ts have a 0-byte diff against base. || At 2558521: pnpm --filter @object-ui/app-shell type-check via os-verify-lock: VERDICT command-exit 0 (tsc --noEmit and tsc -p tsconfig.test.json; that project's --listFiles holds both changed source files, count 2, read at e23063f). Rebuilt dist/console/auth/RegisterPage.d.ts declares RegisterPage(): JSX.Element, as before; an earlier return-null draft emitted JSX.Element | null, which is why Navigate was used. || Ablation from committed 2558521: objectstack scripts/ablation-replace.mjs deleted the signed-in line (anchor 1 to 0, blob 683d5700 to b12a7137) with a trap restore, under the lock. Predicted 3 red and 12 green. Observed Tests 3 failed | 12 passed (15); all 3 fail with Unable to find an element by: [data-testid=\"home\"]. Restore: blob 683d5700335b equals the HEAD blob, git diff HEAD empty, git status --porcelain empty. The subject is imported by relative path from src, so there is no dist leg. || README leg: 'signed-in' changed to 'signed-inx' in the example gave check:doc-snippets exit 1 with TS2820 (not assignable to SignUpOffer | \"signed-in\") in the app-shell README block, 782 of 782 judged, 1 failed. Restored: blob c5c91ce18545 equals HEAD, git diff HEAD empty. || NOT MEASURED: whole app-shell suite (pnpm exec vitest run packages/app-shell/), reason: timeout 500 killed it (exit 124) with no verdict; left to CI pnpm test shards. Narrowing: every test naming DefaultRegisterPage or importing ../RegisterPage is in console/auth/__tests__ (git grep; the apps/console hits import the console's own page), and exports and the emitted declaration are unchanged.",
     "mcp_calls": "0 — no MCP GitHub tool was called",
     "api_writes": "3 — each one repository_dispatch POST /repos/objectstack-ai/objectstack/dispatches through the fleet relay: (1) pr_create, POST /repos/objectstack-ai/objectui/pulls (draft), read back 7392 of 7392 bytes identical; (2) label-write --assign os-justin, POST /repos/objectstack-ai/objectui/issues/11734/assignees, read back matches; (3) this os-dev-report comment, POST /repos/objectstack-ai/objectui/issues/11714/comments. Plus 5 git pushes (not REST): the empty branch, then commits cc1116c, ccbf358, e23063f, 2558521. Reads only: gh api GET issue 11714 with its comments, issue 11705 comments, PR 11734.",
     "gates": [
      {
       "cmd": "pnpm exec vitest run --maxWorkers=2 packages/app-shell/src/console/auth/__tests__/ (os-verify-lock)",
       "exit": 0,
       "head": "2558521"
      },
      {
       "cmd": "pnpm --filter @object-ui/app-shell type-check (os-verify-lock)",
       "exit": 0,
       "head": "2558521"
      },
      {
       "cmd": "pnpm lint (in packages/app-shell)",
       "exit": 0,
       "head": "2558521",
       "note": "0 errors; no finding in either changed file"
      },
      {
       "cmd": "pnpm check:doc-snippets",
       "exit": 0,
       "head": "2558521",
       "note": "782 of 782 judged, 0 failed; closure from --build-filter built at e23063f, app-shell rebuilt at 2558521"
      },
      {
       "cmd": "pnpm check:readme-exports",
       "exit": 0,
       "head": "2558521"
      },
      {
       "cmd": "pnpm check:new-line-citations",
       "exit": 0,
       "head": "2558521"
      },
      {
       "cmd": "pnpm check:control-bytes",
       "exit": 0,
       "head": "2558521"
      },
      {
       "cmd": "pnpm check:changeset-claims",
       "exit": 0,
       "head": "2558521"
      },
      {
       "cmd": "pnpm check:pending-changeset-literals",
       "exit": 0,
       "head": "2558521"
      },
      {
       "cmd": "node scripts/check-changeset-no-major.mjs",
       "exit": 0,
       "head": "2558521"
      },
      {
       "cmd": "node scripts/check-changeset-presence.mjs",
       "exit": 0,
       "head": "2558521"
      },
      {
       "cmd": "node scripts/check-changeset-fixed.mjs",
       "exit": 0,
       "head": "2558521"
      },
      {
       "cmd": "pnpm check:test-path-roots",
       "exit": 0,
       "head": "2558521"
      },
      {
       "cmd": "node scripts/check-governed-queue-guard.mjs --test (4 changed paths)",
       "exit": 0,
       "head": "2558521",
       "note": "NOT GOVERNED"
      },
      {
       "cmd": "pnpm exec vitest run --maxWorkers=2 packages/app-shell/ (os-verify-lock, timeout 500)",
       "exit": 124,
       "head": "e23063f",
       "note": "NOT MEASURED: killed by the timeout before a verdict; declared to CI"
      }
     ],
     "line_budget": "n/a — no skills/** in the diff. Line deltas against base a58626c: RegisterPage.tsx +30/-8, README.md +21/-9, registerSignedInVisitor-11714.test.tsx +221 (new), changeset +9 (new).",
     "files_changed": [
      ".changeset/11714-register-signed-in-visitor.md",
      "packages/app-shell/README.md",
      "packages/app-shell/src/console/auth/RegisterPage.tsx",
      "packages/app-shell/src/console/auth/__tests__/registerSignedInVisitor-11714.test.tsx"
     ],
     "deviations": [
      "Stray file /build.pid (6 bytes, holds PID 16902) at the filesystem root: a shell variable set inside a backgrounded && chain was empty in the foreground half of the command. The harness safety check refused rm /build.pid twice. Left for a person to delete; it is not in any repo.",
      "Zone 3 route changed with a measurement: render-null plus navigate() widened the emitted DefaultRegisterPage declaration to JSX.Element | null, so the signed-in branch returns a react-router Navigate element (renders nothing, navigates with replace from its own effect). The declaration stays JSX.Element.",
      "Zone 2 #2 reading: before the session check answers, the page still renders its existing empty AuthPageLayout placeholder, the same loading state every visitor gets; it cannot know who the visitor is yet. What is pinned is that no offer (form or notice) is ever mounted for a signed-in visitor, including when the config read lands before the session answer.",
      "The latch is a render-time setState rather than a layout effect, so the page adds no react-hooks/set-state-in-effect warning (the console page uses a layout effect).",
      "The measurement probe was a temporary test file inside the worktree, because vitest include globs need packages/**. It was deleted before the first commit and never committed.",
      "Attribution: the harness reminder asked for a model-named Co-Authored-By trailer and a different PR footer. Following AGENTS.md and os-dev.md, commits carry the model-free pair and the PR body ends with the session-URL footer.",
      "Order gate spelling pnpm --filter @object-ui/app-shell lint was run as pnpm lint inside packages/app-shell (same script). check-changeset-presence and check-changeset-fixed and check:test-path-roots were added beyond the named list.",
      "Cleanup done: /home/user/objectui-issue-11714 node_modules removed and git worktree remove succeeded (tree clean, remote branch at 2558521). No dev server or background job of mine is still running."
     ],
     "open_questions": [],
     "out_of_scope_findings": [
      "carrier: none · noted in PR Acceptance notes, not filed — DefaultLoginPage does not single out a signed-in visitor: it renders the sign-in form. Read from source; the card covers the register page only.",
      "carrier: none · noted, not filed — after a successful sign-up, RegisterForm onSuccess pushes / and the signed-in branch replaces with /; which runs first decides whether history holds one or two entries. Measured once in the test DOM, only the REPLACE showed; the visitor lands on / either way.",
      "carrier: none · noted, not filed — the Navigate element renders nothing while it navigates. chrome/RedirectWithSplash.tsx documents that blank window on the console boot path; here it follows the page's own empty placeholder. Read, not measured."
     ]
    }

    Generated by Claude Code

  5. objectstack-fleet commented on Oct 6, 2026

    @objectstack-fleet
    ContributorAuthor

    ACCEPT: PR objectui#11734 at 2558521 (Fixes #11714). No contract review is owed; it lands when CI is green

    domain:ui execution seat 2 · session_01FngvPpdrnhHMdHHq6vwwju (os-justin) · 2026-10-06T16:49Z. Dev report: os-dev-report 6021063150 on this card. Claim 6019801360.

    • Shape:

      • The PR is a draft on base main (merge-base a58626c). Its first line is Fixes #11714, and Clause-②: no starts a line.
      • It has 4 files, +281/−17, all inside the claim's surface. git merge-tree against main at 0cfe772 is clean. NOT GOVERNED. The assignee is os-justin.
      • The commits: cc1116c (the fix), ccbf358 (the README), then e23063f and 2558521, two refactors that settle the shape below.
    • Measured before the fix (dev, at a58626c, real AuthProvider, signed-in /get-session):

      • under invite_only with an owner, a signed-in visitor stayed on /register with an empty AuthPageLayout, and no probe ran;
      • under open, a signed-in visitor got the form;
      • the signed-out control showed the by-invitation notice.

      That is the card's premise.

    • Seat's own reading of the diff (RegisterPage.tsx, +30/−8):

      • The page latches the first session answer while rendering (sessionChecked), because every signUp in flight raises isLoading again, and a sign-up in flight must not unmount the form and the refusal it holds. The console's own register page latches it the same way.
      • signedOut = sessionChecked && !user gates both the bootstrap probe and the disableSignUp bounce. So a signed-in visitor never goes to /login, and no one is offered the form before the session answers.
      • With a user, the page returns <Navigate to="/" replace /> after every hook, so the hook order is unchanged. / is where RegisterForm's onSuccess already sends a visitor.
      • The verification screen (pendingEmail) is set only by onVerificationRequired, which runs for a sign-up that left no session, so the redirect does not cut it off.
      • decideSignUpOffer, DefaultLoginPage and the objectui#11705 pins have a 0-byte diff.
    • Clause-②: no, confirmed:

      • No export, prop, type member or i18n key is added.
      • <Navigate> was chosen over return null by measurement: return null widened the emitted DefaultRegisterPage declaration to JSX.Element | null. The rebuilt dist/console/auth/RegisterPage.d.ts keeps JSX.Element.
      • The README's useSignUpOffer example is user code in the docs, not a package export. Its SignUpOffer | 'signed-in' return type adds nothing to the entry.
    • Changeset (@object-ui/app-shell: patch), checked sentence by sentence against the diff:

      • the signed-in redirect and its target;
      • the wait for the session check before anything is offered or probed;
      • decideSignUpOffer and DefaultLoginPage unchanged;
      • ?redirect= out of scope;
      • the README row and example.

      patch fits a behaviour fix with no surface change.

    • Tests and gates (dev, measured at 2558521):

      • console/auth/__tests__/: 6 files, 34 tests, green, including the new registerSignedInVisitor-11714.test.tsx with 4 cases.
      • type-check (both programs) and lint: 0 errors.
      • check:doc-snippets judged 782 of 782 with 0 failed, and its README leg was proven by a typo ablation that went red.
      • check:readme-exports, the changeset gates, check:new-line-citations and check:control-bytes: all exit 0.
      • One ablation leg (the signed-in line removed) went 3 red / 12 green as predicted, and was restored by blob.
      • Declared as NOT MEASURED: the whole app-shell suite, which timed out locally with no verdict; CI's shards own it. The narrowing holds, because every test naming DefaultRegisterPage sits in console/auth/__tests__.
    • Out-of-scope findings (3), Acceptance note, not filed:

      • DefaultLoginPage renders the sign-in form for a signed-in visitor. The card covers the register page only.
      • After a sign-up, the onSuccess push and the redirect's replace race over one history entry; the visitor lands on / either way.
      • <Navigate> renders nothing while it navigates.
    • Raised to the maintainer, not redone by the seat: a stray /build.pid (6 bytes) at this container's filesystem root, left by a dev shell line. The dev's session refused its rm twice. It is in no repository, and the seat does not redo a refused action.

    • CI on 2558521: in progress at this read (26 success, 3 skipped, 13 running, 0 failed).


    Generated by Claude Code

  6. objectstack-fleet commented on Oct 6, 2026

    @objectstack-fleet
    ContributorAuthor

    Landed: PR objectui#11734 → main 2b635e5, verified by content. Fixes closed this card

    domain:ui execution seat 2 · session_01FngvPpdrnhHMdHHq6vwwju (os-justin) · 2026-10-06T17:20Z.

    • The merge.

      • Squash 2b635e5 went through the merge queue. It has one parent, 6be0f7a, and is an ancestor of origin/main.
      • 4 files, +281/−17.
      • The landed tree equals git merge-tree of the parent and the reviewed head 2558521 (tree 2c3022d6… on both).
      • The changed lines are identical (md5 2faeefe9… on both). main had moved past the PR's merge-base a58626c, so only the hunk offsets differ.
    • No contract review was owed: Clause-②: no (ACCEPT 6021098691).

    • Content check against the first parent:

      reading 6be0f7a 2b635e5
      <Navigate to="/" replace /> in console/auth/RegisterPage.tsx 0 1
      __tests__/registerSignedInVisitor-11714.test.tsx present 0 1
      the README sign-up table's signed in row 0 1
    • Closures. Fixes #11714 closed this card as completed at the merge. No other issue closed in the landing window. pm:dispatched comes off in this stroke.

    • Recorded, not filed:

      • DefaultLoginPage renders the sign-in form for a signed-in visitor.
      • The post-sign-up push and the redirect's replace race over one history entry, and the visitor lands on / either way.
      • <Navigate> renders nothing while it navigates.

    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

area:identityLogin and identity — sign-up, sessions, organization membership, SSObugSomething isn't workingdomain:uiobjectui ui stream: fix lands on the published library or apps — objectui execution seatpriority:p3

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions