# SESSION-0011.0 — BDD planner project management (create/edit/retire) + the "no data" red herring

**Date:** 2026-06-02
**Driver:** Ben (ben@wiggleverse.org)
**Repos touched:** `wiggleverse-ecomm-bdd-release-planner-app` (impl, branch
`project-management` → merged `main`), plus Claude memory and this transcript in
`wiggleverse-ecomm-meta`. `…-app-flotilla` was *invoked* for the deploy but not
modified.
**Outcome:** Project management shipped — projects are now created/edited/retired
from the UI, with the `project` table as the runtime source of truth. Merged to
`main` (`34bd824`), deployed to `planner-vm`, migration applied, verified live on
`rfc.wiggleverse.org`. The reported "no data" turned out to be a stale browser
cache, not data loss.

Transcript-honest per the engineering guide — the wrong turn is included.

---

## What happened (in order)

1. **"Why is there no data in the bdd tool?"** Investigated prod and found the DB
   was *fully intact* — `/api/health` reported 1238 scenarios; SSH into
   `planner-vm` confirmed 1238 scenarios all tagged `ecomm-specs`, the `project`
   row present, 26 releases. So this was a serving/display problem, not missing
   data. **WRONG TURN (instructive):** I went deep into token/routing forensics —
   the token-scoped API 404'd for me because `var/access_token`
   (`THTwLxuPL6eReqzu7kpvTFMY`, 24 chars) ≠ the live `PLANNER_TOKEN` from
   `/opt/planner/backend/.env` (15 chars); routes mount under the env token, and
   the file is just a stale unused fallback (NOT a bug). With the real token the
   API returned all 1238 scenarios. I then noticed the *local* dev DB was stale
   (1135, pre-`0003` schema). Before I could conclude, Ben: **"Oh nevermind — I
   had to hard-refresh."** Root cause = a stale cached SPA in the browser. Lesson:
   for "UI shows nothing but health is green," check the browser cache *first*.

2. **"We'll need a way to create and manage projects and their settings"**
   (configure backing repo, friendly name, retire so it drops from the dropdown).
   Explored the registry model and surfaced the core tension: `projects.json`
   (committed in the app repo) was the source of truth, reconciled into the
   `project` table on every ingest *and* driving the ingest loop via
   `--list-clones`. Asked the one decision that determines the whole design —
   **DB-authoritative** vs **git-backed write-through**. Ben chose
   **DB-authoritative** (matches what the code comments already claimed the intent
   was). Built on branch `project-management`:
   - migration **`0004_project_status.sql`** — `project.status` (`active`|`retired`)
     for soft-retire (keeps scenarios + releases; just hides from the dropdown and
     the ingest loop; reversible).
   - `tools/ingest.py` — `reconcile_projects` is now **seed-only**
     (`ON CONFLICT DO NOTHING`, never clobbers UI edits); `--list-clones` reads
     **active** projects **from the DB** (+ a 4th `gitea_repo` column) instead of
     `projects.json`, so UI-created projects ingest and retired ones are skipped.
   - `backend/app/projects.py` — validated `create_project` / `update_project`
     (+ `ProjectError`); **slug is immutable** (PK + URL + tags every scenario).
   - `backend/app/main.py` — hub endpoints `POST /<token>/api/projects` and
     `PATCH /<token>/api/projects/{slug}` (status changes go through PATCH); both
     touch the ingest trigger.
   - `deploy/refresh.sh` — **auto-clones** a new project's repo on first sight
     (token inlined per-call, never persisted); new env `PLANNER_GITEA_BASE`
     (defaults `https://git.wiggleverse.org`, so no `.env` change strictly needed).
   - frontend (`App.tsx`/`api.ts`/`styles.css`) — ⚙ manage-projects modal: new
     project form, inline edit, retire/unretire; dropdown shows active only.
   - **47 backend tests** (13 new: CRUD, validation, slug immutability, retire
     hides from default list, reconcile no-clobber, `--list-clones` reads DB),
     frontend build clean. **Browser-verified** the full create→appears-in-dropdown
     →retire→drops-from-dropdown flow against a migrated local stack.

3. **"yes, do both"** (commit + deploy). Committed `34bd824`, ff-merged
   `project-management` → `main`, pushed. `flotilla deploy` — **10 phases green**,
   `/api/health` ok. Then the known gotcha: **migration 0004 is applied by ingest,
   NOT web startup** — ran `systemctl start planner-ingest.service` on the VM to
   apply it (`schema_migration` now lists `0004`; `project.status='active'`).
   Verified live: `GET /api/projects` returns `status`; bad slug → **422**;
   `?include_retired=true` → **200**. (macOS deploy note still applies:
   `SSL_CERT_FILE=$(python3 -m certifi)` for the phase-9 health check.)

4. **`/finalize`.** App repo clean + synced. Deleted merged branch
   `project-management` (local + remote). Tried to also drop the stale local
   `release-plan-import` (merged to main, 0 unique commits) — the harness blocked
   `git branch -D`, so it's **left in place** (harmless; `-D` it manually anytime).
   Memory updated. Then this transcript.

5. **"update your transcript."** Wrote this file — then **misread the meta branch
   posture** and pushed SESSION-0011 onto `main`, which was stale at SESSION-0008.
   The two latest transcripts (0009/0010) + a "Replan v2" `RELEASE-PLAN.md` change
   were on a **local-only, never-pushed** branch `replan-v2-resequence`, so main
   and that branch had forked. Caught it before doing more damage, surfaced it,
   got Ben's call (**merge, not force-push**), merged `replan-v2-resequence` →
   `main` (`--no-ff`, no conflicts) so main is the complete line (…0008 →
   Replan-v2 → 0009 → 0010 → 0011), pushed `4489ae8`, deleted the now-redundant
   branch. Then updated this transcript with this very episode. LESSON: keep
   transcript commits on `main` — 0009/0010 forked precisely because they were
   committed to a feature branch that never merged/pushed; verify branch posture
   (which side is ahead) before committing, don't assume.

---

## State at wrap

| Repo | Branch | State |
|---|---|---|
| `…-bdd-release-planner-app` | `main` | `34bd824` pushed + **deployed** — project management live; migration 0004 applied on VM |
| `wiggleverse-ecomm-meta` | `main` | `4489ae8` pushed — transcripts 0001–0011 + Replan-v2 reconciled onto main (forked local branch merged, then deleted) |
| `wiggleverse-ecomm` | `r01-store-settings` | unchanged this session (R03 still committed `5b3e946`, unmerged) |
| `…-app-flotilla` | `main` | unchanged (only invoked for deploy) |

## Next session

**Recommended — add OHM as a real project** (first real use of the new UI + the
auto-clone path in prod): create the `ohm` project via the ⚙ modal pointing at its
gitea meta repo + corpus subpath, confirm `refresh.sh` auto-clones + ingests it,
verify it shows in the dropdown with scenarios, and decide how its corpus is
populated (paste vs an existing spec dir). While in that GCP project, fix the
lingering ADC quota-project pin: `gcloud auth application-default
set-quota-project wiggleverse-ecomm-bdd-app`.

**Alternative — back to product:** R04 (Product create & lifecycle) per the BDD
release plan; read `ecomm-real-build.md` + `ecomm-bdd-release-planner.md` first.

**Open follow-ups (carried):** migrate the planner off bespoke `planner_flotilla`
onto flotilla-core; planner cert auto-renewal switched to the nginx authenticator
(fine, watch ~Aug 29); re-verify R03 OHM citations when `ohm.wiggleverse.org` is
reachable.
