Loading…
Reference in a new issue
No description provided.
Delete branch "mesh-meter/smc"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Stacked on #622 and #630. The base is
jouleclaw-energy/smc-system(#622). The branch also mergesmesh-meter/min-window(#630), so until #630 lands the diff includes its commit. Only the last commit,e7403fde3, is new here. Once both merge, retarget this PR tomain.What changes
mesh-meter'shw-meter-applefeature now also enablesjouleclaw-energy/smc. On macOS 27, IOReport's CPU rail is frozen for an unprivileged reader (seen on an M5 Max and an M3 Ultra). On such a Mac,HwMeter::detectnow picks the SMC's whole-machine power integral (ModelBased,EnergyDomain::System) instead of the load estimator. A live IOReport counter still comes first.Why this is sound:
ModelBased. A shorter one, which covers most served requests, is billed this crate's estimate of its own length, as before.Systemcovers the whole request (#622), so a long span's figure stands for it. It reads high, because it includes whatever else the machine powered, but never low.mesh-core,mesh-openaiandmesh-engine-ggufpick this up through their ownhw-meter-appleandmetalfeatures.ProcessMeter's host fallback also becomes the SMC on such a Mac, under the same window rule. The docs (crate,HwMeter,mesh-openai's serve example) describe the new backend. A new hardware test covers the Mac path.Verified on an M3 Ultra (IOReport CPU rails frozen)
apple-smc, with a 2 s floorEstimator, 0.38 JModelBased, 152.6 J (the whole machine, which other jobs share)mesh-openaiserve example,server,hw-meter-appleEstimator, 172 µJmesh-openaiserve example,server,metalHwShuntTests:
mesh-meterandmesh-corewithhw-meter-apple;mesh-openaiwithserver,hw-meter-appleand withserver,metal. Clippy is clean.mesh-engine-gguf --features metalpassescargo check.mesh-meterwithhw-meter-applepasses, and clippy is clean.🤖 Generated with Claude Code
§3.6 already makes a decision receipt verifiable **by re-execution**: with `weights_digest` and `precision`, a verifier runs the forward pass again and gets the same probabilities. That settles whether this answer came from these weights. It says nothing about where the weights came from — and a decision model is ordinarily fitted to a corpus of earlier decisions, which is what decides which answer the probabilities favour before any request arrives. §3.7 adds that binding as two OPTIONAL fields, paired the way `weights_digest` and `precision` are because neither carries the claim alone: training_digest BLAKE3 over the canonical encoding of the corpus records in the order the fit consumed them, each as its content id. The order is in the address because it is part of what the fit consumed. training_authority what a verifier can DO with that corpus: `signed` (every record signed by the principal that produced it, so a third party can check it without trusting whoever trained on it), `logged` (append-only, attested head, so removal and reordering are detectable, but records are not attributable), or `opaque` (bytes and a digest). As with `weights_digest`, the absence is the signal: a verifier distinguishes an unattributable model from an attributable one instead of assuming, which is the only reason these are optional rather than required. The section also forbids something. A fitted decision model is usually introduced because it is cheaper than the generation it displaces, and a receipt MUST NOT state that saving: those joules were never metered, because that generation was never run. `uj_per_decision` is a measured figure, and a difference against an unrun alternative is not — a receipt carrying one would assert an estimate in a field a reader is entitled to read as measurement. An operator who wants the comparison runs both and keeps both receipts, so the difference lives between two sealed figures rather than inside one of them. Conformance vectors do not move. The published reference serve in `conformance/v1/` is a generation, and both fields are decision-only and OPTIONAL, so `reference/signed_core.hex` and `reference/envelope.hex` are unchanged and need no regeneration. Nothing in this repository yet produces a `training_digest`. The spec now says how such a model is bound; the fit that emits one is in INGEST.md's Adding list, which is honest about the order these landed in. INGEST.md also gains the `mesh/` section it never had. Noted while there and NOT fixed here, because it is a separate job: that file is dated 2026-05-23, carries 4 sections for 22 standards, pins "Rust 1.95.0" where the root `rust-toolchain.toml` says 1.98.0, and routes 12 links to github.com issues, which is not where this project's issues live any more. Guards run locally, all clean: comparative prose (4104 files), vanity metrics (523 Markdown files), spec refs (1966 citations across 17 standards, all resolve), orphan sources. Co-Authored-By: Claude Opus 5 <[email protected]>WAI's WebAssembly legs ran two stock wasmtime versions: 49.0.2 in the quantum and face install steps, and 38.0.3 in wai-ops.yml and wai-vector.yml (wai-ops runs the wasm32-wasip2 decode determinism-tiers §5 cites). A stock wasmtime leaves NaN canonicalisation off and lets each relaxed SIMD instruction take the host's own behaviour, so the bits of a NaN a module reads back, and the result of a relaxed instruction, were the engine's choice. Every install step now pins wasmtime 50.0.1 by version and SHA-256 (the x86_64 Linux release archive, 685466455dd4...98a5, the digest the release lists), and every run passes -W nan-canonicalization=y -W relaxed-simd-deterministic=y wasmtime's two determinism settings: every NaN a float instruction makes is the canonical one, and each relaxed SIMD instruction has one behaviour on every host. The flag names are 50.0.1's own, read from that release's `wasmtime run -W help` on the build host. The two 38.0.3 steps gain the architecture check and the digest the others already had. Both settings took effect on the build host (arm64, the 50.0.1 release for that platform). f32.add of a NaN with payload 0x200001 and 1.0 gives 0x7fe00001 without the flags and the canonical 0x7fc00000 with them. The fixed relaxed behaviour is the engine's, not always the one WebAssembly's deterministic profile prescribes: f32x4.relaxed_madd(1+2^-12, 1+2^-12, -(1+2^-11)) gives the fused 2^-24 with and without the flag, where the profile's choice (parameter 0) is the unfused fadd(fmul), which gives 0. The workflows' comment says so. Co-Authored-By: Claude Opus 5.5 <[email protected]>The install steps' comment said every WAI workflow that runs wasmtime pins one version and passes both determinism settings, but nothing enforced it: a step that ran a stock or differently pinned wasmtime would have merged green. scripts/check-wasmtime-pin.py now fails, in the repository checks, any workflow that 1. downloads a wasmtime release other than 50.0.1, or checks it against any SHA-256 but that archive's; 2. installs wasmtime another way (cargo install, the install script, an action); 3. runs wasmtime (run, serve, compile, or a module given to it) or names it as a CARGO_TARGET_*_RUNNER without -W nan-canonicalization=y and -W relaxed-simd-deterministic=y. It also fails when it finds no download or no run, so a check that looked in the wrong place cannot pass. On this tree it finds the downloads and runs it should. Its self-test (scripts/check-wasmtime-pin-selftest.sh) passes a scratch workflow shaped like these and fails each way of breaking it that the self-test lists, matching the reason in the output. The comment's relaxed_madd claim was measured on arm64 only. It now rests on both architectures, measured on an arm64 macOS host and an x86_64 Linux host with a small probe (wasmtime 50.0.1's release for the host, checked against the digest the release lists): host Darwin arm64; wasmtime 50.0.1 (c307ec81d 2026-10-29) f32.add(bits 0x7fa00001, 1.0) [no flags]: 0x7fe00001 f32x4.relaxed_madd(1+2^-12, 1+2^-12, -(1+2^-11)) [no flags]: 0x33800000 f32.add(bits 0x7fa00001, 1.0) [both flags]: 0x7fc00000 f32x4.relaxed_madd(1+2^-12, 1+2^-12, -(1+2^-11)) [both flags]: 0x33800000 an unknown -W option is refused: error: failed to parse -W / --wasm option: unknown option: no-such-option host Linux x86_64; wasmtime 50.0.1 (c307ec81d 2026-10-29) (the same five lines, bit for bit) 0x33800000 is 2^-24, the fused result; the unfused fadd(fmul) gives 0. So the NaN setting takes effect on both, and relaxed_madd is fused on both with and without the relaxed setting. That matches 50.0.1's source (the wasmtime-internal-cranelift crate, read from the registry): the translator lowers F32x4/F64x2RelaxedMadd through fma_f32x4/fma_f64x2 (src/translate/code_translator.rs L2530-2539), which emit a native fma on a host that has one, a fused library call under relaxed-simd-deterministic on a host that has none, and the unfused fmul and fadd only on a host with no FMA and the setting off (src/func_environ.rs L5907-5925). The setting is what makes the result fused on every host. And since an unknown -W option stops wasmtime, a run that exits 0 with the two flags has parsed them. Co-Authored-By: Claude Opus 5.5 <[email protected]>conformance-results §4.1: a relying party that admits an implementation on a conform-result/1 record requires the record accepted, its run passed (not_conformant), its suite one whose corpus the party holds (suite_unknown), and its corpus digest that corpus's (corpus_mismatch). wai verify --conformant [--root <wai-dir>] applies the rules against a checkout; without it a record of a run that did not pass verifies as before. A sink kind: wai conform sink --suite native-sink gives a sink each session of live-conformance/native-sink/ with its answers withheld, and each configuration the corpus states a session refuses; wai_native_sink_vectors answers [--c-abi] is the reference sink, through its module or through the C interface the platform integrations link. wai-breaking.yml's runner job runs the native sink both ways and the score decoder, each record admitted against the checkout's corpus, and a planted sink that presents an object whose digest does not match: its run must exit 1 with tampered-fragment failed, and admission must refuse its record at rule 2. tests/cli_conform_sinks.rs holds the same, and corpus_mismatch and suite_unknown; it has its [[test]] entry with its required features, so check-tests-in-ci.py passes. The binaries are built with the test step's features, so cargo reuses what that step built. The browser sink has no sink suite, and §7 says that §4.1 has only this reference implementation, with no admission vectors. The catalogue's receipt.verify (the new options, and the envelopes the pin-by-default commit added) and conformance.run (the sink kind, the {case} placeholder) are exported again, and Studio's actions regenerated from the export: actions.mjs --check had failed since that commit. c_abi::take reads and frees no null buffer. Co-Authored-By: Claude Opus 5.5 <[email protected]>