osrforge.contracts.overrides
The overrides contract: the human correction channel, overrides.yaml.
Overrides are a human-authored input, not a produced artifact, and carry no
version field in v1 — strict unknown-key rejection means a future revision that
needs one can add it detectably. Every entry carries a required, non-empty
reason. Replacement payloads are osrlib's own models embedded directly —
never re-declared — so an override osrlib would reject fails at overrides load
time, not assembly time.
Field semantics, pinned: absent means untouched; explicit null means
clear. Pydantic's unset-vs-None distinction models this exactly — check
model_fields_set to tell them apart. Application happens during assembly,
in osrforge.overrides.
EdgeKeyString
module-attribute
EdgeKeyString = Annotated[str, AfterValidator(_validate_edge_key)]
An edge key: x,y:direction, any of the four directions.
osrlib's canonical edge_key form stores only
north/west keys (a cell's east edge is its eastern neighbour's west edge);
override keys accept all four directions and application canonicalizes them
(canonicalize_edge_key).
AreaGeometryOverride
AreaOverride
Bases: BaseModel
Replace fields of one keyed area, add an area, or remove one.
An entry addressing an area the draft doesn't have is an area add and must carry the full required payload — enforced at application time, since only assembly knows what the draft contains.
description
class-attribute
instance-attribute
description: str | None = None
Replace the area's description.
encounter
class-attribute
instance-attribute
encounter: KeyedEncounter | None = None
Replace the area's whole built encounter (an osrlib spec, post-mapping).
treasure
class-attribute
instance-attribute
treasure: AreaTreasureSpec | None = None
Replace the area's treasure — the parsed grammar never runs on an overridden slot.
features
class-attribute
instance-attribute
features: tuple[FeatureSpec, ...] | None = None
Replace the area's features.
remove
class-attribute
instance-attribute
remove: bool = False
Remove the area from the draft entirely.
GeometryOverride
Bases: BaseModel
Correct one level's geometry: area cells, edges, entrance, transitions.
The nesting follows osrlib's models: a level owns edges, entrance, and transitions; an area owns only its cells.
areas
class-attribute
instance-attribute
areas: dict[_AreaKeyString, AreaGeometryOverride] = {}
Area key → its replacement cell cluster.
edges
class-attribute
instance-attribute
edges: dict[EdgeKeyString, Edge] = {}
Edge key → its replacement edge; an override edge always wins over the synthesized one.
entrance
class-attribute
instance-attribute
entrance: Position | None = None
Replace the level's entrance cell.
transitions
class-attribute
instance-attribute
transitions: tuple[TransitionSpec, ...] | None = None
Replace the level's transitions wholesale.
ModuleOverride
Bases: BaseModel
Replace adventure metadata fields: name, description, hooks.
MonsterOverride
Bases: BaseModel
Remap one extracted monster name to a catalog template.
template_id
instance-attribute
template_id: Annotated[str, StringConstraints(min_length=1)]
The catalog template the name should resolve to — including an emitted custom template's id.
Overrides
Bases: BaseModel
The overrides.yaml document: the v1 override kinds.
monsters
class-attribute
instance-attribute
monsters: dict[_NonEmptyKey, MonsterOverride] = {}
Extracted monster name → catalog remap. Keys match under the monsters stage's normalization (casefold, whitespace collapsed).
monster_templates
class-attribute
instance-attribute
monster_templates: dict[_NonEmptyKey, StatBlockOverride] = {}
Extracted monster name → stat-block patch or supply, same key
normalization. The same name under both this and monsters: is rejected
as contradictory.
areas
class-attribute
instance-attribute
areas: dict[AreaAddressString, AreaOverride] = {}
Area address → its field replacements, add, or removal.
geometry
class-attribute
instance-attribute
geometry: dict[LevelAddressString, GeometryOverride] = {}
Level address → its geometry corrections.
town
class-attribute
instance-attribute
town: TownOverride | None = None
Base-town metadata replacements.
module
class-attribute
instance-attribute
module: ModuleOverride | None = None
Adventure metadata replacements.
StatBlockOverride
Bases: BaseModel
Patch fields of one name's extracted stat block, or supply a complete one.
Keyed by monster name like monsters:, matched under the same
normalization. Fields mirror the raw printed block
(RawStatBlock) — corrections
land pre-mapping, so one correction fixes a printed value once instead
of both derived forms. Absent means untouched; explicit null clears the
field back to unprinted. An entry on a name with no cached block supplies
the candidate block from its own fields alone; an entry on a name the
tiers resolved forces emission — the remedy for a flagless wrong LLM pick.
TownOverride
Bases: BaseModel
Replace base-town metadata fields (TownSpec fields).
description
class-attribute
instance-attribute
description: str | None = None
Replace the town's description.
services
class-attribute
instance-attribute
Replace the town's services list.
travel_turns
class-attribute
instance-attribute
Replace the dungeon id → town-to-entrance travel cost (in exploration turns) table.
load_overrides
Load an overrides file, or the empty Overrides when it doesn't exist.
Parsing uses a safe loader that rejects duplicate mapping keys; the result is model-validated, so typos and payloads osrlib would reject fail here.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
path
|
Path
|
The |
required |
Returns:
| Type | Description |
|---|---|
Overrides
|
The validated overrides. |
Raises:
| Type | Description |
|---|---|
OverrideError
|
If the document repeats a mapping key — two contradictory corrections, one of which would silently lose. |
ValidationError
|
If the document doesn't match the contract. |
YAMLError
|
If the file is not valid YAML. |
Examples: