Skip to content

teams: one wake per reply, stops reach background members, the belt follows the role, and four store fixes - #1514

Merged
AbirAbbas merged 9 commits into
devfrom
fix/teams-behaviour
Sep 25, 2026
Merged

AbirAbbas merged 9 commits into
devfrom
fix/teams-behaviour

Conversation

@AbirAbbas

Copy link
Copy Markdown
Collaborator

Follows #1429 / #1485 / #1494 / #1436 review: the seven team manager and store should-fixes. One commit per item.

What was wrong → what is true now

  1. A member's reply woke its manager, and the finished of the same member turn, ~13 s later, woke it again. That doubled the paid turns, and the 10-wake loop breaker tripped after ~5 real rounds. → One reply is one wake. The dedupe is read back from the Traffic, so it holds across a restart. The ending reaches the manager at its next step. A finished with no reply, a failure or a question still wakes it, and ten wakes are now ten replies.
  2. Teams.Name / Teams.Propose with a zero or negative Budget gave the engine's model call no deadline. → Zero uses the engine's 30 s ceiling, and every budget is capped at it. A negative budget answers deadline exceeded without a call.
  3. A demoted manager kept every team verb, each refusing. → The belt matches the role at the next step, and the other tools keep their order. A remembered call is told team_send is no longer one of your tools: this conversation no longer manages a team. An unreadable teams file removes nothing.
  4. team_stop could not stop a member codeaf opened in the background, because only a window performed the stop. → The member's own session honours its manager's stop while a turn runs (the manager stopped this turn). It ignores old stops, stops for others and stops from links, and never touches a turn that has already ended. The tool reply and the manual say it stops again.
  5. Closing a sub-team whose manager alone was working closed it at once while the manager kept running. → The card opens with Wrap up first leading and names the manager. Close now stops that manager's turn but keeps its tab, because it is still in the team above.
  6. An unreadable day spend counted as $0, so a team's cap stopped holding. → Fail closed: harbor has a $5 daily cap and today's spend could not be read (<error>), so nothing new starts until it can be read. No cap card is raised, the next check retries, and an uncapped team never reads the spend.
  7. Packet rotation dropped answered packets after two rotations: an answer its asker had not run to see yet, and today's cap decision. → The asker's delivery appends a told line. Rotation now carries waiting packets, today's cap packets, and answers not yet told, newest first within half the rotation size.

Every change updates the manual (team-manager.md, team-questions-and-caps.md, teams-page.md), with retrieval probes and dated notes in DESIGN.md.

Validation contract, and how it was checked
Each item has a test derived from the contract, and each fails on origin/dev by construction. On dev the manager is woken a second time, the zero budget has no deadline, team_send stays on the belt, the headless member's turn never ends, the close happens at once, the hold is empty, and the rotated packet is ErrNoPacket. They pass here:

  • TestTeamWake{AReplyAndItsFinishedTurnWakeTheManagerOnce,FinishedAfterReplyStillDeduplesAfterManagerRestart,TheLoopBreakerCountsTenMemberReplies}
  • TestTeamAskBudgetBoundsEveryModelCall, TestExpiredTeamAskNeverCallsTheModel
  • TestTeamRoleDemotionRemovesOnlyLostVerbsAndRearmingAppends, TestTeamToolsLeaveWhenTheTeamsFileIsGone
  • TestTeamStop{EndsAHeadlessMembersCurrentTurn,IgnoresOldOtherAndSharedStops}
  • TestTeamsCloseCountsAndStopsASubteamManagerSharedWithItsParent
  • TestTeamUnreadableSpendHoldsCappedWorkWithoutAPacket, TestTeamCapHoldsWhenTheUsageLedgerPathIsADirectory, TestTeamWithoutACapNeverReadsAnUnreadableLedger
  • TestRotationKeepsAnUntoldAnswerAcrossSeveralFiles, TestTodaysCapDecisionSurvivesRotationAndOwedCarryStaysBounded, TestTeamAnswerDeliveredAfterPacketRotationsIsMarkedTold

The whole TestTeam* session group passes, along with the teams, remote and manual packages, the tui3 close tests and make pr-ready.

The loop-breaker test failed once inside a long package run. It used a positional script, and another request of the member's took the next round's step. Its rounds are now armed per request, and it passes alone and in the same full group run where it had failed.

There was no real-binary hand check: every changed behaviour is in the engine, the store, or the close card's model, and the tests above drive each one directly.

🤖 Generated with Claude Code

AbirAbbas and others added 9 commits September 25, 2026 15:54
Teams.Name and Teams.Propose carry how long the wall will wait, and the
engine bounded the naming or Organize model call by it only when it was
positive: zero or negative gave the call no deadline at all. Zero now means
the engine's own ceiling for one ask (30 s, longer than the wall's 5 s and
10 s waits), any budget is capped at that ceiling, and a negative budget,
already expired, answers deadline exceeded without a model call.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
A sub-team's manager is also a member of the team above, so the close's
running count filtered it out as "also in another open team", and Close…
closed the team at once while its manager kept working. The manager of a
team being closed now counts as working: the card opens with Wrap up first
leading and names it, and Close now stops its current turn while its tab
stays open, because it is still in the team above.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
teamPoolSpend counted a spend it could not read (the usage ledger unreadable,
or the teams file failing to load for the fold) as $0, so the daily cap
stopped holding exactly when it could not be checked. It now fails closed:
the wake, the brief and team_start are held with one sentence naming the
error, no cap card is raised against a figure nobody read, and the next check
reads again. An uncapped team never reads the spend. The wrap-up's $2 bound
is measured only from a spend that was read, and a closing report whose spend
cannot be read leaves the figure out.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Past 1 MB a team's packet file started a new one carrying only waiting
packets, so a decided one lived for one more rotation and was gone: an answer
whose asker had not run since, and today's cap decision (a raise was forgotten
and the card came back), were lost. The raiser's delivery now appends a
"told" line once it hands the answer over, and a rotation carries every
waiting packet, today's cap packets, and the decided answers not yet told,
newest first within half the rotation size. A told answer keeps its old
one-rotation lifetime; a conflict's ruling travels in Traffic and needs none.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Team verbs were armed at the boundary that found a role and never left, so a
manager removed from its team kept team_send, team_stop, team_start and the
rest, each refusing when called. The boundary now takes off every team verb
the current roles do not give (one prompt re-price, at a rare moment), keeps
the order of everything else, and answers a remembered call with the role
that went: "team_send is no longer one of your tools: this conversation no
longer manages a team." An unreadable teams file removes nothing, and a role
gained again appends its verbs at the tail as before.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
A manager's stop was performed only by a window holding the member, so a
member codeaf opened headless to run a woken turn ran on to its end whatever
the manager said (f26f25c made the tool and the manual say so). The member's
own session now watches its team's Traffic while a turn runs, one stat a tick,
and ends the turn the way the person's Stop does when its manager's stop
arrives, with its own door ("the manager stopped this turn"). A stop older
than the running turn, one for another member, or one from a link does not
stop it, and a turn that already ended is never touched. The tool's reply and
the manual say it stops again.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
A member's team_post to the manager woke it after the 5 s settle, and the
finished event of the same member turn, arriving about 13 s later, woke it a
second time: twice the paid manager turns per round, and the 10-wake loop
breaker tripped after about 5 real rounds. A finished event that ends a turn
which already replied to the manager (read back from the Traffic, so it holds
across a restart) now starts no wake; the manager is handed "@web finished its
turn" at its next step. A finished with no reply, a failure and a question
still wake it, and ten wakes are ten replies.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@AbirAbbas
AbirAbbas merged commit e7b9512 into dev Sep 25, 2026
4 checks passed
@AbirAbbas
AbirAbbas deleted the fix/teams-behaviour branch September 25, 2026 20:22
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