When two reports disagree, Hippocampus doesn’t ask a model who is right. A small, pure function, the Archivist’s rules in reconcile.ts, compares the new report with the current value and decides. The order of precedence is fixed:
- HumanYour word, from Obsidian, a ruling, or a memory you scribe. It replaces any agent's value.
- Lane authorityAn agent whose authority domains match the note's tags. Its report is canon at once.
- CorroborationAgents without authority start as rumor. Enough distinct agents agreeing make it canon.
- RecencyA source may correct its own earlier report. Newer wins only within the same source.
Authority is worked out per note, at the moment of the decision. An agent has authority over a note when one of its authority domains matches the note’s tags or type. Party and lanes covers how that works. Below, “authority” means an agent with authority over this note. “Without authority” means everyone else, including agents with no party sheet.
The precedence table
Rows are what the field holds now. Columns are who sends the new report.
| Current value ↓ · new report → | You | Agent with authority | Agent without authority |
|---|---|---|---|
| No value yet | canon | canon | rumor |
| Same value | confirmed; a rumor becomes canon | confirmed; a rumor becomes canon | corroborated: canon once canon_threshold agents agree |
| Differs, current is yours | replaced | dispute | dispute |
| Differs, current is from an authority | replaced | dispute | kept: the report is not adopted |
| Differs, current is from an agent without authority | replaced | replaced, now canon | dispute |
| Differs, same source sends a newer report | replaced | replaced (self-correction) | replaced (self-correction) |
| Field is disputed | replaced, dispute resolved | claim added to the dispute | claim added to the dispute |
A self-correction becomes canon if the source has authority. Otherwise the fact keeps the status it had. A replaced value is never lost: it moves to the fact’s was list.
Secret fields are the one exception. Ciphertext can’t be compared, so they skip this table and the latest report replaces the stored value. See Secrets.
Worked examples from the Lisbon arc
Authority holds. The Migration Agency note is tagged residency, and the residency agent has authority over residency. Its report of the appointment date is canon at once. When the campus agent later reports a different date, the residency agent’s value is kept and the campus agent’s claim is not adopted. The episode is still chronicled, so nothing is forgotten.
Peers disagree. The campus agent says the agency’s office is in Alfama. A day later the home finder says its public counter is now in Belém. Neither has authority over the agency, so the fact turns Disputeddisputed and a dispute note opens.
A source corrects itself. The residency agent books an appointment, then reports that it moved. Same source, newer report: the new date replaces the old one, which moves to was.
An agent contradicts you. You wrote a rent budget of 1,100 EUR on your own character note. If an agent reports 1,200 EUR, it can’t overwrite you, so a dispute opens and waits for your ruling.
How a dispute opens
The dispute is a note in disputes/, named after the entity and field:
---
type: dispute
entity: "[[migration-agency]]"
field: office_address
status: open
claims:
- { value: Alfama office, by: campus-agent, at: 2026-09-23T13:15:00Z, src: [ep-01J9X3K2QD] }
- { value: Belém office, by: home-finder, at: 2026-09-24T17:45:00Z, src: [ep-01J9Y8M4TR] }
opened: 2026-09-25T02:30:00Z
---
The file is disputes/dispute-migration-agency-office-address.md. Its body lists the claims and ends with a “Ruling needed” callout. While the dispute is open:
- the fact keeps the value it had, with status Disputeddisputed;
- further reports about that field are added as claims to the same note;
- it shows up in the Council (with a badge), on the Tavern, in the morning review, in
HANDBOOK.md, and in agents’get,briefingandask_canonanswers.
Ruling from the Council
Open the dashboard’s Council. Each dispute shows its claims: who made each one, whether they had authority, and when. You can:
- Pick a claim. Usually the right answer is already on the table.
- Apply the ruling written in the note, if you already set
ruling:in Obsidian and don’t want to wait for the sleep. - Type a new value, when every claim is wrong. This isn’t offered for secret fields, because the value would be stored in the note as plain text. Pick a claim there instead.
Your ruling applies immediately, as canon by you:
- the fact becomes canon, with
byset to your human id; - its sources are merged from every claim, and the previous value moves to
was; - the dispute is marked
resolved, with a timestamp; HANDBOOK.mdis regenerated.
All of it is saved as one change. On a vault in GitHub (--github, or the hosted app), that’s a single commit such as rule(player): migration-agency.office_address = Belém office, and on the hosted app the message also names the GitHub account that ruled. In a local folder the notes are rewritten in place, ready for your usual git sync.
Ruling from Obsidian
Prefer your editor? Open the dispute note and add one property:
ruling: Belém office
The next sleep applies rulings first, before it reads any new episode. The result is exactly what the Council would have done, just later. An empty ruling: is ignored.
After the ruling
The dispute note stays in disputes/ as a record, with status: resolved. If an agent later contradicts your ruling, the same note reopens. The new claim is added, your old ruling is cleared from the note, and you’re asked again. The fact keeps your value, marked disputed, until you rule.