diff --git a/quest/m0/README.md b/quest/m0/README.md index bf047680..934ee4fb 100644 --- a/quest/m0/README.md +++ b/quest/m0/README.md @@ -87,14 +87,16 @@ ownership-manifest design: - [The land fixer resolves every mechanical failure](/quest/m0/land-fixer/README.md) - workflow pushes and the PR's own CI as context - [Reviewer usage limits](/quest/m0/review-quota.md) - `quest review` exits distinctly on a reviewer's quota and prints the reset time - [Drafts in quest waiting](/quest/m0/waiting-drafts.md) - `quest waiting` lists open draft PRs' `## Waiting` items beside the tree's -- [Rejected options in decision records](/quest/m0/decision-records.md) - grill and plan label rejected options so no one reads them as qualifiers +- [Decision records](/quest/m0/decision-records.md) - grill and plan label rejected options, and record a decision in the PR when the PR deletes the quest - [Kix decision UI](/quest/m0/kix/README.md) - planning and implementation through prompts and summaries, run on the maintainer's own runners +- [Per-PR picks in /quest-complete](/quest/m0/complete-per-pr.md) - one question per PR, with no grouped or blanket option offered - [Codex cloud off](/quest/m0/codex-cloud-off.md) - automatic Codex cloud reviews stop once no open PR relies on them - [Bun EFAULT report](/quest/m0/bun-efault.md) - report concurrent `rmSync` `EFAULT` on Windows, and drop the workaround once Bun fixes it - [Codex project-config skip](/quest/m0/codex-project-config.md) - once Codex keeps a supported way to skip a project's `.codex/` layer, reviews keep the user's config - [Gate bench](/quest/m0/gate-bench.md) - measure headroom admission on an idle host - [Agent workflow helpers](/quest/m0/helpers/README.md) - CLI commands for CI waits, PR status, claims, quest moves, and serialized merges - [Worktree hooks here](/quest/m0/worktree-hooks.md) - `quest` reaches Claude Code's hooks and the merge driver in this repository, then `quest init` installs the hooks +- [Wrapped worktree hooks](/quest/m0/wrapped-hooks.md) - `quest init` accepts a hook that runs `… worktree hook` through a wrapper such as `nix run` - [Remote control worktrees](/quest/m0/worktree-routes.md) - live-check `claude remote-control --spawn worktree` against the hooks, from a session spawned on claude.ai - [Session checkouts released](/quest/m0/session-checkouts.md) - a Claude session's own checkout is released when the session ends and reclaimed on resume - [claude rm upstream report](/quest/m0/claude-rm-upstream.md) - waiting on approval: ask Claude Code to run `WorktreeRemove` instead of advising an unlock diff --git a/quest/m0/complete-per-pr.md b/quest/m0/complete-per-pr.md new file mode 100644 index 00000000..a4367064 --- /dev/null +++ b/quest/m0/complete-per-pr.md @@ -0,0 +1,31 @@ +# [XS] /quest-complete never offers a grouped pick + +## Goal + +`/quest-complete` asks one question per PR and offers no option that covers +several PRs at once, such as "merge all 20 landable PRs" or "accept every +recommendation". A blanket answer that the maintainer gives on their own +still counts, as `assets/skills/complete.md` already describes. + +## Plan + +Decided 2026-11-03 (maintainer, /quest-complete on moq-dev/moq): "Ask per +PR. Update quest to always ask per PR." Milestone: m0, ranked right after the +Kix decision UI. moq-dev/moq runs `/quest-complete` every day, and m0's Plan +ranks the land work, then Kix, before the rest of m0. + +The skill already says to ask "with one question per PR, never grouping PRs +into one question". The agent still added a grouped "merge all 20 landable +PRs" option, maybe because the next paragraph describes a blanket answer as +valid. + +Implementation guidance: + +- In `assets/skills/complete.md`, say that no option may name more than one + PR, so no grouped or blanket option appears, and that each question's + options are only that PR's actions. +- Reword the blanket-answer sentence so it applies only to an answer the + maintainer gives on their own, never to an option the agent offers. +- Check the other skills that ask about several PRs, such as + `assets/skills/unblock.md` and `assets/skills/afk.md`, and apply the same + rule where they put PR picks to the user. diff --git a/quest/m0/decision-records.md b/quest/m0/decision-records.md index 95cd859a..463714ef 100644 --- a/quest/m0/decision-records.md +++ b/quest/m0/decision-records.md @@ -1,4 +1,4 @@ -# [XS] Recorded decisions mark the rejected options +# [XS] Decision records that last and mark the rejected options ## Goal @@ -7,6 +7,10 @@ marked and the rejected options labelled as rejected, such as `✅ Yes, as stated (rejected: without the overlap check; drop it)`, so no reader takes a rejected option for a qualifier of the chosen one. +Each record also outlives its quest: a decision goes in the quest's Plan, +or in the PR body's `## Decisions` when that PR deletes the quest, since the +deletion would take the Plan's record with it. + ## Plan Decided 2026-11-02 (user, /quest-spawn follow-ups): ✅ plan as stated @@ -18,3 +22,19 @@ Decided 2026-11-02 (user, /quest-spawn follow-ups): ✅ plan as stated it. - Change the recording instruction in `assets/skills/grill.md` and `assets/skills/plan.md`. Existing records stay as written. + +Decided 2026-11-03 (maintainer, /quest-complete on moq-dev/moq, planned +through moq-dev/moq's coordinator): fold where decisions are recorded into +this quest, since it changes the same recording instructions. It stays in +m0 at its rank. + +- `assets/skills/plan.md` says to record each settled decision "in the + quest's Plan", and `assets/skills/unblock.md` records an answer in the + quest's Plan and then deletes a quest whose only purpose was the wait. + A PR that finishes a quest deletes its file, so a decision made in that + PR has no Plan to live in. +- Suggested wording: "record it in the quest Plan, or in the PR's Decisions + if the PR deletes the quest." Apply it in `plan.md` and `unblock.md`, and + wherever else the guide or a skill sends decisions to a quest's Plan. + `assets/skills/iterate.md` already records decisions in the PR's + description; name the same `## Decisions` section there. diff --git a/quest/m0/land-fixer/README.md b/quest/m0/land-fixer/README.md index dc71728d..05ee54f6 100644 --- a/quest/m0/land-fixer/README.md +++ b/quest/m0/land-fixer/README.md @@ -153,6 +153,8 @@ work, done once the Required quests below have merged. ## Required +- [Leave held PRs alone](/quest/m0/land-fixer/holds.md) - the watcher never fixes, pushes to, or re-enqueues a PR another session holds +- [Run the repository's checks](/quest/m0/land-fixer/checks.md) - the fixer runs the repository's own lint, type, build, and test checks before it requeues - [Workflow permission](/quest/m0/land-fixer/workflows-permission.md) - waits on the maintainer to grant moq-bot `workflows`, so pushes touching workflows are accepted ## Related diff --git a/quest/m0/land-fixer/checks.md b/quest/m0/land-fixer/checks.md new file mode 100644 index 00000000..09dd7232 --- /dev/null +++ b/quest/m0/land-fixer/checks.md @@ -0,0 +1,39 @@ +# [S] The land fixer runs the repository's own checks + +## Goal + +Before the land fixer reports `fixed` or `requeue`, it runs the checks the +repository's own instructions name for the languages its PR and its fix +touch: lint, format, and type checks as well as build and test. On +moq-dev/moq that is `just check` and `just test`, so the JavaScript type +check runs beside the Rust build. A head the fixer re-enqueues therefore +passes what the merge queue's build will run, or goes back as a handback +quoting the failing command. + +## Plan + +Decided 2026-11-03 (maintainer, /quest-complete on moq-dev/moq, planned +through moq-dev/moq's coordinator): plan this follow-up. Milestone: m0, +under the land fixer epic. moq-dev/moq lands through this fixer every day, +and m0's Plan ranks the land work first. + +What happened: on +[moq-dev/moq#6949](https://github.com/moq-dev/moq/pull/6949), the fixer +requeued the PR without running moq's JavaScript check, and the next build +failed on it. `assets/land-fix.md` tells the fixer to "build and test the +packages the PR and your fix touch", which it read as building and testing +only, and it skipped the check that failed. + +Implementation guidance: + +- Rewrite that rule in `assets/land-fix.md`: find the repository's check and + test commands in its root instructions, `CONTRIBUTING.md`, or task runner, + such as `just check` and `just test`; run them over the PR's and the fix's + changes; and name each command run in the reason. When the repository + names no check command, run each touched language's own type check and + linter beside its build and test. +- A `requeue` of an unchanged head runs the same checks, since the base may + have moved under it. +- Keep the existing rule: a check the fixer cannot run, or cannot get + passing mechanically, goes back as a handback quoting the command and its + output. diff --git a/quest/m0/land-fixer/holds.md b/quest/m0/land-fixer/holds.md new file mode 100644 index 00000000..46e951c5 --- /dev/null +++ b/quest/m0/land-fixer/holds.md @@ -0,0 +1,47 @@ +# [S] The land fixer leaves a held PR alone + +## Goal + +`quest land watch` neither runs the fixer on a PR another session holds, nor +pushes a fixer result to it or re-enqueues it. A hold is any hold label +`isHoldLabel` accepts (`src/core/hold.ts`), such as the `quest:active` that +`/quest-iterate` takes, or an older pin's `quest:iterate`. The watcher +checks for a hold before it starts a job and again before it pushes or +re-enqueues. A held PR gets one comment saying the watcher left it to the +session that holds it. + +Non-goals: the frozen batching gate (`quest land serve`), which only +moq-dev/moq.pro still uses until it is +[retired](/quest/m0/queue-watcher/retire.md). + +## Plan + +Decided 2026-11-03 (maintainer, /quest-complete on moq-dev/moq, planned +through moq-dev/moq's coordinator): plan this follow-up. Milestone: m0, +under the land fixer epic. moq-dev/moq lands through this fixer every day, +and m0's Plan ranks the land work first. + +What happened on +[moq-dev/moq#6949](https://github.com/moq-dev/moq/pull/6949): the +maintainer added `quest:iterate` at 2026-11-01 16:41Z for a `/quest-iterate` +session. The fixer still pushed its merge `7c10f33cbc` at 16:52Z, and moq-bot +re-armed `quest:merge` at 16:56Z, while the session was pushing its own +fixes on the same branch. The hold was lifted at 17:22Z. That was the host +gate. `quest land watch`, which replaced the gate on moq-dev/moq, has the +same gap: `src/cli/land-watch.ts` and `src/cli/land-watch-fix.ts` never read +the PR's labels for holds. + +Implementation guidance: + +- Read the hold labels with the snapshot the watcher already takes for each + PR the queue drops, and again right before a result is pushed or the PR is + re-enqueued, so a hold taken while the fixer runs is respected too. +- Open question for the starter: what happens to the pick of a held PR? + Recommended: the hold ends it, as a person's removal from the queue does + (`endPick`). A maintainer enqueues the PR again once its session finishes, + as `/quest-iterate`'s `/quest-merge` hand-off already does. The other + option is to wait and fix it once the hold clears, but by then the session + has usually pushed, and a push by anyone but the fixer already ends the + pick. +- Add a regression test: a PR the queue drops while it holds `quest:active` + is neither fixed nor re-enqueued. diff --git a/quest/m0/wrapped-hooks.md b/quest/m0/wrapped-hooks.md new file mode 100644 index 00000000..57bd248d --- /dev/null +++ b/quest/m0/wrapped-hooks.md @@ -0,0 +1,40 @@ +# [XS] quest init recognizes wrapped worktree hooks + +## Goal + +`quest init` treats any command hook whose arguments end in `worktree hook` +as its own, such as moq-dev/moq's +`nix run "${CLAUDE_PROJECT_DIR}#quest" -- worktree hook`, which runs the +`quest` the repository pins. It needs no configuration. In a repository with +wrapped hooks, `quest init` then succeeds without changing them, and +`quest uninstall` removes them like the plain ones. + +## Plan + +Decided 2026-11-03 (maintainer, moq-dev/moq, planned through moq-dev/moq's +coordinator): + +- How should `quest init` recognize its hook when a repository wraps it? + - ✅ Match any command hook whose arguments end in `worktree hook` + - A configured hook command (rejected) + - No change (rejected) + +Milestone: m0, ranked after [Worktree hooks here](/quest/m0/worktree-hooks.md). +m0 is adoption on moq-dev's own repositories, and moq-dev/moq hits this +today. + +What happens: +[moq-dev/moq#7674](https://github.com/moq-dev/moq/pull/7674) runs moq's hooks +through its flake's pinned `quest`, so agents use the version moq pins. +`isQuestHook` (`src/core/init.ts`) matches only the exact `HOOK_COMMAND`, +`quest worktree hook`. So `quest init` counts the wrapped `WorktreeCreate` +and `WorktreeRemove` hooks as someone else's and refuses to run. The +workaround is to drop the hooks, run init, and restore them. + +Implementation guidance: + +- Widen `isQuestHook` to a command whose last two words are `worktree hook`. + A fresh install still writes the plain `HOOK_COMMAND`. +- `quest uninstall` (`src/cli/setup.ts`) uses the same check, so it removes + wrapped hooks too. Say so in its docs. +- Test a wrapped hook in init, re-init, and uninstall.