docs: frame Distribution Stage 1 — binaries on tag
.github/workflows/ contains exactly one workflow and it is test-only. There is no release job, no artifact upload, no tags-to-binaries path. Installing pmacs means `git clone` plus knowing the feature-flag matrix. COHERENCE.md §17 grades this "missing — zero release machinery exists", and §20 puts it at Priority 8 with the note that every other priority's value is invisible until it exists. Scope is deliberately ONE STAGE: binaries when a tag is pushed, attached to a GitHub Release. Channels, rollback, update-in-place, signing and first-launch tool detection are out of scope and named in §5. A baseline, not the arc. Revision 2, approved with amendments. Two of them corrected revision 1: THE GLIBC ARITHMETIC. Revision 1 implied that moving off ubuntu-latest buys reach "several distro generations" including RHEL 9. It does not. RHEL 9 ships glibc 2.34, which is BELOW the 2.35 floor a pinned ubuntu-22.04 build sets, so RHEL 9 is excluded by that choice rather than covered by it. The floor is now stated explicitly with its table, so a RHEL 9 user reads "not supported yet" instead of discovering a loader error; supporting it needs a lower-glibc container or cross-build and is parked. WHY CO-LOCATION IS REQUIRED. Revision 1 said separating `pmacs` from `pmacs-gpu` makes `--gpu` "silently fail". Verified against src/main.rs:304: `gpu_binary` prefers a co-located binary when that path is_file(), falls back to a bare-name PATH lookup, and on failure names both — "sibling … is absent and PATH lookup for pmacs-gpu failed". So the requirement is that a release archive be SELF-CONTAINED for a user who unpacks it somewhere off PATH, not that failure is quiet. The load-bearing finding: a release build can produce FIVE binaries and three must never ship. Cargo auto-discovers src/bin/*.rs, so alongside pmacs and pmacs-audit it also builds pmacs_fake_lsp and pmacs_fake_mcp — test fixtures. Exclusion is therefore two-layered, because neither layer suffices alone: explicit --bin targets so the unwanted binaries are not produced, AND an explicit staged asset list so the archive's contents are a decision rather than a directory's residue. Layer 1 alone still archives whatever a cached target/release holds from an earlier step; layer 2 alone relies on a list nobody re-checks when a new src/bin/*.rs appears. Two facts checked rather than assumed while framing: `pmacs-gpu --version` already exists (pmacs-gpu/src/main.rs:667) and prints "pmacs-gpu <ver> (protocol v21)", so asserting both binaries report 1.1.0 is directly implementable after the bump. And `run_gpu` refuses a non-CRDT build outright — "pmacs: --gpu requires pmacs built with --features crdt" — which is a direct citation for shipping CRDT rather than the inference from capability defaults revision 1 used. Framing only. No workflow, no version bump, no release. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
4984169022
commit
2ed2596046
|
|
@ -0,0 +1,321 @@
|
||||||
|
# Framing — Distribution Stage 1: binaries on tag
|
||||||
|
|
||||||
|
**Revision 2.** Status: **approved with amendments** (revision 1 →
|
||||||
|
2 records them). Scouted against `githubsucks/main` @ `c5f7501` (#209).
|
||||||
|
|
||||||
|
`.github/workflows/` contains exactly one workflow and it is test-only.
|
||||||
|
**There is no release job, no artifact upload, no tags-to-binaries path.**
|
||||||
|
Installing pmacs means `git clone` plus knowing the feature-flag matrix.
|
||||||
|
|
||||||
|
**Scope is deliberately one stage: produce binaries when a tag is
|
||||||
|
pushed, and attach them to a GitHub Release.** Channels, rollback,
|
||||||
|
update-in-place, signing, and §17's first-launch tool detection are all
|
||||||
|
**out of scope and named in §5**. This establishes a baseline, not the
|
||||||
|
arc.
|
||||||
|
|
||||||
|
**Revision 1 → 2**, all from review:
|
||||||
|
|
||||||
|
- **Q#D2 decided with a correction to revision 1's reasoning.** It is
|
||||||
|
`ubuntu-22.04` with an explicit **glibc ≥ 2.35** floor — and revision 1
|
||||||
|
was wrong to imply an older runner reaches RHEL 9. It does not (§1.6).
|
||||||
|
- **Q#D1 decided**, with acceptance strengthened to assert *both*
|
||||||
|
binaries report 1.1.0 (§1.3, acceptance 4).
|
||||||
|
- **The binary-exclusion mechanism is now two-layered**, not one:
|
||||||
|
explicit `--bin` targets *and* an explicit staged asset list (§1.2).
|
||||||
|
- **Revision 1 mis-stated `pmacs --gpu`'s failure mode**, and the
|
||||||
|
corrected version changes *why* co-location is required rather than
|
||||||
|
whether (§1.2a).
|
||||||
|
- **Both runners are pinned**, not just Linux (§1.8).
|
||||||
|
- **The RC is cut after merge from the merge SHA** and the final tag
|
||||||
|
reuses that same verified SHA (§7).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 0. Coherence impact (COHERENCE §20)
|
||||||
|
|
||||||
|
**Squarely §17 / §20 Priority 8: it completes journey step 1 without
|
||||||
|
adding an interaction island, a config surface, or a background-work
|
||||||
|
model.**
|
||||||
|
|
||||||
|
- **Journey step touched: step 1 (install)** — the one step no prior arc
|
||||||
|
could reach.
|
||||||
|
- **Concern: §17 Distribution**, graded "missing — zero release
|
||||||
|
machinery exists." This moves it to **Partial**, not Strong: binaries
|
||||||
|
on tag is the first of the seven things §17 asks for.
|
||||||
|
- **Interaction islands added:** none.
|
||||||
|
- **Config registry adoption:** none — this stage introduces no setting.
|
||||||
|
- **Background-work attribution:** none — no worker, job, or process.
|
||||||
|
- **Why now:** §20 P8 says every other priority's value is invisible
|
||||||
|
until this exists, and its prerequisite — a tree whose tests actually
|
||||||
|
run — was only satisfied by #209. Before that, a release would have
|
||||||
|
shipped from a corpus half of which CI had never compiled.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 1. Ground truth (measured at `c5f7501`, 2026-08-01)
|
||||||
|
|
||||||
|
### 1.1 What exists
|
||||||
|
|
||||||
|
Nothing. One workflow, `ci.yml`, test-only; the only `release` strings
|
||||||
|
in it are `cargo test --release` flags.
|
||||||
|
|
||||||
|
### 1.2 The binary set is NOT what a glob would produce
|
||||||
|
|
||||||
|
`Cargo.toml` declares two `[[bin]]` targets, `pmacs` and `pmacs-audit`.
|
||||||
|
But **cargo also auto-discovers `src/bin/*.rs`**, so a release build
|
||||||
|
additionally produces `pmacs_fake_lsp` and `pmacs_fake_mcp` — test
|
||||||
|
fixtures whose purpose is to be spawned by acceptance suites. Plus
|
||||||
|
`pmacs-gpu` from its own package.
|
||||||
|
|
||||||
|
**Five binaries can land in `target/release`, and three must never
|
||||||
|
ship.**
|
||||||
|
|
||||||
|
| binary | ship? | why |
|
||||||
|
|---|---|---|
|
||||||
|
| `pmacs` | **yes** | the editor |
|
||||||
|
| `pmacs-gpu` | **yes** | the GPU frontend |
|
||||||
|
| `pmacs-audit` | **no** | audits pmacs source against the v1.0 lint rules — a contributor tool with no answer to "what is this for" |
|
||||||
|
| `pmacs_fake_lsp` | **never** | test fixture |
|
||||||
|
| `pmacs_fake_mcp` | **never** | test fixture |
|
||||||
|
|
||||||
|
**Exclusion is two-layered, deliberately.** Avoiding an upload glob is
|
||||||
|
not sufficient on its own:
|
||||||
|
|
||||||
|
1. **Build explicit `--bin` targets** — `--bin pmacs` and the
|
||||||
|
`pmacs-gpu` package — so the unwanted binaries are not produced by
|
||||||
|
the release build at all.
|
||||||
|
2. **Stage an explicit asset list** — copy named files into a staging
|
||||||
|
directory and archive *that*, so the archive's contents are a
|
||||||
|
decision rather than a directory's residue.
|
||||||
|
|
||||||
|
Layer 1 without layer 2 still archives whatever a cached
|
||||||
|
`target/release` happens to hold from an earlier step; layer 2 without
|
||||||
|
layer 1 relies on a list nobody re-checks when a new `src/bin/*.rs`
|
||||||
|
appears. Acceptance 2 asserts the **complete member list**, the
|
||||||
|
**executable bits**, and the **absence of all three** excluded binaries.
|
||||||
|
|
||||||
|
### 1.2a Why `pmacs` and `pmacs-gpu` must be co-located — corrected
|
||||||
|
|
||||||
|
Revision 1 said separating them makes `--gpu` "silently fail." **That is
|
||||||
|
wrong, and the real behaviour is better.** `gpu_binary`
|
||||||
|
(`src/main.rs:304`) prefers a **co-located** `pmacs-gpu` when that path
|
||||||
|
`is_file()`, otherwise falls back to the bare name `pmacs-gpu` for a
|
||||||
|
**PATH lookup**; if neither resolves, the error names both — *"sibling
|
||||||
|
… is absent and PATH lookup for pmacs-gpu failed"*.
|
||||||
|
|
||||||
|
So the requirement is not "otherwise it breaks quietly." It is that
|
||||||
|
**a release archive must be self-contained**: a user who unpacks it
|
||||||
|
somewhere not on `PATH` gets a working `--gpu` only if the two binaries
|
||||||
|
sit together. The fallback is a convenience for installed layouts, not a
|
||||||
|
substitute for shipping them as a unit.
|
||||||
|
|
||||||
|
### 1.3 The version is already incoherent, and a tag makes it visible
|
||||||
|
|
||||||
|
| crate | now | after |
|
||||||
|
|---|---|---|
|
||||||
|
| `pmacs` | 1.0.0 | **1.1.0** |
|
||||||
|
| `pmacs-gpu` | **0.0.1** | **1.1.0** |
|
||||||
|
| `pmacs-protocol` | 1.0.0 | **1.0.0** (unchanged) |
|
||||||
|
|
||||||
|
`pmacs-protocol` stays: it is the wire crate, carries publish-shaped
|
||||||
|
metadata, and versions on its own schedule — the protocol is v21 and
|
||||||
|
independent of the editor's release number.
|
||||||
|
|
||||||
|
Both shipped binaries report their own `env!("CARGO_PKG_VERSION")`:
|
||||||
|
`pmacs --version` at `src/main.rs:393`, and `pmacs-gpu --version` at
|
||||||
|
`pmacs-gpu/src/main.rs:667`, which prints `pmacs-gpu <ver> (protocol
|
||||||
|
v21)` — the protocol number is worth carrying into the release notes.
|
||||||
|
|
||||||
|
Tagging `v1.1.0` against the tree as it stands would publish a release
|
||||||
|
containing a `pmacs` reporting `1.0.0` and a `pmacs-gpu` reporting
|
||||||
|
`0.0.1`. **The workflow must refuse rather than publish** (acceptance
|
||||||
|
4), and acceptance asserts the *binaries'* output, not the manifests.
|
||||||
|
|
||||||
|
### 1.4 The existing `v1.0.0` tag is stale and is not re-used
|
||||||
|
|
||||||
|
`v1.0.0` is pushed and points at `d3fa632` — the old release mirror's
|
||||||
|
head, **1,025 commits behind `main`**. There is also an `M8` milestone
|
||||||
|
tag. A `v*`-triggered workflow does not retroactively build for either,
|
||||||
|
and re-tagging would rewrite a published ref. The first real release is
|
||||||
|
**`v1.1.0`**, preceded by `v1.1.0-rc.1` (§7).
|
||||||
|
|
||||||
|
### 1.5 CRDT is not optional for a useful release
|
||||||
|
|
||||||
|
`default = ["luajit"]`; `luajit` and `lua54` are **mutually exclusive**;
|
||||||
|
`crdt` is opt-in on the root package, activated workspace-wide as
|
||||||
|
`pmacs/crdt`. README's documented build is the one to ship:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
cargo build --release --workspace --features pmacs/crdt
|
||||||
|
```
|
||||||
|
|
||||||
|
**This is not a size/quality trade — a non-CRDT build refuses `--gpu`
|
||||||
|
outright.** `run_gpu` opens with a guard printing *"pmacs: --gpu
|
||||||
|
requires pmacs built with --features crdt"*. #209 established the same
|
||||||
|
thing on the wire side: `InstanceCapabilities::default` advertises
|
||||||
|
`multi_frontend` / `crdt_replica` / `semantic_render` only under the
|
||||||
|
feature. A non-CRDT release ships an editor that cannot use the GPU
|
||||||
|
frontend shipped beside it.
|
||||||
|
|
||||||
|
### 1.6 The glibc floor — decided, and revision 1's reasoning corrected
|
||||||
|
|
||||||
|
**Linux releases build on pinned `ubuntu-22.04`, with a stated support
|
||||||
|
floor of glibc ≥ 2.35.**
|
||||||
|
|
||||||
|
Revision 1 implied that moving off `ubuntu-latest` buys reach "several
|
||||||
|
distro generations" including RHEL 9. **It does not, and the arithmetic
|
||||||
|
matters:**
|
||||||
|
|
||||||
|
| target | glibc | covered by a 22.04 build? |
|
||||||
|
|---|---|---|
|
||||||
|
| Ubuntu 22.04 (jammy) | 2.35 | **yes** — this is the floor |
|
||||||
|
| Debian 12 (bookworm) | 2.36 | **yes** |
|
||||||
|
| Ubuntu 24.04 | 2.39 | yes |
|
||||||
|
| **RHEL 9** | **2.34** | **NO — below the floor** |
|
||||||
|
|
||||||
|
RHEL 9 is *older* than the floor, so it needs a lower-glibc container or
|
||||||
|
cross-build. **That is not a one-word runner change** and is parked
|
||||||
|
(§5). Stating the floor explicitly is what keeps this honest: a user on
|
||||||
|
RHEL 9 should read "not supported yet," not discover a loader error.
|
||||||
|
|
||||||
|
References: [runner images](https://github.com/actions/runner-images),
|
||||||
|
[jammy libc6](https://packages.ubuntu.com/jammy-updates/libc6),
|
||||||
|
[bookworm libc6](https://packages.debian.org/bookworm/libc6).
|
||||||
|
|
||||||
|
### 1.7 Runtime dependencies are documented but never checked
|
||||||
|
|
||||||
|
README names `/bin/sh`, `stty`, coreutils, git and tar, and tells
|
||||||
|
packagers to encode them. **Nothing checks any of them at runtime.**
|
||||||
|
Out of scope here (§5), but the release notes carry the list rather than
|
||||||
|
assume a downloader reads the README.
|
||||||
|
|
||||||
|
`pmacs-gpu` additionally needs a working Vulkan/Metal adapter; there is
|
||||||
|
no software-rasterizer fallback in a shipped binary.
|
||||||
|
|
||||||
|
### 1.8 Runner pinning, and what is NOT established
|
||||||
|
|
||||||
|
**Both runners are pinned**, not just Linux: `macos-latest` currently
|
||||||
|
resolves to macos-15 (ARM64) and **will drift** — the same silent-choice
|
||||||
|
problem as §1.6, in the other direction, where a future move could
|
||||||
|
change the minimum supported macOS without a commit to point at.
|
||||||
|
|
||||||
|
- **No release has ever been produced**, so nothing here is verified
|
||||||
|
end-to-end. Unlike #209 there is no existing behaviour to measure
|
||||||
|
against; the RC is the first evidence.
|
||||||
|
- **No Intel macOS** (§5). arm64 only.
|
||||||
|
- **No signing or notarization.** A downloaded macOS binary is
|
||||||
|
Gatekeeper-quarantined and needs an explicit override. Expected for an
|
||||||
|
unsigned baseline; it belongs in the release notes rather than in a
|
||||||
|
claim that macOS "just works".
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 2. Decisions (all questions resolved at approval)
|
||||||
|
|
||||||
|
- **Q#D1 — versions.** `pmacs` and `pmacs-gpu` → 1.1.0;
|
||||||
|
`pmacs-protocol` stays 1.0.0. Acceptance asserts both shipped binaries
|
||||||
|
*report* 1.1.0 and the tag is `v1.1.0`.
|
||||||
|
- **Q#D2 — Linux runner.** Pinned `ubuntu-22.04`; support floor
|
||||||
|
glibc ≥ 2.35, covering Ubuntu 22.04 and Debian 12 but **not RHEL 9**.
|
||||||
|
- **Q#D3 — `pmacs-audit`.** Does not ship.
|
||||||
|
- **Q#D4 — Intel macOS.** Not in the baseline. macOS runner pinned.
|
||||||
|
- **Q#D5 — checksums.** Ship them.
|
||||||
|
- **Q#D6 — tests on release.** Do not re-run the suite; assert the
|
||||||
|
tagged commit is an ancestor of `main`, which catches the real mistake
|
||||||
|
(tagging a branch) at negligible cost.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 3. Bets
|
||||||
|
|
||||||
|
- **Bet 1 — the release build is the CI build with different flags** and
|
||||||
|
will succeed first time.
|
||||||
|
- **Bet 2 — the artifact, not the build, is where this goes wrong.** The
|
||||||
|
plausible failures are packaging-shaped: a stray binary, a split
|
||||||
|
archive, a version mismatch, a glibc floor nobody notices.
|
||||||
|
- **Bet 3 — one RC is enough evidence.** A release either produces two
|
||||||
|
runnable, correctly-versioned binaries at a URL or it does not.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 4. Acceptance
|
||||||
|
|
||||||
|
1. Pushing a tag matching `v*` produces a **GitHub Release** with
|
||||||
|
attached artifacts; no other trigger produces one. `v1.1.0-rc.1` is
|
||||||
|
marked **prerelease**.
|
||||||
|
2. Each archive's **complete member list** is asserted, along with
|
||||||
|
**executable bits**, and the **absence of `pmacs-audit`,
|
||||||
|
`pmacs_fake_lsp` and `pmacs_fake_mcp`**. Verified by listing the
|
||||||
|
downloaded archive, not by trusting the build command.
|
||||||
|
3. `pmacs` and `pmacs-gpu` are in the **same directory** within the
|
||||||
|
archive, so an unpacked release is self-contained (§1.2a).
|
||||||
|
4. **Version coherence, asserted from the binaries:** the workflow
|
||||||
|
refuses to publish when the tag disagrees with the root crate
|
||||||
|
version, and the downloaded `pmacs --version` and `pmacs-gpu
|
||||||
|
--version` both report **1.1.0**. Verified by a deliberate mismatch,
|
||||||
|
not by inspection.
|
||||||
|
5. The tagged commit is an ancestor of `main`.
|
||||||
|
6. Each artifact is a **CRDT build**, verified by running the shipped
|
||||||
|
binary rather than trusting the flag (§1.5).
|
||||||
|
7. The Linux binary **runs on Ubuntu 22.04 and Debian 12** — verified in
|
||||||
|
containers — and its glibc floor is stated in the release notes.
|
||||||
|
8. `SHA256SUMS` covers every published artifact and verifies against the
|
||||||
|
downloads.
|
||||||
|
9. Release notes carry the runtime dependencies (§1.7), the glibc floor,
|
||||||
|
the arm64-only macOS scope, and the unsigned/Gatekeeper caveat.
|
||||||
|
10. `README.md`'s install section offers the download path **before**
|
||||||
|
from-source.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 5. Parked (explicitly out of scope)
|
||||||
|
|
||||||
|
Named so they read as decisions. All are §17 requirements this stage
|
||||||
|
does not meet:
|
||||||
|
|
||||||
|
- **RHEL 9 and older glibc** — needs a container or cross-build (§1.6).
|
||||||
|
- **Intel macOS.**
|
||||||
|
- **Release channels**, stable/nightly.
|
||||||
|
- **Update-in-place and rollback.**
|
||||||
|
- **Signing and notarization.**
|
||||||
|
- **Reproducible builds.**
|
||||||
|
- **Package managers** — Homebrew, AUR, nixpkgs, distro packages.
|
||||||
|
- **Windows.** Unsupported anywhere in the tree today.
|
||||||
|
- **First-launch experience** — §17's config-directory creation and
|
||||||
|
optional-tool detection. That is §18 onboarding work.
|
||||||
|
- **Protocol/package-API compatibility reporting.**
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 6. Gates
|
||||||
|
|
||||||
|
The standing `CLAUDE.md` suite applies unchanged; this stage adds no
|
||||||
|
Rust logic and no test, beyond the version bumps which the whole suite
|
||||||
|
covers. **Its real verification is the RC artifact** — acceptance 2, 3,
|
||||||
|
4, 6, 7 and 8 are all performed against a *downloaded* archive, because
|
||||||
|
that is the only thing that tests a release.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 7. Branch plan
|
||||||
|
|
||||||
|
One branch, `distribution-stage1`:
|
||||||
|
|
||||||
|
1. **Bump `pmacs` and `pmacs-gpu` to 1.1.0** (Q#D1).
|
||||||
|
2. **Add `.github/workflows/release.yml`** — `on: push: tags: ['v*']`,
|
||||||
|
pinned `ubuntu-22.04` + pinned macOS runner, explicit `--bin`
|
||||||
|
targets, explicit staged asset list, the tag/version assertion, the
|
||||||
|
ancestor check, and `SHA256SUMS`.
|
||||||
|
3. **Update `README.md`** so download precedes build-from-source, and
|
||||||
|
state the glibc floor and macOS scope.
|
||||||
|
4. **Merge.**
|
||||||
|
5. **Tag `v1.1.0-rc.1` from the merge SHA**, marked prerelease. Verify
|
||||||
|
acceptance 2–8 against the published artifacts.
|
||||||
|
6. **Tag `v1.1.0` from that same verified SHA.**
|
||||||
|
|
||||||
|
**Steps 5 and 6 are the point of the ordering.** A tag on a branch would
|
||||||
|
publish a release from unmerged code, so the RC necessarily follows the
|
||||||
|
merge — and it is cut *from the merge SHA*, so the final tag can reuse
|
||||||
|
the exact commit the RC verified. **If the RC finds a defect, it is
|
||||||
|
fixed in a new PR and another RC is cut; the final tag is never the
|
||||||
|
first live execution of this workflow.**
|
||||||
Loading…
Reference in New Issue