mirror of
https://github.com/vitorpamplona/amethyst.git
synced 2026-10-06 03:38:23 +00:00
Our leaf advertised `receive` only, which was honest while nothing could originate a stream and is not any more. It now advertises `receive`, `send` and `fanout` — the same set MDK puts on every KeyPackage it publishes — so a group requiring any of them admits us. A capability is a claim about what the client supports, not a duty to stream: a member that never originates one is a quiet member, not a broken one. The role-gate test asserted the old behaviour, so it was testing our own capability set rather than the gate. It now builds a deliberately reduced leaf and checks that THAT is refused, which keeps working whatever we go on to advertise; a second case pins the new fact that we fill every role the profile defines. `MarmotAgentStreamWatcher` in commons follows the newest kind:1200 in a group, folds the QUIC records behind it under the receive discipline, and settles the result against the durable kind:9 — confirmed when the transcript agrees, dropped when it does not, because a disagreement means we rendered something the publisher never sent. Resolving the final message lives here rather than in the UI so a front end only has to say "the feed moved", and so the whole decision is testable without a UI. Android shows it as an italic, labelled row between the transcript and the composer. Provisional content has to look provisional: preview text is not durable history until the final message vouches for it, and the row disappears the moment it is confirmed or contradicted. Progress and status records render as separate chrome, never as answer text, which is what the spec requires of them. Every failure path ends as "no preview" rather than as a broken group: no stream, no broker candidate, an unreachable broker, an unimplemented stream type, or a platform with no QUIC at all. `receive` explicitly does not require the QUIC data plane. The desktop app has no Marmot chat screen to render into — its chat UI is NIP-17 only — so there is nothing to wire there yet. The watcher is in commons and speaks only quartz's transport port, so desktop inherits it the day that screen exists. Interop unchanged at 19 of 19 with all three roles advertised. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016kCuA6tc4JQzHPCDd39GHq