Skip to content

fix(sessions): a died hook-* session never holds a capacity slot (#523) - #682

Merged
defangdevs merged 3 commits into
masterfrom
fix/523-died-hook-cap
Sep 11, 2026
Merged

fix(sessions): a died hook-* session never holds a capacity slot (#523)#682
defangdevs merged 3 commits into
masterfrom
fix/523-died-hook-cap

Conversation

@defangdevs

Copy link
Copy Markdown
Owner

Summary

Test plan

  • python3 tests/test-session-capacity.py - added test_died_never_holds_a_slot_even_with_its_pane_still_up, confirmed it fails without the fix and passes with it; all 13 tests pass
  • python3 tests/test_agentbox.py - 149 passed, no drift
  • python3 bin/assemble-module.py --check - modules/agent-box.nix regenerated and up to date
  • python3 scripts/check_backend_parity.py - OK, no undeclared divergence
  • python3 tests/test-assemble-module.py - OK
  • python3 scripts/check_vendor.py - OK
  • Patched the two golden fixtures that embed this shared library's body (tests/golden/vm/payloads/agent-box-session-capacity/... and tests/golden/web/payloads/agent-box-settings/...) to match, verified byte-for-byte against bin/assemble-module.py --resolve
  • Not run here (aarch64 box, VM tests are x86-only): nix build .#checks.x86_64-linux.sessions and friends - relying on CI for those

Closes #523

🤖 Generated with Claude Code

capacity_check() counted a `died` entry as `pending` (its `stopped` flag
is never set, issue #516) and its lingering post-mortem-shell pane as
`live`, so a crashed hook-* session held its slot forever -- only
`agent-box-session rm` ever freed it. Four such corpses made every
standing watch inert with nothing actually running, the same shape as
the pre-#280 bug this admission policy was built to fix.

Exclude any session the registry flags `died` from both `live` and
`pending`, in the single shared session-capacity.py the CLI, supervisor,
webhook spawner and settings daemon all admit through since #668.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0188bYSAQvRmVjNDtsgznirR
@coderabbitai

coderabbitai Bot commented Sep 11, 2026

Copy link
Copy Markdown

Review Change StackReview Change Stack

Warning

Review limit reached

Next included review available in 41 minutes.

Check out review usage here.

View limit details

Limit details: You’ve used the included review currently available.

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

Learn how review limits work.

Review configuration:

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Advanced

Run ID: e4d280ad-a142-4739-aea4-a17315e775ba

📥 Commits

Reviewing files that changed from the base of the PR and between b457ffc and 694ec34.

📒 Files selected for processing (5)
  • modules/agent-box.nix
  • modules/src/lib/session-capacity.py
  • tests/golden/vm/payloads/agent-box-session-capacity/bin/agent-box-session-capacity
  • tests/golden/web/payloads/agent-box-settings/bin/agent-box-settings
  • tests/test-session-capacity.py

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Advanced

Run ID: e3a28147-cb03-428f-9d5a-d86991005adf

📥 Commits

Reviewing files that changed from the base of the PR and between 045dc6f and b457ffc.

📒 Files selected for processing (5)
  • modules/agent-box.nix
  • modules/src/lib/session-capacity.py
  • tests/golden/vm/payloads/agent-box-session-capacity/bin/agent-box-session-capacity
  • tests/golden/web/payloads/agent-box-settings/bin/agent-box-settings
  • tests/test-session-capacity.py

Included review availability: Your plan provides up to 1 included review per hour; 0 remain after this review.


📝 Walkthrough

Walkthrough

The change updates capacity checks to exclude crashed sessions from live and pending accounting. It applies the logic to standing-watch and spawning paths, updates generated payloads, and adds regression coverage for crashed sessions with live panes.

Changes

Session capacity accounting

Layer / File(s) Summary
Capacity accounting implementation
modules/src/lib/session-capacity.py, modules/agent-box.nix
Capacity checks derive a died set, remove those sessions from live panes, and exclude them from pending admissions in both execution paths.
Capacity regression coverage
tests/test-session-capacity.py, tests/golden/.../agent-box-session-capacity, tests/golden/.../agent-box-settings
The unit test and golden payloads verify that a died session does not hold capacity when its pane remains live.

Priority: ➖ Normal

Estimated code review effort: 3 (Moderate) | ~20 minutes

Change: Bug fix · Severity of issue fixed: Medium

Suggested reviewers: lionello

Merge Risk: ⚪ Minimal · up to b457f

Crashed sessions no longer retain capacity solely because a post-mortem pane remains present, and the updated paths are covered consistently.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 25.00% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 4 functions across 2 files. (3 skipped: 3… Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly identifies the fix: sessions marked died no longer hold capacity slots. It is concise and directly matches the main change.
Description check ✅ Passed The description accurately explains the capacity issue, the implementation, affected admission paths, and test coverage. It is directly related to the changeset.
Linked Issues check ✅ Passed The implementation satisfies issue #523. capacity_check() builds a set from registry entries with died set, removes those names from live, and excludes them from pending. A died session theref…
Out of Scope Changes check ✅ Passed The changes stay within issue #523. The source change updates shared capacity accounting, the test adds coverage for died sessions, and the generated modules and golden fixtures maintain parity for th…
Full details: Docstring Coverage

Explanation

Docstring coverage is 25.00% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 4 functions across 2 files. (3 skipped: 3 unsupported.)

✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/523-died-hook-cap

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

defangdevs and others added 2 commits September 11, 2026 22:46
writePython3Bin's flakeIgnore replaces pycodestyle's defaults, so W503
(normally off) became a build error on the `and` line break split across
two continuation lines in capacity_check()'s `pending` comprehension --
caught by CI's native-checks build, not by anything runnable without Nix.
Rewritten as three `if` clauses (implicitly ANDed in a comprehension),
which sidesteps the rule instead of choosing a side of it.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0188bYSAQvRmVjNDtsgznirR
CI's VM (sessions) lane caught what the native tests couldn't: excluding
a `died` entry from `pending` (not just from counting against everyone
else) made it structurally impossible for the supervisor to ever
re-admit that SAME name. `agent-box-session restart` on a died session
kills its old pane and relies on the supervisor's own spawn admission to
start a fresh one and clear the flag -- but with the died name absent
from `pending`, it could never again appear in `admitted`, so the
restart hung forever (CI: "a spawn clears a stale died flag" timed out
at 120s).

Keep `pending` unfiltered (a died entry stays a valid candidate for its
own restart), and instead exclude `died` names only from `used` (the
total charged against the limit) and from the `live` count `available`
subtracts -- so a died session's corpse still doesn't cost anyone ELSE a
slot, but remains admissible for itself. Added a regression test at the
unit level (`test_died_entry_remains_its_own_revival_candidate`) so this
deadlock shape doesn't need a 12-minute VM run to catch again.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0188bYSAQvRmVjNDtsgznirR
@defangdevs
defangdevs merged commit 0e85416 into master Sep 11, 2026
7 checks passed
@defangdevs
defangdevs deleted the fix/523-died-hook-cap branch September 11, 2026 23:11
@github-project-automation github-project-automation Bot moved this from Backlog to Done in Agent-Box Sep 11, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

A died hook-* session holds dispatch capacity for good, and now we can tell

1 participant