Settings and rerun
Pipeline behavior is a set of deterministic knobs on
ConversionSettings, echoed into each
workdir's run.json so every stage reads the same configuration the run was
started with.
The knobs
| Knob | Default | Meaning |
|---|---|---|
render_dpi |
150 | Page-render resolution (a legibility knob, not a cost knob — image tokens are DPI-independent) |
max_pages |
200 | Source page-count guardrail |
max_source_bytes |
100 MiB | Source file-size guardrail |
blank_page_renders |
() |
Page numbers whose renders are emitted as blank white PNGs (text layer still extracted) — the content-safety-filter workaround; each blanked page is flagged page_unreadable |
content_batch_pages |
8 | Content-pass batch size in pages (floor 2) |
survey_max_pages |
50 | The survey chunk size — the service's measured 50-images-per-request cap: a source at or under this many pages surveys in one request; a larger source surveys in page windows of this size, merged before normalization |
monster_fuzzy_threshold |
0.85 | Monster resolution's fuzzy-tier auto-accept floor, pinned against measured catalog pairs |
monster_llm_top_k |
8 | Candidate templates offered per name in the monster-resolution LLM tier |
custom_monsters |
emit |
Whether the monsters stage runs the stat-block pass feeding custom-template emission: emit gives unresolved names the module's own creatures; off skips the per-unresolved-name model spend and keeps the draft SRD-catalog-pure |
unresolved_fallback |
best-effort |
Where resolution or parsing came up empty and no usable stat block exists: flagged level-band monster stand-ins and unguarded-treasure rolls (best-effort), or leave the gap (omit) |
On the CLI, --set KEY=VALUE is the repeatable settings channel; values parse
as YAML, so --set 'blank_page_renders=[21]' and --set
unresolved_fallback=omit both coerce naturally.
One asymmetry worth knowing: custom_monsters is owned by the monsters
stage — assembly is driven purely by cache contents and never reads the knob
— so rerun assemble --set custom_monsters=off is rejected with "rerun
monsters instead", and toggling it re-rolls the monsters stage's LLM
resolution tier along with the stat-block pass. unresolved_fallback, its
policy sibling, is assembly-owned and flips for free.
Rerun: resume any stage
rerun re-runs one named stage — and everything downstream of it — from
cached upstream outputs:
osrforge rerun assemble --workdir my-module.forge # the correction loop's assemble
osrforge rerun monsters --workdir my-module.forge # re-resolve, then re-assemble
osrforge rerun survey --workdir my-module.forge # re-survey, then everything after
The stage argument is the skip: everything upstream is kept verbatim, and
each stage already clears or supersedes its downstream caches, so the workdir
stays artifact-consistent. rerun assemble needs no provider and is the
documented correction-loop step; rerun preprocess reads the workdir's own
source.pdf.
The drift guard
Changing settings on an existing workdir goes through rerun --set:
osrforge rerun preprocess --set 'blank_page_renders=[21]' --workdir my-module.forge
osrforge rerun assemble --set unresolved_fallback=omit --workdir my-module.forge
Every knob has an owning stage, and a knob owned by a stage upstream of the rerun stage is rejected with the stage to rerun instead:
$ osrforge rerun assemble --set render_dpi=200 --workdir my-module.forge
osrforge: setting 'render_dpi' belongs to the preprocess stage, upstream of assemble — rerun preprocess instead
Without the guard, the run.json settings echo would claim pages were
rendered at a DPI they weren't — the echo is the single source of truth stages
read, and it is never allowed to lie about how upstream artifacts were
produced.