* test(#1964): add failing-first semantic-recall contract tests Epic #1957 Phase 3C (final). Source-text-is-the-product contract tests: semantic recall via MemPalace (top-k meaning-similar prior resolutions, catches same-root-cause/different-wording cases), indexing resolved sessions at archive, graceful degradation to keyword matching when MemPalace is absent, knowledge-base.md stays the durable plain-text source of truth, agent Phase 0 / Matching Logic is semantic-first (the stale 'keyword overlap, not semantic similarity' claim must go), and no new embedding/vector infra (reuse MemPalace). Failing-first: reference, the Matching Logic reframe, the Phase 0 consolidation, and the archive indexing step do not yet exist. * feat(#1964): semantic knowledge-base recall via MemPalace (keyword fallback) Epic #1957 Phase 3C (FINAL). Replaces keyword-overlap matching with semantic recall: at Phase 0 the debugger queries MemPalace with the current symptoms and surfaces the top-k meaning-similar prior resolutions, catching the same-root-cause/different-wording cases keyword overlap missed (the self-noted 'keyword overlap, not semantic similarity' limitation). Resolved sessions are indexed into MemPalace at archive (symptoms + root_cause(s) + fix + recurrence guard). knowledge-base.md remains the durable plain-text source of truth; when MemPalace is absent the debugger falls back to keyword-overlap matching (logged, never a silent skip). No new embedding/vector infrastructure — MemPalace is reused. Size-neutral agent edits: the Matching Logic section reframed (keyword-only -> semantic-first + keyword-fallback + @-include); Phase 0's three keyword bullets consolidated into one semantic-first bullet; one MemPalace-indexing step added at archive. Agent at 57222 B (122 B headroom — final phase). Full rules in gsd-core/references/debugger-semantic-recall.md. INVENTORY + manifest + agent-size baseline + install-parity goldens + AGENTS.md updated. * fix(#1964): address orthogonal review (invocation mechanism, index Resolution-not-symptoms + redaction, fallback detail) - HIGH: the 'query MemPalace' instruction was WHAT-level only; the agent has no MCP tools. Added an Invocation section naming the Bash CLI (mempalace search --wing <wing>) + MCP-when-registered + wing resolution (config.mempalace.wing -> project_code -> project dir), matching every other MemPalace integration. Without this the feature silently degraded to keyword matching even when MemPalace was present. - MEDIUM (security x2): index the agent-authored Resolution summary (root_cause + fix + recurrence_guard), NOT raw user-supplied Symptoms — excludes attacker-controlled prose from the cross-session index AND reduces secret/PII leakage. Redact secret-shaped values before indexing. Stated the write order (KB append + commit MUST succeed before indexing). - LOW: restored 'identifiers' + 'case-insensitive' to the keyword fallback; added a test asserting the fallback mechanics survived the Phase 0 consolidation (Error patterns field, 2+ token overlap, identifiers, case-insensitive). * chore(#1964): ratchet agent-size baseline downward (leaner archive bullet shrank gsd-debugger.md 57222->57197) * chore(#1964): backfill changeset pr number (PR #2416)
105 lines
5.7 KiB
JavaScript
105 lines
5.7 KiB
JavaScript
// allow-test-rule: source-text-is-the-product (see #1964)
|
|
// Agent .md + reference .md files — their text IS what the runtime loads.
|
|
// Testing text content tests the deployed semantic-recall contract.
|
|
// Per CONTRIBUTING.md exception matrix. Covers epic #1957 Phase 3C (#1964).
|
|
'use strict';
|
|
|
|
const { describe, test } = require('node:test');
|
|
const assert = require('node:assert/strict');
|
|
const fs = require('node:fs');
|
|
const path = require('node:path');
|
|
|
|
const ROOT = process.cwd();
|
|
const AGENT = path.join(ROOT, 'agents/gsd-debugger.md');
|
|
const REFERENCE = path.join(ROOT, 'gsd-core/references/debugger-semantic-recall.md');
|
|
|
|
describe('semantic knowledge-base recall via MemPalace (#1964, epic #1957 Phase 3C)', () => {
|
|
describe('reference extract exists and is wired in', () => {
|
|
test('gsd-core/references/debugger-semantic-recall.md exists', () => {
|
|
assert.ok(fs.existsSync(REFERENCE), 'debugger-semantic-recall.md reference must exist');
|
|
});
|
|
|
|
test('gsd-debugger.md @-includes the semantic-recall reference', () => {
|
|
const content = fs.readFileSync(AGENT, 'utf8');
|
|
assert.ok(
|
|
content.includes('@~/.claude/gsd-core/references/debugger-semantic-recall.md'),
|
|
'gsd-debugger.md must @-include the semantic-recall reference from the knowledge_base_protocol / Matching Logic'
|
|
);
|
|
});
|
|
});
|
|
|
|
describe('semantic recall via MemPalace (criterion 1 — same root cause, different wording)', () => {
|
|
test('reference documents querying MemPalace for meaning-similar prior resolutions', () => {
|
|
const content = fs.readFileSync(REFERENCE, 'utf8');
|
|
assert.ok(/mempalace/i.test(content), 'must name MemPalace as the semantic-memory surface');
|
|
assert.ok(/semantic/i.test(content), 'must document semantic (not keyword) recall');
|
|
assert.ok(/top-?k|meaning.similar|semantically.similar/i.test(content),
|
|
'must document surfacing top-k meaning-similar prior resolutions');
|
|
});
|
|
|
|
test('reference states the payoff: catches lexically-different / same-root-cause cases', () => {
|
|
const content = fs.readFileSync(REFERENCE, 'utf8');
|
|
assert.ok(/different.{0,30}word|lexically|same root cause|wording/i.test(content),
|
|
'must state that semantic recall catches same-root-cause/different-wording cases keyword overlap misses (the self-noted limitation)');
|
|
});
|
|
|
|
test('reference documents indexing resolved sessions into MemPalace at archive', () => {
|
|
const content = fs.readFileSync(REFERENCE, 'utf8');
|
|
assert.ok(/index|archive|store|capture/i.test(content),
|
|
'must document that resolved sessions are indexed into MemPalace at archive time');
|
|
});
|
|
});
|
|
|
|
describe('graceful degradation — MemPalace absent falls back to keyword matching (criterion 2)', () => {
|
|
test('reference documents the keyword fallback when MemPalace is unavailable', () => {
|
|
const content = fs.readFileSync(REFERENCE, 'utf8');
|
|
assert.ok(/fall[\s-]?back|fallback|when.*(?:absent|unavailable)|degrade/i.test(content),
|
|
'must document degradation to keyword matching when MemPalace is absent');
|
|
assert.ok(/keyword/i.test(content), 'must name keyword matching as the fallback');
|
|
});
|
|
|
|
test('the keyword-fallback mechanics survived the Phase 0 consolidation', () => {
|
|
// Guards against the consolidation dropping the extraction detail the
|
|
// fallback path needs. The reference must still document the Error
|
|
// patterns field scan + the 2+ token threshold + identifiers + case-insensitive.
|
|
const content = fs.readFileSync(REFERENCE, 'utf8');
|
|
assert.ok(/error patterns/i.test(content), 'fallback must scan the Error patterns field');
|
|
assert.ok(/2\+ token overlap/i.test(content), 'fallback must keep the 2+ token overlap threshold');
|
|
assert.ok(/identifier/i.test(content), 'fallback must keep identifier extraction (highest-signal token)');
|
|
assert.ok(/case-insensitive/i.test(content), 'fallback must keep the case-insensitive qualifier');
|
|
});
|
|
|
|
test('knowledge-base.md remains the durable plain-text source of truth', () => {
|
|
const content = fs.readFileSync(REFERENCE, 'utf8');
|
|
assert.ok(/knowledge-base\.md|durable|plain[\s-]?text|source of truth/i.test(content),
|
|
'must state that knowledge-base.md remains the durable plain-text source of truth (semantic recall is layered on top)');
|
|
});
|
|
});
|
|
|
|
describe('agent wiring — Phase 0 / Matching Logic is semantic-first', () => {
|
|
test('gsd-debugger.md knowledge_base_protocol describes semantic-first matching', () => {
|
|
const content = fs.readFileSync(AGENT, 'utf8');
|
|
// The Matching Logic section must now lead with semantic recall, not "keyword overlap, not semantic"
|
|
assert.ok(/semantic/i.test(content), 'agent must reference semantic recall');
|
|
assert.ok(/mempalace/i.test(content), 'agent must name MemPalace');
|
|
assert.ok(/fall[\s-]?back|fallback/i.test(content), 'agent must describe the keyword fallback');
|
|
});
|
|
|
|
test('the stale "keyword overlap, not semantic similarity" claim is gone', () => {
|
|
const content = fs.readFileSync(AGENT, 'utf8');
|
|
assert.ok(
|
|
!/keyword overlap, not semantic similarity/i.test(content),
|
|
'the old "Matching is keyword overlap, not semantic similarity" claim must be removed (it is now semantic-first)'
|
|
);
|
|
});
|
|
});
|
|
|
|
describe('no new embedding/vector infrastructure (Choose Boring / Zawinski)', () => {
|
|
test('reference states MemPalace is reused — no new vector store', () => {
|
|
const content = fs.readFileSync(REFERENCE, 'utf8');
|
|
assert.ok(/reuse|no new|without adding|existing.*(?:semantic|memory|capability)/i.test(content),
|
|
'must state MemPalace is reused rather than adding new embedding/vector infrastructure');
|
|
});
|
|
});
|
|
});
|