Skip to content

Commit c572d48

Browse files
fix(formal): make the local Coq assumptions gate capable of failing (#202)
fix(formal): make the local Coq assumptions gate capable of failing `just -f formal/Justfile check-assumptions` returned 0 whether or not anything compiled, so a green local proof gate was not evidence of a proof. Demonstrated by putting a stub `coqc` that exits 127 on PATH: $ PATH=/tmp/fakebin:$PATH just -f formal/Justfile check-planner coqc: not found OK(Planner): Q1-lite 3 theorems x 4 axioms whitelisted exit=0 Cause: every compile recipe was `coqc -q X.v | tee X.out`. A pipeline's exit status is its *last* command's, so `just` saw `tee`'s 0 and moved on; `coqc`'s diagnostics go to stderr, which `tee` never captures. The guard then ran awk over an empty `X.out`, found no axioms, and reported OK. Fixed by redirecting instead of piping: `coqc -q X.v > X.out`. The exit status is now `coqc`'s and `just` aborts the recipe. Note this is deliberately NOT fixed with `set shell := [... "pipefail" ...]`. The guards are shaped `awk | sort -u | grep -vE '<whitelist>' | { ... }`, and `grep -v` exits 1 precisely when it filters everything out — i.e. on the success path, where every axiom is whitelisted. Enabling pipefail would turn every passing check into a failure. `.github/workflows/coq-build.yml` already handles this correctly (`set -euo pipefail` *and* `|| true` on each grep), so CI was never affected; this was a local-only divergence. Also adds `Set Printing Width 400.` to all nine modules. Both the CI and Justfile guards match axiom names with `awk '/^[A-Za-z_][A-Za-z0-9_]* :/'`, which only fires when the name and its colon share a line. Coq wraps at ~78 columns and `Planner.out`'s longest line was **77** — one character from silently escaping the check. With the directive, statements print in full (Normalizer 75 -> 157, WAL 62 -> 127, Octad 62 -> 127, PlannerSemantic 74 -> 113, Drift 72 -> 95). To be precise about what this did and did not find: comparing the axiom names visible to the guard with and without the directive shows **no difference today**. Nothing was being hidden; this closes a latent escape before it opens, it does not fix an active one. Verified: with a broken `coqc` the gate now exits 127 ("recipe `planner` failed on line 29"); with the real coqc 8.20.1 all nine modules compile and `check-assumptions` exits 0 with 9/9 OK lines. `reuse lint` still compliant.
1 parent 9aef456 commit c572d48

10 files changed

Lines changed: 90 additions & 9 deletions

File tree

formal/Drift.v

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,15 @@
2727

2828
Require Import Coq.Init.Logic.
2929

30+
(* Keep Print Assumptions output on one line per axiom: the CI and Justfile
31+
guards match /^name :/ with awk, and Coq's default ~78-column wrap would
32+
split a longer axiom type across lines and silently escape the check. *)
33+
Set Printing Width 400.
34+
35+
(* Keep Print Assumptions output on one line per axiom: the CI and Justfile
36+
guards match /^name :/ with awk, and Coq's default ~78-column wrap would
37+
split a longer axiom type across lines and silently escape the check. *)
38+
3039
(** ** Domain *)
3140

3241
(** Opaque score type. In the Rust source this is [f64]. *)

formal/Justfile

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -17,31 +17,31 @@ all: provenance drift transaction planner wal normalizer vcl planner-semantic oc
1717
# --- Per-module compile recipes -------------------------------------------
1818

1919
provenance:
20-
{{COQC}} -q Provenance.v | tee Provenance.out
20+
{{COQC}} -q Provenance.v > Provenance.out
2121

2222
drift:
23-
{{COQC}} -q Drift.v | tee Drift.out
23+
{{COQC}} -q Drift.v > Drift.out
2424

2525
transaction:
26-
{{COQC}} -q Transaction.v | tee Transaction.out
26+
{{COQC}} -q Transaction.v > Transaction.out
2727

2828
planner:
29-
{{COQC}} -q Planner.v | tee Planner.out
29+
{{COQC}} -q Planner.v > Planner.out
3030

3131
wal:
32-
{{COQC}} -q WAL.v | tee WAL.out
32+
{{COQC}} -q WAL.v > WAL.out
3333

3434
normalizer:
35-
{{COQC}} -q Normalizer.v | tee Normalizer.out
35+
{{COQC}} -q Normalizer.v > Normalizer.out
3636

3737
vcl:
38-
{{COQC}} -q VCL.v | tee VCL.out
38+
{{COQC}} -q VCL.v > VCL.out
3939

4040
planner-semantic:
41-
{{COQC}} -q PlannerSemantic.v | tee PlannerSemantic.out
41+
{{COQC}} -q PlannerSemantic.v > PlannerSemantic.out
4242

4343
octad:
44-
{{COQC}} -q Octad.v | tee Octad.out
44+
{{COQC}} -q Octad.v > Octad.out
4545

4646
# --- Whitelist guards -----------------------------------------------------
4747
# Each module declares its own set of Parameters/Axioms; the guard greps

formal/Normalizer.v

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,15 @@
4747
Require Import Coq.Logic.FunctionalExtensionality.
4848
Require Import Coq.Bool.Bool.
4949

50+
(* Keep Print Assumptions output on one line per axiom: the CI and Justfile
51+
guards match /^name :/ with awk, and Coq's default ~78-column wrap would
52+
split a longer axiom type across lines and silently escape the check. *)
53+
Set Printing Width 400.
54+
55+
(* Keep Print Assumptions output on one line per axiom: the CI and Justfile
56+
guards match /^name :/ with awk, and Coq's default ~78-column wrap would
57+
split a longer axiom type across lines and silently escape the check. *)
58+
5059
(** ** Domain *)
5160

5261
Parameter modality : Type.

formal/Octad.v

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,15 @@
8989
Require Import Coq.Lists.List.
9090
Require Import Coq.Bool.Bool.
9191
Require Import Coq.Logic.FunctionalExtensionality.
92+
93+
(* Keep Print Assumptions output on one line per axiom: the CI and Justfile
94+
guards match /^name :/ with awk, and Coq's default ~78-column wrap would
95+
split a longer axiom type across lines and silently escape the check. *)
96+
Set Printing Width 400.
97+
98+
(* Keep Print Assumptions output on one line per axiom: the CI and Justfile
99+
guards match /^name :/ with awk, and Coq's default ~78-column wrap would
100+
split a longer axiom type across lines and silently escape the check. *)
92101
Import ListNotations.
93102

94103
(** ** [def:modset] — Modality Set

formal/Planner.v

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,15 @@
3232

3333
Require Import Coq.Lists.List.
3434
Require Import Coq.Sorting.Permutation.
35+
36+
(* Keep Print Assumptions output on one line per axiom: the CI and Justfile
37+
guards match /^name :/ with awk, and Coq's default ~78-column wrap would
38+
split a longer axiom type across lines and silently escape the check. *)
39+
Set Printing Width 400.
40+
41+
(* Keep Print Assumptions output on one line per axiom: the CI and Justfile
42+
guards match /^name :/ with awk, and Coq's default ~78-column wrap would
43+
split a longer axiom type across lines and silently escape the check. *)
3544
Import ListNotations.
3645

3746
(** ** Domain *)

formal/PlannerSemantic.v

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,15 @@
5050

5151
Require Import Coq.Lists.List.
5252
Require Import Coq.Sorting.Permutation.
53+
54+
(* Keep Print Assumptions output on one line per axiom: the CI and Justfile
55+
guards match /^name :/ with awk, and Coq's default ~78-column wrap would
56+
split a longer axiom type across lines and silently escape the check. *)
57+
Set Printing Width 400.
58+
59+
(* Keep Print Assumptions output on one line per axiom: the CI and Justfile
60+
guards match /^name :/ with awk, and Coq's default ~78-column wrap would
61+
split a longer axiom type across lines and silently escape the check. *)
5362
Import ListNotations.
5463

5564
(** ** Domain (reusing Planner.v abstractions) *)

formal/Provenance.v

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,15 @@
3535
*)
3636

3737
Require Import Coq.Lists.List.
38+
39+
(* Keep Print Assumptions output on one line per axiom: the CI and Justfile
40+
guards match /^name :/ with awk, and Coq's default ~78-column wrap would
41+
split a longer axiom type across lines and silently escape the check. *)
42+
Set Printing Width 400.
43+
44+
(* Keep Print Assumptions output on one line per axiom: the CI and Justfile
45+
guards match /^name :/ with awk, and Coq's default ~78-column wrap would
46+
split a longer axiom type across lines and silently escape the check. *)
3847
Import ListNotations.
3948

4049
(** ** Domain *)

formal/Transaction.v

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,15 @@
3838

3939
Require Import Coq.Init.Logic.
4040

41+
(* Keep Print Assumptions output on one line per axiom: the CI and Justfile
42+
guards match /^name :/ with awk, and Coq's default ~78-column wrap would
43+
split a longer axiom type across lines and silently escape the check. *)
44+
Set Printing Width 400.
45+
46+
(* Keep Print Assumptions output on one line per axiom: the CI and Justfile
47+
guards match /^name :/ with awk, and Coq's default ~78-column wrap would
48+
split a longer axiom type across lines and silently escape the check. *)
49+
4150
(** ** Domain *)
4251

4352
Inductive txn_state : Type :=

formal/VCL.v

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,15 @@
4343

4444
Require Import Coq.Init.Logic.
4545

46+
(* Keep Print Assumptions output on one line per axiom: the CI and Justfile
47+
guards match /^name :/ with awk, and Coq's default ~78-column wrap would
48+
split a longer axiom type across lines and silently escape the check. *)
49+
Set Printing Width 400.
50+
51+
(* Keep Print Assumptions output on one line per axiom: the CI and Justfile
52+
guards match /^name :/ with awk, and Coq's default ~78-column wrap would
53+
split a longer axiom type across lines and silently escape the check. *)
54+
4655
(** ** Syntax *)
4756

4857
Inductive ty : Type :=

formal/WAL.v

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,15 @@
4545

4646
Require Import Coq.Lists.List.
4747
Require Import Coq.Logic.FunctionalExtensionality.
48+
49+
(* Keep Print Assumptions output on one line per axiom: the CI and Justfile
50+
guards match /^name :/ with awk, and Coq's default ~78-column wrap would
51+
split a longer axiom type across lines and silently escape the check. *)
52+
Set Printing Width 400.
53+
54+
(* Keep Print Assumptions output on one line per axiom: the CI and Justfile
55+
guards match /^name :/ with awk, and Coq's default ~78-column wrap would
56+
split a longer axiom type across lines and silently escape the check. *)
4857
Import ListNotations.
4958

5059
(** ** Domain *)

0 commit comments

Comments
 (0)