Skip to content

feat(cli): adjudicate --apply interactive merge walk (#137, Slice 2b-ii)#165

Merged
jasonssdev merged 1 commit into
mainfrom
feat/adjudicate-apply
Jul 25, 2026
Merged

feat(cli): adjudicate --apply interactive merge walk (#137, Slice 2b-ii)#165
jasonssdev merged 1 commit into
mainfrom
feat/adjudicate-apply

Conversation

@jasonssdev

Copy link
Copy Markdown
Owner

Part of the #139#137 curation-output arc (Slice 2b-ii, final slice). Advances #137.

What

Gives adjudicate a path to action: --apply walks the SAME verdicts and, per eligible group, previews what will fuse then prompts before merging. Reuses the 2b-i prepare_merge/merge_core blocks verbatim — the destructive core is untouched.

Per eligible group: stale-id pre-check → prepare_merge preview → Merge <absorbed> into <survivor>? [y/N/skip]merge_core → per-merge autocommit.

Guardrails (destructive, but reversible via unmerge)

  • Eligible = verdict SAME AND exactly 2 members. DIFFERENT/UNCERTAIN never merge. N>2 SAME groups → skipped (N>2, merge manually).
  • Survivor = member_ids[0] (alphabetical-first), absorbed = member_ids[1].
  • Prompt: only y/yes applies; empty/n/skip/other decline.
  • Stale-id guard: a member absorbed by an earlier merge this run → skipped (member already merged), never crashes.
  • Mid-run failure (prepare_merge or merge_core) stops the run (exit 1); prior per-merge commits remain and are unmerge-reversible.
  • --apply + --json rejected (exit 2, before any read); --apply + --same-only is a no-op.
  • End summary: applied X, skipped Y (N>2 / already-merged / declined).

Scope

  • Additive: non---apply adjudicate (plain / --json / --same-only) is byte-identical. Only adjudicate + tests touched; merge/unmerge/prepare_merge/merge_core unchanged (diff is +142/-0 in main.py).
  • Deferred (still out): guarded unattended batch (--apply-same, no confirm), gated on bug: adjudicate reports a flat 0.95 confidence and marks part-whole pairs as SAME #138 verdict quality; N>2 merging; survivor heuristics beyond alphabetical.

Verification

  • Full suite: 2023 passed (2024 with the added coverage test); ruff/format/mypy clean.
  • Strict TDD, 19 --apply tests incl. accept→merge→ledger, unmerge round-trip, stale-id guard (overlapping groups), each prompt answer, mid-run failure (both prepare_merge and merge_core), --apply --json rejection, summary counts.
  • Independent verify: PASS WITH WARNINGS (0 critical). Bounded risk review: 0 data-loss findings — survivor/absorbed direction confirmed correct (member_ids = tuple(sorted(...))), preview==apply (same prepared object), partial-failure recoverable, destructive core untouched. The one coverage WARNING (prepare_merge failure branch) is now closed by an added test.

Give adjudicate a path to action: --apply walks the SAME verdicts and, per
eligible group, previews what will fuse then prompts before merging. Final slice
(2b-ii) of the #139->#137 arc; reuses the 2b-i prepare_merge/merge_core blocks
verbatim (no change to merge/unmerge or the destructive core).

- eligible = verdict SAME AND exactly 2 members; survivor = member_ids[0]
  (alphabetical-first), absorbed = member_ids[1]
- N>2 SAME groups: skipped (N>2, merge manually)
- per group: stale-id pre-check (_resolve_concept_path) -> prepare_merge preview
  -> prompt 'Merge <absorbed> into <survivor>? [y/N/skip]' (only y/yes applies;
  empty/n/skip/other decline) -> merge_core -> per-merge autocommit
- stale-id guard: a member absorbed by an earlier merge this run is skipped
  (member already merged), never crashes
- mid-run merge_core/prepare_merge failure stops the run (exit 1); prior
  per-merge commits remain and are unmerge-reversible
- --apply + --json rejected (exit 2); --apply + --same-only is a no-op
- end summary: applied X, skipped Y (N>2 / already-merged / declined)

Additive: non---apply adjudicate (plain / --json / --same-only) byte-identical.
Destructive but reversible via unmerge. Only SAME 2-member groups ever merge.

Guarded batch (--apply-same, no confirm) remains deferred, gated on #138.
@jasonssdev
jasonssdev merged commit c733734 into main Jul 25, 2026
6 checks passed
@jasonssdev
jasonssdev deleted the feat/adjudicate-apply branch July 25, 2026 01:21
jasonssdev added a commit that referenced this pull request Jul 25, 2026
Merge the adjudicate --apply delta (12 requirements: interactive merge walk,
eligibility, prompt semantics, stale-id guard, per-merge commit, mid-run failure,
--apply/--json exclusivity, summary) into entity-resolution-adjudication (#139 +
Slice-2a requirements preserved) and move the change folder to archive/.
Implementation shipped in #165. #137 stays open for the deferred batch slice.
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