Skip to content

feat(results): no-force-push results sync (auto-merge loop)#1506

Merged
christso merged 4 commits into
mainfrom
feat/av-raf-no-force-push-results-sync
Jun 24, 2026
Merged

feat(results): no-force-push results sync (auto-merge loop)#1506
christso merged 4 commits into
mainfrom
feat/av-raf-no-force-push-results-sync

Conversation

@christso

Copy link
Copy Markdown
Collaborator

Summary

Implements Phase 0 + Phase 1 of the conflict-free results sync design
(docs/plans/2026-06-24-001-feat-conflict-free-results-sync-plan.md),
making results-branch sync never force-push. The backup_and_force_push
escape hatch is replaced by an artifact-aware auto-merge push loop.

Beads: av-raf.1 (Phase 0), av-raf.2 (Phase 1).

Phase 0 — artifact-aware merge drivers (av-raf.1)

  • Adds a tiny, dependency-free agentv-json 3-way JSON merge driver
    (set/field union; tag add/remove are commutative; regenerable bookkeeping
    scalars take max; a genuine scalar conflict exits non-zero).
  • Registers the driver in the AgentV-owned results checkout's local git
    config (never global) and materializes the script under the checkout's git dir.
  • Maps merge attributes via a committed .gitattributes
    (index.jsonl merge=union, metadata/runs/**/*.json merge=agentv-json) for
    portability and mirrors them into repo-local info/attributes so local
    merges apply the drivers even on branches predating .gitattributes and in the
    detached merge-tree path.

Phase 1 — fetch → merge → push loop, no force (av-raf.2)

  • Rewrites resolveResultBranchPushConflict() as a bounded optimistic loop:
    fast-forward when possible; otherwise commit a real 3-way merge (working-tree
    git merge on a checked-out branch, merge-tree + update-ref on a detached
    storage branch) and FF the canonical branch onto it; retry benign push races.
  • A genuine conflict aborts the merge and returns a distinct needs_human_merge
    blocked outcome whose block_reason never tells users to enable force push.
    The temp-branch + PR resolution flow is Phase 2 (av-raf.3) — out of scope.
  • No force push, ever. No backup ref, ever.

backup_and_force_push handling — DEPRECATED (not removed)

It is referenced by shipped surfaces (CLI remote.ts, dashboard, projects.ts,
config loader/validator), so per product-boundary §6 it is deprecated rather
than hard-removed
: the config key still validates for back-compat, but it now
auto-merges (no force) and emits a one-time deprecation notice. The dashboard
no longer recommends opting into it.

Verification (red → green)

  • bun run verify (build + typecheck + lint + test): green.
  • Targeted: packages/core/test/evaluation/results-repo.test.ts — 58 pass / 0 fail.
  • Full suite: core 1983, sdk 88, cli 700, dashboard 123 — 0 fail.
  • New/updated tests cover: FF push without force; disjoint diverged auto-merge
    (real merge commit) + push; append-only index union; overlay tag union via
    agentv-json; genuine overlay scalar conflict → needs_human_merge (remote
    unchanged); benign push race retry; assertions that no agentv/backups/* ref is
    created and the previous remote tip stays an ancestor (no rewrite).
  • Heavy agent-provider evals were not run.

Deferred scope

  • Phase 2 (av-raf.3): temp-branch + GitHub PR auto-resolution of needs_human_merge.
  • Phase 3: dashboard UX for driving that human-merge flow.

christso and others added 3 commits June 24, 2026 16:25
… loop

Phase 0 (av-raf.1): register a tiny dependency-free `agentv-json` 3-way JSON
merge driver and mirror union/agentv-json merge attributes into the AgentV-owned
results checkout (committed `.gitattributes` for portability plus repo-local
`info/attributes` so local merges always apply the drivers). Append-only run
indexes union-merge; editable tag/feedback overlays set/field-union, and a
genuine scalar conflict falls through to a human merge.

Phase 1 (av-raf.2): rewrite resolveResultBranchPushConflict as a bounded
fetch -> merge -> push loop. Fast-forward when possible, otherwise commit a real
3-way merge (working-tree merge on a checked-out branch, merge-tree+update-ref on
a detached storage branch) and fast-forward the canonical branch onto it; retry
benign push races. A genuine conflict aborts the merge and returns a distinct
`needs_human_merge` blocked outcome. Never force-pushes and never creates a
backup ref. `push_conflict_policy: backup_and_force_push` is deprecated: it is
kept for config back-compat but now auto-merges (no force) and warns once.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Replace the force-push/backup-conflict tests with auto-merge coverage over temp
local git remotes: disjoint diverged pushes produce a real merge commit and FF
the remote (no force, no backup ref); concurrent run-index appends union-merge;
overlay tag additions from both sides merge via the agentv-json driver; a genuine
overlay scalar conflict returns needs_human_merge with the remote unchanged; a
benign push race (remote advanced between fetch and push) retries and succeeds.
Assert the previous remote tip stays an ancestor and no agentv/backups ref is
ever created.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Add the needs_human_merge sync state to the dashboard status types and view, and
stop recommending backup_and_force_push in push-conflict next actions now that
results sync auto-merges and never force-pushes. The needs_human_merge view points
users to a GitHub pull request instead.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Jun 24, 2026

Copy link
Copy Markdown

Deploying agentv with  Cloudflare Pages  Cloudflare Pages

Latest commit: d904ca2
Status: ✅  Deploy successful!
Preview URL: https://a39b2d8d.agentv.pages.dev
Branch Preview URL: https://feat-av-raf-no-force-push-re.agentv.pages.dev

View logs

…currency guard

The agentv-json driver carried tag_revision forward as max() of the two
sides' hashes. Because tag_revision is a content-derived optimistic-
concurrency token, a stale client holding the surviving hash could pass
assertExpectedTagRevision and silently overwrite the merged tag union.
Drop tag_revision during a real merge so the reader recomputes a token
matching the merged content; updated_at (display-only) still regenerates.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@christso christso marked this pull request as ready for review June 24, 2026 23:47
@christso christso merged commit ad87d26 into main Jun 24, 2026
8 checks passed
@christso christso deleted the feat/av-raf-no-force-push-results-sync branch June 24, 2026 23:49
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