kaldamus entity reference · EnrichmentConfig · EvalConfig · GenerationConfig
Every other page in this set documents a row a job produces. This one documents the three hand-edited, git-tracked JSON files that decide what those jobs do — nothing here is generated, mutated, or purged by the pipeline itself.
| Registry | Drives | Shape |
|---|---|---|
| EnrichmentConfig | the enrichment stage of update-events — classifier + geo routing | per-section {backend, model, base_url, extra_body} |
| EvalConfig | policy for update-reports — sampling, judge, per-check thresholds | flat — no per-artifact sections |
| GenerationConfig | summaries / scripts / prophecies + factors + dependencies | one file, five per-artifact prompt sections |
default.jsondefault.json is one config, experimental.json another; identical contents under different names are different configs.default.json ≠ experimental.jsondefault.json is the only required file per registry; everything else is an optional named variant, added by copying a file.
flowchart TD
classDef enrichNode fill:#16233b,stroke:#5a8fd4,stroke-width:1.5px,color:#dfe7f5;
classDef genNode fill:#241d0c,stroke:#c9a84c,stroke-width:1.5px,color:#f3e6bd;
classDef decisionNode fill:#12151f,stroke:#5a6178,stroke-width:1px,color:#c9cbd6;
subgraph EV["update-events — enrichment stage"]
A1{"--gen-config NAME?"}:::decisionNode
A1 -- yes --> A2["name = NAME"]:::enrichNode
A1 -- no --> A3["env GENERATION_CONFIG,
else default"]:::enrichNode
A2 --> A4["reads BOTH under that name:
enrichment + generation"]:::enrichNode
A3 --> A4
end
subgraph EVJ["update-reports — eval stage"]
B1{"--enrichment-config NAME?"}:::decisionNode
B1 -- yes --> B2["use NAME"]:::enrichNode
B1 -- no --> B3{"enrichments.json envelope
records a name?"}:::decisionNode
B3 -- yes --> B4["use envelope name"]:::enrichNode
B3 -- no --> B5["env ENRICHMENT_CONFIG,
else default"]:::enrichNode
C1{"--eval-config NAME?"}:::decisionNode
C1 -- yes --> C2["use NAME"]:::genNode
C1 -- no --> C3["env EVAL_CONFIG,
else default"]:::genNode
end
Three independent resolution paths, not one. Blue resolves an EnrichmentConfig name; gold a GenerationConfig or EvalConfig name. The eval stage's middle branch is the one place a name is inferred rather than passed or defaulted.
default unless a --gen-config / --enrichment-config / --eval-config flag (or its env var) names something else.default--gen-config picks both the enrichment and generation registries at once — they share a name during update-events by construction.enrichments.json envelope name| Config files (this page) | Every other entity in this set | |
|---|---|---|
| Who writes it | a person, in an editor, whenever | a job process, on a schedule or CLI run |
| Persisted as | one JSON file per name, tracked in git | one row inside a JSON array a repo owns |
| How it changes | git commit — ordinary source history | first-write-wins / upsert / append |
| Deletion | rm the file, or don't — nothing automated touches it | TTL cascade, scripted purge, retention cap |
git log — none of the row-state machinery elsewhere in this set applies.git log is the version historyenrich_model → v2 sections, on loaddefault.json → all default jobs see it next readcontent_hash is derived at load, not identity — edit one byte and it changes on the very next read.sha256(canonical_json(payload−name))[:16]EventForecast.config_hash, NewsBrief.config_hash …generated_at against git log or a ConfigSnapshot.config_hash field
flowchart LR
classDef enrichNode fill:#16233b,stroke:#5a8fd4,stroke-width:1.5px,color:#dfe7f5;
classDef genNode fill:#241d0c,stroke:#c9a84c,stroke-width:1.5px,color:#f3e6bd;
classDef decisionNode fill:#12151f,stroke:#5a6178,stroke-width:1px,color:#c9cbd6;
classDef deadEnd fill:#12151a,stroke:#3a4058,stroke-width:1px,color:#7a8296,stroke-dasharray:3 3;
A["classifier.backend"]:::enrichNode --> B{"= mlx?"}:::decisionNode
B -- no --> F["loads independently"]:::enrichNode
B -- yes --> E{"geo.backend also mlx?"}:::decisionNode
E -- no --> G["geo loads independently"]:::enrichNode
E -- yes --> H{"classifier.model ==
geo.model?"}:::decisionNode
H -- yes --> I["one load;
geo reuses the model"]:::genNode
H -- no --> J["ValueError at __init__:
share one local model"]:::deadEnd
The one cross-section constraint in EnrichmentConfig. There is no partial-load state — the exception fires before either validator is usable.
mlx, they must name the same model — the pipeline refuses to start otherwise.