Skip to content

nightly 2026-09-07 (v0.3.13-beta.22): it never built on Linux — a cfg! that was never compiled out, and a libc bump that broke the Python runtime - #315

Merged
physics515 merged 4 commits into
masterfrom
nanna-nightly-2026-09-07
Sep 8, 2026
Merged

physics515 merged 4 commits into
masterfrom
nanna-nightly-2026-09-07

Conversation

@physics515

@physics515 physics515 commented Sep 7, 2026

Copy link
Copy Markdown
Owner

What this run found

origin/master did not build on Linux. Not "had warnings", not "a test failed" — cargo build --workspace produced no binary. The dev host moved to Arch/Omarchy in September and, as far as this
run can tell, nothing had compiled the workspace there since. Verified against a pristine
origin/master
before touching anything, so this is a pre-existing break, not something the
dependency sweep introduced.

Two independent causes, and the same reason neither was caught: a platform gate is only tested by
the platform it excludes.

1. A runtime cfg! where a compile-time #[cfg] was meant

crates/nanna-scripting/src/bridge.rs:746 picked the exec shell with:

let mut cmd = if cfg!(windows) { /* Git Bash / PowerShell routing */ } else { /* sh */ };

cfg!(windows) is a boolean expression, not conditional compilation. It selects the correct
branch at runtime — so this was never a behaviour bug — but both arms are still type-checked on
every platform
, and the four helpers the Windows arm calls (strip_outer_quotes,
classify_windows_command, git_bash_path, WinShell) are #[cfg(windows)] and genuinely absent
on Linux. Five E0425/E0433, and nanna-scripting — hence the nanna binary — could not compile.

Fixed by splitting into #[cfg(windows)] / #[cfg(not(windows))] bindings. No behaviour change on
Windows:
the same arm is selected, just at compile time. Net −7/+5 lines.

Also removed normalize_drive_paths's #[cfg(not(windows))] identity stub — its only non-test caller
is #[cfg(windows)] and its tests are #[cfg(all(test, windows))], so it was dead on every
platform and merely invisible while the crate never compiled here. Deleted rather than #[allow]-ed.

2. libc 0.2.187 broke the vendored Python runtime

libc corrected POSIX_SPAWN_SETSID from c_int to c_short on linux-gnu — correctly; glibc really
does store spawn flags in a short. But rustpython-vm 0.5.0 hands that constant straight to
nix::spawn::PosixSpawnFlags::from_bits_retain, which nix 0.30 types as c_int. E0308 at
rustpython-vm-0.5.0/src/stdlib/posix.rs:1812, killing the python feature.

The fix is already merged upstream and never releasedRustPython #8343 "Fix building against
new libc"
, merged 2026-07-22; 0.5.0 is still
the newest on crates.io. So libc is held at 0.2.186.

That window is narrower than it looks: rustpython-stdlib 0.5.0 itself requires libc ^0.2.183, so
exactly four releases satisfy both constraints — which is why a bare cargo update lands outside it
every single time.

Increments landed

  1. fix(scripting) — both Linux build fixes + the dependency freshness sweep. These could not be
    split: neither is green without the other, so the smallest green unit contains both.
  2. test(storage) — a version-ceiling guard, the mirror of the existing unification guard.
  3. cicompile-tests-linux, an ubuntu-latest mirror of the Windows test-compile job.
  4. chore(release) — v0.3.13-beta.22 prep.

Dependency freshness

  • ocrs 0.12 → 0.13 + rten 0.24 → 0.26 — unblocks a pin that three previous runs recorded as
    "not ours to fix". ocrs 0.13.0 shipped against rten 0.26, so the pair moves together,
    rten/rten-tensor stay unified, and OcrEngineParams { detection_model, recognition_model }
    the exact call the roadmap predicted would fail — compiles with zero source changes.
  • wide 1.6 → 1.7, playwright-rs 0.16 → 0.17, deno_core 0.410 → 0.411, plus the compatible
    cargo update sweep. malachite-bigint re-pinned to 0.9.2 as documented.
  • Rejected on purpose: criterion 0.8 → "0.7" (a downgrade, as the roadmap warns);
    typescript 7 (vue-tsc still cannot load it); vuedraggable left at ^4.1.0 — a blanket
    pnpm update --latest would have silently downgraded it to the Vue-2 line, so packages were
    upgraded explicitly instead.
  • Frontend: @tiptap/* 3.31.3, vitest 4 → 5, @lucide/vue 1.42, vue-router 5.3.1,
    @playwright/test 1.63, happy-dom 20.14, @vue/test-utils 2.5, postcss 8.5.28, Tauri plugins
    — all with zero source changes.

The new guard

held_back_crates_stay_below_their_ceiling catches a crate resolving to one version that is too
new
, where the August guard catches two versions. CeilingCrate carries a lift_when field
beside reason/remedy: a ceiling holds back upstream fixes, so recording the condition that
retires it means the pin gets deleted on purpose rather than renewed forever.

Version comparison is positional and dependency-free, and compares components numerically on
purpose — as text, "0.2.9" sorts above "0.2.186", which would make the guard silently useless. A
negative-space test pins that.

Verified it fires, not just that it was written: re-applying cargo update -p libc --precise 0.2.189 makes it report libc resolved to 0.2.189 but must stay at or below 0.2.186 with the remedy
and the lift condition. 5 tests, 0.00s.

Verification

All on Linux, after the fixes:

Gate Result
cargo build --workspace --exclude nanna-gui green
cargo test --workspace --exclude nanna-gui 1683 passed / 0 failed / 12 ignored, 47 test binaries
cargo clippy --workspace --all-targets --exclude nanna-gui 0 errors; 2722 warnings, none in the changed regions or the new test
cargo build --release -p nanna-daemon green, 13m52s — no tokio ICE, no turso depth overflow
vue-tsc --noEmit / pnpm test / pnpm build clean / 238 passed / green

Real-binary check. The built Linux daemon, booted against a scratch config (NANNA_CONFIG_PATH

  • --data-dir + --no-pid-file, ports 51997/51998 — never the operator's), reaches Daemon ready,
    serves IPC and health, answers GET /health with
    {"status":"ok","version":"0.3.11","uptime_secs":1}, handles SIGTERM cleanly, and logs zero
    panics
    . The only errors are Ollama being unreachable (not installed on this host), which the
    readiness-wait path handles as designed rather than by burning retry budget.

Benchmark (wide touches nanna-simd, so the sweep is perf-relevant):

N measured budget prior p95
1k 0.040 ms ≤ 0.20 ms 0.072 ms
10k 0.869 ms ≤ 5.0 ms 2.55 ms
50k 5.20 ms ≤ 25 ms 11.0 ms

Inside budget at every size. bench/BASELINE.md was deliberately not updated: the recorded
numbers are Windows, these are Linux, and the box was at load average 112 with a second Rust build
running — three uncontrolled variables at once. Contention can only have hurt these numbers, so
passing under it is a sound pass, but it is not a measurement worth enshrining. Filed as a re-measure.

Not verified

  • The Tauri GUI on Linux. cargo build and cargo test are green; the desktop app is not part of
    that claim, and nanna-gui stays excluded from the new CI job because it needs WebKitGTK system
    packages. Filed.
  • compile-tests-linux itself has never run. It has now: it passed on this PR's first CI
    run in 7m54s
    , with no extra system packages needed. (Kept here rather than deleted so the claim
    is traceable — it was written before the run and is now settled.)

Environment notes (need your attention)

  • The dev tree was root-owned with no passwordless sudo when this run started, which blocked the
    documented worktree setup entirely. You fixed it mid-run. One leftover I fixed myself:
    /mnt/deepmem/.pnpm-store was still root-owned, failing every pnpm install with
    ERR_PNPM_EACCES; I chowned it to you.
  • A stale nanna-nightly.lock from 2026-09-02 and an orphaned ../nanna-nightly worktree were
    left by a run that died early (its branch had no commits, so nothing was lost). Both cleared.
  • The mummu-dev-routine ran concurrently for most of this session. Load average hit 112 with
    87% iowait, several rust-lld linkers at ~4 GB each; one cargo test was killed outright and
    cargo was SIGKILLed twice early on. Everything here was re-run to completion at -j 3/-j 4, but
    the two nightlies contending for one disk is worth scheduling around.
  • There is an un-dispatched release backlog: RELEASE_NOTES.md on master describes
    v0.3.11-beta.20, PR nightly 2026-08-28 (v0.3.12-beta.21): live-and-wrong code — reactions that inverted their meaning, two unbounded maps, and read_pdf that never worked #285 prepares v0.3.12-beta.21, and the newest published tag is
    v0.3.10-beta.19.

Post-merge — cutting the release

gh workflow run release.yml -f version=0.3.13-beta.22 -f release_type=pre-release
# then, from the signed artifacts:
node gui/scripts/make-updater-manifest.mjs v0.3.13-beta.22 "Linux builds at all now: a cfg! that was never compiled out, and a libc bump that broke the Python runtime"
# and open a follow-up PR committing .updater/latest.json — that is the publish

🤖 Generated with Claude Code

Nanna and others added 4 commits September 7, 2026 15:26
…latest

`origin/master` did not compile on Linux at all — verified against a pristine
checkout before touching anything. The dev host moved to Arch/Omarchy in
September and nothing had compiled the workspace there since. Two independent
causes, neither reachable from Windows CI:

1. `bridge.rs` chose the exec shell with `cfg!(windows)` — a *runtime* boolean —
   where `#[cfg(windows)]` was meant. Both arms are therefore type-checked on
   every platform, while the four helpers the Windows arm calls
   (`strip_outer_quotes`, `classify_windows_command`, `git_bash_path`,
   `WinShell`) are `#[cfg(windows)]` and absent on Linux: 5x E0425/E0433, so
   `nanna-scripting` and with it the `nanna` binary could not build. Split into
   `#[cfg(windows)]` / `#[cfg(not(windows))]` bindings. No behaviour change on
   Windows — the same arm is selected, just at compile time rather than runtime.

2. `libc 0.2.187` corrected `POSIX_SPAWN_SETSID` from `c_int` to `c_short` on
   linux-gnu (glibc really does store spawn flags in a `short`), but
   `rustpython-vm 0.5.0` hands that constant to
   `nix::spawn::PosixSpawnFlags::from_bits_retain`, typed `c_int` — E0308,
   killing the `python` feature. The fix is merged upstream but unreleased
   (RustPython PR #8343, 2026-07-22; 0.5.0 is still the newest on crates.io), so
   `libc` is held at 0.2.186. `rustpython-stdlib 0.5.0` itself requires
   `libc ^0.2.183`, so the buildable window is only 0.2.183..=0.2.186 — a bare
   `cargo update` lands outside it every time.

Also removes `normalize_drive_paths`'s `#[cfg(not(windows))]` identity stub: its
only non-test caller is `#[cfg(windows)]` and its tests are
`#[cfg(all(test, windows))]`, so it was dead on every platform and merely
invisible while the crate never compiled here.

Dependency freshness (the run's standalone sweep):
- `ocrs 0.12 -> 0.13` + `rten 0.24 -> 0.26`. This unblocks a pin three previous
  runs recorded as "not ours to fix": `ocrs 0.13.0` ships against `rten 0.26`,
  so the pair moves together, `rten`/`rten-tensor` stay unified at one version,
  and `OcrEngineParams { detection_model, recognition_model }` — the exact call
  predicted to fail — compiles with zero source changes.
- `wide 1.6 -> 1.7`, `playwright-rs 0.16 -> 0.17`, `deno_core 0.410 -> 0.411`,
  plus the compatible `cargo update` sweep. `malachite-bigint` re-pinned to
  0.9.2 as documented. `criterion 0.8 -> "0.7"` rejected again: it is a
  downgrade.
- Frontend: `@tiptap/* 3.31.3`, `vitest 4 -> 5`, `@lucide/vue 1.42`,
  `vue-router 5.3.1`, `@playwright/test 1.63`, `happy-dom 20.14`,
  `@vue/test-utils 2.5`, `postcss 8.5.28` and the Tauri plugins — all with zero
  source changes. `vuedraggable` deliberately held at ^4.1.0 (its `latest`
  dist-tag points at the older Vue-2 line) and `typescript` at 5.9.3 (`vue-tsc`
  still cannot load TS 7).

Verified on Linux: `cargo build --workspace --exclude nanna-gui` green;
`cargo test --workspace --exclude nanna-gui` **1683 passed / 0 failed / 12
ignored** across 47 test binaries; `cargo clippy --workspace --all-targets
--exclude nanna-gui` 0 errors with no new warnings in the changed regions;
frontend `vue-tsc --noEmit` clean, 238/238 vitest, `pnpm build` green. The built
Linux daemon boots against a scratch config to `Daemon ready`, answers
`GET /health` with `{"status":"ok","version":"0.3.11","uptime_secs":1}`, handles
SIGTERM cleanly, and logs zero panics.

Co-Authored-By: Claude Opus 5 <[email protected]>
The `libc <= 0.2.186` hold added in the previous commit is the third dependency
constraint in this repo whose only enforcement was a ROADMAP line saying
"remember to redo this after `cargo update`". The other two became
`dep_version_unification.rs` in August; this one joins them rather than becoming
another note the next run has to rediscover.

`held_back_crates_stay_below_their_ceiling` is the mirror of the existing guard:
that one catches a crate resolving to *two* versions, this one catches a crate
resolving to *one version that is too new*. Both failure modes come from the
same place — a dependency of ours requiring a version range that includes a
release it does not itself compile against — and cargo picks the newest member
of that range every time.

Design notes:
- `CeilingCrate` carries `lift_when` alongside `reason` and `remedy`. A ceiling
  holds back upstream fixes, so it is a liability; recording the condition that
  retires it means the pin gets deleted on purpose instead of renewed forever.
  For `libc` that condition is "rustpython publishes anything after 0.5.0" —
  the fix is already merged upstream.
- Version comparison is positional and dependency-free, matching the sibling
  lockfile parser. It compares components numerically on purpose: as text,
  "0.2.9" sorts *above* "0.2.186", which would make the guard silently useless.
  A negative-space test pins that.
- Like the unification guard, it fails if a guarded crate leaves the graph, so a
  dead ceiling is removed deliberately rather than passing forever.

Verified it catches the real regression rather than only being written: with
`cargo update -p libc --precise 0.2.189` re-applied it reports `libc resolved to
0.2.189 but must stay at or below 0.2.186` together with the remedy command and
the lift condition. 5 tests, 0.00s.

Co-Authored-By: Claude Opus 5 <[email protected]>
The Windows-only `compile-tests` job carries a comment explaining why it runs on
Windows: only Windows exercises `#[cfg(windows)]`, where the service layer
lives. That reasoning is correct, and the job stays. It is also exactly
one-sided, and the missing half cost this project a completely broken Linux
build that went unnoticed for however long the port had been sitting there.

Both breaks fixed earlier in this branch — the `cfg!(windows)` misuse in
`bridge.rs` and the `libc`/`rustpython-vm` type mismatch — are plain compile
errors. A Linux `cargo test --no-run` would have caught each on the commit that
introduced it. No amount of Windows CI could: **a platform gate is only tested
by the platform it excludes.**

`compile-tests-linux` is a straight `ubuntu-latest` mirror of the existing job,
same pinned toolchain, same `--workspace --exclude nanna-gui --locked`, same
30-minute bound (the shared dependency graph dominates and is the same graph).

`nanna-gui` stays excluded on Linux for the existing reason plus one more: the
Tauri crate needs WebKitGTK system packages there, which would turn a smoke
check into a provisioning job. Linux GUI coverage is deliberately not claimed by
this workflow, and is filed in ROADMAP.md as an open question rather than
quietly implied.

Co-Authored-By: Claude Opus 5 <[email protected]>
Base bumped 0.3.11 -> 0.3.13 across all four version files (root `[package]`,
`[workspace.package]`, `gui/package.json`, `gui/src-tauri/tauri.conf.json`),
beta counter 20 -> 22.

Both increments are deliberate. The base must move on every release because the
updater compares **base semver only** — the `-beta.N` suffix never reaches the
installer — so shipping a new beta at an unchanged base is invisible to every
installed client. And the numbering skips a step because PR #285 is still
unmerged and already claims v0.3.12-beta.21; taking 0.3.12 here would collide
with it.

`release.yml`'s version guard simulated locally before committing — both
conditions hold: base == tauri.conf.json version (0.3.13), and base !=
the version `.updater/latest.json` advertises (0.3.10). `tauri.conf.json`
re-parsed after editing, since two invalid keys once blocked a bundle *after*
the tag was cut.

Re-verified green after the bump: `cargo build --workspace --exclude nanna-gui`
clean, and the `Cargo.lock` diff is **21 workspace version lines and nothing
else** — no dependency moved as a side effect.

`.updater/latest.json` is deliberately untouched: it carries a minisign
signature over the built installer, which only the signed release build can
produce. Committing it here would advertise an update whose signature matches no
binary. Publishing stays the human's two post-merge commands, recorded in the PR.

Co-Authored-By: Claude Opus 5 <[email protected]>
@physics515
physics515 merged commit 57c2ec9 into master Sep 8, 2026
8 checks passed
@physics515
physics515 deleted the nanna-nightly-2026-09-07 branch September 8, 2026 03:05
physics515 pushed a commit that referenced this pull request Sep 8, 2026
PR #315 landed first and superseded two of this branch's three concerns, so the
conflicts resolve asymmetrically rather than by preferring one side wholesale:

- **Dependency and version files take master.** This branch's 2026-08-28
  freshness sweep and its `v0.3.12-beta.21` prep are both older than #315's,
  which already carries `ocrs 0.13`/`rten 0.26`, the `libc 0.2.186` ceiling and
  a 0.3.13 base. Keeping this branch's versions would walk the tree backwards
  and collide with the release guard. `Cargo.lock` is master's plus cargo's own
  correction adding `lopdf` to the graph, which this branch's `pdf.read`
  registration genuinely needs — verified with `cargo metadata --locked`.

- **The dependency guard takes THIS branch's design.** Both sides extended
  `dep_version_unification.rs`. This branch replaced the hardcoded `remedy`
  string with a `Remedy::{PinBackTo, Manual}` enum that *derives* the pin-back
  command from the versions actually observed in the lockfile — and it is right
  for a reason master's version demonstrates: the entry #315 shipped hardcoded
  `@0.10.0` while the graph had already drifted to `0.11.0`, so it printed a
  `cargo update -p ...@<gone>` that errors instead of fixing anything. The
  ceiling guard from #315 (`held_back_crates_stay_below_their_ceiling`, which
  holds `libc` at 0.2.186) is kept and layered on top; it stays a plain string
  because a ceiling has exactly one resolved version, not a split, so
  `Remedy::describe`'s "at least one stray" contract does not apply to it.

- Everything else auto-merged, including `ROADMAP.md` and
  `crates/nanna-daemon/src/server.rs`.

Co-Authored-By: Claude Opus 5 <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant