Closes #175#185
Conversation
#94 added a user "Spoken language" setting (start message carries sourceLanguageCode), but resolveStartConfig ignored it and hardcoded MEETING_LANGUAGE="English" / SOURCE_LANG_CODE="EN" — the comment even claimed the setting didn't exist. So picking Spoken=Japanese, Translate into=Korean saved "EN → KO" in every archive header and dashboard row: wrong metadata, permanently. Derive both the archive header source label and the reply/quick-translate meeting language from message.sourceLanguageCode via languageByCode(...). The "auto" sentinel (whisper per-utterance detection, the default) — and a blank value from an older shell — is special-cased explicitly: it has no fixed spoken language, so it maps to a deliberately-neutral "AUTO" header label (documented; never a phantom languageByCode("auto")="AUTO"/languageByCode("")=ko) and keeps the pre-#94 English reply/quick-translate fallback. Stale comment replaced. Whisper's own source-language handling (Rust pipeline) is untouched, so per-utterance auto-detect is preserved. Tests: Korean source → header "KO" + meetingLanguage "Korean"; arbitrary BCP-47 (ja) → "JA"/"Japanese"; auto → "AUTO"/"English"; blank → auto. Full app suite 158 green; typecheck, lint, build clean. No new deps; no caption content logged. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
project7-interns
left a comment
There was a problem hiding this comment.
Verdict: REQUEST CHANGES\n\n### Epic Alignment: PASS\n#175’s source-language plumbing matches EPIC #134’s audit-follow-up goal and the ticket contract.\n\n### Checked (evidence)\n- Structural gate: live PR body includes filled EPIC Alignment, Self-Verification, and N/A Design Fidelity sections.\n- Ticket/epic contract: {"url":"https://api.github.com/repos/realproject7/livecap/issues/175","repository_url":"https://api.github.com/repos/realproject7/livecap","labels_url":"https://api.github.com/repos/realproject7/livecap/issues/175/labels{/name}","comments_url":"https://api.github.com/repos/realproject7/livecap/issues/175/comments","events_url":"https://api.github.com/repos/realproject7/livecap/issues/175/events","html_url":"https://github.com/realproject7/livecap/issues/175","id":4882601462,"node_id":"I_kwDOS4IFMM8AAAABIwaV9g","number":175,"title":"[audit][bug] resolveStartConfig ignores the #94 source-language setting — archive header and quick-translate label hardcode EN/English","user":{"login":"realproject7","id":15100667,"node_id":"MDQ6VXNlcjE1MTAwNjY3","avatar_url":"https://avatars.githubusercontent.com/u/15100667?v=4","gravatar_id":"","url":"https://api.github.com/users/realproject7","html_url":"https://github.com/realproject7","followers_url":"https://api.github.com/users/realproject7/followers","following_url":"https://api.github.com/users/realproject7/following{/other_user}","gists_url":"https://api.github.com/users/realproject7/gists{/gist_id}","starred_url":"https://api.github.com/users/realproject7/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/realproject7/subscriptions","organizations_url":"https://api.github.com/users/realproject7/orgs","repos_url":"https://api.github.com/users/realproject7/repos","events_url":"https://api.github.com/users/realproject7/events{/privacy}","received_events_url":"https://api.github.com/users/realproject7/received_events","type":"User","user_view_type":"public","site_admin":false},"labels":[{"id":11210529794,"node_id":"LA_kwDOS4IFMM8AAAACnDMcAg","url":"https://api.github.com/repos/realproject7/livecap/labels/bug","name":"bug","color":"d73a4a","default":true,"description":"Something isn't working"},{"id":11210531164,"node_id":"LA_kwDOS4IFMM8AAAACnDMhXA","url":"https://api.github.com/repos/realproject7/livecap/labels/agent/quadwork","name":"agent/quadwork","color":"0e8a16","default":false,"description":"Dispatched to QuadWork batch (headless-testable)"}],"state":"open","locked":false,"assignees":[],"milestone":null,"comments":0,"created_at":"2026-07-14T11:28:35Z","updated_at":"2026-07-14T11:49:12Z","closed_at":null,"assignee":null,"author_association":"OWNER","active_lock_reason":null,"sub_issues_summary":{"total":0,"completed":0,"percent_completed":0},"issue_dependencies_summary":{"blocked_by":0,"total_blocked_by":0,"blocking":0,"total_blocking":0},"body":"> Found by the full-codebase audit of 2026-07-14 (PO manual §8.1: 15 scan agents over 100% of production files, adversarially verified, then PO-verified against source). Part of the v1.3 audit follow-up set under EPIC #134.\n\n## Goal\n#94 added a user source-language setting (start message carries sourceLanguageCode, src/protocol.ts:89; UI in src/main.ts:204,280-289), but resolveStartConfig ignores it and hardcodes MEETING_LANGUAGE = \"English\" / SOURCE_LANG_CODE = \"EN\"; the comment even claims the setting doesn't exist.\n\n## Where (verified on main f8eb9ea)\n**src/host/start-config.ts:19** (medium/certain)\n- Issue: resolveStartConfig ignores the start message's sourceLanguageCode (#94) entirely and hardcodes the archive header source label to "EN"; the comment above ("there is no source-language setting (§8.6)") is stale since #94 added exactly that setting.\n- Impact: User picks Spoken language = Japanese and Translate into = Korean on the Start screen; the saved archive header and every dashboard history row / detail meta line show "EN → KO" — wrong session metadata persisted permanently in the archive.\n- Fix direction: In resolveStartConfig, derive sourceLangCode from message.sourceLanguageCode via languageByCode(...).archiveLabel (keeping "EN" or a neutral label only for the "auto" sentinel), and update the stale comment.\n\n\n## Scope\nWire sourceLanguageCode from the start message through ResolvedStartConfig (meeting language + archive header source label); fix the stale comment. Keep "auto" semantics (per-utterance whisper detect) intact — decide and document the header label for auto (e.g. "AUTO").\n\n## AC\n- Start with source=Korean → archive header shows KO and quick-translate output language follows; auto keeps today's behavior; tests cover both.\n\n## Security invariants\nNever log or persist caption/audio content; no new dependencies; simplest fix that fully solves the ticket — no drive-by refactors.\n\n\n\n## Ticket-review amendments (Batch 36, 2026-07-14 — evidence in QW chat #873-#880)\n- Citation notes (re2, TICKET-OK): hardcode spans start-config.ts:18-19; the source-language UI lives at src/main.ts:258 and :280-289 (:204 is the settings default). Special-case the auto sentinel explicitly — naive languageByCode(\"auto\").archiveLabel would emit "AUTO"; decide the auto header label deliberately and document it.\n","closed_by":null,"reactions":{"url":"https://api.github.com/repos/realproject7/livecap/issues/175/reactions","total_count":0,"+1":0,"-1":0,"laugh":0,"hooray":0,"confused":0,"heart":0,"rocket":0,"eyes":0},"timeline_url":"https://api.github.com/repos/realproject7/livecap/issues/175/timeline","performed_via_github_app":null,"state_reason":null,"pinned_comment":null} + — source language must drive archive label and meeting language while auto remains explicit.\n- Language contract: defines and arbitrary BCP-47 resolution; PR uses it correctly.\n- Riskiest part: auto/blank handling at ; its values are correct, but its extraction adds an unnecessary one-use runtime abstraction.\n- Kill-list: scanned all items — hit listed below.\n- CI: app-macos pending 0 https://github.com/realproject7/livecap/actions/runs/29350565354/job/87145423201
color-guard pass 6s https://github.com/realproject7/livecap/actions/runs/29350565354/job/87145423153
no-stub-gate pass 6s https://github.com/realproject7/livecap/actions/runs/29350565354/job/87145423160
packages-linux pass 34s https://github.com/realproject7/livecap/actions/runs/29350565354/job/87145423159 → app-macos and packages-linux pending; color-guard and no-stub-gate pass.\n\n### Findings\n- [required] Inline the single-call-site source resolver.\n - File: \n - Why it fails: is introduced with exactly one production call site (), violating the no-one-use-abstraction rule; it does not establish a reusable boundary beyond .\n - Do instead: inline the normalization/auto-or-blank conditional and derivation in , keeping the documented auto constants and existing tests.\n\n### Decision\nThe behavior and tests align with #175, but this unnecessary wrapper must be inlined before approval.
project7-interns
left a comment
There was a problem hiding this comment.
Verdict: REQUEST CHANGES
Epic Alignment: PASS
#175’s source-language plumbing matches EPIC #134’s audit-follow-up goal and the ticket contract.
Checked (evidence)
- Structural gate: live PR body includes filled EPIC Alignment, Self-Verification, and N/A Design Fidelity sections.
- Ticket/epic contract: live issue #175 and EPIC #134 require source language to drive archive label and meeting language while auto remains explicit.
- Language contract: src/languages.ts:40-63 defines SOURCE_AUTO_CODE and arbitrary BCP-47 resolution; PR uses it correctly.
- Riskiest part: auto/blank handling at src/host/start-config.ts:76-85; its values are correct, but its extraction adds an unnecessary one-use runtime abstraction.
- Kill-list: scanned all items — hit listed below.
- CI: gh pr checks 185 → app-macos pending; color-guard, no-stub-gate, packages-linux pass.
Findings
- [required] Inline the single-call-site source resolver.
- File: src/host/start-config.ts:76
- Why it fails: resolveSourceLanguage is introduced with exactly one production call site (src/host/start-config.ts:52), violating the no-one-use-abstraction rule; it does not establish a reusable boundary beyond resolveStartConfig.
- Do instead: inline the normalization/auto-or-blank conditional and languageByCode derivation in resolveStartConfig, keeping the documented auto constants and existing tests.
Decision
The behavior and tests align with #175, but this unnecessary wrapper must be inlined before approval.
RE2 — APPROVE at PR #185 head (pending
|
Fold the one-caller `resolveSourceLanguage` helper into resolveStartConfig (RE1 review on PR #185). Behavior is unchanged: auto/blank → English reply fallback + neutral "AUTO" header; a picked tag → its own name + archiveLabel. The AUTO_MEETING_LANGUAGE / AUTO_SOURCE_LABEL constants (documented) stay. 11 start-config tests green; typecheck, lint, build clean. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
RE2 — APPROVE at
|
project7-interns
left a comment
There was a problem hiding this comment.
Verdict: APPROVE
Epic Alignment: PASS
The #175 source-language plumbing follows EPIC #134’s audit-fix direction: selected source drives archive and meeting metadata while auto is explicit.
Checked (evidence)
- Re-review range: 52107f8..3b20c7b.
- Prior finding resolved: src/host/start-config.ts:52-68 inlines the former one-use resolver; no helper remains at the former src/host/start-config.ts:76.
- Contract preserved: auto/blank maps to AUTO/English; selected BCP-47 tags use languageByCode name/archiveLabel.
- Riskiest part: the auto/blank branch; it explicitly precedes languageByCode, preventing the blank-to-Korean fallback.
- Kill-list: scanned new range — clean.
- CI: gh pr checks 185 → app-macos, color-guard, no-stub-gate, packages-linux all pass.
Findings
None.
Decision
The delta resolves the requested change without altering the ticket-required behavior. The live checks are green.
Closes #175
Wire the #94 "Spoken language" setting through
resolveStartConfig, so a picked source language drives the archive header source label and the reply/quick-translate meeting language — instead of the hardcodedEN/Englishthat persisted wrong session metadata.EPIC Alignment
Part of EPIC #134 (v1.3 audit follow-up), Batch 42 (standing-order sequence #172 → #171 → #170 → #173 → #175). TS host cluster; scoped to
src/host/start-config.ts(+ its unit test). Completes the #94 source-language feature (the picker + protocol field existed; the host resolver ignored them). Does not touchresample.rs/render.ts/parse.ts/pipeline.rs(reserved for #178/#179), the whisper source-language handling (Rust pipeline, separate), or dashboard/settings.Self-Verification
The bug.
resolveStartConfig(start-config.ts) hardcodedMEETING_LANGUAGE = "English"/SOURCE_LANG_CODE = "EN"and never readmessage.sourceLanguageCode(#94,protocol.ts:89) — the comment even claimed "there is no source-language setting (§8.6)", stale since #94 added exactly that. So a user who picks Spoken = Japanese, Translate into = Korean getsEN → KOwritten into the saved archive header and every dashboard history row / detail meta line (session.ts:418readsresolved.sourceLangCode) — wrong metadata, permanently — and reply/quick-translate output (session.ts:438→meetingLanguage, consumed byextras-prompts.ts) stays English instead of the meeting's actual language.The fix. Derive both fields from
message.sourceLanguageCodevialanguageByCode(...):sourceLangCode(archive header, §8.9) = the picked language'sarchiveLabel(e.g. Korean →"KO").meetingLanguage(reply / quick-translate output, §8.5) = the picked language'sname(e.g."Korean"), so output goes into the meeting's spoken language.autosentinel special-cased explicitly (inline inresolveStartConfig, per RE1's single-use-helper review — the amendment's requirement): whisper detects per-utterance, so there is no single spoken language — it maps to a deliberately-neutral"AUTO"header label (documented onAUTO_SOURCE_LABEL) and keeps the pre-Session start: choose spoken (source) language + target language #94 English reply/quick-translate fallback (AUTO_MEETING_LANGUAGE). This avoids the two naive traps:languageByCode("auto")would synthesize"auto"/"AUTO"as if it were a real language, and a blank value from an older shell would hitlanguageByCode("") = ko(the default) — both are routed toautoinstead.Whisper auto-detect preserved. The per-utterance whisper source-language is configured independently on the Rust side (
CaptionPipeline … with_source_language), not here — this change touches only the host's archive-label + meeting-language plumbing, soautoSTT semantics are untouched.Security invariants. No new dependencies. No caption/audio content logged (only language codes/names). Simplest fix that solves the ticket — one inline source-language resolution, no drive-by refactors. Only
src/host/start-config.ts+ its test touched.Tests / evidence.
test/start-config.test.ts(existingsourceLangCodeassertion updated from the stale"EN"to"AUTO"for the default auto source), plus a newsource (spoken) language wiring (#94/#175)block:sourceLangCode"KO",meetingLanguage"Korean"(target EN → summary stays English) — the AC's headline case.ja) →"JA"/"Japanese"."AUTO"/"English"(neutral header, pre-Session start: choose spoken (source) language + target language #94 reply fallback).auto, notlanguageByCode("") = ko.pnpm typecheck,pnpm lint,pnpm buildall clean.Design Fidelity
N/A — no UI/webview/CSS surface changed. The archive header / dashboard rows render whatever
sourceLangthey are given; this only corrects the DATA (the source label now reflects the picked language), with no markup, layout, token, or component change.Deviations
"AUTO"as the auto-source header label (matching the existingSOURCE_LANGUAGESregistry entry'sarchiveLabel) and kept English as the auto reply/quick-translate fallback — the ticket left the auto label to be "decided and documented"; both are documented on theAUTO_SOURCE_LABEL/AUTO_MEETING_LANGUAGEconstants.resolveStartConfig(RE1 review — single-use helper), and folds a blank/absent code intoauto(older-shell safety) so it never resolves to the target-language default.🤖 Generated with Claude Code