Skip to content
v1.13.0May 20, 2026

**v0.2 Interactive Rule-Approval (`plan-v0.2-interactive-rule-approval`)**.

**v0.2 Interactive Rule-Approval (`plan-v0.2-interactive-rule-approval`)**. Closes the silent-self-attestation bug class in Massu's auto-learning system. v0.1 (`auto-learning.md:35-46`) was a protocol obligation the model self-enforces at `/massu-loop` end, audited post-hoc by `/massu-learning-audit`. v0.2 adds real...

v0.2 Interactive Rule-Approval (plan-v0.2-interactive-rule-approval). Closes the silent-self-attestation bug class in Massu's auto-learning system. v0.1 (auto-learning.md:35-46) was a protocol obligation the model self-enforces at /massu-loop end, audited post-hoc by /massu-learning-audit. v0.2 adds real-time correction detection (UserPromptSubmit hook, score-based threshold ≥60), side-channel rule-candidate funnel (.massu/rule-candidates/<sha>.json), explicit slash command /massu-rule list|show|approve|dismiss|recurrence, atomic write through applyRuleCandidate() helper with audit_log UNIQUE-INDEX idempotency, three-class rubric (pattern-scanner | claude-md-cr | corrections-md) + autoLearning.customDestinations config extension point. Three-layer structural enforcement: protocol gate (slash command + hook) + idempotency lock (audit_log UNIQUE INDEX) + drift-guard vitest (rule-promotion-effectiveness.test.ts). New canonical rule CR-53 codifies "auto-learned rules must be effective". Ships as @massu/core@1.13.0 — new MCP-adjacent capability + new slash command + backwards-compatible audit_log.event_type CHECK extension (internal-process table, zero external schema consumers — minor justified per semver §7).

Added

  • CR-53 / VR-INTERACTIVE-LEARNING — every audit_log row with event_type='rule_promoted' older than 7 days MUST have metadata.recurrence_count == 0. Three-layer enforcement: protocol gate (/massu-rule approve inserts recurrence_count: 0) + increment hook (post-tool-use.ts:incrementRecurrenceCountsForScannerFailures via lib/recurrence-incrementer.ts) + drift-guard (rule-promotion-effectiveness.test.ts dual-channel: audit_log AND .cr53-increment-failures.jsonl). Allowlist via MASSU_KNOWN_RULE_LIMITATIONS env-var for documented exceptions (channel-a only; failure-log channel-b cannot be silenced).
  • packages/core/src/rule-candidate-detector.tsscoreCorrectionPrompt() scoring model with 9 signals + threshold ≥60. Replaces the binary correctionPatterns regex from prompt-analyzer.ts:59 which mis-fired on "no problem" / "no thanks". Calibration: precision=1.000, recall=0.844 on 32 labeled positives + 122 negatives.
  • .claude/commands/massu-rule.md + paired website/content/docs/commands/massu-rule.mdx — slash command with list | show <id> | approve <id> | dismiss <id> | recurrence subcommands. Show-before-approve enforced via .shown-this-session.jsonl (single-keystroke read-then-act; no --force flag — CR-46 #3).
  • packages/core/src/rule-candidate-applier.ts — atomic-write applier with snapshot-set rollback. Single authoring surface for all 4 destinations (pattern-scanner, claude-md-cr, corrections-md, custom-destination). UNIQUE INDEX idx_audit_rule_promoted on (event_type, json_extract(metadata, '$.prompt_hash')) is the §5 idempotency lock — second approve of same prompt_hash is idempotent_noop. claude-md-cr destination splices the Canonical Rules table row AND appends body section (CR-46 #3 — no piecemeal escape hatch).
  • packages/core/src/rule-classifier.ts — 4-rubric destination dispatch: (1) literal-grepable token → pattern-scanner, (2) process/protocol wording → claude-md-cr, (3) custom-destination from autoLearning.customDestinations config triggerKeywords, (4) corrections-md catchall.
  • packages/core/src/template-renderer.ts — RCE-safe template engine for custom-destination templates. Regex-substitution only, allowlist set {date, slug, score, signals_csv, prompt_preview, destination_name}. ${process.exit(1)} fails identifier-shape; ${process} fails allowlist. 10 explicit RCE-attempt test cases.
  • packages/core/src/rule-candidate-renderer.ts — six-section preview renderer for /massu-rule show <id> (detected correction + reacting-to + proposed rule + destination + enforcement + conflicts).
  • packages/core/src/rule-promotion-effectiveness.ts + tests/rule-promotion-effectiveness.test.ts — CR-53 dual-channel evaluator consumed by both the drift-guard vitest test and /massu-learning-audit Section 6.
  • packages/core/src/lib/recurrence-incrementer.ts — extracted from hooks/post-tool-use.ts (ARCH-04 fix; breaks test-infra ↔ esbuild-entry coupling). Tight 1-line FAIL scope per scanner violation (ARCH-05).
  • SQLite schema additions in memory-db.ts: audit_log CHECK constraint extended 6 → 9 event_type values (rule_candidate_emitted, rule_promoted, rule_dismissed) via canonical 12-step recreate procedure. prompt_outcomes_signal_blacklist table for dismissal-loop signal downweighting. UNIQUE INDEX idx_audit_rule_promoted (partial — only on rule_promoted rows). Migration helper migrateAuditLogCheckExtension() is idempotent via CHECK-clause-shape parse with full event_type set verification (ARCH-06).
  • AuditEntry.eventType union in audit-trail.ts extended 6 → 9 in lockstep with SQL CHECK.
  • scripts/massu-pattern-scanner.sh Check 29 + pattern-scanner-check-29.test.ts drift-guard — auto-generated scanner additions must carry # auto-generated by /massu-rule approve <hash> (slug=<slug>) marker followed by # Check N: within 4 lines.
  • .claude/commands/massu-learning-audit.md Section 6 — Interactive Rule-Candidate Funnel with 6 health metrics + source-tag split + VR-INTERACTIVE-LEARNING.
  • 15 new vitest test files in packages/core/src/tests/: rule-candidate-detector (49 tests), rule-candidate-detector-calibration (5), rule-candidate-renderer (9), rule-candidate-applier (10), rule-candidate-applier-extended (9), rule-candidate-applier-arch-fixes (11), rule-classifier (22), template-renderer (21), cr53-recurrence-increment (7), rule-promotion-effectiveness (10), audit-log-event-type-migration (11), pattern-scanner-check-29 (3), auto-learning-source-tag (3), auto-learning-mirror-drift-guard (4). 175 new tests total.
  • autoLearning.customDestinations schema in packages/core/src/config.ts + massu.config.yaml default block. Massu framework remains generalized — project-specific destinations are config-driven, NEVER framework-baked.
  • v0.1 protocol amendment in .claude/commands/massu-loop/references/auto-learning.md (+ byte-equivalent mirror at packages/core/commands/... enforced by auto-learning-mirror-drift-guard.test.ts): before writing to corrections.md, resolve MEMORY.md path via encodeMemoryDirName(getProjectRoot()) and check for an existing prompt_hash: line — idempotent across v0.1 + v0.2 paths.
  • Follow-up plan docs/plans/2026-05-20-loop-controller-mirror-drift-closure.md filed to close the preexisting 78-line drift in loop-controller.md mirror (deliberately out of scope for v0.2 per CR-46 #4).

Changed

  • packages/core/src/hooks/user-prompt.ts:115 — wires scoreCorrectionPrompt() into the UserPromptSubmit hook. On emitCandidate=true, writes .massu/rule-candidates/<prompt_hash>.json (sha-keyed → idempotent on retry). Stderr nudge fires when candidate count grows since last-surfaced. Detector-swallow writes .detector-failures.jsonl for parallel observability symmetry with the CR-53 increment hook (ARCH-07). Transcript path bound to /.claude/projects/ prefix (SEC-05).
  • packages/core/src/hooks/post-tool-use.ts — calls incrementRecurrenceCountsForScannerFailures after Bash(massu-pattern-scanner.sh) invocations. Failure-surfaced try/catch writes to .cr53-increment-failures.jsonl so silent in-hook failures still surface in CI.
  • DEFAULT_ABANDON_PATTERNS in prompt-analyzer.ts:22exported so the detector can reference it (used as a comparison constant for the dedicated CORRECTION_DISMISSAL_PATTERN in the detector). The detector itself uses a TIGHTER regex (excludes "instead" and "different" which are routine CORRECTION tokens).
  • scripts/massu-pattern-scanner.sh — added Check 29 at the end (29 checks total, up from 28).
  • .claude/CLAUDE.md — CR-53 row in Canonical Rules table + body section + VR-INTERACTIVE-LEARNING row in Verification Requirements table.
  • packages/core/src/tests/codebase-introspector.test.ts — perf test now uses explicit 15s timeout + 2 retries to absorb parallel-suite measurement noise (pre-existing flake surfaced during this release's gate run; assertion stays strict at <2000ms).
  • website/src/tests/changelog-parse.test.ts:EXPECTED_COUNT bumped 41 → 42.

Fixed

  • SEC-01 path traversalCANDIDATE_ID_PATTERN = /^[a-f0-9]{16}$/ validates candidateId at every I/O boundary in applyRuleCandidate, readCandidate, dismissRuleCandidate. Closes the <id> like ../../../tmp/foo arbitrary-file-deletion class.
  • SEC-02 symlink bypassrealpathSync containment check on customDestination.path rejects symlinks that point outside projectRoot even when the lexical path is contained.
  • SEC-03 slug shell injectionderiveSlug is always called regardless of caller-supplied source; SLUG_ALLOWED regex re-validates the result. Caller opts.slug is a hint, never authority.
  • SEC-04 candidate payload tamperingvalidateCandidatePayload runtime checks prompt_hash shape, score finite-range, signals array structure, required string fields. Planted/corrupted sidecars throw CandidatePayloadValidationError before any audit_log write.
  • ARCH-02 dismiss pathdismissRuleCandidate() writes the prompt_outcomes_signal_blacklist UPSERT + audit_log row + .dismissed.jsonl + deletes the candidate sidecar in one SQLite transaction. Closes the "documented end-to-end but the write path was unimplemented" structural drift class.

Try this release

Install the latest version of Massu and start governing your AI development today.