Skip to content

fix(native-teams): unregisterNativeMember actually removes the entry - #1180

Merged
namastex888 merged 1 commit into
devfrom
fix/native-team-kill-removes-member
Apr 18, 2026
Merged

namastex888 merged 1 commit into
devfrom
fix/native-team-kill-removes-member

Conversation

@automagik-genie

Copy link
Copy Markdown
Contributor

Closes #1179.

Summary

`unregisterNativeMember` marked `isActive: false` and left the member in the array. No reader consults inactive entries for history, but two active readers silently pick them up:

  1. `resolveNativeMemberName` has an explicit active→inactive fallback (see existing test "prefers active members over inactive"). A stale entry from a prior team membership silently claims messages addressed by name.
  2. `findTeamsContainingAgent` — the spawn-resolver tier 5 from feat(tui-spawn-dx): CLI-symmetric agent/team primitives + canonical-UUID invariant #1172 — matches members by `name` regardless of `isActive`. A stale entry routes future spawns into the wrong team.

Observed live: `~/.claude/teams/genie/config.json` had 5 members after a spawn-storm — 2 real plus 3 killed workers all `isActive: false`. Every bare `genie spawn ` hit the stale fallback chain before resolving. Manually purging the file stopped the ghost `teammate-message` announcements.

Fix

`unregisterNativeMember` now removes the member from the array. The per-member inbox at `~/.claude/teams//inboxes/.json` is already cleared by `clearNativeInbox` (called sibling to this in the kill path), so no residual state is worth preserving.

Tests

5 new cases in `claude-native-teams.test.ts`:

  • `removes the member entry entirely (not just isActive flip)`
  • `is a no-op when the member does not exist`
  • `is a no-op when the team does not exist`
  • `findTeamsContainingAgent stops matching after unregister (regression)`
  • `resolveNativeMemberName stops resolving after unregister (regression)`

The existing `'prefers active members over inactive'` test still passes — `resolveNativeMemberName`'s fallback logic is unchanged; it just never fires because unregistered members are no longer in the array.

Full suite: 2601 pass / 0 fail.

Test plan

  • Unit tests cover the 5 cases above
  • Full repo test suite passes locally
  • CI on `dev` target green
  • Manual verification: spawn a worker, kill it, inspect `~/.claude/teams//config.json` — the worker's entry is gone (previously was `isActive: false`).

🤖 Generated with Claude Code

Closes #1179.

`unregisterNativeMember` marked `isActive: false` and left the member in
the array, citing "preserves history". No reader consults inactive
entries for history. Two real readers do pick them up, silently:

  1. `resolveNativeMemberName` has an explicit active→inactive fallback
     (test: "prefers active members over inactive"). A stale entry from
     a prior team membership silently claims messages addressed by name.
  2. `findTeamsContainingAgent` — the spawn-resolver tier 5 — matches
     members by `name` regardless of `isActive`. A stale entry routes
     future spawns into the wrong team.

Observed on a live server: `~/.claude/teams/genie/config.json` had 5
members from a spawn-storm — 2 real plus 3 killed workers (simone@genie,
patch-test@genie, genie-3@genie) all `isActive: false`. Every bare
`genie spawn <name>` hit the stale fallback chain before resolving.

Fix: remove the member from the array. The per-member inbox at
~/.claude/teams/<team>/inboxes/<name>.json is cleared by
`clearNativeInbox` (called sibling to this in the kill path), so no
residual state is worth preserving.

Tests: 5 new cases in claude-native-teams.test.ts (basic removal,
no-op on missing member, no-op on missing team, findTeamsContainingAgent
regression, resolveNativeMemberName regression). Full suite: 2601/2601.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Apr 18, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 2391cab3-57eb-4272-820b-7b933143c6e7

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/native-team-kill-removes-member

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 and usage tips.

@namastex888
namastex888 merged commit 58326f9 into dev Apr 18, 2026
6 checks passed

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Code Review

This pull request modifies the unregisterNativeMember function to completely remove member entries from the team configuration instead of simply marking them as inactive. This change addresses issues where stale, inactive entries were still being processed by other system components. Accompanying tests have been added to ensure correct behavior and prevent regressions. Feedback suggests that the isActive property and related fallback logic may now be obsolete and should be considered for removal in future maintenance.

Comment on lines +492 to +497
* Removes the member entry from the `members` array. The prior implementation
* marked `isActive: false` "to preserve history", but no call site ever
* consults inactive members for history — meanwhile two active readers
* (`resolveNativeMemberName`'s active→inactive fallback and
* `findTeamsContainingAgent`'s team-resolver tier 5) silently pick up stale
* entries, routing messages and spawn-team resolution to the wrong worker.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

medium

Since unregisterNativeMember now removes the member from the array instead of marking it as inactive, the isActive property on the NativeTeamMember interface and its associated logic in other functions (such as the fallback in resolveNativeMemberName) appear to be redundant. While out of scope for this immediate fix, consider cleaning these up in a future PR to improve maintainability and avoid confusion about the existence of 'inactive' members.

@automagik-genie
automagik-genie deleted the fix/native-team-kill-removes-member branch September 25, 2026 04:50
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