Repository navigation
feat(harness-ops): give converge a planning script that groups by path, and stop sync pointing blocked and worktree rows at converge #7448
Description
What happened
On 2026-10-14 (harness-ops 3.14.0, WSL2), sync printed a Divergences: row ending in "→ run /harness-ops:plugins converge" with 57 actionable divergences. Converge then had 57 divergences covering 932 lagging pins across 108 project paths. 474 of those pins sat in paths not present on the machine, so converge marks them BLOCKED. Most of the rest belonged to linked worktrees, where the right fix is removing the worktree (/source-control:worktree cleanup reaps its records), not converging its pins.
Converge has no script (SKILL.md:50-51: "converge stays model-driven until it gains a script of its own"). Step 2 and Step 3 (context/converge.md:117-125) require a per-pin confirm, by AskUserQuestion per plugin or an enumerated batch. At 932 pins that cannot be done in one session.
Expected
- Converge groups rows by
projectPathand strategy, and presents one batch per path that the user can approve or skip per row. - Sync's pointer to converge counts only rows converge can act on, and sends the user to worktree cleanup when the divergent pins live in linked worktrees. (Shipped in fix(harness-ops): split sync's divergence count into converge-actionable, worktree and blocked pins #8019.)
Repro
- Have many linked worktrees and some removed ones, each with project-scope records behind user scope.
- Run
/harness-ops:plugins sync, then/harness-ops:plugins converge.
Evidence
Paths are relative to plugins/harness-ops/skills/plugins/ on main at 8718950e9d.
scripts/render-report.jq:184-188: theDivergences:row always ends in "→ run/harness-ops:plugins converge" when the count is non-zero, whatever the rows are.context/converge.md:94-104: absent-path rows are BLOCKED, yet they reach the count the sync row points at.context/converge.md:117-125: per-pin confirmation.- Counts from this run: 57 divergences, 932 lagging pins, 108 paths, 474 pins in absent paths.
Proposed fix
- Add
scripts/converge-plan.sh: readfleet-state.shoutput and emit one row per(projectPath, id)with strategy, exact command, and a class:actionable,blocked-absent,blocked-home(fix(harness-ops): converge treats a user home directory (including /mnt/c/Users/* on WSL) as a project path #7447),worktree(path is a linked worktree of a repository found through its.gitfile),blocked-catalog. Group the output by path. - Converge Step 3 confirms per path: one enumerated batch per path, with approve/skip per row. Keep the rule against a single blanket yes.
Sync's: shipped in fix(harness-ops): split sync's divergence count into converge-actionable, worktree and blocked pins #8019 (closed as completed).Divergences:row split
Scope now: fixes 1-2. Its blocker, #7891 (converge Step 2 and strategy defaults), merged 2026-10-20.
Done when
-
plugins/harness-ops/skills/plugins/scripts/converge-plan.shreadsfleet-state.shoutput and emits one row per(projectPath, id): strategy, exact command, and class (actionable,blocked-absent,blocked-home,worktree,blocked-catalog), grouped by path. Aworktreerow is a path whose.gitis a file. Strategies match the defaults fix(harness-ops): converge defaults to update for pins mirroring committed enables #7891 set (context/converge.md: update for pins that mirror committed enables). Check: the PR's CI runs a newconverge-plan.test.shwith one fixture row per class, and it passes. -
context/converge.mdStep 3 confirms one batch per path, with approve or skip per row, and still refuses a single blanket yes. Check: the reviewer reads Step 3; the PR's CI runs the markdown lint and it passes. -
SKILL.md:50-51no longer says converge stays model-driven. Check: the PR's CI runs the skill-quality check on the changed SKILL.md and it passes. - A
.changes/harness-ops/fragment exists. Check: the PR's CI runsscripts/check-changelog-fragments.sh --checkand it passes.
🤖 Generated with Claude Code
Activity
github-actions commentedon Oct 14, 2026
Thanks for the report. Automated triage handed this issue to a maintainer.
Proposed work class: work-class: scoped
Basis: automated intake triage; a maintainer confirms or changes it.
Automated triage. A maintainer reviews it.
kyle-sexton commentedon Oct 18, 2026
This was generated by AI during backlog shaping.
This issue is split into 2 pieces, each sized for one lane PR. The sync pointer is still unconditional (origin/main render-report.jq:184-188 ends any non-zero count with 'run converge'), and fleet-state.sh keeps absent-path rows in divergences[] by rule (fleet-state.sh:86-91: projectPathPresent is advisory and never filters), so the counts can be split without changing that rule. The converge planning script and per-path confirm edit converge.md, which open PR #7891 (#7446) is changing in Step 2, and SKILL.md's 'converge stays model-driven until it gains a script'. Two children.
Filed pieces are sub-issues of this one, and the paced queue admits them to the lane. Unfiled pieces wait on the blocker shown. The owner approved this split in an attended backlog-shaping session on 2026-10-18.