# Patch Bundle operations

Patch Bundle is an independently governed, manifest-backed, idempotent SQL
migration paradigm. It is not Seed, an application artifact, a release phase,
or permission to mutate a shared environment.

## Definition contract

Each supported bundle is one tracked directory below this directory and
contains `patch-bundle.json` (or the legacy `patch-manifest.json`) plus its
ordered SQL files. The manifest declares at least `created_at` and a non-empty
`sql_files` list. Optional assertions are read-only single-statement queries
with explicit row-count or column expectations.

SQL is validated for the repository's idempotency subset before the first file
runs. Bundle order comes only from the manifest. Symlinks, untracked files,
dirty bundle bytes, a non-exact source commit, and an existing evidence
directory fail before SQL execution. Non-empty legacy `refs` are rejected:
Patch Bundle source identity is the explicit operation commit/path/digest, not
an application release tuple.

The public adapter derives the reviewed tree digest directly from the selected
commit's Git blobs. Before the first SQL file runs, the deep module copies the
selected working tree into the operation evidence directory and requires that
sealed digest to equal the Git-blob digest. It then rechecks the seal at every
SQL/assertion boundary. Concurrent checkout mutation therefore cannot change
the reviewed bytes used by an active operation.

## Independent execution mechanism

The public mechanism is:

```bash
python3 scripts/run_patch_bundle.py \
  --env-file /absolute/path/to/runtime.env \
  --patch-dir docs/migration/patch-bundles/<bundle> \
  --operation-id <unique-operation-id> \
  --expected-source-commit <exact-40-character-commit> \
  --evidence-dir /new/absolute/evidence/directory
```

Each invocation selects exactly one bundle directory. The operator never
discovers, queues, or replays sibling bundles under `docs/migration/patch-bundles`.
The standalone CLI has no implicit selection and therefore refuses to run
without `--patch-dir`; Test and Staging deployment inputs default to an empty
path, which means no Patch Bundle replay.

The target runtime env supplies TiDB connection authority at execution time;
credentials are neither accepted as command arguments nor written to the
receipt. `patch-summary.json` binds the operation ID, exact source commit,
tracked repository path, complete bundle tree digest, ordered SQL files,
target environment plus a non-plaintext connection-identity digest, bounded
assertion row counts/result hashes, and terminal success. Raw mutation stdout,
database endpoints, credentials, and assertion rows are not retained as
operation evidence.

`deployment_patch_replay.execute_patch_bundle()` is the deep module interface.
The CLI and retained Staging convenience adapter use that interface rather than
implementing separate manifest, SQL, retry, assertion, or evidence semantics.

## Environment authority

The CLI deliberately does not infer an environment, stop runtimes, acquire a
shared-environment write fence, route traffic, publish a release Tag, or update
Prod release state. The caller must establish and independently prove the
source review and environment-specific mutation authority before invoking it.

Current Staging D3 may invoke Patch Bundle replay inside its deployment. Its
successful dispatch records the nullable path/tree digest; the v5 D3 Tag copies
that exact identity, and Prod replays a non-null bundle from the Tag-selected L2
tree immediately before Catalog apply. Prod exposes no independent Patch input,
and the Tag carries no raw SQL or replay result. The standalone CLI remains a
separate migration mechanism: invoking it for Prod requires its own reviewed
authority, fence, recovery boundary, and post-migration readback.
