Skip to content

v2.0.0 — architecture review remediation

Choose a tag to compare

@wuwangzhang1216 wuwangzhang1216 released this 04 Aug 18:38
· 6 commits to main since this release
1e112c2

An architecture review of the storage and memory layers found defects reproducible on the default configuration. This release fixes them, adds regression coverage that fails against the previous code, and withdraws or restates published claims that were measured on an instrument that could not fail.

Verification is A/B — the same behaviour probe against the previous release and against this one:

v1.5.0:      14 defects present in this tree
v2.0.0:       0 defects present in this tree

Tests 282 → 417. With PostgreSQL available: 417 passed. Without: 403 passed, 14 skipped.

⚠️ Breaking: defaults changed

setting was now
backend postgres sqlite
host 0.0.0.0 127.0.0.1
cors_origins ["*"] []
vision_enabled true false

With auth unenforced, the old combination made the workspace reachable from the local network, scriptable by any web page the developer visited, and uploaded indexed images to a third-party API off an ambient env var. An upgrade that does not set these explicitly will find a Postgres-backed server running on SQLite and no longer reachable off localhost.

Data loss and correctness

  • Supersede destroyed data on the default memory type. Three dated bug-fix records about one component collapsed into one, and superseded_id pointed at a row that no longer existed. Prior versions now go to memory_revisions, readable via memory_history().
  • Reading a memory reset its time-decay clock. A 400-day-old fact that had been read once outranked the fresh fact that replaced it.
  • Recall set confidence = 1.0 on every hit, so the FSRS curve could only demote memories nobody read. Recall is read-only now.
  • total was the candidate-window size, not the match count. Any offset >= 60 returned nothing however many memories matched.

Transactions, retrieval, PostgreSQL parity

  • All writes go through one write_txn(): BEGIN IMMEDIATE, rollback on any BaseException, bounded retry with jitter on SQLITE_BUSY.
  • CreateInvoice was a single unicode61 token, so invoice, create invoice and "where do we create invoices" all returned zero results — on the project's own flagship example.
  • Japanese and Korean were routed to jieba, a Chinese segmenter. Tokenization is now fingerprinted and skew is reported by opendb doctor.
  • PostgreSQL had carried none of the SQLite fixes, plus an unconditional BEFORE UPDATE trigger. It now passes the same conformance suite, every assertion parametrised over both backends.

Security

ApiKeyMiddleware was implemented, documented, unit-tested — and never mounted, so FILEDB_AUTH_API_KEY did nothing. _resolve_workspace swallowed the ValueError from relative_to() and returned the path anyway, making the only containment check a no-op. A crafted grep pattern hung over 20 seconds on a two-line file. sort_field/sort_dir were interpolated into ORDER BY unvalidated on PostgreSQL. Uploads read the whole body then checked the size.

⚠️ Benchmark claims withdrawn and restated

"100% R@5" is withdrawn. It was measured on longmemeval_oracle.json, where all 500 questions satisfy set(haystack_session_ids) == set(answer_session_ids) with zero distractors — R@5 is arithmetically guaranteed for 497/500. Pooled mode indexes every question's sessions into one 882-session corpus: R@5 = 79.1%, median recall 7.5 ms.

CodeMemEval is restated with its error bars. 96.3% is 26/27, whose 95% interval is [81.7%, 99.3%] — 17.6 points wide, overlapping the cheap reader's 92.6% across nearly its whole width. This benchmark cannot tell those two readers apart, and per-category results (n = 3–6) are now reported as counts.

The paraphrase split is now measured rather than asserted. Same corpus, same gold sessions, only the question wording differs:

Questions R@1 R@5
as written 100% (24/24) 100% (24/24)
restated, 0% lexical overlap 45.8% (11/24) 75.0% (18/24)

That gap is the honest boundary of a pure-lexical retriever, and it was previously averaged away.

The LLM judge is unvalidated. Both accuracy figures come from a judge sharing a model family with the reader it grades, and nothing has yet measured how often it accepts a wrong answer — treat them as upper bounds. codemem_hard.py --run-judge now measures it, scoring 10 plausible-but-false answers against correct-answer controls (a judge that rejects everything otherwise scores a flawless 0% false-accept rate).

Notes

  • Eight existing tests asserted the defective behaviour (e.g. test_recall_resets_confidence_to_one literally tested the bug). They are rewritten to assert corrected semantics, not deleted.
  • PostgreSQL tests skip unless OPENDB_TEST_PG_DSN is set, so CI stays green without a server.

Full changelog: https://github.com/opendb-ai/openDB/blob/main/CHANGELOG.md