[4/4] buzz teams: group published personas into rosters - #5845
Open
Maxwellimus wants to merge 1 commit into
Open
[4/4] buzz teams: group published personas into rosters#5845Maxwellimus wants to merge 1 commit into
Maxwellimus wants to merge 1 commit into
Conversation
Maxwellimus
marked this pull request as ready for review
August 14, 2026 06:22
Maxwellimus
force-pushed
the
maxwell/cli-teams
branch
from
August 14, 2026 18:39
99a2f1f to
2fa2150
Compare
Maxwellimus
force-pushed
the
maxwell/cli-teams
branch
2 times, most recently
from
August 14, 2026 19:59
8b726c0 to
ccd1e37
Compare
Maxwellimus
force-pushed
the
maxwell/cli-teams
branch
from
August 15, 2026 00:29
ccd1e37 to
6c4e387
Compare
Completes the definition surface: `buzz teams create|list|get|delete` writes kind:30176 over the personas from [3/4], from flags or a Desktop `.team.json` export. Membership resolution is the load-bearing part. A team event stores persona d-tags, and Desktop publishes personas under their record id — usually a UUID — while its team export names members only by display name. Matching on the slugified name would therefore resolve nothing for every Desktop-exported roster. `--persona` accepts a d-tag, a slugified d-tag, or a unique display name, in that order; an ambiguous display name is an error rather than a guess, and a member with no published persona is refused rather than published as a seat that silently stays empty. A team id is used verbatim, never normalized. The relay enforces the slug grammar on persona d-tags but only a length bound on team ids, and Desktop writes raw UUIDs and ids like `builtin-team:welcome` — normalizing would address a different coordinate than the one Desktop published, making its teams unreachable. Since kind:30176 has no envelope validator on the relay, the CLI is the only guard against a blank or oversized id. `instructions` and `persona_ids` are always published. On the wire an absent field means "publisher predates always-publish, membership unknown, preserve local" — distinct from an explicit empty. A new client must never claim the former, or a write meant to clear a roster reads as "leave it alone" and one meant to leave it alone wipes it. The e2e suite gains the relay rule the delete path depends on: a tombstone older than its target head is accepted, deletes nothing, and still reports OK. Signed-off-by: Max Lampert <maxwell@squareup.com>
Maxwellimus
force-pushed
the
maxwell/cli-teams
branch
from
August 15, 2026 00:40
6c4e387 to
6472616
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Completes the definition surface:
buzz teams create|list|get|deletewriteskind:30176 over the personas from [3/4], from flags or a Desktop
.team.jsonexport.
Membership resolution
The load-bearing part. A team event stores persona d-tags, and Desktop publishes
personas under their record id — usually a UUID — while its team export names
members only by display name. Matching on the slugified name would therefore
resolve nothing for every Desktop-exported roster.
--personaaccepts a d-tag, a slugified d-tag, or a unique display name, inthat order. An ambiguous display name is an error rather than a guess, and a
member with no published persona is refused rather than published as a seat that
silently stays empty.
Team ids are used verbatim
The relay enforces the slug grammar on persona d-tags but only a length bound on
team ids, and Desktop writes raw UUIDs and ids like
builtin-team:welcome.Normalizing would address a different coordinate than the one Desktop published,
making its teams unreachable. Since kind:30176 has no envelope validator on the
relay, the CLI is the only guard against a blank or oversized id.
The one id
createdoes slugify is one it derives from--name, soteams get "Red team"misses thered-teamit just wrote. Reads stay verbatim —normalizing them is what would break Desktop's ids — so the not-found error names
the slug instead.
Always-publish for
instructionsandpersona_idsOn the wire an absent field means "publisher predates always-publish, membership
unknown, preserve local" — distinct from an explicit empty. A new client must
never claim the former, or a write meant to clear a roster reads as "leave it
alone" and one meant to leave it alone wipes it.
Test plan
just cicrates/buzz-test-client/tests/e2e_team.rsgainstest_tombstone_older_than_head_does_not_delete, pinning the relay rule thedelete path in [3/4] depends on.
crates/buzz-cli/TESTING.md§6.13.Deferred
which
resolve_createnow reports locally instead of letting the write failopaquely after every member has resolved. Instructions are executable
configuration reaching an ACP harness verbatim, so the invisible-character
rules personas get in [2/4] apply on the merits — but Desktop applies no text
rules to a team, and a CLI-only rule would refuse a roster Desktop exported
legitimately. That asymmetry is the thing [2/4] exists to prevent, so closing
this means adding the rule on the Desktop side first.