Skip to content

madcop v1.3.0-rc.3 — Skill crystallization (L4 cluster heads)

Pre-release
Pre-release

Choose a tag to compare

@linmy666 linmy666 released this 26 Jun 13:36

v1.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.crystallize ships:
    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=skill so 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 crystallized tag — call db.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-limit written with crystallized tag; idempotent re-run returns [] PASS