You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
A map for a session that has to change one fact and know which test will notice. It says,
for each thing the book-production loop reasons about, the module that holds it, the one
function that reads it (the house rule the docstrings state dozens of times as "one
source, no second answer"), what writes it, and the test that pins it. It points at ledger
entries (plan/stage-0-decisions.md, cited as §N) and restates none of their numbers; the
numbers about the code itself are regenerated by tools/maintainability_survey.py and
recorded in plan/maintainability-survey.md.
Two checks keep this page from decaying: every backticked symbol below must exist in the
package or the suite, and every backticked test_ name must be a real test
(tests/test_architecture.py, the same checks that guard the docstrings).
Source-preservation amendment (§251): a system may have held-or-unheld capabilities with
scale maximum one, while rank gates and ownership prerequisites retain their arithmetic.
Completion does not ask for invented depth. The configuration scale label is not a printed
column; column-label checks remain separate. The regression
test_a_binary_system_preserves_rank_gates_and_does_not_offer_deepening exercises this case.
How a fact moves through the loop
A world is declared as StateRecord rows (litharness_contracts), each a subject, a
predicate, a value or an object reference, a story position, and an authority. The
Architect proposes rows; world accept makes them canon; the packet reads canon at a scene's
position; the scene prompt renders the packet plus the lines the book prints; the writer
returns prose; the gate ladder refuses or accepts it; the extractor reads the printed lines
back into rows. Every table below is one stop on that path.
Where a name lives versus where it is imported.domain/extraction.py was split on
2026-09-03 into names, sheet, graphline and moves beneath it (stage-0 §215), and it
re-exports every name they define, so an import site may still read extraction.sheet_for;
the tables name the module that is the fact's home. gamesystem was split the same way
(stage-0 §216): systems holds the definition and how it is written down, advancement the
arithmetic, and gamesystem keeps the readers and re-exports the rest; all three sit below the
five above.
The world's vocabulary
Fact
Home
The one reader
Written by
Pinned by
The predicates a world may use: node types, entity roles, the protagonist, what a person can do, what the system offers, rules and consequences, criteria and ladders, claims and disclosure, cardinality, change roles, views
domain/worlds.py (constants, one section per family)
the readers in the same module: entity_roles, criteria, ladder_of, rung_index, standing_of, capabilities_of, claims, disclosures, cardinality_shapes
worlds.world_record (content-derived id, so a changed value is a new row: §11, §160)
test_world_slots.py::test_every_documented_slot_is_the_slot_its_reader_reads reads the Architect's vocabulary line by line against these readers; test_the_documented_line_names_the_slots_its_own_record_fills
What the Architect is told the slots are
application/world.py::vocabulary (the views in VIEWS)
the CLI's world subcommands, one per view
by hand, beside the reader it documents (§152, §153)
the two tests above; test_the_vocabulary_an_architect_reads_names_the_domain_and_the_criterion
sheet.Sheet, SheetField, declared under status_sheet
sheet.sheet_for: the declaration, else the columns the book's snapshots imply, else nothing (§205); an owner's sheet for an owner (§206); a system's columns as they stand for a sheet that names its system (§211)
a drawn system (records_for), world declare, or the first line an undeclared book prints (§205)
sheet.snapshot_at chooses which record stands (the protagonist's first, §170; one key space, §165); sheet.state_as_it_stands folds forward across that subject's snapshots (§161)
moves.offered_line, with every guard moves.offered_choice has
—
test_two_systems.py::test_two_declared_systems_and_the_one_printing_the_line_is_the_one_read; the prompt-budget row offer_line
Positions
Fact
Home
The one reader
Pinned by
Where a scene sits in story time
the book's own evidence: a canon record citing the scene
extraction.attested_position, which abstains on ambiguity; extraction.stated_position accepts the planner's key only for a book with no vocabulary of its own (has_story_vocabulary, OWN_POSITION_VERSIONS)
mints nothing: the subject must be one canon uses, the position attested or stated, the value verbatim; a partial line is completed from the fold (§203); the first line of an undeclared book is its declaration (§205); an identical restatement is dropped
a proposal reaches no packet; the one canon-writable shape is a declared subject at a declared rung; promotion is a later scene naming the thing under a different predicate
test_a_printed_rung_on_a_declared_ladder_is_canon_at_that_position; test_worlds.py under the graph-line entries
a replay converges rather than duplicates; two disagreeing readings are two rows the detector can see
the two tests above
The moves a scene may be asked for
Fact
Home
The one reader
Pinned by
What a scheduled beat may name as moving
moves.movables (two arms, no mode flag: the declared system's legal_moves, else the columns the line holds) and its projections movable_names, moved_values, moved_to
genre.beat_text composes the beat; progression.moved_example shows the line after the move (§186); progression.gate_progression checks that the named column moved, never a direction (§184)
The words of this system that may never reach a reader
house.MACHINERY_WORDS
schema_words (names and titles), moves.counted_names and moves._named_moves (beat vocabulary), moves.offered_choice (a fork abstains whole), the concept redraw
house.demands counts; the ceilings live in the suite
tests/test_prompt_budget.py (BUDGET, HOUSE_BUDGET, SCENE_CONDITIONAL_BUDGET, SCENE_MAXIMAL_BUDGET), one row per role with the reason beside every change
Concepts are intended book plans. World creation receives Concept.render_for_world, which
selects setting, background and mechanics while omitting fields for future scene actions,
arc endings and promised answers. The supplied listing remains a promise to support, and the
original author brief still constrains world building. Chapter reconciliation receives the
chapter and author brief without replaying the treatment. The full concept remains with the
planner. This is field
routing, not a semantic classifier of arbitrary prose; existing accepted world rules are not
automatically reclassified. The boundary is covered by
test_future_story_fields_cannot_return_as_world_declaration_material in test_concept.py.
An accepted change's component records depend on its occurrence record's time and visibility,
even when the components carry no position themselves. Drafting, planning and repair apply
this dependency before projecting prose. Drafting uses an evidence-attested scene coordinate
when available; an unknown coordinate admits only unplaced records. The cases are covered in test_change_context.py and test_repair_workflow.py.
Fact
Home
The one reader
Pinned by
What a scene is told about its book
domain/context.py::assemble (sections, the summary share, the token budget of §132)
application/model_context.py::at_scene applies the position cutoff; extraction.CONFIGURATION_PREDICATES is the one list of rows that configure the telling and never reach a packet (§161)
application/planner.py::render_prompt over packet_for
litharness prompts renders every role's prompt for a stored book, which is how a budget is read
test_planner.py::test_the_prompt_carries_the_context_packet_and_ends_with_the_instruction; the budget tests above
What happens to a returned draft
application/handlers.py::make_scene_draft_handler: strip the em dash and markup, the tells pass (§199), draft.gate_draft (shape, canonical text), the integrity detectors (integrity.CONTRADICTION_RULE, DUPLICATE_RULE, OVERDUE_RULE), progression.gate_progression, then extraction before acceptance
the handler; every verdict is a recorded PolicyDecision (domain/policy.py)
providers/cli.py (the frontier pin, and the two flags that keep CLAUDE.md out of every call: §109)
providers/registry.py, bound only in cli.py
test_providers.py under LITHARNESS_LIVE_PROVIDERS=1; test_architecture.py::test_the_registry_still_satisfies_the_port_the_application_asks_for
The agent surface (stage-0 §241)
mcp_server.py (an entrypoint beside cli.py: READ_TOOLS, PROPOSE_TOOLS, TIERS, FENCE), over application/dossier.py, application/views.py, application/operations.py, status.report and world.view — the one source both surfaces print
reads open SqliteStore.open_read_only, writes open_existing; no profile creates, migrates, accepts, spends or posts; the tier table equals the parser
application/scene_trace.py, exposed as MCP scene_trace; SqliteStore.read_job_log filters by book, branch and job before decoding payloads
joins decision/revision identities; frozen job input is not a provider transport capture; no prose scoring or reconstruction; bounded stage excerpts and explicit missing/withheld evidence
Every numeric constant with a reason beside it is listed by tools/maintainability_survey.py constants, with its home and the first line of its reason; the prompt ceilings are the rows
of tests/test_prompt_budget.py; the draw bounds are the constants from MIN_ABILITIES to
MAX_SCALE_MAXIMUM in domain/gamesystem.py; the packet budget is context.DEFAULT_TOKEN_BUDGET; the seed's
wall-clock ceiling is world_agent.SEED_TIMEOUT_SECONDS. A number copied out of one of
those homes into prose is the number to distrust first (PLAN.md header).