Append-Only Timeline Fact Corrections #29
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Summary
Implement append-only timeline corrections (
POST /v1/captureswithkind: "correction", andlife timeline [--corrected]), appending new corrective events into SQLitelife_eventsreferencing earlier events viacorrection_target, strictly enforcing immutable table triggers, rejecting attempts to rewrite confirmed transport facts or create cyclic references (invalid_input), and providing both raw chronological and folded corrected timeline query views.Background & Technical Rationale
Human memory and initial reporting are fallible. Users will inevitably report inaccurate durations, misattribute work blocks, or record mistaken outcomes. In conventional systems, corrections are handled by performing destructive SQL
UPDATEorDELETEoperations on historical rows. This approach creates severe systemic failure modes:evidence_class: "confirmed_service") falsifies the historical fact of what was actually transmitted to and acknowledged by the remote server.Life guarantees historical integrity through an append-only architecture:
life_eventsis guarded by triggerslife_events_no_updateandlife_events_no_deletethat raiseABORT. No application code or administrator query can update or delete rows through normal operations.life_eventswherecorrection_targetstores theevent_idof the target record. The target record remains unaltered in storage (Scenario W14).life task update).evidence_class: "user_report") and derived interpretations (evidence_class: "derived") are correctable. Transport confirmations (evidence_class: "confirmed_service") represent verified physical network transactions and cannot be corrected via capture.correction_targetexists and performs cycle detection to preventA \to B \to Areference loops. Invalid targets or cycles are rejected withinvalid_input(HTTP 400 / Exit 2).--view raw) or a folded corrected view (--view corrected) that computes the effective state by following correction chains while exposing original event IDs and provenance.Exact Technical References & Specifications
1. Timeline Consistency & Correction Semantics (
docs/technical/timeline-consistency.md)Section:
## Context delivery and correction(lines 160–165):Section:
## Illustrative schema(lines 37–62):2. Workflows Specification (
docs/technical/workflows.md)Section:
## Lifecycle and review(line 38):Section:
## Capture and retrieval(line 20):Section:
## Weekly analytics(line 56):3. CLI and API Route & Payloads (
docs/technical/cli-api.md)Section:
## Command-to-route table(lines 40, 48):Section:
## Command payloads and results(lines 87, 95, 102):Section:
## Error identifiers(line 110):4. Verification Scenarios W14 & R13 (
docs/technical/verification.md)Section:
## Workflow scenarios(line 28):Section:
## Recovery scenarios(line 99):What to build
1. Correction Validator & Cycle Detector (
src/domain/timeline/correction.rs)life_events WHERE event_id = ?.404 Not Foundwithcode: "not_found".target.evidence_class == "confirmed_service":400 Bad Requestandcode: "invalid_input"("Cannot correct confirmed transport facts") (verifying Scenario R13).target.evidence_class IN ('user_report', 'derived').replacementJSON structure must match the semantic kind oftarget.kind.target_event_id, followcorrection_targetreferences.A \to B \to A), reject immediately with400 Bad Requestandcode: "invalid_input"(verifying Scenario R13).2. Timeline Correction Appender (
src/storage/timeline_repo.rs)life_eventsrow:event_id: Unique prefixed ID (evt_cor_...).dedupe_key: Derived fromoperation_id(op_cor_...:fact:correction).schema_version:1.kind:target.kind(or"correction").evidence_class:"user_report".recorded_at: Current UTC timestamp.occurred_at:replacement.occurred_atif provided, elsetarget.occurred_at.actor:"user".source:"cli_api".collection_id:target.collection_id.uid:target.uid.before_json:target.after_json.after_json: Serializedreplacementpayload.reason: The user-provided reason string.provenance_json: Metadata including client request ID andtarget_event_id.operation_id: Current operation ID.correction_target:target.event_id.life_events.3. Timeline Query Projection Engine (
src/domain/timeline/projection.rs)GET /v1/timeline:from,to: ISO-8601 timestamps filtering byrecorded_at(default: last 7 local days).occurred_from,occurred_to: Optional ISO-8601 timestamps filtering strictly byoccurred_at.view: Enum"raw"|"corrected"(default:"raw").item_id: Optional filter.evidence_class: Optional filter.cursor: Opaque pagination cursor.limit: Integer (default 50, max 200).events: Paginated list of timeline items.next_cursor: Null at end.coverage: Temporal observation coverage metadata.unknown_time_count: Count of returned events with unknownoccurred_at.view == "raw":life_eventsordered bysequence ASC(orrecorded_at).view == "corrected":after_json.4. CLI Presentation (
src/cli/timeline.rs)life timeline [--from ISO] [--to ISO] [--occurred-from ISO] [--occurred-to ISO] [--corrected] [--json]--correctedis passed, setview=corrected.--jsonemits standard JSON envelope.Acceptance Criteria
life_eventswithcorrection_targetset to the target'sevent_id, while leaving the original row completely unmodified (verifying Scenario W14).UPDATEorDELETEonlife_eventstriggers an SQLite abort exception (life_events_no_update/life_events_no_delete).evidence_class: "confirmed_service"fails with HTTP 400 andcode: "invalid_input"(verifying Scenario R13).invalid_input(Scenario R13).A \to B \to A) is detected and rejected withinvalid_input(Scenario R13).life timeline --view rawreturns both the original and corrective events.life timeline --corrected --jsonreturns the latest folded values and explicitly discloses original event IDs and correction provenance (Scenario W14).from/to) from occurrence-time filters (occurred_from/occurred_to), explicitly reportingunknown_time_countandcoverageacross paginated results (Scenario W15).Notes
MAX_CORRECTION_HOPS = 16and cannot rewrite aconfirmed_servicetransport fact; a replacement outside the correctable vocabulary is refused.#17's refusal fixture now reflects thatkind: correctionis implemented, and the skill's CLI reference was updated in the same commit.Blocked by
Issue #029: Append-Only Timeline Fact Correctionsto Append-Only Timeline Fact Corrections