Hand off: stage next work, move eval debt to ROADMAP, trim Current state

This commit is contained in:
Grant Gilliam
2026-06-13 18:16:04 -05:00
parent 0af86411c2
commit fc80f6707a
2 changed files with 14 additions and 13 deletions
+7 -13
View File
@@ -78,19 +78,13 @@ open /Applications/Ten31Transcripts.app
- Never do per-platform display-name matching for self (Zoom/Meet/Signal names differ) — channel + one canonical name only.
- Never treat a solid camera-off avatar tile (Meet's orange/magenta fill) as an active speaker — the real cue is a thin **hollow** coloured ring; require thin-edge + hue gate (see `GridCallAnalyzer.isHollow`, `FrameSampler.thinColoredPoints`).
- Never collapse adjacent same-speaker transcript segments (reverted by request) — one line per diarized utterance.
- Never send call audio to a raw IP the user didn't configure. The backend host (`$SPARK_BACKEND_URL`) is a private `.local` mDNS name a plain `swiftc` binary can't resolve via URLSession (`-1009`) — use the **real app** for backend runs (or `curl` for health checks).
- Never send call audio to a raw IP the user didn't configure. Offline backend checks: a `.local` mDNS host can't be resolved by a plain `swiftc`/URLSession binary (`-1009`) — use the **real app** or `curl`; but a **configured raw IP _is_ reachable from a plain swiftc URLSession binary** (that's how the TLS fix was verified offline).
- Never commit to `main` or force-push a shared branch; branch first and ask.
## Current state
Present tense; overwritten each session. 73 tests pass; `/Applications/Ten31Transcripts.app` matches HEAD and runs; working tree clean and pushed to `origin`/`main`. A full independent evaluation ran 2026-06-13 → `EVALUATION.md` (committed at repo root; overwritten + re-committed each run for a reviewable diff); its findings are triaged into the lists below. The eval's P1 (TLS) is now **fixed** and verified against the live backend.
- **Working:** call detection (Meet/Zoom/Teams/Signal), dual-track capture, dual-channel + chunked backend hand-off, speaker reconciliation, recap (`transcript.md` + recap-relay-styled `recap.html`), speaker editor, configurable chunk length, standalone Settings window.
- **In progress:** the Meet visual fix (reject solid camera-off tiles) is unverified end-to-end — no clean run exists yet; the saved Meet session's `visual_timeline.json` predates the fix.
- **Done this session (was eval P1):** TLS validation is now **on by default** and the skip-TLS escape hatch is **scoped to the configured host** (`InsecureTrustDelegate.allowsTrustOverride`, covered by `InsecureTrustDelegateTests`). Supported path = the StartOS Root CA trusted in the System keychain; verified `URLSession` default validation returns 200 against both the primary backend IP and its fallback.
- **Work queue (next up):** wire the backend URL + primary→fallback into config. Today it's a single `backendBaseURL` with no fallback logic, and on this Mac no value is saved (so it resolves to the `your-spark-backend.local` placeholder); the real setup is a primary LAN IP with a fallback IP (both port 62419) — the actual addresses live in Settings/UserDefaults, never source.
- **Known debt (P2 — fix before wider use):**
- `RecapAnalyzer.mmss()` fatally crashes on NaN/∞ (reproduced 2×); a malformed/MITM'd backend `duration` (e.g. `1e400``Double.infinity`) aborts the app at recap-render time — add a finite-guard fallback (`RecapAnalyzer.swift:137`).
- README is stale by six phases — still says "Phase 0 (scaffold) / no audio capture, detection, or backend hand-off yet" for a shipped Phase-6 app; same lie in source comment `AppSettings.swift:7`; and `README.md:49` still calls skip-TLS "on by default" (now off). Rewrite to match reality.
- `SessionController` (670 lines, the most concurrency-dense file) has zero unit tests — cover `pendingAutoStop` (auto-start-then-immediate-call-end) and the visual-adoption generation guard before any refactor.
- **Deferred (P3 — later decision or bulk cleanup; full evidence in `EVALUATION.md`):** `docs/` specs drifted from the dual-channel API + recap phase; `docs/01` §7 lists already-resolved open items; `docs/02` §2.10 claims MenuBarUI features that don't exist; AGENTS.md Layout listings under `Audio/`/`Detection/` are incomplete; the `manifest.json` sha256 contract is specced but never written; env-var precedence footgun (saved URL shadows `SPARK_BACKEND_URL`); `SessionController` owns three jobs (extract the open-panel UI); unused `NSAppleEventsUsageDescription`; unauthenticated LAN backend (consider a shared bearer token).
- **Known bugs:** Meet speaking-detection is sparse (faint blue border); the mic channel emits some sub-second junk "self" fragments; the same person on desktop-mic vs phone-speakerphone does not unify by voiceprint.
- **Next (product validation — no agent could reach the live backend, so this stays manual):** (1) re-process the saved Meet session in the app, then read its `speakers.json` + `cluster_fingerprints.json` to confirm ~4 speakers recover; (2) record a fresh Meet call to validate the visual fix on a clean capture. (The old "confirm Your name = Grant" item is moot — the committed default is the generic `"Me"`; "Grant" only ever lives in local UserDefaults.)
Present tense; overwritten each session. `main` clean and pushed; 73 tests pass; `/Applications/Ten31Transcripts.app` is built from HEAD — **quit + relaunch the menu-bar app** to load the TLS change. A 2026-06-13 independent eval → `EVALUATION.md`; its only P1 (TLS) is fixed, the rest are P2/P3 in `ROADMAP.md` (full evidence in `EVALUATION.md`).
- **Working:** call detection (Meet/Zoom/Teams/Signal), dual-track capture, dual-channel + chunked backend hand-off, speaker reconciliation, recap (`transcript.md` + `recap.html`), speaker editor, configurable chunk length, standalone Settings.
- **Done this session:** TLS validation on by default + skip-TLS bypass scoped to the configured host (`InsecureTrustDelegate.allowsTrustOverride`, unit-tested); verified `URLSession` default validation reaches the live backend + fallback. Ran + triaged the eval. Purged backend LAN IPs from git history (2nd `filter-repo` rewrite; backups `../ten31-transcripts-*.bundle`).
- **Next up (start here): backend URL + primary→fallback.** App has a single `backendBaseURL`, no fallback, and on this Mac no value is saved (resolves to the placeholder → recordings wouldn't reach SparkControl). (1) persist the URL in Settings + confirm it actually saves; (2) primary→fallback on connection failure + show which endpoint is live; (3) freebie: the `mmss()` NaN/∞ guard. Sketch before coding. Keep real IPs out of source — use `192.0.2.x` placeholders.
- **In progress / unverified:** the Meet visual fix (reject solid camera-off tiles) has no clean end-to-end run yet — validate by re-processing the saved Meet session and recording a fresh Meet call (needs the real app + backend; not doable offline).
- **Known bugs:** sparse Meet speaking-detection (faint blue border); sub-second junk "self" mic fragments; same person on desktop-mic vs phone doesn't unify by voiceprint.
+7
View File
@@ -22,5 +22,12 @@ Longer-term backlog and deferred decisions. Near-term status + the next few step
- Decide whether to add a linter/formatter (SwiftLint/SwiftFormat) — none configured today.
- `SPARK_BACKEND_URL` is read only at `AppSettings.init` and is shadowed by any value already saved in Settings (UserDefaults wins). So once a backend URL has been saved, the env var has no effect — a stale stored value can override it in dev/CI/harness runs. If that bites, treat an empty/placeholder stored URL as absent so the env var can still win.
## Quality / debt (from the 2026-06-13 independent eval — full queue + evidence in `EVALUATION.md`)
- Guard `RecapAnalyzer.mmss()` (`:137`) against NaN/∞ — a malformed backend `duration` aborts the app at recap render (eval P2). Cheap; fold into the next backend change.
- Rewrite the stale README: it claims "Phase 0 / no audio capture" for a shipped Phase-6 app; the `AppSettings.swift:7` comment and the `README.md:49` skip-TLS "on by default" line are also stale (eval P2).
- Add `SessionController` state-machine tests (`pendingAutoStop`, visual-adoption generation guard) before refactoring; then extract its saved-session / open-panel UI (eval P2/P3).
- Reconcile `docs/` specs with reality: the dual-channel API fields (`mic_file`/`system_file`/`self_name`/`self_vad`) and the recap/LLM phase are undocumented; `docs/01` §7 lists already-resolved open items; `docs/02` §2.10 claims absent MenuBarUI features (eval P3).
- Smaller P3s in `EVALUATION.md`: incomplete AGENTS Layout listings, unwritten `manifest.json` sha256 contract, unused `NSAppleEventsUsageDescription`, unauthenticated LAN backend (consider a bearer token).
## Deferred decisions
- Cross-device self unification (same person, desktop mic vs phone speakerphone) does not work by voiceprint and is treated as a separate identity; revisit only if a reliable signal emerges (mic-channel-as-self remains the robust path).