<!-- source: openspec/decisions.md -->

# Decisions

> Bootstrap copy created by `define-design-system-spec-convention`. Promotes to `openspec/decisions.md` at archive (Phase 4 → Phase 7).
>
> **Schema:** `| ID | Status | Owner | Statement |`. No Date column — dates live in capability frontmatter, per `archive/2026-05-08-add-forge-convention-adapter/design.md:50–56`.
>
> **ID prefix is per-capability:** `D-<CAPABILITY>-N` (per `current/forge/entities.md § Convention adapters`, "decision IDs prefixed by capability"). For design-system: `D-DS-N`.
>
> **Mutation rule:** ratified decisions are not edited. They are superseded by a new change that registers a successor `D-<…>-N` referencing the prior. The historical entry keeps `ratified` status but gains a `supersededBy` field on amendment.

---

## Design-system

| ID | Status | Owner | Statement |
|---|---|---|---|
| D-DS-1 | ratified | Pavel | Adopted design-system spec convention rules R1..R13 per `define-design-system-spec-convention`. Rules live in `openspec/_methodology/design-system-convention.md`. |
| D-DS-2 | ratified | Pavel | Adopted operating model with four roles (Design System Lead / Design Agent / Code Agent / Investigator Agent) per `openspec/_methodology/design-system-operating-model.md`. |
| D-DS-3 | ratified | Pavel | Quarterly audit cadence with three-tier severity scale (S0 blocking / S1 next-sprint / S2 open-question) per `openspec/_methodology/design-system-audit-protocol.md`. |
| D-DS-4 | ratified | Pavel | `agent-brief.md` is a required artefact in every design-system-related change. Template lives at `openspec/_methodology/templates/design-system/agent-brief.md.template`. The brief stays in the change folder root and is **not** promoted at archive — it remains in the archive folder as historical record. |
| D-DS-5 | ratified | Pavel | Deck typography ramp tokens (`--text-display-deck`, `--text-h1-deck`, `--text-h2-deck`, `--text-body-deck`) live at `design-tokens.md § Typography › Deck ramp`. They are typography, not surface-specific. A separate `§ Surface-specific typography` block would invite additive growth without analytical benefit. Closes Q-DS-3 per `improve-design-system-token-coherence/design.md § 8`. |
| D-DS-6 | ratified | Pavel | The light `--bg-3` value is declared and kept as forward-looking. Removing it would break the variant-portable invariant that `bg-bg-3` works in both modes (per `design-tokens.md § Light-mode token strategy`). Closes Q-DS-4. |
| D-DS-7 | ratified | Pavel | `--color-accent` rename: brand-canonical name is the primary slot for terracotta in `globals.css`. Cool blue stays at `--color-blueprint`. The shadcn-derived `--accent` alias remains via `@theme inline` for backward compatibility. Implemented by RAP-206 / PR #507. |
| D-DS-8 | ratified | Pavel | Narrow gradient exception. `design-system.md` rule 5 ("no gradients") targets decorative colour washes and soft-elevation gradients; structural, single-tone, geometric pattern utilities built on `linear/radial-gradient` (drafting grids, hatching) are an explicit exception **only as decorative fill on text-free zones**. Gradients/patterns behind text and non-flat backgrounds behind content remain forbidden — `design-tokens.md § Hard rules at the colour level` clauses are unchanged in force. Ratified for `add-background-pattern-system` / RAP-1030 via change `ratify-pattern-gradient-exception`. |
| D-DS-9 | ratified | Pavel | Background-pattern total-per-page budget raised 2 → 3; the spacing rule (≥1 bare section between any two placements) is the governing constraint, with the count cap as a coarse upper bound. Adds the **nested-wrapper CAD-fade technique**: to fade `bg-pattern-cad` (which owns `mask-image`), put `pattern-fade-*` on a parent wrapper so the two masks composite; same-element pairing remains a documented anti-pattern. Ratified for change `apply-connected-stack-coordinate-grid` / RAP-1265 (first non-shipping-precedent tile, P5 on `connected-stack`). |

<!-- Add D-DS-N entries via change folder, not direct edit. -->

---

## Methodology

> Added 2026-05-18 from change `add-sdd-methodology-positioning` (RAP-1078). Prefix `D-MTH-N`. Companion doc: `openspec/_methodology/sdd-positioning.md`.

| ID | Status | Owner | Statement |
|---|---|---|---|
| D-MTH-1 | ratified | Pavel | Keep `openspec/current/` as the capability-spec directory; document the divergence from vanilla OpenSpec 1.0's `openspec/specs/`. Alternatives rejected: (a) **rename** `current/` → `specs/` causes mass path churn across hundreds of files plus `CLAUDE.md`, `openspec/AGENTS.md`, and the openspec-bundle generator (`tools/build-openspec-bundle.mjs`) — contradicts the change's stated non-goals; (b) **symlink** `current/ → specs/` is fragile under the Cloudflare Workers + OpenNext build, carries git symlink-permission risk, and fragments search/tooling across two path roots. `current/` is also semantically more precise for an internal-first monorepo where OpenSpec tooling-compatibility is not a constraint. Ratified via change `add-sdd-methodology-positioning`. |
| D-MTH-2 | ratified | Pavel | OpenSpec is positioned as the **upstream / parent** methodology that Rapoport Studio uses and extends — not a peer methodology the studio competes with or stands alongside. The studio's distinctive practices (capability-split, `verification.md` as a first-class artifact, Forge as an execution adapter) are extensions on top of OpenSpec, not a separate framework. Ratified via change `add-sdd-methodology-positioning`. |

<!-- Add D-MTH-N entries via change folder, not direct edit. -->

---

## Other capabilities

<!-- Placeholder sections — populated by their own future changes, not this one. Each capability defines its own prefix (auth → AUTH, db → DB, forge → FORGE, telegram → TG, …). -->

### Web (favicon) — `D-FAV-N`

> Added 2026-05-25 from change `add-studio-favicon` (RAP-1221). Prefix `D-FAV-N`. Companion doc: `openspec/current/web.md § Icon contract`.

| ID | Status | Owner | Statement |
|---|---|---|---|
| D-FAV-1 | ratified | Pavel | Adopt Next.js 16's file-based icon convention (`apps/web/src/app/icon.tsx`, `apple-icon.tsx`, `icon.svg`). Delete the legacy `favicon.ico`. The `apps/web/src/app/[locale]/layout.tsx` `generateMetadata()` does **not** declare `icons` — Next 16 auto-emits `<link>` tags from the file-based convention; an explicit `metadata.icons` would override the discovery. |
| D-FAV-2 | ratified | Pavel | The mark is the **RS glyph framed by four corner L-brackets** — `StudioLogo` `glyph` variant + tactical-frame motif. JetBrains Mono SemiBold uppercase, no tracking, on a canvas tile with terracotta brackets. Per-surface palette: light tab (ivory canvas, ink letters, terracotta brackets), dark tab (near-black canvas, lifted-ink letters, orange-400 brackets), apple touch tile (terracotta canvas, ivory letters + ivory brackets — accent-on-accent collapses to canvas). |
| D-FAV-3 | ratified | Pavel | Geometry as percentages of the 256-px source viewBox: brackets 18 % length × 4.5 % stroke × 7 % inset; letters 53 % cap-height, weight 600 (JetBrains Mono SemiBold), tracking `0em`. Values frozen from live prototyping; heavier weights (700, 800) tested in prototyping made the mark feel cramped against the brackets at tab-strip sizes. |
| D-FAV-4 | ratified | Pavel | `apps/web/src/app/icon.svg` static fallback ships the **light** variant unconditionally for consumers that resolve the static file rather than the dynamic route. The dark variant is a refinement delivered via the `@media (prefers-color-scheme: dark)` switch inside the SVG body (D-FAV-11(b)). |
| D-FAV-5 | ratified | Pavel | Single source SVG at `packages/ui/assets/marks/rs-glyph.svg`; `icon.tsx`, `apple-icon.tsx`, and `icon.svg` all derive from it (via the build-time codegen at `apps/web/src/generated/rs-glyph.ts`, D-FAV-11(a)). No duplication of letter paths across consumers. |
| D-FAV-6 | ratified | Pavel | Codify the icon contract in `openspec/current/web.md § Icon contract` and the brand-mark exports in `openspec/brands/studio/design-components.md` § "RS glyph — favicon export" + § "Tactical bracket frame — favicon" at archive. The pre-2026-05-25 silence on what the studio puts in a 16x16 tab strip is what let the Next.js default ship in production for months. |
| D-FAV-7 | ratified | Pavel | Apple touch tile = solid terracotta (`--color-accent`) with ivory RS + ivory brackets. No media variant — iOS does not respect `(prefers-color-scheme)` on touch icons. Single high-contrast tile reads correctly against any home-screen wallpaper and iOS 17+ tinted-icon mode. |
| D-FAV-8 | deferred | Pavel | PWA `manifest.webmanifest` + maskable 512x512 are deferred to a future change `add-pwa-manifest`. The marketing site is not installable today; the workspace `app.rapoport.studio` is not maskable-tile-aware either. |
| D-FAV-9 | ratified | Pavel | One favicon across `rapoport.studio` and `app.rapoport.studio`. The mark is the same brand; the chrome differs, the favicon does not. Revisit if the workspace ever rebrands. |
| D-FAV-10 | ratified | Pavel | The four corner L-brackets render as separate elements inside `icon.tsx` / `apple-icon.tsx` / `icon.svg`, **not** baked into `rs-glyph.svg`. `icon.tsx` and `icon.svg` emit eight axis-aligned `<rect>`s (one per leg, four L-shapes); `apple-icon.tsx` uses four absolutely-positioned `<div>`s with `border-top` + `border-left` (etc.). Keeping the source SVG single-channel (`currentColor`) lets the bracket colour swap per surface (terracotta on tab, ivory on touch tile) without forking the source. The `BRACKET = { lenPct: 18, weightPct: 4.5, insetPct: 7 }` const literal lives in both `icon.tsx` and `apple-icon.tsx`; `icon.svg` inlines the integer-pixel equivalents. |
| D-FAV-11 | ratified | Pavel | Three live-system corrections folded into the implementation. **(a)** The source SVG reaches the icon routes via build-time codegen (`tools/build-rs-glyph.mjs` → `apps/web/src/generated/rs-glyph.ts`), not a runtime `fs.readFile` — Cloudflare Workers do not bundle paths outside `apps/<app>/` and the route returns 500 in production (worked example: PRs #1179 + #1182 + archive `2026-05-15-harden-cookie-transparency` — the studio took the marketing site red for 14 hours on the same pattern with `_legal/`). **(b)** `icon.tsx` returns a hand-crafted SVG via plain `Response`, not `next/og`'s `ImageResponse` — Satori does not support `dangerouslySetInnerHTML`, which the design.md § 3 example would have failed at build; a plain SVG body lets us embed `@media (prefers-color-scheme: dark)` inside the SVG itself (Next 16's `generateImageMetadata.media` field is dropped by `resolve-icons.js`, so two `<link rel="icon">` tags would otherwise reach the browser untagged). **(c)** `apple-icon.tsx` keeps `ImageResponse` for PNG output but embeds the glyph via `<img src="data:image/svg+xml;base64,…">` instead of `dangerouslySetInnerHTML` — Satori renders `<img>` data URLs reliably. |

<!-- Add D-FAV-N entries via a new change folder, not direct edit. -->
