# mattermost-lts — parity & coverage map (Phase 2) ## P2 — Parity port **No recipe-maintainer corpus exists for mattermost-lts** (`/srv/recipe-maintainer/recipe-info/` has no `mattermost-lts/` entry). P2 (parity) is therefore **vacuously satisfied** — there are no `recipe-info/mattermost-lts/tests/*.py` scripts to port. Coverage is delivered entirely via the generic lifecycle tiers (install/upgrade/backup/restore) + the recipe-specific functional tests below. ## Lifecycle (generic tiers — Phase 1d/1e) mattermost-lts ships no `test_.py` overlays, so the **generic** install/upgrade/backup/restore tiers run by default (the Phase-1e invariant: no overlay ⇒ generic runs). The stack bundles its own postgres in-compose (no external dep), so no dependency resolution is needed. ## P3 — Recipe-specific functional tests (≥2 separate characteristic tests) 1. `functional/test_create_message.py::test_create_message_roundtrip` — **§4.3 create-an-object + read-it-back**: first user (system admin) → login → create team → create channel → POST a unique marker message → GET it back by id → assert the text round-trips. 2. `functional/test_multiuser_message.py::test_second_user_reads_first_users_message` — the defining **team-chat** behaviour (distinct code path: membership + ACL + cross-user delivery): user_a posts a unique marker; a SECOND user (created via admin API, added to team+channel) logs in with its own session and GETs the channel posts → asserts it sees user_a's message. Not a self read-back. - `functional/test_health_check.py` — `test_root_serves` (`/` 200/302) + `test_system_ping_ok` (`/api/v4/system/ping` → `{"status":"OK"}`, API liveness). Supporting health/liveness, not counted toward the P3 ≥2 floor. ## P4 — Backup data-integrity (real) `ops.py` seeds a postgres `ci_marker` row (psql in the `postgres` service); `test_backup.py` asserts it at backup time, `test_restore.py` asserts it survives restore, `test_upgrade.py` asserts it survives the upgrade. **Requires recipe-PR `recipe-maintainers/mattermost-lts#1`**: the published recipe dumped the DB on backup but shipped NO `backupbot.restore.post-hook` and archived the whole live PGDATA dir, so a restore extracted files under the running postgres without reloading them → the DB silently kept the un-restored state (`test_restore_returns_state` RED). The PR switches to the coop-cloud `/pg_backup.sh` convention (dump-only backup + terminate/FORCE-drop/recreate/reimport restore); with it the ci_marker survives backup→restore. See DECISIONS.md "mattermost-lts postgres restore recipe-PR".