Skip to content

feat: AI voice-discovery flow for series style guide (#2179)#2251

Open
atomantic wants to merge 2 commits into
mainfrom
claim/issue-2179
Open

feat: AI voice-discovery flow for series style guide (#2179)#2251
atomantic wants to merge 2 commits into
mainfrom
claim/issue-2179

Conversation

@atomantic

Copy link
Copy Markdown
Owner

Summary

Ships the AI-assisted voice-discovery flow — the phase headline of CWQE Phase 14 (#2179). Filling a voice exemplar from a blank page is the hard part, so this lets the author hear the voice instead of describing it.

A new Discover voice button on the series style-guide editor runs one LLM call that writes the same invented scene beat five ways — spare / lyric / wry / close-psychic / cinematic. Each candidate renders side-by-side with its register label; one click files it into voiceExemplars ("the tuning fork") or, for a wrong-register passage, into voiceAntiExemplars. Both stay capped at 3, and the register rides along as the passage note.

This is the natural next slice after #2232 (exemplar schema + prompt injection) and #2247 (voice-fingerprint baseline hook).

What shipped

  • server/lib/styleGuide.jsVOICE_REGISTERS / VOICE_REGISTER_IDS: the five distinct registers (stable ids + LLM-steering hints), shared by the service, prompt, and UI.
  • server/services/pipeline/seriesVoiceDiscover.jsdiscoverSeriesVoice(): runs the stage, normalizes/dedupes candidates by register into canonical order, clamps passages to the exemplar char cap. Returns candidates without persisting (mirrors generateSeriesConcept). Strips any existing exemplars from the prompt context so a re-run surfaces fresh contrast instead of echoing the already-picked voice.
  • server/routes/pipeline/series.jsPOST /pipeline/series/:id/discover-voice (Zod-validated provider/model overrides).
  • data.reference/prompts/stages/pipeline-series-voice-discover.md + stage-config.json entry — a brand-new stage template, so no hash migration is needed (setup-data.js seeds missing stage files + merges the new config key on existing installs).
  • ClientdiscoverSeriesVoice API wrapper + the candidate-picker UI in PipelineSeries.jsx (flushes dirty edits before the call; explicit-click only, honoring the no-cold-bootstrap AI policy).

Test plan

  • server/services/pipeline/seriesVoiceDiscover.test.js (new, 12 cases): register normalization / dedupe / canonical ordering, unknown-register + empty-passage dropping, char-cap clamp, empty-result error, context passing, no-universe tolerance, and the no-exemplar-leak regression.
  • server/lib/styleGuide.test.js — added VOICE_REGISTERS shape + uniqueness coverage.
  • Verified the prompt template renders both conditional sections (universe / established-tone) with the local Mustache engine, no leftover {{...}}.
  • npm run build (client) ✅, ESLint clean, all pipeline route/service suites green (285 passed).

Remaining on #2179 (out of scope for this slice)

  • Writers Room parity — same exemplar/voice fields on a work's settings, consumed by writers-room-continue.md + the Phase 9 polish loop.

Refs #2179

atomantic added 2 commits July 6, 2026 23:49
Adds a 'Discover voice' action to the series style-guide editor: one LLM
call writes the same invented scene beat in five distinct registers
(spare / lyric / wry / close-psychic / cinematic), presented side-by-side
so the author picks the series voice by ear. Picking files the passage
into voiceExemplars ('the tuning fork'); rejecting files it into
voiceAntiExemplars. Nothing persists until save (mirrors the New Series
concept flow), and the call fires only on explicit click (no
cold-bootstrap LLM work).

- server/lib/styleGuide.js: VOICE_REGISTERS / VOICE_REGISTER_IDS
- server/services/pipeline/seriesVoiceDiscover.js: discoverSeriesVoice()
  (strips existing exemplars from context so a re-run doesn't homogenize)
- server/routes/pipeline/series.js: POST /series/:id/discover-voice
- data.reference/prompts/stages/pipeline-series-voice-discover.md (+ stage-config)
- client: discoverSeriesVoice API + candidate-picker UI

Fourth slice of #2179 (the phase headline); Writers Room parity ships separately.

Refs #2179
#2179)

Review fixes (codex HIGH, claude LOW):
- Add migration 174 to seed the new pipeline-series-voice-discover stage
  into existing installs. Boot runs migrations but NOT setup-data.js, so a
  pull + pm2 restart (vs update.sh) would otherwise leave the stage
  unregistered and 'Discover voice' would throw 'Stage not found'. Mirrors
  the makeSeedMigration pattern (048).
- Drop the redundant seen Set in discoverSeriesVoice — the byRegister Map is
  already the seen-set (keep-first semantics unchanged).

Refs #2179
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