docs(staging): add personal report acceptance and rollback runbook
This commit is contained in:
@@ -0,0 +1,168 @@
|
||||
# Personal Report Staging Acceptance and Rollback
|
||||
|
||||
This runbook covers the staging-only rollout of `ReportDocument v1`, personal report generation, the report reader, D1 SVG rendering, and browser print-to-PDF. It does **not** authorize a production migration or deployment.
|
||||
|
||||
## Release identity
|
||||
|
||||
- Pre-change application baseline: `49da8f916960030d5760d8dedf4e77820732a527`
|
||||
- Read-only upstream Skill source commit: `unknown` (the local source has no usable Git metadata)
|
||||
- Read-only upstream source tree SHA-256: `9034e1967032d09c7fbae83fc2205f7e75e8ad482c5f9eba1bf309fe30aef5bb`
|
||||
- Packaged `SKILL.md` SHA-256: read from `references/upstream/yinduzhanxing/source-manifest.json`
|
||||
- Deployment SHA: use the exact full SHA shared by `main` and `staging`; never substitute a short SHA or mutable image tag.
|
||||
- Application rollback target: `49da8f916960030d5760d8dedf4e77820732a527`, subject to successful gate artifact retention.
|
||||
|
||||
## Staging configuration
|
||||
|
||||
The server-owned `/opt/jyotisha-staging/.env.staging` must remain mode `0600`. Do not print or copy the file. In addition to the existing self-hosted identity settings, configure:
|
||||
|
||||
```dotenv
|
||||
PERSONAL_REPORT_ENABLED=true
|
||||
PERSONAL_REPORT_DAILY_LIMIT=5
|
||||
```
|
||||
|
||||
`PERSONAL_REPORT_ALLOWED_ORIGINS` is normally omitted because browser requests are same-origin. Add it only for an explicitly reviewed origin. `JYOTISH_SKILL_SNAPSHOT_SHA256` and `JYOTISH_SKILL_SOURCE_COMMIT` are optional deployment pins; without a valid override, the web bundle uses the statically packaged, validated source manifest and fails closed if its SHA is invalid.
|
||||
|
||||
Validate without logging values:
|
||||
|
||||
```bash
|
||||
cd /opt/jyotisha-staging
|
||||
./deploy/validate-staging-env.sh .env.staging
|
||||
docker compose --env-file .env.staging -f deploy/docker-compose.server.yml config --quiet
|
||||
```
|
||||
|
||||
The report API reads these values server-side through Compose `env_file`. They must not be changed to `NEXT_PUBLIC_*` build arguments.
|
||||
|
||||
## Exact-SHA release sequence
|
||||
|
||||
Follow `deploy/README.md`; the short form is:
|
||||
|
||||
1. Confirm the reviewed `main` full SHA and fast-forward `staging` to the same SHA.
|
||||
2. Wait for `Staging Backend Quality Gate` on the `staging` push to succeed and publish the immutable API/web digest manifest.
|
||||
3. Let the automatic read-only deployment check stop on pending migrations.
|
||||
4. Run `Migrate Staging Database` manually from the `main` controller with the exact full SHA.
|
||||
5. Confirm the migration ledger contains `20260806000000_personal_reports.sql`.
|
||||
6. Run `Deploy staging` manually with that same SHA and `allow_rollback=false`.
|
||||
7. Verify `https://staging.jyotisha.chat/api/health` reports that exact SHA and both private services healthy.
|
||||
|
||||
Do not deploy the application before the additive migration. Do not trigger production workflows.
|
||||
|
||||
## Automated acceptance
|
||||
|
||||
Before pushing, record the literal command and outcome for:
|
||||
|
||||
```bash
|
||||
python3 -m pytest -q \
|
||||
tests/test_cross_project_contract.py \
|
||||
tests/test_cross_project_sync_status.py \
|
||||
tests/test_import_yinduzhanxing.py
|
||||
|
||||
python3 -m pytest -q \
|
||||
tests/test_unified_consultation_orchestrator.py \
|
||||
tests/test_report_orchestrator_reader_contract.py \
|
||||
tests/test_consultation_consumer_context.py \
|
||||
tests/test_personal_report_contract.py \
|
||||
tests/test_supabase_migration_versions.py
|
||||
|
||||
npm test --prefix frontend
|
||||
npm run lint --prefix frontend
|
||||
npm run build --prefix frontend
|
||||
```
|
||||
|
||||
If the complete frontend suite has environment-only failures, preserve their exact count and cause; do not report the suite as green. The personal-report-focused test set, TypeScript check, Python contract test, migration contract, production build, and `git diff --check` must pass before release.
|
||||
|
||||
## Synthetic browser acceptance
|
||||
|
||||
Use only synthetic accounts and synthetic birth facts. Never paste real birth data into tickets, logs, screenshots, or this document.
|
||||
|
||||
Prepare these profiles:
|
||||
|
||||
1. `confirmed` with an exact synthetic active time.
|
||||
2. `accepted` with a user-adopted synthetic candidate time.
|
||||
3. A report whose evidence contains blocked/conflicting techniques.
|
||||
4. A second synthetic owner account for isolation checks.
|
||||
|
||||
For each supported owner profile:
|
||||
|
||||
1. Sign in and complete a personal consultation with workflow evidence.
|
||||
2. Confirm the “生成个人报告” CTA is visible only for `accepted` or `confirmed` active time. It must be hidden for `reported` and unaccepted `candidate` states.
|
||||
3. Generate one report. Confirm the button prevents duplicate in-flight clicks and the app navigates to `/reports/<uuid>`.
|
||||
4. Confirm content order is summary, thematic narrative, then evidence appendix.
|
||||
5. Confirm D1 renders from real document facts. D9/D10 must be absent when their complete facts are unavailable.
|
||||
6. Confirm blocked claims use uncertainty language and contain no deterministic prediction.
|
||||
7. Reload the report URL and confirm the same validated document is returned.
|
||||
8. Attempt the report URL as the second synthetic owner; expect `404`/not found and no document data.
|
||||
9. Delete as the owner and confirm subsequent retrieval is not found.
|
||||
10. Generate with the same request ID and payload to confirm replay behavior; a different payload under the same ID must return `409 report_request_conflict`.
|
||||
|
||||
PDF/browser matrix:
|
||||
|
||||
| Client | Required check | Status before user handoff |
|
||||
| --- | --- | --- |
|
||||
| Desktop Chrome | Print → Save as PDF; SVG sharp; Chinese text intact; tables not clipped | pending manual |
|
||||
| macOS Safari | Print → Save as PDF; pagination and fonts | pending manual |
|
||||
| iPhone Safari | Share/Print flow and mobile hint | pending manual |
|
||||
| WeChat in-app browser | Export guidance is understandable | pending manual |
|
||||
|
||||
For a long synthetic document, target 20–40 printed pages and verify that print CSS expands the evidence appendix as designed. The report action must only wait for `document.fonts.ready` and call `window.print()`.
|
||||
|
||||
## Security and server assertions
|
||||
|
||||
Verify logged-out and cross-owner behavior without recording tokens:
|
||||
|
||||
```bash
|
||||
curl -sS -o /dev/null -w '%{http_code}\n' https://staging.jyotisha.chat/api/account
|
||||
curl -sS -o /dev/null -w '%{http_code}\n' https://staging.jyotisha.chat/api/reports/00000000-0000-4000-8000-000000000000
|
||||
```
|
||||
|
||||
Expected logged-out status is `401`. Authenticated owner/non-owner checks must be performed in the browser or with ephemeral local credentials that are never pasted into logs.
|
||||
|
||||
On the host, confirm no product PDF browser runtime exists:
|
||||
|
||||
```bash
|
||||
cd /opt/jyotisha-staging
|
||||
docker compose --env-file .env.staging -f deploy/docker-compose.server.yml exec -T web \
|
||||
sh -lc '! command -v chromium && ! command -v chromium-browser && ! command -v google-chrome'
|
||||
docker compose --env-file .env.staging -f deploy/docker-compose.server.yml exec -T web \
|
||||
sh -lc '! ps aux | grep -E "[c]hromium|[p]laywright|[p]uppeteer"'
|
||||
```
|
||||
|
||||
Inspect logs only for stable codes and operational state. Do not log or copy report text, prompts, birth facts, JWTs, cookies, model keys, exception stacks, or the staging env file.
|
||||
|
||||
## Resource evidence
|
||||
|
||||
Record before, during one generation, and during two synthetic users attempting concurrent generation:
|
||||
|
||||
```bash
|
||||
cd /opt/jyotisha-staging
|
||||
docker stats --no-stream
|
||||
docker compose --env-file .env.staging -f deploy/docker-compose.server.yml ps
|
||||
docker compose --env-file .env.staging -f deploy/docker-compose.server.yml logs --tail=200 api web caddy
|
||||
```
|
||||
|
||||
Capture only aggregate CPU, memory, container restart count, request duration, stable failure state, and serialized report byte size. Confirm:
|
||||
|
||||
- one generation per user at a time;
|
||||
- a second concurrent request for the same user returns the stable in-progress response;
|
||||
- serialized `ReportDocument` is at most 1.5 MiB;
|
||||
- no OOM or container restart;
|
||||
- no Chromium/Playwright server process.
|
||||
|
||||
One successful sample does not establish high-concurrency capacity.
|
||||
|
||||
## Rollback
|
||||
|
||||
### Application
|
||||
|
||||
Run `Deploy staging` from the trusted `main` controller using the previous known-good full SHA and `allow_rollback=true`. The selected SHA must still have a successful quality-gate artifact. Do not use a mutable tag or manually overwrite the server tree.
|
||||
|
||||
### Database
|
||||
|
||||
The personal report migration is additive. Application rollback intentionally leaves `public.personal_reports`, its grants, constraints, indexes, and RLS policies in place. Do not run a destructive down migration. Delete only explicitly identified synthetic test rows if cleanup is required.
|
||||
|
||||
### Feature pause
|
||||
|
||||
If generation must stop while the current application remains deployed, set `PERSONAL_REPORT_ENABLED=false` in the server-owned staging env under the deployment lock and recreate only the web service after validation. This is an operational containment action, not a substitute for an application rollback. Restore `true` only after the incident is resolved.
|
||||
|
||||
### Skill
|
||||
|
||||
Revert the commercial repository import/semantic-merge commits as reviewed. Do not modify the read-only upstream source directory. Preserve the import manifest and record that the target revision was rolled back; never rewrite provenance history.
|
||||
Reference in New Issue
Block a user