Fix 3 — P5 Fail-Closed Exact Oracle
05 — FIX 3: P5 FAIL-CLOSED BAD-INPUT HARNESS (the rejecting blocker)
Root cause (Codex A9)
Rev-1 c1_run did pass=(ex='reject') in a WHEN OTHERS catch — so ANY exception (wrong
SQLSTATE, missing prerequisite, typo, unrelated error) was marked PASS. Assertions were
non-fatal SELECT 'RESIDUE_FAIL' … strings; psql exited 0; P5_DONE printed after logical failure.
Fix — exact oracle
c1_run(case_no, phase, label, expected_reject_code, expected_sqlstate, query):
- Accepted bad input → FAIL: the
EXECUTE qsuccess branch hardcodespass=false("invalid input was accepted"). - Rejected → PASS only on exact match:
ok := (exp_code IS NOT NULL AND rc=exp_code) OR (exp_state IS NOT NULL AND st=exp_state)whererc=split_part(MESSAGE_TEXT,' |',1),st=RETURNED_SQLSTATE. An unexpected exception cannot match →pass=false. c1_test_results.case_nois PRIMARY KEY (duplicate/missing case caught); result INSERTs are OUTSIDE the inner exception wrapper, so an insert failure propagates and aborts P5.
The 9 expected signals (each case → exact expected)
| # | label | expected |
|---|---|---|
| 1 | missing operation_code | reject_code C1_REJ_MISSING_CODE |
| 2 | duplicate operation_code | SQLSTATE 23505 (unique_violation) |
| 3 | empty title | C1_REJ_EMPTY_TITLE |
| 4 | invalid operation_group | C1_REJ_INVALID_GROUP |
| 5 | missing required_inputs | C1_REJ_MISSING_REQUIRED_INPUTS |
| 6 | bad expected_outputs (object) | C1_REJ_BAD_EXPECTED_OUTPUTS |
| 7 | unknown allowed mode | C1_REJ_UNKNOWN_MODE |
| 8 | write official dot_tools (isolation) |
SQLSTATE 42P01 (undefined_table) |
| 9 | mark production-ready | C1_REJ_PRODUCTION_READY_FORBIDDEN |
FATAL postcondition (after COMMIT; ON_ERROR_STOP=1 → psql exit 3)
IF total<>9 THEN RAISE 'P5_FATAL_CASE_COUNT'; END IF;
IF accepted<>0 THEN RAISE 'P5_FATAL_BAD_ACCEPTED'; END IF; -- fail-open guard
IF failed<>0 THEN RAISE 'P5_FATAL_SIGNAL_MISMATCH'; END IF; -- unexpected exception guard
IF passed<>9 THEN RAISE 'P5_FATAL_PASS_COUNT'; END IF;
IF residue<>3 THEN RAISE 'P5_FATAL_RESIDUE'; END IF;
On any failure psql exits nonzero → the bin wrapper (set -euo pipefail) never prints P5_DONE → the plan aborts and the EXIT trap drops the sandbox.
Read-only verification of oracle assumptions (no sandbox, no write)
- PostgreSQL short-circuits the trigger's
ORchain:SELECT true OR (jsonb_array_length('null'::jsonb)<1)→true; case5/case6 boolean exprs evaluate totruewithout raising → cases 5/6 reachC1_REJ_MISSING_REQUIRED_INPUTS/C1_REJ_BAD_EXPECTED_OUTPUTS(not a jsonb error). split_part('C1_REJ_… | …',' |',1)→ the reject code (verified for cases 1 and 9).
Honest caveat: the exact runtime reject_code/SQLSTATE of all 9 cases is statically derived (against the deployed trigger/constraint logic) and read-only-verified for the short-circuit + extraction mechanics; full runtime confirmation occurs during the Codex-R2-gated dry-run. If any expected signal were wrong, the FATAL gate fails closed (P5 aborts) — never a false PASS.
sha256 sql/p5-bad-input-harness.sql = 0658ba6260314ef293eb4c58d51f492a83e6ce86f427448ca116232fa4176146.