Repository navigation
A wrong date can be corrected without deleting the document - #311
Conversation
13696a6 to
f210415
Compare
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Signed-off-by: WaylandYang <wayland0916@gmail.com>
f210415 to
e4ed4d8
Compare
|
Review pass on The correction could put a fact somewhere it could not be edited again. The editor accepts an empty start and an open end, and a fact with no date on either end drops out of the timeline's dated group into "Undated", which renders Two people correcting the same fact could both succeed. A failed snapshot silently swallowed the ledger entry. Also: the "Interval corrected" toast no longer fires when the server reports Skipped:
|
Closes #302 (the editing half;
instantprecision stays a separate cut).Extraction reads "the first half of 2023" as
2023-01-01, precisionday. A wrong name reaches Review; a wrong date reached nothing, so the only fix was deleting the document and re-extracting it — on a product whose whole claim is time.The interval goes through the ledger
correct_intervalisclose_superseded's sibling: invalidate the old row, insert a corrected row withsupersedespointing back, copy the evidence. Both ends come from the caller rather than being inherited.Not
UPDATE facts SET valid_from = …. Editing in place erases the correction itself, and the correction is what the recording axis exists to replay (0019) — after this change, asking in March and asking in September give different intervals, which is the first real content that record has to replay.What each axis shows
The recording axis (the entity panel's History) gains the edit for free —
entity_historyderivescorrectedfromsupersedes IS NOT NULL. Two things had to be fixed for it to say anything true:intervalNoteassumed a correction is a closure: with avalid_toit said "closed at X", otherwise nothing. An edited start has no end, so the event rendered as a bare icon. Both branches now state the interval after the correction, without claiming a cause.correctedlisted three actions and not this one, so a person's edit was credited to engine. A decision ledger that records a human decision as a machine's is worse than one that records nothing.The world axis (Timeline) keeps only the new interval. The old one is our misreading, not a state the world was in; two rows side by side read as two handovers. The ⟲ marker stays but its tooltip no longer names a source — automatic succession, a review ruling and a hand edit are indistinguishable on that row, and History has the actor.
Reconciliation runs again
Moving a start can carry it past a successor's start date, which is where the uniqueness invariant sees the collision for the first time. The edit reuses
reconcile_moved_facts— a changed interval is the same kind of event as a moved subject.Not included
No entity-level "why" enum. "We misread it" and "new evidence says June" are identical in the ledger, and forcing a choice on every edit makes the entry heavier while the criterion stays vague. An optional one-line note goes to the audit record instead; it can be promoted to a field if it turns out to be needed.
Verified
Four database-backed tests in
a_wrong_time_can_be_corrected.rs: the old reading stays in the ledger with evidence copied; an end that was never there can be taken back (precision cleared with it); moving a start earlier makes that fact the predecessor and closes it at the successor's start; an already-invalidated row cannot be corrected twice.End to end in the browser on a seeded base: pencil on hover → edit
2023-01-01to2023-06→ row becomes2023-06 ~ nowwith ⟲ → History shows "Interval corrected · from 2023-06 · open-ended · Time Tester" above the original "Recorded · from 2023-01 · engine". The audit row carries both intervals, the precision change fromdaytomonth, and the note. Unchanged submits short-circuit; a date without a precision and an inverted interval are both refused with a readable message and leave no rows behind.cargo fmt --check,cargo clippy -D warnings,cargo test --workspacewithUTOPIA_TEST_REQUIRE_DB=1, andpnpm buildall pass.🤖 Generated with Claude Code