# YachtMemory Source Catalog v2 — Receiver 0.1.0 (REVIEW ONLY)

**Neither signed nor deployable.** This is a standalone **CLI TEST receiver** hard-pinned to the isolated `yachtmemory_catalog_v2_test` MySQL 8.0 schema. It is **not** connected to the productive Sync-Controller or Sync-Receiver and does not implement production transport authentication, Outbox receipts, or central reconciliation scheduling.

## Contents

- `receiver/ym-catalog-v2-test-receiver.php`: complete test receiver for `header`, `chunk`, and `finalize`, with InnoDB transactions, SHA-256 checks, idempotent staging, per-vessel activation lock, and history maintenance.
- `protocol/catalog_v2.py`: unchanged reference codec from prior review (offline only).
- `protocol/PROTOCOL-v2.md`: prior draft contract.
- `sql/central_schema_v2_REVIEW.sql`: unchanged prior draft schema, **not to execute on production**.
- `fixtures/revision-1`, `fixtures/revision-2`: synthetic requests for one unknown path plus a larger 801-record dataset. Fixed test-vessel UUID from the previously established isolated fixture. Do not use as production payloads.
- `tests/test_receiver_contract.py`: offline protocol + independent PHP/Python SHA-256 compatibility checks.
- `tests/mysql_test_review.sh`: **opt-in**, one-shot MySQL integration test for the already-created isolated test schema. It refuses to run if snapshots or active catalog rows already exist.

## Offline validation on YMServer

```sh
cd /var/www/app.yachtmemory.net/YM-Source-Catalog-v2-Receiver-0.1.0-REVIEW
php -l receiver/ym-catalog-v2-test-receiver.php
python3 -m py_compile protocol/catalog_v2.py tests/test_receiver_contract.py
python3 -m unittest discover -s tests -v
```

## Isolated MySQL test (later, after reviewing implementation)

`bash tests/mysql_test_review.sh` requires `sudo mysql`, `sudo php` and previously installed schema `yachtmemory_catalog_v2_test`. This operation writes **only** to that test database. Test-fixture tables must be initially empty; it fails closed otherwise. It deliberately does not create or drop any databases.

## Implementation scope and safety boundaries

- The receiver accepts only `operation=header|chunk|finalize` JSON via CLI stdin (maximum 32 KiB per request).
- `header` persists the immutable manifest; `chunk` requires its header to exist and persists each uniquely indexed, hash-checked chunk. Identical retries are accepted; conflicting chunks fail.
- `finalize` serializes per-vessel activation by row lock. Missing chunks return `incomplete`, leaving the last active snapshot unchanged.
- Completed snapshots require exact index set, individual chunk checksum, global SHA-256, record uniqueness, sorted ordering, and path integrity. An activation occurs in **one MySQL InnoDB transaction**. Identical finalize retries are idempotent.
- Old snapshots become `superseded`; unknown paths are accepted with value types `unknown` etc. Only **selected** Signal-K paths are represented as currently observed; absence does not prove sensor removal.
- PHP and Python canonical JSON encoders are cross-tested with current fixtures. A future formal wire contract must specify numeric formatting and Unicode canonicalization more rigorously; current code is review-only.

**Important open work before production:** trusted vessel-to-device binding, integrating the existing signed sync transport and `sync_receipts`, complete adversarial/roll-back/crash injection, operation quotas and retention, migration rerun checks, cleanup policy, and a signable deployable release. No commands target Wildbad or `SilentMessDB`.
