Skip to content

Commit a7f3433

Browse files
docs(stance): add RUST-SPARK-STANCE (close P0 #127) (#48)
P0 #127 of the estate proof-debt epic. **Finding:** the audit's "ambientops SPARK theatre — `SPARK_Mode On`, zero contracts" is a **body-vs-spec miscount**. SPARK contracts live on `.ads` specs, not `.adb` bodies. Real coverage: `snapshot_manager.ads` 25, `safety_boundary.ads` 15, `safety_invariant.ads` 14, plus 5 more contracted specs. ambientops also already has the Idris2 ABI seam + Zig FFI + a `spark` build mode — it was *structurally compliant already*; only the **stance doc was missing**. **This PR:** adds `RUST-SPARK-STANCE.adoc` (mirrors the proof-of-work exemplar) with a contract-coverage matrix and honest gaps. **Genuine residuals (tracked, not theatre):** - `backend_interface.ads` — abstract interface, no `Pre'Class`/`Post'Class` → OWED proof obligation under standards#124/#127. - `reversibility_types.ads` — deliberate `SPARK_Mode (Off)`, documented in-file (Snapshot_ID name clash); honest deferral. Refs hyperpolymath/standards#124 Refs hyperpolymath/standards#127 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 263c8cc commit a7f3433

1 file changed

Lines changed: 125 additions & 0 deletions

File tree

RUST-SPARK-STANCE.adoc

Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
// SPDX-License-Identifier: PMPL-1.0-or-later
2+
= Rust/SPARK Stance — ambientops
3+
:toc: macro
4+
:toclevels: 2
5+
6+
toc::[]
7+
8+
== Summary
9+
10+
This monorepo's application logic is largely Rust (≈168 `.rs` files
11+
across `personal-sysadmin`, `czech-file-knife`, `contracts-rust`,
12+
`emergency-room/rust`, and other crates). Per the estate language policy
13+
(`standards/rhodium-standard-repositories/spec/LANGUAGE-POLICY.adoc`
14+
§Terminology), *"Rust" means "Rust/SPARK"*: Rust is a primary
15+
implementation language, but the project is *designed to admit
16+
SPARK/Ada verification modules* across a stable, Idris2-typed boundary,
17+
with Zig as the FFI layer. Rust here is never the ABI/API/FFI layer.
18+
19+
Unlike a bare-Rust crate, ambientops *already* satisfies the structural
20+
requirements of that policy and goes further than most estate repos:
21+
22+
* An Idris2 ABI seam exists (`src/abi/{Types,Layout,Foreign}.idr`, plus
23+
per-component `*/src/abi/` seams) with no dangerous patterns in the
24+
ABI layer — see `PROOF-NEEDS.md` and `ABI-FFI-README.md`.
25+
* A Zig FFI layer is present (`*/ffi/zig/`, `*/build.zig`).
26+
* Real, *non-theatrical* SPARK/Ada exists in
27+
`total-update/ada/dnfinition/` with a dedicated `spark` build mode in
28+
`dnfinition.gpr` (`BUILD_MODE=spark`) and proven subprogram contracts
29+
on the safety-critical specs.
30+
31+
This document is the project's compliance stance. The audit (2026-05-18)
32+
flagged ambientops as "`SPARK_Mode On`, zero contracts, no stance doc".
33+
That is **inaccurate on contracts** (see the coverage matrix below — the
34+
safety-critical specs are heavily contracted) and **correct on the
35+
stance doc** (this file was missing). The one genuine contract gap and
36+
one deliberate `SPARK_Mode (Off)` are documented honestly under
37+
<<Honest gaps>>.
38+
39+
== SPARK contract coverage (`total-update/ada/dnfinition/src`)
40+
41+
Contracts in SPARK live on the package *spec* (`.ads`), not the body
42+
(`.adb`); body files carrying zero `Pre/Post` is correct, not theatre.
43+
Spec-level coverage:
44+
45+
[cols="2,1,3",options="header"]
46+
|===
47+
| Spec | Contracts | Assessment
48+
49+
| `reversibility/snapshot_manager.ads` | 25 | Strong — pre/postconditions on snapshot lifecycle
50+
| `safety/safety_boundary.ads` | 15 | Strong — safety-boundary enforcement
51+
| `safety/safety_invariant.ads` | 14 | Strong — invariant preservation
52+
| `plugins/strategy_matrix.ads` | 5 | Adequate
53+
| `platform/platform_detection.ads` | 4 | Adequate
54+
| `backends/backend_guix.ads` | 3 | Adequate
55+
| `backends/backend_nix.ads` | 2 | Minimal but present
56+
| `plugins/plugin_registry.ads` | 1 | Weak — registration pre-only (OWED: strengthen)
57+
| `backends/backend_interface.ads` | 0 | **OWED** — abstract interface with no `Pre'Class`/`Post'Class` (see gaps)
58+
| `reversibility/reversibility_types.ads` | n/a | Deliberate `pragma SPARK_Mode (Off)` — documented in-file (Snapshot_ID name clash); not theatre
59+
|===
60+
61+
== What is correctness-critical here
62+
63+
ambientops manages host system operations (package transactions,
64+
reversibility/rollback, emergency intervention) where incorrect
65+
behaviour can destabilise the host. The proof-relevant surface, per
66+
`PROOF-NEEDS.md`:
67+
68+
[cols="1,3",options="header"]
69+
|===
70+
| Property | Where
71+
72+
| Rollback atomicity (failed op rolls back completely, no partial state)
73+
| `reversibility/snapshot_manager.ads` (contracted), `reversibility_types.ads`
74+
| Reversibility-operation idempotency
75+
| `safety/safety_invariant.ads`, emergency-room components
76+
| Privilege / scope containment (no operation escalates beyond declared scope)
77+
| `safety/safety_boundary.ads`
78+
| Backend transaction soundness (install/remove/upgrade contracts)
79+
| `backends/backend_*.ads` against the `backend_interface` contract
80+
|===
81+
82+
== The seam
83+
84+
[cols="1,3",options="header"]
85+
|===
86+
| Layer | Artifact
87+
88+
| ABI (Idris2) | `src/abi/{Types,Layout,Foreign}.idr` + per-component `*/src/abi/`
89+
| FFI (Zig) | `*/ffi/zig/`, `*/build.zig`
90+
| SPARK proof | `total-update/ada/dnfinition/` with `dnfinition.gpr` `BUILD_MODE=spark`; `gnatprove` is the discharge tool for the `.ads` contracts above
91+
|===
92+
93+
The Rust crates sit on the application side of this seam; they are never
94+
the ABI/FFI boundary, satisfying §"Rust is never the ABI".
95+
96+
[#honest-gaps]
97+
== Honest gaps
98+
99+
* *`backend_interface.ads` (OWED).* This is a pure abstract interface
100+
(`type Package_Manager_Backend is interface;`, ~20 `is abstract`
101+
primitives: `Install`, `Remove`, `Upgrade`, `Search`, …). It carries
102+
no class-wide contracts, so `gnatprove` cannot propagate obligations
103+
to the `backend_guix`/`backend_nix` implementations. Adding
104+
`Pre'Class`/`Post'Class` to the safety-relevant primitives (notably
105+
`Install`/`Remove`/`Upgrade` result states and `Is_Available`
106+
preconditions) is the principal remaining SPARK proof obligation.
107+
Tracked under `standards#124` / `#127`.
108+
* *`plugin_registry.ads` (weak).* One contract only; strengthen
109+
registration post-state. Lower priority than the interface.
110+
* *`reversibility_types.ads` is deliberately `SPARK_Mode (Off)`.* The
111+
in-file comment documents the reason (a record-component / type-name
112+
clash on `Rollback_Result.Snapshot_ID`); SPARK is re-enabled once a
113+
genuine proof obligation justifies resolving the clash. This is an
114+
honest, documented deferral — explicitly *not* the "theatre" pattern.
115+
* *`.claude/CLAUDE.md` language drift.* Any stale ReScript/Tauri/Deno
116+
table is superseded by the estate policy and this stance doc; reconcile
117+
separately.
118+
119+
== References
120+
121+
* `standards/rhodium-standard-repositories/spec/LANGUAGE-POLICY.adoc`
122+
§Terminology, §"Rust is never the ABI"
123+
* `PROOF-NEEDS.md` (this repo) — Idris2 proof obligations and priorities
124+
* `ABI-FFI-README.md` (this repo) — ABI/FFI architecture
125+
* Estate exemplar stance: `proof-of-work/RUST-SPARK-STANCE.adoc`

0 commit comments

Comments
 (0)