Skip to content

fix(desktop): repair dropped team membership links at boot and on edit - #5904

Merged
wesbillman merged 7 commits into
mainfrom
duncan/team-membership-repair
Aug 17, 2026
Merged

fix(desktop): repair dropped team membership links at boot and on edit#5904
wesbillman merged 7 commits into
mainfrom
duncan/team-membership-repair

Conversation

@wpfleger96

@wpfleger96 wpfleger96 commented Aug 14, 2026

Copy link
Copy Markdown
Member

Two membership-propagation defects let an agent team silently lose members — both observed live on Will's store (Sietch Tabr), not hypothetical.

Stale persona_ids dropped on save. Team records written before persona ids were namespaced hold bare slugs (thufir) instead of the namespaced id (sietch-tabr:thufir). Nothing rewrites them, and the interactive save path (ensure_persona_ids_are_active) drops any id it cannot resolve — so the next in-app save shrinks the team. This nuked four of five Sietch Tabr members.

team_id drifts from team membership. Team instructions are injected at spawn by matching record.team_id (spawn_snapshot::effective_team_instructions), so an instance's binding must track its persona's membership. It drifts two ways: adding a persona to a team leaves the persona's already-running instances at team_id: null (a member in the roster but not in behavior — seen twice, Gurney and Hayt), and removing a persona while keeping its agents leaves the kept instance bound to a team that no longer lists it (still drawing that team's instructions at spawn).

Fix

A boot migration (migration/team_membership.rs) heals existing stores in one pass over teams.json + managed-agents.json:

  • Rewrite stale ids. A stale id is one no definition slug resolves. Its target is the definition whose source_team_persona_slug equals the bare slug, scoped to the team's source team (via source_dir for a directory-backed team, or the unique source_team among resolvable members for a detached one). Rewrite only when exactly one candidate matches; zero or many leave the id in place — strictly safer than the save path, which drops it.
  • Repair team_id. Backfill an instance whose persona is a team member but whose own binding is unset, and heal a stale binding whose team no longer lists the persona (re-point when exactly one other team claims it, otherwise unbind). Both directions gate on single-team evidence — a persona spanning several teams has none (JSON team order is not ownership), so it is left as-is and logged. A binding whose team still lists the persona is authoritative and never touched.

Runs BEFORE detach_directory_backed_teams (so a not-yet-detached team can still be scoped by its source_dir) and before any UI save can drop an id. Rewrite-or-leave converges to a fixed point, so a second boot is a no-op; the store is backed up once before either write.

The edit path (commands/teams.rs) propagates a membership change to live instances immediately, without waiting for the next boot, scoped to the delta between the pre-edit and post-edit rosters:

  • Added personas (on the team now, not before) backfill team_id on their unbound instances. An explicit add is legitimate binding evidence even for a persona shared across teams — unlike the order-blind boot case.
  • Removed personas (on the team before, not now) clear team_id on instances bound to this team (bindings to other teams are untouched), so a "keep agents" removal stops feeding a kept instance the old team's instructions.
  • Delta-scoping keeps a metadata-only edit inert: with no roster change, no instance is re-pointed — a shared unbound persona is never silently bound to whichever team was edited last.

Propagation is best-effort after the authoritative save_teams (mirroring retain_team_pending): the team already exists on disk, and boot repair is the designed retry for a stale/unset binding, so a secondary managed-agents.json write failure no longer fails a command whose team write succeeded — which would otherwise let a UI retry mint a duplicate team.

Two membership-propagation defects let a team lose members silently:

- Team `persona_ids` written before ids were namespaced hold bare slugs
  (`thufir` vs `sietch-tabr:thufir`). The interactive save path
  (`ensure_persona_ids_are_active`) *drops* an id it cannot resolve,
  shrinking the team on the next save.
- Adding a standalone persona to a team records it on the team but does
  not backfill `team_id` on the persona's running instances, so team
  instructions (`spawn_snapshot::effective_team_instructions`, keyed on
  `record.team_id`) are skipped at spawn — a member in name only.

Add a boot migration that rewrites a stale id to the persona it
unambiguously names and backfills `team_id` on orphaned instances. It
runs before `detach_directory_backed_teams` (so a not-yet-detached team
can still be scoped by its `source_dir`) and before any UI save can drop
an id. Rewrite-or-leave and set-if-unset make a second boot a no-op;
never drops an id it cannot resolve.

Close the source of the second defect in `create_team`/`update_team`:
backfill member instances' `team_id` immediately after `save_teams`.

Co-authored-by: Will Pfleger <pfleger.will@gmail.com>
Signed-off-by: Will Pfleger <pfleger.will@gmail.com>
@wpfleger96
wpfleger96 requested a review from a team as a code owner August 14, 2026 20:19
Duncan and others added 2 commits August 14, 2026 17:06
Pass-1 review found two correctness gaps in the boot repair:

- Startup relay replay could non-deterministically undo the repair.
  `apply_workspace` only *spawned* the disk->retention reconcile and
  returned, so the frontend history fetch could replay a stale relay
  team head and overwrite the repaired `persona_ids` before the
  repaired head was retained. Await the reconcile (on `spawn_blocking`)
  before `apply_workspace` resolves, so the repaired head is durably
  retained with a superseding `monotonic_created_at` and the inbound
  equal/older guard rejects the stale head.

- Boot `team_id` backfill bound an unbound shared persona to an
  arbitrary team (first-team-wins). The product permits one persona
  under multiple teams with distinct instructions, so JSON team order
  is not ownership evidence. Backfill only when exactly one team
  references the persona; leave and log zero-or-multiple.

Co-authored-by: Will Pfleger <pfleger.will@gmail.com>
Signed-off-by: Will Pfleger <pfleger.will@gmail.com>
…uity

Pass-2 review found two IMPORTANT residuals:

- The awaited reconcile was not a success barrier. `run_event_sync`
  and its team leg logged and swallowed every failure, so
  `apply_workspace` could still return `Ok`, expose the community, and
  let a stale inbound relay head overwrite the repaired roster before a
  superseding head was retained. Make the team leg fatal: `run_event_sync`
  and `run_event_sync_blocking` return `Result`, and `apply_workspace`
  propagates it — including a failed scope resolution, a prerequisite for
  the superseding head. Persona/agent/legacy-adopt legs stay best-effort.

- Ambiguity poisoning fired on every second occurrence of a persona id,
  including a duplicate within one team. Since the storage boundary does
  not dedupe `persona_ids`, a same-team repeat stranded a legitimately
  single-team instance. Poison only when a *distinct* team id is seen.

Also correct the ordering test's name/comment (it proves retention
precedence, not the `apply_workspace` await) and add an error-contract
test for the fatal team leg plus a same-team-duplicate regression.

Co-authored-by: Will Pfleger <pfleger.will@gmail.com>
Signed-off-by: Will Pfleger <pfleger.will@gmail.com>

@themiguelamador themiguelamador left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

I found four remaining correctness issues in the membership propagation path:

  1. update_team backfills against the entire final roster, rather than the membership delta. A metadata-only edit can therefore bind every unbound instance of a persona shared by several teams to whichever team happened to be edited, contradicting the PR's own rule that JSON/team order is not ownership evidence.
  2. The inverse transition is not propagated. Removing a persona and choosing the UI's “Keep agents” path leaves those instances' team_id pointing at the old team, so they continue receiving instructions for a team they no longer belong to.
  3. create_team/update_team commit teams.json and then propagate ? from a second, fallible managed-agents.json write. If that secondary write fails, the command reports failure even though its authoritative mutation already succeeded; retrying a create can produce a duplicate team. The secondary propagation must be best-effort (with boot repair as its retry path), or both stores need a real transaction.
  4. Successful create/update operations still do not schedule nest regeneration, leaving generated team/member context stale until an unrelated regeneration trigger or restart.

The repair branch makes propagation transition-aware, detaches removed-but-kept agents, adds boot repair for stale bindings, preserves an already-committed command result if the secondary store fails, and regenerates the nest after successful edits.

Verified: 21 team command/storage tests; 14 membership-migration tests; 7 team-event reconciliation tests plus the stale-inbound ordering regression; strict Tauri Clippy with -D warnings; Rust formatting; desktop file-size gate.

Fix commit: https://github.com/Complear/buzz/commit/c0335e320
Branch: https://github.com/Complear/buzz/tree/review/pr-5904-fix

Duncan and others added 2 commits August 17, 2026 11:44
An outside review of the team-membership repair surfaced three defects in
the edit-time propagation:

- update_team backfilled team_id against the whole final roster on every
  edit, so a metadata-only edit of one team could bind an unbound instance
  of a persona shared across teams to whichever team was touched last —
  contradicting the boot-repair doctrine that a multi-team persona has no
  ownership evidence. Backfill is now scoped to the personas *added* in this
  edit; an explicit add stays legitimate evidence even for a shared persona.
- Removing a persona while keeping its agents left the kept instance bound
  to the old team, so effective_team_instructions kept feeding it that
  team's instructions at spawn. update_team now detaches instances whose
  persona left the roster (only bindings to this team), and boot repair
  heals an already-stale binding — re-pointing on single-team evidence,
  else unbinding.
- create_team/update_team propagated the secondary managed-agents.json
  write with ?, failing a command whose authoritative team write already
  succeeded and letting a UI retry mint a duplicate team. The propagation
  is now best-effort after save_teams, mirroring retain_team_pending, since
  boot repair is the designed retry for a stale/unset binding.

Co-authored-by: Will Pfleger <pfleger.will@gmail.com>
Signed-off-by: Will Pfleger <pfleger.will@gmail.com>
The five existing tests exercise apply_team_membership_delta directly, so
a call-site miswire passing the wrong prior roster went undetected. Extract
AppHandle-free commit_team_create/commit_team_update orchestration cores with
injected persistence, then add wiring tests that catch it: passing &[] instead
of the captured previous roster now turns the suite RED.

Co-authored-by: Will Pfleger <pfleger.will@gmail.com>
Signed-off-by: Will Pfleger <pfleger.will@gmail.com>

@wesbillman wesbillman left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Carl, an automated reviewer, commenting via Wes’s GitHub account.

Requesting changes on exact head 4469210b5deb07109a92f2b02b87496887bc5928 for two remaining correctness gaps:

  1. Inbound team edits still leave live instance bindings stale. The local create_team/update_team paths apply the prior-to-current roster delta to ManagedAgentRecord.team_id, but the kind:30176 ingress in commands/personas/inbound.rs only merges the team and saves teams.json (169-173; merge at 444-461). A team edit arriving from another device can therefore add a persona without binding its existing instances, or remove a persona while those instances remain bound and continue receiving the old team's instructions until restart. Capture the prior roster and apply the same add/backfill and remove/detach semantics under the existing store lock, with inbound regressions for both transitions.

  2. A repair failure can destroy the evidence required for a later repair. repair_team_membership logs and swallows every error (migration/team_membership.rs:39-49), then boot unconditionally runs detach_directory_backed_teams (migration.rs:188-189). For a stale bare slug shared by definitions from multiple source teams, source_dir is the evidence that makes the rewrite unambiguous. If backup or write fails, detachment clears that evidence; the next boot may only see ambiguous global candidates and leave the stale ID unresolved, allowing the original membership-loss path to recur. Gate detachment on successful repair (at minimum skip it for that boot) and add an orchestration regression proving failure preserves source_dir for a successful retry.

There is also a recovery-contract mismatch worth fixing with the second item: team_membership.rs:84-88 says both pristine backups are captured before either live write, but the implementation writes teams.json before creating the managed-agents backup (89-107). Create every required backup before the first live-store write, or narrow the stated recovery guarantee.

The local command delta logic, conservative multi-team ambiguity handling, stale-inbound retention precedence, and fatal startup reconcile barrier otherwise look disciplined. GitHub's exact-head checks were all successful when inspected (24 successful, Web skipped); I did not duplicate CI-equivalent suites locally.

Duncan and others added 2 commits August 17, 2026 14:43
…pair

Three CHANGES_REQUESTED findings on the team-membership-repair work:

Inbound 30176 team edits landed on teams.json but never touched
ManagedAgentRecord.team_id, so a remote add left running instances unbound
and a remote remove left them drawing the old team's instructions until
restart. Route the inbound KIND_TEAM arm through a new AppHandle-free
commit_inbound_team core that captures the prior roster, applies the
projection, persists teams, then reuses the local command path's
propagate_membership_best_effort to apply the add/backfill + remove/detach
delta under the existing store lock.

Boot detach ran unconditionally after repair; a failed repair whose backup
or write errored would still have its source_dir cleared by detach,
destroying the disambiguating evidence a retry needs and letting the
membership-loss path recur. Gate detach on a successful repair via a shared
orchestrate_repair_then_detach seam.

The repair backups violated their stated contract (both pristine backups
before either live write): teams.json was rewritten before the
managed-agents.json backup was taken, so a crash between the two writes left
an incomplete recovery pair. Reorder so both backups precede either store
write.

Co-authored-by: Will Pfleger <pfleger.will@gmail.com>
Signed-off-by: Will Pfleger <pfleger.will@gmail.com>
…p-repair

* origin/main:
  Rename Bumble agent to Pollen (#5864)
  fix(desktop): resolve agent profiles through one archive-aware selector (#5706)
  fix(acp): gate relay-signed workflow messages on their attributed author (#6129)
  fix(acp): replace Goose native system prompt (#5964)
  feat(workflows): add responsive library card actions (#6008)
  fix(desktop): enforce shared agent access across devices (#6086)
  feat(model-capabilities): drive model capabilities and labels from one manifest (#5597)
  docs: refresh agent development guidance (#6049)
  feat(mobile): require device authentication for identity export (#5116)
  fix(desktop): hide the offcanvas-collapsed sidebar so it stops painting over the community rail (#5947)
  Polish mobile message threads and composer (#5645)
  chore(release): release Buzz Desktop version 0.5.14 (#5917)
  ci(release): remove desktop smoke gate (#5914)
  chore(release): release Buzz Desktop version 0.5.13 (#5912)
  fix(ci): read Playwright version without nested shell quoting (#5910)
  fix(desktop): restore the agent trading-card mint button (#5900)
  Projects v3: unify sharing, discussions, and issue ownership (#5792)
  chore(release): release Buzz Desktop version 0.5.12 (#5903)
  fix(mobile): unwrap batched observer telemetry (#5805)
  perf(desktop): update active turns incrementally (#5897)

Signed-off-by: Duncan <dcfd242e557282d7a1e2cf2e6877522682f1e5c6156dc92ca7d90eaedd3b0f95@buzz.block.builderlab.xyz>

# Conflicts:
#	desktop/src-tauri/src/migration.rs

@wesbillman wesbillman left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Carl, an automated reviewer, commenting via Wes’s GitHub account.

Approved exact head 48db98a41bdaebcb58284ae9411666f1fc6ff1eb after consolidated Royal Court review.

The corrective commits close the prior blockers:

  • inbound kind:30176 edits now propagate the prior-to-current roster delta to live instance bindings under the existing store lock;
  • repair failure skips directory-backed detachment, preserving source_dir as retry evidence;
  • every required pristine backup is created before either live store is rewritten;
  • local and inbound propagation are delta-scoped and secondary agent-store writes remain best-effort after the authoritative team write;
  • workspace apply awaits the fatal team-event retention barrier before inbound replay can expose a stale relay head.

The boot repair remains conservative for ambiguous multi-team ownership, and generated nest context does not render team membership or instructions, so no team-triggered nest regeneration is required.

All applicable exact-head checks passed. I also verified Rust formatting and git diff --check locally. A focused local Rust test attempt could not start because the review checkout intentionally lacks the generated desktop/src-tauri/binaries/buzz-acp-aarch64-apple-darwin resource; I relied on the passing exact-head Desktop Core, Rust Lint, macOS/Windows build, smoke, and integration CI jobs rather than fabricating a binary into the review tree.

@wesbillman
wesbillman merged commit 57feca2 into main Aug 17, 2026
24 checks passed
@wesbillman
wesbillman deleted the duncan/team-membership-repair branch August 17, 2026 21:44
wpfleger96 pushed a commit that referenced this pull request Aug 17, 2026
…gaps

* origin/main:
  fix(desktop): align preview sidebar row styling (#6163)
  fix(desktop): repair dropped team membership links at boot and on edit (#5904)
  fix(cli): keep project replacement timestamps at or after wall clock (#5666)
  Remove GitHub security advisory commitment (#6144)
  Rename Bumble agent to Pollen (#5864)
  fix(desktop): resolve agent profiles through one archive-aware selector (#5706)
  fix(acp): gate relay-signed workflow messages on their attributed author (#6129)
  fix(acp): replace Goose native system prompt (#5964)
  feat(workflows): add responsive library card actions (#6008)
  fix(desktop): enforce shared agent access across devices (#6086)

Signed-off-by: Duncan <dcfd242e557282d7a1e2cf2e6877522682f1e5c6156dc92ca7d90eaedd3b0f95@buzz.block.builderlab.xyz>
morgmart added a commit that referenced this pull request Aug 18, 2026
…graphy-staging

* origin/main:
  test(desktop): cover exact workflow batch limit (#6168)
  chore(release): release Buzz Desktop version 0.5.15 (#6173)
  Preserve managed agent mentions during relay errors (#6167)
  fix(workflows): preserve multi-channel listing semantics (#6009)
  Remove Startup Recovery section in base prompt (#6161)
  fix(desktop): align preview sidebar row styling (#6163)
  fix(desktop): repair dropped team membership links at boot and on edit (#5904)
  fix(cli): keep project replacement timestamps at or after wall clock (#5666)

Signed-off-by: morgmart <98432065+morgmart@users.noreply.github.com>
wolfyy970 added a commit to wolfyy970/buzz that referenced this pull request Aug 18, 2026
block#5904 added membership propagation on team create/update/inbound. The
rebase onto that must keep those agent-store imports next to the
reviewable-text check.

Signed-off-by: KC <79471844+wolfyy970@users.noreply.github.com>
wpfleger96 pushed a commit that referenced this pull request Aug 18, 2026
…arer-auth

* origin/main: (21 commits)
  fix(desktop): bind presence retry timers (#6213)
  ci: make file-size policy a first-class gate (#6187)
  fix(desktop): eliminate mounted-view CPU burn — compositor-safe shimmer, observer append fast path, poll-tick disk reads (#6198)
  chore(release): release Buzz Desktop version 0.5.16 (#6191)
  fix(desktop): restore release agent mentions (#6182)
  test(desktop): cover exact workflow batch limit (#6168)
  chore(release): release Buzz Desktop version 0.5.15 (#6173)
  Preserve managed agent mentions during relay errors (#6167)
  fix(workflows): preserve multi-channel listing semantics (#6009)
  Remove Startup Recovery section in base prompt (#6161)
  fix(desktop): align preview sidebar row styling (#6163)
  fix(desktop): repair dropped team membership links at boot and on edit (#5904)
  fix(cli): keep project replacement timestamps at or after wall clock (#5666)
  Remove GitHub security advisory commitment (#6144)
  Rename Bumble agent to Pollen (#5864)
  fix(desktop): resolve agent profiles through one archive-aware selector (#5706)
  fix(acp): gate relay-signed workflow messages on their attributed author (#6129)
  fix(acp): replace Goose native system prompt (#5964)
  feat(workflows): add responsive library card actions (#6008)
  fix(desktop): enforce shared agent access across devices (#6086)
  ...

Signed-off-by: Duncan <dcfd242e557282d7a1e2cf2e6877522682f1e5c6156dc92ca7d90eaedd3b0f95@buzz.block.builderlab.xyz>

# Conflicts:
#	CHANGELOG.md
tlongwell-block pushed a commit that referenced this pull request Aug 18, 2026
Co-authored-by: Wren <5217c5c2f7bfb4333e46d17c98a9255a52dadee18dcd43a43536b95e6776dfa0@buzz.block.builderlab.xyz>
Signed-off-by: Wren <5217c5c2f7bfb4333e46d17c98a9255a52dadee18dcd43a43536b95e6776dfa0@buzz.block.builderlab.xyz>

* origin/main:
  fix(desktop): bind presence retry timers (#6213)
  ci: make file-size policy a first-class gate (#6187)
  fix(desktop): eliminate mounted-view CPU burn — compositor-safe shimmer, observer append fast path, poll-tick disk reads (#6198)
  chore(release): release Buzz Desktop version 0.5.16 (#6191)
  fix(desktop): restore release agent mentions (#6182)
  test(desktop): cover exact workflow batch limit (#6168)
  chore(release): release Buzz Desktop version 0.5.15 (#6173)
  Preserve managed agent mentions during relay errors (#6167)
  fix(workflows): preserve multi-channel listing semantics (#6009)
  Remove Startup Recovery section in base prompt (#6161)
  fix(desktop): align preview sidebar row styling (#6163)
  fix(desktop): repair dropped team membership links at boot and on edit (#5904)

Signed-off-by: Wren <5217c5c2f7bfb4333e46d17c98a9255a52dadee18dcd43a43536b95e6776dfa0@buzz.block.builderlab.xyz>
mfethe1 pushed a commit to mfethe1/buzz that referenced this pull request Aug 18, 2026
…nvariant

The `::` card-key separator is safe because the left segment cannot contain it.
That comment enumerated three persona-id shapes; block#5904 introduced a fourth,
`<store-slug>:<persona-slug>`, when it migrated team membership onto namespaced
ids.

The invariant still holds — `slugify` maps every non-alphanumeric to `-`, so
neither half of that form can carry a colon and the whole id has exactly one —
but a reader checking the claim against current `main` would find a shape the
comment does not mention and reasonably doubt the rest of it. Stating the rule
(at most one colon, because every shape is slug-constrained) rather than listing
cases also stops the comment going stale on the fifth shape.

Signed-off-by: Michael Feth <michael@jira-flow.com>
bhargavms pushed a commit to EWA-Services/buzz that referenced this pull request Aug 18, 2026
block#5904)

Two membership-propagation defects let an agent team silently lose
members — both observed live on Will's store (Sietch Tabr), not
hypothetical.

**Stale `persona_ids` dropped on save.** Team records written before
persona ids were namespaced hold bare slugs (`thufir`) instead of the
namespaced id (`sietch-tabr:thufir`). Nothing rewrites them, and the
interactive save path (`ensure_persona_ids_are_active`) *drops* any id
it cannot resolve — so the next in-app save shrinks the team. This nuked
four of five Sietch Tabr members.

**`team_id` drifts from team membership.** Team instructions are
injected at spawn by matching `record.team_id`
(`spawn_snapshot::effective_team_instructions`), so an instance's
binding must track its persona's membership. It drifts two ways: adding
a persona to a team leaves the persona's already-running instances at
`team_id: null` (a member in the roster but not in behavior — seen
twice, Gurney and Hayt), and removing a persona while keeping its agents
leaves the kept instance bound to a team that no longer lists it (still
drawing that team's instructions at spawn).

## Fix

A boot migration (`migration/team_membership.rs`) heals existing stores
in one pass over `teams.json` + `managed-agents.json`:

- **Rewrite stale ids.** A stale id is one no definition slug resolves.
Its target is the definition whose `source_team_persona_slug` equals the
bare slug, scoped to the team's source team (via `source_dir` for a
directory-backed team, or the unique `source_team` among resolvable
members for a detached one). Rewrite only when exactly one candidate
matches; zero or many leave the id in place — strictly safer than the
save path, which drops it.
- **Repair `team_id`.** Backfill an instance whose persona is a team
member but whose own binding is unset, and heal a stale binding whose
team no longer lists the persona (re-point when exactly one *other* team
claims it, otherwise unbind). Both directions gate on single-team
evidence — a persona spanning several teams has none (JSON team order is
not ownership), so it is left as-is and logged. A binding whose team
still lists the persona is authoritative and never touched.

Runs BEFORE `detach_directory_backed_teams` (so a not-yet-detached team
can still be scoped by its `source_dir`) and before any UI save can drop
an id. Rewrite-or-leave converges to a fixed point, so a second boot is
a no-op; the store is backed up once before either write.

The edit path (`commands/teams.rs`) propagates a membership change to
live instances immediately, without waiting for the next boot, scoped to
the delta between the pre-edit and post-edit rosters:

- **Added personas** (on the team now, not before) backfill `team_id` on
their unbound instances. An explicit add is legitimate binding evidence
even for a persona shared across teams — unlike the order-blind boot
case.
- **Removed personas** (on the team before, not now) clear `team_id` on
instances bound to *this* team (bindings to other teams are untouched),
so a "keep agents" removal stops feeding a kept instance the old team's
instructions.
- **Delta-scoping keeps a metadata-only edit inert:** with no roster
change, no instance is re-pointed — a shared unbound persona is never
silently bound to whichever team was edited last.

Propagation is best-effort after the authoritative `save_teams`
(mirroring `retain_team_pending`): the team already exists on disk, and
boot repair is the designed retry for a stale/unset binding, so a
secondary `managed-agents.json` write failure no longer fails a command
whose team write succeeded — which would otherwise let a UI retry mint a
duplicate team.

---------

Signed-off-by: Will Pfleger <pfleger.will@gmail.com>
Co-authored-by: Duncan <dcfd242e557282d7a1e2cf2e6877522682f1e5c6156dc92ca7d90eaedd3b0f95@buzz.block.builderlab.xyz>
Signed-off-by: bhargavms <bhargav.m@ewa-services.com>
sandro-sq added a commit that referenced this pull request Aug 18, 2026
* origin/main: (78 commits)
  Polish mobile timeline navigation (#5874)
  chore(release): release Buzz Desktop version 0.5.17 (#6234)
  fix(prompt): simplify pickup follow-through (#6186)
  fix(mcp): scope todo usage (#6216)
  fix(desktop): bound remote agent mention authorization (#6224)
  fix: bump h2 for RUSTSEC-2026-0258 (#6222)
  fix(desktop): bind presence retry timers (#6213)
  ci: make file-size policy a first-class gate (#6187)
  fix(desktop): eliminate mounted-view CPU burn — compositor-safe shimmer, observer append fast path, poll-tick disk reads (#6198)
  chore(release): release Buzz Desktop version 0.5.16 (#6191)
  fix(desktop): restore release agent mentions (#6182)
  test(desktop): cover exact workflow batch limit (#6168)
  chore(release): release Buzz Desktop version 0.5.15 (#6173)
  Preserve managed agent mentions during relay errors (#6167)
  fix(workflows): preserve multi-channel listing semantics (#6009)
  Remove Startup Recovery section in base prompt (#6161)
  fix(desktop): align preview sidebar row styling (#6163)
  fix(desktop): repair dropped team membership links at boot and on edit (#5904)
  fix(cli): keep project replacement timestamps at or after wall clock (#5666)
  Remove GitHub security advisory commitment (#6144)
  ...

Signed-off-by: Alessandro Joabar <sandro@squareup.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.

3 participants