From 5898d1b1cb1a2328ce5b4044d26705817041f820 Mon Sep 17 00:00:00 2001 From: Victor Garcia Date: Sun, 4 Oct 2026 01:32:25 -0600 Subject: [PATCH] =?UTF-8?q?release(swarm):=200.5.0=20=E2=80=94=20pick=20th?= =?UTF-8?q?e=20winner?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bumps the plugin to 0.5.0 (herdr-plugin.toml and package.json in lockstep) so the suite site can pin and document the new workflow as released rather than as an unreleased development checkout. CHANGELOG: [Unreleased] is split into [0.5.0] — 2026-10-04 (validate, finish detection, compare and merge winner, slot environment, per-slot tasks, broadcast and elapsed time, the conflict resolver and conclude, the harvest-step split, and the previously unlisted strict candidate handoff from #15) and [0.4.0] — 2026-09-14, which is byte-identical to the Unreleased section at the commit the site pinned as 0.4.0 (09dd1f2), where it was never cut. README gains a workflow overview linking each step, the harvest pane's new keys, the 0.7.5+ requirement for the resolver and in-agent slot variables, and drops "development path" from the strict candidate handoff. docs/readiness.md records the 2026-10-04 live end-to-end smoke on Herdr 0.8.2 (scripted stand-in agents; what it did and did not cover) and refreshes the recommended next work. Co-Authored-By: Claude Opus 5.5 --- CHANGELOG.md | 36 +++++++++++++++++++++++-------- README.md | 35 +++++++++++++++++++++++++++--- docs/readiness.md | 55 ++++++++++++++++++++++++++++++++++++----------- herdr-plugin.toml | 2 +- package.json | 2 +- 5 files changed, 103 insertions(+), 27 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 77dc2f5..b2eff53 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,13 @@ Notable changes to the Swarm plugin. Format follows ## [Unreleased] +## [0.5.0] — 2026-10-04 + +The "pick the winner" release: Swarm now checks each slot, notices when a +slot is done, compares them, lands the winner, steers running agents, and +hands merge conflicts to a resolver, all without giving up review-first +merging. Exercised live end to end on Herdr 0.8.2 (see `docs/readiness.md`). + ### Changed - `scripts/harvest-step.sh` (1,863 lines, 23 verbs) is split into domain modules it sources: `harvest-step-{merge,slot,publish,validate,settle,compare,broadcast,resolve}.sh`. @@ -30,15 +37,6 @@ Notable changes to the Swarm plugin. Format follows harvest preview. The plugin's own report holds Herdr's lifecycle authority, which suppresses screen detection (live-verified on 0.8.2). Finish detection now corrects it while the status pane is open. -- The shared test environment now supplies its fixture Git identity to stub - subprocesses too, avoiding hostname-based identity detection during commits - and reflog writes when user/system Git configuration is disabled (#11). -- Harvest now reconciles the completed slot's plugin-reported state before - automatic archive. On Herdr's pane-backed path, a successful merge could - previously leave the slot marked working and unnecessarily block cleanup. - Archive still verifies agent state and worktree contents before removal. -- Archive recognizes Herdr 0.8.2's `done` state (an unseen background idle - agent) as settled, instead of refusing cleanup until its tab is focused. ### Added - Conflict resolver: `resolve ` (`g` in the conflict view) hands a @@ -97,6 +95,26 @@ Notable changes to the Swarm plugin. Format follows `HERDR_SWARM_CANDIDATE_VALIDATION_FILE` still wins. The repo lock is released while the hook runs. On `HERDR_SWARM_VALIDATE_TIMEOUT` the hook's whole process group is killed. A slot that changes during the run records nothing. +- Strict candidate handoff (#15): `candidate-status ` previews, and + `publish-candidate-pr ` publishes, a clean slot only with passing + validation, a passing Browser QA result for the same SHA, and an operator + review bound to the run, slot, and SHA. Every input is re-read before any + push, and the handoff never merges. + +## [0.4.0] — 2026-09-14 + +### Fixed +- The shared test environment now supplies its fixture Git identity to stub + subprocesses too, avoiding hostname-based identity detection during commits + and reflog writes when user/system Git configuration is disabled (#11). +- Harvest now reconciles the completed slot's plugin-reported state before + automatic archive. On Herdr's pane-backed path, a successful merge could + previously leave the slot marked working and unnecessarily block cleanup. + Archive still verifies agent state and worktree contents before removal. +- Archive recognizes Herdr 0.8.2's `done` state (an unseen background idle + agent) as settled, instead of refusing cleanup until its tab is focused. + +### Added - Opt-in `publish-pr ` harvest verb (`g`, then slot in the pane) pushes the audited commit and creates/reuses its exact GitHub draft PR. Existing `publish` remains push-only. Optional SHA-bound validation JSON or Browser diff --git a/README.md b/README.md index 0c6f225..a2fce59 100644 --- a/README.md +++ b/README.md @@ -13,6 +13,25 @@ at a time. Agents commit locally and never push; the orchestrator merges. is the practical guide to this plugin and its three siblings (Browser, Guard, Conductor). +## The workflow (0.5.0) + +Running N agents only pays off if you can pick the best result. From fan-out +to a landed winner: + +| Step | What happens | Section | +| --- | --- | --- | +| **Fan out** | One task, or a different task per slot, into N worktrees. Each slot gets its dependencies (copy-on-write `node_modules`), its own ports, and its slot variables. Swarm warns up front when two slots' tasks name the same files | [Scripting fan-out](#scripting-fan-out), [Fresh worktrees](#fresh-worktrees-lack-your-env) | +| **Steer** | `broadcast` one message to every running agent | [Steering](#steering-a-running-swarm) | +| **Know when done** | The status pane records each slot finished (its marker, or its agent exiting), shows elapsed time, and notifies once when all are done | [Finish detection](#finish-detection) | +| **Check** | `validate.sh` runs on each slot's exact commit, automatically on finish if you opt in | [Validating slots](#validating-slots) | +| **Compare** | A ranked table (checks, commits, files, overlap, time) and a diff of any two slots | [Comparing slots](#comparing-slots-and-picking-a-winner) | +| **Land** | Merge the winner at the exact commit you compared; finished losers are skipped and archived, and branches are kept | [Comparing slots](#comparing-slots-and-picking-a-winner) | +| **Resolve** | A conflicting merge can go to a resolver agent. You review the resolution (including any change outside the conflicts) before it lands | [Resolving conflicts](#resolving-conflicts) | + +Nothing merges without your explicit selection or confirmation. The merge +guarantees are unchanged: drift-checked, compare-and-swap, journaled, and +review-first. + ## Requirements - **herdr 0.7.4 or newer.** Fan-out works on both 0.7.4 and 0.7.5+, by two @@ -39,6 +58,12 @@ Conductor). Harvest, abort, and prune of an existing run work on every supported version (they are mostly git). Versions above the newest tested get a warning, never a refusal. + + Two 0.5.0 features need the 0.7.5+ pane-built path: the **conflict + resolver** (refused on 0.7.4) and **slot variables inside the agent + process** (on 0.7.4 the agent learns its ports from the task file instead). + The whole 0.5.0 flow was exercised live on Herdr 0.8.2; see + [readiness](docs/readiness.md). - **git >= 2.38** recommended (relies on `git worktree`, three-arg `git update-ref` compare-and-swap, and `git merge-base --is-ancestor`). - **Node.js >= 20** on your PATH (manifest handling, manifest validation, and @@ -97,7 +122,8 @@ add your own, see below): unreachable agents show as `unknown` with their committed work still harvestable. 3. **Harvest** (`structupath.swarm.harvest`) — review-first merge-back. Keys: - `1`–`9` select a slot, `r` re-previews, `q` quits. Per slot: + `1`–`9` select a slot, `w` opens the compare view (diff two slots, merge a + winner), `v` validates a slot, `r` re-previews, `q` quits. Per slot: - *Clean slot* — merged `--no-ff` with a templated message. The base ref is drift-checked before **every** merge; if it moved, all slots re-preview. When base is not checked out anywhere, the merge runs in a plugin-owned @@ -343,12 +369,15 @@ not copied. See [GitHub handoff contract and recovery](docs/github-handoff.md) for the file schema, Console integration output, and failure handling. -### Strict candidate handoff (opt-in development path) +### Strict candidate handoff For a selected **clean** slot HEAD, keep validation, Browser QA, and the operator's review in three separate regular files. Validation checks must all pass; Browser QA must pass for that same SHA; the review must approve the exact -run ID, slot, and SHA. Preview the readiness gaps locally before publishing: +run ID, slot, and SHA. The validation file can be the one `validate ` +records: with `HERDR_SWARM_CANDIDATE_VALIDATION_FILE` unset, it's used +automatically (see [Validating slots](#validating-slots)). Preview the +readiness gaps locally before publishing: ```sh export HERDR_SWARM_CANDIDATE_VALIDATION_FILE=/absolute/private/checks.json diff --git a/docs/readiness.md b/docs/readiness.md index 51ee5a7..580799b 100644 --- a/docs/readiness.md +++ b/docs/readiness.md @@ -1,7 +1,9 @@ # Swarm readiness -The plugin targets version 0.4.0; changes on this branch are recorded under -Unreleased in the changelog. The manifest still requires Herdr >=0.7.4. +The plugin is at version 0.5.0 (see the changelog). The manifest still +requires Herdr >=0.7.4. The broad compatibility baseline remains Herdr +0.7.4/0.7.5; Herdr 0.8.2 has the live evidence below. 0.7.4 does not support +the conflict resolver or agent-side slot variables. ## Repeatable validation @@ -52,16 +54,43 @@ shell pid marks exit. Those shapes back finish detection's stubs. See The session was stopped afterwards. No paid agent was run, so Herdr-native detection after `release-agent` remains unverified. +## Live end-to-end smoke — 2026-10-04 (0.5.0) + +A throwaway named Herdr 0.8.2 session (protocol 20) ran the whole 0.5.0 flow +against a disposable repository with temporary plugin state and config. Every +inherited `HERDR_*` routing variable was stripped, and `plugin …` calls were +refused so the installed plugin could not touch real state. Scripted +stand-in agents and a scripted resolver were used; no paid model agent ran. +Each step was exercised through the real verbs: + +| Step | Live result | +| --- | --- | +| Scripted fan-out, per-slot task file | 3 created, 3 started; slot count from sections; conflict hint fired for two slots naming `app.txt` | +| Slot environment | Each agent saw its own `HERDR_SWARM_SLOT`, run id, and port base (via `pane split --env`), its own worktree, cloned `node_modules`, and its task file | +| Finish detection | `settle` recorded all three finished by marker; one notification; a second settle was a no-op | +| Validate | Two passed, one failed by design, each bound to its tip SHA | +| Compare | Passed slots ranked above the failed one; `app.txt` overlap shown | +| Broadcast | Delivered once to each running agent. After one agent exited, a second broadcast refused the bare shell | +| Merge | One slot landed at its compared tip through the detached locus and compare-and-swap | +| Conflict → resolve → conclude → land | Merge stopped with the merged tip journaled. The resolver ran in a pane split from the slot's pane, inside the merge tree, and made one commit. The read-only review recorded nothing; `apply` and `resume complete` landed exactly the reviewed commit | +| Review guards | A file slipped into the merge commit was flagged `outside_conflict`; applying the earlier-reviewed SHA after an amend was refused (exit 30) | +| Archive, prune | Exact one-use approvals removed worktrees holding cloned `node_modules`; branches kept; prune dry-run listed 2 merged and kept 1 unmerged | + +Not covered: real agent quality (claude/codex), the status pane and its +periodic settle (opened through the plugin action, which was blocked; `settle` +was run directly), and Herdr 0.7.4. The session was stopped and every fixture +removed afterwards. + ## Recommended next work -1. Add opt-in named-session integration coverage for released Herdr versions, - especially agent identity/state and worktree removal. Keep real-git fixture - coverage for drift, conflicts, snapshots, and interrupted-run recovery. -2. Validate each team's setup hook and agent preset against a small task before - increasing slot count. Fresh worktrees lack ignored dependencies and secrets; - setup-hook failure currently warns and still starts the agent. -3. Keep conflict resolution review-first. The resolver-agent document in - `docs/plans/` describes future work, not a shipped feature. -4. Use `publish-pr` for an explicit draft GitHub handoff with SHA-bound supplied - evidence, and `pr-status` for a current CI snapshot. Ordinary `publish` still - only pushes. The orchestrator remains responsible for the final review. +1. Run one live flow with real agent presets (`claude`, `codex`), including + an approval prompt during broadcast and a real resolver resolution. + Interpreter-launched agents (`node cli.js`) read as `unknown` to the + resolver and broadcast checks by design; confirm that is workable. +2. Add opt-in named-session integration coverage for released Herdr versions. + Keep real-git fixture coverage for drift, conflicts, snapshots, and + interrupted-run recovery. +3. Raise the "newer than tested" baseline once 0.8.x evidence is broad + enough; today it warns once per slot during fan-out. +4. Validate each team's `setup.sh`, `validate.sh`, and presets against a + small task before increasing slot count. diff --git a/herdr-plugin.toml b/herdr-plugin.toml index 0dfbe3f..f9d64aa 100644 --- a/herdr-plugin.toml +++ b/herdr-plugin.toml @@ -1,6 +1,6 @@ id = "structupath.swarm" name = "Swarm" -version = "0.4.0" +version = "0.5.0" min_herdr_version = "0.7.4" description = "Worktree-per-agent fan-out, per-slot change visibility, and review-first harvest for parallel coding agents" platforms = ["macos", "linux"] diff --git a/package.json b/package.json index 906dbfe..b074395 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "herdr-swarm", - "version": "0.4.0", + "version": "0.5.0", "private": true, "type": "module", "engines": { "node": ">=20" },