feat: tighten search contract (Phase 8 - DISC-01 + SAFE-01)#91
feat: tighten search contract (Phase 8 - DISC-01 + SAFE-01)#91PatrickSys merged 4 commits intomasterfrom
Conversation
renderMapMarkdown now emits '# Codebase Map — <project>' instead of '# Codebase Intelligence'. Two stale assertions in tests/multi-project-routing.test.ts were not updated during execution. Full suite: 412/412 pass.
…ss-aware edit gating
Greptile SummaryThis PR formalises a compact/full two-mode contract for
Confidence Score: 4/5Safe to merge — all 426 tests pass, logic is correct, findings are P2 clean-ups and defensive suggestions. The compact/full fork and freshness gating are well-tested (14 new integration tests) and the logic is sound. The three flagged issues are all P2: a stale type field, a defensive readyToEdit guard, and a memory-filter edge case for single-term queries. None are blockers. src/tools/types.ts (stale consumers field) and src/tools/search-codebase.ts (filterStrongMemories single-term gap)
|
| Filename | Overview |
|---|---|
| src/tools/search-codebase.ts | Main change: compact/full mode fork, new graph helpers (getImportedByCount, getTopExports, buildNextHops), memory relevance filter, and freshness signal wiring. Minor: filterStrongMemories silently drops memories for single-term queries. |
| src/preflight/evidence-lock.ts | Adds indexFreshness parameter with stale/aging gate logic. Stale forces status = 'block'; aging adds a gap warning. readyToEdit doesn't independently check freshness — relies on side-effect of status override. |
| src/tools/types.ts | Adds abstain?: boolean to DecisionCard. However, consumers is not removed from SearchResultItem.hints despite being dropped from the implementation. |
| tests/search-safe-01.test.ts | 6 integration tests covering low-confidence, fresh, aging, stale, explore-bypass, and gap-propagation. Good fixture isolation with temp dirs and hoisted search mocks. |
| tests/search-compact-mode.test.ts | 8 tests covering result capping, graph context fields, hints/consumers absence, budget/patternSummary/bestExample/nextHops, and memory gating. Solid fixture setup. |
| tests/multi-project-routing.test.ts | Two assertion strings updated from '# Codebase Intelligence' to '# Codebase Map' to match header change from a prior phase. Straightforward fix. |
| tests/search-decision-card.test.ts | Regression fix: mode: 'full' added to snippet-dependent test calls so they use the full response shape (which includes hints/snippet fields). |
| tests/search-snippets.test.ts | Regression fix: mode: 'full' added to ensure snippet tests exercise the full-mode response path. |
Flowchart
%%{init: {'theme': 'neutral'}}%%
flowchart TD
A([search_codebase called]) --> B{mode param?}
B -- compact / default --> C[Slice results to ≤6]
B -- full --> D[All results]
A --> E{intent?}
E -- edit / refactor / migrate --> F[Full preflight path]
E -- explore / none --> G[Lite preflight path]
F --> H[computeIndexConfidence]
H --> I{indexFreshness?}
I -- fresh --> J[buildEvidenceLock — no freshness gate]
I -- aging --> K[buildEvidenceLock + aging gap added]
I -- stale --> L[buildEvidenceLock + status forced to block]
J & K & L --> M{evidenceLock.status == block or searchQuality == low_confidence?}
M -- yes --> N[decisionCard.abstain = true, ready = false]
M -- no --> O[decisionCard.ready = true]
G --> P[buildEvidenceLock — indexFreshness omitted]
P --> Q[lite preflight: ready + reason only]
C --> R[Compact response: budget, patternSummary, bestExample, nextHops, importedByCount, topExports]
D --> S[Full response: budget, hints, relatedMemories]
N & O --> R
N & O --> S
Comments Outside Diff (2)
-
src/preflight/evidence-lock.ts, line 222-225 (link)readyToEditdoesn't independently guard againstindexFreshness === 'stale'readyToEditrelies entirely onstatus === 'pass'— which is correct now because the stale branch setsstatus = 'block'earlier. But if the stale gate is ever reordered (e.g., moved before the epistemic-stress block that can lower'pass'→'warn') or refactored,readyToEditwould silently becometruefor a stale index. Adding an explicit freshness guard makes the contract self-documenting and regression-proof: -
src/tools/types.ts, line 83-88 (link)Stale
consumersfield remains in exported typeThe PR removes
consumersfrom thebuildRelationshipHintsimplementation (with the comment"consumers removed — it was identical to callers"), but the exportedSearchResultItem.hintsinterface still declaresconsumers?: string[]. This creates a dead field: the type says it's allowed but the tool never sets it. Any consumer relying on this field in the SDK/API response will silently getundefined. The field should be removed here to keep the type accurate.
Reviews (1): Last reviewed commit: "feat: implement DISC-01 compact/full sea..." | Re-trigger Greptile
|
Updated in b549be4: I fixed the stale guard and removed hints.consumers. I left the compact-memory threshold unchanged on purpose and recorded that recall tradeoff as Phase 8 technical debt in .planning/phases/08-tighten-search-contract/08-VERIFICATION.md. |
Summary
search_codebase(DISC-01): compact is now the default, capped at 6 results with light graph context (importedByCount,topExports,layer), top-levelbudget/patternSummary/bestExample/nextHops, and strongly-relevant memories only. Full mode preserves the previous response shape plus addsbudget.hints.consumersfield (was identical tohints.callers).relevanceReasonin results (both modes) - previously computed but never returned.tests/multi-project-routing.test.tsthat were not updated whenrenderMapMarkdownheader changed.Tests
tests/search-compact-mode.test.ts(8 tests) - modes, graph context, memory gating, budget, consumers removaltests/search-safe-01.test.ts(6 tests) - low-confidence, fresh, aging, stale, explore, propagationpnpm tsc --noEmit: 0 errorsFiles changed
src/tools/search-codebase.ts- two-mode fork, new helpers, memory filter, graph data wiringsrc/preflight/evidence-lock.ts-indexFreshnessparameter with stale/aging gatessrc/tools/types.ts-abstain?: booleanadded to DecisionCardtests/search-compact-mode.test.ts- newtests/search-safe-01.test.ts- newtests/search-decision-card.test.ts,tests/search-snippets.test.ts- regression fixes (mode: 'full' added to snippet tests)tests/multi-project-routing.test.ts- Phase 7 test fix (map header assertion)