Skip to content

Materialization reconciles the rows it writes, and a version keeps the date it was pushed with - #911

Merged
WaylandYang merged 3 commits into
devfrom
fix/timeline-reconcile-899-900
Sep 25, 2026
Merged

WaylandYang merged 3 commits into
devfrom
fix/timeline-reconcile-899-900

Conversation

@WaylandYang

Copy link
Copy Markdown
Contributor

Fixes the two gaps @Maya-Kid pinned down in the #875 replay. Their reproductions run un-ignored as the acceptance tests.

#899. Typed materialization wrote rows through the graph's gate but never ran the uniqueness-timeline reconciliation the write path runs after every state fact, so a functional attribute kept two open values. materialize and try_materialize now collect the rows they wrote (new, merged, implied) and reconcile them after the commit through the same reconcile_facts; Outcome reports corrected and conflicts. A timeline rewrite (close, rehome) carries from_statement_id, implied and both source tables onto the corrected row, so the next round does not add a second one.

#900. A same-identity update replaces the document's doc_time, so evidence left on the earlier version dated at the later time and the values looked simultaneous. document_versions gains doc_time (migration 0090, backfilled for the current version), every version row records the document's date at that moment, and the timeline dates a fact by its evidence's own version, falling back to the document's date for older rows. A pushed statements document now carries the observation's external_id and doc_time ahead of the three arrays, so the same payload under a new identity is a second document under the one-document-per-content index, never a rename. The parser reads only e, s, n.

Record 0054 and the ingest guide say both. CLI schema version 76.

Tests: a_later_bound_statement_closes_the_earlier_place, a_same_identity_update_closes_the_earlier_place, the explicit-reconcile test now expecting materialization to have done the work, and the_same_payload_under_a_new_identity_is_a_second_observation. Store and server suites green on a fresh database; clippy clean.

Closes #899
Closes #900

🤖 Generated with Claude Code

…e date it was pushed with

Two gaps from the #875 replay (#899, #900).

Typed materialization wrote rows through the graph's gate but never ran
the uniqueness-timeline reconciliation the write path runs after every
state fact, so a functional attribute kept two open values and a later
observation could not close the earlier one without a manual reconcile.
materialize and try_materialize now collect the rows they wrote (new,
merged and implied) and reconcile them after the commit, the same
reconcile_facts the write path uses; Outcome reports corrected and
conflicts. A timeline rewrite (close, rehome) now carries
from_statement_id, implied, typed_fact_sources and implied_fact_sources
onto the corrected row, so the next round sees it as already computed
instead of adding a second one.

A same-identity update replaces the document's doc_time, so evidence
that stayed on the earlier version dated at the later time and the two
values looked simultaneous. document_versions gains doc_time (migration
0090, backfilled for the current version), every version row records
the document's date at that moment, and the timeline dates a fact by
its evidence's own version, falling back to the document's date for
older rows.

A pushed statements document now carries the observation's external_id
and doc_time ahead of the three arrays, so two observations that saw
the same thing are two documents under the one-document-per-content
index, and the same payload under a new identity is never a rename.
The parser reads only e, s and n. The record and the guide say so.

Tests: the two reproductions from #899 and #900 run un-ignored as
acceptance; the explicit-reconcile test now expects the materialization
to have done the work; a route test pushes one payload under two
identities and gets two dated documents. Store and server suites green
on a fresh database, clippy clean.

Closes #899
Closes #900

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Signed-off-by: Wayland Yang <wayland0916@gmail.com>
@WaylandYang

Copy link
Copy Markdown
Contributor Author

Ran this end to end against a live server built from 12f4a68 (fresh database with migration 0090 applied at startup, job worker on, no chat model). Setup through the API: a cup class, location declared as a functional state attribute with cup as its domain, a Statements source. Two things seeded by SQL because no model runs here, both mirroring what a person does in the alignment queue: a bound kind-word row cup → cup, and an undecided phrase row for is on × cup × value that the real review endpoint then decides. 31 checks pass.

#899, one identity per observation. Push cup-7 is on desk at 08:00 and cup-7 is on shelf at 08:10 under two identities; the worker extracts both onto one typed entity. A person binds is on to location through POST /review/alignment/phrases/{id}; the materialize job runs and the typed timeline reads desk closed (ended, date unknown) and shelf open, with no manual reconcile, no conflict row, an empty conflicts queue, and the entity page showing both rows.

#900, same identity updated. box-3 is on desk at 08:00 under obs-B, materialized and open; then obs-B pushed again with shelf at 08:10 → updated, two versions dated 08:00 and 08:10, and after materialization the desk row is closed rather than recorded as simultaneous.

Same payload, new identity. obs-2's payload pushed again as obs-3, and once more at 08:20 as obs-4: both created, three documents, nothing renamed, all resolving to one cup-7. Repeats of the same assertion land as evidence on the one open statement (shelf has three evidence rows, one per observation), not as new statements. The stored document carries external_id and doc_time beside the three arrays.

WaylandYang and others added 2 commits September 25, 2026 10:45
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Signed-off-by: Wayland Yang <wayland0916@gmail.com>
@WaylandYang
WaylandYang merged commit 961c3c0 into dev Sep 25, 2026
7 checks passed
@WaylandYang
WaylandYang deleted the fix/timeline-reconcile-899-900 branch September 25, 2026 02:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

1 participant