Files
amethyst/commons/src/jvmTest/resources/marmot/vectors/group-data-update.v1.json
T
Claude 14b02a1ebb feat(marmot): disband a group, edit its avatar link, and replay seven more vectors
Disband (`marmot.group.lifecycle.v1`, 0x800c)
--------------------------------------------
We enforced the Disbanded state but nothing on this side could enter it, so
the enforcement was only reachable from a peer's commit. `disbandGroup` writes
the component in a Commit every member replays. It refuses what is
structurally impossible — a non-admin, a legacy MIP-01 group with no carrier
for a lifecycle state, a second disband — and, unlike every other metadata
setter, refuses to report success when no relay acknowledged the commit: the
caller is about to tell a human the conversation is over, and a group that is
still live for everyone else must not be announced as ended. The obligation
stays queued either way.

On Android it is an admin-only action in the group header behind its own
confirmation, worded for what it is: for everyone, and not reopenable.

Avatar link (`marmot.group.avatar-url.v1`, 0x8007)
--------------------------------------------------
`setGroupAvatarUrl` existed but only `amy` could reach it — the renderer
already preferred a URL avatar over the Blossom image, and no Android screen
could set one. Edit Group Info now carries the field; it commits separately
from the profile so saving a rename does not rewrite the avatar state, and
clearing it falls the group back to the uploaded image.

Seven more scenario vectors
---------------------------
New steps: `update_group_data`, `remove_members`, and the delivery-fault
family — `omit_message`, `duplicate_message`, `reorder_messages`,
`withhold_message`, `release_withheld`. Selectors are matched key by key and
an unknown key is refused, because a silently widened selector injects a
different fault from the scripted one while still reporting under the
vector's name. `group_profile` outcomes are checked too.

Replaying now: group-data-update, deferred-tick-catchup, incremental-growth,
drop-queued, queue-faults, delayed-past-epoch-app-message,
readd-after-eviction. 18 vector tests, all green.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016kCuA6tc4JQzHPCDd39GHq
2026-09-10 11:50:18 +00:00

128 lines
2.4 KiB
JSON

{
"scenario_name": "group-data-update/v1",
"vector_version": "1",
"conformance_version": "0.9.19",
"seed": null,
"scenario": {
"name": "group-data-update/v1",
"spec_version": "2",
"clients": [
"alice",
"bob"
],
"steps": [
{
"type": "create_group",
"creator": "alice",
"name": "before",
"invitees": [
"bob"
],
"required_features": [],
"pending": "create"
},
{
"type": "acknowledge_outbound",
"client": "alice",
"publication": "create",
"outcome": "accepted"
},
{
"type": "deliver_all"
},
{
"type": "tick",
"clients": [
"bob"
]
},
{
"type": "clear_events",
"clients": [
"alice",
"bob"
]
},
{
"type": "update_group_data",
"client": "alice",
"name": "after",
"pending": "rename"
},
{
"type": "acknowledge_outbound",
"client": "alice",
"publication": "rename",
"outcome": "accepted"
},
{
"type": "deliver_all"
},
{
"type": "tick",
"clients": [
"bob"
]
},
{
"type": "observe",
"clients": [
"alice",
"bob"
]
}
]
},
"expected_outcomes": [
{
"type": "pending_resolution",
"step_index": 1,
"client": "alice",
"pending": "create",
"resolution": "confirmed"
},
{
"type": "pending_resolution",
"step_index": 6,
"client": "alice",
"pending": "rename",
"resolution": "confirmed"
},
{
"type": "client_state",
"client": "alice",
"epoch": 2,
"member_count": 2,
"received_payloads": []
},
{
"type": "client_state",
"client": "bob",
"epoch": 2,
"member_count": 2,
"received_payloads": []
},
{
"type": "group_profile",
"client": "alice",
"name": "after",
"description": ""
},
{
"type": "group_profile",
"client": "bob",
"name": "after",
"description": ""
},
{
"type": "clients_converged",
"clients": [
"alice",
"bob"
],
"epoch": 2,
"member_count": 2
}
]
}