Cross-issue prose continuity: inject prior issue's prose tail + next issue's beats into the prose stage#2233
Merged
Merged
Conversation
…ats into the prose stage The prose stage drafted each issue blind to the previous issue's actual closing prose and the next issue's opening beats — so chapter boundaries didn't flow and the narrative voice didn't carry across units. This adds a cross-issue continuity block to the prose prompt (CWQE Phase 12): the previous issue's closing prose tail (~2000 chars) and the next issue's beat-sheet head, both token-budgeted via contextBudget.js so a small-context model degrades by trimming rather than erroring. When the prior issue's prose doesn't exist yet (non-linear/parallel generation, or first issue of a volume) the block simply doesn't render — no fabricated continuity. Wired into buildStageContext for the prose stage, so every full prose (re)generation path gets it: manual route, autoRunner, and Series Autopilot. Neighbor resolution is factored into a shared resolveVolumeNeighbors helper (loading without run history) that the idea-stage augment now shares too. pipeline-prose.md is a shipped template: migration 168 rewrites it on existing installs (customization-safe), with the pipeline-prose lineage (003/027/054/ 127/166) and the setup-data drift baseline resynced to the new shipped hash. Closes #2177
… the closing survives trimContextToBudget keeps the head of the string, so on a small-context local model the prior-issue prose tail lost its literal closing lines — the exact seam the prose template tells the model to open from. Size the tail via extractProseTail (which keeps the end) capped at the budget instead, and pin it with a regression assertion that the trimmed tail contains the closing marker, not the opening.
…erged #2178 #2178 (editorial-premature-reveal-stage) merged to main and took migration number 168, colliding with this branch's cross-issue-continuity migration. Renumber ours to the next free slot (169) and fix the internal references: the .test.js import path, describe() label, and migration-NNN- prefix, plus the post-168 → post-169 lineage comments in the resynced prose-prompt migrations (003/027/054/127/166). Content hashes are unchanged.
badca84 to
7ff6622
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
CWQE Phase 12 (#2177). Previously each issue's prose stage drafted blind to its neighbors — every issue opened and closed in a vacuum, producing the "every chapter opens/closes the same way" tic and giving the editorial loop more to fix. This wires cross-issue continuity into the prose generation stage:
buildProseContextAugment(server/services/pipeline/textStages.js) injects the previous issue's actual closing prose (last ~2000 chars, cut on a paragraph boundary) aspriorIssueProseTailand the next issue's opening beats asnextIssueBeats. Neighbor resolution is factored into a sharedresolveVolumeNeighborshelper (also used by the idea-stage augment), loaded without run history.data.reference/prompts/stages/pipeline-prose.md) renders both blocks conditionally under{{#hasNeighborContinuity}}with guidance to open so it flows from the prior ending (without repeating its closing image) and land the ending so it hands off to the next issue's beats. Injected content is fenced with an "quoted context only" injection guard.contextBudget.js— the two blocks share a fraction of the resolved usable input budget (prior tail keeps priority), so a small-context local model degrades by trimming rather than erroring. The prior tail is trimmed from its head so the actual closing survives.generateStage.pipeline-prose.mdfor existing installs (customization-safe; customized prompts are left intact and warned). Earlier prose-touching migrations (003/027/054/127/166) and the drift baseline are resynced to the new shipped hash.This is one slice of the multi-phase #2177 epic — the
pipeline-manuscript-fix.mdrevision path and the Phase 7 revision loop do not yet assemble the same neighbor context (task 4 of the issue), so the issue stays open.Test plan
server/services/pipeline/textStages.test.js— 63 pass. New coverage: continuity injection for a middle issue, no prior tail on the first issue of a volume, prior block absent when the prior issue has no prose yet, ungrouped-issue (no season) yields no blocks, next-beats synopsis fallback, idea stage does NOT get the prose-tail blocks,extractProseTaillength/boundary/absent behavior,extractNextIssueBeatsprecedence, and a small-context-window trim test that pins the trimmed tail keeps the CLOSING content (not the opening).scripts/migrations/168-prose-cross-issue-continuity.test.jsandscripts/setup-data-drift.test.jspass; migrations 003/027/054/127/166 tests pass with resynced hashes.Refs #2177