web: join/recover/portal/admin views + team claims + authorize bounce (I6) #15

Merged
PerishFire merged 26 commits from i6-web into main 2026-07-18 08:37:46 +00:00
Owner
No description provided.
Four views on the component vocabulary (six new atoms: Bar, Page,
Board, Line, Code, Tag + the sheet token). Anonymous /authorize now
bounces to /login carrying its return; id_token/userinfo/the /auth
probe carry team claims for downstream AuthZ. Vite proxies the api
by method where SPA routes and ceremonies share a path. Acts assert
the bounce and the claims.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
A login clash used to spend the invite and strand the joiner. The
ceremony now refuses 409 pre-burn; the act proves the code survives
a clash and still admits the next login.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Join honors the auto-login outcome; sign-out only claims success when
the session actually ended; admin renders refusals as refusals, not
empty lists; the recovery notice rides sessionStorage instead of a
forgeable query param; DESIGN.md's token table catches up with the
registered vocabulary (warn/flush, sheet).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Join births first and burns the invite after, compensating a lost
race; team claims fail closed as 500 instead of signing empty; every
ceremony's failure copy now matches its status (clash vs grant vs
fault) on both wire and views. DESIGN.md codifies structural values.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
whoami tells anonymous from unreachable and both views render an
honest Down card instead of a false login bounce; Actor patches map
their status like every other ceremony; portal page faults and
mint faults stop sharing one warning slot.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Every wire helper catches thrown fetches and maps them to its honest
fallback, so a dead network renders Down instead of a blank page. A
401 reads as a session that ended, never as a missing grant. The
recovery nag persists until codes are truly minted. A failed Pass
write unwinds the whole join — actor ended, grants ended, invite
re-armed from the code's own hash.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The refloor nag binds to the recovered login and clears on sign-out;
overlapping admin loads carry a ticket so stale reads never overwrite
fresh lists; mint failure stops prescribing an impossible remedy.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
A failed re-invite no longer hides the still-valid prior code; mint
tells an ended session from a fault; join's compensation failures
land in the journal instead of vanishing.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Recovery used to strand you sessioned but passwordless. A signed-in
operator can now set a new password — own-subtree authority, argon2
in spawn_blocking, old rows ended first; the act walks recover →
repass → old password dead, new one lives. Spending an invite maps
storage faults to 500, not a lying 404.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
A barred account could still mint sessions and loop silently between
portal and login. Login and revive now refuse barred at the door with
honest copy; the act proves the 403.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The password floor counts characters, not bytes. The authorize return
survives detours through join and recover (and back() now refuses
protocol-relative escapes). The recovery nag clears only after both
halves — new password and fresh codes — are truly done.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Barred is disclosed only to valid credentials, service faults stop
wearing the barred verdict, the return check refuses backslash
authority tricks, and recovery always lands on the portal so the
re-floor cannot be skipped by a pending authorize return.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The return path is validated by resolving it against our own origin
and rejecting any result that lands elsewhere — newline/tab/backslash
authority tricks all fail closed. Sign-out is withheld during an
incomplete re-floor so a code-burned account cannot strand itself.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The re-floor could never be truly enforced from tab-local storage, so
five rounds circled it. Fold the new password into /revive itself:
verify the code, burn every code and session, set the new password,
mint the session — atomically. No passwordless window, no client-side
lock theater, no bypass. The return check also refuses paths whose
normalized form escapes the origin (//host after dot-segments).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Recovery reordered: set the new password first (compensating to the
old shield on a put fault), and only then burn the used code and
re-floor. A storage fault now leaves the account with its old
password and every code intact — a 500, never a lockout.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
/revive folds rotate-password + burn-codes + end-sessions into one
sudo batch; changing a password takes the current one; the swap runs
in the actor's own batch. Dead helpers retire.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The post-commit session mint could fail after the recovery batch had
already changed the password and burned the codes. Drop it: /revive
returns 204, and the Recover form signs in with the new password it
just set — a separate, idempotent step outside the destructive
transaction. repass splits 403 (wrong current password) from 401
(session ended) so the portal stops conflating them.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The Actors board no longer offers Bar on your own row (self-bar is a
sudo-recoverable lockout, but never an accident from the UI). The
rescue-codes copy stops implying three independent sign-ins: any one
code recovers once, and recovering sets a new password and burns the
whole set.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Recovery's atomic batch now also burns Renew rows, so a recovered
account's OIDC refresh tokens die with its sessions — an act proves a
refresh grant cannot outlive recovery. One-time secrets (rescue codes,
invite codes) clear on pagehide and sign-out replaces history, so
Back/BFCache can never redisplay them after the session ends.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
guard() returns Result<Option> so login and repass can tell a backend
outage (500) from a missing or mismatched credential (401/403) —
shield collapsed both to None, so a query failure read as a wrong
current password.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
web: single-word shield, honest outage copy (review r23)
All checks were successful
guard / guard (pull_request) Successful in 3m34s
15b3ac2f3a
reshield_batch → shield obeys the single-word law. The fallback view
no longer claims ensign 'did not answer' — an answered 5xx still lands
here, so it says identity could not be confirmed right now.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
PerishFire deleted branch i6-web 2026-07-18 08:37:47 +00:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
PerishLab/ensign!15
No description provided.