Skip to content

feat(roadmap): promote rc to a first-class channel#125

Merged
ntatschner merged 1 commit into
nextfrom
feat/roadmap-rc-channel
May 27, 2026
Merged

feat(roadmap): promote rc to a first-class channel#125
ntatschner merged 1 commit into
nextfrom
feat/roadmap-rc-channel

Conversation

@ntatschner
Copy link
Copy Markdown
Collaborator

Summary

  • ChannelName gains a 5th variant Rc (serialised "rc").
  • CHANNEL_MAP['rc'] in roadmap-emit-event.mjs now routes to channel='rc', new_status='shipped' instead of folding into beta.
  • Spec §2.1 (ChannelStatus enum) + §4.1 (CI event payload schema) updated to list rc as a first-class channel.
  • 2 new tests cover Rc round-trip + serde wire format.
  • No migration: channel_statuses.channel is TEXT; new "rc" value just becomes valid per the project's closed-vocabulary-enum convention.

Why

Before: rc-tagged shipments folded into beta with new_status='beta', collapsing beta-track and rc-track progress into a single ChannelStatus row. The roadmap pipeline couldn't observe rc as distinct from beta.

After: rc-tagged shipments target their own channel with new_status='shipped'. Each tag-suffix (alpha / beta / rc / live) targets its own channel at shipped maturity — mirroring the existing alpha/beta/live pattern.

Surfaced by labeling the recently-promoted Issues with channel/* labels in TheCodeSaiyan/StarStats: only 4 of the 5 CI release stages had a corresponding channel, and the rc gap was real per the spec.

What does NOT change

  • RoadmapStatus is untouched. new_status='beta' is still valid on the beta channel (and other channels); we just stop emitting channel='beta', new_status='beta' for rc shipments.
  • Old ChannelStatus rows that recorded rc shipments as channel='beta', status='beta' stay as-is. No retroactive migration.
  • Headline aggregation rule (spec §2.3) needs no change — it iterates whatever channels exist on the item; rc just becomes another participant.

Operator action after merge

  1. The channel/rc label may already exist in the repo (or may not — depends on whether anyone created it pre-fix). If not present, it'll be auto-created by scripts/normalize-roadmap-project.mjs --create-labels next time an Issue is promoted with rc in its channel list.
  2. Existing Issues with channel/rc labels (none today on TheCodeSaiyan/StarStats but historically possible) will start populating rc rows in their channel_statuses[] on next reconcile tick or webhook fire.

Test plan

  • cargo test -p starstats-server roadmap:: (108/108 pass, including 2 new rc tests)
  • cargo clippy -p starstats-server --all-targets (clean under -D warnings)
  • cargo fmt -p starstats-server --check (clean)
  • cargo check -p starstats-server --all-targets exhaustiveness verified — no non-exhaustive matches on ChannelName surfaced (existing call-sites all route through parse() which returns Option<ChannelName>)
  • After merge: cut a tray-vX.Y.Z-rc.N release and verify the receiver writes a ChannelStatus row with channel='rc', status='shipped' instead of channel='beta', status='beta'

Pairs with #112 (issues-webhook handler) and #113 (operator tooling) for the full roadmap-pipeline refresh.

Before this change, rc-tagged shipments folded into the beta channel
with new_status='beta' (per CHANNEL_MAP in roadmap-emit-event.mjs).
That collapsed beta-track and rc-track progress into a single
ChannelStatus row, so the roadmap pipeline couldn't observe rc as
distinct from beta.

ChannelName gains a 5th variant: Rc, serialised as "rc". The mapper's
extract_channels picks up channel/rc labels automatically (via
ChannelName::parse). The CI event handler accepts channel: "rc" via
the same parse() path.

CHANNEL_MAP['rc'] now routes to channel='rc', new_status='shipped'
instead of folding into channel='beta', new_status='beta'. This
mirrors the alpha/beta/live pattern — each tag-suffix targets its
own channel at shipped maturity.

Per the project's "closed-vocabulary TEXT-at-DB-layer" enum
convention, no migration is needed: channel_statuses.channel is
already TEXT, the new "rc" value just becomes valid.

Pre-v1.8.9 behaviour: channel/rc labels were silently dropped by
mapper::extract_channels (unknown channel), so existing boards that
already used channel/rc start working without operator action. Old
ChannelStatus rows that recorded rc shipments as channel='beta'
status='beta' stay as-is — there's no retroactive migration of past
fold-ins, but new rc shipments after deploy land on the rc channel.

Spec §2.1 + §4.1 updated. roadmap-emit-event.mjs CHANNEL_MAP
updated. 2 new tests cover Rc round-trip + serde format.
@ntatschner ntatschner merged commit 1db038f into next May 27, 2026
10 checks passed
@ntatschner ntatschner deleted the feat/roadmap-rc-channel branch May 27, 2026 18:27
ntatschner pushed a commit that referenced this pull request May 27, 2026
When PR #125 introduced `rc` as a first-class ChannelName variant and
updated CHANNEL_MAP to route rc → channel:'rc', the tray-v1.8.9-rc.1
release tag fired the emit script against a production server still
running v1.8.9 (pre-#125), which rejected `channel: 'rc'` with
400 "UnknownChannel: rc". The non-retryable-4xx fatal path then
exit-1'd, blocking the release workflow.

Mirror the existing 404-on-unknown-slug pattern: if the server
returns 400 AND the response text matches /unknown.*channel/i, treat
as a soft failure and exit 0. Same root cause class as 404 (config /
rollout-order chicken-and-egg between client + server); same
disposition (the release artifacts are fine, telemetry is optional,
unblock the workflow).

The regex is deliberately narrow — only matches "unknown" adjacent to
"channel" in the body — so other 400s (auth, bad payload, schema
mismatch) still hard-fail per existing behaviour.

Behavioral tests in this branch's worktree confirmed both paths:
- 400 + "UnknownChannel: rc" body → soft-fail, exit 0
- 400 + "malformed payload" body  → hard-fail, exit 1

Surfaced on tray-v1.8.9-rc.1 (run 26532296011). Live emit was
unaffected because channel:'live' has been valid on the server for
all relevant versions; rc is the only channel that just gained
server-side support and not yet deployed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant