refactor(cache): Phase B language-advantage pass — dichotomy wave

One pooled *sql.DB per Env (lazily created, schema verified once — the
oracle re-ran the PRAGMA/DDL block on every call; identical observable
behavior since IF NOT EXISTS is idempotent and WAL persists in the
file). ContentHash hex-encodes only the 8 bytes it returns; Compress
builds via strings.Builder. Benchmarks added (hash 140ns/op, compress
6.5µs, recordHit 0.9µs, getCache-hit 23.7µs, putCache 42.6µs).

Full ladder re-run after the rewrite: frozen battery green, gofmt/vet/
build clean, live parity 100% (16/16), freeze --verify 78/78, Python
battery 12 passed both pins.
This commit is contained in:
Nick committed 2026-10-14 02:59:43 +01:00
1 parent f944d7df38
commit e0fd14409e
10 files changed
+101 -22

No files matched your search

+24 -18
View File
@@ -48,10 +48,9 @@ var invalidationMap = map[string][]string{
// Env — the module-global state of cache.py (DB path, clock, the
// in-memory hit/miss accumulators) behind injectable seams.
type Env struct {
MemoryDir string
clockFn func() time.Time
monotonic func() float64
dbPathOnce string
MemoryDir string
clockFn func() time.Time
monotonic func() float64
mu sync.Mutex
hitCounts map[string]int
@@ -60,6 +59,10 @@ type Env struct {
lastMisses map[string]string
flushCounter int
lastFlushT float64
dbOnce sync.Once
db *sql.DB
dbErr error
}
// NewEnv — module globals at import time (fresh accumulators, empty
@@ -169,6 +172,16 @@ func (e *Env) connect() (*sql.DB, error) {
return db, nil
}
// openDB — Phase B: one pooled *sql.DB per Env (lazily created, schema
// verified once). The oracle opens a fresh sqlite3 connection AND
// re-runs the PRAGMA/DDL block on every call; the pool removes the
// per-call DDL walk with identical observable behavior (IF NOT EXISTS
// is idempotent; WAL mode persists in the database file).
func (e *Env) openDB() (*sql.DB, error) {
e.dbOnce.Do(func() { e.db, e.dbErr = e.connect() })
return e.db, e.dbErr
}
// recordHit — Python _record_hit: accumulate a hit in memory; flush to
// SQLite when the threshold is reached.
func (e *Env) recordHit(key string) {
@@ -236,11 +249,10 @@ func (e *Env) flushStats() {
return
}
db, err := e.connect()
db, err := e.openDB()
if err != nil {
return
}
defer db.Close()
for key, count := range hits {
db.Exec("UPDATE cache SET hit_count=hit_count+?, last_hit=? WHERE key=?",
count, lastOrNow(lh, key, e), key)
@@ -262,11 +274,10 @@ func lastOrNow(m map[string]string, key string, e *Env) string {
// memory (no SQLite write on the hot path). The pending count is
// captured BEFORE recording (the oracle's double-count audit fix).
func (e *Env) getCache(key string) *OrderedMap {
db, err := e.connect()
db, err := e.openDB()
if err != nil {
return NewOrderedMap(KV{"hit", false}, KV{"key", key})
}
defer db.Close()
var compressed, full, contentHash, scope, createdAt sql.NullString
var hitCount int
@@ -310,7 +321,7 @@ func nullStr(ns sql.NullString) any {
func (e *Env) putCache(key, value string, compressed *string, scope, sourceHash string) *OrderedMap {
e.flushStats()
db, err := e.connect()
db, err := e.openDB()
if err != nil {
return nil
}
@@ -329,7 +340,6 @@ func (e *Env) putCache(key, value string, compressed *string, scope, sourceHash
created_at = excluded.created_at,
invalidated_at = NULL`,
key, scope, contentHash, value, comp, sourceHash, e.now())
db.Close()
return NewOrderedMap(KV{"stored", key}, KV{"content_hash", contentHash}, KV{"scope", scope})
}
@@ -343,10 +353,9 @@ func ContentCompressed(compressed *string, value string) string {
// invalidate — Python invalidate: invalidate a specific entry.
func (e *Env) invalidate(key, reason string) *OrderedMap {
db, err := e.connect()
db, err := e.openDB()
if err == nil {
db.Exec("UPDATE cache SET invalidated_at=? WHERE key=? AND invalidated_at IS NULL", e.now(), key)
db.Close()
}
return NewOrderedMap(KV{"invalidated", key}, KV{"reason", reason})
}
@@ -355,7 +364,7 @@ func (e *Env) invalidate(key, reason string) *OrderedMap {
// a scope.
func (e *Env) invalidateScope(scope, reason string) *OrderedMap {
count := 0
db, err := e.connect()
db, err := e.openDB()
if err == nil {
if res, err := db.Exec(
"UPDATE cache SET invalidated_at=? WHERE scope=? AND invalidated_at IS NULL", e.now(), scope); err == nil {
@@ -363,7 +372,6 @@ func (e *Env) invalidateScope(scope, reason string) *OrderedMap {
count = int(n)
}
}
db.Close()
}
return NewOrderedMap(KV{"invalidated_scope", scope}, KV{"count", count}, KV{"reason", reason})
}
@@ -371,7 +379,7 @@ func (e *Env) invalidateScope(scope, reason string) *OrderedMap {
// invalidateAll — Python invalidate_all: nuclear option.
func (e *Env) invalidateAll(reason string) *OrderedMap {
count := 0
db, err := e.connect()
db, err := e.openDB()
if err == nil {
if res, err := db.Exec(
"UPDATE cache SET invalidated_at=? WHERE invalidated_at IS NULL", e.now()); err == nil {
@@ -379,7 +387,6 @@ func (e *Env) invalidateAll(reason string) *OrderedMap {
count = int(n)
}
}
db.Close()
}
return NewOrderedMap(KV{"invalidated_all", count}, KV{"reason", reason})
}
@@ -389,14 +396,13 @@ func (e *Env) invalidateAll(reason string) *OrderedMap {
func (e *Env) cacheStats() *OrderedMap {
e.flushStats()
db, err := e.connect()
db, err := e.openDB()
if err != nil {
return NewOrderedMap(
KV{"total", 0}, KV{"active", 0}, KV{"invalidated", 0},
KV{"hits", 0}, KV{"misses", 0}, KV{"hit_rate", "0%"},
KV{"scopes", NewOrderedMap()})
}
defer db.Close()
var total, active int
var hits, misses sql.NullInt64
+3 -1
View File
@@ -9,7 +9,9 @@ import (
)
// ContentHash — sha256[:16] hex (the cache's change-detection hash).
// Phase B: hex-encode only the first 8 bytes (16 hex chars) instead of
// encoding all 32 and slicing — identical output, half the work.
func ContentHash(text string) string {
sum := sha256.Sum256([]byte(text))
return hex.EncodeToString(sum[:])[:16]
return hex.EncodeToString(sum[:8])
}
+48
View File
@@ -14,6 +14,7 @@ import (
"path/filepath"
"regexp"
"sort"
"strings"
"testing"
"time"
)
@@ -304,6 +305,53 @@ func TestPluginManifest(t *testing.T) {
}
}
// ── Phase B benchmarks ────────────────────────────────────────────────
var benchSink string
func BenchmarkContentHash(b *testing.B) {
for i := 0; i < b.N; i++ {
benchSink = ContentHash("benchmark input line for hashing")
}
}
func BenchmarkCompress(b *testing.B) {
text := strings.Repeat("# comment\n====\n(_source_: cite)\nsubstantive benchmark line number here\n\n", 40)
b.ResetTimer()
for i := 0; i < b.N; i++ {
benchSink = Compress(text)
}
}
func BenchmarkRecordHitPending(b *testing.B) {
e := NewEnv(b.TempDir())
e.monotonic = func() float64 { return 0 } // interval never fires
e.putCache("k", "v", nil, "general", "")
b.ResetTimer()
for i := 0; i < b.N; i++ {
e.recordHit("k")
}
}
func BenchmarkGetCacheHit(b *testing.B) {
e := NewEnv(b.TempDir())
e.monotonic = func() float64 { return 0 }
e.putCache("k", "value line", nil, "general", "")
b.ResetTimer()
for i := 0; i < b.N; i++ {
benchSink = encodePythonJSON(e.getCache("k"), -1)
}
}
func BenchmarkPutCache(b *testing.B) {
e := NewEnv(b.TempDir())
e.monotonic = func() float64 { return 0 }
b.ResetTimer()
for i := 0; i < b.N; i++ {
e.putCache("k", "value line", nil, "general", "")
}
}
// ── CLI live parity vs the running oracle ──────────────────────────────
var (
+6 -3
View File
@@ -18,7 +18,7 @@ func Compress(text string) string {
return ""
}
lines := strings.Split(strings.TrimSpace(text), "\n")
var compressed []string
var sb strings.Builder
for _, line := range lines {
stripped := strings.TrimSpace(line)
if stripped == "" {
@@ -43,9 +43,12 @@ func Compress(text string) string {
if len(stripped) < 5 {
continue
}
compressed = append(compressed, stripped)
if sb.Len() > 0 {
sb.WriteByte('\n')
}
sb.WriteString(stripped)
}
result := strings.Join(compressed, "\n")
result := sb.String()
if len(result) > 800 {
result = result[:797] + "..."
}
@@ -0,0 +1 @@
0
+1
View File
@@ -0,0 +1 @@
0
+1
View File
@@ -0,0 +1 @@
0
@@ -0,0 +1 @@
0
+1
View File
@@ -0,0 +1 @@
0
+15
View File
@@ -54,3 +54,18 @@ Oracle: src/rune/cache.py (492 lines, 17 fns).
- Flush-timing is invisible in every observable (row+pending invariant
flushed at put/stats): first-record flush behavior under either
monotonic epoch cannot diverge in outputs.
## Phase B (commit 2) re-verification
- One pooled *sql.DB per Env (lazily created; the oracle re-ran the
PRAGMA/DDL block on EVERY call — the pool drops that per-call walk
with identical observable behavior: IF NOT EXISTS is idempotent,
WAL persists in the file); ContentHash hex-encodes only the 8 bytes
it needs; Compress builds via strings.Builder.
- Ladder re-run after Phase B: battery green (cache-phaseb-gotest),
gofmt/vet/build clean (cache-phaseb-goladder), live parity 100%
16/16 again (cache-phaseb-live-parity), freeze --verify 78/78
(cache-phaseb-freeze-verify), Python battery 12 passed
(cache-phaseb-pytest).
- Benchmarks (200x): ContentHash 139.9 ns/op, Compress 6.5 µs/op,
recordHit-pending 0.9 µs/op, getCache-hit 23.7 µs/op, putCache
42.6 µs/op.