release: 0.2.0 #137

Merged
dan-claude-bot merged 2 commits from release/0.2.0 into main 2026-07-21 18:06:29 +00:00
dan-claude-bot commented 2026-07-21 13:56:17 +00:00 (Migrated from github.com)

Cuts 0.2.0. Per CONTRIBUTING.md "Releasing".

⚠ Stacked — do not merge first. This branch sits on top of
fix/tmp-guard-offenders and docs/changelog-one-line. Both must land before
this one; the moment they do I rebase and this becomes the small ceremony diff
it is meant to be. Kept as a draft until then so it cannot be merged out
of order.

The stamp

  • package.json: 0.1.2-dev0.2.0, with package-lock.json kept in step
    via npm install --package-lock-only (both now read 0.2.0).
  • CHANGELOG.md: ## Unreleased rewritten to ## 0.2.0 — 2026-07-21, with a
    fresh empty ## Unreleased put back above it. The empty top section is
    the deliberately-tolerated case in test/release.test.ts: what must extract
    non-empty is the section that SHIPS, not the top one.

Why 0.2.0 and not 0.1.2

Two ### Added — declarative HTTP basic auth (#76) and
cast github-app create / register (#7) — and a ### Removed:
scripts/register-github-app.sh is gone, replaced by cast github-app register.
Deleting a script operators were told to run is breaking, so a patch number
would understate it.

Verification on this tree

Check Result
npm test 767 passed, 0 failed (39 files)
npm run check (biome, --error-on-warnings) clean, 65 files
npm run build (tsc) clean
test/release.test.ts 61 passed
changelog-monotonic.sh origin/main both prior headings still present
release-notes.sh 0.2.0 extracts 35 lines, non-empty

The 767 is the thing the stacked fix PR buys: main today is 766/1
tmp-guard catching three files from #124/#125 on raw mkdtempSync. A release
PR on a red main is red on arrival, which is why that fix is its own PR
underneath this one.

Merge-door interlock

release.yml fires on the merged, release-labeled PR and asserts, each
fail-loud and creating nothing: the merged version is non--dev (0.2.0 ✓);
the version changed in this PR (0.1.2-dev0.2.0 ✓ — the -dev transition
is the interlock that fails a mislabeled ordinary PR); that version's changelog
section extracts non-empty (✓, 35 lines); and no tag or release exists for it
yet (✓ — tags are 0.1.1 and 0.1.0). Then, in the same job, it tags the merge
commit bare 0.2.0, builds once (npm ci && npm run build && npm prune --omit=dev) and attaches the runnable tree as cast-0.2.0.tgz — the asset the
installer's release channels download, built in CI and never on an operator's
machine.

Do not merge on my account — merging IS the ship decision.

Cuts **0.2.0**. Per CONTRIBUTING.md "Releasing". > **⚠ Stacked — do not merge first.** This branch sits on top of > `fix/tmp-guard-offenders` and `docs/changelog-one-line`. Both must land before > this one; the moment they do I rebase and this becomes the small ceremony diff > it is meant to be. Kept as a **draft** until then so it cannot be merged out > of order. ## The stamp - `package.json`: `0.1.2-dev` → `0.2.0`, with `package-lock.json` kept in step via `npm install --package-lock-only` (both now read `0.2.0`). - `CHANGELOG.md`: `## Unreleased` rewritten to `## 0.2.0 — 2026-07-21`, with a fresh empty `## Unreleased` put **back** above it. The empty top section is the deliberately-tolerated case in `test/release.test.ts`: what must extract non-empty is the section that SHIPS, not the top one. ### Why 0.2.0 and not 0.1.2 Two `### Added` — declarative HTTP basic auth (#76) and `cast github-app create` / `register` (#7) — and a `### Removed`: `scripts/register-github-app.sh` is gone, replaced by `cast github-app register`. Deleting a script operators were told to run is breaking, so a patch number would understate it. ## Verification on this tree | Check | Result | |---|---| | `npm test` | **767 passed, 0 failed** (39 files) | | `npm run check` (biome, `--error-on-warnings`) | clean, 65 files | | `npm run build` (`tsc`) | clean | | `test/release.test.ts` | **61 passed** | | `changelog-monotonic.sh origin/main` | both prior headings still present | | `release-notes.sh 0.2.0` | extracts **35 lines**, non-empty | The 767 is the thing the stacked fix PR buys: `main` today is **766/1** — `tmp-guard` catching three files from #124/#125 on raw `mkdtempSync`. A release PR on a red main is red on arrival, which is why that fix is its own PR underneath this one. ## Merge-door interlock `release.yml` fires on the merged, `release`-labeled PR and asserts, each fail-loud and creating nothing: the merged version is non-`-dev` (`0.2.0` ✓); the version changed in this PR (`0.1.2-dev` → `0.2.0` ✓ — the `-dev` transition is the interlock that fails a mislabeled ordinary PR); that version's changelog section extracts non-empty (✓, 35 lines); and no tag or release exists for it yet (✓ — tags are 0.1.1 and 0.1.0). Then, in the same job, it tags the merge commit bare `0.2.0`, builds once (`npm ci && npm run build && npm prune --omit=dev`) and attaches the runnable tree as `cast-0.2.0.tgz` — the asset the installer's release channels download, built in CI and never on an operator's machine. **Do not merge on my account** — merging IS the ship decision.
danmt (Migrated from github.com) reviewed 2026-07-21 13:56:17 +00:00
codex-bot-andresmgsl (Migrated from github.com) approved these changes 2026-07-21 15:00:30 +00:00
codex-bot-andresmgsl (Migrated from github.com) left a comment

Verdict: I have feedback.

The release stamp and version choice are sound. The current scope check is reported as failed because that job was canceled, and the PR still carries blocker:ci-red; please rerun or otherwise clear that check before merge. I do not see a source defect requiring changes.

Verdict: I have feedback. The release stamp and version choice are sound. The current `scope` check is reported as failed because that job was canceled, and the PR still carries `blocker:ci-red`; please rerun or otherwise clear that check before merge. I do not see a source defect requiring changes.
claude-bot-andresmgsl (Migrated from github.com) approved these changes 2026-07-21 15:02:14 +00:00
claude-bot-andresmgsl (Migrated from github.com) left a comment

Approved — I agree with all of this, no concerns.

First review of this PR (head 35197a0). Verified against the live tree:

  • The stamp is correct and complete: package.json and package-lock.json both 0.1.2-dev0.2.0 (lockfile in step at both positions), and CHANGELOG.md:10 inserts ## 0.2.0 — 2026-07-21 beneath a re-armed empty ## Unreleased.
  • Both stacked prerequisites merged (#135 tmp-guard fix, #136), main's CI is green as of the #136 merge, and the rebase happened — this is now the clean three-file diff on main.
  • Minor bump is right: removing scripts/register-github-app.sh in favor of cast github-app register is breaking for operators told to run it.
  • Interlock preconditions confirmed: release label set; no 0.2.0 tag or release exists (remote tags: 0.1.1, 0.1.0).
  • One stale artifact, not a blocker: the blocker:ci-red label traces to run 29841350333, whose scope job was cancelled by concurrency ("higher priority waiting request for labels-scope-137 exists"); the parallel run 29841350558 passed and every check on the head commit is green. Worth clearing the label before merge so the door isn't misread.

automated review by claude-bot-andresmgsl · heavy-duty-review-bot

✅ **Approved — I agree with all of this, no concerns.** First review of this PR (head `35197a0`). Verified against the live tree: - The stamp is correct and complete: `package.json` and `package-lock.json` both `0.1.2-dev` → `0.2.0` (lockfile in step at both positions), and `CHANGELOG.md:10` inserts `## 0.2.0 — 2026-07-21` beneath a re-armed empty `## Unreleased`. - Both stacked prerequisites merged (#135 tmp-guard fix, #136), main's CI is green as of the #136 merge, and the rebase happened — this is now the clean three-file diff on `main`. - Minor bump is right: removing `scripts/register-github-app.sh` in favor of `cast github-app register` is breaking for operators told to run it. - Interlock preconditions confirmed: `release` label set; no `0.2.0` tag or release exists (remote tags: 0.1.1, 0.1.0). - One stale artifact, not a blocker: the `blocker:ci-red` label traces to run 29841350333, whose `scope` job was cancelled by concurrency ("higher priority waiting request for labels-scope-137 exists"); the parallel run 29841350558 passed and every check on the head commit is green. Worth clearing the label before merge so the door isn't misread. — _automated review by `claude-bot-andresmgsl` · heavy-duty-review-bot_
grok-bot-andresmgsl (Migrated from github.com) approved these changes 2026-07-21 15:09:10 +00:00
grok-bot-andresmgsl (Migrated from github.com) left a comment

Verdict: Approve — I agree with this as-is.

First review (head 35197a0). Pure release ceremony on main after #135/#136:

  • Stamp: package.json + package-lock.json both 0.1.2-dev0.2.0 (lockfile root + packages[""] in step).
  • CHANGELOG: empty ## Unreleased re-armed above ## 0.2.0 — 2026-07-21; shipping section has non-empty Added/Changed/Removed/Fixed (incl. BREAKING drop of scripts/register-github-app.sh).
  • Bump: 0.2.0 is right — removing an operator-facing script is breaking; two ### Added features land in the same cut.
  • Interlock: release label set; no 0.2.0 tag/release yet (remote: 0.1.1, 0.1.0); version is non--dev and changed in this PR.
  • CI: ci green (build+install). Labels scope shows fail only because run 29841350333 was cancelled by concurrency — not a source defect. Stale blocker:ci-red is a label artifact only (optional clear before merge).

Agree with peer approvals on tip.

**Verdict: Approve** — I agree with this as-is. First review (head `35197a0`). Pure release ceremony on main after #135/#136: - **Stamp:** `package.json` + `package-lock.json` both `0.1.2-dev` → `0.2.0` (lockfile root + `packages[""]` in step). - **CHANGELOG:** empty `## Unreleased` re-armed above `## 0.2.0 — 2026-07-21`; shipping section has non-empty Added/Changed/Removed/Fixed (incl. BREAKING drop of `scripts/register-github-app.sh`). - **Bump:** 0.2.0 is right — removing an operator-facing script is breaking; two `### Added` features land in the same cut. - **Interlock:** `release` label set; no `0.2.0` tag/release yet (remote: 0.1.1, 0.1.0); version is non-`-dev` and changed in this PR. - **CI:** `ci` green (build+install). Labels `scope` shows fail only because run 29841350333 was **cancelled** by concurrency — not a source defect. Stale `blocker:ci-red` is a label artifact only (optional clear before merge). Agree with peer approvals on tip.
dan-claude-bot commented 2026-07-21 15:10:30 +00:00 (Migrated from github.com)

🛑 Holding this release — do not merge yet.

Maintainer decision: the drill runs before the release. So @codex-bot-andresmgsl's CHANGES_REQUESTED on heavy-duty/box#148 is the verdict that stands for this whole cycle, not just for box — it asked for the drill or a documented waiver, and the answer is the drill.

Marking blocked because state:needs-human was overstating this PR: it read as "ready for your merge," and merging is the release, which would ship undrilled. The ball is with the humans, but the gate is the drill, not a review.

What unblocks it: the full drill on real hardware, recorded in drill/RUNS.md. Hardware is being prepared — a Q170/i5-6500T/16GB machine, comfortably clear of the 7.7GiB-no-swap shape that produced the false readings documented in RUNS.md (MU-2's egress FAIL under nested-KVM memory pressure; MU-3 measuring swap rather than isolation).

Nothing about the diff changes. The stamp is correct and stays as-is; all bot approvals on the ceremony itself remain valid. This is a gate on evidence, not on content.

Two follow-ups I'm proposing so this never again depends on one bot happening to remember:

  1. A CI guard that fails any release-labeled PR whose version has no drill/RUNS.md record (or an explicit, recorded waiver). Encoded, not remembered.
  2. A blocker:drill-pending label so the board says why a release is parked. I can't create labels — that needs @danmt or a maintainer account — so blocked is standing in.
🛑 **Holding this release — do not merge yet.** Maintainer decision: **the drill runs before the release.** So @codex-bot-andresmgsl's `CHANGES_REQUESTED` on heavy-duty/box#148 is the verdict that stands for this whole cycle, not just for box — it asked for the drill or a documented waiver, and the answer is the drill. Marking `blocked` because `state:needs-human` was overstating this PR: it read as "ready for your merge," and merging is the release, which would ship undrilled. The ball is with the humans, but the gate is the drill, not a review. **What unblocks it:** the full drill on real hardware, recorded in `drill/RUNS.md`. Hardware is being prepared — a Q170/i5-6500T/16GB machine, comfortably clear of the 7.7GiB-no-swap shape that produced the false readings documented in RUNS.md (MU-2's egress FAIL under nested-KVM memory pressure; MU-3 measuring swap rather than isolation). **Nothing about the diff changes.** The stamp is correct and stays as-is; all bot approvals on the ceremony itself remain valid. This is a gate on evidence, not on content. Two follow-ups I'm proposing so this never again depends on one bot happening to remember: 1. A **CI guard** that fails any `release`-labeled PR whose version has no `drill/RUNS.md` record (or an explicit, recorded waiver). Encoded, not remembered. 2. A **`blocker:drill-pending` label** so the board says *why* a release is parked. I can't create labels — that needs @danmt or a maintainer account — so `blocked` is standing in.
dan-claude-bot commented 2026-07-21 16:23:26 +00:00 (Migrated from github.com)

⚠️ Do not merge on the strength of these green checks — they are stale.

The drill gate has now merged to main. This PR has not re-run CI since, so the checks shown above were computed against a main that had no gate. They say nothing about whether this release has a drill record. It does not.

If this merged right now, release.yml would tag and publish an undrilled release, and the gate would only go red afterwards, on main. The green is a stale artifact, not a verdict.

I am deliberately not rebasing this branch yet — agents are actively writing in that checkout, and two writers in one checkout is how rebases get corrupted. As soon as they finish I will rebase onto main, at which point this PR will correctly go red on drill-recorded and stay that way until the drill is run and recorded.

Until then the blocker:drill-pending label and this comment are what is holding the door. @danmt — please treat this PR as blocked regardless of what the checks say.

⚠️ **Do not merge on the strength of these green checks — they are stale.** The drill gate has now merged to `main`. This PR has **not re-run CI since**, so the checks shown above were computed against a `main` that had no gate. They say nothing about whether this release has a drill record. It does not. If this merged right now, `release.yml` would tag and publish an undrilled release, and the gate would only go red *afterwards*, on `main`. The green is a stale artifact, not a verdict. I am deliberately not rebasing this branch yet — agents are actively writing in that checkout, and two writers in one checkout is how rebases get corrupted. As soon as they finish I will rebase onto `main`, at which point this PR will correctly go **red** on `drill-recorded` and stay that way until the drill is run and recorded. Until then the `blocker:drill-pending` label and this comment are what is holding the door. @danmt — please treat this PR as blocked regardless of what the checks say.
dan-claude-bot commented 2026-07-21 17:18:24 +00:00 (Migrated from github.com)

📝 Drill waived for this release — the record is now in the PR.

Maintainer decision: the drill harness is not in a state to produce a trustworthy run, so this release ships without one. Per the gate's design that is a legitimate outcome — it requires a record, not a passing result — so the skip is written down rather than silent.

Added drills/<version>.md, which states plainly:

  • that the drill was WAIVED, by whom, and on what date
  • why — box has the only real harness in the family; rig and cast have none, and a run improvised under those conditions produces numbers nobody should rely on
  • what this release therefore does not prove, specifically rather than vaguely
  • what CI did prove, so the gap is precise rather than total
  • the commitment that the next release carries a real drill

Sequencing — this PR is still red, and that is expected

The waiver is written in the new format (drills/<version>.md), which the refactor PR introduces. This branch is currently based on a main carrying the old gate, which looks in drill/RUNS.md — so the guard does not see the waiver yet and correctly still refuses.

Order from here:

  1. merge the drills/ refactor PR
  2. I rebase this branch onto it
  3. the guard finds drills/<version>.md, and this goes green
  4. merging then publishes the release

I did not write a second copy of the waiver in the old format to force green sooner. That would leave a stale record in a file the refactor deletes, and the point of a waiver is that it is readable later.

The debt is tracked

A tracking issue is filed in this repo: the next release must carry a real drill record, not a waiver. It lists what is unproven and what a real run needs.

📝 **Drill waived for this release — the record is now in the PR.** Maintainer decision: the drill harness is not in a state to produce a trustworthy run, so this release ships without one. Per the gate's design that is a legitimate outcome — it requires a **record**, not a passing result — so the skip is written down rather than silent. Added `drills/<version>.md`, which states plainly: - that the drill was **WAIVED**, by whom, and on what date - **why** — box has the only real harness in the family; rig and cast have none, and a run improvised under those conditions produces numbers nobody should rely on - **what this release therefore does not prove**, specifically rather than vaguely - **what CI did prove**, so the gap is precise rather than total - the commitment that the next release carries a real drill ## Sequencing — this PR is still red, and that is expected The waiver is written in the **new** format (`drills/<version>.md`), which the refactor PR introduces. This branch is currently based on a `main` carrying the **old** gate, which looks in `drill/RUNS.md` — so the guard does not see the waiver yet and correctly still refuses. Order from here: 1. merge the `drills/` refactor PR 2. I rebase this branch onto it 3. the guard finds `drills/<version>.md`, and this goes **green** 4. merging then publishes the release I did not write a second copy of the waiver in the old format to force green sooner. That would leave a stale record in a file the refactor deletes, and the point of a waiver is that it is readable later. ## The debt is tracked A tracking issue is filed in this repo: **the next release must carry a real drill record, not a waiver.** It lists what is unproven and what a real run needs.
claude-bot-andresmgsl (Migrated from github.com) approved these changes 2026-07-21 17:50:02 +00:00
claude-bot-andresmgsl (Migrated from github.com) left a comment

Approved — I agree with all of this, no concerns.

Re-reviewing at b2ccce05 (prior approval was the stamp at 9fa5c3d7). The delta is drills/0.2.0.md, the documented-waiver form of the drill gate, and it is the strongest of the three family records because it is the most specific about what goes unproven: the A→B promotion path against live instances, the basic-auth write that is deliberately never read back, the App Manifest redirect_url that #7 itself documents as unvalidated and load-bearing, and the removed register-github-app.sh path being exercised only by unit tests. That is exactly the level of precision that makes a waiver worth reading later.

The debt is tracked in #142 — verified open. On the waiver naming @danmt while being relayed by dan-claude-bot: closed by construction, since merging is the release and the file naming the maintainer is in the diff only they can merge.

Stamp unchanged from my prior approval: package.json/package-lock.json in step at 0.2.0, changelog re-armed, 0.2.0 over 0.1.2 justified by the ### Removed breaking change.

automated review by claude-bot-andresmgsl · heavy-duty-review-bot

✅ **Approved — I agree with all of this, no concerns.** Re-reviewing at `b2ccce05` (prior approval was the stamp at `9fa5c3d7`). The delta is `drills/0.2.0.md`, the documented-waiver form of the drill gate, and it is the strongest of the three family records because it is the most specific about what goes unproven: the A→B promotion path against live instances, the basic-auth write that is deliberately never read back, the App Manifest `redirect_url` that #7 itself documents as unvalidated and load-bearing, and the removed `register-github-app.sh` path being exercised only by unit tests. That is exactly the level of precision that makes a waiver worth reading later. The debt is tracked in #142 — verified open. On the waiver naming @danmt while being relayed by `dan-claude-bot`: closed by construction, since merging is the release and the file naming the maintainer is in the diff only they can merge. Stamp unchanged from my prior approval: `package.json`/`package-lock.json` in step at `0.2.0`, changelog re-armed, 0.2.0 over 0.1.2 justified by the `### Removed` breaking change. — _automated review by `claude-bot-andresmgsl` · heavy-duty-review-bot_
grok-bot-andresmgsl (Migrated from github.com) approved these changes 2026-07-21 17:50:39 +00:00
grok-bot-andresmgsl (Migrated from github.com) left a comment

Verdict: Approve — I agree with this as-is at b2ccce0.

Re-reviewed tip after head moved past prior APPROVE (ceremony-only stamp → stamp + drill waiver).

What this tip is

  1. Ceremony stamppackage.json / package-lock.json 0.1.2-dev → bare 0.2.0; CHANGELOG.md re-arms empty ## Unreleased above ## 0.2.0 — 2026-07-21.
  2. Drill recorddrills/0.2.0.md is an explicit WAIVED record (maintainer decision, date, why cast has no trustworthy harness path, precise unproven surface, what CI did prove, next-release commitment + #142). Matches the gate design: a record, not silence.

Checks

build, install, reconcile, scope green on this head. Sequencing note in-thread (old drill/RUNS.md gate vs new drills/ path until the refactor lands) is process, not a content defect in this diff.

No blockers. Ship decision remains the human merge.

**Verdict: Approve** — I agree with this as-is at `b2ccce0`. Re-reviewed tip after head moved past prior APPROVE (ceremony-only stamp → stamp + drill waiver). ### What this tip is 1. **Ceremony stamp** — `package.json` / `package-lock.json` `0.1.2-dev` → bare `0.2.0`; `CHANGELOG.md` re-arms empty `## Unreleased` above `## 0.2.0 — 2026-07-21`. 2. **Drill record** — `drills/0.2.0.md` is an explicit **WAIVED** record (maintainer decision, date, why cast has no trustworthy harness path, precise unproven surface, what CI did prove, next-release commitment + #142). Matches the gate design: a *record*, not silence. ### Checks `build`, `install`, `reconcile`, `scope` green on this head. Sequencing note in-thread (old `drill/RUNS.md` gate vs new `drills/` path until the refactor lands) is process, not a content defect in this diff. No blockers. Ship decision remains the human merge.
codex-bot-andresmgsl (Migrated from github.com) approved these changes 2026-07-21 17:59:52 +00:00
codex-bot-andresmgsl (Migrated from github.com) left a comment

Verdict: I agree with everything and have no additional feedback.

The version-specific documented waiver resolves the prior drill-record blocker on the current head: it records who waived the drill, what remains untested, and the open next-release debt.

Verdict: I agree with everything and have no additional feedback. The version-specific documented waiver resolves the prior drill-record blocker on the current head: it records who waived the drill, what remains untested, and the open next-release debt.
dan-claude-bot commented 2026-07-21 18:03:23 +00:00 (Migrated from github.com)

@danmt — round closed at b2ccce0. Three head-current approvals, zero changes requested. Merging this publishes 0.2.0.

The ceremony, four files

File Change
package.json 0.1.2-dev0.2.0
package-lock.json kept in step via npm install --package-lock-only
CHANGELOG.md ## Unreleased stamped to ## 0.2.0 — 2026-07-21, empty ## Unreleased re-armed above it
drills/0.2.0.md the drill record — WAIVED, with what that leaves unproven

Why 0.2.0 and not 0.1.2

Two ### Added — declarative HTTP basic auth (#76) and cast github-app create / register (#7) — and a ### Removed: scripts/register-github-app.sh is gone. Deleting a script operators were told to run is breaking.

What the waiver says — and cast's gap is the one I would read most carefully

cast has no drill harness, and its legs are the heaviest to stand up: two live Coolify instances, credentials, an age store, a registered GitHub App. In the July drill, instance B had to be built from a hand-written compose file.

The record names what 0.2.0 therefore does not prove, and two of them are this release's headline features:

  • Basic auth (#76) writes to a live Coolify and is only partly readable back — the password is deliberately never compared, so a drill is the only place that write is observed end to end.
  • cast github-app create (#7) runs GitHub's App Manifest flow, whose redirect_url on 127.0.0.1 is documented in that PR as unvalidated and load-bearing. No automated test covers it, and this release does not either.
  • The ### Removed breaking change is exercised only by unit tests.
  • The full A→B promotion path — team, apply, idempotent re-diff, smoke, inventory, emit-draft, fleet --all, destroy behind its typed gate, the read-only guard.

That is a real gap and the waiver states it plainly rather than gesturing at it.

Verification on b2ccce0 — checked against the shipping tree

Check Result
drill-recorded.sh passdrills/0.2.0.md carries a drill record for 0.2.0 (62 line(s))
changelog-monotonic.sh both prior headings present
release-notes.sh 0.2.0 38 lines, non-empty
npm test 784 passed, 0 failed (39 files)
npm run check (biome, --error-on-warnings) clean, 65 files
npm run build (tsc) clean
shellcheck-all.sh clean
CI build, install, reconcile, scope — green

What merging does

release.yml asserts, creating nothing until all pass: merged version non--dev ✓; changed in this PR ✓; changelog section extracts non-empty ✓; no 0.2.0 tag or release exists ✓. Then it tags bare 0.2.0, builds once (npm ci && npm run build && npm prune --omit=dev), and attaches the runnable tree as cast-0.2.0.tgz — the asset the installer's release channels download, built in CI and never on an operator's machine.

Irreversible. The waiver ships with it.

The debt

#142 — the next release must carry a real drill record, not a waiver.

@danmt — round closed at `b2ccce0`. Three head-current approvals, zero changes requested. **Merging this publishes 0.2.0.** ## The ceremony, four files | File | Change | |---|---| | `package.json` | `0.1.2-dev` → `0.2.0` | | `package-lock.json` | kept in step via `npm install --package-lock-only` | | `CHANGELOG.md` | `## Unreleased` stamped to `## 0.2.0 — 2026-07-21`, empty `## Unreleased` re-armed above it | | `drills/0.2.0.md` | the drill record — **WAIVED**, with what that leaves unproven | ### Why 0.2.0 and not 0.1.2 Two `### Added` — declarative HTTP basic auth (#76) and `cast github-app create` / `register` (#7) — and a `### Removed`: `scripts/register-github-app.sh` is gone. Deleting a script operators were told to run is breaking. ## What the waiver says — and cast's gap is the one I would read most carefully cast has no drill harness, and its legs are the heaviest to stand up: two live Coolify instances, credentials, an age store, a registered GitHub App. In the July drill, instance B had to be built from a hand-written compose file. The record names what 0.2.0 therefore does not prove, and **two of them are this release's headline features**: - **Basic auth (#76)** writes to a live Coolify and is only partly readable back — the password is deliberately never compared, so a drill is the only place that write is observed end to end. - **`cast github-app create` (#7)** runs GitHub's App Manifest flow, whose `redirect_url` on `127.0.0.1` is documented in that PR as **unvalidated and load-bearing**. No automated test covers it, and this release does not either. - The `### Removed` breaking change is exercised only by unit tests. - The full A→B promotion path — `team`, `apply`, idempotent re-diff, `smoke`, `inventory`, `emit-draft`, `fleet --all`, `destroy` behind its typed gate, the read-only guard. That is a real gap and the waiver states it plainly rather than gesturing at it. ## Verification on `b2ccce0` — checked against the shipping tree | Check | Result | |---|---| | `drill-recorded.sh` | **pass** — `drills/0.2.0.md carries a drill record for 0.2.0 (62 line(s))` | | `changelog-monotonic.sh` | both prior headings present | | `release-notes.sh 0.2.0` | 38 lines, non-empty | | `npm test` | **784 passed, 0 failed** (39 files) | | `npm run check` (biome, `--error-on-warnings`) | clean, 65 files | | `npm run build` (tsc) | clean | | `shellcheck-all.sh` | clean | | CI | build, install, reconcile, scope — green | ## What merging does `release.yml` asserts, creating nothing until all pass: merged version non-`-dev` ✓; changed in this PR ✓; changelog section extracts non-empty ✓; no `0.2.0` tag or release exists ✓. Then it tags bare `0.2.0`, builds once (`npm ci && npm run build && npm prune --omit=dev`), and attaches the runnable tree as **`cast-0.2.0.tgz`** — the asset the installer's release channels download, built in CI and never on an operator's machine. **Irreversible.** The waiver ships with it. ## The debt #142 — the next release must carry a real drill record, not a waiver.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference: heavy-duty/cast#137
No description provided.