R-469: lift the MariaDB half of the engine-major rule; add R-450's own-edge clause
gates / gates (push) Successful in 1s
gates / gates (push) Successful in 1s
Slice 4 shipped 2026-09-13, so the rule's own expiry condition is met — for MariaDB.
PostgreSQL and MySQL stay refused (R-463: no pg_upgrade, refuses to start on an
older major's datadir across eleven templates).
A MariaDB major is now allowed ONLY as its own edge: never in the same commit as
another image move in that template (R-450, the bookstack 0b73e5e shape).
Two new decoy cases; two red-proofs, each seen to fail. 40 cases green.
No template moved.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS
This commit is contained in:
@@ -225,16 +225,21 @@ def main():
|
||||
DOCMOST = "templates/docmost/docker-compose.yml"
|
||||
|
||||
# ── THE FACTS: these must be refused ─────────────────────────────────────────────────
|
||||
out = case("FACT: kimai-db mariadb:11.6 -> 12.3 (cross-major)", clone,
|
||||
[(KIMAI, swap_image("kimai-db", "mariadb:11.6", "mariadb:12.3"))],
|
||||
out = case("FACT: docmost-postgres 16-alpine -> 17-alpine bundled with the app bump", clone,
|
||||
[(DOCMOST, lambda t: swap_image("docmost-postgres", "postgres:16-alpine", "postgres:17-alpine")(t))],
|
||||
expect_rc=1,
|
||||
must_contain=("ENGINE-MAJOR GATE FAILED", "kimai-db", "mariadb 11 -> 12",
|
||||
"R-448", "EXPIRY"))
|
||||
must_contain=("ENGINE-MAJOR GATE FAILED", "docmost-postgres", "postgres 16 -> 17"))
|
||||
if "REFUSAL_TEXT" in os.environ:
|
||||
print(out)
|
||||
case("FACT: docmost-postgres postgres:16-alpine -> 17-alpine", clone,
|
||||
[(DOCMOST, swap_image("docmost-postgres", "postgres:16-alpine", "postgres:17-alpine"))],
|
||||
expect_rc=1, must_contain=("docmost-postgres", "postgres 16 -> 17"))
|
||||
expect_rc=1, must_contain=("docmost-postgres", "postgres 16 -> 17", "R-463"))
|
||||
# R-469 + R-450 (2026-09-21): a MariaDB major bundled with the app's own bump is the
|
||||
# bookstack 0b73e5e shape — two migrations behind one edge — and stays refused.
|
||||
case("FACT: kimai-db 11.6 -> 12.3 BUNDLED with the kimai app bump", clone,
|
||||
[(KIMAI, lambda t: swap_image("kimai", "kimai/kimai2:apache-2.57.0", "kimai/kimai2:apache-2.58.0")(
|
||||
swap_image("kimai-db", "mariadb:11.6", "mariadb:12.3")(t)))],
|
||||
expect_rc=1, must_contain=("IN THE SAME COMMIT as kimai", "OWN EDGE", "R-450"))
|
||||
case("FACT: kimai-db mariadb:11.6 -> mariadb:lts (major unreadable)", clone,
|
||||
[(KIMAI, swap_image("kimai-db", "mariadb:11.6", "mariadb:lts"))],
|
||||
expect_rc=2, must_contain=("INCONCLUSIVE",))
|
||||
@@ -243,6 +248,11 @@ def main():
|
||||
case("GENUINE: kimai-db mariadb:11.6 -> 11.8 (within major)", clone,
|
||||
[(KIMAI, swap_image("kimai-db", "mariadb:11.6", "mariadb:11.8"))],
|
||||
expect_rc=0, must_contain=("engine-major gate OK",))
|
||||
# R-469: the LIFT itself. A MariaDB major ALONE in its template is now permitted, and the
|
||||
# gate says so by name rather than passing in silence.
|
||||
case("GENUINE: kimai-db mariadb:11.6 -> 12.3 ALONE (the R-469 lift)", clone,
|
||||
[(KIMAI, swap_image("kimai-db", "mariadb:11.6", "mariadb:12.3"))],
|
||||
expect_rc=0, must_contain=("ALLOWED", "kimai-db", "mariadb 11 -> 12", "R-469"))
|
||||
|
||||
# ── THE DECOYS: the label moves, the fact does not — these must pass ─────────────────
|
||||
def comment_and_env(text):
|
||||
|
||||
Reference in New Issue
Block a user