# Changelog — concepts/

Product-surface concepts: app, console, activation & onboarding, Context Map /
Explore, mobile, auth, errors, easter eggs. Newest first; entries are curated
(one line per meaningful change), full detail in `git log -- concepts/`.
Pre-2026-07-19 work lived under `web/` and the repo root — `git log --follow`
traces any file across the move.

## 2026-08-10 — Files becomes its own rail section: `app-v35/files.html`
- New `app-v35/files.html` — the v3 GitHub shell folded into the app per the
  day's direction calls (relay-board PRD.cloud-files §6.0): **Files is its own
  rail section, not a tab inside Catalog.** It sits directly after Overview
  (recommended placement — the rail call itself is still open) and owns the
  content area, drawing its own tree beside the persistent rail: library
  selector and lens switch in-surface, "Go to file" + `T`, a shelf tree that
  replaces the chips (chips die past ~6 shelves; the tree proves depth 3 —
  Auth & identity › On mobile › Warm), Last change / History / envelope diffs,
  and Edit naming the next version before you type. The cross-type Objects
  table moved in from Catalog as "All objects" — same table, every row and
  count per-viewer now, including the ⌘K palette's object results.
- Runs on the catalog-shelves seeded corpus (mulberry32(42)) plus a second
  seeded supersession layer (mulberry32(7)) for version chains, so the two
  prototypes describe the same workspace. Chain rules AND correctly on nested
  shelves (the tab prototype's `Object.assign` merge silently dropped a
  parent's tag when the child also tested one — fixed in the new surface).
- `app-v35/catalog-shelves.html` banner-superseded and kept as the record of
  the composed-into-Catalog answer; its rail group that listed the four
  lenses under the label "Shelves" now reads **Lenses** (the vocabulary bug
  flagged in the 2026-08-10 handoff — the group itself moves inside Files in
  the settled direction).
- `files-v3.html` got its index card — it had shipped card-less on the
  branch, the exact miss the maintenance rules exist for. Clean URLs
  retargeted: `/concepts/files` → `files-v3`, `/concepts/shelves` →
  `app-v35/files`.
- Verified in Chromium at 1320 and 500 over HTTP (tokens resolving): no page
  errors, zero horizontal overflow at both widths, view-as switching changes
  shelf contents per viewer, the depth-3 chain renders its full AND predicate,
  and the narrow topbar no longer clips the View-as control (caught by an
  element-edge probe; the scroll-width probe alone is blinded by
  `overflow-x:hidden`). Sub-500 widths remain unverifiable in this container.

## 2026-08-10 — Files v3: the GitHub shell the brief actually asked for
- New `files-v3.html`. v1 drew Drive folders; v2 drew the set model correctly
  but as a four-pane inspector — it proved the semantics and lost the shell.
  v3 is the shell: **library selector where the branch picker sits**, "Go to
  file" + `T` as the search spine, a shelf tree, and a listing whose second
  column is **Last change** — a supersession note, not a commit. The change
  bar, `..` row, breadcrumb-with-copy and History page carry GitHub's shape
  straight across; History opens the version chain and a click diffs two
  versions with an envelope header above the text.
- What is deliberately **not** copied from GitHub: colour never carries type
  (no blue folders — v3.5 keeps type on glyphs, which also keeps the tree
  legible without colour vision), and there are no lock or shield glyphs. A
  shelf shows what your grants already reach; it never widens them.
- The set model survives the reshell intact: rule predicate under the
  breadcrumb, `added` chips on hand-pinned rows, struck-through excluded rows
  visible only to a curator, and every count post-filter — *"3 items you can
  see"*, never a total. Switch **View as** (Erik → Dana → Sam) and the same
  shelf changes contents while its definition stays shared.
- Editing a claimed object names the version before you type: *"claimed by 2
  people — editing creates v7"*. The brief's most important single moment,
  which v2 had dropped.
- Deep-linkable, same convention as the billing/gateway concepts:
  `?as=sam` · `?lib=me` · `?shelf=decisions` · `?obj=o1&view=history` · `?q=acme`.
  Verified in Chromium at 1320 and 500 — no page errors, and a scroll-width
  probe finds zero horizontal overflow at 500. Sub-500 widths were NOT
  verifiable here (this headless build clamps the viewport to 500 minimum);
  the mobile rules below that are written but unproven — check on a device.
- v1 and v2 are kept as the version record; neither is deleted.

## 2026-08-08 — Billing surfaces: app module + console gateway panel
- `app-v35/billing.html` — the member-facing half of the billing lifecycle on
  the shipped rail (Billing under Account): plan and seats, usage against the
  plan contract, invoices and receipts, payment method. Built on the three
  states the platform actually resolves — `active`, `past_due` (retrying, full
  access retained), `unpaid` (dunning exhausted, effective tier drops to the
  Free contract). Switching state moves the usage ceilings to Free with
  over-limit treatment and flips the open row to *Pay invoice*; nothing is
  deleted and billing stays reachable throughout. Reactivation copy holds the
  locked decision: webhook-confirmed, never client-claimed. Figures match the
  shipped tier contract and the billing-lifecycle email set, so app and email
  tell one story. Deep-linkable `?state=retrying` / `?state=paused`.
  Mirrors relay-platform RCTX-996/997/998; documents anticipate RCTX-993.
- `console-v35/finance-lifecycle.html` — new **Gateway** screen (RCTX-1055):
  connection health + console-managed config, framed adapter-shaped rather
  than Stripe-shaped so a Launchpad product on another processor inherits it
  (RCTX-1056). Three scenarios, all real failure modes: healthy, webhooks
  stale (the only check that catches an outage rather than a misconfiguration
  — it reads `processor_events`, no API call), and test key in prod. Secrets
  reported presence-only, never shown or settable, with the env-file boundary
  stated on the panel. Deep-linkable `?gw=stale` / `?gw=testkey`.

## 2026-08-08 — Hats & Lenses: the multi-hat framing made touchable
- New `hats-and-lenses-v1.html`. EC's framing observation — users wear
  multiple hats, work through different lenses, across various platforms
  and accounts — built as an interactive demonstration rather than prose.
- The mechanic is the argument: **node positions never move.** A working
  week's context (20 objects across employer / two clients / personal)
  is laid out once; switching a **hat** seals or unseals, switching a
  **lens** emphasises or recedes. If a hat switch moved things it would
  be a filter, not a boundary.
- The money shot is the *All hats* view: four clusters, **zero edges
  between them**. Cross-hat edge count is computed from the data and
  shown in the readout, so the claim is asserted rather than drawn.
- "Reveal what's sealed" separates what the owner can see from what an
  agent in that hat can — an honest distinction the framing needs.
- Also states the precision ("ties it all together" means across tools
  and across time, never across identities), the argument against
  single-identity platform memory, and the single-point-of-trust
  objection answered by the zero-knowledge posture.
- Companion to the framing proposal in
  `relay-board/docs/strategy/framing-substrate-vs-transport.md`.
  Clean URL `/concepts/hats-lenses`.

## 2026-08-08 — Organizing layer: the nouns are decided (Library · Shelf)
- RCTX-1091 closed. A **container is a Library**, the rule-populated set at its
  root is a **Shelf**. Applied across `app-v35/catalog-shelves.html`,
  `console-v35/org-ia.html` and `shelves-mobile-v1.html` — display strings only.
- The RBAC constants deliberately do **not** follow: they stay
  `container.manage` / `slot.author` because each writes a permanent
  `rbac_audit` row, and an audit trail must not change vocabulary partway
  through its own history. The console delegation card now says so on screen,
  so the mismatch reads as a decision rather than a miss.
- Rationale: relay-board `organizing-layer.md` §3.1; correction recorded in
  relay-platform `SPEC.collections.md` §6 (now **ratified**, schema landed).

## 2026-08-08 — Console Investor track: MSA → platform ToS (correction)
- The MSA column and matrix row are gone. Erik: no MSA — the platform-side
  obligation is the **Terms of Service**, which every user already accepts at
  activation (`tos_accepted` → `registration_metadata`, text at
  `relayctx.com/terms`). NDA already applies to everyone, so the screen now
  shows **NDA version + ToS acceptance date**, and the lens matrix reads
  EAPA / NDA / ToS.
- Lens & gate tab gains the reduced-scope note: no new document type is
  needed, and the whole change is *EAPA becomes product-lens only*.
- Two findings recorded on the same tab: the ToS is an **unversioned**
  checkbox (a terms change re-consents nobody; the signed text isn't
  recoverable from the record, unlike `legal_acceptances`) — a real gap that
  belongs to the whole user base, not this screen; and `BPA` is labelled
  "Platform Agreement" in `DOC_LABELS` while being the **retired** Beta
  Participant Agreement that EAPA replaced, which now reads as the live
  platform terms.

## 2026-08-07 — Console: Investor track screen (draft, awaiting approval)
- New screen in `console-v35/console.html` — **Investor track**, in the Access
  group, tier-1 badged. Four tabs: Register (opaque 6-char pack IDs, lens
  badges, NDA/MSA status by version), Compliance (access-without-a-current-
  signature as a flagged live state, since a gate-mode version bump re-gates
  prior signers), Audit (grant/revoke with actor + timestamp), and **Lens &
  gate**.
- The Lens & gate tab is the point of the screen: it carries the argument that
  EAPA cannot be made optional in the signing-gate component, because that
  component only renders what `GET /api/legal/pending` returns. Skipping it
  client-side leaves `gate_needed()` returning true at seven server call sites
  (login, user API, MCP writes) — the user is blocked with nothing to sign.
  Proposes **applicability** as a third axis beside version and enforcement
  mode.
- Revoke deliberately names what it does *not* reach: clearing the lens leaves
  the Cloudflare Access policy on that pack untouched, a manual step until the
  two systems are unified.
- Shell gains hash deep-linking (`console.html#screen-id`) so the index cards
  can land directly on a screen.
- **Draft — nothing is built.** Spec and rationale live in relay-platform
  (`docs/SPEC.investor-track.md`, `docs/DESIGN-NOTE.legal-gate-audience.md`);
  both carry open questions, including one counsel question that blocks the
  NDA-tier unlock specifically.

## 2026-08-07 — Console board dashboard: tranche gates instrumented, roadmap dual-render
- New: `console-v35/board-dashboard.html` — a board-level console surface, gated
  tier-1/finance. Four screens in the v3.5-a console shell (same `tokens.css`,
  same shell vocabulary as `finance-lifecycle.html`): **Gate progress**,
  **Roadmap**, **Investor track**, **Sources & freshness**. Clean URL
  `/concepts/board`.
- The core move: **instrument the tranche gates, don't build a metrics
  dashboard.** Revenue and committed capital are both $0, so a metrics wall
  reads as failure and tells nobody anything. The gates (T1 Protect $120K →
  T2 Sustain $200K → T3 Team $680K, cumulative $1M = the round floor →
  T4 Scale $641K, cumulative $1,641,000 = target) are already the company's
  high-level goals, so those are what the screen renders.
- **Five source states, deliberately not four.** live · manual · stale ·
  not instrumented · **not computable**. The last two exist because the
  concept refuses to collapse two pairs: measured-zero vs. never-wired
  (`repeat unprompted use` has no source at all), and zero vs. undefined
  (NRR with no paid cohort is a division by zero, not 0%). Every figure
  carries a provenance chip — source + as-of — and a stale manual input says
  so instead of showing an old value as current.
- **Roadmap is one source with two renders**, live-toggleable in the page:
  board view keeps hard dates (fiduciary readers want slippage); the investor
  render drops every date *at render time* and removes rows touching
  protection still in progress — then reports its own withheld-row count, so a
  filtered pack is never mistaken for the whole plan. Not two roadmaps.
- **Onboarding track** screen — deliberately *not* a second investor register.
  The register, compliance view, grant/revoke audit and the legal-gate argument
  are owned by `console-v35/console.html#investor-track` and
  `relay-platform/docs/SPEC.investor-track.md`; this screen adds only the column
  that surface doesn't carry — **onboarding enrollment** — and what it costs the
  gate signals. Reconciled on merge after the investor-track screen landed
  first; shipping two registers is the exact drift the rest of this concept
  argues against. It shows the two ways enrollment fails: an investor wrongly enrolled in the six-step
  *First Relay* sequence, and a principal holding access on a superseded
  agreement version. A dual-role row (investor **and** working user) is
  included on purpose: tracks are not exclusive, and suppressing that user's
  onboarding would break a real experience to satisfy a tidy model.
- Money figures render the **real current state** ($0 committed, NRR not
  computable); platform-derived signals are sample. The preview bar says which
  is which. Nothing is wired.
- Companion docs: relay-platform `docs/SPEC.board-dashboard.md` +
  `docs/DESIGN-NOTE.onboarding-tracks.md`; product shape and the edge-case
  register in `relay-board/docs/product/board-dashboard.md`. **Concept and
  docs only — the build is gated on approval and on settling the canonical
  source, which does not yet exist on a main line.**

## 2026-07-30 — Catalog prototype: Objects tab, cross-type table (relay-app#458, scope-extended)
- New: `app-v35/catalog.html` — Catalog (relay-app#458, epic #449 /
  `docs/DESIGN-NOTE.list-views-refresh.md`). Built against EC's 2026-07-18 issue
  comment, which **extended** #458's scope beyond the original Labels/taxonomy
  convergence: Catalog becomes the rich object browser over the whole relay
  object base. Confirmed via `mcp__github__issue_read` before building — the
  comment text is reproduced verbatim in an HTML comment near the top of the
  file. **The original Labels/taxonomy convergence (server-side `labels` table,
  `/api/user/v1/labels`) already SHIPPED separately on 2026-07-18 and is NOT
  touched here** — the real `catalog.ts`/`tags.ts` were read to confirm Labels
  is already server-persisted, live, and consumed by the Transfers filter bar.
- Tab bar: Tags and Labels are lightweight static stubs (per scope — this issue
  isn't about them) reproducing catalog.ts's real `.catalog-tab` visual pattern
  (one deliberate correction: active-tab color/border moved from the real
  code's literal `--teal` to the spec-correct `--accent-text` role token, per
  the design note's "re-check against v3.5" requirement). **Objects** is the
  new third sibling tab and the prototype's default/active tab.
- Objects tab — the actual deliverable: a real table (not cards) over ~90
  seeded rows spanning Relay/Series/Session/Stream (36/14/20/20), each typed to
  its real field shape from `shared/src/types/{relay,transfer,stream}.ts` (wire
  status vocab per type — relay: pending/claimed/expired/deleted; series &
  session: open/closed; stream: fresh/recent/stale/very-stale/unknown). Type
  facet with live counts (shape-alphabet icons matching the Graph canvas
  vocabulary: relay=rect · series=rounded-rect · session=diamond ·
  stream=circle), a text+tag filter, a count line ("x–y of N (filtered from
  M)"), and click-to-sort column headers (Name/Title, Type, Status, Updated)
  per EC's comment. Pager is Transfers' `.pager`/`.pgbtn`/`.range` component
  and JS reused near-verbatim (range · numbered pages · page size 25/50/100).
- **Column strategy (design call, documented in-file):** rather than a sparse
  table with many always-empty cells, shared columns (Name/Title, Type, Status,
  Tags, Updated) carry the table; type-specific fields (direction/weight/claims
  for Relay, relay+session counts for Series, agent+handoff for Session,
  item/unread/pinned for Stream) live in a row-click peek drawer instead of as
  dedicated columns. Tags column is genuinely empty ("—") for Series/Session
  since neither carries a `tags` field on the real type — not a placeholder
  bug, an accurate reflection of the schema.
- **Row-click / #488 honesty finding:** the brief's honesty constraint required
  either a real link or a clearly-labeled "#488 coming soon" stub per row.
  Checked production code (`relay-detail.ts`, `series.ts`'s `openSeriesDetail`,
  `sessions.ts`'s `openSessionDetail`, and `stream.ts`) plus this repo's own
  sibling prototypes — **all four in-scope object types already have a real,
  live per-type destination today** (relay-app#488's unified cross-type
  object-detail page is what doesn't exist; the per-type flows do). So every
  row's peek drawer links out for real (`target="_blank"`) to the matching
  sibling prototype — Relay→`transfers.html`, Series→`series.html`,
  Session→`sessions.html`, Stream→`stream.html` — **zero rows are #488 stubs**.
  Documented limitation stated in the drawer's own fine print and here: each
  sibling prototype seeds its own independent mock dataset, so the link lands
  on that object type's list/shell generally, not deep-linked to the specific
  row — a static multi-file demo constraint, not a fabricated destination.
- Reusability for the epic's knock-ons (not built this round, per EC's
  comment): the filter/sort logic never hardcodes a "not deleted" assumption,
  so a future Trash variant (#607, deleted-only) or `/search` convergence
  (#456) can reuse the same table without a rewrite — flagged in an HTML
  comment, not over-built.
- Verified functionally (no headless Chromium available in this sandbox — the
  playwright browser download was blocked by the proxy) via a jsdom harness
  exercising the actual page script: type/tag/text filtering, click-to-sort
  (asc/desc, all 4 columns), pager (page size, next, numbered pages), all four
  drawer branches, tab switching, empty-state, and the ⌘K palette all run
  clean. Caught and fixed one real bug pre-publish: sort-header click handlers
  were being wired before the `<table>` existed in the DOM (now rewired inside
  `renderObjects()`, alongside row-click, on every re-render — matches
  Transfers' own `wireList()`-after-innerHTML pattern).
- Card index: `app-v35/index.html` gets a Catalog card in the "App shell — as
  shipped" section, and the stale "Send / Catalog follow" note is updated now
  that both have landed.

## 2026-07-30 — Settings prototype: sectioned restructure, change-password removed
- New: `app-v35/settings.html` — Settings (relay-app#459, epic #449 /
  `docs/DESIGN-NOTE.list-views-refresh.md` Batch 2 "Settings — restructure").
  Copies the Stream/Transfers rail/topbar/⌘K shell, retargeted to Settings.
- **EC-confirmed scope (2026-07-18 issue comment on #459), not a fresh
  interpretation:** re-read the comment thread directly before building.
  Three confirmed items, all reflected honestly against the *current* code
  (re-checked, not assumed from the brief's original audit):
  - **Change-password UI removed** — the card that used to POST
    `/api/user/v1/password` is **omitted entirely**, no placeholder. Turns
    out it's already gone from the real `settings.ts`/`index.html` too (the
    comment's `settings.ts:212-231` citation no longer matches current
    content) — this prototype doesn't reintroduce it. The separate
    forgot-password reset markup in the auth *login* flow
    (`web/index.html`, unauthenticated recovery) still exists there and was
    flagged by the same comment as a sweep candidate — noted in an HTML
    comment for the next implementation pass, not this Settings-page prototype's
    job to fix.
  - **Timezone default** — the picker pre-selects the browser-detected zone
    (`Intl.DateTimeFormat().resolvedOptions().timeZone`), not
    first-alphabetical `Africa/Abidjan`. Also already fixed in the real
    `datetime.ts` (`displayTimeZone()` / `populateTimezoneSelect()`) — the
    prototype mirrors that real implementation verbatim (comment + code)
    instead of re-deriving a "fix" that's already shipped.
  - **Agreements "lists EAPA twice"** — re-read `loadLegalStatus` before
    reproducing this: each row already carries its own version + date, so
    the two seeded rows here are genuinely distinct acceptances (a BPA→EAPA
    program rename), not a fabricated duplicate-same-date bug.
- **Sectioned restructure:** sticky left anchor rail (Account / Notifications
  / Integrations / Program / Danger) with scroll-spy, chosen over top tabs —
  card density varies too much per section (Notifications is long, Danger is
  one row) to hide any of it behind an unselected tab panel. Collapses to a
  sticky horizontal tab strip under 900px.
- **Export relocated** out of Danger Zone into its own non-destructive
  "Data" card under Account, next to Privacy & Defaults — Danger Zone is
  delete-only, per the brief.
- **Slack** placed under its own Integrations section (connection status
  only); the Slack notification-channel toggle stays in the Notifications
  card, since that's delivery preference, not connection state — one
  placement decision, kept consistent rather than duplicating the card.
- **Skeletons + failure states**, per the brief's explicit ask: a demo strip
  (Loaded / Loading / Failed, also `?state=loading` / `?state=error`) drives
  every async card — Plan, Loop, Slack, Notifications, Communications,
  Agreements, Autojoin — through a real skeleton-shimmer state and a real
  error-with-retry state, not just prose describing one.
- Card index: `app-v35/index.html` gets a Settings card in the same "App
  shell — as shipped" section as the other list-shell/tools screens.

## 2026-07-30 — Send prototype: live recipient-side preview
- New: `app-v35/send.html` — Send (relay-app#457, epic #449 /
  `docs/DESIGN-NOTE.list-views-refresh.md`). Copies the Transfers/Stream
  rail/topbar/⌘K shell, retargeted to Send.
- **Confirmed, scoped-down gap:** per the brief, Send's progressive
  disclosure — essentials (title/content/recipient/visibility/max receives)
  collapsing the rest (tags/expiry/bring-back/series) behind a "More
  options" disclosure with a live count badge — is **already shipped**
  (`send-claim.ts`'s `send-more-options` + `updateSendMoreOptionsCount()`,
  ~line 139) and is reproduced field-for-field here, **not** redesigned. The
  real gap was the empty right half of the viewport once that disclosure
  collapsed the form. Only new work: a **live recipient-side preview** in
  that column — a claim-landing card wired to real `oninput`/`change`
  listeners on title/content/tags/visibility/max-receives/expiry so it
  visibly updates as you type, modeled on `send-claim.ts`'s
  `doClaimPreview()` (title, "From: X · date", provenance badges) and
  extended with a content preview, tag chips, and a receives-left/expiry
  footer per the brief's explicit list. Bring-back and Series are
  sender-only settings the recipient never sees, so they intentionally do
  not feed the preview.
- Mobile posture noted inline (HTML comment): preview column drops below
  the form, never side-by-side.
- Card index: `app-v35/index.html` gets a Send card in the same "App shell
  — as shipped" section as Transfers/Series/Sessions/Stream, plain `.tag`
  badge per the Stream card's convention.

## 2026-07-30 — Stream list-shell prototype: pagination + shell alignment
- New: `app-v35/stream.html` — Stream (relay-app#454, epic #449 /
  `docs/DESIGN-NOTE.list-views-refresh.md`), the fourth and final list-shell
  screen after Transfers (#451), Series (#452), Sessions (#453). Copies
  Transfers' rail/topbar/⌘K shell and pager component near-verbatim (range ·
  ‹ numbered pages › · page size 25/50/100), seeded with 70 focus areas
  (mulberry32(42)) so pagination is honestly necessary at 25/page.
- **Confirmed, scoped-down gap:** per the brief's own inventory, Stream's
  search bar, sort dropdown (Last activity / Stalest first / Most items /
  Recently read / Title A→Z / Created), and combinable status/type/tag
  filter-chip row are already shipped and already "the most complete, natural
  donor pattern" — so none of that toolbar was redesigned into Transfers'
  popover-facet style. The real, confirmed gap was pagination alone (Stream
  renders its entire filtered list, no page size, no pager, no honest "x–y of
  N"); that's the only new chrome this prototype adds, positioned after the
  list per the shared list-shell anatomy.
- **Not new work — flagging so it isn't re-done:** the has-content suppression
  guard for the "Meet Stream" intro (#455/#604) is already live in production
  (`feature-intro.ts` `maybeShowFeatureIntro()` `opts.hasContent` branch,
  wired from `stream.ts`'s `loadStreamList()`). This prototype does not model
  the empty-first-run intro at all; it seeds a populated list on purpose.
- Card index: `app-v35/index.html` gets a Stream card in the same "App shell —
  as shipped" section as Transfers/Series/Sessions.

## 2026-08-03 — Responsive shell v1: the shell laws, at full scale
- New: `shell-responsive-v1/` — `index.html` (app), `console.html` (operator twin), shared
  `shell.css`. `shells-v35.html` states the seven shell laws and demos the three temperaments in
  miniature; this is the same system as a **working prototype at real scale**, one document per
  room that folds rather than forks.
- Desktop: 220↔56px rail, brand-mark collapse persisted to `localStorage`, the single 2px accent
  left-stripe, ⌘K principal search. At ≤860px the rail becomes an off-canvas drawer over a scrim —
  same groups, same order, same stripe, **no bottom tabs** (law 5). Drawer and sheet both dismiss
  four ways (trigger, backdrop, Esc, navigate) and return focus.
- Cards are **DEC-025 composed**: the Code is the head and the one teal moment when shared; the
  head *closes up* on unshared objects with the title held at unchanged rank (L3) and the share
  action carrying the accent instead (L2). "Never shared · 41" appears as a filter chip, not a
  badge on every row (L4).
- Chrome budget is two rows — topbar + control row — with status, direction, personal state, the
  sharing axis and 115 tags all behind a transform-only filter sheet (`translateY`, never `height`,
  per `SPEC.app-components.md`).
- Console shares the CSS unchanged; indigo marks the operator layer (status strip + active stripe)
  and never the content, and the dense approvals table becomes cards below 860px rather than a tiny
  table. Reference implementation for `briefs/BRIEF.ui-component-kit.md`.
- Clean URLs: `/concepts/shell` and `/concepts/shell-console`.

## 2026-08-03 — Cloud Files: Drive-shaped folders, search as the spine
- New: `shelves-mobile-v1.html` (`/concepts/shelves-mobile`) — the organizing layer at 390px,
  390-first: lens/container segments, shelf list with predicates, origin markers, bottom sheets
  for filters / view-as / the object sheet (attribution basis + why-on-this-shelf + deciding
  properties). New: `console-v35/org-ia.html` — the org-admin governance screen: containers with
  deny-only overrides, rules with validity state, delegation, and the audit feed carrying each
  rule edit's predicate before → after. Updated: `app-v35/catalog-shelves.html` to
  SPEC.collections — attribution basis in the peek drawer (held vs reachable, opening a
  reachable object is a claim) and rule-validity surfaced to slot.author holders only.
  RCTX-1176/1177.
- New: `app-v35/catalog-shelves.html` (`/concepts/shelves`) — the organizing layer
  **composed into the Catalog screen** as a Shelves tab, the way `catalog.ts` grows. Reuses the
  existing rail tiers, `.typecell`/`.statuscell`/`.tagchip`, peek drawer and v3.5-a tokens; no new
  class prefix. Lens + containers sit in the rail on desktop and move into the content area below
  900px. Slot predicate is visible; origin markers render only as the exception; the peek drawer
  answers "why is this here" and shows the properties that decide it. **View as** switches the
  same org shelf between Owner/Member/Viewer. Answers the composition gap in `files-v2.html`,
  which stays as the model argument. RCTX-1106/1107.
- New: `files-v2.html` (`/concepts/files`) — the **organizing layer**. v1 drew folders;
  this draws containers and slots — sets populated by a rule, augmented by hand, filtered
  per viewer. Container rail (personal + org IA side by side), lens separation (Catalog and
  Workspace live; Graph and Journey greyed), membership origin markers (matched / added /
  excluded), org override indicators, and a **view-as** switch that changes what the same org
  shelf contains. Counts are post-filter throughout — never a total. `/concepts/files` now
  points here; v1 stays reachable at `/concepts/files-v1`. Plan:
  `relay-board/docs/product/organizing-layer.md`.
- New: `files-v1.html` (`/concepts/files`) — the third projection of the corpus,
  after list (search) and graph (Context Map). Prototypes the Cloud Files model
  from `briefs/BRIEF.cloud-files.md`: **Google Drive folders, not Windows
  directories**. Folders are loose, shallow buckets an object lives in *one* of;
  labels cut across them; search is the spine and sits inside the view rather
  than being somewhere you leave to, scoped to the current folder with a visible
  widen. **Unfiled is a first-class state** — a large share of the fake corpus is
  deliberately unfiled, and there are no counts, badges, or filing nags anywhere,
  because the brief's core test is that an unorganised workspace still reads as
  fine. "Shared with me" holds received/claimed relays as a peer of the tree.
  Also draws the two screens the model turns on: the **integrity moment** in the
  editor (*"This was claimed by 2 people. Editing creates v5"* — sent context
  never mutates, edits supersede) and the **Git-familiar unified diff** across a
  four-version chain, with an envelope header for title/label/folder changes.
  `@`-autocomplete authors references (every accepted one is a graph edge).
  No lock or shield glyphs anywhere: in v1 filing is organisation, never access.

## 2026-08-01 — Code presence: the display direction for DEC-025
- New: `code-presence-v1.html` — what a relay surface looks like when the Code is
  legitimately absent. Under DEC-025 lazy mint a Code exists only where an actor
  deliberately elevated context for handoff, so most objects never get one, and
  every surface built on "there is always a Code" now has a second state.
  Proposes four laws: **L1** mark presence never absence (no placeholder, no
  em dash, no "not shared" stamp — a symbol for *nothing happened* is what reads
  as an error); **L2** one teal moment per object, the accent tracking where
  intent lives (the Code when shared, the share action when not, so the two
  states differ by shape rather than hue); **L3** the title never changes rank,
  same slot and size in both states; **L4** on lists, absence is a filter you
  select, not a badge on every row. Relay detail drawn in both states with an
  annotation overlay, the mint moment as a live event (pulse family #7, the one
  animation on the page), a mixed list with a circulation segment and an honest
  counter, and the four rejected drafts rendered so they are not re-proposed.
  Clean URL: `/concepts/code-presence`.
- The rejected drafts, kept visible: title promoted to hero (rejected by EC —
  title is the most generic field in the schema), title in Code costume, the
  internal ID shown as a stand-in (invariant C2 — IDs are machine handles, and
  their narrow alphabet is what keeps them shape-disjoint from Codes), and a
  placeholder in the Code slot.
- Canon correction in `PRODUCT.md`: design principle #1 said the Code is the
  hero artifact full stop. Narrowed to *every surface where sharing is the
  subject* — share panel, handoff, claim, notifications, onboarding. The
  artifact is unchanged; the scope claim was the overreach. relay-app
  `REFERENCE.product.md:47` and `REFERENCE.screens.md:19` carry the same line
  and still need the same fix, which gates Train 3 app work.
- Brief: `briefs/BRIEF.code-presence.md`. MCP tiers: `mcp/code-presence-display.html`.
  Upstream: relay-platform `docs/DESIGN-NOTE.identity-and-codes.md`, RCTX-1066,
  relay `AJA9TN`.

## 2026-07-30 — Public Views: support form
- New: `public/support-form-v1.html` — **the support contact form**
  (`relayctx.com/support`), the category's first *interactive* member. Proposes
  one addition to the slot contract: **`.form`**, left-aligned, sitting between
  `.body` and `.actions`; prefilled fields ring in accent so a person can see
  what the link filled in for them. Clickable states for arrival (bare ·
  `?topic=account-merge` · `&ref=…` · unknown-topic fallback · fully composed)
  and outcome (ticket created · **ticket system down** · security check failed ·
  rate limited), plus a deep-link builder that makes the URL-prefill contract
  touchable. Clean URL: `/concepts/support-form`.
- Note: the **live** `/support` shipped ahead of this concept (it was closing a
  404 the app was already linking into) on a chrome copied from `/feedback` —
  so it is not yet a member. This page is the proposal to fold it in; adopting
  it is a render-layer reskin only.

## 2026-07-30 — Seats & Segments added to console Finance
- New screen `console-v35/finance-lifecycle.html#fin-segments` — "Seats &
  Segments": splits orgs into five commercial buckets (Free, EAP · Open,
  EAP · Grace, Paid · Full, Paid · Discounted) instead of one blended list,
  so unpaid-seat cost (AI usage + infra) stays separable from paid-seat
  revenue performance. Filter pills recompute the summary tiles live — the
  margin tile flips to "Net burn" when only unpaid segments are selected,
  since those orgs cost money and generate none. Sortable table (click any
  column), working CSV export, contract-org flag reusing the same purple
  used for discounted pricing. Nav item added to the Finance group; ported
  from an `/impeccable`-style artifact draft into the shell's real markup
  and token classes (`b-free`/`b-eap-open`/`b-eap-grace`/`b-paid-full`/
  `b-paid-disc` badges, new `--purple` token pair light/dark).
- Flags two open decisions inline rather than deciding them here: what an
  expired EAP grace period converts to (today's `eap-graduation` sweep
  drops it straight to `free` — no discounted-tier conversion exists yet),
  and that the 30% graduation discount shown is a placeholder pending
  campaign terms.
- `console-v35/index.html` gained a missing card for `finance-lifecycle.html`
  entirely (it linked only `console.html` before); `concepts/index.html`'s
  existing finance-lifecycle card updated to describe the new screen.

## 2026-07-30 — Search v2 concept (one engine, two mounts)
- New: `app-v35/search.html` — interactive concept for the Search Experience v2
  plan (relay-board `PRD.search-experience-v2`): the `/search` screen + the ⌘K
  palette as two mounts of one engine (shared parser / scorer / row spec),
  two-pass local→engine results, narrowing operators with live chips, facet
  counts, unread + ⚡ agent-touch annotations rendered at last, intent-gated
  Code-status card, zero-query discovery, settled-only recents, URL-as-state.
  Carded on the app-v35 index under Concepts in review.

## 2026-07-30 — Public Views category + console notification layer
- New category: **Public Views** (`public/`) — every surface served without a
  session (error pages, maintenance, link-expiry, claim gates) unified on one
  chrome, the **public `.shell`** (`public/shell.html`): mark → status strip →
  headline → body → actions → support ref, live state switcher (404 · 500 ·
  503 · expired · notice), slot contract, and the `/api/frontend-error`
  triage beacon (category `public`, PB-… refs). Section renamed from
  "Errors & States"; the live error-page set stays put as a member.
- New: `console-v35/notifications.html` — **error statuses in the shell**:
  tier chips (active critical/warning counts) on every console screen + bell
  with per-admin unseen count and notification panel over `platform_alerts`
  (incl. the new `client`/`public` categories from the relay-platform
  error-triage pipeline). Interactive spike simulations; mark-seen (per-admin
  cursor) vs resolve (global) modeled as the backend contract.

## 2026-07-30 — Context Map v3.7: as-built alignment of the v3.6 refinement
- New: `map-v37.html` — v3.6's persistent-rail refinement updated to match what
  actually shipped in relay-app (branch `claude/context-map-graph-view-xh81fx`):
  the rail's feed rows that touch the selection are tinted (not just re-titled),
  the type chips **and new status chips** (Open/Received/Locked, pre-filter
  counts, strike-through when excluded) really filter the canvas, and the
  control strip gains the **Views menu with a default star** (RCTX-592 —
  one default per user; a bare Graph open lands on the starred view, explicit
  links always win). Same map mechanics and v3.5 neutral-first tokens as v3.6.

## 2026-07-29 — app-v35: custody-shell gains the Overview lens-set
- `custody-shell.html`: the workspace switcher dropdown now has two zones —
  **acting context** (always exactly one) and **"view" checkboxes** to check
  other workspaces into a read-only overview. Foreign rows render receded
  (dashed) with their context chip; actions reduce to Timeline (read-only) and
  **Open →** (guided switch into the owning workspace). `a` toggles the
  all-contexts lens. Encodes the spec refinement: strict scoping governs
  *acting*, the lens-set governs *scanning* — unified-inbox pattern.

## 2026-07-29 — app-v35: Custody in the app shell
- New: `app-v35/custody-shell.html` — the custody flip inside the shipped shell
  anatomy (shell.html chrome): functional workspace switcher dropdown +
  `[`/`]` cycling with the lens-flip transition, topbar region readout, bell
  popover carrying guided switches (tap → lens flips → lands on the item),
  strictly-scoped Transfers list per context, claim simulator, Pass → across
  joined workspaces with dual-sided provenance timelines. Keys: `[ ]` `1-3`
  `h` `b` `j/k` `o` (timeline) `p` (pass) `t` (theme). Hub fresh-card now
  points here; the standalone walkthrough remains in the area index.

## 2026-07-29 — app-v35: Address custody walkthrough v2 (rulings applied)
- `app-v35/custody-addressing.html` upgraded to v2: the blend-vs-strict toggle
  is resolved (**strict scoping** per the SPEC-address-custody-v1 ruling) and
  removed; added the org-tagged bell with **guided switching**, one-tap Home,
  and the **Pass →** action — relaying an object between joined workspaces as
  an explicit policy-checked event, with the **per-object timeline** recording
  provenance on both sides (origin workspace, policy check, custody + region
  at each hop). Demonstrates "data crosses org walls only as a relay" and
  timeline continuity across contexts.

## 2026-07-29 — app-v35: Address custody walkthrough (interactive)
- New: `app-v35/custody-addressing.html` — prototype for `SPEC-address-custody-v1`
  / RCTX-979. Per-membership contact-address mapping (1:1 picker), claim
  simulator (mapped / unmapped / billing-lapsed / membership-ended paths with
  the governance fallbacks), workspace switcher over custody-scoped lists with
  data-region chips, and the blend-vs-strict Personal-scoping question as a
  live toggle. Index card added under Concepts in review.

## 2026-07-29 — console-v35: Account migrations pattern-setter
- New screen in `console-v35/console.html` (shell + 6 screens now): Account
  migrations — the operator surface for the shipped merge/split backend
  (relay-board `SPEC-account-migration-v1`, relay-platform
  `/api/admin/v1/account-migrations`). Kind badge (merge/split), consent
  progress (1/2), status chips across the full state machine (awaiting
  consent / consented / completed / cancelled), execute+cancel confirm
  modals, journal viewer, tier-1 + signed-pointer framing in the buildbar.
  Reached from the rail (Users section, warn pill = ready-to-execute count)
  or the Users row action "Merge…".

## 2026-07-29 — index-card CI check + pre-existing drift fixes
- New: `scripts/check_index_cards.py`, run in the "Content checks" workflow —
  fails a PR if a page under an area folder has zero references anywhere in
  the repo. See MAINTENANCE.md.
- Fixed drift the new check found here: `onboarding-current-state.html` and
  `onboarding-journey-concept.html` existed but were never referenced —
  added as Reference cards next to Onboarding Flows.

## 2026-07-29 — Context Map v2 + Canvas Motion + Shells ported from frozen `prototype`
- New: `map-v35-2.html` (density × lenses × list, PR #185 / relay KTVANV),
  `map-custody-concept.html` (journey view + custody edge cases, same PR),
  `canvas-motion.html` (gc-* grammar motion, relay FMZRNG), `shells-v35.html`
  (App UI System — universal rail, shell temperaments, relay FMZRNG). All four
  only ever landed on the `prototype` branch, which froze at the 2026-07-19
  restructure and is slated for deletion 2026-08-09 — ported the files here so
  nothing is lost, with cards added in this same change. Not yet ratified:
  whether `map-v35-2` supersedes `map-v35.html` (v1) is an open decision, see
  MEMORY.md.

## 2026-07-26 — ComfyUI added to Apps
- New: `app-comfyui.html` — Relay's first node-graph-tool concept, alongside
  Slack/Chat/Relay Agent in the Apps section. A working prototype, not a
  mockup: `relay-platform/clients/comfyui-relay-nodes` (branch
  `claude/comfy-relay-integration-9yfv7r`) is a real, tested ComfyUI custom-node
  package — `Relay In` fetches a Code and splits its markdown content from a
  tagged-on ` ```relay-fields ` JSON block; typed `Relay Field` nodes pull one
  key out as STRING/INT/FLOAT for the graph. Zero backend changes needed to
  prove the *in* direction works. Diagram mirrors the real node
  inputs/outputs, not an artist's impression.
- Deliberately **not** covered: pushing generated images back *out* into a
  relay — needs binary/object relay support first (Relay's `content` is
  text-only today), tracked separately so it doesn't block this concept.
- Tracked: Linear `RCTX-823` (epic, Plugin & Integration Payload Registry
  project) / `RCTX-827` (productionize this prototype against the registry).

## 2026-07-25 — Mobile: You becomes a Menu sheet, persistent bell, Activity unified
- `app-mobile-v2.html`: the You tab is no longer a 5th screen — **Menu** now slides a sheet
  up over the current screen and tab bar (same mechanic as the tools sheet), collapsing back
  down on a second tap, the backdrop, an explicit close, or picking any other tab. Nothing
  underneath is lost. Content unchanged (identity, this-week stats, Explore/tools entry,
  Security, Settings), just no longer its own route.
- Added a persistent notification bell (top-right, every screen) opening the same
  dropdown-panel pattern as the Relay Agent concept's bell. Its badge reads the same count as
  the Activity tab badge, made explicit as a standing rule in
  `briefs/SPEC.app-components.md`: Activity is the one unified space for notifications and
  activity, the bell is a shortcut into it, never a second inbox.
- Explore's back-link now returns to Home and reopens the Menu sheet, since there's no You
  screen to return to.

## 2026-07-25 — cross-surface components: tools panel, profile/security, SPEC doc
- New: `briefs/SPEC.app-components.md` — the component inventory + surface
  capability matrix for `concepts/app-*.html`, so Tools/Notifications/
  Profile+Security stay consistent instead of drifting per file. Read this
  before adding chrome to any Apps-section concept.
- `app-relay-agent.html`: added the tools panel (`+` next to the input
  opens a sheet with Graph/Streams/Explore, Explore shown locked/Horizon
  rather than hidden), a notification bell with badge, and a quick-glance
  profile + security panel (passkey, active sessions).
- `app-mobile-v2.html`: brought the same three to Mobile — a "Jump to a
  feature" row on Home opens a bottom sheet (slides up over the tab bar)
  with the identical Graph/Streams/Explore tiles, and the You tab gained
  an identity header + Security section matching Relay Agent's panel.
  Wearable is the one surface that intentionally excludes all three (see
  its own concept notes) — Slack and Chat get an explicit N/A in the SPEC
  matrix since Relay is a guest in someone else's chrome there.

## 2026-07-25 — Relay Agent concept added to Apps
- New: `app-relay-agent.html` — Relay's own first-party conversational
  surface (not Relay's cards rendered by a third-party host, which is what
  the Chat concept covers). Same morning-brief → capture → claim loop, but
  replies use the actual designed app card component (working buttons,
  brand avatars) rather than a raw MCP tool-call block, since Relay
  controls this surface end to end. Deliberately shown able to approve a
  connection request directly, contrasting with the Chat concept's guest
  agents, which can't.

## 2026-07-25 — new Apps section: Wearable, Slack, Chat
- Added an **Apps** section at the top of the gallery — the surfaces Relay
  actually runs on were scattered (Mobile was buried as the 6th of 7
  sections) and wearable/Slack/chat had no home at all. Moved Mobile V2 (+
  the superseded V1 and Phase 3) up into it, and added three new greenfield
  concepts alongside: `app-wearable-v1.html`, `app-slack.html`,
  `app-chat.html`.
- **Wearable**: not a shrunk phone — three faces only (Glance, Act,
  Capture), no keyboard/Search/You, digital-crown-first approve, voice-only
  capture.
- **Slack**: Relay as a native app, not a dashboard link-out. Reuses the
  MCP response-card component (`.cm`/`.cm-tool`/`.cm-body` from
  `mcp/response-cards.html`) inside Slack's own message/attachment chrome,
  with real inline approve/deny and `/relay capture`.
- **Chat**: the agent's own chat window as the surface — a full claim →
  load → capture → pending-approvals transcript using the identical MCP
  card component, switchable across Claude/ChatGPT/Cursor-style chrome to
  show the card travels unchanged.

## 2026-07-25 — app-mobile-v2 remediation + Capture icon fix
- `app-mobile-v2.html` (live) taken through an `/impeccable` critique pass
  (P0 error states, Activity/Home IA fix, Send+Claim segmented Capture, icon
  language, undo-on-deny, contrast/keyboard fixes — see PR #171) then a
  follow-up fix: the Capture tab's FAB read as a mic/walkie-talkie even
  though Capture is Send-or-Claim, a two-way handoff, not audio-only —
  swapped for a bidirectional exchange glyph; the mic icon stays inside the
  Send pane's actual voice-record button, where it's accurate.
- Snapshots kept in `_archive/`: `app-mobile-v2.1.html` (post-critique-pass,
  pre-icon-fix) and `app-mobile-v2.2.html` (current, post-icon-fix). The live
  file at `concepts/app-mobile-v2.html` always tracks the latest.

## 2026-07-19 — Team & Collaborator Onboarding (new section)
- New section: `onboarding-collaborator-v1.html` — the internal, team-facing
  collaborator-welcome component (distinct from the app's own user-onboarding
  line above). Placeholder data; real per-person instances are gated on
  `resources.relayctx.com/onboarding/<person>` (relay-resources
  `docs/onboarding/`). First built for the initial brand & product hire.

## 2026-07-19 — console-v35 nav completed to full audit inventory
- `console-v35/console.html`: added the remaining Batch 4 screens from
  `AUDIT.console-v35.md` to the rail nav as placeholders — Releases (Content);
  Onboarding mgmt, Legal, Trial users, Trash, Network (System). All render via
  the existing "on the map, not yet skinned" placeholder; no built screens
  touched. My Account intentionally not re-added — cut per Part 5 of the audit
  (redundant with the app, `Account ↗` deep-link instead).

## 2026-07-19 — area restructure
- Folder created in the creative-domain restructure: `web/` product prototypes
  and root-level strays (onboarding, mobile, launcher, errors) homed here.
  Old URLs 301 via `_redirects`.
- `explore/` direction studies (minimal/soft/swiss/maximal) split out to
  `marketing/web/explore/`; `explore/journey.html` (product concept) stays.
- Console fork preserved: prototype's 21-screen operator shell is canonical at
  `console-v35/console.html`; main's 2026-07-18 finance-lifecycle build kept at
  `console-v35/finance-lifecycle.html` pending fold-in.

## 2026-07 (pre-restructure)
- **07-18** Activation connect-first flow (#147); transfer-claim un-retired and
  synced to shipped claim process (#144); app-v35 gc-* kit explorer; Connect
  screen (tiered client picker, #143); Network page concept (#142); screen
  reality matrix + as-shipped design-system canon.
- **07-17** console-v35 Campaigns screen (F-6); Capture full concept
  (inbox + slackbox + Relay AI routing); Send → Capture experience
  (RCTX-730/733/734); campaign-x /x/{slug} edge cases; transfer-claim M2 states.
- **07-16** console-v35 operator shell + RBAC Roles & access screen; universal
  menu (no bottom tabs).
- **07-13/14** Explore journey/v2, sequential-onboarding storyboard.
- **07-12 and earlier** Context Map line (map-v35/v36, graph-components,
  mobile map concept), app-v35 multi-screen shell (home/series/sessions/
  manifest), onboarding prototypes, app-mobile-v2.
