feat(rpc): /action/enqueueFile + chained reimport E2E#248
Merged
Conversation
515b90f to
9f8a604
Compare
Exposes the menu's "Open from Recording" entry point over RPC. Body is
`{"path":"..."}`; returns 200 on success, 400 on missing/empty path or
file that doesn't exist. Wires through to the same AppState.enqueueFiles
the NSOpenPanel flow uses, so the import code path is identical.
Motivation: e2e-app.sh wants to feed a recorded WAV back through the
pipeline for a content-based transcript assertion. The fixture-based
xctest E2Es never exercise the file-import path with live-recorded audio.
Three integration tests cover missing path → 400, nonexistent path → 400,
and valid path → 200 with closure invocation. Existence check lives on
the closure side (AppState) so the RPC layer stays a thin transport.
Adds --reimport-recorded mode that runs a record-only meeting (live
capture → mix.wav), then POSTs that WAV to /action/enqueueFile and
asserts the resulting transcript contains the fixture's spoken keyword
("meeting", case-insensitive).
Closes the gap between the existing transcript lane (uses fixture WAV
directly, doesn't exercise recorder output) and the record-only lane
(only checks files exist, doesn't validate content). Catches three
failure classes neither lane sees alone:
- Recorder writes a malformed WAV → record-only would still pass on
file size; reimport fails because AudioMixer can't decode it.
- AudioMixer 3-tier file-load fallback regresses → currently only
fixture-tested via xctest, never live.
- Live capture is silent/garbled → transcript lane's fixture-direct
path never touches the recorder, so a routing regression on
BlackHole / mic / default-output goes undetected.
recordOnly toggle stays on during the reimport phase but only affects
WatchLoop.enqueueRecording — AppState.enqueueFiles bypasses it.
Wires up a third step in e2e-app.yml after the existing two lanes,
sharing the deployed bundle via --no-build. Adds ~1 min wall on Mini.
9f8a604 to
38f148b
Compare
4 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
POST /action/enqueueFileRPC endpoint exposes the menu's "Open from Recording" entry point. Body{"path":"..."}, returns 200/400.e2e-app.sh --reimport-recordedchains a record-only meeting with a re-import: live capture writes a WAV, then that WAV gets POSTed back into the pipeline. Asserts transcript contains the fixture keyword (meeting, case-insensitive).e2e-app.ymlafter the existing transcript + record-only lanes (~1 min wall extra on Mini,--no-buildreuses the bundle)._poll_for_new_lastjob_terminalhelper eliminates ~50 lines of polling duplication betweenrun_one_meetingandrun_one_reimport. Single source of truth for theIFS='|'framing rationale.Commits
feat(rpc): add POST /action/enqueueFile endpoint— Swift code + 3 integration tests (poll loop on the observable to harden against sanitizer-lane flake).test(e2e-app): chain record-only with re-import + transcript assertion— driver + workflow + shared poll helper + namedRECORDER_FINALIZE_WAIT_Sconstant.Why
Closes E2E coverage gap #6 (file-import path is only fixture-tested via xctest, never live) AND ratchets up the toothless
> 100 bytestranscript check to a content-based assertion. The chain catches three failure classes the single lanes miss:AudioMixer.loadAudioAsFloat32regressesImplementation notes
FileManager.default.fileExists(atPath: url.path)on the AppState side; RPC layer just translatesfalse→ 400. Keeps the transport thin.recordOnly=truestays on during the reimport phase — only affectsWatchLoop.enqueueRecording, notAppState.enqueueFiles. No restart needed.meeting(case-insensitive). The fixture hasProjekt Meeting, alsoMeetingin the simulator window title; robust to Parakeet/WhisperKit casing differences.Test plan
swift test --filter DebugRPCServerIntegrationTests— 12 tests pass incl. 3 new./scripts/lint.sh— 0 violationsbash -n scripts/e2e-app.sh— syntax OKe2e-app.ymlpush-trigger fires all 3 lanes: