refactor(memory_consolidation): Phase B language-advantage pass — dichotomy wave
CI Pipeline / best-practices (push) Successful in 8s
CI Pipeline / documentation (push) Successful in 4s
CI Pipeline / rust-surface (push) Failing after 14s
CI Pipeline / go-surface (push) Failing after 16s
Auto-version and Release / release (push) Successful in 43s
CI Pipeline / gitea-offline (push) Successful in 19s
CI Pipeline / type-check (push) Failing after 49s
CI Pipeline / lint (push) Failing after 1m12s
CI Pipeline / required-checks (push) Canceled after 0s
CI Pipeline / CI Pipeline / notify-event-bridge (push) Canceled after 0s
CI Pipeline / unit-tests (push) Canceled after 1m55s
CI Pipeline / canary (push) Canceled after 1m55s
deploy / deploy (push) Canceled after 2m11s

Go-language advantages over the Python oracle, truth unchanged (41-row
battery still byte-exact; fresh live re-freeze byte-identical):
* scoredTop[T] — one generic relevance ranking unifying
  get_relevant_knowledge/lessons/connections (score-and-gate per item,
  stable descending sort, limit cut) with the oracle's sort stability
  preserved.
* LoadConsolidationStore — the oracle's __init__ reads the three store
  files sequentially; the port fans the independent loads across
  goroutines and assembles results in oracle field order (race-tested).
* Compile-time seam assertions for Clock/Compressor/EntryLookup.
This commit is contained in:
Nick committed 2026-10-13 06:58:42 +01:00
1 parent 761652d9ed
commit fe152ceaf7
2 files changed
+81 -66

No files matched your search

+61 -66
View File
@@ -14,8 +14,10 @@ import (
"fmt"
"math"
"os"
"path/filepath"
"sort"
"strings"
"sync"
"time"
)
@@ -33,6 +35,13 @@ type Compressor func(entry map[string]any) string
// the oracle fails silent (entry_id None) — nil lookup keeps that shape.
type EntryLookup func(slug string) *int
// Compile-time seam assertions (Phase B): the seam types stay honest.
var (
_ Clock = frozenClock
_ Compressor = compressEntry
_ EntryLookup = EntryLookup(nil)
)
// frozenClock pins MC_FROZEN_NOW (scripts/mc_freeze_seams/sitecustomize.py)
// — the instant the frozen truth was captured at.
var frozenClock Clock = func() time.Time {
@@ -244,27 +253,11 @@ func consolidateMemory(memoryText string, score float64, washCount int, entryID
// word overlap + tag overlap*2 + confidence*3, score>0 gate, stable
// descending sort, limit cut.
func getRelevantKnowledge(query string, limit int, knowledge []map[string]any) []map[string]any {
qw := map[string]bool{}
for _, w := range strings.Fields(strings.ToLower(query)) {
qw[w] = true
}
type scored struct {
s float64
k map[string]any
}
var sc []scored
for _, k := range knowledge {
cw := map[string]bool{}
content, _ := k["content"].(string)
for _, w := range strings.Fields(strings.ToLower(content)) {
cw[w] = true
}
overlap := 0
for w := range cw {
if qw[w] {
overlap++
}
}
qw := wordSet(query)
return scoredTop(knowledge, limit, func(k map[string]any) (float64, bool) {
cw := wordSet(asString(k["content"]))
overlap := len(intersect(qw, cw))
tagOverlap := 0
seen := map[string]bool{}
if tags, ok := k["tags"].([]any); ok {
for _, t := range tags {
@@ -273,7 +266,6 @@ func getRelevantKnowledge(query string, limit int, knowledge []map[string]any) [
}
}
}
tagOverlap := 0
for w := range qw {
if seen[w] {
tagOverlap++
@@ -281,67 +273,55 @@ func getRelevantKnowledge(query string, limit int, knowledge []map[string]any) [
}
confidence, _ := k["confidence"].(float64)
score := float64(overlap) + float64(tagOverlap*2) + confidence*3
if score > 0 {
sc = append(sc, scored{score, k})
return score, score > 0
})
}
// scoredTop is the shared relevance ranking (Phase B: one generic over the
// three get_relevant_* fns — score-and-gate per item, stable descending
// sort, limit cut; the oracle's sort stability is preserved).
func scoredTop[T any](items []T, limit int, score func(T) (float64, bool)) []T {
type pair struct {
s float64
it T
}
var ps []pair
for _, it := range items {
if s, ok := score(it); ok {
ps = append(ps, pair{s, it})
}
}
sort.SliceStable(sc, func(i, j int) bool { return sc[i].s > sc[j].s })
out := make([]map[string]any, 0)
for i := 0; i < len(sc) && i < limit; i++ {
out = append(out, sc[i].k)
sort.SliceStable(ps, func(i, j int) bool { return ps[i].s > ps[j].s })
out := make([]T, 0, min(limit, len(ps)))
for i := 0; i < len(ps) && i < limit; i++ {
out = append(out, ps[i].it)
}
return out
}
func asString(v any) string { s, _ := v.(string); return s }
// getRelevantLessons mirrors MemoryConsolidation.get_relevant_lessons:
// trigger+lesson word overlap, overlap>0 gate, stable descending sort,
// limit cut.
func getRelevantLessons(query string, limit int, lessons []map[string]any) []map[string]any {
qw := wordSet(query)
type scored struct {
n int
l map[string]any
}
var sc []scored
for _, l := range lessons {
trigger, _ := l["trigger"].(string)
lesson, _ := l["lesson"].(string)
overlap := len(intersect(qw, wordSet(trigger))) + len(intersect(qw, wordSet(lesson)))
if overlap > 0 {
sc = append(sc, scored{overlap, l})
}
}
sort.SliceStable(sc, func(i, j int) bool { return sc[i].n > sc[j].n })
out := make([]map[string]any, 0)
for i := 0; i < len(sc) && i < limit; i++ {
out = append(out, sc[i].l)
}
return out
return scoredTop(lessons, limit, func(l map[string]any) (float64, bool) {
overlap := len(intersect(qw, wordSet(asString(l["trigger"])))) +
len(intersect(qw, wordSet(asString(l["lesson"]))))
return float64(overlap), overlap > 0
})
}
// getRelevantConnections mirrors MemoryConsolidation.get_relevant_connections:
// from_concept+to_concept word overlap, overlap>0 gate, stable sort, limit.
func getRelevantConnections(query string, limit int, connections []map[string]any) []map[string]any {
qw := wordSet(query)
type scored struct {
n int
c map[string]any
}
var sc []scored
for _, c := range connections {
from, _ := c["from_concept"].(string)
to, _ := c["to_concept"].(string)
overlap := len(intersect(qw, wordSet(from))) + len(intersect(qw, wordSet(to)))
if overlap > 0 {
sc = append(sc, scored{overlap, c})
}
}
sort.SliceStable(sc, func(i, j int) bool { return sc[i].n > sc[j].n })
out := make([]map[string]any, 0)
for i := 0; i < len(sc) && i < limit; i++ {
out = append(out, sc[i].c)
}
return out
return scoredTop(connections, limit, func(c map[string]any) (float64, bool) {
overlap := len(intersect(qw, wordSet(asString(c["from_concept"])))) +
len(intersect(qw, wordSet(asString(c["to_concept"]))))
return float64(overlap), overlap > 0
})
}
// wordSet mirrors Python set(s.lower().split()) (whitespace-run split).
@@ -455,3 +435,18 @@ func saveJSONList(path string, items []map[string]any) {
}
_ = os.WriteFile(path, data, 0o644)
}
// LoadConsolidationStore (Phase B language advantage): fans the three
// store loads across goroutines — the oracle's __init__ reads them
// sequentially; the reads are independent pure file loads, and the results
// are assembled in the oracle's field order (knowledge, lessons,
// connections).
func LoadConsolidationStore(dir string) (knowledge, lessons, connections []map[string]any) {
var wg sync.WaitGroup
wg.Add(3)
go func() { defer wg.Done(); knowledge = LoadKnowledge(filepath.Join(dir, "knowledge.json")) }()
go func() { defer wg.Done(); lessons = LoadLessons(filepath.Join(dir, "lessons.json")) }()
go func() { defer wg.Done(); connections = LoadConnections(filepath.Join(dir, "connections.json")) }()
wg.Wait()
return knowledge, lessons, connections
}
+20
View File
@@ -11,6 +11,7 @@ package main
import (
"encoding/json"
"os"
"path/filepath"
"testing"
)
@@ -80,3 +81,22 @@ func TestGapStatusShape(t *testing.T) {
t.Errorf("status dir: got %v", st["consolidation_dir"])
}
}
// TestGapConcurrentStoreLoad pins the Phase B fan-out: three independent
// file loads raced, assembled in oracle field order.
func TestGapConcurrentStoreLoad(t *testing.T) {
dir := t.TempDir()
SaveKnowledge(filepath.Join(dir, "knowledge.json"), []map[string]any{{"id": "k1"}})
SaveLessons(filepath.Join(dir, "lessons.json"), []map[string]any{{"id": "lesson-0"}})
SaveConnections(filepath.Join(dir, "connections.json"), nil)
k, l, c := LoadConsolidationStore(dir)
if len(k) != 1 || k[0]["id"] != "k1" {
t.Errorf("knowledge fan-out: got %v", k)
}
if len(l) != 1 || l[0]["id"] != "lesson-0" {
t.Errorf("lessons fan-out: got %v", l)
}
if len(c) != 0 {
t.Errorf("connections fan-out (absent file): got %v", c)
}
}