Skip to content

feat(phase5): contested status for close-call conflict resolution#166

Open
salishforge wants to merge 1 commit into
feat/phase5-bootstrapfrom
feat/phase5-contested-conflicts
Open

feat(phase5): contested status for close-call conflict resolution#166
salishforge wants to merge 1 commit into
feat/phase5-bootstrapfrom
feat/phase5-contested-conflicts

Conversation

@salishforge

Copy link
Copy Markdown
Owner

Summary

The final Phase 5 slice — the Feature 1 remnant that never landed with #137. Stacked on #165#164#163#160.

Phase 2.5 conflict resolution now refuses to pick a winner on noise: a score gap of at most one point between two live memories marks both contested (no winner, no loser penalty). Three deliberate departures from the umbrella reference, all driven by the adversarial review:

  1. Absolute delta, not a 20% ratio — ratios invert on small quantized scores (pure-noise 1-vs-0 reads as 100% decisive; well-evidenced 6-vs-5 reads as contested) and are distorted by the mutual +100 supersession offset.
  2. Superseded rows never contest — supersession is absolute; contesting two stale facts would resurface them as live disputes.
  3. Contested is not terminal — Phase 5.12 promotes corroborated contested rows (same evidence bar as provisional/inferred), and a decisive re-resolution clears the winner's badge to provisional. Without these exits, this diff would have shipped the exact terminal-status trap feat(phase5): cross-agent transfer learning bootstrap (v3.12) #165 fixed for inferred (the review caught it as a high-severity finding: this diff is the codebase's first-ever writer of contested).

Review process

Two-lens adversarial review workflow (8 agents): 6 raw findings → 6 confirmed (0 rejected — an unusually accurate review), all fixed, including two test-design flaws (a wall-clock-dependent pinned date, and a degenerate close-call fixture that separate-INSERT now() drift would have scored 1-vs-3 anyway).

Test evidence

Suite Result
npm run type-check / npm run lint clean
tests/contested-conflicts.test.ts (new) 9/9
npm run test:epistemic-confidence (2 tests updated to pin the new promotion behavior) 31/31
npm run test:multi-device 14/14
npm run test:integration 24/24

🤖 Generated with Claude Code

https://claude.ai/code/session_011xCqQo49d3CEbn6oEvb3Ru

The final Phase 5 slice — the Feature 1 remnant that never landed with
PR #137. Phase 2.5 conflict resolution stops encoding noise as fact.

- When the multi-factor score gap between two conflicting live memories
  is at most one point (one factor's worth of noise on the quantized
  integer scale), both are marked epistemic_status='contested' and the
  conflict resolves with a contested(...) strategy and no winner. The
  umbrella used a relative 20% threshold, which inverts on small
  integer scores (pure-noise 1-vs-0 reads as decisive, well-evidenced
  6-vs-5 as contested) and is distorted by the mutual +100 supersession
  offset — the absolute delta is immune to both.
- Superseded rows never contest: supersession is an absolute signal,
  and marking stale facts contested would resurface them as live
  disputes.
- Contested is not terminal (the trap this same stack fixed for
  'inferred'): Phase 5.12 promotes contested rows that earn the
  corroboration bar, and a decisive re-resolution of the dispute clears
  the winner's badge back to provisional.
- tests/contested-conflicts.test.ts: 9 tests — close-call semantics,
  the exact one-vs-two-point boundary, winner/loser path preservation
  incl. untouched winner confidence, both-superseded decisiveness,
  contested recovery via decisive re-resolution. Conflict pairs share
  an identical relative timestamp (separate INSERTs see different
  now(), silently handing one side the +3 recency factor).
- tests/epistemic-confidence.test.ts: the promotion tests now pin the
  new behavior (corroborated contested rows promote; uncorroborated
  ones stay).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011xCqQo49d3CEbn6oEvb3Ru
@salishforge

Copy link
Copy Markdown
Owner Author

CI status: all 11 checks fail in ~5-30s with an npm ci ERESOLVE inherited from main — typescript@^7.0.2 (bumped in #154) conflicts with every published @typescript-eslint release (peer cap <6.1.0). Nothing in this PR's diff is implicated; main's own CI has been red since that bump.

Fix: #167 pins typescript ~6.0.3 (verified npm ci + type-check + lint + build locally). Once it merges I'll cascade main into the stack branches (#160#163#164#165#166) so CI reruns green here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant