diff --git a/CHANGELOG.md b/CHANGELOG.md index d913833..66db849 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,24 +7,18 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [1.4.0] - 2026-04-28 -### Added +### Memory Quality Cleanup -- Unified memory quality gate in `src/memory-quality.ts` as the single source of truth for all memory quality rules. -- CRITICAL MEMORY RULES in compaction prompt with explicit good/bad examples. -- Auto-supersede migration `2026-04-28-quality-cleanup` that marks low-quality compaction memories as superseded on first load. +- Unified quality gate for compaction memory candidates and cleanup checks. +- Rewritten compaction memory prompt to reduce over-production of low-quality memories. +- Conservative one-time quality cleanup migration (`2026-04-28-quality-cleanup`) that supersedes only high-confidence garbage patterns: progress snapshots, raw errors, commit/CI snapshots, temporary status notes, active file snapshots, code/API signatures, path-heavy entries, and empty entries. +- Soft heuristic failures (`bad_feedback`, `bad_decision`) are intentionally excluded from automatic migration cleanup to protect durable declarative memories such as branding rules, API facts, release rules, and architecture decisions. +- Migration audit log: `~/.local/share/opencode-working-memory/migration-logs/2026-04-28-quality-cleanup.jsonl`. +- Extraction rejection log: `~/.local/share/opencode-working-memory/extraction-rejections.jsonl`. -### Changed +### Recovery note -- Memory quality rules now apply to all memory types, not just project entries. -- Compaction prompt explicitly instructs model that most compactions should produce zero memories. -- Low-quality compaction memories (progress snapshots, implementation notes, session-internal notes) are automatically superseded during workspace memory normalization. - -### Migration Notes - -- Existing low-quality `source: "compaction"` entries will be marked as `superseded` once on first load after upgrade. -- Explicit and manual memories are never affected by quality cleanup. -- Superseded entries are retained on disk with `quality_cleanup` tags for audit purposes. -- Migration is idempotent and runs exactly once per workspace. +The cleanup migration changes matching entries to `status: "superseded"`; it does not delete the entry. If a useful memory is superseded, inspect the migration audit log and restore by changing that entry back to `status: "active"` in the workspace's `workspace-memory.json`. The migration runs once per workspace. ## [1.3.3] - 2026-04-28 diff --git a/README.md b/README.md index 9614372..2760930 100644 --- a/README.md +++ b/README.md @@ -174,6 +174,8 @@ It includes guards for: The goal is to remember durable facts, not every detail. +Historical cleanup is intentionally conservative: extraction-time filtering may reject more aggressively, but one-time migration cleanup only supersedes high-confidence garbage patterns. This protects existing durable memories written in declarative style, such as "API endpoint is X" or "Product branding is Y". + ## Configuration OpenCode Working Memory works out of the box. diff --git a/scripts/dev/dry-run-migration.ts b/scripts/dev/dry-run-migration.ts new file mode 100644 index 0000000..807411d --- /dev/null +++ b/scripts/dev/dry-run-migration.ts @@ -0,0 +1,17 @@ +import { loadWorkspaceMemory } from "../../src/workspace-memory.ts"; + +const roots = [ + "/Users/sd_wo/work/opencode-working-memory", + "/Users/sd_wo/Documents/projects/Pre-cancer-atlas", + "/Users/sd_wo/work/opencode-record", + "/Users/sd_wo/work/pathology-agent-reports", + "/Users/sd_wo/work/pathology-extraction", +]; + +for (const root of roots) { + console.log(`Loading workspace memory: ${root}`); + const store = await loadWorkspaceMemory(root); + const active = store.entries.filter(entry => entry.status !== "superseded").length; + const superseded = store.entries.filter(entry => entry.status === "superseded").length; + console.log(` active=${active} superseded=${superseded} migrations=${(store.migrations ?? []).join(",")}`); +}