From 4532903c16c499142e91c8ae5cdc2284d0f76021 Mon Sep 17 00:00:00 2001 From: Luke Curley Date: Tue, 27 Oct 2026 22:32:12 -0700 Subject: [PATCH 1/3] chore(quest): claim quest/m1/resolve-tuning.md Quest-Claim: 4b9caed036295fe5 From e5fce68f1a5faeb40bd52048dbb85022d9976983 Mon Sep 17 00:00:00 2001 From: Luke Curley Date: Tue, 27 Oct 2026 22:51:28 -0700 Subject: [PATCH 2/3] Preserve Git merge driver marker metadata --- README.md | 11 ++++ quest/m1/resolve-tuning.md | 28 ++++++---- src/cli/main.ts | 10 ++-- src/cli/resolve.ts | 36 +++++++++---- src/core/merge.ts | 18 +++---- test/resolve.test.ts | 106 +++++++++++++++++++++++++++++++++---- 6 files changed, 169 insertions(+), 40 deletions(-) diff --git a/README.md b/README.md index 14f60cc8..ee2c05bc 100644 --- a/README.md +++ b/README.md @@ -268,6 +268,17 @@ command registers the driver in a fresh clone or worktree whose falls back to `git merge-file`, and GitHub's merges ignore drivers, so a PR shows as conflicting until a local merge from its base is pushed. +The registered driver passes Git's conflict marker length and revision labels +to `quest resolve`, including the ancestor label for `diff3` conflicts. A direct +invocation defaults to seven-character markers and `ours`/`base`/`theirs`; +`--marker-size`, `--ours-label`, `--base-label`, and `--theirs-label` override +them. Labels must fit on one line. The fallback carries the same Git metadata +when `quest` is missing or too old to accept those options. + +Existing configured drivers are preserved. For a checkout still using the old +quest-generated command, clear its local `merge.quest.driver` entry and run any +quest command to register the current one. + ## Wait for pull request activity `quest wait` blocks until a GitHub PR has a review, comment, review-thread diff --git a/quest/m1/resolve-tuning.md b/quest/m1/resolve-tuning.md index 9145d17f..b2bdb702 100644 --- a/quest/m1/resolve-tuning.md +++ b/quest/m1/resolve-tuning.md @@ -2,9 +2,8 @@ ## Goal -The `quest resolve` merge driver's real effect is measured on moq-dev/moq's -merge history, and its unresolved conflict markers match git's own labels -and marker size. +The `quest resolve` merge driver's real effect is measured on an agreed, +reproducible corpus of moq-dev/moq's merge history. ## Plan @@ -12,9 +11,20 @@ Decided 2026-10-24 (user) as follow-ups of [kixelated/quest#219](https://github.com/kixelated/quest/pull/219), ranked after launch: -- **Replay.** Rerun the plan's replay of 280 merges of `main` into PR - branches in moq-dev/moq through the driver, and record how many of the 29 - quest-only conflicts it resolves and which shapes still conflict. -- **Marker labels.** Register the driver with git's `%L`, `%X`, and `%Y` and - pass them to `git merge-file`, so markers carry git's branch labels and - marker size. +- **Replay decision.** The original plan records 280 merges (128 conflicted, + 29 quest-only) but no merge SHA list or ref snapshot. Supply that corpus, + or accept the explicitly proposed replacement measured in + [kixelated/quest#256](https://github.com/kixelated/quest/pull/256). + Do not describe the replacement as a replay of the original 280. + +Checkpoint in that PR: marker labels and size are implemented, including the +ancestor label and native fallback. A proposed replacement selects two-parent +merges reachable from the recorded local heads, committed from +2026-09-23T00:00:00-07:00 through 2026-10-23T09:11:00-07:00, whose second +parent is on the first-parent chain of main snapshot +`bea4214598a6b3b2419dd59ce7f8ea44837ca3f8`. Its full merge SHA list is retained +in the PR. Of 1,108 merges, 642 conflict natively and 220 conflict only in +`quest/`; the driver resolves 111 of those 220 and leaves 109. Remaining +conflicts include prose edits and structural Git conflicts. These counts +measure mechanical conflict resolution, not the semantic correctness of +historical manual resolutions. No replacement corpus has been accepted yet. diff --git a/src/cli/main.ts b/src/cli/main.ts index d32e46b4..3b97b1bb 100644 --- a/src/cli/main.ts +++ b/src/cli/main.ts @@ -36,7 +36,7 @@ import { type Hold, type State, finish, land, release, take } from "./hold"; import { LAND_CHECK, checkQueue, parsePlan, parseResult, pushQueue, resolveQueue } from "./land"; import { landed } from "./landed"; import { type Report, moveQuest, removeQuest } from "./move"; -import { resolveFile } from "./resolve"; +import { type ResolveOptions, resolveFile } from "./resolve"; import { heal, init, uninstall } from "./setup"; import { Refusal, describe, notUpstream, releaseQuest, startQuest } from "./start"; import { GUIDE, SKILLS, skill } from "./skills"; @@ -947,8 +947,12 @@ export function main(argv: string[], out: Output): number | Promise { .argument("", "Our version, overwritten with the result (git's %A)") .argument("", "The common ancestor (git's %O)") .argument("", "Their version (git's %B)") - .action((ours: string, base: string, theirs: string) => { - if (resolveFile(ours, base, theirs) > 0) code = 1; + .option("--marker-size ", "Conflict marker length (git's %L; default: 7)", positiveInteger("marker-size")) + .option("--ours-label