Skip to content

[Decision] What is an authenticated session with NO active organization? Three subsystems answered it three contradictory ways in one shift (fail-open / fail-closed / permanently-invisible ledger rows) #8247

Description

@hotlong

Filed by the triage seat (scheduled fire, session session_01BJ9jjXsUuc4Mkiyzvv1xUW, 2026-08-12 ~22:47Z round). This decision has no single natural anchor — it sits upstream of three measured cards in three subsystems — so it gets a standalone card per the escalation protocol.

Background

One and the same state — an authenticated session whose activeOrganizationId is null — produced three different, mutually contradictory behaviors, all measured live on 2026-08-12:

Card Subsystem Behavior under the state Consequence
#8158 plugin-sharing adminOrgScope fell OPEN org-scoped manage_sharing read/wrote ALL tenants' sharing rules (fixed to reject, PR #8237)
#8208 Layer 0 tenant wall + write stamping falls CLOSED, silently HTTP-created record stamped organization_id: NULL, immediately invisible to its own creator
#8245 audit ledger writes rows no reader can ever see every audit row from a user's FIRST session carries a NULL tenant, permanently invisible to RLS readers

None of the three implementations is individually wrong; the platform has never declared what the state means, so each layer improvised. The state is structurally guaranteed to occur: better-auth defers the ADR-0093 membership reconciler past the signup transaction, so every new user's first session predates their membership (ADR-0081 D1 defaultActiveOrg finds no sys_member row). It can also arise later (member removed from their org, etc.), so it cannot be defined away by fixing signup alone.

Premises (re-check before ruling)

The question

Is "authenticated, but no active organization" a legal session state with defined semantics, or an illegal intermediate to be eliminated at the mint point?

Options

Recommendation: C

Security/permission-boundary semantics ⇒ human floor; not auto-adjudicable.

Downstream

Disposition of findings #8208 and #8245 is gated on this ruling; #8158's fix stands either way. Related: #8241 (RLS policy-composition trap, same family but a different mechanism — not gated on this).

Activity

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

Metadata

Metadata

Assignees

Labels

No labels
No labels

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions