diff --git a/ROADMAP.md b/ROADMAP.md
--- a/ROADMAP.md
+++ b/ROADMAP.md
@@ -2,7 +2,7 @@
 
 **Stage: alpha** · next: beta, ~25 points of "ready for real work" and ~160–240 h away
 
-> **Last reviewed:** 2026-10-11 · **Last updated:** 2026-10-25 · **Change:** minor (AutoSum over a selected row puts its total to the right, and fills a selection's empty last row and column) · **Target:** Microsoft Excel (Microsoft 365)
+> **Last reviewed:** 2026-10-26 · **Last updated:** 2026-10-26 · **Change:** trivial (Flatpak runtime candidate #2608; readiness estimates unchanged) · **Target:** Microsoft Excel (Microsoft 365)
 
 GridCraft aims at full Microsoft Excel parity, and at being better in places: faster, open (XLSX
 is the native format), fully scriptable by agents (MCP, control channel, CLI), and on the web.
@@ -135,6 +135,7 @@ Ranked; estimates in Opus 5.5 agent-hours. Detail and the full beta-gate list in
 
 | Date | What landed |
 |---|---|
+| 2026-10-26 | Flatpak candidate #2608: both the source and release-bundle manifests use Freedesktop 26.08. Source preparation also vendors unused Cargo patches without changing Cargo.lock. Release-bundle builds, file operations and the Rust SDK extension probe pass on native x86_64 and aarch64. Full source builds and package exports also pass on both architectures. ARM GUI acceptance remains unverified; readiness estimates are unchanged. |
 | 2026-10-25 | AutoSum over a selection does what Excel does: a selected row gets one total to its right (in its last cell if that is empty), not a one-cell total under each cell; a block whose last column is empty gets each row's total there, one whose last row is empty each column's, and with both the corner gets the total of the block; otherwise totals go under each column as before |
 | 2026-10-24 | Go To lists the named ranges of every sheet (`Sheet2!Name` for a name scoped to another sheet; hidden names, constants and formulas left out) and the references entered before, a double-click goes to an entry, and the Reference box takes several names or references separated by commas (`Price, Type`, `B14:C22,F19:G30`) |
 | 2026-10-24 | Status bar: a right-click opens a menu that sets which selection statistics show (Average, Count and Sum by default; Numerical Count, Minimum and Maximum are new), kept with the preferences (`view.statusBar`) |
@@ -242,6 +243,7 @@ Ranked; estimates in Opus 5.5 agent-hours. Detail and the full beta-gate list in
 
 | Date | Change | Summary |
 |---|---|---|
+| 2026-10-26 | trivial | Record Flatpak 26.08 candidate #2608 and the limits of compatibility checks; estimates unchanged |
 | 2026-10-25 | minor | Progress log: AutoSum over a selected row, and a selection's empty last row and column |
 | 2026-10-23 | minor | Progress log: accounting negatives in number text |
 | 2026-10-23 | minor | Progress log: INDEX with one index on a 2-D reference is #REF! |
diff --git a/packaging/linux/flatpak/ai.storyteller.gridcraft.bundle.yml b/packaging/linux/flatpak/ai.storyteller.gridcraft.bundle.yml
--- a/packaging/linux/flatpak/ai.storyteller.gridcraft.bundle.yml
+++ b/packaging/linux/flatpak/ai.storyteller.gridcraft.bundle.yml
@@ -13,7 +13,7 @@
 # runtime, runtime-version, sdk and finish-args identical in both (packaging-lint checks this).
 id: ai.storyteller.gridcraft
 runtime: org.freedesktop.Platform
-runtime-version: '25.08'
+runtime-version: '26.08'
 sdk: org.freedesktop.Sdk
 command: gridcraft
 finish-args:
diff --git a/packaging/linux/flatpak/ai.storyteller.gridcraft.yml b/packaging/linux/flatpak/ai.storyteller.gridcraft.yml
--- a/packaging/linux/flatpak/ai.storyteller.gridcraft.yml
+++ b/packaging/linux/flatpak/ai.storyteller.gridcraft.yml
@@ -2,8 +2,11 @@
 #
 # Flatpak builds run offline, so the crate sources must be vendored first. From the repo root:
 #
-#   curl -fsSLO https://raw.githubusercontent.com/flatpak/flatpak-builder-tools/master/cargo/flatpak-cargo-generator.py
-#   python3 flatpak-cargo-generator.py Cargo.lock -o packaging/linux/flatpak/cargo-sources.json
+#   curl -fsSLO https://raw.githubusercontent.com/flatpak/flatpak-builder-tools/9d86d336a39b9af38b86f114b6ce5820fe260f91/cargo/flatpak-cargo-generator.py
+#   python3 packaging/linux/flatpak/generate-cargo-sources.py Cargo.lock -o packaging/linux/flatpak/cargo-sources.json
+# The wrapper vendors [[patch.unused]] and keeps git revisions separate so Cargo can
+# resolve the complete dependency graph offline.
+#
 #   flatpak-builder --user --install --force-clean build-flatpak packaging/linux/flatpak/ai.storyteller.gridcraft.yml
 #   flatpak run ai.storyteller.gridcraft
 #
@@ -12,7 +15,7 @@
 # which repackages the prebuilt release binaries. Keep runtime-version and finish-args identical.
 id: ai.storyteller.gridcraft
 runtime: org.freedesktop.Platform
-runtime-version: '25.08'
+runtime-version: '26.08'
 sdk: org.freedesktop.Sdk
 sdk-extensions:
   - org.freedesktop.Sdk.Extension.rust-stable
diff --git a/packaging/linux/flatpak/generate-cargo-sources.py b/packaging/linux/flatpak/generate-cargo-sources.py
new file mode 100644
--- /dev/null
+++ b/packaging/linux/flatpak/generate-cargo-sources.py
@@ -0,0 +1,63 @@
+#!/usr/bin/env python3
+"""Prepare complete, revision-specific offline inputs for flatpak-cargo-generator.
+
+flatpak-cargo-generator reads [[package]] but omits [[patch.unused]]. Cargo still
+loads those patch manifests before resolving the locked dependency graph. Add
+them to the generator's in-memory input without changing the project's lockfile.
+The upstream generator also keys git replacements by URL alone. Keep each locked
+revision separate when several dependencies use different commits of one repo.
+The upstream generator supplies the pinned sources and normalizes git packages.
+"""
+import argparse
+import asyncio
+import json
+from pathlib import Path
+import runpy
+from urllib.parse import parse_qs, urlparse
+
+
+def main():
+    parser = argparse.ArgumentParser(description=__doc__)
+    parser.add_argument("cargo_lock", type=Path)
+    parser.add_argument("--generator", type=Path, default=Path("flatpak-cargo-generator.py"))
+    parser.add_argument("-o", "--output", type=Path, required=True)
+    args = parser.parse_args()
+    generator = runpy.run_path(str(args.generator), run_name="flatpak_cargo_generator")
+    lock = generator["load_toml"](str(args.cargo_lock))
+    packages = lock["package"]
+    keys = {(p["name"], p["version"], p.get("source")) for p in packages}
+    for patch in lock.get("patch", {}).get("unused", []):
+        key = (patch["name"], patch["version"], patch.get("source"))
+        if key not in keys:
+            packages.append(patch)
+            keys.add(key)
+    sources = asyncio.run(generator["generate_sources"](lock))
+    config_source = next(
+        s for s in sources
+        if s.get("dest") == generator["CARGO_HOME"] and s.get("dest-filename") == "config"
+    )
+    config = generator["tomlkit"].parse(config_source["contents"]).unwrap()
+    replacements = config["source"]
+    for name in list(replacements):
+        if "git" in replacements[name]:
+            del replacements[name]
+    for package in packages:
+        source = package.get("source", "")
+        if not source.startswith("git+"):
+            continue
+        replacement = {
+            "git": generator["canonical_url"](source).geturl(),
+            "replace-with": generator["VENDORED_SOURCES"],
+        }
+        query = parse_qs(urlparse(source).query)
+        for reference in ("rev", "tag", "branch"):
+            if reference in query:
+                value, = query[reference]
+                replacement[reference] = value
+        replacements[source] = replacement
+    config_source["contents"] = generator["tomlkit"].dumps(config)
+    args.output.write_text(json.dumps(sources, indent=2) + "\n", encoding="utf-8")
+
+
+if __name__ == "__main__":
+    main()
