2026-09-23·by Sijie Wang#node#standmeet#architecture

access-control

Pillar 6 · Access control (the valves)

Parent: key-designs

Who may see and do what — the most heavily tested pillar (the acl-* e2e matrices). Entry is by access code (= invitation, QR); a code issues against a role whose RoleSnapshot freezes at issue (in-session rules never drift). Authorization composes as pure AND narrowing across three layersglobal (live) ∧ role (frozen) ∧ ¬code-deny (frozen) — a code can only subtract, never re-allow (sparse deny tables, no tri-state). Identity rides the neutral _meta sidechannel; owner identity is an Ed25519 keypair (private key never enters domain); BYOAI modes let a visitor bring their own model under an envelope.

Status: landed (global layer live; role/code deny tables per the finalized 2026-06-23 design).

Data model (ER)

Read it with the three layers in mind: capability_settings is the live global layer; everything reachable from roles freezes into the RoleSnapshot at issue; the code_*_denials tables (capability / skill / corpus — the corpus one landed 2026-07-16, 6395374b0, backend/db/schema.sql code_corpus_denials) are the frozen, subtract-only third layer.

The timing story — when each control acts

Children

  • access-control-diagram-coverage — diagram-coverage ledger.
  • acl-and-quota-granularity — the three-layer pure-AND model; sparse deny tables.
  • role-snapshot-frozen — freeze-at-issue vs the live global layer.
  • trusted-identity-via-meta — identity via the neutral _meta sidechannel.
  • byoai-envelope · byoai-browser-vault — visitor-supplied models, contained.
  • owner-keypair-auth — Ed25519 Sigv1 on /mcp/*: private PEM returned once, ±5min window + one-time nonce; ⚠ signature binds caller, not the request.
  • embed-credential-never-carries-the-code — the embed analog of the above: a per-embed Ed25519 EdDSA JWT authenticates a widget session so the code stays server-side; folds in bound origin + exp + one-time jti. Shipped 2026-09-01 (2098975db, backend/internal/access/usecase/embed_token.go); the Turnstile cnf binding is the one layer still deferred.
  • owner-sessions-and-abuse-controls — the small valves: Redis owner sessions that sign-out really revokes + the active-sessions panel, keypair last-used device/ip, per-IP code-fail lockout (codefail:ip:, 10 in 15 min) and banned_ips, gas metering for the no-code tier, the 30/hour per-recipient mail throttle, APP_BIND_HOST + Referrer-Policy. Shipped 2026-08-31 → 2026-09-06.
  • coded-landing-and-code-rotation — a code's three parts: row id (what links key on), snowflake slug → /c/<slug> (a locator, never a credential; ?code= is absorbed out of the URL on first paint), and the 64-bit code string — the only part codes.rotate replaces, killing every printed copy and live session while embeds/applications survive. Shipped 2026-09-06 → 07 (c6c54ce88, 505b3fc4f, backend/internal/access/usecase/codes.go).
access-control