All notable changes to ProvableWorldModel are documented here. The format follows
Keep a Changelog, and the project adheres
to Semantic Versioning under the 0.x
convention. See specs.md and roadmap.md.
This is a single workspace changelog; per-crate sections may be split out before
the first 1.0 release. Relation and schema-version events are first-class
entries: a new relation_id, manifest_version, or artifact_version is an
Added line, and any change that narrows verifier acceptance is a Security
entry.
- The predictor bundle is now commitment-chained to the export (#188): the
Python export emits, in
lewm_predictor.json, a predictor-scopedweights_rootcomputed over exactly the 30 proven block tensors in the Rust prover's canonicaltensor_idorder (pwm_export.export.predictor_weight_dicts), and the prover binds that carried value into the model commitment (prove_predictor_with_weights_root), soverify_predictorrejects withCommitmentMismatch(Model)unless the proven weights reproduce the export's commitment bit-for-bit. The artifact alone now certifies which weight set was proven (bundle ⇄ export bound; checkpoint ⇄ export remains trusted preprocessing — documented in README and specs §13). The Python↔Rust canonical-encoding parity gate is now two-way: the multi-leafweights_rootvector and the full predictor weight scheme are pinned on both sides.
-
The
prove-predictordemo path is now commitment-bound (#187): the full 6-block predictor (synthetic and--profile real) routes throughpwm_prover::prove_predictor→PredictorArtifactand is verified bypwm_verifier::verify_predictor, so the demo's ACCEPT now asserts the model / quantization / planner / input / output commitments in the artifact's public input, not just the arithmetic.lewm_predictor::provereturnsResult<PredictorArtifact, ProveError>(was a bareBlockwith an internalexpect),verifytakes the artifact, and the builders return aPredictorCircuitstruct (block, weights, tables, scales, inputs) instead of a 4-tuple. The CLI VERIFY stage narration states the commitment checks, and the report carries the quantization / input / output commitments. -
Pivot (2026-06-05): cryptographic backend changed from Circle-STARK (vendored Stwo) to the CommitLLM commit-and-audit scheme. The proof target (quantized LeWorldModel predictor → rollout → fixed-candidate planner) is unchanged. Removed the
pwm-airandpwm-circuitscrates and the vendoredthird_party/stwoandthird_party/stwo-circuitstrees; the workspace is now the five cratespwm-core,pwm-export,pwm-prover,pwm-verifier,pwm-testkit. Replaced the nightly toolchain with stable Rust (the nightly-only Stwo dependency is gone).pwm-coregains a nativeM31, the audit fieldFp61, a native Fiat-Shamir transcript, thefreivaldscheck, and thetracemodel; the pre-pivot spec corpus is archived underdocs/legacy-stark/. See roadmap.md, specs.md, backlog.md. -
Decomposed the CLI
prove-predictorcommand (a ~340-line match arm that interleaved proving and rendering) into a singlePredictorReportcomputation plus pureprint_predictor_report_{json,human}reporters; output is unchanged. -
Locked in a curated, cast-noise-free slice of clippy style lints in
[workspace.lints.clippy](unreadable_literal,redundant_closure_for_method_calls,map_unwrap_or,explicit_iter_loop,uninlined_format_args,semicolon_if_nothing_returned) and applied the resulting idiom fixes, so the gate prevents regressions without the noise a blanketpedanticwould add. -
Replaced stringly-typed rejection sub-discriminants with typed enums:
VerifyError::CommitmentMismatch(CommitmentKind)andMissingBinding(BindingKind)(was&'static str), and splitBlockError::MissingBindingintoMissingWeight,MissingTable, andInvalidRounding{op_id,discriminant}. Rejection codes are now compiler-checked and stable for downstream matchers. -
pwm-testkit::lewm::provereturnsResult<AuditArtifact, ProveError>instead of panicking, so a malformed bundle whose input escapes the M31 range fails cleanly. -
Routed the predictor block prover's linear ops through the shared
pwm_core::predictor::linearkernel (was an inlined loop), removing prover / reference / verifier drift; narrowedpwm_core::freivalds::dot_fp_i64topub(crate).
- The soundness mutation campaign registered no mutant for the
tensor_memory(op-to-op wiring) component, so its merge gate passed vacuously; it now exercises aWiringMismatchmutant. The committedrequantizegolden fixture is now run through the real primitive (it was only parsed), andverify_planning_batchedgained the missing argmin/cost reject tests. - Corrected stale documentation:
pwm-exportis consumed bypwm-proverandpwm-testkit(not a dependency-DAG leaf; the verifier trust root depends on it only as a dev-dependency); thecommithash rationale (Blake2s is the transcript sponge, not a vendored-Stwo match); the dependency DAGs inspecs.md/README; and three release-tooling docstrings pointing at the relocated spec path.
- Cargo workspace and the first-party crates
pwm-core,pwm-export,pwm-prover,pwm-verifier,pwm-testkit;pwm-verifierbuildsno_std, float-free, and does not depend onpwm-export(#23). - The commit-and-audit protocol: Blake2s Merkle commitments, the native
Fiat-Shamir transcript, the Freivalds linear check, and the exact-recompute
trace model (
pwm-core). - The P0 quantized feed-forward statement (
pwm.lewm.mlp.v1), the P1 rollout, and the P2 fixed-candidate planning proof, withprove_*/verify_*(pwm-prover,pwm-verifier). - The full named-buffer le-wm predictor (AdaLN-zero, multi-head attention, GELU
FFN, gated residuals) as a block DAG, proven by
prove_blockand audited byverify_block; the exporter ingests the realquentinll/lewm-pushtcheckpoint. - A first-class commitment-bound predictor relation
pwm.lewm.predictor_step.v1(RELATION_PREDICTOR):prove_predictor/verify_predictorrecompute and check the model, quantization, input, and output commitments (PRED-02, #179). - The
pwmdemo CLI with a staged, observable pipeline (LOAD → INFER → COMMIT → VERIFY → TAMPER, op histogram, MAC count, latency/throughput), the Docker compose demo (synthetic and--profile realpaths), and the interactive explainer site. - CI merge-gate pipeline:
cargo fmt,clippy -D warnings, tests on MSRV and stable, theno_stdverifier build, the documentation build with an internal link check, the license/SPDX + supply-chain (cargo deny check) gate, and a real constraint-mutation gate (#73, #74). pwm-core::obs: the structured-logging schema, theLevelpolicy, the type-level redaction guard (LoggableValue), the named metric set, and the span-tree scaffolding, behind the off-by-defaultobsfeature so the verifier trust root excludes it (#66).pwm-core::relation::StatementType, the P0–P4 statement discriminant (#66).pwm-testkit: the accept/reject (dual-test) harness, the golden-vector loader, and a real soundness mutation campaign over the live verifier (#77).docs/security/soundness-binding-checklist.md, mapping each binding and range-safety requirement to its enforcing RFC, issue, rejection, and test (#80).- Release automation: centralized
[workspace.dependencies]versioning, thisCHANGELOG.md, the changelog/semver lint (ci/check-changelog.py), the release-preparation helper (ci/prepare-release.py), and the tagged release workflow (#76).
- Freivalds accumulator range guard. The mod-
pFreivalds check now rejects any input, bias, or claimed accumulator outside the single-M31 envelope (and any layer too wide for the soundness margin), closing a mod-paccumulator-aliasing forgery where a prover could add a multiple ofpto an accumulator and have the verifier accept an attacker-chosen output. Regression-locked by an executed+preject test and a soundness mutation campaign. - Overflow-safe planning and recompute.
mse_costaccumulates in checkedi128(the 192-dim cost no longer overflowsi64into a wrapped argmin); requant/rescale shifts are validated before use (InvalidShift); andoverflow-checksis enabled in the release profile so any integer wrap on the recompute path traps instead of silently producing a wrong-but-matching value.