Skip to content

F4: canary-rollout engine operates on v<major>-<tier> channels (fallback-safe) [#657] #696

Closed

Description

@don-petry

Phase F4 of the major-scoped-channels epic #657. Make the canary-rollout engine operate on v<major>-<tier> channels — backward-compatible with the current live bare-tier tags (F5 migrates the live tags + consumers; F4 must NOT break the running fleet, which is still on <agent>/<tier>). Gated by the Canary-rollout Tests suite (#685) — keep scripts/lib/canary-rollout.sh pure.

The transition constraint (critical — same as F3)

The scheduled engine mutates production tags every 4h. Today those are <agent>/<tier>. F4 adds the ability to resolve/promote/autocut <agent>/v<M>-<tier>, but until F5 migrates the live tags, the engine must keep working on the bare-tier tags. Approach: resolution falls back — prefer <agent>/v<M>-<tier> when it exists, else the legacy <agent>/<tier>. On today's fleet (no v-tags yet) the engine behaves byte-identically. Verify: evaluate/autocut/promote against the current registry produce the SAME verdicts/moves as before F4.

Changes (scripts/canary-rollout.sh; pure bits in lib/)

  1. Channel resolution (channel_commit + the git/ref/tags/<agent>/<tier> reads): given an agent + tier + major, resolve <agent>/v<major>-<tier>, falling back to <agent>/<tier> when the v-form tag is absent. Reuse F3's ring_pinned_major/ring_canonical_ref conventions for the tag names (keep name-building consistent across ring-pins and the engine).
  2. autocut (_autocut_agent): the cut version's major (already computed via _autocut_bump — it supports major) selects the target line. A major bump seeds <agent>/v<newmajor>-next (a fresh major line) rather than moving the existing next; minor/patch move the current major's v<M>-next. Immutable <agent>/vX.Y.Z release tags unchanged.
  3. cmd_promote / promote-all: advance <agent>/v<M>-<tier> within a major line (a v2 candidate soaks v2-next→v2-ring0→…→v2-stable independently of v1-*). --override/--confirm/--allow-pre-existing semantics unchanged.
  4. evaluate: report the major line under evaluation (e.g. "candidate (v2-next) = …").

Registry (standards/canary-rings.json, jq -a)

If a per-agent "current major" is needed for resolution, derive it from the latest <agent>/vX.Y.Z release tag (no new required field). Add an OPTIONAL major_line hint only if derivation is insufficient — prefer derivation to avoid schema churn.

Tests (tests/canary_rollout.bats, gated by #685)

  • resolution prefers v<M>-<tier> when present, falls back to bare <tier> when absent → on the current (bare-tier) fixture, verdicts are byte-identical to pre-F4 (the transition-safety guard).
  • autocut of a major bump seeds v<newmajor>-next (fresh line), not a move of the old next.
  • autocut of minor/patch moves the current major's v<M>-next.
  • promote advances within a major line; a v2 promotion never touches v1-* tags.
  • evaluate prints the major line.

Out of scope

F5: live tag migration (<agent>/<tier>→<agent>/v<M>-<tier>), consumer re-pins, retirement of the bare-tier form. F4 makes the engine CAPABLE + fall-back-safe; it does not migrate live tags.

Acceptance

  • Engine resolves/promotes/autocuts v<M>-<tier> with fallback to bare-tier; zero behavior change on today's fleet (bats fixture proves byte-identical verdicts).
  • major bump seeds a fresh major line; promotion stays within a major.
  • lib/ pure; bats green under Canary-rollout Tests; shellcheck clean.

Activity

  1. don-petry commented on Jul 13, 2026

    @don-petry
    ContributorAuthor

    Dev-Lead Implementation Plan

    Issue: #696 — F4: canary-rollout engine operates on v- channels (fallback-safe) [#657]

    Scope

    Make the canary-rollout engine resolve/promote/autocut major-scoped <agent>/v<M>-<tier> channel tags, preferring the v-form when it exists and falling back to the legacy bare <agent>/<tier> — so on today's (bare-tier) fleet the engine is byte-identical to pre-F4.

    Implementation Checklist

    • scripts/lib/canary-rollout.sh (pure): add major_component <version> and channel_tag <agent> <tier> [major] name-builders (matching F3 ring_canonical_ref convention)
    • scripts/canary-rollout.sh: add _agent_current_major (derive major from highest <agent>/vX.Y.Z release), _channel_tag_commit, _looks_like_oid, _resolved_channel/_resolved_channel_tag
    • scripts/canary-rollout.sh: rewrite channel_commit to prefer v<M>-<tier> then fall back to bare <tier>
    • scripts/canary-rollout.sh: cmd_promote moves the resolved frontier tag (v-form within a major line, else bare)
    • scripts/canary-rollout.sh: _autocut_agent — major bump seeds a fresh <agent>/v<newmajor>-next; minor/patch move the resolved current-major next tag (bare on today's fleet)
    • scripts/canary-rollout.sh: cmd_evaluate reports the major line under evaluation (e.g. candidate (v2-next) = …)

    Tests to Write (tests/canary_rollout.bats, gated by #685)

    • pure: major_component extracts MAJOR; channel_tag builds v-form + bare form
    • transition-safety: on the bare-tier fixture, evaluate verdict + labels are byte-identical to pre-F4 (fall-back to bare)
    • resolution prefers v<M>-<tier> when that tag is present
    • autocut of a major bump seeds v<newmajor>-next (fresh line), does not move the old next
    • autocut of minor/patch moves the current major's v<M>-next when the v-line exists
    • promote advances within a major line; a v2 promotion never touches v1-* tags
    • evaluate prints the major line

    Test Command

    GH_TOKEN=dummy bats tests/canary_rollout.bats (CI: Canary-rollout Tests — shellcheck + bats)

  2. don-petry commented on Jul 13, 2026

    @don-petry
    ContributorAuthor

    ✅ F4 complete — canary-rollout engine now operates on v<major>-<tier> channels (fallback-safe)

    Implemented per the Phase-1 plan. The engine is now capable of resolving, promoting, and autocutting major-scoped <agent>/v<M>-<tier> channel tags while remaining fall-back-safe: it prefers the v-form tag when it exists, otherwise the legacy bare <agent>/<tier>. On today's bare-tier fleet (no v-tags) the engine is byte-identical to pre-F4 — the transition-safety guarantee.

    What changed

    scripts/lib/canary-rollout.sh (pure core — kept side-effect-free):

    • major_component <version> — MAJOR of a strict MAJOR.MINOR.PATCH, empty otherwise.
    • channel_tag <agent> <tier> [major] — builds <agent>/v<M>-<tier> with a major (mirrors F3's ring_canonical_ref), else bare <agent>/<tier>.

    scripts/canary-rollout.sh (orchestrator / I/O glue):

    • _looks_like_oid — hex guard so only a real commit id (never an absent-tag/{} sentinel) is preferred over the bare form.
    • _agent_current_major — derives the current major from the agent's highest vX.Y.Z release (no new required registry field — derivation only).
    • _channel_tag_commit / _resolved_channel / _resolved_channel_tag — unified prefer-v-then-fallback resolution shared by commit lookup, promote, autocut, and display.
    • channel_commit — now delegates to _resolved_channel (fall-back-safe).
    • cmd_promote — advances the resolved v<M>-<tier> within a major line (a v2 promotion never touches a v1 tag). Logical tier still drives the gate and is reported as promoted_ring.
    • _autocut_agent — a MAJOR bump seeds a fresh <agent>/v<newmajor>-next line; minor/patch advance the current major's v<M>-next, falling back to bare next where no v-line exists yet.
    • cmd_evaluate — reports the resolved major line (e.g. candidate (v2-next) = …, ring listing shows v2-stable).

    Test-first (TDD)

    Added 10 tests to tests/canary_rollout.bats (written red-first, confirmed failing before implementation): pure channel_tag/major_component; v-line resolution + evaluate label; promote-within-major; autocut MAJOR-seeds-v3-next, patch-advances-v2-next, patch-falls-back-to-bare; and a byte-identical-on-bare-fixture transition-safety guard. The shared _autocut_stub was made faithful to the bare fleet (a v<M>-next channel probe resolves absent), so its release-tag existence probe is unaffected.

    Verification

    • bats tests/canary_rollout.bats — 180/180 passing (170 pre-existing unchanged + 10 new).
    • shellcheck --severity=warning -x scripts/canary-rollout.sh scripts/lib/canary-rollout.sh — clean.
    • .dev-lead/scripts/dev-lead-lint.sh — all checks passed.

    Out of scope (as specified)

    F5 — live tag migration and consumer re-pins. F4 only makes the engine capable + safe; today's fleet behavior is unchanged.

  3. added a commit that references this issue on Jul 13, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    dev-leadFor dev-lead agent pickup

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions