fix(agent-team): harden listener respawn/close, broaden handle_event guard, channel_ref partial-unique #29
No reviewers
Labels
No labels
app
bug
ci
compliance
content
dependencies
docs
documentation
duplicate
enhancement
github_actions
good first issue
help wanted
infra
invalid
javascript
needs-triage
python
question
tests
wontfix
No milestone
No project
No assignees
1 participant
Due date
No due date set.
Dependencies
No dependencies set.
Reference: adam/orchestrator#29
Loading…
Add table
Reference in a new issue
No description provided.
Delete branch "fix/agent-team-listener-robustness"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Three robustness hardening fixes to the agent-team listener/coordinator/ledger, surfaced by earlier
/sh-security-reviewpasses.Changes
close()leak (CWE-772) —coordinator.py:_supervise_slack_listenercloses the dead listener (_close_dead_listener) before respawning, and_run_listenercloses in afinally(binding a local first so a concurrent respawn can't close the wrong handle). Stops Socket Mode socket/thread leaks on repeated flaps.handle_eventguard —slack_listener.py: aexcept Exception(after the existingexcept ValueError) logs WARNING (exc_info) and returnsNone, so aKeyError/sqlite3.Errorfrom_question_turn/_question_threadcan't escape and kill the listener thread. Authorization still runs first; never fabricates acceptance.channel_refpartial-unique —db/schema.py/schema.sql:UNIQUE INDEX ... ON pending_questions(channel_ref) WHERE channel_ref IS NOT NULL AND status='open', ininit_db+migrate(idempotent). Defense-in-depth so two open rows can never share a channel_ref.Verification
/sh-security-review: PASS — detector fan-out (authz/injection/logic) zero findings. Auth-first preserved; broad except returns None only; close-before-respawn race-safe + idempotent; index consistent with all notify/reopen/redeliver paths; DDL static; no log leak (literal message, exc_info exposes no answer content/tokens).ruff check .+ruff format --check .clean;pytest(agent-team) 968 passed (+8 regression tests: respawn-close, crash-finally-close, KeyError/sqlite3.Error swallow, partial-unique reject/allow-nulls/ignore-closed/migrate).Migration note
migrate()installs the partial index unconditionally (idempotentIF NOT EXISTS) so existing v1 DBs get it. It would raiseIntegrityErrorloudly only on a legacy DB holding a genuine duplicate open channel_ref (none expected; this is fail-loud, not fail-silent).Non-blocking follow-up (from the review)
If a post-accept helper raises after the CAS flip but before
enqueue_resume, the broad except swallows it → the answer is stuck until the nextrecover()sweep. Worth a small follow-up (enqueue before the helper calls, or recover-on-tick).