osrforge.contracts.report
The extraction report: the report.json contract.
The report is regenerated on every assembly and is the complete input a review UI needs. The wire format lives here, beside the other consumer contracts, so consumers and tests pin exactly the models assembly writes.
AreaAddressString
module-attribute
AreaAddressString = Annotated[str, AfterValidator(_validate_area_address_string)]
An area address in its serialized <dungeon-id>/<level-number>/<area-key> form.
FlagString
module-attribute
FlagString = Annotated[str, AfterValidator(_validate_flag_string)]
A serialized report flag: <flag> or <flag>:<detail>, prefix a Flag member.
LevelAddressString
module-attribute
LevelAddressString = Annotated[str, AfterValidator(_validate_level_address_string)]
A level address in its serialized <dungeon-id>/<level-number> form.
AreaAddress
Bases: BaseModel
A keyed area's address: <dungeon-id>/<level-number>/<area-key>.
osrlib allows any string id, so the address grammar is only unambiguous
because osr-forge constrains what it emits: / is forbidden in dungeon ids
and area keys (survey normalization enforces it at the source).
parse
classmethod
parse(value: str) -> AreaAddress
Parse the <dungeon-id>/<level-number>/<area-key> form.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
value
|
str
|
The address string. |
required |
Returns:
| Type | Description |
|---|---|
AreaAddress
|
The parsed address. |
Raises:
| Type | Description |
|---|---|
ValueError
|
If the string is not three non-empty |
AreaReport
Bases: BaseModel
One keyed area's extraction record.
id
instance-attribute
The area's address, <dungeon-id>/<level-number>/<area-key>.
source_pages
class-attribute
instance-attribute
The source pages the area's content came from — an extraction fact that persists under overrides.
confidence
class-attribute
instance-attribute
The extraction confidence — likewise a persistent extraction fact.
flags
class-attribute
instance-attribute
flags: tuple[FlagString, ...] = ()
The area's flags, describing the built draft.
CustomMonsterRecord
Bases: BaseModel
One emitted custom template's review record.
The monster_custom flag is the review badge; this is the review detail:
the emitted id, the extracted name it serves, the pages its stat block was
transcribed from, and every field the mapping derived, defaulted, or
discarded-and-rederived rather than read off the printed page.
source_pages
class-attribute
instance-attribute
The pages the stat block was transcribed from.
ExtractionReport
Bases: BaseModel
The report.json document.
flags carries module-scope conditions with no per-area home — a defaulted
adventure title or town name — in the same flag grammar as per-area flags.
findings is empty from assemble() (stale lint about a changed draft is
worse than none; re-assembly wipes findings by design) and populated by
check().
schema_version
class-attribute
instance-attribute
schema_version: int = SCHEMA_VERSION
The report schema version.
osrforge_version
class-attribute
instance-attribute
osrforge_version: str = Field(default_factory=osrforge_version)
The producing package version.
areas
class-attribute
instance-attribute
areas: tuple[AreaReport, ...] = ()
One record per keyed area, in draft order.
flags
class-attribute
instance-attribute
flags: tuple[FlagString, ...] = ()
Module-scope flags with no per-area home.
findings
class-attribute
instance-attribute
findings: tuple[LintFinding, ...] = ()
The playability findings — empty from assemble(), populated by
check().
Flag
Bases: StrEnum
The report's enumerated flag vocabulary — UIs badge on these.
GEOMETRY_SYNTHESIZED
class-attribute
instance-attribute
CONNECTION_AMBIGUOUS
class-attribute
instance-attribute
LevelAddress
Bases: BaseModel
A dungeon level's address: <dungeon-id>/<level-number> (geometry overrides).
parse
classmethod
parse(value: str) -> LevelAddress
Parse the <dungeon-id>/<level-number> form.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
value
|
str
|
The address string. |
required |
Returns:
| Type | Description |
|---|---|
LevelAddress
|
The parsed address. |
Raises:
| Type | Description |
|---|---|
ValueError
|
If the string is not two non-empty |
LintCheck
LintFinding
Bases: BaseModel
One structured playability finding, as merged into report.json by check.
Severity is a field rather than a function of the id: the id→severity table
is the producer's pin (check), so the contract needn't change if a check's
severity is ever re-judged.
severity
instance-attribute
severity: Literal['error', 'warning']
error breaks the correction loop's exit code; warning records an
acceptable-by-decision condition.
location
instance-attribute
location: str
Where the finding points: an area address, a level address, or a dungeon id, at whichever granularity the check works.
ModuleInfo
MonsterSummary
Bases: BaseModel
The monster-resolution summary.
custom records the emitted templates actually bundled into the draft —
additive and defaulted, so reports written before emission existed still
validate; vetoed (likewise additive and defaulted) records the picks
the stat-block veto discarded, straight from the monsters cache.
resolved
class-attribute
instance-attribute
How many names resolved to a template in the draft's catalog union — SRD picks and emitted custom templates alike.
unresolved
class-attribute
instance-attribute
The names that resolved to nothing.
custom
class-attribute
instance-attribute
custom: tuple[CustomMonsterRecord, ...] = ()
The emitted custom templates actually bundled into the draft.
vetoed
class-attribute
instance-attribute
vetoed: tuple[VetoedResolution, ...] = ()
The resolutions the stat-block veto discarded, in name order.
ValidationResult
VetoedResolution
Bases: BaseModel
One resolution the stat-block veto discarded.
The vetoed pick's review record: the extracted name, the discarded
catalog pick, and the both-readings detail. unresolved stays a tuple of
strings — no existing surface re-shapes.
format_flag
Serialize a flag and optional detail into the report's string form.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
flag
|
Flag
|
The flag. |
required |
detail
|
str | None
|
Optional free-text detail. Must be non-empty when given. |
None
|
Returns:
| Type | Description |
|---|---|
str
|
|
Raises:
| Type | Description |
|---|---|
ValueError
|
If |
parse_flag
Split a serialized flag string into its flag and optional detail.
Serialized flags are plain strings shaped <flag> or <flag>:<detail> —
e.g. monster_unresolved:hobgoblin chieftain. The prefix must be a
Flag member; the detail is free text and
may itself contain colons.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
value
|
str
|
The serialized flag string. |
required |
Returns:
| Type | Description |
|---|---|
tuple[Flag, str | None]
|
The flag and its detail ( |
Raises:
| Type | Description |
|---|---|
ValueError
|
If the prefix is not a known flag or the detail is empty. |