Expose typed channel lifecycle (active | archived) on channel reads, not only as a write error
- Dominant language
- Rust
- Stars
- 32.7k
- Forks
- 4.3k
- Avg merge
- 1d 13h
- Merged PRs (30d)
- 253
Description
## Ask
Expose a typed channel lifecycle fact — `active | archived` — on the channel **read** surface (`buzz channels get` and `buzz channels list`, and the underlying API), so a consumer can know a channel is archived without attempting a write.
## Why this is a contract gap rather than a nice-to-have
Today the only way to learn that a channel is archived is to write to it and read the error:
```
$ buzz channels add-member --channel 49bb9526-... --pubkey a9f344c3...
400: invalid: channel is archived
```
`buzz channels get` and `buzz channels list` return the same shape for an archived channel as for an active one, with no flag distinguishing them. That has two consequences we hit in production today:
1. **A write-probe is the only classifier, and it is not a safe one.** The archive check fires *before* the permission check, so `400: invalid: channel is archived` and an authorization failure are indistinguishable from the error alone — and both are indistinguishable from a transport failure once a client collapses the call to a boolean. Classifying on that string means misclassifying authorization and transport problems as "archived".
2. **An enumerating service cannot avoid doomed writes.** `buzz channels list` includes archived channels with no way to filter them, so any service that reconciles state across the channel inventory will attempt writes it can never complete.
## What it cost us
`BuzzObserverd` maintains a compact workflow register in each work channel's name. On a deploy today it reconciled its full channel inventory and quarantined 15 lanes with `channel name update failed`. On probing, **12 of the 15 were simply archived channels** — finished work that will never accept a write again — and only 2 were a genuine authorization gap. The service had no way to tell those apart, so it retried and quarantined finished lanes permanently and reported itself `degraded` on the strength of it.
Our design owner ruled that we may not work around this client-side: inferring "archived" from a failed write or from a generic falsy update result conflates it with authorization and transport failure, so the correct shape is expand-then-migrate — the read contract exposes the lifecycle fact first, consumers carry it, and only then may an archived channel be excluded from write paths. That leaves the workaround-free path blocked on this read contract.
## Shape we would consume
Either is fine; the first is smaller:
- A `lifecycle` (or `archived`) field on the channel object returned by `channels get` / `channels list`.
- Optionally a filter on `channels list` (`--lifecycle active`) so an enumerating consumer does not have to page archived channels at all.
What matters is that it is a **typed fact on a read**, not an error string on a write, and that it is present on both the single-channel read and the inventory listing.
## Notes
- Archived channels remain listed by `channels list` today, which is what makes the inventory case unavoidable rather than a client bug.
- We are not asking for any change to archive semantics, permissions, or write behaviour — only for the existing state to be observable on the read path.
Contributor guide
Assessment
This issue has not been assessed yet.