Files
openhuman/docs/tinycortex-parity-checklist.md
T

128 lines
11 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# TinyCortex Data-Format Parity Checklist (Phase 0.3)
**Purpose.** Existing user workspaces must open **unchanged** after every cutover flip.
This checklist enumerates every on-disk format shared between the host engine and TinyCortex,
records the audit result, and specifies the **golden-workspace parity harness** that gates W3, W5, W6.
**Hard rule (plan §0.3/§6):** any mismatch is fixed **upstream in tinycortex**, never papered over
with a host shim.
Anchors: host `7850cf363` · tinycortex `d1a8c7be` (v0.1.1).
## Ownership tiers in the shared workspace (key finding)
A user workspace's `chunks.db` (and content vault) holds **two tiers**:
1. **Crate-owned substrate** — moves to TinyCortex, schema must match byte-for-byte:
`vectors`, `kv_global`, `kv_namespace`, `store_meta`, `legacy_marker`, `mcp_writes`,
`mem_tree_chunks`, `mem_tree_chunk_embeddings`, `mem_tree_chunk_reembed_skipped`,
`mem_tree_summaries`, `mem_tree_summary_embeddings`, `mem_tree_summary_reembed_skipped`,
`mem_tree_buffers`, `mem_tree_trees`, `mem_tree_score`, `mem_tree_entity_index`,
`mem_tree_entity_edges`, `mem_tree_entity_hotness`, `mem_tree_ingested_sources`,
`mem_tree_jobs` **(20 tables — exact name parity confirmed)**.
2. **Host-retained `UnifiedMemory` namespace-document tier** — stays host (the "namespace
document/graph store" plan §1 keeps host), coexisting in the **same** DB file:
`memory_docs`, `graph_global`, `graph_namespace`, `episodic_log` (+ `episodic_fts` virtual +
`episodic_ai/ad/au` triggers), `event_log` (+ `event_fts` + `event_embeddings` +
`event_ai/ad/au` triggers), `conversation_segments`, `segment_embeddings`, `vector_chunks`,
`user_profile` **(10 tables + FTS + triggers)**.
These live in `src/openhuman/memory_store/unified/{init,fts5,events,segments,profile}.rs`.
**W3 must keep the host creating/reading these in the same DB the crate now manages**
the crate's `chunks::with_connection` opens the shared handle; host `UnifiedMemory` schema
init runs alongside the crate's. Parity requirement: crate schema init and host `unified`
init must **compose without collision** on both fresh and existing DBs.
## Parity results by format dimension
| # | Format | Result | Evidence |
| --- | --- | --- | --- |
| P1 | **Deterministic chunk ID** | ✅ **IDENTICAL** | `chunk_id()` = SHA-256 over `source_kind.as_str()` `\0` `source_id` `\0` `seq_in_source.to_be_bytes()` `\0` `content`, first 32 hex chars. Host `memory_store/chunks/types.rs:269` vs crate `chunks/types.rs:282` — byte-for-byte identical. |
| P2 | **Vector encoding (packed f32)** | ✅ **IDENTICAL** | `vec_to_bytes`: little-endian `f32::to_le_bytes`, 4 bytes/elem, no header. Host `vectors/store.rs:467` vs crate `store/vectors/store.rs:397` — identical. |
| P3 | **`vectors` table schema** | ✅ **IDENTICAL** | `(id TEXT, namespace TEXT, text TEXT, embedding BLOB, metadata TEXT DEFAULT '{}', created_at REAL, updated_at REAL, PRIMARY KEY(namespace,id))` + `idx_vectors_ns`. Identical. |
| P4 | **`mem_tree_jobs` (queue) columns** | ✅ **MATCH** | Both persist `(id, kind, payload_json, dedupe_key, status, attempts, max_attempts, available_at_ms, locked_until_ms, last_error, created_at_ms, started_at_ms, completed_at_ms)` (identical INSERT column list). Job **payload_json** shapes must also match — verify per `JobKind` in harness (P9). |
| P5 | **`mem_tree_chunks` base columns** | ✅ **MATCH (base)** ⚠️ **new-DB divergence** | Base 15 columns identical (`id…chunk_id`). **Divergence:** crate's `CREATE` inlines 3 legacy embedding columns (`model_signature TEXT, vector BLOB, dim INTEGER`) that the host **dropped** after migrating inline embeddings to the `mem_tree_chunk_embeddings` sidecar (host `chunks/store.rs:110` comment, #1574). **Existing DBs: compatible** — both run `CREATE TABLE IF NOT EXISTS` (no-op on existing) + `migrate_legacy_embeddings_to_sidecar` (crate `chunks/migrations.rs:23`). **Fresh DBs: crate adds 3 unused columns.** Risk: positional `INSERT`/`SELECT *`. **Action: harness asserts fresh-DB schema equality; if the 3 cols matter, drop them upstream.** |
| P6 | **Content vault paths** | ✅ **IDENTICAL sig** ⚠️ verify `sanitize_filename` | `chunk_rel_path(source_kind, source_id, chunk_id)` and `summary_rel_path(tree_kind, scope_slug, level, summary_id)` — identical signatures, same per-`source_kind` branching (`email` special-case). Host sanitizes chunk-id colons → `-` (`content/paths.rs:284`); crate uses `sanitize_filename` (`paths.rs:179`). **Action: harness asserts identical relative paths for a corpus of colon/unicode/long chunk-ids** (Windows-illegal chars are the risk). |
| P7 | **YAML frontmatter** | ✅ **MATCH** (verify key order) | Summary markdown frontmatter delimited by `---\n … ---\n` (crate `content/compose/summary.rs:76,127`; `split_front_matter` on `rposition(line=="---")`). **Action: harness asserts identical frontmatter key set + order + serialization** for chunk & summary markdown (byte-compare composed files). |
| P8 | **Entity markdown** | ⏳ harness | `entities/` registry markdown. Host `memory_entities` (0 external refs) ↔ crate `entities/`. Low risk (full port, no drift). Harness byte-compares entity files. |
| P9 | **Git diff-ledger layout** | ✅ git-backed both | Host migrated to git-backed ledger 06-25 (`040e6e20d`), captured in port (crate `diff/ledger.rs`, `diff.rs:98`). Verify `.git` repo layout + snapshot markdown + read-marker storage identical. Harness opens an existing diff repo with both. |
| P10 | **`store_meta` / embedding signature** | ✅ format | `format_embedding_signature` = `"provider={name};model={model};dims={dims}"` (crate `store/vectors/embedding.rs`). Host must produce the identical signature string from `Config` (W1 `embeddings.rs` seam) or re-embed churn triggers. **Action: seam test asserts signature string equality.** |
| P11 | **Remaining `mem_tree_*` column parity** | ⏳ harness | `mem_tree_summaries`, `mem_tree_buffers`, `mem_tree_trees`, `mem_tree_score`, `mem_tree_entity_index`, `mem_tree_entity_edges`, `mem_tree_entity_hotness`, `mem_tree_ingested_sources`, `mem_tree_chunk_embeddings`, reembed-skipped tables, `kv_*`, `mcp_writes`, `legacy_marker`. Spot-checks clean; full column+index+PK diff is automated in the harness. |
| P12 | **Host-retained tier coexistence** | ⏳ W3 gate | Crate schema init + host `unified` init must both run on the shared DB without `CREATE`/index collisions. Harness opens a real workspace, runs crate init then host init (and vice-versa), asserts full `sqlite_master` superset is preserved and no data dropped. |
Legend: ✅ audited-identical · ⚠️ divergence flagged · ⏳ deferred to harness (automated per-flip).
---
## The golden-workspace parity harness (design)
The built-in parity harness is the read-side comparator that gates each risky flip. It exists at
two layers.
### Layer 1 — schema/format asserters (host-side unit tests, cheap, run every PR)
A `tests/tinycortex_parity/` module with pure-function comparators (no disk):
- **`chunk_id_parity`** — table of `(source_kind, source_id, seq, content)` → assert host `chunk_id`
== `tinycortex::memory::chunks::chunk_id` (covers P1). *(After W3 both resolve to the crate; keep
the vector as a regression pin.)*
- **`vector_roundtrip_parity`** — random `Vec<f32>``vec_to_bytes``bytes_to_vec` byte-equal
across both (P2).
- **`content_path_parity`** — corpus of adversarial ids (colons, unicode, >255 chars, `email`
source) → assert identical `chunk_rel_path`/`summary_rel_path` (P6).
- **`frontmatter_parity`** — compose a fixed chunk+summary → byte-compare markdown incl. frontmatter
key order (P7).
- **`embedding_signature_parity`** — assert the W1 seam's `signature()` string == the format the
store persisted into `store_meta` (P10).
### Layer 2 — golden-workspace differential harness (the flip gate)
The core mechanism from plan §0.3: **one on-disk workspace, opened by both engines, outputs compared.**
**Fixture.** Check in a small, deterministic `tests/fixtures/golden-workspace/` produced by the
*pre-migration* build: a real `chunks.db` + content vault + diff `.git`, seeded via a fixed script
(`scripts/gen-golden-workspace.sh`) with: a handful of chat + document + email sources across ≥2
namespaces, ingested + scored + sealed to ≥2 tree levels, some entities/edges, a few queue jobs in
mixed states, and both tiers populated (episodic/event/segment rows present). Store the **generator
script** and a **manifest** (expected chunk-ids, summary paths, recall snapshots) so the fixture is
regenerable and reviewable, not an opaque blob.
**Comparators (read-only, both engines open the SAME copied workspace):**
1. **Schema snapshot** — dump `sqlite_master` (tables, indexes, triggers, `sql` text normalized) from
the DB after each engine's `open`/init; assert the crate-owned 20-table set is identical and the
host-retained 10-table tier is untouched (P3P5, P11, P12).
2. **Recall/retrieval snapshot** — run a fixed query battery through the stable public surface
(`openhuman::memory::` recall + `read_rpc` retrieval primitives) on pre- and post-migration builds;
assert identical ordered hit ids + scores (within f64 epsilon) + `supporting_relations` (guards G2)
+ taint (guards the security seam).
3. **Tree read snapshot**`read_tree` / `drill_down` / `cover_window` over the sealed tree; assert
identical node structure + summary content.
4. **Byte-compare vault** — after a read-only open, assert **no content files changed** (a flip must
not rewrite the vault) and, for a controlled re-ingest of one source, assert composed markdown is
byte-identical.
5. **Idempotent re-open** — open → close → open with the post-migration build; assert no migration
churn (no re-embed storm, no schema rewrite) on an already-current DB.
**Wiring.** Runs under `pnpm test:rust` (host-side, counts toward coverage) and as a dedicated
`tests/memory_golden_parity_e2e.rs`. The existing crate-level integration tests
(`tests/memory_roundtrip_e2e.rs`, `memory_tree_sync_deep_raw_coverage_e2e.rs`) act as the
"public-surface still green" guard (plan §5.1); this harness adds the **differential** guard that a
flip preserves *existing* data, not just that the API still functions.
**Gate mapping:** Layer-1 asserters run every PR. Layer-2 golden harness is **green-before-merge** on
**W3** (store+chunks), **W5** (tree+retrieval+score), **W6** (ingest). W4 (queue) additionally asserts
job payload_json parity (P4/P9). Any red = upstream fix in tinycortex, re-bump submodule, re-run.
## Open divergences to resolve upstream before their flip
| Item | Flip gated | Resolution |
| --- | --- | --- |
| P5 `mem_tree_chunks` 3 legacy inline columns (fresh-DB) | W3 | Confirm no positional `INSERT`/`SELECT *`; if the columns are dead, drop them in a tinycortex PR so fresh DBs match. |
| P6 `sanitize_filename` vs host colon→`-` | W3 | Prove identical output on adversarial id corpus; align upstream if any diverge (Windows-illegal chars). |
| P7 frontmatter key **order** | W5/W6 | Byte-compare composed markdown; align serializer order upstream if diff. |
| G2 `supporting_relations` (graph_* host-retained vs crate derive-on-read) | W6/W7 | Recall snapshot (comparator 2) must match; else upstream relation persist. |
All other dimensions (P1P4, P8P12) audited compatible or covered by the automated harness.