kaldamus entity reference · EventForecast · EventForecastHistory

The kaldamus probability

A second, independent probability per event — assembled from causal structure and researched evidence through a deterministic log-odds engine that is structurally forbidden from reading the number it will later be compared against.

01

Five moving parts, one number

flowchart LR
    classDef llmNode fill:#161822,stroke:#e0e0e0,stroke-width:2px,color:#f0f0f0;
    classDef facNode fill:#241d0c,stroke:#c9a84c,stroke-width:1.5px,color:#f3e6bd;

    BR["ForecastBaseRate
the outside view
mandatory · structurally separate"]:::llmNode ED["ForecastEdge[]
factor / event drivers
salience · direction · elasticity"]:::llmNode EV["EvidenceItem[]
citations per edge
support −1..1, driver-relative"]:::llmNode CR["ContributionRow[]
salience × elasticity × sign × support
= signed logit shift"]:::facNode AT["AggregationTrace
base_logit + Σcontributions
→ sigmoid → final_probability"]:::facNode BR --> AT ED --> CR EV --> CR CR --> AT

Grey = LLM-proposed structure (a bounded scalar plus a rationale string). Gold = deterministic output — the engine's arithmetic, never free-generated.

EntityidHolds
EventForecastevent_idkaldamus_probability (1–99) · model + evidence · aggregation_trace · basis / quant_share · divergence
EventForecastHistoryevent_id::generated_atfrozen snapshot only: kaldamus_probability, kalshi_probability_at_generation, divergence — no model / evidence / trace; server-only
Concept
Example
EventForecast is a small pipeline of derived structures — base rate, edges, evidence, contributions, aggregation — each a pure function of the one before, ending in a single integer 1–99.
σ(base_logit + Σ contributions) 1–99
The LLM proposes only bounded scalars — salience, support, a base rate; a closed-form engine does every multiplication.
grey = LLM scalar · gold = engine arithmetic
The trace is recomputable from model + evidence alone — the number is a function of the stated reasons, not free-generated.
arithmetic_reproducible eval re-derives it
02

Stages A–F, and the one line that reads the price

flowchart TD
    classDef llmNode fill:#161822,stroke:#e0e0e0,stroke-width:2px,color:#f0f0f0;
    classDef detNode fill:#12151f,stroke:#5a6178,stroke-width:1px,color:#c9cbd6;
    classDef evNode fill:#16233b,stroke:#5a8fd4,stroke-width:1.5px,color:#dfe7f5;
    classDef facNode fill:#241d0c,stroke:#c9a84c,stroke-width:1.5px,color:#f3e6bd;

    A["Stage A · Assemble
redacted subgraph — probability fields stripped"]:::detNode B["Stage B · Parameterize (LLM)
ForecastModel: edges + base_rate"]:::llmNode C["Stage C · Research
FactorObservation + news + web"]:::detNode D["Stage D · Map evidence (LLM)
EvidenceItem[], support −1..1"]:::llmNode E["Stage E · Aggregate
pure, closed-form"]:::detNode F["Stage F · Review (LLM, skippable)
bounded review_adjustment_pp"]:::llmNode ROW["EventForecast row written"]:::facNode PRICE["events.json → event.probability"]:::evNode STAMP["stamp comparison
the ONLY read of the price"]:::evNode A --> B --> C --> D --> E --> F --> ROW ROW --> STAMP PRICE -. "read only here, after F" .-> STAMP

Blue = the Kalshi/market side. Every node in Stages A–F never sees it — redaction happens once at Stage A; the price re-enters exactly one step after the forecast is finished.

Concept
Example
One job, one ChatClient, six fixed stages: three LLM calls (parameterize, map evidence, review) bracketing two deterministic stages (assemble, aggregate).
A → B → C → D → E → F
The load-bearing fact: the Kalshi price is read in exactly one place — after Stage F, only to stamp the comparison — never in any prompt.
price read once, after F
Stage A redacts the subgraph at construction: probability, outcome prices, and market signals are stripped before anything reaches a prompt.
redacted_event_view() drops price keys
Stage C is deterministic network, never LLM — a claims scrub drops anything quoting market odds or a blocklisted prediction-market domain.
kalshi.com / polymarket.com citations dropped
Stage E is the honesty guarantee: same inputs, same output, every time. Stage F may nudge within a bounded cap, then re-clips to any declared precondition ceiling.
review cap ±10pp, re-clipped after
Coverage is opt-in — the job isn't in update-all; it runs on a priority gate plus whatever the latest Daily Brief flagged as impacted.
only a fraction of events carry a forecast
03

How state is managed

FieldComputed byChanges again when…
basiscompute_basis, after the final Stage-E traceevery regeneration — a pure function of quant_share, never hand-edited
quant_shareΣ(prior-backed edge weight × |contribution|) ÷ Σ|contribution|same
config_hashGenerationConfig.content_hash, stamped at generationonly when the forecast prompt/config block itself changes
aggregation_traceStage E + one re-clip after Stage Fnever independently — recomputable from model + evidence alone
Concept
Example
basis grades not "is this forecast good" but "how much of the log-odds shift is measured rather than judged" — quantitative / partial / cosmetic.
real outside view, no valued buffer cosmetic
For observation-kind evidence, the job clamps the LLM's support to a deterministic prior regardless of what the model said.
LLM support within ±0.2 of the prior accepted
A large share of rows grade cosmetic — not a hidden bug, but the indicator-coverage gap the grade exists to surface.
most cited indicators never resolve to a value
04

Transient, or permanent?

EventForecastEventForecastHistory
Overwritten byevery successful regeneration — replaced whole, nothing mergednever — append-only, one new row per generation
History keptnone — current best estimate onlyup to a per-event retention cap, oldest pruned first
Shipped to the static buildyes — optional bundleno — server-only, never reaches ui/dist
Concept
Example
Split like Factor/EventFactor — but reversed: the row users would query (EventForecast) is disposable; the durable append-only log sits behind it, server-only.
query current · log stays server-side
Most forecasted events have only a single history point, so trajectories are still shallow — the calibration loop can't run at scale yet.
most events forecast once or twice
The history log is capped per event, oldest pruned first — it can't grow unbounded the way events.json does.
prune_per_event keeps the newest N
05

The independence rule's real incident: comparing two different questions

Concept
Example
divergence = kaldamus − kalshi only means something when both numbers answer the same proposition. For most of this feature's life, the code subtracted them regardless.
k − kalshi computed blindly
kaldamus always answers "does this event happen." On a binary market Kalshi's price answers the same; on exclusive/scaled it's the leading outcome's own price — a narrower, different question.
scaled market different proposition
The tell: the "model disagrees with the market" watchlist filled up with non-binary rows — it was surfacing a category error, not disagreement.
watchlist top-10: all non-binary
The fix: divergence_for returns (None, "not_comparable") for any non-binary market; a basis field distinguishes "not comparable" from "no price yet."
KXAAAGASMINNY (scaled) divergence: null
The independence invariant was never at risk — the price is read once, after Stage F. What broke was the arithmetic on the number after that legitimate read.
two invariants: never-in-prompt · never-wrong-question

See also