Expand description
Where a component renders — the Mode A / Mode B decision, and what it costs to be wrong.
docs/05-tier-lowering.md §5.1 gives two rendering
modes over one source:
| Mode A — thin | Mode B — local | |
|---|---|---|
view runs on | server | client |
| Wire carries | DOM patches | data patches (state diffs) |
| Optimistic UI | no | yes — the same fold runs locally, reconciled by seq |
The row that decides everything is the second one. Mode A sends the browser a rendering of the state; Mode B sends it the state. Everything below follows from taking that literally.
§The rule: a Mode B page may not be a function of who is asking
A view has the shape (state, session) -> Html. If it reads who the session is, it renders a
different page for different actors from the same state — which is to say it is filtering,
scoping or hiding by identity. Running that view on the client requires giving the client the
state it filters, so every actor receives what the filter was removing. The page would still
look right. That is the worst kind of wrong.
So a component whose view reads the session’s identity is refused Mode B, and the refusal names
the reason rather than a rule. What is left is exactly the class §5.1 and
docs/10-decisions.md D5 describe as Mode B’s: pages
that are the same function of the same state for everybody — editors, typeaheads, drag-and-drop,
anything single-user or public.
§Which half of the session, and why the distinction is structural
Session carries three fields and they are not one kind of thing. actor and claims say
who is asking and are what an identity provider verified; path says where they are and
is the client’s own statement about itself. The argument above is entirely about the first pair:
a page that renders by route is not hiding anything from the browser it is running in, because
that browser chose the route and already holds the state.
So the refusal is decided by SessionUse, which reads the view’s own code and asks which
fields of a Session it can observe. The coarser fact — whether the page is per_session at
all — is still what §3.8’s fanout analysis and §5.3’s shared cut use, and it is still true of a
page that reads only the route: two people on two routes see two pages, so the operators below
the session are theirs. Eligibility and fanout are different questions, and this is where they
stopped being the same answer.
§Optimism is a property of what crosses, not of a component
“The browser applies the expected event to its local copy speculatively — legitimate because it runs the same pure fold the server runs” (D5). That is only available to a client that holds the value the fold is of. A client holding a projection — a session’s filtered list, say — could not apply an event to it without a second, different fold that no program writes. So optimism is not an extra feature layered on Mode B; it is the same fact stated twice, and this module reports it as one decision with two consequences.
§And the rule that points the other way
§3.7 asks for one more thing of a guess: that the page can say it is one. “Signal[T] carries
a freshness dimension (confirmed | pending(n)) that UI code can render ("saving…") —
staleness is typed, not pretended away.” freshness() is that dimension, and it is the only
thing here a server cannot answer: what a server renders is what it has recorded, so its
answer is Confirmed at every position of every log. So a page reading it is refused Mode A
(B0518) exactly as a page reading presence is refused Mode B — the two rules are the same
rule about two facts that live on opposite sides of the wire.
Structs§
- Decision
- How one component renders, and what follows from it.
Enums§
- Mode
- Where a component’s
viewruns. - NoOptimism
- Why a Mode B client may not guess.
- Session
Use - What a view can observe about the
Sessionit is handed. - Why
- Why a component renders where it does.
Constants§
- ROUTE_
FIELD - The field of a
Sessionthat says where rather than who.