diff --git a/COHERENCE.md b/COHERENCE.md index 97a0133..c447a76 100644 --- a/COHERENCE.md +++ b/COHERENCE.md @@ -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 11–12** | **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 diff --git a/README.md b/README.md index f1554c0..76b3d87 100644 --- a/README.md +++ b/README.md @@ -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 diff --git a/docs/active-work.md b/docs/active-work.md index c7adaba..6374a1b 100644 --- a/docs/active-work.md +++ b/docs/active-work.md @@ -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; diff --git a/docs/agent-handoff.md b/docs/agent-handoff.md index 15357ca..77c7642 100644 --- a/docs/agent-handoff.md +++ b/docs/agent-handoff.md @@ -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) diff --git a/src/main.rs b/src/main.rs index cdb0b8f..3adbc6e 100644 --- a/src/main.rs +++ b/src/main.rs @@ -39,12 +39,14 @@ usage: pmacs [-nw|--no-window] [--help] [--version] [FILE] pmacs --attach 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 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:`. 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, frontend: FrontendChoice, @@ -177,8 +183,8 @@ fn build_attach_mode(file: Option, socket: Option) -> Result Result { 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,