verae-mcp-timestamping-serv.../docs/cutover.md
George Lambert 30b5df6757 docs: cutover checklist and tsnats usage
Add docs/cutover.md (shadow :8001, embedded NATS :4223, REQUIRE_BEARER
host-token default, cutover/rollback; no JetStream for job-complete).
Expand README Usage with env table and pkg/tsnats snippet; add
examples/tsnats-bulk.
2026-09-29 12:14:46 -04:00

67 lines
3.2 KiB
Markdown

# Shadow deploy and cutover (Go MCP)
Python stays on `127.0.0.1:8000`. Go shadows on `127.0.0.1:8001` with embedded NATS on `127.0.0.1:4223`. Do **not** install or enable the Go unit on ns1 until an explicit publish/deploy order.
## Shadow layout
| Role | Bind | Notes |
| --- | --- | --- |
| Python MCP (live) | `127.0.0.1:8000` | Caddy → public `/mcp` |
| Go MCP (shadow) | `127.0.0.1:8001` | Internal smoke only until cutover |
| Go embedded NATS | `127.0.0.1:4223` | `pkg/tsnats` / bulk workers |
Install tree (when deploying): `/opt/verae/verae-mcp-timestamping-server-go/` (does not overwrite the Python venv). Unit file in-repo: `deploy/verae-mcp-timestamping-go.service`.
## Bearer / host-token (shadow default)
| `VERAE_MCP_REQUIRE_BEARER` | Behavior |
| --- | --- |
| `0` or unset (**default**) | Caller `Authorization: Bearer` wins when present. Otherwise the process keeps a host token from `~/.verae/auth.properties` (or `VERAE_AUTH_PROPERTIES` / `VERAE_GLOBAL_TOKEN`) and refreshes before expiry. |
| `1` | Caller bearer required for global VeraeTime paths; no host-token fallback. |
Shadow unit ships `VERAE_MCP_REQUIRE_BEARER=0` so operators can smoke without every client supplying a JWT.
## Embedded NATS / job-complete
- Listen: `VERAE_NATS_LISTEN=127.0.0.1:4223` (set empty to disable embed).
- Request/reply: `verae.ts.request`, `verae.ts.verify`, `verae.hash.report`.
- Job-complete / jobId notify: **core NATS only** on `verae.ts.completed` (and receipt notify if used). **No JetStream** (or other persistent stream) for job-complete. Publishers fire-and-forget; listeners subscribe.
## Env cheat sheet (shadow)
```sh
VERAE_MCP_TRANSPORT=streamable-http
VERAE_MCP_HOST=127.0.0.1
VERAE_MCP_PORT=8001
VERAE_NATS_LISTEN=127.0.0.1:4223
VERAE_MCP_REQUIRE_BEARER=0
# optional: VERAE_AUTH_PROPERTIES, VERAE_LEDGER_PATH, VERAE_GLOBAL_URL, VERAE_GLOBAL_TOKEN, VERAE_MCP_CORS
```
Service user on ns1 is `verae-mcp` with `HOME=/var/lib/verae-mcp` (share or isolate `auth.properties` vs Python as chosen for the soak).
## Local parity before soak
With Python on `:8000` and Go on `:8001`:
```sh
./scripts/parity_smoke.sh
```
Compares `tools/list` name sets. Optionally stamp/verify/hash_report the same digests against both ports during soak.
## Cutover checklist
1. Shadow green for the agreed soak (tools/list parity, global stamp/verify/hash_report, local ledger, NATS stamp + `verae.ts.completed` observe).
2. Stop Python unit **or** switch Caddy upstream away from `:8000` Python.
3. Point Go at public port: set `VERAE_MCP_PORT=8000` (or leave Go on `8001` and point Caddy at Go).
4. Confirm `https://mcp.verae.ai/mcp` `tools/list` and a known digest `hash_report`.
5. Keep the Python tree on disk for one release cycle.
6. Do not enable JetStream for job-complete as part of cutover.
## Rollback checklist
1. Restore Python `ExecStart` / Caddy upstream to `127.0.0.1:8000` Python.
2. Stop or disable `verae-mcp-timestamping-go.service` (or move Go back to `:8001` only).
3. Restart Python; confirm public `tools/list` and a known `hash_report`.
4. Leave Go binary under `/opt/verae/verae-mcp-timestamping-server-go/` for a later retry; do not delete until soak of the rollback is confirmed.