v2.4.2 - brand_match + compliance_check enrichment with agent_memory
v2.4.2 — brand_match + compliance_check enrichment with agent_memory
Date: 2026-07-28
Schema: v20 (unchanged from v2.4.1; v2.4.2 is additive integration)
Canonical tool count: 35 (unchanged — no new tools, no schema migration)
Commit: 36c9513
What this release fixes
v2.4.0 wired agent_memory into the vibe-loop (ContextRecap on
session_start, drift_judge enrichment on publish_vibe, PriorFindings
on research_topic). But the canonical LLM-as-judge path (Judge,
JudgeConsensus) — used by brand_match, compliance_check, pii_detect,
prompt_injection_scan, grounding_check — was still blind to prior
context. A brand voice LLM scored new copy without seeing the brand
canon. A compliance LLM scored EU marketing copy without seeing GDPR
Article 13. v2.4.2 closes the "judges are blind" debt for
brand_match + compliance_check.
Strategy: PINNED memories, not BM25
v2.4.0 drift_judge enrichment (in PublishVibe) uses BM25 search
against the artifact text. v2.4.2 brand_match + compliance_check
enrichment uses PINNED memories instead, because:
- Brand decisions are operator-curated: the operator pinned them
because they're the brand canon. Pinned = explicit operator
intent, not text similarity. - Compliance decisions + findings are similar: operator pinned them
because they're jurisdictional canon. - BM25 against the artifact text is fragile for these judges: a
compliance decision like "GDPR Article 13 disclosure" rarely
shares keywords with the artifact copy being reviewed. Pinned
gives predictable, curated context. - drift_judge keeps BM25 (in PublishVibe) because drift detection
benefits from SPEC-relevant context, not pinned canon.
What gets enriched (per eval_type)
| eval_type | Kinds injected | Why |
|---|---|---|
brand_match |
[decision] |
Brand canon = operator-pinned decisions |
compliance_check |
[decision, finding] |
Compliance rules + prior flags |
drift_judge |
(unchanged) | Lives in PublishVibe (v2.4.0) |
pii_detect |
(none) | Pattern-matching, not RAG |
prompt_injection_scan |
(none) | Pattern-matching, not RAG |
grounding_check |
(out-of-scope) | Future v2.4.4 candidate |
Wire contract (additive)
// dark_memory_judge (orchestrator.O5):
{
"eval_type": "brand_match" | "compliance_check" | ...,
"content": "...",
"agent_id": "...", // NEW v2.4.2 — same priority chain as v2.4.1
"no_enrich": false, // NEW v2.4.2 — opt-out escape hatch
// ... rest unchanged
}
// dark_memory_consensus (orchestrator.O8):
{
"eval_type": "...",
"content": "...",
"agent_id": "...", // NEW v2.4.2 — forwarded to all N samples
"no_enrich": false, // NEW v2.4.2 — forwarded to all N samples
"n": 3,
// ... rest unchanged
}AgentID priority chain (unchanged from v2.4.1)
- Caller-supplied
AgentIDon the Judge call. projects.default_agent_id(set at tenant provisioning).- Empty string — no agent filter; v2.4.0 backward compat.
NoEnrich opt-out
Operators who want raw, no-enrichment behavior (e.g., sensitive
audits where the brand canon must not leak into the verdict) can
pass no_enrich: true on the Judge call. The LLM receives the
raw content unchanged. Default false = enrichment on.
Operator procedure for stale canon
When brand voice or compliance rules evolve, the operator's
canonical workflow is:
- Identify stale canon:
agent_memory_list(kind=decision, pinned_only=true, scope=project). - Save new canon first:
agent_memory_save(kind=decision, pinned=true, tags=brand,voice,2026-q3). - Unpin stale canon (don't delete):
agent_memory_update(id=stale_id, pinned=false). - Verify new canon is the only one surfaced.
- Re-run brand_match verdicts if needed (use
no_enrich=trueduring transition).
Limitations: v2.4.2 does NOT provide automatic staleness detection
or canon-versioning. Operators manage canon lifecycle manually.
Tests (9 new defensive tests, all pass)
Orchestrator-level (in tests/orchestration/agent_memory_v2_4_2_test.go):
TestV242_BrandMatch_EnrichesWithBrandDecisions— kind=decision
surfaces; kind=finding + kind=link filtered out (all pinned to
isolate the kind filter).TestV242_ComplianceCheck_EnrichesWithDecisionsAndFindings—
both decision + finding surface; note is filtered.TestV242_BrandMatch_NoEnrich_RespectsOptOut—no_enrich=true
→ LLM sees raw content unchanged.TestV242_PIIDetect_NoEnrichment— pattern-matching eval_type
stays blind.TestV242_Consensus_PassesAgentIDToAllSamples— N=3 consensus:
each sample sees same agent-scoped enrichment.TestV242_Consensus_PassesNoEnrichToAllSamples—no_enrich=true
forwarded to all N consensus samples.TestV242_AgentID_PriorityChain_ResolvesInJudge— Judge resolves
AgentID via v2.4.1 priority chain.TestV242_DriftJudge_EnrichmentUnchangedInPublishVibe— regression
guard: drift_judge enrichment still in PublishVibe, NOT moved to
Judge in v2.4.2.
Store-level (in tests/dual_driver/agent_memory_v2_4_2_test.go):
TestV242_Store_SearchAgentMemory_FilterByKind_DefenseInDepth
— verifies the Store's Kind filter actually filters.
Full test suite green.
Drift governance
drift_judge evaluation converged in 3 iterations:
- Eval 420:
drift_detectedconfidence 0.78 (5 concerns,
including legitimate NoEnrich-on-consensus-path bug) - Eval 421:
drift_detectedconfidence 0.72 (concerns
addressed but operator message needed verbatim citation) - Eval 422:
alignedconfidence 0.82 (all 5 concerns
resolved; release approved)
The drift_judge artifact (rev3) cites the verbatim operator message,
provides operational impact analysis for stale pinned canon,
includes an explicit INV-1 recoverability matrix, and documents the
operator procedure for handling stale canon.
What v2.4.2 does NOT do (deliberate scope)
- Does not touch drift_judge enrichment — it still lives in
PublishVibe(auditable since v2.4.0). Operators using
dark_memory_judge(eval_type=drift_judge)directly without
PublishVibeget NO enrichment — they must go through
PublishVibefor enriched prompts. - Does not enrich pii_detect, prompt_injection_scan, or
grounding_check. Pattern-matching judges don't benefit from
RAG; grounding_check is out-of-scope for v2.4.2. - The enriched prompt is NOT persisted in the audit trail —
only the LLM response (SDDEvaluation.VerdictJSON) is.
Operators needing prompt-level audit get it in v2.4.4+. - Memory-RAG is best-effort. If
agent_memoryis broken, Judge
runs with raw content (same fail-safe as v2.4.0).
Upgrade notes
- Wire contract is additive only. Existing v2.4.1 callers see no
behavioral change unless they explicitly opt in to
brand_match/compliance_check enrichment (which is on by default). - Operators who want raw, no-enrichment behavior can pass
no_enrich: trueper call. - Operators must PIN important brand + compliance decisions for
them to surface as enrichment (pinned = operator-curated canon). - v2.4.0 drift_judge enrichment in PublishVibe is unchanged.
- Tool count remains 35 (additive integration, no new tools).
Checksums (SHA-256)
dark-mem-mcp.exe 6AC77E507CC448B53F76A66864768E6FE959FF8AE5DD9E6F07017ACDF408EC11 25619968 bytes
dark-mem-cli.exe 6905E52261D266F6774D5163E5BA81AF93BEA79F91049CAD59CB900DF494F4C4 20588544 bytes
dark-mem-inspect.exe 500F757672786973B1F0DDCE96919863AB69712612E95930CA447B3BAE2567A3 20133376 bytes
Verified by dark-mem-inspect --version → dark-mem-inspect 2.4.2.
Carrying forward from v2.4.1
- 35 canonical tools (no new tool in v2.4.2)
- Schema v20 unchanged (additive integration only)
- All v2.4.1 INV-10 backward compat preserved
- drift_judge enrichment path unchanged