ADR-021: semantic-correctness layer lands in pathway_memory (A+B+C)
lakehouse/auditor 4 blocking issues: todo!() macro call in tests/real-world/scrum_master_pipeline.ts

Phase A — data model (vectord/src/pathway_memory.rs):
  + SemanticFlag enum (9 variants: UnitMismatch, TypeConfusion,
    NullableConfusion, OffByOne, StaleReference, PseudoImpl, DeadCode,
    WarningNoise, BoundaryViolation) as #[serde(tag = "kind")]
  + TypeHint { source, symbol, type_repr }
  + BugFingerprint { flag, pattern_key, example, occurrences }
  + PathwayTrace gains semantic_flags, type_hints_used, bug_fingerprints
    all #[serde(default)] for back-compat deserialization of pre-ADR-021
    traces on disk
  + build_pathway_vec now tokenizes flag:{variant} + bug:{flag}:{key}
    so traces with different bug histories cluster separately in the
    similarity gate (proven by pathway_vec_differs_when_bug_fingerprint_added
    test)

Phase B — producer (scrum_master_pipeline.ts):
  + Prompt addendum: each finding must carry `**Flag: <CATEGORY>**` tag
    alongside the existing Confidence: NN% tag. 9 category choices plus
    `None` for improvements that aren't bug-shaped.
  + Parser extracts tagged flags from reviewer markdown; falls back to
    bare-word match if reviewer omits the label. Deduplicated per trace.
  + PathwayTracePayload gains semantic_flags / type_hints_used /
    bug_fingerprints fields. Wire format matches Rust serde tagged enum
    so TS and Rust interop directly.

Phase C — pre-review enrichment:
  + new `/vectors/pathway/bug_fingerprints` endpoint aggregates
    occurrences by (flag, pattern_key) across traces sharing a narrow
    fingerprint, sorts by frequency, returns top-K.
  + scrum calls it before the ladder and prepends a PATHWAY MEMORY
    preamble to the reviewer prompt ("these patterns appeared N times
    on this file area before — check for recurrences"). Empty on
    fresh install; grows as the matrix index learns.

Tests: 27 pathway_memory tests green (was 18). New tests:
  - pathway_trace_deserializes_without_new_fields_backcompat
  - semantic_flag_serializes_as_tagged_enum
  - bug_fingerprint_roundtrips_through_serde
  - pathway_vec_differs_when_bug_fingerprint_added
  - semantic_flag_discriminates_by_variant
  - bug_fingerprints_aggregate_by_pattern_key (sums occurrences, sorts desc)
  - bug_fingerprints_empty_for_unseen_fingerprint
  - bug_fingerprints_respects_limit
  - insert_preserves_semantic_fields (roundtrip via persist + reload)

Workspace warnings unchanged at 11.

What's still queued (not this commit):
  - type_hints_used population from catalogd column types + Arrow schema
  - bug_fingerprint extraction from reviewer output (Phase D — for now
    semantic_flags populate but the fingerprint key requires parsing
    code-shape from the finding; next iteration's work)
  - auditor → pathway audit_consensus update wire (explicit-fail gate)

Why this commit matters: the mechanical applier's gates are syntactic
(warning count, patch size, rationale-token alignment). The
queryd/delta.rs base_rows bug (86901f8) was found by human reading —
unit mismatch between row counts and file counts. At 100 bugs this
deep, humans can't catch them all; the matrix index has to learn the
shapes. This commit gives it the fields to learn into and the surface
to read from.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
root
2026-04-24 05:49:10 -05:00
co-authored by Claude Opus 4.7
parent 92df0e930a
commit 0a0843b605
3 changed files with 475 additions and 4 deletions
+26
View File
@@ -151,6 +151,8 @@ pub fn router(state: VectorState) -> Router {
.route("/pathway/query", post(pathway_query))
.route("/pathway/record_replay", post(pathway_record_replay))
.route("/pathway/stats", get(pathway_stats))
// ADR-021 Phase C: pre-review bug-fingerprint retrieval.
.route("/pathway/bug_fingerprints", post(pathway_bug_fingerprints))
.with_state(state)
}
@@ -2914,6 +2916,30 @@ async fn pathway_stats(State(state): State<VectorState>) -> impl IntoResponse {
Json(state.pathway_memory.stats().await)
}
#[derive(Deserialize)]
struct PathwayBugFingerprintsRequest {
task_class: String,
file_path: String,
signal_class: Option<String>,
limit: Option<usize>,
}
async fn pathway_bug_fingerprints(
State(state): State<VectorState>,
Json(req): Json<PathwayBugFingerprintsRequest>,
) -> impl IntoResponse {
let fps = state
.pathway_memory
.bug_fingerprints_for(
&req.task_class,
&req.file_path,
req.signal_class.as_deref(),
req.limit.unwrap_or(5),
)
.await;
Json(json!({ "fingerprints": fps }))
}
#[cfg(test)]
mod extractor_tests {
use super::*;