memory: /snapshot — condense in-flight to milestone-close; person-prime shipped+verified, R39 arc closed; first persistent-memory.d/ detail files
This commit is contained in:
@@ -0,0 +1,41 @@
|
|||||||
|
# [2026-07-16] bifrost scan/cursor conformance gap → snapshot-cursor ruled NORMATIVE
|
||||||
|
|
||||||
|
## The gap (I surfaced it; operator's catch that it was bifrost's to fix)
|
||||||
|
The heid-bug-hunt flagged our offset cursor's cross-page dup/drop under mutation. On
|
||||||
|
verifying before routing, it turned out sharper than "robustness": bifrost's PROTOCOL
|
||||||
|
already mandates snapshot cursors — the dispatch engine (`bifrost/memory.py:311-314`)
|
||||||
|
drops `sort` on a cursor continuation with the comment *"the cursor's snapshotted order is
|
||||||
|
authoritative"*, and maps `ScanCursorExpired → 410`. The reference `InMemoryMemoryStore`
|
||||||
|
implements it (frozen ordered id-list per opaque token + TTL). But bifrost's **conformance
|
||||||
|
suite had ZERO scan/cursor coverage** — so our non-snapshot offset cursor passed
|
||||||
|
conformance while violating the protocol contract. That coverage hole is the real
|
||||||
|
completeness concern. Routed to bifrost-dev (thread `01KXK7MDTY…`).
|
||||||
|
|
||||||
|
## bifrost-dev's ruling
|
||||||
|
1. **Snapshot-cursor is NORMATIVE, not opaque/per-store.** Operator ruled: cursor
|
||||||
|
snapshots a frozen ordered id-list, continuation ignores `sort`, stale/unknown cursor →
|
||||||
|
`ScanCursorExpired` → 410. **Offset-with-documented-limits is NOT blessed.**
|
||||||
|
2. **Conformance coverage added** in **bifrost 1.1.3** (`bifrost.conformance.
|
||||||
|
memory_store_conformance`, 4 probes: `scan_snapshot_order_authoritative`,
|
||||||
|
`scan_no_dup_or_drop`, `scan_unknown_cursor_expired`, `scan_snapshot_stable_under_write`
|
||||||
|
opt-in). Our offset bug ships as their negative-canary fixture
|
||||||
|
(`fixtures.v0_7.offset_cursor_store.OffsetCursorMemoryStore`). `main()` grades import
|
||||||
|
failure as exit 2 (setup error) vs exit 1 (conformance FAIL).
|
||||||
|
|
||||||
|
## Our status + the TODO (operator-sequenced, NOT urgent)
|
||||||
|
Single-page person-prime (`cursor=None`) is already conformant — nothing shipped is broken;
|
||||||
|
it's only multi-page continuation that's non-conformant. Our contract INV-010 currently
|
||||||
|
marks the offset cursor **v1-provisional / KNOWN DEVIATION** (commit `8199774`).
|
||||||
|
|
||||||
|
TODO when sequenced:
|
||||||
|
1. Bump pin bifrost `1.1.1 → 1.1.3`.
|
||||||
|
2. Replace the offset cursor with the reference snapshot semantics (frozen id-list per
|
||||||
|
opaque token + `ScanCursorExpired` → 410).
|
||||||
|
3. Run `run_all(store_factory=..., include_optional=True)` against our SQLite store —
|
||||||
|
expect P1/P2/P3 RED → green (the before/after IS the validation). Report to bifrost-dev
|
||||||
|
(we're their canary — first non-reference scan implementer).
|
||||||
|
4. Flip INV-010 from v1-provisional to snapshot semantics.
|
||||||
|
|
||||||
|
TTL-duration expiry NOT asserted by the harness (no portable clock hook via store_factory);
|
||||||
|
bifrost-dev offered a `clock_control` opt-in if we ever need time-based expiry certified —
|
||||||
|
parked, not needed yet.
|
||||||
@@ -0,0 +1,65 @@
|
|||||||
|
# [2026-07-15/16] person-prime `scan` build — SHIPPED + DEPLOYED + LIVE-VERIFIED (v0.20.14)
|
||||||
|
|
||||||
|
**The "last push": fix Sindra not remembering Vuong's name across sessions.**
|
||||||
|
|
||||||
|
## Root cause (worldtree-dev)
|
||||||
|
WT injects a recalled fact only if combined score (sim×salience) ≥ **0.45**
|
||||||
|
(`auto_inject_combined_score_threshold`, `core/memory/context_promotion/config.py`),
|
||||||
|
and recall is per-turn **query-gated** → moderate-sim durable facts (name hit ~0.40)
|
||||||
|
never inject. Designed turn-0 fix = WT **#349 person-prime**: a query-LESS
|
||||||
|
top-N-by-recency durable-fact injection, capability-gated on the store advertising
|
||||||
|
`updated_at` in `sort_fields` at the Bifrost handshake — DARK for our provider until now.
|
||||||
|
Fix (ZERO Worldtree change): implement the sorted `scan` verb + advertise the cap.
|
||||||
|
|
||||||
|
## What shipped (6 commits, v0.20.11 → v0.20.14; suite 639 green throughout)
|
||||||
|
- `8fc757a` **v0.20.11** — `scan` verb + `sortable_chunk_fields` cap. Query-LESS,
|
||||||
|
LIVE-only (INV-009: superseded/tombstoned excluded server-side), globally-ordered-
|
||||||
|
before-pagination by indexed `updated_at` (INV-010), sort dispatch-gated. Offset
|
||||||
|
cursor with a `has_more` peek (no empty trailing page = reference-parity). TDD 7/7
|
||||||
|
incl. `parity_vs_reference` #195. NUANCE resolved: bifrost's `InMemoryMemoryStore`
|
||||||
|
READS `updated_at` (never stamps it) — identical to ours; ref does NOT lifecycle-
|
||||||
|
filter so parity is over the live set only.
|
||||||
|
- `a9c521a` **v0.20.12** — Sindra holodesk first-message preset (split out of the
|
||||||
|
soong-lab redefine as its own concern).
|
||||||
|
- `25ccb5c` **v0.20.13** — heid-bug-hunt fix: a truthy non-dict `sort`
|
||||||
|
(`"updated_at"`/`["updated_at"]`/int) hit `(sort or {}).get(...)` → AttributeError
|
||||||
|
instead of InvalidArguments. Added isinstance guard (Gróa#1/Hulda#2 confirmed).
|
||||||
|
- `8199774` — contract: marked the offset cursor **v1-provisional / KNOWN DEVIATION**
|
||||||
|
(see [[2026-07-16-bifrost-cursor-conformance]]).
|
||||||
|
- `f46ccba` **v0.20.14** — **THE DEPLOY-BREAKER** (see Tried/abandoned): advertised
|
||||||
|
`sortable_chunk_fields=[{"name":"updated_at"}]` WITHOUT `type` → bifrost
|
||||||
|
`handshake_response` `SortableChunkField` requires BOTH name+type
|
||||||
|
(`additionalProperties:false`) → whole bind broke. Fixed → add `"type":"timestamp"`
|
||||||
|
+ regression guard in the caps test.
|
||||||
|
|
||||||
|
## heid-bug-hunt triage (panel Gróa/Hulda/Regin, thread `01KXK5XTYHV8TGEDRAZV8GRXWC`)
|
||||||
|
FIXED: non-dict sort (v0.20.13). SURFACED→operator: offset-cursor cross-page dup/drop
|
||||||
|
(→ became the bifrost cursor arc). NOTED (reference-parity/accept-known-risk, no fork):
|
||||||
|
full-table materialize-then-Python-filter (matches ref's O(store) iteration), unbound
|
||||||
|
limit, falsy scope coercion, lexical timestamp ordering. REFUTED: Regin's mixed-type
|
||||||
|
ORDER BY "crash" (SQLite orders by storage class, doesn't raise) + its self-retracted
|
||||||
|
None item.
|
||||||
|
|
||||||
|
## Deploy + live verify (2026-07-15, operator-authorized)
|
||||||
|
Restarted BOTH :8392 combined provider + :8765 web on the new code via the env-
|
||||||
|
preserving `scratchpad/relaunch_by_pid.py <pid>` (captures /proc cmdline+environ+cwd →
|
||||||
|
byte-identical config; self-daemonizes). Added the missing REQUIRED
|
||||||
|
`RATATOSKR_MEMORY_EMBEDDING_DIM=1024` to `env.sh`.
|
||||||
|
|
||||||
|
Drove a bound Sindra turn (`ratatoskr --new --agent ratatoskr:sindra --send … --bifrost-url
|
||||||
|
http://10.100.10.50:8392 --end-user-id ratatoskr-tui`):
|
||||||
|
- **GATE LIT + scan fired ONCE at turn 1** with worldtree-dev's exact args
|
||||||
|
(`scope_all={end_user:ratatoskr-tui} cursor=null limit=3 sort={updated_at,desc}`) →
|
||||||
|
3 records in **~5ms** (no 500ms fail-open). Injection confirmed in Sindra's CoT.
|
||||||
|
- **Cross-session recognition WORKS** — she recalls Vuong as a distinct person + his
|
||||||
|
patterns. The blank-slate problem is SOLVED.
|
||||||
|
- **BUT name-recall FAILS** — `"Name is Vuong."` is the OLDEST chunk (07:09) → excluded
|
||||||
|
from top-3-by-recency AND scores 0.354 (sub-0.45) on the query path → injects via
|
||||||
|
NEITHER; meanwhile a stale contradictory `"user has not yet provided their name"`
|
||||||
|
(07:58, 0.46) IS injected → she concludes she lacks the name. **Root cause = WORLDTREE
|
||||||
|
ranking/hygiene** (WT #364), not our wire. See [[2026-07-16-wt364-r39-name-recall]].
|
||||||
|
|
||||||
|
## Status
|
||||||
|
Technical path GREEN end-to-end (logged by worldtree-dev as the person-prime live
|
||||||
|
milestone). Name-recall waits on WT #364 + R39-designed identity-class pinning. Keeping
|
||||||
|
the live 10-chunk store as the #364 re-verify target.
|
||||||
@@ -0,0 +1,65 @@
|
|||||||
|
# [2026-07-16] Name-recall gap → WT #364 + brokkr R39 re-drive (DECISIVE) + subject-provenance catch
|
||||||
|
|
||||||
|
Downstream of the person-prime live verify ([[2026-07-16-person-prime-scan-shipped]]),
|
||||||
|
which proved the wire is green but the *name* still misses. Root cause is Worldtree-side.
|
||||||
|
|
||||||
|
## WT #364 (worldtree-dev filed; our live specimen = the evidence base)
|
||||||
|
The name-recall miss is TWO defect classes, both at promotion:
|
||||||
|
1. **Contradiction-reconciliation missing.** Promotion wrote a NEGATIVE-knowledge fact
|
||||||
|
("user has not yet provided their name") that was already false; promotion does NO
|
||||||
|
contradiction check against the store, so both the true and stale facts sit live and
|
||||||
|
the WRONG one wins both recall paths (newer → recency top-3; 0.46 → above the 0.45
|
||||||
|
query gate, where the true name sits at 0.354).
|
||||||
|
2. **Subject-attribution leak (operator-caught, NEW class).** Fact `75aa3110` ("prefers
|
||||||
|
clear parameters Intensity/Mood/Willingness…") is NOT a user fact — Vuong never said
|
||||||
|
it; it's **Sindra's OWN system-prompt scripted behavior mis-extracted into the USER
|
||||||
|
memory partition**. `e35b9dfe` (closeness) maybe the same. So the extractor leaks
|
||||||
|
CHARACTER-self facts into user memory — a subject-correctness axis orthogonal to the
|
||||||
|
recency/threshold/stale-negative story. worldtree-dev folded it into #364 as a
|
||||||
|
**subject-attribution gate at promotion** (a third reconciliation dimension).
|
||||||
|
|
||||||
|
**The #364 fix that ships = `(subject,relation)` slot-supersession + identity-tier
|
||||||
|
surfacing** — NOT a threshold tweak. Our harness data directly shaped it. It lands with a
|
||||||
|
re-verify request to us. **#349 ranking decision already RULED by operator (2026-07-15 via
|
||||||
|
brokkr's R39 thread): no top-N recency band-aid; straight to R39 identity-class pinning.**
|
||||||
|
|
||||||
|
## brokkr R39 Phase-1 Arm-0 fusion bake-off — DECISIVE
|
||||||
|
brokkr replayed our frozen 7-fact specimen. **HEADLINE: no (similarity, salience) fusion
|
||||||
|
can fix #364.** The stale negative PARETO-DOMINATES the true name — more similar
|
||||||
|
(0.463 > 0.354) AND equal salience (1.0 = 1.0) — so any monotone f(sim,sal) puts stale
|
||||||
|
above true: S0 product / S1 weighted-sum / S2 RRF all fail. Only **S3 bounded-boost** lands
|
||||||
|
true-in ∧ stale-out, and ONLY via the identity-class/source signal + negative-validity
|
||||||
|
retirement, NOT the sim/sal fusion. **Threshold-tuning is a dead end; the fix is the signal
|
||||||
|
FAMILY** (hard confirmation of Phase-0). Write-up: brokkr
|
||||||
|
`research/R39-memory-salience-dreams-surfacing/phase-1/re-drive-results.md`.
|
||||||
|
|
||||||
|
My 3 findings all confirmed + folded: (1) salience blind — both name facts salience 1.0;
|
||||||
|
(2) shared `(user,name)` supersession slot (Phase-0 Q3); (3) char-self-leak = "genuine NEW
|
||||||
|
class" that RAISED the VoI of R39's dream/offline-hygiene facet (offline consolidation
|
||||||
|
re-partitioning mis-attributed facts).
|
||||||
|
|
||||||
|
## Data structure findings (for the export)
|
||||||
|
Our provider persists ONLY `salience` (+ the embedding). `similarity`/`combined` are
|
||||||
|
WT-side query-time (`bifrost_memory_store.py:702`, combined = sim×salience) — NOT in our
|
||||||
|
store. **Person-prime is query-LESS → carries NO similarity** (brokkr's Arm-1 finding).
|
||||||
|
Recovered per-fact similarity from the verify SEARCH log (query "Hi Sindra — do you
|
||||||
|
remember me?"): name 0.354, stale 0.463; ×salience-1.0 = combined, matching brokkr's
|
||||||
|
0.354/0.46 grounding. `salience_word` (granite categorical) is a WT-extraction-time
|
||||||
|
artifact, not persisted.
|
||||||
|
|
||||||
|
## The export + the specimen
|
||||||
|
- Operator approved **VERBATIM** export ("nothing there is really a concern"). The
|
||||||
|
classifier had blocked writing PII to shared `/mnt/smithy`; routed to operator → he chose
|
||||||
|
full → delivered INLINE (scoped) in brokkr thread `01KXMN7NR54…` as 7-row JSONL.
|
||||||
|
- **⚠️ My verify drive CONTAMINATED the specimen**: it wrote 3 new chunks (re-extractions
|
||||||
|
incl. a 3rd "name unknown" negative) → store is now **10, not 7**. Original 7 intact.
|
||||||
|
- brokkr ACCEPTED the 3 verify-adds as the **Phase-2 Arm-2 seed** (domain-contradiction
|
||||||
|
set). I froze a WAL-consistent snapshot of the full 10-chunk store at
|
||||||
|
`r39-frozen-specimen/sindra-10chunk-specimen.db` (gitignored, `VACUUM INTO`) so it
|
||||||
|
SURVIVES #364 reconciliation. Export on brokkr's Phase-2 signal.
|
||||||
|
- **R39 Arm-0 hold LIFTED** (worldtree-dev). Live store kept UNTOUCHED as the #364
|
||||||
|
re-verify target; frozen snapshot carries the research seed forward independently.
|
||||||
|
|
||||||
|
## Peer threads
|
||||||
|
worldtree-dev verify `01KXK86PZ9…` + hold `01KXMK1C44…`; brokkr R39 `01KXMN7NR54…`;
|
||||||
|
bifrost cursor `01KXK7MDTY…` (see [[2026-07-16-bifrost-cursor-conformance]]).
|
||||||
+46
-50
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user