Repository navigation
Conversation
added 5 commits
November 7, 2026 01:14
A finished scene now advances the story instead of ending it. The arc runs rising action, climax, falling action, resolution, and the story's new scene_budget (5 scenes by default) decides how long each phase lasts — so a story always reaches its resolution. The old heuristic could never leave rising action: tension saturated below the climax threshold, no plot thread was ever closed, so the arc could never report the story complete. The story state is checkpointed after every scene, and start_or_resume() returns that checkpoint instead of restarting the campaign, so an interrupted campaign keeps its scenes, its arc position and its in-game time. Counting a finished scene happens in one place now: the caller counts the scene it just played and the transition only opens the next one. It used to count it too, so scenes_completed grew twice per scene.
finalize() sets finalize_requested and the graph routes straight from load_context to complete_current_scene, so a scene the player quits out of is not resolved and narrated as an empty turn first.
In a group conversation every NPC now hears what the others said before it answers, so the group answers as a group instead of in isolation.
The arc's phase now comes from an index into the four phases rather than a chain of comparisons against the scene count, which makes the phases — and the tension each one carries — one thing to read and one thing to test. The tests pin the whole curve: which phase each scene lands in, the tension it carries, and when the plot threads open and are paid off. The PDF tests pin the exact pages a section claims and the depth of the front matter. Every mutant the changed lines can produce is killed by these tests.
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.
Landing the two pieces of pending loop work that were reviewed and are worth
keeping, rebased onto
master(the original branch was 39 commits behind andconflicted in three loop files).
Ingestion (
2289ca7, cherry-picked unchanged — it applies cleanly)on_job_createdcallbackinstead of monkey-patching
mongodb_create_ingestion_job. The patch wasmodule-level, so concurrent ingests could claim each other's job id.
and keep the front matter before the first bookmark as its own section
(those pages used to be dropped entirely).
back through its ancestors.
scripts/assess_ingestion_corpus.pyto measure PDF coverage without an LLM.Story arc (
b30de84,a3e4d05)A finished scene now advances the story instead of ending it, and the story
ends when its arc resolves.
The arc runs rising action → climax → falling action → resolution, and the
new
scene_budgetonStoryState(5 scenes by default) decides how long eachphase lasts. The old heuristic could never leave
rising_action: tensionsaturated below the climax threshold and no plot thread was ever closed, so
story_completecould never become true — the story had no way to end.The story state is checkpointed after every scene, and
start_or_resume()returns that checkpoint instead of restarting the campaign, so an interrupted
campaign keeps its scenes, its arc position and its in-game time.
Counting a finished scene now happens in one place: the caller counts the
scene it just played and the transition only opens the next one. It used to
count it in both, so
scenes_completedgrew twice per scene.Scene and conversation fixes (
db68b96,b9cf7e9)finalize()closes the scene without resolving or narrating an empty turn.this round.
Verification
packages/agents,packages/data-layer,packages/ui/backendand therepo-root
tests/suitecheck_layer_dependencies.pypackages/agents/src— no new errors (the 12 that remain arepre-existing, in files this PR does not touch)
packages/agents/tests/test_story_arc_contract.py, plus PDF page-boundtests in
packages/data-layer/tests/test_db/test_ingest_tools.pyMutation testing runs locally, not in CI. On the changed lines, every mutant
the code can produce is killed by the tests — 42 of 42, checked one at a time
(cosmic-ray needs longer than the budget on these modules).
Three pre-existing notes, all reproduced on
masterwithout these changes:typecheckfails on the strict-mypy backlog (the job iscontinue-on-error).unit-testsreaches 96% green and then hits the job's 20-minute timeout;master's run is cancelled the same way.
mutation-diffexceeds the 600s per-module budget onindexer/agent.py,the same way every recent PR does.