Resolve Azure field conflicts only at reviewed revisions

Merged
UN
3d ago
+1905-45

An interrupted resolution could previously PATCH Azure and then lose its local lease or tracker write, leaving no resumable receipt. Saved plans also persisted organization and project configuration. This change makes reviewed conflict decisions resumable and removes identifying scope values from portable/saved artifacts.

ado resolve-plan produces version 2 artifacts with eight field digest rows, explicit choices and an opaque credential-keyed organization/project reference. --save still uses ordinary core Plan storage. Organization URL, project name, token and Basic encoding are absent from Plan bodies and history. Version 1 artifacts refuse rather than silently retaining their raw scope.

ado resolve-apply now performs two audited SDK mutations. Before Azure is called, prepare commits the canonical plan/choice ID, original local revision, Azure revision/digest, exact PATCH and expected post-PATCH revision into the target item's durable intent/history. Settlement holds a fenced item lease, sends the saved PATCH with its leading test /rev and a unique System.History decision marker, then atomically commits the pm fields, successful receipt and intent removal. The pm CLI 2026.10.23 pin supplies expired-lease fencing.

On retry, the same intent plus Azure's expected revision, decision marker and mapped result prove a successful prior PATCH. The adapter completes pm settlement without patching again. If Azure is provably unchanged, the exact saved revision-checked PATCH can be attempted. Changed local context, conflicting intents, unexpected Azure revisions/results and unreadable recovery data return typed ado_partial_apply with the intent coordinate, expected revision and same-plan recovery instructions. No blind rollback or overwrite of a newer Azure revision occurs.

Blocking findingFix and regression evidence
PATCH before a durable local recovery pointIntent/history is committed before REST. Real SDK lease expiry/takeover and real filesystem write failure after PATCH both recover using the same plan with exactly one PATCH. Lost/error responses, local-only recovery, competing writers, changed contexts and altered Azure outcomes are also covered.
Raw scope persisted by --saveVersion 2 stores a keyed opaque reference. The saved Plan body and its entire history are scanned for the configured organization URL, project name, a synthetic PAT-shaped credential and its Basic encoding.

Independent behavioral revert proofs: removing only the durable prepare-field write fails lease recovery 1/1; disabling applied-PATCH recognition fails tracker-write recovery 1/1; replacing only opaque scope generation with raw configuration fails saved Plan/history privacy 1/1. Removing only pending-intent retry classification also fails the real held-lock regression 1/1 (apply_failed instead of ado_partial_apply). All source was restored. Targeted suite and PM-linked run: 18/18, zero skipped. Targeted resolution.ts measurement: 100% V8 lines, branches and functions. Source/test typechecks, 79-declaration docstring lint, changelog generation/check and diff checks pass locally. The saturated host did not run a full local release gate.

The original acceptance remains covered: stale saved local/Azure revisions refuse before prepare writes; invalid or conflicting choices refuse before REST; successful immediate and historical replay add no PATCH or history event. Actual CLI JSON/TOON and core Plan persistence work in non-git trackers with git absent from PATH. Scalar plans preserve the existing relation adapter and legacy-base behavior; revisions-feed reconciliation remains excluded.

Public-data validation uses an unchanged non-git archive of the public unbraind/pm-ado tracker at 1fe0a306e13417115e66de9b48ac2e50deaa25d1: 28 certified items, 224 field comparisons, 28 synthetic conflicts, 28 valid plans and 28 incomplete-choice refusals; version 2 plans average 2,576 JSON bytes. All overlays remain in memory, copied source fingerprints are unchanged, and Azure writes are zero. Azure response fixtures follow Work Item Tracking REST 7.1; their README cites the revision and update APIs. Live Azure permissions and custom process behavior remain unverified because no live credentials were used.

CI evidence for the follow-up head: run 39939836334 passed on exact head 195f7eb3da9d6521b28c43cf9917e6447da4ce07. Both npm run release:check and bun run release:check passed 215/215 tests in each V8 and independent Istanbul run, with zero failures or skips. All seven configured sources measured 100% lines/branches/functions and 1,228/1,228 independently instrumented statements (100%), preserving every threshold. Docstring lint documented 79 declarations across 11 files; production audit reported 0 vulnerabilities. Typechecks, package contents, changelog, publish-attestation and version-date checks passed. Node 22 and Node 26 CI jobs also passed. The existing workflow was dispatched explicitly because automatic synchronization runs were not created for the latest pushes; all evidence is bound to the pushed head above.

PM evidence: pm-ado-4x3u, including both review fixes and all revert proofs. The implementation claim is released; the item is unclosed. Prior issue #33 ownership evidence remains in pm-ado-github-5532dc4b9a65-33: delivery selection is owned by pm-github, not this package's closeout configuration.

No review-thread replies, mentions, merge or package release were performed.

Summary by Sourcery

Implement resumable, revision-bound Azure field conflict resolution with privacy-preserving artifacts and durable recovery state.

New Features:

  • Add ado resolve-plan and ado resolve-apply commands for reviewing and applying explicit Azure field conflict decisions.
  • Provide version 2 portable resolution artifacts and core Plan storage with opaque scope references that exclude organization, project, and credential data.
  • Expose a revision-bound resolution service and typed refusal/receipt APIs for SDK consumers.

Bug Fixes:

  • Make Azure conflict application resumable after leases, PATCH responses, or local tracker writes fail, without blindly repeating successful updates or overwriting newer revisions.
  • Require explicit choices for all differing fields and refuse stale, malformed, conflicting, or altered resolution inputs before unsafe writes.
  • Preserve correct three-way conflict detection and lifecycle metadata while handling scalar resolution decisions.

Enhancements:

  • Persist durable resolution intents before Azure mutations and settle local tracker state atomically with audited receipts and history.
  • Bind decisions to local and Azure revisions, field digests, state mappings, exact PATCHes, and expected post-update revisions.
  • Classify partial-apply recovery failures with stable typed codes and actionable remedies.

Build:

  • Raise the minimum supported pm CLI and peer dependency version to 2026.10.23.
  • Include conflict-resolution documentation and generated resolution artifacts in the package.

CI:

  • Expand regression coverage for conflict planning, replay, lease recovery, write failures, races, privacy, CLI behavior, and concurrent settlement.

Documentation:

  • Document revision-bound conflict resolution, portable artifacts, recovery procedures, privacy guarantees, and non-git usage.

Tests:

  • Add Azure revision fixtures and corpus validation for digest-based plans without performing writes against the public tracker.

Chores:

  • Update changelog and PM tracking artifacts for the released implementation.