review(2): Q4.4 ghost PASS — COLD full lifecycle GREEN (my clone, log adv-ghost-pr1) 5 tiers, deploy-count=1, real upgrade crossover 1.1.1+6-alpine→1.3.0+6.21.2-alpine (chaos 6d6227f7+U, HC1 preserved), create_post_roundtrip + restore + backup + upgrade markers PASS, clean teardown; P4 MySQL ci_marker restore proven NON-VACUOUS via PR=0 negative control (published recipe → test_restore_returns_state FAILED 'Table ghost.ci_marker doesnt exist', fail-loud) — recipe-PR ghost#1 is a genuine reimport-on-restore fix (4th data-loss recipe bug cc-ci caught); §4.3 create-post real (cookie admin session + unique-marker title+body read-back) CLOSES the ghost §4.3 floor; +U HC1 fix & healthcheck overlay reviewed legit (not weakening); clean teardown after FAILED run too; no veto

This commit is contained in:
2026-05-30 07:57:56 +01:00
parent e2be3cc07e
commit baa7ad828b

View File

@ -1737,3 +1737,75 @@ upgrade/backup/restore tiers were not in this scoped run (install,custom only)
plausible still ride the normal gate path if/when claimed; this probe targeted the §4.3 floor that was
my standing obligation. No VETO. NOTE: ClickHouse boot is intermittently flaky on the single node
(1-in-2 here) — a real env-fragility worth a retry/readiness margin if plausible runs go in CI rotation.
## Q4.4 ghost — PASS @2026-05-30T06:57Z (COLD, first-hand, my clone /root/adv-verify @origin/main c60d5b5)
Cold full-lifecycle re-run from my OWN clone — the exact claimed command — PLUS a negative control.
Logs `/root/adv-ghost-pr1.log` (PR=1, the fix) and `/root/adv-ghost-pr0-neg.log` (PR=0, published).
**Primary — PR=1 (recipe-PR `recipe-maintainers/ghost#1`, REF=6d6227f7), all 5 tiers GREEN:**
- RUN SUMMARY: `deploy-count = 1 (expect 1)`; `install/upgrade/backup/restore/custom` **all pass**.
No cold-init flake on my run (install passed first try; ENV-NOTE retry not needed).
- Upgrade: `head_ref=6d6227f7 chaos-version=6d6227f7+U version=1.1.1+6-alpine→1.3.0+6.21.2-alpine`
(HC1, real prev→PR-head crossover; the `+U` untracked-overlay marker correctly tolerated by the
`a7e2af4` fix — which I reviewed: it strips ONLY the working-tree marker and still requires the
commit to equal head_ref, so HC1 is preserved, not weakened).
- `tests/ghost/test_upgrade.py::test_upgrade_preserves_state PASSED`,
`test_backup.py::test_backup_captures_state PASSED`,
`test_restore.py::test_restore_returns_state PASSED` (MySQL `ci_marker='original'` read back),
`functional/test_post_roundtrip.py::test_create_post_roundtrip PASSED` (6s).
- Clean teardown: post-run no ghost stack; 0 ghost secrets / 0 volumes / 0 networks.
**P4 — the headline crux — restore PROVEN non-vacuous via NEGATIVE CONTROL (decisive).** Re-ran the
SAME overlay against the **published** recipe (`PR=0`, no fix), STAGES=install,backup,restore:
- `tests/_generic/test_restore.py::test_restore_healthy PASSED` (app healthy after restore) **but**
`tests/ghost/test_restore.py::test_restore_returns_state FAILED` —
`RuntimeError: docker exec … failed (rc=1) … ERROR 1146 (42S02) … Table 'ghost.ci_marker' doesn't
exist`. RUN SUMMARY: `restore : fail` (install+backup pass).
- Confirms: (a) the published ghost recipe's restore is a **silent no-op** — it ships a mysqldump
`--tab` backup pre-hook but **no `backupbot.restore.*` reimport hook**, so the dropped table never
returns (looks healthy, data lost — the immich#1 / mattermost-lts#1 class); (b) the P4 overlay is
**non-vacuous** (health-only passes here, the data-integrity assertion catches it); (c) it fails
**LOUD** — `exec_in_app` RAISES on a failed exec, never a silent `''`; (d) `ops.pre_restore` DROPs
`ci_marker` AND asserts the drop took (information_schema count=0), so a no-op restore is observable
in-band on EVERY run too. recipe-PR #1 (`ci/mysql-backup`) adds the reimport-on-restore hook →
`test_restore_returns_state` PASSES (PR=1). The recipe-PR is a **genuine fix**, verified end-to-end
by running both halves myself.
**P3 — §4.3 create-post is REAL (read the body), closes the standing ghost §4.3 floor:**
`test_create_post_roundtrip` waits for the Admin API → bootstraps the owner (`/authentication/setup/`)
→ establishes a real cookie-aware admin **session** (`_ghost.GhostAdmin` builds a urllib opener with
an HTTPCookieProcessor + the CSRF `Origin` header Ghost requires) → POSTs a **published** post with a
unique-per-run marker in title+body (`/posts/?source=html`) → GETs it back by id (`?formats=html`) →
asserts BOTH the title and the body-html marker round-trip. Per-run UUID marker ⇒ no stale/echo
false-pass; exercises DB-write + Admin-API + publishing path. This **replaces the weak**
`test_content_api` (which accepted 401/403/400) as the §4.3 floor — my standing DONE-blocker #3 for
ghost is CLEARED. (`test_admin_redirect`, `test_content_api`, `test_health_check` also PASS as
supporting liveness.)
**P2 N/A** (no recipe-maintainer corpus — documented in `tests/ghost/PARITY.md`). **P5/P6 N/A** —
postgres/MySQL is in-recipe (no external dep); core publishing exercised via the Admin API; no
browser-only UX owed. **P7** — no weakened/skipped/mocked tests. The two cc-ci infra changes are
legitimate, NOT test-weakening: (1) `compose.ccci-health.yml` start_period overlay gives Ghost's
~6-9min fresh MySQL migration time to finish so the healthcheck doesn't kill it mid-migration
(`migrations_lock` deadlock) — a test-harness fixture for a real slow-cold-boot, the migration itself
is genuine; (2) the `+U` HC1 fix (reviewed above, preserves the commit match).
**Break-it checks:** (1) PR=0 negative control → restore RED on the published recipe (teeth proven);
(2) clean teardown after a **FAILED** run — post-PR=0 node fully clean (no ghost residue); (3) per-run
unique post marker defeats stale-response false-pass; (4) in-band pre_restore drop+assert-took; (5)
deploy-count=1 (no hidden redeploy). ENV fragility noted: ghost's mysql:8.0 cold-init healthcheck is
flaky (Builder saw one install timeout pr1c → passed on retry pr1d); my PR=1 install passed first try.
**Verdict: Q4.4 ghost PASS.** Full lifecycle GREEN cold, deploy-count=1, real upgrade crossover
1.1.1+6-alpine→1.3.0+6.21.2-alpine, P4 MySQL ci_marker survives backup→restore (non-vacuous, proven
by PR=0 negative control), §4.3 create-post real (closes the ghost §4.3 floor), clean teardown (incl.
after failure). No `## VETO`. Advances P1 coverage (ghost full green). recipe-PR
`recipe-maintainers/ghost#1` is a real restore fix — 4th data-loss-class recipe bug cc-ci has caught
(immich, mattermost-lts, ghost; bluesky's volume restore was already sound). **My standing ghost §4.3
DONE-blocker is CLEARED.**
**Isolation note:** verdict from the plan (P1P8) + the test code (ops.py / test_{restore,backup,
upgrade}.py / functional/{_ghost,test_post_roundtrip}.py) + the `a7e2af4` HC1 diff + the STATUS
Gate-Q4.4 verification info + my own cold PR=1 full run AND PR=0 negative control. JOURNAL-2 not
consulted before this verdict.