session-memory Phase 2: versioned Pattern Catalog store (T02)

Files-first catalog (one JSON per pattern, id = source-key). Single
idempotent upsert path: added / unchanged / updated (status-only, no bump) /
versioned (content change bumps semver + archives prior to <id>.history.jsonl).
Dedup is structural on pattern id. 5 new tests; suite 52/52 green.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-06-07 00:18:01 +02:00
parent 5f810a6992
commit c6164a82ba
3 changed files with 219 additions and 1 deletions

View File

@@ -0,0 +1,86 @@
"""Versioned Pattern Catalog tests (T02): round-trip, dedup, idempotent upsert."""
import os
import sys
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
from session_memory.curate.catalog import ( # noqa: E402
ADDED,
UNCHANGED,
UPDATED,
VERSIONED,
Catalog,
)
from session_memory.curate.schema import ( # noqa: E402
Provenance,
Resolution,
Scope,
SolutionPattern,
)
def _pattern(src="success:clean_pass:outcome", problem="ran tests, clean finish"):
return SolutionPattern(
id=SolutionPattern.make_id(src),
name="Run tests before declaring success",
version="1.0.0",
polarity="success",
problem=problem,
resolutions=[Resolution(summary="run the suite")],
scope=Scope(flavors=["claude", "grok"]),
provenance=Provenance(source_key=src, evidence={"frequency": 18}),
)
def test_add_then_load_round_trips(tmp_path):
cat = Catalog(str(tmp_path))
assert cat.upsert(_pattern()) == ADDED
loaded = cat.load(SolutionPattern.make_id("success:clean_pass:outcome"))
assert loaded is not None
assert loaded.problem == "ran tests, clean finish"
assert loaded.created_at and loaded.updated_at
assert [p.id for p in cat.list()] == [loaded.id]
def test_resave_identical_is_noop(tmp_path):
cat = Catalog(str(tmp_path))
cat.upsert(_pattern())
assert cat.upsert(_pattern()) == UNCHANGED
# version not bumped, no history written
assert cat.load(_pattern().id).version == "1.0.0"
assert cat.history(_pattern().id) == []
def test_dedup_on_source_key(tmp_path):
cat = Catalog(str(tmp_path))
cat.upsert(_pattern())
cat.upsert(_pattern()) # same source key -> same id -> one file
assert len(cat.list()) == 1
def test_content_change_bumps_version_and_archives(tmp_path):
cat = Catalog(str(tmp_path))
cat.upsert(_pattern())
assert cat.upsert(_pattern(problem="now with more nuance")) == VERSIONED
current = cat.load(_pattern().id)
assert current.version == "1.0.1"
assert current.problem == "now with more nuance"
hist = cat.history(_pattern().id)
assert len(hist) == 1
assert hist[0]["version"] == "1.0.0"
assert hist[0]["status"] == "superseded"
def test_status_only_change_updates_without_bump(tmp_path):
cat = Catalog(str(tmp_path))
cat.upsert(_pattern())
p = _pattern()
p.status = "approved"
p.distribution_ready = True
assert cat.upsert(p) == UPDATED
current = cat.load(p.id)
assert current.status == "approved"
assert current.distribution_ready is True
assert current.version == "1.0.0" # metadata change, no bump
assert cat.history(p.id) == []