Skip to content

Commit f49a312

Browse files
avrabeclaude
andcommitted
feat(codegen): Kani harnesses for generated-code AADL contract preservation
Add three #[kani::proof] harnesses in crates/spar-codegen/tests/kani_contracts.rs that prove each codegen pass preserves the AADL source contract (spar's Logika-equivalent strategy: machine-checked proofs on the generated-code path). - prove_thread_period_preserved: for any Period p in (0, 1_000_000_000] ns, the emitted dispatch-metadata string round-trips back to exactly p (no truncation, no off-by-one) - prove_port_direction_preserved: Out→In connections produce complementary WIT setter+getter pairs; same-direction connections never produce a complementary pair (AADL §9 directionality contract) - prove_access_right_preserved: Access_Rights = Read_Only never produces &mut in the generated access shim; Read_Write always does (type-level read-only enforcement) Wire-up: add kani-harnesses feature flag to spar-codegen/Cargo.toml; extend CI Kani job to run each harness explicitly; add REQ-KANI-CODEGEN-001 + TEST-KANI-CODEGEN to artifacts YAML. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
1 parent fa983a9 commit f49a312

5 files changed

Lines changed: 418 additions & 3 deletions

File tree

.github/workflows/ci.yml

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -323,5 +323,13 @@ jobs:
323323
cargo kani setup
324324
- name: Run Kani on spar-solver
325325
run: cargo kani --tests -p spar-solver
326-
- name: Run Kani on spar-codegen
327-
run: cargo kani --tests -p spar-codegen
326+
- name: Run Kani on spar-codegen (schedule harness)
327+
run: cargo kani --tests -p spar-codegen --harness kani_emit_preserves_schedule
328+
- name: Run Kani on spar-codegen (AADL contract harnesses)
329+
# prove_thread_period_preserved — period round-trip (no truncation)
330+
# prove_port_direction_preserved — WIT direction token mapping
331+
# prove_access_right_preserved — Read_Only never widens to &mut
332+
run: >-
333+
cargo kani --tests -p spar-codegen --harness prove_thread_period_preserved &&
334+
cargo kani --tests -p spar-codegen --harness prove_port_direction_preserved &&
335+
cargo kani --tests -p spar-codegen --harness prove_access_right_preserved

artifacts/requirements.yaml

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -855,6 +855,27 @@ artifacts:
855855
- type: traces-to
856856
target: REQ-CODEGEN-001
857857

858+
- id: REQ-KANI-CODEGEN-001
859+
type: requirement
860+
title: Kani harnesses for generated-code AADL contract preservation
861+
description: >
862+
Three Kani bounded model-checking harnesses in crates/spar-codegen/tests/
863+
kani_contracts.rs prove that each codegen pass preserves the AADL source
864+
contract: (1) thread Period is emitted without truncation or off-by-one
865+
(prove_thread_period_preserved), (2) port direction is faithfully mapped
866+
to the WIT interface token (prove_port_direction_preserved), (3) a
867+
bus-access feature with Access_Rights = Read_Only never generates a &mut
868+
reference (prove_access_right_preserved). This is spar's
869+
Logika-equivalent strategy: machine-checked proofs on the codegen output
870+
path rather than importing a new prover language.
871+
status: implemented
872+
tags: [codegen, kani, verification, v0100, safety]
873+
links:
874+
- type: traces-to
875+
target: REQ-CODEGEN-VERIFY-PROOF
876+
- type: traces-to
877+
target: REQ-CODEGEN-001
878+
858879
- id: REQ-SYSML2-PARSE
859880
type: requirement
860881
title: Parse SysML v2 textual notation (KerML grammar)

artifacts/verification.yaml

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -914,6 +914,39 @@ artifacts:
914914
- type: verifies
915915
target: REQ-CODEGEN-VERIFY-PROOF
916916

917+
- id: TEST-KANI-CODEGEN
918+
type: feature
919+
status: passing
920+
title: Kani — AADL contract preservation harnesses for codegen
921+
description: >
922+
Three #[kani::proof] harnesses in crates/spar-codegen/tests/kani_contracts.rs
923+
constitute spar's Logika-equivalent strategy for generated-code correctness.
924+
Each harness uses kani::any() + kani::assume() for symbolic inputs and
925+
asserts the postcondition that the codegen pass must satisfy:
926+
prove_thread_period_preserved — for any Period p in (0, 1_000_000_000] ns,
927+
the emitted dispatch-metadata string round-trips back to exactly p ns
928+
(no truncation, no off-by-one);
929+
prove_port_direction_preserved — Out source maps exclusively to a WIT setter
930+
and In sink to a WIT getter; a well-formed Out→In connection always produces
931+
a complementary setter+getter pair; same-direction features never produce a
932+
complementary pair;
933+
prove_access_right_preserved — Access_Rights = Read_Only never produces
934+
&mut in the generated access shim (read-only enforcement at the type level),
935+
and Read_Write always does.
936+
fields:
937+
method: formal-bounded
938+
steps:
939+
- run: cargo kani --tests -p spar-codegen --harness prove_thread_period_preserved
940+
- run: cargo kani --tests -p spar-codegen --harness prove_port_direction_preserved
941+
- run: cargo kani --tests -p spar-codegen --harness prove_access_right_preserved
942+
links:
943+
- type: satisfies
944+
target: REQ-KANI-CODEGEN-001
945+
- type: satisfies
946+
target: REQ-CODEGEN-VERIFY-PROOF
947+
- type: satisfies
948+
target: REQ-CODEGEN-001
949+
917950
- id: VAL-MUTATION-001
918951
type: feature
919952
status: pass

crates/spar-codegen/Cargo.toml

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,16 @@ harness = false
3131
[target.'cfg(kani)'.dev-dependencies]
3232
# `kani` is injected by cargo-kani; no version pin needed.
3333

34+
[features]
35+
# Enable the AADL-contract Kani harnesses in tests/kani_contracts.rs.
36+
# Under `cargo kani --tests`, the harnesses are compiled via the `#[cfg(kani)]`
37+
# cfg-guard (injected by the cargo-kani driver). This feature flag is a
38+
# no-op at runtime; it exists so `cargo build -p spar-codegen --features
39+
# kani-harnesses` can verify the harness module compiles under a normal
40+
# Rust toolchain without requiring the Kani driver.
41+
kani-harnesses = []
42+
3443
[lints.rust]
35-
# Permit the `#[cfg(kani)]` gates used by `tests/kani_codegen.rs`.
44+
# Permit the `#[cfg(kani)]` gates used by `tests/kani_codegen.rs` and
45+
# `tests/kani_contracts.rs`.
3646
unexpected_cfgs = { level = "warn", check-cfg = ['cfg(kani)'] }

0 commit comments

Comments
 (0)