Task: Enter and leave a tenant in the web

Table of Contents

This page documents a task in the Act inside a tenant story. It captures the goal, current status, acceptance, and any notes or results.

1. Goal

(Describe what user-visible-or-internal change this task produces.)

2. Status

Field Value
State DONE
Parent story Act inside a tenant
Now Nothing.
Waiting on Nothing.
Next Nothing.
Last touched 2026-10-03

3. Acceptance

  • The BFF swaps the browser session to the tenant-scoped one on entry and back on leave, and refuses a session outside system administration.
  • Every screen shows that the person is acting in the tenant, and the way out.
  • Screen and route tests prove entry, the banner and leaving, and the flow was read live.

4. Plan

(Implementation strategy. Written when work starts; key decisions are distilled into the parent story's * Decisions at close, but the plan itself stays — it is the historical record of what we did.)

5. Measurements

Every number this task claims about a tree, with the command that produced it and the commit it was measured at. A number without both is not a measurement, because a clean-up record describes a tree and trunk moves under a branch: a consumer count, a gate's component count and a suite's size all change with no code changing, and the reader of a bare number cannot tell which tree it came from. Where the raw output matters, put it in an evidence/ file beside the task and name that file in the Command column.

What Value Command Commit
       

6. Notes

7. Test Scenarios

Manual QA scenarios (scaffolded via compass add test_scenario) that verify this task. Link new ones here as they're created; the scenario doc itself links back via its "Verifies task" field.

Scenario State Notes
     

8. PRs

PR Title
#2534 [web] Enter and leave a tenant, and say so on every screen

9. Review

# Comment summary File Decision Notes
L1 Test files are left out of the web typecheck, so a fixture missing a new field went unnoticed AppRoutes.test.tsx Accept The fixture gains actingIn; the typecheck scope is a separate matter, left as it is.
L2 The roster row's menu was to offer the entry too TenantsPage.tsx Decline Open already leads to the tenant's screen, which offers it; the journey says so.
R1.1 Two entries at once can store the first's tenant token as the way out client.ts Accept The client holds the entry under way and refuses a second; a test covers it, and the BFF route inherits it.
R1.2 A failed exit record leaves the browser showing the tenant server.ts Accept The route logs the failed record and answers the session as it now reads, outside; a test covers it.
R1.3 Reads in flight can refill the cache after a rescope SessionProvider.tsx Accept Rescoping cancels the other queries before removing them.
R1.4 The synthetic party's fixed fields need a word sessions.ts Accept A comment says so.
R1.5 The guard's key falls back to the raw URL server.ts Decline An unmatched route fails closed, which is the safe direction.
R1.6 Leave after the outside token expired is not tested client.ts Decline The restored token takes the ordinary refresh path, which its own tests cover.

10. Result

OresClient enters and leaves a tenant, holding the entered tenant and the token it entered from in one field; a lapsed tenant session returns to that token without asking the server and throws TenantSessionEndedError. The BFF serves POST and DELETE on /api/session/tenant, reads the session's tenant, party and mode from the client, answers a lapse with 409 tenant-session-ended, and refuses every change while inside before the route runs, except leaving, signing out and watching for changes. The tenant's screen offers Act in this tenant; every screen inside carries a banner naming the tenant and the administrator, saying it is read only, with Leave the tenant, which returns to the tenant's screen. The home screen offers no change to a read-only session.

Tests: four client cases (enter, refused entry, leave, lapse), six BFF route cases with a stub proof of the guard, and banner, button and home screen cases in the web suite. Live, the run in Issue a session inside a tenant covers these routes, 15 of 15.

Emacs 29.3 (Org mode 9.6.15)