Skip to content

Commit 8c332fc

Browse files
authored
Merge PR_26180_BRAVO_002-complete-messages-creator-tool
Complete Messages Creator Tool MVP with API-backed fields and validation.
2 parents 994b844 + d525bd8 commit 8c332fc

9 files changed

Lines changed: 468 additions & 16 deletions

File tree

dev/build/database/ddl/messages.sql

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,9 @@ CREATE TABLE IF NOT EXISTS messages_records (
7272
"emotionProfileKey" text NOT NULL REFERENCES messages_emotion_profiles(key),
7373
"voiceProfileKey" text NOT NULL REFERENCES messages_tts_profiles(key),
7474
"messageText" text NOT NULL,
75+
"speaker" text NOT NULL DEFAULT '',
76+
"trigger" text NOT NULL DEFAULT '',
77+
"typewriterSpeed" numeric NOT NULL DEFAULT 30,
7578
"notes" text NOT NULL DEFAULT '',
7679
"active" boolean NOT NULL DEFAULT true,
7780
"createdAt" timestamptz NOT NULL DEFAULT now(),
@@ -106,6 +109,10 @@ CREATE TABLE IF NOT EXISTS messages_event_actions (
106109
"updatedBy" text NOT NULL REFERENCES users(key)
107110
);
108111

112+
ALTER TABLE messages_records ADD COLUMN IF NOT EXISTS "speaker" text NOT NULL DEFAULT '';
113+
ALTER TABLE messages_records ADD COLUMN IF NOT EXISTS "trigger" text NOT NULL DEFAULT '';
114+
ALTER TABLE messages_records ADD COLUMN IF NOT EXISTS "typewriterSpeed" numeric NOT NULL DEFAULT 30;
115+
109116
CREATE INDEX IF NOT EXISTS idx_messages_records_categorykey ON messages_records ("categoryKey");
110117
CREATE INDEX IF NOT EXISTS idx_messages_records_emotionprofilekey ON messages_records ("emotionProfileKey");
111118
CREATE INDEX IF NOT EXISTS idx_messages_records_voiceprofilekey ON messages_records ("voiceProfileKey");
Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
# PR_26180_BRAVO_002-complete-messages-creator-tool
2+
3+
## Branch Validation
4+
5+
PASS - Current branch is `PR_26180_BRAVO_002-complete-messages-creator-tool`.
6+
PASS - Scoped PR_002 Messages Creator Tool changes were preserved.
7+
PASS - Artifact paths use `dev/reports` and `dev/workspace/zips`.
8+
PASS - `dev/build/database/seed/guest/game-crew.json` was not modified.
9+
PASS - `dev/tests/dev-runtime/DbSeedIntegrity.test.mjs` was not modified for Game Crew.
10+
PASS - PR_003+ Game Crew cleanup was not started from this dirty branch.
11+
PASS - Branch was refreshed with current `origin/main` to restore PR mergeability.
12+
13+
## Product Owner Testable Outcome
14+
15+
After applying this PR, the Product Owner can test the API-backed Message Studio MVP workflow:
16+
17+
- Create, edit, save, archive, and delete Messages.
18+
- Use creator-facing `Speaker`, `Text`, `Trigger`, `Typewriter Speed`, and `TTS Profile` fields.
19+
- Preview Message and sentence playback through existing Text To Speech behavior.
20+
- Add sentences with emotions scoped by the selected TTS Profile.
21+
- Confirm guest browsing is allowed while guest saves redirect to `account/sign-in.html`.
22+
- Confirm referenced Messages cannot be deleted while they have sentence usage.
23+
24+
This PR is not part of the Game Crew cleanup batch. Previous dependency: none for PR_002. Next dependency: resolve the separate Game Crew guest seed ownership cleanup before running full seed integrity as a required gate.
25+
26+
## Requirement Checklist
27+
28+
PASS - Preserve current PR_002 Messages Creator Tool changes.
29+
PASS - Do not modify guest `game-crew` seed files.
30+
PASS - Do not modify `DbSeedIntegrity` for Game Crew in this PR.
31+
PASS - Do not run or plan PR_003+ from this dirty branch.
32+
PASS - Document Game Crew seed integrity failure as unrelated/out-of-scope.
33+
PASS - Run only in-scope Messages validation and impacted Playwright.
34+
PASS - Produce PR_002 artifacts.
35+
PASS - Browser-owned product data was not introduced.
36+
PASS - No silent JSON fallback was introduced.
37+
PASS - No MEM DB/local-mem was introduced.
38+
PASS - No unrelated cleanup.
39+
40+
## Changed File Inventory
41+
42+
- `dev/build/database/ddl/messages.sql`
43+
- `dev/tests/dev-runtime/MessagesPublishValidation.test.mjs`
44+
- `dev/tests/helpers/playwrightRepoServer.mjs`
45+
- `dev/tests/playwright/tools/MessagesTool.spec.mjs`
46+
- `src/dev-runtime/messages/messages-postgres-service.mjs`
47+
- `toolbox/messages/index.html`
48+
- `toolbox/messages/messages.js`
49+
- `dev/reports/codex_changed_files.txt`
50+
- `dev/reports/codex_review.diff`
51+
- `dev/reports/PR_26180_BRAVO_002-complete-messages-creator-tool.md`
52+
53+
## DB/API Inventory
54+
55+
- `messages_records` DDL includes `speaker`, `trigger`, and `typewriterSpeed`.
56+
- Messages Postgres service normalizes, validates, serializes, creates, and updates `speaker`, `trigger`, and `typewriterSpeed`.
57+
- `typewriterSpeed` must be a number of 0 or greater.
58+
- Messages write resources require authenticated API actors.
59+
- Existing Text To Speech profile and Emotion Profile service contracts remain API-backed.
60+
- Guest writes redirect to `account/sign-in.html` through the existing account route.
61+
62+
## Validation Lane Report
63+
64+
PASS - Scoped Node/API Messages validation:
65+
66+
```powershell
67+
node --test dev/tests/tools/Text2SpeechShell.test.mjs dev/tests/tools/MessagesPlaybackSource.test.mjs dev/tests/dev-runtime/MessagesPublishValidation.test.mjs
68+
```
69+
70+
Result: PASS, 21/21 tests.
71+
72+
PASS - Messages Playwright validation:
73+
74+
```powershell
75+
npx playwright test --config dev/workspace/tmp/pr_26180_bravo_002.playwright.headless.config.cjs dev/tests/playwright/tools/MessagesTool.spec.mjs --project=playwright
76+
```
77+
78+
Result: PASS, 6/6 tests.
79+
80+
PASS - Text To Speech Playwright validation:
81+
82+
```powershell
83+
npx playwright test --config dev/workspace/tmp/pr_26180_bravo_002.playwright.headless.config.cjs dev/tests/playwright/tools/TextToSpeechFunctional.spec.mjs --project=playwright
84+
```
85+
86+
Result: PASS, 4/4 tests.
87+
88+
INFO - A temporary ignored Playwright config under `dev/workspace/tmp` was used to run the repo's `playwright` project headlessly in this environment. The product/test delta does not depend on that generated file.
89+
90+
## Playwright Impacted Assessment
91+
92+
PASS - `dev/tests/playwright/tools/MessagesTool.spec.mjs` validates:
93+
94+
- table-first Message Studio structure
95+
- Speaker, Text, Trigger, Typewriter Speed fields
96+
- TTS Profile selection
97+
- API-backed profile consumption
98+
- sentence emotion filtering by selected profile
99+
- referenced Message delete protection
100+
- guest save redirect
101+
- Creator-safe load failures
102+
103+
PASS - `dev/tests/playwright/tools/TextToSpeechFunctional.spec.mjs` validates existing Text To Speech behavior remains intact.
104+
105+
The Playwright repo helper was fixed so static files are served from the repository root instead of `dev/`.
106+
107+
## Manual Validation Notes
108+
109+
Recommended Product Owner manual validation:
110+
111+
1. Open Message Studio as an authenticated Creator.
112+
2. Add a message with Speaker, Text, Trigger, Typewriter Speed, and TTS Profile.
113+
3. Save and reload to confirm API/Postgres persistence.
114+
4. Edit the same fields and confirm changes persist.
115+
5. Add a sentence with a profile-scoped emotion and confirm playback.
116+
6. Confirm guest can browse but Save redirects to `account/sign-in.html`.
117+
7. Confirm referenced Message Delete remains blocked.
118+
119+
## Known Issues
120+
121+
- Full `DbSeedIntegrity` remains blocked outside PR_002 because `dev/build/database/seed/guest/game-crew.json` publishes `game-crew` while canonical inventory expects Game Crew under `users`.
122+
- This PR intentionally does not clean up Game Crew guest seed JSON ownership.
123+
- The Game Crew cleanup should be planned from clean `main` as a separate batch after PR_002 is clean, committed, and opened.
124+
125+
## ZIP Outcome
126+
127+
DELTA artifact:
128+
129+
`dev/workspace/zips/PR_26180_BRAVO_002-complete-messages-creator-tool_delta.zip`
-1.54 KB
Binary file not shown.

dev/reports/codex_review.diff

-85.3 KB
Binary file not shown.

dev/tests/dev-runtime/MessagesPublishValidation.test.mjs

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -612,3 +612,71 @@ test("Messages API requires sign-in for Text To Speech profile and emotion write
612612
assert.equal(authenticated.ttsProfile.name, "Authenticated TTS Profile");
613613
service.close();
614614
});
615+
616+
test("Messages API requires sign-in for Message and sentence writes", async () => {
617+
const { service } = createServiceHarness();
618+
const voice = await createWorkingTtsProfile(service, { name: "Authenticated Message Profile" });
619+
const emotion = voice.emotionSettings.find((setting) => setting.emotionLabel === "Calm");
620+
assert.ok(emotion);
621+
622+
const messagePayload = {
623+
emotionProfileKey: emotion.key,
624+
messageText: "Authenticated message text.",
625+
name: "Authenticated Message",
626+
speaker: "Guide",
627+
trigger: "quest.start",
628+
typewriterSpeed: 22,
629+
voiceProfileKey: voice.key,
630+
};
631+
632+
await assert.rejects(
633+
() => handleMessagesApiContract({
634+
body: messagePayload,
635+
method: "POST",
636+
parts: ["messages"],
637+
service,
638+
}),
639+
/Sign in required to save Messages through the API/,
640+
);
641+
642+
const created = await handleMessagesApiContract({
643+
actorKey: "test-author",
644+
body: messagePayload,
645+
method: "POST",
646+
parts: ["messages"],
647+
service,
648+
});
649+
assert.equal(created.message.name, "Authenticated Message");
650+
assert.equal(created.message.messageText, "Authenticated message text.");
651+
assert.equal(created.message.speaker, "Guide");
652+
assert.equal(created.message.trigger, "quest.start");
653+
assert.equal(created.message.typewriterSpeed, 22);
654+
655+
const segmentPayload = {
656+
displayOrder: 1,
657+
emotionProfileKey: emotion.key,
658+
messageKey: created.message.key,
659+
segmentText: "Authenticated sentence text.",
660+
voiceProfileKey: voice.key,
661+
};
662+
663+
await assert.rejects(
664+
() => handleMessagesApiContract({
665+
body: segmentPayload,
666+
method: "POST",
667+
parts: ["segments"],
668+
service,
669+
}),
670+
/Sign in required to save Messages through the API/,
671+
);
672+
673+
const segment = await handleMessagesApiContract({
674+
actorKey: "test-author",
675+
body: segmentPayload,
676+
method: "POST",
677+
parts: ["segments"],
678+
service,
679+
});
680+
assert.equal(segment.segment.segmentText, "Authenticated sentence text.");
681+
service.close();
682+
});

0 commit comments

Comments
 (0)