Skip to content

fix: hold the wording path to the same bar as the sentinel path - #5

Closed
cannabinoids wants to merge 2 commits into
michelhelsdingen:mainfrom
cannabinoids:fix/completion-detection
Closed

cannabinoids wants to merge 2 commits into
michelhelsdingen:mainfrom
cannabinoids:fix/completion-detection

Conversation

@cannabinoids

@cannabinoids cannabinoids commented Aug 13, 2026 •

Copy link
Copy Markdown

Rebased onto current main. 1782034 covers the case that killed the four-agent
research team — raised idle thresholds plus CONTINUATION_PATTERNS for progress
reports — so this is now scoped to three things that fix does not reach. Reproductions
are in #4.

What changes

The wording path still ends a run on two agents, whatever the team size.
hasTwoRecentCompletionSignals returns true for any two distinct agents, so once a
trio is quiet past TWO_SIGNAL_IDLE_THRESHOLD_MS the third can still be cut off by the
other two — which is what the comment directly above that call warns about. It becomes
hasRecentCompletionSignalsFromAll: same sliding window, every active agent must appear
in it. The sentinel path already holds this bar.

Two guards on the heuristic path, inside isCompletionStatement and placed after
the CLOSING_PATTERNS check, so an unambiguous sign-off still wins outright:

  • a sign-off is short — a 600-character analysis containing "done" is an agent working
  • a sign-off does not quote the machinery

The second came from a review task pointed at scripts/collab-poll.sh: both agents
quoted its own ---STATUS:{ACTIVE,QUIET,DONE,WAITING} sentinel and the run ended
mid-analysis. CONTINUATION_PATTERNS doesn't catch those, because nothing in them
announces further work — they aren't progress reports, they're descriptions of the
protocol.

Completion counts only from the last user message. ensemble steer exists so a user
can redirect a running team, but a sentinel sent before the redirect still counted, so a
team could disband while an agent was answering the new instruction — observed with a 15
second gap between the sentinel and the interjection. "Wrap it up" followed by sentinels
still disbands.

Tests

Nine specs: five in premature-disband.test.ts (machinery-quoting, DONE-protocol talk,
team-say announcements, the long-analysis case, and a genuine short sign-off still
counting), four in ensemble.test.ts (trio needs all three; sentinels before a user
interjection are void; sentinels after it still disband). All nine fail on main and
pass with this change.

tsc --noEmit and eslint clean. The whole suite passes except
onboarding-smoke.test.ts, which times out on my machine at the default 5s and is
untouched here — it's green in your CI, so it looked like my hardware rather than
something to change in your repo.

Not included

Deliberately narrow. A separate branch carries user-interjection ergonomics (durable
per-agent inbox, idle-gated delivery, pause/resume), agent-transcript isolation via
--append-system-prompt-file and a pinned --session-id, and ollama-backed agents via
ollama launch. Those change behaviour rather than fixing defects, so they stay out
unless you want them.

cannabinoids added a commit to cannabinoids/ensemble that referenced this pull request Aug 13, 2026
Upstream moved 16 commits while this branch sat on an old base, and several of
those commits covered the same ground. Rather than replay our history through
the conflicts, this reapplies what is still ours onto upstream's code.

Dropped as superseded: our preflight agent-scoping (upstream's is broader and
covers grok), our trio-aware prompt wording, our sentinel-path disband fix, and
our launcher template flag -- upstream has all four, in some cases better.

Kept, re-applied onto upstream's versions: user interjection with a durable
per-agent inbox and idle-gated delivery, pause/resume, agent transcript pinning
and archiving, the watchdog participation and busy-pane gates, ollama-backed
agents, positional --roles, monitor keys 1-9 and p, the API-key cost guard, and
project-context prompts.

The disband work now sits on upstream's shape: their sentinel path and idle
threshold are untouched, and ours adds the all-agents bar on the wording path,
the sign-off content guards, and the user-redirect cutoff -- the same change
proposed in PR michelhelsdingen#5.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Rebased onto main after 1782034. That commit raised the idle thresholds and
added CONTINUATION_PATTERNS, which covers progress reports -- the case that
killed the four-agent research team. Three things it does not cover remain.

The wording path still ends a run on two agents, whatever the team size.
`hasTwoRecentCompletionSignals` returns true for any two distinct agents, so
once a trio is quiet past TWO_SIGNAL_IDLE_THRESHOLD_MS the third can still be
cut off by the other two -- exactly what the comment above the call warns
about. It now requires every active agent, matching the sentinel path.

Two guards on the heuristic path in isCompletionStatement, after the explicit
CLOSING_PATTERNS check so an unambiguous sign-off still wins outright. A
sign-off is short, and it does not quote the machinery: on a review task
pointed at collab-poll.sh both agents quoted its own
---STATUS:{ACTIVE,QUIET,DONE,WAITING} sentinel inside long analysis messages,
and that ended the session. CONTINUATION_PATTERNS does not catch it, because
nothing about those messages announces further work.

Completion is also counted only from the last message the user sent. `ensemble
steer` exists so a user can redirect a running team, but a sentinel from
before the redirect still counted, so a team could disband while an agent was
answering the new instruction -- seen live with a 15s gap between the sentinel
and the interjection. "Wrap it up" followed by sentinels still disbands.

Nine specs added, five in premature-disband.test.ts and four in
ensemble.test.ts. All nine fail on main and pass with the change.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@cannabinoids
cannabinoids force-pushed the fix/completion-detection branch from b3c8658 to 1d8a80a Compare August 18, 2026 17:23
cannabinoids added a commit to cannabinoids/ensemble that referenced this pull request Aug 18, 2026
Upstream shipped 8 commits while this branch sat still. Unlike the last sync,
none of it superseded ours -- it is complementary, so everything here is our
work re-applied onto his newer code rather than dropped.

Watchdog: his failed-nudge ceiling (measured 45.088 failed nudges across 7
teams) decides when to stop retrying a vanished session; our two gates decide
which agents may be nudged at all -- one that never received the task prompt,
or one whose pane is mid-generation, is left alone. His runaway fixtures now
set promptInjectedAt, because a spawned agent whose session later vanished has
it in production, and without it the gate correctly refuses to nudge.

Agents: our systemPromptFileFlag / sessionIdFlag / transcriptPathTemplate are
now optional fields on his agent config contract, and the ollama entries sit
beside his glm and grok. His loader rejects unknown agent names instead of
silently spawning a second claude, which is strictly better than what we had.

Disband: carries the same three changes as PR michelhelsdingen#5, on his shape -- the wording
path held to every active agent, the short/no-machinery guards on the
heuristic path, and completion counted only from the last user redirect (here
also honouring lastResumedAt, which the fork has and upstream does not).

Prompt, interjection, pause/resume, transcript archiving and the CLI surface
are re-applied unchanged in behaviour, on his current wording.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The cutoff filtered the whole message list, which also fed the min-message
floor and the idle clock. Both then restarted at every `ensemble steer`, so a
team that finished shortly after being steered -- in words rather than the
sentinel -- never met the floor again and stayed active indefinitely. That is
worse than the bug the cutoff fixes: a stale sign-off ends a run early, this
never ends it at all.

Sentinels and completion wording are now filtered to messages at or after the
last user message; the count and the idle clock read the whole run.

Two specs: a team that wraps up right after a redirect still disbands, and a
single-agent team still ends through the long-idle fallback -- both the
sentinel path and the all-agents wording path need two or more agents, so a
solo run has only that route out.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@cannabinoids

Copy link
Copy Markdown
Author

Closing this one myself — I'd rather not leave a PR sitting against a function you're actively iterating on, and your threshold raise in 1782034 already covers most of what prompted it.

The three changes live on my fork if they're ever useful: the wording path held to every active agent (matching the sentinel path, and what the comment above that call already describes), two guards so an agent quoting a script's own DONE sentinel isn't read as finishing, and completion counted only from the last user redirect. Reproductions are in #4 and stand on their own.

Thanks for ensemble — it's a genuinely nice thing to work in.

cannabinoids added a commit to cannabinoids/ensemble that referenced this pull request Aug 28, 2026
PR michelhelsdingen#5 is closed. Upstream's threshold raise absorbed most of the practical
risk it addressed, and what remained sits in a function upstream is actively
iterating on, where a standing PR is friction rather than help. The
reproductions in issue michelhelsdingen#4 are left as information, not as a request.

From here the fork tracks rather than proposes: read what upstream ships, take
what is better, keep the rest local. Convergence is the expected outcome — the
sentinel-path fix, agent-scoped preflight and progress-vs-completion wording all
arrived upstream independently, from the same evidence.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
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.

1 participant