Files
buzz/docs/solo-mobile-contract.md
klopez4212 c9e35f8ac7 fix(mobile): restore Solo chats from channel labels (#8466)
Restore Solo chats and project placement on mobile using `buzz.solo`
labels and creator metadata. Invalidate stale channel details when
identity changes so opening and sending preserve refreshed Solo
identity; shared chats retain ordinary sending. New mobile Solo chats
publish the discovery label, and the personal send guard enforces
ownership even when route hints or legacy placement suggest Solo.

The current desktop producer lives in `block/buzz-app`. [Contract
documentation](0201ca0572/docs/solo-mobile-contract.md)
links its production creation call to relay identity generation and
mobile regression coverage. Public metadata fields are documented.

Validation: clean analysis; 3,542 mobile tests (5 skipped), 4 push
checks, and 280 core unit/doc tests passed. Removing the cache fix
reproduces the send failure. Local push hooks were skipped with owner
approval after an unrelated terminal timeout and disk exhaustion; full
local CI is not green. GitHub CI must validate the pushed commit. The
initial build was installed/launched on iPhone; follow-up native and
live cross-client confirmation remain pending.

The ownership regression supplies a valid owned member recipient and
checks the exact rejection. A New chat UI test captures the real signed
kind-9007 command. Both regressions were mutation-verified: removing the
ownership guard or the production creation label causes the
corresponding test to fail.

---------

Signed-off-by: kenny lopez <klopez4212@gmail.com>
Co-authored-by: Terp <5856f6900e8e0a4e0ea1f4f8d2ee33e4753d2119bc122f94ecafc660b46c0511@buzz.block.builderlab.xyz>
2026-10-20 11:10:24 -04:00

43 lines
2.8 KiB
Markdown

# Solo desktop/mobile contract
The current Solo producer is **[block/buzz-app](https://github.com/block/buzz-app)**,
not the older `desktop/` client retained in this repository.
The captured producer revision is
[`64726576ed3b082daa5786e5e7ca6b5a018663a1`](https://github.com/block/buzz-app/commit/64726576ed3b082daa5786e5e7ca6b5a018663a1):
- [`SoloDraft.tsx`](https://github.com/block/buzz-app/blob/64726576ed3b082daa5786e5e7ca6b5a018663a1/src/features/solo/SoloDraft.tsx) calls `session.channelWrites.create`.
- [`channel-writes.ts`](https://github.com/block/buzz-app/blob/64726576ed3b082daa5786e5e7ca6b5a018663a1/src/features/relay/channel-writes.ts) emits kind 9007 with `channel_type=stream`, `visibility=private`, and `t=buzz.solo`. Its existing production-service test is “creates a Solo chat in its single durable outbox command” in `channel-writes.test.ts`.
- [`model.ts`](https://github.com/block/buzz-app/blob/64726576ed3b082daa5786e5e7ca6b5a018663a1/src/features/channel-templates/model.ts) retains project assignments but drops the legacy `groups.channels` discovery list.
The desktop does **not** author `P`. The relay derives the creator from the
signed creation event. In this repository, `channel_labels_from_tags` in
`crates/buzz-relay/src/handlers/side_effects.rs` parses creation labels;
`group_state_identity_tags` in `crates/buzz-core/src/channel.rs` emits the
leading type `t`, subsequent label `t` tags, and uppercase creator `P`.
`emit_group_discovery_events` uses that builder for relay metadata. Mobile reads those
facts through `ChannelData.fromEvent` and its channel providers.
## Reproducible contract coverage
`test-fixtures/solo-creation.json` contains an **actual captured production
create command**, plus expected relay identity tags using a synthetic creator.
To recapture it from a checkout of the pinned desktop revision:
```sh
node --experimental-transform-types scripts/contracts/capture-solo-creation.mjs /path/to/buzz-app > test-fixtures/solo-creation.json
```
The script invokes `createChannelWrites(...).create(...)` and captures its
outbox command without publishing anything. The core test
`desktop_solo_creation_preserves_mobile_identity_contract` feeds those command
labels through the production parser and relay identity builder. The mobile
regression “refresh replaces stale Solo details before opening and sending”
consumes the same identity tags through the real list/detail providers, primes
old details, refreshes, opens Solo, and sends through the personal sender with
an empty legacy chat list. Existing widget coverage checks project and unfiled
placement and shared-chat ordinary sending.
These are compositional contract tests, not a live desktop/relay/device E2E
run. Physical-device installation and launch alone do not prove that journey.