# 03-architecture.md — Architecture Collapse

**Authored:** 2026-04-21 13:38 UTC
**Author:** CC-OPS-SPECSEED root orchestrator (Opus 4.7)
**Inputs:** `03-architect-A.md` (file tree + interfaces + configs), `03-architect-B.md` (signatures + data flow + contracts)
**Supersedes on conflict:** Source worker docs
**Binding for:** Phase 4 (Build) — every file listed here is a target.

---

## 1. Canonical file tree (final)

All paths relative to `/var/www/specseed-io/`. No `src/`. App Router at project root. Path alias `@/*` active.

```
/var/www/specseed-io/
├── app/
│   ├── layout.tsx                         # RootLayout: Inter+IBM Plex Mono, metadata, globals.css
│   ├── page.tsx                           # HomePage — lifts [input,setInput]; 7 sections
│   ├── globals.css                        # @tailwind base → fleet imports → @tailwind components/utilities → utilities
│   ├── playground/
│   │   └── page.tsx                       # PlaygroundPage — Nav + SeedGenerator(fullBleed) + Footer
│   └── styles/
│       ├── palette.css                    # fleet copy
│       └── components/
│           ├── buttons.css                # fleet
│           ├── cards.css                  # fleet
│           ├── forms.css                  # fleet
│           ├── navigation.css             # fleet
│           ├── badges.css                 # bespoke (Haiku ghost / Sonnet outline / Opus fill)
│           ├── segmented.css              # bespoke
│           ├── tabs.css                   # bespoke (mirrors nav-link idiom)
│           ├── code.css                   # bespoke (crimson left border, mono)
│           ├── hero.css                   # bespoke (dot grid + code-scroll @keyframes)
│           └── octopus.css                # bespoke (scroll-snap + fan-out SVG)
├── components/
│   ├── Nav.tsx
│   ├── Hero.tsx
│   ├── Footer.tsx
│   ├── HowItWorks.tsx
│   ├── PhaseCard.tsx
│   ├── MarkdownPreview.tsx
│   ├── ArtifactTabs.tsx
│   ├── PhaseOctopus.tsx
│   ├── SeedGenerator.tsx
│   └── ui/
│       ├── Button.tsx
│       ├── TabStrip.tsx
│       ├── FormField.tsx                  # dispatcher: reads FormFieldSpec → renders right control
│       ├── SegmentedControl.tsx
│       ├── TierBadge.tsx
│       └── CodeBlock.tsx
├── lib/
│   ├── seedSchema.ts
│   ├── constants.ts
│   ├── formFields.ts
│   ├── wavePlan.ts
│   ├── helpers.ts
│   ├── generateSeedSections.ts
│   ├── generateSeed.ts
│   ├── generateClaudeMd.ts
│   ├── generateAgentsMd.ts
│   ├── generateClaudeAgents.ts
│   ├── generateCodexConfig.ts
│   ├── generateOsAdapters.ts
│   ├── compileFullSeed.ts
│   ├── buildAdapterZip.ts
│   ├── downloadFile.ts
│   ├── clipboard.ts
│   └── cx.ts
├── public/
│   ├── robots.txt
│   ├── sitemap.xml
│   └── og-image.png                       # 1200×630 placeholder; Phase 8
├── docs/
│   ├── specseed-product.md                # Phase 8
│   └── phase-octopus.md                   # Phase 8
├── .claude/
│   ├── settings.json
│   └── agents/
│       ├── recon.md
│       ├── tester.md
│       └── reviewer.md
├── .codex/
│   ├── config.toml
│   └── agents/
│       ├── reviewer.toml
│       └── worker.toml
├── _mos/                                  # COMMITTED — build audit trail
├── _theme/                                # COMMITTED — fleet staging
├── CLAUDE.md
├── AGENTS.md
├── README.md
├── deploy.sh
├── next.config.ts
├── tailwind.config.ts
├── postcss.config.mjs
├── tsconfig.json
├── eslint.config.mjs
├── .gitignore
├── package.json
└── package-lock.json                      # generated by npm
```

---

## 2. `lib/seedSchema.ts` — full source (binding)

Full source block is in `03-architect-A.md §2`. Key points:

- `SeedInput` = 12 fields per seed-brief
- Literal unions: `ProjectType`, `AgentPlatform`, `Environment`, `Scope`, `Risk`, `Parallelism`, `OutputStyle`, `DeploymentTarget`, `ModelTier`, `PhaseName`
- `PhaseSpec` (readonly fields: `index`, `name`, `model`, `effort`, `duration`, `fanOut`, `artifact`, `workerCount`)
- `WavePlan` (readonly: `workerCap`, `decompositionDepth`, `useAgentTeams`, `phases: readonly PhaseSpec[]`)
- `GeneratedSeed`:
  ```ts
  export interface GeneratedSeed {
    readonly slug: string                              // from toSlug(input.projectName)
    readonly plan: WavePlan
    readonly seedMd: string
    readonly claudeMd: string
    readonly agentsMd: string
    readonly claudeAgents: {
      readonly reviewer: string
      readonly recon: string
      readonly tester: string
    }
    readonly codexAgents: {
      readonly reviewer: string
      readonly worker: string
    }
    readonly codexConfig: string
    readonly macosSetup: string
    readonly ubuntuBootstrap: string
  }
  ```
- `DEFAULT_SEED_INPUT: SeedInput` — exact from seed-brief (as const)
- Tuple consts: `PROJECT_TYPES`, `AGENT_PLATFORMS`, `ENVIRONMENTS`, `SCOPES`, `RISKS`, `PARALLELISMS`, `OUTPUT_STYLES`, `DEPLOYMENT_TARGETS` — all `as const satisfies readonly …[]`

**Note on field naming**: Architect A used `.codex.{configToml, reviewerToml, workerToml}` nested object. Architect B flattened to `codexConfig`, `codexAgents.reviewer`, `codexAgents.worker`. **Orchestrator decision: B's flatter shape wins** — fewer keys, simpler JSZip mapping, matches the `claudeAgents` pattern which A itself uses. Final:

```ts
codexAgents: { reviewer: string; worker: string }
codexConfig: string
```

Similarly macos/ubuntu are flat top-level, not nested under `.os`:
```ts
macosSetup: string
ubuntuBootstrap: string
```

---

## 3. `lib/constants.ts` — binding content

Per `03-architect-A.md §3`. Includes all 8 option arrays, `PHASE_TEMPLATE` (9 `PhaseSpec` entries with Phase 4 `workerCount: 0` placeholder), `TIER_BADGE_CLASS` (haiku→ghost, sonnet→secondary, opus→primary), `AGENT_ROLES` (9 entries), `SCOPE_BASE` / `PARALLELISM_BOOST` / `RISK_BOOST` maps, `WORKER_CAP_MIN = 1`, `WORKER_CAP_MAX = 12`.

Phase 4 worker is free to reorder fields for readability but must not add or remove entries.

---

## 4. `lib/formFields.ts` — binding content

Per `03-architect-A.md §4`. 12-item `FORM_FIELDS` literal matching §8 of `02-decomposition.md`. Reconciliation note: Architect A had `projectType` as `select` and `agentPlatform` as `segmented`; Decomposer A had `agentPlatform` as `select` and `environment` as `segmented`. **Final**:

| # | id | kind |
|---|---|---|
| 1 | `projectName` | text |
| 2 | `objective` | textarea(3) |
| 3 | `projectType` | select |
| 4 | `agentPlatform` | segmented |
| 5 | `environment` | segmented |
| 6 | `scope` | segmented |
| 7 | `risk` | segmented |
| 8 | `parallelism` | segmented |
| 9 | `outputStyle` | segmented |
| 10 | `deploymentTarget` | select |
| 11 | `constraints` | textarea(3) |
| 12 | `repoNotes` | textarea(3) |

---

## 5. `lib/wavePlan.ts` — binding signatures

```ts
export function workerCap(scope: Scope, parallelism: Parallelism, risk: Risk): number
// Returns Math.max(1, Math.min(12, SCOPE_BASE[scope] + PARALLELISM_BOOST[parallelism] + RISK_BOOST[risk]))

export function decompositionDepth(scope: Scope): 1 | 2 | 3
// tiny/small → 1; medium → 2; large/platform → 3

export function shouldUseAgentTeams(scope: Scope, parallelism: Parallelism): boolean
// (large|platform) && parallelism !== 'conservative'

export function buildPhases(cap: number): readonly PhaseSpec[]
// Clones PHASE_TEMPLATE and replaces phase 4 workerCount with cap

export function buildWavePlan(input: SeedInput): WavePlan
// Composes all four above
```

Unit tests (Phase 6): enumerate all 45 (scope, parallelism, risk) cells, assert `workerCap` against the canonical 45-row table in `02-decompose-B.md §5.1`. Assert `buildPhases(5).length === 9` and Phase 4 `workerCount === 5`.

---

## 6. Generator function signatures — binding

Per `03-architect-B.md §1`. Summary of exports by file:

- **`generateSeedSections.ts`**: 11 section builders — `sectionObjective`, `sectionOperatingPrinciple`, `sectionTargetRuntime`, `sectionGlobalConstraints`, `sectionNinePhaseOctopus(plan)`, `sectionAgentRoles(input, plan)`, `sectionWavePlan(plan)`, `sectionClaudeAdapter(input)`, `sectionCodexAdapter(input)`, `sectionOsAdapter(input)`, `sectionDefinitionOfDone(input)`.
- **`generateSeed.ts`**: `generateSeed(input, plan): string` — composes the 11 sections via `joinLines`.
- **`generateClaudeMd.ts`**: `generateClaudeMd(input): string`, `claudeMission(input)`, `buildCommandsFor(input)`, `fileOwnershipSummary(input)`.
- **`generateAgentsMd.ts`**: `generateAgentsMd(input): string`, `environmentNotes(env)`.
- **`generateClaudeAgents.ts`**: `generateClaudeAgent(name: 'reviewer'|'recon'|'tester', input): string`, + helpers `claudeAgentFrontmatter`, `claudeAgentBody`.
- **`generateCodexConfig.ts`**: `generateCodexConfig(): string` (constant `[agents]\nmax_threads = 6\nmax_depth = 1\n`), `generateCodexAgent(name: 'reviewer'|'worker'): string`.
- **`generateOsAdapters.ts`**: `generateMacosSetup(input): string`, `generateUbuntuBootstrap(input): string`.
- **`compileFullSeed.ts`**: `compileFullSeed(input): GeneratedSeed`. Sequence per `03-architect-B.md §8` — fills `slug` from `toSlug(input.projectName)` and `plan` from `buildWavePlan(input)`.
- **`buildAdapterZip.ts`**: `buildAdapterZip(bundle: GeneratedSeed): Promise<Blob>` — **lazy-imports JSZip** via `const { default: JSZip } = await import('jszip')`, then assembles the 11-file bundle per the structure in `03-architect-B.md §6`.
- **`downloadFile.ts`**: `downloadFile(filename, content, mime?): void` + `downloadBundle(bundle, slug): Promise<void>` (calls `buildAdapterZip` then `downloadFile`).
- **`clipboard.ts`**: `copyToClipboard(text): Promise<boolean>` — impl per `03-architect-B.md §4`.
- **`helpers.ts`**: `slugify(s)` (`toSlug` alias from `lib/slug.ts` merged into helpers), `joinLines`, `markdownTable`, `bulletList`, `section`, `indent`, `repeat`, `escapeYaml`, `tomlString`.
- **`cx.ts`**: `export { clsx as cx, clsx } from 'clsx'`.

---

## 7. Configuration files — exact contents

Per Architect A §5–§9. Summaries:

### `next.config.ts`

```ts
import type { NextConfig } from 'next'
const nextConfig: NextConfig = {
  output: 'export',
  trailingSlash: true,
  distDir: 'out',
  images: { unoptimized: true },
  typescript: { ignoreBuildErrors: false },
  eslint: { ignoreDuringBuilds: false },
  poweredByHeader: false,
  generateBuildId: async () => 'specseed',
}
export default nextConfig
```

### `tailwind.config.ts`

Key `theme.extend`:
- `colors.concrete` (9 shades from the fleet palette)
- `colors.crimson` (DEFAULT + dark + glow)
- `fontFamily.sans` → `['var(--font-body)', 'system-ui', ...]`
- `fontFamily.mono` → `['var(--font-mono)', 'JetBrains Mono', 'Menlo', 'monospace']`
- `boxShadow.brick` → `'4px 4px 0 #0a0a0a'`, `'brick-hover'` → `'6px 6px 0 #0a0a0a'`
- `borderRadius.none` = `'0'`, `.sharp` = `'2px'`
- `screens.gen` = `'900px'` (custom)
- `keyframes['code-scroll']` + `animation['code-scroll']` for hero background

Content array: `['./app/**/*.{ts,tsx}', './components/**/*.{ts,tsx}', './lib/**/*.{ts,tsx}']`.

Full TS source block in `03-architect-A.md §6`.

### `tsconfig.json`

Strict + `noUncheckedIndexedAccess` + path alias `@/*: ["./*"]`. Full JSON in `03-architect-A.md §7`.

### `eslint.config.mjs` (flat config)

Extends `next/core-web-vitals` + `next/typescript` via `FlatCompat`. Fallback to `.eslintrc.json` if create-next-app emits the legacy form. Full in `03-architect-A.md §8`.

### `postcss.config.mjs`

`tailwindcss` + `autoprefixer`. Per `03-architect-A.md §9`.

### `app/globals.css` — binding import order

```css
@tailwind base;                              /* 1. Preflight reset */
@import './styles/palette.css';              /* 2. Fleet tokens */
@import './styles/components/buttons.css';   /* 3. Fleet components */
@import './styles/components/cards.css';
@import './styles/components/forms.css';
@import './styles/components/navigation.css';
@import './styles/components/badges.css';    /* bespoke */
@import './styles/components/segmented.css';
@import './styles/components/tabs.css';
@import './styles/components/code.css';
@import './styles/components/hero.css';
@import './styles/components/octopus.css';
@tailwind components;                        /* 4. Tailwind component layer */
@tailwind utilities;                         /* 5. Tailwind utilities (escape hatch) */
/* 6. Project utilities: .bg-dot-grid, .focus-brick, .octopus-scroll, reduced-motion overrides */
```

Justification: base reset first, component layers next, utilities last so JSX Tailwind classes can override fleet rules when needed. No `!important` required.

### `package.json`

Per `03-architect-A.md §10`. Dependencies: `next ^14.2.0`, `react ^18.3.0`, `react-dom ^18.3.0`, `framer-motion ^11.0.0`, `clsx ^2.1.0`, `jszip ^3.10.0`. DevDeps: `typescript ^5.4`, `@types/{node,react,react-dom}`, `tailwindcss ^3.4`, `postcss ^8.4`, `autoprefixer ^10.4`, `eslint ^8.57`, `eslint-config-next ^14.2`.

Scripts: `dev`, `build`, `start`, `lint`, `typecheck`.

**If `create-next-app@latest` in April 2026 emits Next 15**, bump next + eslint-config-next pins to `^15.0.0`. Other pins stay compatible.

### `.gitignore`

Per `03-architect-A.md §13`. `node_modules`, `.next`, `out`, `next-env.d.ts`, `.env*.local`, logs, `.DS_Store`, `*.tsbuildinfo`. **Committed**: `_mos/`, `_theme/`, `docs/`. Guards: `_theme/*.raw`, `_theme/theme-ref.json` (future-proof).

---

## 8. Component prop interfaces — binding

Per `03-architect-A.md §11`. Key contracts:

```ts
type HeroProps = Record<string, never>
type HowItWorksProps = Record<string, never>
type FooterProps = Record<string, never>

interface SeedGeneratorProps {
  initialInput?: SeedInput       // defaults to DEFAULT_SEED_INPUT if absent
  fullBleed?: boolean            // no section chrome; used by /playground/
  input?: SeedInput              // controlled mode (HomePage)
  onInputChange?: (next: SeedInput) => void  // controlled mode pair
}
// If (input, onInputChange) are provided, component is controlled.
// Otherwise it manages its own [input, setInput] from initialInput.

interface MarkdownPreviewProps {
  content: string
  filename?: string
  language?: 'markdown' | 'toml' | 'bash'
}

interface PhaseOctopusProps {
  plan?: WavePlan                // falls back to buildWavePlan(DEFAULT_SEED_INPUT)
}

interface ArtifactTabsProps {
  seed?: GeneratedSeed           // falls back to precomputed default
}

interface PhaseCardProps {
  phase: PhaseSpec
  active?: boolean
  onHover?: (idx: number | null) => void
}

interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
  variant?: 'primary' | 'secondary' | 'ghost' | 'danger'
  size?: 'sm' | 'md' | 'lg'
  as?: 'button' | 'a'
  href?: string                  // required if as='a'
}

interface TabStripProps {
  tabs: readonly { id: string; label: string }[]
  activeTab: string
  onChange: (id: string) => void
}

interface FormFieldProps {
  spec: FormFieldSpec
  value: string
  onChange: (next: string) => void
}

interface SegmentedControlProps {
  name: string
  options: readonly { value: string; label: string }[]
  value: string
  onChange: (next: string) => void
  label?: string
  hint?: string
}

interface TierBadgeProps {
  tier: ModelTier
}

interface CodeBlockProps {
  code: string
  language?: string
  maxHeight?: string
  className?: string
}
```

**`SeedGenerator` controlled-vs-uncontrolled pattern**: if the parent passes `input` + `onInputChange`, the component defers state to parent (used by HomePage so `PhaseOctopus` can read the same `input`). If neither is passed, the component uses its own `useState(initialInput ?? DEFAULT_SEED_INPUT)` (used by `/playground/`). This stays within `useState`-only discipline.

---

## 9. End-to-end data flow — binding

Per `03-architect-B.md §3`. Summary:

1. `HomePage` mounts with `useState(DEFAULT_SEED_INPUT)`.
2. User keystroke → `onFieldChange(field, value)` → immutable `setInput` → new `input` reference.
3. `useMemo(() => compileFullSeed(input), [input])` recomputes (~3 ms).
4. `useMemo(() => buildWavePlan(input), [input])` supplies the same plan to `PhaseOctopus`.
5. Active preview tab reads `generated[activeKey]`; `MarkdownPreview` renders it inside `<pre>` + fade.
6. Copy: `copyToClipboard(generated[activeKey])` → toast.
7. Download SEED: `downloadFile('SEED-${slug}.md', generated.seedMd, 'text/markdown')`.
8. Download pack: `downloadBundle(generated, slug)` — lazy-loads JSZip, builds, downloads `specseed-${slug}.zip`.
9. Reset: `setInput(DEFAULT_SEED_INPUT)`.

---

## 10. JSZip adapter pack structure — binding (with lazy import)

```ts
// lib/buildAdapterZip.ts
import type { GeneratedSeed } from './seedSchema'

export async function buildAdapterZip(bundle: GeneratedSeed): Promise<Blob> {
  const { default: JSZip } = await import('jszip')  // lazy — saves 30 KB on initial load
  const zip = new JSZip()
  const root = zip.folder('specseed-output')!
  root.file('SEED.md',   bundle.seedMd)
  root.file('CLAUDE.md', bundle.claudeMd)
  root.file('AGENTS.md', bundle.agentsMd)
  const ca = root.folder('.claude')!.folder('agents')!
  ca.file('reviewer.md', bundle.claudeAgents.reviewer)
  ca.file('recon.md',    bundle.claudeAgents.recon)
  ca.file('tester.md',   bundle.claudeAgents.tester)
  const cx = root.folder('.codex')!
  cx.file('config.toml', bundle.codexConfig)
  const cxA = cx.folder('agents')!
  cxA.file('reviewer.toml', bundle.codexAgents.reviewer)
  cxA.file('worker.toml',   bundle.codexAgents.worker)
  root.file('macos-setup.sh',      bundle.macosSetup)
  root.file('ubuntu-bootstrap.md', bundle.ubuntuBootstrap)
  return zip.generateAsync({ type: 'blob' })
}
```

**Count audit: 11 files** under `specseed-output/`.

---

## 11. Agent / adapter file contents — binding sketches

### `.claude/agents/recon.md`

```markdown
---
name: recon
description: Session-start inventory for SpecSeed.io — file tree, deps, TODO scan.
tools: Read, Grep, Glob, Bash
model: haiku
---
You are the recon subagent. Inventory the repo. Report: file tree (2 levels), package.json scripts, open TODOs in source. No code changes.
```

### `.claude/agents/tester.md`

```markdown
---
name: tester
description: Run npm lint + build + DoD verification for SpecSeed.io.
tools: Read, Bash, Edit
model: sonnet
---
Run `npm run lint && npm run build`. Report pass/fail. On failure, extract the first 20 lines of error output and identify root file + line. Fix only lint-level issues you can resolve in a single edit; flag build errors for the orchestrator.
```

### `.claude/agents/reviewer.md`

```markdown
---
name: reviewer
description: Final pre-ship review of SpecSeed.io against _mos/ DoD. Read-only.
tools: Read, Grep, Glob
model: opus
---
You are the review agent. Compare implementation against SEED.md §5 (Octopus), §7 (Wave Plan), §11 (DoD). Return issues only. Each issue: path:line, severity (P0/P1/P2), fix suggestion. No summaries, no praise.
```

### `.claude/settings.json` — project-level

```json
{
  "permissions": {
    "allow": [
      "Read", "Write", "Edit",
      "Bash(npm:*)", "Bash(npx:*)",
      "Bash(node:*)", "Bash(ls:*)",
      "Glob", "Grep", "LS"
    ],
    "deny": [
      "Bash(curl:*)", "Bash(wget:*)", "Bash(rm -rf:*)",
      "Bash(sudo:*)"
    ]
  }
}
```

### `.codex/config.toml`

```toml
[agents]
max_threads = 6
max_depth = 1
```

### `.codex/agents/reviewer.toml`

```toml
name = "reviewer"
description = "Read-only reviewer for SpecSeed.io diffs."
model = "o3"
model_reasoning_effort = "high"
sandbox_mode = "read-only"
developer_instructions = """
Review like an owner. Prioritize: regressions, missing type safety, accessibility violations, deployment risk, missing edge cases. Return concise findings with file references and line numbers.
"""
```

### `.codex/agents/worker.toml`

```toml
name = "worker"
description = "Scoped implementation worker for SpecSeed.io."
model = "o4-mini"
model_reasoning_effort = "medium"
sandbox_mode = "workspace-write"
developer_instructions = """
Receive a single scoped task. Implement only what is specified. Do not modify files outside your scope. Do not refactor adjacent code. Report: files changed, lines added/removed, decisions made.
"""
```

---

## 12. CLAUDE.md + AGENTS.md structure

### `CLAUDE.md` (< 200 lines, hard cap)

Sections:
1. `# CLAUDE.md — SpecSeed.io` (title)
2. `## Mission` — derived from `objective`
3. `## Operating doctrine` — 5 numbered bullets (read SEED.md, explore before code, collapse phases, scoped changes, lint+build verify)
4. `## Subagents` — `@.claude/agents/{recon,tester,reviewer}.md`
5. `## Build commands` — `npm install`, `npm run dev`, `npm run build`, `npm run lint`, `npm run typecheck`
6. `## File ownership` — one-liner per top-level dir (`app/`, `components/`, `lib/`, `_mos/`, `_theme/`)
7. `## References` — `@docs/specseed-product.md`, `@docs/phase-octopus.md`, `@SEED.md`
8. `## Verification` — boilerplate lint+build + no-suppression rule

### `AGENTS.md`

Sections:
1. `# AGENTS.md — SpecSeed.io`
2. `## Purpose`
3. `## Spawning subagents` — explicit parallel spawn pattern per seed-brief
4. `## Scope boundaries` — workers single-task, reviewers read-only, environment notes
5. `## Build commands`
6. `## References`

---

## 13. Build-group execution order

Final sequence (repeated from `02-decomposition.md §4` for Phase 4 reference):

**Group A — Foundation (blocks B, C)**:
1. Run `create-next-app` (prompts: typescript, tailwind, eslint, app, no-src-dir, `@/*` alias)
2. Overwrite configs: `next.config.ts`, `tailwind.config.ts`, `tsconfig.json`, `eslint.config.mjs` (if emitted as `.eslintrc.json`, convert), `postcss.config.mjs`
3. `npm install framer-motion clsx jszip`
4. Copy fleet CSS into `app/styles/` + write bespoke CSS modules
5. Write `lib/` files in dependency order (schema → constants → formFields → wavePlan → helpers → generators → compileFullSeed → buildAdapterZip → downloadFile + clipboard + cx)
6. Write `app/globals.css` with the 5-layer import order

**Group B — Components** (depends on A):
1. Primitives (parallel): `Button`, `TabStrip`, `FormField`, `SegmentedControl`, `TierBadge`, `CodeBlock`
2. Leaf sections (parallel): `Nav`, `Footer`, `HowItWorks`, `Hero`, `PhaseCard`, `MarkdownPreview`
3. Composites: `ArtifactTabs`, `PhaseOctopus`, `SeedGenerator`

**Group C — Pages** (depends on B):
1. `app/layout.tsx`, `app/page.tsx`, `app/playground/page.tsx`

**Group D — Repo-root artifacts** (parallel with A/B/C):
1. `CLAUDE.md`, `AGENTS.md`, `README.md`, `deploy.sh`, `.gitignore`
2. `.claude/settings.json`, 3 agent .md files
3. `.codex/config.toml`, 2 agent .toml files
4. `public/robots.txt`, `public/sitemap.xml`, `public/og-image.png` (placeholder)

**Gates:**
- After A+B finish: `npm run lint` must pass (no unresolved imports).
- After C: `npm run build` must succeed and emit `out/`.
- Group D doesn't gate anything.

---

## 14. Static-export compatibility — confirmed PASS

Per `03-architect-B.md §13`. No dynamic routes, no `next/image` remote sources, no server-only APIs, no route handlers, no middleware. All client-interactive components carry `'use client'`. All DOM APIs guarded by `typeof window !== 'undefined'`.

---

## 15. Performance budget

Per `03-architect-B.md §10`:

| Package | gzipped |
|---|---|
| react + react-dom | ~45 KB |
| next runtime | ~25 KB |
| framer-motion (tree-shaken) | ~35 KB |
| jszip | **lazy** — not in initial bundle; pays ~30 KB on button click |
| clsx | ~0.5 KB |
| Our code | ~15 KB |
| **Initial first-load JS** | **~120 KB gzipped** |

**Comfortable under 200 KB budget.** Room for future additions.

---

## 16. Pre/post/invariant contracts — binding

Per `03-architect-B.md §2`:

| function | hardest-to-verify invariant |
|---|---|
| `compileFullSeed` | Same input → byte-for-byte same output (twice). Every string ends with `\n`. No literal `undefined`/`null` in any string. |
| `generateSeed` | Exactly 11 `## ` sections. Starts with `# SpecSeed: ${projectName}\n`. |
| `generateClaudeMd` | `result.split('\n').length < 200`. 7 H2 sections. |
| `generateCodexAgent` | Valid TOML. Double-quoted strings. Multi-line uses `"""…"""`. |
| `generateClaudeAgent` | Valid YAML frontmatter. Tools comma-separated (not YAML list). |
| `buildWavePlan` | `workerCap ∈ [1,12]`. 9 phases in order. Phase 4 `workerCount === workerCap`. Phases 2,3 `workerCount === 2`. Others = 1. |
| `copyToClipboard` | Fallback textarea always removed. Never throws during normal browser operation in secure context. |
| `downloadFile` | Object URL always revoked. SSR no-op. |

Phase 6 tests encode these as assertions.

---

## 17. Phase 5 Wire checks (preview)

10 checks from `03-architect-B.md §12`. Phase 5 walks these manually after Phase 4 Build completes. Summary: load, field-change propagation, all 4 actions fire, `/playground/` resolves, crimson focus visible, reset restores.

---

## 18. Open items deferred

**Not in MVP — flagged for potential future work (not Phase 4 blockers):**

- Scroll-spy nav active-state (Decomposer A flag #7).
- Accordion fallback for ArtifactTabs on mobile if horizontal scroll proves bad UX (Decomposer A flag #4 interpretation).
- `input.environment`-driven conditional generation of OS adapters (v2 polish).
- `.codex/config.toml` `max_threads` = live `workerCap` (v2 enhancement; MVP uses constant 6).

---

## Definition of "Phase 3 done"

- [x] Complete file tree locked
- [x] All TypeScript interfaces locked (`seedSchema.ts` source-ready)
- [x] All configuration file contents locked (`next.config.ts`, `tailwind.config.ts`, `tsconfig.json`, `eslint.config.mjs`, `postcss.config.mjs`)
- [x] All lib function signatures locked
- [x] All component prop contracts locked
- [x] Build-group execution order locked
- [x] JSZip structure + lazy-import decision locked
- [x] Agent/adapter file structures locked
- [x] CLAUDE.md / AGENTS.md skeletons locked (< 200-line cap)
- [x] Performance budget confirmed under 200 KB gz
- [x] Static-export compatibility confirmed

**READY for Phase 4 Build.**

---

*CC-OPS-SPECSEED — Root collapse of Phase 3*
