Skip to content

v2.4.2 - brand_match + compliance_check enrichment with agent_memory

Choose a tag to compare

@nicourrutia98 nicourrutia98 released this 28 Jul 15:32

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)

  1. Caller-supplied AgentID on the Judge call.
  2. projects.default_agent_id (set at tenant provisioning).
  3. 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:

  1. Identify stale canon: agent_memory_list(kind=decision, pinned_only=true, scope=project).
  2. Save new canon first: agent_memory_save(kind=decision, pinned=true, tags=brand,voice,2026-q3).
  3. Unpin stale canon (don't delete): agent_memory_update(id=stale_id, pinned=false).
  4. Verify new canon is the only one surfaced.
  5. Re-run brand_match verdicts if needed (use no_enrich=true during 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_RespectsOptOutno_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_PassesNoEnrichToAllSamplesno_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_detected confidence 0.78 (5 concerns,
    including legitimate NoEnrich-on-consensus-path bug)
  • Eval 421: drift_detected confidence 0.72 (concerns
    addressed but operator message needed verbatim citation)
  • Eval 422: aligned confidence 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)

  1. 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
    PublishVibe get NO enrichment — they must go through
    PublishVibe for enriched prompts.
  2. 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.
  3. 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+.
  4. Memory-RAG is best-effort. If agent_memory is 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: true per 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 --versiondark-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