v0.1 spec¶
Six design decisions (not research questions — see
docs/decisions/open-questions.md) that gate the first code milestone.
Adopted below.
1. World scope¶
Whiterun hold only — the north-star scenario's own setting
(docs/vision.md), roughly 20-30 named NPCs (the court: Balgruuf,
Proventus, Irileth, Vignar, Hrongar; guards; merchants: Belethor, Arcadia,
the Battle-Born/Grey-Mane feud households; innkeeper Hulda; a handful of
commoners). Not all ~1,000 — that's the eventual math-tier target, but
proving the cascade on a small, hand-known cast is faster to build,
faster to eyeball-verify in the dashboard, and the sparse-graph/
observer-local-reputation rules (ADR-0006) don't get easier at scale, so
nothing about proving them requires scale yet.
2. Minimum cascade event set¶
The three event types already in chronicle/events.py are sufficient —
no fourth type needed for v0.1:
NPCDied— the triggering event.CrimeWitnessed— seeds suspicion (not certainty) about who did it.RumorHeard— carries the story onward, with mutation happening at the claim/variant layer, not by changing the event itself.
Conversation-tier events (player statements) stay deferred with the LLM
tiers, per the build order in docs/architecture.md.
3. First player-visible (v0.1: dashboard-visible) payoff¶
A headless scenario, asserted in scenarios/: Jarl Balgruuf dies →
witnesses form high-confidence beliefs, others form low-confidence
rumor-sourced beliefs → the story mutates in at least one concrete way
as it crosses 2+ retellings → for any NPC's belief, the dashboard's
causality-timeline can answer "since when, from what evidence, through
whom" by walking Evidence → Claim/Variant → originating Event
(ADR-0007). Succession/guard-patrol consequences are not required for
v0.1 — they're the acceptance test for the whole architecture eventually,
but belief formation + mutation + inspectability is the provable slice
now.
4. Rule budget (~20 rules for v0.1)¶
- Witnessing an event creates a Claim plus a
witnessed-type Evidence plus a high-confidenceBeliefInstancefor the witness. - Rumor propagation requires a sampled encounter (shared location + schedule overlap) — never a global broadcast.
- Each retelling has a mutation probability, not certainty of mutation.
- Mutation changes exactly one typed claim slot per retelling (e.g.
perpetrator,cause,location) — never a full rewrite. - Verbatim strength decays faster than gist strength (fuzzy-trace
theory), per
docs/architecture.md's bounded-memory item. - Confidence decays with time since last rehearsal.
- Confidence rises with distinct corroborating source count, not repetition count from the same source.
- A grudge is created only when the holder has an existing relationship edge to the victim (sparse-graph rule, ADR-0006) — never unconditionally.
- Grudge severity scales with relationship closeness + evidentiary strength, not a flat penalty.
- Reputation updates are observer-local (
(observer, subject, context)) — never a global score (ADR-0006). - Relationship edges are created only via co-location, kinship, faction, or shared employer — never for an arbitrary pair.
- Canonical claims never mutate in place; a mutation always produces a
new
Variantlinked to its predecessor. - Every
BeliefInstancemust resolve to an evidence chain back to a canonical event (ADR-0007) — no orphan beliefs. CrimeWitnessedwith no confirmed perpetrator seeds suspicion, not a named-culprit belief, until testimony accumulates.- Encounter sampling draws from NPC schedules — no "everyone within N ticks" shortcut.
- Rumor stage machine:
unheard -> heard -> repeated -> dormant -> forgotten. EventLog.append()'s idempotency guarantee is relied on, not re-implemented, at the claim layer.- Obligations, grudges, and reputation stay three separate record kinds — never merged (ADR-0006).
- Belief derivation is lazy/cached per ADR-0006's consequence, not eagerly maintained on every tick.
- No
adapters/skyrim/code is touched until this scenario suite is green headless. - Two witnesses to the same canonical event share one
Claimrecord (looked up bycanonical_event_key), not one independent claim each — a second witness's disagreement belongs on their ownVariant/belief, never on a second, differently-worded canonical claim for the same event (rule 12's immutability guarantee would otherwise be defeated at the store level, not just the object level). Enforced byClaimStore.witness().
5. Rumor representation¶
Typed claim slots (Claim(kind, slots)), not a feature-vector.
Slots are named and typed per claim kind (e.g. a death claim has
perpetrator, cause, location slots) — this is what makes rule 4
above ("mutate exactly one slot") and rule 13 (evidence-chain
inspectability) implementable without inferring structure from a vector.
6. Headless duration¶
Stay headless through the entirety of the claim/variant + belief +
evidence-chain scenario suite (rules 1-19 above, demonstrated by the
payoff in §3). adapters/skyrim/ isn't touched until that suite is
green — matches the existing status line in README.md and
docs/decisions/open-questions.md.
Next¶
First code milestone: chronicle/claims.py — Claim, Variant,
Evidence, BeliefInstance per ADR-0006's record shapes, built on top
of the existing EventLog, with a scenario test exercising rules 1, 3,
4, and 13 above (witness -> claim -> mutated variant -> evidence-chain
lookup).