feat(memory-diag): add quality review board command

Add memory-diag quality command for objective review of memory-system
mechanisms and active memory content. The command is read-only and
non-authoritative, providing evidence, heuristic flags, and review
questions without making quality judgments or suggesting mutations.

Key components:
- quality-review-model.ts: builds ReviewBoardReport with provenance,
  re-absorption detection, mechanism facts (rejection, reinforcement,
  eviction/caps, identity/dedup), and memory content facts
- formatters/quality.ts: human and JSON output with separate
  system-mechanism and memory-content sections
- commands/quality.ts: command entry point with --json, --verbose,
  --no-emoji, --raw options
- cli.ts: parser whitelist for quality accepting --workspace, --json,
  rejecting mutation/filter flags

co-author: code-execute-agent, comprehensive-code-reviewer,
systems-architect, creative-disruptor

Closes docs/plans/2026-05-11-memory-diag-quality-review-board.md
This commit is contained in:
Ralph Chang
2026-05-12 14:13:03 +08:00
parent e4dfe81d89
commit 5bca3432b0
11 changed files with 1953 additions and 7 deletions
+3 -2
View File
@@ -10,6 +10,7 @@ export function usage(): string {
memory-diag missing [--workspace <path>] [--verbose] [--json]
memory-diag explain [memory-id] [--workspace <path>] [--raw]
memory-diag commands [--workspace <path>] [--verbose] [--json]
memory-diag quality [--workspace <path>] [--verbose] [--json] [--raw] [--no-emoji]
memory-diag revert (--memory <replacement-id> | --event <event-id>) [--workspace <path>] [--apply]
Global options:
@@ -103,12 +104,12 @@ export function parseArgs(argv: string[]): ParsedArgs {
if (command === "status") {
if (options.all) return error(`${command} does not accept --all`);
} else if (command === "rejected" || command === "missing" || command === "coverage" || command === "explain" || command === "commands" || command === "revert") {
} else if (command === "rejected" || command === "missing" || command === "coverage" || command === "explain" || command === "commands" || command === "quality" || command === "revert") {
if (options.all) return error(`${command} does not accept --all`);
} else {
if (options.all || options.workspace) return error(`${command} does not accept --all or --workspace`);
}
if (options.json && command !== "status" && command !== "rejected" && command !== "missing" && command !== "coverage" && command !== "commands") {
if (options.json && command !== "status" && command !== "rejected" && command !== "missing" && command !== "coverage" && command !== "commands" && command !== "quality") {
return error(`${command} does not accept --json`);
}
if (command !== "rejected" && (options.softOnly || options.triggerOnly || options.since)) {
+1 -1
View File
@@ -1,4 +1,4 @@
export const VISIBLE_COMMANDS = ["status", "rejected", "missing", "explain", "commands", "revert"] as const;
export const VISIBLE_COMMANDS = ["status", "rejected", "missing", "explain", "commands", "quality", "revert"] as const;
export const HIDDEN_COMMANDS = ["coverage", "audit"] as const;
export type VisibleCommand = typeof VISIBLE_COMMANDS[number];
+2
View File
@@ -3,6 +3,7 @@ import { runCommands } from "./commands/commands.ts";
import { runCoverage } from "./commands/coverage.ts";
import { runExplain } from "./commands/explain.ts";
import { runMissing } from "./commands/missing.ts";
import { runQuality } from "./commands/quality.ts";
import { runRejected } from "./commands/rejected.ts";
import { runRevert } from "./commands/revert.ts";
import { runStatus } from "./commands/status.ts";
@@ -17,6 +18,7 @@ export async function dispatch(command: Command, options: CliOptions): Promise<C
case "audit": return runAudit(options);
case "explain": return runExplain(options);
case "commands": return runCommands(options);
case "quality": return runQuality(options);
case "revert": return runRevert(options);
}
}
+20
View File
@@ -0,0 +1,20 @@
import { buildQualityJSON, formatQualityReviewBoard } from "../formatters/quality.ts";
import { buildInspectionReadModel } from "../inspection-model.ts";
import { buildQualityReviewBoard } from "../quality-review-model.ts";
import type { CliOptions, CommandResult } from "../types.ts";
export async function runQuality(options: CliOptions): Promise<CommandResult> {
const model = await buildInspectionReadModel(options);
const report = buildQualityReviewBoard(model, {
verbose: options.verbose,
raw: options.raw,
noEmoji: options.noEmoji,
json: options.json,
});
if (options.json) {
return { stdout: JSON.stringify(buildQualityJSON(report, options.raw), null, 2) };
}
return { stdout: formatQualityReviewBoard(report, { verbose: options.verbose, noEmoji: options.noEmoji }) };
}
+314
View File
@@ -0,0 +1,314 @@
import { cleanText, formatDetails } from "../text.ts";
import type {
CandidateProvenance,
HeuristicFlag,
ProvenanceClassification,
ReviewBoardActiveMemory,
ReviewBoardCandidate,
ReviewBoardReport,
} from "../quality-review-model.ts";
const PROVENANCE_ORDER: ProvenanceClassification[] = [
"explicit_migration_evidence",
"legacy_unversioned_format",
"reabsorbed_post_rejection",
"suspected_pre_migration_legacy",
"likely_current_behavior",
"unversioned_ambiguous",
];
const REVIEW_FLAG_CAVEAT = "This flag is a prompt for review, not a conclusion.";
export function buildQualityJSON(report: ReviewBoardReport, raw = false): unknown {
if (raw) return report;
return redactUnknown(report);
}
export function formatQualityReviewBoard(
report: ReviewBoardReport,
options: { verbose?: boolean; noEmoji?: boolean },
): string {
const bullet = "-";
const lines: string[] = [];
lines.push("Memory quality review board");
lines.push("Purpose: evidence for human/agent review only; no automatic judgment or cleanup.");
lines.push("Producer version note: historical records do not include package/plugin version; provenance below is inferred.");
lines.push("Primary review purpose: SYSTEM MECHANISM observations (filters, reinforcement, eviction/caps, identity/dedup).");
lines.push("Secondary review purpose: MEMORY CONTENT quality (staleness, durability, redundancy, specificity).");
lines.push("");
pushEvidenceProvenance(lines, report, bullet);
lines.push("");
pushSystemMechanismFacts(lines, report, bullet);
lines.push("");
pushMemoryContentFacts(lines, report, bullet);
lines.push("");
pushSystemMechanismCandidates(lines, report, bullet);
lines.push("");
pushMemoryContentCandidates(lines, report, bullet, options);
lines.push("");
pushReviewQuestions(lines, report, bullet);
lines.push("");
pushNextCommands(lines, report, bullet);
return lines.join("\n");
}
function pushEvidenceProvenance(lines: string[], report: ReviewBoardReport, bullet: string): void {
const context = report.provenanceContext;
lines.push("Evidence provenance");
lines.push(` ${bullet} method: migration/timestamp/format inference`);
lines.push(` ${bullet} confidence: ${context.confidenceDisclaimer}`);
lines.push(` ${bullet} migration timeline: ${formatMigrationTimeline(context.migrationTimeline)}`);
if (context.lastActivityAt) lines.push(` ${bullet} last activity: ${context.lastActivityAt}`);
}
function pushSystemMechanismFacts(lines: string[], report: ReviewBoardReport, bullet: string): void {
const facts = report.facts.systemMechanisms;
lines.push("Facts - system mechanisms");
lines.push(" Provenance counts for mechanism evidence");
lines.push(` ${bullet} ${formatProvenanceCounts(report.provenanceContext.countsByClassification)}`);
lines.push(" Rejection filters");
lines.push(` ${bullet} rejected records: ${facts.rejectionFilters.totalRecords} (unique: ${facts.rejectionFilters.uniqueTexts})`);
lines.push(` ${bullet} raw reason-code distribution: ${formatCounts(facts.rejectionFilters.byRawReasonCode)}`);
lines.push(` ${bullet} type distribution: ${formatCounts(facts.rejectionFilters.byType)}`);
lines.push(` ${bullet} ambiguous/architecture-like rejected candidates: ${facts.rejectionFilters.ambiguousOrArchitectureLike}`);
lines.push(` ${bullet} status-or-hard-reason evidence: ${facts.rejectionFilters.hardReasonOrNoiseHeuristic}`);
lines.push(` ${bullet} re-absorbed rejected texts: ${facts.rejectionFilters.reabsorbedRejectedTexts}`);
lines.push(" Reinforcement rules");
lines.push(` ${bullet} reinforce attempts: ${facts.reinforcementRules.reinforceEvents}, reinforced: ${facts.reinforcementRules.reinforcedEvents}, rejected/blocked: ${facts.reinforcementRules.rejectedOrBlockedEvents}`);
lines.push(` ${bullet} reinforcement-window blocked: ${facts.reinforcementRules.windowBlockedEvents} (rate: ${formatPercent(facts.reinforcementRules.windowBlockRate)})`);
lines.push(` ${bullet} repeated blocks by memory: ${formatRepeatedBlocks(facts.reinforcementRules.repeatedBlocksByMemory)}`);
lines.push(` ${bullet} malformed command events: ${facts.reinforcementRules.malformedCommandEvents}`);
lines.push(" Eviction and caps");
lines.push(` ${bullet} active memories: ${facts.evictionAndCaps.activeMemories} / ${facts.evictionAndCaps.maxEntries}`);
lines.push(` ${bullet} rendered memories: ${facts.evictionAndCaps.renderedMemories}`);
lines.push(` ${bullet} full caps: ${formatFullCaps(facts.evictionAndCaps.fullCaps, facts.evictionAndCaps.typeCounts, facts.evictionAndCaps.typeCaps, facts.evictionAndCaps.activeMemories, facts.evictionAndCaps.maxEntries)}`);
lines.push(` ${bullet} capacity removals: total=${facts.evictionAndCaps.removedByCapacity}, global=${facts.evictionAndCaps.removedByGlobalCap}, type=${facts.evictionAndCaps.removedByTypeCap}`);
lines.push(` ${bullet} recent evictions by type: ${formatCounts(facts.evictionAndCaps.recentEvictionsByType)}`);
lines.push(` ${bullet} recent evicted content shown: ${facts.evictionAndCaps.recentEvictedContentShown}`);
lines.push(` ${bullet} evidence-only disappearances: ${facts.evictionAndCaps.missingEvidenceOnly} (unknown: ${facts.evictionAndCaps.unknownDisappearances})`);
lines.push(" Identity and dedup");
lines.push(` ${bullet} replacements: total=${facts.identityAndDedup.replacementEvents}, same-type=${facts.identityAndDedup.sameTypeReplacementEvents}, cross-type=${facts.identityAndDedup.crossTypeReplacementEvents}`);
lines.push(` ${bullet} superseded entries: ${facts.identityAndDedup.supersededEntries}`);
lines.push(` ${bullet} exact duplicate/identity groups identified: ${facts.identityAndDedup.duplicateTextOrIdentityGroups}`);
}
function pushMemoryContentFacts(lines: string[], report: ReviewBoardReport, bullet: string): void {
const facts = report.facts.memoryContent;
lines.push("Facts - memory content");
lines.push(` ${bullet} rendered memories: ${facts.renderedMemories}`);
lines.push(` ${bullet} evidence coverage: ${facts.evidenceCoverage.covered} / ${facts.evidenceCoverage.total}`);
lines.push(` ${bullet} type counts: ${formatTypeCountsWithCaps(facts.typeCounts, facts.typeCaps)}`);
lines.push(` ${bullet} weakest/strongest active memory previews: weakest=${formatMemoryPreviews(facts.weakestActiveMemories)}; strongest=${formatMemoryPreviews(facts.strongestActiveMemories)}`);
}
function pushSystemMechanismCandidates(lines: string[], report: ReviewBoardReport, bullet: string): void {
const display = report.provenanceContext.candidateDisplay;
if (report.provenanceContext.candidateLimit && display && display.shown < display.total) {
lines.push(`System mechanism review candidates (representative; ${display.shown} shown of ${display.total} total; limit ${report.provenanceContext.candidateLimit} per mechanism category)`);
} else {
lines.push("System mechanism review candidates");
}
pushCandidateGroup(lines, "Rejection filter evidence", candidatesFor(report, ["rejection_rule_evidence"]), bullet);
pushCandidateGroup(lines, "Re-absorption evidence", candidatesFor(report, ["reabsorption_evidence"]), bullet);
pushCandidateGroup(lines, "Reinforcement rule evidence", candidatesFor(report, ["numbered_command_evidence"]), bullet);
pushCandidateGroup(lines, "Eviction/cap evidence", candidatesFor(report, ["eviction_cap_evidence", "missing_evidence"]), bullet);
pushCandidateGroup(lines, "Identity/dedup evidence", candidatesFor(report, ["identity_dedup_evidence"]), bullet);
}
function pushCandidateGroup(lines: string[], title: string, candidates: ReviewBoardCandidate[], bullet: string): void {
lines.push(` ${title}`);
if (candidates.length === 0) {
lines.push(" (none)");
return;
}
const shared = sharedProvenance(candidates);
if (shared) lines.push(` shared provenance for displayed candidates in this group: ${formatProvenance(shared)}`);
for (const candidate of candidates) pushCandidate(lines, candidate, bullet, shared);
}
function pushCandidate(lines: string[], candidate: ReviewBoardCandidate, bullet: string, groupProvenance?: CandidateProvenance): void {
const rawReasonCodes = candidate.evidence.rawReasonCodes && candidate.evidence.rawReasonCodes.length > 0
? candidate.evidence.rawReasonCodes.join(", ")
: "none";
const question = candidate.reviewQuestions[0] ?? "What should a reviewer infer from this evidence?";
lines.push(` ${bullet} concern=${formatConcern(candidate.concernKind)} id=${candidate.id} source=${candidate.source} mechanism=${candidate.mechanism ?? "unspecified"} raw reason codes=${rawReasonCodes} question=${question}`);
if (candidate.provenance && (!groupProvenance || formatProvenance(candidate.provenance) !== formatProvenance(groupProvenance))) {
lines.push(` provenance: ${formatProvenance(candidate.provenance)}`);
}
if (candidate.evidence.eventIds && candidate.evidence.eventIds.length > 0) lines.push(` event ids: ${candidate.evidence.eventIds.join(", ")}`);
if (candidate.evidence.textAvailable) {
lines.push(` text preview: ${candidate.evidence.textPreview ?? "available but empty after redaction"}`);
} else {
lines.push(" text preview: unavailable in historical evidence");
}
lines.push(` facts: ${formatCandidateFacts(candidate.facts)}`);
pushHeuristicFlags(lines, candidate.heuristicFlags, " ", bullet);
}
function pushMemoryContentCandidates(lines: string[], report: ReviewBoardReport, bullet: string, options: { verbose?: boolean }): void {
const display = report.activeMemoryDisplay;
lines.push("Memory content review candidates");
if (report.reviewQuestions.memoryContent.length > 0) {
lines.push(" Standard review questions (applicable to all active memories below):");
for (const question of report.reviewQuestions.memoryContent) lines.push(` ${bullet} ${question}`);
}
if (display.total === 0) {
lines.push(" Active memories (none)");
return;
}
if (display.total <= display.threshold) {
lines.push(` Active memories (showing all ${display.total} because <= ${display.threshold})`);
} else if (display.mode === "all" || options.verbose) {
lines.push(` Active memories (showing all ${display.total} because --verbose)`);
} else {
lines.push(` Active memories (showing ${display.shown} of ${display.total})`);
lines.push(` Showing ${display.shown} of ${display.total} active memories. Use --verbose or --json for all active memory text.`);
}
display.items.forEach((item, index) => pushActiveMemory(lines, item, index + 1, bullet, report.reviewQuestions.memoryContent));
}
function pushActiveMemory(lines: string[], item: ReviewBoardActiveMemory, index: number, bullet: string, standardQuestions: string[]): void {
const strength = typeof item.strength === "number" ? item.strength.toFixed(3) : "unknown";
lines.push(` [${index}] id=${item.id} type=${item.type} source=${item.source} status=${item.status} strength=${strength}`);
lines.push(" text: " + indentContinuation(item.text, " "));
const rawReasonCodes = item.evidence.rawReasonCodes.length > 0 ? item.evidence.rawReasonCodes.join(", ") : "none";
lines.push(` evidence: events=${item.evidence.eventCount} raw reason codes=${rawReasonCodes}`);
if (item.provenance) lines.push(` provenance: ${formatProvenance(item.provenance)}`);
pushHeuristicFlags(lines, item.heuristicFlags, " ", bullet);
if (questionsEqual(item.reviewQuestions, standardQuestions)) return;
const additionalQuestions = item.reviewQuestions.filter(question => !standardQuestions.includes(question));
if (additionalQuestions.length > 0 && additionalQuestions.length < item.reviewQuestions.length) {
lines.push(" additional review questions:");
for (const question of additionalQuestions) lines.push(` ${bullet} ${question}`);
return;
}
lines.push(" review questions:");
for (const question of item.reviewQuestions) lines.push(` ${bullet} ${question}`);
}
function pushHeuristicFlags(lines: string[], flags: HeuristicFlag[], indent: string, bullet: string): void {
if (flags.length === 0) return;
lines.push(`${indent}heuristic flags:`);
for (const flag of flags) {
const caveat = flag.caveat || REVIEW_FLAG_CAVEAT;
lines.push(`${indent} ${bullet} ${flag.label}: ${flag.evidence}. ${caveat}`);
}
}
function pushReviewQuestions(lines: string[], report: ReviewBoardReport, bullet: string): void {
lines.push("Review questions");
lines.push(" SYSTEM MECHANISM");
for (const question of report.reviewQuestions.systemMechanism) lines.push(` ${bullet} ${question}`);
lines.push(" MEMORY CONTENT");
for (const question of report.reviewQuestions.memoryContent) lines.push(` ${bullet} ${question}`);
}
function pushNextCommands(lines: string[], report: ReviewBoardReport, bullet: string): void {
lines.push("Next commands");
for (const command of report.nextCommands) lines.push(` ${bullet} ${command}`);
}
function candidatesFor(report: ReviewBoardReport, sources: ReviewBoardCandidate["source"][]): ReviewBoardCandidate[] {
const sourceSet = new Set(sources);
return report.reviewCandidates.filter(candidate => candidate.concernKind === "system_mechanism" && sourceSet.has(candidate.source));
}
function sharedProvenance(candidates: ReviewBoardCandidate[]): CandidateProvenance | undefined {
if (candidates.length <= 1) return undefined;
const first = candidates[0]?.provenance;
if (!first) return undefined;
const key = formatProvenance(first);
return candidates.every(candidate => candidate.provenance && formatProvenance(candidate.provenance) === key) ? first : undefined;
}
function formatConcern(concern: ReviewBoardCandidate["concernKind"]): string {
return concern === "system_mechanism" ? "SYSTEM MECHANISM" : "MEMORY CONTENT";
}
function formatMigrationTimeline(timeline: ReviewBoardReport["provenanceContext"]["migrationTimeline"]): string {
if (timeline.length === 0) return "(none)";
return timeline.map(row => `${row.migrationId}=${row.presentInStore ? "present" : "absent"}${row.firstEvidenceAt ? ` firstEvidenceAt=${row.firstEvidenceAt}` : ""}`).join(", ");
}
function formatProvenanceCounts(counts: Record<ProvenanceClassification, number>): string {
return PROVENANCE_ORDER.map(classification => `${classification}=${counts[classification] ?? 0}`).join(", ");
}
function formatCounts(counts: Record<string, number>): string {
const entries = Object.entries(counts).sort((a, b) => b[1] - a[1] || a[0].localeCompare(b[0]));
return entries.length === 0 ? "(none)" : entries.map(([key, count]) => `${key}=${count}`).join(", ");
}
function formatTypeCountsWithCaps(counts: Record<string, number>, caps: Record<string, number>): string {
const keys = uniqueSorted([...Object.keys(caps), ...Object.keys(counts)]);
return keys.length === 0 ? "(none)" : keys.map(key => `${key} ${counts[key] ?? 0}/${caps[key] ?? "?"}`).join(", ");
}
function formatFullCaps(fullCaps: string[], typeCounts: Record<string, number>, typeCaps: Record<string, number>, active: number, maxEntries: number): string {
if (fullCaps.length === 0) return "(none)";
return fullCaps.map(cap => cap === "global" ? `global ${active}/${maxEntries}` : `${cap} ${typeCounts[cap] ?? 0}/${typeCaps[cap] ?? "?"}`).join(", ");
}
function formatRepeatedBlocks(blocks: ReviewBoardReport["facts"]["systemMechanisms"]["reinforcementRules"]["repeatedBlocksByMemory"]): string {
if (blocks.length === 0) return "(none)";
return blocks.map(block => `${block.memoryId} count=${block.count} refs=${block.refs.join("|") || "none"} raw reason codes=${block.rawReasonCodes.join("|") || "none"}`).join(", ");
}
function formatMemoryPreviews(items: ReviewBoardReport["facts"]["memoryContent"]["weakestActiveMemories"]): string {
if (items.length === 0) return "(none)";
return items.map(item => `${item.id} type=${item.type} strength=${typeof item.strength === "number" ? item.strength.toFixed(3) : "unknown"} text=${JSON.stringify(item.textPreview)}`).join(" | ");
}
function formatPercent(value: number): string {
return `${(Number.isFinite(value) ? value * 100 : 0).toFixed(1)}%`;
}
function formatProvenance(provenance: CandidateProvenance): string {
return `${provenance.classification} confidence=${provenance.confidence}; basis=${provenance.basis.join("; ") || "unavailable"}; caveat=${provenance.interpretationCaveat}`;
}
function formatCandidateFacts(facts: Record<string, unknown>): string {
if (Object.keys(facts).length === 0) return "(none)";
return formatDetails(Object.fromEntries(
Object.entries(facts).map(([key, value]) => [key, formatFactValue(value)]),
));
}
function formatFactValue(value: unknown): string | number | boolean | string[] | undefined {
if (value === undefined) return undefined;
if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") return value;
if (value === null) return "null";
if (Array.isArray(value)) return value.map(item => typeof item === "string" || typeof item === "number" || typeof item === "boolean" || item === null ? String(item) : stringifyUnknown(item));
return stringifyUnknown(value);
}
function stringifyUnknown(value: unknown): string {
try {
const serialized = JSON.stringify(value);
return serialized === undefined ? String(value) : serialized;
} catch {
return String(value);
}
}
function questionsEqual(a: string[], b: string[]): boolean {
return a.length === b.length && a.every((value, index) => value === b[index]);
}
function indentContinuation(text: string, indent: string): string {
return text.split("\n").map((line, index) => index === 0 ? line : `${indent}${line}`).join("\n");
}
function uniqueSorted(values: string[]): string[] {
return [...new Set(values)].sort();
}
function redactUnknown(value: unknown): unknown {
if (typeof value === "string") return cleanText(value, false);
if (Array.isArray(value)) return value.map(item => redactUnknown(item));
if (!value || typeof value !== "object") return value;
return Object.fromEntries(Object.entries(value).map(([key, item]) => [key, redactUnknown(item)]));
}
+930
View File
@@ -0,0 +1,930 @@
import { createHash } from "node:crypto";
import type { EvidenceEventV1 } from "../../src/evidence-log.ts";
import { RETENTION_TYPE_MAX } from "../../src/retention.ts";
import type { LongTermMemoryEntry, LongTermType } from "../../src/types.ts";
import { TYPES } from "./constants.ts";
import { disappearanceRows } from "./inspection-model.ts";
import { rejectionQualitySummary, uniqueByCanonicalText } from "./rejections-model.ts";
import { canonicalMemoryText, cleanText, countBy, objectFromCounts, truncate, uniqueStrings, workspaceRootHash } from "./text.ts";
import type { MemoryInspectionReadModel, NormalizedRejection } from "./types.ts";
export type ReviewBoardReport = {
version: 1;
generatedAt: string;
workspace: { rootHash: string; key: string };
purpose: "review_evidence_only";
languageGuidance: {
nonAuthoritative: true;
mutation: "none";
rawReasonCodesAreEvidence: true;
producerVersionRecorded: false;
provenanceInferenceOnly: true;
primaryReviewPurpose: "system_mechanism_observations";
secondaryReviewPurpose: "memory_content_quality";
};
provenanceContext: {
method: "migration_timestamp_and_format_inference";
confidenceDisclaimer: string;
falseCurrentRiskBias: "prefer_unversioned_ambiguous_when_uncertain";
producerVersionAvailable: false;
migrationTimeline: Array<{ migrationId: string; presentInStore: boolean; firstEvidenceAt?: string }>;
lastActivityAt?: string;
countsByClassification: Record<ProvenanceClassification, number>;
candidateLimit?: number;
candidateDisplay?: {
shown: number;
total: number;
byMechanism: Record<string, { shown: number; total: number }>;
};
};
facts: {
systemMechanisms: {
rejectionFilters: {
totalRecords: number;
uniqueTexts: number;
byRawReasonCode: Record<string, number>;
byType: Record<string, number>;
ambiguousOrArchitectureLike: number;
hardReasonOrNoiseHeuristic: number;
reabsorbedRejectedTexts: number;
};
reinforcementRules: {
reinforceEvents: number;
reinforcedEvents: number;
rejectedOrBlockedEvents: number;
windowBlockedEvents: number;
windowBlockRate: number;
repeatedBlocksByMemory: Array<{ memoryId: string; count: number; refs: string[]; rawReasonCodes: string[] }>;
malformedCommandEvents: number;
};
evictionAndCaps: {
activeMemories: number;
maxEntries: number;
renderedMemories: number;
typeCounts: Record<string, number>;
typeCaps: Record<string, number>;
fullCaps: string[];
missingEvidenceOnly: number;
unknownDisappearances: number;
removedByCapacity: number;
removedByGlobalCap: number;
removedByTypeCap: number;
recentEvictionsByType: Record<string, number>;
recentEvictedContentShown: number;
};
identityAndDedup: {
replacementEvents: number;
sameTypeReplacementEvents: number;
crossTypeReplacementEvents: number;
supersededEntries: number;
duplicateTextOrIdentityGroups: number;
};
};
memoryContent: {
activeMemories: number;
renderedMemories: number;
evidenceCoverage: { covered: number; total: number };
typeCounts: Record<string, number>;
typeCaps: Record<string, number>;
weakestActiveMemories: Array<{ id: string; type: string; strength?: number; textPreview: string }>;
strongestActiveMemories: Array<{ id: string; type: string; strength?: number; textPreview: string }>;
};
};
activeMemoryDisplay: {
threshold: number;
mode: "all" | "sample";
shown: number;
total: number;
items: ReviewBoardActiveMemory[];
};
reviewCandidates: ReviewBoardCandidate[];
reviewQuestions: {
systemMechanism: string[];
memoryContent: string[];
};
nextCommands: string[];
};
export type ReviewBoardActiveMemory = {
id: string;
type: string;
source: string;
status: string;
strength?: number;
text: string;
evidence: { eventCount: number; eventIds: string[]; rawReasonCodes: string[] };
provenance?: CandidateProvenance;
heuristicFlags: HeuristicFlag[];
reviewQuestions: string[];
};
export type ReviewBoardCandidate = {
concernKind: "system_mechanism" | "memory_content";
mechanism?: "rejection_filter" | "reinforcement_rule" | "eviction_cap" | "identity_dedup" | "retention_rendering";
source:
| "active_memory"
| "rejection_rule_evidence"
| "missing_evidence"
| "numbered_command_evidence"
| "eviction_cap_evidence"
| "reabsorption_evidence"
| "identity_dedup_evidence";
id: string;
facts: Record<string, unknown>;
evidence: { eventIds?: string[]; rawReasonCodes?: string[]; textPreview?: string; textAvailable: boolean };
provenance?: CandidateProvenance;
heuristicFlags: HeuristicFlag[];
reviewQuestions: string[];
nextCommands: string[];
};
export type ProvenanceClassification =
| "explicit_migration_evidence"
| "legacy_unversioned_format"
| "reabsorbed_post_rejection"
| "suspected_pre_migration_legacy"
| "likely_current_behavior"
| "unversioned_ambiguous";
export type CandidateProvenance = {
classification: ProvenanceClassification;
confidence: "high" | "medium" | "low";
basis: string[];
interpretationCaveat: string;
};
export type HeuristicFlag = {
id: string;
label: string;
evidence: string;
caveat: string;
};
export const ACTIVE_MEMORY_FULL_TEXT_THRESHOLD = 40;
export const REPRESENTATIVE_CANDIDATE_LIMIT = 10;
export const RECENT_EVICTION_DAYS = 7;
const KNOWN_MIGRATION_IDS = [
"2026-04-26-p0-cleanup",
"2026-04-28-quality-cleanup",
"2026-05-01-retention-clock-backfill",
] as const;
const PROVENANCE_CLASSIFICATIONS: ProvenanceClassification[] = [
"explicit_migration_evidence",
"legacy_unversioned_format",
"reabsorbed_post_rejection",
"suspected_pre_migration_legacy",
"likely_current_behavior",
"unversioned_ambiguous",
];
const HARD_OR_NOISE_REASON_CODES = new Set([
"progress_snapshot",
"active_file_snapshot",
"commit_or_ci_snapshot",
"temporary_status",
"raw_error",
"code_or_api_signature",
"bad_feedback",
]);
const MALFORMED_COMMAND_REASON_CODES = new Set([
"invalid_memory_command",
"invalid_memory_ref",
"invalid_memory_type",
"empty_replacement_text",
]);
type ReabsorbedMatch = {
key: string;
record: NormalizedRejection;
activeMemory: LongTermMemoryEntry;
};
type ProvenanceContextInputs = {
firstMigrationBoundary?: string;
latestMigrationBoundary?: string;
lastActivityAt?: string;
};
type DatedCandidateInput = {
candidate: ReviewBoardCandidate;
timestamp?: string;
tieId: string;
textHash?: string;
};
export function buildQualityReviewBoard(
model: MemoryInspectionReadModel,
options: { verbose?: boolean; raw?: boolean; noEmoji?: boolean; json?: boolean },
generatedAt = new Date().toISOString(),
): ReviewBoardReport {
const raw = options.raw === true;
const activeMemories = model.store.entries.filter(entry => entry.status !== "superseded");
const typeCounts = typeCountsFor(activeMemories);
const typeCaps = Object.fromEntries(TYPES.map(type => [type, RETENTION_TYPE_MAX[type]]));
const rejectionSummary = rejectionQualitySummary(model.rejectionRecords);
const rejectionGroups = rejectionSummary.possibleFalsePositiveGroups;
const migrationTimeline = buildMigrationTimeline(model);
const provenanceInputs = migrationBoundaries(model);
const activeKeyMatches = reabsorbedRejectedMatches(activeMemories, model.rejectionRecords);
const reabsorbedKeys = new Set(activeKeyMatches.map(match => match.key));
const activeMemoryByKey = new Map(activeKeyMatches.map(match => [match.key, match.activeMemory]));
const disappearances = disappearanceRows(model);
const reinforcementFacts = buildReinforcementFacts(model.evidenceEvents);
const evictionFacts = buildEvictionFacts(model, activeMemories, typeCounts, typeCaps, disappearances, generatedAt);
const identityFacts = buildIdentityFacts(model, activeMemories);
const memoryContentFacts = buildMemoryContentFacts(model, activeMemories, typeCounts, typeCaps, raw);
const systemMechanismCandidateInputs = {
rejection_filter: [
...buildRejectionCandidates(model.rejectionRecords, provenanceInputs, raw),
...buildReabsorptionCandidates(activeKeyMatches, provenanceInputs, raw),
],
reinforcement_rule: buildReinforcementCandidates(model.evidenceEvents, provenanceInputs, raw),
eviction_cap: buildEvictionCandidates(disappearances, model.evidenceEvents, provenanceInputs, raw, generatedAt),
identity_dedup: buildIdentityCandidates(model, activeMemories, provenanceInputs, raw),
};
const showAllSystemMechanismCandidates = options.verbose === true || options.json === true;
const systemCandidateDisplay = buildSystemCandidateDisplay(systemMechanismCandidateInputs, showAllSystemMechanismCandidates);
const allSystemMechanismCandidates = Object.values(systemMechanismCandidateInputs)
.flatMap(inputs => selectRepresentative(inputs, true).map(item => item.candidate));
const reviewCandidates = [
...systemCandidateDisplay.candidates,
...buildMemoryContentCandidates(model, activeMemories, raw),
];
const activeMemoryDisplay = buildActiveMemoryDisplay(model, activeMemories, reabsorbedKeys, activeMemoryByKey, provenanceInputs, raw, options.verbose === true);
const countsByClassification = countProvenanceClassifications(allSystemMechanismCandidates);
return {
version: 1,
generatedAt,
workspace: {
rootHash: workspaceRootHash(model.snapshot?.store?.workspace?.root ?? model.store.workspace.root),
key: model.snapshot?.store?.workspace?.key ?? model.store.workspace.key,
},
purpose: "review_evidence_only",
languageGuidance: {
nonAuthoritative: true,
mutation: "none",
rawReasonCodesAreEvidence: true,
producerVersionRecorded: false,
provenanceInferenceOnly: true,
primaryReviewPurpose: "system_mechanism_observations",
secondaryReviewPurpose: "memory_content_quality",
},
provenanceContext: {
method: "migration_timestamp_and_format_inference",
confidenceDisclaimer: "Producer version is not recorded in historical evidence; provenance is inferred and should not be used as proof of current behavior.",
falseCurrentRiskBias: "prefer_unversioned_ambiguous_when_uncertain",
producerVersionAvailable: false,
migrationTimeline,
lastActivityAt: model.store.lastActivityAt,
countsByClassification,
...(systemCandidateDisplay.limited ? { candidateLimit: REPRESENTATIVE_CANDIDATE_LIMIT, candidateDisplay: systemCandidateDisplay.summary } : {}),
},
facts: {
systemMechanisms: {
rejectionFilters: {
totalRecords: rejectionSummary.totalRecords,
uniqueTexts: rejectionSummary.uniqueTexts,
byRawReasonCode: rejectionSummary.reasonDistribution,
byType: objectFromCounts(countBy(model.rejectionRecords.map(record => record.type))),
ambiguousOrArchitectureLike:
(rejectionGroups.architecture_like_possible_false_positive?.count ?? 0)
+ (rejectionGroups.ambiguous?.count ?? 0),
hardReasonOrNoiseHeuristic: rejectionGroups.clearly_garbage?.count ?? 0,
reabsorbedRejectedTexts: new Set(activeKeyMatches.map(match => match.key)).size,
},
reinforcementRules: reinforcementFacts,
evictionAndCaps: evictionFacts,
identityAndDedup: identityFacts,
},
memoryContent: memoryContentFacts,
},
activeMemoryDisplay,
reviewCandidates,
reviewQuestions: {
systemMechanism: systemMechanismQuestions(),
memoryContent: memoryContentQuestions(),
},
nextCommands: nextCommands(),
};
}
function typeCountsFor(entries: LongTermMemoryEntry[]): Record<string, number> {
return Object.fromEntries(TYPES.map(type => [type, entries.filter(entry => entry.type === type).length]));
}
function buildMigrationTimeline(model: MemoryInspectionReadModel): ReviewBoardReport["provenanceContext"]["migrationTimeline"] {
const present = new Set(model.store.migrations ?? []);
return KNOWN_MIGRATION_IDS.map(migrationId => {
const matchingTimes = model.evidenceEvents
.filter(event => event.details?.migrationId === migrationId)
.map(event => event.createdAt)
.sort();
const row: { migrationId: string; presentInStore: boolean; firstEvidenceAt?: string } = {
migrationId,
presentInStore: present.has(migrationId),
};
if (matchingTimes[0]) row.firstEvidenceAt = matchingTimes[0];
return row;
});
}
function migrationBoundaries(model: MemoryInspectionReadModel): ProvenanceContextInputs {
const present = new Set(model.store.migrations ?? []);
const matchingTimes = model.evidenceEvents
.filter(event => typeof event.details?.migrationId === "string" && present.has(event.details.migrationId))
.map(event => event.createdAt)
.sort();
return {
firstMigrationBoundary: matchingTimes[0],
latestMigrationBoundary: matchingTimes[matchingTimes.length - 1],
lastActivityAt: model.store.lastActivityAt,
};
}
function classifyProvenance(input: {
event?: EvidenceEventV1;
rejection?: NormalizedRejection;
reabsorbed?: boolean;
}, context: ProvenanceContextInputs): CandidateProvenance {
if (input.event?.details?.migrationId) {
return provenance("explicit_migration_evidence", "high", [`migration evidence event ${String(input.event.details.migrationId)}`]);
}
if (input.rejection && !hasWorkspaceScope(input.rejection)) {
return provenance("legacy_unversioned_format", "high", ["rejection record without workspace scope fields"]);
}
if (input.reabsorbed) {
return provenance("reabsorbed_post_rejection", "high", ["typed canonical rejected text appears in active memory"]);
}
const timestamp = input.event?.createdAt ?? input.rejection?.timestamp;
if (timestamp && context.firstMigrationBoundary && compareIso(timestamp, context.firstMigrationBoundary) < 0) {
return provenance("suspected_pre_migration_legacy", "medium", ["evidence timestamp predates first known migration boundary"]);
}
if (timestamp && context.latestMigrationBoundary && compareIso(timestamp, context.latestMigrationBoundary) >= 0) {
if (!context.lastActivityAt || compareIso(timestamp, context.lastActivityAt) >= 0) {
return provenance("likely_current_behavior", "medium", ["evidence timestamp is after known migration evidence and workspace last activity"]);
}
}
return provenance("unversioned_ambiguous", "low", ["no producer version or decisive migration/timestamp signal is recorded"]);
}
function provenance(classification: ProvenanceClassification, confidence: CandidateProvenance["confidence"], basis: string[]): CandidateProvenance {
return {
classification,
confidence,
basis,
interpretationCaveat: "Producer version is not recorded; treat this as inferred review context rather than proof of current behavior.",
};
}
function hasWorkspaceScope(record: NormalizedRejection): boolean {
return Boolean(record.workspaceKey || record.workspaceRoot || record.workspaceRootHash);
}
function compareIso(a: string, b: string): number {
const aTime = new Date(a).getTime();
const bTime = new Date(b).getTime();
if (!Number.isFinite(aTime) || !Number.isFinite(bTime)) return 0;
return aTime - bTime;
}
function reabsorbedRejectedMatches(activeMemories: LongTermMemoryEntry[], records: NormalizedRejection[]): ReabsorbedMatch[] {
const activeByKey = new Map(activeMemories.map(memory => [typedCanonicalKey(memory.type, memory.text), memory]));
const matches: ReabsorbedMatch[] = [];
const seen = new Set<string>();
for (const record of records) {
const key = typedCanonicalKey(record.type, record.text);
const activeMemory = activeByKey.get(key);
if (!activeMemory || seen.has(key)) continue;
seen.add(key);
matches.push({ key, record, activeMemory });
}
return matches;
}
function typedCanonicalKey(type: LongTermType | string, text: string): string {
return `${type}:${canonicalMemoryText(text)}`;
}
function buildReinforcementFacts(events: EvidenceEventV1[]): ReviewBoardReport["facts"]["systemMechanisms"]["reinforcementRules"] {
const attempts = events.filter(isReinforcementEvent);
const windowBlocked = attempts.filter(event => event.reasonCodes.includes("reinforcement_window_blocked"));
const grouped = new Map<string, { memoryId: string; count: number; refs: Set<string>; rawReasonCodes: Set<string>; eventIds: string[] }>();
for (const event of windowBlocked) {
const memoryId = event.memory?.memoryId ?? "unknown";
const current = grouped.get(memoryId) ?? { memoryId, count: 0, refs: new Set<string>(), rawReasonCodes: new Set<string>(), eventIds: [] };
current.count += 1;
current.eventIds.push(event.eventId);
const ref = typeof event.details?.ref === "string" ? event.details.ref : undefined;
if (ref) current.refs.add(ref);
for (const reason of event.reasonCodes) current.rawReasonCodes.add(reason);
grouped.set(memoryId, current);
}
return {
reinforceEvents: attempts.length,
reinforcedEvents: attempts.filter(event => event.outcome === "reinforced" || event.type === "memory_reinforced" && event.outcome !== "rejected").length,
rejectedOrBlockedEvents: attempts.filter(event => event.outcome === "rejected" || event.reasonCodes.includes("reinforcement_window_blocked")).length,
windowBlockedEvents: windowBlocked.length,
windowBlockRate: attempts.length === 0 ? 0 : windowBlocked.length / attempts.length,
repeatedBlocksByMemory: [...grouped.values()]
.filter(group => group.count > 1)
.sort((a, b) => b.count - a.count || a.memoryId.localeCompare(b.memoryId))
.map(group => ({ memoryId: group.memoryId, count: group.count, refs: [...group.refs].sort(), rawReasonCodes: [...group.rawReasonCodes].sort() })),
malformedCommandEvents: events.filter(isMalformedCommandEvent).length,
};
}
function isReinforcementEvent(event: EvidenceEventV1): boolean {
const type = String(event.type);
return type === "memory_reinforced"
|| type === "reinforce_memory"
|| type === "reinforced"
|| event.phase === "reinforcement";
}
function isMalformedCommandEvent(event: EvidenceEventV1): boolean {
return event.type === "extraction_candidate_rejected"
&& event.reasonCodes.some(reason => MALFORMED_COMMAND_REASON_CODES.has(reason));
}
function buildEvictionFacts(
model: MemoryInspectionReadModel,
activeMemories: LongTermMemoryEntry[],
typeCounts: Record<string, number>,
typeCaps: Record<string, number>,
disappearances: ReturnType<typeof disappearanceRows>,
generatedAt: string,
): ReviewBoardReport["facts"]["systemMechanisms"]["evictionAndCaps"] {
const capacityEvents = model.evidenceEvents.filter(event => event.type === "memory_removed_capacity");
const recentCapacityEvents = capacityEvents.filter(event => isWithinDaysOf(event.createdAt, generatedAt, RECENT_EVICTION_DAYS));
const fullCaps = [
...(activeMemories.length >= model.store.limits.maxEntries ? ["global"] : []),
...TYPES.filter(type => (typeCounts[type] ?? 0) >= (typeCaps[type] ?? Number.POSITIVE_INFINITY)),
];
return {
activeMemories: activeMemories.length,
maxEntries: model.store.limits.maxEntries,
renderedMemories: model.snapshot.retention.rendered.length,
typeCounts,
typeCaps,
fullCaps,
missingEvidenceOnly: disappearances.length,
unknownDisappearances: disappearances.filter(row => row.classification === "historical_absent_unknown_reason").length,
removedByCapacity: capacityEvents.length,
removedByGlobalCap: capacityEvents.filter(event => event.reasonCodes.includes("global_cap")).length,
removedByTypeCap: capacityEvents.filter(event => event.reasonCodes.includes("type_cap")).length,
recentEvictionsByType: objectFromCounts(countBy(recentCapacityEvents.map(event => event.memory?.type ?? "unknown"))),
recentEvictedContentShown: recentCapacityEvents.length,
};
}
function isWithinDaysOf(iso: string, referenceIso: string, days: number): boolean {
const time = new Date(iso).getTime();
const reference = new Date(referenceIso).getTime();
return Number.isFinite(time) && Number.isFinite(reference) && time >= reference - days * 86_400_000;
}
function buildIdentityFacts(model: MemoryInspectionReadModel, activeMemories: LongTermMemoryEntry[]): ReviewBoardReport["facts"]["systemMechanisms"]["identityAndDedup"] {
const replacementEvents = model.evidenceEvents.filter(event => event.type === "memory_replaced_numbered_ref");
return {
replacementEvents: replacementEvents.length,
sameTypeReplacementEvents: replacementEvents.filter(isSameTypeReplacement).length,
crossTypeReplacementEvents: replacementEvents.filter(isCrossTypeReplacement).length,
supersededEntries: model.store.entries.filter(entry => entry.status === "superseded").length,
duplicateTextOrIdentityGroups: duplicateGroups(activeMemories, model.evidenceEvents).length,
};
}
function isSameTypeReplacement(event: EvidenceEventV1): boolean {
if (event.reasonCodes.includes("same_type_replace")) return true;
const types = relationTypes(event);
return types.length >= 2 && new Set(types).size === 1;
}
function isCrossTypeReplacement(event: EvidenceEventV1): boolean {
if (event.reasonCodes.includes("cross_type_replace")) return true;
const types = relationTypes(event);
return types.length >= 2 && new Set(types).size > 1;
}
function relationTypes(event: EvidenceEventV1): string[] {
return uniqueStrings(event.relations?.map(relation => relation.memory?.type ?? "") ?? []);
}
function duplicateGroups(activeMemories: LongTermMemoryEntry[], events: EvidenceEventV1[]): Array<{ id: string; memoryIds: string[]; basis: string }> {
const groups: Array<{ id: string; memoryIds: string[]; basis: string }> = [];
const byText = groupBy(activeMemories, memory => typedCanonicalKey(memory.type, memory.text));
for (const [key, memories] of byText.entries()) {
if (memories.length > 1) groups.push({ id: `text:${hashText(key)}`, memoryIds: memories.map(memory => memory.id).sort(), basis: "exact typed canonical text" });
}
const identityRefs = events
.map(event => event.memory)
.filter((memory): memory is NonNullable<EvidenceEventV1["memory"]> => Boolean(memory?.identityKeyHash && memory.memoryId));
const byIdentity = groupBy(identityRefs, memory => String(memory.identityKeyHash));
for (const [key, refs] of byIdentity.entries()) {
const ids = uniqueStrings(refs.map(ref => ref.memoryId ?? "")).sort();
if (ids.length > 1) groups.push({ id: `identity:${hashText(key)}`, memoryIds: ids, basis: "shared evidence identity hash" });
}
return groups;
}
function groupBy<T>(items: T[], keyFor: (item: T) => string): Map<string, T[]> {
const grouped = new Map<string, T[]>();
for (const item of items) {
const key = keyFor(item);
grouped.set(key, [...(grouped.get(key) ?? []), item]);
}
return grouped;
}
function buildMemoryContentFacts(
model: MemoryInspectionReadModel,
activeMemories: LongTermMemoryEntry[],
typeCounts: Record<string, number>,
typeCaps: Record<string, number>,
raw: boolean,
): ReviewBoardReport["facts"]["memoryContent"] {
const evidenceCovered = activeMemories.filter(memory => (model.evidenceByMemoryId.get(memory.id) ?? []).length > 0).length;
const weakest = model.snapshot.retention.sorted.slice(-5).reverse();
const strongest = model.snapshot.retention.sorted.slice(0, 5);
return {
activeMemories: activeMemories.length,
renderedMemories: model.snapshot.retention.rendered.length,
evidenceCoverage: { covered: evidenceCovered, total: activeMemories.length },
typeCounts,
typeCaps,
weakestActiveMemories: weakest.map(item => retentionPreview(item.entry, item.strength, raw)),
strongestActiveMemories: strongest.map(item => retentionPreview(item.entry, item.strength, raw)),
};
}
function retentionPreview(entry: LongTermMemoryEntry, strength: number | undefined, raw: boolean): { id: string; type: string; strength?: number; textPreview: string } {
return { id: entry.id, type: entry.type, strength, textPreview: truncate(cleanText(entry.text, raw), 120) };
}
function buildActiveMemoryDisplay(
model: MemoryInspectionReadModel,
activeMemories: LongTermMemoryEntry[],
reabsorbedKeys: Set<string>,
activeMemoryByKey: Map<string, LongTermMemoryEntry>,
provenanceInputs: ProvenanceContextInputs,
raw: boolean,
verbose: boolean,
): ReviewBoardReport["activeMemoryDisplay"] {
const mode: "all" | "sample" = activeMemories.length <= ACTIVE_MEMORY_FULL_TEXT_THRESHOLD || verbose ? "all" : "sample";
const shownMemories = mode === "all" ? activeMemories : activeMemories.slice(0, ACTIVE_MEMORY_FULL_TEXT_THRESHOLD);
const items = shownMemories.map(memory => {
const events = model.evidenceByMemoryId.get(memory.id) ?? [];
const key = typedCanonicalKey(memory.type, memory.text);
const item: ReviewBoardActiveMemory = {
id: memory.id,
type: memory.type,
source: memory.source,
status: memory.status,
strength: model.snapshot.retention.sorted.find(candidate => candidate.entry.id === memory.id)?.strength,
text: cleanText(memory.text, raw),
evidence: {
eventCount: events.length,
eventIds: events.map(event => event.eventId),
rawReasonCodes: uniqueStrings(events.flatMap(event => event.reasonCodes)).sort(),
},
heuristicFlags: activeMemoryFlags(memory, events),
reviewQuestions: memoryContentQuestions(),
};
if (reabsorbedKeys.has(key) && activeMemoryByKey.get(key)?.id === memory.id) {
item.provenance = classifyProvenance({ reabsorbed: true }, provenanceInputs);
}
return item;
});
return { threshold: ACTIVE_MEMORY_FULL_TEXT_THRESHOLD, mode, shown: items.length, total: activeMemories.length, items };
}
function activeMemoryFlags(memory: LongTermMemoryEntry, events: EvidenceEventV1[]): HeuristicFlag[] {
const flags: HeuristicFlag[] = [];
if (events.length === 0) {
flags.push(flag("no_evidence", "No linked evidence events", `memory ${memory.id} has no lifecycle evidence events`));
}
if ((memory.supersedes ?? []).length > 0) {
flags.push(flag("supersedes_other_memory", "Supersession relationship present", `memory ${memory.id} supersedes ${memory.supersedes?.length ?? 0} prior entries`));
}
return flags;
}
function buildSystemCandidateDisplay(
candidateInputs: Record<string, DatedCandidateInput[]>,
showAll: boolean,
): { candidates: ReviewBoardCandidate[]; limited: boolean; summary: NonNullable<ReviewBoardReport["provenanceContext"]["candidateDisplay"]> } {
const candidates: ReviewBoardCandidate[] = [];
const byMechanism: Record<string, { shown: number; total: number }> = {};
let shown = 0;
let total = 0;
let limited = false;
for (const [mechanism, inputs] of Object.entries(candidateInputs)) {
const selected = selectRepresentative(inputs, showAll);
candidates.push(...selected.map(item => item.candidate));
byMechanism[mechanism] = { shown: selected.length, total: inputs.length };
shown += selected.length;
total += inputs.length;
if (selected.length < inputs.length) limited = true;
}
return { candidates, limited, summary: { shown, total, byMechanism } };
}
function buildRejectionCandidates(records: NormalizedRejection[], context: ProvenanceContextInputs, raw: boolean): DatedCandidateInput[] {
const candidateRecords = records
.filter(record => record.reasons.includes("bad_decision"))
.map(record => ({ record, label: neutralRejectionLabel(record) }))
.filter(item => item.label === "architecture_like_rejected_candidate" || item.label === "ambiguous_rejected_candidate")
.sort((a, b) =>
timestampValue(b.record.timestamp) - timestampValue(a.record.timestamp)
|| a.record.type.localeCompare(b.record.type)
|| a.record.text.localeCompare(b.record.text)
);
const candidates = uniqueByCanonicalText(candidateRecords.map(item => item.record))
.map(record => ({ record, label: neutralRejectionLabel(record) }))
.map(({ record, label }) => ({
candidate: candidate({
concernKind: "system_mechanism",
mechanism: "rejection_filter",
source: "rejection_rule_evidence",
id: `rejection:${record.timestamp || "unknown"}:${hashText(record.type + record.text)}`,
facts: { type: record.type, neutralLabel: label, timestamp: record.timestamp || undefined, origin: record.origin },
evidence: { rawReasonCodes: record.reasons, textPreview: truncate(cleanText(record.text, raw), 120), textAvailable: true },
provenance: classifyProvenance({ rejection: record }, context),
heuristicFlags: [flag(label, label.replaceAll("_", " "), "existing rejection summary grouped this record for human review")],
reviewQuestions: ["Are rejection filters over-filtering durable decisions or under-filtering non-durable candidates for this workspace?"],
nextCommands: ["memory-diag rejected --verbose"],
}),
timestamp: record.timestamp,
tieId: record.timestamp || "unknown",
textHash: hashText(record.text),
}));
return candidates;
}
function neutralRejectionLabel(record: NormalizedRejection): "architecture_like_rejected_candidate" | "ambiguous_rejected_candidate" | "status_or_hard_reason_evidence" {
const hardReasons = record.reasons.filter(reason => HARD_OR_NOISE_REASON_CODES.has(reason));
const statusLike = /\b(?:implemented|added|updated|fixed|completed|reviewed|tests?|CI|commit|wave|phase|task|session)\b/i.test(record.text);
const architectureLike = /\b(?:architecture|retention|migration|schema|policy|model|dedup|identity|parser|formatter|diagnostic|evidence|cap|window|api|contract)\b/i.test(record.text);
if (architectureLike && hardReasons.length === 0 && !statusLike) return "architecture_like_rejected_candidate";
if (hardReasons.length > 0 || statusLike) return "status_or_hard_reason_evidence";
return "ambiguous_rejected_candidate";
}
function buildReabsorptionCandidates(matches: ReabsorbedMatch[], context: ProvenanceContextInputs, raw: boolean): DatedCandidateInput[] {
const candidates = matches.map(match => ({
candidate: candidate({
concernKind: "system_mechanism",
mechanism: "rejection_filter",
source: "reabsorption_evidence",
id: `reabsorbed:${match.activeMemory.id}:${hashText(match.key)}`,
facts: { activeMemoryId: match.activeMemory.id, type: match.activeMemory.type, rejectedAt: match.record.timestamp || undefined },
evidence: { rawReasonCodes: match.record.reasons, textPreview: truncate(cleanText(match.record.text, raw), 120), textAvailable: true },
provenance: classifyProvenance({ rejection: match.record, reabsorbed: true }, context),
heuristicFlags: [flag("reabsorbed_rejected_text", "Rejected text appears in active memory", "typed canonical text is present in both rejection records and active memory")],
reviewQuestions: ["Did later context make this rejected candidate worth reviewing for filter calibration?"],
nextCommands: ["memory-diag rejected --verbose", `memory-diag explain ${match.activeMemory.id}`],
}),
timestamp: match.record.timestamp,
tieId: match.activeMemory.id,
textHash: hashText(match.key),
}));
return candidates;
}
function buildReinforcementCandidates(events: EvidenceEventV1[], context: ProvenanceContextInputs, raw: boolean): DatedCandidateInput[] {
const blocked = events.filter(event => isReinforcementEvent(event) && event.reasonCodes.includes("reinforcement_window_blocked"));
const grouped = [...groupBy(blocked, event => event.memory?.memoryId ?? "unknown").entries()].map(([memoryId, group]) => ({ memoryId, group }));
const repeated = grouped.filter(item => item.group.length > 1).map(item => {
const latest = newestEvent(item.group);
return {
candidate: candidate({
concernKind: "system_mechanism",
mechanism: "reinforcement_rule",
source: "numbered_command_evidence",
id: `reinforcement:${item.memoryId}:${item.group.length}`,
facts: { memoryId: item.memoryId, blockCount: item.group.length, refs: uniqueStrings(item.group.map(event => String(event.details?.ref ?? "")).filter(Boolean)).sort() },
evidence: { eventIds: item.group.map(event => event.eventId), rawReasonCodes: uniqueStrings(item.group.flatMap(event => event.reasonCodes)).sort(), textAvailable: false },
provenance: classifyProvenance({ event: latest }, context),
heuristicFlags: [flag("repeated_reinforcement_window_block", "Repeated reinforcement window block", `${item.group.length} reinforcement attempts were blocked for memory ${item.memoryId}`)],
reviewQuestions: ["Is the day-based reinforcement window too restrictive when the same memory receives repeated reinforce intent?"],
nextCommands: ["memory-diag commands --verbose", `memory-diag explain ${item.memoryId}`],
}),
timestamp: latest?.createdAt,
tieId: item.memoryId,
textHash: item.memoryId,
};
});
const malformed = events.filter(isMalformedCommandEvent).map(event => ({
candidate: candidate({
concernKind: "system_mechanism",
mechanism: "reinforcement_rule",
source: "numbered_command_evidence",
id: `malformed-command:${event.eventId}`,
facts: { eventType: event.type, createdAt: event.createdAt },
evidence: { eventIds: [event.eventId], rawReasonCodes: event.reasonCodes, textPreview: event.textPreview ? truncate(cleanText(event.textPreview, raw), 120) : undefined, textAvailable: Boolean(event.textPreview) },
provenance: classifyProvenance({ event }, context),
heuristicFlags: [flag("malformed_numbered_command", "Malformed numbered-memory command evidence", "command parser rejected a memory command form")],
reviewQuestions: ["Do numbered-memory command rules match how agents actually express reinforcement intent?"],
nextCommands: ["memory-diag commands --verbose"],
}),
timestamp: event.createdAt,
tieId: event.eventId,
textHash: event.eventId,
}));
return [...repeated, ...malformed];
}
function buildEvictionCandidates(
disappearances: ReturnType<typeof disappearanceRows>,
events: EvidenceEventV1[],
context: ProvenanceContextInputs,
raw: boolean,
generatedAt: string,
): DatedCandidateInput[] {
const recentCapacity = events.filter(event => event.type === "memory_removed_capacity" && isWithinDaysOf(event.createdAt, generatedAt, RECENT_EVICTION_DAYS));
const capacityCandidates = recentCapacity.map(event => ({
candidate: candidate({
concernKind: "system_mechanism",
mechanism: "eviction_cap",
source: "eviction_cap_evidence",
id: `eviction:${event.eventId}`,
facts: { ...(safeDetails(event.details, raw) ?? {}), createdAt: event.createdAt, memoryId: event.memory?.memoryId, type: event.memory?.type },
evidence: { eventIds: [event.eventId], rawReasonCodes: event.reasonCodes, textPreview: event.textPreview ? truncate(cleanText(event.textPreview, raw), 120) : undefined, textAvailable: Boolean(event.textPreview) },
provenance: classifyProvenance({ event }, context),
heuristicFlags: [flag("recent_capacity_removal", "Recent capacity-removal evidence", "memory_removed_capacity appeared within the recent eviction window")],
reviewQuestions: ["Are eviction and cap rules preserving the intended memories under pressure?"],
nextCommands: ["memory-diag missing --verbose --explain"],
}),
timestamp: event.createdAt,
tieId: event.eventId,
textHash: event.textPreview ? hashText(event.textPreview) : event.eventId,
}));
const unknownCandidates = disappearances
.filter(row => row.classification === "historical_absent_unknown_reason")
.map(row => {
const latest = newestEvent(row.events);
return {
candidate: candidate({
concernKind: "system_mechanism",
mechanism: "eviction_cap",
source: "missing_evidence",
id: `missing:${row.id}`,
facts: { memoryId: row.id, terminalType: row.terminalType, eventCount: row.events.length },
evidence: { eventIds: row.events.map(event => event.eventId), rawReasonCodes: uniqueStrings(row.events.flatMap(event => event.reasonCodes)).sort(), textPreview: latest?.textPreview ? truncate(cleanText(latest.textPreview, raw), 120) : undefined, textAvailable: Boolean(latest?.textPreview) },
provenance: classifyProvenance({ event: latest }, context),
heuristicFlags: [flag("unknown_disappearance", "Evidence-only disappearance without terminal removal evidence", `memory ${row.id} has evidence but is not active`)],
reviewQuestions: ["Does missing-memory evidence indicate a cap, retention, or recording rule needs review?"],
nextCommands: ["memory-diag missing --verbose --explain"],
}),
timestamp: latest?.createdAt,
tieId: row.id,
textHash: row.id,
};
});
return [...capacityCandidates, ...unknownCandidates];
}
function safeDetails(details: EvidenceEventV1["details"], raw: boolean): Record<string, unknown> | undefined {
if (!details) return undefined;
return Object.fromEntries(Object.entries(details).map(([key, value]) => [key, typeof value === "string" ? cleanText(value, raw) : value]));
}
function buildIdentityCandidates(model: MemoryInspectionReadModel, activeMemories: LongTermMemoryEntry[], context: ProvenanceContextInputs, raw: boolean): DatedCandidateInput[] {
const replacementCandidates = model.evidenceEvents
.filter(event => event.type === "memory_replaced_numbered_ref" || event.type === "promotion_superseded")
.map(event => ({
candidate: candidate({
concernKind: "system_mechanism",
mechanism: "identity_dedup",
source: "identity_dedup_evidence",
id: `identity-event:${event.eventId}`,
facts: { eventType: event.type, memoryId: event.memory?.memoryId, relationRoles: event.relations?.map(relation => relation.role) ?? [] },
evidence: { eventIds: [event.eventId], rawReasonCodes: event.reasonCodes, textPreview: event.textPreview ? truncate(cleanText(event.textPreview, raw), 120) : undefined, textAvailable: Boolean(event.textPreview) },
provenance: classifyProvenance({ event }, context),
heuristicFlags: [flag("replacement_or_supersession", "Replacement or supersession evidence", `${event.type} records identity/dedup behavior`)],
reviewQuestions: ["Are identity and dedup rules preserving separate memories when expected to remain distinct?"],
nextCommands: ["memory-diag commands --verbose", event.memory?.memoryId ? `memory-diag explain ${event.memory.memoryId}` : "memory-diag missing --verbose --explain"],
}),
timestamp: event.createdAt,
tieId: event.eventId,
textHash: event.eventId,
}));
const duplicateCandidates = duplicateGroups(activeMemories, model.evidenceEvents).map(group => ({
candidate: candidate({
concernKind: "system_mechanism",
mechanism: "identity_dedup",
source: "identity_dedup_evidence",
id: `duplicate:${group.id}`,
facts: { memoryIds: group.memoryIds, basis: group.basis },
evidence: { eventIds: group.memoryIds.flatMap(id => (model.evidenceByMemoryId.get(id) ?? []).map(event => event.eventId)), rawReasonCodes: [], textAvailable: false },
provenance: classifyProvenance({}, context),
heuristicFlags: [flag("exact_duplicate_group", "Exact duplicate text or identity group", `${group.memoryIds.length} memories share ${group.basis}`)],
reviewQuestions: ["Are exact duplicate text or identity groups expected for this workspace?"],
nextCommands: group.memoryIds.map(id => `memory-diag explain ${id}`).slice(0, 3),
}),
timestamp: undefined,
tieId: group.id,
textHash: group.id,
}));
return [...replacementCandidates, ...duplicateCandidates];
}
function buildMemoryContentCandidates(model: MemoryInspectionReadModel, activeMemories: LongTermMemoryEntry[], raw: boolean): ReviewBoardCandidate[] {
return activeMemories.slice(0, ACTIVE_MEMORY_FULL_TEXT_THRESHOLD).map(memory => {
const events = model.evidenceByMemoryId.get(memory.id) ?? [];
return candidate({
concernKind: "memory_content",
mechanism: "retention_rendering",
source: "active_memory",
id: `active:${memory.id}`,
facts: { id: memory.id, type: memory.type, source: memory.source, status: memory.status },
evidence: { eventIds: events.map(event => event.eventId), rawReasonCodes: uniqueStrings(events.flatMap(event => event.reasonCodes)).sort(), textPreview: truncate(cleanText(memory.text, raw), 120), textAvailable: true },
heuristicFlags: activeMemoryFlags(memory, events),
reviewQuestions: memoryContentQuestions(),
nextCommands: [`memory-diag explain ${memory.id}`],
});
});
}
function candidate(input: ReviewBoardCandidate): ReviewBoardCandidate {
return input;
}
function selectRepresentative(items: DatedCandidateInput[], verbose: boolean): DatedCandidateInput[] {
const sorted = [...items].sort((a, b) => {
const timeDelta = timestampValue(b.timestamp) - timestampValue(a.timestamp);
if (timeDelta !== 0) return timeDelta;
const idDelta = a.tieId.localeCompare(b.tieId);
if (idDelta !== 0) return idDelta;
return (a.textHash ?? "").localeCompare(b.textHash ?? "");
});
return verbose ? sorted : sorted.slice(0, REPRESENTATIVE_CANDIDATE_LIMIT);
}
function timestampValue(iso: string | undefined): number {
const time = iso ? new Date(iso).getTime() : 0;
return Number.isFinite(time) ? time : 0;
}
function newestEvent(events: EvidenceEventV1[]): EvidenceEventV1 | undefined {
return [...events].sort((a, b) => timestampValue(b.createdAt) - timestampValue(a.createdAt) || a.eventId.localeCompare(b.eventId))[0];
}
function flag(id: string, label: string, evidence: string): HeuristicFlag {
return {
id,
label,
evidence,
caveat: "This flag is a prompt for review, not a conclusion.",
};
}
function systemMechanismQuestions(): string[] {
return [
"Are rejection rules over-filtering durable decisions or under-filtering non-durable candidates for this workspace?",
"Is the reinforcement window too restrictive when the same memory receives repeated reinforce intent?",
"Are eviction and cap rules preserving target memories under full caps?",
"Are identity and dedup rules collapsing items expected to remain separate, or not collapsing equivalent items?",
];
}
function memoryContentQuestions(): string[] {
return [
"Does this memory remain durable and actionable for future sessions?",
"Is this memory non-stale, specific, and supported by available evidence?",
"Does this memory overlap with other active memories in a way a reviewer should consider?",
];
}
function nextCommands(): string[] {
return [
"memory-diag rejected --verbose",
"memory-diag missing --verbose --explain",
"memory-diag commands --verbose",
"memory-diag explain <memory-id>",
];
}
function countProvenanceClassifications(candidates: ReviewBoardCandidate[]): Record<ProvenanceClassification, number> {
const counts = Object.fromEntries(PROVENANCE_CLASSIFICATIONS.map(classification => [classification, 0])) as Record<ProvenanceClassification, number>;
for (const provenanceItem of candidates.map(candidate => candidate.provenance)) {
if (!provenanceItem) continue;
counts[provenanceItem.classification] += 1;
}
return counts;
}
function hashText(text: string): string {
return createHash("sha256").update(text).digest("hex").slice(0, 12);
}