Skip to content

Install CLEWs country models straight from their GitHub repositories - #519

Open
marcelolafleur wants to merge 6 commits into
EAPD-DRB:mainfrom
marcelolafleur:feature/clews-install-layer
Open

Install CLEWs country models straight from their GitHub repositories#519
marcelolafleur wants to merge 6 commits into
EAPD-DRB:mainfrom
marcelolafleur:feature/clews-install-layer

Conversation

@marcelolafleur

@marcelolafleur marcelolafleur commented Aug 6, 2026

Copy link
Copy Markdown
Collaborator

This gives CLEWs models the same install experience the OG side already has: point MUIOGO at a country repository and it installs the model.

What it does

  • A country repo describes what it ships in a clews-country.json file at its root. MUIOGO reads it, downloads the case archives, verifies them against the repo's published checksums, and imports them through the same pipeline the restore button uses. A failed checksum installs nothing. A repo without the file is refused, not guessed at.
  • Every imported case gets a small provenance file: where it came from, its checksum, when it was installed. It travels with backups, so a shared case can still be verified on the receiving machine.
  • At startup MUIOGO compares its records with DataStorage: a model folder added by hand shows up as untracked, a removed one is dropped. Records follow the disk; nothing is ever deleted by this.

New endpoints under /clews, plus GET /getVersion. Backend only, like the OG install layer — UI later (#491 / #380).

What doesn't change

Upload and restore behave exactly as before: same messages, no overwriting, old backups still restore. No new dependencies. Existing cases simply show as untracked in the new list.

Please test it

Draft until a few contributors have tried it — Windows especially.

  1. pytest — 156 tests should pass (75+ new).
  2. Start the app and check the CLEWs case registry: startup line. Add or remove a case folder by hand and confirm GET /clews/getInstalledCountries tracks it.
  3. Install from a local folder: POST /clews/inspectSource, then /clews/installCountry with {"source_type": "local_path", "local_path": "..."}, then poll getInstallStatus. An example manifest is in the docstring of API/Classes/Clews/CountryManifest.py.
  4. Upload and restore a normal case backup — nothing should feel different.

No country repo carries the manifest yet (CLEWs-PHL will be the first), so a real GitHub install can't be tried end to end — inspecting any repo URL today shows the clean refusal.

…'s case version

Restoring a case archive and any future programmatic install now run the exact
same code: the zip-processing core of handle_full_zip moved to
Classes/Case/CaseImporter.py (import_zip), together with the version-migration
helpers. The upload route keeps only the HTTP concerns and delegates.

The versions the importer accepts are now named constants instead of string
literals scattered through the ladder, and a new GET /getVersion reports them,
so a client can check compatibility before sending an archive.

No behavior change on the upload path: same messages, same duplicate refusal,
same cleanup, legacy pre-EAPD-DRB#331 arcnames still restore. Covered by new tests in
tests/clews/ (every accepted version imports; route drives the real HTTP path).
… at launch

Every imported case now gets a provenance sidecar (clews-provenance.json inside
the case folder): where the archive came from, its checksum, whether it matched
a published one, and when it was installed. Because the sidecar rides inside the
case, it survives backup, hand-off and restore. Copying a case restamps the
copy's sidecar as derived from the original instead of letting it claim to be
the pristine archive.

A per-storage index (.clews_registry.json at the DataStorage root) is reconciled
against a directory scan at server launch and on every installed-list read: a
case dropped in by hand shows up as unmanaged, a case directory removed by hand
is dropped from the index, and a case installed through a tracked path is
indexed from its sidecar. The launch pass logs one summary line and never blocks
startup. New GET /clews/getInstalledCountries serves the reconciled list.

The index deliberately lives inside DataStorage (a dot-file next to
Parameters.json), not at the user level: it describes one storage, and several
MUIOGO checkouts on one machine must not fight over a shared index. Verified
against a running server: hand-added case reported untracked at boot,
hand-removed case dropped on the next read.
A CLEWs country repository can now declare what it ships in a clews-country.json
manifest at its root: country identity, one or more vintages (model generations,
each a directory of portable MUIO case archives with a SHA256SUMS file), and
which vintage and case are recommended. MUIOGO reads that manifest and installs
from it -- it never guesses at repository layout, because country repos ship
several vintages side by side and sniffing for zip files would pick the wrong
model.

New endpoints under /clews:
- inspectSource reads the manifest (from a GitHub URL or a local folder) and
  returns the full menu -- vintages, cases, name collisions, version gate --
  before anything downloads.
- installCountry runs the install as a background job: fetch the declared
  archives (raw fetches, no clone -- repos are tens of MB, the payload a few MB),
  verify each against the published checksum (a mismatch installs nothing),
  then import through the exact pipeline the browser upload uses. Progress via
  getInstallStatus, cancellable via cancelInstall; downloads stage outside
  DataStorage so a partial download can never appear as a case.
- checkCountryUpdate compares an installed case's recorded checksum with what
  the source publishes now. Check-only; applying an update stays a deliberate
  delete + reinstall.
- getCountryCatalog reflects a country register when one is configured
  (none exists publicly yet, so it defaults to an honest empty list).

Name collisions are reported per case (already_exists) and never overwrite;
there is deliberately no replace option and no unregister endpoint -- the index
follows the disk. Interrupted installs are marked failed at the next launch.

Verified against a running server: full install from a fixture country repo
(menu, checksum verification, import, registry, classic case picker), a
tampered archive refused with nothing installed, and a manifest-less real
repository refused with a clear message. The live check also caught and fixed
a garbled error message (a fetch failure was rewrapped as a JSON complaint).
- Restoring a backup no longer erases the case's original provenance. A backup
  travels with its sidecar; a plain re-upload now keeps that record (it still
  says where the case came from) and just notes the restore. An installer's
  explicit source stays authoritative. Covered by a roundtrip test through the
  real /backupCase route.
- Version gate: '5.6.0' now equals '5.6'. A manifest declaring the UI's own
  three-part version would previously have refused a matching MUIO.
- Installed-list records now carry the country identity (iso3, name, vintage,
  role) at the top level, lifted from the sidecar's source block, so list
  consumers do not have to dig for it.
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