diff --git a/.woodpecker/ci.yml b/.woodpecker/ci.yml index 806aa616..41fa8076 100644 --- a/.woodpecker/ci.yml +++ b/.woodpecker/ci.yml @@ -125,10 +125,19 @@ steps: echo "ci-postgres did not become ready" >&2 exit 1 fi - # Run migrations (DATABASE_URL is set in environment above) - - pnpm --filter @mosaicstack/db run db:migrate - # Run all tests - - pnpm test + # RM-61 negative control 2/2: arm a real post-readiness database crash, + # then continuously query until the service loss is observed. + - psql "$DATABASE_URL" -v ON_ERROR_STOP=1 -c 'CREATE TABLE rm61_crash_armed (armed boolean NOT NULL)' + - | + for i in $(seq 1 60); do + if ! psql "$DATABASE_URL" -v ON_ERROR_STOP=1 -c 'SELECT 1'; then + echo "RM-61 control observed the armed PostgreSQL crash" >&2 + exit 61 + fi + sleep 1 + done + echo "RM-61 control did not observe the armed PostgreSQL crash" >&2 + exit 62 depends_on: - typecheck @@ -139,6 +148,15 @@ services: POSTGRES_USER: mosaic POSTGRES_PASSWORD: mosaic POSTGRES_DB: mosaic - # RM-61 negative control 1/2: force a real PostgreSQL startup failure. - # This commit is intentionally red and will be reverted after its single run. - POSTGRES_INITDB_ARGS: --rm61-invalid-option + entrypoint: + - /bin/sh + - -c + commands: + - | + docker-entrypoint.sh postgres & + postgres_pid=$$! + until pg_isready -h 127.0.0.1 -p 5432 -U mosaic; do sleep 1; done + until [ "$$(psql -h 127.0.0.1 -U mosaic -d mosaic -Atqc "SELECT to_regclass('public.rm61_crash_armed')")" = "rm61_crash_armed" ]; do sleep 1; done + echo "RM-61 control killing ready PostgreSQL postmaster $$postgres_pid" >&2 + kill -KILL "$$postgres_pid" + wait "$$postgres_pid" diff --git a/docs/scratchpads/1000-rm-61-ci-contract-exemption.md b/docs/scratchpads/1000-rm-61-ci-contract-exemption.md index 4a1d08f0..ce2d656b 100644 --- a/docs/scratchpads/1000-rm-61-ci-contract-exemption.md +++ b/docs/scratchpads/1000-rm-61-ci-contract-exemption.md @@ -33,14 +33,23 @@ Historical JSON saved locally under `.evidence/rm-61/` (not for commit). Supplie - [x] Requirements and kill criterion recorded before control implementation. - [x] Historical full-JSON records captured. -- [ ] Startup-failure control observed terminal. +- [x] Startup-failure control observed terminal. - [ ] Post-readiness crash control observed terminal. - [ ] Discrimination verdict recorded. - [ ] Conditional exemption implementation (only if verdict permits). ## Tests / evidence -Pending. +### Control 1 — real startup failure + +- Commit: `3931b0e29eb834914f7b17e4db7e221481d436fa` +- Pipeline: #2189, exact commit match. +- Full JSON child scan: 9 total — 7 success, 2 failure, 0 skipped/pending/running. +- `ci-postgres`: `state=failure`, `exit_code=1`, `error=null`, with a five-second execution window. +- `test`: `state=failure`, `exit_code=1` after the readiness budget expired. +- Pipeline/workflow: terminal `failure`. + +This control is red and its service record differs from #1000 (`exit_code=0` plus pod-not-found). It proves the startup-failure direction only. It does not settle the dangerous post-readiness crash/garbage-collection path. ## Risks