reshape: move OHM transcripts under ohm/ for org-wide multi-app layout; add org-wide root README

This commit is contained in:
2026-06-03 06:54:38 -07:00
parent bd21825bc2
commit 3713299f08
73 changed files with 200 additions and 181 deletions
@@ -0,0 +1,228 @@
# Session 0028.0 — Transcript
> Date: 2026-05-28
> Start: 2026-05-28T14-05 (PST implied)
> End: 2026-05-28T14-32 (PST implied)
> Subject: flotilla v1.2.0 — deploy robustness + record-maintenance verbs (PR, not merged)
> Status: **FINALIZED.**
---
## Plan
**Item picked:** flotilla **v1.2.0** — deploy-robustness + record-maintenance
verbs (the §19.2 infra candidate surfaced by Session 0022). Pure-flotilla,
touches no rfc-app code → zero collision with the in-flight rfc-app feature
sessions 0026/0027. No OHM deploy, no version-slot contention, no secret bytes.
Working on branch `session-0028/flotilla-v1.2.0`; shipping as a **PR** (operator
merges + tags — per the "let's use branches and PRs" directive this session).
Deliverables:
1. **Preflight SSH-failure disambiguation** (deploy.py phase 2). Today any
non-zero `test -d <install>` is reported "install dir missing" — but a
`gcloud compute ssh` connection/auth/IAP failure also returns non-zero,
so a connectivity failure is misreported as a missing dir (deploy.py:355).
Fix: a connectivity probe runs first; its failure reports the real cause.
2. **SshError → clean phase failure.** `_PhaseRunner.run` only catches
`_PhaseFailure`; an `ssh.SshError` (e.g. a restart SSH timeout) propagates
and leaves the `deploys` row stuck `in_progress` holding the §8.3 lock.
Catch it, record a phase failure, finalize the row.
3. **SSE pre-drain restart** (phase 7). Replace `systemctl restart` with a
flotilla-controlled stop (SIGTERM → bounded drain window → SIGKILL fallback
for lingering SSE keepalive streams) → start. Bounds the window flotilla
waits regardless of the unit's TimeoutStopSec. This is the v0.6.0 (Session
0009/"I") failure made un-reproducible from the flotilla side. A graceful
app-cooperative drain endpoint in rfc-app stays a future §19.2 candidate.
4. **`flotilla deployment update`** verb (registry + CLI) — update mutable
record fields without remove+add. Motivated by the #1 VM rename.
5. **`flotilla deploy reconcile`** verb — probe `/api/health` and reconcile the
deploy log to reality: finalize a stuck `in_progress` row as `succeeded`
when health confirms the target version (releases the lock); honestly report
terminal rows health contradicts without falsifying the audit trail.
Each lands with unit tests (no network — the deploy seams are DI'd). CHANGELOG
1.2.0 + VERSION/pyproject bump. Transcript finalized + published LAST.
Parallel context at claim: sessions 0026 + 0027 also in-progress (launch
prompts not captured in their placeholders). flotilla-only scope chosen
specifically to stay disjoint from whatever rfc-app surfaces they touch.
---
## Friction log
- **14:09 — shared-working-directory collision.** Branches alone don't
isolate concurrent sessions: git tracks one working tree per checkout.
Shortly after I branched in the canonical flotilla dir, another live
session (0026 or 0027) wrote `ohm_rfc_app_flotilla/deploy.py` +
`tests/test_deploy.py` in the **same** directory (a secret-redaction
hardening, "finding L1"). Their files overlap exactly with mine
(`_PhaseRunner`, phase details). Editing in place would corrupt both
sessions' work. Resolution: restored the shared dir to `main` with their
unstaged edits preserved, then created a **manual git worktree** at
`…/ohm-rfc-app-flotilla-s0028` on my branch with its own fresh venv
(`pip install -e .[test]`; the canonical `.venv`'s PEP 660 editable
finder is pinned to the shared dir, so a shared venv would defeat
isolation). Worktree baseline: 157 tests green on clean `c26f251`.
**Handoff implication:** parallel flotilla sessions MUST each take a
worktree; the operator's "branches and PRs" guidance needs the worktree
step to actually isolate. Their redaction change and my v1.2.0 change
both touch `deploy.py` → expect a merge conflict in `_PhaseRunner` when
the second PR merges; resolvable (different concerns: they redact phase
detail, I add an `SshError` branch + DI redactor coexist cleanly).
## Launch prompt
You are an OHM roadmap driver session, running in parallel with others.
Claim session ID first. STATE (end of 0022): OHM live at rfc-app v0.24.0 on
the renamed VM `ohm-rfc-app`; deploys unblocked. Pick ONE disjoint roadmap
item. Strong infra candidate: flotilla v1.2.0 — fix the preflight that
misreports an SSH/auth failure as "install dir missing" (deploy.py:355), add
a `deployment update` verb, add `flotilla deploy reconcile` + SSE pre-drain
(§19.2 from this session). "Let's use branches and PR's so we don't need to
worry about conflicting with other sessions."
---
## What shipped
flotilla **v1.2.0**, on branch `session-0028/flotilla-v1.2.0`, pushed to
`origin` (gitea). **Open as a PR (not yet merged):**
https://git.wiggleverse.org/wiggleverse/ohm-rfc-app-flotilla/pulls/new/session-0028/flotilla-v1.2.0
Commit `51c7ea8`. No OHM deploy, no rfc-app release, no pin bump — this is
operator-tool code. Operator opens + merges the PR (sole-merger rule) and
tags `v1.2.0` after merge.
Five changes, all flotilla-internal, each unit-tested (the deploy seams are
dependency-injected so nothing touches gcloud or the network):
1. **Preflight SSH-failure disambiguation** (`deploy.py` phase 2). The
misreport at `deploy.py:355`: a bare `test -d <install>` whose any-non-zero
return was read as "install dir missing" — but `gcloud compute ssh` exits
non-zero on a connection/auth/IAP failure too, so an unreachable VM was
misdiagnosed as a missing dir. Fix: a trivial `true` connectivity probe
runs first; its non-zero return is reported as the auth/connectivity
failure it is. (Initially gold-plated with a stdout marker; dropped that
for returncode-only after it would have forced every test stub — and every
future one — to simulate the echo. Returncode-only fully solves the actual
bug.)
2. **`_PhaseRunner` catches `ssh.SshError`** → records a clean `failed` phase
instead of unwinding past `run_deploy` and stranding the row `in_progress`
holding the §8.3 lock. This is the structural cause of the v0.6.0 / Session
0009 "aborted but actually fine" — a restart SSH timeout raised mid-phase.
3. **Phase-7 SSE pre-drain.** Replaced `systemctl restart` with a
flotilla-controlled `systemctl kill -s TERM` → bounded `drain_wait_seconds`
(default 20s) → `systemctl kill -s KILL` for lingering SSE keepalive
streams → `systemctl start`. Bounded by `drain + restart_wait` regardless
of the unit's `TimeoutStopSec`, so a held-open SSE stream can't blow past
the SSH timeout. The phase detail records whether it drained via graceful
SIGTERM or had to SIGKILL.
4. **`flotilla deployment update <name> [--flag …]`** (registry +
CLI). In-place edit of mutable record fields (VM name/zone/project/service
user/install dir/systemd unit/tunnel flag, pin source fields, corpus repo,
health URL) without the remove+add that drops the overlay, secret
bindings, and deploy log. The verb the #1 VM rename wanted (session 0022
had to edit the record by hand).
5. **`flotilla deploy reconcile <name> [--json]`.** Probes `/api/health` once
and settles the log against reality: a stuck `in_progress` row is finalized
`succeeded` when health confirms the target version (releasing the lock,
without re-running the deploy); an already-terminal row is never rewritten
— reconcile records a fresh health snapshot and reports the truth
(including the "recorded `failed` but health says target is up" case the
pre-drain fix makes rare). Exits non-zero when not confirmed healthy.
SPEC folded back (§19.3 rule 2): §8.1 step 7 rewritten for the pre-drain,
§12.1 verb inventory gains the two verbs, and a new §19.2 candidate
("graceful app-cooperative SSE drain" — a framework-side drain endpoint in
rfc-app that would make the SIGKILL fallback go unused) records the remaining
future work.
**Tests:** 180 green (157 baseline + 23 new) in the isolated worktree venv.
## Decisions
- **Scope = deploy-robustness, not GCP-resource alignment.** flotilla v1.2.0
is referenced in roadmap #34 as a possible slot, but #34 is the GCP
resource-rename arc. This is a different, disjoint scope; #34 is untouched
and unclaimed. Did NOT edit `ohm-rfc/ROADMAP.md` (no rfc-app/OHM surface
moved, and 0026/0027 may be editing it).
- **Pre-drain is flotilla-only.** A graceful SIGTERM exit needs app
cooperation (rfc-app closing SSE streams on a signal); that's cross-repo
and stays a §19.2 candidate. The SIGKILL fallback is the flotilla-only
mitigation that needs no framework change and makes the v0.6.0 fault
un-reproducible from flotilla's side today.
- **reconcile never rewrites terminal rows.** Finalizing a stuck
`in_progress` is honest (the deploy did complete; only the terminal write
was lost). Rewriting a `failed`/`aborted` row to `succeeded` would erase
the audit trail, so those get a health snapshot + an advisory instead.
- **Branches+PR, no direct main push, no tag.** Per the operator directive
and the sole-merger rule, I pushed the branch and left the merge + tag to
the operator.
## Friction (continued)
- **No gitea PR-create automation available.** `tea` CLI not installed; no
gitea API token in env (HTTPS creds live in macOS keychain — not fished
out). So the PR is "pushed + create-URL handed to operator," not
auto-opened. The operator opens + merges anyway.
## Operating notes / cleanup
- Isolated worktree left in place at
`/Users/benstull/projects/wiggleverse/ohm-rfc-app-flotilla-s0028` (its own
`.venv`) in case the operator wants to iterate on the PR. Remove with
`git worktree remove ohm-rfc-app-flotilla-s0028` after the PR merges.
- The canonical dir `…/ohm-rfc-app-flotilla` was restored to `main` carrying
the OTHER session's (0026/0027) unstaged secret-redaction edits, untouched
— that work is theirs to commit on their branch.
---
## Handoff prompt for the next session
(Delivered to the operator in chat before this transcript was published.)
> You are an OHM roadmap driver session, running in parallel with others.
> CLAIM YOUR SESSION ID FIRST:
> `~/git/ohm-infra/scripts/claim-session-id.sh --start <now PST, YYYY-MM-DDTHH-MM>`
> It prints the active in-progress sessions — coordinate if your work overlaps.
> Read `~/git/ohm-infra/SESSION-PROTOCOL.md` §7 + PULL `ohm-rfc/ROADMAP.md` once.
>
> STATE (end of 0028, 2026-05-28): OHM live at rfc-app v0.24.0 on the renamed
> VM `ohm-rfc-app`; deploys unblocked, lock free. flotilla **v1.2.0** is built
> + pushed as a **PR** (deploy robustness + `deployment update` + `deploy
> reconcile` + phase-7 SSE pre-drain) — NOT merged. Operator: open + merge
> + tag `v1.2.0`:
> https://git.wiggleverse.org/wiggleverse/ohm-rfc-app-flotilla/pulls/new/session-0028/flotilla-v1.2.0
> Note: v1.2.0 and the concurrent secret-redaction work (sessions 0026/0027,
> if they ship it) both touch `deploy.py` `_PhaseRunner` → expect a small
> merge conflict on the second PR; resolvable (distinct concerns).
>
> **CRITICAL for parallel flotilla work:** branches alone do NOT isolate
> concurrent sessions sharing one working dir — take a **manual git worktree**
> (`git worktree add <path> -b <branch> main`) with its own venv
> (`python3 -m venv .venv && .venv/bin/pip install -e .[test]`; the canonical
> `.venv`'s editable finder is pinned to the shared dir).
>
> PICK ONE disjoint item. Open candidates: #28 (PR cross-references — large,
> its own session); #21 Part A Amplitude audit (~week of real data,
> ~2026-06-04); #22 pro-consent copy (needs operator-drafted + counsel text);
> #20/#18 ops (DMARC Phase B ~2026-06-04, stale `wiggleverse/meta` webhook
> still pointing at deprovisioned `rfc.wiggleverse.org`, bounce wiring);
> #31b/#25-redesign (need operator screenshots); #33/#34 repo + GCP name
> alignment (operator-led). AVOID shipped surfaces (#26 ProposeModal/PR/RFC
> views + `proposed_use_cases`; #27 suggest-tags; #29 sign-in resume +
> `/api/auth/me` + `lib/useLastState.js`; v0.21.0 polish surfaces).
>
> Hard rules: never ask for secret bytes (give the `pbpaste | flotilla secret
> set ohm-rfc-app <KEY>` gesture); coordinate the serialized deploy lock +
> version slot with the operator; subagents write their own §5 subsession
> transcripts; finalize + publish your transcript LAST (deliver the handoff
> prompt before publish). Use branches + PRs. Claim your ID, then go.