From 35ba6ecf05e75995f8bb518c270a6c6ae951454a Mon Sep 17 00:00:00 2001 From: Grant Gilliam Date: Tue, 16 Jun 2026 22:15:44 -0500 Subject: [PATCH] Drop unused AppleEvents usage string; de-stale Phase-N comments MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The NSAppleEventsUsageDescription usage string was dead — the app has no AppleEvents/AppleScript code path (Meet detection reads window titles), so the permission prompt never fired; remove it. Rephrase the leftover "Phase N" build-plan references in source comments (one of which falsely claimed "no audio, capture, or call detection yet"), and complete the AGENTS.md Audio/Detection layout listings. --- AGENTS.md | 4 ++-- ROADMAP.md | 3 +-- Ten31Transcripts/App/Ten31TranscriptsApp.swift | 5 ++--- Ten31Transcripts/Audio/AudioRecorder.swift | 2 +- Ten31Transcripts/Audio/MicVAD.swift | 4 ++-- Ten31Transcripts/Backend/SparkControlHealth.swift | 6 +++--- Ten31Transcripts/Session/TranscriptPipeline.swift | 4 ++-- Ten31Transcripts/Support/Info.plist | 2 -- Ten31Transcripts/Visual/VisualTimeline.swift | 2 +- 9 files changed, 14 insertions(+), 18 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index 02dd5b1..d94bb1e 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -49,10 +49,10 @@ open /Applications/Ten31Transcripts.app - `Ten31Transcripts/Session/` — `SessionController` (state machine), `TranscriptPipeline`, `SessionPackager` (chunking), `TranscriptAssembler`, `SpeakerReconciler`, `ChunkPlan` (`ChunkMode`), `SpeakersFile`. - `Ten31Transcripts/Visual/` — `VisualCapture`/`VisualObserver` (ScreenCaptureKit, ~3fps), `GridCallAnalyzer` (+ `FrameSampler`, `TextRecognizer`, `TimelineBuilder`, `VisualTimeline`, `SpeakerObservation`). - `Ten31Transcripts/Adapters/` — per-app screen-readers (`MeetAdapter`, `ZoomAdapter`, `TeamsAdapter`, `SignalAdapter`) + `AdapterRegistry`. -- `Ten31Transcripts/Audio/` — `AudioRecorder`, `MicVAD`, `ChannelSelfVAD`. +- `Ten31Transcripts/Audio/` — `AudioRecorder`, `MicVAD`, `ChannelSelfVAD`, `AudioMixer`, `MonoTrackWriter`, `Resampler`. - `Ten31Transcripts/Backend/` — `SparkControlClient`, `GatewayLLMClient`, `VoiceprintStore`, `SparkControlHealth`, `InsecureTrustDelegate` (TLS skip). - `Ten31Transcripts/Recap/` — `RecapAnalyzer`, `RecapRenderer` (writes `transcript.md` + `recap.html`), `RecapModels`, `RecapTemplate`, `SpeakerEditing`, `RecapEditModel`. -- `Ten31Transcripts/{Detection,Permissions,Settings,UI,Support}/` — `CallDetector`; `PermissionsManager`; `AppSettings` (UserDefaults); SwiftUI views + AppKit window hosts; `Info.plist` + entitlements. +- `Ten31Transcripts/{Detection,Permissions,Settings,UI,Support}/` — `CallDetector`/`AudioInputProcesses`/`MicActivityMonitor`; `PermissionsManager`; `AppSettings` (UserDefaults); SwiftUI views + AppKit window hosts; `Info.plist` + entitlements. - `Ten31TranscriptsTests/` — XCTest. `example-screenshots/` — real fixtures (gitignored). `docs/`, `README.md`. - **Runtime output** (default `~/Ten31Transcripts/sessions/_/`, configurable in Settings): `mic.wav`, `system.wav`, `mixed_mono_16k.wav`, `self_vad.json`, `visual_timeline.json`, `speakers.json` (output), `cluster_fingerprints.json`, `recap.{html,json}`, `transcript.md`. diff --git a/ROADMAP.md b/ROADMAP.md index 80453ca..ff59484 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -28,8 +28,7 @@ Longer-term backlog and deferred decisions. Near-term status + the next few step ## 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. - Add `SessionController` state-machine tests (`pendingAutoStop`, visual-adoption generation guard) before refactoring; then extract its saved-session / open-panel UI (eval P2/P3). -- Optional: sweep the stale "Phase N" references in source comments (e.g. `SparkControlHealth.swift:7` "arrives in Phase 5", `Ten31TranscriptsApp.swift:6` "Phase 0 only") — historical, not false, but dated. `docs/04_BUILD_PLAN.md` is now marked COMPLETE/historical and is the map for these. -- Smaller P3s in `EVALUATION.md`: incomplete AGENTS Layout listings, unwritten `manifest.json` sha256 contract (now documented as not-emitted in `docs/03` §2), unused `NSAppleEventsUsageDescription`, unauthenticated LAN backend (consider a bearer token). +- Smaller P3s in `EVALUATION.md`: whether to actually emit the `manifest.json` per-file `sha256` (now documented as not-emitted in `docs/03` §2); 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). diff --git a/Ten31Transcripts/App/Ten31TranscriptsApp.swift b/Ten31Transcripts/App/Ten31TranscriptsApp.swift index 1db4a83..00a01be 100644 --- a/Ten31Transcripts/App/Ten31TranscriptsApp.swift +++ b/Ten31Transcripts/App/Ten31TranscriptsApp.swift @@ -3,9 +3,8 @@ import SwiftUI /// Menu-bar-only app entry point. /// /// `LSUIElement` (set in Info.plist) keeps the app out of the Dock; the -/// `MenuBarExtra` scene provides the status-bar item and its panel. Phase 0 only -/// wires up permissions, settings, and a backend health check — no audio, -/// capture, or call detection yet. +/// `MenuBarExtra` scene provides the status-bar item and its panel, which wires +/// up permissions, settings, recording control, and the backend health check. @main struct Ten31TranscriptsApp: App { @NSApplicationDelegateAdaptor(AppDelegate.self) private var appDelegate diff --git a/Ten31Transcripts/Audio/AudioRecorder.swift b/Ten31Transcripts/Audio/AudioRecorder.swift index 453c25e..bbda042 100644 --- a/Ten31Transcripts/Audio/AudioRecorder.swift +++ b/Ten31Transcripts/Audio/AudioRecorder.swift @@ -14,7 +14,7 @@ struct RecordingResult { let systemNote: String? } -/// Dual-track local audio capture for Phase 1. +/// Dual-track local audio capture. /// /// - System audio via `SCStream` (`capturesAudio`); its audio handler runs on /// `ioQueue`. A discard-only video output runs on `screenQueue` purely to keep diff --git a/Ten31Transcripts/Audio/MicVAD.swift b/Ten31Transcripts/Audio/MicVAD.swift index 922221a..4b8d772 100644 --- a/Ten31Transcripts/Audio/MicVAD.swift +++ b/Ten31Transcripts/Audio/MicVAD.swift @@ -13,8 +13,8 @@ struct VADSpan: Equatable { /// internal sample cursor always equals the mic file position, and span times /// land on the same instants as `mixed_mono_16k.wav`. /// -/// Phase 3's `TimelineBuilder` will fold these in as high-confidence pre-seeded -/// "self" segments. Thresholds are intentionally simple and will be tuned later. +/// `TimelineBuilder` folds these in as high-confidence pre-seeded "self" +/// segments. Thresholds are intentionally simple. /// /// Single-threaded: all calls happen on `AudioRecorder.ioQueue`. final class MicVAD { diff --git a/Ten31Transcripts/Backend/SparkControlHealth.swift b/Ten31Transcripts/Backend/SparkControlHealth.swift index 491915d..18ae153 100644 --- a/Ten31Transcripts/Backend/SparkControlHealth.swift +++ b/Ten31Transcripts/Backend/SparkControlHealth.swift @@ -1,10 +1,10 @@ import Foundation import Combine -/// Performs the Phase 0 backend reachability check: `GET {baseURL}/api/status`. +/// Performs the backend reachability check: `GET {baseURL}/api/status`. /// -/// This is a thin slice — the full `SparkControlClient` (label-merge, multipart, -/// sequential queueing, retries) arrives in Phase 5. +/// This is a thin slice; the full upload path (label-merge, multipart, sequential +/// queueing, retries) lives in `SparkControlClient`. @MainActor final class SparkControlHealth: ObservableObject { diff --git a/Ten31Transcripts/Session/TranscriptPipeline.swift b/Ten31Transcripts/Session/TranscriptPipeline.swift index cd02bd8..0e6b0c4 100644 --- a/Ten31Transcripts/Session/TranscriptPipeline.swift +++ b/Ten31Transcripts/Session/TranscriptPipeline.swift @@ -121,8 +121,8 @@ final class TranscriptPipeline { return assembled.speakersFile } - /// Build the `label-merge` timeline from mic-VAD self spans (Phase 1/2). Once - /// the visual adapters land (Phase 3–4), their segments are merged in too. + /// Build the `label-merge` timeline from mic-VAD self spans; the visual + /// adapters' segments are merged in alongside these. static func timeline(fromSelfSpans spans: [VADSpan], selfName: String) -> [VisualTimeline.Segment] { spans.map { .init(start: $0.start, end: $0.end, name: selfName, confidence: $0.confidence, source: "mic_vad") } } diff --git a/Ten31Transcripts/Support/Info.plist b/Ten31Transcripts/Support/Info.plist index c3d9db2..59db66d 100644 --- a/Ten31Transcripts/Support/Info.plist +++ b/Ten31Transcripts/Support/Info.plist @@ -30,8 +30,6 @@ Ten31 NSMicrophoneUsageDescription Ten31 Transcripts records your microphone during calls to build the local audio track. - NSAppleEventsUsageDescription - Ten31 Transcripts reads the active browser tab's URL to detect Google Meet calls. NSLocalNetworkUsageDescription Ten31 Transcripts connects to your SparkControl server on the local network. NSAppTransportSecurity diff --git a/Ten31Transcripts/Visual/VisualTimeline.swift b/Ten31Transcripts/Visual/VisualTimeline.swift index aa74988..284d9d5 100644 --- a/Ten31Transcripts/Visual/VisualTimeline.swift +++ b/Ten31Transcripts/Visual/VisualTimeline.swift @@ -62,7 +62,7 @@ struct VisualTimeline: Codable { } /// The flat array `label-merge` wants: `[{start,end,name,confidence}]`, - /// dropping `source`. Slice/rebase to chunk-local seconds happens in Phase 5. + /// dropping `source`. Slice/rebase to chunk-local seconds happens at chunking time. func flatTimelineData() throws -> Data { let flat = segments.map { seg -> [String: Any] in ["start": seg.start, "end": seg.end, "name": seg.name, "confidence": seg.confidence]