This commit completes the migration started in the previous commit, updating all remaining files: - Lexer: Changed token from Extends to Modifies - Parser: Updated lalrpop grammar rules and AST field names - AST: Renamed Schedule.extends field to modifies - Grammar: Updated tree-sitter grammar.js - Tree-sitter: Regenerated parser.c and node-types.json - Examples: Updated baker-family work schedules - Tests: Updated schedule composition tests and corpus - Docs: Updated all reference documentation and tutorials - Validation: Updated error messages and validation logic - Package: Bumped version to 0.3.1 in all package manifests All 554 tests pass.
12 KiB
Validation Rules
The Storybook compiler performs multi-layered validation to catch errors before runtime. This chapter documents all validation rules, organized by declaration type, along with the error messages you can expect and how to fix them.
Validation Layers
Storybook validation happens in four stages:
- Lexical: Tokenization of raw text (invalid characters, malformed literals)
- Syntactic: Grammar structure (missing braces, wrong keyword order)
- Semantic: Cross-reference resolution, type checking, field merging
- Domain: Narrative-specific constraints (bond ranges, schedule overlaps)
Errors at earlier stages prevent later stages from running.
Character Validation
Required Rules
| Rule | Description | Severity |
|---|---|---|
| Unique name | Character names must be unique within their module | Error |
| Species exists | If : Species is used, the species must be defined |
Error |
| Templates exist | All templates in from clause must be defined |
Error |
| No circular inheritance | Template chains cannot form cycles | Error |
| Field type consistency | Field values must match expected types | Error |
| Behavior trees exist | All uses behaviors references must resolve |
Error |
| Schedules exist | All uses schedule references must resolve |
Error |
| Prose tag uniqueness | Each prose tag can appear at most once per character | Error |
Examples
Species not found:
character Martha: Hobbit { // Error: species 'Hobbit' not defined
age: 34
}
Fix: Define the species or correct the reference:
species Hobbit {
lifespan: 130
}
character Martha: Hobbit {
age: 34
}
Duplicate character name:
character Martha { age: 34 }
character Martha { age: 36 } // Error: duplicate character name 'Martha'
Template Validation
| Rule | Description | Severity |
|---|---|---|
| Unique name | Template names must be unique within their module | Error |
| Includes exist | All included templates must be defined | Error |
| No circular includes | Include chains cannot form cycles | Error |
| Range validity | Range bounds must satisfy min <= max | Error |
| Range type match | Both bounds of a range must be the same type | Error |
| Strict enforcement | Characters using strict templates cannot add extra fields | Error |
| Resource links valid | Behavior/schedule references must resolve | Error |
Examples
Invalid range:
template BadRange {
age: 65..18 // Error: range min (65) must be <= max (18)
}
Strict template violation:
template Rigid strict {
required_stat: 10
}
character Constrained from Rigid {
required_stat: 15
extra_field: 42 // Error: field 'extra_field' not allowed by strict template 'Rigid'
}
Behavior Tree Validation
| Rule | Description | Severity |
|---|---|---|
| At least one node | Behavior body must contain at least one node | Error |
| Composite children | choose and then require at least one child |
Error |
| Decorator child | Decorators require exactly one child | Error |
| Subtree exists | include must reference a defined behavior |
Error |
| Expression validity | Condition expressions must be well-formed | Error |
| Duration format | Decorator durations must be valid (e.g., 5s, 10m) |
Error |
| Repeat count valid | repeat N requires N >= 0 |
Error |
| Repeat range valid | repeat min..max requires 0 <= min <= max |
Error |
| Retry count valid | retry N requires N >= 1 |
Error |
Examples
Empty composite:
behavior Empty {
choose options {
// Error: 'choose' requires at least one child
}
}
Invalid subtree reference:
behavior Main {
include NonExistentBehavior // Error: behavior 'NonExistentBehavior' not defined
}
Life Arc Validation
| Rule | Description | Severity |
|---|---|---|
| At least one state | Life arc must contain at least one state | Error |
| Unique state names | State names must be unique within the life arc | Error |
| Valid transitions | Transition targets must reference defined states | Error |
| Expression validity | Transition conditions must be well-formed | Error |
| Field targets valid | On-enter field references must resolve | Error |
| Reachable states | All states should be reachable from initial state | Warning |
Examples
Invalid transition target:
life_arc Broken {
state active {
on timer_expired -> nonexistent // Error: state 'nonexistent' not defined
}
}
Unreachable state (warning):
life_arc HasOrphan {
state start {
on ready -> middle
}
state middle {
on done -> end
}
state orphan {} // Warning: state 'orphan' is not reachable
state end {}
}
Schedule Validation
| Rule | Description | Severity |
|---|---|---|
| Time format | Times must be valid HH:MM or HH:MM:SS | Error |
| Modifies exists | Base schedule must be defined | Error |
| No circular modifies | Schedule chains cannot form cycles | Error |
| Named blocks unique | Block names must be unique within a schedule | Error |
| Action references valid | Action references must resolve to defined behaviors | Error |
| Constraint values valid | Temporal constraint values must reference defined enums | Error |
| Recurrence names unique | Recurrence names must be unique within a schedule | Error |
Examples
Invalid time format:
schedule Bad {
block work {
25:00 - 17:00 // Error: invalid hour '25'
action: work
}
}
Circular modifies:
schedule A modifies B { }
schedule B modifies A { } // Error: circular schedule extension detected
Relationship Validation
| Rule | Description | Severity |
|---|---|---|
| At least two participants | Relationships require >= 2 participants | Error |
| Participants exist | All participant names must reference defined entities | Error |
| Unique participants | Each participant appears at most once | Error |
| Field type consistency | Fields must have valid value types | Error |
Examples
Too few participants:
relationship Lonely {
Martha // Error: relationship requires at least 2 participants
bond: 0.5
}
Species Validation
| Rule | Description | Severity |
|---|---|---|
| Unique name | Species names must be unique within their module | Error |
| No circular includes | Include chains cannot form cycles | Error |
| Includes exist | All included species must be defined | Error |
| Field type consistency | Fields must have valid values | Error |
| Prose tag uniqueness | Each prose tag can appear at most once | Error |
Enum Validation
| Rule | Description | Severity |
|---|---|---|
| Unique enum name | Enum names must be unique within their module | Error |
| Unique variants | Variant names must be unique within the enum | Error |
| Non-empty | Enums must have at least one variant | Error |
| Valid identifiers | Variants must follow identifier rules | Error |
Examples
Duplicate variant:
enum Size {
tiny,
small,
small, // Error: duplicate variant 'small' in enum 'Size'
large
}
Institution and Location Validation
| Rule | Description | Severity |
|---|---|---|
| Unique name | Names must be unique within their module | Error |
| Resource links valid | Behavior/schedule references must resolve | Error |
| Field type consistency | Fields must have valid values | Error |
Expression Validation
Expressions are validated wherever they appear (life arc transitions, behavior tree conditions, if decorators).
| Rule | Description | Severity |
|---|---|---|
| Type consistency | Both sides of comparison must have compatible types | Error |
| Boolean context | Logical operators require boolean operands | Error |
| Field existence | Referenced fields must exist on the entity | Error |
| Collection validity | Quantifiers require collection-typed expressions | Error |
| Variable scope | Quantifier variables only valid within their predicate | Error |
| Enum validity | Enum comparisons must reference defined values | Error |
Examples
Type mismatch:
life_arc TypeError {
state checking {
on count == "five" -> done // Error: cannot compare int with string
}
state done {}
}
Use Statement Validation
| Rule | Description | Severity |
|---|---|---|
| Path exists | Imported paths must reference defined modules/items | Error |
| No circular imports | Modules cannot form circular dependency chains | Error |
| Valid identifiers | All path segments must be valid identifiers | Error |
| Grouped import validity | All items in {} must exist in the target module |
Error |
Examples
Missing import:
use schema::nonexistent::Thing; // Error: module 'schema::nonexistent' not found
Cross-File Validation
When resolving across multiple .sb files, the compiler performs additional checks:
| Rule | Description | Severity |
|---|---|---|
| All references resolve | Cross-file references must find their targets | Error |
| No naming conflicts | Declarations must not collide across files in the same module | Error |
| Import visibility | Only public declarations can be imported | Error |
Common Error Patterns
Missing Definitions
The most common error is referencing something that does not exist:
character Martha: Human from Baker {
specialty: sourdough
}
If Human, Baker, or the sourdough enum variant are not defined or imported, the compiler will report an error. Fix by adding the appropriate use statements:
use schema::core_enums::{SkillLevel, Specialty};
use schema::templates::Baker;
use schema::beings::Human;
character Martha: Human from Baker {
specialty: sourdough
}
Circular Dependencies
Circular references are rejected at every level:
- Templates including each other
- Species including each other
- Schedules extending each other
- Modules importing each other
Break cycles by restructuring into a hierarchy or extracting shared parts into a common module.
Type Mismatches
Storybook has no implicit type coercion. Ensure values match their expected types:
// Wrong:
character Bad {
age: "twenty" // Error: expected int, got string
is_ready: 1 // Error: expected bool, got int
}
// Correct:
character Good {
age: 20
is_ready: true
}
Validation Summary
| Declaration | Key Constraints |
|---|---|
| Character | Unique name, valid species/templates, no circular inheritance |
| Template | Unique name, valid includes, valid ranges, strict enforcement |
| Behavior | Non-empty, valid composites, valid decorators, valid subtrees |
| Life Arc | Non-empty, unique states, valid transitions, reachable states |
| Schedule | Valid times, valid modifies chain, unique block names |
| Relationship | >= 2 participants, valid references |
| Species | Unique name, valid includes, no cycles |
| Enum | Unique name, unique variants, non-empty |
| Institution | Unique name, valid resource links |
| Location | Unique name, valid field types |
| Use | Valid paths, no circular imports |
Cross-References
- Characters - Character-specific validation
- Behavior Trees - Behavior validation
- Life Arcs - Life arc validation
- Schedules - Schedule validation
- Expression Language - Expression validation
- Value Types - Type system constraints