You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Commit 6f79256
Browse filesBrowse the repository at this point in the historyBrowse files
memory: an imported retraction stays retracted on the LadybugDB backend (#123)
Closes#110, taking option 3 of the three the issue costed — persist
`superseded_by` as a column and keep the edge derived from it.
`superseded_by` was reconstructed from the SUPERSEDED_BY edge, and `add()`
cannot create an edge towards a claim the store does not have yet. In the
natural import order it does not have it: `all_claims()` returns oldest-first,
so a superseded claim arrives before the claim that superseded it. The edge was
skipped while `superseded_at` was written, so the same row said "retracted" and
`superseded_by IS NULL` said "current" — `Claim.is_current` believed the second,
and `current("svc")` returned both sides of a correction. Two of three backends
agreed; this one contradicted itself. `supersede()` was never affected because
it writes the edge itself, which is why every test that went through it passed.
The column is what reads project now, and `current()` filters on it rather than
on an OPTIONAL MATCH, which is both tidier and the actual fix — filtering on the
edge is what returned a retracted claim as live.
The edge remains, because it is the provenance chain this backend exists for and
`cypher()` walks it. `_write` reconciles it in both directions on every write:
forward when this claim names a superseder that is present, backward when a
stored claim names *this* one and could not have an edge until now. So the edge
is complete once both ends have arrived, in either order, and a stale one is
dropped first — `add` is an upsert, for the same reason the entity edges are
rebuilt rather than merged.
Option 1 (fail closed) was rejected because it breaks replaying `all_claims()`
in its own returned order, and option 2 (a stub node) because the stub reads
back as a ValidationError and has no `seq`, which is what
`test_add_is_an_upsert_that_keeps_insertion_order` is about.
The cost option 3 was costed at is the schema change, and it is handled rather
than assumed: `CREATE NODE TABLE IF NOT EXISTS` does not alter an existing
table, so `_migrate_superseded_by` adds the column and backfills it from the
edges an older database does have. Verified against a database built with the
driver in the shape the old code created, not a checked-in fixture: the link is
recovered, `seq` does not restart, and a second open is a no-op. A driver that
cannot add the column raises with an explanation instead of writing rows that
are wrong.
The module docstring said `superseded_by` is "an *edge* rather than a foreign
key in a column". It is both now, and says so.
Verified: 2197 selected, 13 deselected, ruff clean. Five of the eight new tests
are red without the fix; the other three guard the mechanism it adds.
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Copy file name to clipboardExpand all lines: docs/deep-dive.md
+1-1Lines changed: 1 addition & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -254,7 +254,7 @@ A stable system is not one that claims to have no edges — it is one whose edge
254
254
-**`.env` and `grapharc.toml` follow the same discovery rule: the working directory, and nowhere else.** Neither searches parent directories — a run must not be governed by a file you did not know about, and must not be *billed* to one either. **This is a behaviour change:** the credential loader used to walk up to `/`, so a `.env` in an ancestor directory (a `$HOME` one on a shared box, a client project one above a demo checkout) was picked up silently. If you relied on that, move the file into the directory you run from, `export` the variable, or pass `env_file=` to name it explicitly. A real environment variable still beats any file.
255
255
-**`grapharc run` has no budget unless you give it one.** Set any of `--max-tokens`, `--max-iterations`, `--max-seconds`, or `--max-concurrency`; without them each dimension is unlimited and the gate admits a topology of any worst-case cost.
256
256
257
-
**Verified this pass:**`pytest` → green, 2,190 selected and 13 deselected (the live ones); `ruff check .` clean; all eight `grapharc demo` stages green, plus the `trace` / `metrics` / `viz` / `replay` tour against a freshly recorded demo trace; the wheel builds and imports all submodules in a clean virtualenv with `[all]`, and `0.1.8` on PyPI is that wheel. The counts are a snapshot, not a property of the project — `pytest` re-derives them in one command, which is the only reason they are quoted, and `tests/test_deep_dive.py` fails this line rather than letting it drift.
257
+
**Verified this pass:**`pytest` → green, 2,197 selected and 13 deselected (the live ones); `ruff check .` clean; all eight `grapharc demo` stages green, plus the `trace` / `metrics` / `viz` / `replay` tour against a freshly recorded demo trace; the wheel builds and imports all submodules in a clean virtualenv with `[all]`, and `0.1.8` on PyPI is that wheel. The counts are a snapshot, not a property of the project — `pytest` re-derives them in one command, which is the only reason they are quoted, and `tests/test_deep_dive.py` fails this line rather than letting it drift.
258
258
259
259
[ROADMAP.md](../ROADMAP.md) tracks what is built and what is not, item by item.
0 commit comments