Skip to content

docs(v0.3.0): research + 18 plans for fat-milestone planning#87

Merged
debpalash merged 4 commits into
mainfrom
docs/v0.3.0-planning-artifacts
May 19, 2026
Merged

docs(v0.3.0): research + 18 plans for fat-milestone planning#87
debpalash merged 4 commits into
mainfrom
docs/v0.3.0-planning-artifacts

Conversation

@debpalash
Copy link
Copy Markdown
Owner

@debpalash debpalash commented May 19, 2026

Planning artifacts for the v0.3.0 single-fat-milestone release. Docs-only — no production code changes.

Summary

This PR lands the 18 PLAN.md files + 6 RESEARCH.md files + 2 SPIKE ADRs + supertonic version bump that decompose v0.3.0 across the 7-phase roadmap. Output of a council-of-6-experts session yesterday (Critic, Strategist, User Advocate, Maintainer, Architect, Whisperer + Release Engineer) and 5 parallel phase researchers.

What lands

Phase Plans Reqs
1 Install + Token + Docs + Error UX 3 18 (INST + DOCS + AUTH)
2 Engine Isolation 4 8 (ENGINE + BUG-01)
3 Supertonic-3 + Mirror 2 11 (TTS + INST-mirror)
4 Adaptive & Specialty 2 + 2 ADRs 13 (SPIKE + GGUF + SING — both spikes GO)
5 Opt-in Bug Reporting 3 12 (REPORT)
6 Release + Retro 4 6 (REL)

Scope decisions locked

Validation

  • 16/18 plans pass gsd-sdk verify.plan-structure (Phase 4's 2 plans need <action> blocks on checkpoint tasks — fix lives in companion P0 PR)
  • All RESEARCH.md files committed
  • 2 SPIKE ADRs in .planning/decisions/

No code touched

git diff --stat origin/main..HEAD shows only .planning/** + CLAUDE.md files. No backend/frontend/test changes.

Companion PR

A separate PR will land the P0 security/correctness wave-1 code work (loopback guard, atomic WAV writes, ffmpeg pin, torch.load removal, TTSBackend.unload foundation, Phase 4 plan <action> fix, capture_ws test fix). That PR depends on this PR landing first (the Phase 4 plan fix references plans introduced here).

🤖 Generated with Claude Code

Summary by CodeRabbit

Documentation

  • Planning documents added for Phase 2–6 roadmap covering engine isolation, new TTS engines (OmniVoice-GGUF, Supertonic-3, OmniVoice-Singing), WAV export fixes, bug reporting, and release verification.
  • Updated dependency metadata for Supertonic-3 (v1.2.3 → v1.3.1).

Review Change Stack

debpalash and others added 4 commits May 18, 2026 22:12
Phase 5 research: prefilled-URL GitHub Issues pattern, default-deny payload,
redaction layer, two-step consent UX, rate/dedup/recursion safeguards,
aggregation across Python/Rust/React error producers. Builds on Phase 1's
links.py + errorDocsMap deeplink infrastructure; uses already-installed
@tauri-apps/plugin-opener (^2.5.4). No new packages required.

Covers REPORT-01..12 with confidence levels, 8 pitfalls, subprocess-engine
error capture handoff to Phase 2, security domain mapped to ASVS, and
3-wave delivery plan (redactor + payload, consent UI, aggregation +
pre-submit search).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
15 new plan files + 2 ADR decision docs across 5 phases. Combined with Phase 1's 3 plans, the v0.3.0 milestone now has 18 PLAN.md files covering all 7 phases (Phase 0 already complete via PR #71).

PHASE 2 (Engine Isolation — 4 plans):
- 02-01: SubprocessBackend primitive + echo sidecar POC + graceful is_available wrap (ENGINE-01/05)
- 02-02: _safe_torchaudio_save helper + migrate 11 WAV write sites + #48 regression (BUG-01)
- 02-03: IndexTTS sidecar entry + venv-probe bootstrap + IndexTTS2Backend rewire (ENGINE-02/03/04/07, closes #42)
- 02-04: Engine Compatibility Matrix UI + /engines/{id}/health route (ENGINE-06)

PHASE 3 (Supertonic-3 + Mirror — 2 plans):
- 03-01: Supertonic-3 engine on SubprocessBackend + SHA pin + license gate (TTS-01..06)
- 03-02: bootstrap.rs mirror cascade + UV_DEFAULT_INDEX migration + frozen enforcement + docs (INST-07..11)

PHASE 4 (Spike-first Adaptive & Specialty — 2 plans + 2 ADRs):
- 04-01: OmniVoice-GGUF hardware-adaptive engine + quant_map + bundled binaries (SPIKE-01, GGUF-01..06)
- 04-02: OmniVoice-Singing subclass + dub pipeline singing mode + segment detector (SPIKE-02, SING-01..05)
- SPIKE-01-gguf.md + SPIKE-02-singing.md ADRs in .planning/decisions/

PHASE 5 (Opt-in Bug Reporting — 3 plans):
- 05-01: Redactor + BugReporter + URL builder + rate/dedup/recursion safeguards + FastAPI router (REPORT-01/02/03/05/06/07/08/10/11)
- 05-02: BugReportDialog two-step consent + PrivacyPanel + ErrorBoundary integration + Rust panic hook (chained) (REPORT-01-Rust/04/09/12)
- 05-03: Dry-run vs 3 historical issues + cross-platform openUrl smoke + Phase 2 subprocess-errors handoff (REPORT-02 smoke, REPORT-03 expansion, REPORT-09)

PHASE 6 (Release + Retro — 4 plans):
- 06-01: rc1 prep — version bump across 4 sources + CHANGELOG + retro stub + PR-73-strategy doc (REL-01/03/06)
- 06-02: CI guards — workflow-parity actionlint + tag-shaped dry-run (Phase 0 retro options B + C; closes release-engineer gap)
- 06-03: PR #73 reimplementation (NOT rebase) — backend-split installer with mirror-cascade integration + pill-mode regression checkpoint
- 06-04: Execute the release — pre-tag gates + 4-OS clean-VM + 48h soak + tag + retro + 3 v0.4 deferral tracking issues (REL-01/02/03/04/05/06)

Scope decisions locked in plans (council session):
- SoniTranslate refactor DEFERRED to v0.4 (Phase 2 ships SubprocessBackend without migrating Soni)
- macOS notarization DEFERRED to v0.4 (Phase 6 ships xattr -cr automation per CLAUDE.md Key Decision #7)
- supertonic pin 1.2.3 → 1.3.1 (already committed in ba63733)
- SPIKE-01 and SPIKE-02 both GO; 13/13 Phase 4 reqs stay in scope
- PR #73 reimplemented, not rebased (93 commits behind main)

All 18 plans validated via gsd-sdk frontmatter.validate + verify.plan-structure.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 19, 2026

📝 Walkthrough

Walkthrough

This PR adds comprehensive planning and research documentation for OmniVoice-Studio's v0.3.0 release across Phases 2–6, including infrastructure work, new engine integrations, bug reporting, and release procedures, with minor Supertonic version metadata updates.

Changes

v0.3.0 Release Planning & Documentation

Layer / File(s) Summary
Phase 2: Subprocess Backend Infrastructure & Spike Decisions
.planning/decisions/SPIKE-01-gguf.md, .planning/decisions/SPIKE-02-singing.md, .planning/phases/02-engine-isolation-subprocessbackend-indextts-wav-export-dubbi/*
Foundational subprocess isolation primitive with echo sidecar for regression testing; WAV corruption fix via centralized audio-write helpers; IndexTTS2 venv-isolated migration resolving transformers version conflict; Engine Compatibility Matrix UI wiring. Spike decisions propose OmniVoice-GGUF hardware-adaptive default cloning (with quant selection and fallback) and omnivoice-singing variant (with [singing] tag injection and dubbing pipeline routing).
Phase 3: Supertonic-3 Engine & Installer Mirror Reliability
.planning/phases/03-supertonic-3-engine-installer-mirror-reliability/*
Opt-in Supertonic-3 CPU ONNX TTS engine with license-acceptance gating and SHA-pinned HuggingFace model snapshots. Hardened restricted-network installer via Rust bootstrap.rs region-aware mirror cascade, uv sync --frozen enforcement, HTTP timeout/retry configuration, and system-Python 3.11+ fallback for air-gapped deployments.
Phase 4: Adaptive Specialty Engines (GGUF & Singing)
.planning/phases/04-adaptive-specialty-engines-spike-first/*
Hardware-adaptive OmniVoice-GGUF runtime bundling omnivoice-tts binaries with quant selection via quant_map.json and fallback to in-process OmniVoiceBackend. ModelsLab omnivoice-singing as OmniVoiceBackend subclass with automatic [singing] control-tag injection, segment-level vocal/instrumental detection (Demucs-based heuristic), and dubbing pipeline routing toggling.
Phase 5: Opt-in Bug Reporting
.planning/phases/05-opt-in-bug-reporting/*
Local-first bug reporting with mandatory two-step consent preview, redaction of sensitive fields (tokens, paths), rate-capping, dedup, recursion guards, and subprocess error capture. GitHub issue prefill via size-bounded URL construction, pre-submit similar-issues search, and end-to-end wiring across backend (redactor + URL builder + settings store), frontend (dialog + privacy toggle + ErrorBoundary), and Rust panic hook chaining.
Phase 6: Release Verification, v0.3.0 Closure & Retro
.planning/phases/06-release-verification-retro/*
Version-source consistency verification (four sources of truth), CHANGELOG.md ## [0.3.0] section with 13-issue verification grid, 4-OS clean-VM manual testing, 48-hour soak monitoring, workflow parity enforcement (tsc --noEmit lint), backend-split installer ensure_backend_ready reimplementation (PR #73), and structured retrospective with Discord support-volume metric and three v0.4 deferral issue templates.
Supertonic Version Metadata Update
CLAUDE.md
Supertonic-3 dependency bump from v1.2.3 (2026-05-15) to v1.3.1 (2026-05-18), updating version compatibility table, PyPI reference links, and sources citations.

Estimated code review effort

🎯 1 (Trivial) | ⏱️ ~4 minutes

🐰 From the Warren, a Planning Proclamation:
Five phases planned with care and delight,
From subprocess backends to bug reports bright,
GGUF engines quantized with quant-map flair,
And v0.3.0 released with retro-review care! 🚀📋

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch docs/v0.3.0-planning-artifacts

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 8

Note

Due to the large number of review comments, Critical, Major severity comments were prioritized as inline comments.

🟡 Minor comments (17)
.planning/phases/03-supertonic-3-engine-installer-mirror-reliability/03-01-PLAN.md-452-460 (1)

452-460: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Terminate the STRIDE table cleanly before the closing tag.

The table is being linted as malformed at the closing line. Add a blank line between the final table row and </threat_model> so markdownlint stops treating the tag as a table row.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
@.planning/phases/03-supertonic-3-engine-installer-mirror-reliability/03-01-PLAN.md
around lines 452 - 460, The STRIDE table ends immediately before the closing tag
which causes markdownlint to parse the closing tag as a table row; insert a
single blank line between the final table row (the row containing "T-03-SC |
Tampering | supertonic supply chain") and the closing </threat_model> tag so the
table is terminated cleanly and linting passes.
.planning/phases/04-adaptive-specialty-engines-spike-first/04-02-PLAN.md-281-289 (1)

281-289: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Close the STRIDE table cleanly before </threat_model>.

Add a blank line after the last row so the closing tag is not parsed as a malformed table row.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.planning/phases/04-adaptive-specialty-engines-spike-first/04-02-PLAN.md
around lines 281 - 289, The STRIDE markdown table isn't terminated cleanly which
makes the closing tag </threat_model> parse as a table row; edit the table block
(the final rows including the T-04-12 row and the table footer) to add a blank
line after the last markdown table row and ensure the table delimiter/pipe lines
end before the </threat_model> tag so the table is closed properly before the
tag.
.planning/phases/03-supertonic-3-engine-installer-mirror-reliability/03-02-PLAN.md-325-332 (1)

325-332: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Fix malformed table termination in STRIDE section.

The table appears to bleed into the closing tag and triggers MD055/MD056. Insert a blank line after the final table row before </threat_model>.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
@.planning/phases/03-supertonic-3-engine-installer-mirror-reliability/03-02-PLAN.md
around lines 325 - 332, The markdown table in the STRIDE section is not properly
terminated which causes MD055/MD056; fix this by inserting a single blank line
after the last table row (after the T-03-10 row) and before the closing
</threat_model> tag so the table is separated from the XML/HTML close tag;
ensure the last row (T-03-10) remains unchanged and only a blank line is added.
.planning/phases/04-adaptive-specialty-engines-spike-first/04-02-PLAN.md-164-164 (1)

164-164: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Switch indented snippets to fenced code blocks (MD046).

Converting these to fenced blocks will resolve lint warnings and keep markdown rendering stable across viewers.

Also applies to: 206-206

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.planning/phases/04-adaptive-specialty-engines-spike-first/04-02-PLAN.md at
line 164, The markdown contains indented code snippets (e.g., the snippet
following the line "Read `backend/services/dub_pipeline.py` and identify:" and
the similar occurrence later) which trigger MD046; replace each indented snippet
with fenced code blocks using triple backticks (```), add an appropriate
language tag if known (e.g., ```python), and ensure opening and closing
backticks wrap the code exactly to preserve formatting and fix the lint
warnings.
.planning/phases/03-supertonic-3-engine-installer-mirror-reliability/03-01-PLAN.md-243-243 (1)

243-243: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Use fenced blocks instead of indented code blocks to satisfy markdownlint MD046.

These sections are being parsed as indented code blocks. Converting them to fenced blocks will remove lint warnings and keep rendering consistent.

Suggested pattern
-    1. Extend `backend/services/settings_store.py` with two helpers:
-       def get_license_accepted(engine_id: str) -> bool:
-           ...
+    1. Extend `backend/services/settings_store.py` with two helpers:
+
+       ```python
+       def get_license_accepted(engine_id: str) -> bool:
+           ...
+       ```

Also applies to: 288-288, 341-341, 408-408

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
@.planning/phases/03-supertonic-3-engine-installer-mirror-reliability/03-01-PLAN.md
at line 243, Indented code blocks in the document are being parsed as indented
code and trigger markdownlint MD046; replace each indented example block with
fenced code blocks using triple backticks and an appropriate language tag (e.g.,
```python) and a closing ``` so examples like the snippet containing the
function signature def get_license_accepted(engine_id: str) -> bool: are wrapped
as ```python ... ```; apply the same fenced-block conversion to the other
similar sections mentioned (the other occurrences of indented examples).
.planning/phases/04-adaptive-specialty-engines-spike-first/04-RESEARCH.md-117-117 (1)

117-117: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Add language identifiers to fenced code blocks (MD040).

Please annotate these fences (e.g., text for architecture diagrams) so markdownlint passes consistently.

Suggested edit style
-```
+```text
  ┌─────────────────────────────────────────────────────────────────────────┐
  ...
-```
+```

Also applies to: 165-165, 207-207

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.planning/phases/04-adaptive-specialty-engines-spike-first/04-RESEARCH.md at
line 117, Add explicit language identifiers to the fenced code blocks that
contain architecture diagrams and plain text so markdownlint rule MD040 is
satisfied; locate the three fenced blocks that currently use bare triple
backticks (the ASCII diagram and the other two blocks mentioned) and change
their opening fences from ``` to ```text (or another appropriate language like
```dot for diagrams) so each code fence is annotated consistently.
.planning/phases/04-adaptive-specialty-engines-spike-first/04-01-PLAN.md-191-191 (1)

191-191: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Normalize indented code samples to fenced blocks (MD046).

These list-embedded snippets should be fenced to avoid markdownlint warnings and improve renderer consistency.

Also applies to: 225-225, 263-263, 270-270

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.planning/phases/04-adaptive-specialty-engines-spike-first/04-01-PLAN.md at
line 191, Normalize the indented/list-embedded code examples into fenced code
blocks: locate the list item that currently shows Create
`backend/engines/omnivoice_gguf/__init__.py` (and the three other list-embedded
snippets flagged in this document) and replace the indented inline snippet style
with proper triple-backtick fenced code blocks (specify language where
appropriate), ensuring opening and closing fences surround the code so
markdownlint MD046 is satisfied.
.planning/phases/04-adaptive-specialty-engines-spike-first/04-01-PLAN.md-306-315 (1)

306-315: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Add a separator line between the STRIDE table and closing tag.

The current layout causes the closing tag to be interpreted as a malformed table row.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.planning/phases/04-adaptive-specialty-engines-spike-first/04-01-PLAN.md
around lines 306 - 315, The STRIDE table currently runs directly into the XML
closing tag and is being parsed as a table row; insert a separator line between
the table and the closing tag by adding a blank line or a Markdown horizontal
rule (e.g., a line with three dashes '---') immediately before </threat_model>
in .planning/phases/04-adaptive-specialty-engines-spike-first/04-01-PLAN.md so
the closing tag is not treated as table content.
.planning/phases/05-opt-in-bug-reporting/05-01-PLAN.md-178-178 (1)

178-178: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Specify a language on the interface fenced block.

Line 178 has an unlabeled code fence (MD040). Add a language (e.g., text) for lint compliance.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.planning/phases/05-opt-in-bug-reporting/05-01-PLAN.md at line 178, The
markdown contains an unlabeled fenced code block marked only by ``` which
triggers MD040; update that fence to include a language identifier (for example
change the opening ``` to ```text) so the block is language-labeled and
lint-compliant, leaving the fence contents unchanged.
.planning/phases/06-release-verification-retro/06-02-PLAN.md-74-74 (1)

74-74: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Add language identifier to the parity-check fenced block.

Line 74 uses an unlabeled fenced block; add bash to satisfy MD040 and keep workflow docs lint-clean.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.planning/phases/06-release-verification-retro/06-02-PLAN.md at line 74, The
unlabeled fenced code block (the triple backtick parity-check block) should be
updated to include the language identifier by replacing the opening ``` with
```bash so the block is labeled as bash (this satisfies MD040 and keeps the
workflow docs lint-clean).
.planning/phases/05-opt-in-bug-reporting/05-02-PLAN.md-168-168 (1)

168-168: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Add a language tag to the interface fenced block.

Line 168 uses an unlabeled fence, triggering MD040. Use text/json as appropriate.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.planning/phases/05-opt-in-bug-reporting/05-02-PLAN.md at line 168, The
fenced code block that contains the interface example is unlabeled and triggers
MD040; update its opening fence from ``` to a language tag such as ```text (or
```json if the block is valid JSON) so the block is explicitly labeled and the
linter warning is resolved.
.planning/phases/06-release-verification-retro/06-01-PLAN.md-32-32 (1)

32-32: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Fix milestone count wording to match the documented issue set.

Line 32 says “all 11 originally-open + addition issues,” but the plan enumerates 13 issue IDs later. Align this count text to avoid release gating confusion.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.planning/phases/06-release-verification-retro/06-01-PLAN.md at line 32,
Update the milestone count wording on the string "GitHub Milestone `v0.3.0`
exists and contains all 11 originally-open + addition issues" to match the
enumerated issue set (13 IDs) later in the plan; replace the quoted phrase with
wording such as "GitHub Milestone `v0.3.0` exists and contains all 13
originally-open + additional issues" or "GitHub Milestone `v0.3.0` exists and
contains the 13 issue IDs listed below" so the text in the line highlighted (the
quoted milestone sentence) aligns with the documented issue list.
.planning/phases/06-release-verification-retro/06-RESEARCH.md-162-162 (1)

162-162: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Label diagram/structure fenced blocks with a language.

Line 162 and Line 211 are unlabeled fences (MD040). Add text for both.

Also applies to: 211-211

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.planning/phases/06-release-verification-retro/06-RESEARCH.md at line 162,
There are two unlabeled fenced code blocks represented by triple backticks (```)
in the document; update each of those fences to include the language label
"text" (i.e., change ``` to ```text) so the Markdown linter rule MD040 is
satisfied for both occurrences.
.planning/phases/05-opt-in-bug-reporting/05-RESEARCH.md-181-181 (1)

181-181: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Add language identifiers to fenced blocks to satisfy markdownlint.

Line 181 and Line 237 use unlabeled fenced blocks, which keeps triggering MD040 and can break docs lint gates.

Suggested edit
-```
+```text
   ┌─────────────────────┐    ┌─────────────────────┐    ┌────────────────────────┐
   │ Python error        │    │ Rust panic          │    │ React error / console  │
   ...
-```
+```

-```
+```text
 backend/
 ├── services/
 │   ├── bug_report.py
 ...
-```
+```

Also applies to: 237-237

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.planning/phases/05-opt-in-bug-reporting/05-RESEARCH.md at line 181, Two
unlabeled fenced code blocks in
.planning/phases/05-opt-in-bug-reporting/05-RESEARCH.md (the ASCII diagram block
around the Python/Rust/React diagram and the backend tree block) trigger
markdownlint MD040; fix by adding a language identifier (use "text") after the
opening triple backticks for both fenced blocks so they read ```text. Locate the
unlabeled blocks by matching their contents (the ASCII diagram and the "backend/
├── services/ │ ├── bug_report.py" tree) and update the opening fence for each
to include the "text" label.
.planning/phases/05-opt-in-bug-reporting/05-RESEARCH.md-497-497 (1)

497-497: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Clarify URL-cap claim wording to avoid over-precision.

Line 497 states a concrete reliability cutoff (“~8 KB falls off; ~6 KB safe”) while the same doc marks this as community consensus, not an official limit. Tighten wording to “conservative cap” to avoid treating it as a hard platform guarantee.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.planning/phases/05-opt-in-bug-reporting/05-RESEARCH.md at line 497, Update
the sentence in .planning/phases/05-opt-in-bug-reporting/05-RESEARCH.md that
currently reads “~8 KB encoded is where reliability falls off; ~6 KB is the safe
upper bound” to soften the claim — replace it with wording that frames this as a
community-recommended conservative cap (e.g., “community-recommended
conservative cap of ~6 KB encoded, as reliability appears to degrade around ~8
KB”) so the doc avoids implying an official GitHub platform limit; keep the
existing mention of community consensus (sindresorhus/new-github-issue-url and
GitHub Community threads) for attribution.
.planning/phases/06-release-verification-retro/06-RESEARCH.md-775-775 (1)

775-775: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Escape || in the table cell to fix broken column parsing.

Line 775 includes inputs.draft || 'true' inside a markdown table row, which is parsed as extra columns (MD056). Escape the pipes or rewrite the expression.

Suggested edit
-| A6 | release.yml's `draft: ${{ inputs.draft || 'true' }}` default applies to tag pushes too (publishes as draft) | Anti-Patterns: "Forgetting `gh release edit --draft=false`" | Need to verify by reading tauri-action's handling of `releaseDraft`; if tag-push actually publishes non-draft by default, the "promote step" in the runbook isn't needed. |
+| A6 | release.yml's `draft: ${{ inputs.draft \|\| 'true' }}` default applies to tag pushes too (publishes as draft) | Anti-Patterns: "Forgetting `gh release edit --draft=false`" | Need to verify by reading tauri-action's handling of `releaseDraft`; if tag-push actually publishes non-draft by default, the "promote step" in the runbook isn't needed. |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.planning/phases/06-release-verification-retro/06-RESEARCH.md at line 775,
The markdown table row contains the expression release.yml's draft: ${{
inputs.draft || 'true' }} which breaks column parsing (MD056); fix it by
escaping the pipe characters in the `||` operator or by wrapping the entire
expression in inline code so the table cell is treated as one column; update the
cell that currently contains "release.yml's `draft: ${{ inputs.draft || 'true'
}}`" to use an escaped form (e.g., backslash-escaped pipes) or surround the
expression with backticks to prevent the table from splitting into extra
columns.
.planning/phases/05-opt-in-bug-reporting/05-01-PLAN.md-209-209 (1)

209-209: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Escape or code-wrap redact(redact(x)[0]) to avoid MD011 parse errors.

Line 209 is parsed as reversed link syntax because of (x)[0]. Wrap the expression in backticks or escape brackets to keep markdown parsing stable.

Suggested edit
-    - **Idempotency:** `redact(redact(x)[0])[0] == redact(x)[0]` for any x — explicit unit test
+    - **Idempotency:** `redact(redact(x)[0])[0] == redact(x)[0]` for any x — explicit unit test
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.planning/phases/05-opt-in-bug-reporting/05-01-PLAN.md at line 209, The
markdown line containing the idempotency property uses raw bracket syntax which
triggers MD011; wrap the whole expression redact(redact(x)[0])[0] ==
redact(x)[0] in inline code ticks (e.g., `redact(redact(x)[0])[0] ==
redact(x)[0]`) or escape the bracket characters (e.g.,
redact(redact(x)\[0\])\[0\] == redact(x)\[0\]) so the parser treats it as code
rather than link syntax; update the line that references the redact function and
the specific expression accordingly.
🧹 Nitpick comments (2)
.planning/phases/02-engine-isolation-subprocessbackend-indextts-wav-export-dubbi/02-04-PLAN.md (1)

205-220: ⚡ Quick win

Use a family-scoped health route to avoid future ID collisions.

/engines/{engine_id}/health requires cross-registry scanning and becomes ambiguous if TTS/ASR/LLM ever share IDs. Prefer /engines/{family}/{engine_id}/health now to keep contract deterministic.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
@.planning/phases/02-engine-isolation-subprocessbackend-indextts-wav-export-dubbi/02-04-PLAN.md
around lines 205 - 220, The current engine_health handler and route use a single
path GET /engines/{engine_id}/health and scan all registries
(tts_backend._REGISTRY, asr_backend._REGISTRY, llm_backend._REGISTRY), which is
ambiguous; change the route to GET /engines/{family}/{engine_id}/health and
update the engine_health function signature to accept family: str, validate
family ∈ {"tts","asr","llm"}, map family to the correct registry (e.g., {"tts":
tts_backend._REGISTRY, "asr": asr_backend._REGISTRY, "llm":
llm_backend._REGISTRY}), then look up engine_id only in that registry and raise
HTTPException(404) for unknown family or missing engine_id.
.planning/phases/02-engine-isolation-subprocessbackend-indextts-wav-export-dubbi/02-01-PLAN.md (1)

288-288: ⚡ Quick win

Avoid _work_queue.qsize() for GPU-slot assertions.

That relies on ThreadPoolExecutor internals and is brittle across Python/platform variants. Prefer asserting observable behavior (e.g., subsequent acquire/generate succeeds within timeout) instead of private queue state.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
@.planning/phases/02-engine-isolation-subprocessbackend-indextts-wav-export-dubbi/02-01-PLAN.md
at line 288, The test test_sidecar_dies_releases_gpu_slot should stop inspecting
ThreadPoolExecutor internals (avoid _get_gpu_pool()._work_queue.qsize()) and
instead assert observable behavior: after launching the sidecar with
OMNIVOICE_ECHO_CRASH=1 and the sidecar exits, attempt to acquire a GPU slot or
run a short generate/openai-like request using the same GPU pool (via
_get_gpu_pool() acquire/submit or the public generate API used by other tests)
and assert it completes within a reasonable timeout; update the test to wait for
the sidecar exit, then perform the acquire/generate and fail the test if it
times out, ensuring you reference test_sidecar_dies_releases_gpu_slot and
_get_gpu_pool() in the change.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.planning/decisions/SPIKE-02-singing.md:
- Around line 35-40: The current rule in OmniVoiceSingingBackend.generate() only
skips prepending when the prompt.startsWith('['), which lets prompts like
'[happy] ...' bypass the required singing tag and cause garbled output; change
the logic to check for the presence of the singing tag (e.g.,
prompt.includes('[singing]') with case-insensitive match) and only skip
prepending if that tag exists, otherwise always prepend '[singing]' to the
prompt before synthesis so power-user bracketed modifiers still work.

In
@.planning/phases/02-engine-isolation-subprocessbackend-indextts-wav-export-dubbi/02-01-PLAN.md:
- Line 283: The sidecar_script() function currently builds its path using
Path(__file__).parent.parent.parent which resolves relative to the tests tree
(tests/backend/...), causing wrong targets; update sidecar_script() to compute a
repo-root-anchored path instead (e.g., resolve Path(__file__).resolve() and walk
parents until you find a repo marker like pyproject.toml or the top-level
"backend" directory, or use git to locate repo root) so the returned path points
to the repo-root backend/engines/_echo/main.py and fixes failures seen in
tests/backend/services/test_subprocess_backend.py.

In
@.planning/phases/02-engine-isolation-subprocessbackend-indextts-wav-export-dubbi/02-02-PLAN.md:
- Line 276: The test's Phase 0 fixture probe currently marks the missing fixture
as xfail which contradicts the requirement to fail CI; change the probe so that
when tests/fixtures/sample_5s.mp4 is not present it calls pytest.fail (with a
clear message like "Phase 0 fixture missing — add tests/fixtures/sample_5s.mp4
before running.") instead of using xfail, updating the test/fixture check logic
(the "Phase 0 fixture probe") to assert failure via pytest.fail.

In
@.planning/phases/02-engine-isolation-subprocessbackend-indextts-wav-export-dubbi/02-03-PLAN.md:
- Line 256: The stub indextts package created under tmpdir/site-packages isn't
visible to the subprocess used by the _venv_can_import_indextts probe; update
tests/backend/services/test_indextts_backward_compat.py to make the stub
importable by the probed interpreter either by (A) setting the subprocess
environment PYTHONPATH to include tmp_path/"site-packages" before running python
-c "import indextts.infer_v2" or (B) resolving the target venv's real
site-packages path (via sysconfig or the venv's python -c query) and writing the
stub files into that site-packages location; use the existing
monkeypatch/tmp_path helpers to implement the chosen approach so the subprocess
import succeeds.

In
@.planning/phases/03-supertonic-3-engine-installer-mirror-reliability/03-RESEARCH.md:
- Around line 324-325: The import for SubprocessBackend is using the
non-canonical module path (engines._subprocess); change it to import the
primitive from the canonical Phase 2 location by importing SubprocessBackend
from backend.services.subprocess_backend so all references use the same module
(SubprocessBackend) and avoid implementation drift.
- Line 35: Pick a single mirror-rotation policy and make the document
consistent: either (A) allow runtime rotation of the allow-list (mirrors.json in
frontend/src-tauri/resources/mirrors.json) without a release, or (B) require app
updates to rotate mirrors. Locate and update the two contradictory statements
(the sentence asserting "rotatable without release" and the sentence stating
"rotation happens only via app updates") so they both state the chosen policy,
and update any dependent wording (e.g., architecture/requirements references) to
match.

In @.planning/phases/06-release-verification-retro/06-04-PLAN.md:
- Line 183: Several <verify><automated> XML blocks contain HTML-escaped shell
operators (&amp;&amp; and &amp;) which will break when executed; open each
<verify><automated> block (the ones used for Task 1, Task 4, Task 5, Task 7 and
the final verification) and replace the escaped sequences &amp;&amp; and &amp;
with the actual shell operators && and & in the GH CLI commands (e.g., the gh
release view ... and gh run list ... command lines) so the commands run
correctly in a shell.
- Line 181: The stderr redirection in the `<action>` command contains an
XML-escaped ampersand (`2>&amp;1`) which breaks the shell redirection; update
the action text that runs `gh release view v0.3.0-rc1 2>&amp;1 | grep -q
"release not found"` to use the correct shell token `2>&1` (i.e., replace
`2>&amp;1` with `2>&1`) so the pipeline `gh release view v0.3.0-rc1 2>&1 | grep
-q "release not found"` works as intended.

---

Minor comments:
In
@.planning/phases/03-supertonic-3-engine-installer-mirror-reliability/03-01-PLAN.md:
- Around line 452-460: The STRIDE table ends immediately before the closing tag
which causes markdownlint to parse the closing tag as a table row; insert a
single blank line between the final table row (the row containing "T-03-SC |
Tampering | supertonic supply chain") and the closing </threat_model> tag so the
table is terminated cleanly and linting passes.
- Line 243: Indented code blocks in the document are being parsed as indented
code and trigger markdownlint MD046; replace each indented example block with
fenced code blocks using triple backticks and an appropriate language tag (e.g.,
```python) and a closing ``` so examples like the snippet containing the
function signature def get_license_accepted(engine_id: str) -> bool: are wrapped
as ```python ... ```; apply the same fenced-block conversion to the other
similar sections mentioned (the other occurrences of indented examples).

In
@.planning/phases/03-supertonic-3-engine-installer-mirror-reliability/03-02-PLAN.md:
- Around line 325-332: The markdown table in the STRIDE section is not properly
terminated which causes MD055/MD056; fix this by inserting a single blank line
after the last table row (after the T-03-10 row) and before the closing
</threat_model> tag so the table is separated from the XML/HTML close tag;
ensure the last row (T-03-10) remains unchanged and only a blank line is added.

In @.planning/phases/04-adaptive-specialty-engines-spike-first/04-01-PLAN.md:
- Line 191: Normalize the indented/list-embedded code examples into fenced code
blocks: locate the list item that currently shows Create
`backend/engines/omnivoice_gguf/__init__.py` (and the three other list-embedded
snippets flagged in this document) and replace the indented inline snippet style
with proper triple-backtick fenced code blocks (specify language where
appropriate), ensuring opening and closing fences surround the code so
markdownlint MD046 is satisfied.
- Around line 306-315: The STRIDE table currently runs directly into the XML
closing tag and is being parsed as a table row; insert a separator line between
the table and the closing tag by adding a blank line or a Markdown horizontal
rule (e.g., a line with three dashes '---') immediately before </threat_model>
in .planning/phases/04-adaptive-specialty-engines-spike-first/04-01-PLAN.md so
the closing tag is not treated as table content.

In @.planning/phases/04-adaptive-specialty-engines-spike-first/04-02-PLAN.md:
- Around line 281-289: The STRIDE markdown table isn't terminated cleanly which
makes the closing tag </threat_model> parse as a table row; edit the table block
(the final rows including the T-04-12 row and the table footer) to add a blank
line after the last markdown table row and ensure the table delimiter/pipe lines
end before the </threat_model> tag so the table is closed properly before the
tag.
- Line 164: The markdown contains indented code snippets (e.g., the snippet
following the line "Read `backend/services/dub_pipeline.py` and identify:" and
the similar occurrence later) which trigger MD046; replace each indented snippet
with fenced code blocks using triple backticks (```), add an appropriate
language tag if known (e.g., ```python), and ensure opening and closing
backticks wrap the code exactly to preserve formatting and fix the lint
warnings.

In @.planning/phases/04-adaptive-specialty-engines-spike-first/04-RESEARCH.md:
- Line 117: Add explicit language identifiers to the fenced code blocks that
contain architecture diagrams and plain text so markdownlint rule MD040 is
satisfied; locate the three fenced blocks that currently use bare triple
backticks (the ASCII diagram and the other two blocks mentioned) and change
their opening fences from ``` to ```text (or another appropriate language like
```dot for diagrams) so each code fence is annotated consistently.

In @.planning/phases/05-opt-in-bug-reporting/05-01-PLAN.md:
- Line 178: The markdown contains an unlabeled fenced code block marked only by
``` which triggers MD040; update that fence to include a language identifier
(for example change the opening ``` to ```text) so the block is language-labeled
and lint-compliant, leaving the fence contents unchanged.
- Line 209: The markdown line containing the idempotency property uses raw
bracket syntax which triggers MD011; wrap the whole expression
redact(redact(x)[0])[0] == redact(x)[0] in inline code ticks (e.g.,
`redact(redact(x)[0])[0] == redact(x)[0]`) or escape the bracket characters
(e.g., redact(redact(x)\[0\])\[0\] == redact(x)\[0\]) so the parser treats it as
code rather than link syntax; update the line that references the redact
function and the specific expression accordingly.

In @.planning/phases/05-opt-in-bug-reporting/05-02-PLAN.md:
- Line 168: The fenced code block that contains the interface example is
unlabeled and triggers MD040; update its opening fence from ``` to a language
tag such as ```text (or ```json if the block is valid JSON) so the block is
explicitly labeled and the linter warning is resolved.

In @.planning/phases/05-opt-in-bug-reporting/05-RESEARCH.md:
- Line 181: Two unlabeled fenced code blocks in
.planning/phases/05-opt-in-bug-reporting/05-RESEARCH.md (the ASCII diagram block
around the Python/Rust/React diagram and the backend tree block) trigger
markdownlint MD040; fix by adding a language identifier (use "text") after the
opening triple backticks for both fenced blocks so they read ```text. Locate the
unlabeled blocks by matching their contents (the ASCII diagram and the "backend/
├── services/ │ ├── bug_report.py" tree) and update the opening fence for each
to include the "text" label.
- Line 497: Update the sentence in
.planning/phases/05-opt-in-bug-reporting/05-RESEARCH.md that currently reads “~8
KB encoded is where reliability falls off; ~6 KB is the safe upper bound” to
soften the claim — replace it with wording that frames this as a
community-recommended conservative cap (e.g., “community-recommended
conservative cap of ~6 KB encoded, as reliability appears to degrade around ~8
KB”) so the doc avoids implying an official GitHub platform limit; keep the
existing mention of community consensus (sindresorhus/new-github-issue-url and
GitHub Community threads) for attribution.

In @.planning/phases/06-release-verification-retro/06-01-PLAN.md:
- Line 32: Update the milestone count wording on the string "GitHub Milestone
`v0.3.0` exists and contains all 11 originally-open + addition issues" to match
the enumerated issue set (13 IDs) later in the plan; replace the quoted phrase
with wording such as "GitHub Milestone `v0.3.0` exists and contains all 13
originally-open + additional issues" or "GitHub Milestone `v0.3.0` exists and
contains the 13 issue IDs listed below" so the text in the line highlighted (the
quoted milestone sentence) aligns with the documented issue list.

In @.planning/phases/06-release-verification-retro/06-02-PLAN.md:
- Line 74: The unlabeled fenced code block (the triple backtick parity-check
block) should be updated to include the language identifier by replacing the
opening ``` with ```bash so the block is labeled as bash (this satisfies MD040
and keeps the workflow docs lint-clean).

In @.planning/phases/06-release-verification-retro/06-RESEARCH.md:
- Line 162: There are two unlabeled fenced code blocks represented by triple
backticks (```) in the document; update each of those fences to include the
language label "text" (i.e., change ``` to ```text) so the Markdown linter rule
MD040 is satisfied for both occurrences.
- Line 775: The markdown table row contains the expression release.yml's draft:
${{ inputs.draft || 'true' }} which breaks column parsing (MD056); fix it by
escaping the pipe characters in the `||` operator or by wrapping the entire
expression in inline code so the table cell is treated as one column; update the
cell that currently contains "release.yml's `draft: ${{ inputs.draft || 'true'
}}`" to use an escaped form (e.g., backslash-escaped pipes) or surround the
expression with backticks to prevent the table from splitting into extra
columns.

---

Nitpick comments:
In
@.planning/phases/02-engine-isolation-subprocessbackend-indextts-wav-export-dubbi/02-01-PLAN.md:
- Line 288: The test test_sidecar_dies_releases_gpu_slot should stop inspecting
ThreadPoolExecutor internals (avoid _get_gpu_pool()._work_queue.qsize()) and
instead assert observable behavior: after launching the sidecar with
OMNIVOICE_ECHO_CRASH=1 and the sidecar exits, attempt to acquire a GPU slot or
run a short generate/openai-like request using the same GPU pool (via
_get_gpu_pool() acquire/submit or the public generate API used by other tests)
and assert it completes within a reasonable timeout; update the test to wait for
the sidecar exit, then perform the acquire/generate and fail the test if it
times out, ensuring you reference test_sidecar_dies_releases_gpu_slot and
_get_gpu_pool() in the change.

In
@.planning/phases/02-engine-isolation-subprocessbackend-indextts-wav-export-dubbi/02-04-PLAN.md:
- Around line 205-220: The current engine_health handler and route use a single
path GET /engines/{engine_id}/health and scan all registries
(tts_backend._REGISTRY, asr_backend._REGISTRY, llm_backend._REGISTRY), which is
ambiguous; change the route to GET /engines/{family}/{engine_id}/health and
update the engine_health function signature to accept family: str, validate
family ∈ {"tts","asr","llm"}, map family to the correct registry (e.g., {"tts":
tts_backend._REGISTRY, "asr": asr_backend._REGISTRY, "llm":
llm_backend._REGISTRY}), then look up engine_id only in that registry and raise
HTTPException(404) for unknown family or missing engine_id.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 64dff68d-de0d-4695-863b-957e10528a71

📥 Commits

Reviewing files that changed from the base of the PR and between e4dbf4c and ff336e6.

📒 Files selected for processing (23)
  • .planning/decisions/SPIKE-01-gguf.md
  • .planning/decisions/SPIKE-02-singing.md
  • .planning/phases/02-engine-isolation-subprocessbackend-indextts-wav-export-dubbi/02-01-PLAN.md
  • .planning/phases/02-engine-isolation-subprocessbackend-indextts-wav-export-dubbi/02-02-PLAN.md
  • .planning/phases/02-engine-isolation-subprocessbackend-indextts-wav-export-dubbi/02-03-PLAN.md
  • .planning/phases/02-engine-isolation-subprocessbackend-indextts-wav-export-dubbi/02-04-PLAN.md
  • .planning/phases/02-engine-isolation-subprocessbackend-indextts-wav-export-dubbi/02-RESEARCH.md
  • .planning/phases/03-supertonic-3-engine-installer-mirror-reliability/03-01-PLAN.md
  • .planning/phases/03-supertonic-3-engine-installer-mirror-reliability/03-02-PLAN.md
  • .planning/phases/03-supertonic-3-engine-installer-mirror-reliability/03-RESEARCH.md
  • .planning/phases/04-adaptive-specialty-engines-spike-first/04-01-PLAN.md
  • .planning/phases/04-adaptive-specialty-engines-spike-first/04-02-PLAN.md
  • .planning/phases/04-adaptive-specialty-engines-spike-first/04-RESEARCH.md
  • .planning/phases/05-opt-in-bug-reporting/05-01-PLAN.md
  • .planning/phases/05-opt-in-bug-reporting/05-02-PLAN.md
  • .planning/phases/05-opt-in-bug-reporting/05-03-PLAN.md
  • .planning/phases/05-opt-in-bug-reporting/05-RESEARCH.md
  • .planning/phases/06-release-verification-retro/06-01-PLAN.md
  • .planning/phases/06-release-verification-retro/06-02-PLAN.md
  • .planning/phases/06-release-verification-retro/06-03-PLAN.md
  • .planning/phases/06-release-verification-retro/06-04-PLAN.md
  • .planning/phases/06-release-verification-retro/06-RESEARCH.md
  • CLAUDE.md

Comment on lines +35 to +40
- `omnivoice-singing` returns garbled output if the `[singing]` tag is missing — automatic injection is load-bearing.

**Mitigations:**
- Per-segment override available in the dubbing UI before any segment is committed to a render (user owns the final route — SING-03 already requires this).
- SING-05 acceptance scoped to native-language singing pass; cross-language flagged as best-effort with model-card disclaimer surfaced in the engine card UI.
- `OmniVoiceSingingBackend.generate()` always prepends `[singing]` unless the prompt already starts with `[`, allowing power users to compose `[singing] [happy]` etc. manually.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Always enforce [singing] presence, not just “starts with [”.

Line 35 states missing [singing] yields garbled output, but Line 40’s rule allows prompts like [happy] ... to bypass injection and break synthesis. Gate on “contains [singing]” (or prepend it) rather than “starts with [”.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.planning/decisions/SPIKE-02-singing.md around lines 35 - 40, The current
rule in OmniVoiceSingingBackend.generate() only skips prepending when the
prompt.startsWith('['), which lets prompts like '[happy] ...' bypass the
required singing tag and cause garbled output; change the logic to check for the
presence of the singing tag (e.g., prompt.includes('[singing]') with
case-insensitive match) and only skip prepending if that tag exists, otherwise
always prepend '[singing]' to the prompt before synthesis so power-user
bracketed modifiers still work.

Step 3 — Define an `_EchoBackend(SubprocessBackend)` subclass IN THE TEST FILE (not in production code, to keep _REGISTRY clean):
- `id = "_echo"`, `display_name = "Echo (test)"`.
- `venv_python()` returns `Path(sys.executable)` — echo sidecar runs under the parent's Python so the test does not require a separate venv.
- `sidecar_script()` returns `Path(__file__).parent.parent.parent / "backend" / "engines" / "_echo" / "main.py"`.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

sidecar_script() path example resolves to the wrong tree.

From tests/backend/services/test_subprocess_backend.py, Path(__file__).parent.parent.parent / "backend" / ... points under tests/backend/..., not repo-root backend/.... Use a root-anchored resolver (or fd-located absolute path) to avoid false test failures.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
@.planning/phases/02-engine-isolation-subprocessbackend-indextts-wav-export-dubbi/02-01-PLAN.md
at line 283, The sidecar_script() function currently builds its path using
Path(__file__).parent.parent.parent which resolves relative to the tests tree
(tests/backend/...), causing wrong targets; update sidecar_script() to compute a
repo-root-anchored path instead (e.g., resolve Path(__file__).resolve() and walk
parents until you find a repo marker like pyproject.toml or the top-level
"backend" directory, or use git to locate repo root) so the returned path points
to the repo-root backend/engines/_echo/main.py and fixes failures seen in
tests/backend/services/test_subprocess_backend.py.


Step 7 — Write `tests/backend/test_dub_pipeline_wav.py`:
- Use `from fastapi.testclient import TestClient` + the app factory from `backend/main.py`.
- Phase 0 fixture probe: check if `tests/fixtures/sample_5s.mp4` exists. If not, the test xfails with a clear message: "Phase 0 fixture missing — add tests/fixtures/sample_5s.mp4 before running." (Do NOT skip silently — the test needs to surface the missing fixture as a CI failure so it gets fixed.)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

xfail conflicts with the stated “must fail CI” requirement.

Line 276 requests xfail for missing fixture but also says absence must be surfaced as a CI failure. Use an explicit assertion/fail (pytest.fail) for missing required fixtures so the gate is enforced.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
@.planning/phases/02-engine-isolation-subprocessbackend-indextts-wav-export-dubbi/02-02-PLAN.md
at line 276, The test's Phase 0 fixture probe currently marks the missing
fixture as xfail which contradicts the requirement to fail CI; change the probe
so that when tests/fixtures/sample_5s.mp4 is not present it calls pytest.fail
(with a clear message like "Phase 0 fixture missing — add
tests/fixtures/sample_5s.mp4 before running.") instead of using xfail, updating
the test/fixture check logic (the "Phase 0 fixture probe") to assert failure via
pytest.fail.

- Returns True if either Probe 1 OR Probe 2 path has a Python executable present (file existence only — no import probe; the import probe runs at resolve time, not at every is_available() call which fires on every Settings page render).
- Cache the resolved path in a module-level variable; clear with `invalidate()` for tests.

Step 3 — Write `tests/backend/services/test_indextts_backward_compat.py` per `<behavior>`. Use `pytest`'s `monkeypatch` and `tmp_path` heavily. For the `_venv_can_import_indextts` probe, in tests, the stub indextts package can be as small as `mkdir -p {tmpdir}/site-packages/indextts && touch {tmpdir}/site-packages/indextts/__init__.py && touch {tmpdir}/site-packages/indextts/infer_v2.py` — the import only needs to succeed at `import indextts.infer_v2`, the test doesn't care about the contents.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Stub-package setup is incomplete for the subprocess import probe.

Creating tmpdir/site-packages/indextts/... alone won’t satisfy python -c "import indextts.infer_v2" unless PYTHONPATH/venv site-packages are wired. Add explicit path injection or build the stub in the probed interpreter’s real site-packages.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
@.planning/phases/02-engine-isolation-subprocessbackend-indextts-wav-export-dubbi/02-03-PLAN.md
at line 256, The stub indextts package created under tmpdir/site-packages isn't
visible to the subprocess used by the _venv_can_import_indextts probe; update
tests/backend/services/test_indextts_backward_compat.py to make the stub
importable by the probed interpreter either by (A) setting the subprocess
environment PYTHONPATH to include tmp_path/"site-packages" before running python
-c "import indextts.infer_v2" or (B) resolving the target venv's real
site-packages path (via sysconfig or the venv's python -c query) and writing the
stub files into that site-packages location; use the existing
monkeypatch/tmp_path helpers to implement the chosen approach so the subprocess
import succeeds.

2. **Model revision pinned by commit SHA, not tag** (TTS-03). The model card is being actively updated (5 commits in the last 12 days as of 2026-05-18). A tag pin is not strong enough — pin to a specific SHA. See Open Questions Q2.
3. **License acceptance gates first use** (TTS-05). The Supertonic-3 model ships under **OpenRAIL-M** (model weights, restricted-use clauses) while the SDK code is **MIT**. We surface both in the engine card with click-through links and require explicit acceptance before download/first generate.
4. **CPU-only honesty** (TTS-04). The engine MUST report CPU-only when CUDA is absent. Because Supertonic-3 has no CUDA path at all in the current SDK, `is_available()` reports `"cpu"` everywhere — no `"mps"` or `"cuda"` paths claimed.
5. **Mirror list is allow-list, JSON-shipped** (INST-08, INST-09). User cannot enter freeform URLs (supply-chain risk per Out of Scope table in REQUIREMENTS.md). The allow-list lives in `frontend/src-tauri/resources/mirrors.json` (or equivalent — see Architecture below) and is rotatable without a release.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Mirror-rotation policy is self-contradictory.

Line 35 says the mirror list is rotatable without release, while Line 658/660 says rotation happens only via app updates. Pick one policy and align all sections to avoid execution-time confusion.

Also applies to: 658-660

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
@.planning/phases/03-supertonic-3-engine-installer-mirror-reliability/03-RESEARCH.md
at line 35, Pick a single mirror-rotation policy and make the document
consistent: either (A) allow runtime rotation of the allow-list (mirrors.json in
frontend/src-tauri/resources/mirrors.json) without a release, or (B) require app
updates to rotate mirrors. Locate and update the two contradictory statements
(the sentence asserting "rotatable without release" and the sentence stating
"rotation happens only via app updates") so they both state the chosen policy,
and update any dependent wording (e.g., architecture/requirements references) to
match.

Comment on lines +324 to +325
from engines._subprocess import SubprocessBackend

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

SubprocessBackend import path is inconsistent with Phase 2 contracts.

This example uses engines._subprocess, but Phase 2 artifacts define the primitive in backend/services/subprocess_backend.py. Keep one canonical path to prevent implementation drift.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
@.planning/phases/03-supertonic-3-engine-installer-mirror-reliability/03-RESEARCH.md
around lines 324 - 325, The import for SubprocessBackend is using the
non-canonical module path (engines._subprocess); change it to import the
primitive from the canonical Phase 2 location by importing SubprocessBackend
from backend.services.subprocess_backend so all references use the same module
(SubprocessBackend) and avoid implementation drift.

<task type="auto">
<name>Task 1: Pre-tag verification + cut v0.3.0-rc1</name>
<files>(no file modifications — only git tag and gh API calls)</files>
<action>Run all pre-tag gates from `<interfaces>` in order: (1) `git status` (clean working tree on main); (2) `git fetch origin && git rev-list --left-right --count main...origin/main` (no divergence); (3) `uv run pytest tests/test_version_consistency.py -v` (must pass); (4) `gh run list --workflow=ci.yml --limit 1 --branch main --json conclusion --jq '.[0].conclusion'` (must equal `success`); (5) `gh run list --workflow=release.yml --limit 1 --branch main --json conclusion --jq '.[0].conclusion'` (must equal `success` from the most recent merged PR's dry-run via 06-02); (6) verify `gh release view v0.3.0-rc1 2>&amp;1 | grep -q "release not found"` (rc1 not yet cut). If any gate fails, STOP and surface the failure. If all pass, cut rc1: `git tag -a v0.3.0-rc1 -m "v0.3.0-rc1: Stabilization milestone release candidate 1"` then `git push origin v0.3.0-rc1`. Watch the run: `gh run watch` (blocks until the workflow completes). After release.yml succeeds across all 3 matrix legs (macOS-14, windows-2022, ubuntu-22.04 per release.yml:122-145), mark the rc1 GH Release as pre-release: `gh release edit v0.3.0-rc1 --prerelease`. Capture the release URL, draft status, and SHA256SUMS-*.txt attachment list — write them as a section header in `.planning/release/v0.3.0-runbook.md` under a new "rc1 cut record" subsection so the next task has a clean handoff.</action>
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical | ⚡ Quick win

Additional XML escape in Task 1 action block.

Line 181 contains 2>&amp;1 in the stderr redirection pattern, which should be 2>&1. This is part of the command: gh release view v0.3.0-rc1 2>&amp;1 | grep -q "release not found".

🐛 Proposed fix

Within the <action> block at line 181, locate and replace:

-verify `gh release view v0.3.0-rc1 2>&amp;1 | grep -q "release not found"`
+verify `gh release view v0.3.0-rc1 2>&1 | grep -q "release not found"`
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
<action>Run all pre-tag gates from `<interfaces>` in order: (1) `git status` (clean working tree on main); (2) `git fetch origin && git rev-list --left-right --count main...origin/main` (no divergence); (3) `uv run pytest tests/test_version_consistency.py -v` (must pass); (4) `gh run list --workflow=ci.yml --limit 1 --branch main --json conclusion --jq '.[0].conclusion'` (must equal `success`); (5) `gh run list --workflow=release.yml --limit 1 --branch main --json conclusion --jq '.[0].conclusion'` (must equal `success` from the most recent merged PR's dry-run via 06-02); (6) verify `gh release view v0.3.0-rc1 2>&amp;1 | grep -q "release not found"` (rc1 not yet cut). If any gate fails, STOP and surface the failure. If all pass, cut rc1: `git tag -a v0.3.0-rc1 -m "v0.3.0-rc1: Stabilization milestone release candidate 1"` then `git push origin v0.3.0-rc1`. Watch the run: `gh run watch` (blocks until the workflow completes). After release.yml succeeds across all 3 matrix legs (macOS-14, windows-2022, ubuntu-22.04 per release.yml:122-145), mark the rc1 GH Release as pre-release: `gh release edit v0.3.0-rc1 --prerelease`. Capture the release URL, draft status, and SHA256SUMS-*.txt attachment list — write them as a section header in `.planning/release/v0.3.0-runbook.md` under a new "rc1 cut record" subsection so the next task has a clean handoff.</action>
<action>Run all pre-tag gates from `<interfaces>` in order: (1) `git status` (clean working tree on main); (2) `git fetch origin && git rev-list --left-right --count main...origin/main` (no divergence); (3) `uv run pytest tests/test_version_consistency.py -v` (must pass); (4) `gh run list --workflow=ci.yml --limit 1 --branch main --json conclusion --jq '.[0].conclusion'` (must equal `success`); (5) `gh run list --workflow=release.yml --limit 1 --branch main --json conclusion --jq '.[0].conclusion'` (must equal `success` from the most recent merged PR's dry-run via 06-02); (6) verify `gh release view v0.3.0-rc1 2>&1 | grep -q "release not found"` (rc1 not yet cut). If any gate fails, STOP and surface the failure. If all pass, cut rc1: `git tag -a v0.3.0-rc1 -m "v0.3.0-rc1: Stabilization milestone release candidate 1"` then `git push origin v0.3.0-rc1`. Watch the run: `gh run watch` (blocks until the workflow completes). After release.yml succeeds across all 3 matrix legs (macOS-14, windows-2022, ubuntu-22.04 per release.yml:122-145), mark the rc1 GH Release as pre-release: `gh release edit v0.3.0-rc1 --prerelease`. Capture the release URL, draft status, and SHA256SUMS-*.txt attachment list — write them as a section header in `.planning/release/v0.3.0-runbook.md` under a new "rc1 cut record" subsection so the next task has a clean handoff.</action>
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.planning/phases/06-release-verification-retro/06-04-PLAN.md at line 181,
The stderr redirection in the `<action>` command contains an XML-escaped
ampersand (`2>&amp;1`) which breaks the shell redirection; update the action
text that runs `gh release view v0.3.0-rc1 2>&amp;1 | grep -q "release not
found"` to use the correct shell token `2>&1` (i.e., replace `2>&amp;1` with
`2>&1`) so the pipeline `gh release view v0.3.0-rc1 2>&1 | grep -q "release not
found"` works as intended.

<files>(no file modifications — only git tag and gh API calls)</files>
<action>Run all pre-tag gates from `<interfaces>` in order: (1) `git status` (clean working tree on main); (2) `git fetch origin && git rev-list --left-right --count main...origin/main` (no divergence); (3) `uv run pytest tests/test_version_consistency.py -v` (must pass); (4) `gh run list --workflow=ci.yml --limit 1 --branch main --json conclusion --jq '.[0].conclusion'` (must equal `success`); (5) `gh run list --workflow=release.yml --limit 1 --branch main --json conclusion --jq '.[0].conclusion'` (must equal `success` from the most recent merged PR's dry-run via 06-02); (6) verify `gh release view v0.3.0-rc1 2>&amp;1 | grep -q "release not found"` (rc1 not yet cut). If any gate fails, STOP and surface the failure. If all pass, cut rc1: `git tag -a v0.3.0-rc1 -m "v0.3.0-rc1: Stabilization milestone release candidate 1"` then `git push origin v0.3.0-rc1`. Watch the run: `gh run watch` (blocks until the workflow completes). After release.yml succeeds across all 3 matrix legs (macOS-14, windows-2022, ubuntu-22.04 per release.yml:122-145), mark the rc1 GH Release as pre-release: `gh release edit v0.3.0-rc1 --prerelease`. Capture the release URL, draft status, and SHA256SUMS-*.txt attachment list — write them as a section header in `.planning/release/v0.3.0-runbook.md` under a new "rc1 cut record" subsection so the next task has a clean handoff.</action>
<verify>
<automated>gh release view v0.3.0-rc1 --json tagName,isDraft,isPrerelease,assets --jq '{tag:.tagName,draft:.isDraft,prerelease:.isPrerelease,assetCount:(.assets|length)}' &amp;&amp; gh run list --workflow=release.yml --branch main --limit 1 --json conclusion --jq '.[0].conclusion'</automated>
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical | ⚡ Quick win

Critical: XML escape sequences will break shell commands.

The <verify><automated> blocks contain &amp;&amp; and &amp; instead of && and &, which are XML/HTML escape sequences. When these commands execute in a shell context, they will fail with syntax errors because the shell will interpret the literal string &amp;&amp; rather than the logical AND operator &&.

Affected locations:

  • Task 1 verification (Line 183)
  • Task 4 verification (Line 234)
  • Task 5 verification (Line 244)
  • Task 7 verification (Line 283)
  • Final verification section (Lines 315-318)
🐛 Proposed fix: Replace XML escapes with shell operators

Line 183 (Task 1):

-    <automated>gh release view v0.3.0-rc1 --json tagName,isDraft,isPrerelease,assets --jq '{tag:.tagName,draft:.isDraft,prerelease:.isPrerelease,assetCount:(.assets|length)}' &amp;&amp; gh run list --workflow=release.yml --branch main --limit 1 --json conclusion --jq '.[0].conclusion'</automated>
+    <automated>gh release view v0.3.0-rc1 --json tagName,isDraft,isPrerelease,assets --jq '{tag:.tagName,draft:.isDraft,prerelease:.isPrerelease,assetCount:(.assets|length)}' && gh run list --workflow=release.yml --branch main --limit 1 --json conclusion --jq '.[0].conclusion'</automated>

Line 234 (Task 4):

-    <automated>RELEASE_GATE=1 uv run pytest tests/test_changelog.py -v &amp;&amp; gh release view v0.3.0 --json tagName,isDraft,isPrerelease,assets,body --jq '{tag:.tagName,draft:.isDraft,pre:.isPrerelease,assetCount:(.assets|length),bodyLen:(.body|length),hasFallback:(.body|test("Auto-generated release"))}'</automated>
+    <automated>RELEASE_GATE=1 uv run pytest tests/test_changelog.py -v && gh release view v0.3.0 --json tagName,isDraft,isPrerelease,assets,body --jq '{tag:.tagName,draft:.isDraft,pre:.isPrerelease,assetCount:(.assets|length),bodyLen:(.body|length),hasFallback:(.body|test("Auto-generated release"))}'</automated>

Line 244 (Task 5):

-    <automated>gh issue list --label deferred-from-v0.3 --milestone v0.4 --state open --json number --jq 'length' &amp;&amp; awk '/^## \[0\.3\.0\]/{flag=1;next}/^## \[/{flag=0}flag' CHANGELOG.md | grep -cE "^\| #(35|42|48|54|55|56|57|58|60|65|72|76|80) " &amp;&amp; for n in 35 42 48 54 55 56 57 58 60 65 72 76 80; do echo -n "$n:"; gh issue view $n --json state --jq .state; done</automated>
+    <automated>gh issue list --label deferred-from-v0.3 --milestone v0.4 --state open --json number --jq 'length' && awk '/^## \[0\.3\.0\]/{flag=1;next}/^## \[/{flag=0}flag' CHANGELOG.md | grep -cE "^\| #(35|42|48|54|55|56|57|58|60|65|72|76|80) " && for n in 35 42 48 54 55 56 57 58 60 65 72 76 80; do echo -n "$n:"; gh issue view $n --json state --jq .state; done</automated>

Line 283 (Task 7):

-    <automated>test -f .planning/retros/v0.3.0-retro.md &amp;&amp; wc -l .planning/retros/v0.3.0-retro.md &amp;&amp; grep -c "^## " .planning/retros/v0.3.0-retro.md &amp;&amp; grep -cE "Weighted closure|Net inbox|Discord support" .planning/retros/v0.3.0-retro.md</automated>
+    <automated>test -f .planning/retros/v0.3.0-retro.md && wc -l .planning/retros/v0.3.0-retro.md && grep -c "^## " .planning/retros/v0.3.0-retro.md && grep -cE "Weighted closure|Net inbox|Discord support" .planning/retros/v0.3.0-retro.md</automated>

Lines 315-318 (Verification section):

 - `gh release view v0.3.0 --json tagName,isDraft,isPrerelease,assets --jq '{tag:.tagName,draft:.isDraft,pre:.isPrerelease,assetCount:(.assets|length)}'` => `{tag:"v0.3.0", draft:false, pre:false, assetCount: >= 8}`
 - `RELEASE_GATE=1 uv run pytest tests/test_changelog.py -v` => pass
 - `grep -E "^## \[0\.3\.0\] — 2[0-9]{3}-[0-9]{2}-[0-9]{2}$" CHANGELOG.md` => 1 match
 - `gh issue list --label deferred-from-v0.3 --milestone v0.4 --state open --json number --jq 'length'` => 3
 - For each of `35 42 48 54 55 56 57 58 60 65 72 76 80`: `gh issue view <n> --json state,milestone` shows CLOSED or v0.4-milestone
-- `.planning/retros/v0.3.0-retro.md` exists with all 6 sections and 3 metrics populated
-- `.planning/release/verification-matrix.md` "Wave-2 verifier signoff" column is filled for all rows

(Note: Lines 319-320 don't contain shell commands with &&, so no changes needed there.)

Also applies to: 234-234, 244-244, 283-283, 315-318

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.planning/phases/06-release-verification-retro/06-04-PLAN.md at line 183,
Several <verify><automated> XML blocks contain HTML-escaped shell operators
(&amp;&amp; and &amp;) which will break when executed; open each
<verify><automated> block (the ones used for Task 1, Task 4, Task 5, Task 7 and
the final verification) and replace the escaped sequences &amp;&amp; and &amp;
with the actual shell operators && and & in the GH CLI commands (e.g., the gh
release view ... and gh run list ... command lines) so the commands run
correctly in a shell.

@debpalash debpalash merged commit a5e1bb3 into main May 19, 2026
8 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant