fix(release): make the recovery path usable, and stop promising updates that do not exist - #566
Merged
Merged
Conversation
…es that do not exist Two things #561 left behind, both about the pipeline telling the truth. `publish-packages.yml` has a `workflow_dispatch` escape hatch whose only possible use is a tag that is already published -- recovering after the snap job failed, or exercising the workflow without cutting a release. But Chocolatey accepts a version exactly once, so on that path the Chocolatey job always fails, on a duplicate that is expected rather than wrong. The escape hatch reported a failure that meant nothing, which is the same disease #561 treated: a signal nobody can act on. The job now asks the feed first and skips a version already on it. A check that cannot answer falls through to the push, which is the real gate -- the point is to drop a known non-event, not to make publishing conditional on a lookup succeeding. Separately, the README told `.deb` and `.rpm` users they "continue to update through their distribution channels". There is no apt or dnf repository, and tauri-plugin-updater supports neither format, so those users have no update path at all: they install once, and nothing ever tells them a new version exists. RELEASING.md carried the same claim. Both now say what is true. The Chocolatey half of that sentence was correct and stays. The Snap half is a live question in #562 and is untouched here. Two assertions added. One holds the README, the release-body download table and the publishing workflow to the same set of package managers, in both directions -- the snap went dead for three months while both documents kept recommending it, and retiring the snap would make the same drift possible with the arrow reversed. The other holds the Chocolatey skip to gating the push rather than merely existing. Both were checked by mutation: deleting `snapcraft push` fails the first and not the second; dropping the `if:` fails the second and not the first. 953 tests pass. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The sentence added a moment ago said nothing in Markpad would tell a package-managed install that a new version exists. It does tell them, and then fails to install it -- #570 traces that to __TAURI_BUNDLE_TYPE not being patched into the Linux binary, which sends deb, rpm and snap down the AppImage install path. Both documents now point at it. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This was referenced Aug 10, 2026
PathGao
pushed a commit
that referenced
this pull request
Aug 11, 2026
#566 added this test alongside its fix and asserted the fix: a part literally named `rust-deps`, and `after: [rust-deps]` on the rust part. That fix does not work, so the test was holding the file to a spelling that fails to build. What has to stay true is the two constraints the four runs established. Rust must come from a phase that runs before any part is pulled -- build-packages -- because a part that installs it is too late for the part pulling alongside it. And nothing may ask the rust plugin to validate the environment, which reported `'rustup' not found` twice with rustup present and runnable. Plus the toolchain choice that the plugin's pull script used to make and no longer does. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
PathGao
added a commit
that referenced
this pull request
Aug 11, 2026
…ll requests (#577) * fix(snap): keep the gnome SDK's libc off the rustup call, and pack the snap on pull requests The v2.7.3 snap publish failed in rust-deps, the part #566 added: /snap/rustup/1504/bin/rustup: symbol lookup error: /snap/gnome-46-2404-sdk/current/usr/lib/x86_64-linux-gnu/libc.so.6: undefined symbol: __nptl_change_stack_perm, version GLIBC_PRIVATE `extensions: [gnome]` puts the gnome SDK's libraries on LD_LIBRARY_PATH for every part's build, and the rustup snap's binary resolves libc.so.6 out of the SDK rather than out of the one it was linked against. Cleared for that one call: node/20/stable runs under the same LD_LIBRARY_PATH and has always been fine, and the markpad part links against the SDK deliberately. The second half is why this could ship broken at all. publish-packages.yml checks out a release tag, so snapcraft.yaml is first executed after a change to it has been merged, tagged and published. test_snap.yml packs it on any pull request that touches it and stops there -- no release upload, no store push. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * fix(snap): install rustup from rustup.rs instead of the snap Run 31479631082 -- the pack job this branch adds -- got `rust-deps` past the GLIBC_PRIVATE crash and then failed in `markpad`: Environment validation failed for part 'markpad': 'rustup' not found. The short form. v2.7.3's had a second clause naming rust-deps; that clause is satisfied now, so the part is found and the binary will not run. Prefixing my own call with `env -u LD_LIBRARY_PATH` cannot reach the one snapcraft makes when it validates the rust plugin's environment. So the carrier goes rather than the call site. The rustup.rs installer produces an ordinary ELF linked against the instance's glibc, which is the same 2.39 the Ubuntu 24.04-based gnome SDK ships, so it does not matter which of the two is ahead on the library path. A classic snap's binary is linked against its own runtime and does. `markpad` names $HOME/.cargo/bin explicitly: its override-build replaces the rust plugin's build step, so the plugin's PATH is not a thing to rely on. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * fix(snap): take rustup from apt, and drop the rust-deps part Run 31480354438 -- the rustup.rs installer in rust-deps -- failed earlier than the run before it: Pulling rust-deps / Pulling markpad both 10:06:42 /root/parts/markpad/run/pull.sh: line 4: rustup: command not found `after:` orders build and stage, not pull. Both parts pull in the same second, and the rust plugin's own pull script runs `rustup update stable` before any override-build has had a chance to install anything. No part can provide rustup to the part that pulls alongside it. Between the three runs the constraints are now both known and they only leave one carrier. It has to exist before anything is pulled, which is build-packages or build-snaps; and it has to be an ordinary ELF rather than a classic snap's, or LD_LIBRARY_PATH from the gnome extension feeds it the SDK's libc. apt is the intersection: noble ships rustup 1.26.0 in universe, linked against the instance's own glibc. rust-deps goes with it. That part existed to satisfy the rust plugin when rustup was not on PATH; it is on PATH now. This is a smaller file than the one v2.7.3 shipped, and smaller than v2.6.11's. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * fix(snap): stop using the rust plugin this part never built with Run 31481081985, with apt's rustup installed: Environment validation failed for part 'markpad': 'rustup' not found and part 'markpad' does not depend on a part named 'rust-deps' [...] noble's rustup package installs /usr/bin/rustup, /usr/bin/cargo and /usr/bin/rustc. Run 31479631082 had the snap's rustup on PATH and had just watched the plugin's own pull script run it successfully, and got the same 'rustup' not found. Twice the binary was present and the validation said it was not, so the validation is the thing to stop trying to satisfy. Nothing here uses the plugin. override-build runs npm, runs tauri and installs the binary itself, and has since the snap was added -- `plugin: rust` contributed a build step this file overrides, a pull script that runs rustup, and the validation. `plugin: nil` keeps `source:` and drops all three. `rustup default stable` moves into override-build, because the pull script that used to do it is gone and apt's cargo and rustc are shims that refuse to run without a toolchain. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * test(release): assert what makes rustup findable, not the shape that did #566 added this test alongside its fix and asserted the fix: a part literally named `rust-deps`, and `after: [rust-deps]` on the rust part. That fix does not work, so the test was holding the file to a spelling that fails to build. What has to stay true is the two constraints the four runs established. Rust must come from a phase that runs before any part is pulled -- build-packages -- because a part that installs it is too late for the part pulling alongside it. And nothing may ask the rust plugin to validate the environment, which reported `'rustup' not found` twice with rustup present and runnable. Plus the toolchain choice that the plugin's pull script used to make and no longer does. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> --------- Co-authored-by: PathGao <gaoyanbo@gaoyanbodeMacBook-Air.local> Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
PathGao
pushed a commit
that referenced
this pull request
Aug 11, 2026
…gain build.yml compiles Markpad on ubuntu-24.04 and uploads a .deb. snapcraft.yaml then compiled it a second time inside LXD, from the same source, on core24 -- which is Ubuntu 24.04. Measured on run 31481634640: 8m15s of a 14m55s pack. The cost was never mainly the minutes. Two independent compilations produce two different binaries, so a snap user and a .deb user of the same version did not have the same file. And compiling here is why this file held rust and node, which is what #566 and three runs on #577 were about. `plugin: dump` with `source-type: deb` removes the compiler, the toolchain, and the hand-written desktop file and icon installs -- the .deb already carries all three, including a 256x256@2 icon this file never installed. The version comes from `dpkg-deb -f markpad.deb Version` rather than from package.json, so the snap cannot be labelled a version it does not contain. Verified before writing any of it: the .deb's payload is usr/bin/Markpad, the desktop file and three icons, and the binary names 16 libraries by DT_NEEDED with no RPATH. core24 covers libc, libm and libgcc_s; the gnome extension covers the GTK and glib stack; stage-packages already covers webkit, jsc and soup. libssl.so.3 and libcrypto.so.3 are covered by none of those three on paper, so test_snap.yml now fails on snapcraft's missing-dependency report rather than leaving it as a warning in the log. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
PathGao
pushed a commit
that referenced
this pull request
Aug 11, 2026
…gain build.yml compiles Markpad on ubuntu-24.04 and uploads a .deb. snapcraft.yaml then compiled it a second time inside LXD, from the same source, on core24 -- which is Ubuntu 24.04. Measured on run 31481634640: 8m15s of a 14m55s pack. The cost was never mainly the minutes. Two independent compilations produce two different binaries, so a snap user and a .deb user of the same version did not have the same file. And compiling here is why this file held rust and node, which is what #566 and three runs on #577 were about. `plugin: dump` with `source-type: deb` removes the compiler, the toolchain, and the hand-written desktop file and icon installs -- the .deb already carries all three, including a 256x256@2 icon this file never installed. The version comes from `dpkg-deb -f markpad.deb Version` rather than from package.json, so the snap cannot be labelled a version it does not contain. Verified before writing any of it: the .deb's payload is usr/bin/Markpad, the desktop file and three icons, and the binary names 16 libraries by DT_NEEDED with no RPATH. core24 covers libc, libm and libgcc_s; the gnome extension covers the GTK and glib stack; stage-packages already covers webkit, jsc and soup. libssl.so.3 and libcrypto.so.3 are covered by none of those three on paper, so test_snap.yml now fails on snapcraft's missing-dependency report rather than leaving it as a warning in the log. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
PathGao
added a commit
that referenced
this pull request
Aug 11, 2026
…gain (#579) build.yml compiles Markpad on ubuntu-24.04 and uploads a .deb. snapcraft.yaml then compiled it a second time inside LXD, from the same source, on core24 -- which is Ubuntu 24.04. Measured on run 31481634640: 8m15s of a 14m55s pack. The cost was never mainly the minutes. Two independent compilations produce two different binaries, so a snap user and a .deb user of the same version did not have the same file. And compiling here is why this file held rust and node, which is what #566 and three runs on #577 were about. `plugin: dump` with `source-type: deb` removes the compiler, the toolchain, and the hand-written desktop file and icon installs -- the .deb already carries all three, including a 256x256@2 icon this file never installed. The version comes from `dpkg-deb -f markpad.deb Version` rather than from package.json, so the snap cannot be labelled a version it does not contain. Verified before writing any of it: the .deb's payload is usr/bin/Markpad, the desktop file and three icons, and the binary names 16 libraries by DT_NEEDED with no RPATH. core24 covers libc, libm and libgcc_s; the gnome extension covers the GTK and glib stack; stage-packages already covers webkit, jsc and soup. libssl.so.3 and libcrypto.so.3 are covered by none of those three on paper, so test_snap.yml now fails on snapcraft's missing-dependency report rather than leaving it as a warning in the log. Co-authored-by: PathGao <gaoyanbo@gaoyanbodeMacBook-Air.local> Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
PathGao
added a commit
that referenced
this pull request
Aug 12, 2026
…660) * docs: bring the release runbook and the syntax reference up to 2.7.4 Four claims in the docs describe behaviour that PRs since 2.7.3 changed, and two features shipped without reaching the file that documents what Markpad can do. RELEASING.md - snapcraft.yaml no longer builds the app; it unpacks the release's own .deb (#579), so the `npm ci` note and the `rust-deps` troubleshooting row both described a file that no longer exists in that shape (#577). - The .deb/.rpm coverage note still said *Check for Updates…* offers an update and then fails to install it. #573 asks `self_update_supported` first, so it says where updates come from instead. - Adds the AppImage checks (#584, #658) as their own troubleshooting row, and notes that release builds are serialized (#612). README, README.zh-CN - The same pre-#573 claim, in both languages. The Chinese one also told .deb/.rpm users to update "through their distribution channels", which is the sentence #566 removed from the English one — there is no apt or dnf repository. snapcraft.yaml - The comment pointed at .github/workflows/test_snap.yml, deleted in #601. samples/markdown-syntax{,.zh-CN}.md - Lists: Enter continues the marker, Tab changes level, Enter on an empty item leaves the list (#636), and the three list chords (#652). - Tables: cell, row and column keys, why deleting a row has no chord (#645, #653). - Links: Ctrl/Cmd+K (#652). npm test 904 pass, vitest 365 pass. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * docs(syntax): drop two design arguments that belong in the PRs, not here The syntax reference carries no issue numbers, no history and no defence of a decision anywhere in its 500 lines; where it does give a reason -- the three deliberate incompatibilities -- the reason tells the reader what to write instead. Two sentences I added argued for the design at the reader: that four other editors use Mod+K, and why deleting a row has no chord while deleting a column does. Neither changes anything the reader would type. What is left of the second is the part that was actually useful: to delete a row, delete its line. * docs(readme): drop the only issue number a reader ever sees #570 was the last issue number in either README, and it was one I added a few days ago. It is a closed bug report, and after #573 the sentence it was attached to describes ordinary behaviour -- so a reader asking "how does my .deb update" now clicks through to a fault that no longer exists. The half-sentence in front of it went for the same reason: "rather than offering one it cannot install" describes what the app used to do. What is left is what the reader needs -- .deb and .rpm are one-time installs, there is no apt or dnf repository, and Check for Updates says so. Both READMEs keep the Report a Bug link, which is the only issue link either of them had before. * docs(releasing): cut the post-mortems back out of the runbook This file is what you read on the day you cut a release. Over three days in August I turned it into a runbook with post-mortems threaded through it: which run pushed Chocolatey 2.7.2 at 15:37, that the snap served 2.6.11 for three months and six versions, which two of the three v2.7.2 attempts the AppImage strip failed in, how the 2.7.2/2.7.3 lock skew was found. All true, none of it changes what you do next, and it sits between you and step 5 while a build is running. Test applied to each one: can it change an action taken on release day. Gone: the "Why package managers publish after the release" section entirely -- its one operational sentence (workflow_dispatch works against a published tag, the only way to exercise snapcraft.yaml) moves into step 7, where you would need it. The failure histories in three troubleshooting rows, keeping the symptom and the fix. The placeholder-pubkey era. Two design defences. Kept: reasons that stop you doing the wrong thing -- why not to create anything at alecdotdev/Markpad, why the Cargo.lock bump is the one that gets forgotten. A prohibition without its reason gets deleted as superstition by whoever comes next. 1957 -> 1563 words. The version before I started was 883. --------- Co-authored-by: PathGao <gaoyanbo@gaoyanbodeMacBook-Air.local> Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Two things #561 left behind. Both are the pipeline telling the truth about itself.
1. The recovery path always reported a failure that meant nothing
publish-packages.ymlhas aworkflow_dispatchinput, and its only possible use is a tag that is already published — recovering after the snap job failed, or exercising the workflow without cutting a release. That is exactly what #561's own description asks a maintainer to do againstv2.7.2.But Chocolatey accepts a version exactly once, and
markpad-app2.7.2 has been on the feed since 2026-08-07. So every use of that escape hatch would have reported:This is the same disease #561 treated, one level along: a signal nobody can act on. There it was a failure dressed as success; here it is a non-event dressed as a failure. Both train people to stop reading.
The job now asks the feed before packing:
Asked of the feed rather than inferred from the text of a push error, and a check that cannot answer — network, rate limit — deliberately falls through to the push, which is the real gate. The point is to drop a known non-event, not to make publishing conditional on a lookup succeeding. On the
release: publishedpath nothing changes: a duplicate there is a genuine problem and still fails.Verified against the live feed: the query returns the version row for 2.7.2 and nothing for a version that does not exist.
2.
.deband.rpmusers were told they get updatesREADME, before:
There is no apt repository and no dnf repository, and
tauri-plugin-updatercannot replace a package-managed install. So those users have no update path at all.RELEASING.mdcarried the same claim in the maintainer's own runbook, which is how it survived.The first version of this change over-corrected, and the second commit fixes it. It said "nothing in Markpad will tell you one exists", which is not true and is not even the charitable reading: Markpad does tell them, and then fails to install it. Chasing that down produced #570 —
__TAURI_BUNDLE_TYPEis not patched into the Linux binary, sobundle_type()isNoneand.deb,.rpmand snap all take the AppImage install path, which renames a downloaded file over/usr/bin/Markpad. Both documents now say that, and point at the issue.The Chocolatey half of the original sentence was correct and is kept. The Snap half is a live question in #562 and is untouched here.
Tests
Two assertions, both mutation-checked.
The package managers we recommend must be the ones we publish to — across three files, in both directions: the README, the download table written into every release body, and
publish-packages.yml. These drifted once already and nobody noticed for three months. The drift is about to be possible again with the arrow reversed: #562 asks whether to retire the snap, and retiring it means deleting that job — doing so without touching the two documents leaves a recommendation for a channel that no longer receives anything. The test makes that deletion fail until it is complete.The Chocolatey skip must gate the push, not merely exist.
snapcraft push→snapcraft-DELETEDif:onPack and publishnpm run checkclean🤖 Generated with Claude Code