docs: absorb the v1.1.0 release, and correct what it made stale

Two parts, one intent: record the release, and fix the user-facing
surfaces it falsified.

ABSORPTION. v1.1.0 shipped and nothing recorded it. docs/active-work.md
had no distribution lane, the handoff anchor still named c5f7501, and
COHERENCE.md — a REQUIRED framing input — still asserted "zero release
machinery exists" and graded journey step 1 as source-build-only. Both
are now false, and a framing doc written against them would have been
written against a lie.

  * §0 scorecard: step 1 Partial -> Works; §17 Missing -> Partial; the
    journey row moves off "steps 1, 11 and 12 remain the thin end" to
    name 11 and 12 only.
  * §17 ground truth rewritten: what Stage 1 shipped, and the nine
    things it explicitly did not.
  * §20 Priority 8: "State: zero" -> Stage 1 shipped, with the blocker
    it named ("every other priority's value is invisible until this one
    exists") recorded as LIFTED. Its next increment is a DECISION about
    channels/update/signing, not a queued plan — worth stating so nobody
    treats Stage 2 as pre-approved.
  * A distribution lane in active-work.md, rewritten-not-removed because
    the arc is not done.

Five durable facts move to the handoff §1, each of which cost something
to learn:

  * a release build can produce FIVE binaries and three must never ship;
    layer-2 exclusion is load-bearing, demonstrated when target/release
    still held all three after building only two;
  * `env!("CARGO_PKG_VERSION")` expands in the crate being COMPILED, and
    three correct tests could not fail while two crates shared a number;
  * pin release runners, and assert the glibc floor from the binary
    rather than trusting the pin;
  * a tag pushed before its workflow reaches the default branch does
    nothing, SILENTLY;
  * verify from the downloaded artifact, with a negative control — the
    1,576 `loro` strings mean nothing without the control build's zero.

STALENESS, found by reading the surfaces a new downloader hits first.

`pmacs --help` claimed the TUI was "currently the only frontend;
reserved for the M4 GUI rollout, where `pmacs` will default to the GUI".
That is not merely dated — it is false in a release that SHIPS the GPU
frontend as a second binary. Rewritten to say what -nw actually does
(name the default explicitly for scripts and wrappers), and --gpu now
states its two real preconditions: a `crdt` build, and pmacs-gpu either
beside the binary or on PATH. Both are things a downloader can get
wrong and neither was documented where they would look.

Also in main.rs: the TLS attach line said "activation in v0.2" and four
doc comments dated themselves "v0.1" or "M4+" while describing behaviour
that is still current. The behaviour claims were accurate; only the
version labels lied, so the labels are gone rather than the sentences
rewritten. One comment gained a correction it needed regardless —
FrontendChoice is IN-PROCESS dispatch and the GPU frontend is not a
value of it, which the old text implied it eventually would be.

README status block: v1.0.0 -> v1.1.0, protocol v20 -> v21, and it
pointed at docs/roadmap-2026-07.md for "current direction" — a file that
opens by calling itself a historical snapshot and redirecting to the
handoff. It now points at COHERENCE.md and the handoff, and mentions the
arcs that landed since it was last touched.

Verified: fmt, diff-check, clippy with and without crdt, --lib 1896,
--lib --features crdt 2081, pmacs-protocol 19, m4 149, required GPU 221,
and `pmacs --help` rendered and read.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Levi Neuwirth 2026-08-01 18:09:59 -04:00
parent 000b6cd333
commit 7bfb238474
No known key found for this signature in database
5 changed files with 166 additions and 46 deletions

View File

@ -95,7 +95,7 @@ remain open to them.
| § | Concern | Grade | One-line state |
|---|---|---|---|
| 2 | Golden product journey | **Runs to step 10** | `pmacs .` opens the directory (1a); the interface introduces itself (1b-3); a missing language server says so (1b-2, #204); a build is bound and prefilled (1b-1, #203). Steps 1, 11 and 12 remain the thin end |
| 2 | Golden product journey | **Runs end to end, thin at 1112** | **Step 1 now works — v1.1.0 ships binaries (#211)**, so the journey no longer begins with a source build. `pmacs .` opens the directory (1a); the interface introduces itself (1b-3); a missing language server says so (1b-2, #204); a build is bound and prefilled (1b-1, #203). **Steps 11 (background-work ownership, §9) and 12 (session restore) are the remaining thin end** |
| 3 | Zero-configuration state | **Partial** | Defaults genuinely strong; missing-tool failure is silent, not graceful |
| 4 | Progressive disclosure | **Inverted** | The advanced level is real; the beginner level is the missing one |
| 5 | Unified discoverability | **Partial** | Discovery Stage 1: eleven `help.*` commands (describe key/mode/hook/buffer/command/setting, where-is, list commands/keybindings/settings, apropos) over the existing registries, indexed by `M-x help`. Commands, keys, modes, hooks and settings are now reachable, and `*workers*` already was (`M-x editor.list-workers`); **packages have no comparable surface** (§13), and workers still lack owner/purpose/hierarchy and any indicator (§9). `Command` still has no title/category/flags, M-x rows are still bare names, and the Rust help layer is still orphaned |
@ -110,7 +110,7 @@ remain open to them.
| 14 | Workbench primitives | **Partial (best trajectory)** | Listview is a real primitive but only 3 call sites, all LSP panels; buffer-list and search re-implement it; bottom panel complete on BOTH frontends (#155 + Stage 2) |
| 15 | Contextual affordances | **Weak** | Right-click menu only; code actions apply first-blindly; no git integration at all |
| 16 | Semantic frontend | **Strong** | v6..=v21 schema support; production attach remains v20 during the dark panel slice; degradation practiced |
| 17 | Distribution | **Missing** | CI is test-only; no binaries, channels, checksums, or update path |
| 17 | Distribution | **Partial** | **v1.1.0 ships prebuilt Linux/macOS binaries on tag** (#211) with checksums and a stated glibc floor. No channels, in-place update, rollback, signing, or package-manager distribution |
| 18 | Onboarding | **Partial** | Journey Stage 1b-3: an unconfigured launch greets in `*scratch*` naming `M-x` and four real bindings, and `M-x help` renders a cheat sheet. Still no tutorial and `C-h` still deletes a word — deliberately, see §18 |
| 19 | Coherence acceptance tests | **Started** | `tests/journey_acceptance.rs` carries 45 pins over steps 2, 3, 4, 5, 6 and 9 — the ratchet is real and stages add rows to it. The other five §19 scenarios (workspace lifecycle, worker ownership, config provenance, package lifecycle, extension isolation) are still unwritten |
@ -389,7 +389,7 @@ Full verdict table:
| # | Step | Verdict | Evidence |
|---|---|---|---|
| 1 | Install | **Partial** | Source build only: `cargo build --release --workspace --features pmacs/crdt` (`README.md`). No binaries, no packaging. Runtime deps (`/bin/sh`, git, tar, coreutils) documented, never checked at runtime |
| 1 | Install | **Works** | **v1.1.0 ships prebuilt Linux x86_64 / macOS arm64 binaries with `SHA256SUMS`** (#211); source build remains. Not yet: package managers, in-place update, signing. Runtime deps (`/bin/sh`, git, tar, coreutils) are documented in the release notes but still never checked at runtime |
| 2 | Launch unconfigured | **Works** | `EditorState::new()` → empty `*scratch*`; missing config is not an error (`src/config.rs:7-9`); recentf/saveplace/autosave default-on |
| 3 | Open real project | **Works at the CLI** | Journey Stage 1a: `resolve_target_buffer` answers `ResolvedTarget::Directory` before the EISDIR-producing load, and `EditorState::open` / the daemon bootstrap dispatch the `path.open-directory` chain, whose fallback is dired (#165's buffer, reached rather than duplicated). Startup no longer fails: an unreadable directory, a crashed resolver, and a cleared handler all report on the status line and leave the session running. Because the listing is async and the bootstrap is synchronous, the commit runs against a destination captured at request time (`pmacs.window.commit_to`) rather than against the ambient frontend |
| 4 | Understand interface | **Partial** | Mode line gives name/modified/L:C/scroll + mode/LSP/terminal segments. Journey Stage 1b-3 adds a welcome in `*scratch*` and `M-x help`; **still Partial** because `C-h` deletes a word (deliberately — §18) and there is no tutorial |
@ -1487,13 +1487,22 @@ optional external tools, and let the user open a project immediately.
### Ground truth
**Grade: missing — zero release machinery exists.**
**Grade: partial — binaries on tag exist; everything after them does
not.**
`.github/workflows/` contains exactly one workflow, `ci.yml`, and it is
test-only (fmt/clippy/test matrix; the only `release` strings in it are
`cargo test --release` flags). No release job, no artifact upload, no
tags-to-binaries path, no checksums, no channels, no update or rollback
mechanism. Installation is `git clone` + `cargo build --release
**Distribution Stage 1 (#211, shipped as v1.1.0) closed the first of the
seven things this section asks for.** A `v*` tag now builds `pmacs` and
`pmacs-gpu` on pinned `ubuntu-22.04` and `macos-15`, asserts the tag
against the crate version and the commit against `main`, verifies the
archive's exact contents, machine-checks a **glibc ≥ 2.35** floor, and
publishes a GitHub Release with `SHA256SUMS`.
Still missing: channels, in-place update, rollback, signing and
notarization, reproducible builds, package-manager distribution,
Windows, Intel macOS, RHEL 9 (below the glibc floor), and
protocol/package-API compatibility reporting. See
`docs/distribution-stage1-framing.md` §5, where each is a stated
non-goal rather than an omission. Installation is `git clone` + `cargo build --release
--workspace --features pmacs/crdt` (README), which additionally requires
knowing the feature-flag matrix (luajit vs lua54 × crdt). Runtime
dependencies (`/bin/sh`, `stty`, git, tar) are documented in the README
@ -1681,10 +1690,18 @@ sequencing per §13.
### Priority 8: Ship binaries and release channels
**State: zero (§17). Independent of everything — can start anytime.**
The editor becomes testable by users who are not repository
contributors; every other priority's value is invisible until this one
exists.
**State: Stage 1 SHIPPED as v1.1.0 (#211); the rest of §17 is
untouched.** The editor is now installable by someone who has never
cloned the repository — **journey step 1 is reachable for the first
time**, and this priority's stated blocker ("every other priority's
value is invisible until this one exists") is lifted.
What Stage 1 deliberately did not do is as important as what it did:
channels, in-place update, rollback, signing, reproducible builds, and
package-manager distribution are all still absent, and each is a named
non-goal in `docs/distribution-stage1-framing.md` §5 rather than an
oversight. The next increment is a decision about which of those the
project actually wants, not a continuation of a plan.
### How this maps to arcs
@ -1718,7 +1735,9 @@ implementation — this list is direction, not commitment):
6. **Workspace entity** (P2): the object, then location values.
7. **Config provenance + adoption** (P6).
8. **Package lifecycle** (P7, after 4).
9. **Distribution** (P8, anytime).
9. **Distribution** (P8): **Stage 1 landed (#211)** — binaries on tag,
checksums, a machine-checked glibc floor. Later stages (channels,
update, signing) are unscoped and independent.
A standing process change accompanies all of them (§1.3): **every new
framing doc must state its coherence impact** — which journey steps it

View File

@ -29,17 +29,25 @@ the same buffers concurrently with live cursor/selection presence.
## Status
**v1.0.0 --- stable core, active development.** The v1.0 gate (the
instance/frontend partition, the Lua surface, and a REPL package audited
to use zero direct Rust core access) shipped some time ago. Development
since has expanded the semantic frontend protocol from v6 through v20,
brought the GPU frontend near input/render parity with the TUI, and
completed the LSP, editing, persistence, themes, and terminal arcs. Recent
work added major modes and modeline detection, a typed configuration
registry, composable statuslines, multi-language syntax processing, and
cross-frontend tab-width parity. Current direction lives in
`docs/roadmap-2026-07.md`. Public contributions are open: use, evaluate,
file issues, and send pull requests.
**v1.1.0 --- stable core, active development, and the first release
with prebuilt binaries.** The v1.0 gate (the instance/frontend
partition, the Lua surface, and a REPL package audited to use zero
direct Rust core access) shipped some time ago. Development since has
expanded the semantic frontend protocol from v6 through **v21**, brought
the GPU frontend near input/render parity with the TUI, and completed
the LSP, editing, persistence, themes, and terminal arcs. Recent work
added major modes and modeline detection, a typed configuration
registry, composable statuslines, multi-language syntax processing,
cross-frontend tab-width parity, a directory browser, a describe/list
command family, and a bottom panel on both frontends.
Current direction lives in `COHERENCE.md` (the product-coherence thesis
and its audited priority order) and `docs/agent-handoff.md` (durable
project state). `docs/roadmap-2026-07.md` is a historical planning
snapshot and is no longer the authority.
Public contributions are open: use, evaluate, file issues, and send
pull requests.
## Highlights

View File

@ -205,6 +205,47 @@ git worktree add ../pmacs-ci-crdt \
githubsucks/ci-crdt-coverage
```
## Distribution (P8) — STAGE 1 SHIPPED as v1.1.0 (#211)
**Rewritten as a lane rather than removed**: the arc is not done — Stage
1 was scoped to binaries-on-tag and everything else in §17 is untouched.
Framing `docs/distribution-stage1-framing.md` revision 3. Durable facts
are in `docs/agent-handoff.md` §1.
- **Released 2026-08-01.** `v1.1.0-rc.1` (prerelease) then `v1.1.0`,
**both cut from the same commit `000b6cd`** — the #211 merge SHA — so
the final release was built from byte-identical source to the one whose
artifacts were verified.
- **Verified against the DOWNLOADED artifacts, both tags, not the build
logs:** archive member lists (exactly `pmacs`, `pmacs-gpu`, README, two
licenses), executable bits, absence of `pmacs-audit` /
`pmacs_fake_lsp` / `pmacs_fake_mcp`, `pmacs --version` = `1.1.0` and
`pmacs-gpu --version` = `1.1.0 (protocol v21)`, `SHA256SUMS`, the
glibc floor, and CRDT presence **against a non-CRDT negative control**
(1,576 `loro` strings shipped versus **0** in a control build — the
control is what makes the number mean anything).
- **`pmacs` alone needs only glibc 2.34; `pmacs-gpu` needs 2.35.** The
stated floor is the pair's, 2.35, not the more flattering single-binary
number. That is why RHEL 9 (2.34) is excluded even though the editor
binary would run there.
### Still owned by this lane, not yet done
Each is a stated non-goal of Stage 1 (framing §5), not an oversight.
**The next increment is a decision about which of these the project
wants, not a continuation of a plan.**
- **Channels** (stable/nightly), **in-place update**, **rollback**.
- **Signing and notarization.** macOS binaries are Gatekeeper-quarantined
today; the release notes say so.
- **RHEL 9 and older glibc** — needs a container or cross-build, not a
runner change.
- **Intel macOS**, **Windows**, **reproducible builds**,
**package-manager distribution**.
- **Runtime dependency checking.** §17 asks first launch to identify
optional external tools; `/bin/sh`, `stty`, git and tar are documented
and never checked. That is §18 onboarding work.
## Discovery lane (P4) — STAGE 1 MERGED (#207); STAGE 2 IS NEXT
**Rewritten, not removed.** Rule 4 removes a lane when its ARC is done;

View File

@ -1,6 +1,9 @@
# Agent handoff — cross-machine continuity
**Last updated: 2026-08-01, as the CI CRDT coverage lane #209 — the
**Last updated: 2026-08-01, as Distribution Stage 1 #211 — released as
v1.1.0, the first pmacs release with prebuilt binaries, which makes
journey step 1 reachable without cloning the repository. Beneath it the
docs absorption #210 and the CI CRDT coverage lane #209 — the
first time CI has ever compiled and run the `crdt` half of the test
corpus, closing a gap that left 279 tests (including a REQUIRED
`CLAUDE.md` gate) unexecuted for the project's whole life. Development
@ -65,14 +68,55 @@ commands, read `docs/active-work.md` immediately after this file.
## 1. Where the project stands (2026-08-01)
- **`main` @ `c5f7501`.** The CI CRDT coverage lane #209 lands atop the
docs absorption #208 and `cfc1710`. Beneath that, nine PRs landed in
- **`main` @ `000b6cd`, released as v1.1.0.** Distribution Stage 1 #211
lands atop the docs absorption #210, the CI CRDT coverage lane #209,
the absorption #208 and `cfc1710`. Beneath that, nine PRs landed in
this order: the ledger absorption #199, the process-signal diagnostic
#200, the test ambient-root isolation **framing** #201, the
reap-ledger diagnostic #202, Journey Stage **1b-1** #203, **1b-2**
#204 and **1b-3** #205, the ambient-root isolation **implementation**
#206, and discovery Stage 1 #207. Each has its own bullet below; this
line is the head-of-`main` anchor and nothing else.
- **pmacs is installable without cloning — Distribution Stage 1, #211,
released as v1.1.0.** A `v*` tag builds `pmacs` and `pmacs-gpu` on
pinned `ubuntu-22.04` / `macos-15` and publishes a GitHub Release with
`SHA256SUMS`. **Journey step 1 works for the first time**, and
`COHERENCE.md` §17 moves missing → Partial. Scope was deliberately
binaries-only; channels, update, rollback and signing are stated
non-goals. Five durable facts:
- **A release build can produce FIVE binaries and three must never
ship.** Cargo auto-discovers `src/bin/*.rs`, so `pmacs-audit`,
`pmacs_fake_lsp` and `pmacs_fake_mcp` appear alongside the two real
ones. Exclusion is **two-layered** — explicit `--bin` targets *and*
an explicit staged asset list — and layer 2 is not belt-and-braces:
building the branch, `target/release` still held all three from an
earlier `cargo test --release`, and `Swatinem/rust-cache` restores
exactly that in CI. **Archiving `target/release` would have published
a fake language server.**
- **`env!("CARGO_PKG_VERSION")` expands in the crate being COMPILED.**
`InstanceIdentity::for_running_process` lived in `pmacs-protocol` and
read it there, so the daemon reported the *protocol* crate's version
to every frontend under a field named `pmacs_version`. Three tests
asserted the right thing and **could not fail** while both crates
read 1.0.0 — diverging them is what made the tests discriminating.
*A test can be correct and still prove nothing when the two things it
compares are equal for an unrelated reason.*
- **Pin release runners, never `-latest`.** `ubuntu-latest` (glibc
2.39) silently produces binaries that fail to load on Ubuntu 22.04
and Debian 12; `macos-latest` drifts the minimum supported macOS with
no commit to point at. And **a pinned runner proves nothing about the
artifact** — the glibc floor is asserted by reading versioned symbols
out of the binary (`objdump -T | grep GLIBC_`), so a bad runner
change fails in CI instead of shipping.
- **A tag pushed before its workflow is on the default branch does
nothing, silently.** `on: push: tags` resolves the workflow file at
the tagged commit, and GitHub registers workflows from the default
branch. No run, no error — indistinguishable from "not started yet",
which is the worst possible shape for a release step. Confirm a run
actually appeared.
- **Verify a release from the DOWNLOADED artifact, and use a negative
control.** Checking CRDT presence by counting `loro` strings means
nothing without building a non-CRDT binary and getting zero.
- **CI runs the CRDT half of the corpus for the first time — #209.**
`.github/workflows/ci.yml` had never enabled the `crdt` feature, so
every `#[cfg(feature = "crdt")]` test was **not compiled** — not
@ -140,7 +184,7 @@ anchor, so every item is startable.
| 5 | Workbench convergence | Partial, best trajectory | Bottom panel done both frontends; **Stage 3 = flip the adopter default**. Then the tree primitive — build it *before* dired and the worker tree invent two |
| 6 | Config productization | Foundation only | Value provenance, then layering, then adoption migration (**table-valued settings are the hard prerequisite** — `ConfigValue` is four scalars) |
| 7 | Package lifecycle | Not started | Correctly sequenced after P3 |
| 8 | Distribution | Zero | Independent of everything, startable any time. **Every other priority's value is invisible until this one exists** |
| 8 | **Distribution** | **Stage 1 SHIPPED (v1.1.0, #211)** | Binaries on tag, checksums, machine-checked glibc floor. **Journey step 1 now works and the "invisible until this exists" blocker is lifted.** Next is a *decision* about channels / update / signing, not a queued plan |
#### Open lanes (branch exists, work not finished)

View File

@ -39,12 +39,14 @@ usage: pmacs [-nw|--no-window] [--help] [--version] [FILE]
pmacs --attach <target>
pmacs --daemon-attach [--socket NAME|PATH]
-nw, --no-window select the TUI frontend explicitly
(currently the only frontend; reserved for the
M4 GUI rollout, where `pmacs` will default to
the GUI and `-nw` will keep launching the TUI)
-nw, --no-window select the TUI frontend explicitly. This is the
default; `pmacs FILE` already opens the TUI, so
the flag exists to say so unambiguously in
scripts and wrappers.
--gpu start or reuse a CRDT daemon, then launch the
separate pmacs-gpu frontend
separate pmacs-gpu frontend. Requires a build
with the `crdt` feature, and the `pmacs-gpu`
binary either beside this one or on PATH.
When FILE is present, open it before the GPU window appears.
--daemon run as a foreground daemon listening on a Unix
socket; supervised by the user (systemd, tmux,
@ -67,20 +69,24 @@ attach <target> shorthand:
pmacs --attach user@host ssh as user
pmacs --attach ssh:user@host/research ssh, target instance `research`
pmacs --attach local:/tmp/foo.sock explicit local socket path
pmacs --attach tls:host:port#cert.pem TLS (parses; activation in v0.2)
pmacs --attach tls:host:port#cert.pem TLS (parsed, not yet implemented)
A bare hostname is interpreted as `ssh:<host>`. Use `local:` or
`--socket` for local-socket attaches.
";
/// Frontend the user asked for. Only `Tui` is implemented in v0.1;
/// `GuiAuto` records "the user did not force TUI" so future builds
/// can dispatch to a GUI frontend without touching the parsing layer.
/// Frontend the user asked for by IN-PROCESS dispatch. Both variants
/// run the TUI: the GPU frontend is a separate binary reached through
/// `--gpu`, not a value of this enum. `Auto` records "the user did not
/// force TUI" so a future display-detecting default can dispatch
/// without touching the parsing layer.
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
enum FrontendChoice {
/// Explicit `-nw` / `--no-window`. Always TUI.
Tui,
/// Default. v0.1: TUI. M4+: TUI when no display is available, GUI otherwise.
/// Default. Runs the TUI today. Reserved for a future
/// display-detecting default; `--gpu` is the explicit GPU path and
/// does not route through here.
Auto,
}
@ -93,7 +99,7 @@ struct CliArgs {
#[derive(Debug, PartialEq, Eq)]
enum Mode {
/// Plain `pmacs` (or with `-nw` / a file): run a fresh in-process
/// TUI. The default for v0.1 — no daemon-attach magic.
/// TUI. The default — no daemon-attach magic.
Local {
file: Option<PathBuf>,
frontend: FrontendChoice,
@ -177,8 +183,8 @@ fn build_attach_mode(file: Option<PathBuf>, socket: Option<String>) -> Result<At
/// continue to work.
///
/// IPv6 literals like `[::1]` are not supported as bare hostnames
/// — the strict parser would reject them anyway. v0.1 SSH config
/// aliases and IPv4 / DNS hostnames are the supported shapes.
/// — the strict parser would reject them anyway. SSH config aliases
/// and IPv4 / DNS hostnames are the supported shapes.
fn parse_attach_target_with_shorthand(s: &str) -> Result<AttachTarget, AttachTargetError> {
if s.contains(':') {
AttachTarget::parse(s)
@ -399,10 +405,12 @@ fn main() -> ExitCode {
ExitCode::from(2)
}
CliResult::Run(parsed) => match parsed.mode {
// FrontendChoice::Auto and ::Tui both run the TUI in v0.1.
// The match is structured this way deliberately so that
// when a GUI frontend lands the second arm becomes
// `editor::run_gui(file)` without touching parsing.
// FrontendChoice::Auto and ::Tui both run the TUI. The
// match is structured this way deliberately so a future
// display-detecting default can make the second arm
// dispatch elsewhere without touching parsing. Note this
// is NOT how the GPU frontend is reached — `--gpu` spawns
// the separate pmacs-gpu binary via run_gpu().
Mode::Local {
file,
frontend: FrontendChoice::Tui | FrontendChoice::Auto,