docs: define browser map installer safety contract

This commit is contained in:
Torlando
2026-08-31 04:43:30 +00:00
parent 39b0faf07c
commit a3d1e04ffb
3 changed files with 60 additions and 1 deletions
+12
View File
@@ -340,6 +340,18 @@
<li>Click <strong>Install and Enable</strong>, then choose the mounted SD-card root.</li>
<li>Safely eject the SD card, return it to the T-Deck, power it on, and open Maps.</li>
</ol>
<div class="warning map-safety-contract">
<strong>Before installing:</strong> close all other Pyxis flasher tabs or
windows, and do not run the command-line installer against this same
mounted card at the same time. The cross-tab lock coordinates only
tabs of this flasher in the same browser profile; it cannot see the
CLI or other browsers.
<br><br>
<strong>After installing:</strong> wait for the verified completion
message, then safely eject the card. If activation fails after a pack
was published, retry with the exact same ZIP and the same name and
pack ID.
</div>
<p class="map-note">Existing unrelated SD-card files are preserved. Map tiles are validated locally and are never uploaded.</p>
<div class="map-installer-grid">
<div class="map-field">
+10 -1
View File
@@ -10,7 +10,8 @@ Open the Pyxis web flasher in current Chrome or Edge and use **Install Offline M
2. Turn the T-Deck off, remove its SD card, and mount the card on the computer.
3. Choose the ZIP, enter a map name and pack ID, and wait for local validation.
4. Click **Install and Enable**, then choose the SD-card root.
5. After the verified completion message, safely eject the card and return it to the T-Deck.
5. Wait for the verified completion message, then safely eject the card and
return it to the T-Deck.
The browser accepts stored ZIP entries rooted at either `<z>/<x>/<y>.png` or
`maps/<style>/<z>/<x>/<y>.png`. It rejects mixed styles, traversal, duplicate
@@ -19,6 +20,14 @@ ZIP records, unsafe PNGs, quota violations, and noncanonical XYZ paths. Tiles
are validated and read back one at a time; the complete archive is not loaded
into JavaScript memory.
**Single writer.** The browser's cross-tab lock serializes only tabs of the
same flasher origin in the same browser profile. Close all other flasher tabs
and windows before installing, and do not run the CLI and the browser
installer against the same mounted card at the same time. Wait for the
verified completion message, then safely eject the card. A
published-but-not-activated pack is never deleted: retry activation with the
exact same ZIP, map set, name, and pack ID.
Installation refuses to overwrite an existing pack. A verified pack from an
earlier activation failure can be reselected with the exact same ZIP and
metadata. Tiles are published first, `manifest.pmp` is published last, and only
@@ -61,6 +61,44 @@ def test_map_installer_explains_the_complete_sd_card_workflow() -> None:
assert positions == sorted(positions)
def test_map_installer_documents_the_single_writer_contract() -> None:
"""B9: both the flasher UI and the docs must state the supported
concurrency model — no CLI+browser at once, close other flasher tabs,
wait for verified completion, safe eject, exact retry — and must never
tell users to clean up marker files."""
flasher = FLASHER.read_text(encoding="utf-8")
docs = (ROOT / "docs/offline-map-packs.md").read_text(encoding="utf-8")
assert 'class="warning map-safety-contract"' in flasher
# Normalize whitespace so phrase checks survive HTML line-wrapping.
flasher_norm = " ".join(flasher.split())
contract_phrases = (
"close all other Pyxis flasher tabs",
"command-line installer",
"mounted card at the same time",
"completion message",
"safely eject",
"retry with the exact same ZIP",
)
for phrase in contract_phrases:
assert phrase in flasher_norm, f"flasher missing: {phrase!r}"
# The docs carry the same contract, plus the lock-scope limitation.
docs_norm = " ".join(docs.split())
assert "do not run the CLI and the browser installer" in docs_norm
assert "Close all other flasher tabs" in docs_norm
assert "Wait for the verified completion message" in docs_norm
assert "same browser profile" in docs_norm
# No marker-file cleanup instructions anywhere in the map installer docs.
lower_docs = docs_norm.lower()
for forbidden in (
"delete the marker",
"remove the marker",
"clean up the marker",
"delete the active-pack",
"remove the active-pack",
):
assert forbidden not in lower_docs
def test_map_installer_has_no_tile_network_fetch_path() -> None:
source = INSTALLER.read_text(encoding="utf-8").lower()
for forbidden in ("fetch(", "xmlhttprequest", "websocket", "http://", "https://"):