# Python service deployment and read-only release verification

Use this checklist for transactional applications that deploy a Python service plus a browser frontend against a live database.

## Exact artifact deployment

1. Record the reviewed branch head and the normal merge commit separately.
2. After merge, read the PR through the REST API and record `merged`, `merge_commit_sha`, `head.sha`, and `base.sha`; do not infer the deployment SHA from local branch movement.
3. Fetch remote `main` and verify it equals the recorded merge SHA before deployment.
4. Update a separate clean deployment worktree in detached-HEAD mode to that exact SHA; never deploy an approximate branch tip.
5. Build the frontend from the deployment worktree, then restart services deliberately.

Some `gh pr merge` flows switch or fast-forward the caller's current worktree to `main`, especially when deleting the feature branch. Treat the feature worktree as mutable after merge: re-read its branch and HEAD, and never use it as deployment provenance. The detached deployment worktree plus REST-reported merge SHA remain authoritative.

## Python runtime provenance check

An editable install can report success while Python still imports an older package copy from `site-packages`. Immediately after installation, verify both:

```bash
/path/to/runtime/python - <<'PY'
import package.module as m
print(m.__file__)
print(m.EXPECTED_VERSION_MARKER)
PY
```

The module path and version marker must identify the exact deployment tree/candidate. If they do not, install a non-editable wheel or force-reinstall from the exact tree, repeat the provenance check, and only then restart the backend. A successful `pip install -e` message is not deployment evidence.

## Backup/restore evidence

Before restarting the write-capable runtime:

- create an online SQLite backup with mode `0600`;
- restore it into an isolated file;
- compare integrity, foreign-key findings, table count, total row count, and a deterministic digest of per-table counts;
- keep the restore test disconnected from production.

## Responsive deployed UAT

Probe the live route at desktop, tablet, and mobile acceptance widths. Record:

- exact viewport dimensions;
- horizontal overflow delta and offending elements;
- responsive grid column count;
- minimum height of task-relevant controls (not every global button);
- required workflow copy;
- console/JavaScript errors.

Store screenshots or machine-readable evidence outside Git with mode `0600` when the page can expose private finance context.

## Productive read-only preview

Run the same real-file preview twice when practical: once on the frozen candidate and once on the exact deployed merge. Compare masked counts and thresholds. For each run, capture before/after:

- full database file SHA-256, size, and modification timestamp;
- schema version, integrity result, and foreign-key findings from `mode=ro&immutable=1`;
- deterministic per-table row counts plus critical-table counts;
- timer enabled/active state and write/valuation gates;
- deployment worktree HEAD and cleanliness;
- explicit flags that Confirm and Realimport were not called.

When comparing pre/post sentinels, separate immutable-data fields from expected deployment metadata. The deployment HEAD must change from the old SHA to the exact merge SHA, while database hash/size/mtime, table counts, schema, integrity, foreign keys, timer state, and safety gates must remain identical. Calling the whole JSON unequal because the intended code SHA changed is a comparison bug; excluding database fields to force equality is equally wrong.

A technically valid preview can still have `business_ready_for_confirm=false`. Treat that as a successful fail-closed release outcome, not permission to weaken gates. Report coverage, review burden, latency, and the blocked Confirm state explicitly.

## Review completion discipline

If the release contract requires an independent review of the final candidate, do not mark the review or release-report task complete after merely fixing findings from an earlier review. Either obtain an independent verdict on the frozen exact SHA or clearly keep the task open. After that verdict, perform direct regression verification of any fixes; avoid endless review loops.

## CI evidence without full Checks API scope

A pull-request-capable token may still receive `Resource not accessible by personal access token` from GraphQL `statusCheckRollup` and the commit-status/check-runs endpoints. Do not weaken the gate or rely only on PR prose.

If the repository's required workflow is GitHub Actions and the token can read Actions runs:

1. resolve the immutable feature commit SHA;
2. query `GET /repos/{owner}/{repo}/actions/runs?head_sha={sha}`;
3. select the expected workflow by name and record its run ID and URL;
4. poll `GET /repos/{owner}/{repo}/actions/runs/{run_id}` with a bounded timeout;
5. require `status=completed` and `conclusion=success` before merge.

Then query the PR REST endpoint and require `mergeable=true` plus `mergeable_state=clean`. The Actions run is the CI evidence; mergeability is a separate branch-protection/conflict gate. If neither checks nor Actions runs are readable, keep the release blocked rather than treating `unknown` or a locally green suite as hosted-CI success.
