This file was generated by
rivet init --agents. Re-run the command any time artifacts change to keep this file current.
This project uses Rivet for SDLC artifact traceability.
- Config:
rivet.yaml - Schemas: common, stpa, aspice, dev
- Artifacts: 213 across 11 types
- Validation:
rivet validate(current status: pass)
| Command | Purpose | Example |
|---|---|---|
rivet validate |
Check link integrity, coverage, required fields | rivet validate --format json |
rivet list |
List artifacts with filters | rivet list --type requirement --format json |
rivet stats |
Show artifact counts by type | rivet stats --format json |
rivet add |
Create a new artifact | rivet add -t requirement --title "..." --link "satisfies:SC-1" |
rivet link |
Add a link between artifacts | rivet link SOURCE -t satisfies --target TARGET |
rivet serve |
Start the dashboard | rivet serve --port 3000 |
rivet export |
Generate HTML reports | rivet export --format html --output ./dist |
rivet impact |
Show change impact | rivet impact --since HEAD~1 |
rivet coverage |
Show traceability coverage | rivet coverage --format json |
rivet diff |
Compare artifact versions | rivet diff --base path/old --head path/new |
| Type | Count | Description |
|---|---|---|
control-action |
26 | An action issued by a controller to a controlled process or another controller. |
controlled-process |
5 | A process being controlled — the physical or data transformation acted upon by controllers. |
controller |
7 | A system component (human or automated) responsible for issuing control actions. Each controller has a process model — its internal beliefs about the state of the controlled process. |
controller-constraint |
45 | A constraint on a controller's behavior derived by inverting a UCA. Specifies what the controller must or must not do. |
hazard |
10 | A system state or set of conditions that, together with worst-case environmental conditions, will lead to a loss. |
loss |
5 | An undesired or unplanned event involving something of value to stakeholders. Losses define what the analysis aims to prevent. |
loss-scenario |
21 | A causal pathway describing how a UCA could occur or how the control action could be improperly executed, leading to a hazard. |
requirement |
27 | A functional or non-functional requirement |
sub-hazard |
10 | A refinement of a hazard into a more specific unsafe condition. |
system-constraint |
12 | A condition or behavior that must be satisfied to prevent a hazard. Each constraint is the inversion of a hazard. |
uca |
45 | An Unsafe Control Action — a control action that, in a particular context and worst-case environment, leads to a hazard. Four types (provably complete): 1. Not providing the control action leads to a hazard 2. Providing the control action leads to a hazard 3. Providing too early, too late, or in the wrong order 4. Control action stopped too soon or applied too long |
design-decision |
0 | An architectural or design decision with rationale |
feature |
0 | A user-visible capability or feature |
stakeholder-req |
0 | Stakeholder requirement (SYS.1) |
sw-arch-component |
0 | Software architectural element (SWE.2) |
sw-detail-design |
0 | Software detailed design or unit specification (SWE.3) |
sw-integration-verification |
0 | Software component and integration verification measure (SWE.5 — Software Component Verification and Integration Verification) |
sw-req |
0 | Software requirement (SWE.1) |
sw-verification |
0 | Software verification measure against SW requirements (SWE.6 — Software Verification) |
sys-integration-verification |
0 | System integration and integration verification measure (SYS.4 — System Integration and Integration Verification) |
sys-verification |
0 | System verification measure against system requirements (SYS.5 — System Verification) |
system-arch-component |
0 | System architectural element (SYS.3) |
system-req |
0 | System requirement derived from stakeholder needs (SYS.2) |
unit-verification |
0 | Unit verification measure (SWE.4 — Software Unit Verification) |
verification-execution |
0 | A verification execution run against a specific version |
verification-verdict |
0 | Pass/fail verdict for a single verification measure in an execution run |
- Artifacts are stored as YAML files in:
safety/stpa,safety/requirements - Schema definitions:
schemas/directory - Documents:
docs
rivet add -t requirement --title "New requirement" --status draft --link "satisfies:SC-1"Always run rivet validate after modifying artifact YAML files.
Use rivet validate --format json for machine-readable output.
| Link Type | Description | Inverse |
|---|---|---|
acts-on |
Control action acts on a process or controller | acted-on-by |
allocated-to |
Source is allocated to the target (e.g. requirement to architecture component) | allocated-from |
caused-by-uca |
Loss scenario is caused by an unsafe control action | causes-scenario |
constrained-by |
Source is constrained by the target | constrains |
constrains-controller |
Constraint applies to a specific controller | controller-constrained-by |
depends-on |
Source depends on target being completed first | depended-on-by |
derives-from |
Source is derived from the target | derived-into |
implements |
Source implements the target | implemented-by |
inverts-uca |
Controller constraint inverts (is derived from) an UCA | inverted-by |
issued-by |
Control action or UCA is issued by a controller | issues |
leads-to-hazard |
UCA or loss scenario leads to a hazard | hazard-caused-by |
leads-to-loss |
Hazard leads to a specific loss | loss-caused-by |
mitigates |
Source mitigates or prevents the target | mitigated-by |
part-of-execution |
Verification verdict belongs to a verification execution run | contains-verdict |
prevents |
Constraint prevents a hazard | prevented-by |
refines |
Source is a refinement or decomposition of the target | refined-by |
result-of |
Verification verdict is the result of executing a verification measure | has-result |
satisfies |
Source satisfies or fulfils the target | satisfied-by |
traces-to |
General traceability link between any two artifacts | traced-from |
verifies |
Source verifies or validates the target | verified-by |
- Artifact IDs follow the pattern: PREFIX-NNN (e.g., REQ-001, FEAT-042)
- Use
rivet addto create artifacts (auto-generates next ID) - Always include traceability links when creating artifacts
- Run
rivet validatebefore committing
This project enforces commit-to-artifact traceability.
Required git trailers:
trace-> maps to link typeTrace
To skip traceability for a commit, add: Trace: skip
The content below is NOT auto-generated by rivet. Preserve it during
rivet init --agentsregeneration. If the tool overwrites this section, restore it from git history.
Meld is a static component fusion tool for WebAssembly. It takes composed P2/P3 components and fuses them into a single core wasm module, eliminating the need for runtime linking.
Part of the pulseengine toolchain:
- loom — WebAssembly optimizer (formally verified)
- meld — Static component fuser (this tool)
# Build all crates
cargo build
# Build release
cargo build --release
# Run tests
cargo test
# Run specific test
cargo test --package meld-core test_name
# Run CLI
cargo run --bin meld -- fuse input.wasm -o output.wasm
# Build for WASM target
cargo build --target wasm32-wasip2 --profile release-wasm# Build all targets
bazel build //...
# Build specific target
bazel build //meld-cli:meld
# Run tests
bazel test //...
# Build with release config
bazel build --config=release //meld-cli:meldmeld/
├── meld-core/ # Core fusion library
│ ├── src/
│ │ ├── lib.rs # Public API
│ │ ├── parser.rs # Component parsing (wasmparser)
│ │ ├── resolver.rs # Dependency resolution
│ │ ├── merger.rs # Module merging
│ │ ├── adapter/ # Adapter generation
│ │ │ ├── mod.rs # Trait interface
│ │ │ └── fact.rs # FACT-style implementation
│ │ ├── error.rs # Error types (thiserror)
│ │ └── attestation.rs # wsc-attestation integration
│ └── Cargo.toml
├── meld-cli/ # CLI binary
│ ├── src/main.rs
│ └── Cargo.toml
└── rules/ # Bazel rules (for rules_wasm_component)
├── meld.bzl # meld_fuse() rule
└── providers.bzl
P2/P3 Components → Parser → Resolver → Merger → Adapter Gen → Single Module
- Parser: Extracts core modules and type info from components
- Resolver: Builds import/export graph, topological sort
- Merger: Combines function/memory/table/global spaces
- Adapter Gen: Creates Canonical ABI trampolines for cross-component calls
- Multi-memory (default): Each component keeps its own linear memory.
Cross-component calls that pass pointers use adapters that allocate in
the callee's memory via
cabi_realloc, copy data withmemory.copy, call the target, and copy results back. Requires WebAssembly multi-memory (Core Spec 3.0, supported by wasmtime/Chrome/Firefox). - Shared memory (legacy): All components share a single linear memory.
Simpler but broken when any component uses
memory.grow, because one component's growth corrupts every other component's address space. Use--memory sharedto opt in.
- Error Handling: Use
anyhowfor CLI,thiserrorfor library errors - Testing: Property-based tests with
proptestfor core logic - Documentation: Doc comments on all public APIs
- Logging: Use
logcrate, configure viaRUST_LOGenv var
meld-core/src/parser.rs— Component binary parsingmeld-core/src/resolver.rs— Import/export resolutionmeld-core/src/merger.rs— Module merging logicmeld-core/src/rewriter.rs— Instruction rewriting (index remapping)meld-core/src/adapter/mod.rs— Adapter trait definitionmeld-core/src/adapter/fact.rs— FACT-style adapter generationmeld-core/src/segments.rs— Data/element segment handlingmeld-cli/src/main.rs— CLI entry point
Track transformation provenance through fusion. Add attestation to output module's custom section.
Output is optimizable by LOOM. Use LOOM after meld for whole-program optimization:
meld fuse a.wasm b.wasm -o fused.wasm
loom optimize fused.wasm -o optimized.wasmBazel rule integration via meld_fuse():
load("@meld//rules:meld.bzl", "meld_fuse")
meld_fuse(
name = "fused",
components = [":component_a", ":component_b"],
)# All tests (unit + integration)
cargo test
# Specific integration test
cargo test --test cross_component_call
cargo test --test multi_memory
cargo test --test rebasing_end_to_end
# Specific unit test
cargo test --package meld-core test_name# Validate output
wasm-tools validate fused.wasm
# Print structure
wasm-tools print fused.wasm | head -50
# Component info
wasm-tools component wit input.wasmKani/CBMC runs out of memory on code that exercises std::io (BufReader,
BorrowedBuf), rich Vec manipulation, or deep generic trait dispatch. When a
Kani harness OOMs, that is NOT evidence the property holds — it is evidence
the tool cannot reach the property. Fall back to the nearest lower-level
Kani proof on the primitives the code composes, and document the limitation
in the finding report.
This project uses Rocq 9.0 (formerly Coq) for formal verification of the fusion
pipeline. Proofs are built via Bazel using rules_rocq_rust, which provides
both the Rocq toolchain and rocq-of-rust for Rust-to-Rocq translation.
Rocq 9.0 introduced significant naming changes. The codebase uses the new conventions:
(* OLD Coq 8.x style - DO NOT USE *)
From Coq Require Import List ZArith.
(* NEW Rocq 9.0 style - USE THIS *)
From Stdlib Require Import List ZArith Lia Arith.Many lemmas were renamed to follow a consistent property_type pattern:
| Old Name (8.x) | New Name (9.0) |
|---|---|
app_length |
length_app |
map_length |
length_map |
app_nil_r |
app_nil_r (same) |
app_assoc |
app_assoc (same) |
fold_left_app |
fold_left_app |
nth_error_None |
nth_error_None |
nth_error_Some |
nth_error_Some |
in_map_iff |
in_map_iff |
in_seq |
in_seq |
# Build all proofs
bazel build //proofs:all_proofs
# Run a specific proof test (note: tagged 'manual')
bazel test //proofs:parser_proofs_test
# Build Rust-translated proofs
bazel build //proofs/rust_verified:merger_core_proofsNote: Proof builds require Nix for the hermetic Rocq toolchain.
-
lia(Linear Integer Arithmetic): Solves goals involving linear arithmetic over integers/naturals. Use for bounds, inequalities, and simple arithmetic.Proof. intros. lia. Qed.
-
nia(Nonlinear Integer Arithmetic): Extendsliawith limited nonlinear support. More powerful but slower. -
omega: Deprecated in Rocq 9.0. Useliainstead.
-
auto: Basic proof search using hint databases. Fast but limited.auto with arith. (* Use arithmetic hints *)
-
eauto: Likeautobut handles existentials. Useeauto with *for aggressive search. -
intuition: Propositional logic solver. Combinesautowith logical decomposition.intuition lia. (* Decompose then solve arithmetic *) -
tauto: Pure propositional tautology checker. Fast and complete for propositional goals. -
firstorder: First-order logic prover. Powerful but can be slow.firstorder auto. (* First-order with auto fallback *)
From MODULE.bazel, the following Rocq extensions are available:
- rocq_stdlib: Standard library (Lists, Arith, ZArith, etc.)
- rocq_coqutil: Utility library with tactics and definitions
- rocq_hammer: Automated theorem prover integration (for hard goals)
- rocq_smpl: Simplification tactics
-
Use sections for local assumptions:
Section MergeCorrectness. Variable input : merge_input. Hypothesis Hwf : well_formed input. Lemma helper1 : ... . Lemma helper2 : ... . Theorem main : ... . End MergeCorrectness.
-
Break into helper lemmas: Each file in
proofs/contains multiple lemmas building toward main theorems.
-
assert (H: P): ProvePfirst, then useHin the main goal. Most common pattern.assert (Hbound: x < length l). { (* prove bound *) lia. } (* now use Hbound *) -
enough (H: P): AssumeH, prove main goal, then proveH. Use whenHmakes the main goal obvious.enough (Heq: x = y). { subst. reflexivity. } (* now prove x = y *) -
cut P: Likeassertbut leaves goals in reverse order. Rarely needed; preferassert.
When induction needs a stronger hypothesis, use revert to generalize:
(* BAD: IH is too weak *)
Lemma fold_monotonic : forall l base,
base <= fold_left f l base.
Proof.
induction l. (* IH only works for specific base *)
...
(* GOOD: revert makes IH general *)
Lemma fold_monotonic : forall l base,
base <= fold_left f l base.
Proof.
induction l; intro base. (* IH works for all base values *)
- simpl. lia.
- simpl. apply IH. (* Can apply to any base *)
Qed.See proofs/transformations/merge/merge_layout.v for examples of this pattern
in fold_left_add_nonneg_ge and related lemmas.
-
set (x := expr): Name a subexpression without generating equality. Good for readability.set (offset := compute_offset input space mod_idx).
-
remember expr as x eqn:Heq: Name subexpression AND generate equality hypothesis. Use when you need to unfold later.remember (j - i) as diff eqn:Hdiff.
Rust code is translated to Rocq via coq_of_rust_library rules. See
proofs/rust_verified/BUILD.bazel:
coq_of_rust_library(
name = "merger_core_translated",
rust_sources = ["merger_core.rs"],
edition = "2021",
)
rocq_library(
name = "merger_core",
srcs = [":merger_core_translated"],
deps = [":rocq_of_rust_lib"],
include_path = "meld",
extra_flags = ["-impredicative-set"],
)The translated code uses the rocq-of-rust runtime library. Proofs then bridge between the translated Rust and pure-model specifications.
lia cannot reason about fold_left directly. Abstract the term first:
(* BAD: lia fails *)
Lemma bad : forall l, 0 <= fold_left (fun a x => a + x) l 0.
Proof. intros. lia. (* FAILS *) Abort.
(* GOOD: use a helper lemma *)
Lemma fold_left_nonneg : forall l base,
base <= fold_left (fun a x => a + x) l base.
Proof.
induction l; intro base; simpl.
- lia.
- specialize (IHl (base + a)). lia.
Qed.
Lemma good : forall l, 0 <= fold_left (fun a x => a + x) l 0.
Proof. intros. apply fold_left_nonneg. Qed.See proofs/transformations/merge/merge_layout.v:fold_left_add_nonneg_ge.
Boolean && is left-associative. When matching on complex conditions:
(* The expression ((A && B) && C) && D *)
apply Bool.andb_true_iff in H.
destruct H as [H123 H4]. (* Split off D *)
apply Bool.andb_true_iff in H123.
destruct H123 as [H12 H3]. (* Split off C *)
apply Bool.andb_true_iff in H12.
destruct H12 as [H1 H2]. (* Split A and B *)If induction gives a weak hypothesis, generalize more variables:
(* Weak: IH only for fixed values *)
induction l.
(* Strong: generalize auxiliary variables *)
generalize dependent aux_var.
induction l; intros aux_var.
(* Or use revert before induction *)
revert aux_var.
induction l.Converting between In and nth_error:
(* In -> nth_error *)
apply In_nth_error in Hin.
destruct Hin as [i Hi].
(* nth_error -> In *)
apply nth_error_In in Hnth.
(* Checking bounds *)
apply nth_error_Some. rewrite H. discriminate.
apply nth_error_None in H. (* H : i >= length l *)All proofs across the entire proofs/ directory are fully closed (Qed).
There are zero Admitted theorems, zero admit tactics, and zero
Axiom declarations. If you add new proofs, aim to close them fully.
| Proofs path | Source path | Focus |
|---|---|---|
proofs/parser/ |
meld-core/src/parser.rs |
Parsing and decoding |
proofs/resolver/ |
meld-core/src/resolver.rs |
Import/export resolution |
proofs/merger/ |
meld-core/src/merger.rs |
Index-space merging |
proofs/adapter/ |
meld-core/src/adapter/ |
Canonical ABI adapters |
proofs/rewriter/ |
meld-core/src/rewriter.rs |
Rewrite passes |
proofs/segments/ |
meld-core/src/segments.rs |
Segment layout |
proofs/attestation/ |
meld-core/src/attestation.rs |
Attestation integrity |
proofs/rust_verified/ |
(special) | Rust-to-Rocq translated proofs |
proofs/spec/ |
(specifications) | Core spec definitions |
proofs/transformations/ |
(specs for transforms) | Transform correctness specs |
From proofs/DECISIONS.md:
- Core spec: WebAssembly Core Specification, Release 3.0
- Component Model: Commit
deb0b0a - WASI: v0.2.3 WIT definitions
-
Start with the spec: Define what correctness means in
proofs/spec/orproofs/transformations/before proving. -
Use pure-model definitions: Mirror Rust implementation in a simpler form (see
merger_core_proofs.vfor examples). -
Build incrementally: Small lemmas compose into theorems.
-
Leverage automation: Try
auto,eauto,liaearly. Useintuitionfor propositional goals. -
Document admitted proofs: Explain why and what's needed to complete.
-
Human readability: All lemmas, theorems, and proof structures must be human readable and understandable. Proofs should be written so that a developer can follow the logical reasoning without needing to step through tactics interactively. Prefer explicit structure over tactic magic:
- Use meaningful names for hypotheses (
Hbound,Hvalid, notH1,H2) - Add comments for non-obvious proof steps
- Break complex proofs into named helper lemmas
- Avoid deeply nested bullet structures (max 3-4 levels)
- When using
admit, document what remains to be proven
- Use meaningful names for hypotheses (
Mythos-style agentic bug hunting is wired into this repo. Prompts, rubric,
and the portable HOWTO live in scripts/mythos/:
rank.md— file ranking (1–5) by bug likelihood, meld-specific rubricdiscover.md— per-file discovery prompt with oracle requirementvalidate.md— fresh-session confirmation (rejects hallucinations)emit.md— converts confirmed findings todraft LS-Nentries insafety/stpa/loss-scenarios.yaml, grouped under existing UCAs (UCA IDs use controller-prefixed form:UCA-P-Nfor parser,UCA-M-Nfor merger, etc.)HOWTO.md— portable pipeline documentation (same across all PulseEngine repos)
A failing PoC test is ALWAYS required for a confirmed finding — this is the deterministic oracle. A failing Kani harness is required unless the subject code exercises a symbolic surface CBMC cannot handle (see Kani scope limitation above); in that case, cite the nearest primitive-layer Kani proof and document the limitation. Hallucinations are more expensive than silence. If neither oracle can be produced, the finding does not count — do not report it.
Before creating a release tag, run a Mythos delta pass scoped by release type:
| Release | Scope |
|---|---|
| Patch (x.y.Z) | Tier-5 files changed since last tag |
| Minor (x.Y.z) | Tier-5 + tier-4 files changed since last tag |
| Major / LTS | Full tier-5 sweep regardless of diff |
Procedure:
# Identify changed tier-5 files (meld-core parser / fusion / types / writer)
git diff --name-only v<last>..HEAD -- \
meld-core/src/parser.rs \
meld-core/src/merger.rs \
'meld-core/src/fuse/**' \
'meld-core/src/fusion/**' \
'meld-core/src/types/**' \
'meld-core/src/type_check/**' \
'meld-core/src/writer.rs' \
'meld-core/src/emit/**'For each file, in a fresh Claude Code session:
Read scripts/mythos/discover.md and apply it to <file>. Do not relax the
oracle requirement.
For each finding, fresh session: Read scripts/mythos/validate.md and apply it to the report above.
Block the release if any confirmed finding lacks an approved LS-N in
safety/stpa/loss-scenarios.yaml with a shipped fix or an explicit
risk-acceptance note.
- All changes via PR: Never push directly to main for any code changes
- CI must pass completely: Wait for ALL CI jobs to succeed before merging
- Watch the full CI run: Do not assume CI passes — verify it
- Mythos delta pass: Run per
### Pre-Release Mythos delta passabove. Zeroconfirmedfindings, OR everyconfirmedfinding maps to anapproved LS-Ninsafety/stpa/loss-scenarios.yamlwith a shipped fix
-
Create version bump PR:
git checkout -b release/vX.Y.Z # Update version in Cargo.toml # Update internal dependency versions git commit -m "chore: bump version to X.Y.Z" git push -u origin release/vX.Y.Z gh pr create
-
Wait for CI to complete: Watch ALL checks pass
gh pr checks <PR#> --watch
-
Merge PR: Only after all checks pass
gh pr merge <PR#> --squash
-
Create release: Only after merge and main CI passes
# Pull latest main git checkout main && git pull # Verify main CI passed gh run list --branch main --limit 1 # Create and push tag git tag -a vX.Y.Z -m "Release vX.Y.Z" git push origin vX.Y.Z # Create GitHub release gh release create vX.Y.Z --generate-notes
- NEVER release without CI verification
- NEVER push tags before PR is merged and CI passes
- NEVER assume CI will pass — always watch it complete
- NEVER release if any fusion-correctness test fails