Skip to content

feat(auto-pm): fan [Spike & plan] out to the concurrency, one PENDING-locked ticket per agent (#1327) - #1364

Merged
suleimansh merged 1 commit into
mainfrom
worktree-spike-fanout-1327
Jul 29, 2026
Merged

feat(auto-pm): fan [Spike & plan] out to the concurrency, one PENDING-locked ticket per agent (#1327)#1364
suleimansh merged 1 commit into
mainfrom
worktree-spike-fanout-1327

Conversation

@suleimansh

Copy link
Copy Markdown
Member

Closes nothing yet — the code half of #1327; the maintainer's Spike & plan prompt rewrite composes on top.

What this does

Clicking [Trigger routine now] with Concurrent agents = N, the other routines unticked, and an empty queue now spins up N concurrent Spike & plan agents, one ticket each — the fan-out beat #1327 asks for.

  • Fan-out: AutoPmJob.fansOut (declared on the spike job only) lets a rotation job batch like draining does (auto-pm.ts). Each agent gets a pinnedSpikeJob prompt — the pin is appended to the stock preset so the maintainer's coming prompt rewrite can't silently lose it.
  • PENDING locks (new spike-locks.ts): before agents start, the daemon pre-creates each ticket's .spike.md/.plan.md as PENDING:<AGENT_ID> placeholders — one pathspec-scoped batch commit, pushed to the current branch. The daemon pushes, not the agents, per the Goal: fire 10 Spike & plan agents concurrently #1327 thread agreement (cloud sessions can't push, Web runs complete their work but cannot push: cloud container has no GitHub write access unless the account's Claude GitHub app covers the repo #1320). Push failure keeps the batch (the commit still guards local forks) and logs.
  • Staleness (thread rule): a lock still placeholder + older than 60 min (commit time) + untouched by any open PR is released before enumeration, so a dead agent can't brick its ticket. Conservative on every unprovable case (uncommitted placeholder, unreadable gh, open PR).
  • Reader awareness: a PENDING sibling reads as locked, not spiked/planned (dashboard/tickets.ts), contributes no effort, and a placeholder plan promotes no quick-win (fails closed in planned-quick-wins.ts, now tested).
  • Composability: locks cover the window before a PR exists; the merged Queue claims are per-machine: two daemons draining the same queue double-assign an entry #1313 PR-diff claims cover after. The stock (unpinned) spike prompt now also names the placeholder convention, so a single-agent run skips locked tickets too.

Fallbacks

Missing seams, zero candidates, or a lock that claimed nothing all degrade to the exact pre-#1327 behaviour (one unpinned agent / rotation advance). No settings changes needed — autoPmConcurrency (#1204) already exists and caps the batch.

Tests

  • spike-locks.test.ts: acquire (batch commit, pathspec scope, push, lost-race skip, commit rollback, push-failure tolerance) and release (stale / young / open-PR / unreadable-PR / uncommitted / real-sibling cases).
  • auto-pm.test.ts: fan-out to concurrency, partial locks, lock-failure fallback, seamless fallback, in-flight ticket pinning, rotation advance on nothing-to-spike, pinned-prompt shape, catalog flag.
  • tickets.test.ts / planned-quick-wins.test.ts: PENDING placeholders read as locks and promote nothing.

the-framework: 1630 pass · framework-dashboard: 653 pass.

🤖 Generated with Claude Code

…-locked ticket per agent (#1327)

The rotation's spike job now fans out like draining does: the sweep asks
for the open tickets with no sibling at all, locks a batch of them by
pre-creating each ticket's .spike.md/.plan.md as PENDING:<AGENT_ID>
placeholders — one pathspec-scoped commit, pushed by the daemon since
cloud agents cannot push (#1320) — and starts one pinned agent per
locked ticket. A stale lock (still a placeholder, older than 60 min, no
open PR touching it) is released before enumeration, so a dead agent
cannot brick its ticket. Lock failure falls back to the stock single
unpinned agent, the pre-#1327 behaviour.

The readers learn what a placeholder is: a PENDING sibling reads as
locked, not spiked/planned, so the dashboard does not claim work that
has not happened, and a lock placeholder plan promotes no quick-win.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@suleimansh
suleimansh marked this pull request as ready for review July 29, 2026 01:21
@suleimansh

Copy link
Copy Markdown
Member Author

@brillout This PR also touch the spike_and_plan.md

@@ -1,5 +1,7 @@
Spike & plan every ticket that has no spike or plan yet, most important first.

A `.spike.md` or `.plan.md` that already exists counts even when it only reads `PENDING:<agent>` — that placeholder is another agent's claim on the ticket, so leave both files alone and skip the ticket.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good

@suleimansh
suleimansh merged commit 3dd84ef into main Jul 29, 2026
2 checks passed
@suleimansh
suleimansh deleted the worktree-spike-fanout-1327 branch July 29, 2026 20:38
@brillout

Copy link
Copy Markdown
Member

Couple of smells:

  • HEAD:<current branch> (see spec.md) => should be HEAD:origin/main
  • SPIKE_LOCK_STALE_MS 60 min => should be longer (spike & planning can take hours, and it's a bug recovery mechanism so, ideally, it's never needed)
  • There is a lot of LoC addition, but few LoC removal => does this PR delete all code that is outdated?

Does this PR introduce AI slop (I think yes) and how much? Let's further gauge and keep on the radar how much AI slop the code has (helps us take the right decisions).

@suleimansh

Copy link
Copy Markdown
Member Author

Both code smells fixed in #1394

suleimansh added a commit that referenced this pull request Jul 30, 2026
… -> 6h (#1364 review) (#1394)

The lock commit pushed HEAD:<current branch>, publishing whatever
branch the daemon's checkout was on and leaving main-forked machines
blind to the locks. It now pushes to origin's default branch, and only
when the checkout is on it — HEAD:main from a feature branch would
carry foreign commits onto main. Skips are logged.

SPIKE_LOCK_STALE_MS becomes 6 hours: spiking and planning can take
hours, and staleness release is recovery, ideally never needed.

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
@brillout

Copy link
Copy Markdown
Member

It makes me think that reading the spec.md diff can be worth it to catch such issues early. (And my gut feeling tells me we need to know about all high-level flows that exist in the codebase, but let's see.)

That said, we can be less careful about AI slop for TF's experimental parts.

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.

2 participants