fix(continual-learning): harden wasRealCollision verifier (Codex review)

Addresses the P1 brittleness in the Step 3 verifier so learned_from edges
(graph/live.ts:413) can't be silently zeroed on stage.

- Capture overlap AT detection time as Collision.gitOverlap (podman.ts), while
  engineer_states are still fresh, instead of re-deriving from possibly-stale
  state when the user clicks. deriveWasRealCollision() now prefers this stored
  evidence and only falls back to a live re-derivation for older collisions.
- Canonicalize engineer names (trim + lowercase) on both the capture and the
  fallback path, so "Karti" vs "karti" no longer misses the git state.
- conflictKey now reuses the shared comparableBasename() helper (dedupe).

shared/src/collision.ts gains optional `gitOverlap?: boolean` (additive).
shared rebuilt; backend+frontend typecheck + eslint pass. PLAN.md rung 3 updated.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
sb-iam
2026-06-28 07:57:38 -05:00
parent d9776452b2
commit 1901010996
4 changed files with 73 additions and 23 deletions
+12 -7
View File
@@ -510,14 +510,19 @@ no schema change. Owner: RSI track. Independent of the MongoDB-cleanup handoff.
kind), `plan.md:66` (second similar event behaves differently).
3. **Step 3 - derive `wasRealCollision` from git overlap (backend-authoritative)**
- `backend/src/memory/store.ts` `recordOutcome` now overrides the
client-supplied `wasRealCollision` with `deriveWasRealCollision()`: a
collision is real only if BOTH named engineers currently have the collided
file in their git `changedFiles` (`getGitStates`, 120s freshness TTL).
Conservative `false` when orphaned/stale. `frontend/.../useInterventions.ts`
stops sending a hardcoded `true` (now a backend-overridden placeholder).
- Restores the (accepted × wasReal) 2×2 the spec assumes.
- Overlap is captured AT detection time as `Collision.gitOverlap`
(`backend/src/agent/podman.ts`), while `engineer_states` are still fresh —
true only if ALL involved engineers have the collided file in their git
`changedFiles`, matched on case/whitespace-canonical names.
- `backend/src/memory/store.ts` `recordOutcome` overrides the client value
with `deriveWasRealCollision()`, which prefers the stored `gitOverlap`
(immune to late clicks / stale sidecars / the 120s TTL) and only falls back
to a live canonical-name re-derivation for pre-existing collisions.
`frontend/.../useInterventions.ts` stops sending hardcoded `true`.
- Restores the (accepted × wasReal) 2×2 the spec assumes; keeps `learned_from`
edges (`graph/live.ts:413`) from being silently zeroed on stage.
- Spec: `docs/continual-learning/spec.md:98-108`, `policy.md:35-42`.
- Hardened per Codex review (name canonicalization + detection-time capture).
Follow-ups (separate rungs, not in this change): Step 4-5 `strategy_versions` +
Gemini-proposed `LearningProposal` slice; Step 6 durable `owns` write; seed a