Lattice reference · 4 of 4
Validation and diagnostics
Lattice first reads the files, then validates the structure at either outline or publish readiness. Authoring inspection combines that typed structure with exact locale-aware prose statistics. Use publish readiness before preview or delivery, then read the affected route yourself.
Parse and validate are different gates
Parse
Parse checks:
- Lattice syntax in every loaded
.lafile; - quoted, relative
usepaths; - that imports stay inside the project;
- duplicate imports and import cycles.
A parse result is valid when there are no syntax or import errors. It does not promise that metadata types, references, graph structure, or runtime paths are valid.
Validate
Validate then checks:
- required metadata and value types;
- entity, Scene, Block, annotation, Predicate, State, Group, Pool, and Module references;
- the declarations and flow endings allowed by the chosen story type;
- whether links stay inside the main story or the current Module;
- narrative setup, requirement, resolution, beat, and reveal properties;
- Linear or branching graph properties;
- finite-state runtime reachability, soft locks, cycles, and Module usefulness;
- whether every possible route can be checked completely.
A validation result is valid only when the selected validation path finishes completely with no error diagnostic. Warnings and informational messages do not make the story invalid.
outline readiness applies the same structural checks but temporarily suppresses only the missing-reader-prose error. It lets an author establish stable Scene and Block IDs, summaries, purposes, flow, budgets, and continuity relationships before drafting. publish is the default and retains the complete validation rules.
Inspect authoring progress
Authoring inspection reports the source-derived prose goal, exact Story, Scene, and Block counts, observed readiness, and the largest remaining local deficits. Scene and Block targets are planning budgets. A Story minimum or maximum becomes a hard completion gate only when the approved task explicitly selects that goal.
The required edit loop
- Edit one coherent group.
Keep the change small enough that a diagnostic can be connected to its cause. - Parse the configured entry.
Fix syntax and import errors before interpreting metadata or graph messages. - Validate and inspect the outline.
Check structure, exact progress, and local deficits while prose remains incomplete. - Validate for publish.
Restore the visible-content requirement, fix every error, and deliberately judge every warning. - Experience the affected route.
Structural validity cannot prove voice, pacing, or meaningful choices.
Always validate the configured entry and its complete import expansion. Parsing one isolated file can miss duplicate IDs, unresolved cross-file targets, and global route failures.
Reading a diagnostic
A useful diagnostic provides:
- a stable diagnostic code;
- severity (
error,warning, or informational); - the exact file and source range;
- a message describing the violated rule;
- related source locations when another declaration or edge participates;
- help text when a safe correction is known.
Start with the earliest syntax/import error. A missing delimiter can shift the parser and make later diagnostics misleading. After the syntax layer is sound, follow references to their declaration and related locations rather than editing only the final message site.
Severity and authoring action
| Severity | Meaning | Required action |
|---|---|---|
| Error | The story cannot produce a valid reading experience | Fix before completion |
| Warning | The structure works, but something may be unintended | Review it in context |
| Informational | Helpful context that does not affect validity | Use as guidance |
Do not turn a warning into an automatic rewrite. A never-eligible Module might be accidental dead content, or it might be a deliberate draft waiting for another route. Inspect creative intent before changing it.
Common syntax failures
Missing semicolon
# Wrong
use "./story/opening.la"
# Correct
use "./story/opening.la";Remember that scene and module bodies, and the outer choice body, close without a semicolon. Their internal content and options still use semicolons.
Wrong comment marker
# Correct comment
# Mara enters from the west.
# Wrong
// Mara enters from the west.Quoted reference instead of an ID
# Wrong: string
entry: "opening"
# Correct: Block ID
entry: openingText form used where a string is required
# Wrong
language: en
# Correct
language: "en"Duplicate or unknown metadata
# Wrong: duplicate title and unsupported key
scene garden (
title: "Garden",
title: "The garden",
color: "blue"
) { ... }Keep each key once. Remove unsupported fields or rename intentional extension metadata to an x_ key, understanding that it will not affect built-in semantics.
Common reference and ownership failures
Wrong entity kind
A Dialogue speaker or Scene pov must reference a character. Scene location must reference a location. A CYOA event tuple must match its Predicate schema exactly.
Missing or renamed IDs
Changing a title does not affect references. Changing an ID requires updating every entry, flow target, owner field, Guard, Effect, and annotation reference that names it.
Cross-owner flow
A main-story Block cannot next or choice into a Module. A Module cannot target main story or another Module. Main story enters a Module workflow only through enter <pool> -> <resume>; a Module returns only through complete.
Story type mismatch
Linear story does not allow choices, finite State, Pools, Modules, enter, complete, or initial_state. Switch to CYOA only when the story itself needs branching or remembered State—not simply to silence an error.
Linear structure recovery
For a Linear error, draw one chain from story.entry and verify:
- the entry has no incoming edge;
- every other Block has one incoming
next; - every Block is reachable;
- no Block can reach itself;
- exactly one Block ends with
end;.
Declaration order and Scene grouping are irrelevant to these graph rules. A disconnected Block must be linked into the chain or removed; placing it next to another Block does not connect it.
Branching CYOA recovery
For a CYOA without Pools/Modules:
- begin at
story.entry; - follow every option, not only the preferred path;
- confirm every target exists and stays in the main story;
- check all Blocks are reachable;
- reject cycles;
- confirm every maximal path reaches
end;.
Convergence is allowed. A shared Block may have several incoming choice edges.
Review a Pool and its Modules
Before running full validation, manually enumerate each Pool:
- active State on Pool entry;
- every eligible unfinished Module;
- every State produced by each possible
complete; - whether the exit Guard matches after each completion;
- whether another unfinished Module remains eligible when exit is still false;
- whether the resume route can reach an ending.
This review can reveal where a route gets stuck, but it does not replace Validate. TypeApe still checks every reachable Module order and State combination.
Soft lock pattern
This Pool can fail if no Module is able to activate st_knows_signal:
pool investigation (
title: "Investigate",
exit_requires: [st_knows_signal]
);When the exit is false and there is no eligible unfinished Module, no reader action can change State. Add a reachable Module/Effect, correct the Guards, or revise the exit condition; do not hide the problem with extension metadata.
Runtime cycle pattern
Even when every owner-local Block graph is acyclic, State and Pool transitions can create a repeated runtime configuration. Full validation rejects a reachable runtime cycle because a reader could continue without guaranteed termination.
What validation does not decide
Validation checks structure, not every part of the writing experience:
- Branching continuity is not always path-universal. In a branching-only graph, a setup warning may prove that some earlier setup can reach a Block, not that every incoming route contains it.
- Floating beat-order diagnostics are limited. Pool/Module runtime validation does not currently emit every static
beat_orderwarning. - Same-Block event ordering is conservative in Floating stories. Put linked foreshadowing and reveal events in separate Blocks when path-sensitive order matters.
- Narrative marker IDs are idempotent set facts. Repeating one marker does not create counted occurrences.
- Predicates are typed tuple labels, not a rule engine. No transitivity, ontology inference, or wildcard matching is implied.
requireshas two domains. Blockrequiresnames narrative markers; Modulerequiresand Poolexit_requiresname runtime State IDs.- Validity is not literary quality. Validation does not prove that prose is coherent, choices are meaningful, or endings are satisfying.
If the manual and TypeApe disagree
Use the diagnostic shown in TypeApe, and do not work around it with undocumented syntax or x_ metadata. When asking for help, include the diagnostic code and the smallest source example that reproduces the problem.
Return to the Lattice language overview, or continue with Agent workflows.
