# Session 0060.0 — Transcript

> Date: 2026-06-01
> Start: 2026-06-01T06-30 (PST implied)
> Goal: launch-app **Slice 2** — correct the SPEC against the extracted
> engine, build the `deployment.toml` schema + fail-closed `validate` verb
> (SPEC §5.3), and author the `define-deployment` skill (§6.6). Pre-prod,
> single environment.
>
> Outcome: **All Slice 2 deliverables shipped and MERGED.**
> `wiggleverse/engineering` PR #3 (SPEC v0.0.2 + `define-deployment` skill +
> ROADMAP close) → merged `914bf74`. `flotilla-core` extended to **v0.3.0**
> (`scaffold` / fail-closed `validate` / reconciling `import` +
> `gcloud.describe_config`) → PR #1 merged `4841361`, **371 tests green**.
> Dogfood produced + validated `wiggle-snip/deployment.toml`. The session
> also **created the `wiggleverse/flotilla-core` Gitea repo** (operator) and
> **integrated a live collision** with a parallel preview-environments line.
> **Post-publish addendum:** also merged the Slice-1 OHM shim
> (`ohm-rfc-app-flotilla` → thin shim over flotilla-core, PR #4 → `1319fd7`)
> and pinned its dependency to the released **flotilla-core v0.3.0** (tagged) —
> this transcript was re-finalized for that OHM-material work.
>
> Highlights:
> - Spec-leads-code done literally: the SPEC correction landed as its **own
>   commit** before any verb was built (`43bfa93`, guide §3.2).
> - Discovered a **parallel session actively building preview-environments**
>   in flotilla-core's main checkout → isolated all work in a git **worktree**
>   (guide §5.4 / memory). That call paid off: the two lines collided on a
>   shared `v0.2.0`; the worktree let the rebase-to-`v0.3.0` be clean.
> - The §8.3 secrets rule held mechanically end to end — the Gitea bot token
>   was used (to drive PRs via the API) **without a single secret byte
>   entering the session**: fetched into a shell var, never echoed.

---

## Launch prompt

```
# launch-app Slice 2 — deployment.toml schema + define-deployment (SPEC §5, §6.6)

Slice 1 is done and verified: flotilla-core v0.1.0 is extracted at
~/projects/wiggleverse/flotilla-core (315 tests green), ohm-rfc-app-flotilla is a
thin shim over it (v1.8.0, branch slice1-extract-flotilla-core pushed, PR open,
NOT yet merged), and OHM re-deploys through the core unchanged (live DB + pin
0.31.3 + 8 secret refs + live /api/health 200 all proven).

## Task
1. FIRST correct the SPEC per SLICE-1-SPEC-FEEDBACK.md (its own commit, guide §3.2).
2. Firm up the §5.1 schema and build the fail-closed `validate` verb (§5.3).
3. Build `define-deployment`: the topology+names interview deriving from the One
   Name (§3.3), emitting + validating the record per the §8 UX contract. NEVER ask
   for secret bytes (§8.3).

## Tests
- Each §5.3 rule rejects a crafted-bad record with the right message.
- A good record validates and round-trips through flotilla-core's loader.
- Dogfood: define-deployment produces a valid deployment.toml for wiggle-snip.

## Scope guard
Pre-prod, single environment. NO slots/ramp/promote/rollback/compat-gate.

## Process
Spec-driven, cite section numbers in commits; branch + PR (Gitea, no gh CLI).
Hard secrets rule (SPEC §8.3): stdin-piped gestures only. Test run of our own
tooling — do NOT publish a transcript unless I say so.
```

> Note on the transcript: the launch prompt said "do NOT publish a transcript
> unless I say so." Mid-session the operator said to publish — hence this file.

---

## Pre-session state

- **launch-app suite** (`~/projects/wiggleverse/engineering/launch-app/`):
  SPEC v0.0.1 + ROADMAP + `SLICE-1-SPEC-FEEDBACK.md` existed locally but were
  **never committed** (the `engineering` repo tracked only the top-level
  handbook `README.md`).
- **flotilla-core** (`~/projects/wiggleverse/flotilla-core`): v0.1.0 at commit
  `cf22fc8` (315 tests). **No git remote.** Its main working tree carried
  **uncommitted preview-environments WIP** (`health.py`, `registry.py`,
  `009_previews.sql`) — a parallel effort.
- **wiggle-snip** (`~/projects/wiggleverse/wiggle-snip`): the §5.1 happy-path
  fixture; built + tested; **not a git repo**; no `deployment.toml`; no GCP
  foundation yet. Needs only `DATABASE_PATH`; no secrets (URL shortener).
- **`scaffold-gcp-project`** skill exists; no other launch-app skill existed.

---

## Turn-by-turn arc

### Arc 1 — Read the contract before touching code

Read SPEC, ROADMAP, `SLICE-1-SPEC-FEEDBACK.md`, the engineering guide, and the
extracted engine (`deployment_toml.py`, `registry.py`, `cli.py`, `context.py`,
`gcloud.py`, `secrets.py`, `plan.py`, conftest) plus the wiggle-snip fixture and
the `scaffold-gcp-project` skill (to mirror skill conventions). Settled the
build shape: the schema + `validate` + `scaffold` are **testable flotilla-core
code**; `define-deployment` is a **skill** that drives those verbs.

### Arc 2 — Correct the SPEC FIRST (its own commit, guide §3.2)

Baseline-committed the un-tracked Slice-1 artifacts (`330d879`) so the
correction would land as a clean diff, then made the **SPEC v0.0.2**
correction (`43bfa93`) settling all of `SLICE-1-SPEC-FEEDBACK`:

- **§5.2** — config (`deployment.toml`) vs the engine's separate local **state
  store** (deploy history / health snapshots / the §8.3 deploy lock). The toml
  is config-only; that state is never in it and never reconstructable from it.
- **§3.2.1** — the canonicity fork settled: **toml-canonical** for new apps,
  the registry a reconcilable cache; OHM stays grandfathered registry-canonical.
- **§5.1** — added `[app].gitea_host` + optional `[app].gitea_read_secret_ref`
  (a private-repo read credential — a reference, never bytes); §5.2.1 states the
  single-repo assumption (OHM's pin/source/content split is grandfathered).
- **§5.3** — the `vm.project == gcloud_config-project` check needs a NEW
  read-only `gcloud config configurations describe`; **PASS/WARN/FAIL**
  outcomes; §5.3.1 scopes `validate` to define-deployment-authored records.
- **§7.1** — "operator-CLI engine", not "9-phase deploy engine".

Verified the `gcloud config configurations describe <name> --format=json` shape
is read-only **before** depending on it: it returns `properties.core.project`
and the on-disk active-config pointer (`benstull-infra`) stayed put.

### Arc 3 — A parallel session is live → isolate in a worktree

On branching flotilla-core, found **uncommitted preview-environments WIP** in
the main tree — and on re-checking minutes later it had **grown** (now
`cloudrun.py`, `preview.py`, `CHANGELOG.md`, a `VERSION`/`pyproject` bump):
a **parallel session was actively building** there. Deleted the entangled
branch and moved all Slice 2 work into an **isolated git worktree**
(`~/projects/wiggleverse/flotilla-core-slice2`, branched from `cf22fc8`, own
venv) per guide §5.4 / the worktree-for-parallel-git memory. Only read-only git
was ever run in the shared main checkout thereafter.

### Arc 4 — Build flotilla-core v0.2.0 (the mechanical core)

- `gcloud.describe_config()` / `config_project()` — the read-only project read,
  injectable (a `GcloudRunner`) so tests exercise it with no real gcloud;
  unreadable → a `GcloudReadError` the validator renders as **WARN**.
- `deployment_toml.scaffold()` — derive a full §5.1 record from the One Name
  (§3.3). Mechanical §8.3 guard: refuses any `--secret-ref` /
  `gitea_read_secret_ref` that doesn't match the `<project>/<id>[@version]`
  reference shape, so the emitter can never write secret bytes.
- `deployment_toml.validate()` — the §5.3 fail-closed checks, each PASS/WARN/FAIL
  + remediation; only a FAIL blocks. (`_is_under` uses path-segment containment
  so `/opt/x-evil` is correctly **not** under `/opt/x`.)
- `sync_to_registry(reconcile=…)` — toml-canonical (§3.2.1): re-import updates
  the row in place and prunes overlay/secret keys the toml dropped.
- CLI verbs `deployment scaffold | validate | import`.

**Dead end (kept, honest):** the first commit attempt used `git commit -m '…'`
with a message containing "the §5.1 schema's own verbs" — the apostrophe in
"schema's" closed the single quote and zsh tried to run the backticks/`>` in the
rest as shell. Switched to `git commit -F <file>` for every multi-line message
after. Committed as `a9a4983` (v0.2.0).

### Arc 5 — Tests + dogfood

28 new tests: each §5.3 rule rejects a crafted-bad record with its message; a
good scaffolded record validates + round-trips through the loader; reconcile
prunes; CLI exit codes. **Full suite 343 passed.** Then ran the real
`define-deployment` gesture against wiggle-snip → `deployment.toml` validates
(5 PASS, 1 expected WARN: its gcloud config doesn't exist until Slice 3/5) →
`import` → `deployment show` → 9-phase plan assembly. Surfaced one friction note
(scaffold always emits `APP_URL`, which wiggle-snip doesn't consume → Slice-5
backlog).

### Arc 6 — The `define-deployment` skill (§6.6)

Authored `launch-app/skills/define-deployment/SKILL.md`: probe → confirm the One
Name → ask the non-derivable choices → scaffold → validate → explain → import.
Hard §8.3 rule throughout — records secret **references** only, hands the
operator the stdin-piped `secret set` gesture, never asks for a value. Committed
`c47386e` with the ROADMAP Slice 2 close + next-session brief.

### Arc 7 — Ship it (PRs over the Gitea API, secrets-safe)

Pushed the `engineering` branch (SSH). The operator had asked for "branch + PR".
Rather than hand back a URL, drove the PR via the Gitea API — fetching the
`ohm-rfc-app-gitea-bot-token` into a shell variable that was **never echoed**
(no secret byte in the session, §8.3). Confirmed the bot has admin/push on
`wiggleverse/engineering`, opened **PR #3**, and (operator-approved) **merged**
it → `914bf74`; synced local `main`.

### Arc 8 — flotilla-core repo creation: a real wall

The flotilla-core repo had no remote. Tried to create `wiggleverse/flotilla-core`
via the API with the bot token → **403** (the bot lacks org repo-create). Tried
SSH push-to-create → **"Push to create is not enabled for organizations."** So
repo creation was genuinely operator-only. Pre-set the `origin` remote so the
push would just work once it existed, and handed the operator the one manual
step. Recorded the concurrent-lines hazard + likely **v0.2.0 collision** in
memory.

### Arc 9 — Operator created the repo; push + the collision

Operator created `wiggleverse/flotilla-core` (private). Their manual push failed
only because pasted `# cf22fc8` comments were read as refspecs; pushed `main` +
`slice2-schema-validate` from the session instead. Opened **PR #1** — but it came
back **`mergeable: False`**. Root cause: the **parallel preview-environments line
had pushed straight to `main`** as `333e0ff` (also tagged "v0.2.0") in the gap.
The two lines had diverged from `cf22fc8` — the predicted collision, live.

### Arc 10 — Integrate: rebase to v0.3.0, prove coexistence

Measured the conflict surface: only `VERSION`, `pyproject.toml`, `cli.py`
(`registry.py`/`health.py` were preview-only — no overlap). Rebased the Slice 2
branch onto the new `main` in the worktree; `cli.py` **auto-merged cleanly**
(both the `preview` command group and the `deployment scaffold|validate|import`
verbs present); resolved `VERSION`/`pyproject` to **v0.3.0** (deconflicting the
duplicate 0.2.0). Reinstalled + ran the **combined** suite (preview tests + mine):
**371 passed.** Amended the commit to v0.3.0 (`9b15b2a`), force-pushed (updated
PR #1), confirmed **`mergeable: True`**, and — operator-asked — **merged** PR #1
→ `4841361`. Deliberately did **not** `git pull` the shared main checkout (the
parallel session has uncommitted work there; its next pull picks up the merge).

### Arc 11 — Publish (this transcript)

Operator asked to publish a transcript. Claimed **0060** via
`claim-session-id.sh`, finalized this file, gave the next-session handoff in
chat, and published (`4b324e4`; `sessions.json` title set).

### Arc 12 — Post-publish: merge the OHM shim + pin its dep (re-finalize)

Operator asked how to do follow-up #2 (merge `slice1-extract-flotilla-core`) and
chose "merge + pin the dep." Findings: there was **no open PR** (launch prompt
stale), the branch was a clean 1-commit FF onto `main`, and the local
`ohm-rfc-app-flotilla` checkout was on `feat/preview-environments` with the
**parallel session's uncommitted work** — so all git went through an **isolated
worktree** + the **API** (no local-checkout disruption). The honest catch on
"pin the dep": flotilla-core is a **private, index-less** repo, so a hard
git-URL pin would break the shim's CI runner (no auth) — so the pin was the safe,
faithful form: **tagged flotilla-core `v0.3.0`**, bumped the shim's floor
`>=0.1.0 → >=0.3.0`, and documented the published git source (laptop deploys have
it installed; CI installability of the private dep is a tracked follow-up).
Opened + merged **PR #4** (`ohm-rfc-app-flotilla` → thin shim, `1319fd7`). This
is OHM-material, so the transcript was **re-finalized** (this arc) and
republished.

---

## Cross-references

- **`wiggleverse/engineering`** — PR #3 MERGED `914bf74`. Commits: `330d879`
  (baseline Slice-1 artifacts), `43bfa93` (SPEC v0.0.2 correction), `c47386e`
  (define-deployment skill + ROADMAP close). SPEC now **v0.0.2**.
- **`wiggleverse/flotilla-core`** — repo created (private), PR #1 MERGED
  `4841361`. Now **v0.3.0** (`9b15b2a` rebased atop the preview line `333e0ff`).
  Worktree at `~/projects/wiggleverse/flotilla-core-slice2` (branch deleted on
  remote post-merge; safe to remove). **371 tests green.**
  Tagged **`v0.3.0`** (`a602112`/`4841361`) for the shim to pin against.
- **`wiggleverse/ohm-rfc-app-flotilla`** — PR #4 MERGED `1319fd7`: the Slice-1
  thin-shim (`8c03538`, v1.8.0) + the dep pin to flotilla-core `>=0.3.0`
  (`90a613b`). Done via an isolated worktree + the API (the local checkout was
  mid-parallel-work on `feat/preview-environments`).
- **wiggle-snip** — `deployment.toml` generated + validated (not a git repo).
- **Parallel line** — preview-environments (`feat/preview-environments` + the
  WIP that became `333e0ff` on flotilla-core main) is a separate, still-active
  effort. No OHM **deploy**, no `ohm-rfc` / §13 edit happened this session — the
  only OHM-material change was the shim merge (Arc 12), which alters how OHM's
  operator CLI is packaged, not the live deployment.

---

## Session close

Stopped here at the operator's call — Slice 2 shipped + merged across three
repos, the OHM shim merged + dep-pinned (Arc 12), and `flotilla-core` tagged
`v0.3.0`. **Done this session:** Slice 2 (engineering #3, flotilla-core #1), the
shim merge (former follow-up #c), and the dep pin to v0.3.0 (part of #b). No live
OHM deploy. The next-session launch prompt below is the closing handoff.

## Next-session prompt

```
# launch-app Slice 3 — provision-vm + scaffold-gitea-repos (SPEC §2, §6.7, §6.8)

## State (after Slice 2 / session 0060, 2026-06-01)
- launch-app SPEC is v0.0.2; ROADMAP Slice 2 closed.
- Skills exist: scaffold-gcp-project (§6.5), define-deployment (§6.6,
  ~/projects/wiggleverse/engineering/launch-app/skills/define-deployment/).
- flotilla-core v0.3.0 on wiggleverse/flotilla-core main (private, tagged
  v0.3.0): deployment scaffold|validate|import + gcloud.describe_config, 371
  tests green. It sits ATOP a parallel preview-environments line (still active).
- ohm-rfc-app-flotilla main is the v1.8.0 thin shim, dep pinned flotilla-core>=0.3.0.
- wiggle-snip (~/projects/wiggleverse/wiggle-snip, NOT a git repo) has a
  validated deployment.toml. The §5.3 `validate` gate is built + proven.

## Read first
- SPEC: ~/projects/wiggleverse/engineering/launch-app/SPEC.md (§2 topology, §6.7
  provision-vm, §6.8 scaffold-gitea-repos)
- ROADMAP: same dir, Slice 3
- Session 0060 transcript (wiggleverse/ohm-session-history, 0060/) for context.

## Task
1. wiggle-snip has no GCP foundation yet — run scaffold-gcp-project for it FIRST
   (clears the one dogfood WARN and gives provision-vm a project to target).
2. Build `provision-vm` (§6.7): create the micro VM (IAP-only, no public :22),
   install the runtime (Python, Node, nginx, systemd unit), TLS via Cloudflare.
   Idempotent / re-runnable. It gates on `flotilla-core deployment validate`.
3. Build `scaffold-gitea-repos` (§6.8): the repo set + bot user/token; record
   whether pre-prod uses its own Gitea or shares.
4. Proof: a fresh micro VM comes up, /api/health reachable through nginx after a
   hand-run deploy, re-running the skill is a no-op.

## Constraints
- Scope: pre-prod, single environment. NO slots/ramp/promote/rollback (guide §10).
- Hard secrets rule (SPEC §8.3): stdin-piped `secret set` gestures only; NEVER
  ask for secret bytes.
- gcloud isolation: pin CLOUDSDK_ACTIVE_CONFIG_NAME per-process; never touch the
  shared on-disk active-config pointer.
- A parallel preview-environments line shares flotilla-core — if you touch that
  repo, use an isolated git worktree; never run mutating git in a checkout the
  parallel session holds.
- Spec-driven; cite section numbers in commits; branch + PR (Gitea, no gh CLI).

## Open follow-ups (pick up if relevant, not blocking)
- CI installability of the private flotilla-core for the shim's runner
  (SSH/token wiring or a package index).
- Add flotilla-core to the Patchwatch runner build context before its rebuild.
- Install/symlink the launch-app skills so they're invocable.
- Slice-5 backlog: define-deployment's scaffold emits an unused APP_URL overlay
  key by default — make derived-but-optional overlay keys a choice.
```
