1010 - " .github/workflows/spec-drift-guard.yml"
1111
1212# Rebuild t27c from upstream master and regenerate every committed backend
13- # under gen/<target>/wire .<ext> from specs/wire .t27. If any committed output
14- # disagrees with the freshly generated output, the job fails with a diff so
15- # drift between the SSOT and generated code cannot land silently.
13+ # under gen/<target>/<spec> .<ext> from specs/<spec> .t27. If any committed
14+ # output disagrees with the freshly generated output, the job fails with a
15+ # diff so drift between the SSOT and generated code cannot land silently.
1616#
17- # Covered backends:
18- # - Rust (t27c gen- rust) -> gen/rust/ wire.rs
19- # - Zig (t27c gen) -> gen/zig/wire .zig
20- # - C (t27c gen-c) -> gen/c/wire.c
17+ # Covered specs (3) × backends (3) = 9 drift checks :
18+ # wire.t27 → gen/{ rust,wire.rs} gen/{zig,wire.zig} gen/{c, wire.c}
19+ # hello.t27 → gen/{rust,hello.rs} gen/{ zig,hello .zig} gen/{c,hello.c}
20+ # etx.t27 → gen/{rust,etx.rs} gen/{zig,etx.zig} gen/{c,etx.c}
2121#
22- # ExprCast is lowered in all three via t27#1320 (Rust) and t27#1337 (Zig+C).
22+ # ExprCast is lowered in all three backends via t27#1320 (Rust) + t27#1337 (Zig+C).
2323# See docs/T27_FIRST_MIGRATION.md for the SSOT contract.
2424# Anchor: phi^2 + phi^-2 = 3.
2525
2626jobs :
2727 regenerate-and-diff :
28- name : regen gen/<target>/wire.* from specs/wire.t27
28+ name : drift check (3 specs × 3 backends)
2929 runs-on : ubuntu-latest
3030 steps :
3131 - name : Checkout tri-net
@@ -47,65 +47,53 @@ jobs:
4747 working-directory : t27
4848 run : cargo build --release --manifest-path bootstrap/Cargo.toml --bin t27c
4949
50- - name : Regenerate gen/rust/wire.rs
50+ - name : Drift check — Rust (all specs)
5151 working-directory : tri-net
5252 run : |
53- ../t27/target/release/t27c gen-rust specs/wire.t27 > /tmp/wire_regen.rs
54- echo "=== regenerated Rust head ==="
55- head -20 /tmp/wire_regen.rs
53+ T27C=../t27/target/release/t27c
54+ STATUS=0
55+ for spec in wire hello etx; do
56+ $T27C gen-rust specs/${spec}.t27 > /tmp/${spec}_regen.rs
57+ if ! diff -u gen/rust/${spec}.rs /tmp/${spec}_regen.rs; then
58+ echo "::error file=gen/rust/${spec}.rs::DRIFT: gen/rust/${spec}.rs != t27c gen-rust specs/${spec}.t27"
59+ echo "Fix: t27c gen-rust specs/${spec}.t27 > gen/rust/${spec}.rs"
60+ STATUS=1
61+ else
62+ echo "gen/rust/${spec}.rs matches specs/${spec}.t27"
63+ fi
64+ done
65+ exit $STATUS
5666
57- - name : Diff regenerated Rust vs committed
67+ - name : Drift check — Zig (all specs)
5868 working-directory : tri-net
5969 run : |
60- if ! diff -u gen/rust/wire.rs /tmp/wire_regen.rs; then
61- echo ""
62- echo "::error file=gen/rust/wire.rs::SPEC/GEN DRIFT (Rust): gen/rust/wire.rs disagrees with freshly regenerated output from specs/wire.t27."
63- echo ""
64- echo "Fix: rebuild t27c from t27 master, then run"
65- echo " t27c gen-rust specs/wire.t27 > gen/rust/wire.rs"
66- echo "See docs/T27_FIRST_MIGRATION.md for the full regeneration recipe."
67- exit 1
68- fi
69- echo "gen/rust/wire.rs matches specs/wire.t27 -> t27c gen-rust output. No drift."
70+ T27C=../t27/target/release/t27c
71+ STATUS=0
72+ for spec in wire hello etx; do
73+ $T27C gen specs/${spec}.t27 > /tmp/${spec}_regen.zig
74+ if ! diff -u gen/zig/${spec}.zig /tmp/${spec}_regen.zig; then
75+ echo "::error file=gen/zig/${spec}.zig::DRIFT: gen/zig/${spec}.zig != t27c gen specs/${spec}.t27"
76+ echo "Fix: t27c gen specs/${spec}.t27 > gen/zig/${spec}.zig"
77+ STATUS=1
78+ else
79+ echo "gen/zig/${spec}.zig matches specs/${spec}.t27"
80+ fi
81+ done
82+ exit $STATUS
7083
71- - name : Regenerate gen/zig/wire.zig
84+ - name : Drift check — C (all specs)
7285 working-directory : tri-net
7386 run : |
74- ../t27/target/release/t27c gen specs/wire.t27 > /tmp/wire_regen.zig
75- echo "=== regenerated Zig head ==="
76- head -20 /tmp/wire_regen.zig
77-
78- - name : Diff regenerated Zig vs committed
79- working-directory : tri-net
80- run : |
81- if ! diff -u gen/zig/wire.zig /tmp/wire_regen.zig; then
82- echo ""
83- echo "::error file=gen/zig/wire.zig::SPEC/GEN DRIFT (Zig): gen/zig/wire.zig disagrees with freshly regenerated output from specs/wire.t27."
84- echo ""
85- echo "Fix: rebuild t27c from t27 master, then run"
86- echo " t27c gen specs/wire.t27 > gen/zig/wire.zig"
87- echo "See docs/T27_FIRST_MIGRATION.md for the full regeneration recipe."
88- exit 1
89- fi
90- echo "gen/zig/wire.zig matches specs/wire.t27 -> t27c gen output. No drift."
91-
92- - name : Regenerate gen/c/wire.c
93- working-directory : tri-net
94- run : |
95- ../t27/target/release/t27c gen-c specs/wire.t27 > /tmp/wire_regen.c
96- echo "=== regenerated C head ==="
97- head -20 /tmp/wire_regen.c
98-
99- - name : Diff regenerated C vs committed
100- working-directory : tri-net
101- run : |
102- if ! diff -u gen/c/wire.c /tmp/wire_regen.c; then
103- echo ""
104- echo "::error file=gen/c/wire.c::SPEC/GEN DRIFT (C): gen/c/wire.c disagrees with freshly regenerated output from specs/wire.t27."
105- echo ""
106- echo "Fix: rebuild t27c from t27 master, then run"
107- echo " t27c gen-c specs/wire.t27 > gen/c/wire.c"
108- echo "See docs/T27_FIRST_MIGRATION.md for the full regeneration recipe."
109- exit 1
110- fi
111- echo "gen/c/wire.c matches specs/wire.t27 -> t27c gen-c output. No drift."
87+ T27C=../t27/target/release/t27c
88+ STATUS=0
89+ for spec in wire hello etx; do
90+ $T27C gen-c specs/${spec}.t27 > /tmp/${spec}_regen.c
91+ if ! diff -u gen/c/${spec}.c /tmp/${spec}_regen.c; then
92+ echo "::error file=gen/c/${spec}.c::DRIFT: gen/c/${spec}.c != t27c gen-c specs/${spec}.t27"
93+ echo "Fix: t27c gen-c specs/${spec}.t27 > gen/c/${spec}.c"
94+ STATUS=1
95+ else
96+ echo "gen/c/${spec}.c matches specs/${spec}.t27"
97+ fi
98+ done
99+ exit $STATUS
0 commit comments