feat(roadmap): promote rc to a first-class channel#125
Merged
Conversation
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.
4 tasks
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.
6 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
ChannelNamegains a 5th variantRc(serialised"rc").CHANNEL_MAP['rc']inroadmap-emit-event.mjsnow routes tochannel='rc',new_status='shipped'instead of folding into beta.channel_statuses.channelis 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
RoadmapStatusis untouched.new_status='beta'is still valid on the beta channel (and other channels); we just stop emittingchannel='beta', new_status='beta'for rc shipments.ChannelStatusrows that recorded rc shipments aschannel='beta', status='beta'stay as-is. No retroactive migration.Operator action after merge
channel/rclabel 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 byscripts/normalize-roadmap-project.mjs --create-labelsnext time an Issue is promoted with rc in its channel list.channel/rclabels (none today on TheCodeSaiyan/StarStats but historically possible) will start populating rc rows in theirchannel_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-targetsexhaustiveness verified — no non-exhaustive matches on ChannelName surfaced (existing call-sites all route throughparse()which returnsOption<ChannelName>)tray-vX.Y.Z-rc.Nrelease and verify the receiver writes a ChannelStatus row withchannel='rc', status='shipped'instead ofchannel='beta', status='beta'Pairs with #112 (issues-webhook handler) and #113 (operator tooling) for the full roadmap-pipeline refresh.