From 0a61dce2494bf32767c457cd33a8266f4d59a782 Mon Sep 17 00:00:00 2001 From: Graeme Geldenhuys Date: Wed, 24 Jun 2026 00:23:47 +0100 Subject: [PATCH] docs(skill): update cut-blaise-release with v0.12.0-cut gaps - archive the NATIVE stage-2 binary (/tmp/fpn_blaise2), not the QBE one - COMPILER_ID drops -SNAPSHOT at release, re-gains it at the dev-cycle bump; keep base version synced with project.xml or bif-coverage fails - add fixpoint-warmcache.sh (WARMCACHE_FIXPOINT_OK) to the verification set - rename the -pre bootstrap dir to the next cycle (not refresh-in-place) - define the changelog/community-post range as ..v - note the CI STAGE1_TAG / rolling-bootstrap anchor bump --- .claude/skills/cut-blaise-release/SKILL.md | 409 +++++++++++++++++++++ 1 file changed, 409 insertions(+) create mode 100644 .claude/skills/cut-blaise-release/SKILL.md diff --git a/.claude/skills/cut-blaise-release/SKILL.md b/.claude/skills/cut-blaise-release/SKILL.md new file mode 100644 index 0000000..2c20344 --- /dev/null +++ b/.claude/skills/cut-blaise-release/SKILL.md @@ -0,0 +1,409 @@ +--- +name: cut-blaise-release +description: | + Cut a new Blaise compiler release. Bumps the version in Blaise.pas + project.xml, + rebuilds compiler + RTL + stage-2 binary, verifies all four self-hosting + fixpoints (QBE, native, internal-assembler, warm-cache), runs the full test + suite, commits, tags, archives the NATIVE stage-2 binary under releases/vX.Y.Z/ + (NOT committed — releases/ is gitignored), renames + refreshes the -pre + bootstrap dir to the next cycle, writes the community post + changelog, then + bumps Blaise.pas + project.xml + uCompilerId.pas to the next -SNAPSHOT version. + Use when asked to "cut a release", "release v0.X.Y", "tag a release", or after + the user confirms a fixpoint is achieved. +allowed-tools: + - Bash + - Read + - Edit + - Write + - AskUserQuestion +--- + +# Cutting a Blaise release + +This skill mirrors the verified release process used for v0.11.0. +Run every step in order. Stop and surface the failure to the user if any +step fails — never paper over a missing fixpoint. + +## Inputs + +The user will name the release version (e.g. "0.11.0"). If they didn't, +ask them via AskUserQuestion. The next-dev version is the next minor with +a `-SNAPSHOT` suffix (0.11.0 → 0.12.0-SNAPSHOT). Confirm with the user if unsure. + +## Preconditions to check before starting + +1. Run `git status`. The working tree often carries **unrelated** uncommitted + changes (e.g. `compiler/project.xml` and `tools/kanban/project.xml` build- + option tweaks, plus many untracked `.txt`/`.adoc` working files). These are + NORMAL on this repo and must NOT be swept into the release commit. The root + `project.xml` may also carry unrelated edits — you will stage only its + version line (see Step 5). If you see uncommitted changes that look like + in-progress feature work, ask the user whether to proceed. +2. The current `Version` constant in `compiler/src/main/pascal/Blaise.pas` + should look like `'-SNAPSHOT'` (the dev marker). If it's already a + plain non-dev version, ask the user — they may have already cut this release. +3. All commands run from the project root `/data/devel/new-pascal-compiler` + (PasBuild requirement — sub-modules lack the `` field). +4. `vendor/qbe/qbe` must exist (the fixpoint scripts need it). The current + release binary lives at the newest `releases/v*-pre/blaise` or + `releases/v*/blaise` — the fixpoint scripts auto-pick it via `sort -V`. + +## Step 1 — bump version to release + +Edit `compiler/src/main/pascal/Blaise.pas`. Find the line: + +```pascal + Version = '-SNAPSHOT'; +``` + +and change it to: + +```pascal + Version = ''; +``` + +Also edit `project.xml` in the project root. Find the line: + +```xml + -SNAPSHOT +``` + +and change it to: + +```xml + +``` + +Edit `compiler/src/main/pascal/uCompilerId.pas`. The `COMPILER_ID` looks like +`'blaise--SNAPSHOT+bif'`. For the release, **drop the `-SNAPSHOT`** +but **keep the `+bif` tag** → `'blaise-+bif'`. Only bump the +`+bif` number if the `.bif` interface format actually changed this cycle +(`IFACE_VERSION` in `uUnitInterfaceIO.pas` — the two must agree). + +IMPORTANT (bif-coverage sync): the `bif-coverage` tool's `TestRun_BifCoverage_NoGaps` +asserts the project.xml base version (with `-SNAPSHOT` stripped) is a substring +of `COMPILER_ID`. So `COMPILER_ID` and project.xml `` must carry the +**same base version** at all times — here at release, and again at the dev-cycle +bump in Step 7. A mismatch silently fails that test. + +## Step 2 — verify the QBE fixpoint (NOT the binary we ship) + +The project's `scripts/fixpoint.sh` does a whole QBE stage-2 build: it +rebuilds + installs the runtime, uses the latest release binary as stage-1 to +emit stage-2 IR, assembles + links the stage-2 binary to **`/tmp/fp_blaise2`**, +then emits stage-3 IR and diffs it. + +NOTE: since v0.12.0 the **native backend is the default**, so the binary we +actually archive and ship is the NATIVE stage-2 binary from Step 3 +(`/tmp/fpn_blaise2`), NOT `/tmp/fp_blaise2`. This step still runs — the QBE +fixpoint is a required reproducibility guard and prints the IR line count we +quote in the commit message and docs — but `/tmp/fp_blaise2` is only used to +rebuild `compiler/target/blaise` below so the native fixpoints run on the +released version. + +```bash +./scripts/fixpoint.sh # must print FIXPOINT_OK +``` + +Note the stage-2 IR line count it prints ("stage-2 IR: N lines") — you'll quote +it in the commit message and the docs. + +The verified stage-2 binary is **`/tmp/fp_blaise2`**. (If the release stage-1 +was too old to reach fixpoint in one round, `fixpoint.sh` extends a round and +the binary becomes `/tmp/fp_blaise3` — read the script's output to see which.) + +`fixpoint.sh` only updated the IR-emitting path; `compiler/target/blaise` may +still be the old `-SNAPSHOT` build. Rebuild it from the fixpoint binary so the +native fixpoints and the test runner use the released version: + +```bash +cp compiler/target/blaise_rtl.a /tmp/blaise_rtl.a # FindRTL looks beside --compiler +pasbuild compile -m blaise-compiler --compiler /tmp/fp_blaise2 +compiler/target/blaise --help | head -1 # must print: Blaise Compiler v +``` + +ALWAYS pass `--compiler` to pasbuild — without it, PasBuild falls back to FPC, +which this project does not use. + +## Step 3 — verify the native, internal-assembler, and warm-cache fixpoints + +`fixpoint.sh` (Step 2) only exercises the QBE backend. Three more fixpoints +guard the native backend, the in-process internal assembler, and warm-cache +(incremental) rebuilds. Run all three: + +```bash +./scripts/fixpoint-native.sh # must print NATIVE_FIXPOINT_OK +./scripts/fixpoint-native-internal.sh # must print NATIVE_INTERNAL_OK +./scripts/fixpoint-warmcache.sh # must print WARMCACHE_FIXPOINT_OK +``` + +`fixpoint-native.sh` writes the **native stage-2 binary to `/tmp/fpn_blaise2`** +— that is the binary we archive and ship (Step 6), because native is the +default backend. Confirm it prints the right version: + +```bash +/tmp/fpn_blaise2 --help | head -1 # must print: Blaise Compiler v +``` + +If any of the four fixpoints does not print its OK line, **stop**. Show the +user the output and do not proceed. There is no acceptable "almost fixpoint" — +any divergence means the release is not reproducible. + +## Step 4 — run the full test suite with the fixpoint binary + +Build the TestRunner with the verified stage-2 binary, then run the whole suite +(do NOT use `pasbuild test` — build the runner and invoke it directly so you see +the real total): + +```bash +cp compiler/target/blaise_rtl.a /tmp/blaise_rtl.a +pasbuild test-compile -m blaise-compiler --compiler /tmp/fp_blaise2 +compiler/target/TestRunner # must print: OK (N tests, ...) +``` + +Note the test count N. If any test fails, stop — do not release. + +## Step 5 — commit and tag + +Stage `Blaise.pas` whole (its only change is the version), but stage **only the +version-line hunk** of `project.xml` — it frequently carries unrelated working +changes that must not enter the release commit: + +```bash +git add compiler/src/main/pascal/Blaise.pas +printf '%s\n' 'y' 'n' 'n' | git add -p project.xml # stage hunk 1 (version) only +git diff --cached --stat # MUST show exactly: Blaise.pas | 2 +- AND project.xml | 2 +- +``` + +If `git diff --cached --stat` shows project.xml with more than 2 changed lines, +you swept in unrelated changes — `git restore --staged project.xml` and redo the +`git add -p`. (The hunk-selection answers `y n n` assume the version line is the +first hunk; if project.xml has a different shape, inspect with `git add -p` and +stage only the `` hunk.) + +Commit with this pattern (HEREDOC for clean formatting): + +``` +release: v + + +``` + +Then tag: + +```bash +git tag v +``` + +**Never reference Claude in the commit message.** **Do not push.** +The user pushes manually. + +## Step 6 — archive the release binary + refresh the -pre bootstrap binary + +Archive the **native** stage-2 binary (`/tmp/fpn_blaise2` from Step 3) — native +is the default backend, so the shipped/bootstrap binary must be native, NOT the +QBE `/tmp/fp_blaise2`: + +```bash +mkdir -p releases/v +cp /tmp/fpn_blaise2 releases/v/blaise # NATIVE binary from fixpoint-native.sh +chmod +x releases/v/blaise +cp compiler/target/blaise_rtl.a releases/v/blaise_rtl.a +releases/v/blaise --help | head -1 # sanity: Blaise Compiler v +``` + +Every release directory must contain both `blaise` and `blaise_rtl.a` — the +bootstrap (`FindRTL`) looks for the archive beside the binary, so a release +missing `blaise_rtl.a` cannot serve as a stage-1 bootstrap. + +Now **rename the rolling `-pre` directory to the next cycle** and refresh its +binary to this verified build, so cold-bootstrap of `master` stays current for +the dev cycle about to open. `releases/` is gitignored, so this is a plain +filesystem `mv` (no `git mv`): + +```bash +# The -pre dir from the previous cycle is named v-pre. Rename it to the +# NEXT minor so the newest releases/v*-pre/ tracks the cycle we are opening. +mv releases/v-pre releases/v.0-pre # e.g. v0.12.0-pre -> v0.13.0-pre +cp /tmp/fpn_blaise2 releases/v.0-pre/blaise +cp compiler/target/blaise_rtl.a releases/v.0-pre/blaise_rtl.a +rm -f releases/v.0-pre/*.bak # drop any stale backup cruft +releases/v.0-pre/blaise --help | head -1 # sanity check +``` + +(If no `-pre` directory exists yet, create `releases/v.0-pre/` +directly. The GitHub Actions CI and `rolling-bootstrap.sh` both look for the +newest `releases/v*-pre/`, so the name must be the cycle just opened — not the +one just released.) + +Update the test count in `README.adoc` (the "Testing: N tests" line in the +Project Status section) to match the suite total from Step 4, then commit it: + +```bash +git add README.adoc +git commit -m "docs: update test count to for v" +``` + +Then build the release tarball for the GitHub Releases page — a single +top-level directory containing `blaise`, `blaise_rtl.a`, `README.adoc`, +`NOTICE`, and `LICENSE`: + +```bash +STAGING=$(mktemp -d) +DIRNAME="blaise-v-linux-x86_64" +mkdir "$STAGING/$DIRNAME" +cp releases/v/blaise "$STAGING/$DIRNAME/blaise" +cp releases/v/blaise_rtl.a "$STAGING/$DIRNAME/blaise_rtl.a" +cp README.adoc "$STAGING/$DIRNAME/README.adoc" +cp NOTICE "$STAGING/$DIRNAME/NOTICE" +cp LICENSE "$STAGING/$DIRNAME/LICENSE" +tar -czf releases/blaise-v-linux-x86_64.tar.gz -C "$STAGING" "$DIRNAME" +rm -rf "$STAGING" +tar -tzf releases/blaise-v-linux-x86_64.tar.gz # verify +``` + +**Do not `git add` any binary files or the tarball.** `releases/` is gitignored +and the user keeps binaries local on purpose. + +## Step 7 — bump to next -dev version + +Edit `compiler/src/main/pascal/Blaise.pas` again, changing `''` to +`'.0-SNAPSHOT'` (e.g. `0.11.0` → `0.12.0-SNAPSHOT`). Use +`-SNAPSHOT` in BOTH files — the older `-dev` suffix in Blaise.pas was retired so +the two version strings stay in sync. + +Also edit `project.xml`, changing `` to `.0-SNAPSHOT`. + +REQUIRED: also bump `compiler/src/main/pascal/uCompilerId.pas` back to the +`-SNAPSHOT` form for the new base version, keeping the same `+bif` tag → +`'blaise-.0-SNAPSHOT+bif'`. This keeps `COMPILER_ID` in sync +with project.xml's base version — otherwise `bif-coverage`'s +`TestRun_BifCoverage_NoGaps` fails (it checks the project base version is a +substring of `COMPILER_ID`). Do NOT bump `+bif` here; the `.bif` format +hasn't changed just by opening a dev cycle. + +Stage selectively again (project.xml may still carry unrelated changes): + +```bash +git add compiler/src/main/pascal/Blaise.pas compiler/src/main/pascal/uCompilerId.pas +printf '%s\n' 'y' 'n' 'n' | git add -p project.xml +git diff --cached --stat # Blaise.pas, uCompilerId.pas, project.xml — version lines only +git commit -m "chore: begin v.0-dev cycle" +``` + +NOTE on CI / rolling-bootstrap anchor: when this release becomes the new +cold-bootstrap baseline, bump `STAGE1_TAG` in `.github/workflows/bootstrap.yml` +and the rolling-bootstrap default-`--from` anchor to `v`. This is a +CI-only change and typically lands in its own commit alongside the release +(it does not block the release itself). + +## Step 8 — write community post and changelog + +Write two documents at the project root. Both are untracked (do not `git add` +them) — they are working files the user edits and publishes manually. + +Both documents cover **only the commits between the previous release tag and +the tag being cut now** — the range `..v`, where `` +is the most recent existing release tag before this one. Find it with +`git describe --tags --abbrev=0 v^` (the latest tag reachable from the +commit just before the release commit), or `git tag --sort=-v:refname | head`. +Do NOT summarise the whole history — only this cycle's delta. + +Survey the commits first (the `v` tag already exists from Step 5): +`git log ..v --oneline`, and group by theme. Helpful groupings: +`git log ..v --oneline | grep ' feat'` (features), +`... | grep ' fix'` (fixes), `... | grep ' perf'` (performance). + +### community-post-v.md + +A warm, readable announcement for the Blaise community (forums, mailing lists, +social media). Style: + +- **Not** a commit-by-commit log — group changes into themes with a clear + headline win up top. +- Sprinkle emoji throughout section headings and milestone call-outs. +- Warm, collaborative voice; British English spelling (see the global writing + style guide). +- Include **tiny code examples** for the headline language features — a 3–6 + line snippet per feature is far more compelling than prose. VERIFY each + snippet actually compiles before publishing: write it to `/tmp/snip.pas` and + run `compiler/target/blaise --source /tmp/snip.pas --output /tmp/snip` (try + both `--backend qbe` and `--backend native` for codegen-sensitive features). +- Cover: headline win(s), language/stdlib additions, bug-fix hardening, notable + compiler internals, the fixpoint line count and test count, and a closing + call to action pointing at the GitHub release page. +- End with a forward-looking line ("Onwards to v! 🙌"). +- Reference `changelog-v.md` for full details. + +### changelog-v.md + +A technical changelog for the GitHub Releases page. Style: + +- Grouped by area (Native backend, Toolchain, Language, ARC/runtime, stdlib, + Codegen, Semantic, Debugging, Performance, Tooling/CI). +- Each entry is one concise line: what changed and why it matters. More + technical than the community post. +- A short "Examples" block under the Language section showing the new syntax is + welcome (same verify-it-compiles rule applies). +- Close with the fixpoint IR line count and the test count. + +## Step 9 — report to the user + +Summarise: + +- Tag created (e.g. `v`) +- Stage-2 IR line count and all four OK lines: "FIXPOINT_OK / NATIVE_FIXPOINT_OK + / NATIVE_INTERNAL_OK / WARMCACHE_FIXPOINT_OK" +- Test count (N tests passing) +- Binary path: `releases/v/blaise` (note: not in git) +- `-pre` bootstrap binary refreshed +- New dev version on master +- Last 3–4 commit oneliners +- Community post: `community-post-v.md` (untracked) +- Changelog: `changelog-v.md` (untracked) +- Release tarball: `releases/blaise-v-linux-x86_64.tar.gz` (upload to GitHub Releases) + +Mention that the user must `git push --tags` themselves if they want the tag on +the remote — never push automatically. + +## Common pitfalls + +- **Unrelated changes swept into the release commit.** `git add project.xml` + stages the WHOLE file, including pre-existing build-option edits. Always + `git add -p` and confirm `git diff --cached --stat` shows exactly two + one-line changes before committing. (This bit the v0.11.0 cut — the commit had + to be reset and redone.) +- **Archiving the QBE binary instead of the native one.** Native is the default + backend, so the shipped/bootstrap binary must be `/tmp/fpn_blaise2` (from + `fixpoint-native.sh`), NOT the QBE `/tmp/fp_blaise2` (from `fixpoint.sh`). The + QBE fixpoint is still required as a reproducibility guard — it just isn't the + artefact. +- **Stale fixpoint binary in /tmp.** A `/tmp/fpn_blaise2` (or `/tmp/fp_blaise3`) + left over from an earlier run can be days old. Always confirm the binary you + archive prints the RIGHT version: ` --help | head -1`. +- **COMPILER_ID out of sync with project.xml → bif-coverage fails.** At release + `COMPILER_ID` drops `-SNAPSHOT`; at the dev-cycle bump it must re-gain + `-SNAPSHOT` for the NEW base version. The base version in `COMPILER_ID` must + always match project.xml's `` base, or `TestRun_BifCoverage_NoGaps` + fails. Keep the `+bif` tag unchanged unless the `.bif` format changed. +- **Forgetting to rename the -pre dir.** The newest `releases/v*-pre/` must name + the cycle being OPENED, not the one just released. After cutting v, + `mv releases/v-pre releases/v.0-pre` (filesystem move — + releases/ is gitignored). CI and rolling-bootstrap pick the newest by name. +- **`compiler/target/blaise` still on the old version.** `fixpoint.sh` does not + rebuild it; do the `pasbuild compile --compiler /tmp/fp_blaise2` step (Step 2) + before the native fixpoints, or they run against the previous version. +- **Forgetting `--compiler`.** Every `pasbuild` command must pass + `--compiler `; without it PasBuild falls back to FPC, which is + not part of this toolchain. +- **Missing `blaise_rtl.a` beside `--compiler`.** When pointing `--compiler` at + `/tmp/fp_blaise2`, copy `compiler/target/blaise_rtl.a` to `/tmp/blaise_rtl.a` + first — `FindRTL` looks beside the binary, and a stale archive causes + undefined-reference link errors. +- **Wrong working directory.** All `pasbuild` commands fail outside the project + root with a confusing version error. Stay at `/data/devel/new-pascal-compiler`. +- **Backgrounded fixpoint output drops.** Run the fixpoint scripts in the + foreground with a generous timeout (600000 ms). Self-built compilation of the + compiler takes ~2 min per stage.