# NOTES.md — running memory for the 20-concept slate run

## Setup (session start)
- Live site recon: current tpengdesign.com is the "small room" gallery — a white-cube photo
  hero, letterspaced serif labels, all work gated behind scroll. Nothing visible at t=0.
  Every concept here must beat that on immediacy, per the brief's t=0 rule.
- verify-slate.sh gate decoded: 20 concept dirs, each serving >2000 bytes at
  /concepts/<slug>/, index serving at /, four non-empty md files, ≥20 `- ` bullets in
  registry.md. Server: python3 http.server on 127.0.0.1:8078, started in background.
- Playwright CLI 1.61.1 works headless on this box (tested against live site) — builders
  and judges can screenshot their own work. chrome-devtools MCP avoided (SIGTRAPs on VPS).
- Box has 16 cores; concurrency will be enforced at ≤8 via a semaphore in the workflow
  script, not left to the default pool cap (14).

## Architecture decisions (ambiguity calls, per the autonomy clause)
- Isolation model: one fresh Workflow subagent per concept; builders receive only the
  content pack + font menu + their own principle. They never read concepts/ siblings.
- Principle claiming: 20 sequential proposal agents, each fresh, each shown ONLY the
  one-line principles claimed so far (that is exactly what registry.md exists for).
  Sequential claiming makes collisions structurally rare instead of policed after the fact.
  Registry is materialized to registry.md by the orchestrator after the claim phase —
  equivalent outcome to builders appending it themselves, without 20-way file-write races.
- Blind judging: a fresh judge per concept gets ONLY the slug + URL — no principle, no
  builder identity, no sibling list. Coverage-first rubric (report every flaw w/ severity),
  pass bar at 7/10. Fail → one rebuild by a fresh agent that gets the principle + judge
  criticisms but is forbidden from opening the failed index.html (true fresh start).
- CONTENT-GAPS.md: builders RETURN invented copy in structured output; orchestrator
  aggregates. Avoids concurrent-append corruption on a shared file.
- Fonts: since concepts must be $0/no-CDN, a shared self-hosted font menu (~15 OFL
  families, woff2, variable where possible) is downloaded once into assets/fonts/ during
  the content-pack phase. Builders pick from the menu or use system stacks.
- Model routing: builders = Sonnet 5 @ xhigh effort (taste-driven build), judges = Sonnet 5
  (first Sonnet tier with high-res vision), proposals = Sonnet 5. Orchestration + SLATE.md
  conviction ordering = main loop.

## Run 2 (build run) — deviations & calls
- Model routing OVERRIDE: operator set this session to Fable 5 (/model) before the build
  run — a deliberate signal, since Fable is the design model. Builders and principle
  proposals now run on Fable 5; judges stay Sonnet 5 (vision). Everything else in the
  Run 1 architecture is kept as written.
- Rebuild mechanics: a rebuild agent cannot overwrite a file it hasn't read (Write-tool
  rule), so rebuilders `rm` the failed index.html first, then write fresh — preserving
  the "never sees the failed output" guarantee literally.
- Attempt cap: 3 build attempts per concept inside the workflow; any concept still under
  the 7/10 bar after 3 gets escalated to the main loop rather than looping forever.
- 2026-07-10 ~20:00 UTC: plan-pool session limit hit mid-run (resets 09:00 UTC 07-11).
  Survived: all 20 claims + registry.md + 4 fully-returned builds (itemized-invoice,
  job-jacket-stack, riveted-fan-deck, shelf-planogram — kept on disk, results cached in
  the workflow journal). 5 partially-written concept dirs (builder died before returning,
  invented-copy log lost) were DELETED so their attempt-1 builders restart clean:
  back-matter-index, bilingual-facing-pages, seven-line-transit, unfolded-dieline,
  untrimmed-press-sheet. Auto-resume scheduled for ~09:02 UTC via workflow resume cache
  (resumeFromRunId wf_492a8181-30a). Plan-auth-only rule respected — no paid-API fallback.
- 2026-07-11 01:42 UTC: pool recovered early (5-hour window rollover, not the 09:00 hard
  reset) — confirmed by a one-word Haiku probe. Timer cancelled, workflow resumed from
  cache ~7h ahead of schedule.
- 2026-07-11 22:11 UTC: resumed run hit a Fable 5 usage-limit (distinct from the earlier
  session limit) after finishing all attempts. Final: 14/20 passed blind judge (≥7/10).
  6 exhausted all 3 rebuild attempts without clearing the bar: seven-line-transit (6),
  contact-sheet-loupe (6), carousel-slide-talk (6), paint-by-numbers (6), flat-pack-manual
  (5), tasting-menu (5). Paused per operator request to review before deciding whether to
  re-roll these 6 with fresh principles or push more rebuild attempts.
- 2026-07-11 22:11 UTC: operator's browser couldn't reach 127.0.0.1:8078 (loopback-only,
  and the session runs on the VPS, not the operator's machine — expected, brief's server
  was only ever reachable from tool calls inside this session). Operator asked for a
  thomaspeng.ca subdomain instead. Added slate.thomaspeng.ca via a new Caddy site block
  (/etc/caddy/sites/personal/slate.caddy, follows the reviews.caddy pattern: plain
  file_server browse + noindex header, no systemd unit — pure static, no app process
  needed) pointed directly at the slate dir root, bypassing the python http.server
  entirely. Validated with `caddy validate` before reload; TLS cert auto-issued via
  existing wildcard-routed ACME on reload. Does not touch tpengdesign.com's own Caddy
  block or the live site, per the original constraint.
