mirror of
https://github.com/torlando-tech/pyxis.git
synced 2026-09-01 16:48:23 +00:00
docs: define browser map installer safety contract
This commit is contained in:
@@ -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,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://"):
|
||||
|
||||
Reference in New Issue
Block a user