madcop v1.3.0-rc.3 — Skill crystallization (L4 cluster heads)
Pre-releasev1.3.0-rc.3 adds the L4 layer — skill crystallization. After enough plan-execute runs, the brain accumulates many small skill pages whose topic: values share a prefix (rate-limit-retry, rate-limit-burst, rate-limit-headers). L4 compresses them into a single named cluster head.
What changes
-
New module
madcop.agent.crystallizeships:
cluster_topics()— pure: group pages by topic-prefix
aggregate_outcome()— pure: majority-wins aggregation
render_skill_body()— pure: frontmatter + body builder
crystallize_skills()— pure driver: writes one head per cluster
SkillCrystallizer— middleware: opt-in (enabled=False default), runs at HOOK_PLAN_END -
Cluster heads are
type=skillso retrieval + outcome-aware ranking treat them like any other skill page. -
Cluster heads carry the aggregated outcome (success/failure/unknown) so L3 ranking benefits from cluster-level evidence.
-
Cluster heads get a
crystallizedtag — calldb.search(..., tags=["crystallized"])to retrieve just the heads.
Why "delete + insert" on refresh
A cluster's member set may grow (a 4th reflection joins). The brain's pages_touch SQLite trigger fires on UPDATE pages when updated_at is unchanged, which on SQLite 3.40.x trips a "database disk image is malformed" error. The crystallizer works around this by db.delete(slug) then db.save(slug, ...) — a delete followed by an INSERT, which is the safe path. Idempotent for callers; one extra row in ingest_log.
Quick start
from madcop.agent.crystallize import crystallize_skills
from madcop.brain.store import PageDB
db = PageDB("~/.madcop/brain.db")
new_slugs = crystallize_skills(db, min_cluster_size=3)Or run on the middleware chain (opt-in):
from madcop.agent import MiddlewareChain, SkillCrystallizer
chain = MiddlewareChain([
SkillCrystallizer(db, enabled=True), # opt-in
])Defaults
min_cluster_size = 3— smallest pattern size that suggests a real recurring shape.prefix_split = "-"— topics are slug-shaped by convention.
Tests
27 new tests in tests/agent/test_crystallize.py. Total 928/928 passing.
Install
pip install --upgrade madcop==1.3.0rc3
Verification
- pytest: 928 passed in 4.92s
python3 -c "from madcop import __version__"->1.3.0rc3- Fresh-venv
pip install --force-reinstall madcop==1.3.0rc3-> imports L4 surface; E2E:skill-rate-limitwritten withcrystallizedtag; idempotent re-run returns[]PASS