Skip to content

Commit ecd78b5

Browse files
author
DavidQ
committed
Order text2speach-V2 controls by dependency and wire filter effects - PR_26130_011-text2speach-v2-control-dependency-order
1 parent 5b8e487 commit ecd78b5

7 files changed

Lines changed: 328 additions & 114 deletions

File tree

Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
1+
# PR_26130_011-text2speach-v2-control-dependency-order
2+
3+
## Purpose
4+
5+
Lock `text2speach-V2` control order and dependency behavior without adding controls, renaming the tool, or restructuring `/src/engine/audio/`.
6+
7+
## Scope
8+
9+
Changed only the `text2speach-V2` UI/control wiring, speech option defaults, targeted Playwright coverage, and this PR's required reports.
10+
11+
No `start_of_day` files were changed.
12+
13+
## Implementation Summary
14+
15+
- Set the visible dependency order to:
16+
1. Gender
17+
2. Language
18+
3. Voice
19+
4. Voice Age
20+
5. Character Preset
21+
6. SSML-like Preset
22+
7. Text
23+
8. Queue Mode
24+
9. Auto Speak
25+
10. Repeat Count
26+
11. Delay Between Repeats
27+
12. Volume
28+
13. Rate / Speed
29+
14. Pitch
30+
15. Speak / Pause / Resume / Stop
31+
- Moved Text into the ordered Speech Options flow.
32+
- Moved Speak/Pause/Resume/Stop to the end of the ordered control flow.
33+
- Changed Gender to a helper filter with `Any`, `Male Preferred`, and `Female Preferred`.
34+
- Included unknown and explicit neutral voices in both preferred Gender buckets so language coverage is not lost.
35+
- Removed claims of true gender transformation from behavior/logging; Gender is logged as a helper filter only.
36+
- Kept Language filtering scoped to the currently selected Gender helper bucket.
37+
- Kept Voice as the final `speechSynthesis` voice selection.
38+
- Kept Voice Age out of Language/Voice filtering; it shapes default pitch/rate only.
39+
- Added SSML-like preset defaults so `normal`, `slow`, and `whisper-ish` visibly update pitch/rate/volume.
40+
- Added manual slider override tracking so manual Volume, Rate, and Pitch changes stop later preset-derived auto-shaping from overwriting those sliders.
41+
- Added filter count logging on Gender/Language changes: available languages, available voices, selected voice, and the helper-only Gender note.
42+
- Preserved Queue Mode, Auto Speak, Repeat Count, Delay Between Repeats, and runtime Speak/Pause/Resume/Stop behavior.
43+
44+
## Tool Completion Status
45+
46+
Failing/unclear behavior before: control order did not match dependency order, Gender behaved like hard buckets, Voice Age was still entangled with voice filtering, SSML-like preset did not visibly update sliders, and manual slider override behavior was not explicitly protected.
47+
48+
Tool fixed: `text2speach-V2`.
49+
50+
Remaining failures after targeted validation: none found in `npm run test:workspace-v2`.
51+
52+
## Playwright Impact
53+
54+
Playwright impacted: Yes.
55+
56+
Coverage added/updated for:
57+
58+
- exact control ordering from Gender through Speak/Pause/Resume/Stop
59+
- Gender-to-Language filtering through preferred helper buckets
60+
- unknown and explicit neutral voices remaining available under preferred Gender helper buckets
61+
- Language-to-Voice filtering within the selected Gender helper bucket
62+
- invalid Voice reset when a selected voice is no longer valid after Gender changes
63+
- filter count logging on Gender/Language changes
64+
- Character Preset slider updates
65+
- SSML-like Preset slider updates
66+
- manual Volume/Rate/Pitch slider override behavior after preset-derived values
67+
- Voice Age shaping without filtering or clearing the selected Language/Voice
68+
- Auto Speak and runtime queue action behavior already covered by the speech action path
69+
70+
Expected pass behavior: controls appear in the requested order, Gender helper filters keep unknown/neutral voices available in preferred buckets, Language narrows Voice choices within the selected Gender helper, invalid selected voices are adjusted and logged, presets visibly update sliders, manual slider edits are preserved against later derived shaping, and runtime speech actions still target the current queue/options.
71+
72+
Expected fail behavior: tests fail if order regresses, Gender loses unknown/neutral voices, Language/Voice filtering breaks, invalid voice reset is silent, preset slider updates stop applying, manual slider edits are overwritten by later Voice Age shaping, Auto Speak no longer queues valid playback, or Speak/Pause/Resume/Stop stop operating on the runtime queue.
73+
74+
## Validation
75+
76+
Passed:
77+
78+
```text
79+
npm run test:workspace-v2
80+
```
81+
82+
Result:
83+
84+
```text
85+
28 passed
86+
```
87+
88+
Additional checks passed:
89+
90+
```text
91+
node --check src/engine/audio/TextToSpeechDefaults.js
92+
node --check tools/text2speach-V2/js/controls/SpeechOptionsControl.js
93+
node --check tools/text2speach-V2/js/TextToSpeechToolApp.js
94+
node --check tests/playwright/tools/WorkspaceManagerV2.spec.mjs
95+
node -e "JSON.parse(require('node:fs').readFileSync('tools/schemas/tools/text2speach-V2.schema.json','utf8'));"
96+
rg -n -P "<script(?![^>]*\bsrc=)|<style|\son[a-zA-Z]+=" tools/text2speach-V2/index.html
97+
git diff --check HEAD -- .
98+
```
99+
100+
The workspace-v2 Playwright run also generated advisory V8 coverage reports:
101+
102+
- `docs/dev/reports/playwright_v8_coverage_report.txt`
103+
- `docs/dev/reports/coverage_changed_js_guardrail.txt`
104+
105+
## Full Samples Smoke Test
106+
107+
Skipped. The full samples smoke test is intentionally out of scope because this PR is limited to `text2speach-V2` control ordering, dependency behavior, helper filtering, and targeted Workspace Manager V2 Playwright coverage.
108+
109+
## ZIP Artifact
110+
111+
Repo-structured delta ZIP:
112+
113+
```text
114+
tmp/PR_26130_011-text2speach-v2-control-dependency-order_delta.zip
115+
```
116+
117+
## Manual Validation Steps
118+
119+
1. Open `tools/text2speach-V2/index.html`.
120+
2. Confirm the visible control order matches the numbered dependency order in this report.
121+
3. Confirm Gender options are `Any`, `Male Preferred`, and `Female Preferred`.
122+
4. Select `Male Preferred` and confirm unknown voices remain available while explicitly female voices are omitted.
123+
5. Select a Language and confirm Voice narrows to voices in that language.
124+
6. Select a Voice, change Gender so it is no longer valid, and confirm the Voice selection is adjusted with a log line.
125+
7. Select Character Preset values and confirm Volume, Rate, and Pitch update visibly.
126+
8. Select SSML-like Preset values and confirm Volume, Rate, and Pitch update visibly.
127+
9. Manually change Volume, Rate, and Pitch, then change Voice Age; manual slider values should remain.
128+
10. Enable Auto Speak and edit valid Text; playback should queue automatically.
129+
11. Use Speak, Pause, Resume, and Stop; each should log the runtime action.
130+
131+
Expected outcome: control order reads top-down by dependency, helper filtering is explicit and non-transformative, presets are visible but manual slider edits win, and speech actions operate on the current runtime queue.
132+
133+
## Changed Files
134+
135+
- `src/engine/audio/TextToSpeechDefaults.js`
136+
- `tests/playwright/tools/WorkspaceManagerV2.spec.mjs`
137+
- `tools/text2speach-V2/index.html`
138+
- `tools/text2speach-V2/js/TextToSpeechToolApp.js`
139+
- `tools/text2speach-V2/js/controls/SpeechOptionsControl.js`
140+
- `tools/text2speach-V2/styles/text2speach-V2.css`
141+
- `docs/dev/reports/PR_26130_011-text2speach-v2-control-dependency-order.md`
142+
- `docs/dev/reports/codex_review.diff`
143+
- `docs/dev/reports/codex_changed_files.txt`
144+
- `docs/dev/codex_commands.md`
145+
- `docs/dev/commit_comment.txt`

src/engine/audio/TextToSpeechDefaults.js

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,9 @@ const TEXT_TO_SPEECH_LANGUAGE_OPTIONS = Object.freeze([
1111
]);
1212

1313
const TEXT_TO_SPEECH_GENDER_FILTER_OPTIONS = Object.freeze([
14-
Object.freeze({ label: "All", value: "all" }),
15-
Object.freeze({ label: "Female", value: "female" }),
16-
Object.freeze({ label: "Male", value: "male" }),
17-
Object.freeze({ label: "Neutral", value: "neutral" })
14+
Object.freeze({ label: "Any", value: "any" }),
15+
Object.freeze({ label: "Male Preferred", value: "male-preferred" }),
16+
Object.freeze({ label: "Female Preferred", value: "female-preferred" })
1817
]);
1918

2019
const TEXT_TO_SPEECH_AGE_FILTER_OPTIONS = Object.freeze([
@@ -60,6 +59,12 @@ const TEXT_TO_SPEECH_SSML_LIKE_PRESET_OPTIONS = Object.freeze([
6059
Object.freeze({ label: "Whisper-ish", value: "whisper-ish" })
6160
]);
6261

62+
const TEXT_TO_SPEECH_SSML_LIKE_PRESET_DEFAULTS = Object.freeze({
63+
normal: Object.freeze({ pitchOffset: 0, rateMultiplier: 1, volumeMultiplier: 1 }),
64+
slow: Object.freeze({ pitchOffset: -0.1, rateMultiplier: 0.75, volumeMultiplier: 0.95 }),
65+
"whisper-ish": Object.freeze({ pitchOffset: -0.3, rateMultiplier: 0.8, volumeMultiplier: 0.6 })
66+
});
67+
6368
const TEXT_TO_SPEECH_RANGE_DEFAULTS = Object.freeze({
6469
delayBetweenRepeatsMs: Object.freeze({ max: 5000, min: 0, step: 100, value: 0 }),
6570
pitch: Object.freeze({ max: 2, min: 0, step: 0.1, value: 1 }),
@@ -168,6 +173,7 @@ export {
168173
TEXT_TO_SPEECH_REPEAT_COUNT_OPTIONS,
169174
TEXT_TO_SPEECH_SAMPLE_TEXT,
170175
TEXT_TO_SPEECH_SCHEMA_ID,
176+
TEXT_TO_SPEECH_SSML_LIKE_PRESET_DEFAULTS,
171177
TEXT_TO_SPEECH_SSML_LIKE_PRESET_OPTIONS,
172178
TEXT_TO_SPEECH_TOOL_ID,
173179
TEXT_TO_SPEECH_VOICE_AGE_PRESET_DEFAULTS

0 commit comments

Comments
 (0)