Artifex/docs/story_authoring_workflow.md

307 lines
15 KiB
Markdown
Raw Normal View History

# Story Authoring Workflow
Artifex stores approved fiction state in Django/PostgreSQL and unfinished execution state in LangGraph checkpoints. Draft fragments and EPUB files remain ordinary artifacts under the story's configured artifact root.
## Workflow
The `story_authoring` graph runs these stages:
1. Build a chapter context snapshot from the approved bible, outline, canon, previous chapter, and optional source revision.
2. Use Terra to generate a self-contained scene plan with exact values, forbidden events, and an explicit ending, then pause for human approval.
3. Draft the complete chapter in one resumable Terra call from the approved consolidated beat plan and full previous-chapter canon.
4. Use one Luna call to extract the complete chapter state and immutable state changes while checking every required beat, exact value, constraint, forbidden event, final image, and objective continuity issue. Deterministic checks independently enforce known temporal-state and exact-payout rules.
5. Validate every proposed state change against exact prose evidence. Hard canon, chronology, exact values,
forbidden events, and explicitly required beats can block; optional scene texture remains nonblocking.
6. If the combined audit finds objective, locally repairable MEDIUM-or-higher defects, let Luna apply one exact
patch touching at most five percent of the chapter. LOW and subjective findings are never patched
automatically.
7. Run one targeted Luna verifier over only the supplied findings, hard requirements, and changed
passages. It cannot discover new issues or trigger another patch.
8. Pause for final chapter approval with state coverage, patch metadata, and residual findings attached.
9. Atomically commit validated state changes, materialize a cumulative canon snapshot, promote the
revision, and rebuild the EPUB.
The approval inbox at `/approvals/` resumes the persisted checkpoint. A final request for revision ends
the automated run; it never starts another model loop. Start a new explicit run for additional work.
## Production Setup
Story workflows require PostgreSQL for durable cross-process resume. SQLite uses an in-memory checkpoint saver and is suitable only for tests that start and resume in one process.
```bash
pip install -e .
export DATABASE_URL=postgresql://artifex:artifex@localhost:5432/artifex
python manage.py migrate
python manage.py seed_spark_resources
python manage.py runserver
```
Run Artifex on Spark for the simplest deployment. If the Django process runs elsewhere, set `ARTIFEX_OPENCODE_TRANSPORT=ssh` and `ARTIFEX_SPARK_SSH_ALIAS=spark`; if it runs on Spark, leave the transport as `local`. Configure the Terra and Luna OpenCode commands with `ARTIFEX_<MODEL>_OPENCODE_COMMAND` when they differ from `opencode run`.
## Import And Run
Import an approved story bible and outline, creating locked canon through Chapter 1:
```bash
python manage.py story_workflow import \
--slug the-fortune-below \
--title "The Fortune Below" \
--series "Labyrinth Hero" \
--brief /path/to/labyrinth-hero-brief.md \
--plan /path/to/labyrinth-hero-plan.json \
--source-dir /path/to/labyrinth-hero \
--locked-through 1 \
--artifact-root /path/to/artifacts
```
Start Chapter 2 with the old chapter retained as source material:
```bash
python manage.py story_workflow start \
--slug the-fortune-below \
--chapter 2 \
--source /path/to/labyrinth-hero-chapter-02-a-fortune-with-witnesses.md
```
Start a clean run while retaining but disabling older paused runs:
```bash
python manage.py story_workflow start \
--slug the-fortune-below \
--chapter 2 \
--fresh \
--supersede-active
```
Approve or return a paused gate from the shell:
```bash
python manage.py story_workflow resume --graph-run 42 --decision approve
python manage.py story_workflow resume --graph-run 42 --decision request_revision --notes "Slow the transition into the lodging scene."
python manage.py story_workflow resume --graph-run 42 --decision reject
```
Every model request, context snapshot, review finding, approval, revision, canon snapshot, and publication artifact remains queryable in Django.
## State Ledger
`StoryEntity` gives every tracked person, item, location, account, relationship, organization,
and plot thread a stable key. `StateChange` stores immutable, evidence-backed transitions for those
entities. `ChapterStateDocument` stores the readable chapter state and contract coverage, while
`CanonSnapshot` materializes the complete approved book state for fast generation context.
Only validated changes from an approved revision are committed. Rejected revisions retain proposed
changes for audit but never alter canon. Corrections use superseding changes rather than rewriting history.
Build or inspect a state document and query committed entity history:
```bash
python manage.py story_state build --revision <revision-uuid>
python manage.py story_state show --revision <revision-uuid>
python manage.py story_state history --slug the-fortune-below --entity character.corin.vale
```
Each build writes `chapter-NN-rN.state.json` and `chapter-NN-rN.state.md` under the story artifact
root. The database remains authoritative; these files are human-readable projections.
## Book Authoring State
`BookStateVersion` is the versioned planning contract for a whole work. Its JSON content owns act and chapter
structure, chapter dependencies, book constraints and forbidden events, arc and thread progression, and planning
continuity facts. Validation checks that structure and dependency graph; separate structural, continuity, and
editorial reviews remain attached to the immutable version. Revisions point to their parent and carry an impact
report so changed chapters and downstream dependencies can be inspected before approval.
Create and operate on book state with `fiction_book`:
```bash
python manage.py fiction_book create --series-slug labyrinth-hero \
--work-slug the-fortune-below --input /path/to/book-state.json
python manage.py fiction_book validate --id <state-uuid>
python manage.py fiction_book review --id <state-uuid> --level continuity --model luna
python manage.py fiction_book impact --id <state-uuid>
python manage.py fiction_book approve --id <state-uuid> --actor daniel
python manage.py fiction_book start-run --id <state-uuid>
python manage.py fiction_book sync-run --run-id <run-uuid>
python manage.py fiction_book review-run --run-id <run-uuid> --model luna
```
The equivalent API is `GET|POST /api/authoring/book-states/`, `GET
/api/authoring/book-states/<uuid>/`, and `POST /api/authoring/book-states/<uuid>/actions/`. Actions are
`validate`, `review`, `approve`, `reject`, `revise`, `impact`, `start_run`, `sync_run`, and `review_run`. A `BookRun` stores a
durable chapter cursor and completed work, allowing an approved plan to resume without inferring progress from
generated prose. Once every bound scene is approved, the run stops in review until a current whole-run continuity
review passes. Bind a standalone scene to one approved chapter with `--book-state` and `--chapter-key`, or the
scene-create JSON fields `book_state_id` and `chapter_key`.
Completed runs retain the exact reviewed scene manifest. Start a new run before creating later revisions against
the same approved book state.
Book state is planning authority, not publication authority. Approval does not promote any fact into canon,
generate or approve chapter prose, or auto-approve a standalone scene; those remain explicit authoring and human
approval steps.
## Source Registry
Register source files before extracting continuity claims. Registration stores immutable file versions,
SHA-256 hashes, explicit authority labels, and line/character-addressable passages. It does not infer
authority from directory or filename conventions and does not promote extracted facts into canon.
Use `--dry-run` first when inspecting an existing corpus:
```bash
python manage.py story_sources register \
--root /path/to/manuscripts/the-fortune-below \
--series-slug labyrinth-hero \
--series-title "Labyrinth Hero" \
--work-slug the-fortune-below \
--work-title "The Fortune Below" \
--authority provisional \
--document-type other \
--dry-run
```
Authority values are `canon`, `provisional`, `planning`, `superseded`, `rejected`, and
`noncanon_experiment`. Register mixed-authority corpora in separate, explicitly classified batches.
Changing an authority label creates a superseding source version even when the file content is unchanged.
Use repeated `--include-glob` values to register explicit authority batches while retaining paths relative to
the full corpus root. Shared canon belongs to a `series_reference` work so every book in that series can retrieve
it without seeing sibling-book drafts.
## Standalone Scenes
Standalone scenes have their own persistent plan, cited context pack, frozen requirements, resumable prose,
review, hashes, artifacts, and approval state. They do not require fake chapters and do not alter series canon.
Final approval registers the generated scene as `provisional`; canon promotion remains a separate decision.
Ask Sol to propose new evidence-backed scenes before creating any scene record:
```bash
python manage.py fiction_ideas propose \
--series-slug labyrinth-hero \
--work-slug the-fortune-below \
--target-book "Book Two" \
--focus "Unspent Sabine and Corin choices that preserve current physical continuity" \
--candidate-count 10 \
--include-authority canon \
--include-authority planning \
--model sol
```
Each persisted proposal includes its exact context hash, authority-labelled citations, candidate briefs,
the opportunity each scene spends, future opportunities its ending creates, continuity questions, risks, and
prompt/response hashes. The default ten-candidate menu covers ten generic dramatic functions: quiet connection,
major turn, physical escalation, conflict pressure, boundary choice, revelation/discovery,
aftermath/consequence, competence/task, external plot action, and ensemble/social. These types classify dramatic
function without assuming a particular book, cast, genre, or relationship. Proposal is read-only and creates no scene. Inspect a
proposal and explicitly select one candidate with:
```bash
python manage.py fiction_ideas show --id <idea-uuid>
python manage.py fiction_ideas export --id <idea-uuid> --output /path/to/scene-ideas.md
python manage.py fiction_ideas select --id <idea-uuid> --candidate-id idea-02
```
Pass `--book-state <approved-state-uuid>` to freeze the approved book contract into ideation context. Selecting
from a bound proposal also requires `--chapter-key`, and the resulting scene is bound to that exact state/chapter.
Export renders the persisted proposal, frozen citation index, selection state, and generation hashes as
deterministic Markdown. It does not call a model or mutate the proposal. Selection is idempotent and creates one
`planning` scene for the existing plan/write/review workflow. Repeating
the same selection returns the same scene. Ideation consults `canon` and `planning` by default; pass explicit
`--include-authority` values to narrow or deliberately expand that evidence set.
`--target-book` is mandatory for new proposals. The selected book is a hard premise boundary: later-book canon
may constrain consequences, but events, roles, locations, relationships, and abilities first established later
cannot stage the proposed scene. Every candidate exports its prerequisites and explicit book-scope justification.
Each candidate also explains why its primary scene type fits. A `physical_escalation` must cross or sharply
approach a meaningful established physical threshold; routine care, medical assistance, incidental contact,
bathing, or help dressing and undressing is not sufficient.
Use repeated `--scene-type` values to request alternatives within one or more dramatic functions. When one type
is requested, multiple candidates may use that type; when several are requested, the proposal covers every
requested type before repeating one:
```bash
python manage.py fiction_ideas propose \
--series-slug labyrinth-hero \
--work-slug the-fortune-below \
--target-book "Book Two" \
--candidate-count 3 \
--scene-type physical_escalation \
--model sol
```
Use `--governing-document` for an authoritative guide that the model must receive in full. Governing documents
are frozen verbatim into the context pack before supplementary RAG passages are selected. `--pin-document`
continues to prioritize relevant excerpts and should not be used when complete-document context is required.
Pass `--compact` to generate lightweight ideation candidates containing only the title, brief, citations,
opportunity spent, and future opportunities. The same flag on `fiction_ideas export` produces a review Markdown
without planning constraints, risks, citation index, or other full-detail sections.
Create and plan a scene:
```bash
python manage.py fiction_scene run \
--series-slug labyrinth-hero \
--work-slug the-fortune-below \
--title "Fourteen Seconds" \
--brief /path/to/scene-brief.md \
--target-words 1800 \
--constraint "Sabine owns the timing." \
--boundary "Stop when Sabine leaves the office."
```
After `fiction_scene create`, preview the exact source passages before planning with:
```bash
python manage.py fiction_scene context --id <scene-uuid> \
--include-authority canon \
--pin-document path/relative/to/the/registered/corpus.md
```
The command stops at plan review. Inspect the returned plan and continue explicitly:
```bash
python manage.py fiction_scene approve-plan --id <scene-uuid>
python manage.py fiction_scene write --id <scene-uuid>
python manage.py fiction_scene review --id <scene-uuid>
python manage.py fiction_scene approve --id <scene-uuid> --actor daniel
```
For an intentional plan-to-draft run that still stops before final prose approval:
```bash
python manage.py fiction_scene run ... --auto-approve-plan
```
Context retrieval uses only the latest versions with `canon` authority by default. Add an authority only when
the scene should deliberately consult it, for example `--include-authority planning`. Pin a known document with
`--pin-document book-two/planning/fortune-below-sabine-corin-turn-and-household-rules.md`.
The same workflow is available through JSON endpoints:
- `GET|POST /api/authoring/ideas/`
- `GET /api/authoring/ideas/<uuid>/`
- `POST /api/authoring/ideas/<uuid>/actions/` with action `select`
- `GET|POST /api/authoring/scenes/`
- `GET /api/authoring/scenes/<uuid>/`
- `POST /api/authoring/scenes/<uuid>/actions/`
Supported actions are `context`, `plan`, `approve_plan`, `write`, `review`, `approve`, and `reject`. Scene detail
omits prose by default; request `?include_prose=1` only when the caller needs the full draft.
## Model Policy
The default book policy uses only Terra, Luna, and Qwen:
- Terra: chapter planning and complete chapter prose.
- Luna: combined continuity/state extraction and objective audit, one bounded exact patch, and targeted verification.
- Qwen3.8 no-thinking: reserved for local structured fallback work.
- Human: plan approval and final chapter approval.
The combined Luna and deterministic audit must reject chronology drift, incorrect economics, canon conflicts,
omitted required beats, and prose that continues beyond the approved final image. Automation performs at most
one bounded patch; unresolved blockers return to the human gate.