Summary
Grounding the "different faces, same cube" claim against a fresh build (the invariant-path faces profile + verify-same-cube.sh) shows the six faces do not produce byte-identical typed-wasm for the same program. They split into two classes because the face transformers disagree on how to lower a block's trailing statement (statement { println(x); } vs tail-expression { println(x) }).
Evidence
Corpus: one program (greet) written in every face — identical strings and structure (invariant-path/examples/same-cube/greet/). Built affinescript at HEAD (full suite 457 tests green; tools/run_face_transformer_tests.sh 6/6 green), compiled each face with compile --face <face>, sha256'd the wasm:
| wasm class |
faces |
trailing call lowered as |
56c454be… |
canonical, jaffa, cafe |
statement { println(x); } |
2ff63dd1… |
rattle, pseudo, lucid |
tail-expression { println(x) } |
preview-python (etc.) confirms it: it emits fn main() -{IO}-> () { println("…") } (no trailing ;), while the canonical reference has { println("…"); }.
Impact
- For a unit-returning trailing call (e.g.
println : … -> ()) the two lowerings are observationally identical (same effects, same unit return) — machine-checked in invariant-path/proofs/SameCube.agda (agda --safe, no postulates). So today's examples still behave the same.
- For a value-returning trailing expression they genuinely diverge: the statement form discards the value and returns
(), the tail-expression form returns the value. A face that lowers { …; lastExpr } as a statement would silently change the block's value/type — a real latent correctness gap, not a cosmetic wasm difference.
Suggested fix
Pick one trailing-statement convention and make all lib/<face>_face.ml transformers agree. Most faithful to AffineScript's expression-oriented blocks: preserve the tail expression (the rattle/pseudo/lucid behaviour), inserting ; only for genuine non-tail statements. Then the same-cube verifier collapses to one wasm class and byte-level same-cube holds.
Repro
# in invariant-path, with affinescript built at ../affinescript/_build:
just same-cube # scripts/verify-same-cube.sh examples/same-cube/greet
just proofs # agda --safe proofs/SameCube.agda
Found while grounding the faces work (invariant-path#33, affinescript#600).
🤖 Filed via Claude Code — https://claude.ai/code/session_01KPG9mEQXFyA3k7NWAzMNMr
Summary
Grounding the "different faces, same cube" claim against a fresh build (the
invariant-pathfacesprofile +verify-same-cube.sh) shows the six faces do not produce byte-identical typed-wasm for the same program. They split into two classes because the face transformers disagree on how to lower a block's trailing statement (statement{ println(x); }vs tail-expression{ println(x) }).Evidence
Corpus: one program (
greet) written in every face — identical strings and structure (invariant-path/examples/same-cube/greet/). Built affinescript at HEAD (full suite 457 tests green;tools/run_face_transformer_tests.sh6/6 green), compiled each face withcompile --face <face>, sha256'd the wasm:56c454be…{ println(x); }2ff63dd1…{ println(x) }preview-python(etc.) confirms it: it emitsfn main() -{IO}-> () { println("…") }(no trailing;), while the canonical reference has{ println("…"); }.Impact
println : … -> ()) the two lowerings are observationally identical (same effects, same unit return) — machine-checked ininvariant-path/proofs/SameCube.agda(agda --safe, no postulates). So today's examples still behave the same.(), the tail-expression form returns the value. A face that lowers{ …; lastExpr }as a statement would silently change the block's value/type — a real latent correctness gap, not a cosmetic wasm difference.Suggested fix
Pick one trailing-statement convention and make all
lib/<face>_face.mltransformers agree. Most faithful to AffineScript's expression-oriented blocks: preserve the tail expression (the rattle/pseudo/lucid behaviour), inserting;only for genuine non-tail statements. Then the same-cube verifier collapses to one wasm class and byte-level same-cube holds.Repro
Found while grounding the faces work (invariant-path#33, affinescript#600).
🤖 Filed via Claude Code — https://claude.ai/code/session_01KPG9mEQXFyA3k7NWAzMNMr