# Linux VPS pilot package

Phase 6 milestone 14 prepares a reproducible upload artifact and read-only host preflight. The owner selected **prepare for a Linux VPS** on 2026-10-15. No VPS has been purchased or configured. Deployment and AI evaluation are the current priority; additional outbound-email implementation is deferred while the pilot path is prepared.

The package is a server-source ZIP, not a built Docker image, live-site replacement or signed mobile app. It contains the API/migrations, web source/assets, shared contracts, dependency locks, deployment files, installation scripts and documentation. The mobile package manifest is included only because the web build uses the existing workspace lockfile; native source/bundles are not shipped in this server package.

## Create a release candidate locally

From `platform/`:

```sh
mkdir -p .local/releases
python3 scripts/package-staging.py create \
  --release pilot-20261022-01 \
  --output .local/releases/pilot-20261022-01
```

Use a new release label and new output directory for each candidate. An existing output directory is refused. A failed output is marked `INCOMPLETE` and must not be uploaded. Successful output contains the ZIP, its `.sha256` file and a readable `RELEASE-MANIFEST.json`.

The manifest records each source file's size/hash, the aggregate source digest and migration head. ZIP member timestamps, order and modes are normalized, so identical source and release labels produce identical archive bytes. No source file is modified. The allowlist excludes local databases, environment settings, attachments, caches, installed dependencies, preview outputs and credential-named files. It rejects symlinks and oversized inputs. This is not a general secret scanner: never embed a real secret in application source or documentation.

Use the printed ZIP SHA-256 as the expected value for local verification:

```sh
python3 scripts/package-staging.py verify \
  --archive .local/releases/pilot-20261022-01/phonebuzz-pilot-20261022-01.zip \
  --sha256 EXPECTED_SHA256_FROM_CREATION
```

Verification does not extract anything. It checks the trusted archive digest, safe member names/types/modes, duplicate entries, required sources, bounded expanded size, file hashes, migration chain and exact manifest. A checksum identifies this artifact and detects corruption; it is not a signature or proof of production readiness. Record the checksum through a trusted channel rather than trusting an altered ZIP and checksum together.

## On the selected VPS

Keep the existing PHP website on its current host. Upload the ZIP and checksum to a new private directory on the Linux VPS, outside every public web root. Do not copy the entire development folder or any `.local` data. From that directory, first compare the received checksum with the trusted value and then run:

```sh
sha256sum -c phonebuzz-pilot-20261022-01.zip.sha256
unzip phonebuzz-pilot-20261022-01.zip
cd phonebuzz-platform
python3 scripts/check-host.py
```

Stop if checksum verification fails. Extract into a fresh directory, never over an existing installation. The host preflight needs Python 3.10+ and checks Linux, accessible Linux Docker Engine, Compose v2.24+ and deployment source presence. It performs only read-only probes; it does not install software, pull images, bind ports or start services. Exit 0 means those prerequisites passed, **not** that the application is deployed or ready for staff.

Follow [STAGING.md](STAGING.md) to generate fresh private settings with the actual approved hostnames, TLS email and allowed office/VPN ranges. Then run:

```sh
python3 scripts/check-host.py --require-config
```

This additionally checks private configuration permissions and runs Compose validation with output suppressed. It never prints secret values. Continue with the existing build/start/admin-creation instructions only on the identified authorized server. Record API/web/database/proxy image digests after building; base image tags are not yet pinned by this package.

## First pilot scope

Use synthetic records initially. Exercise staff login/MFA, catalogue and company setup, stock/wanted matching, quotation and separate approval, orders/dispatch/returns, and reviewed assistant lookup/feedback. Live email, WhatsApp, push and formal invoice issuance remain disabled. Existing live website accounts are not imported.

The server work still needs Linux image/build verification, startup/volume checks, DNS/TLS/access restrictions, backup/restore, monitoring, operational security and staff acceptance. The user authorized prioritizing this limited pilot; it does not waive those checks or authorize a hosting purchase.

The [private VPS model connection](SERVER-AI.md) is now prepared as Phase 6 milestone 15. The base staging stack still starts with AI off. Validate the optional model overlay and synthetic probe on the VPS before enabling staff requests. First collect representative questions, approved corrections and held-out evaluation examples; automatic model weight training is not enabled. Never present test-generated examples as real staff feedback.

## Evidence

Package tests cover reproducibility, preserved source, local-data exclusion, symlink refusal, overwrite refusal, corrupt checksums/manifests, unsafe ZIP entries, migration completeness and size limits. Host checks cover missing prerequisites, version parsing, secret redaction and private configuration modes. Existing staging generator/readiness checks and Compose/Caddy validation are also recorded in [VALIDATION.md](VALIDATION.md). Full container execution still requires a Linux Docker host.

The package now includes the [offline staff pilot rehearsal](PILOT-REHEARSAL.md), Phase 6 milestone 16. Run it with the API virtualenv in the extracted source directory before hosted acceptance. It uses a new disposable SQLite database, never the configured PostgreSQL server, and is not part of the runtime container. Keep its report with the release evidence; hosted coordinated restore remains required.

## Verify extracted source before building

Run the verified package's `scripts/package-staging.py compare --archive PATH_TO_ZIP --sha256 TRUSTED_SHA256` from the extracted project. It compares all allowlisted source bytes with the verified manifest, reporting missing/changed/unexpected selected files and returning nonzero on drift. Use `--source-root PATH` to inspect another extraction. Local configuration, databases, dependencies and build products are excluded. This does not validate image contents, deployment or the entire filesystem.

The [DevOps handover](DEVOPS-HANDOVER.md) consolidates installation order, acceptance evidence, release tracking and the update/recovery boundary. It has not been sent externally.

## Combined offline release rehearsal

Before handing off a new candidate, run [RELEASE-CHECK.md](RELEASE-CHECK.md) against that exact ZIP with its trusted checksum. The tool uses the extracted API source, verifies locked dependencies, checks fresh migrations and both empty-holdout evaluators, runs the 15-checkpoint workflow/restore rehearsal and writes a private receipt. It does not build/deploy images or replace hosted acceptance.
