Skip to content

feat(upgrade,canary): Phase 6 — vendored upgrade + canary suite (0.9.0)#37

Merged
broomva merged 2 commits into
mainfrom
feat/phase-6-vendored-canary
May 18, 2026
Merged

feat(upgrade,canary): Phase 6 — vendored upgrade + canary suite (0.9.0)#37
broomva merged 2 commits into
mainfrom
feat/phase-6-vendored-canary

Conversation

@broomva
Copy link
Copy Markdown
Owner

@broomva broomva commented May 18, 2026

Summary

Phase 6 of substrate completion (BRO-1158 under epic BRO-1148). Closes two v1.0 blockers: §4.3.2 (vendored installs can't auto-upgrade) and §4.6.2 (no canary suite verifying substrate invariants on fresh installs).

Vendored upgrade path

bstack upgrade --self for installs without .git (the npx skills add path) now downloads a release tarball + sha256, verifies, and atomically swaps into ~/.agents/skills/bstack.

Step Action
1 curl bstack-vX.Y.Z.tar.gz + .sha256 from GitHub Release
2 Verify sha256 — mandatory, no --skip-sha256 flag (fail-closed)
3 tar -xzf into temp dir
4 mv current → .bak, mv new → install (atomic swap)
5 Restore .bak on swap failure
6 Write ~/.bstack/just-upgraded-from for JUST_UPGRADED next session
7 Structured log at ~/.bstack/auto-upgrade.log

Tarball publishing is a new step in release.yml (built from in-repo skill payload, excludes .git/.github/tests/worktree dirs, tar --sort=name for byte-deterministic sha256, uploads via gh release upload --clobber).

BSTACK_DRY_RUN=1 env override prints the upgrade plan without writing. Falls back to manual npx skills add guidance if the tarball is missing (pre-0.9.0 releases).

Canary suite

Four canary tests verify load-bearing substrate contracts on a fresh install. 21 assertions total, ~5s combined runtime.

Canary Phase Coverage
01-fresh-bootstrap Plant Contract bootstrap exits 0, governance scaffold, hooks wire SessionStart+Stop+PreToolUse, doctor exits 0 (HC-1) (10 assertions)
02-metrics-pipeline Phase 1 v0.4.0 collect produces valid JSON ≥4 setpoints, latest.json on disk, observe single setpoint (3 assertions)
03-status-surface Phase 2 v0.5.0 7 core sections render, --json shape, --setpoint deep view, --aggregate exits 3 (4 assertions)
04-schemas-validate Phase 3 v0.6.0 4 schemas valid draft-07, primitives.yaml + companion-skills.yaml + policy.yaml.template validate (4 assertions)

.github/workflows/ci.yml gains a new canary job (gated on lint + doctor), installs jq + jsonschema + PyYAML, runs tests/canary/*.test.sh.

Files

  • EDIT bin/bstack (+ ~110 LOC) — bstack_upgrade_vendored function
  • EDIT .github/workflows/release.yml — packaging + tarball upload step
  • EDIT .github/workflows/ci.yml — new canary job
  • NEW tests/canary/01-fresh-bootstrap.test.sh
  • NEW tests/canary/02-metrics-pipeline.test.sh
  • NEW tests/canary/03-status-surface.test.sh
  • NEW tests/canary/04-schemas-validate.test.sh
  • EDIT VERSION0.9.0
  • EDIT CHANGELOG.md

Local validation (all green)

shellcheck bin/bstack + 4 canaries          → 0 warnings
tests/canary/01-fresh-bootstrap             → 10/10 pass
tests/canary/02-metrics-pipeline            → 3/3 pass
tests/canary/03-status-surface              → 4/4 pass
tests/canary/04-schemas-validate            → 4/4 pass
─────────────────────────────────────────────
Canary suite: 21/21 assertions pass

Out of scope (deferred to v0.9.1)

  • Cosign signature verification — sha256 covers principal integrity; cosign adds publisher identity proof (staged for v0.9.1)
  • bstack reproduce subcommand — drift detection vs fresh-install reference (Phase 6.1)
  • Canary tests 05-08 — skills install + gates audit + release pipeline E2E (ship as Phases 4-6 stabilize further)

SLO targets (introduced)

  • bstack upgrade --self (vendored, cold network): p50 < 30s, p99 < 60s
  • Canary suite (4 tests, sequential): p99 < 30s

Self-validation note

This release's release.yml job will be the first to publish the tarball + sha256 for v0.9.0. After merge, downstream vendored installs running bstack upgrade --self against v0.9.0 will exercise the full path end-to-end. Future v0.9.1+ releases use the same machinery.

Stack position

PR 10 of N in substrate completion arc. Spec: §6 Phase 6.

🤖 Generated with Claude Code

Implements §6 Phase 6 of substrate completion spec (BRO-1158 under
epic BRO-1148). Closes two v1.0 blockers: §4.3.2 (vendored installs
can't auto-upgrade) and §4.6.2 (no canary suite verifying substrate
invariants on fresh installs).

# Vendored upgrade path

bstack upgrade for installs without .git (the npx skills add path)
now downloads a release tarball + sha256, verifies, and atomically
swaps into ~/.agents/skills/bstack.

  bin/bstack: new bstack_upgrade_vendored function
    1. curl bstack-vX.Y.Z.tar.gz + .sha256 from GitHub Release
    2. Verify sha256 (mandatory — no --skip flag, fail-closed)
    3. tar -xzf into temp dir
    4. mv current → .bak, mv new → install (atomic swap)
    5. Restore .bak on swap failure
    6. Write ~/.bstack/just-upgraded-from for JUST_UPGRADED next session
    7. Structured log at ~/.bstack/auto-upgrade.log

  .github/workflows/release.yml: new packaging step
    - Builds bstack-vX.Y.Z.tar.gz from in-repo skill payload
    - Excludes .git, .github, tests, worktree dirs
    - tar --sort=name for byte-deterministic sha256
    - Uploads tarball + sha256 sidecar via gh release upload

  Falls back to manual 'npx skills add -g broomva/bstack' guidance if
  the tarball is missing (pre-0.9.0 releases without the new job).

# Canary suite

Four canary tests verify load-bearing substrate contracts on a fresh
install (no companion skills, no workspace state, no prior bstack
state). Each canary covers one phase's deliverables:

  tests/canary/01-fresh-bootstrap.test.sh   (Plant Contract)
    - bootstrap.sh exits 0
    - governance files scaffold (CLAUDE, AGENTS, .control/policy.yaml)
    - .claude/settings.json wires SessionStart + Stop + PreToolUse
    - doctor produces expected summary + exits 0 (HC-1: never block)
    (10 assertions)

  tests/canary/02-metrics-pipeline.test.sh  (Phase 1 v0.4.0)
    - collect produces valid JSON with ≥4 setpoints
    - latest.json on disk with generated_at timestamp
    - observe single setpoint returns id-matched JSON
    (3 assertions)

  tests/canary/03-status-surface.test.sh    (Phase 2 v0.5.0)
    - 7 core sections render in text mode
    - --json shape: bstack_version + workspace + profile + setpoints + summary
    - --setpoint S11 --json returns id-matched deep view
    - --aggregate exits 3 (Phase 8 placeholder)
    (4 assertions)

  tests/canary/04-schemas-validate.test.sh  (Phase 3 v0.6.0)
    - 4 schemas valid draft-07
    - primitives.yaml validates against primitives.v1.json (20 entries)
    - companion-skills.yaml validates against companion-skills.v1.json (31)
    - policy.yaml.template structural shape + flat-schema parts valid
    (4 assertions)

Total: 21 assertions across 4 canary tests, ~5s combined runtime.

.github/workflows/ci.yml: new 'canary' job gated on lint + doctor;
installs jq + jsonschema + PyYAML; runs tests/canary/*.test.sh.

# Out of scope (deferred to v0.9.1)

  - Cosign signature verification (sha256 covers principal integrity;
    cosign adds publisher identity proof — staged for v0.9.1)
  - bstack reproduce subcommand (drift detection vs fresh-install ref)
  - Canary tests 05-08 (skills install, gates audit, release pipeline E2E)
    — ship as Phase 4-6 deliverables stabilize further

# Validation

  Local lint: shellcheck OK (bin/bstack + 4 canaries)
  Local canary suite: 21/21 assertions pass
  Tarball packaging: tested via dry-run path; CI publishes on next bump

# SLO targets (introduced)

  bstack upgrade --self (vendored, cold network): p50 < 30s, p99 < 60s
  Canary suite (4 tests, sequential): p99 < 30s

Linear: BRO-1158 (Phase 6, parent epic BRO-1148).
Spec: §6 Phase 6 of specs/2026-05-18-substrate-completion.md.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 18, 2026

Warning

Rate limit exceeded

@broomva has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 41 minutes and 55 seconds before requesting another review.

You’ve run out of usage credits. Purchase more in the billing tab.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 338f3962-f8dc-4bbd-b401-292d3ab3806c

📥 Commits

Reviewing files that changed from the base of the PR and between 658822e and ffcbd59.

📒 Files selected for processing (10)
  • .github/workflows/ci.yml
  • .github/workflows/release.yml
  • CHANGELOG.md
  • VERSION
  • bin/bstack
  • tests/canary/01-fresh-bootstrap.test.sh
  • tests/canary/02-metrics-pipeline.test.sh
  • tests/canary/03-status-surface.test.sh
  • tests/canary/04-schemas-validate.test.sh
  • tests/onboard.test.sh
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/phase-6-vendored-canary

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

The original portable T1 fix (PR #36 commit a2bd9b9) was orphaned in the
v0.8.0 squash merge — same race condition that lost the v0.2.2 SC2034
exclude. CI's Ubuntu strips '# ' from --help via GNU sed; macOS keeps
it via BSD sed. The grep '^# Usage:' anchor passes locally and fails
in CI. Asserting the un-prefixed 'Usage:' token works on both.

Including in Phase 6 PR since CI was blocking on it.
@broomva broomva merged commit fd4843b into main May 18, 2026
6 checks passed
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