SpeakTrue

M004 Workflow Validation and UAT Pack

Reader and post-read action

This pack is for a reviewer landing cold on M004/S05. After reading it, the reviewer should be able to trace R045 and R046 from the product target through local executable proof, run the validation guard for this pack, and perform the prerequisite-gated manual UAT for the legacy web generate speech to Soundboard workflow without using privileged browser storage writes.

Scope

This document validates the M004 product-visible path where generated speech is saved for Soundboard reuse. It consumes these tracked source documents instead of replacing them:

This pack does not claim live Supabase, GCS, ElevenLabs, or production-storage proof. Manual UAT that depends on live provider or storage credentials is prerequisite-gated and must be recorded separately when those credentials and a safe test account are available.

Decision context

R045 validation: generate speech can be saved and reused from Soundboard

R045 requires users to generate speech from text and save or reuse the generated result from the Soundboard workflow. The proof chain is:

  1. The legacy web target defines the user path: generate speech, retain the latest generated artifact reference, save that artifact to a selected Soundboard category, reload the category, then play, download, or reuse the saved clip.
  2. The browser VM check validates the client-side state handoff. It verifies that window.latestTTSSpeechArtifact and window.__ttsSoundboardWorkflowTestHooks.getState() expose the generated artifact and save diagnostics without depending on toast prose alone.
  3. Flask contract pytest validates the server-side workflow. It covers /api/text-to-speech, /api/soundboard/save-clip, canonical artifact fields, save metadata, category reload metadata, and structured missing/invalid artifact failures.
  4. Manual UAT below validates the product-visible browser path when a safe local or live provider setup is available.

R045 is advanced by local deterministic proof and manual instructions. It is not fully closed by this T01 document alone; later S05 validation must record fresh command evidence and any prerequisite-gated manual UAT result. The user-visible mapping includes category reload. Play the saved clip from Soundboard. Use the download control. Reuse the saved clip as follow-through checks for the saved artifact.

R046 validation: stable contract semantics across backend and clients

R046 requires a stable request, response, and error contract with explicit artifact path and status semantics. The proof chain is:

  1. The canonical speech workflow contract requires generation success fields success, status, artifact_id, artifact_path, audio_path, and download_path.
  2. The save contract requires category, original text, and canonical artifact_path; it accepts audio_path for compatibility but keeps privileged storage writes server-side.
  3. The shared failure envelope requires error, error_code, operation, status, and retryable, with bounded details that do not expose provider secrets, bearer tokens, absolute paths, or full upstream bodies.
  4. Supabase Edge Deno tests guard the edge tts-generate handler contract.
  5. Android parity tests (TTSRepositoryTest, TTSViewModelTest, and SoundboardRepositoryTest) guard native parsing, UI state, server-side save handoff, canonical generation success, malformed success rejection, traversal/absolute artifact path rejection, structured failures, stale-artifact clearing, and save-retry preservation.

R046 is advanced by this cross-surface mapping and by requiring the exact commands below. Native/server save-to-Soundboard parity now forwards artifact_path to server-side save logic instead of relying only on the Android local-upload path. The remaining follow-up is live provider/storage smoke against deployed tts-generate artifact mode plus soundboard-save-generated.

Executable local commands

Run commands from the repository root. These checks do not require production secrets.

Browser VM workflow diagnostic

node web/python-web-app/tests/js/tts_soundboard_workflow_runtime_check.mjs

Proof target: browser generation artifact retention, save payload construction, structured browser diagnostics, missing-artifact blocking, malformed generation handling, and safe retry behavior.

Flask workflow and contract pytest

web/python-web-app/venv/bin/pytest web/python-web-app/tests/api/test_speech_contract_hardening.py web/python-web-app/tests/api/test_tts_soundboard_workflow_target.py web/python-web-app/tests/api/test_tts.py web/python-web-app/tests/api/test_soundboard_supabase_mode.py web/python-web-app/tests/test_m004_workflow_validation_pack.py

Proof target: canonical artifact fields, save-to-Soundboard server path, Soundboard reload metadata, structured Flask failures, Supabase-mode compatibility, and this pack’s structural coverage.

Supabase Edge handler contract

deno test backend/supabase/functions/tts-generate/handler_test.ts

Proof target: edge handler validation, provider/runtime failures, success envelope shape, and error semantics at the privileged server boundary.

Android native parity

./android/gradlew -p android :app:testDebugUnitTest --tests 'com.speaktrue.features.tts.data.TTSRepositoryTest' --tests 'com.speaktrue.features.tts.presentation.TTSViewModelTest' --tests 'com.speaktrue.features.soundboard.data.SoundboardRepositoryTest'

Proof target: native contract parsing, UI state handling, generated speech artifacts, server-side save handoff, structured diagnostics, stale-artifact clearing, unsafe path rejection, and retry-preserving save failures.

S05 validation pack guard

web/python-web-app/venv/bin/pytest web/python-web-app/tests/test_m004_workflow_validation_pack.py

Proof target: this document contains required R045/R046, D017/D018/D019, command, UAT, diagnostic, redaction, and tracked-source references.

S05 workflow validation gate

python3 scripts/verify_m004_s05_workflow_validation.py

Proof target: later S05 validation evidence rows, required command strings, diagnostics, and redaction rules. This command is part of the S05 closure bar and is available through the repository-root validation gate.

Fresh local verification evidence

These rows are deterministic local proof from the S05 final validation pass. They do not require production secrets and do not claim live provider/storage smoke.

Command Exit code Result summary Proof target
node web/python-web-app/tests/js/tts_soundboard_workflow_runtime_check.mjs 0 ✅ pass — browser VM reported tts_soundboard_workflow_runtime_check: OK. R045 browser artifact handoff, save payload construction, missing-artifact blocking, malformed generation handling, save diagnostics, and retry behavior.
web/python-web-app/venv/bin/pytest web/python-web-app/tests/api/test_speech_contract_hardening.py web/python-web-app/tests/api/test_tts_soundboard_workflow_target.py web/python-web-app/tests/api/test_tts.py web/python-web-app/tests/api/test_soundboard_supabase_mode.py web/python-web-app/tests/test_m004_workflow_validation_pack.py 0 ✅ pass — 44 Flask/API/pack tests passed. R045 save-to-Soundboard server workflow and R046 Flask contract hardening, canonical artifact fields, structured failures, Supabase-mode compatibility, and pack structural coverage.
deno test backend/supabase/functions/tts-generate/handler_test.ts 0 ✅ pass — 11 edge handler tests passed. R046 Supabase Edge request validation, auth/config failures, quota/provider failures, bounded details, and success envelope pass-through.
./android/gradlew -p android :app:testDebugUnitTest --tests 'com.speaktrue.features.tts.data.TTSRepositoryTest' --tests 'com.speaktrue.features.tts.presentation.TTSViewModelTest' --tests 'com.speaktrue.features.soundboard.data.SoundboardRepositoryTest' 0 ✅ pass — Gradle completed :app:testDebugUnitTest successfully for the focused TTS repository, view-model, and Soundboard repository classes. R046 Android native generation artifact parsing, server-side save handoff, structured diagnostics, stale-artifact clearing, unsafe path rejection, and retry-preserving save failure state.
web/python-web-app/venv/bin/pytest web/python-web-app/tests/test_m004_workflow_validation_pack.py 0 ✅ pass — validation-pack pytest passed after evidence update. S05 structural guard for R045/R046 mappings, D017/D018/D019 references, required commands, diagnostics, UAT guidance, and redaction constraints.
python3 scripts/verify_m004_s05_workflow_validation.py 0 ✅ pass — workflow validation gate passed after evidence update. S05 final gate for required evidence rows, required command strings, R045/R046 mapping, diagnostics, D019 deferred storage scope, and unsafe-content redaction constraints.

Deterministic proof versus deferred smoke

Deterministic local proof covers the browser VM handoff, Flask workflow contracts, Supabase Edge handler semantics, Android native parity state, and this pack’s structural validation. It is sufficient for the M004/S05 local closure bar because it exercises the generate speech → save/reuse contract without requiring production credentials.

Deferred smoke remains intentionally separate. Live ElevenLabs generation, Supabase-hosted edge execution, GCS or production object-storage writes, billing entitlements, and user-media persistence require safe credentials and a disposable account; those runs should be recorded as prerequisite-gated provider/storage smoke evidence and must not rewrite the deterministic local proof above.

Manual UAT prerequisites

Manual UAT is prerequisite-gated. Do not claim it as local deterministic proof unless all prerequisites are available and the result is recorded with date, runtime mode, and test account details that do not include secrets.

Prerequisites:

Prohibited during UAT:

Manual UAT steps

  1. Open the legacy web main TTS surface in the chosen safe runtime.
  2. Enter a short unique phrase, for example M004 S05 reusable speech UAT, and generate speech.
  3. Confirm the generated audio is playable on the TTS surface.
  4. Inspect the generation response in the browser network panel. Confirm success: true, numeric status: 200, artifact_id, artifact_path, audio_path, and download_path are present.
  5. Open the browser console and inspect window.__ttsSoundboardWorkflowTestHooks.getState() if available. Confirm the latest artifact is present and no stale generation diagnostic is active.
  6. Open the Save to Soundboard modal from the generated result.
  7. Select the disposable category and submit the save request.
  8. Inspect the save request body in the network panel. Confirm it includes category, original text, and artifact_path or compatible audio_path. Confirm it does not include provider credentials, service-role keys, direct object-storage write credentials, traversal paths, or absolute filesystem paths.
  9. Confirm the save response returns success: true and clip metadata including filename and category.
  10. Open or reload the selected Soundboard category.
  11. Confirm the saved clip appears in the category list with playable audio metadata.
  12. Play the saved clip from Soundboard.
  13. Use the download control for the saved clip and confirm a download URL is produced by the server/storage provider path.
  14. Reuse the saved clip through the existing Soundboard reuse/copy-to-TTS control where the runtime exposes it.
  15. Reload the page or category and confirm the clip remains visible through the Soundboard category reload path.

Manual negative UAT steps

These checks verify structured invalid or missing artifact failures without privileged browser storage writes.

  1. Before generating audio, attempt to open or submit Save to Soundboard. Expected result: the UI blocks submission or surfaces a clear failure; it must not send a save request missing both artifact_path and audio_path.
  2. Generate audio, then simulate a malformed latest artifact only through the app’s supported test hook or a local developer build. Expected result: save is blocked or the server returns a structured validation failure. Do not write directly to provider storage.
  3. Submit or exercise a save request missing the artifact reference in a controlled local test environment. Expected server result: SPEECH_ARTIFACT_REFERENCE_REQUIRED, operation save-clip-to-soundboard, status 400, and retryable: false.
  4. Submit or exercise a save request whose artifact reference points to a non-existent generated artifact in a controlled local test environment. Expected server result: SPEECH_ARTIFACT_NOT_FOUND, operation save-clip-to-soundboard, status 404, and retryable: false.
  5. Exercise a malformed generation success in local tests. Expected client result: stale reusable artifact is cleared, save remains disabled, and diagnostics identify the generation contract failure.
  6. Exercise a provider/runtime failure in local tests. Expected result: structured error envelope with operation, stable error code, numeric status, retryability, and bounded non-secret details.

Diagnostics and failure triage

Use these signals before changing code:

Triage order:

  1. If the browser cannot save, check whether generation produced the canonical artifact fields and whether stale artifacts were cleared after any failure.
  2. If save fails, branch on error_code and status instead of message prose.
  3. If reload does not show the clip after save success, inspect clip metadata, category cache invalidation logs, and provider path writes.
  4. If native parity fails, compare the failure to the canonical speech workflow contract before changing platform-specific behavior.
  5. If a live provider or storage run fails, record it as prerequisite-gated provider smoke evidence and do not rewrite local deterministic proof to hide the failure.

Known limits and follow-ups

Fresh-reader checklist

A reviewer can act on this pack when all items are true: