feat: conflict resolution + remote-contribution review queue (#11) #67

Merged
claude-bot merged 3 commits from feat/v7-conflict-review-queue into main 2026-06-30 02:04:19 +00:00
Contributor

Closes #11 — the final slice of v7 host-inbound-first.

Conflict gate (optimistic lock)

Remote updates now compare the local entry's updated_at to the activity's published timestamp (threaded through from the inbox). If the local copy changed more recently, the update is held back as a conflict instead of overwriting. Non-conflicting updates still apply automatically (last-write-wins) — matching the milestone's "auto-apply, review only conflicts" decision.

Review queue (owner only)

  • GET /api/contributions?project_id=&status=conflict — lists contributions with the proposed payload beside the current entry content + the actor's display name.
  • POST /api/contributions/:id/resolve { action: 'apply' | 'reject' } — apply forces the remote version over the local entry (re-sanitized, re-embedded, audited); reject discards it. Already-resolved → 409; non-owner → 403.
  • UI: an owner-only "Remote edit conflicts" panel on the project page showing current vs. proposed with Apply remote / Keep mine.

This is the minimal queue the milestone calls for; v8's moderation layer will later generalize it (the remote_contributions table is the shared substrate).

Verification (dev server)

remoteContributionReview.test.ts7 tests: stale update → conflict (entry untouched); future-dated update → applied; queue lists conflicts with payload+current; resolve(apply) overwrites; resolve(reject) leaves local; double-resolve → 409; non-owner → 403.

Full API suite 203 passed (was 196); app npm run build green.

🤖 Generated with Claude Code

Closes #11 — the final slice of v7 host-inbound-first. ## Conflict gate (optimistic lock) Remote updates now compare the local entry's `updated_at` to the activity's `published` timestamp (threaded through from the inbox). If the local copy changed more recently, the update is **held back as a `conflict`** instead of overwriting. Non-conflicting updates still apply automatically (last-write-wins) — matching the milestone's "auto-apply, review only conflicts" decision. ## Review queue (owner only) - `GET /api/contributions?project_id=&status=conflict` — lists contributions with the **proposed payload beside the current entry content** + the actor's display name. - `POST /api/contributions/:id/resolve` `{ action: 'apply' | 'reject' }` — apply forces the remote version over the local entry (re-sanitized, re-embedded, audited); reject discards it. Already-resolved → `409`; non-owner → `403`. - **UI:** an owner-only "Remote edit conflicts" panel on the project page showing current vs. proposed with *Apply remote* / *Keep mine*. This is the minimal queue the milestone calls for; v8's moderation layer will later generalize it (the `remote_contributions` table is the shared substrate). ## Verification (dev server) `remoteContributionReview.test.ts` — **7 tests**: stale update → conflict (entry untouched); future-dated update → applied; queue lists conflicts with payload+current; resolve(apply) overwrites; resolve(reject) leaves local; double-resolve → `409`; non-owner → `403`. Full API suite **203 passed** (was 196); app `npm run build` green. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
- Optimistic lock on remote updates: if the local entry's updated_at is
  newer than the activity's published timestamp, the update is queued as a
  'conflict' instead of overwriting (last-write-wins otherwise). The inbox
  now passes the activity's published timestamp through.
- Review queue API (routes/contributions.ts, owner only):
  GET /api/contributions?project_id=&status= lists contributions (with the
  proposed payload + current entry content); POST /api/contributions/:id/resolve
  {apply|reject} forces the remote version over the local entry or discards it.
- ProjectDetailPage: an owner-only "Remote edit conflicts" panel showing
  current vs proposed content with Apply remote / Keep mine.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
docs(p11): changelog for conflict review queue (#11)
Some checks failed
CI / App — typecheck, test & build (push) Successful in 1m39s
CI / API — typecheck & tests (push) Failing after 2m44s
83c4e71c7e
test(p11): cache the remote actor so the queue surfaces its display name
All checks were successful
CI / App — typecheck, test & build (push) Successful in 1m52s
CI / API — typecheck & tests (push) Successful in 3m32s
CI / App — typecheck, test & build (pull_request) Successful in 2m32s
CI / API — typecheck & tests (pull_request) Successful in 3m54s
744b465c07
claude-bot scheduled this pull request to auto merge when all checks succeed 2026-06-30 01:59:25 +00:00
claude-bot deleted branch feat/v7-conflict-review-queue 2026-06-30 02:04:19 +00:00
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
rbrooks/TeaLeaves!67
No description provided.