Skip to content

Resolve Azure field conflicts only at reviewed revisions - #41

Merged
unbraind merged 9 commits into
mainfrom
feat/conflict-resolution-plans
Oct 23, 2026
Merged

unbraind merged 9 commits into
mainfrom
feat/conflict-resolution-plans

Conversation

@unbraind

@unbraind unbraind commented Oct 23, 2026 •

Copy link
Copy Markdown
Owner

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 finding Fix and regression evidence
PATCH before a durable local recovery point Intent/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 --save Version 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.

@greptile-apps greptile-apps Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Your trial has ended. Reactivate Greptile to resume code reviews.

@coderabbitai

coderabbitai Bot commented Oct 23, 2026 •

Copy link
Copy Markdown

Important

  • 🔍 Trigger review

This repository does not receive automatic reviews because it has fewer than 10 stars.

⚙️ Run configuration
  • Source mode: Auto
  • Repository: Unavailable
  • Branch: Unavailable
  • File: No configuration file from this repository applied
  • Commit: Unavailable
  • Layers: Organization UI
  • Review profile: ASSERTIVE
  • Plan: Advanced
  • Run ID: 15e9f52b-f647-4874-988f-ca06ffc51d89
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@sourcery-ai

sourcery-ai Bot commented Oct 23, 2026

Copy link
Copy Markdown

Sorry @unbraind, you've used your own review budget of 250,000 diff characters for the last 7 days.

You can request another review in 1 day and 1 hour by commenting @sourcery-ai review. Upgrade to get a review now.

@sourcery-ai

sourcery-ai Bot commented Oct 23, 2026

Copy link
Copy Markdown

Reviewer's Guide

This PR introduces revision-bound Azure field conflict resolution through portable typed plans, explicit choices, fenced audited application, and immutable idempotent receipts, integrates it into the non-git CLI/SDK workflow, updates synchronization helpers and dependency floors, and adds extensive synthetic acceptance coverage and documentation.

Sequence diagram for revision-bound Azure conflict resolution

sequenceDiagram
    actor Agent
    participant CLI as ado CLI
    participant Service as AdoResolutionService
    participant PM as Core SDK
    participant Azure as Azure REST API

    Agent->>CLI: ado resolve-plan --item id
    CLI->>Service: plan(id)
    Service->>PM: listAllComplete()
    Service->>PM: readLocatedItem()
    Service->>Azure: getWorkItems()
    Azure-->>Service: hydrated item and revision
    Service-->>CLI: ResolutionPlan with field digests
    CLI-->>Agent: review choices
    Agent->>CLI: ado resolve-apply --artifact file
    CLI->>Service: apply(plan)
    Service->>PM: validateResolutionPlan()
    Service->>PM: mutateItemWithHistoryContext()
    PM->>Service: read local document and history
    Service->>Azure: getWorkItems()
    Azure-->>Service: current revision and snapshot
    Service->>PM: previewItemMutations()
    Service->>Azure: updateWorkItem(id, expectedRevision, fields)
    Azure-->>Service: updated item
    Service->>PM: record receipt and immutable history
    Service-->>CLI: ResolutionReceipt
Loading

Entity relationship diagram for resolution artifacts and receipts

erDiagram
    CORE_PLAN {
        string plan_id PK
        string resolution_artifact_body
    }
    RESOLUTION_PLAN {
        string schema
        string local_revision
        int remote_revision
        string remote_digest
        string mapping_digest
    }
    RESOLUTION_FIELD {
        string field
        string base_digest
        string local_digest
        string remote_digest
        boolean conflict
    }
    RESOLUTION_CHOICE {
        string field
        string take
    }
    RESOLUTION_RECEIPT {
        string decision PK
        string pm_id
        boolean replayed
    }
    CORE_PLAN ||--|| RESOLUTION_PLAN : stores
    RESOLUTION_PLAN ||--|{ RESOLUTION_FIELD : contains
    RESOLUTION_PLAN ||--o{ RESOLUTION_CHOICE : has
    RESOLUTION_PLAN ||--o| RESOLUTION_RECEIPT : produces
Loading

State diagram for an Azure resolution plan

stateDiagram-v2
    [*] --> Planned: plan(id)
    Planned --> Reviewed: add explicit local/remote choices
    Reviewed --> Refused: invalid choices
    Reviewed --> Refused: local digest changed
    Reviewed --> Refused: Azure revision or snapshot changed
    Reviewed --> Applying: apply(plan)
    Applying --> Applied: revision checks pass and PATCH succeeds
    Applied --> Replayed: same decision receipt found
    Replayed --> [*]
    Applied --> [*]
    Refused --> [*]: generate fresh plan
Loading

File-Level Changes

Change Details Files
Adds revision-bound Azure conflict planning and application with typed, portable decision contracts.
  • Introduces eight-field digest plans containing local document, Azure revision/snapshot, scope, mapping, and explicit local/remote choices.
  • Validates plans and choices before writes, refusing missing, duplicate, unknown, edited, stale, or out-of-scope decisions with stable remedies.
  • Applies through complete SDK reads, the existing three-way projections, staged local mutation validation, an audited fenced lease, and Azure test/revision PATCHes.
  • Persists idempotent decision receipts in item metadata and immutable history so immediate and older replays avoid PATCHes and new history events.
  • Exposes SDK service, plan/choice/receipt/refusal types, digest helpers, and CLI commands for portable JSON or ordinary core Plan storage.
resolution.ts
index.ts
sync.ts
dist/resolution.js
dist/resolution.d.ts
dist/index.js
dist/index.d.ts
Extends the CLI and package integration for non-git conflict resolution workflows.
  • Registers ado resolve-plan and ado resolve-apply with artifact and saved-Plan modes.
  • Raises the SDK peer, manifest, and development dependency floor to 2026.10.23 for expired-lease fencing.
  • Adds the resolution receipt metadata field and updates package exports, lockfile, generated distributions, and publish contents.
  • Documents plan review, refusal remedies, lease boundaries, replay behavior, scalar-only scope, and cross-system recovery.
README.md
docs/conflict-resolution.md
docs/sync.md
manifest.json
package.json
package-lock.json
CHANGELOG.md
dist/index.js
dist/index.d.ts
dist/index.js.map
dist/index.d.ts.map
Aligns existing synchronization conflict detection and exported helpers with revision-bound resolution.
  • Exports canonical value, base-reading, field projection, mutation, and three-way conflict helpers for reuse.
  • Treats one-sided or base-less divergent fields as requiring explicit resolution while preserving existing import/export behavior.
  • Keeps lifecycle transitions, assignee clearing, state aliases, and graph relation handling compatible with existing sync semantics.
sync.ts
dist/sync.js
dist/sync.d.ts
dist/sync.js.map
Adds broad fixture-backed acceptance coverage for stale-writer safety, validation, replay, CLI output, lifecycle behavior, and offline corpus measurement.
  • Tests local comments and Azure revision changes refusing before writes, REST revision races, malformed choices, scope changes, and edited digests.
  • Verifies successful local/remote decisions, idempotent immediate and historical replay, unchanged tracker bytes, and zero redundant PATCHes.
  • Covers core Plan persistence, portable artifacts, JSON/TOON output without git, typed refusal remedies, state aliases, assignees, terminal/reopen lifecycle, and failure sanitization.
  • Adds synthetic Azure REST 7.1 revision fixtures and a public-tracker corpus measurement script with source-fingerprint protection.
test/sync.test.ts
test/fixtures/resolutions/README.md
test/fixtures/resolutions/revision-2.json
scripts/validate-resolution-corpus.ts
Updates PM delivery and history artifacts to record the feature and related closeouts.
  • Adds feature delivery and history records.
  • Adds the issue ownership receipt and moves selected changelog entries into a Closed section without rewriting closeout history.
.agents/pm/features/pm-ado-4x3u.toon
.agents/pm/history/pm-ado-4x3u.jsonl
.agents/pm/history/pm-ado-github-5532dc4b9a65-33.jsonl
.agents/pm/issues/pm-ado-github-5532dc4b9a65-33.toon
CHANGELOG.md

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@greptile-apps greptile-apps Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Your trial has ended. Reactivate Greptile to resume code reviews.

@greptile-apps greptile-apps Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Your trial has ended. Reactivate Greptile to resume code reviews.

@greptile-apps greptile-apps Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Your trial has ended. Reactivate Greptile to resume code reviews.

@greptile-apps greptile-apps Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Your trial has ended. Reactivate Greptile to resume code reviews.

@unbraind unbraind left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

VERDICT: BLOCK
FINDINGS:

  • [blocking] resolution.ts:252 — Azure is PATCHed before the local commit without compensation — a subsequent lease expiry or tracker write failure leaves Azure changed, pm unchanged, and no successful replay receipt.
  • [blocking] resolution.ts:200 — Plans contain the raw organization URL, which --save persists in the tracked Plan body — configured organization details therefore leak into tracker files and history.
    SUMMARY: The PR adds revision-bound conflict plans, explicit field choices, and replay receipts. Tests cover stale revisions, invalid choices, replay, and non-git usage, but omit post-PATCH local failures and organization-URL privacy assertions; tests were inspected, not executed.

Review by a read-only codex review agent (gpt-6.1-sol), posted by the orchestrator; the PR returns to its author agent for the fixes.

@greptile-apps greptile-apps Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Your trial has ended. Reactivate Greptile to resume code reviews.

@greptile-apps greptile-apps Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Your trial has ended. Reactivate Greptile to resume code reviews.

@greptile-apps greptile-apps Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Your trial has ended. Reactivate Greptile to resume code reviews.

@unbraind unbraind left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Orchestrator review (built-in Claude review agent, verified by the orchestrator; bots are not waited for since 2026-10-22):

VERDICT: MERGE
FINDINGS:

  • none
    SUMMARY: The fixes add durable, fenced resolution recovery and opaque HMAC scope references without persisting credentials in saved plans. Inspected regression tests cover lease expiry, tracker write failure, single-PATCH recovery, revision checks and Plan privacy; I did not rerun them.

Re-review of the fix commits (e12ab27..195f7eb) by a read-only codex review agent (gpt-6.1-sol), posted by the orchestrator. Both earlier blocking findings are resolved: durable intent before the Azure PATCH with fenced settlement on resume (single PATCH, lease-expiry and tracker-write-failure paths tested), and opaque HMAC scope references instead of the organization URL in saved plans. CI npm + bun 215/215, coverage 100%.

@greptile-apps greptile-apps Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Your trial has ended. Reactivate Greptile to resume code reviews.

@unbraind unbraind left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Orchestrator review (built-in Claude review agent, verified by the orchestrator; bots are not waited for since 2026-10-22):

VERDICT: MERGE
FINDINGS:

  • none
    SUMMARY: The fixes add durable, fenced resolution recovery and opaque HMAC scope references without persisting credentials in saved plans. Inspected regression tests cover lease expiry, tracker write failure, single-PATCH recovery, revision checks and Plan privacy; I did not rerun them.

Re-review of the fix commits (e12ab27..195f7eb) by a read-only codex review agent (gpt-6.1-sol), posted by the orchestrator. Both earlier blocking findings are resolved: durable intent before the Azure PATCH with fenced settlement on resume (single PATCH, lease-expiry and tracker-write-failure paths tested), and opaque HMAC scope references instead of the organization URL in saved plans. CI npm + bun 215/215, coverage 100%.

@unbraind
unbraind merged commit 3592ce9 into main Oct 23, 2026
10 of 14 checks passed
@unbraind
unbraind deleted the feat/conflict-resolution-plans branch October 23, 2026 11:04
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