{
  "format": "odb-inspection/1",
  "executed": false,
  "source": {
    "path": "components/ultrasound/convex-decoder/1.0.0/src/lib.rs",
    "sha256": "93a7d80de814a9fdde3bdc131a8deb3980b3ff7fe399e2e5143bf8064228cfda",
    "build": "npm run probe:build (same Rust crate as native rlib; in-memory resource ABI6); npm run components:build",
    "files": [
      {
        "path": "components/ultrasound/convex-decoder/1.0.0/Cargo.lock",
        "sha256": "a89f9d40168858def7e4ee35a1bba63208b8322e3a7ce64270157c2730f44165",
        "text": "# This file is automatically @generated by Cargo.\n# It is not intended for manual editing.\nversion = 4\n\n[[package]]\nname = \"block-buffer\"\nversion = \"0.10.4\"\nsource = \"registry+https://github.com/rust-lang/crates.io-index\"\nchecksum = \"3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71\"\ndependencies = [\n \"generic-array\",\n]\n\n[[package]]\nname = \"cfg-if\"\nversion = \"1.0.5\"\nsource = \"registry+https://github.com/rust-lang/crates.io-index\"\nchecksum = \"4e7648175b45a9a48536d676f68d918270699102aa8dab5496df06904c914600\"\n\n[[package]]\nname = \"cpufeatures\"\nversion = \"0.2.17\"\nsource = \"registry+https://github.com/rust-lang/crates.io-index\"\nchecksum = \"59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280\"\ndependencies = [\n \"libc\",\n]\n\n[[package]]\nname = \"crypto-common\"\nversion = \"0.1.7\"\nsource = \"registry+https://github.com/rust-lang/crates.io-index\"\nchecksum = \"78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a\"\ndependencies = [\n \"generic-array\",\n \"typenum\",\n]\n\n[[package]]\nname = \"digest\"\nversion = \"0.10.7\"\nsource = \"registry+https://github.com/rust-lang/crates.io-index\"\nchecksum = \"9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292\"\ndependencies = [\n \"block-buffer\",\n \"crypto-common\",\n]\n\n[[package]]\nname = \"generic-array\"\nversion = \"0.14.7\"\nsource = \"registry+https://github.com/rust-lang/crates.io-index\"\nchecksum = \"85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a\"\ndependencies = [\n \"typenum\",\n \"version_check\",\n]\n\n[[package]]\nname = \"itoa\"\nversion = \"1.0.18\"\nsource = \"registry+https://github.com/rust-lang/crates.io-index\"\nchecksum = \"8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682\"\n\n[[package]]\nname = \"libc\"\nversion = \"0.2.191\"\nsource = \"registry+https://github.com/rust-lang/crates.io-index\"\nchecksum = \"65cd87c9a6d60536580b316ad985726104730a5151c99845f2490428ef91240a\"\n\n[[package]]\nname = \"memchr\"\nversion = \"2.8.3\"\nsource = \"registry+https://github.com/rust-lang/crates.io-index\"\nchecksum = \"cf8baf1c55e62ffcace7a9f06f4bd9cd3f0c4beb022d3b367256b91b87513d98\"\n\n[[package]]\nname = \"odb-convex-decoder\"\nversion = \"1.0.0\"\ndependencies = [\n \"serde_json\",\n \"sha2\",\n]\n\n[[package]]\nname = \"proc-macro2\"\nversion = \"1.0.107\"\nsource = \"registry+https://github.com/rust-lang/crates.io-index\"\nchecksum = \"985e7ec9bb745e6ce6535b544d84d6cd6f7ad8bd711c398938ae983b91a766d9\"\ndependencies = [\n \"unicode-ident\",\n]\n\n[[package]]\nname = \"quote\"\nversion = \"1.0.47\"\nsource = \"registry+https://github.com/rust-lang/crates.io-index\"\nchecksum = \"1fbf4db142a473a8d80c26bbf18454ed458bf8d26c8219c331daecfdbd079001\"\ndependencies = [\n \"proc-macro2\",\n]\n\n[[package]]\nname = \"serde\"\nversion = \"1.0.229\"\nsource = \"registry+https://github.com/rust-lang/crates.io-index\"\nchecksum = \"4148590afebada386688f18773da617792bf2ef03ffc1e4cbd2b1d45b023e0ba\"\ndependencies = [\n \"serde_core\",\n]\n\n[[package]]\nname = \"serde_core\"\nversion = \"1.0.229\"\nsource = \"registry+https://github.com/rust-lang/crates.io-index\"\nchecksum = \"67dca2c9c51e58a4791a4b1ed58308b39c64224d349a935ab5039aa360942a48\"\ndependencies = [\n \"serde_derive\",\n]\n\n[[package]]\nname = \"serde_derive\"\nversion = \"1.0.229\"\nsource = \"registry+https://github.com/rust-lang/crates.io-index\"\nchecksum = \"e7a5d71263a5a7d47b41f6b3f06ba276f10cc18b0931f1799f710578e2309348\"\ndependencies = [\n \"proc-macro2\",\n \"quote\",\n \"syn\",\n]\n\n[[package]]\nname = \"serde_json\"\nversion = \"1.0.154\"\nsource = \"registry+https://github.com/rust-lang/crates.io-index\"\nchecksum = \"e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6\"\ndependencies = [\n \"itoa\",\n \"memchr\",\n \"serde\",\n \"serde_core\",\n \"zmij\",\n]\n\n[[package]]\nname = \"sha2\"\nversion = \"0.10.9\"\nsource = \"registry+https://github.com/rust-lang/crates.io-index\"\nchecksum = \"a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283\"\ndependencies = [\n \"cfg-if\",\n \"cpufeatures\",\n \"digest\",\n]\n\n[[package]]\nname = \"syn\"\nversion = \"3.0.6\"\nsource = \"registry+https://github.com/rust-lang/crates.io-index\"\nchecksum = \"8593e8e72159ed2257d083c7a454a85cbf854f37a0966d8d483aff8c8a3ebcee\"\ndependencies = [\n \"proc-macro2\",\n \"quote\",\n \"unicode-ident\",\n]\n\n[[package]]\nname = \"typenum\"\nversion = \"1.20.1\"\nsource = \"registry+https://github.com/rust-lang/crates.io-index\"\nchecksum = \"b6f5e870be6c3b371b77fe0ee0bafb859fa4964b4404c27de1d380043c4dda20\"\n\n[[package]]\nname = \"unicode-ident\"\nversion = \"1.0.27\"\nsource = \"registry+https://github.com/rust-lang/crates.io-index\"\nchecksum = \"a2c754d6c33795a1c324727428e5a7dedb5b06195f9890bdbcba760d3e246563\"\n\n[[package]]\nname = \"version_check\"\nversion = \"0.9.5\"\nsource = \"registry+https://github.com/rust-lang/crates.io-index\"\nchecksum = \"0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a\"\n\n[[package]]\nname = \"zmij\"\nversion = \"1.0.23\"\nsource = \"registry+https://github.com/rust-lang/crates.io-index\"\nchecksum = \"29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b\"\n"
      },
      {
        "path": "components/ultrasound/convex-decoder/1.0.0/Cargo.toml",
        "sha256": "7f927acd5159c79e9e5cd6e86da164fb52b8ecc0ff9f3676186c7e99899ce91c",
        "text": "[package]\nname = \"odb-convex-decoder\"\nversion = \"1.0.0\"\nedition = \"2024\"\nlicense = \"AGPL-3.0-or-later\"\npublish = false\n[lib]\ncrate-type = [\"cdylib\", \"rlib\"]\n[features]\ndefault = [\"ffi\"]\nffi = []\n\n[dependencies]\nserde_json = \"1\"\nsha2 = \"0.10\"\n[profile.release]\nopt-level = 3\nlto = true\nstrip = true\npanic = \"abort\"\n"
      },
      {
        "path": "components/ultrasound/convex-decoder/1.0.0/source-origin.json",
        "sha256": "2105fe63c1c9ad1f565f0343e16abc23636a0e5a47b621979de8f140ff78d516",
        "text": "{\n  \"origin\": \"Owner-authored Rust probe driver, extracted for browser execution\",\n  \"upstream_commit\": \"1bd9d10\",\n  \"modules\": [\n    {\n      \"module\": \"convex_bfsp.rs\",\n      \"source_sha256\": \"31b51224bfc5813b7b4c429b3136dda44a05198be9775706149da831f786c3f2\"\n    },\n    {\n      \"module\": \"convex_dtgc.rs\",\n      \"source_sha256\": \"8dd333970fa7ce5ceb45fd3c04a1d2dbbe3e49e9b1082ebce17b80613ee2adac\"\n    },\n    {\n      \"module\": \"convex_compound.rs\",\n      \"source_sha256\": \"f39ceed6034eafac78c8d7c16995a4d2534db54211d0a89fa402cc9b3c3980eb\"\n    },\n    {\n      \"module\": \"convex_sri.rs\",\n      \"source_sha256\": \"49fcb50828b9ac48a000bf8a00ede3b569a1186db3756f9cf4dbb66eefb9e603\"\n    },\n    {\n      \"module\": \"convex_sri_plan.rs\",\n      \"source_sha256\": \"53578e297399d1a0e0abcb0df4fabc4135fdb94bb729dde9485b25a70b0f15e6\"\n    },\n    {\n      \"module\": \"convex_dsc.rs\",\n      \"source_sha256\": \"b64867e7b13f2fa4732aeccc2ff25a626e6fb98821c4d500216ce14c17167140\"\n    },\n    {\n      \"module\": \"convex_pipeline.rs\",\n      \"source_sha256\": \"086f35c11e86709085a6b96e3f583b8ab04db3d2e414a648d7ad0e3a34836513\"\n    },\n    {\n      \"module\": \"convex_lifecycle.rs\",\n      \"source_sha256\": \"16bad10d43419885d4c4498301bcd2e5c29bd461b1a1494189b97bfcd2379445\"\n    },\n    {\n      \"module\": \"convex_group.rs\",\n      \"source_sha256\": \"251fe999180ff02b44239fbb0b32fe826a478299b8bf61741cd6d5f279166b2c\"\n    },\n    {\n      \"module\": \"rgba_png.rs\",\n      \"source_sha256\": \"8c4a5221666fd8e2d20182cffb08ca4f2e88243d1aeb4371f2610bdb93708a07\"\n    },\n    {\n      \"module\": \"known_convex_sri_layout.json\",\n      \"source_sha256\": \"4cafbc69a11b93c19d04d390aa1989d5a241df0d928d027ebe7632bf1921f396\"\n    },\n    {\n      \"module\": \"lib.rs\",\n      \"source_sha256\": \"62c14bbdb1c70ccc04854189763fb56e0b3b53268fbf833c918e7812661fc714\"\n    },\n    {\n      \"module\": \"convex_parameters.rs\",\n      \"source_sha256\": \"95d76b3daea9b4ae718be85c47a9f8ef620a3f1b351cd90f322a6cc1eba4a015\"\n    },\n    {\n      \"module\": \"convex_producers.rs\",\n      \"source_sha256\": \"44421bbc67e54a2fbbd54bb6eb1179d4f91ff6831f245cf787c026e21a49bab2\"\n    },\n    {\n      \"module\": \"convex_configuration.rs\",\n      \"source_sha256\": \"00e8f3ee059726d28a7cf3e4d1d4dde458fc0d80b34a13d989522cada6a5b166\"\n    },\n    {\n      \"module\": \"convex_command.rs\",\n      \"source_sha256\": \"fe379e1a238acc793bced432830c4409c7d7e98368741ece2bacfede9d6a5273\"\n    }\n  ],\n  \"vendor_resources_included\": false,\n  \"upstream_commit_scope\": \"Historical extraction base; per-module source_sha256 values identify upstream inputs, not the current modified files. Current source hashes are locked by component.json.\",\n  \"original_changes_2026_11_05\": [\n    \"Shared native/WASM in-memory Session and bounded resource sources\",\n    \"Reconstruction-only session without exclusively transmission or HV inputs\",\n    \"Original linear-gray-v1 display generator, no vendor palette payload\",\n    \"Offline native host and archived-data comparison harness\"\n  ],\n  \"autonomy_complete\": false\n}\n"
      },
      {
        "path": "components/ultrasound/convex-decoder/1.0.0/src/admission.rs",
        "sha256": "5aba1902cdaa2a8aeed10737896ee186ca8dcbc69d57b4cff92977c093557269",
        "text": "use crate::{HEADER_BYTES, MARKER, Result, convex_bfsp::Plan};\npub fn audit_candidate(lines: &[u8], header: &[u8], plan: Plan) -> Result<u8> {\n    if header.len() != HEADER_BYTES\n        || header[..4] != MARKER\n        || header[4..8] != MARKER\n        || ![0, 1, 5, 6].contains(&header[16])\n        || lines.len() != plan.input_bytes()\n    {\n        return Err(\n            \"Require candidate B header1024 and exact declared General B line-buffer length\".into(),\n        );\n    }\n    for line in lines.chunks_exact(plan.line_words() * 4) {\n        let word = u32::from_le_bytes(line[4..8].try_into().unwrap());\n        if line[..4] != MARKER\n            || word & 0xffff != plan.line_words() as u32\n            || ([5, 6].contains(&header[16]) && (word >> 20) & 15 >= 4)\n        {\n            return Err(\"Candidate line marker/word length/B subtype mismatch\".into());\n        }\n    }\n    Ok(header[17])\n}\n"
      },
      {
        "path": "components/ultrasound/convex-decoder/1.0.0/src/archive.rs",
        "sha256": "098ebf2b90a99e35d507fc8765184fc1f68631afb96382a2a2138f5104b409f6",
        "text": "use crate::Result;\nuse serde_json::{Value, json};\nuse sha2::{Digest, Sha256};\nuse std::path::Path;\npub fn sha(bytes: &[u8]) -> String {\n    format!(\"{:x}\", Sha256::digest(bytes))\n}\npub fn source_provenance() -> Value {\n    json!({\"program\":\"odb-convex-decoder\",\"version\":\"1.0.0\",\"runtime\":if cfg!(target_arch=\"wasm32\") {\"browser-wasm\"} else {\"native-memory\"}})\n}\n// Persistent archives are outside this browser decoder's capabilities.\npub fn write_new(_: &Path, _: &[u8]) -> Result<()> {\n    Err(\"Persistent filesystem unavailable in decoder\".into())\n}\npub fn checkpoint(_: &Path, _: &Value) -> Result<()> {\n    Err(\"Persistent filesystem unavailable in decoder\".into())\n}\n\npub fn diagnostic_sha(bytes: &[u8]) -> String {\n    if cfg!(target_arch = \"wasm32\") {\n        String::new()\n    } else {\n        sha(bytes)\n    }\n}\n"
      },
      {
        "path": "components/ultrasound/convex-decoder/1.0.0/src/convex_bfsp.rs",
        "sha256": "9c078685c2ba936c640ca1f62d1cf45107e78e7d3040a284f2f60a20ae8d4c4f",
        "text": "// SPDX-License-Identifier: AGPL-3.0-or-later\n//! Selected UC5-2S_16 General B preprocessing. Explicit backing state is required:\n//! native halo reads and unwritten destinations are not invented samples.\nuse crate::{Result, archive};\nuse serde_json::{Value, json};\nuse std::path::Path;\n\npub const GROUPS: usize = 32;\npub const SAMPLES: usize = 1024;\npub(crate) const INPUTS: [(&str, usize, &str); 4] = [\n    (\n        \"A_Probe.bin\",\n        68,\n        \"9b8e95810fe33a085f2be2e58f082de9915cb3d7f66324d01145e4c211c2efcb\",\n    ),\n    (\n        \"A_BF.bin\",\n        44,\n        \"28ed79893f9f224a7c1a29e2288491cb3bf224bbb3851d308c50e799b48dbdee\",\n    ),\n    (\n        \"B_PRF.bin\",\n        388,\n        \"bf553725fc08bf50b6c4919ebc38d8cb8d648b8f03072a6d2da6fe32dcd84231\",\n    ),\n    (\n        \"B_LPF.bin\",\n        256,\n        \"69f3e66397510c09a5b68fecfe3113120b1248db880f89c643b86728759e69cc\",\n    ),\n];\n\n#[derive(Clone, Copy, Debug)]\npub struct Settings {\n    pub depth: usize,\n    pub selector: usize,\n    pub line_words: usize,\n}\nimpl Settings {\n    pub fn from_json(v: &Value) -> Result<Self> {\n        let o = v.as_object().ok_or(\"BFSP settings must be an object\")?;\n        if o.len() != 4\n            || o.keys().any(|k| {\n                ![\n                    \"schema_version\",\n                    \"depth_index\",\n                    \"selector_index\",\n                    \"line_words\",\n                ]\n                .contains(&k.as_str())\n            })\n            || v[\"schema_version\"] != \"convex-bfsp-settings-v1\"\n        {\n            return Err(\"Require exact convex-bfsp-settings-v1 settings; no defaults\".into());\n        }\n        let get = |key: &str| {\n            v[key]\n                .as_u64()\n                .and_then(|n| usize::try_from(n).ok())\n                .ok_or_else(|| format!(\"Invalid {key}\"))\n        };\n        let settings = Self {\n            depth: get(\"depth_index\")?,\n            selector: get(\"selector_index\")?,\n            line_words: get(\"line_words\")?,\n        };\n        if settings.depth >= 8 || settings.selector >= 2 {\n            return Err(\"General supports depth0..7 and selector0..1 only\".into());\n        }\n        Ok(settings)\n    }\n    pub fn json(self) -> Value {\n        json!({\"schema_version\":\"convex-bfsp-settings-v1\",\"depth_index\":self.depth,\"selector_index\":self.selector,\"line_words\":self.line_words})\n    }\n}\n\npub struct Assets {\n    coefficients: [f32; 8],\n    downsample: usize,\n    provenance: Value,\n    selection: (usize, usize),\n}\nimpl Assets {\n    pub(crate) fn selected(&self) -> ([f32; 8], usize) {\n        (self.coefficients, self.downsample)\n    }\n    pub(crate) fn from_selected(\n        settings: Settings,\n        coefficients: [f32; 8],\n        downsample: usize,\n    ) -> Result<Self> {\n        if settings.depth >= 8\n            || settings.selector >= 2\n            || coefficients.iter().any(|x| !x.is_finite())\n        {\n            return Err(\"Invalid selected BFSP profile\".into());\n        }\n        Plan::new(settings.line_words, downsample)?;\n        Ok(Self {\n            coefficients,\n            downsample,\n            selection: (settings.depth, settings.selector),\n            provenance: json!({\"policy\":\"selected-memory-profile-v1\"}),\n        })\n    }\n\n    pub fn load(directory: &Path, settings: Settings) -> Result<Self> {\n        Self::from_source(&crate::resources::Files(directory), settings)\n    }\n    pub fn from_source(\n        directory: &dyn crate::resources::Source,\n        settings: Settings,\n    ) -> Result<Self> {\n        if settings.depth >= 8 || settings.selector >= 2 {\n            return Err(\"Invalid General selection\".into());\n        }\n        let mut inputs = Vec::new();\n        let mut files = Vec::new();\n        for (name, size, expected) in INPUTS {\n            let bytes = directory.read(name, size as u64)?;\n            if bytes.len() != size || archive::sha(&bytes) != expected {\n                return Err(format!(\n                    \"{name}: require the complete known General input group\"\n                ));\n            }\n            files.push(json!({\"name\":name,\"bytes\":size,\"sha256\":expected}));\n            inputs.push(bytes);\n        }\n        let word = |file: usize, offset: usize| {\n            u32::from_le_bytes(inputs[file][offset..offset + 4].try_into().unwrap())\n        };\n        if word(0, 0x1c) != 8\n            || word(1, 4) != 4\n            || word(1, 8) != 2\n            || word(1, 12) != 128\n            || word(2, 0x104 + 32 * settings.selector + 4 * settings.depth) != 2\n        {\n            return Err(\"General B configuration disagrees with the traced profile\".into());\n        }\n        let downsample = (word(2, 0xe4 + 4 * settings.depth) as usize).div_ceil(2);\n        let offset = 16 * settings.depth + 128 * settings.selector;\n        let coefficients = std::array::from_fn(|i| {\n            i16::from_le_bytes(\n                inputs[3][offset + 2 * i..offset + 2 * i + 2]\n                    .try_into()\n                    .unwrap(),\n            ) as f32\n                / 256.0\n        });\n        Ok(Self {\n            coefficients,\n            downsample,\n            selection: (settings.depth, settings.selector),\n            provenance: json!({\"profile\":\"Plus-UC5-2S_16-General-B4-T128-m2-type8\",\"files\":files,\"depth_index\":settings.depth,\"selector_index\":settings.selector,\"coefficient_payload_copied\":false}),\n        })\n    }\n    pub fn plan(&self, settings: Settings) -> Result<Plan> {\n        if (settings.depth, settings.selector) != self.selection {\n            return Err(\"Settings selection differs from loaded assets\".into());\n        }\n        Plan::new(settings.line_words, self.downsample)\n    }\n    pub fn provenance(&self) -> Value {\n        self.provenance.clone()\n    }\n    pub fn process(&self, plan: Plan, state: &mut State, phase: u8) -> Result<()> {\n        if plan.downsample != self.downsample {\n            return Err(\"Plan downsample differs from loaded assets; state unchanged\".into());\n        }\n        process(plan, &self.coefficients, state, phase)\n    }\n}\n\n#[derive(Clone, Copy, Debug)]\npub struct Plan {\n    line_words: usize,\n    line_vectors: usize,\n    positions: usize,\n    up_stride: usize,\n    downsample: usize,\n    raw_bytes: usize,\n    up_bytes: usize,\n}\nimpl Plan {\n    pub fn new(line_words: usize, downsample: usize) -> Result<Self> {\n        // Bounds precede products. Fixed General B4/T128/m2: e4, R32,\n        // E words32 per line, L=E/2 ushort4, K8 words32 => H4 vectors.\n        if !(512..=32768).contains(&line_words)\n            || !line_words.is_multiple_of(2)\n            || !(1..=64).contains(&downsample)\n        {\n            return Err(\"Invalid bounded even line_words or downsample\".into());\n        }\n        let line_vectors = line_words / 2;\n        let positions = line_vectors / 256 * 256;\n        if positions > line_vectors - 4 {\n            return Err(\"Native LPF destinations overlap adjacent groups; concurrent write order is undefined\".into());\n        }\n        let up_stride = 4 * (line_vectors - 4);\n        let raw_read_end = ((GROUPS - 1) * line_vectors + 4 + positions + 16) * 8;\n        let raw_bytes = raw_read_end\n            .max(GROUPS * line_words * 4)\n            .max(GROUPS * SAMPLES * 8);\n        let up_bytes = ((GROUPS - 1) * up_stride + (4 * positions).max(SAMPLES * downsample)) * 8;\n        if raw_bytes > 4 * 1024 * 1024 || up_bytes > 16 * 1024 * 1024 {\n            return Err(\"Native raw/Up4 allocation bound exceeded\".into());\n        }\n        Ok(Self {\n            line_words,\n            line_vectors,\n            positions,\n            up_stride,\n            downsample,\n            raw_bytes,\n            up_bytes,\n        })\n    }\n    pub fn line_words(self) -> usize {\n        self.line_words\n    }\n    pub fn input_bytes(self) -> usize {\n        GROUPS * self.line_words * 4\n    }\n    pub fn raw_bytes(self) -> usize {\n        self.raw_bytes\n    }\n    pub fn up_bytes(self) -> usize {\n        self.up_bytes\n    }\n    pub fn reshape_bytes(self) -> usize {\n        GROUPS * SAMPLES * 16\n    }\n    pub fn json(self) -> Value {\n        json!({\"groups\":GROUPS,\"output_samples_per_group\":SAMPLES,\"line_words\":self.line_words,\"prefix_words\":8,\n            \"line_ushort4_vectors\":self.line_vectors,\"prefix_ushort4_vectors\":4,\"downsample\":self.downsample,\n            \"lpf_dispatch\":[GROUPS,self.positions/16],\"lpf_local\":[4,16],\"lpf_positions_written_per_group\":self.positions,\n            \"lpf_halo_vectors_after_last_output_position\":16,\"up4_stride_vectors\":self.up_stride,\n            \"up4_unwritten_vectors_between_groups\":self.up_stride-4*self.positions,\n            \"mdown_reads_past_group_stride\":SAMPLES*self.downsample>self.up_stride,\n            \"mdown_dispatch\":[GROUPS,SAMPLES],\"reshape_dispatch\":[GROUPS,SAMPLES],\n            \"input_line_buffer_bytes\":self.input_bytes(),\"raw_backing_bytes\":self.raw_bytes,\n            \"up4_backing_bytes\":self.up_bytes,\"reshape_backing_bytes\":self.reshape_bytes(),\n            \"state_policy\":\"explicit-active-backing-prefixes-v1\",\"native_full_allocations_exported\":false})\n    }\n}\n\npub struct State {\n    pub raw: Vec<u8>,\n    pub up4: Vec<u8>,\n    pub reshaped: Vec<[f32; 4]>,\n}\nimpl State {\n    pub fn from_bytes(plan: Plan, raw: Vec<u8>, up4: Vec<u8>, reshaped: Vec<u8>) -> Result<Self> {\n        if raw.len() != plan.raw_bytes\n            || up4.len() != plan.up_bytes\n            || reshaped.len() != plan.reshape_bytes()\n        {\n            return Err(\n                \"All three backing prefixes must have the exact planned byte lengths\".into(),\n            );\n        }\n        let reshaped = reshaped\n            .as_chunks::<16>()\n            .0\n            .iter()\n            .map(|b| {\n                std::array::from_fn(|i| f32::from_le_bytes(b[i * 4..i * 4 + 4].try_into().unwrap()))\n            })\n            .collect();\n        let state = Self { raw, up4, reshaped };\n        state.validate(plan)?;\n        Ok(state)\n    }\n    pub(crate) fn validate(&self, plan: Plan) -> Result<()> {\n        if self.raw.len() != plan.raw_bytes\n            || self.up4.len() != plan.up_bytes\n            || self.reshaped.len() != GROUPS * SAMPLES\n            || self.reshaped.iter().flatten().any(|f| !f.is_finite())\n        {\n            return Err(\n                \"Backing lengths or finite reshape state disagree with plan; state unchanged\"\n                    .into(),\n            );\n        }\n        Ok(())\n    }\n    pub fn reshaped_bytes(&self) -> Vec<u8> {\n        self.reshaped\n            .iter()\n            .flatten()\n            .flat_map(|f| f.to_le_bytes())\n            .collect()\n    }\n}\n\nfn sample(bytes: &[u8], vector: usize, lane: usize) -> f32 {\n    let offset = vector * 8 + lane * 2;\n    u16::from_le_bytes(bytes[offset..offset + 2].try_into().unwrap()) as f32\n}\nfn put(bytes: &mut [u8], vector: usize, lane: usize, value: f32) {\n    let offset = vector * 8 + lane * 2;\n    bytes[offset..offset + 2].copy_from_slice(&(value as u16).to_le_bytes());\n}\n\n/// Exact bounded schedule, binary32 left-to-right filter, x+(y-x)*fraction mix,\n/// host log10f and saturating round-towards-zero integer conversion. OpenCL's\n/// actual mix/log implementations and device rounding remain unvalidated.\npub fn process(plan: Plan, coefficients: &[f32; 8], state: &mut State, phase: u8) -> Result<()> {\n    state.validate(plan)?;\n    if coefficients\n        .iter()\n        .any(|c| !c.is_finite() || c.abs() > 128.0)\n    {\n        return Err(\"Finite signed-i16/256 coefficient range required; state unchanged\".into());\n    }\n    for group in 0..GROUPS {\n        for position in 0..plan.positions {\n            let base = group * plan.line_vectors + 4 + position;\n            for lane in 0..4 {\n                let filter = |start| {\n                    let mut sum = (sample(&state.raw, start, lane)\n                        + sample(&state.raw, start + 15, lane))\n                        * coefficients[0];\n                    for (tap, coefficient) in coefficients.iter().enumerate().skip(1) {\n                        sum += (sample(&state.raw, start + tap, lane)\n                            + sample(&state.raw, start + 15 - tap, lane))\n                            * coefficient;\n                    }\n                    sum\n                };\n                let left = filter(base);\n                let right = filter(base + 1);\n                let target = group * plan.up_stride + 4 * position;\n                put(&mut state.up4, target, lane, left);\n                for (i, fraction) in [0.25f32, 0.5, 0.75].iter().enumerate() {\n                    put(\n                        &mut state.up4,\n                        target + i + 1,\n                        lane,\n                        left + (right - left) * fraction,\n                    );\n                }\n            }\n        }\n    }\n    for group in 0..GROUPS {\n        for position in 0..SAMPLES {\n            let base = group * plan.up_stride + position * plan.downsample;\n            for lane in 0..4 {\n                let mut sum = 0.0f32;\n                for i in 0..plan.downsample {\n                    sum += sample(&state.up4, base + i, lane);\n                }\n                let value = (sum / plan.downsample as f32).max(1.0).log10() * 12094.771f32;\n                put(&mut state.raw, group * SAMPLES + position, lane, value);\n            }\n        }\n    }\n    for group in 0..GROUPS {\n        for position in 0..SAMPLES {\n            let index = group * SAMPLES + position;\n            if phase == 1 {\n                if group + 1 < GROUPS {\n                    state.reshaped[index][2] = sample(&state.raw, index, 0);\n                    state.reshaped[index][3] = sample(&state.raw, index, 1);\n                    state.reshaped[index + SAMPLES][0] = sample(&state.raw, index, 2);\n                    state.reshaped[index + SAMPLES][1] = sample(&state.raw, index, 3);\n                }\n            } else {\n                state.reshaped[index] = std::array::from_fn(|lane| sample(&state.raw, index, lane));\n            }\n        }\n    }\n    Ok(())\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n    #[test]\n    fn asset_bound_api_rejects_foreign_plan_before_state_mutation() {\n        let assets = Assets {\n            coefficients: [0.0; 8],\n            downsample: 3,\n            selection: (0, 0),\n            provenance: json!({\"synthetic\":true}),\n        };\n        let plan = Plan::new(520, 4).unwrap();\n        let mut state = State::from_bytes(\n            plan,\n            vec![99; plan.raw_bytes()],\n            vec![42; plan.up_bytes()],\n            vec![0; plan.reshape_bytes()],\n        )\n        .unwrap();\n        assert!(assets.process(plan, &mut state, 1).is_err());\n        assert!(state.raw.iter().all(|b| *b == 99));\n        assert!(state.up4.iter().all(|b| *b == 42));\n        assert!(\n            assets\n                .plan(Settings {\n                    depth: 1,\n                    selector: 0,\n                    line_words: 520\n                })\n                .is_err()\n        );\n    }\n}\n"
      },
      {
        "path": "components/ultrasound/convex-decoder/1.0.0/src/convex_command.rs",
        "sha256": "480fbc33846874ae68b0396cb2913f69f7ec199b90b873060af4946a09cb01bd",
        "text": "// SPDX-License-Identifier: AGPL-3.0-or-later\n//! Pure UC5-2S control-envelope serialization.\n//!\n//! Internal kind 99 is constructed with wire type 2. The named native producers\n//! enqueue the pair (0x00060001, 0) for Start and (0x00060001, 1) for Freeze.\n//! Construction below assumes an otherwise empty queue/map. These bytes have\n//! not been replayed on this unit; names do not establish acoustic states.\n//! There is no transport, arbitrary-register encoder or initialization API.\n\npub const PACKET_BYTES: usize = 512;\npub const PROFILE: &str = \"convex-01\";\npub const VID_PID: &str = \"04b4:4611\";\npub const COMMAND_ENDPOINT: u8 = 0x02;\npub const INTERNAL_KIND: u32 = 99;\npub const WIRE_TYPE: u32 = 2;\npub const EVIDENCE_KIND: &str = \"static_candidate_not_replayed\";\n\nconst HEADER: [u8; 4] = [0xa5, 0xa5, 0x5a, 0x5a];\nconst FOOTER: [u8; 4] = [0x5a, 0x5a, 0xa5, 0xa5];\nconst CONTROL_KEY: u32 = 0x0006_0001;\n\n/// Native producer names only. Freeze is not a verified acoustic stop or power-off.\n#[derive(Clone, Copy, Debug, PartialEq, Eq)]\npub enum Command {\n    Start,\n    Freeze,\n}\n\nimpl Command {\n    fn value(self) -> u32 {\n        match self {\n            Self::Start => 0,\n            Self::Freeze => 1,\n        }\n    }\n}\n\n/// Serialize one isolated named control; this function performs no I/O.\npub fn encode(command: Command) -> [u8; PACKET_BYTES] {\n    let mut packet = [0; PACKET_BYTES];\n    packet[..4].copy_from_slice(&HEADER);\n    packet[4..8].copy_from_slice(&WIRE_TYPE.to_le_bytes());\n    packet[16..20].copy_from_slice(&CONTROL_KEY.to_le_bytes());\n    packet[20..24].copy_from_slice(&command.value().to_le_bytes());\n    packet[24..28].copy_from_slice(&WIRE_TYPE.to_le_bytes());\n    packet[28..32].copy_from_slice(&FOOTER);\n    packet\n}\n\n#[derive(Clone, Copy, Debug, PartialEq, Eq)]\npub enum InspectError {\n    WrongLength { actual: usize },\n    WrongHeader,\n    WrongWireType,\n    ReservedBytesNonzero,\n    MissingAlignedTrailer,\n    PaddingNonzero,\n}\n\nimpl std::fmt::Display for InspectError {\n    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {\n        match self {\n            Self::WrongLength { actual } => write!(f, \"Expected one 512-byte packet, got {actual}\"),\n            Self::WrongHeader => f.write_str(\"Missing convex type-2 header\"),\n            Self::WrongWireType => f.write_str(\"Expected little-endian wire type 2\"),\n            Self::ReservedBytesNonzero => f.write_str(\"Bytes 8..16 must be zero in this envelope\"),\n            Self::MissingAlignedTrailer => f.write_str(\"Missing type-2 trailer at a pair boundary\"),\n            Self::PaddingNonzero => f.write_str(\"Nonzero bytes follow the type-2 trailer\"),\n        }\n    }\n}\n\nimpl std::error::Error for InspectError {}\n\n/// Two literal little-endian words retained without assigning register semantics.\n#[derive(Clone, Copy, Debug, PartialEq, Eq)]\npub struct OpaquePair {\n    pub byte_offset: usize,\n    pub words: [u32; 2],\n}\n\n#[derive(Clone, Copy, Debug, PartialEq, Eq)]\npub struct LocatedCommand {\n    pub byte_offset: usize,\n    pub command: Command,\n}\n\n/// Structural interpretation of one candidate envelope, never proof of execution.\n#[derive(Clone, Debug, PartialEq, Eq)]\npub struct Inspection {\n    pub known_commands: Vec<LocatedCommand>,\n    pub opaque_pairs: Vec<OpaquePair>,\n    pub pair_count: usize,\n    pub trailer_offset: usize,\n    pub padding_bytes: usize,\n}\n\nimpl Inspection {\n    pub fn isolated_command(&self) -> Option<Command> {\n        match self.known_commands.as_slice() {\n            [\n                LocatedCommand {\n                    byte_offset: 16,\n                    command,\n                },\n            ] if self.pair_count == 1\n                && self.opaque_pairs.is_empty()\n                && self.trailer_offset == 24\n                && self.padding_bytes == 480 =>\n            {\n                Some(*command)\n            }\n            _ => None,\n        }\n    }\n}\n\n/// Inspect one zero-padded type-2 packet (at most 61 pairs), not concatenated\n/// USB transfers or incoming data. The last aligned marker is the candidate\n/// trailer, so an identical pair inside the payload is retained as opaque.\n/// Unknown pairs, including zero pairs, are preserved without interpretation.\n/// No checksum, acknowledgement, queue history or hardware state is inferred.\npub fn inspect(packet: &[u8]) -> Result<Inspection, InspectError> {\n    if packet.len() != PACKET_BYTES {\n        return Err(InspectError::WrongLength {\n            actual: packet.len(),\n        });\n    }\n    if packet[..4] != HEADER {\n        return Err(InspectError::WrongHeader);\n    }\n    if packet[4..8] != WIRE_TYPE.to_le_bytes() {\n        return Err(InspectError::WrongWireType);\n    }\n    if packet[8..16] != [0; 8] {\n        return Err(InspectError::ReservedBytesNonzero);\n    }\n    let trailer_offset = (16..512)\n        .step_by(8)\n        .rev()\n        .find(|&offset| {\n            packet[offset..offset + 4] == WIRE_TYPE.to_le_bytes()\n                && packet[offset + 4..offset + 8] == FOOTER\n        })\n        .ok_or(InspectError::MissingAlignedTrailer)?;\n    if packet[trailer_offset + 8..].iter().any(|byte| *byte != 0) {\n        return Err(InspectError::PaddingNonzero);\n    }\n    let mut result = Inspection {\n        known_commands: Vec::new(),\n        opaque_pairs: Vec::new(),\n        pair_count: (trailer_offset - 16) / 8,\n        trailer_offset,\n        padding_bytes: PACKET_BYTES - trailer_offset - 8,\n    };\n    for (index, pair) in packet[16..trailer_offset]\n        .as_chunks::<8>()\n        .0\n        .iter()\n        .enumerate()\n    {\n        let words = [\n            u32::from_le_bytes(pair[..4].try_into().expect(\"four-byte key\")),\n            u32::from_le_bytes(pair[4..].try_into().expect(\"four-byte value\")),\n        ];\n        let byte_offset = 16 + index * 8;\n        let command = match words {\n            [CONTROL_KEY, 0] => Some(Command::Start),\n            [CONTROL_KEY, 1] => Some(Command::Freeze),\n            _ => None,\n        };\n        if let Some(command) = command {\n            result.known_commands.push(LocatedCommand {\n                byte_offset,\n                command,\n            });\n        } else {\n            result.opaque_pairs.push(OpaquePair { byte_offset, words });\n        }\n    }\n    Ok(result)\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn isolated_bytes_follow_literal_little_endian_envelope() {\n        for (command, value) in [(Command::Start, 0), (Command::Freeze, 1)] {\n            let packet = encode(command);\n            let mut expected = [0u8; 512];\n            expected[..32].copy_from_slice(&[\n                0xa5, 0xa5, 0x5a, 0x5a, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 6, 0, value, 0,\n                0, 0, 2, 0, 0, 0, 0x5a, 0x5a, 0xa5, 0xa5,\n            ]);\n            assert_eq!(packet, expected);\n            assert_eq!(inspect(&packet).unwrap().isolated_command(), Some(command));\n        }\n    }\n\n    #[test]\n    fn rejects_truncation_concatenation_and_wrong_endianness() {\n        let packet = encode(Command::Start);\n        for length in [0, 4, 16, 24, 31, 32, 511] {\n            assert_eq!(\n                inspect(&packet[..length]),\n                Err(InspectError::WrongLength { actual: length })\n            );\n        }\n        assert!(inspect(&[packet.as_slice(), packet.as_slice()].concat()).is_err());\n        for offset in [0, 4, 24, 28] {\n            let mut changed = packet;\n            changed[offset..offset + 4].reverse();\n            assert!(inspect(&changed).is_err(), \"offset {offset}\");\n        }\n    }\n\n    #[test]\n    fn rejects_nonzero_reserved_padding_and_unaligned_trailers() {\n        for offset in [8, 15, 32, 511] {\n            let mut packet = encode(Command::Freeze);\n            packet[offset] = 1;\n            assert!(inspect(&packet).is_err(), \"offset {offset}\");\n        }\n        let mut packet = encode(Command::Start);\n        packet.copy_within(24..32, 25);\n        packet[24] = 0;\n        assert_eq!(inspect(&packet), Err(InspectError::MissingAlignedTrailer));\n    }\n\n    #[test]\n    fn unknown_pairs_are_opaque_including_a_marker_pair_inside_payload() {\n        let mut packet = encode(Command::Start);\n        // The old trailer becomes an opaque pair; a new one follows it.\n        packet[32..36].copy_from_slice(&[0x78, 0x56, 0x34, 0x12]);\n        packet[36..40].copy_from_slice(&[0xef, 0xcd, 0xab, 0x90]);\n        packet[40..48].copy_from_slice(&[2, 0, 0, 0, 0x5a, 0x5a, 0xa5, 0xa5]);\n        let result = inspect(&packet).unwrap();\n        assert_eq!(result.pair_count, 3);\n        assert_eq!(\n            result.opaque_pairs,\n            vec![\n                OpaquePair {\n                    byte_offset: 24,\n                    words: [2, 0xa5a5_5a5a]\n                },\n                OpaquePair {\n                    byte_offset: 32,\n                    words: [0x1234_5678, 0x90ab_cdef]\n                },\n            ]\n        );\n        assert_eq!(result.isolated_command(), None);\n    }\n\n    #[test]\n    fn bounds_opaque_pairs_to_one_packet_without_guessing_zero_fill() {\n        let mut packet = [0u8; 512];\n        packet[..4].copy_from_slice(&HEADER);\n        packet[4..8].copy_from_slice(&WIRE_TYPE.to_le_bytes());\n        packet[504..508].copy_from_slice(&WIRE_TYPE.to_le_bytes());\n        packet[508..].copy_from_slice(&FOOTER);\n        let result = inspect(&packet).unwrap();\n        assert_eq!(result.pair_count, 61);\n        assert_eq!(result.opaque_pairs.len(), 61);\n        assert_eq!(result.padding_bytes, 0);\n        assert!(result.known_commands.is_empty());\n    }\n\n    #[test]\n    fn control_key_with_unrecognized_value_is_preserved() {\n        let mut packet = encode(Command::Start);\n        packet[20..24].copy_from_slice(&0x0100_0000u32.to_le_bytes());\n        let result = inspect(&packet).unwrap();\n        assert_eq!(result.opaque_pairs[0].words, [CONTROL_KEY, 0x0100_0000]);\n        assert_eq!(result.isolated_command(), None);\n    }\n}\n"
      },
      {
        "path": "components/ultrasound/convex-decoder/1.0.0/src/convex_compound.rs",
        "sha256": "a87d04c92d51de21aec911267eb73c4ecccdcac75bef13c362b3b3e4f7967359",
        "text": "// SPDX-License-Identifier: AGPL-3.0-or-later\n//! Selected General m2 compound with explicit native64 backing and a separate\n//! trace of RDH writes outside that allocation. No undefined GPU effect inferred.\nuse crate::{Result, archive, convex_bfsp, convex_dtgc, linear_post::unorm};\nuse serde_json::{Value, json};\nuse std::path::Path;\n\npub const BYTES: usize = convex_dtgc::IMAGE_BYTES;\npub const POLICY: &str = \"record-outside-native64-v1\";\npub const STATE_FILES: [&str; 5] = [\n    \"history.u8\",\n    \"output.u8\",\n    \"diff.u8\",\n    \"coefficient.u8\",\n    \"rdh.u8\",\n];\n\n#[derive(Clone)]\npub struct State {\n    pub initialized: bool,\n    pub history: Vec<u8>,\n    pub output: Vec<u8>,\n    pub diff: Vec<u8>,\n    pub coefficient: Vec<u8>,\n    pub rdh: Vec<u8>,\n}\nimpl State {\n    pub fn metadata(&self) -> Value {\n        json!({\"schema_version\":\"convex-compound-state-v1\",\"history_initialized\":self.initialized,\"rdh_write_policy\":POLICY})\n    }\n    pub fn from_bytes(metadata: &Value, files: [Vec<u8>; 5]) -> Result<Self> {\n        let o = metadata\n            .as_object()\n            .ok_or(\"Require compound state metadata\")?;\n        if o.len() != 3\n            || o.keys().any(|s| {\n                ![\"schema_version\", \"history_initialized\", \"rdh_write_policy\"].contains(&s.as_str())\n            })\n            || metadata[\"schema_version\"] != \"convex-compound-state-v1\"\n            || metadata[\"rdh_write_policy\"] != POLICY\n        {\n            return Err(\n                \"Require exact compound state and explicit record-outside-native64-v1 policy\"\n                    .into(),\n            );\n        }\n        let initialized = metadata[\"history_initialized\"]\n            .as_bool()\n            .ok_or(\"Explicit boolean history_initialized required\")?;\n        if files.iter().any(|v| v.len() != BYTES) {\n            return Err(\"Require five complete64x1024UNORM8 backing images\".into());\n        }\n        let [history, output, diff, coefficient, rdh] = files;\n        Ok(Self {\n            initialized,\n            history,\n            output,\n            diff,\n            coefficient,\n            rdh,\n        })\n    }\n    pub fn files(&self) -> [(&'static str, &[u8]); 5] {\n        [\n            (STATE_FILES[0], &self.history),\n            (STATE_FILES[1], &self.output),\n            (STATE_FILES[2], &self.diff),\n            (STATE_FILES[3], &self.coefficient),\n            (STATE_FILES[4], &self.rdh),\n        ]\n    }\n    pub(crate) fn validate(&self) -> Result<()> {\n        if self.files().iter().any(|(_, v)| v.len() != BYTES) {\n            return Err(\"Invalid compound backing length\".into());\n        }\n        Ok(())\n    }\n}\n\npub struct Processor {\n    window: usize,\n    coef0: f32,\n    threshold_a: f32,\n    threshold_b: f32,\n    source_assets: Value,\n    provenance: Value,\n}\npub struct Outcome {\n    pub state: State,\n    pub correlation_kernel: Vec<u8>,\n    pub rdh_outside_native: Vec<u8>,\n}\nimpl Processor {\n    pub(crate) fn selected(&self) -> (usize, f32, f32, f32) {\n        (self.window, self.coef0, self.threshold_a, self.threshold_b)\n    }\n    pub(crate) fn from_selected(\n        window: usize,\n        coef0: f32,\n        threshold_a: f32,\n        threshold_b: f32,\n    ) -> Result<Self> {\n        if !(1..=63).contains(&window)\n            || window.is_multiple_of(2)\n            || !coef0.is_finite()\n            || !threshold_a.is_finite()\n            || !threshold_b.is_finite()\n            || threshold_b <= 0.\n        {\n            return Err(\"Invalid selected compound profile\".into());\n        }\n        Ok(Self {\n            window,\n            coef0,\n            threshold_a,\n            threshold_b,\n            source_assets: Value::Null,\n            provenance: json!({\"policy\":\"selected-memory-profile-v1\"}),\n        })\n    }\n\n    pub fn load(\n        directory: &Path,\n        source: convex_bfsp::Settings,\n        dtgc: convex_dtgc::Settings,\n    ) -> Result<Self> {\n        Self::from_source(&crate::resources::Files(directory), source, dtgc)\n    }\n    pub fn from_source(\n        directory: &dyn crate::resources::Source,\n        source: convex_bfsp::Settings,\n        dtgc: convex_dtgc::Settings,\n    ) -> Result<Self> {\n        let preceding = convex_dtgc::Processor::from_source(directory, source, dtgc)?;\n        // Never activate another model's smoothing bank or silently ignore it.\n        if directory.exists(\"B_Smooth.bin\")? {\n            return Err(\"General requires B_Smooth absent; ThreeLine unsupported\".into());\n        }\n        let bytes = directory.read(\"B_BF.bin\", 20)?;\n        const SHA: &str = \"e0dd053a850c10f0c9f25bbbcc5cafbb77d9e177c18c16f62b6b745245efb3a6\";\n        if bytes.len() != 20 || archive::sha(&bytes) != SHA {\n            return Err(\"Require complete known General B_BF.bin\".into());\n        }\n        let values: Vec<f32> = bytes\n            .as_chunks::<4>()\n            .0\n            .iter()\n            .map(|b| f32::from_le_bytes(*b))\n            .collect();\n        let depth = preceding.report()[\"native_depth_parameter\"]\n            .as_f64()\n            .unwrap() as f32;\n        let mut p = Self::new(depth, values[0], values[1], values[2], values[3])?;\n        p.source_assets = preceding.provenance();\n        let mut files = p.source_assets[\"files\"].as_array().unwrap().clone();\n        files.push(json!({\"name\":\"B_BF.bin\",\"bytes\":20,\"sha256\":SHA}));\n        p.provenance = json!({\"profile\":\"Plus-UC5-2S_16-General-B4-T128-m2-type8\",\"files\":files,\n            \"three_line_enabled\":false,\"smoothing_policy\":\"known-General-B_Smooth-absent-v1\",\"coefficient_payload_copied\":false});\n        Ok(p)\n    }\n    fn new(depth: f32, coef0: f32, threshold_a: f32, threshold_b: f32, width: f32) -> Result<Self> {\n        let n = (((width * 0.1) / depth) * 1024. + 0.5).trunc();\n        if !depth.is_finite()\n            || depth <= 0.\n            || !n.is_finite()\n            || !(1.0..=i32::MAX as f32).contains(&n)\n            || !coef0.is_finite()\n            || !threshold_a.is_finite()\n            || !threshold_b.is_finite()\n            || threshold_b <= 0.\n        {\n            return Err(\"Invalid compound scalar/window parameters\".into());\n        }\n        let window = if n < 32. { 2 * n as usize - 1 } else { 63 };\n        Ok(Self {\n            window,\n            coef0,\n            threshold_a,\n            threshold_b,\n            source_assets: Value::Null,\n            provenance: Value::Null,\n        })\n    }\n    pub fn source_assets(&self) -> Value {\n        self.source_assets.clone()\n    }\n    pub fn provenance(&self) -> Value {\n        self.provenance.clone()\n    }\n    pub fn report(&self) -> Value {\n        json!({\"window\":self.window,\"diff_correlation_dispatch\":[32,1024],\"diff_correlation_local\":[8,16],\n            \"smoothing_dispatch\":[32,1],\"smoothing_local\":[32,1],\"native_image_shape_y_x_components\":[1024,64,4],\n            \"rdh_attempted_write_x_range\":[0,128],\"rdh_native_width\":64,\"rdh_outside_write_calls\":65536,\n            \"rdh_outside_shape_y_x_components\":[1024,64,4],\"rdh_outside_origin_x\":64,\"rdh_write_policy\":POLICY,\n            \"native_fill_region\":[256,1024,1],\"native_fill_exceeds_image\":true,\"native_gpu_result_defined\":false,\n            \"history_copy\":\"full current DTGC -> history after all three kernels; initialized=false also overwrites full output with current\",\n            \"numeric_policy\":\"ordered binary32 without contraction; UNORM8 reads byte/255 and writes clamp then binary32*255 round-even\",\n            \"full_native_lifecycle_reproduced\":false,\"gpu_equivalence_validated\":false})\n    }\n    pub fn process(&self, current: &[u8], before: &State) -> Result<Outcome> {\n        before.validate()?;\n        if current.len() != BYTES {\n            return Err(\"Require exact64x1024 DTGC image\".into());\n        }\n        let mut state = before.clone();\n        // DiffAbs writes only columns0..31; prior columns32..63 remain.\n        for y in 0..1024 {\n            for x in 0..32 {\n                for c in 0..4 {\n                    let k = (y * 64 + x) * 4 + c;\n                    state.diff[k] =\n                        unorm((normalized(current[k]) - normalized(before.history[k])).abs());\n                }\n            }\n        }\n        let mut outside = vec![0; BYTES]; // every component is written, no invented retained state\n        for x in 0..32 {\n            let idx = (self.window / 2) as isize;\n            let mut sum = [0.; 4];\n            for i in 0..self.window {\n                for (c, s) in sum.iter_mut().enumerate() {\n                    *s += sample(&state.diff, x, i as isize - idx, c);\n                }\n            }\n            for y in 0..1024 {\n                if y > 0 {\n                    for (c, s) in sum.iter_mut().enumerate() {\n                        // Native rolling recurrence is preserved verbatim: this is\n                        // not replaced with a symmetric mathematical window.\n                        *s += sample(&state.diff, x, y as isize + idx, c);\n                        *s -= sample(&state.diff, x, y as isize - idx, c);\n                    }\n                }\n                for (c, s) in sum.iter().enumerate() {\n                    let mean = (*s / self.window as f32) * 255.;\n                    let adaptive = ((mean - self.threshold_a) / self.threshold_b).clamp(0., 1.);\n                    let rdh = (0.3_f32 - 0.125) * adaptive + 0.125;\n                    let coefficient = (1. - adaptive) * self.coef0;\n                    if !coefficient.is_finite() || !rdh.is_finite() {\n                        return Err(\"Nonfinite compound arithmetic; input state unchanged\".into());\n                    }\n                    state.coefficient[(y * 64 + x) * 4 + c] = unorm(coefficient);\n                    let dest_x = x * 4 + c;\n                    // Record every attempted write, with native bounds intact.\n                    let (dest, xx) = if dest_x < 64 {\n                        (&mut state.rdh, dest_x)\n                    } else {\n                        (&mut outside, dest_x - 64)\n                    };\n                    dest[(y * 64 + xx) * 4..(y * 64 + xx) * 4 + 4].fill(unorm(rdh));\n                }\n            }\n        }\n        for y in 0..1024 {\n            for x in 0..32 {\n                for c in 0..4 {\n                    let k = (y * 64 + x) * 4 + c;\n                    let corr = normalized(state.coefficient[k]);\n                    let v =\n                        normalized(current[k]) * (1. - corr) + normalized(before.history[k]) * corr;\n                    state.output[k] = unorm(v);\n                }\n            }\n        }\n        let correlation_kernel = state.output.clone();\n        if !before.initialized {\n            state.output.copy_from_slice(current);\n        }\n        state.history.copy_from_slice(current);\n        state.initialized = true;\n        Ok(Outcome {\n            state,\n            correlation_kernel,\n            rdh_outside_native: outside,\n        })\n    }\n}\nfn normalized(value: u8) -> f32 {\n    value as f32 / 255.\n}\nfn sample(image: &[u8], x: usize, y: isize, c: usize) -> f32 {\n    normalized(image[(y.clamp(0, 1023) as usize * 64 + x) * 4 + c])\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n    fn state(initialized: bool) -> State {\n        State {\n            initialized,\n            history: vec![0; BYTES],\n            output: vec![151; BYTES],\n            diff: vec![37; BYTES],\n            coefficient: vec![83; BYTES],\n            rdh: vec![213; BYTES],\n        }\n    }\n    #[test]\n    fn first_copy_happens_after_kernels_and_history_is_current_not_correlation() {\n        let p = Processor::new(3., 0.5, 50., 20., 1.).unwrap();\n        let current = vec![20; BYTES];\n        let a = p.process(&current, &state(false)).unwrap();\n        assert_eq!(a.state.output, current);\n        assert_eq!(a.state.history, current);\n        assert!(a.state.initialized);\n        assert_eq!(a.correlation_kernel[0], 10);\n        assert_eq!(a.state.coefficient[0], 128);\n        assert_eq!(a.state.rdh[0], 32);\n        assert_eq!(a.rdh_outside_native[0], 32);\n        let b = p.process(&vec![40; BYTES], &a.state).unwrap();\n        assert_eq!(b.state.output[0], 30);\n        assert_eq!(b.state.history[0], 40);\n        assert_eq!(b.state.output[128], 20); // output's unwritten half retains first full copy\n    }\n    #[test]\n    fn native_shapes_and_unwritten_regions_are_preserved() {\n        let p = Processor::new(12., 0.5, 50., 20., 1.).unwrap();\n        assert_eq!(p.window, 17);\n        let a = p.process(&vec![255; BYTES], &state(true)).unwrap();\n        for y in 0..1024 {\n            let k = (y * 64 + 32) * 4;\n            assert_eq!(&a.state.diff[k..k + 128], &[37; 128]);\n            assert_eq!(&a.state.coefficient[k..k + 128], &[83; 128]);\n            assert_eq!(&a.state.output[k..k + 128], &[151; 128]);\n        }\n        assert!(a.state.rdh.iter().all(|v| *v == 76));\n        assert!(a.rdh_outside_native.iter().all(|v| *v == 76));\n    }\n    #[test]\n    fn native_rolling_recurrence_is_not_a_recentered_mean() {\n        let p = Processor::new(12., 1., 0., 255., 1.).unwrap();\n        let mut current = vec![0; BYTES];\n        // N17: native y1 removes edge row0, while adding row9. A high\n        // row0 therefore leaves eight copies rather than nine.\n        current[..128].fill(255);\n        let a = p.process(&current, &state(true)).unwrap();\n        assert_eq!(a.state.coefficient[0], 120);\n        assert_eq!(a.state.coefficient[64 * 4], 135);\n    }\n    #[test]\n    fn state_policy_and_lengths_cannot_be_implied() {\n        let s = state(false);\n        let mut v = s.metadata();\n        v[\"rdh_write_policy\"] = json!(\"ignore\");\n        assert!(State::from_bytes(&v, std::array::from_fn(|_| vec![0; BYTES])).is_err());\n        let mut s = s;\n        s.rdh.pop();\n        assert!(\n            Processor::new(3., 0.5, 50., 20., 1.)\n                .unwrap()\n                .process(&vec![0; BYTES], &s)\n                .is_err()\n        );\n        assert!(Processor::new(1000., 0.5, 50., 20., 0.).is_err());\n    }\n}\n"
      },
      {
        "path": "components/ultrasound/convex-decoder/1.0.0/src/convex_configuration.rs",
        "sha256": "dbdc8df42ad13c65de76e15ca08f767bdce12b79e4667845f94f58902cd61ef8",
        "text": "// SPDX-License-Identifier: AGPL-3.0-or-later\n//! Offline, hash-bound UC5-2S producer bundle. Not a transport/executable plan.\nuse crate::{\n    Result,\n    convex_parameters::{self as p, Adc8, Prf8, TxWave8, Upload},\n    convex_producers as c,\n};\nuse serde_json::{Value, json};\nuse std::{collections::BTreeMap, path::Path};\nconst EXTRA: [(&str, usize); 5] = [\n    (\"A_BF.bin\", 44),\n    (\"B_TxControl.bin\", 1024),\n    (\"B_DynamicFilter.bin\", 43084),\n    (\"B_LPF.bin\", 256),\n    (\"A_Up4Coef.bin\", 364),\n];\npub struct Request {\n    depth: usize,\n    frequency: usize,\n    focus: usize,\n    logic: u32,\n    low_power: u8,\n    disable_low_power: bool,\n}\nimpl Request {\n    pub fn parse(v: &Value) -> Result<Self> {\n        let keys = [\n            \"schema_version\",\n            \"depth_index\",\n            \"frequency_index\",\n            \"focus_index\",\n            \"logic_compile_version\",\n            \"low_power_mode\",\n            \"disable_low_power\",\n            \"state_policy\",\n            \"register_order\",\n        ];\n        let obj = v.as_object().ok_or(\"Convex request must be an object\")?;\n        if obj.len() != keys.len()\n            || obj.keys().any(|k| !keys.contains(&k.as_str()))\n            || v[\"schema_version\"] != \"convex-b-producers-request-v1\"\n            || v[\"state_policy\"] != \"fresh-b-only-v1\"\n            || v[\"register_order\"] != \"ascending-address-portability-v1\"\n        {\n            return Err(\"Require exact convex-b-producers-request-v1 with explicit fresh-B state and register-order policy\".into());\n        }\n        let get = |k: &str, max: u64| {\n            v[k].as_u64()\n                .filter(|v| *v <= max)\n                .ok_or_else(|| format!(\"Invalid {k}\"))\n        };\n        Ok(Self {\n            depth: get(\"depth_index\", 7)? as usize,\n            frequency: get(\"frequency_index\", 2)? as usize,\n            focus: get(\"focus_index\", 6)? as usize,\n            logic: get(\"logic_compile_version\", u32::MAX as u64)? as u32,\n            low_power: get(\"low_power_mode\", 3)? as u8,\n            disable_low_power: v[\"disable_low_power\"]\n                .as_bool()\n                .ok_or(\"Explicit disable_low_power boolean required\")?,\n        })\n    }\n    fn json(&self) -> Value {\n        json!({\"schema_version\":\"convex-b-producers-request-v1\",\"depth_index\":self.depth,\"frequency_index\":self.frequency,\n        \"focus_index\":self.focus,\"logic_compile_version\":self.logic,\"low_power_mode\":self.low_power,\"disable_low_power\":self.disable_low_power,\n        \"state_policy\":\"fresh-b-only-v1\",\"register_order\":\"ascending-address-portability-v1\"})\n    }\n}\nstruct Packet {\n    name: &'static str,\n    kind: u32,\n    wire: u32,\n    bytes: Vec<u8>,\n    role: &'static str,\n}\nfn packet(kind: u32, metadata: u32, payload: &[u8]) -> Result<Vec<u8>> {\n    if payload.is_empty()\n        || !payload.len().is_multiple_of(4)\n        || payload.len() > 4096 * 4\n        || metadata > 4095\n        || kind > 255\n    {\n        return Err(\"Invalid bounded producer payload/metadata\".into());\n    }\n    let meaningful = payload.len() + 24;\n    let mut result = vec![0; meaningful.div_ceil(512) * 512];\n    result[..16].copy_from_slice(&c::words([0x5a5aa5a5, kind | metadata << 20, 0, 0]));\n    result[16..16 + payload.len()].copy_from_slice(payload);\n    result[16 + payload.len()..meaningful].copy_from_slice(&c::words([kind, 0xa5a55a5a]));\n    Ok(result)\n}\nfn registers(entries: &[(u32, u32)]) -> Result<Vec<u8>> {\n    if entries.is_empty() || entries.len() > 61 {\n        return Err(\"Selected register packet requires1..61pairs\".into());\n    }\n    packet(2, 0, &c::words(entries.iter().flat_map(|&(a, b)| [a, b])))\n}\nstruct Inputs {\n    raw: BTreeMap<String, Vec<u8>>,\n    hv: Vec<u8>,\n    files: Value,\n    matches: Vec<String>,\n    hv_file: Value,\n}\n/// Inputs are loaded and hash-bound before opening USB. Logic/low-power can\n/// only be supplied later by the acquisition coordinator's persisted message.\npub(crate) struct Prepared {\n    inputs: Inputs,\n    selection: Value,\n}\nimpl Prepared {\n    pub(crate) fn load(directory: &Path, hv: &Path, selection: Value) -> Result<Self> {\n        Self::from_source(\n            &crate::resources::Files(directory),\n            &crate::resources::Files(hv),\n            selection,\n        )\n    }\n    pub(crate) fn from_source(\n        directory: &dyn crate::resources::Source,\n        hv: &dyn crate::resources::Source,\n        selection: Value,\n    ) -> Result<Self> {\n        validate_selection(&selection)?;\n        Ok(Self {\n            inputs: load_source(directory, hv)?,\n            selection,\n        })\n    }\n    pub(crate) fn report(&self) -> Value {\n        json!({\"selection\":self.selection,\"files\":self.inputs.files,\n            \"hv_file\":self.inputs.hv_file,\"matching_verified_asset_groups\":self.inputs.matches})\n    }\n    pub(crate) fn bind(self, logic: u32, low_power: u8) -> Result<Bundle> {\n        let mut request = self.selection;\n        request[\"schema_version\"] = json!(\"convex-b-producers-request-v1\");\n        request[\"logic_compile_version\"] = json!(logic);\n        request[\"low_power_mode\"] = json!(low_power);\n        Bundle::build(self.inputs, Request::parse(&request)?)\n    }\n}\n/// Validate the fixed acquisition inputs before a caller starts a preview or\n/// opens USB. This report is not a capability to bind hardware parameters.\npub fn preparation_report(directory: &Path, hv: &Path, selection: Value) -> Result<Value> {\n    Ok(Prepared::load(directory, hv, selection)?.report())\n}\nfn validate_selection(v: &Value) -> Result<()> {\n    let keys = [\n        \"schema_version\",\n        \"depth_index\",\n        \"frequency_index\",\n        \"focus_index\",\n        \"disable_low_power\",\n        \"state_policy\",\n        \"register_order\",\n    ];\n    if !v\n        .as_object()\n        .is_some_and(|o| o.len() == keys.len() && o.keys().all(|k| keys.contains(&k.as_str())))\n        || v[\"schema_version\"] != \"convex-b-message-selection-v1\"\n        || v[\"state_policy\"] != \"fresh-b-only-v1\"\n        || v[\"register_order\"] != \"ascending-address-portability-v1\"\n        || ![\n            (\"depth_index\", 7),\n            (\"frequency_index\", 2),\n            (\"focus_index\", 6),\n        ]\n        .iter()\n        .all(|(key, max)| v[key].as_u64().is_some_and(|n| n <= *max))\n        || v[\"disable_low_power\"].as_bool().is_none()\n    {\n        return Err(\"Require exact convex-b-message-selection-v1 and bounded B-only selection; no caller-supplied logic or low-power\".into());\n    }\n    Ok(())\n}\nfn load(directory: &Path, hv_directory: &Path) -> Result<Inputs> {\n    load_source(\n        &crate::resources::Files(directory),\n        &crate::resources::Files(hv_directory),\n    )\n}\nfn load_source(\n    directory: &dyn crate::resources::Source,\n    hv_directory: &dyn crate::resources::Source,\n) -> Result<Inputs> {\n    let mut raw = BTreeMap::new();\n    let mut files = Vec::new();\n    for (name, size) in p::FILES.into_iter().chain(EXTRA) {\n        let b = directory.read(name, size as u64)?;\n        p::exact(&b, size, name)?;\n        files.push(json!({\"name\":name,\"bytes\":b.len(),\"sha256\":p::sha(&b)}));\n        raw.insert(name.into(), b);\n    }\n    let known: Value = serde_json::from_str(include_str!(\"known_convex_producer_assets.json\"))\n        .map_err(|e| e.to_string())?;\n    let matches: Vec<String> = known[\"profiles\"]\n        .as_object()\n        .ok_or(\"Missing known producer groups\")?\n        .iter()\n        .filter_map(|(name, expected)| {\n            expected\n                .as_object()?\n                .iter()\n                .all(|(name, meta)| {\n                    files.iter().any(|r| {\n                        r[\"name\"] == *name\n                            && r[\"sha256\"] == meta[\"sha256\"]\n                            && r[\"bytes\"] == meta[\"bytes\"]\n                    })\n                })\n                .then_some(name.clone())\n        })\n        .collect();\n    if matches.is_empty() {\n        return Err(\n            \"Inputs must match one complete known twelve-file UC5-2S producer group\".into(),\n        );\n    }\n    let g = c::Geometry::parse(&raw[\"A_Probe.bin\"])?;\n    let name = format!(\"{}.coe\", g.hv_index);\n    let meta = &known[\"hv_files\"][&name];\n    let size = meta[\"bytes\"].as_u64().ok_or(\"Unrecognized HV selection\")?;\n    let hv = hv_directory.read(&name, size)?;\n    p::exact(&hv, size as usize, &name)?;\n    if meta[\"sha256\"] != p::sha(&hv) {\n        return Err(\"HV input hash mismatch\".into());\n    }\n    let hv_file = json!({\"name\":name,\"bytes\":hv.len(),\"sha256\":p::sha(&hv)});\n    Ok(Inputs {\n        raw,\n        hv,\n        files: json!(files),\n        matches,\n        hv_file,\n    })\n}\n/// Named fixed producers only. Payloads remain private to this module and are\n/// neither accepted by the linear executor nor exported by the report CLI.\npub struct Bundle {\n    request: Request,\n    inputs: Inputs,\n    packets: Vec<Packet>,\n    tx: Value,\n    scan: Value,\n    waveform: usize,\n    register_count: usize,\n}\nimpl Bundle {\n    pub(crate) fn into_packets(self) -> Vec<(&'static str, Vec<u8>)> {\n        self.packets\n            .into_iter()\n            .map(|p| (p.name, p.bytes))\n            .collect()\n    }\n    pub fn load(directory: &Path, hv_directory: &Path, request: Request) -> Result<Self> {\n        Self::build(load(directory, hv_directory)?, request)\n    }\n    fn build(inputs: Inputs, request: Request) -> Result<Self> {\n        let r = &inputs.raw;\n        let g = c::Geometry::parse(&r[\"A_Probe.bin\"])?;\n        let selected = Prf8::parse(&r[\"B_PRF.bin\"])?.select(request.depth, g.clock)?;\n        let selection = c::select_tx(\n            &r[\"B_TxControl.bin\"],\n            g,\n            request.depth,\n            request.frequency,\n            request.focus,\n        )?;\n        let wave = TxWave8::parse(&r[\"A_TxWave.bin\"])?.fundamental(selection.waveform)?;\n        let tx = c::tx(&r[\"B_TxControl.bin\"], g, &selection, wave)?;\n        let rx = c::rx(g)?;\n        let filters = c::filters(\n            &r[\"B_DynamicFilter.bin\"],\n            &r[\"B_LPF.bin\"],\n            &r[\"A_Up4Coef.bin\"],\n            request.depth,\n            request.frequency,\n        )?;\n        let scan = c::scan(\n            g,\n            selected,\n            &r[\"A_BF.bin\"],\n            request.logic,\n            request.low_power,\n            request.disable_low_power,\n        )?;\n        let mut map = BTreeMap::new();\n        let mut add = |entries: &[(u32, u32)]| -> Result<()> {\n            for &(k, v) in entries {\n                if let Some(previous) = map.insert(k, v)\n                    && previous != v\n                {\n                    return Err(format!(\"Conflicting selected producer register{k:08x}\"));\n                }\n            }\n            Ok(())\n        };\n        let adc = Adc8::parse(&r[\"A_ADC.bin\"])?;\n        add(&adc\n            .0\n            .iter()\n            .enumerate()\n            .map(|(i, &v)| (0x50035 + i as u32, v))\n            .collect::<Vec<_>>())?;\n        add(&[\n            (0x70003, wave.fields[1] | wave.fields[4].wrapping_shl(8)),\n            (0x70021, wave.fields[0]),\n        ])?;\n        add(&tx.gates)?;\n        add(&filters.registers)?;\n        add(&scan.registers)?;\n        let f = selected.fields;\n        let points = f[1] as i64;\n        if points <= 0 || f[11] < 0 {\n            return Err(\"Points/multiplier outside selected B branch\".into());\n        }\n        let upload = points * 2 / filters.iq_m as i64;\n        let bf_cut = c::integer(\n            (((g.offset + g.offset) / f32::from_bits(0x3fc51eb8)) * g.clock * 0.25) as f64,\n            \"BF cut\",\n        )? as i64;\n        add(&[\n            (0x50030, 0),\n            (0x5000e, 2),\n            (0x5001e, 3),\n            (0x50009, 2),\n            (0x60017, c::half(upload, 0)?),\n            (0x60018, c::half((points + 32) * 2, bf_cut)?),\n            (0x60042, c::half(0, 32)?),\n            (0x60046, c::half((f[11] as i64 * upload + 32) / 4, 0)?),\n            (0x60047, 2),\n            (0x60048, c::unsigned((2 * upload + 32) / 4)?),\n            (0x50047, c::unsigned(f[8] as i64)?),\n            (0x50033, 0),\n            (0x50034, 0),\n        ])?;\n        let register_count = map.len();\n        let sorted: Vec<_> = map.into_iter().collect();\n        let mut packets = vec![\n            Packet {\n                name: \"probe-index-activation\",\n                kind: 100,\n                wire: 2,\n                bytes: registers(&[(0x50060, 1)])?,\n                role: \"native immediate candidate; not a scheduler barrier\",\n            },\n            Packet {\n                name: \"deduplicated-registers\",\n                kind: 2,\n                wire: 2,\n                bytes: registers(&sorted)?,\n                role: \"buffered family; ascending-address portability order\",\n            },\n        ];\n        for (name, kind, metadata, payload) in [\n            (\"TX16\", 5, 8, tx.payload),\n            (\"RX-ADC8\", 6, 0, rx),\n            (\"B-LPF\", 8, 1280, filters.lpf),\n            (\"B-IQ\", 16, 512, filters.iq),\n            (\"Up4\", 18, 0, filters.up4),\n            (\"HV-SW\", 21, 0, c::hv(&inputs.hv)?),\n        ] {\n            packets.push(Packet {\n                name,\n                kind,\n                wire: kind,\n                bytes: packet(kind, metadata, &payload)?,\n                role: \"buffered family\",\n            });\n        }\n        for (name, kind, upload) in [\n            (\"ATGC\", 12, Upload::Atgc),\n            (\"Apo\", 13, Upload::Apo),\n            (\"ApoComp\", 14, Upload::ApoComp),\n        ] {\n            packets.push(Packet {\n                name,\n                kind,\n                wire: kind,\n                bytes: upload.encode(&r[upload.file()])?,\n                role: \"buffered family\",\n            });\n        }\n        packets.push(Packet {\n            name: \"ScanCtrl\",\n            kind: 1,\n            wire: 1,\n            bytes: packet(1, 0, &scan.payload)?,\n            role: \"buffered family\",\n        });\n        packets.push(Packet {\n            name: \"voltage-state\",\n            kind: 2,\n            wire: 2,\n            bytes: wave.voltage_packet(),\n            role: \"direct candidate with repeated key; never deduplicated\",\n        });\n        Ok(Self {\n            request,\n            inputs,\n            packets,\n            tx: tx.report,\n            scan: scan.report,\n            waveform: selection.waveform,\n            register_count,\n        })\n    }\n    pub fn report(&self) -> Value {\n        json!({\"schema_version\":\"convex-b-producer-bundle-v1\",\"profile\":\"convex-01\",\"vid_pid\":\"04b4:4611\",\"software\":crate::identity::build_provenance(),\n            \"mode\":\"offline_only\",\"selected_branch_producers_materialized\":true,\"complete_configuration\":false,\"executable_plan\":false,\"usb_accessed\":false,\n            \"request\":self.request.json(),\"matching_verified_asset_groups\":self.inputs.matches,\"files\":self.inputs.files,\"hv_file\":self.inputs.hv_file,\n            \"selection\":{\"fundamental_waveform_index\":self.waveform,\"origin\":\"B_TxControl depth/frequency/focus getters\",\"TXchannels\":16,\"ADCvariant\":8,\n                \"mode\":\"B\",\"harmonic\":false,\"NE\":false,\"PA\":false,\"C_D_frequencies_for_Up4\":0},\n            \"TX\":self.tx,\"ScanCtrl\":self.scan,\"deduplicated_register_count\":self.register_count,\n            \"packets\":self.packets.iter().map(|p|json!({\"producer\":p.name,\"internal_kind\":p.kind,\"wire_type\":p.wire,\"bytes\":p.bytes.len(),\"sha256\":p::sha(&p.bytes),\"role\":p.role})).collect::<Vec<_>>(),\n            \"packet_payloads_exported\":false,\"listing_is_execution_order\":false,\"native_buffer_drain_order\":[2,5,6,8,16,18,21,12,13,14,1,99],\n            \"controls\":[{\"name\":\"Start\",\"internal_kind\":99,\"wire_type\":2,\"sha256\":p::sha(&crate::convex_command::encode(crate::convex_command::Command::Start))},\n                {\"name\":\"Freeze\",\"internal_kind\":99,\"wire_type\":2,\"sha256\":p::sha(&crate::convex_command::encode(crate::convex_command::Command::Freeze))}],\n            \"numerical_policy\":\"sequential host binary32; TX +/-0.5 in binary64 then truncation, RX +/-0.5 in binary32; checked integer conversions\",\n            \"register_order_policy\":\"ascending-address-portability-v1; native unordered_map iteration is not reproduced\",\n            \"padding_policy\":\"explicit zeros; no uninitialized native bytes copied\",\"physical_calibration\":null,\"gpu_or_native_equivalence_validated\":false,\n            \"unresolved_required\":[\"actual logic-version/low-power hardware message and reconnect attribution\",\"callback side effects (including LogicType!=0 and voltage10)\",\n                \"complete lifecycle executor and hardware acknowledgements/error recovery\",\"attributed transfer order/timing and numeric reference runtime\",\"phantom image and verified acoustic/electrical stop\"],\n            \"limitations\":[\"Materialized producer families do not prove a complete native configuration or executable activation sequence\",\n                \"Declared fresh B-only state excludes harmonic/PA/NE/debug/C/D and focus overrides\",\n                \"Native first ordinary packet can write implicit Freeze; kind100 can write immediately; timer can later write Start without UnFreeze\",\n                \"No USB access, device compatibility, voltage units, sound speed or geometric calibration inferred from file settings\",\n                \"Vendor inputs read once and hash-bound; reports export digests and selected derived settings, not payloads\"]})\n    }\n}\n\n#[cfg(test)]\npub(crate) mod tests {\n    use super::*;\n    fn put(raw: &mut [u8], off: usize, v: u32) {\n        raw[off..off + 4].copy_from_slice(&v.to_le_bytes());\n    }\n    fn request() -> Value {\n        json!({\"schema_version\":\"convex-b-producers-request-v1\",\"depth_index\":0,\"frequency_index\":1,\"focus_index\":6,\n        \"logic_compile_version\":0,\"low_power_mode\":2,\"disable_low_power\":false,\"state_policy\":\"fresh-b-only-v1\",\"register_order\":\"ascending-address-portability-v1\"})\n    }\n    pub(crate) fn bundle() -> Bundle {\n        Bundle::build(inputs(), Request::parse(&request()).unwrap()).unwrap()\n    }\n    pub(crate) fn prepared() -> Prepared {\n        let mut v = request();\n        v.as_object_mut().unwrap().remove(\"logic_compile_version\");\n        v.as_object_mut().unwrap().remove(\"low_power_mode\");\n        v[\"schema_version\"] = json!(\"convex-b-message-selection-v1\");\n        Prepared {\n            inputs: inputs(),\n            selection: v,\n        }\n    }\n    fn inputs() -> Inputs {\n        let mut raw: BTreeMap<String, Vec<u8>> = p::FILES\n            .into_iter()\n            .chain(EXTRA)\n            .map(|(n, s)| (n.into(), vec![0; s]))\n            .collect();\n        let probe = raw.get_mut(\"A_Probe.bin\").unwrap();\n        for (o, v) in [\n            (0, 0.5f32.to_bits()),\n            (4, 50f32.to_bits()),\n            (8, 10f32.to_bits()),\n            (0x10, 1),\n            (0x14, 2),\n            (0x18, 100f32.to_bits()),\n            (0x1c, 8),\n            (0x24, 64),\n            (0x40, 16),\n        ] {\n            put(probe, o, v);\n        }\n        let bf = raw.get_mut(\"A_BF.bin\").unwrap();\n        for (o, v) in [(4, 4), (12, 128), (16, 64)] {\n            put(bf, o, v);\n        }\n        let tx = raw.get_mut(\"B_TxControl.bin\").unwrap();\n        for (i, v) in [1, 2, 3].into_iter().enumerate() {\n            put(tx, 4 * i, v);\n        }\n        for d in 0..8 {\n            for j in 0..8 {\n                put(tx, 0x40 + 44 * d + 4 * j, 20 + 10 * j as u32);\n            }\n            for (j, v) in [2, 1, 0].into_iter().enumerate() {\n                put(tx, 0x40 + 44 * d + 32 + 4 * j, v);\n            }\n            put(tx, 0x1a0 + 16 * d, 16);\n            for j in 1..4 {\n                put(tx, 0x1a0 + 16 * d + 4 * j, (d as u32 + 1) * 20);\n            }\n        }\n        let prf = raw.get_mut(\"B_PRF.bin\").unwrap();\n        put(prf, 0, 8);\n        for (bank, v) in [0, 100, 1000, 1000, 2000, 24, 24, 4, 2, 2, 4, 4]\n            .into_iter()\n            .enumerate()\n        {\n            for d in 0..8 {\n                put(prf, 4 + bank * 32 + d * 4, v);\n            }\n        }\n        let dynf = raw.get_mut(\"B_DynamicFilter.bin\").unwrap();\n        put(dynf, 0, 2);\n        for f in 0..3 {\n            put(dynf, 0xa834 + 4 * f, 3);\n        }\n        Inputs {\n            raw,\n            hv: b\"01020304,\\r\\nA0B0C0D0;\".to_vec(),\n            files: json!([]),\n            matches: vec![],\n            hv_file: json!({\"synthetic\":true}),\n        }\n    }\n    #[test]\n    fn request_requires_all_logic_and_policy_fields_and_refuses_unmapped_scopes() {\n        assert!(Request::parse(&request()).is_ok());\n        for key in request().as_object().unwrap().keys() {\n            let mut v = request();\n            v.as_object_mut().unwrap().remove(key);\n            assert!(Request::parse(&v).is_err(), \"{key}\");\n        }\n        for (key, value) in [\n            (\"depth_index\", json!(8)),\n            (\"frequency_index\", json!(3)),\n            (\"focus_index\", json!(7)),\n            (\"low_power_mode\", json!(4)),\n            (\"logic_compile_version\", json!(4294967296u64)),\n            (\"logic_compile_version\", json!(1.5)),\n            (\"disable_low_power\", json!(0)),\n            (\"state_policy\", json!(\"remembered\")),\n            (\"register_order\", json!(\"native\")),\n            (\"harmonic\", json!(true)),\n        ] {\n            let mut v = request();\n            v[key] = value;\n            assert!(Request::parse(&v).is_err(), \"{key}\");\n        }\n    }\n    #[test]\n    fn bounded_packet_envelopes_keep_count_metadata_trailers_and_zero_padding() {\n        let p = packet(5, 8, &[7; 32]).unwrap();\n        assert_eq!(p.len(), 512);\n        assert_eq!(p::word(&p, 4), 0x00800005);\n        assert_eq!(&p[48..56], &c::words([5, 0xa5a55a5a]));\n        assert!(p[56..].iter().all(|v| *v == 0));\n        let p = packet(6, 0, &vec![9; 1024]).unwrap();\n        assert_eq!(p.len(), 1536);\n        assert_eq!(&p[1040..1048], &c::words([6, 0xa5a55a5a]));\n        for (kind, meta, raw) in [\n            (2, 0, vec![]),\n            (8, 4096, vec![0; 4]),\n            (256, 0, vec![0; 4]),\n            (5, 0, vec![0; 3]),\n            (6, 0, vec![0; 16388]),\n        ] {\n            assert!(packet(kind, meta, &raw).is_err());\n        }\n        assert!(registers(&[(1, 2); 62]).is_err());\n    }\n    #[test]\n    fn full_synthetic_bundle_materializes13_families_and_distinguishes_activation_voltage_and_controls()\n     {\n        let b = Bundle::build(inputs(), Request::parse(&request()).unwrap()).unwrap();\n        let report = b.report();\n        assert_eq!(report[\"packets\"].as_array().unwrap().len(), 13);\n        assert_eq!(report[\"usb_accessed\"], false);\n        assert_eq!(report[\"complete_configuration\"], false);\n        assert_eq!(report[\"executable_plan\"], false);\n        assert_eq!(report[\"listing_is_execution_order\"], false);\n        assert_eq!(report[\"ScanCtrl\"][\"nodes\"], 194);\n        let names: Vec<_> = b.packets.iter().map(|p| p.name).collect();\n        assert_eq!(\n            names,\n            [\n                \"probe-index-activation\",\n                \"deduplicated-registers\",\n                \"TX16\",\n                \"RX-ADC8\",\n                \"B-LPF\",\n                \"B-IQ\",\n                \"Up4\",\n                \"HV-SW\",\n                \"ATGC\",\n                \"Apo\",\n                \"ApoComp\",\n                \"ScanCtrl\",\n                \"voltage-state\"\n            ]\n        );\n        let regs = crate::convex_command::inspect(&b.packets[1].bytes).unwrap();\n        let pairs = regs.opaque_pairs;\n        let keys: Vec<_> = pairs.iter().map(|p| p.words[0]).collect();\n        assert!(keys.windows(2).all(|w| w[0] < w[1]));\n        assert!(pairs.iter().any(|p| p.words == [0x60017, 1000]));\n        assert!(pairs.iter().any(|p| p.words == [0x60018, 324 << 16 | 2064]));\n        assert!(\n            pairs\n                .iter()\n                .all(|p| p.words[0] != 0x60001 && p.words[0] != 0x50060 && p.words[0] != 0x70034)\n        );\n        let voltage = crate::convex_command::inspect(&b.packets[12].bytes).unwrap();\n        assert_eq!(voltage.opaque_pairs[0].words, [0x70034, 0]);\n        assert_eq!(voltage.opaque_pairs[2].words, [0x70034, 0x10]);\n        assert_eq!(b.packets[0].kind, 100);\n        assert_eq!(b.packets[0].wire, 2);\n        for p in &b.packets {\n            assert!(p.bytes.len().is_multiple_of(512));\n            assert_eq!(p::word(&p.bytes, 0), 0x5a5aa5a5);\n        }\n    }\n    #[test]\n    fn producer_build_rejects_overflow_and_branch_mismatches_before_any_transport_exists() {\n        for case in 0..8 {\n            let mut f = inputs();\n            match case {\n                0 => put(f.raw.get_mut(\"A_Probe.bin\").unwrap(), 0, f32::NAN.to_bits()),\n                1 => put(f.raw.get_mut(\"A_Probe.bin\").unwrap(), 0x14, 1),\n                2 => put(f.raw.get_mut(\"A_Probe.bin\").unwrap(), 0x3c, 4),\n                3 => put(f.raw.get_mut(\"A_BF.bin\").unwrap(), 12, 256),\n                4 => put(f.raw.get_mut(\"B_PRF.bin\").unwrap(), 4 + 32 * 5, 16),\n                5 => put(f.raw.get_mut(\"B_PRF.bin\").unwrap(), 4 + 32 * 2, 100000),\n                6 => put(f.raw.get_mut(\"B_TxControl.bin\").unwrap(), 0, 65536),\n                _ => put(\n                    f.raw.get_mut(\"B_DynamicFilter.bin\").unwrap(),\n                    0xa834 + 4,\n                    256,\n                ),\n            }\n            assert!(\n                Bundle::build(f, Request::parse(&request()).unwrap()).is_err(),\n                \"case{case}\"\n            );\n        }\n    }\n    #[test]\n    fn public_loader_rejects_unknown_twelve_file_group_and_symlink_without_exporting_payloads() {\n        use std::sync::atomic::{AtomicUsize, Ordering};\n        static NEXT: AtomicUsize = AtomicUsize::new(0);\n        let path = std::env::temp_dir().join(format!(\n            \"SYNTHETIC-convex-bundle-{}-{}\",\n            std::process::id(),\n            NEXT.fetch_add(1, Ordering::Relaxed)\n        ));\n        std::fs::create_dir(&path).unwrap();\n        let input = inputs();\n        for (n, b) in &input.raw {\n            std::fs::write(path.join(n), b).unwrap();\n        }\n        assert!(\n            Bundle::load(&path, &path, Request::parse(&request()).unwrap())\n                .err()\n                .unwrap()\n                .contains(\"complete known\")\n        );\n        std::fs::remove_file(path.join(\"A_BF.bin\")).unwrap();\n        std::os::unix::fs::symlink(path.join(\"A_Probe.bin\"), path.join(\"A_BF.bin\")).unwrap();\n        assert!(Bundle::load(&path, &path, Request::parse(&request()).unwrap()).is_err());\n        std::fs::remove_dir_all(path).unwrap();\n    }\n}\n\n#[cfg(test)]\nmod selection_tests {\n    use super::*;\n    #[test]\n    fn live_selection_requires_exact_explicit_b_scope_without_declared_logic() {\n        let valid = tests::prepared().selection;\n        validate_selection(&valid).unwrap();\n        for key in valid.as_object().unwrap().keys() {\n            let mut v = valid.clone();\n            v.as_object_mut().unwrap().remove(key);\n            assert!(validate_selection(&v).is_err());\n        }\n        for (key, value) in [\n            (\"logic_compile_version\", json!(0)),\n            (\"low_power_mode\", json!(0)),\n            (\"depth_index\", json!(8)),\n            (\"frequency_index\", json!(3)),\n            (\"focus_index\", json!(7)),\n            (\"disable_low_power\", json!(0)),\n            (\"state_policy\", json!(\"resume\")),\n        ] {\n            let mut v = valid.clone();\n            v[key] = value;\n            assert!(validate_selection(&v).is_err());\n        }\n    }\n}\n"
      },
      {
        "path": "components/ultrasound/convex-decoder/1.0.0/src/convex_dsc.rs",
        "sha256": "1cfa44b12ba6b8b7d8b8f768460ca6e04a475444e0d58c14cae797aa49461e0d",
        "text": "// SPDX-License-Identifier: AGPL-3.0-or-later\n//! General convex DSC: native host geometry/LUT then original image math.\n//! Private resource files only; explicit CPU normalized-border sampling policy.\nuse crate::{Result, archive, linear_post::unorm};\nuse serde_json::{Value, json};\nuse std::path::Path;\npub const SRI_BYTES: usize = 128 * 320 * 4;\npub const INTERP_BYTES: usize = 256 * 1024 * 4;\npub const POLICY: &str = \"normalized-clamp-bilinear-f32-v1\";\nconst GENERAL: [(&str, usize, &str); 4] = [\n    (\n        \"A_Probe.bin\",\n        68,\n        \"9b8e95810fe33a085f2be2e58f082de9915cb3d7f66324d01145e4c211c2efcb\",\n    ),\n    (\n        \"A_BF.bin\",\n        44,\n        \"28ed79893f9f224a7c1a29e2288491cb3bf224bbb3851d308c50e799b48dbdee\",\n    ),\n    (\n        \"B_PRF.bin\",\n        388,\n        \"bf553725fc08bf50b6c4919ebc38d8cb8d648b8f03072a6d2da6fe32dcd84231\",\n    ),\n    (\n        \"B_SRI.bin\",\n        352,\n        \"06822694c67a7c94168be168d86221301853e8ce8aba48c49fedd7b1cde2164b\",\n    ),\n];\nconst MAPS: [(&str, usize, &str); 2] = [\n    (\n        \"B_GrayMap.bin\",\n        8192,\n        \"157b02fd561b0a240bf81ddcd9005945cfeb7ae98e3b778f462cb0a145e7a5d4\",\n    ),\n    (\n        \"B_TintMap.bin\",\n        9216,\n        \"f23838245b6f944fc9b3a42b76d5525f21821702fa19b52270369efc46adc037\",\n    ),\n];\n#[derive(Clone, Copy, Debug)]\npub struct Settings {\n    pub depth: usize,\n    pub width: usize,\n    pub height: usize,\n    pub gray: usize,\n    pub tint: usize,\n}\nimpl Settings {\n    pub fn parse(v: &Value) -> Result<Self> {\n        let keys = [\n            \"schema_version\",\n            \"depth_index\",\n            \"width\",\n            \"height\",\n            \"gray_map\",\n            \"tint_map\",\n        ];\n        let o = v.as_object().ok_or(\"Require explicit DSC settings\")?;\n        if o.len() != keys.len()\n            || o.keys().any(|s| !keys.contains(&s.as_str()))\n            || v[\"schema_version\"] != \"convex-dsc-settings-v1\"\n        {\n            return Err(\"Require exact convex-dsc-settings-v1; no defaults\".into());\n        }\n        let get = |s: &str| {\n            v[s].as_u64()\n                .and_then(|n| usize::try_from(n).ok())\n                .ok_or_else(|| format!(\"Invalid DSC setting{s}\"))\n        };\n        let s = Self {\n            depth: get(\"depth_index\")?,\n            width: get(\"width\")?,\n            height: get(\"height\")?,\n            gray: get(\"gray_map\")?,\n            tint: get(\"tint_map\")?,\n        };\n        s.validate()?;\n        Ok(s)\n    }\n    fn validate(self) -> Result<()> {\n        if self.depth > 7\n            || self.width == 0\n            || self.width > 2048\n            || self.height == 0\n            || self.height > 2048\n            || self.gray > 8\n            || self.tint > 8\n        {\n            return Err(\"Require depth0..7,width/height1..2048,gray/tint0..8\".into());\n        }\n        Ok(())\n    }\n    pub fn json(self) -> Value {\n        json!({\"schema_version\":\"convex-dsc-settings-v1\",\"depth_index\":self.depth,\"width\":self.width,\"height\":self.height,\"gray_map\":self.gray,\"tint_map\":self.tint})\n    }\n}\nfn load_group(\n    dir: &dyn crate::resources::Source,\n    group: &[(&str, usize, &str)],\n) -> Result<(Vec<Vec<u8>>, Vec<Value>)> {\n    let mut data = Vec::new();\n    let mut rows = Vec::new();\n    for (name, size, hash) in group {\n        let b = dir.read(name, *size as u64)?;\n        if b.len() != *size || archive::sha(&b) != *hash {\n            return Err(format!(\n                \"Require complete known Plus General DSC input{name}\"\n            ));\n        }\n        rows.push(json!({\"file\":name,\"bytes\":size,\"sha256\":hash}));\n        data.push(b)\n    }\n    Ok((data, rows))\n}\nfn word(b: &[u8], i: usize) -> u32 {\n    u32::from_le_bytes(b[4 * i..4 * i + 4].try_into().unwrap())\n}\nfn fword(b: &[u8], i: usize) -> f32 {\n    f32::from_bits(word(b, i))\n}\nfn hex(v: u32) -> String {\n    v.to_le_bytes().iter().map(|b| format!(\"{b:02x}\")).collect()\n}\n#[derive(Clone)]\npub struct Plan {\n    sampling: std::sync::OnceLock<Sampling>,\n    pub settings: Settings,\n    pub parameters: Vec<u8>,\n    pub map: Vec<u8>,\n    pub dispatch: Vec<u8>,\n    pub bindings: Value,\n    pub recipe: Value,\n    pub hostplan: Value,\n    pub provenance: Value,\n    pub sri_assets: Value,\n}\nimpl Plan {\n    pub(crate) fn from_selected(\n        settings: Settings,\n        parameters: [u8; 40],\n        map: [u8; 1024],\n    ) -> Result<Self> {\n        settings.validate()?;\n        if word(&parameters, 2) != settings.width as u32\n            || word(&parameters, 3) != settings.height as u32\n            || [6, 7, 8, 9]\n                .iter()\n                .any(|&i| !fword(&parameters, i).is_finite() || fword(&parameters, i) <= 0.)\n            || map\n                .as_chunks::<4>()\n                .0\n                .iter()\n                .enumerate()\n                .any(|(i, p)| p[3] != i as u8)\n        {\n            return Err(\"Invalid selected DSC profile\".into());\n        }\n        Ok(Self {\n            sampling: std::sync::OnceLock::new(),\n            settings,\n            parameters: parameters.to_vec(),\n            map: map.to_vec(),\n            dispatch: Vec::new(),\n            bindings: json!([]),\n            recipe: json!({\"policy\":POLICY}),\n            hostplan: Value::Null,\n            provenance: json!({\"policy\":\"selected-memory-profile-v1\"}),\n            sri_assets: Value::Null,\n        })\n    }\n\n    pub fn load(\n        assets: &Path,\n        maps: &Path,\n        settings: Settings,\n        custom: Option<&[u8]>,\n    ) -> Result<Self> {\n        Self::from_source(\n            &crate::resources::Files(assets),\n            &crate::resources::Files(maps),\n            settings,\n            custom,\n            crate::Palette::Reference,\n        )\n    }\n    pub fn from_source(\n        assets: &dyn crate::resources::Source,\n        maps: &dyn crate::resources::Source,\n        settings: Settings,\n        custom: Option<&[u8]>,\n        palette: crate::Palette,\n    ) -> Result<Self> {\n        settings.validate()?;\n        if (settings.gray == 8) != custom.is_some() || custom.is_some_and(|b| b.len() != 256) {\n            return Err(\"Gray8 requires exactly256custom bytes; other gray selections require no custom curve\".into());\n        }\n        let (a, asset_rows) = load_group(assets, &GENERAL)?;\n        let (m, map_rows) = match palette {\n            crate::Palette::Reference => load_group(maps, &MAPS)?,\n            crate::Palette::LinearGray => {\n                if settings.gray != 0 || settings.tint != 0 || custom.is_some() {\n                    return Err(\"linear-gray-v1 requires gray0/tint0 and no custom curve\".into());\n                }\n                (\n                    Vec::new(),\n                    vec![\n                        json!({\"generator\":\"linear-gray-v1\",\"origin\":\"original arithmetic\",\"license\":\"AGPL-3.0-or-later\"}),\n                    ],\n                )\n            }\n        };\n        if word(&a[0], 3) != 64\n            || word(&a[0], 4) != 1\n            || word(&a[0], 7) != 8\n            || word(&a[1], 1) != 4\n            || word(&a[1], 2) != 2\n            || word(&a[1], 3) != 128\n        {\n            return Err(\"Unsupported known General DSC geometry/organization\".into());\n        }\n        let depth = (word(&a[2], 1 + settings.depth) as i32 as f32) / 10.;\n        // AArch64 FRINTP rounds toward positive infinity.\n        let mut rounded = ((depth + depth).ceil() * 0.5).max(2.);\n        if matches!(word(&a[0], 7), 8 | 16) {\n            rounded = rounded.ceil()\n        }\n        let zoom = depth / rounded;\n        let theta = (fword(&a[0], 0) / fword(&a[0], 1)) * word(&a[0], 3) as i32 as f32;\n        let radius = fword(&a[0], 1) / (depth * 10.);\n        let h = radius * (theta * 0.5).cos();\n        if [depth, zoom, theta, radius, h]\n            .iter()\n            .any(|v| !v.is_finite() || *v <= 0.)\n        {\n            return Err(\"Invalid General DSC nominal geometry\".into());\n        }\n        let words = [\n            depth.to_bits(),\n            0,\n            settings.width as u32,\n            settings.height as u32,\n            0,\n            0,\n            zoom.to_bits(),\n            theta.to_bits(),\n            radius.to_bits(),\n            h.to_bits(),\n        ];\n        let parameters = words.iter().flat_map(|v| v.to_le_bytes()).collect();\n        let map = match palette {\n            crate::Palette::LinearGray => crate::linear_gray_map(),\n            crate::Palette::Reference => {\n                let mut map = Vec::with_capacity(1024);\n                for i in 0..256 {\n                    let level = if let Some(curve) = custom {\n                        curve[i]\n                    } else {\n                        m[0][settings.gray * 1024 + i * 4]\n                    };\n                    let offset = settings.tint * 1024 + level as usize * 4;\n                    map.extend_from_slice(&m[1][offset..offset + 3]);\n                    map.push(i as u8);\n                }\n                map\n            }\n        };\n        let pre = [128u64, 256];\n        let pre_local = [32u64, 1];\n        let post = [\n            settings.width.div_ceil(32) as u64 * 32,\n            settings.height.div_ceil(8) as u64 * 8,\n        ];\n        let post_local = [32u64, 8];\n        let dispatch = [pre, pre_local, post, post_local]\n            .into_iter()\n            .flatten()\n            .flat_map(|v| v.to_le_bytes())\n            .collect();\n        let mut binding = Vec::new();\n        for (kernel, name, args) in [\n            (\"0x4888\", \"DSC_pre\", vec![\"SRI_output\", \"0x48b0\", \"0x48a0\"]),\n            (\"0x4898\", \"DSC_CP\", vec![\"0x48a0\", \"0x48a8\"]),\n        ] {\n            for (i, source) in args.into_iter().enumerate() {\n                binding.push(json!({\"kernel_slot\":kernel,\"kernel\":name,\"argument\":i,\"bytes\":8,\"value\":{\"kind\":\"image_or_buffer\",\"source\":source}}))\n            }\n        }\n        for (i, bits) in [\n            h.to_bits(),\n            radius.to_bits(),\n            theta.to_bits(),\n            zoom.to_bits(),\n            settings.width as u32,\n            settings.height as u32,\n        ]\n        .into_iter()\n        .enumerate()\n        {\n            binding.push(json!({\"kernel_slot\":\"0x4898\",\"kernel\":\"DSC_CP\",\"argument\":i+2,\"bytes\":4,\"value\":{\"kind\":\"scalar32\",\"value_hex\":hex(bits)}}))\n        }\n        let image = |w, h| json!({\"width\":w,\"height\":h,\"channel_order\":\"CL_RGBA\",\"channel_type\":\"CL_UNORM_INT8\"});\n        let hostplan = json!({\"schema_version\":\"convex-dsc-oracle-config-v1\",\"images\":{\"sri\":image(128,320),\"map\":image(256,1),\"interp\":image(256,1024),\"output\":image(settings.width,settings.height)},\"pre\":{\"global\":pre,\"local\":pre_local},\"post\":{\"kernel\":\"DSC_CP\",\"global\":post,\"local\":post_local,\"arguments\":{\"W\":settings.width,\"H\":settings.height,\"h_bits\":h.to_bits(),\"R_bits\":radius.to_bits(),\"theta_bits\":theta.to_bits(),\"zoom_bits\":zoom.to_bits()}}});\n        let recipe = json!({\"schema_version\":\"convex-dsc-recipe-v1\",\"operations\":[{\"operation\":\"kernel\",\"slot\":\"0x4888\",\"name\":\"DSC_pre\",\"global\":pre,\"local\":pre_local,\"dimensions\":2},{\"operation\":\"kernel\",\"slot\":\"0x4898\",\"name\":\"DSC_CP\",\"global\":post,\"local\":post_local,\"dimensions\":2},{\"operation\":\"finish\"}],\"fully_written_images\":[\"0x48a0\",\"0x48a8\",\"0x48b0\"],\"map_fourth_channel\":\"original intensity index0..255, not opacity\",\"numeric_policy\":POLICY,\"physical_calibration\":null,\"native_geometry_only\":true,\"gpu_equivalence_validated\":false});\n        let sri_assets = json!([asset_rows[1], asset_rows[2], asset_rows[3]]);\n        let provenance = json!({\"profile\":\"Plus-UC5-2S_16-General-B4-T128-m2-type8\",\"assets\":asset_rows,\"maps\":map_rows,\"custom_gray\":custom.map(|b|json!({\"bytes\":b.len(),\"sha256\":archive::sha(b)})),\"payload_embedded\":false,\"host_numeric_policy\":\"binary32 ordered/noFMA; FRINTPceil; cosfCPU substitution; prepared fresh host scalar block only\",\"nominal_geometry_not_measured\":true});\n        Ok(Self {\n            sampling: std::sync::OnceLock::new(),\n            settings,\n            parameters,\n            map,\n            dispatch,\n            bindings: json!(binding),\n            recipe,\n            hostplan,\n            provenance,\n            sri_assets,\n        })\n    }\n    pub fn files(&self) -> Vec<(String, Vec<u8>)> {\n        vec![\n            (\"parameters.bin\".into(), self.parameters.clone()),\n            (\"map.rgba\".into(), self.map.clone()),\n            (\"dispatch.u64le\".into(), self.dispatch.clone()),\n            (\n                \"bindings.json\".into(),\n                serde_json::to_vec_pretty(&self.bindings).unwrap(),\n            ),\n            (\n                \"recipe.json\".into(),\n                serde_json::to_vec_pretty(&self.recipe).unwrap(),\n            ),\n            (\n                \"hostplan.json\".into(),\n                serde_json::to_vec_pretty(&self.hostplan).unwrap(),\n            ),\n        ]\n    }\n    pub fn process(&self, sri: &[u8]) -> Result<Outcome> {\n        if sri.len() != SRI_BYTES {\n            return Err(\"Require exact128x320RGBAUNORM8 SRI output\".into());\n        }\n        let mut interp = vec![0; INTERP_BYTES];\n        for y in 0..256 {\n            for x in 0..128 {\n                for c in 0..4 {\n                    let a = nearest(sri, 128, 320, x as i32 - 2, y + 32, c);\n                    let b = nearest(sri, 128, 320, x as i32 - 1, y + 32, c);\n                    let d = nearest(sri, 128, 320, x as i32, y + 32, c);\n                    let v0 = (a + d) * 0.1328125 + b * 0.734375;\n                    let v1 = (b + d) * 0.5;\n                    for (phase, v) in [v0, v1].into_iter().enumerate() {\n                        let index = ((255. * v) as i32).clamp(0, 255) as usize;\n                        let dst = ((y as usize + c * 256) * 256 + 2 * x + phase) * 4;\n                        interp[dst..dst + 4].copy_from_slice(&self.map[4 * index..4 * index + 4]);\n                    }\n                }\n            }\n        }\n        let width = self.settings.width;\n        let height = self.settings.height;\n        let key = [\n            width as u32,\n            height as u32,\n            word(&self.parameters, 6),\n            word(&self.parameters, 7),\n            word(&self.parameters, 8),\n            word(&self.parameters, 9),\n        ];\n        if self.sampling.get().is_none() {\n            let _ = self.sampling.set(Sampling::new(key)?);\n        }\n        let cached = self.sampling.get().unwrap();\n        // Plans are inspectable; never reuse geometry after a caller changes it.\n        let changed;\n        let sampling = if cached.key == key {\n            cached\n        } else {\n            changed = Sampling::new(key)?;\n            &changed\n        };\n        let gray = self\n            .map\n            .as_chunks::<4>()\n            .0\n            .iter()\n            .all(|v| v[0] == v[1] && v[1] == v[2]);\n        let mut output = vec![0; width * height * 4];\n        for (pixel, sample) in sampling.pixels.iter().enumerate() {\n            if sample.offsets[0] == u32::MAX && sample.offsets.iter().all(|&v| v == u32::MAX) {\n                continue;\n            }\n            for c in 0..4 {\n                if gray && (c == 1 || c == 2) {\n                    output[pixel * 4 + c] = output[pixel * 4];\n                    continue;\n                }\n                let value = |index: usize| {\n                    if sample.offsets[index] == u32::MAX {\n                        0.\n                    } else {\n                        interp[sample.offsets[index] as usize + c] as f32 / 255.\n                    }\n                };\n                let a = sample.a;\n                let d = sample.d;\n                let top = value(0) * (1. - a) + value(1) * a;\n                let bottom = value(2) * (1. - a) + value(3) * a;\n                output[pixel * 4 + c] = unorm(top * (1. - d) + bottom * d);\n            }\n        }\n        Ok(Outcome { interp, output })\n    }\n}\n#[derive(Clone)]\nstruct Sample {\n    offsets: [u32; 4],\n    a: f32,\n    d: f32,\n}\n#[derive(Clone)]\nstruct Sampling {\n    key: [u32; 6],\n    pixels: Vec<Sample>,\n}\nimpl Sampling {\n    fn new(key: [u32; 6]) -> Result<Self> {\n        let width = key[0] as usize;\n        let height = key[1] as usize;\n        let [zoom, theta, radius, h] = [key[2], key[3], key[4], key[5]].map(f32::from_bits);\n        let mut pixels = Vec::with_capacity(width * height);\n        for y in 0..height {\n            for x in 0..width {\n                let xx = (((x as f32 + 0.5) - 0.5 * width as f32) / height as f32)\n                    * (1. + radius - h)\n                    * zoom;\n                let yy = ((y as f32 + 0.5) / height as f32) * (1. + radius - h) * zoom + h;\n                let u = (xx / yy).atan() / theta + 0.5;\n                let v = xx.hypot(yy) - radius;\n                let x = u * 256. - 0.5;\n                let y = v * 1024. - 0.5;\n                if !u.is_finite() || !v.is_finite() || !x.is_finite() || !y.is_finite() {\n                    return Err(\"Nonfinite DSC coordinate; no image committed\".into());\n                }\n                let mut sample = Sample {\n                    offsets: [u32::MAX; 4],\n                    a: 0.,\n                    d: 0.,\n                };\n                if x > -1. && y > -1. && x < 256. && y < 1024. {\n                    let ix = x.floor() as i32;\n                    let iy = y.floor() as i32;\n                    sample.a = x - ix as f32;\n                    sample.d = y - iy as f32;\n                    for (i, (x, y)) in [(ix, iy), (ix + 1, iy), (ix, iy + 1), (ix + 1, iy + 1)]\n                        .into_iter()\n                        .enumerate()\n                    {\n                        if (0..256).contains(&x) && (0..1024).contains(&y) {\n                            sample.offsets[i] = ((y * 256 + x) * 4) as u32;\n                        }\n                    }\n                }\n                pixels.push(sample);\n            }\n        }\n        Ok(Self { key, pixels })\n    }\n}\npub struct Outcome {\n    pub interp: Vec<u8>,\n    pub output: Vec<u8>,\n}\nfn nearest(b: &[u8], w: usize, h: usize, x: i32, y: i32, c: usize) -> f32 {\n    let x = x.clamp(0, w as i32 - 1) as usize;\n    let y = y.clamp(0, h as i32 - 1) as usize;\n    b[(y * w + x) * 4 + c] as f32 / 255.\n}\nfn border(b: &[u8], w: usize, h: usize, x: i32, y: i32, c: usize) -> f32 {\n    if x < 0 || y < 0 || x >= w as i32 || y >= h as i32 {\n        0.\n    } else {\n        b[(y as usize * w + x as usize) * 4 + c] as f32 / 255.\n    }\n}\nfn bilinear(b: &[u8], w: usize, h: usize, u: f32, v: f32, c: usize) -> Result<f32> {\n    let x = u * w as f32 - 0.5;\n    let y = v * h as f32 - 0.5;\n    if !x.is_finite() || !y.is_finite() {\n        return Err(\"DSC coordinate outside explicit CPU sampler domain\".into());\n    }\n    // A footprint entirely outside the image is the zero border, even when\n    // its finite coordinates cannot be represented as integer texel indices.\n    if x <= -1. || y <= -1. || x >= w as f32 || y >= h as f32 {\n        return Ok(0.);\n    }\n    let ix = x.floor() as i32;\n    let iy = y.floor() as i32;\n    let a = x - ix as f32;\n    let d = y - iy as f32;\n    let top = border(b, w, h, ix, iy, c) * (1. - a) + border(b, w, h, ix + 1, iy, c) * a;\n    let bottom = border(b, w, h, ix, iy + 1, c) * (1. - a) + border(b, w, h, ix + 1, iy + 1, c) * a;\n    Ok(top * (1. - d) + bottom * d)\n}\n#[cfg(test)]\nmod tests {\n    use super::*;\n    #[test]\n    fn normalized_clamp_is_zero_border_not_edge() {\n        let p = vec![200; 4];\n        assert_eq!(bilinear(&p, 1, 1, 0., 0., 0).unwrap(), (200. / 255.) * 0.25);\n        assert_eq!(bilinear(&p, 1, 1, 0.5, 0.5, 0).unwrap(), 200. / 255.);\n        assert_eq!(bilinear(&p, 1, 1, -2., -2., 0).unwrap(), 0.);\n        assert_eq!(bilinear(&p, 1, 1, 0.5, 1_186_408.8, 0).unwrap(), 0.);\n        assert_eq!(bilinear(&p, 1, 1, -f32::MAX / 2., 0.5, 0).unwrap(), 0.);\n        assert!(bilinear(&p, 1, 1, f32::NAN, 0., 0).is_err());\n    }\n    #[test]\n    fn dimensions_and_palette_domains_are_explicit() {\n        let mut j = json!({\"schema_version\":\"convex-dsc-settings-v1\",\"depth_index\":0,\"width\":17,\"height\":19,\"gray_map\":8,\"tint_map\":8});\n        assert!(Settings::parse(&j).is_ok());\n        j[\"width\"] = json!(0);\n        assert!(Settings::parse(&j).is_err());\n        j[\"width\"] = json!(17);\n        j[\"gray_map\"] = json!(9);\n        assert!(Settings::parse(&j).is_err());\n        j[\"gray_map\"] = json!(8);\n        j[\"extra\"] = json!(true);\n        assert!(Settings::parse(&j).is_err());\n    }\n    #[test]\n    fn cached_coordinates_match_scalar_sampler_and_invalidate_after_geometry_change() {\n        let settings = Settings {\n            depth: 0,\n            width: 17,\n            height: 19,\n            gray: 0,\n            tint: 0,\n        };\n        let mut parameters = [0u8; 40];\n        for (i, value) in [\n            (2, 17),\n            (3, 19),\n            (6, 1f32.to_bits()),\n            (7, 0.8f32.to_bits()),\n            (8, 0.5f32.to_bits()),\n            (9, 0.2f32.to_bits()),\n        ] {\n            parameters[4 * i..4 * i + 4].copy_from_slice(&value.to_le_bytes());\n        }\n        let sri: Vec<u8> = (0..SRI_BYTES).map(|i| (i * 71 + i / 17) as u8).collect();\n        for gray in [false, true] {\n            let map = std::array::from_fn(|i| {\n                let n = (i / 4) as u8;\n                match i % 4 {\n                    0 => n,\n                    1 => {\n                        if gray {\n                            n\n                        } else {\n                            255 - n\n                        }\n                    }\n                    2 => {\n                        if gray {\n                            n\n                        } else {\n                            n.wrapping_mul(13)\n                        }\n                    }\n                    _ => n,\n                }\n            });\n            let mut plan = Plan::from_selected(settings, parameters, map).unwrap();\n            for zoom in [1f32, 0.75, 1.] {\n                plan.parameters[24..28].copy_from_slice(&zoom.to_le_bytes());\n                let actual = plan.process(&sri).unwrap();\n                let [z, t, r, h] = [6, 7, 8, 9].map(|i| fword(&plan.parameters, i));\n                let mut expected = Vec::new();\n                for y in 0..settings.height {\n                    for x in 0..settings.width {\n                        let xx = (((x as f32 + 0.5) - 0.5 * settings.width as f32)\n                            / settings.height as f32)\n                            * (1. + r - h)\n                            * z;\n                        let yy = ((y as f32 + 0.5) / settings.height as f32) * (1. + r - h) * z + h;\n                        let u = (xx / yy).atan() / t + 0.5;\n                        let v = xx.hypot(yy) - r;\n                        for c in 0..4 {\n                            expected\n                                .push(unorm(bilinear(&actual.interp, 256, 1024, u, v, c).unwrap()));\n                        }\n                    }\n                }\n                assert_eq!(actual.output, expected);\n            }\n        }\n    }\n}\n"
      },
      {
        "path": "components/ultrasound/convex-decoder/1.0.0/src/convex_dtgc.rs",
        "sha256": "dcd7fc2a0aaecdbf6c724689343b99fa00ad32f7d1eb7346023133ff32310e18",
        "text": "// SPDX-License-Identifier: AGPL-3.0-or-later\n//! General B DTGC boundary only. Packed components and retained image columns\n//! are explicit; this is not a scan-converted or calibrated ultrasound image.\nuse crate::{Result, archive, convex_bfsp, linear_post::unorm};\nuse serde_json::{Value, json};\nuse std::path::Path;\n\npub const WIDTH: usize = 64;\npub const IMAGE_BYTES: usize = WIDTH * convex_bfsp::SAMPLES * 4;\npub const RESHAPE_BYTES: usize = convex_bfsp::GROUPS * convex_bfsp::SAMPLES * 16;\nconst DTGC_SHA: &str = \"234969cac6d53acb6bc3b13b62a6d559e9f19396c3c3518df165bdb9878f9044\";\n\n#[derive(Clone, Copy, Debug)]\npub struct Settings {\n    pub bank_selector_0x48: usize,\n    pub gain: f32,\n    pub dynamic_range: f32,\n    pub controls: [f32; 6],\n}\nimpl Settings {\n    pub fn from_json(v: &Value) -> Result<Self> {\n        let keys = [\n            \"schema_version\",\n            \"bank_selector_0x48\",\n            \"gain\",\n            \"dynamic_range\",\n            \"tgc_controls\",\n        ];\n        let o = v.as_object().ok_or(\"DTGC settings must be an object\")?;\n        if o.len() != keys.len()\n            || o.keys().any(|k| !keys.contains(&k.as_str()))\n            || v[\"schema_version\"] != \"convex-dtgc-settings-v1\"\n        {\n            return Err(\"Require exact convex-dtgc-settings-v1 settings; no defaults\".into());\n        }\n        let number = |n: &Value| -> Result<f32> {\n            let x = n.as_f64().ok_or(\"Require finite numeric DTGC setting\")? as f32;\n            if !x.is_finite() {\n                return Err(\"DTGC setting overflows binary32\".into());\n            }\n            Ok(x)\n        };\n        let c = v[\"tgc_controls\"]\n            .as_array()\n            .filter(|c| c.len() == 6)\n            .ok_or(\"Require six explicit TGC controls\")?;\n        let mut controls = [0.; 6];\n        for (out, value) in controls.iter_mut().zip(c) {\n            *out = number(value)?;\n        }\n        let s = Self {\n            bank_selector_0x48: v[\"bank_selector_0x48\"]\n                .as_u64()\n                .and_then(|v| usize::try_from(v).ok())\n                .ok_or(\"Invalid bank selector0x48\")?,\n            gain: number(&v[\"gain\"])?,\n            dynamic_range: number(&v[\"dynamic_range\"])?,\n            controls,\n        };\n        s.validate()?;\n        Ok(s)\n    }\n    fn validate(self) -> Result<()> {\n        if self.bank_selector_0x48 >= 3\n            || !self.gain.is_finite()\n            || !self.dynamic_range.is_finite()\n            || self.dynamic_range <= 0.\n            || self.controls.iter().any(|v| !v.is_finite())\n        {\n            return Err(\n                \"Require bank selector0..2, finite gain/controls and positive finite dynamic range\"\n                    .into(),\n            );\n        }\n        Ok(())\n    }\n    pub fn json(self) -> Value {\n        json!({\"schema_version\":\"convex-dtgc-settings-v1\",\"bank_selector_0x48\":self.bank_selector_0x48,\n            \"gain\":self.gain,\"dynamic_range\":self.dynamic_range,\"tgc_controls\":self.controls})\n    }\n}\n\npub struct Processor {\n    tgc: [f32; 1024],\n    depth: f32,\n    gain: f32,\n    dr: f32,\n    provenance: Value,\n}\nimpl Processor {\n    pub(crate) fn selected(&self) -> ([f32; 1024], f32, f32, f32) {\n        (self.tgc, self.depth, self.gain, self.dr)\n    }\n    pub(crate) fn from_selected(tgc: [f32; 1024], depth: f32, gain: f32, dr: f32) -> Result<Self> {\n        if !(2.0..13.0).contains(&depth)\n            || !gain.is_finite()\n            || !dr.is_finite()\n            || dr <= 0.\n            || tgc.iter().any(|x| !x.is_finite())\n        {\n            return Err(\"Invalid selected DTGC profile\".into());\n        }\n        Ok(Self {\n            tgc,\n            depth,\n            gain,\n            dr,\n            provenance: json!({\"policy\":\"selected-memory-profile-v1\"}),\n        })\n    }\n\n    pub fn load(\n        directory: &Path,\n        source: convex_bfsp::Settings,\n        settings: Settings,\n    ) -> Result<Self> {\n        Self::from_source(&crate::resources::Files(directory), source, settings)\n    }\n    pub fn from_source(\n        directory: &dyn crate::resources::Source,\n        source: convex_bfsp::Settings,\n        settings: Settings,\n    ) -> Result<Self> {\n        settings.validate()?;\n        // Also validate the complete upstream group and selected native profile.\n        let upstream = convex_bfsp::Assets::from_source(directory, source)?;\n        let mut files = upstream.provenance()[\"files\"].as_array().unwrap().clone();\n        let bytes = directory.read(\"B_DTGC.bin\", 6148)?;\n        if bytes.len() != 6148 || archive::sha(&bytes) != DTGC_SHA {\n            return Err(\"Require complete known General B_DTGC.bin\".into());\n        }\n        files.push(json!({\"name\":\"B_DTGC.bin\",\"bytes\":6148,\"sha256\":DTGC_SHA}));\n        let table: Vec<f32> = bytes\n            .as_chunks::<4>()\n            .0\n            .iter()\n            .map(|v| f32::from_le_bytes(*v))\n            .collect();\n        // Exact hashes above establish p=2 and these B_PRF values for General.\n        let depth = native_depth([60, 80, 100, 120, 140, 160, 200, 240][source.depth], 2);\n        let mut p = Self::derive(&table, depth, source.selector, settings)?;\n        p.provenance = json!({\"profile\":\"Plus-UC5-2S_16-General-B4-T128-m2-type8\",\"files\":files,\n            \"depth_index\":source.depth,\"selector_index\":source.selector,\"bank_selector_0x48\":settings.bank_selector_0x48,\n            \"coefficient_payload_copied\":false});\n        Ok(p)\n    }\n    fn derive(table: &[f32], depth: f32, selector: usize, settings: Settings) -> Result<Self> {\n        settings.validate()?;\n        if table.len() != 1537\n            || table.iter().any(|v| !v.is_finite())\n            || selector >= 2\n            || !(2.0..13.0).contains(&depth)\n        {\n            return Err(\n                \"Only bounded General DTGC depth<13 and finite six-bank table supported\".into(),\n            );\n        }\n        let bank = 256 * (selector + 2 * settings.bank_selector_0x48);\n        let gain = (settings.gain / 100.) * table[0];\n        let dr = 255. / settings.dynamic_range;\n        let tgc = std::array::from_fn(|j| {\n            let u = (depth * j as f32) / 51.2;\n            let k = u as usize;\n            let base =\n                table[bank + k + 1] + (u - k as f32) * (table[bank + k + 2] - table[bank + k + 1]);\n            let correction = if j < 85 {\n                settings.controls[0]\n            } else if j >= 935 {\n                settings.controls[5]\n            } else {\n                let t = (j - 85) as f32 / 170.;\n                let i = t as usize;\n                settings.controls[i]\n                    + (t - i as f32) * (settings.controls[i + 1] - settings.controls[i])\n            };\n            // Native assembly adds base AFTER the interpolated correction.\n            base + correction\n        });\n        if !gain.is_finite() || !dr.is_finite() || tgc.iter().any(|x| !x.is_finite()) {\n            return Err(\"Nonfinite DTGC derived parameter\".into());\n        }\n        Ok(Self {\n            tgc,\n            depth,\n            gain,\n            dr,\n            provenance: Value::Null,\n        })\n    }\n    pub fn provenance(&self) -> Value {\n        self.provenance.clone()\n    }\n    pub fn report(&self) -> Value {\n        json!({\"native_depth_parameter\":self.depth,\"kernel_depth_argument_used\":false,\n            \"gain_parameter\":self.gain,\"dr_parameter\":self.dr,\"dispatch\":[1024,32],\"local\":[32,8],\n            \"image_shape_y_x_components\":[1024,64,4],\"written_columns\":[0,32],\"retained_columns\":[32,64],\n            \"numeric_policy\":\"binary32 ordered operations without contraction; CL_UNORM_INT8 clamp and round ties to even\",\n            \"host_lifecycle_reproduced\":false,\"upstream_banks_semantics_validated\":false})\n    }\n    pub fn tgc_bytes(&self) -> Vec<u8> {\n        self.tgc.iter().flat_map(|x| x.to_le_bytes()).collect()\n    }\n    pub fn process(&self, reshape: &[u8], prior_image: &[u8]) -> Result<Vec<u8>> {\n        if reshape.len() != RESHAPE_BYTES || prior_image.len() != IMAGE_BYTES {\n            return Err(\n                \"Require exact group-major32x1024float4 and full64x1024UNORM8 backing\".into(),\n            );\n        }\n        let mut out = prior_image.to_vec();\n        for (i, b) in reshape.as_chunks::<4>().0.iter().enumerate() {\n            let input = f32::from_le_bytes(*b);\n            let group = i / (1024 * 4);\n            let sample = (i / 4) % 1024;\n            let value = (((input / 604. + self.tgc[sample]) + self.gain) - 33.88) * self.dr + 80.5;\n            if !input.is_finite() || !value.is_finite() {\n                return Err(\"Nonfinite DTGC sample/intermediate; no output returned\".into());\n            }\n            out[(sample * WIDTH + group) * 4 + i % 4] = unorm((value / 255.).clamp(0., 1.));\n        }\n        Ok(out)\n    }\n}\nfn native_depth(prf: i32, p: i32) -> f32 {\n    let scaled = (prf as f32 / 10.) / p as f32;\n    (((f64::from(scaled + scaled) + 0.99).trunc() as i32) as f32 * 0.5).max(2.)\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n    fn settings() -> Settings {\n        Settings {\n            bank_selector_0x48: 0,\n            gain: 0.,\n            dynamic_range: 255.,\n            controls: [0.; 6],\n        }\n    }\n    #[test]\n    fn transpose_retains_full_unwritten_half() {\n        let mut p = Processor::derive(&vec![0.; 1537], 3., 0, settings()).unwrap();\n        p.tgc.fill(33.88);\n        let input: Vec<u8> = (0..32 * 1024 * 4)\n            .flat_map(|i| ((i % 4) as f32 * 604.).to_le_bytes())\n            .collect();\n        let old: Vec<u8> = (0..IMAGE_BYTES).map(|i| (i * 71 + 31) as u8).collect();\n        let out = p.process(&input, &old).unwrap();\n        for j in 0..1024 {\n            for x in 0..64 {\n                let k = (j * 64 + x) * 4;\n                if x < 32 {\n                    assert_eq!(&out[k..k + 4], &[80, 82, 82, 84]);\n                } else {\n                    assert_eq!(&out[k..k + 4], &old[k..k + 4]);\n                }\n            }\n        }\n    }\n    #[test]\n    fn tgc_control_knots_and_boundaries() {\n        let mut s = settings();\n        s.controls = [0., 1., 2., 3., 4., 5.];\n        let p = Processor::derive(&vec![0.; 1537], 12., 1, s).unwrap();\n        for (i, v) in [\n            (0, 0.),\n            (84, 0.),\n            (85, 0.),\n            (255, 1.),\n            (425, 2.),\n            (595, 3.),\n            (765, 4.),\n            (935, 5.),\n            (1023, 5.),\n        ] {\n            assert_eq!(p.tgc[i], v);\n        }\n        assert!(p.tgc[934] < 5.);\n        assert_eq!(native_depth(0, 2), 2.);\n        assert_eq!(native_depth(240, 2), 12.);\n    }\n    #[test]\n    fn explicit_settings_and_nonfinite_rejections() {\n        let mut v = settings().json();\n        assert!(Settings::from_json(&v).is_ok());\n        v[\"extra\"] = json!(1);\n        assert!(Settings::from_json(&v).is_err());\n        v.as_object_mut().unwrap().remove(\"extra\");\n        v[\"dynamic_range\"] = json!(0);\n        assert!(Settings::from_json(&v).is_err());\n        let p = Processor::derive(&vec![0.; 1537], 3., 0, settings()).unwrap();\n        let mut input = vec![0; RESHAPE_BYTES];\n        input[..4].copy_from_slice(&f32::NAN.to_le_bytes());\n        assert!(p.process(&input, &vec![0; IMAGE_BYTES]).is_err());\n        assert!(p.process(&[], &vec![0; IMAGE_BYTES]).is_err());\n        assert!(Processor::derive(&vec![0.; 1537], 13., 0, settings()).is_err());\n    }\n}\n"
      },
      {
        "path": "components/ultrasound/convex-decoder/1.0.0/src/convex_group.rs",
        "sha256": "d88d35ce2c5d7b1821f9f305379c11805c0dfb7c3dbdda64da80a07f5c75a7d3",
        "text": "// SPDX-License-Identifier: AGPL-3.0-or-later\n//! Native B/BM size-publication model, fed by the bounded 32C inspector.\n//! A publication is a numerical input candidate, never a physical frame claim.\nuse crate::{\n    HEADER_BYTES, MARKER, PREFIX_BYTES, Parameters, Result, Segment, archive, line_length,\n};\nuse serde_json::{Value, json};\nuse std::sync::Arc;\n\npub const POLICY: &str = \"new-organizer-per-observed-epoch-v1\";\n#[derive(Clone, Copy)]\npub struct Settings {\n    pub b_capacity: usize,\n    pub m_capacity: usize,\n    pub m_lines: usize,\n    pub bm_26: u16,\n    pub bm_28: u32,\n}\nimpl Settings {\n    pub fn parse(v: &Value) -> Result<Self> {\n        let keys = [\n            \"schema_version\",\n            \"epoch_policy\",\n            \"b_capacity_bytes\",\n            \"m_capacity_bytes\",\n            \"m_line_count\",\n            \"bm_header_26\",\n            \"bm_header_28\",\n        ];\n        let o = v.as_object().ok_or(\"Require explicit grouping settings\")?;\n        if o.len() != keys.len()\n            || o.keys().any(|k| !keys.contains(&k.as_str()))\n            || v[\"schema_version\"] != \"convex-b-grouping-settings-v1\"\n            || v[\"epoch_policy\"] != POLICY\n        {\n            return Err(\"Require exact convex-b-grouping-settings-v1 and explicit new-organizer epoch policy\".into());\n        }\n        let get = |k: &str| {\n            v[k].as_u64()\n                .ok_or_else(|| format!(\"Invalid grouping setting {k}\"))\n        };\n        let s = Self {\n            b_capacity: usize::try_from(get(\"b_capacity_bytes\")?).map_err(|e| e.to_string())?,\n            m_capacity: usize::try_from(get(\"m_capacity_bytes\")?).map_err(|e| e.to_string())?,\n            m_lines: usize::try_from(get(\"m_line_count\")?).map_err(|e| e.to_string())?,\n            bm_26: u16::try_from(get(\"bm_header_26\")?).map_err(|e| e.to_string())?,\n            bm_28: u32::try_from(get(\"bm_header_28\")?).map_err(|e| e.to_string())?,\n        };\n        s.validate()?;\n        Ok(s)\n    }\n    fn validate(self) -> Result<()> {\n        if !(1..=8 * 1024 * 1024).contains(&self.b_capacity)\n            || !(1..=8 * 1024 * 1024).contains(&self.m_capacity)\n            || !(1..=65535).contains(&self.m_lines)\n        {\n            return Err(\"Require capacities1..8MiB and M line count1..65535\".into());\n        }\n        Ok(())\n    }\n}\nfn counter(h: &[u8]) -> u32 {\n    u32::from_le_bytes(h[12..16].try_into().unwrap())\n}\nfn short(h: &[u8], at: usize) -> u16 {\n    u16::from_le_bytes(h[at..at + 2].try_into().unwrap())\n}\nfn expected(h: &[u8], p: Parameters) -> Result<usize> {\n    let length = line_length(0, short(h, 24), 0, Some(p), i32::MAX as usize)?;\n    let n = length\n        .checked_mul(usize::from(short(h, 28)))\n        .ok_or(\"Group length overflow\")?;\n    if n > i32::MAX as usize {\n        return Err(\"Native signed group length domain exceeded\".into());\n    }\n    Ok(n)\n}\n#[derive(Clone)]\npub struct Line {\n    pub offset: u64,\n    pub bytes: Vec<u8>,\n    pub wire_header: Arc<[u8]>,\n    pub wire_header_offset: u64,\n}\npub struct Group {\n    pub lines: Vec<Line>,\n    pub algorithm_header: Vec<u8>,\n    pub publication_wire_header: Arc<[u8]>,\n    pub expected_bytes: usize,\n}\nimpl Group {\n    pub fn bytes(&self) -> Vec<u8> {\n        self.lines\n            .iter()\n            .flat_map(|l| l.bytes.iter().copied())\n            .collect()\n    }\n    pub fn audit(&self) -> Value {\n        let first = &self.lines[0];\n        let e = short(&first.bytes, 4) as usize;\n        let uniform = self.lines.iter().all(|l| {\n            l.bytes.len() == e * 4\n                && short(&l.bytes, 4) as usize == e\n                && l.wire_header == first.wire_header\n        });\n        let header_matches = self.algorithm_header.as_slice() == first.wire_header.as_ref();\n        let geometry = self.lines.len() == 32\n            && uniform\n            && e >= 8\n            && self.expected_bytes == 32 * e * 4\n            && short(&self.algorithm_header, 28) == 32;\n        json!({\"line_words\":e,\"line_count\":self.lines.len(),\"uniform_lengths_and_wire_headers\":uniform,\n            \"algorithm_header_equals_first_wire_header\":header_matches,\n            \"general_bfsp_length_compatible\":geometry,\n            \"assets_settings_and_bfsp_domain_audited\":false,\n            \"source_header_counter\":counter(&first.wire_header),\"algorithm_header_counter\":counter(&self.algorithm_header),\n            \"physical_frame_complete\":null,\"spatial_line_indices_validated\":false,\n            \"line_sources\":self.lines.iter().map(|l|json!({\"offset\":l.offset,\"bytes\":l.bytes.len(),\"sha256\":archive::sha(&l.bytes),\"wire_header_offset\":l.wire_header_offset,\"wire_header_sha256\":archive::sha(&l.wire_header)})).collect::<Vec<_>>()})\n    }\n}\npub struct Step {\n    pub events: Vec<Value>,\n    pub group: Option<Group>,\n}\nimpl Step {\n    fn new() -> Self {\n        Self {\n            events: Vec::new(),\n            group: None,\n        }\n    }\n}\n\npub struct Organizer {\n    p: Parameters,\n    s: Settings,\n    wire: Option<Arc<[u8]>>,\n    wire_offset: u64,\n    current: Vec<u8>,\n    remembered_b: Vec<u8>,\n    remembered_bm: Vec<u8>,\n    expected_b: usize,\n    expected_bm: usize,\n    expected_m: usize,\n    b: Vec<Line>,\n    b_bytes: usize,\n    m_bytes: usize,\n}\nimpl Organizer {\n    pub fn snapshot(&self) -> Value {\n        json!({\"B_bytes\":self.b_bytes,\"M_bytes\":self.m_bytes,\"expected_B\":self.expected_b,\n            \"expected_BM\":self.expected_bm,\"expected_M\":self.expected_m,\n            \"current_header_sha256\":archive::sha(&self.current),\n            \"remembered_B_sha256\":archive::sha(&self.remembered_b),\n            \"remembered_BM_sha256\":archive::sha(&self.remembered_bm)})\n    }\n    pub fn new(p: Parameters, s: Settings) -> Result<Self> {\n        s.validate()?;\n        // Negative/overflowing native configurations are not reproduced.\n        if p.a < 0 || p.c <= 0 || (p.a == 1 && p.c < 2) {\n            return Err(\"Require nonnegative A and positive effective C for B grouping\".into());\n        }\n        Ok(Self {\n            p,\n            s,\n            wire: None,\n            wire_offset: 0,\n            current: vec![0; HEADER_BYTES],\n            remembered_b: vec![0; HEADER_BYTES],\n            remembered_bm: vec![0; HEADER_BYTES],\n            expected_b: 0,\n            expected_bm: 0,\n            expected_m: 0,\n            b: Vec::new(),\n            b_bytes: 0,\n            m_bytes: 0,\n        })\n    }\n    fn drop_b(&mut self, why: &str, step: &mut Step) {\n        if self.b_bytes != 0 {\n            step.events.push(json!({\"event\":\"discard_B\",\"reason\":why,\"bytes\":self.b_bytes,\n                \"line_sources\":self.b.iter().map(|l|json!({\"offset\":l.offset,\"bytes\":l.bytes.len(),\"sha256\":archive::sha(&l.bytes)})).collect::<Vec<_>>() }));\n        }\n        self.b.clear();\n        self.b_bytes = 0;\n    }\n    fn drop_m(&mut self, why: &str, step: &mut Step) {\n        if self.m_bytes != 0 {\n            step.events\n                .push(json!({\"event\":\"discard_M\",\"reason\":why,\"bytes\":self.m_bytes}));\n        }\n        self.m_bytes = 0;\n    }\n    /// This is an explicit new organizer, NOT native Clear or a DSP reset.\n    pub fn boundary(&mut self, reason: &str) -> Result<Step> {\n        let mut step = Step::new();\n        self.drop_b(reason, &mut step);\n        self.drop_m(reason, &mut step);\n        step.events.push(json!({\"event\":\"new_organizer_boundary\",\"reason\":reason,\"native_Clear_emulated\":false,\"dsp_reset_inferred\":false}));\n        *self = Self::new(self.p, self.s)?;\n        Ok(step)\n    }\n    pub fn push(&mut self, segment: &Segment) -> Result<Step> {\n        let mut step = Step::new();\n        if segment.kind == \"frame_header\" {\n            if segment.bytes.len() != HEADER_BYTES\n                || segment.bytes[..4] != MARKER\n                || segment.bytes[4..8] != MARKER\n            {\n                return Err(\"Require complete 32C header segment\".into());\n            }\n            self.wire = Some(Arc::from(segment.bytes.as_slice()));\n            self.wire_offset = segment.offset;\n            self.current = segment.bytes.clone();\n            step.events.push(json!({\"event\":\"wire_header\",\"offset\":segment.offset,\"bytes\":HEADER_BYTES,\"sha256\":archive::sha(&segment.bytes),\"counter\":counter(&self.current),\"mode\":self.current[16]}));\n            return Ok(step);\n        }\n        if segment.kind != \"line\" {\n            return self.boundary(segment.kind);\n        }\n        let Some(wire) = &self.wire else {\n            return Err(\"Line segment without header context\".into());\n        };\n        let wire = wire.clone();\n        let line = &segment.bytes;\n        if line.len() < PREFIX_BYTES || line[..4] != MARKER {\n            return Err(\"Invalid complete line segment\".into());\n        }\n        let mode = self.current[16];\n        let bm = matches!(mode, 5 | 6);\n        if !matches!(mode, 0 | 1 | 5 | 6) {\n            step.events.push(json!({\"event\":\"non_B_line\",\"mode\":mode,\"offset\":segment.offset,\"bytes\":line.len(),\"B_preserved\":true}));\n            return Ok(step);\n        }\n        if !line.len().is_multiple_of(4) {\n            // Native reader copies (formula_length >> 2) words, unlike the\n            // lossless Inspector's exact-byte segment. Do not invent a native\n            // publication from those additional bytes or silently drop them.\n            let mut rejected = self.boundary(\"non_word_native_line\")?;\n            rejected.events.push(json!({\"event\":\"line_domain_rejected\",\"reason\":\"native reader truncates copied bytes to words\",\n                \"offset\":segment.offset,\"observed_segment_bytes\":line.len(),\"native_floor_copy_bytes\":line.len()/4*4}));\n            return Ok(rejected);\n        }\n        let word = u32::from_le_bytes(line[4..8].try_into().unwrap());\n        if line_length(\n            mode,\n            short(&self.current, 24),\n            word,\n            Some(self.p),\n            1024 * 1024,\n        )? != line.len()\n        {\n            return Err(\"Line length disagrees with declared parser geometry\".into());\n        }\n        let changed = counter(&self.current)\n            != counter(if bm {\n                &self.remembered_bm\n            } else {\n                &self.remembered_b\n            });\n        if changed {\n            self.drop_b(\"counter_changed\", &mut step);\n            if bm {\n                self.drop_m(\"BM_counter_changed\", &mut step);\n            }\n            match expected(&self.current, self.p) {\n                Ok(n) => {\n                    if bm {\n                        self.expected_bm = n;\n                        self.expected_m =\n                            (32 + 2 * usize::from(short(&self.current, 24))) * self.s.m_lines;\n                        if self.expected_m > i32::MAX as usize {\n                            self.expected_bm = 0;\n                            self.expected_m = 0;\n                            step.events.push(json!({\"event\":\"native_numeric_domain_rejected\",\"reason\":\"M signed length domain exceeded\",\"offset\":segment.offset}));\n                        }\n                    } else {\n                        self.expected_b = n;\n                    }\n                }\n                Err(e) => {\n                    if bm {\n                        self.expected_bm = 0;\n                        self.expected_m = 0;\n                    } else {\n                        self.expected_b = 0;\n                    }\n                    step.events.push(json!({\"event\":\"native_numeric_domain_rejected\",\"reason\":e,\"offset\":segment.offset}));\n                }\n            }\n        }\n        let target = if bm {\n            self.expected_bm\n        } else {\n            self.expected_b\n        };\n        let subtype = (word >> 20) & 15;\n        step.events.push(json!({\"event\":\"line\",\"offset\":segment.offset,\"bytes\":line.len(),\"counter\":counter(&self.current),\n            \"mode\":mode,\"subtype\":if bm{Some(subtype)}else{None},\"expected_B_bytes\":target,\"expected_M_bytes\":if bm{Some(self.expected_m)}else{None}}));\n        if target == 0 || (bm && self.expected_m == 0) {\n            step.events.push(json!({\"event\":\"line_not_accumulated\",\"reason\":\"zero_expected_length\",\"offset\":segment.offset}));\n            // Native jumps past the remembered-header update on this path.\n            return Ok(step);\n        } else if !bm || subtype < 4 {\n            if line.len() > self.s.b_capacity.saturating_sub(self.b_bytes) {\n                self.drop_b(\"B_capacity\", &mut step);\n                if bm {\n                    self.drop_m(\"B_capacity\", &mut step);\n                }\n                step.events.push(json!({\"event\":\"line_not_accumulated\",\"reason\":\"B_capacity\",\"offset\":segment.offset}));\n            } else {\n                self.b.push(Line {\n                    offset: segment.offset,\n                    bytes: line.clone(),\n                    wire_header: wire.clone(),\n                    wire_header_offset: self.wire_offset,\n                });\n                self.b_bytes += line.len();\n                if self.b_bytes == target {\n                    let header = if bm {\n                        self.current[0x26..0x28].copy_from_slice(&self.s.bm_26.to_le_bytes());\n                        self.current[0x28..0x2c].copy_from_slice(&self.s.bm_28.to_le_bytes());\n                        self.current.clone()\n                    } else {\n                        self.remembered_b.clone()\n                    };\n                    step.group = Some(Group {\n                        lines: std::mem::take(&mut self.b),\n                        algorithm_header: header,\n                        publication_wire_header: wire,\n                        expected_bytes: target,\n                    });\n                    self.b_bytes = 0;\n                    step.events.push(json!({\"event\":\"native_B_size_publication\",\"bytes\":target,\"FIFO_schedule_observed\":false,\"physical_frame_complete\":null}));\n                } else if self.b_bytes > target {\n                    self.drop_b(\"over_expected_B_length\", &mut step);\n                }\n            }\n        } else if subtype == 4 {\n            if line.len() > self.s.m_capacity.saturating_sub(self.m_bytes) {\n                self.drop_b(\"M_capacity\", &mut step);\n                self.drop_m(\"M_capacity\", &mut step);\n                step.events.push(json!({\"event\":\"line_not_accumulated\",\"reason\":\"M_capacity\",\"offset\":segment.offset}));\n            } else {\n                self.m_bytes += line.len();\n                if self.m_bytes == self.expected_m {\n                    step.events.push(json!({\"event\":\"native_M_size_publication\",\"bytes\":self.m_bytes,\"M_processing_performed\":false}));\n                    self.m_bytes = 0;\n                } else if self.m_bytes > self.expected_m {\n                    self.drop_m(\"over_expected_M_length\", &mut step);\n                }\n            }\n        } else {\n            step.events\n                .push(json!({\"event\":\"foreign_subtype\",\"subtype\":subtype,\"offset\":segment.offset}));\n        }\n        // Native thread updates the remembered header AFTER possible publication.\n        if changed {\n            if bm {\n                self.remembered_bm = self.current.clone();\n            } else {\n                self.remembered_b = self.current.clone();\n            }\n        }\n        Ok(step)\n    }\n}\n"
      },
      {
        "path": "components/ultrasound/convex-decoder/1.0.0/src/convex_lifecycle.rs",
        "sha256": "3e0b28199d0e95074fd454d06dbd9f83f309bab0f1a3fab38d7fe703b069175e",
        "text": "// SPDX-License-Identifier: AGPL-3.0-or-later\n//! B_mode attempted-call scheduling, separate from CPU numerical policies.\n//! Update precedes BFSP and its counter survives a subsequent failure.\nuse crate::Result;\nuse serde_json::{Value, json};\n\n#[derive(Clone, Copy, Debug, PartialEq, Eq)]\npub enum Stage {\n    Bfsp,\n    Sri,\n    Ne,\n    Dsc,\n}\nimpl Stage {\n    pub fn name(self) -> &'static str {\n        match self {\n            Self::Bfsp => \"BFSP\",\n            Self::Sri => \"SRI\",\n            Self::Ne => \"NE\",\n            Self::Dsc => \"DSC\",\n        }\n    }\n}\n#[derive(Clone, Copy, Debug)]\npub struct State {\n    pub frame_count: usize,\n    pub dirty: bool,\n    pub bound_mask_correlation: f32,\n}\nimpl State {\n    pub fn json(self) -> Value {\n        json!({\"frame_count\":self.frame_count,\"dirty\":self.dirty,\n            \"bound_mask_correlation_bits\":self.bound_mask_correlation.to_bits()})\n    }\n    pub fn validate(self) -> Result<()> {\n        if self.frame_count > 2\n            || !self.bound_mask_correlation.is_finite()\n            || !(0. ..=1.).contains(&self.bound_mask_correlation)\n        {\n            return Err(\"Invalid convex lifecycle counter/mask\".into());\n        }\n        Ok(())\n    }\n    /// Native software message only. No buffer clear and no acoustic command.\n    pub fn software_freeze(&mut self) {\n        self.frame_count = 0;\n    }\n}\npub struct Attempt {\n    pub native_status_candidate: Option<i32>,\n    pub error: Option<String>,\n    pub report: Value,\n}\n/// The callback executes sub-stages, with native-style return codes for the\n/// documentary oracle. A Rust arithmetic error is distinct: no native code is\n/// invented for it. Production uses successful CPU kernels or a size rejection.\npub fn run(\n    state: &mut State,\n    selected_correlation: f32,\n    ne: bool,\n    mut process: impl FnMut(Stage) -> Result<i32>,\n) -> Result<Attempt> {\n    state.validate()?;\n    if !selected_correlation.is_finite() || !(0. ..=1.).contains(&selected_correlation) {\n        return Err(\"Invalid selected convex correlation; attempt not started\".into());\n    }\n    let before = *state;\n    let update = state.dirty || state.frame_count < 2;\n    let mut calls = Vec::new();\n    if update {\n        // The CPU backend has no failing OpenCL binding API. Only successful\n        // Update binding semantics are implemented here; original API errors\n        // are documentary native-oracle cases, not emulated GPU effects.\n        if state.frame_count < 2 {\n            state.bound_mask_correlation = if state.frame_count == 0 {\n                0.\n            } else {\n                selected_correlation\n            };\n            state.frame_count += 1;\n        }\n        calls.push(json!({\"call\":\"Update\",\"state_after\":state.json(),\n            \"policy\":\"successful-CPU-binding-v1\"}));\n        // Neither original Process nor Update clears dirty.\n    }\n    let mut status = None;\n    let mut error = None;\n    for stage in [Stage::Bfsp, Stage::Sri, Stage::Ne, Stage::Dsc] {\n        if stage == Stage::Ne && !ne {\n            continue;\n        }\n        match process(stage) {\n            Ok(code) => {\n                calls.push(json!({\"call\":stage.name(),\"return\":code}));\n                if code != 0 {\n                    status = Some(match stage {\n                        Stage::Bfsp if code == -91 => -91,\n                        Stage::Bfsp => -92,\n                        Stage::Sri => -93,\n                        Stage::Ne => -95,\n                        Stage::Dsc => -94,\n                    });\n                    break;\n                }\n            }\n            Err(e) => {\n                calls.push(json!({\"call\":stage.name(),\"port_error\":e}));\n                error = Some(e);\n                break;\n            }\n        }\n    }\n    if status.is_none() && error.is_none() {\n        status = Some(if state.frame_count == 1 { -100 } else { 0 });\n    }\n    let report = json!({\"before\":before.json(),\"after\":state.json(),\"update_attempted\":update,\n        \"calls\":calls,\"native_status_candidate\":status,\"port_error\":error,\n        \"publish_candidate\":status==Some(0),\"warmup\":status==Some(-100),\n        \"hardware_status_or_ACK\":false,\"gpu_execution\":false});\n    Ok(Attempt {\n        native_status_candidate: status,\n        error,\n        report,\n    })\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n    #[test]\n    fn failed_first_attempt_advances_and_later_success_is_not_warmup() {\n        let mut s = State {\n            frame_count: 0,\n            dirty: true,\n            bound_mask_correlation: 0.7,\n        };\n        let a = run(&mut s, 0.5, false, |_| Ok(-91)).unwrap();\n        assert_eq!(a.native_status_candidate, Some(-91));\n        assert_eq!(s.frame_count, 1);\n        assert_eq!(s.bound_mask_correlation, 0.);\n        assert!(s.dirty);\n        assert_eq!(\n            run(&mut s, 0.5, false, |_| Ok(0))\n                .unwrap()\n                .native_status_candidate,\n            Some(0)\n        );\n        assert_eq!(s.bound_mask_correlation, 0.5);\n    }\n    #[test]\n    fn warmup_computes_all_stages_and_freeze_preserves_binding_and_dirty() {\n        let mut s = State {\n            frame_count: 0,\n            dirty: false,\n            bound_mask_correlation: 0.8,\n        };\n        let mut calls = Vec::new();\n        let a = run(&mut s, 0.5, false, |v| {\n            calls.push(v);\n            Ok(0)\n        })\n        .unwrap();\n        assert_eq!(calls, [Stage::Bfsp, Stage::Sri, Stage::Dsc]);\n        assert_eq!(a.native_status_candidate, Some(-100));\n        s.frame_count = 2;\n        s.bound_mask_correlation = 0.75;\n        let a = run(&mut s, 0.1, false, |_| Ok(0)).unwrap();\n        assert_eq!(a.report[\"update_attempted\"], false);\n        assert_eq!(s.bound_mask_correlation, 0.75);\n        s.software_freeze();\n        assert_eq!(s.frame_count, 0);\n        assert!(!s.dirty);\n        assert_eq!(s.bound_mask_correlation, 0.75);\n    }\n    #[test]\n    fn returns_map_at_first_failed_stage_without_later_calls() {\n        for (failed, code, mapped) in [\n            (Stage::Bfsp, -9, -92),\n            (Stage::Sri, -7, -93),\n            (Stage::Ne, 3, -95),\n            (Stage::Dsc, 9, -94),\n        ] {\n            let mut s = State {\n                frame_count: 2,\n                dirty: true,\n                bound_mask_correlation: 0.6,\n            };\n            let mut calls = Vec::new();\n            let a = run(&mut s, 0.1, true, |v| {\n                calls.push(v);\n                Ok(if v == failed { code } else { 0 })\n            })\n            .unwrap();\n            assert_eq!(calls.last(), Some(&failed));\n            assert_eq!(a.native_status_candidate, Some(mapped));\n            assert_eq!(s.bound_mask_correlation, 0.6);\n        }\n    }\n    #[test]\n    fn port_error_is_not_a_fabricated_native_status_and_update_survives() {\n        let mut s = State {\n            frame_count: 0,\n            dirty: true,\n            bound_mask_correlation: 0.6,\n        };\n        let a = run(&mut s, 0.1, false, |_| Err(\"CPU failure\".into())).unwrap();\n        assert_eq!(s.frame_count, 1);\n        assert!(a.native_status_candidate.is_none());\n        assert_eq!(a.error.as_deref(), Some(\"CPU failure\"));\n    }\n}\n"
      },
      {
        "path": "components/ultrasound/convex-decoder/1.0.0/src/convex_messages.rs",
        "sha256": "aa00a808c67b7daec150fb1fddf6121e9e38a3bf69f9d407b265d2b892bc4db2",
        "text": "// SPDX-License-Identifier: AGPL-3.0-or-later\nuse crate::{Result, convex_parameters::sha};\nuse serde_json::{Value, json};\nfn u16_at(b: &[u8], o: usize) -> u16 {\n    u16::from_le_bytes(b[o..o + 2].try_into().unwrap())\n}\nfn u32_at(b: &[u8], o: usize) -> u32 {\n    u32::from_le_bytes(b[o..o + 4].try_into().unwrap())\n}\npub fn decode(raw: &[u8]) -> Result<Value> {\n    if raw.len() != 512 {\n        return Err(\n            \"Require one complete512-byte host read; partials are not padded or concatenated\"\n                .into(),\n        );\n    }\n    let version = u32_at(raw, 8);\n    let flags = u16_at(raw, 500);\n    let pid = u32_at(raw, 504);\n    let msg_type = u32_at(raw, 16);\n    let probe = u16_at(raw, 12);\n    let connection = u16_at(raw, 76);\n    let family = if pid == 0 {\n        \"hardware_parameters_candidate\"\n    } else if pid == 1 {\n        \"gyro_candidate\"\n    } else if msg_type == 2 {\n        \"button_candidate\"\n    } else {\n        \"unknown\"\n    };\n    Ok(\n        json!({\"schema_version\":\"convex-message-candidate-v1\",\"bytes\":512,\"sha256\":sha(raw),\"family\":family,\n        \"header_word\":u32_at(raw,0),\"tail_word\":u32_at(raw,508),\"framing_or_checksum_validated\":false,\n        \"logic_revision_bytes\":[raw[4],raw[5]],\"hardware_revision_bytes\":[raw[6],raw[7]],\n        \"logic_compile_version\":version,\"logic_type\":(version>>14)&3,\"product_series\":(version>>9)&31,\"logic_revision_bits\":version&511,\n        \"reported_probe_id\":probe,\"java_probe_id_candidate\":if probe==0&&connection==0{21845}else{probe},\"probe_backup_flags\":u16_at(raw,14),\n        \"secondary_probe_id\":u16_at(raw,72),\"secondary_probe_append\":u16_at(raw,74),\"probe_connection_bits\":connection,\n        \"message_type\":msg_type,\"message_value\":u32_at(raw,20),\"message_pid\":pid,\n        \"special_flag0\":u16_at(raw,498),\"special_flag1\":flags,\"low_power_mode\":(flags&6)>>1,\"pluggable_probe_bits\":(flags&24)>>3,\"color_type\":u16_at(raw,502),\n        \"motion_raw_i16\":(0..6).map(|n|u16_at(raw,52+2*n) as i16).collect::<Vec<_>>(),\n        \"selected_uc5_2s_parameters_candidate\":pid==0&&probe==1435,\n        \"native_deferred_probe_branch_possible\":((version>>9)&31==14||(version>>9)&31==15)&&probe==0,\n        \"device_unique_fields_exported\":false,\"physical_calibration\":null,\"acoustic_state_verified\":false,\n        \"scope\":\"Field interpretation of one complete host-read payload; neither source authenticity nor live/current device state\"}),\n    )\n}\n"
      },
      {
        "path": "components/ultrasound/convex-decoder/1.0.0/src/convex_parameters.rs",
        "sha256": "27dcc979d239197a2767d16783450c6c78aef4e89744e14167b965a8c74ea961",
        "text": "// SPDX-License-Identifier: AGPL-3.0-or-later\n//! Bounded UC5-2S TX16/ADC8 configuration primitives, offline only.\n//! These are parts of an unresolved complete lifecycle, never an executable\n//! activation plan. Vendor file payloads are supplied locally, not embedded.\nuse crate::Result;\nuse sha2::{Digest, Sha256};\nuse std::{\n    fs::{self, File},\n    io::Read,\n    path::Path,\n};\n\npub(crate) const FILES: [(&str, usize); 7] = [\n    (\"A_Probe.bin\", 68),\n    (\"A_ADC.bin\", 20),\n    (\"A_TxWave.bin\", 660),\n    (\"B_PRF.bin\", 388),\n    (\"A_ATGC.bin\", 1024),\n    (\"A_Apo.bin\", 2048),\n    (\"A_ApoComp.bin\", 2048),\n];\npub(crate) fn word(bytes: &[u8], offset: usize) -> u32 {\n    u32::from_le_bytes(bytes[offset..offset + 4].try_into().unwrap())\n}\npub(crate) fn exact(bytes: &[u8], size: usize, name: &str) -> Result<()> {\n    if bytes.len() != size {\n        Err(format!(\"{name} requires exactly{size}bytes\"))\n    } else {\n        Ok(())\n    }\n}\npub(crate) fn sha(bytes: &[u8]) -> String {\n    format!(\"{:x}\", Sha256::digest(bytes))\n}\n\n#[derive(Clone, Copy, Debug, PartialEq)]\npub struct Probe {\n    pub clock_setting: f32,\n}\nimpl Probe {\n    pub fn parse(bytes: &[u8]) -> Result<Self> {\n        exact(bytes, 68, \"A_Probe.bin\")?;\n        let clock_setting = f32::from_bits(word(bytes, 0x18));\n        if word(bytes, 0x1c) != 8\n            || word(bytes, 0x40) != 16\n            || word(bytes, 0x38) != 0\n            || word(bytes, 0x10) != 1\n        {\n            return Err(\"This partial profile requires non-PA/TX16/ADC8/NEoff; folder name is not a selector\".into());\n        }\n        if !clock_setting.is_finite() || clock_setting <= 0.0 {\n            return Err(\"Clock setting must be finite and positive\".into());\n        }\n        Ok(Self { clock_setting })\n    }\n}\n\n#[derive(Clone, Debug, PartialEq, Eq)]\npub struct Adc8(pub(crate) [u32; 5]);\nimpl Adc8 {\n    pub fn parse(bytes: &[u8]) -> Result<Self> {\n        exact(bytes, 20, \"A_ADC.bin\")?;\n        Ok(Self(std::array::from_fn(|i| word(bytes, 4 * i))))\n    }\n    /// Isolated kind2 buffer with only these five producer entries present.\n    pub fn isolated_packet(&self) -> Vec<u8> {\n        pairs(\n            &self\n                .0\n                .iter()\n                .enumerate()\n                .map(|(i, &v)| (0x0005_0035 + i as u32, v))\n                .collect::<Vec<_>>(),\n        )\n    }\n}\n\n#[derive(Clone, Debug)]\npub struct TxWave8(Vec<u32>);\n#[derive(Clone, Copy, Debug, PartialEq, Eq)]\npub struct FundamentalWave {\n    pub(crate) fields: [u32; 5],\n}\nimpl TxWave8 {\n    pub fn parse(bytes: &[u8]) -> Result<Self> {\n        exact(bytes, 660, \"A_TxWave.bin\")?;\n        Ok(Self((0..165).map(|i| word(bytes, 4 * i)).collect()))\n    }\n    pub fn fundamental(&self, index: usize) -> Result<FundamentalWave> {\n        if index >= 16 {\n            return Err(\"Fundamental TxWave index must be0..15\".into());\n        }\n        Ok(FundamentalWave {\n            fields: std::array::from_fn(|bank| self.0[33 * bank + index]),\n        })\n    }\n}\nimpl FundamentalWave {\n    pub fn isolated_packet(self) -> Vec<u8> {\n        pairs(&[\n            (0x0007_0003, self.fields[1] | self.fields[4].wrapping_shl(8)),\n            (0x0007_0021, self.fields[0]),\n        ])\n    }\n    /// Direct builder: ordering and repeated key are retained, not map-deduped.\n    /// Native SendVoltageMsg ends with 0x10, not 1 (USB-test start).\n    /// This is only the voltage-state envelope, not voltage units or Start.\n    pub fn voltage_packet(self) -> Vec<u8> {\n        pairs(&[\n            (0x0007_0034, 0),\n            (0x0007_001a, self.fields[3]),\n            (0x0007_0034, 0x10),\n        ])\n    }\n    pub fn delay_setting(self) -> u32 {\n        self.fields[2]\n    }\n}\n\n#[derive(Clone, Debug)]\npub struct Prf8 {\n    count: usize,\n    banks: [[i32; 8]; 12],\n}\n#[derive(Clone, Copy, Debug, PartialEq, Eq)]\npub struct SelectedPrf {\n    pub display_setting: i32,\n    pub fields: [i32; 13],\n}\nimpl Prf8 {\n    pub fn parse(bytes: &[u8]) -> Result<Self> {\n        exact(bytes, 388, \"B_PRF.bin\")?;\n        let count = word(bytes, 0) as usize;\n        if !(1..=8).contains(&count) {\n            return Err(\"PRF8 count must be1..8\".into());\n        }\n        Ok(Self {\n            count,\n            banks: std::array::from_fn(|b| {\n                std::array::from_fn(|i| word(bytes, 4 + 32 * b + 4 * i) as i32)\n            }),\n        })\n    }\n    pub fn depth_count(&self) -> usize {\n        self.count\n    }\n    pub fn select(&self, depth: usize, clock: f32) -> Result<SelectedPrf> {\n        // Native depth==count aliases later banks/clock: deliberately refused.\n        if depth >= self.count || !clock.is_finite() || clock <= 0.0 {\n            return Err(\"Invalid PRF depth or clock setting\".into());\n        }\n        let mut fields = [0; 13];\n        for (out, bank) in [1, 2, 3, 4].into_iter().enumerate() {\n            fields[out] = self.banks[bank][depth];\n        }\n        for (out, bank) in [(4, 3), (5, 4)] {\n            let divisor = self.banks[bank][depth];\n            if divisor <= 0 {\n                return Err(\"PRF timing divisor must be positive\".into());\n            }\n            let v = ((clock * 1_000_000.0) / divisor as f32) * 0.25;\n            if !v.is_finite() || !(0.0..2_147_483_648.0).contains(&v.trunc()) {\n                return Err(\"PRF timing conversion exceeds signed32\".into());\n            }\n            fields[out] = i32::try_from((v.trunc() as i64) * 4)\n                .map_err(|_| \"PRF shifted timing exceeds signed32\")?;\n        }\n        for (out, bank) in (5..12).enumerate() {\n            fields[out + 6] = self.banks[bank][depth];\n        }\n        Ok(SelectedPrf {\n            display_setting: self.banks[0][depth],\n            fields,\n        })\n    }\n}\n\n// Private serializer: fixed named producers above, no public arbitrary-register\n// builder and no conversion into the linear executor's sealed Plan type.\nfn pairs(entries: &[(u32, u32)]) -> Vec<u8> {\n    let mut bytes = vec![0; 512];\n    put(&mut bytes, 0, 0x5a5a_a5a5);\n    put(&mut bytes, 4, 2);\n    for (i, &(key, value)) in entries.iter().enumerate() {\n        put(&mut bytes, 16 + 8 * i, key);\n        put(&mut bytes, 20 + 8 * i, value);\n    }\n    put(&mut bytes, 16 + 8 * entries.len(), 2);\n    put(&mut bytes, 20 + 8 * entries.len(), 0xa5a5_5a5a);\n    bytes\n}\nfn put(bytes: &mut [u8], offset: usize, value: u32) {\n    bytes[offset..offset + 4].copy_from_slice(&value.to_le_bytes());\n}\n\n#[derive(Clone, Copy, Debug)]\npub enum Upload {\n    Atgc,\n    Apo,\n    ApoComp,\n}\nimpl Upload {\n    pub fn file(self) -> &'static str {\n        match self {\n            Self::Atgc => \"A_ATGC.bin\",\n            Self::Apo => \"A_Apo.bin\",\n            Self::ApoComp => \"A_ApoComp.bin\",\n        }\n    }\n    pub fn encode(self, raw: &[u8]) -> Result<Vec<u8>> {\n        let (kind, size, metadata) = match self {\n            Self::Atgc => (12, 1024, 256u32),\n            Self::Apo => (13, 2048, 0),\n            Self::ApoComp => (14, 2048, 0),\n        };\n        exact(raw, size, self.file())?;\n        let meaningful = 16 + raw.len() + 8;\n        let mut bytes = vec![0; meaningful.div_ceil(512) * 512];\n        put(&mut bytes, 0, 0x5a5a_a5a5);\n        put(&mut bytes, 4, kind | metadata << 20);\n        bytes[16..16 + raw.len()].copy_from_slice(raw);\n        put(&mut bytes, 16 + raw.len(), kind);\n        put(&mut bytes, 20 + raw.len(), 0xa5a5_5a5a);\n        Ok(bytes)\n    }\n}\n\npub(crate) fn load(directory: &Path, name: &str, size: usize) -> Result<Vec<u8>> {\n    let path = directory.join(name);\n    if !fs::symlink_metadata(&path)\n        .map_err(|e| e.to_string())?\n        .file_type()\n        .is_file()\n    {\n        return Err(format!(\"{name}: regular non-symlink input required\"));\n    }\n    let file = File::open(&path).map_err(|e| e.to_string())?;\n    if !file.metadata().map_err(|e| e.to_string())?.is_file() {\n        return Err(\"Opened input is not regular\".into());\n    }\n    let mut bytes = Vec::new();\n    file.take(size as u64 + 1)\n        .read_to_end(&mut bytes)\n        .map_err(|e| e.to_string())?;\n    exact(&bytes, size, name)?;\n    Ok(bytes)\n}\n"
      },
      {
        "path": "components/ultrasound/convex-decoder/1.0.0/src/convex_pipeline.rs",
        "sha256": "4fb4925ede9fc66f4fb0292fae144b25822a515b17c60f8567dcb339f33fb11e",
        "text": "// SPDX-License-Identifier: AGPL-3.0-or-later\n//! Stateful General convex CPU engine. Immutable resources; explicit backing\n//! creation/resumption, attempted-call scheduling and retained failure state.\nuse crate::{\n    Result, archive, convex_bfsp as bfsp, convex_compound as compound, convex_dsc as dsc,\n    convex_dtgc as dtgc, convex_lifecycle as lifecycle, convex_sri as sri,\n    convex_sri_plan as sri_plan, linear_dsp::read_regular, rgba_png,\n};\nuse serde_json::{Value, json};\nuse std::{collections::BTreeMap, fs, path::Path};\n\n#[derive(Clone, Copy)]\npub struct Settings {\n    pub bfsp: bfsp::Settings,\n    pub dtgc: dtgc::Settings,\n    pub enhancement: usize,\n    pub correlation: usize,\n    pub dsc: dsc::Settings,\n    pub max_groups: usize,\n}\nfn exact_keys(v: &Value, keys: &[&str]) -> Result<()> {\n    let o = v.as_object().ok_or(\"Require settings object\")?;\n    if o.len() != keys.len() || o.keys().any(|k| !keys.contains(&k.as_str())) {\n        return Err(\"Require exact convex pipeline keys; no defaults\".into());\n    }\n    Ok(())\n}\nimpl Settings {\n    pub fn parse(v: &Value) -> Result<Self> {\n        exact_keys(\n            v,\n            &[\"schema_version\", \"bfsp\", \"dtgc\", \"sri\", \"dsc\", \"max_groups\"],\n        )?;\n        exact_keys(&v[\"sri\"], &[\"enhancement\", \"correlation_index\"])?;\n        if v[\"schema_version\"] != \"convex-pipeline-settings-v1\" {\n            return Err(\"Require convex-pipeline-settings-v1\".into());\n        }\n        let bfsp = bfsp::Settings::from_json(&v[\"bfsp\"])?;\n        let dtgc = dtgc::Settings::from_json(&v[\"dtgc\"])?;\n        let dsc = dsc::Settings::parse(&v[\"dsc\"])?;\n        let s = sri_plan::Settings::from_json(&json!({\"schema_version\":\"convex-sri-settings-v1\",\n            \"depth_index\":bfsp.depth,\"enhancement\":v[\"sri\"][\"enhancement\"],\n            \"correlation_index\":v[\"sri\"][\"correlation_index\"],\"frame_count_before\":0}))?;\n        let max_groups = v[\"max_groups\"]\n            .as_u64()\n            .filter(|n| (1..=128).contains(n))\n            .ok_or(\"max_groups must be1..128\")? as usize;\n        if dsc.depth != bfsp.depth {\n            return Err(\"BFSP and DSC depths must match\".into());\n        }\n        Ok(Self {\n            bfsp,\n            dtgc,\n            enhancement: s.enhancement,\n            correlation: s.correlation,\n            dsc,\n            max_groups,\n        })\n    }\n    pub fn json(self) -> Value {\n        json!({\"schema_version\":\"convex-pipeline-settings-v1\",\"bfsp\":self.bfsp.json(),\n            \"dtgc\":self.dtgc.json(),\"sri\":{\"enhancement\":self.enhancement,\"correlation_index\":self.correlation},\n            \"dsc\":self.dsc.json(),\"max_groups\":self.max_groups})\n    }\n}\npub struct Resources {\n    bfsp: bfsp::Assets,\n    plan: bfsp::Plan,\n    dtgc: dtgc::Processor,\n    compound: compound::Processor,\n    sri: [sri::Processor; 3],\n    dsc: dsc::Plan,\n    settings: Settings,\n    provenance: Value,\n    identity: String,\n}\nimpl Resources {\n    pub(crate) fn selected(&self) -> Result<crate::ImageProfile> {\n        if self.settings.enhancement != 0 {\n            return Err(\"Only no-enhancement selected profiles supported\".into());\n        }\n        let (bfsp_coefficients, bfsp_downsample) = self.bfsp.selected();\n        let (dtgc_tgc, dtgc_depth, dtgc_gain, dtgc_dr) = self.dtgc.selected();\n        let (compound_window, compound_coef0, compound_threshold_a, compound_threshold_b) =\n            self.compound.selected();\n        let temporal_correlation = f32::from_bits(\n            self.sri[1].plan().recipe[\"effective_mask_correlation_bits\"]\n                .as_u64()\n                .ok_or(\"Missing temporal correlation\")? as u32,\n        );\n        Ok(crate::ImageProfile {\n            settings: self.settings.json(),\n            bfsp_coefficients,\n            bfsp_downsample,\n            dtgc_tgc,\n            dtgc_depth,\n            dtgc_gain,\n            dtgc_dr,\n            compound_window,\n            compound_coef0,\n            compound_threshold_a,\n            compound_threshold_b,\n            temporal_correlation,\n            dsc_parameters: self\n                .dsc\n                .parameters\n                .clone()\n                .try_into()\n                .map_err(|_| \"DSC parameter shape\")?,\n            display_map: self\n                .dsc\n                .map\n                .clone()\n                .try_into()\n                .map_err(|_| \"DSC map shape\")?,\n        })\n    }\n    pub(crate) fn from_selected(settings: Settings, profile: crate::ImageProfile) -> Result<Self> {\n        if settings.enhancement != 0\n            || settings.json() != Settings::parse(&profile.settings)?.json()\n        {\n            return Err(\"Selected image profile and settings mismatch\".into());\n        }\n        let bfsp = bfsp::Assets::from_selected(\n            settings.bfsp,\n            profile.bfsp_coefficients,\n            profile.bfsp_downsample,\n        )?;\n        let plan = bfsp.plan(settings.bfsp)?;\n        let dtgc = dtgc::Processor::from_selected(\n            profile.dtgc_tgc,\n            profile.dtgc_depth,\n            profile.dtgc_gain,\n            profile.dtgc_dr,\n        )?;\n        let compound = compound::Processor::from_selected(\n            profile.compound_window,\n            profile.compound_coef0,\n            profile.compound_threshold_a,\n            profile.compound_threshold_b,\n        )?;\n        let sri = [\n            sri::Processor::no_enhancement(profile.temporal_correlation, 0)?,\n            sri::Processor::no_enhancement(profile.temporal_correlation, 1)?,\n            sri::Processor::no_enhancement(profile.temporal_correlation, 2)?,\n        ];\n        let dsc =\n            dsc::Plan::from_selected(settings.dsc, profile.dsc_parameters, profile.display_map)?;\n        let provenance = json!({\"policy\":\"selected-memory-profile-v1\",\"parameters_sha256\":archive::sha(&serde_json::to_vec(&profile.json()).unwrap())});\n        let identity = archive::sha(&serde_json::to_vec(&provenance).unwrap());\n        Ok(Self {\n            bfsp,\n            plan,\n            dtgc,\n            compound,\n            sri,\n            dsc,\n            settings,\n            provenance,\n            identity,\n        })\n    }\n\n    pub fn plan(&self) -> bfsp::Plan {\n        self.plan\n    }\n    pub fn settings(&self) -> Settings {\n        self.settings\n    }\n    pub fn provenance(&self) -> &Value {\n        &self.provenance\n    }\n    pub fn identity(&self) -> &str {\n        &self.identity\n    }\n    pub fn load(\n        assets: &Path,\n        sri_resources: &Path,\n        maps: &Path,\n        settings: Settings,\n        custom: Option<&[u8]>,\n    ) -> Result<Self> {\n        Self::from_source(\n            &crate::resources::Files(assets),\n            &crate::resources::Files(sri_resources),\n            &crate::resources::Files(maps),\n            settings,\n            custom,\n            crate::Palette::Reference,\n        )\n    }\n    pub fn from_source(\n        assets: &dyn crate::resources::Source,\n        sri_resources: &dyn crate::resources::Source,\n        maps: &dyn crate::resources::Source,\n        settings: Settings,\n        custom: Option<&[u8]>,\n        palette: crate::Palette,\n    ) -> Result<Self> {\n        // Revalidate programmatic callers too.\n        let settings = Settings::parse(&settings.json())?;\n        let bfsp = bfsp::Assets::from_source(assets, settings.bfsp)?;\n        let plan = bfsp.plan(settings.bfsp)?;\n        let dtgc = dtgc::Processor::from_source(assets, settings.bfsp, settings.dtgc)?;\n        let compound = compound::Processor::from_source(assets, settings.bfsp, settings.dtgc)?;\n        let load = |frame_count| {\n            sri::Processor::from_source(\n                assets,\n                sri_resources,\n                sri_plan::Settings {\n                    depth: settings.bfsp.depth,\n                    enhancement: settings.enhancement,\n                    correlation: settings.correlation,\n                    frame_count,\n                },\n            )\n        };\n        let sri = [load(0)?, load(1)?, load(2)?];\n        let dsc = dsc::Plan::from_source(assets, maps, settings.dsc, custom, palette)?;\n        let provenance = json!({\"bfsp\":bfsp.provenance(),\"bfsp_plan\":plan.json(),\"dtgc\":dtgc.provenance(),\n            \"compound\":compound.provenance(),\"sri\":sri[0].provenance,\"dsc\":dsc.provenance,\n            \"settings\":settings.json(),\"custom_gray_sha256\":custom.map(archive::sha),\n            \"policy\":\"immutable-General-CPU-resources-v1\",\"NE_enabled\":false,\"ThreeLine_enabled\":false});\n        let identity = archive::sha(&serde_json::to_vec(&provenance).unwrap());\n        Ok(Self {\n            bfsp,\n            plan,\n            dtgc,\n            compound,\n            sri,\n            dsc,\n            settings,\n            provenance,\n            identity,\n        })\n    }\n}\npub struct State {\n    pub bfsp: bfsp::State,\n    pub dtgc: Vec<u8>,\n    pub compound: compound::State,\n    pub sri: sri::State,\n    pub host: lifecycle::State,\n    pub attempts: u64,\n    pub poisoned: bool,\n    pub initialization: String,\n}\nfn sri_layout() -> Vec<(String, usize)> {\n    let v: Value = serde_json::from_str(include_str!(\"known_convex_sri_layout.json\")).unwrap();\n    v[\"images\"]\n        .as_array()\n        .unwrap()\n        .iter()\n        .map(|i| {\n            let slot =\n                u16::from_str_radix(i[\"slot\"].as_str().unwrap().trim_start_matches(\"0x\"), 16)\n                    .unwrap();\n            (\n                format!(\"{slot:04x}.u8\"),\n                i[\"General_bytes\"].as_u64().unwrap() as usize,\n            )\n        })\n        .collect()\n}\nimpl State {\n    /// Deliberate initialization of OUR CPU memory, never a native cold-start claim.\n    pub fn cpu_zeroed(plan: bfsp::Plan) -> Result<Self> {\n        let compound = compound::State::from_bytes(\n            &json!({\"schema_version\":\"convex-compound-state-v1\",\n            \"history_initialized\":false,\"rdh_write_policy\":compound::POLICY}),\n            std::array::from_fn(|_| vec![0; compound::BYTES]),\n        )?;\n        let sri = sri::State::from_bytes(\n            &json!({\"schema_version\":\"convex-sri-state-v1\",\"policy\":sri::POLICY,\n            \"frame_count\":0,\"bound_mask_correlation_bits\":0}),\n            sri_layout().iter().map(|(_, n)| vec![0; *n]).collect(),\n        )?;\n        Ok(Self {\n            bfsp: bfsp::State::from_bytes(\n                plan,\n                vec![0; plan.raw_bytes()],\n                vec![0; plan.up_bytes()],\n                vec![0; plan.reshape_bytes()],\n            )?,\n            dtgc: vec![0; dtgc::IMAGE_BYTES],\n            compound,\n            sri,\n            host: lifecycle::State {\n                frame_count: 0,\n                dirty: true,\n                bound_mask_correlation: 0.,\n            },\n            attempts: 0,\n            poisoned: false,\n            initialization: \"cpu-zeroed-v1\".into(),\n        })\n    }\n    pub fn software_freeze(&mut self) -> Value {\n        let before = self.host.json();\n        self.host.software_freeze();\n        self.sri.frame_count = 0;\n        self.compound.initialized = false;\n        json!({\"event\":\"software_Freeze\",\"before\":before,\"after\":self.host.json(),\n            \"compound_initialized_after\":false,\"backings_cleared\":false,\"acoustic_command_sent\":false,\n            \"policy\":\"explicit-CPU-history-boundary-v1\"})\n    }\n    fn files(&self) -> Vec<(String, Vec<u8>)> {\n        let mut files = vec![\n            (\"bfsp-raw.bin\".into(), self.bfsp.raw.clone()),\n            (\"bfsp-up4.u16le\".into(), self.bfsp.up4.clone()),\n            (\"bfsp-reshape.f32le\".into(), self.bfsp.reshaped_bytes()),\n            (\"dtgc.u8\".into(), self.dtgc.clone()),\n        ];\n        files.extend(\n            self.compound\n                .files()\n                .iter()\n                .map(|(n, b)| (format!(\"compound-{n}\"), b.to_vec())),\n        );\n        files.extend(\n            self.sri\n                .files()\n                .iter()\n                .map(|(n, b)| (format!(\"sri-{n}\"), b.to_vec())),\n        );\n        files\n    }\n    pub fn save(&self, directory: &Path, resources: &Resources) -> Result<Value> {\n        fs::create_dir(directory)\n            .map_err(|e| format!(\"New pipeline state directory required: {e}\"))?;\n        let mut rows = Vec::new();\n        for (name, bytes) in self.files() {\n            archive::write_new(&directory.join(&name), &bytes)?;\n            rows.push(json!({\"file\":name,\"bytes\":bytes.len(),\"sha256\":archive::sha(&bytes)}));\n        }\n        let meta = json!({\"schema_version\":\"convex-pipeline-state-v1\",\"resource_identity\":resources.identity,\n            \"host\":self.host.json(),\"compound\":self.compound.metadata(),\"sri\":self.sri.metadata(),\n            \"attempts\":self.attempts,\"poisoned\":self.poisoned,\"initialization\":self.initialization,\"files\":rows});\n        archive::write_new(\n            &directory.join(\"state.json\"),\n            &serde_json::to_vec_pretty(&meta).unwrap(),\n        )?;\n        fs::File::open(directory)\n            .and_then(|f| f.sync_all())\n            .map_err(|e| e.to_string())?;\n        Ok(meta)\n    }\n    pub fn load(directory: &Path, resources: &Resources) -> Result<Self> {\n        let meta: Value =\n            serde_json::from_slice(&read_regular(&directory.join(\"state.json\"), 32768)?)\n                .map_err(|e| e.to_string())?;\n        exact_keys(\n            &meta,\n            &[\n                \"schema_version\",\n                \"resource_identity\",\n                \"host\",\n                \"compound\",\n                \"sri\",\n                \"attempts\",\n                \"poisoned\",\n                \"initialization\",\n                \"files\",\n            ],\n        )?;\n        if meta[\"schema_version\"] != \"convex-pipeline-state-v1\"\n            || meta[\"resource_identity\"] != resources.identity\n            || meta[\"poisoned\"] != false\n        {\n            return Err(\n                \"State schema/resources mismatch or incomplete CPU state; no implicit recovery\"\n                    .into(),\n            );\n        }\n        exact_keys(\n            &meta[\"host\"],\n            &[\"frame_count\", \"dirty\", \"bound_mask_correlation_bits\"],\n        )?;\n        let mut expected = vec![\n            (\"bfsp-raw.bin\".into(), resources.plan.raw_bytes()),\n            (\"bfsp-up4.u16le\".into(), resources.plan.up_bytes()),\n            (\"bfsp-reshape.f32le\".into(), resources.plan.reshape_bytes()),\n            (\"dtgc.u8\".into(), dtgc::IMAGE_BYTES),\n        ];\n        expected.extend(\n            compound::STATE_FILES\n                .iter()\n                .map(|n| (format!(\"compound-{n}\"), compound::BYTES)),\n        );\n        expected.extend(sri_layout().iter().map(|(n, b)| (format!(\"sri-{n}\"), *b)));\n        let rows = meta[\"files\"]\n            .as_array()\n            .filter(|r| r.len() == expected.len())\n            .ok_or(\"Require complete51-file state index\")?;\n        let mut files = BTreeMap::new();\n        for (name, size) in &expected {\n            let matches: Vec<_> = rows.iter().filter(|r| r[\"file\"] == *name).collect();\n            if matches.len() != 1 {\n                return Err(\"Duplicate/missing pipeline state file\".into());\n            }\n            let raw = read_regular(&directory.join(name), *size as u64)?;\n            if raw.len() != *size\n                || matches[0][\"bytes\"] != *size\n                || matches[0][\"sha256\"] != archive::sha(&raw)\n            {\n                return Err(format!(\"Pipeline state file changed: {name}\"));\n            }\n            files.insert(name.clone(), raw);\n        }\n        let bfsp = bfsp::State::from_bytes(\n            resources.plan,\n            files.remove(\"bfsp-raw.bin\").unwrap(),\n            files.remove(\"bfsp-up4.u16le\").unwrap(),\n            files.remove(\"bfsp-reshape.f32le\").unwrap(),\n        )?;\n        let dtgc = files.remove(\"dtgc.u8\").unwrap();\n        let compound = compound::State::from_bytes(\n            &meta[\"compound\"],\n            std::array::from_fn(|i| {\n                files\n                    .remove(&format!(\"compound-{}\", compound::STATE_FILES[i]))\n                    .unwrap()\n            }),\n        )?;\n        let sri = sri::State::from_bytes(\n            &meta[\"sri\"],\n            sri_layout()\n                .iter()\n                .map(|(n, _)| files.remove(&format!(\"sri-{n}\")).unwrap())\n                .collect(),\n        )?;\n        let dirty = meta[\"host\"][\"dirty\"]\n            .as_bool()\n            .ok_or(\"Explicit dirty flag required\")?;\n        if meta[\"host\"][\"frame_count\"] != sri.frame_count\n            || meta[\"host\"][\"bound_mask_correlation_bits\"] != sri.bound_mask_correlation.to_bits()\n        {\n            return Err(\"Host/SRI state mismatch\".into());\n        }\n        let host = lifecycle::State {\n            frame_count: sri.frame_count,\n            dirty,\n            bound_mask_correlation: sri.bound_mask_correlation,\n        };\n        host.validate()?;\n        let attempts = meta[\"attempts\"]\n            .as_u64()\n            .ok_or(\"Explicit attempts required\")?;\n        let initialization = meta[\"initialization\"]\n            .as_str()\n            .filter(|s| [\"cpu-zeroed-v1\", \"caller-explicit-v1\"].contains(s))\n            .ok_or(\"Unknown state initialization policy\")?\n            .to_string();\n        Ok(Self {\n            bfsp,\n            dtgc,\n            compound,\n            sri,\n            host,\n            attempts,\n            poisoned: false,\n            initialization,\n        })\n    }\n}\npub struct Engine {\n    resources: Resources,\n    pub state: State,\n}\npub struct Output {\n    pub attempt: lifecycle::Attempt,\n    pub png: Option<Vec<u8>>,\n    pub rgba: Option<Vec<u8>>,\n    pub interp: Option<Vec<u8>>,\n    pub compound_outside: Option<Vec<u8>>,\n    pub stages: Vec<Value>,\n}\nimpl Engine {\n    pub fn resources(&self) -> &Resources {\n        &self.resources\n    }\n    pub fn new(resources: Resources, state: State) -> Result<Self> {\n        state.host.validate()?;\n        bfsp::State::from_bytes(\n            resources.plan,\n            state.bfsp.raw.clone(),\n            state.bfsp.up4.clone(),\n            state.bfsp.reshaped_bytes(),\n        )?;\n        if state.poisoned\n            || state.dtgc.len() != dtgc::IMAGE_BYTES\n            || state.sri.frame_count != state.host.frame_count\n            || state.sri.bound_mask_correlation.to_bits()\n                != state.host.bound_mask_correlation.to_bits()\n        {\n            return Err(\"Incomplete or inconsistent pipeline state\".into());\n        }\n        // Public backing fields must also be valid before beginning Update.\n        compound::State::from_bytes(\n            &state.compound.metadata(),\n            std::array::from_fn(|i| state.compound.files()[i].1.to_vec()),\n        )?;\n        Ok(Self { resources, state })\n    }\n    /// Typed B_mode boundary: exact size rejection occurs AFTER Update. Header\n    /// admission is the caller's distinct audit, not a fabricated native return.\n    pub fn process(&mut self, lines: &[u8], phase: u8) -> Result<Output> {\n        self.process_output(lines, phase, true, true)\n    }\n    pub(crate) fn process_rgba(&mut self, lines: &[u8], phase: u8) -> Result<Output> {\n        self.process_output(lines, phase, false, true)\n    }\n    pub(crate) fn update_only(&mut self, lines: &[u8], phase: u8) -> Result<Output> {\n        self.process_output(lines, phase, false, false)\n    }\n    fn process_output(\n        &mut self,\n        lines: &[u8],\n        phase: u8,\n        encode_png: bool,\n        render: bool,\n    ) -> Result<Output> {\n        if self.state.poisoned {\n            return Err(\"CPU pipeline poisoned; preserve snapshot and explicitly recreate\".into());\n        }\n        // State is public for explicit preparation/checkpointing. Reject any\n        // caller damage before Update rather than slicing a shortened backing.\n        self.state.host.validate()?;\n        self.state.bfsp.validate(self.resources.plan)?;\n        self.state.compound.validate()?;\n        if self.state.dtgc.len() != dtgc::IMAGE_BYTES\n            || self.state.sri.frame_count != self.state.host.frame_count\n            || self.state.sri.bound_mask_correlation.to_bits()\n                != self.state.host.bound_mask_correlation.to_bits()\n        {\n            return Err(\"Caller changed pipeline state inconsistently; attempt not started\".into());\n        }\n        let before = self.state.host;\n        let count = before.frame_count;\n        let selected = f32::from_bits(\n            self.resources.sri[1].plan().recipe[\"effective_mask_correlation_bits\"]\n                .as_u64()\n                .unwrap() as u32,\n        );\n        self.state.attempts = self\n            .state\n            .attempts\n            .checked_add(1)\n            .ok_or(\"Attempt count overflow\")?;\n        let mut png = None;\n        let mut rgba = None;\n        let mut interp = None;\n        let mut outside = None;\n        let mut stages = Vec::new();\n        let r = &self.resources;\n        let state = &mut self.state;\n        let attempt = lifecycle::run(&mut state.host, selected, false, |stage| {\n            match stage {\n                lifecycle::Stage::Bfsp => {\n                    if lines.len() != r.plan.input_bytes() {\n                        return Ok(-91);\n                    }\n                    state.bfsp.raw[..lines.len()].copy_from_slice(lines);\n                    r.bfsp.process(r.plan, &mut state.bfsp, phase)?;\n                    stages.push(json!({\"operation\":\"BFSP/preprocess\",\"reshape_sha256\":archive::diagnostic_sha(&state.bfsp.reshaped_bytes())}));\n                    state.dtgc = r.dtgc.process(&state.bfsp.reshaped_bytes(), &state.dtgc)?;\n                    stages\n                        .push(json!({\"operation\":\"BFSP/DTGC\",\"sha256\":archive::diagnostic_sha(&state.dtgc)}));\n                    let out = r.compound.process(&state.dtgc, &state.compound)?;\n                    state.compound = out.state;\n                    outside = Some(out.rdh_outside_native);\n                    stages.push(json!({\"operation\":\"BFSP/compound\",\"output_sha256\":archive::diagnostic_sha(&state.compound.output),\n                        \"rdh_sha256\":archive::diagnostic_sha(&state.compound.rdh),\"outside_trace_consumed\":false}));\n                }\n                lifecycle::Stage::Sri => {\n                    // Re-evaluate the numerical recipe from the saved PRE-Update\n                    // scalar snapshot. This does NOT perform a second observable\n                    // Update; lifecycle state already changed before BFSP.\n                    let mut input = state.sri.clone();\n                    input.frame_count = count;\n                    input.bound_mask_correlation = before.bound_mask_correlation;\n                    let out = if encode_png {\n                        r.sri[count].process(&state.compound.output, &state.compound.rdh, &input)?\n                    } else {\n                        r.sri[count].process_live(\n                            &state.compound.output,\n                            &state.compound.rdh,\n                            &input,\n                        )?\n                    };\n                    stages.push(\n                        json!({\"operation\":\"SRI\",\"stages\":out.stages,\"histogram\":out.histogram,\n                        \"recipe\":out.recipe,\"scalar_adapter\":\"pre-Update-snapshot-v1\"}),\n                    );\n                    state.sri = out.state;\n                }\n                lifecycle::Stage::Dsc => {\n                    if !render {\n                        return Ok(0);\n                    }\n                    let files = state.sri.files();\n                    let input = files.iter().find(|(n, _)| n == \"0548.u8\").unwrap().1;\n                    let out = r.dsc.process(input)?;\n                    if encode_png {\n                        png = Some(rgba_png::encode(\n                            r.settings.dsc.width,\n                            r.settings.dsc.height,\n                            &out.output,\n                        )?);\n                    }\n                    stages.push(json!({\"operation\":\"DSC\",\"rgba_sha256\":archive::diagnostic_sha(&out.output)}));\n                    rgba = Some(out.output);\n                    interp = Some(out.interp);\n                }\n                lifecycle::Stage::Ne => return Err(\"NE outside General CPU domain\".into()),\n            }\n            Ok(0)\n        })?;\n        // A failed BFSP attempt still advances host scalars; image state remains\n        // exactly what the CPU stages actually completed, without rollback.\n        state.sri.frame_count = state.host.frame_count;\n        state.sri.bound_mask_correlation = state.host.bound_mask_correlation;\n        state.poisoned = attempt.error.is_some();\n        Ok(Output {\n            attempt,\n            png,\n            rgba,\n            interp,\n            compound_outside: outside,\n            stages,\n        })\n    }\n}\n"
      },
      {
        "path": "components/ultrasound/convex-decoder/1.0.0/src/convex_producers.rs",
        "sha256": "41a50d9b9d549088c2caf6e1eff19531ae443df986427bee824190522a08e9f8",
        "text": "// SPDX-License-Identifier: AGPL-3.0-or-later\n//! Pure selected TX16/ADC8, non-PA, fundamental B producers. No transport.\n//! Host sequential binary32 is declared; native ARM numerical identity is unproven.\nuse crate::{\n    Result,\n    convex_parameters::{self as p, FundamentalWave},\n};\nuse serde_json::{Value, json};\nconst SPEED: f32 = f32::from_bits(0x3fc5_1eb8);\n\npub(crate) fn integer(value: f64, name: &str) -> Result<i32> {\n    let v = value.trunc();\n    if !v.is_finite() || v < i32::MIN as f64 || v > i32::MAX as f64 {\n        return Err(format!(\"{name}: nonfinite or signed32 conversion overflow\"));\n    }\n    Ok(v as i32)\n}\nfn round_tx(value: f32) -> Result<i32> {\n    integer(\n        value as f64 + if value >= 0. { 0.5 } else { -0.5 },\n        \"TX rounding\",\n    )\n}\npub(crate) fn half(lo: i64, hi: i64) -> Result<u32> {\n    if !(0..=65535).contains(&lo) || !(0..=65535).contains(&hi) {\n        return Err(\"Register half-word overflow\".into());\n    }\n    Ok(lo as u32 | (hi as u32) << 16)\n}\npub(crate) fn unsigned(v: i64) -> Result<u32> {\n    u32::try_from(v).map_err(|_| \"Unsigned register overflow\".into())\n}\npub(crate) fn words(values: impl IntoIterator<Item = u32>) -> Vec<u8> {\n    values.into_iter().flat_map(u32::to_le_bytes).collect()\n}\n#[derive(Clone, Copy)]\npub(crate) struct Geometry {\n    pub pitch: f32,\n    pub radius: f32,\n    pub offset: f32,\n    pub clock: f32,\n    pub ctrl_min: i32,\n    pub hv_index: u8,\n}\nimpl Geometry {\n    pub fn parse(raw: &[u8]) -> Result<Self> {\n        let probe = p::Probe::parse(raw)?;\n        let g = Self {\n            pitch: f32::from_bits(p::word(raw, 0)),\n            radius: f32::from_bits(p::word(raw, 4)),\n            offset: f32::from_bits(p::word(raw, 8)),\n            clock: probe.clock_setting,\n            ctrl_min: p::word(raw, 0x24) as i32,\n            hv_index: (p::word(raw, 0x3c) & 255) as u8,\n        };\n        if [g.pitch, g.radius, g.offset].iter().any(|v| !v.is_finite())\n            || g.pitch <= 0.\n            || g.radius <= 0.\n            || g.offset < 0.\n            || g.ctrl_min <= 0\n            || p::word(raw, 0x14) != 2\n            || g.hv_index != 0\n        {\n            return Err(\n                \"Require finite positive convex geometry, reduction2, ctrlMin>0 and selected HV0\"\n                    .into(),\n            );\n        }\n        Ok(g)\n    }\n}\npub(crate) struct TxSelection {\n    pub lo: f32,\n    pub hi: f32,\n    pub aperture: u32,\n    pub waveform: usize,\n}\npub(crate) fn select_tx(\n    raw: &[u8],\n    g: Geometry,\n    depth: usize,\n    frequency: usize,\n    focus: usize,\n) -> Result<TxSelection> {\n    p::exact(raw, 1024, \"B_TxControl.bin\")?;\n    if depth > 7 || frequency > 2 || focus > 6 {\n        return Err(\"TX selector out of bounds\".into());\n    }\n    let base = 0x40 + 44 * depth;\n    let at = |i| p::word(raw, base + 4 * i) as i32;\n    let (lo, hi) = if focus == 6 {\n        (at(6), at(7))\n    } else {\n        (at(focus), at(focus))\n    };\n    if lo < 0 || hi < lo {\n        return Err(\"Negative/reversed TX focal interval\".into());\n    }\n    // Aperture selection compares Fend for focus6, before adding Probe.offset.\n    let compare = hi as f32;\n    let threshold = |i| p::word(raw, 0x1a0 + 16 * i + 4 * (3 - frequency)) as i32;\n    let mut bank = 7;\n    for i in 0..7 {\n        let a = threshold(i);\n        let b = threshold(i + 1);\n        if a < 0 || b < 0 {\n            return Err(\"Negative TX aperture threshold\".into());\n        }\n        if compare <= a as f32 {\n            bank = i;\n            break;\n        }\n        if a != 0 && compare <= b as f32 {\n            bank = i + 1;\n            break;\n        }\n    }\n    let aperture = p::word(raw, 0x1a0 + 16 * bank);\n    let waveform = usize::try_from(at(10 - frequency)).map_err(|_| \"Negative waveform selector\")?;\n    if aperture > 32 || waveform > 15 {\n        return Err(\"Aperture/waveform outside selected TX16 branch\".into());\n    }\n    Ok(TxSelection {\n        lo: lo as f32 + g.offset,\n        hi: hi as f32 + g.offset,\n        aperture,\n        waveform,\n    })\n}\npub(crate) struct Tx {\n    pub payload: Vec<u8>,\n    pub gates: [(u32, u32); 3],\n    pub report: Value,\n}\nfn aperture_mask(a: u32) -> Result<u32> {\n    match a {\n        0 => Ok(0),\n        32 => Ok(u32::MAX),\n        1..=31 => Ok(((1u32 << a) - 1) << ((32 - a).div_ceil(2))),\n        _ => Err(\"Aperture must be0..32\".into()),\n    }\n}\npub(crate) fn tx(raw: &[u8], g: Geometry, s: &TxSelection, wave: FundamentalWave) -> Result<Tx> {\n    let mut q = [0i32; 16];\n    for (i, out) in q.iter_mut().enumerate() {\n        let pos = i as f32 - 7.5;\n        let f =\n            s.lo.max(s.hi / (s.aperture as f32 * 0.5).max(1.) * ((pos.abs() + 1.).trunc()));\n        let r = g.radius + f;\n        let distance = (g.radius * g.radius + r * r\n            - ((pos * g.pitch) / g.radius).cos() * (g.radius + g.radius) * r)\n            .sqrt();\n        let x = ((f - distance) * g.clock) / SPEED;\n        // Assembly confirms f64 +/-0.5 after binary32 geometry, unlike RX.\n        *out = round_tx(x)?;\n    }\n    let qmin = *q.iter().min().unwrap() as i64;\n    let qmax = *q.iter().max().unwrap() as i64;\n    let w = i32::try_from(wave.delay_setting()).map_err(|_| \"TX delay setting exceeds signed32\")?\n        as i64;\n    let h = w / 2;\n    let t = (h + 3 - qmin.min(0)) / 4 + 1;\n    let mask = aperture_mask(s.aperture)?;\n    let mut payload = Vec::with_capacity(32);\n    let mut delays = Vec::new();\n    for (i, v) in q.iter().enumerate() {\n        let d = 4 * t - h + *v as i64;\n        if !(0..=32767).contains(&d) {\n            return Err(\"TX delay exceeds15bits\".into());\n        }\n        delays.push(d);\n        let encoded = d as u16 | (((mask >> (23 - i)) & 1) as u16) << 15;\n        payload.extend_from_slice(&encoded.to_le_bytes());\n    }\n    let a = p::word(raw, 0) as i32 as i64;\n    let b = p::word(raw, 4) as i32 as i64;\n    let c = p::word(raw, 8) as i32 as i64;\n    let v = t + (qmax + h + 3) / 4 + 1;\n    let gates = [\n        (0x60012, half(a, b)?),\n        (0x60014, half(b, v)?),\n        (0x60016, half(b + t, b + t + c)?),\n    ];\n    Ok(Tx {\n        payload,\n        gates,\n        report: json!({\"delay_min\":delays.iter().min(),\"delay_max\":delays.iter().max(),\n        \"raw_q_min\":qmin,\"raw_q_max\":qmax,\"t\":t,\"aperture_setting\":s.aperture,\n        \"focal_interval_setting\":[s.lo,s.hi],\"physical_units_validated\":false}),\n    })\n}\npub(crate) fn rx(g: Geometry) -> Result<Vec<u8>> {\n    let mut tables = [[[0u32; 2]; 24]; 8];\n    for (i, table) in tables.iter_mut().enumerate() {\n        let spacing = if i < 4 { 0.5 } else { 1. };\n        let group = [1.5, 0.5, -0.5, -1.5][i % 4];\n        for (j, pair) in table.iter_mut().enumerate() {\n            let theta = ((j as f32 - 11.5 + group * spacing) * g.pitch) / g.radius;\n            let a = (g.radius + g.radius) * (1. - theta.cos());\n            let z = a * g.radius;\n            let v = ((g.clock + g.clock) * a) / SPEED;\n            let c1 = integer((v + if v >= 0. { 0.5 } else { -0.5 }) as f64, \"RX C1\")?;\n            let c1 = i16::try_from(c1).map_err(|_| \"RX C1 exceeds signed16\")?;\n            let ratio = g.clock / SPEED;\n            let c2 = integer(((ratio * ratio) * z + 0.5) as f64, \"RX C2\")?;\n            *pair = [c1 as i32 as u32, c2 as u32];\n        }\n    }\n    let mut result = Vec::with_capacity(1024);\n    for pos in (8..16).chain(16..20).chain(4..8).chain(0..4).chain(20..24) {\n        for table in &tables[..4] {\n            result.extend(words(table[pos]));\n        }\n    }\n    for pos in 8..16 {\n        for table in &tables[4..] {\n            result.extend(words(table[pos]));\n        }\n    }\n    Ok(result)\n}\npub(crate) struct Filters {\n    pub iq: Vec<u8>,\n    pub lpf: Vec<u8>,\n    pub up4: Vec<u8>,\n    pub registers: Vec<(u32, u32)>,\n    pub iq_m: i32,\n}\npub(crate) fn filters(\n    dynamic: &[u8],\n    lpf1: &[u8],\n    up4: &[u8],\n    depth: usize,\n    frequency: usize,\n) -> Result<Filters> {\n    p::exact(dynamic, 43084, \"B_DynamicFilter.bin\")?;\n    p::exact(lpf1, 256, \"B_LPF.bin\")?;\n    p::exact(up4, 364, \"A_Up4Coef.bin\")?;\n    if depth > 7 || frequency > 2 {\n        return Err(\"Filter selection out of bounds\".into());\n    }\n    let iq_m = p::word(dynamic, 0) as i32;\n    if iq_m <= 0 {\n        return Err(\"IQ_M must be positive\".into());\n    }\n    let n = p::word(dynamic, 0xa834 + 4 * frequency);\n    if n > 255 {\n        return Err(\"B_n exceeds byte\".into());\n    }\n    let mut registers = vec![\n        (0x5003e, p::word(dynamic, 4 + 16 * frequency)),\n        (0x5003f, p::word(dynamic, 12 + 16 * frequency)),\n        (0x50046, n),\n        (0x50061, iq_m as u32),\n    ];\n    for i in 0..4 {\n        registers.push((0x5003a + i as u32, p::word(lpf1, 16 * depth + 4 * i)));\n    }\n    let mut selectors = [0usize; 11];\n    for (i, out) in selectors.iter_mut().enumerate() {\n        *out = p::word(up4, 320 + 4 * i) as usize;\n        if *out > 9 {\n            return Err(\"Up4 selector exceeds ten banks\".into());\n        }\n    }\n    let mut coefficients = Vec::with_capacity(128);\n    // Fresh C/D sentinel frequencies are replaced by0 in SendDepth.\n    for i in [2 - frequency, 7, 9, 10] {\n        let off = 32 * selectors[i];\n        coefficients.extend_from_slice(&up4[off..off + 32]);\n    }\n    Ok(Filters {\n        iq: dynamic[0x34 + 0x800 * frequency..0x34 + 0x800 * frequency + 2048].to_vec(),\n        lpf: dynamic[0x3034 + 0x1400 * frequency..0x3034 + 0x1400 * frequency + 5120].to_vec(),\n        up4: coefficients,\n        registers,\n        iq_m,\n    })\n}\npub(crate) struct Scan {\n    pub payload: Vec<u8>,\n    pub registers: [(u32, u32); 3],\n    pub report: Value,\n}\npub(crate) fn scan(\n    g: Geometry,\n    prf: p::SelectedPrf,\n    bf: &[u8],\n    logic: u32,\n    low_power: u8,\n    disabled: bool,\n) -> Result<Scan> {\n    p::exact(bf, 44, \"A_BF.bin\")?;\n    let f = prf.fields;\n    if p::word(bf, 4) != 4\n        || p::word(bf, 12) != 128\n        || p::word(bf, 16) != 64\n        || f[6] != 24\n        || f[9] != 2\n        || low_power > 3\n    {\n        return Err(\"Scan branch requires waveBeams4/dense128/sparse64, synthetic3/beamAdd2 and lowPower0..3\".into());\n    }\n    if f[0] <= 0 || f[4] <= 0 {\n        return Err(\"Frame/line rate must be positive\".into());\n    }\n    let budget = integer(\n        (((g.clock * 1_000_000.) * 0.25) / f[0] as f32) as f64,\n        \"Scan budget\",\n    )? as i64;\n    let min_prf = (f[4] / 4) as i64;\n    let ctrl = g.ctrl_min as i64;\n    let series = (logic >> 9) & 31;\n    let low_power_branch = !disabled\n        && low_power != 2\n        && (low_power == 1 || (5..=21).contains(&series) || series == 29);\n    let (b, control) = if low_power_branch {\n        (min_prf, ctrl.max(budget - 96 * min_prf))\n    } else {\n        (min_prf.max((budget - ctrl) / 96), ctrl)\n    };\n    let mut nodes = Vec::with_capacity(194);\n    for pass in 0..2u32 {\n        nodes.push((nodes.len() as u32) << 20 | 0x34000 | if pass == 1 { 0x2000 } else { 0 });\n        for q in 0..32u32 {\n            let last = pass == 1 && q == 31;\n            let element = if last { 62 } else { 2 * q + pass };\n            let completion = if last { 1 } else { 3 };\n            for k in (1..=3u32).rev() {\n                nodes.push(\n                    (nodes.len() as u32) << 20\n                        | u32::from(k == 1) << 16\n                        | completion << 12\n                        | k << 8\n                        | element,\n                );\n            }\n        }\n    }\n    Ok(Scan {\n        payload: words(nodes),\n        registers: [\n            (0x60011, unsigned(b)?),\n            (0x60055, unsigned(control)?),\n            (0x60010, 193),\n        ],\n        report: json!({\"nodes\":194,\"passes\":2,\"first_pass_nodes\":97,\"assigned_control_event_count\":1,\n            \"period_denominator\":96,\"budget_setting\":budget,\"low_power_branch\":low_power_branch,\n            \"logic_compile_version\":logic,\"product_series\":series,\"logic_type\":(logic>>14)&3,\n            \"logic_origin\":\"explicit unverified declaration; not USB firmware1.32\",\"physical_calibration\":null}),\n    })\n}\npub(crate) fn hv(raw: &[u8]) -> Result<Vec<u8>> {\n    if raw.is_empty() || raw.len() > 4096 * 11 {\n        return Err(\"HV file outside word bound\".into());\n    }\n    let count = raw.len().div_ceil(11);\n    let mut payload = Vec::with_capacity(count * 4);\n    for (i, record) in raw.chunks(11).enumerate() {\n        let last = i + 1 == count;\n        if record.len() < 9\n            || record[..8].iter().any(|b| !b.is_ascii_hexdigit())\n            || !matches!(record[8], b',' | b';')\n            || (!last && &record[9..] != b\"\\r\\n\")\n            || (last && !matches!(&record[9..], b\"\" | b\"\\r\\n\"))\n        {\n            return Err(\n                \"HV requires eight hex digits, separator and exact11-byte stride (last9/11)\".into(),\n            );\n        }\n        let value = u32::from_str_radix(std::str::from_utf8(&record[..8]).unwrap(), 16)\n            .map_err(|e| e.to_string())?;\n        payload.extend_from_slice(&value.to_le_bytes());\n    }\n    Ok(payload)\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n    fn put(b: &mut [u8], offset: usize, v: u32) {\n        b[offset..offset + 4].copy_from_slice(&v.to_le_bytes());\n    }\n    fn geometry() -> Geometry {\n        Geometry {\n            pitch: 0.,\n            radius: 50.,\n            offset: 0.,\n            clock: 100.,\n            ctrl_min: 64,\n            hv_index: 0,\n        }\n    }\n    #[test]\n    fn derived_aperture_mask_is_centered_with_exact_bit_counts_for_all33_cases() {\n        for a in 0..=32 {\n            let m = aperture_mask(a).unwrap();\n            assert_eq!(m.count_ones(), a);\n            if a > 0 {\n                assert_eq!(m.trailing_zeros(), (32 - a).div_ceil(2));\n                assert_eq!(m.leading_zeros(), (32 - a) / 2);\n            }\n        }\n        assert!(aperture_mask(33).is_err());\n    }\n    #[test]\n    fn tx_on_axis_analytic_case_and_f64_rounding_preserve_gate_and_channel_packing() {\n        // Zero pitch is a mathematical test of the pure helper, not a supported\n        // hardware input (Geometry::parse requires positive pitch).\n        let mut raw = vec![0; 1024];\n        for (i, v) in [1, 2, 3].into_iter().enumerate() {\n            put(&mut raw, 4 * i, v);\n        }\n        let mut w = vec![0; 660];\n        put(&mut w, 2 * 33 * 4, 8);\n        let wave = p::TxWave8::parse(&w).unwrap().fundamental(0).unwrap();\n        let s = TxSelection {\n            lo: 100.,\n            hi: 100.,\n            aperture: 16,\n            waveform: 0,\n        };\n        let out = tx(&raw, geometry(), &s, wave).unwrap();\n        assert_eq!(out.payload, [4, 128].repeat(16));\n        assert_eq!(\n            out.gates,\n            [\n                (0x60012, 0x00020001),\n                (0x60014, 0x00040002),\n                (0x60016, 0x00070004)\n            ]\n        );\n        assert_eq!(round_tx(8_388_609.).unwrap(), 8_388_609);\n        assert_eq!(round_tx(-8_388_609.).unwrap(), -8_388_609);\n        assert_eq!(round_tx(1.5).unwrap(), 2);\n        assert_eq!(round_tx(-1.5).unwrap(), -2);\n        assert!(round_tx(f32::NAN).is_err());\n        assert!(round_tx(f32::INFINITY).is_err());\n        assert!(round_tx(2_147_483_648.).is_err());\n        assert!(half(-1, 0).is_err());\n        assert!(half(0, 65536).is_err());\n    }\n    #[test]\n    fn focal_selection_uses_end_for_focus6_aperture_and_reversed_frequency_banks() {\n        let mut raw = vec![0; 1024];\n        for i in 0..8 {\n            for j in 0..8 {\n                put(\n                    &mut raw,\n                    0x40 + 44 * i + 4 * j,\n                    if j == 6 {\n                        5\n                    } else if j == 7 {\n                        65\n                    } else {\n                        15\n                    },\n                );\n            }\n            for j in 0..3 {\n                put(&mut raw, 0x40 + 44 * i + 32 + 4 * j, (j + 7) as u32);\n            }\n            put(&mut raw, 0x1a0 + 16 * i, (i + 1) as u32);\n            for j in 1..4 {\n                put(&mut raw, 0x1a0 + 16 * i + 4 * j, (20 * (i + 1)) as u32);\n            }\n        }\n        let mut g = geometry();\n        g.offset = 10.;\n        let a = select_tx(&raw, g, 7, 2, 6).unwrap();\n        assert_eq!((a.lo, a.hi, a.aperture, a.waveform), (15., 75., 4, 7));\n        let b = select_tx(&raw, g, 0, 0, 0).unwrap();\n        assert_eq!((b.lo, b.hi, b.aperture, b.waveform), (25., 25., 1, 9));\n        for (d, f, k) in [(8, 0, 0), (0, 3, 0), (0, 0, 7)] {\n            assert!(select_tx(&raw, g, d, f, k).is_err());\n        }\n        put(&mut raw, 0x40 + 40, 16);\n        assert!(select_tx(&raw, g, 0, 0, 0).is_err());\n    }\n    #[test]\n    fn rx_has_exact_b_and_c_region_sizes_zero_axis_and_overflow_rejection() {\n        let out = rx(geometry()).unwrap();\n        assert_eq!(out.len(), 1024);\n        assert!(out.iter().all(|v| *v == 0));\n        let mut g = geometry();\n        g.pitch = 0.5;\n        let out = rx(g).unwrap();\n        assert!(out.iter().any(|v| *v != 0));\n        // C-group +0.5 at j11 and -0.5 at j12 both have theta0.\n        assert_eq!(&out[768 + (3 * 4 + 1) * 8..768 + (3 * 4 + 2) * 8], &[0; 8]);\n        assert_eq!(&out[768 + (4 * 4 + 2) * 8..768 + (4 * 4 + 3) * 8], &[0; 8]);\n        g.clock = f32::MAX;\n        assert!(rx(g).is_err());\n    }\n    #[test]\n    fn filter_slices_and_all_up4_selectors_are_bounded_without_pointer_aliasing() {\n        let mut dynamic = vec![0; 43084];\n        put(&mut dynamic, 0, 2);\n        for freq in 0..3 {\n            put(&mut dynamic, 4 + 16 * freq, 10 + freq as u32);\n            put(&mut dynamic, 12 + 16 * freq, 20 + freq as u32);\n            put(&mut dynamic, 0xa834 + 4 * freq, 3 + freq as u32);\n            dynamic[0x34 + 0x800 * freq..0x34 + 0x800 * freq + 2048].fill(freq as u8 + 30);\n            dynamic[0x3034 + 0x1400 * freq..0x3034 + 0x1400 * freq + 5120].fill(freq as u8 + 40);\n        }\n        let mut up = vec![0; 364];\n        for i in 0..10 {\n            up[i * 32..i * 32 + 32].fill(i as u8);\n        }\n        for i in 0..11 {\n            put(&mut up, 320 + 4 * i, (i % 10) as u32);\n        }\n        let mut lpf = vec![0; 256];\n        for i in 0..8 {\n            lpf[i * 16..i * 16 + 16].fill(i as u8);\n        }\n        for freq in 0..3 {\n            let out = filters(&dynamic, &lpf, &up, 7, freq).unwrap();\n            assert_eq!(out.iq, vec![freq as u8 + 30; 2048]);\n            assert_eq!(out.lpf, vec![freq as u8 + 40; 5120]);\n            assert_eq!(\n                out.up4,\n                [\n                    vec![(2 - freq) as u8; 32],\n                    vec![7; 32],\n                    vec![9; 32],\n                    vec![0; 32]\n                ]\n                .concat()\n            );\n            assert!(out.registers.contains(&(0x5003a, 0x07070707)));\n        }\n        for i in 0..11 {\n            let mut bad = up.clone();\n            put(&mut bad, 320 + 4 * i, 10);\n            assert!(filters(&dynamic, &lpf, &bad, 0, 0).is_err());\n        }\n        put(&mut dynamic, 0, 0);\n        assert!(filters(&dynamic, &lpf, &up, 0, 0).is_err());\n    }\n    #[test]\n    fn scan_nodes_and_period_use_first_pass_minus_assigned_single_control_event() {\n        let mut bf = vec![0; 44];\n        for (o, v) in [(4, 4), (12, 128), (16, 64)] {\n            put(&mut bf, o, v);\n        }\n        let mut fields = [0; 13];\n        fields[0] = 100;\n        fields[4] = 4000;\n        fields[6] = 24;\n        fields[9] = 2;\n        let prf = p::SelectedPrf {\n            display_setting: 0,\n            fields,\n        };\n        let base = scan(geometry(), prf, &bf, 0, 0, false).unwrap();\n        assert_eq!(\n            base.registers,\n            [(0x60011, 2603), (0x60055, 64), (0x60010, 193)]\n        );\n        let n: Vec<_> = base\n            .payload\n            .as_chunks::<4>()\n            .0\n            .iter()\n            .map(|v| u32::from_le_bytes(*v))\n            .collect();\n        assert_eq!(n.len(), 194);\n        assert_eq!(n[0], 0x34000);\n        assert_eq!(n[97], 97 << 20 | 0x36000);\n        assert_eq!(n[1], 1 << 20 | 0x3300);\n        assert_eq!(n[193], 193 << 20 | 0x1113e);\n        for (i, v) in n.iter().enumerate() {\n            assert_eq!(v >> 20, i as u32);\n        }\n        for (logic, low, disabled, special) in [\n            (5 << 9, 0, false, true),\n            (0, 1, false, true),\n            (5 << 9, 2, false, false),\n            (5 << 9, 3, false, true),\n            (5 << 9, 1, true, false),\n            (22 << 9, 0, false, false),\n            (29 << 9, 0, false, true),\n        ] {\n            let out = scan(geometry(), prf, &bf, logic, low, disabled).unwrap();\n            assert_eq!(out.report[\"low_power_branch\"], special);\n            if special {\n                assert_eq!(&out.registers[..2], &[(0x60011, 1000), (0x60055, 154000)]);\n            }\n        }\n    }\n    #[test]\n    fn hv_stride_count_and_literal_word_order_reject_native_allocation_quirks() {\n        assert_eq!(\n            hv(b\"01234567,\\r\\n89ABCDEF;\").unwrap(),\n            words([0x01234567, 0x89abcdef])\n        );\n        assert_eq!(hv(b\"01234567;\\r\\n\").unwrap(), words([0x01234567]));\n        for b in [\n            &b\"\"[..],\n            b\"1234567;\",\n            b\"12345678\\n\",\n            b\"1234567Z;\",\n            b\"12345678;\\n\",\n            b\"12345678;\\r\\nextra\",\n            b\"12345678,  00000000;\",\n        ] {\n            assert!(hv(b).is_err(), \"{b:?}\");\n        }\n        assert!(hv(&vec![b'0'; 4096 * 11 + 1]).is_err());\n    }\n}\n"
      },
      {
        "path": "components/ultrasound/convex-decoder/1.0.0/src/convex_sri.rs",
        "sha256": "74057b9a8cdc0c1012ae40390bb832f05866a07fff2f90234e8ac5c73e9a6d4d",
        "text": "// SPDX-License-Identifier: AGPL-3.0-or-later\n//! General convex SRI CPU image operations with caller-supplied complete state.\n//! No native/GPU/physical equivalence; coefficients remain external and hash-bound.\nuse crate::{\n    Result, archive,\n    convex_sri_plan::{Plan, Settings},\n    linear_dsp::read_regular,\n    linear_post::unorm,\n};\nuse serde_json::{Value, json};\nuse std::{collections::BTreeMap, path::Path};\npub const POLICY: &str = \"full-native-backing-v1\";\npub const EXTERNAL_BYTES: usize = 64 * 1024 * 4;\ntype Images = BTreeMap<u16, Image>;\n#[derive(Clone, Copy, PartialEq, Debug)]\nenum Kind {\n    Unorm,\n    Snorm,\n    Int,\n}\n#[derive(Clone)]\nstruct Image {\n    w: usize,\n    h: usize,\n    kind: Kind,\n    bytes: Vec<u8>,\n}\nimpl Image {\n    fn get(&self, x: i32, y: i32, c: usize) -> f32 {\n        let x = x.clamp(0, self.w as i32 - 1) as usize;\n        let y = y.clamp(0, self.h as i32 - 1) as usize;\n        let b = self.bytes[(y * self.w + x) * 4 + c];\n        match self.kind {\n            Kind::Unorm => b as f32 / 255.,\n            Kind::Snorm => (b as i8 as f32 / 127.).max(-1.),\n            Kind::Int => b as i8 as f32,\n        }\n    }\n    fn set(&mut self, x: usize, y: usize, c: usize, v: f32) -> Result<()> {\n        if x >= self.w || y >= self.h || !v.is_finite() {\n            return Err(\"Invalid/outside/nonfinite SRI image write; state unchanged\".into());\n        }\n        self.bytes[(y * self.w + x) * 4 + c] = match self.kind {\n            Kind::Unorm => unorm(v),\n            Kind::Snorm => (v.clamp(-1., 1.) * 127.).round_ties_even() as i8 as u8,\n            Kind::Int => {\n                if v.trunc() != v || !(0. ..=8.).contains(&v) {\n                    return Err(format!(\"SRI direction{v} outside0..8; no bank read\"));\n                }\n                v as i8 as u8\n            }\n        };\n        Ok(())\n    }\n}\nfn slot(s: &str) -> u16 {\n    u16::from_str_radix(s.strip_prefix(\"0x\").unwrap_or(s), 16).unwrap()\n}\nfn template() -> Vec<(u16, usize, usize, Kind)> {\n    let j: Value = serde_json::from_str(include_str!(\"known_convex_sri_layout.json\")).unwrap();\n    j[\"images\"]\n        .as_array()\n        .unwrap()\n        .iter()\n        .map(|a| {\n            (\n                slot(a[\"slot\"].as_str().unwrap()),\n                a[\"General_width\"].as_u64().unwrap() as usize,\n                a[\"height\"].as_u64().unwrap() as usize,\n                match a[\"channel_type\"].as_str().unwrap() {\n                    \"CL_SNORM_INT8\" => Kind::Snorm,\n                    \"CL_SIGNED_INT8\" => Kind::Int,\n                    _ => Kind::Unorm,\n                },\n            )\n        })\n        .collect()\n}\n#[derive(Clone)]\npub struct State {\n    pub frame_count: usize,\n    pub bound_mask_correlation: f32,\n    images: Images,\n}\nimpl State {\n    pub fn load(directory: &Path) -> Result<(Self, Vec<u8>)> {\n        let raw = read_regular(&directory.join(\"state.json\"), 16384)?;\n        let j: Value = serde_json::from_slice(&raw).map_err(|e| e.to_string())?;\n        let mut files = Vec::new();\n        for (s, w, h, _) in template() {\n            files.push(read_regular(\n                &directory.join(format!(\"{s:04x}.u8\")),\n                (w * h * 4) as u64,\n            )?)\n        }\n        Ok((Self::from_bytes(&j, files)?, raw))\n    }\n    pub fn from_bytes(meta: &Value, files: Vec<Vec<u8>>) -> Result<Self> {\n        let keys = [\n            \"schema_version\",\n            \"policy\",\n            \"frame_count\",\n            \"bound_mask_correlation_bits\",\n        ];\n        let o = meta\n            .as_object()\n            .ok_or(\"Require explicit SRI state metadata\")?;\n        if o.len() != 4\n            || o.keys().any(|s| !keys.contains(&s.as_str()))\n            || meta[\"schema_version\"] != \"convex-sri-state-v1\"\n            || meta[\"policy\"] != POLICY\n        {\n            return Err(\"Require exact convex-sri-state-v1 and full-native-backing-v1\".into());\n        }\n        let frame_count = meta[\"frame_count\"]\n            .as_u64()\n            .filter(|n| *n <= 2)\n            .ok_or(\"Invalid explicit SRI frame count\")? as usize;\n        let bits = meta[\"bound_mask_correlation_bits\"]\n            .as_u64()\n            .and_then(|v| u32::try_from(v).ok())\n            .ok_or(\"Require explicit bound correlation bits\")?;\n        let bound_mask_correlation = f32::from_bits(bits);\n        if !bound_mask_correlation.is_finite() || !(0. ..=1.).contains(&bound_mask_correlation) {\n            return Err(\"Invalid bound mask correlation\".into());\n        }\n        let layout = template();\n        if layout.len() != files.len() {\n            return Err(\"Require all42 SRI image backings\".into());\n        }\n        let mut images = Images::new();\n        for ((s, w, h, kind), bytes) in layout.into_iter().zip(files) {\n            if bytes.len() != w * h * 4 {\n                return Err(format!(\"Require complete SRI image{s:04x}\"));\n            }\n            images.insert(s, Image { w, h, kind, bytes });\n        }\n        Ok(Self {\n            frame_count,\n            bound_mask_correlation,\n            images,\n        })\n    }\n    pub fn metadata(&self) -> Value {\n        json!({\"schema_version\":\"convex-sri-state-v1\",\"policy\":POLICY,\"frame_count\":self.frame_count,\"bound_mask_correlation_bits\":self.bound_mask_correlation.to_bits()})\n    }\n    pub fn files(&self) -> Vec<(String, &[u8])> {\n        self.images\n            .iter()\n            .map(|(s, i)| (format!(\"{s:04x}.u8\"), i.bytes.as_slice()))\n            .collect()\n    }\n}\nfn get(a: &Images, s: u16, x: i32, y: i32, c: usize) -> f32 {\n    a[&s].get(x, y, c)\n}\nfn stage(\n    a: &mut Images,\n    s: u16,\n    w: usize,\n    h: usize,\n    f: impl Fn(&Images, i32, i32, usize) -> f32,\n) -> Result<()> {\n    let mut dst = a[&s].clone();\n    if w > dst.w || h > dst.h {\n        return Err(\"SRI dispatch outside native image\".into());\n    }\n    for y in 0..h {\n        for x in 0..w {\n            for c in 0..4 {\n                dst.set(x, y, c, f(a, x as i32, y as i32, c))?\n            }\n        }\n    }\n    a.insert(s, dst);\n    Ok(())\n}\nfn copy(a: &mut Images, src: u16, dst: u16, w: usize, h: usize) -> Result<()> {\n    let s = &a[&src];\n    let d = &a[&dst];\n    if w > s.w || h > s.h || w > d.w || h > d.h || s.kind != d.kind {\n        return Err(\"Invalid SRI copy region/format\".into());\n    }\n    let mut d = d.clone();\n    for y in 0..h {\n        d.bytes[y * d.w * 4..y * d.w * 4 + w * 4]\n            .copy_from_slice(&s.bytes[y * s.w * 4..y * s.w * 4 + w * 4])\n    }\n    a.insert(dst, d);\n    Ok(())\n}\nfn convolution(i: &Image, x: i32, y: i32, c: usize, dx: &[i32], dy: &[i32], k: &[f32]) -> f32 {\n    let mut v = 0.;\n    for (j, &oy) in dy.iter().enumerate() {\n        for (n, &ox) in dx.iter().enumerate() {\n            v += i.get(x + ox, y + oy, c) * k[j * dx.len() + n]\n        }\n    }\n    v\n}\nfn vector(i: &Image, x: i32, y: i32, c: usize, offset: i32, k: &[f32], vertical: bool) -> f32 {\n    let mut v = 0.;\n    for (j, &weight) in k.iter().enumerate() {\n        let d = offset + j as i32;\n        v += i.get(\n            x + if vertical { 0 } else { d },\n            y + if vertical { d } else { 0 },\n            c,\n        ) * weight\n    }\n    v\n}\nfn polyphase(i: &Image, x: i32, y: i32, c: usize, k: &[f32]) -> f32 {\n    let (dx, dy, weights): (&[i32], &[i32], &[f32]) = match (x % 2, y % 2) {\n        (0, 0) => (&[-2, -1, 0, 1, 2], &[-2, -1, 0, 1, 2], &k[..25]),\n        (1, 0) => (&[-1, 0, 1, 2], &[-2, -1, 0, 1, 2], &k[25..45]),\n        (0, 1) => (&[-2, -1, 0, 1, 2], &[-1, 0, 1, 2], &k[45..65]),\n        _ => (&[-1, 0, 1, 2], &[-1, 0, 1, 2], &k[65..]),\n    };\n    convolution(i, x / 2, y / 2, c, dx, dy, weights)\n}\nfn neighbors(i: &Image, x: i32, y: i32, c: usize, center: bool) -> f32 {\n    let mut v = 0.;\n    for dy in -1..=1 {\n        for dx in -1..=1 {\n            if center || dx != 0 || dy != 0 {\n                v += i.get(x + dx, y + dy, c)\n            }\n        }\n    }\n    v\n}\nfn direction(mask: &Image, angle: &Image, x: i32, y: i32, c: usize) -> f32 {\n    let (mut max, mut chosen, mut total) = (0., 0., 0.);\n    for dy in -2..=2 {\n        for dx in -1..=1 {\n            let r = mask.get(x + dx, y + dy, c);\n            if max <= r {\n                max = r;\n                chosen = angle.get(x + dx, y + dy, c)\n            }\n            total += r\n        }\n    }\n    let mut sum = 0.;\n    for dy in -2..=2 {\n        for dx in -1..=1 {\n            let t = angle.get(x + dx, y + dy, c);\n            let d = t - chosen;\n            sum += mask.get(x + dx, y + dy, c)\n                * (t - if d > 0.5 { 1. } else { 0. } + if d < -0.5 { 1. } else { 0. })\n        }\n    }\n    let mut mean = sum / if total == 0. { 1. } else { total };\n    mean = mean - if mean > 0.9375 { 1. } else { 0. } + if mean < -0.0625 { 1. } else { 0. };\n    if mask.get(x, y, c) > 0. {\n        -((mean + 0.1875) * -8.).trunc()\n    } else {\n        0.\n    }\n}\n#[allow(clippy::assign_op_pattern)] // Preserve native (count - average) + previous association.\nfn histogram(i: &Image, n: usize, ratio: f32) -> Result<(f32, Value)> {\n    let mut bins = [0u32; 128];\n    let last = [0, 144, 80, 59, 48][n];\n    for x in 0..64 {\n        for y in 16..last {\n            for c in 0..4 {\n                let v = i.get(x, y, c);\n                if !(0. ..=1.).contains(&v) {\n                    return Err(\"Invalid SRI histogram amplitude\".into());\n                }\n                bins[(v * 127.).round_ties_even() as usize] += 1\n            }\n        }\n    }\n    let total = bins.iter().sum::<u32>();\n    let avg = total as f32 / 128.;\n    let target = (total as f32 * ratio).trunc() as u32;\n    let (mut sum, mut percentile, mut found, mut maxidx, mut best) = (0, 0, false, 0, 0.);\n    for (j, &count) in bins.iter().enumerate() {\n        sum += count;\n        if !found && sum >= target {\n            percentile = j;\n            found = true\n        }\n        let d = sum as f32 - j as f32 * avg;\n        if d > best {\n            maxidx = j;\n            best = d\n        }\n    }\n    maxidx = maxidx.min(64);\n    let mut second = 0;\n    if maxidx > 0 {\n        let avg = bins[..2 * maxidx].iter().sum::<u32>() as f32 / (2 * maxidx) as f32;\n        let mut sum = bins[0] as f32 - avg;\n        let mut best = 0.;\n        for (j, &count) in bins.iter().enumerate().take(2 * maxidx).skip(1) {\n            sum = count as f32 - avg + sum;\n            if sum > best {\n                best = sum;\n                second = j\n            }\n        }\n    }\n    let threshold = (percentile.max(second).max(30) as f32 + 0.5) / 127.;\n    Ok((\n        threshold,\n        json!({\"votes\":total,\"bins\":bins.to_vec(),\"threshold\":threshold,\"native_second_denominator_zero\":maxidx==0,\"zero_denominator_policy\":\"Unused native NaN intermediate skipped when loop empty; threshold selection unchanged\"}),\n    ))\n}\nfn final_phase(n: usize, p: usize, k: &[f32]) -> (i32, &[f32]) {\n    match (n, p) {\n        (2, 0) => (-1, &k[..3]),\n        (2, 1) => (0, &k[3..5]),\n        (3, 0) => (-1, &k[5..7]),\n        (3, 1) => (-1, &k[7..10]),\n        (3, 2) => (0, &k[10..12]),\n        (4, 0) => (-1, &k[12..14]),\n        (4, 1) => (-1, &k[14..17]),\n        (4, 2) => (0, &k[17..19]),\n        (4, 3) => (0, &k[19..21]),\n        _ => unreachable!(),\n    }\n}\npub struct Processor {\n    plan: Plan,\n    kernels: BTreeMap<String, Vec<f32>>,\n    pub provenance: Value,\n}\npub struct Outcome {\n    pub state: State,\n    pub stages: Vec<Value>,\n    pub histogram: Value,\n    pub bindings: Value,\n    pub recipe: Value,\n}\nimpl Processor {\n    pub(crate) fn no_enhancement(correlation: f32, frame_count: usize) -> Result<Self> {\n        Ok(Self {\n            plan: Plan::no_enhancement(correlation, frame_count)?,\n            kernels: BTreeMap::new(),\n            provenance: json!({\"policy\":\"no-enhancement-temporal-v1\"}),\n        })\n    }\n\n    pub fn plan(&self) -> &Plan {\n        &self.plan\n    }\n    pub fn load(assets: &Path, resources: &Path, settings: Settings) -> Result<Self> {\n        Self::from_source(\n            &crate::resources::Files(assets),\n            &crate::resources::Files(resources),\n            settings,\n        )\n    }\n    pub fn from_source(\n        assets: &dyn crate::resources::Source,\n        resources: &dyn crate::resources::Source,\n        settings: Settings,\n    ) -> Result<Self> {\n        let plan = Plan::from_source(assets, resources, settings)?;\n        let name = \"convex-sri-convolution-coefficients.json\";\n        let raw = resources.read(name, 65536)?;\n        const HASH: &str = \"f3a88ac8f628c9b84287dbfe39b32ded023cfccc7f166001350f2f568693cd8e\";\n        if archive::sha(&raw) != HASH {\n            return Err(\"Require complete known convex SRI coefficients JSON\".into());\n        }\n        let v: Value = serde_json::from_slice(&raw).map_err(|e| e.to_string())?;\n        let mut kernels = BTreeMap::new();\n        for (name, count) in [\n            (\"SRI_DownSampling\", 9),\n            (\"SRI_UpSampling\", 81),\n            (\"SRI_UpSamplingN\", 15),\n            (\"SRI_UpSamplingN_final\", 21),\n            (\"FrameCorrelation_Coef\", 25),\n        ] {\n            let values = v[\"kernels\"][name][\"f32_values\"]\n                .as_array()\n                .filter(|v| v.len() == count)\n                .ok_or(\"Invalid SRI coefficient vector\")?\n                .iter()\n                .map(|v| {\n                    v.as_f64()\n                        .map(|n| n as f32)\n                        .filter(|v| v.is_finite())\n                        .ok_or_else(|| \"Invalid SRI coefficient\".to_owned())\n                })\n                .collect::<Result<Vec<_>>>()?;\n            kernels.insert(name.to_string(), values);\n        }\n        let provenance = json!({\"plan\":plan.provenance,\"coefficient_file\":name,\"coefficient_sha256\":HASH,\"payload_embedded\":false});\n        Ok(Self {\n            plan,\n            kernels,\n            provenance,\n        })\n    }\n    /// Selected temporal-only path. Same byte quantization/history; no per-pixel map lookups.\n    pub(crate) fn process_live(\n        &self,\n        compound: &[u8],\n        rdh: &[u8],\n        before: &State,\n    ) -> Result<Outcome> {\n        if self.plan.provenance[\"policy\"] != \"no-enhancement-temporal-v1\" {\n            return self.process(compound, rdh, before);\n        }\n        if compound.len() != EXTERNAL_BYTES\n            || rdh.len() != EXTERNAL_BYTES\n            || self.plan.recipe[\"frame_count_before\"] != before.frame_count\n        {\n            return Err(\"Require exact temporal inputs and matching frame count\".into());\n        }\n        let mut images = before.images.clone();\n        let mut reformatted = images[&0x308].clone();\n        for y in 0..320 {\n            for x in 0..128 {\n                for c in 0..4 {\n                    let source_y = (y as i32 - 32 + 256 * c as i32).clamp(0, 1023) as usize;\n                    reformatted.bytes[(y * 128 + x) * 4 + c] =\n                        compound[(source_y * 64 + (x >> 2)) * 4 + (x & 3)];\n                }\n            }\n        }\n        images.insert(0x308, reformatted);\n        copy(&mut images, 0x308, 0x350, 128, 320)?;\n        let color = f32::from_bits(\n            self.plan.recipe[\"operations\"][2][\"color_f32_bits\"]\n                .as_u64()\n                .unwrap() as u32,\n        );\n        let mask = images.get_mut(&0x530).unwrap();\n        for y in 0..160 {\n            mask.bytes[y * mask.w * 4..y * mask.w * 4 + 64 * 4].fill(unorm(color));\n        }\n        let current = &images[&0x350];\n        let history = &images[&0x538];\n        let mask = &images[&0x530];\n        let mut output = images[&0x548].clone();\n        for y in 0..320 {\n            for x in 0..128 {\n                for c in 0..4 {\n                    let k = mask.bytes[((y / 2) * mask.w + (x >> 1)) * 4 + c] as f32 / 255.;\n                    let previous = history.bytes[(y * history.w + x) * 4 + c] as f32 / 255.;\n                    let now = current.bytes[(y * current.w + x) * 4 + c] as f32 / 255.;\n                    output.bytes[(y * output.w + x) * 4 + c] = unorm(previous * k + now * (1. - k));\n                }\n            }\n        }\n        images.insert(0x548, output);\n        copy(&mut images, 0x548, 0x538, 128, 320)?;\n        copy(&mut images, 0x3b8, 0x540, 64, 160)?;\n        let corr = if before.frame_count < 2 {\n            f32::from_bits(\n                self.plan.recipe[\"effective_mask_correlation_bits\"]\n                    .as_u64()\n                    .unwrap() as u32,\n            )\n        } else {\n            before.bound_mask_correlation\n        };\n        Ok(Outcome {\n            state: State {\n                frame_count: (before.frame_count + 1).min(2),\n                bound_mask_correlation: corr,\n                images,\n            },\n            stages: Vec::new(),\n            histogram: Value::Null,\n            bindings: self.plan.bindings.clone(),\n            recipe: self.plan.recipe.clone(),\n        })\n    }\n\n    pub fn process(&self, compound: &[u8], rdh: &[u8], before: &State) -> Result<Outcome> {\n        if compound.len() != EXTERNAL_BYTES\n            || rdh.len() != EXTERNAL_BYTES\n            || self.plan.recipe[\"frame_count_before\"] != before.frame_count\n        {\n            return Err(\n                \"Require exact native64x1024 inputs and matching explicit SRI frame count\".into(),\n            );\n        }\n        let mut a = before.images.clone();\n        for (s, b) in [(0x22f0, compound), (0x2310, rdh)] {\n            a.insert(\n                s,\n                Image {\n                    w: 64,\n                    h: 1024,\n                    kind: Kind::Unorm,\n                    bytes: b.to_vec(),\n                },\n            );\n        }\n        let mut bindings = self.plan.bindings.clone();\n        let mut recipe = self.plan.recipe.clone();\n        let corr = if before.frame_count < 2 {\n            f32::from_bits(recipe[\"effective_mask_correlation_bits\"].as_u64().unwrap() as u32)\n        } else {\n            before.bound_mask_correlation\n        };\n        let hex = corr\n            .to_bits()\n            .to_le_bytes()\n            .iter()\n            .map(|v| format!(\"{v:02x}\"))\n            .collect::<String>();\n        for b in bindings.as_array_mut().unwrap() {\n            if b[\"kernel_slot\"] == \"0x518\" && b[\"argument\"] == 3 {\n                b[\"value\"][\"value_hex\"] = json!(hex)\n            }\n        }\n        recipe[\"effective_mask_correlation_bits\"] = json!(corr.to_bits());\n        recipe[\"images_computed\"] = json!(true);\n        recipe[\"historical_bound_mask_preserved\"] = json!(before.frame_count >= 2);\n        let n = recipe[\"N\"].as_u64().unwrap() as usize;\n        let offset = [0, 0, 16, 22, 24][n];\n        let bank = f32s(&self.plan.coarse);\n        let kernels = &self.kernels;\n        #[allow(unused_mut)] // Diagnostic hashes are omitted in the browser build.\n        let mut stages = Vec::new();\n        let mut hist = Value::Null;\n        for op in recipe[\"operations\"].as_array().unwrap() {\n            match op[\"operation\"].as_str().unwrap() {\n                \"copy_image\" => copy(\n                    &mut a,\n                    slot(op[\"source\"].as_str().unwrap()),\n                    slot(op[\"destination\"].as_str().unwrap()),\n                    op[\"region\"][0].as_u64().unwrap() as usize,\n                    op[\"region\"][1].as_u64().unwrap() as usize,\n                )?,\n                \"fill_image\" => {\n                    let s = slot(op[\"destination\"].as_str().unwrap());\n                    let v = f32::from_bits(op[\"color_f32_bits\"].as_u64().unwrap() as u32);\n                    stage(&mut a, s, 64, 160, |_, _, _, _| v)?\n                }\n                \"kernel\" => {\n                    let kernel = slot(op[\"slot\"].as_str().unwrap());\n                    let w = op[\"global\"][0].as_u64().unwrap() as usize;\n                    let h = op[\"global\"][1].as_u64().unwrap() as usize;\n                    let mut im = [0u16; 9];\n                    let mut scalar = [0u32; 9];\n                    for b in bindings\n                        .as_array()\n                        .unwrap()\n                        .iter()\n                        .filter(|b| slot(b[\"kernel_slot\"].as_str().unwrap()) == kernel)\n                    {\n                        let j = b[\"argument\"].as_u64().unwrap() as usize;\n                        if b[\"value\"][\"kind\"] == \"scalar32\" {\n                            let s = b[\"value\"][\"value_hex\"].as_str().unwrap();\n                            let bytes: Vec<_> = s\n                                .as_bytes()\n                                .as_chunks::<2>()\n                                .0\n                                .iter()\n                                .map(|v| {\n                                    u8::from_str_radix(std::str::from_utf8(v).unwrap(), 16).unwrap()\n                                })\n                                .collect();\n                            scalar[j] = u32::from_le_bytes(bytes.try_into().unwrap());\n                        } else {\n                            im[j] = match b[\"value\"][\"source\"].as_str().unwrap() {\n                                \"compound_output\" => 0x22f0,\n                                \"native_RDH64\" => 0x2310,\n                                s => slot(s),\n                            }\n                        }\n                    }\n                    match kernel {\n                        0x220 => stage(&mut a, im[1], w, h, |a, x, y, c| {\n                            get(a, im[0], x >> 2, y - 32 + 256 * c as i32, (x & 3) as usize)\n                        })?,\n                        0x228 | 0x230 => stage(&mut a, im[1], w, h, |a, x, y, c| {\n                            let (dx, dy) = if kernel == 0x228 { (0, 1) } else { (1, 0) };\n                            let u = get(a, im[0], x - dx, y - dy, c);\n                            let v = get(a, im[0], x, y, c);\n                            let z = get(a, im[0], x + dx, y + dy, c);\n                            let k = if kernel == 0x228 {\n                                0.\n                            } else {\n                                get(a, im[2], x, y - 32 + 256 * c as i32, 0)\n                            };\n                            let flag = if u - v >= 8.5 / 255. && z - v >= 8.5 / 255. {\n                                k + (0.25 - k)\n                            } else {\n                                k\n                            };\n                            (u + z) * flag + v * (1. - flag * 2.)\n                        })?,\n                        0x238 => stage(&mut a, im[1], w, h, |a, x, y, c| {\n                            vector(&a[&im[0]], x, y, c, -1, &[0.25, 0.5, 0.25], true)\n                        })?,\n                        0x240 => {\n                            let mut dst = [a[&im[1]].clone(), a[&im[2]].clone(), a[&im[3]].clone()];\n                            for y in 0..h {\n                                for x in 0..w {\n                                    for c in 0..4 {\n                                        let mut sum = get(&a, im[0], x as i32, (y * n) as i32, c);\n                                        for d in 1..n {\n                                            sum += get(&a, im[0], x as i32, (y * n + d) as i32, c)\n                                        }\n                                        sum *= match n {\n                                            2 => 0.5,\n                                            3 => 0.3333333,\n                                            _ => 0.25,\n                                        };\n                                        dst[0].set(x, y + offset, c, sum)?;\n                                        dst[1].set(x, y + offset, c, sum)?;\n                                        for d in 0..n {\n                                            dst[2].set(x, y * n + d, c, sum)?\n                                        }\n                                    }\n                                }\n                            }\n                            for (s, i) in [im[1], im[2], im[3]].into_iter().zip(dst) {\n                                a.insert(s, i);\n                            }\n                        }\n                        0x248 => {\n                            let len = [0, 0, 128, 86, 64][n];\n                            let mut dst = a[&im[1]].clone();\n                            for y in 0..h {\n                                for x in 0..w {\n                                    for c in 0..4 {\n                                        let first = if c == 0 {\n                                            get(&a, im[0], x as i32, 32, 0)\n                                        } else {\n                                            get(&a, im[0], x as i32, (len + y) as i32, c - 1)\n                                        };\n                                        let last = if c == 3 {\n                                            get(&a, im[0], x as i32, (len + 31) as i32, 3)\n                                        } else {\n                                            get(&a, im[0], x as i32, (32 + y) as i32, c + 1)\n                                        };\n                                        dst.set(x, y, c, first)?;\n                                        dst.set(x, 32 + len + y, c, last)?\n                                    }\n                                }\n                            }\n                            a.insert(im[1], dst);\n                        }\n                        0x250 => {\n                            let (kstart, k) = match n {\n                                2 => (-1, &kernels[\"SRI_UpSamplingN\"][..4]),\n                                3 => (-2, &kernels[\"SRI_UpSamplingN\"][4..9]),\n                                _ => (-2, &kernels[\"SRI_UpSamplingN\"][9..]),\n                            };\n                            stage(&mut a, im[2], w, h, |a, x, y, c| {\n                                get(a, im[0], x, y, c)\n                                    - vector(&a[&im[1]], x, y, c, kstart, k, true)\n                            })?\n                        }\n                        0x268 => {\n                            stage(&mut a, im[1], w, h, |a, x, y, c| {\n                                convolution(\n                                    &a[&im[0]],\n                                    2 * x,\n                                    2 * y,\n                                    c,\n                                    &[-1, 0, 1],\n                                    &[-1, 0, 1],\n                                    &kernels[\"SRI_DownSampling\"],\n                                )\n                            })?;\n                            copy(&mut a, im[1], im[2], w, h)?\n                        }\n                        0x270 => stage(&mut a, im[2], 2 * w, 2 * h, |a, x, y, c| {\n                            get(a, im[0], x, y, c)\n                                - polyphase(&a[&im[1]], x, y, c, &kernels[\"SRI_UpSampling\"])\n                        })?,\n                        0x280 => {\n                            for (dst, vertical) in [(im[1], false), (im[2], true)] {\n                                stage(&mut a, dst, w, h, |a, x, y, c| {\n                                    let mut v = 0.;\n                                    for (d, k) in [\n                                        (-3, 0.125),\n                                        (-2, 0.5),\n                                        (-1, 0.625),\n                                        (1, -0.625),\n                                        (2, -0.5),\n                                        (3, -0.125),\n                                    ] {\n                                        v += get(\n                                            a,\n                                            im[0],\n                                            x + if vertical { 0 } else { d },\n                                            y + if vertical { d } else { 0 },\n                                            c,\n                                        ) * k\n                                    }\n                                    v * 2.\n                                })?\n                            }\n                        }\n                        0x288 => {\n                            for (dst, angle) in [(im[2], false), (im[3], true)] {\n                                stage(&mut a, dst, w, h, |a, x, y, c| {\n                                    let gx = vector(\n                                        &a[&im[0]],\n                                        x,\n                                        y,\n                                        c,\n                                        -2,\n                                        &[0.0625, 0.25, 0.375, 0.25, 0.0625],\n                                        true,\n                                    );\n                                    let gy = vector(\n                                        &a[&im[1]],\n                                        x,\n                                        y,\n                                        c,\n                                        -2,\n                                        &[0.0625, 0.25, 0.375, 0.25, 0.0625],\n                                        false,\n                                    );\n                                    if angle {\n                                        let v = gy.atan2(gx) / std::f32::consts::PI;\n                                        v + if v <= 0. { 1. } else { 0. }\n                                    } else {\n                                        gx.hypot(gy)\n                                    }\n                                })?\n                            }\n                        }\n                        0x290 => {\n                            let (t, report) = histogram(&a[&im[0]], n, f32::from_bits(scalar[2]))?;\n                            hist = report;\n                            stage(&mut a, im[1], w, 160, |a, x, y, c| {\n                                if get(a, im[0], x, y, c) >= t { 1. } else { 0. }\n                            })?\n                        }\n                        0x298 => stage(&mut a, im[1], w, h, |a, x, y, c| {\n                            if neighbors(&a[&im[0]], x, y, c, true) >= 2.5 {\n                                1.\n                            } else {\n                                0.\n                            }\n                        })?,\n                        0x2a0 => {\n                            stage(&mut a, im[2], w, h, |a, x, y, c| {\n                                get(a, im[1], x, y, c)\n                                    * if neighbors(&a[&im[0]], x, y, c, true) >= 4.5 {\n                                        1.\n                                    } else {\n                                        0.\n                                    }\n                            })?;\n                            stage(&mut a, im[3], w, h, |a, x, y, c| {\n                                ((neighbors(&a[&im[0]], x, y, c, true) - 5.) * 0.25).clamp(0., 1.)\n                            })?\n                        }\n                        0x2a8 => stage(&mut a, im[2], w, h, |a, x, y, c| {\n                            direction(&a[&im[0]], &a[&im[1]], x, y, c)\n                        })?,\n                        0x2b0 => {\n                            for y in 0..h {\n                                for x in 0..w {\n                                    for c in 0..4 {\n                                        if !(0. ..=8.)\n                                            .contains(&get(&a, im[1], x as i32, y as i32, c))\n                                        {\n                                            return Err(\"Direction outside convex SRI bank\".into());\n                                        }\n                                    }\n                                }\n                            }\n                            stage(&mut a, im[3], w, h, |a, x, y, c| {\n                                let dir = get(a, im[1], x, y, c) as usize;\n                                convolution(\n                                    &a[&im[0]],\n                                    x,\n                                    y,\n                                    c,\n                                    &[-2, -1, 0, 1, 2],\n                                    &[-2, -1, 0, 1, 2],\n                                    &bank[25 * dir..25 * (dir + 1)],\n                                )\n                            })?\n                        }\n                        0x2b8 => {\n                            let contrast = f32::from_bits(scalar[6]);\n                            let enhance = f32::from_bits(scalar[7]);\n                            let mix = f32::from_bits(scalar[8]);\n                            stage(&mut a, im[4], w, h, |a, x, y, c| {\n                                let v = get(a, im[0], x, y, c);\n                                let t = (v * 8. - neighbors(&a[&im[0]], x, y, c, false)) * enhance;\n                                let sharp = t.clamp(-0.046875, 0.125)\n                                    * get(a, im[2], x, y, c).min(1.)\n                                    * get(a, im[3], x, y, c)\n                                    + v;\n                                let target = (0.125 + (sharp - 0.125) * contrast).clamp(0., 1.);\n                                let base = get(a, im[1], x, y, c);\n                                base + (target - base) * mix\n                            })?\n                        }\n                        0x2c0 => {\n                            stage(&mut a, im[2], 2 * w, 2 * h, |a, x, y, c| {\n                                (polyphase(&a[&im[0]], x, y, c, &kernels[\"SRI_UpSampling\"])\n                                    + get(a, im[1], x, y, c))\n                                .clamp(0., 1.)\n                            })?;\n                            copy(&mut a, im[2], im[3], 2 * w, 2 * h)?\n                        }\n                        0x260 => stage(&mut a, im[2], w, n * h, |a, x, y, c| {\n                            if n == 1 {\n                                return get(a, im[0], x, y, c);\n                            }\n                            let (o, k) =\n                                final_phase(n, y as usize % n, &kernels[\"SRI_UpSamplingN_final\"]);\n                            (vector(&a[&im[0]], x, y / n as i32 + offset as i32, c, o, k, true)\n                                + get(a, im[1], x, y, c))\n                            .clamp(0., 1.)\n                        })?,\n                        0x518 => {\n                            let corr = f32::from_bits(scalar[3]);\n                            stage(&mut a, im[2], w, h, |a, x, y, c| {\n                                let d = (get(a, im[0], x, y, c) - get(a, im[1], x, y, c))\n                                    .abs()\n                                    .clamp(0., 0.196078);\n                                if corr == 0. {\n                                    0.\n                                } else if d > 0.117647 {\n                                    (0.196078 - d) / (0.196078 - 0.117647) * corr\n                                } else {\n                                    (0.117647 - d) / 0.117647 * (0.5 - corr * 0.5) + corr\n                                }\n                            })?\n                        }\n                        0x520 => stage(&mut a, im[1], w, h, |a, x, y, c| {\n                            convolution(\n                                &a[&im[0]],\n                                x,\n                                y,\n                                c,\n                                &[-2, -1, 0, 1, 2],\n                                &[-2, -1, 0, 1, 2],\n                                &kernels[\"FrameCorrelation_Coef\"],\n                            )\n                        })?,\n                        0x510 => stage(&mut a, im[3], w, h, |a, x, y, c| {\n                            let k = get(a, im[2], x >> 1, y / (2 * n as i32), c);\n                            get(a, im[1], x, y, c) * k + get(a, im[0], x, y, c) * (1. - k)\n                        })?,\n                        _ => return Err(format!(\"Unsupported General SRI dispatch{kernel:04x}\")),\n                    }\n                }\n                _ => return Err(\"Unknown SRI recipe operation\".into()),\n            }\n            #[cfg(not(target_arch = \"wasm32\"))]\n            {\n                let hashes: Vec<_> = a\n                    .iter()\n                    .filter(|(s, _)| **s < 0x1000)\n                    .map(\n                        |(s, i)| json!({\"slot\":format!(\"{s:04x}\"),\"sha256\":archive::sha(&i.bytes)}),\n                    )\n                    .collect();\n                stages.push(json!({\"operation\":op,\"images\":hashes}));\n            }\n        }\n        a.remove(&0x22f0);\n        a.remove(&0x2310);\n        let state = State {\n            frame_count: (before.frame_count + 1).min(2),\n            bound_mask_correlation: corr,\n            images: a,\n        };\n        Ok(Outcome {\n            state,\n            stages,\n            histogram: hist,\n            bindings,\n            recipe,\n        })\n    }\n}\nfn f32s(b: &[u8]) -> Vec<f32> {\n    b.as_chunks::<4>()\n        .0\n        .iter()\n        .map(|b| f32::from_le_bytes(*b))\n        .collect()\n}\n#[cfg(test)]\nmod tests {\n    use super::*;\n    #[test]\n    fn full_state_and_domain_are_mandatory() {\n        let meta = json!({\"schema_version\":\"convex-sri-state-v1\",\"policy\":POLICY,\"frame_count\":2,\"bound_mask_correlation_bits\":0.4_f32.to_bits()});\n        let files: Vec<_> = template()\n            .iter()\n            .map(|(_, w, h, _)| vec![173; w * h * 4])\n            .collect();\n        let s = State::from_bytes(&meta, files.clone()).unwrap();\n        assert_eq!(\n            s.files().iter().map(|(_, b)| b.len()).sum::<usize>(),\n            5038080\n        );\n        assert_eq!(s.metadata(), meta);\n        let mut bad = meta.clone();\n        bad[\"bound_mask_correlation_bits\"] = json!(f32::NAN.to_bits());\n        assert!(State::from_bytes(&bad, files.clone()).is_err());\n        let mut short = files;\n        short.pop();\n        assert!(State::from_bytes(&meta, short).is_err());\n    }\n    #[test]\n    fn copy_retains_native_tails_and_signed_roundtrip() {\n        let mut a = Images::new();\n        for s in [1, 2] {\n            a.insert(\n                s,\n                Image {\n                    w: 4,\n                    h: 4,\n                    kind: Kind::Unorm,\n                    bytes: vec![s as u8; 64],\n                },\n            );\n        }\n        copy(&mut a, 1, 2, 2, 3).unwrap();\n        assert_eq!(a[&2].bytes[8], 2);\n        assert_eq!(a[&2].bytes[32], 1);\n        assert_eq!(a[&2].bytes[48], 2);\n        let mut i = Image {\n            w: 1,\n            h: 1,\n            kind: Kind::Snorm,\n            bytes: vec![0; 4],\n        };\n        i.set(0, 0, 0, -1.).unwrap();\n        assert_eq!(i.bytes[0], 129);\n        assert_eq!(i.get(0, 0, 0), -1.);\n        assert!(i.set(0, 1, 0, 0.).is_err());\n        i.kind = Kind::Int;\n        assert!(i.set(0, 0, 0, 9.).is_err());\n    }\n    #[test]\n    fn temporal_live_matches_generic_all_backings_and_retained_tails() {\n        let files: Vec<Vec<u8>> = template()\n            .iter()\n            .enumerate()\n            .map(|(j, (_, w, h, _))| (0..w * h * 4).map(|i| (i * 19 + j * 71) as u8).collect())\n            .collect();\n        for corr in [0f32, 0.37, 1.] {\n            let meta = json!({\"schema_version\":\"convex-sri-state-v1\",\"policy\":POLICY,\"frame_count\":0,\"bound_mask_correlation_bits\":0f32.to_bits()});\n            let mut generic = State::from_bytes(&meta, files.clone()).unwrap();\n            let mut live = generic.clone();\n            for step in 0..4 {\n                let p = Processor::no_enhancement(corr, generic.frame_count).unwrap();\n                let compound: Vec<u8> = (0..EXTERNAL_BYTES)\n                    .map(|i| (i * 43 + i / 11 + step * 17) as u8)\n                    .collect();\n                let rdh = vec![0; EXTERNAL_BYTES];\n                generic = p.process(&compound, &rdh, &generic).unwrap().state;\n                live = p.process_live(&compound, &rdh, &live).unwrap().state;\n                assert_eq!(live.metadata(), generic.metadata());\n                assert_eq!(live.files(), generic.files());\n            }\n        }\n    }\n}\n"
      },
      {
        "path": "components/ultrasound/convex-decoder/1.0.0/src/convex_sri_plan.rs",
        "sha256": "fabc74491f2b537dcfb50bc9c66045e4d962b2ca0d1391d596e32b9e1bdea57d",
        "text": "// SPDX-License-Identifier: AGPL-3.0-or-later\n//! General SRI parameter/binding/execution recipe. No image kernels execute here.\n//! Derived tables/banks must remain private and are never embedded in this crate.\nuse crate::{Result, archive, linear_dsp::read_regular};\nuse serde_json::{Value, json};\nuse std::{\n    collections::BTreeMap,\n    fs::{self, File},\n    path::Path,\n};\nconst ASSETS: [(&str, usize, &str); 3] = [\n    (\n        \"A_BF.bin\",\n        44,\n        \"28ed79893f9f224a7c1a29e2288491cb3bf224bbb3851d308c50e799b48dbdee\",\n    ),\n    (\n        \"B_PRF.bin\",\n        388,\n        \"bf553725fc08bf50b6c4919ebc38d8cb8d648b8f03072a6d2da6fe32dcd84231\",\n    ),\n    (\n        \"B_SRI.bin\",\n        352,\n        \"06822694c67a7c94168be168d86221301853e8ce8aba48c49fedd7b1cde2164b\",\n    ),\n];\nconst RESOURCES: [(&str, usize, &str); 5] = [\n    (\n        \"direction-base-225.f32le\",\n        900,\n        \"d3b36f851a8f2dbe0ee1ffffd154795abdf038f01947ce2fc9a8a2dc9bec67d9\",\n    ),\n    (\n        \"direction-delta-200.f32le\",\n        800,\n        \"b2b0106e0ce2997b31674daa14dde0aaa03b9b58737e5197ecadcd436b5ffdb6\",\n    ),\n    (\n        \"isotropic-iterations-1to3.f32le\",\n        24,\n        \"e8e95fdbb5c03a86b7cef320de6179837054e4eac52ef9fd7a4cd49c3da1293e\",\n    ),\n    (\n        \"isotropic-fallback.f32le\",\n        8,\n        \"8ac3a611b819e18e9409f486739caa9bf6fb8d37957ca7b7dca75f2f774bc55a\",\n    ),\n    (\n        \"correlation-default-9.f32le\",\n        36,\n        \"176d2008e9196bbdb706427f68cb07ff20fb7ae71550c2f7b4b5bf4834f5d1a2\",\n    ),\n];\n#[derive(Clone, Copy, Debug)]\npub struct Settings {\n    pub depth: usize,\n    pub enhancement: usize,\n    pub correlation: usize,\n    pub frame_count: usize,\n}\nimpl Settings {\n    pub fn from_json(v: &Value) -> Result<Self> {\n        let keys = [\n            \"schema_version\",\n            \"depth_index\",\n            \"enhancement\",\n            \"correlation_index\",\n            \"frame_count_before\",\n        ];\n        let o = v.as_object().ok_or(\"Require SRI settings object\")?;\n        if o.len() != keys.len()\n            || o.keys().any(|s| !keys.contains(&s.as_str()))\n            || v[\"schema_version\"] != \"convex-sri-settings-v1\"\n        {\n            return Err(\"Require exact convex-sri-settings-v1 settings; no defaults\".into());\n        }\n        let get = |key: &str| {\n            v[key]\n                .as_u64()\n                .and_then(|n| usize::try_from(n).ok())\n                .ok_or_else(|| format!(\"Invalid {key}\"))\n        };\n        let s = Self {\n            depth: get(\"depth_index\")?,\n            enhancement: get(\"enhancement\")?,\n            correlation: get(\"correlation_index\")?,\n            frame_count: get(\"frame_count_before\")?,\n        };\n        s.validate()?;\n        Ok(s)\n    }\n    fn validate(self) -> Result<()> {\n        if self.depth >= 8 || self.enhancement > 8 || self.correlation > 8 || self.frame_count > 2 {\n            return Err(\"Require depth0..7, enhancement/correlation0..8, frame_count0..2\".into());\n        }\n        Ok(())\n    }\n    pub fn json(self) -> Value {\n        json!({\"schema_version\":\"convex-sri-settings-v1\",\"depth_index\":self.depth,\"enhancement\":self.enhancement,\"correlation_index\":self.correlation,\"frame_count_before\":self.frame_count})\n    }\n}\npub struct Plan {\n    pub parameters: Vec<u8>,\n    pub coarse: Vec<u8>,\n    pub fine: Vec<u8>,\n    pub dispatch: Vec<u8>,\n    pub state_after_update: Vec<u8>,\n    pub bindings: Value,\n    pub recipe: Value,\n    pub provenance: Value,\n}\nfn load_group(\n    directory: &dyn crate::resources::Source,\n    group: &[(&str, usize, &str)],\n) -> Result<(Vec<Vec<u8>>, Vec<Value>)> {\n    let mut files = Vec::new();\n    let mut rows = Vec::new();\n    for (name, size, expected) in group {\n        let bytes = directory.read(name, *size as u64)?;\n        if bytes.len() != *size || archive::sha(&bytes) != *expected {\n            return Err(format!(\"Require complete known General SRI input {name}\"));\n        }\n        rows.push(json!({\"file\":name,\"bytes\":size,\"sha256\":expected}));\n        files.push(bytes);\n    }\n    Ok((files, rows))\n}\nfn word(raw: &[u8], i: usize) -> u32 {\n    u32::from_le_bytes(raw[4 * i..4 * i + 4].try_into().unwrap())\n}\nfn floats(raw: &[u8]) -> Vec<f32> {\n    raw.as_chunks::<4>()\n        .0\n        .iter()\n        .map(|b| f32::from_le_bytes(*b))\n        .collect()\n}\nfn bytes(values: &[f32]) -> Vec<u8> {\n    values.iter().flat_map(|v| v.to_le_bytes()).collect()\n}\nfn slot(v: &str) -> usize {\n    usize::from_str_radix(v.strip_prefix(\"0x\").unwrap(), 16).unwrap()\n}\nfn hex(bytes: &[u8]) -> String {\n    bytes.iter().map(|b| format!(\"{b:02x}\")).collect()\n}\nimpl Plan {\n    pub(crate) fn no_enhancement(correlation: f32, frame_count: usize) -> Result<Self> {\n        if !correlation.is_finite() || !(0.0..=1.0).contains(&correlation) || frame_count > 2 {\n            return Err(\"Invalid temporal correlation or frame counter\".into());\n        }\n        let count_after = (frame_count + 1).min(2);\n        let effective = if frame_count == 0 { 0. } else { correlation };\n        let bindings = json!([\n            {\"kernel_slot\":\"0x220\",\"argument\":0,\"bytes\":8,\"value\":{\"kind\":\"image_or_buffer\",\"source\":\"compound_output\"}},\n            {\"kernel_slot\":\"0x220\",\"argument\":1,\"bytes\":8,\"value\":{\"kind\":\"image_or_buffer\",\"source\":\"0x308\"}},\n            {\"kernel_slot\":\"0x510\",\"argument\":0,\"bytes\":8,\"value\":{\"kind\":\"image_or_buffer\",\"source\":\"0x350\"}},\n            {\"kernel_slot\":\"0x510\",\"argument\":1,\"bytes\":8,\"value\":{\"kind\":\"image_or_buffer\",\"source\":\"0x538\"}},\n            {\"kernel_slot\":\"0x510\",\"argument\":2,\"bytes\":8,\"value\":{\"kind\":\"image_or_buffer\",\"source\":\"0x530\"}},\n            {\"kernel_slot\":\"0x510\",\"argument\":3,\"bytes\":8,\"value\":{\"kind\":\"image_or_buffer\",\"source\":\"0x548\"}}\n        ]);\n        let recipe = json!({\"N\":1,\"frame_count_before\":frame_count,\"frame_count_after_update\":count_after,\"effective_mask_correlation_bits\":effective.to_bits(),\"operations\":[\n            {\"operation\":\"kernel\",\"slot\":\"0x220\",\"global\":[128,320]},\n            {\"operation\":\"copy_image\",\"source\":\"0x308\",\"destination\":\"0x350\",\"region\":[128,320,1]},\n            {\"operation\":\"fill_image\",\"destination\":\"0x530\",\"color_f32_bits\":if count_after>1 {correlation.to_bits()} else {0},\"region\":[64,160,1]},\n            {\"operation\":\"kernel\",\"slot\":\"0x510\",\"global\":[128,320]},\n            {\"operation\":\"copy_image\",\"source\":\"0x548\",\"destination\":\"0x538\",\"region\":[128,320,1]},\n            {\"operation\":\"copy_image\",\"source\":\"0x3b8\",\"destination\":\"0x540\",\"region\":[64,160,1]}\n        ]});\n        Ok(Self {\n            parameters: Vec::new(),\n            coarse: Vec::new(),\n            fine: Vec::new(),\n            dispatch: Vec::new(),\n            state_after_update: Vec::new(),\n            bindings,\n            recipe,\n            provenance: json!({\"policy\":\"no-enhancement-temporal-v1\"}),\n        })\n    }\n\n    pub fn load(assets: &Path, resources: &Path, settings: Settings) -> Result<Self> {\n        Self::from_source(\n            &crate::resources::Files(assets),\n            &crate::resources::Files(resources),\n            settings,\n        )\n    }\n    pub fn from_source(\n        assets: &dyn crate::resources::Source,\n        resources: &dyn crate::resources::Source,\n        settings: Settings,\n    ) -> Result<Self> {\n        settings.validate()?;\n        if assets.exists(\"B_Persist.bin\")? {\n            return Err(\"Known General has no B_Persist; overrides unsupported\".into());\n        }\n        let (a, asset_rows) = load_group(assets, &ASSETS)?;\n        let (r, resource_rows) = load_group(resources, &RESOURCES)?;\n        if word(&a[0], 1) != 4 || word(&a[0], 2) != 2 || word(&a[0], 3) != 128 {\n            return Err(\"General BF profile differs from B4/m2/T128\".into());\n        }\n        let mut p = Self::derive(&a[2], &r, settings)?;\n        p.provenance = json!({\"profile\":\"Plus-UC5-2S_16-General-B4-T128-m2-type8\",\"assets\":asset_rows,\"resources\":resource_rows,\n            \"B_Persist_present\":false,\"payload_embedded\":false,\"payload_copied_to_archive\":false});\n        Ok(p)\n    }\n    fn derive(raw: &[u8], r: &[Vec<u8>], settings: Settings) -> Result<Self> {\n        settings.validate()?;\n        if raw.len() != 352\n            || r.len() != 5\n            || r.iter().zip(RESOURCES).any(|(b, (_, n, _))| b.len() != n)\n        {\n            return Err(\"Invalid complete SRI parameter/resource lengths\".into());\n        }\n        let i = settings.enhancement.saturating_sub(1);\n        let f = |row: usize| f32::from_bits(word(raw, row * 8 + i));\n        let int = |row: usize| word(raw, row * 8 + i);\n        let coarse_iterations = int(2);\n        let fine_iterations = int(7);\n        let n = if settings.enhancement == 0 {\n            1\n        } else {\n            word(raw, 80 + settings.depth)\n        };\n        if !(1..=4).contains(&n) || !(1..=3).contains(&coarse_iterations) || fine_iterations != 0 {\n            return Err(\n                \"Unsupported General SRI branch; fine pass is inactive in the known group\".into(),\n            );\n        }\n        let scale = f(4) + f(4);\n        let mix = 1. - f(8);\n        let words = [\n            if settings.enhancement == 0 {\n                (-1.0_f32).to_bits()\n            } else {\n                ((word(raw, i) as i32 as f32) * 0.125).to_bits()\n            },\n            f(1).to_bits(),\n            coarse_iterations,\n            int(3),\n            scale.to_bits(),\n            f(5).to_bits(),\n            f(6).to_bits(),\n            fine_iterations,\n            0,\n            f(9).to_bits(),\n            mix.to_bits(),\n            n,\n            64,\n            0,\n            word(&r[4], settings.correlation),\n        ];\n        for index in [0, 1, 4, 5, 6, 9, 10, 14] {\n            if !f32::from_bits(words[index]).is_finite() {\n                return Err(\"Nonfinite SRI parameter\".into());\n            }\n        }\n        let parameters: Vec<u8> = words.iter().flat_map(|v| v.to_le_bytes()).collect();\n        let base = floats(&r[0]);\n        let delta = floats(&r[1]);\n        let isotropic = floats(&r[2]);\n        let fallback = floats(&r[3]);\n        if [&base, &delta, &isotropic, &fallback]\n            .into_iter()\n            .flatten()\n            .any(|v| !v.is_finite())\n        {\n            return Err(\"Nonfinite SRI bank resource\".into());\n        }\n        let bank = |iterations: u32| {\n            let (side, center) = if (1..=3).contains(&iterations) {\n                (\n                    isotropic[3 + iterations as usize - 1],\n                    isotropic[iterations as usize - 1],\n                )\n            } else {\n                (fallback[0], fallback[1])\n            };\n            let mut values = base.clone();\n            values[..25].fill(0.);\n            for j in [7, 11, 13, 17] {\n                values[j] = side;\n            }\n            values[12] = center;\n            for j in 0..200 {\n                values[j + 25] = base[j + 25] + delta[j] * scale;\n            }\n            bytes(&values)\n        };\n        let coarse = bank(coarse_iterations);\n        let fine = bank(fine_iterations);\n        let layout: Value =\n            serde_json::from_str(include_str!(\"known_convex_sri_layout.json\")).unwrap();\n        let mut dims = BTreeMap::new();\n        let mut dispatch = Vec::new();\n        for address in (0x440..=0x500).step_by(16) {\n            let v = &layout[\"dimensions_after_SetKernelArg\"][format!(\"0x{address:x}\")];\n            let v = if v[0].is_array() {\n                &v[n as usize - 1]\n            } else {\n                v\n            };\n            let d = [v[0].as_u64().unwrap(), v[1].as_u64().unwrap()];\n            dims.insert(format!(\"0x{address:x}\"), d);\n            for value in d {\n                dispatch.extend_from_slice(&value.to_le_bytes());\n            }\n        }\n        let mut bindings = BTreeMap::new();\n        for kernel in layout[\"kernels\"].as_array().unwrap() {\n            for arg in kernel[\"bound_arguments\"].as_array().unwrap() {\n                if arg[\"condition\"] == \"fine_iterations==0\" && fine_iterations != 0 {\n                    continue;\n                }\n                let source = arg[\"source\"].as_str().unwrap();\n                let length = arg[\"bytes\"].as_u64().unwrap();\n                let binding = if length == 8 {\n                    let source = if source == \"external_BFSP_image_pointer_reference\" {\n                        \"compound_output\"\n                    } else if source == \"external_BFSP_RDH_pointer_reference\" {\n                        \"native_RDH64\"\n                    } else {\n                        source\n                            .strip_prefix(\"this+\")\n                            .ok_or(\"Unknown SRI pointer source\")?\n                    };\n                    json!({\"kind\":\"image_or_buffer\",\"source\":source})\n                } else {\n                    let value = if source == \"address_of_local_zero_i32\" {\n                        vec![0; 4]\n                    } else {\n                        let offset = slot(\n                            source\n                                .strip_prefix(\"this+\")\n                                .ok_or(\"Unknown SRI scalar source\")?,\n                        );\n                        if !(0x164..0x1a0).contains(&offset) {\n                            return Err(\"Scalar source outside SRI parameter block\".into());\n                        }\n                        parameters[offset - 0x164..offset - 0x164 + 4].to_vec()\n                    };\n                    json!({\"kind\":\"scalar32\",\"value_hex\":hex(&value)})\n                };\n                let k = kernel[\"slot\"].as_str().unwrap();\n                let idx = arg[\"argument\"].as_u64().unwrap();\n                bindings.insert((k.to_string(),idx),json!({\"kernel_slot\":k,\"kernel\":kernel[\"name\"],\"argument\":idx,\"bytes\":length,\"value\":binding}));\n            }\n        }\n        // UpdataKernelArg forces mask correlation0 before the first frame only.\n        let effective_correlation = if settings.frame_count == 0 {\n            0\n        } else {\n            words[14]\n        };\n        bindings.get_mut(&(\"0x518\".to_string(), 3)).unwrap()[\"value\"][\"value_hex\"] =\n            json!(hex(&effective_correlation.to_le_bytes()));\n        let count_after = (settings.frame_count + 1).min(2) as u32;\n        let state_after_update = [count_after.to_le_bytes(), words[14].to_le_bytes()].concat();\n        let mut operations = vec![];\n        let kernel = |operations: &mut Vec<Value>, address: usize| {\n            let metadata = layout[\"kernels\"]\n                .as_array()\n                .unwrap()\n                .iter()\n                .find(|v| v[\"slot\"] == format!(\"0x{address:x}\"))\n                .unwrap();\n            let global = if metadata[\"global_dimensions_slot\"] == \"runtime-final\" {\n                json!([128, 320 / n])\n            } else {\n                json!(dims[metadata[\"global_dimensions_slot\"].as_str().unwrap()])\n            };\n            operations.push(json!({\"operation\":\"kernel\",\"slot\":metadata[\"slot\"],\"name\":metadata[\"name\"],\"global\":global,\"local\":dims[metadata[\"local_dimensions_slot\"].as_str().unwrap()],\"dimensions\":metadata[\"dimensions\"]}));\n        };\n        let copy = |operations: &mut Vec<Value>, src: &str, dst: &str, region: [usize; 3]| {\n            operations.push(\n                json!({\"operation\":\"copy_image\",\"source\":src,\"destination\":dst,\"region\":region}),\n            )\n        };\n        kernel(&mut operations, 0x220);\n        if settings.enhancement == 0 {\n            copy(&mut operations, \"0x308\", \"0x350\", [128, 320, 1]);\n        } else {\n            kernel(&mut operations, 0x228);\n            kernel(&mut operations, 0x230);\n            if n == 1 {\n                copy(&mut operations, \"0x318\", \"0x328\", [128, 320, 1]);\n            } else {\n                for addr in [0x238, 0x240, 0x248, 0x250] {\n                    kernel(&mut operations, addr);\n                }\n            }\n            for addr in [\n                0x268, 0x270, 0x280, 0x288, 0x290, 0x298, 0x2a0, 0x2a8, 0x2b0,\n            ] {\n                kernel(&mut operations, addr);\n            }\n            for _ in 1..coarse_iterations {\n                copy(&mut operations, \"0x3b8\", \"0x3b0\", [64, 160, 1]);\n                kernel(&mut operations, 0x2b0);\n            }\n            for addr in [0x2b8, 0x2c0, 0x260] {\n                kernel(&mut operations, addr);\n            }\n        }\n        if settings.enhancement == 0 {\n            operations.push(json!({\"operation\":\"fill_image\",\"destination\":\"0x530\",\"color_f32_bits\":if count_after>1 {words[14]} else {0},\"region\":[64,160,1]}));\n        } else {\n            kernel(&mut operations, 0x518);\n            kernel(&mut operations, 0x520);\n        }\n        kernel(&mut operations, 0x510);\n        copy(&mut operations, \"0x548\", \"0x538\", [128, 320, 1]);\n        copy(&mut operations, \"0x3b8\", \"0x540\", [64, 160, 1]);\n        let recipe = json!({\"schema_version\":\"convex-sri-recipe-v1\",\"settings\":settings.json(),\"parameters_native_slot_begin\":\"0x164\",\"parameters_bytes\":60,\n            \"coarse_iterations\":coarse_iterations,\"fine_iterations\":fine_iterations,\"N\":n,\"P\":64,\"images\":layout[\"images\"],\"persistent_image_bytes\":5038080,\n            \"dimensions\":dims,\"operations\":operations,\"bound_but_not_dispatched\":[\"0x258\",\"0x278\"],\n            \"frame_count_before\":settings.frame_count,\"frame_count_after_update\":count_after,\"warmup\":count_after<2,\n            \"effective_mask_correlation_bits\":effective_correlation,\"success_status_candidate\":if count_after<2 {-100} else {0},\n            \"setparam_fill\":{\"destination\":\"0x548\",\"color_f32_bits\":0,\"region\":[128,320,1]},\n            \"numeric_policy\":\"binary32 separate multiply/add, no FMA; finite scalar resources only\",\n            \"images_computed\":false,\"native_GPU_or_full_engine_equivalence\":false,\n            \"limitations\":[\"Prepared General plan only; no image kernels, backing state, raw grouping or acquisition executed\",\n                \"Dormant HF outputs must retain supplied state in a future processor; no implicit recalculation or zeroing\",\n                \"Native RDH64 must retain clamp-to-edge reads; outside-write diagnostic is not an image extension\",\n                \"Frame counter and status are predictions for successful host calls, not observed device readiness\",\n                \"Fresh SetParam resets count; provided frame_count forecasts a later update, not attested state continuity\"]});\n        Ok(Self {\n            parameters,\n            coarse,\n            fine,\n            dispatch,\n            state_after_update,\n            bindings: json!(bindings.into_values().collect::<Vec<_>>()),\n            recipe,\n            provenance: Value::Null,\n        })\n    }\n}\n/// Durable plan archive only. Every derived bank/parameter must remain ignored.\npub fn run(assets: &Path, resources: &Path, settings_file: &Path, output: &Path) -> Result<Value> {\n    let settings_raw = read_regular(settings_file, 16384)?;\n    let settings =\n        Settings::from_json(&serde_json::from_slice(&settings_raw).map_err(|e| e.to_string())?)?;\n    let plan = Plan::load(assets, resources, settings)?;\n    fs::create_dir(output).map_err(|e| format!(\"New SRI plan directory required: {e}\"))?;\n    File::open(\n        output\n            .parent()\n            .filter(|p| !p.as_os_str().is_empty())\n            .unwrap_or(Path::new(\".\")),\n    )\n    .and_then(|f| f.sync_all())\n    .map_err(|e| e.to_string())?;\n    let mut manifest = json!({\"schema\":\"probe-convex-sri-plan-v1\",\"state\":\"in_progress\",\"software\":archive::source_provenance(),\"settings\":settings.json(),\"provenance\":plan.provenance,\n        \"inputs\":[],\"input_copies_complete\":false,\"results\":[],\"images_computed\":false,\"image_decoded\":false,\"acquisition_validated\":false,\"physical_calibration\":null,\"usb_accessed\":false,\"h4_validated\":false,\"gpu_equivalence_validated\":false,\n        \"scope\":\"Complete known General host parameters, two directional banks, final bindings, dispatch and successful-call recipe; no image processing\"});\n    archive::checkpoint(output, &manifest)?;\n    let operation = (|| -> Result<()> {\n        archive::write_new(&output.join(\"settings.json\"), &settings_raw)?;\n        manifest[\"inputs\"] = json!([{\"file\":\"settings.json\",\"bytes\":settings_raw.len(),\"sha256\":archive::sha(&settings_raw)}]);\n        manifest[\"input_copies_complete\"] = json!(true);\n        archive::checkpoint(output, &manifest)?;\n        for (name, b) in [\n            (\"parameters.bin\", plan.parameters),\n            (\"coarse.f32le\", plan.coarse),\n            (\"fine.f32le\", plan.fine),\n            (\"dispatch.u64le\", plan.dispatch),\n            (\"state-after-update.bin\", plan.state_after_update),\n            (\n                \"bindings.json\",\n                serde_json::to_vec_pretty(&plan.bindings).unwrap(),\n            ),\n            (\n                \"recipe.json\",\n                serde_json::to_vec_pretty(&plan.recipe).unwrap(),\n            ),\n        ] {\n            archive::write_new(&output.join(name), &b)?;\n            manifest[\"results\"]\n                .as_array_mut()\n                .unwrap()\n                .push(json!({\"file\":name,\"bytes\":b.len(),\"sha256\":archive::sha(&b)}));\n        }\n        Ok(())\n    })();\n    match operation {\n        Ok(()) => {\n            manifest[\"state\"] = json!(\"complete_unvalidated\");\n            archive::checkpoint(output, &manifest)?;\n            Ok(manifest)\n        }\n        Err(error) => {\n            manifest[\"state\"] = json!(\"failed\");\n            manifest[\"error\"] = json!(error);\n            archive::checkpoint(output, &manifest)\n                .map_err(|e| format!(\"{error}; checkpoint failed: {e}\"))?;\n            Err(error)\n        }\n    }\n}\n#[cfg(test)]\nmod tests {\n    use super::*;\n    fn settings(e: usize, count: usize) -> Settings {\n        Settings {\n            depth: 0,\n            enhancement: e,\n            correlation: 0,\n            frame_count: count,\n        }\n    }\n    fn inputs() -> (Vec<u8>, Vec<Vec<u8>>) {\n        let mut raw = vec![0; 352];\n        for i in 0..8 {\n            raw[64 + 4 * i..68 + 4 * i].copy_from_slice(&3_u32.to_le_bytes());\n            raw[320 + 4 * i..324 + 4 * i].copy_from_slice(&3_u32.to_le_bytes());\n        }\n        let mut r: Vec<Vec<u8>> = RESOURCES.iter().map(|(_, n, _)| vec![0; *n]).collect();\n        r[0] = bytes(&vec![1.; 225]);\n        r[1] = bytes(&vec![0.25; 200]);\n        (raw, r)\n    }\n    #[test]\n    fn full_recipe_preserves_dormant_states_and_general_n3_tail() {\n        let (raw, r) = inputs();\n        let p = Plan::derive(&raw, &r, settings(8, 0)).unwrap();\n        assert_eq!(p.recipe[\"N\"], 3);\n        assert_eq!(p.recipe[\"images\"].as_array().unwrap().len(), 42);\n        let ops = p.recipe[\"operations\"].as_array().unwrap();\n        assert!(\n            !ops.iter()\n                .any(|v| v[\"slot\"] == \"0x258\" || v[\"slot\"] == \"0x278\")\n        );\n        assert_eq!(ops.iter().filter(|v| v[\"slot\"] == \"0x2b0\").count(), 3);\n        assert_eq!(\n            ops.iter().find(|v| v[\"slot\"] == \"0x260\").unwrap()[\"global\"],\n            json!([128, 106])\n        );\n        assert_eq!(p.recipe[\"frame_count_after_update\"], 1);\n        assert_eq!(p.recipe[\"success_status_candidate\"], -100);\n    }\n    #[test]\n    fn zero_enhancement_keeps_host_copy_fill_and_warmup() {\n        let (raw, r) = inputs();\n        let p = Plan::derive(&raw, &r, settings(0, 1)).unwrap();\n        assert_eq!(p.recipe[\"N\"], 1);\n        assert_eq!(p.recipe[\"success_status_candidate\"], 0);\n        let ops = p.recipe[\"operations\"].as_array().unwrap();\n        assert!(ops.iter().any(|v| v[\"operation\"] == \"fill_image\"));\n        assert!(!ops.iter().any(|v| v[\"slot\"] == \"0x290\"));\n    }\n    #[test]\n    fn exact_settings_and_resource_domains_are_required() {\n        let mut v = settings(1, 0).json();\n        v[\"extra\"] = json!(1);\n        assert!(Settings::from_json(&v).is_err());\n        let (raw, mut r) = inputs();\n        r[0][..4].copy_from_slice(&f32::NAN.to_le_bytes());\n        assert!(Plan::derive(&raw, &r, settings(1, 0)).is_err());\n        assert!(Plan::derive(&raw, &r, settings(9, 0)).is_err());\n    }\n}\n"
      },
      {
        "path": "components/ultrasound/convex-decoder/1.0.0/src/framing.rs",
        "sha256": "74c4e02ba50a5035517f7b1a7f4023a8ea259af7b92cb0b139e5853d707d653a",
        "text": "// SPDX-License-Identifier: AGPL-3.0-or-later\nuse serde_json::{Value, json};\nuse std::collections::BTreeMap;\n\npub type Result<T> = std::result::Result<T, String>;\npub const MARKER: [u8; 4] = [0, 0, 255, 127];\npub const HEADER_BYTES: usize = 1024;\npub const PREFIX_BYTES: usize = 32;\n\n#[derive(Clone, Copy, Debug, PartialEq, Eq)]\npub struct Parameters {\n    pub a: i32,\n    pub b: i32,\n    pub c: i32,\n    pub d: i32,\n    pub e: i32,\n}\nimpl Parameters {\n    pub fn from_json(value: &Value) -> Result<Self> {\n        let object = value\n            .as_object()\n            .ok_or(\"Parameters must be an object with exactly A,B,C,D,E\")?;\n        if object.len() != 5\n            || object\n                .keys()\n                .any(|key| ![\"A\", \"B\", \"C\", \"D\", \"E\"].contains(&key.as_str()))\n        {\n            return Err(\"Parameters require exactly A,B,C,D,E; no defaults\".into());\n        }\n        let get = |name: &str| -> Result<i32> {\n            value[name]\n                .as_i64()\n                .and_then(|n| i32::try_from(n).ok())\n                .ok_or_else(|| {\n                    format!(\"Parameter {name} must be an explicit signed 32-bit integer\")\n                })\n        };\n        Ok(Self {\n            a: get(\"A\")?,\n            b: get(\"B\")?,\n            c: get(\"C\")?,\n            d: get(\"D\")?,\n            e: get(\"E\")?,\n        })\n    }\n    pub fn json(self) -> Value {\n        json!({\"A\":self.a,\"B\":self.b,\"C\":self.c,\"D\":self.d,\"E\":self.e})\n    }\n}\n\n#[derive(Clone, Copy, Debug)]\npub struct Limits {\n    pub max_input_bytes: u64,\n    pub max_push_bytes: usize,\n    pub max_line_bytes: usize,\n    pub max_buffer_bytes: usize,\n    pub opaque_chunk_bytes: usize,\n    pub max_segment_files: u64,\n}\nimpl Default for Limits {\n    fn default() -> Self {\n        Self {\n            max_input_bytes: 256 * 1024 * 1024,\n            max_push_bytes: 64 * 1024,\n            max_line_bytes: 1024 * 1024,\n            max_buffer_bytes: 1024 * 1024 + 64 * 1024,\n            opaque_chunk_bytes: 64 * 1024,\n            max_segment_files: 100_000,\n        }\n    }\n}\nimpl Limits {\n    fn validate(self) -> Result<()> {\n        if self.max_push_bytes == 0\n            || self.max_line_bytes < PREFIX_BYTES\n            || self.opaque_chunk_bytes < 8\n            || self.max_input_bytes == 0\n            || self.max_segment_files == 0\n            || self.max_buffer_bytes\n                < self\n                    .max_line_bytes\n                    .checked_add(self.max_push_bytes)\n                    .ok_or(\"Buffer bound overflow\")?\n            || self.max_buffer_bytes\n                < self\n                    .opaque_chunk_bytes\n                    .checked_add(8)\n                    .ok_or(\"Opaque bound overflow\")?\n        {\n            return Err(\"Inconsistent/zero resource limits\".into());\n        }\n        Ok(())\n    }\n    pub fn json(self) -> Value {\n        json!({\"max_input_bytes\":self.max_input_bytes,\"max_push_bytes\":self.max_push_bytes,\"max_line_bytes\":self.max_line_bytes,\"max_buffer_bytes\":self.max_buffer_bytes,\"opaque_chunk_bytes\":self.opaque_chunk_bytes,\"max_segment_files\":self.max_segment_files})\n    }\n}\n\n#[derive(Clone, Debug, PartialEq)]\npub struct Segment {\n    pub offset: u64,\n    pub kind: &'static str,\n    pub bytes: Vec<u8>,\n    pub metadata: Value,\n    /// Counts are observations of parser conditions, never proven lost samples.\n    pub diagnostics: BTreeMap<String, u64>,\n}\n\n#[derive(Clone, Copy, Debug)]\nstruct Frame {\n    index: u64,\n    offset: u64,\n    id: u32,\n    mode: u8,\n    p: u16,\n    n: u16,\n}\nimpl Frame {\n    fn json(self) -> Value {\n        json!({\"candidate_frame_index\":self.index,\"header_offset\":self.offset,\"frame_id\":self.id,\"mode\":self.mode,\"P\":self.p,\"N\":self.n,\"frame_complete\":null})\n    }\n}\nfn u16le(bytes: &[u8], offset: usize) -> u16 {\n    u16::from_le_bytes(bytes[offset..offset + 2].try_into().unwrap())\n}\nfn u32le(bytes: &[u8], offset: usize) -> u32 {\n    u32::from_le_bytes(bytes[offset..offset + 4].try_into().unwrap())\n}\n\n/// Computes the evidenced helper's signed-32-bit formula with checked arithmetic.\n/// Rejecting overflow and lengths below the prefix are added defensive policies.\npub fn line_length(\n    mode: u8,\n    p: u16,\n    word: u32,\n    parameters: Option<Parameters>,\n    maximum: usize,\n) -> Result<usize> {\n    let p = i32::from(p);\n    let length = match mode {\n        5 | 6 => i32::try_from((word & 0xffff) * 4).unwrap(),\n        0..=3 => {\n            let v = parameters.ok_or(\"missing_external_parameters\")?;\n            let effective = |x: i32, f: i32| if f == 1 { x / 2 } else { x };\n            let (coefficient, scale) = match mode {\n                0 | 1 => (effective(v.c, v.a), 2),\n                2 => (v.d, 4),\n                3 => (effective(v.e, v.b), 2),\n                _ => unreachable!(),\n            };\n            p.checked_mul(coefficient)\n                .and_then(|n| n.checked_mul(scale))\n                .and_then(|n| n.checked_add(PREFIX_BYTES as i32))\n                .ok_or(\"length_arithmetic_overflow\")?\n        }\n        _ => return Err(\"unsupported_mode\".into()),\n    };\n    if length < PREFIX_BYTES as i32 {\n        return Err(\"length_below_prefix\".into());\n    }\n    let length = usize::try_from(length).map_err(|_| \"length_out_of_range\")?;\n    if length > maximum {\n        return Err(\"line_resource_bound\".into());\n    }\n    Ok(length)\n}\n\n/// Incremental bounded parser. push() rejects oversized chunks/input before\n/// consuming them. Invalid candidate lengths remain opaque bytes with diagnostics.\n/// Segment concatenation exactly reproduces input after finish(). Transport\n/// boundaries have no semantic meaning; opaque chunking may span several pushes.\npub struct Inspector {\n    parameters: Option<Parameters>,\n    limits: Limits,\n    buffer: Vec<u8>,\n    received: u64,\n    offset: u64,\n    frame: Option<Frame>,\n    frame_count: u64,\n    search_cursor: usize,\n    opaque_reason: &'static str,\n    line_parsing: bool,\n    finished: bool,\n}\nimpl Inspector {\n    pub fn new(parameters: Option<Parameters>, limits: Limits) -> Result<Self> {\n        limits.validate()?;\n        Ok(Self {\n            parameters,\n            limits,\n            buffer: Vec::new(),\n            received: 0,\n            offset: 0,\n            frame: None,\n            frame_count: 0,\n            search_cursor: 0,\n            opaque_reason: \"no_frame_context\",\n            line_parsing: false,\n            finished: false,\n        })\n    }\n    pub fn push(&mut self, bytes: &[u8]) -> Result<Vec<Segment>> {\n        if self.finished {\n            return Err(\"Inspector already finished\".into());\n        }\n        if bytes.len() > self.limits.max_push_bytes {\n            return Err(\"Push exceeds max_push_bytes; chunk was not consumed\".into());\n        }\n        let total = self\n            .received\n            .checked_add(bytes.len() as u64)\n            .ok_or(\"Input count overflow\")?;\n        if total > self.limits.max_input_bytes {\n            return Err(\"Input exceeds max_input_bytes; chunk was not consumed\".into());\n        }\n        if self\n            .buffer\n            .len()\n            .checked_add(bytes.len())\n            .is_none_or(|n| n > self.limits.max_buffer_bytes)\n        {\n            return Err(\"Buffer resource bound; chunk was not consumed\".into());\n        }\n        self.received = total;\n        self.buffer.extend_from_slice(bytes);\n        self.process(false)\n    }\n    pub fn finish(&mut self) -> Result<Vec<Segment>> {\n        if self.finished {\n            return Err(\"Inspector already finished\".into());\n        }\n        self.finished = true;\n        self.process(true)\n    }\n    /// End this observed epoch at unknown transport continuity. The remaining\n    /// candidate is retained without an EOF interpretation; no later push is allowed.\n    pub fn end_at_gap(&mut self, reason: &str) -> Result<Vec<Segment>> {\n        if self.finished {\n            return Err(\"Inspector already finished\".into());\n        }\n        let mut segments = self.process(false)?;\n        self.finished = true;\n        if !self.buffer.is_empty() {\n            segments.push(self.take(\n                self.buffer.len(),\n                \"discontinuous_candidate\",\n                json!({\"reason\":reason,\"candidate_frame\":self.frame.map(Frame::json),\n                    \"frame_complete\":null,\"sample_format\":\"unknown\"}),\n                BTreeMap::from([(\"transport_discontinuity\".into(), 1)]),\n            ));\n        }\n        segments.push(self.take(\n            0,\n            \"gap\",\n            json!({\"reason\":reason,\n            \"missing_bytes\":null,\"original_wire_phase_known\":false,\"frame_complete\":null}),\n            BTreeMap::from([(\"transport_discontinuity\".into(), 1)]),\n        ));\n        self.frame = None;\n        self.line_parsing = false;\n        Ok(segments)\n    }\n    pub(crate) fn allow_continuous(&mut self) {\n        // Lifetime counters may grow; individual push, line and buffer bounds remain.\n        self.limits.max_input_bytes = u64::MAX;\n        self.limits.max_segment_files = u64::MAX;\n    }\n    pub fn accepted_bytes(&self) -> u64 {\n        self.received\n    }\n    fn take(\n        &mut self,\n        length: usize,\n        kind: &'static str,\n        metadata: Value,\n        diagnostics: BTreeMap<String, u64>,\n    ) -> Segment {\n        let bytes = self.buffer.drain(..length).collect();\n        let offset = self.offset;\n        self.offset += length as u64;\n        self.search_cursor = self.search_cursor.saturating_sub(length);\n        Segment {\n            offset,\n            kind,\n            bytes,\n            metadata,\n            diagnostics,\n        }\n    }\n    fn opaque(&mut self, length: usize, reason: &str) -> Segment {\n        let mut diagnostics = BTreeMap::new();\n        diagnostics.insert(reason.to_owned(), 1);\n        let mut halfword = 0;\n        let mut other_unaligned = 0;\n        for i in 0..length {\n            if self.buffer.get(i..i + 4) == Some(&MARKER) {\n                match (self.offset + i as u64) % 4 {\n                    2 => halfword += 1,\n                    1 | 3 => other_unaligned += 1,\n                    _ => (),\n                }\n            }\n        }\n        if halfword > 0 {\n            diagnostics.insert(\"halfword_shifted_marker_observed\".into(), halfword);\n        }\n        if other_unaligned > 0 {\n            diagnostics.insert(\"byte_shifted_marker_observed\".into(), other_unaligned);\n        }\n        self.take(length,\"opaque\",json!({\"reason\":reason,\"candidate_frame\":self.frame.map(Frame::json),\"realigned\":false}),diagnostics)\n    }\n    fn process(&mut self, eof: bool) -> Result<Vec<Segment>> {\n        let mut segments = Vec::new();\n        while !self.buffer.is_empty() {\n            // Frames are candidates only; the next header never proves the\n            // preceding frame was complete, even when N lines were observed.\n            let at_header = self.buffer.len() >= 8\n                && self.offset.is_multiple_of(4)\n                && self.buffer[..4] == MARKER\n                && self.buffer[4..8] == MARKER;\n            if at_header {\n                if self.buffer.len() < HEADER_BYTES {\n                    if eof {\n                        let mut d = BTreeMap::new();\n                        d.insert(\"truncated_header\".into(), 1);\n                        segments.push(self.take(\n                            self.buffer.len(),\n                            \"truncated_header\",\n                            json!({\"expected_bytes\":HEADER_BYTES,\"frame_complete\":null}),\n                            d,\n                        ));\n                    }\n                    break;\n                }\n                self.frame_count += 1;\n                let frame = Frame {\n                    index: self.frame_count,\n                    offset: self.offset,\n                    id: u32le(&self.buffer, 0x0c),\n                    mode: self.buffer[0x10],\n                    p: u16le(&self.buffer, 0x18),\n                    n: u16le(&self.buffer, 0x1c),\n                };\n                self.frame = Some(frame);\n                self.search_cursor = 0;\n                let mut diagnostics = BTreeMap::new();\n                self.line_parsing =\n                    matches!(frame.mode, 5 | 6) || (frame.mode <= 3 && self.parameters.is_some());\n                if !self.line_parsing {\n                    self.opaque_reason = if frame.mode <= 3 {\n                        \"missing_external_parameters\"\n                    } else {\n                        \"unsupported_mode\"\n                    };\n                    diagnostics.insert(self.opaque_reason.into(), 1);\n                }\n                segments.push(self.take(HEADER_BYTES, \"frame_header\", frame.json(), diagnostics));\n                continue;\n            }\n            if self.line_parsing {\n                let frame = self.frame.expect(\"line parsing follows a header\");\n                if !self.offset.is_multiple_of(4) {\n                    // Preserve the preceding formula's exact byte length. Our\n                    // four-byte search cannot corroborate the next boundary;\n                    // keep subsequent bytes opaque instead of realigning.\n                    self.line_parsing = false;\n                    self.search_cursor = 0;\n                    self.opaque_reason = \"post_line_boundary_unaligned\";\n                    continue;\n                }\n                if self.buffer.len() < 8 {\n                    if eof {\n                        if MARKER.starts_with(&self.buffer[..self.buffer.len().min(4)]) {\n                            let mut d = BTreeMap::new();\n                            d.insert(\"truncated_line_prefix\".into(), 1);\n                            segments.push(self.take(self.buffer.len(),\"truncated_line\",json!({\"candidate_frame\":frame.json(),\"expected_prefix_bytes\":PREFIX_BYTES}),d));\n                        } else {\n                            let n = self.buffer.len();\n                            segments.push(self.opaque(n, \"desynchronization_observed\"));\n                        }\n                    }\n                    break;\n                }\n                if self.buffer[..4] != MARKER {\n                    self.line_parsing = false;\n                    self.search_cursor = 0;\n                    self.opaque_reason = \"desynchronization_observed\";\n                    continue;\n                }\n                let word = u32le(&self.buffer, 4);\n                let length = match line_length(\n                    frame.mode,\n                    frame.p,\n                    word,\n                    self.parameters,\n                    self.limits.max_line_bytes,\n                ) {\n                    Ok(n) => n,\n                    Err(reason) => {\n                        self.line_parsing = false;\n                        self.search_cursor = 0;\n                        self.opaque_reason = match reason.as_str() {\n                            \"length_arithmetic_overflow\" => \"length_arithmetic_overflow\",\n                            \"length_below_prefix\" => \"length_below_prefix\",\n                            \"line_resource_bound\" => \"line_resource_bound\",\n                            _ => \"invalid_length\",\n                        };\n                        continue;\n                    }\n                };\n                let subtype = (word >> 20) & 15;\n                let next_alignment = (self.offset + length as u64) % 4;\n                let metadata = json!({\"candidate_frame\":frame.json(),\"word_at_4\":word,\"total_line_bytes\":length,\"prefix_bytes\":PREFIX_BYTES,\"next_boundary_alignment_mod4\":next_alignment,\"sample_format\":\"unknown\",\"subtype\":if matches!(frame.mode,5|6){Some(subtype)}else{None},\"candidate_class\":if matches!(frame.mode,5|6){if subtype<4{\"B\"}else if subtype==4{\"M\"}else{\"other_preserved\"}}else{\"unclassified\"}});\n                if self.buffer.len() < length {\n                    if eof {\n                        let mut d = BTreeMap::new();\n                        d.insert(\"truncated_line\".into(), 1);\n                        segments.push(self.take(self.buffer.len(), \"truncated_line\", metadata, d));\n                    }\n                    break;\n                }\n                let mut diagnostics = BTreeMap::new();\n                if next_alignment != 0 {\n                    diagnostics.insert(\"unaligned_following_boundary\".into(), 1);\n                }\n                segments.push(self.take(length, \"line\", metadata, diagnostics));\n                continue;\n            }\n            let mut candidate = None;\n            if self.buffer.len() >= 8 {\n                for i in self.search_cursor..=self.buffer.len() - 8 {\n                    if (self.offset + i as u64).is_multiple_of(4)\n                        && self.buffer[i..i + 4] == MARKER\n                        && self.buffer[i + 4..i + 8] == MARKER\n                    {\n                        candidate = Some(i);\n                        break;\n                    }\n                }\n                self.search_cursor = self.buffer.len() - 7;\n            }\n            if let Some(position) = candidate {\n                if position > 0 {\n                    segments.push(self.opaque(position, self.opaque_reason));\n                }\n                self.search_cursor = 0;\n                continue;\n            }\n            let emit = if eof {\n                self.buffer.len()\n            } else if self.buffer.len() >= self.limits.opaque_chunk_bytes + 7 {\n                self.limits.opaque_chunk_bytes\n            } else {\n                0\n            };\n            if emit == 0 {\n                break;\n            }\n            segments.push(self.opaque(emit, self.opaque_reason));\n        }\n        Ok(segments)\n    }\n}\n"
      },
      {
        "path": "components/ultrasound/convex-decoder/1.0.0/src/known_convex_assets.json",
        "sha256": "700e1c948dfb673980c38fba239bed9a3b01bff558f0d56ee17f1e10343fbd0f",
        "text": "{\n  \"schema_version\": \"convex-configuration-asset-hashes-v1\",\n  \"profiles\": {\n    \"ABD\": {\n      \"A_ADC.bin\": {\n        \"bytes\": 20,\n        \"sha256\": \"4e073dd1aabcd1bad16622ad1ca1182ad08e59fa1db5359e25b6b3f089307e7e\"\n      },\n      \"A_ATGC.bin\": {\n        \"bytes\": 1024,\n        \"sha256\": \"721ce3a1564f7e5cd16c3e0899471ab5cc4e29ce01d0845141535e2ec6768e6c\"\n      },\n      \"A_Apo.bin\": {\n        \"bytes\": 2048,\n        \"sha256\": \"dcde5582467b51f7c82e40bc6306e13d59e71a11bacbd1d808071a208c6fb149\"\n      },\n      \"A_ApoComp.bin\": {\n        \"bytes\": 2048,\n        \"sha256\": \"b4dc0b8f14671df5c0278ea1c58a92099a3b8a5cb50e6da4cec6677ff98eb3d5\"\n      },\n      \"A_Probe.bin\": {\n        \"bytes\": 68,\n        \"sha256\": \"9b8e95810fe33a085f2be2e58f082de9915cb3d7f66324d01145e4c211c2efcb\"\n      },\n      \"A_TxWave.bin\": {\n        \"bytes\": 660,\n        \"sha256\": \"db99ee64fb4185fcb98f1fc21520774dc0c0bb995b4c5bdf88cdce1eb86dd2e3\"\n      },\n      \"B_PRF.bin\": {\n        \"bytes\": 388,\n        \"sha256\": \"9159defd1ef064c0050ec94ce88936c016e86e22e90e682521672edd53d1e5c3\"\n      }\n    },\n    \"Diaphragm\": {\n      \"A_ADC.bin\": {\n        \"bytes\": 20,\n        \"sha256\": \"4e073dd1aabcd1bad16622ad1ca1182ad08e59fa1db5359e25b6b3f089307e7e\"\n      },\n      \"A_ATGC.bin\": {\n        \"bytes\": 1024,\n        \"sha256\": \"721ce3a1564f7e5cd16c3e0899471ab5cc4e29ce01d0845141535e2ec6768e6c\"\n      },\n      \"A_Apo.bin\": {\n        \"bytes\": 2048,\n        \"sha256\": \"dcde5582467b51f7c82e40bc6306e13d59e71a11bacbd1d808071a208c6fb149\"\n      },\n      \"A_ApoComp.bin\": {\n        \"bytes\": 2048,\n        \"sha256\": \"b4dc0b8f14671df5c0278ea1c58a92099a3b8a5cb50e6da4cec6677ff98eb3d5\"\n      },\n      \"A_Probe.bin\": {\n        \"bytes\": 68,\n        \"sha256\": \"9b8e95810fe33a085f2be2e58f082de9915cb3d7f66324d01145e4c211c2efcb\"\n      },\n      \"A_TxWave.bin\": {\n        \"bytes\": 660,\n        \"sha256\": \"db99ee64fb4185fcb98f1fc21520774dc0c0bb995b4c5bdf88cdce1eb86dd2e3\"\n      },\n      \"B_PRF.bin\": {\n        \"bytes\": 388,\n        \"sha256\": \"9159defd1ef064c0050ec94ce88936c016e86e22e90e682521672edd53d1e5c3\"\n      }\n    },\n    \"General\": {\n      \"A_ADC.bin\": {\n        \"bytes\": 20,\n        \"sha256\": \"4e073dd1aabcd1bad16622ad1ca1182ad08e59fa1db5359e25b6b3f089307e7e\"\n      },\n      \"A_ATGC.bin\": {\n        \"bytes\": 1024,\n        \"sha256\": \"3d6237ef3a139581de03cfc0db5b5c2c5519b48e9afeb6499fdf75c0892c8021\"\n      },\n      \"A_Apo.bin\": {\n        \"bytes\": 2048,\n        \"sha256\": \"dcde5582467b51f7c82e40bc6306e13d59e71a11bacbd1d808071a208c6fb149\"\n      },\n      \"A_ApoComp.bin\": {\n        \"bytes\": 2048,\n        \"sha256\": \"b4dc0b8f14671df5c0278ea1c58a92099a3b8a5cb50e6da4cec6677ff98eb3d5\"\n      },\n      \"A_Probe.bin\": {\n        \"bytes\": 68,\n        \"sha256\": \"9b8e95810fe33a085f2be2e58f082de9915cb3d7f66324d01145e4c211c2efcb\"\n      },\n      \"A_TxWave.bin\": {\n        \"bytes\": 660,\n        \"sha256\": \"db99ee64fb4185fcb98f1fc21520774dc0c0bb995b4c5bdf88cdce1eb86dd2e3\"\n      },\n      \"B_PRF.bin\": {\n        \"bytes\": 388,\n        \"sha256\": \"bf553725fc08bf50b6c4919ebc38d8cb8d648b8f03072a6d2da6fe32dcd84231\"\n      }\n    },\n    \"Lung\": {\n      \"A_ADC.bin\": {\n        \"bytes\": 20,\n        \"sha256\": \"4e073dd1aabcd1bad16622ad1ca1182ad08e59fa1db5359e25b6b3f089307e7e\"\n      },\n      \"A_ATGC.bin\": {\n        \"bytes\": 1024,\n        \"sha256\": \"721ce3a1564f7e5cd16c3e0899471ab5cc4e29ce01d0845141535e2ec6768e6c\"\n      },\n      \"A_Apo.bin\": {\n        \"bytes\": 2048,\n        \"sha256\": \"dcde5582467b51f7c82e40bc6306e13d59e71a11bacbd1d808071a208c6fb149\"\n      },\n      \"A_ApoComp.bin\": {\n        \"bytes\": 2048,\n        \"sha256\": \"b4dc0b8f14671df5c0278ea1c58a92099a3b8a5cb50e6da4cec6677ff98eb3d5\"\n      },\n      \"A_Probe.bin\": {\n        \"bytes\": 68,\n        \"sha256\": \"9b8e95810fe33a085f2be2e58f082de9915cb3d7f66324d01145e4c211c2efcb\"\n      },\n      \"A_TxWave.bin\": {\n        \"bytes\": 660,\n        \"sha256\": \"db99ee64fb4185fcb98f1fc21520774dc0c0bb995b4c5bdf88cdce1eb86dd2e3\"\n      },\n      \"B_PRF.bin\": {\n        \"bytes\": 388,\n        \"sha256\": \"9159defd1ef064c0050ec94ce88936c016e86e22e90e682521672edd53d1e5c3\"\n      }\n    },\n    \"OB\": {\n      \"A_ADC.bin\": {\n        \"bytes\": 20,\n        \"sha256\": \"4e073dd1aabcd1bad16622ad1ca1182ad08e59fa1db5359e25b6b3f089307e7e\"\n      },\n      \"A_ATGC.bin\": {\n        \"bytes\": 1024,\n        \"sha256\": \"3d6237ef3a139581de03cfc0db5b5c2c5519b48e9afeb6499fdf75c0892c8021\"\n      },\n      \"A_Apo.bin\": {\n        \"bytes\": 2048,\n        \"sha256\": \"dcde5582467b51f7c82e40bc6306e13d59e71a11bacbd1d808071a208c6fb149\"\n      },\n      \"A_ApoComp.bin\": {\n        \"bytes\": 2048,\n        \"sha256\": \"b4dc0b8f14671df5c0278ea1c58a92099a3b8a5cb50e6da4cec6677ff98eb3d5\"\n      },\n      \"A_Probe.bin\": {\n        \"bytes\": 68,\n        \"sha256\": \"9b8e95810fe33a085f2be2e58f082de9915cb3d7f66324d01145e4c211c2efcb\"\n      },\n      \"A_TxWave.bin\": {\n        \"bytes\": 660,\n        \"sha256\": \"db99ee64fb4185fcb98f1fc21520774dc0c0bb995b4c5bdf88cdce1eb86dd2e3\"\n      },\n      \"B_PRF.bin\": {\n        \"bytes\": 388,\n        \"sha256\": \"9159defd1ef064c0050ec94ce88936c016e86e22e90e682521672edd53d1e5c3\"\n      }\n    },\n    \"Renal\": {\n      \"A_ADC.bin\": {\n        \"bytes\": 20,\n        \"sha256\": \"4e073dd1aabcd1bad16622ad1ca1182ad08e59fa1db5359e25b6b3f089307e7e\"\n      },\n      \"A_ATGC.bin\": {\n        \"bytes\": 1024,\n        \"sha256\": \"3d6237ef3a139581de03cfc0db5b5c2c5519b48e9afeb6499fdf75c0892c8021\"\n      },\n      \"A_Apo.bin\": {\n        \"bytes\": 2048,\n        \"sha256\": \"dcde5582467b51f7c82e40bc6306e13d59e71a11bacbd1d808071a208c6fb149\"\n      },\n      \"A_ApoComp.bin\": {\n        \"bytes\": 2048,\n        \"sha256\": \"b4dc0b8f14671df5c0278ea1c58a92099a3b8a5cb50e6da4cec6677ff98eb3d5\"\n      },\n      \"A_Probe.bin\": {\n        \"bytes\": 68,\n        \"sha256\": \"9b8e95810fe33a085f2be2e58f082de9915cb3d7f66324d01145e4c211c2efcb\"\n      },\n      \"A_TxWave.bin\": {\n        \"bytes\": 660,\n        \"sha256\": \"db99ee64fb4185fcb98f1fc21520774dc0c0bb995b4c5bdf88cdce1eb86dd2e3\"\n      },\n      \"B_PRF.bin\": {\n        \"bytes\": 388,\n        \"sha256\": \"9159defd1ef064c0050ec94ce88936c016e86e22e90e682521672edd53d1e5c3\"\n      }\n    },\n    \"Spine\": {\n      \"A_ADC.bin\": {\n        \"bytes\": 20,\n        \"sha256\": \"4e073dd1aabcd1bad16622ad1ca1182ad08e59fa1db5359e25b6b3f089307e7e\"\n      },\n      \"A_ATGC.bin\": {\n        \"bytes\": 1024,\n        \"sha256\": \"3d6237ef3a139581de03cfc0db5b5c2c5519b48e9afeb6499fdf75c0892c8021\"\n      },\n      \"A_Apo.bin\": {\n        \"bytes\": 2048,\n        \"sha256\": \"dcde5582467b51f7c82e40bc6306e13d59e71a11bacbd1d808071a208c6fb149\"\n      },\n      \"A_ApoComp.bin\": {\n        \"bytes\": 2048,\n        \"sha256\": \"b4dc0b8f14671df5c0278ea1c58a92099a3b8a5cb50e6da4cec6677ff98eb3d5\"\n      },\n      \"A_Probe.bin\": {\n        \"bytes\": 68,\n        \"sha256\": \"9b8e95810fe33a085f2be2e58f082de9915cb3d7f66324d01145e4c211c2efcb\"\n      },\n      \"A_TxWave.bin\": {\n        \"bytes\": 660,\n        \"sha256\": \"db99ee64fb4185fcb98f1fc21520774dc0c0bb995b4c5bdf88cdce1eb86dd2e3\"\n      },\n      \"B_PRF.bin\": {\n        \"bytes\": 388,\n        \"sha256\": \"9159defd1ef064c0050ec94ce88936c016e86e22e90e682521672edd53d1e5c3\"\n      }\n    },\n    \"Uro\": {\n      \"A_ADC.bin\": {\n        \"bytes\": 20,\n        \"sha256\": \"4e073dd1aabcd1bad16622ad1ca1182ad08e59fa1db5359e25b6b3f089307e7e\"\n      },\n      \"A_ATGC.bin\": {\n        \"bytes\": 1024,\n        \"sha256\": \"3d6237ef3a139581de03cfc0db5b5c2c5519b48e9afeb6499fdf75c0892c8021\"\n      },\n      \"A_Apo.bin\": {\n        \"bytes\": 2048,\n        \"sha256\": \"dcde5582467b51f7c82e40bc6306e13d59e71a11bacbd1d808071a208c6fb149\"\n      },\n      \"A_ApoComp.bin\": {\n        \"bytes\": 2048,\n        \"sha256\": \"b4dc0b8f14671df5c0278ea1c58a92099a3b8a5cb50e6da4cec6677ff98eb3d5\"\n      },\n      \"A_Probe.bin\": {\n        \"bytes\": 68,\n        \"sha256\": \"9b8e95810fe33a085f2be2e58f082de9915cb3d7f66324d01145e4c211c2efcb\"\n      },\n      \"A_TxWave.bin\": {\n        \"bytes\": 660,\n        \"sha256\": \"db99ee64fb4185fcb98f1fc21520774dc0c0bb995b4c5bdf88cdce1eb86dd2e3\"\n      },\n      \"B_PRF.bin\": {\n        \"bytes\": 388,\n        \"sha256\": \"9159defd1ef064c0050ec94ce88936c016e86e22e90e682521672edd53d1e5c3\"\n      }\n    }\n  }\n}\n"
      },
      {
        "path": "components/ultrasound/convex-decoder/1.0.0/src/known_convex_producer_assets.json",
        "sha256": "207ec2321a7c01de1b5462a3e61c0b46f09c9dc9e2d9dbcb3db748186fbdbd0a",
        "text": "{\n  \"schema_version\": \"convex-producer-asset-hashes-v1\",\n  \"profiles\": {\n    \"ABD\": {\n      \"A_ADC.bin\": {\n        \"bytes\": 20,\n        \"sha256\": \"4e073dd1aabcd1bad16622ad1ca1182ad08e59fa1db5359e25b6b3f089307e7e\"\n      },\n      \"A_ATGC.bin\": {\n        \"bytes\": 1024,\n        \"sha256\": \"721ce3a1564f7e5cd16c3e0899471ab5cc4e29ce01d0845141535e2ec6768e6c\"\n      },\n      \"A_Apo.bin\": {\n        \"bytes\": 2048,\n        \"sha256\": \"dcde5582467b51f7c82e40bc6306e13d59e71a11bacbd1d808071a208c6fb149\"\n      },\n      \"A_ApoComp.bin\": {\n        \"bytes\": 2048,\n        \"sha256\": \"b4dc0b8f14671df5c0278ea1c58a92099a3b8a5cb50e6da4cec6677ff98eb3d5\"\n      },\n      \"A_Probe.bin\": {\n        \"bytes\": 68,\n        \"sha256\": \"9b8e95810fe33a085f2be2e58f082de9915cb3d7f66324d01145e4c211c2efcb\"\n      },\n      \"A_TxWave.bin\": {\n        \"bytes\": 660,\n        \"sha256\": \"db99ee64fb4185fcb98f1fc21520774dc0c0bb995b4c5bdf88cdce1eb86dd2e3\"\n      },\n      \"B_PRF.bin\": {\n        \"bytes\": 388,\n        \"sha256\": \"9159defd1ef064c0050ec94ce88936c016e86e22e90e682521672edd53d1e5c3\"\n      },\n      \"A_BF.bin\": {\n        \"bytes\": 44,\n        \"sha256\": \"28ed79893f9f224a7c1a29e2288491cb3bf224bbb3851d308c50e799b48dbdee\"\n      },\n      \"B_TxControl.bin\": {\n        \"bytes\": 1024,\n        \"sha256\": \"d13415f8b87474cead27b7454c4549680a71d46e12ea7865d05828ad08dac4a7\"\n      },\n      \"B_DynamicFilter.bin\": {\n        \"bytes\": 43084,\n        \"sha256\": \"81ef617556bf5e84350bf5b59b987685116412e871e3130e88cfb15179e6435b\"\n      },\n      \"B_LPF.bin\": {\n        \"bytes\": 256,\n        \"sha256\": \"69f3e66397510c09a5b68fecfe3113120b1248db880f89c643b86728759e69cc\"\n      },\n      \"A_Up4Coef.bin\": {\n        \"bytes\": 364,\n        \"sha256\": \"5534946090a6eff3789333d3efe7d11eefc2ece88cc3fd4a1c24780d5030e6a3\"\n      }\n    },\n    \"Diaphragm\": {\n      \"A_ADC.bin\": {\n        \"bytes\": 20,\n        \"sha256\": \"4e073dd1aabcd1bad16622ad1ca1182ad08e59fa1db5359e25b6b3f089307e7e\"\n      },\n      \"A_ATGC.bin\": {\n        \"bytes\": 1024,\n        \"sha256\": \"721ce3a1564f7e5cd16c3e0899471ab5cc4e29ce01d0845141535e2ec6768e6c\"\n      },\n      \"A_Apo.bin\": {\n        \"bytes\": 2048,\n        \"sha256\": \"dcde5582467b51f7c82e40bc6306e13d59e71a11bacbd1d808071a208c6fb149\"\n      },\n      \"A_ApoComp.bin\": {\n        \"bytes\": 2048,\n        \"sha256\": \"b4dc0b8f14671df5c0278ea1c58a92099a3b8a5cb50e6da4cec6677ff98eb3d5\"\n      },\n      \"A_Probe.bin\": {\n        \"bytes\": 68,\n        \"sha256\": \"9b8e95810fe33a085f2be2e58f082de9915cb3d7f66324d01145e4c211c2efcb\"\n      },\n      \"A_TxWave.bin\": {\n        \"bytes\": 660,\n        \"sha256\": \"db99ee64fb4185fcb98f1fc21520774dc0c0bb995b4c5bdf88cdce1eb86dd2e3\"\n      },\n      \"B_PRF.bin\": {\n        \"bytes\": 388,\n        \"sha256\": \"9159defd1ef064c0050ec94ce88936c016e86e22e90e682521672edd53d1e5c3\"\n      },\n      \"A_BF.bin\": {\n        \"bytes\": 44,\n        \"sha256\": \"28ed79893f9f224a7c1a29e2288491cb3bf224bbb3851d308c50e799b48dbdee\"\n      },\n      \"B_TxControl.bin\": {\n        \"bytes\": 1024,\n        \"sha256\": \"d13415f8b87474cead27b7454c4549680a71d46e12ea7865d05828ad08dac4a7\"\n      },\n      \"B_DynamicFilter.bin\": {\n        \"bytes\": 43084,\n        \"sha256\": \"81ef617556bf5e84350bf5b59b987685116412e871e3130e88cfb15179e6435b\"\n      },\n      \"B_LPF.bin\": {\n        \"bytes\": 256,\n        \"sha256\": \"69f3e66397510c09a5b68fecfe3113120b1248db880f89c643b86728759e69cc\"\n      },\n      \"A_Up4Coef.bin\": {\n        \"bytes\": 364,\n        \"sha256\": \"5534946090a6eff3789333d3efe7d11eefc2ece88cc3fd4a1c24780d5030e6a3\"\n      }\n    },\n    \"General\": {\n      \"A_ADC.bin\": {\n        \"bytes\": 20,\n        \"sha256\": \"4e073dd1aabcd1bad16622ad1ca1182ad08e59fa1db5359e25b6b3f089307e7e\"\n      },\n      \"A_ATGC.bin\": {\n        \"bytes\": 1024,\n        \"sha256\": \"3d6237ef3a139581de03cfc0db5b5c2c5519b48e9afeb6499fdf75c0892c8021\"\n      },\n      \"A_Apo.bin\": {\n        \"bytes\": 2048,\n        \"sha256\": \"dcde5582467b51f7c82e40bc6306e13d59e71a11bacbd1d808071a208c6fb149\"\n      },\n      \"A_ApoComp.bin\": {\n        \"bytes\": 2048,\n        \"sha256\": \"b4dc0b8f14671df5c0278ea1c58a92099a3b8a5cb50e6da4cec6677ff98eb3d5\"\n      },\n      \"A_Probe.bin\": {\n        \"bytes\": 68,\n        \"sha256\": \"9b8e95810fe33a085f2be2e58f082de9915cb3d7f66324d01145e4c211c2efcb\"\n      },\n      \"A_TxWave.bin\": {\n        \"bytes\": 660,\n        \"sha256\": \"db99ee64fb4185fcb98f1fc21520774dc0c0bb995b4c5bdf88cdce1eb86dd2e3\"\n      },\n      \"B_PRF.bin\": {\n        \"bytes\": 388,\n        \"sha256\": \"bf553725fc08bf50b6c4919ebc38d8cb8d648b8f03072a6d2da6fe32dcd84231\"\n      },\n      \"A_BF.bin\": {\n        \"bytes\": 44,\n        \"sha256\": \"28ed79893f9f224a7c1a29e2288491cb3bf224bbb3851d308c50e799b48dbdee\"\n      },\n      \"B_TxControl.bin\": {\n        \"bytes\": 1024,\n        \"sha256\": \"d13415f8b87474cead27b7454c4549680a71d46e12ea7865d05828ad08dac4a7\"\n      },\n      \"B_DynamicFilter.bin\": {\n        \"bytes\": 43084,\n        \"sha256\": \"81ef617556bf5e84350bf5b59b987685116412e871e3130e88cfb15179e6435b\"\n      },\n      \"B_LPF.bin\": {\n        \"bytes\": 256,\n        \"sha256\": \"69f3e66397510c09a5b68fecfe3113120b1248db880f89c643b86728759e69cc\"\n      },\n      \"A_Up4Coef.bin\": {\n        \"bytes\": 364,\n        \"sha256\": \"5534946090a6eff3789333d3efe7d11eefc2ece88cc3fd4a1c24780d5030e6a3\"\n      }\n    },\n    \"Lung\": {\n      \"A_ADC.bin\": {\n        \"bytes\": 20,\n        \"sha256\": \"4e073dd1aabcd1bad16622ad1ca1182ad08e59fa1db5359e25b6b3f089307e7e\"\n      },\n      \"A_ATGC.bin\": {\n        \"bytes\": 1024,\n        \"sha256\": \"721ce3a1564f7e5cd16c3e0899471ab5cc4e29ce01d0845141535e2ec6768e6c\"\n      },\n      \"A_Apo.bin\": {\n        \"bytes\": 2048,\n        \"sha256\": \"dcde5582467b51f7c82e40bc6306e13d59e71a11bacbd1d808071a208c6fb149\"\n      },\n      \"A_ApoComp.bin\": {\n        \"bytes\": 2048,\n        \"sha256\": \"b4dc0b8f14671df5c0278ea1c58a92099a3b8a5cb50e6da4cec6677ff98eb3d5\"\n      },\n      \"A_Probe.bin\": {\n        \"bytes\": 68,\n        \"sha256\": \"9b8e95810fe33a085f2be2e58f082de9915cb3d7f66324d01145e4c211c2efcb\"\n      },\n      \"A_TxWave.bin\": {\n        \"bytes\": 660,\n        \"sha256\": \"db99ee64fb4185fcb98f1fc21520774dc0c0bb995b4c5bdf88cdce1eb86dd2e3\"\n      },\n      \"B_PRF.bin\": {\n        \"bytes\": 388,\n        \"sha256\": \"9159defd1ef064c0050ec94ce88936c016e86e22e90e682521672edd53d1e5c3\"\n      },\n      \"A_BF.bin\": {\n        \"bytes\": 44,\n        \"sha256\": \"28ed79893f9f224a7c1a29e2288491cb3bf224bbb3851d308c50e799b48dbdee\"\n      },\n      \"B_TxControl.bin\": {\n        \"bytes\": 1024,\n        \"sha256\": \"d13415f8b87474cead27b7454c4549680a71d46e12ea7865d05828ad08dac4a7\"\n      },\n      \"B_DynamicFilter.bin\": {\n        \"bytes\": 43084,\n        \"sha256\": \"81ef617556bf5e84350bf5b59b987685116412e871e3130e88cfb15179e6435b\"\n      },\n      \"B_LPF.bin\": {\n        \"bytes\": 256,\n        \"sha256\": \"69f3e66397510c09a5b68fecfe3113120b1248db880f89c643b86728759e69cc\"\n      },\n      \"A_Up4Coef.bin\": {\n        \"bytes\": 364,\n        \"sha256\": \"5534946090a6eff3789333d3efe7d11eefc2ece88cc3fd4a1c24780d5030e6a3\"\n      }\n    },\n    \"OB\": {\n      \"A_ADC.bin\": {\n        \"bytes\": 20,\n        \"sha256\": \"4e073dd1aabcd1bad16622ad1ca1182ad08e59fa1db5359e25b6b3f089307e7e\"\n      },\n      \"A_ATGC.bin\": {\n        \"bytes\": 1024,\n        \"sha256\": \"3d6237ef3a139581de03cfc0db5b5c2c5519b48e9afeb6499fdf75c0892c8021\"\n      },\n      \"A_Apo.bin\": {\n        \"bytes\": 2048,\n        \"sha256\": \"dcde5582467b51f7c82e40bc6306e13d59e71a11bacbd1d808071a208c6fb149\"\n      },\n      \"A_ApoComp.bin\": {\n        \"bytes\": 2048,\n        \"sha256\": \"b4dc0b8f14671df5c0278ea1c58a92099a3b8a5cb50e6da4cec6677ff98eb3d5\"\n      },\n      \"A_Probe.bin\": {\n        \"bytes\": 68,\n        \"sha256\": \"9b8e95810fe33a085f2be2e58f082de9915cb3d7f66324d01145e4c211c2efcb\"\n      },\n      \"A_TxWave.bin\": {\n        \"bytes\": 660,\n        \"sha256\": \"db99ee64fb4185fcb98f1fc21520774dc0c0bb995b4c5bdf88cdce1eb86dd2e3\"\n      },\n      \"B_PRF.bin\": {\n        \"bytes\": 388,\n        \"sha256\": \"9159defd1ef064c0050ec94ce88936c016e86e22e90e682521672edd53d1e5c3\"\n      },\n      \"A_BF.bin\": {\n        \"bytes\": 44,\n        \"sha256\": \"28ed79893f9f224a7c1a29e2288491cb3bf224bbb3851d308c50e799b48dbdee\"\n      },\n      \"B_TxControl.bin\": {\n        \"bytes\": 1024,\n        \"sha256\": \"d13415f8b87474cead27b7454c4549680a71d46e12ea7865d05828ad08dac4a7\"\n      },\n      \"B_DynamicFilter.bin\": {\n        \"bytes\": 43084,\n        \"sha256\": \"81ef617556bf5e84350bf5b59b987685116412e871e3130e88cfb15179e6435b\"\n      },\n      \"B_LPF.bin\": {\n        \"bytes\": 256,\n        \"sha256\": \"69f3e66397510c09a5b68fecfe3113120b1248db880f89c643b86728759e69cc\"\n      },\n      \"A_Up4Coef.bin\": {\n        \"bytes\": 364,\n        \"sha256\": \"5534946090a6eff3789333d3efe7d11eefc2ece88cc3fd4a1c24780d5030e6a3\"\n      }\n    },\n    \"Renal\": {\n      \"A_ADC.bin\": {\n        \"bytes\": 20,\n        \"sha256\": \"4e073dd1aabcd1bad16622ad1ca1182ad08e59fa1db5359e25b6b3f089307e7e\"\n      },\n      \"A_ATGC.bin\": {\n        \"bytes\": 1024,\n        \"sha256\": \"3d6237ef3a139581de03cfc0db5b5c2c5519b48e9afeb6499fdf75c0892c8021\"\n      },\n      \"A_Apo.bin\": {\n        \"bytes\": 2048,\n        \"sha256\": \"dcde5582467b51f7c82e40bc6306e13d59e71a11bacbd1d808071a208c6fb149\"\n      },\n      \"A_ApoComp.bin\": {\n        \"bytes\": 2048,\n        \"sha256\": \"b4dc0b8f14671df5c0278ea1c58a92099a3b8a5cb50e6da4cec6677ff98eb3d5\"\n      },\n      \"A_Probe.bin\": {\n        \"bytes\": 68,\n        \"sha256\": \"9b8e95810fe33a085f2be2e58f082de9915cb3d7f66324d01145e4c211c2efcb\"\n      },\n      \"A_TxWave.bin\": {\n        \"bytes\": 660,\n        \"sha256\": \"db99ee64fb4185fcb98f1fc21520774dc0c0bb995b4c5bdf88cdce1eb86dd2e3\"\n      },\n      \"B_PRF.bin\": {\n        \"bytes\": 388,\n        \"sha256\": \"9159defd1ef064c0050ec94ce88936c016e86e22e90e682521672edd53d1e5c3\"\n      },\n      \"A_BF.bin\": {\n        \"bytes\": 44,\n        \"sha256\": \"28ed79893f9f224a7c1a29e2288491cb3bf224bbb3851d308c50e799b48dbdee\"\n      },\n      \"B_TxControl.bin\": {\n        \"bytes\": 1024,\n        \"sha256\": \"d13415f8b87474cead27b7454c4549680a71d46e12ea7865d05828ad08dac4a7\"\n      },\n      \"B_DynamicFilter.bin\": {\n        \"bytes\": 43084,\n        \"sha256\": \"81ef617556bf5e84350bf5b59b987685116412e871e3130e88cfb15179e6435b\"\n      },\n      \"B_LPF.bin\": {\n        \"bytes\": 256,\n        \"sha256\": \"69f3e66397510c09a5b68fecfe3113120b1248db880f89c643b86728759e69cc\"\n      },\n      \"A_Up4Coef.bin\": {\n        \"bytes\": 364,\n        \"sha256\": \"5534946090a6eff3789333d3efe7d11eefc2ece88cc3fd4a1c24780d5030e6a3\"\n      }\n    },\n    \"Spine\": {\n      \"A_ADC.bin\": {\n        \"bytes\": 20,\n        \"sha256\": \"4e073dd1aabcd1bad16622ad1ca1182ad08e59fa1db5359e25b6b3f089307e7e\"\n      },\n      \"A_ATGC.bin\": {\n        \"bytes\": 1024,\n        \"sha256\": \"3d6237ef3a139581de03cfc0db5b5c2c5519b48e9afeb6499fdf75c0892c8021\"\n      },\n      \"A_Apo.bin\": {\n        \"bytes\": 2048,\n        \"sha256\": \"dcde5582467b51f7c82e40bc6306e13d59e71a11bacbd1d808071a208c6fb149\"\n      },\n      \"A_ApoComp.bin\": {\n        \"bytes\": 2048,\n        \"sha256\": \"b4dc0b8f14671df5c0278ea1c58a92099a3b8a5cb50e6da4cec6677ff98eb3d5\"\n      },\n      \"A_Probe.bin\": {\n        \"bytes\": 68,\n        \"sha256\": \"9b8e95810fe33a085f2be2e58f082de9915cb3d7f66324d01145e4c211c2efcb\"\n      },\n      \"A_TxWave.bin\": {\n        \"bytes\": 660,\n        \"sha256\": \"db99ee64fb4185fcb98f1fc21520774dc0c0bb995b4c5bdf88cdce1eb86dd2e3\"\n      },\n      \"B_PRF.bin\": {\n        \"bytes\": 388,\n        \"sha256\": \"9159defd1ef064c0050ec94ce88936c016e86e22e90e682521672edd53d1e5c3\"\n      },\n      \"A_BF.bin\": {\n        \"bytes\": 44,\n        \"sha256\": \"28ed79893f9f224a7c1a29e2288491cb3bf224bbb3851d308c50e799b48dbdee\"\n      },\n      \"B_TxControl.bin\": {\n        \"bytes\": 1024,\n        \"sha256\": \"d13415f8b87474cead27b7454c4549680a71d46e12ea7865d05828ad08dac4a7\"\n      },\n      \"B_DynamicFilter.bin\": {\n        \"bytes\": 43084,\n        \"sha256\": \"81ef617556bf5e84350bf5b59b987685116412e871e3130e88cfb15179e6435b\"\n      },\n      \"B_LPF.bin\": {\n        \"bytes\": 256,\n        \"sha256\": \"69f3e66397510c09a5b68fecfe3113120b1248db880f89c643b86728759e69cc\"\n      },\n      \"A_Up4Coef.bin\": {\n        \"bytes\": 364,\n        \"sha256\": \"5534946090a6eff3789333d3efe7d11eefc2ece88cc3fd4a1c24780d5030e6a3\"\n      }\n    },\n    \"Uro\": {\n      \"A_ADC.bin\": {\n        \"bytes\": 20,\n        \"sha256\": \"4e073dd1aabcd1bad16622ad1ca1182ad08e59fa1db5359e25b6b3f089307e7e\"\n      },\n      \"A_ATGC.bin\": {\n        \"bytes\": 1024,\n        \"sha256\": \"3d6237ef3a139581de03cfc0db5b5c2c5519b48e9afeb6499fdf75c0892c8021\"\n      },\n      \"A_Apo.bin\": {\n        \"bytes\": 2048,\n        \"sha256\": \"dcde5582467b51f7c82e40bc6306e13d59e71a11bacbd1d808071a208c6fb149\"\n      },\n      \"A_ApoComp.bin\": {\n        \"bytes\": 2048,\n        \"sha256\": \"b4dc0b8f14671df5c0278ea1c58a92099a3b8a5cb50e6da4cec6677ff98eb3d5\"\n      },\n      \"A_Probe.bin\": {\n        \"bytes\": 68,\n        \"sha256\": \"9b8e95810fe33a085f2be2e58f082de9915cb3d7f66324d01145e4c211c2efcb\"\n      },\n      \"A_TxWave.bin\": {\n        \"bytes\": 660,\n        \"sha256\": \"db99ee64fb4185fcb98f1fc21520774dc0c0bb995b4c5bdf88cdce1eb86dd2e3\"\n      },\n      \"B_PRF.bin\": {\n        \"bytes\": 388,\n        \"sha256\": \"9159defd1ef064c0050ec94ce88936c016e86e22e90e682521672edd53d1e5c3\"\n      },\n      \"A_BF.bin\": {\n        \"bytes\": 44,\n        \"sha256\": \"28ed79893f9f224a7c1a29e2288491cb3bf224bbb3851d308c50e799b48dbdee\"\n      },\n      \"B_TxControl.bin\": {\n        \"bytes\": 1024,\n        \"sha256\": \"d13415f8b87474cead27b7454c4549680a71d46e12ea7865d05828ad08dac4a7\"\n      },\n      \"B_DynamicFilter.bin\": {\n        \"bytes\": 43084,\n        \"sha256\": \"81ef617556bf5e84350bf5b59b987685116412e871e3130e88cfb15179e6435b\"\n      },\n      \"B_LPF.bin\": {\n        \"bytes\": 256,\n        \"sha256\": \"69f3e66397510c09a5b68fecfe3113120b1248db880f89c643b86728759e69cc\"\n      },\n      \"A_Up4Coef.bin\": {\n        \"bytes\": 364,\n        \"sha256\": \"5534946090a6eff3789333d3efe7d11eefc2ece88cc3fd4a1c24780d5030e6a3\"\n      }\n    }\n  },\n  \"hv_files\": {\n    \"0.coe\": {\n      \"bytes\": 16894,\n      \"sha256\": \"e01977406729c1c74d8af7457fa641e29ac252266487e8ba0eb14455cc1d8d18\"\n    }\n  }\n}\n"
      },
      {
        "path": "components/ultrasound/convex-decoder/1.0.0/src/known_convex_sri_layout.json",
        "sha256": "4cafbc69a11b93c19d04d390aa1989d5a241df0d928d027ebe7632bf1921f396",
        "text": "{\n  \"schema_version\": \"convex-sri-static-layout-v1\",\n  \"images\": [\n    {\n      \"slot\": \"0x308\",\n      \"width_expression\": \"2*P\",\n      \"height\": 320,\n      \"General_width\": 128,\n      \"channel_order\": \"CL_RGBA\",\n      \"channel_type\": \"CL_UNORM_INT8\",\n      \"components\": 4,\n      \"component_bytes\": 1,\n      \"General_bytes\": 163840,\n      \"fill_region_equals_allocation\": true\n    },\n    {\n      \"slot\": \"0x310\",\n      \"width_expression\": \"2*P\",\n      \"height\": 320,\n      \"General_width\": 128,\n      \"channel_order\": \"CL_RGBA\",\n      \"channel_type\": \"CL_UNORM_INT8\",\n      \"components\": 4,\n      \"component_bytes\": 1,\n      \"General_bytes\": 163840,\n      \"fill_region_equals_allocation\": true\n    },\n    {\n      \"slot\": \"0x318\",\n      \"width_expression\": \"2*P\",\n      \"height\": 320,\n      \"General_width\": 128,\n      \"channel_order\": \"CL_RGBA\",\n      \"channel_type\": \"CL_UNORM_INT8\",\n      \"components\": 4,\n      \"component_bytes\": 1,\n      \"General_bytes\": 163840,\n      \"fill_region_equals_allocation\": true\n    },\n    {\n      \"slot\": \"0x320\",\n      \"width_expression\": \"2*P\",\n      \"height\": 320,\n      \"General_width\": 128,\n      \"channel_order\": \"CL_RGBA\",\n      \"channel_type\": \"CL_UNORM_INT8\",\n      \"components\": 4,\n      \"component_bytes\": 1,\n      \"General_bytes\": 163840,\n      \"fill_region_equals_allocation\": true\n    },\n    {\n      \"slot\": \"0x328\",\n      \"width_expression\": \"2*P\",\n      \"height\": 320,\n      \"General_width\": 128,\n      \"channel_order\": \"CL_RGBA\",\n      \"channel_type\": \"CL_UNORM_INT8\",\n      \"components\": 4,\n      \"component_bytes\": 1,\n      \"General_bytes\": 163840,\n      \"fill_region_equals_allocation\": true\n    },\n    {\n      \"slot\": \"0x330\",\n      \"width_expression\": \"2*P\",\n      \"height\": 320,\n      \"General_width\": 128,\n      \"channel_order\": \"CL_RGBA\",\n      \"channel_type\": \"CL_UNORM_INT8\",\n      \"components\": 4,\n      \"component_bytes\": 1,\n      \"General_bytes\": 163840,\n      \"fill_region_equals_allocation\": true\n    },\n    {\n      \"slot\": \"0x338\",\n      \"width_expression\": \"2*P\",\n      \"height\": 320,\n      \"General_width\": 128,\n      \"channel_order\": \"CL_RGBA\",\n      \"channel_type\": \"CL_UNORM_INT8\",\n      \"components\": 4,\n      \"component_bytes\": 1,\n      \"General_bytes\": 163840,\n      \"fill_region_equals_allocation\": true\n    },\n    {\n      \"slot\": \"0x340\",\n      \"width_expression\": \"2*P\",\n      \"height\": 320,\n      \"General_width\": 128,\n      \"channel_order\": \"CL_RGBA\",\n      \"channel_type\": \"CL_SNORM_INT8\",\n      \"components\": 4,\n      \"component_bytes\": 1,\n      \"General_bytes\": 163840,\n      \"fill_region_equals_allocation\": true\n    },\n    {\n      \"slot\": \"0x348\",\n      \"width_expression\": \"2*P\",\n      \"height\": 320,\n      \"General_width\": 128,\n      \"channel_order\": \"CL_RGBA\",\n      \"channel_type\": \"CL_SNORM_INT8\",\n      \"components\": 4,\n      \"component_bytes\": 1,\n      \"General_bytes\": 163840,\n      \"fill_region_equals_allocation\": true\n    },\n    {\n      \"slot\": \"0x350\",\n      \"width_expression\": \"2*P\",\n      \"height\": 320,\n      \"General_width\": 128,\n      \"channel_order\": \"CL_RGBA\",\n      \"channel_type\": \"CL_UNORM_INT8\",\n      \"components\": 4,\n      \"component_bytes\": 1,\n      \"General_bytes\": 163840,\n      \"fill_region_equals_allocation\": true\n    },\n    {\n      \"slot\": \"0x358\",\n      \"width_expression\": \"P\",\n      \"height\": 160,\n      \"General_width\": 64,\n      \"channel_order\": \"CL_RGBA\",\n      \"channel_type\": \"CL_UNORM_INT8\",\n      \"components\": 4,\n      \"component_bytes\": 1,\n      \"General_bytes\": 40960,\n      \"fill_region_equals_allocation\": true\n    },\n    {\n      \"slot\": \"0x360\",\n      \"width_expression\": \"2*P\",\n      \"height\": 320,\n      \"General_width\": 128,\n      \"channel_order\": \"CL_RGBA\",\n      \"channel_type\": \"CL_SNORM_INT8\",\n      \"components\": 4,\n      \"component_bytes\": 1,\n      \"General_bytes\": 163840,\n      \"fill_region_equals_allocation\": true\n    },\n    {\n      \"slot\": \"0x368\",\n      \"width_expression\": \"2*P\",\n      \"height\": 320,\n      \"General_width\": 128,\n      \"channel_order\": \"CL_RGBA\",\n      \"channel_type\": \"CL_SNORM_INT8\",\n      \"components\": 4,\n      \"component_bytes\": 1,\n      \"General_bytes\": 163840,\n      \"fill_region_equals_allocation\": true\n    },\n    {\n      \"slot\": \"0x370\",\n      \"width_expression\": \"P\",\n      \"height\": 160,\n      \"General_width\": 64,\n      \"channel_order\": \"CL_RGBA\",\n      \"channel_type\": \"CL_SNORM_INT8\",\n      \"components\": 4,\n      \"component_bytes\": 1,\n      \"General_bytes\": 40960,\n      \"fill_region_equals_allocation\": true\n    },\n    {\n      \"slot\": \"0x378\",\n      \"width_expression\": \"P\",\n      \"height\": 160,\n      \"General_width\": 64,\n      \"channel_order\": \"CL_RGBA\",\n      \"channel_type\": \"CL_SNORM_INT8\",\n      \"components\": 4,\n      \"component_bytes\": 1,\n      \"General_bytes\": 40960,\n      \"fill_region_equals_allocation\": true\n    },\n    {\n      \"slot\": \"0x380\",\n      \"width_expression\": \"P\",\n      \"height\": 160,\n      \"General_width\": 64,\n      \"channel_order\": \"CL_RGBA\",\n      \"channel_type\": \"CL_SNORM_INT8\",\n      \"components\": 4,\n      \"component_bytes\": 1,\n      \"General_bytes\": 40960,\n      \"fill_region_equals_allocation\": true\n    },\n    {\n      \"slot\": \"0x388\",\n      \"width_expression\": \"P\",\n      \"height\": 160,\n      \"General_width\": 64,\n      \"channel_order\": \"CL_RGBA\",\n      \"channel_type\": \"CL_SNORM_INT8\",\n      \"components\": 4,\n      \"component_bytes\": 1,\n      \"General_bytes\": 40960,\n      \"fill_region_equals_allocation\": true\n    },\n    {\n      \"slot\": \"0x390\",\n      \"width_expression\": \"P\",\n      \"height\": 160,\n      \"General_width\": 64,\n      \"channel_order\": \"CL_RGBA\",\n      \"channel_type\": \"CL_UNORM_INT8\",\n      \"components\": 4,\n      \"component_bytes\": 1,\n      \"General_bytes\": 40960,\n      \"fill_region_equals_allocation\": true\n    },\n    {\n      \"slot\": \"0x398\",\n      \"width_expression\": \"P\",\n      \"height\": 160,\n      \"General_width\": 64,\n      \"channel_order\": \"CL_RGBA\",\n      \"channel_type\": \"CL_UNORM_INT8\",\n      \"components\": 4,\n      \"component_bytes\": 1,\n      \"General_bytes\": 40960,\n      \"fill_region_equals_allocation\": true\n    },\n    {\n      \"slot\": \"0x3a0\",\n      \"width_expression\": \"P\",\n      \"height\": 160,\n      \"General_width\": 64,\n      \"channel_order\": \"CL_RGBA\",\n      \"channel_type\": \"CL_UNORM_INT8\",\n      \"components\": 4,\n      \"component_bytes\": 1,\n      \"General_bytes\": 40960,\n      \"fill_region_equals_allocation\": true\n    },\n    {\n      \"slot\": \"0x3a8\",\n      \"width_expression\": \"P\",\n      \"height\": 160,\n      \"General_width\": 64,\n      \"channel_order\": \"CL_RGBA\",\n      \"channel_type\": \"CL_SIGNED_INT8\",\n      \"components\": 4,\n      \"component_bytes\": 1,\n      \"General_bytes\": 40960,\n      \"fill_region_equals_allocation\": true\n    },\n    {\n      \"slot\": \"0x3b0\",\n      \"width_expression\": \"P\",\n      \"height\": 160,\n      \"General_width\": 64,\n      \"channel_order\": \"CL_RGBA\",\n      \"channel_type\": \"CL_UNORM_INT8\",\n      \"components\": 4,\n      \"component_bytes\": 1,\n      \"General_bytes\": 40960,\n      \"fill_region_equals_allocation\": true\n    },\n    {\n      \"slot\": \"0x3b8\",\n      \"width_expression\": \"P\",\n      \"height\": 160,\n      \"General_width\": 64,\n      \"channel_order\": \"CL_RGBA\",\n      \"channel_type\": \"CL_UNORM_INT8\",\n      \"components\": 4,\n      \"component_bytes\": 1,\n      \"General_bytes\": 40960,\n      \"fill_region_equals_allocation\": true\n    },\n    {\n      \"slot\": \"0x3c8\",\n      \"width_expression\": \"P\",\n      \"height\": 160,\n      \"General_width\": 64,\n      \"channel_order\": \"CL_RGBA\",\n      \"channel_type\": \"CL_UNORM_INT8\",\n      \"components\": 4,\n      \"component_bytes\": 1,\n      \"General_bytes\": 40960,\n      \"fill_region_equals_allocation\": true\n    },\n    {\n      \"slot\": \"0x3d0\",\n      \"width_expression\": \"2*P\",\n      \"height\": 320,\n      \"General_width\": 128,\n      \"channel_order\": \"CL_RGBA\",\n      \"channel_type\": \"CL_UNORM_INT8\",\n      \"components\": 4,\n      \"component_bytes\": 1,\n      \"General_bytes\": 163840,\n      \"fill_region_equals_allocation\": true\n    },\n    {\n      \"slot\": \"0x3d8\",\n      \"width_expression\": \"2*P\",\n      \"height\": 320,\n      \"General_width\": 128,\n      \"channel_order\": \"CL_RGBA\",\n      \"channel_type\": \"CL_SNORM_INT8\",\n      \"components\": 4,\n      \"component_bytes\": 1,\n      \"General_bytes\": 163840,\n      \"fill_region_equals_allocation\": true\n    },\n    {\n      \"slot\": \"0x3e0\",\n      \"width_expression\": \"2*P\",\n      \"height\": 320,\n      \"General_width\": 128,\n      \"channel_order\": \"CL_RGBA\",\n      \"channel_type\": \"CL_SNORM_INT8\",\n      \"components\": 4,\n      \"component_bytes\": 1,\n      \"General_bytes\": 163840,\n      \"fill_region_equals_allocation\": true\n    },\n    {\n      \"slot\": \"0x3e8\",\n      \"width_expression\": \"2*P\",\n      \"height\": 320,\n      \"General_width\": 128,\n      \"channel_order\": \"CL_RGBA\",\n      \"channel_type\": \"CL_SNORM_INT8\",\n      \"components\": 4,\n      \"component_bytes\": 1,\n      \"General_bytes\": 163840,\n      \"fill_region_equals_allocation\": true\n    },\n    {\n      \"slot\": \"0x3f0\",\n      \"width_expression\": \"2*P\",\n      \"height\": 320,\n      \"General_width\": 128,\n      \"channel_order\": \"CL_RGBA\",\n      \"channel_type\": \"CL_SNORM_INT8\",\n      \"components\": 4,\n      \"component_bytes\": 1,\n      \"General_bytes\": 163840,\n      \"fill_region_equals_allocation\": true\n    },\n    {\n      \"slot\": \"0x3f8\",\n      \"width_expression\": \"2*P\",\n      \"height\": 320,\n      \"General_width\": 128,\n      \"channel_order\": \"CL_RGBA\",\n      \"channel_type\": \"CL_UNORM_INT8\",\n      \"components\": 4,\n      \"component_bytes\": 1,\n      \"General_bytes\": 163840,\n      \"fill_region_equals_allocation\": true\n    },\n    {\n      \"slot\": \"0x400\",\n      \"width_expression\": \"2*P\",\n      \"height\": 320,\n      \"General_width\": 128,\n      \"channel_order\": \"CL_RGBA\",\n      \"channel_type\": \"CL_UNORM_INT8\",\n      \"components\": 4,\n      \"component_bytes\": 1,\n      \"General_bytes\": 163840,\n      \"fill_region_equals_allocation\": true\n    },\n    {\n      \"slot\": \"0x408\",\n      \"width_expression\": \"2*P\",\n      \"height\": 320,\n      \"General_width\": 128,\n      \"channel_order\": \"CL_RGBA\",\n      \"channel_type\": \"CL_UNORM_INT8\",\n      \"components\": 4,\n      \"component_bytes\": 1,\n      \"General_bytes\": 163840,\n      \"fill_region_equals_allocation\": true\n    },\n    {\n      \"slot\": \"0x410\",\n      \"width_expression\": \"2*P\",\n      \"height\": 320,\n      \"General_width\": 128,\n      \"channel_order\": \"CL_RGBA\",\n      \"channel_type\": \"CL_SIGNED_INT8\",\n      \"components\": 4,\n      \"component_bytes\": 1,\n      \"General_bytes\": 163840,\n      \"fill_region_equals_allocation\": true\n    },\n    {\n      \"slot\": \"0x418\",\n      \"width_expression\": \"2*P\",\n      \"height\": 320,\n      \"General_width\": 128,\n      \"channel_order\": \"CL_RGBA\",\n      \"channel_type\": \"CL_UNORM_INT8\",\n      \"components\": 4,\n      \"component_bytes\": 1,\n      \"General_bytes\": 163840,\n      \"fill_region_equals_allocation\": true\n    },\n    {\n      \"slot\": \"0x420\",\n      \"width_expression\": \"2*P\",\n      \"height\": 320,\n      \"General_width\": 128,\n      \"channel_order\": \"CL_RGBA\",\n      \"channel_type\": \"CL_UNORM_INT8\",\n      \"components\": 4,\n      \"component_bytes\": 1,\n      \"General_bytes\": 163840,\n      \"fill_region_equals_allocation\": true\n    },\n    {\n      \"slot\": \"0x430\",\n      \"width_expression\": \"2*P\",\n      \"height\": 320,\n      \"General_width\": 128,\n      \"channel_order\": \"CL_RGBA\",\n      \"channel_type\": \"CL_UNORM_INT8\",\n      \"components\": 4,\n      \"component_bytes\": 1,\n      \"General_bytes\": 163840,\n      \"fill_region_equals_allocation\": true\n    },\n    {\n      \"slot\": \"0x438\",\n      \"width_expression\": \"2*P\",\n      \"height\": 320,\n      \"General_width\": 128,\n      \"channel_order\": \"CL_RGBA\",\n      \"channel_type\": \"CL_SNORM_INT8\",\n      \"components\": 4,\n      \"component_bytes\": 1,\n      \"General_bytes\": 163840,\n      \"fill_region_equals_allocation\": true\n    },\n    {\n      \"slot\": \"0x538\",\n      \"width_expression\": \"2*P\",\n      \"height\": 320,\n      \"General_width\": 128,\n      \"channel_order\": \"CL_RGBA\",\n      \"channel_type\": \"CL_UNORM_INT8\",\n      \"components\": 4,\n      \"component_bytes\": 1,\n      \"General_bytes\": 163840,\n      \"fill_region_equals_allocation\": true\n    },\n    {\n      \"slot\": \"0x540\",\n      \"width_expression\": \"P\",\n      \"height\": 160,\n      \"General_width\": 64,\n      \"channel_order\": \"CL_RGBA\",\n      \"channel_type\": \"CL_UNORM_INT8\",\n      \"components\": 4,\n      \"component_bytes\": 1,\n      \"General_bytes\": 40960,\n      \"fill_region_equals_allocation\": true\n    },\n    {\n      \"slot\": \"0x528\",\n      \"width_expression\": \"P\",\n      \"height\": 160,\n      \"General_width\": 64,\n      \"channel_order\": \"CL_RGBA\",\n      \"channel_type\": \"CL_UNORM_INT8\",\n      \"components\": 4,\n      \"component_bytes\": 1,\n      \"General_bytes\": 40960,\n      \"fill_region_equals_allocation\": true\n    },\n    {\n      \"slot\": \"0x530\",\n      \"width_expression\": \"P\",\n      \"height\": 160,\n      \"General_width\": 64,\n      \"channel_order\": \"CL_RGBA\",\n      \"channel_type\": \"CL_UNORM_INT8\",\n      \"components\": 4,\n      \"component_bytes\": 1,\n      \"General_bytes\": 40960,\n      \"fill_region_equals_allocation\": true\n    },\n    {\n      \"slot\": \"0x548\",\n      \"width_expression\": \"2*P\",\n      \"height\": 320,\n      \"General_width\": 128,\n      \"channel_order\": \"CL_RGBA\",\n      \"channel_type\": \"CL_UNORM_INT8\",\n      \"components\": 4,\n      \"component_bytes\": 1,\n      \"General_bytes\": 163840,\n      \"fill_region_equals_allocation\": true\n    }\n  ],\n  \"kernels\": [\n    {\n      \"slot\": \"0x220\",\n      \"name\": \"LOG_Reshape\",\n      \"bound_arguments\": [\n        {\n          \"kernel_slot\": \"0x220\",\n          \"kernel\": \"LOG_Reshape\",\n          \"argument\": 0,\n          \"bytes\": 8,\n          \"source\": \"external_BFSP_image_pointer_reference\",\n          \"condition\": \"always\"\n        },\n        {\n          \"kernel_slot\": \"0x220\",\n          \"kernel\": \"LOG_Reshape\",\n          \"argument\": 1,\n          \"bytes\": 8,\n          \"source\": \"this+0x308\",\n          \"condition\": \"always\"\n        }\n      ],\n      \"dispatched_by_Process\": true,\n      \"global_dimensions_slot\": \"0x440\",\n      \"local_dimensions_slot\": \"0x4d0\",\n      \"condition\": \"always\",\n      \"dimensions\": 2\n    },\n    {\n      \"slot\": \"0x228\",\n      \"name\": \"ReduceDarkHole_V\",\n      \"bound_arguments\": [\n        {\n          \"kernel_slot\": \"0x228\",\n          \"kernel\": \"ReduceDarkHole_V\",\n          \"argument\": 0,\n          \"bytes\": 8,\n          \"source\": \"this+0x308\",\n          \"condition\": \"always\"\n        },\n        {\n          \"kernel_slot\": \"0x228\",\n          \"kernel\": \"ReduceDarkHole_V\",\n          \"argument\": 1,\n          \"bytes\": 8,\n          \"source\": \"this+0x310\",\n          \"condition\": \"always\"\n        }\n      ],\n      \"dispatched_by_Process\": true,\n      \"global_dimensions_slot\": \"0x440\",\n      \"local_dimensions_slot\": \"0x4d0\",\n      \"condition\": \"level>0\",\n      \"dimensions\": 2\n    },\n    {\n      \"slot\": \"0x230\",\n      \"name\": \"ReduceDarkHole_H\",\n      \"bound_arguments\": [\n        {\n          \"kernel_slot\": \"0x230\",\n          \"kernel\": \"ReduceDarkHole_H\",\n          \"argument\": 0,\n          \"bytes\": 8,\n          \"source\": \"this+0x310\",\n          \"condition\": \"always\"\n        },\n        {\n          \"kernel_slot\": \"0x230\",\n          \"kernel\": \"ReduceDarkHole_H\",\n          \"argument\": 1,\n          \"bytes\": 8,\n          \"source\": \"this+0x318\",\n          \"condition\": \"always\"\n        },\n        {\n          \"kernel_slot\": \"0x230\",\n          \"kernel\": \"ReduceDarkHole_H\",\n          \"argument\": 2,\n          \"bytes\": 8,\n          \"source\": \"external_BFSP_RDH_pointer_reference\",\n          \"condition\": \"always\"\n        }\n      ],\n      \"dispatched_by_Process\": true,\n      \"global_dimensions_slot\": \"0x440\",\n      \"local_dimensions_slot\": \"0x4d0\",\n      \"condition\": \"level>0\",\n      \"dimensions\": 2\n    },\n    {\n      \"slot\": \"0x238\",\n      \"name\": \"SRI_DownSamplingN_smoothing\",\n      \"bound_arguments\": [\n        {\n          \"kernel_slot\": \"0x238\",\n          \"kernel\": \"SRI_DownSamplingN_smoothing\",\n          \"argument\": 0,\n          \"bytes\": 8,\n          \"source\": \"this+0x318\",\n          \"condition\": \"always\"\n        },\n        {\n          \"kernel_slot\": \"0x238\",\n          \"kernel\": \"SRI_DownSamplingN_smoothing\",\n          \"argument\": 1,\n          \"bytes\": 8,\n          \"source\": \"this+0x320\",\n          \"condition\": \"always\"\n        }\n      ],\n      \"dispatched_by_Process\": true,\n      \"global_dimensions_slot\": \"0x440\",\n      \"local_dimensions_slot\": \"0x4e0\",\n      \"condition\": \"level>0 and N!=1\",\n      \"dimensions\": 2\n    },\n    {\n      \"slot\": \"0x240\",\n      \"name\": \"SRI_DownSamplingN\",\n      \"bound_arguments\": [\n        {\n          \"kernel_slot\": \"0x240\",\n          \"kernel\": \"SRI_DownSamplingN\",\n          \"argument\": 0,\n          \"bytes\": 8,\n          \"source\": \"this+0x320\",\n          \"condition\": \"always\"\n        },\n        {\n          \"kernel_slot\": \"0x240\",\n          \"kernel\": \"SRI_DownSamplingN\",\n          \"argument\": 1,\n          \"bytes\": 8,\n          \"source\": \"this+0x328\",\n          \"condition\": \"always\"\n        },\n        {\n          \"kernel_slot\": \"0x240\",\n          \"kernel\": \"SRI_DownSamplingN\",\n          \"argument\": 2,\n          \"bytes\": 8,\n          \"source\": \"this+0x330\",\n          \"condition\": \"always\"\n        },\n        {\n          \"kernel_slot\": \"0x240\",\n          \"kernel\": \"SRI_DownSamplingN\",\n          \"argument\": 3,\n          \"bytes\": 8,\n          \"source\": \"this+0x338\",\n          \"condition\": \"always\"\n        },\n        {\n          \"kernel_slot\": \"0x240\",\n          \"kernel\": \"SRI_DownSamplingN\",\n          \"argument\": 4,\n          \"bytes\": 4,\n          \"source\": \"this+0x190\",\n          \"condition\": \"always\"\n        }\n      ],\n      \"dispatched_by_Process\": true,\n      \"global_dimensions_slot\": \"0x450\",\n      \"local_dimensions_slot\": \"0x4d0\",\n      \"condition\": \"level>0 and N!=1\",\n      \"dimensions\": 2\n    },\n    {\n      \"slot\": \"0x248\",\n      \"name\": \"SRI_DownSamplingN_Reshape\",\n      \"bound_arguments\": [\n        {\n          \"kernel_slot\": \"0x248\",\n          \"kernel\": \"SRI_DownSamplingN_Reshape\",\n          \"argument\": 0,\n          \"bytes\": 8,\n          \"source\": \"this+0x330\",\n          \"condition\": \"always\"\n        },\n        {\n          \"kernel_slot\": \"0x248\",\n          \"kernel\": \"SRI_DownSamplingN_Reshape\",\n          \"argument\": 1,\n          \"bytes\": 8,\n          \"source\": \"this+0x328\",\n          \"condition\": \"always\"\n        },\n        {\n          \"kernel_slot\": \"0x248\",\n          \"kernel\": \"SRI_DownSamplingN_Reshape\",\n          \"argument\": 2,\n          \"bytes\": 4,\n          \"source\": \"this+0x190\",\n          \"condition\": \"always\"\n        }\n      ],\n      \"dispatched_by_Process\": true,\n      \"global_dimensions_slot\": \"0x4b0\",\n      \"local_dimensions_slot\": \"0x4e0\",\n      \"condition\": \"level>0 and N!=1\",\n      \"dimensions\": 2\n    },\n    {\n      \"slot\": \"0x250\",\n      \"name\": \"SRI_UpSamplingN\",\n      \"bound_arguments\": [\n        {\n          \"kernel_slot\": \"0x250\",\n          \"kernel\": \"SRI_UpSamplingN\",\n          \"argument\": 0,\n          \"bytes\": 8,\n          \"source\": \"this+0x318\",\n          \"condition\": \"always\"\n        },\n        {\n          \"kernel_slot\": \"0x250\",\n          \"kernel\": \"SRI_UpSamplingN\",\n          \"argument\": 1,\n          \"bytes\": 8,\n          \"source\": \"this+0x338\",\n          \"condition\": \"always\"\n        },\n        {\n          \"kernel_slot\": \"0x250\",\n          \"kernel\": \"SRI_UpSamplingN\",\n          \"argument\": 2,\n          \"bytes\": 8,\n          \"source\": \"this+0x340\",\n          \"condition\": \"always\"\n        },\n        {\n          \"kernel_slot\": \"0x250\",\n          \"kernel\": \"SRI_UpSamplingN\",\n          \"argument\": 3,\n          \"bytes\": 4,\n          \"source\": \"this+0x190\",\n          \"condition\": \"always\"\n        }\n      ],\n      \"dispatched_by_Process\": true,\n      \"global_dimensions_slot\": \"0x440\",\n      \"local_dimensions_slot\": \"0x4e0\",\n      \"condition\": \"level>0 and N!=1\",\n      \"dimensions\": 2\n    },\n    {\n      \"slot\": \"0x258\",\n      \"name\": \"SRI_HF_N_Smoothing\",\n      \"bound_arguments\": [\n        {\n          \"kernel_slot\": \"0x258\",\n          \"kernel\": \"SRI_HF_N_Smoothing\",\n          \"argument\": 0,\n          \"bytes\": 8,\n          \"source\": \"this+0x340\",\n          \"condition\": \"always\"\n        },\n        {\n          \"kernel_slot\": \"0x258\",\n          \"kernel\": \"SRI_HF_N_Smoothing\",\n          \"argument\": 1,\n          \"bytes\": 8,\n          \"source\": \"this+0x348\",\n          \"condition\": \"always\"\n        }\n      ],\n      \"dispatched_by_Process\": false\n    },\n    {\n      \"slot\": \"0x260\",\n      \"name\": \"SRI_UpSamplingN_final\",\n      \"bound_arguments\": [\n        {\n          \"kernel_slot\": \"0x260\",\n          \"kernel\": \"SRI_UpSamplingN_final\",\n          \"argument\": 0,\n          \"bytes\": 8,\n          \"source\": \"this+0x420\",\n          \"condition\": \"always\"\n        },\n        {\n          \"kernel_slot\": \"0x260\",\n          \"kernel\": \"SRI_UpSamplingN_final\",\n          \"argument\": 1,\n          \"bytes\": 8,\n          \"source\": \"this+0x438\",\n          \"condition\": \"always\"\n        },\n        {\n          \"kernel_slot\": \"0x260\",\n          \"kernel\": \"SRI_UpSamplingN_final\",\n          \"argument\": 2,\n          \"bytes\": 8,\n          \"source\": \"this+0x350\",\n          \"condition\": \"always\"\n        },\n        {\n          \"kernel_slot\": \"0x260\",\n          \"kernel\": \"SRI_UpSamplingN_final\",\n          \"argument\": 3,\n          \"bytes\": 4,\n          \"source\": \"this+0x190\",\n          \"condition\": \"always\"\n        },\n        {\n          \"kernel_slot\": \"0x260\",\n          \"kernel\": \"SRI_UpSamplingN_final\",\n          \"argument\": 0,\n          \"bytes\": 8,\n          \"source\": \"this+0x3d0\",\n          \"condition\": \"fine_iterations==0\"\n        },\n        {\n          \"kernel_slot\": \"0x260\",\n          \"kernel\": \"SRI_UpSamplingN_final\",\n          \"argument\": 1,\n          \"bytes\": 8,\n          \"source\": \"this+0x340\",\n          \"condition\": \"fine_iterations==0\"\n        }\n      ],\n      \"dispatched_by_Process\": true,\n      \"global_dimensions_slot\": \"runtime-final\",\n      \"local_dimensions_slot\": \"0x4d0\",\n      \"condition\": \"level>0\",\n      \"dimensions\": 2\n    },\n    {\n      \"slot\": \"0x268\",\n      \"name\": \"SRI_DownSampling\",\n      \"bound_arguments\": [\n        {\n          \"kernel_slot\": \"0x268\",\n          \"kernel\": \"SRI_DownSampling\",\n          \"argument\": 0,\n          \"bytes\": 8,\n          \"source\": \"this+0x328\",\n          \"condition\": \"always\"\n        },\n        {\n          \"kernel_slot\": \"0x268\",\n          \"kernel\": \"SRI_DownSampling\",\n          \"argument\": 1,\n          \"bytes\": 8,\n          \"source\": \"this+0x358\",\n          \"condition\": \"always\"\n        },\n        {\n          \"kernel_slot\": \"0x268\",\n          \"kernel\": \"SRI_DownSampling\",\n          \"argument\": 2,\n          \"bytes\": 8,\n          \"source\": \"this+0x3b0\",\n          \"condition\": \"always\"\n        }\n      ],\n      \"dispatched_by_Process\": true,\n      \"global_dimensions_slot\": \"0x470\",\n      \"local_dimensions_slot\": \"0x4e0\",\n      \"condition\": \"level>0\",\n      \"dimensions\": 2\n    },\n    {\n      \"slot\": \"0x270\",\n      \"name\": \"SRI_UpSampling\",\n      \"bound_arguments\": [\n        {\n          \"kernel_slot\": \"0x270\",\n          \"kernel\": \"SRI_UpSampling\",\n          \"argument\": 0,\n          \"bytes\": 8,\n          \"source\": \"this+0x328\",\n          \"condition\": \"always\"\n        },\n        {\n          \"kernel_slot\": \"0x270\",\n          \"kernel\": \"SRI_UpSampling\",\n          \"argument\": 1,\n          \"bytes\": 8,\n          \"source\": \"this+0x358\",\n          \"condition\": \"always\"\n        },\n        {\n          \"kernel_slot\": \"0x270\",\n          \"kernel\": \"SRI_UpSampling\",\n          \"argument\": 2,\n          \"bytes\": 8,\n          \"source\": \"this+0x360\",\n          \"condition\": \"always\"\n        }\n      ],\n      \"dispatched_by_Process\": true,\n      \"global_dimensions_slot\": \"0x470\",\n      \"local_dimensions_slot\": \"0x4e0\",\n      \"condition\": \"level>0\",\n      \"dimensions\": 2\n    },\n    {\n      \"slot\": \"0x278\",\n      \"name\": \"SRI_HF_Smoothing\",\n      \"bound_arguments\": [\n        {\n          \"kernel_slot\": \"0x278\",\n          \"kernel\": \"SRI_HF_Smoothing\",\n          \"argument\": 0,\n          \"bytes\": 8,\n          \"source\": \"this+0x360\",\n          \"condition\": \"always\"\n        },\n        {\n          \"kernel_slot\": \"0x278\",\n          \"kernel\": \"SRI_HF_Smoothing\",\n          \"argument\": 1,\n          \"bytes\": 8,\n          \"source\": \"this+0x368\",\n          \"condition\": \"always\"\n        }\n      ],\n      \"dispatched_by_Process\": false\n    },\n    {\n      \"slot\": \"0x280\",\n      \"name\": \"SRI_Gradient\",\n      \"bound_arguments\": [\n        {\n          \"kernel_slot\": \"0x280\",\n          \"kernel\": \"SRI_Gradient\",\n          \"argument\": 0,\n          \"bytes\": 8,\n          \"source\": \"this+0x358\",\n          \"condition\": \"always\"\n        },\n        {\n          \"kernel_slot\": \"0x280\",\n          \"kernel\": \"SRI_Gradient\",\n          \"argument\": 1,\n          \"bytes\": 8,\n          \"source\": \"this+0x370\",\n          \"condition\": \"always\"\n        },\n        {\n          \"kernel_slot\": \"0x280\",\n          \"kernel\": \"SRI_Gradient\",\n          \"argument\": 2,\n          \"bytes\": 8,\n          \"source\": \"this+0x378\",\n          \"condition\": \"always\"\n        }\n      ],\n      \"dispatched_by_Process\": true,\n      \"global_dimensions_slot\": \"0x470\",\n      \"local_dimensions_slot\": \"0x4e0\",\n      \"condition\": \"level>0\",\n      \"dimensions\": 2\n    },\n    {\n      \"slot\": \"0x288\",\n      \"name\": \"SRI_Gradient_Size_Direction\",\n      \"bound_arguments\": [\n        {\n          \"kernel_slot\": \"0x288\",\n          \"kernel\": \"SRI_Gradient_Size_Direction\",\n          \"argument\": 0,\n          \"bytes\": 8,\n          \"source\": \"this+0x370\",\n          \"condition\": \"always\"\n        },\n        {\n          \"kernel_slot\": \"0x288\",\n          \"kernel\": \"SRI_Gradient_Size_Direction\",\n          \"argument\": 1,\n          \"bytes\": 8,\n          \"source\": \"this+0x378\",\n          \"condition\": \"always\"\n        },\n        {\n          \"kernel_slot\": \"0x288\",\n          \"kernel\": \"SRI_Gradient_Size_Direction\",\n          \"argument\": 2,\n          \"bytes\": 8,\n          \"source\": \"this+0x380\",\n          \"condition\": \"always\"\n        },\n        {\n          \"kernel_slot\": \"0x288\",\n          \"kernel\": \"SRI_Gradient_Size_Direction\",\n          \"argument\": 3,\n          \"bytes\": 8,\n          \"source\": \"this+0x388\",\n          \"condition\": \"always\"\n        }\n      ],\n      \"dispatched_by_Process\": true,\n      \"global_dimensions_slot\": \"0x470\",\n      \"local_dimensions_slot\": \"0x4e0\",\n      \"condition\": \"level>0\",\n      \"dimensions\": 2\n    },\n    {\n      \"slot\": \"0x290\",\n      \"name\": \"SRI_HistogramStatistic\",\n      \"bound_arguments\": [\n        {\n          \"kernel_slot\": \"0x290\",\n          \"kernel\": \"SRI_HistogramStatistic\",\n          \"argument\": 0,\n          \"bytes\": 8,\n          \"source\": \"this+0x380\",\n          \"condition\": \"always\"\n        },\n        {\n          \"kernel_slot\": \"0x290\",\n          \"kernel\": \"SRI_HistogramStatistic\",\n          \"argument\": 1,\n          \"bytes\": 8,\n          \"source\": \"this+0x390\",\n          \"condition\": \"always\"\n        },\n        {\n          \"kernel_slot\": \"0x290\",\n          \"kernel\": \"SRI_HistogramStatistic\",\n          \"argument\": 2,\n          \"bytes\": 4,\n          \"source\": \"this+0x168\",\n          \"condition\": \"always\"\n        },\n        {\n          \"kernel_slot\": \"0x290\",\n          \"kernel\": \"SRI_HistogramStatistic\",\n          \"argument\": 3,\n          \"bytes\": 4,\n          \"source\": \"this+0x190\",\n          \"condition\": \"always\"\n        }\n      ],\n      \"dispatched_by_Process\": true,\n      \"global_dimensions_slot\": \"0x490\",\n      \"local_dimensions_slot\": \"0x4f0\",\n      \"condition\": \"level>0\",\n      \"dimensions\": 1\n    },\n    {\n      \"slot\": \"0x298\",\n      \"name\": \"SRI_Expand\",\n      \"bound_arguments\": [\n        {\n          \"kernel_slot\": \"0x298\",\n          \"kernel\": \"SRI_Expand\",\n          \"argument\": 0,\n          \"bytes\": 8,\n          \"source\": \"this+0x390\",\n          \"condition\": \"always\"\n        },\n        {\n          \"kernel_slot\": \"0x298\",\n          \"kernel\": \"SRI_Expand\",\n          \"argument\": 1,\n          \"bytes\": 8,\n          \"source\": \"this+0x3a0\",\n          \"condition\": \"always\"\n        }\n      ],\n      \"dispatched_by_Process\": true,\n      \"global_dimensions_slot\": \"0x470\",\n      \"local_dimensions_slot\": \"0x4e0\",\n      \"condition\": \"level>0\",\n      \"dimensions\": 2\n    },\n    {\n      \"slot\": \"0x2a0\",\n      \"name\": \"SRI_Corrode\",\n      \"bound_arguments\": [\n        {\n          \"kernel_slot\": \"0x2a0\",\n          \"kernel\": \"SRI_Corrode\",\n          \"argument\": 0,\n          \"bytes\": 8,\n          \"source\": \"this+0x3a0\",\n          \"condition\": \"always\"\n        },\n        {\n          \"kernel_slot\": \"0x2a0\",\n          \"kernel\": \"SRI_Corrode\",\n          \"argument\": 1,\n          \"bytes\": 8,\n          \"source\": \"this+0x380\",\n          \"condition\": \"always\"\n        },\n        {\n          \"kernel_slot\": \"0x2a0\",\n          \"kernel\": \"SRI_Corrode\",\n          \"argument\": 2,\n          \"bytes\": 8,\n          \"source\": \"this+0x390\",\n          \"condition\": \"always\"\n        },\n        {\n          \"kernel_slot\": \"0x2a0\",\n          \"kernel\": \"SRI_Corrode\",\n          \"argument\": 3,\n          \"bytes\": 8,\n          \"source\": \"this+0x398\",\n          \"condition\": \"always\"\n        }\n      ],\n      \"dispatched_by_Process\": true,\n      \"global_dimensions_slot\": \"0x470\",\n      \"local_dimensions_slot\": \"0x4e0\",\n      \"condition\": \"level>0\",\n      \"dimensions\": 2\n    },\n    {\n      \"slot\": \"0x2a8\",\n      \"name\": \"SRI_Direction\",\n      \"bound_arguments\": [\n        {\n          \"kernel_slot\": \"0x2a8\",\n          \"kernel\": \"SRI_Direction\",\n          \"argument\": 0,\n          \"bytes\": 8,\n          \"source\": \"this+0x390\",\n          \"condition\": \"always\"\n        },\n        {\n          \"kernel_slot\": \"0x2a8\",\n          \"kernel\": \"SRI_Direction\",\n          \"argument\": 1,\n          \"bytes\": 8,\n          \"source\": \"this+0x388\",\n          \"condition\": \"always\"\n        },\n        {\n          \"kernel_slot\": \"0x2a8\",\n          \"kernel\": \"SRI_Direction\",\n          \"argument\": 2,\n          \"bytes\": 8,\n          \"source\": \"this+0x3a8\",\n          \"condition\": \"always\"\n        }\n      ],\n      \"dispatched_by_Process\": true,\n      \"global_dimensions_slot\": \"0x470\",\n      \"local_dimensions_slot\": \"0x4e0\",\n      \"condition\": \"level>0\",\n      \"dimensions\": 2\n    },\n    {\n      \"slot\": \"0x2b0\",\n      \"name\": \"SRI_DirectionalSmoothing\",\n      \"bound_arguments\": [\n        {\n          \"kernel_slot\": \"0x2b0\",\n          \"kernel\": \"SRI_DirectionalSmoothing\",\n          \"argument\": 0,\n          \"bytes\": 8,\n          \"source\": \"this+0x3b0\",\n          \"condition\": \"always\"\n        },\n        {\n          \"kernel_slot\": \"0x2b0\",\n          \"kernel\": \"SRI_DirectionalSmoothing\",\n          \"argument\": 1,\n          \"bytes\": 8,\n          \"source\": \"this+0x3a8\",\n          \"condition\": \"always\"\n        },\n        {\n          \"kernel_slot\": \"0x2b0\",\n          \"kernel\": \"SRI_DirectionalSmoothing\",\n          \"argument\": 2,\n          \"bytes\": 8,\n          \"source\": \"this+0x3c0\",\n          \"condition\": \"always\"\n        },\n        {\n          \"kernel_slot\": \"0x2b0\",\n          \"kernel\": \"SRI_DirectionalSmoothing\",\n          \"argument\": 3,\n          \"bytes\": 8,\n          \"source\": \"this+0x3b8\",\n          \"condition\": \"always\"\n        }\n      ],\n      \"dispatched_by_Process\": true,\n      \"global_dimensions_slot\": \"0x470\",\n      \"local_dimensions_slot\": \"0x4e0\",\n      \"condition\": \"level>0\",\n      \"dimensions\": 2\n    },\n    {\n      \"slot\": \"0x2b8\",\n      \"name\": \"SRI_Sharpen\",\n      \"bound_arguments\": [\n        {\n          \"kernel_slot\": \"0x2b8\",\n          \"kernel\": \"SRI_Sharpen\",\n          \"argument\": 0,\n          \"bytes\": 8,\n          \"source\": \"this+0x3b8\",\n          \"condition\": \"always\"\n        },\n        {\n          \"kernel_slot\": \"0x2b8\",\n          \"kernel\": \"SRI_Sharpen\",\n          \"argument\": 1,\n          \"bytes\": 8,\n          \"source\": \"this+0x358\",\n          \"condition\": \"always\"\n        },\n        {\n          \"kernel_slot\": \"0x2b8\",\n          \"kernel\": \"SRI_Sharpen\",\n          \"argument\": 2,\n          \"bytes\": 8,\n          \"source\": \"this+0x3a8\",\n          \"condition\": \"always\"\n        },\n        {\n          \"kernel_slot\": \"0x2b8\",\n          \"kernel\": \"SRI_Sharpen\",\n          \"argument\": 3,\n          \"bytes\": 8,\n          \"source\": \"this+0x398\",\n          \"condition\": \"always\"\n        },\n        {\n          \"kernel_slot\": \"0x2b8\",\n          \"kernel\": \"SRI_Sharpen\",\n          \"argument\": 4,\n          \"bytes\": 8,\n          \"source\": \"this+0x3c8\",\n          \"condition\": \"always\"\n        },\n        {\n          \"kernel_slot\": \"0x2b8\",\n          \"kernel\": \"SRI_Sharpen\",\n          \"argument\": 5,\n          \"bytes\": 4,\n          \"source\": \"this+0x164\",\n          \"condition\": \"always\"\n        },\n        {\n          \"kernel_slot\": \"0x2b8\",\n          \"kernel\": \"SRI_Sharpen\",\n          \"argument\": 6,\n          \"bytes\": 4,\n          \"source\": \"this+0x178\",\n          \"condition\": \"always\"\n        },\n        {\n          \"kernel_slot\": \"0x2b8\",\n          \"kernel\": \"SRI_Sharpen\",\n          \"argument\": 7,\n          \"bytes\": 4,\n          \"source\": \"address_of_local_zero_i32\",\n          \"condition\": \"always\"\n        },\n        {\n          \"kernel_slot\": \"0x2b8\",\n          \"kernel\": \"SRI_Sharpen\",\n          \"argument\": 8,\n          \"bytes\": 4,\n          \"source\": \"this+0x18c\",\n          \"condition\": \"always\"\n        }\n      ],\n      \"dispatched_by_Process\": true,\n      \"global_dimensions_slot\": \"0x470\",\n      \"local_dimensions_slot\": \"0x4e0\",\n      \"condition\": \"level>0\",\n      \"dimensions\": 2\n    },\n    {\n      \"slot\": \"0x2c0\",\n      \"name\": \"SRI_UpSampling2\",\n      \"bound_arguments\": [\n        {\n          \"kernel_slot\": \"0x2c0\",\n          \"kernel\": \"SRI_UpSampling2\",\n          \"argument\": 0,\n          \"bytes\": 8,\n          \"source\": \"this+0x3c8\",\n          \"condition\": \"always\"\n        },\n        {\n          \"kernel_slot\": \"0x2c0\",\n          \"kernel\": \"SRI_UpSampling2\",\n          \"argument\": 1,\n          \"bytes\": 8,\n          \"source\": \"this+0x360\",\n          \"condition\": \"always\"\n        },\n        {\n          \"kernel_slot\": \"0x2c0\",\n          \"kernel\": \"SRI_UpSampling2\",\n          \"argument\": 2,\n          \"bytes\": 8,\n          \"source\": \"this+0x3d0\",\n          \"condition\": \"always\"\n        },\n        {\n          \"kernel_slot\": \"0x2c0\",\n          \"kernel\": \"SRI_UpSampling2\",\n          \"argument\": 3,\n          \"bytes\": 8,\n          \"source\": \"this+0x418\",\n          \"condition\": \"always\"\n        }\n      ],\n      \"dispatched_by_Process\": true,\n      \"global_dimensions_slot\": \"0x470\",\n      \"local_dimensions_slot\": \"0x4e0\",\n      \"condition\": \"level>0\",\n      \"dimensions\": 2\n    },\n    {\n      \"slot\": \"0x2c8\",\n      \"name\": \"SRI_Gradient2\",\n      \"bound_arguments\": [\n        {\n          \"kernel_slot\": \"0x2c8\",\n          \"kernel\": \"SRI_Gradient2\",\n          \"argument\": 0,\n          \"bytes\": 8,\n          \"source\": \"this+0x3d0\",\n          \"condition\": \"always\"\n        },\n        {\n          \"kernel_slot\": \"0x2c8\",\n          \"kernel\": \"SRI_Gradient2\",\n          \"argument\": 1,\n          \"bytes\": 8,\n          \"source\": \"this+0x3d8\",\n          \"condition\": \"always\"\n        },\n        {\n          \"kernel_slot\": \"0x2c8\",\n          \"kernel\": \"SRI_Gradient2\",\n          \"argument\": 2,\n          \"bytes\": 8,\n          \"source\": \"this+0x3e0\",\n          \"condition\": \"always\"\n        }\n      ],\n      \"dispatched_by_Process\": true,\n      \"global_dimensions_slot\": \"0x480\",\n      \"local_dimensions_slot\": \"0x4e0\",\n      \"condition\": \"level>0 and fine_iterations>=1\",\n      \"dimensions\": 2\n    },\n    {\n      \"slot\": \"0x2d0\",\n      \"name\": \"SRI_Gradient_Size_Direction2\",\n      \"bound_arguments\": [\n        {\n          \"kernel_slot\": \"0x2d0\",\n          \"kernel\": \"SRI_Gradient_Size_Direction2\",\n          \"argument\": 0,\n          \"bytes\": 8,\n          \"source\": \"this+0x3d8\",\n          \"condition\": \"always\"\n        },\n        {\n          \"kernel_slot\": \"0x2d0\",\n          \"kernel\": \"SRI_Gradient_Size_Direction2\",\n          \"argument\": 1,\n          \"bytes\": 8,\n          \"source\": \"this+0x3e0\",\n          \"condition\": \"always\"\n        },\n        {\n          \"kernel_slot\": \"0x2d0\",\n          \"kernel\": \"SRI_Gradient_Size_Direction2\",\n          \"argument\": 2,\n          \"bytes\": 8,\n          \"source\": \"this+0x3e8\",\n          \"condition\": \"always\"\n        },\n        {\n          \"kernel_slot\": \"0x2d0\",\n          \"kernel\": \"SRI_Gradient_Size_Direction2\",\n          \"argument\": 3,\n          \"bytes\": 8,\n          \"source\": \"this+0x3f0\",\n          \"condition\": \"always\"\n        }\n      ],\n      \"dispatched_by_Process\": true,\n      \"global_dimensions_slot\": \"0x480\",\n      \"local_dimensions_slot\": \"0x4e0\",\n      \"condition\": \"level>0 and fine_iterations>=1\",\n      \"dimensions\": 2\n    },\n    {\n      \"slot\": \"0x2d8\",\n      \"name\": \"SRI_HistogramStatistic2\",\n      \"bound_arguments\": [\n        {\n          \"kernel_slot\": \"0x2d8\",\n          \"kernel\": \"SRI_HistogramStatistic2\",\n          \"argument\": 0,\n          \"bytes\": 8,\n          \"source\": \"this+0x3e8\",\n          \"condition\": \"always\"\n        },\n        {\n          \"kernel_slot\": \"0x2d8\",\n          \"kernel\": \"SRI_HistogramStatistic2\",\n          \"argument\": 1,\n          \"bytes\": 8,\n          \"source\": \"this+0x3f8\",\n          \"condition\": \"always\"\n        },\n        {\n          \"kernel_slot\": \"0x2d8\",\n          \"kernel\": \"SRI_HistogramStatistic2\",\n          \"argument\": 2,\n          \"bytes\": 4,\n          \"source\": \"this+0x17c\",\n          \"condition\": \"always\"\n        },\n        {\n          \"kernel_slot\": \"0x2d8\",\n          \"kernel\": \"SRI_HistogramStatistic2\",\n          \"argument\": 3,\n          \"bytes\": 4,\n          \"source\": \"this+0x190\",\n          \"condition\": \"always\"\n        },\n        {\n          \"kernel_slot\": \"0x2d8\",\n          \"kernel\": \"SRI_HistogramStatistic2\",\n          \"argument\": 4,\n          \"bytes\": 8,\n          \"source\": \"this+0x430\",\n          \"condition\": \"always\"\n        }\n      ],\n      \"dispatched_by_Process\": true,\n      \"global_dimensions_slot\": \"0x4a0\",\n      \"local_dimensions_slot\": \"0x500\",\n      \"condition\": \"level>0 and fine_iterations>=1\",\n      \"dimensions\": 1\n    },\n    {\n      \"slot\": \"0x2e0\",\n      \"name\": \"SRI_Expand2\",\n      \"bound_arguments\": [\n        {\n          \"kernel_slot\": \"0x2e0\",\n          \"kernel\": \"SRI_Expand2\",\n          \"argument\": 0,\n          \"bytes\": 8,\n          \"source\": \"this+0x3f8\",\n          \"condition\": \"always\"\n        },\n        {\n          \"kernel_slot\": \"0x2e0\",\n          \"kernel\": \"SRI_Expand2\",\n          \"argument\": 1,\n          \"bytes\": 8,\n          \"source\": \"this+0x408\",\n          \"condition\": \"always\"\n        }\n      ],\n      \"dispatched_by_Process\": true,\n      \"global_dimensions_slot\": \"0x480\",\n      \"local_dimensions_slot\": \"0x4e0\",\n      \"condition\": \"level>0 and fine_iterations>=1\",\n      \"dimensions\": 2\n    },\n    {\n      \"slot\": \"0x2e8\",\n      \"name\": \"SRI_Corrode2\",\n      \"bound_arguments\": [\n        {\n          \"kernel_slot\": \"0x2e8\",\n          \"kernel\": \"SRI_Corrode2\",\n          \"argument\": 0,\n          \"bytes\": 8,\n          \"source\": \"this+0x408\",\n          \"condition\": \"always\"\n        },\n        {\n          \"kernel_slot\": \"0x2e8\",\n          \"kernel\": \"SRI_Corrode2\",\n          \"argument\": 1,\n          \"bytes\": 8,\n          \"source\": \"this+0x3e8\",\n          \"condition\": \"always\"\n        },\n        {\n          \"kernel_slot\": \"0x2e8\",\n          \"kernel\": \"SRI_Corrode2\",\n          \"argument\": 2,\n          \"bytes\": 8,\n          \"source\": \"this+0x3f8\",\n          \"condition\": \"always\"\n        },\n        {\n          \"kernel_slot\": \"0x2e8\",\n          \"kernel\": \"SRI_Corrode2\",\n          \"argument\": 3,\n          \"bytes\": 8,\n          \"source\": \"this+0x400\",\n          \"condition\": \"always\"\n        }\n      ],\n      \"dispatched_by_Process\": true,\n      \"global_dimensions_slot\": \"0x480\",\n      \"local_dimensions_slot\": \"0x4e0\",\n      \"condition\": \"level>0 and fine_iterations>=1\",\n      \"dimensions\": 2\n    },\n    {\n      \"slot\": \"0x2f0\",\n      \"name\": \"SRI_Direction2\",\n      \"bound_arguments\": [\n        {\n          \"kernel_slot\": \"0x2f0\",\n          \"kernel\": \"SRI_Direction2\",\n          \"argument\": 0,\n          \"bytes\": 8,\n          \"source\": \"this+0x3f8\",\n          \"condition\": \"always\"\n        },\n        {\n          \"kernel_slot\": \"0x2f0\",\n          \"kernel\": \"SRI_Direction2\",\n          \"argument\": 1,\n          \"bytes\": 8,\n          \"source\": \"this+0x3f0\",\n          \"condition\": \"always\"\n        },\n        {\n          \"kernel_slot\": \"0x2f0\",\n          \"kernel\": \"SRI_Direction2\",\n          \"argument\": 2,\n          \"bytes\": 8,\n          \"source\": \"this+0x410\",\n          \"condition\": \"always\"\n        }\n      ],\n      \"dispatched_by_Process\": true,\n      \"global_dimensions_slot\": \"0x480\",\n      \"local_dimensions_slot\": \"0x4e0\",\n      \"condition\": \"level>0 and fine_iterations>=1\",\n      \"dimensions\": 2\n    },\n    {\n      \"slot\": \"0x2f8\",\n      \"name\": \"SRI_DirectionalSmoothing2\",\n      \"bound_arguments\": [\n        {\n          \"kernel_slot\": \"0x2f8\",\n          \"kernel\": \"SRI_DirectionalSmoothing2\",\n          \"argument\": 0,\n          \"bytes\": 8,\n          \"source\": \"this+0x418\",\n          \"condition\": \"always\"\n        },\n        {\n          \"kernel_slot\": \"0x2f8\",\n          \"kernel\": \"SRI_DirectionalSmoothing2\",\n          \"argument\": 1,\n          \"bytes\": 8,\n          \"source\": \"this+0x410\",\n          \"condition\": \"always\"\n        },\n        {\n          \"kernel_slot\": \"0x2f8\",\n          \"kernel\": \"SRI_DirectionalSmoothing2\",\n          \"argument\": 2,\n          \"bytes\": 8,\n          \"source\": \"this+0x428\",\n          \"condition\": \"always\"\n        },\n        {\n          \"kernel_slot\": \"0x2f8\",\n          \"kernel\": \"SRI_DirectionalSmoothing2\",\n          \"argument\": 3,\n          \"bytes\": 8,\n          \"source\": \"this+0x420\",\n          \"condition\": \"always\"\n        }\n      ],\n      \"dispatched_by_Process\": true,\n      \"global_dimensions_slot\": \"0x480\",\n      \"local_dimensions_slot\": \"0x4e0\",\n      \"condition\": \"level>0 and fine_iterations>=1\",\n      \"dimensions\": 2\n    },\n    {\n      \"slot\": \"0x300\",\n      \"name\": \"SRI_DetailSmoothN\",\n      \"bound_arguments\": [\n        {\n          \"kernel_slot\": \"0x300\",\n          \"kernel\": \"SRI_DetailSmoothN\",\n          \"argument\": 0,\n          \"bytes\": 8,\n          \"source\": \"this+0x340\",\n          \"condition\": \"always\"\n        },\n        {\n          \"kernel_slot\": \"0x300\",\n          \"kernel\": \"SRI_DetailSmoothN\",\n          \"argument\": 1,\n          \"bytes\": 8,\n          \"source\": \"this+0x430\",\n          \"condition\": \"always\"\n        },\n        {\n          \"kernel_slot\": \"0x300\",\n          \"kernel\": \"SRI_DetailSmoothN\",\n          \"argument\": 2,\n          \"bytes\": 4,\n          \"source\": \"this+0x188\",\n          \"condition\": \"always\"\n        },\n        {\n          \"kernel_slot\": \"0x300\",\n          \"kernel\": \"SRI_DetailSmoothN\",\n          \"argument\": 3,\n          \"bytes\": 4,\n          \"source\": \"this+0x190\",\n          \"condition\": \"always\"\n        },\n        {\n          \"kernel_slot\": \"0x300\",\n          \"kernel\": \"SRI_DetailSmoothN\",\n          \"argument\": 4,\n          \"bytes\": 8,\n          \"source\": \"this+0x438\",\n          \"condition\": \"always\"\n        }\n      ],\n      \"dispatched_by_Process\": true,\n      \"global_dimensions_slot\": \"runtime-final\",\n      \"local_dimensions_slot\": \"0x4d0\",\n      \"condition\": \"level>0 and fine_iterations>=1\",\n      \"dimensions\": 2\n    },\n    {\n      \"slot\": \"0x510\",\n      \"name\": \"FrameCorrelation\",\n      \"bound_arguments\": [\n        {\n          \"kernel_slot\": \"0x510\",\n          \"kernel\": \"FrameCorrelation\",\n          \"argument\": 0,\n          \"bytes\": 8,\n          \"source\": \"this+0x350\",\n          \"condition\": \"always\"\n        },\n        {\n          \"kernel_slot\": \"0x510\",\n          \"kernel\": \"FrameCorrelation\",\n          \"argument\": 1,\n          \"bytes\": 8,\n          \"source\": \"this+0x538\",\n          \"condition\": \"always\"\n        },\n        {\n          \"kernel_slot\": \"0x510\",\n          \"kernel\": \"FrameCorrelation\",\n          \"argument\": 2,\n          \"bytes\": 8,\n          \"source\": \"this+0x530\",\n          \"condition\": \"always\"\n        },\n        {\n          \"kernel_slot\": \"0x510\",\n          \"kernel\": \"FrameCorrelation\",\n          \"argument\": 3,\n          \"bytes\": 8,\n          \"source\": \"this+0x548\",\n          \"condition\": \"always\"\n        },\n        {\n          \"kernel_slot\": \"0x510\",\n          \"kernel\": \"FrameCorrelation\",\n          \"argument\": 4,\n          \"bytes\": 4,\n          \"source\": \"this+0x190\",\n          \"condition\": \"always\"\n        }\n      ],\n      \"dispatched_by_Process\": true,\n      \"global_dimensions_slot\": \"0x440\",\n      \"local_dimensions_slot\": \"0x4e0\",\n      \"condition\": \"always\",\n      \"dimensions\": 2\n    },\n    {\n      \"slot\": \"0x518\",\n      \"name\": \"FrameCorrelation_Mask\",\n      \"bound_arguments\": [\n        {\n          \"kernel_slot\": \"0x518\",\n          \"kernel\": \"FrameCorrelation_Mask\",\n          \"argument\": 0,\n          \"bytes\": 8,\n          \"source\": \"this+0x3b8\",\n          \"condition\": \"always\"\n        },\n        {\n          \"kernel_slot\": \"0x518\",\n          \"kernel\": \"FrameCorrelation_Mask\",\n          \"argument\": 1,\n          \"bytes\": 8,\n          \"source\": \"this+0x540\",\n          \"condition\": \"always\"\n        },\n        {\n          \"kernel_slot\": \"0x518\",\n          \"kernel\": \"FrameCorrelation_Mask\",\n          \"argument\": 2,\n          \"bytes\": 8,\n          \"source\": \"this+0x528\",\n          \"condition\": \"always\"\n        },\n        {\n          \"kernel_slot\": \"0x518\",\n          \"kernel\": \"FrameCorrelation_Mask\",\n          \"argument\": 3,\n          \"bytes\": 4,\n          \"source\": \"this+0x19c\",\n          \"condition\": \"always\"\n        }\n      ],\n      \"dispatched_by_Process\": true,\n      \"global_dimensions_slot\": \"0x470\",\n      \"local_dimensions_slot\": \"0x4e0\",\n      \"condition\": \"level>=-0.1\",\n      \"dimensions\": 2\n    },\n    {\n      \"slot\": \"0x520\",\n      \"name\": \"FrameCorrelation_Coef\",\n      \"bound_arguments\": [\n        {\n          \"kernel_slot\": \"0x520\",\n          \"kernel\": \"FrameCorrelation_Coef\",\n          \"argument\": 0,\n          \"bytes\": 8,\n          \"source\": \"this+0x528\",\n          \"condition\": \"always\"\n        },\n        {\n          \"kernel_slot\": \"0x520\",\n          \"kernel\": \"FrameCorrelation_Coef\",\n          \"argument\": 1,\n          \"bytes\": 8,\n          \"source\": \"this+0x530\",\n          \"condition\": \"always\"\n        }\n      ],\n      \"dispatched_by_Process\": true,\n      \"global_dimensions_slot\": \"0x470\",\n      \"local_dimensions_slot\": \"0x4e0\",\n      \"condition\": \"level>=-0.1\",\n      \"dimensions\": 2\n    }\n  ],\n  \"dimensions_after_SetKernelArg\": {\n    \"0x440\": [\n      128,\n      320\n    ],\n    \"0x450\": [\n      [\n        128,\n        320\n      ],\n      [\n        128,\n        160\n      ],\n      [\n        128,\n        106\n      ],\n      [\n        128,\n        80\n      ]\n    ],\n    \"0x460\": [\n      64,\n      160\n    ],\n    \"0x470\": [\n      [\n        64,\n        160\n      ],\n      [\n        64,\n        96\n      ],\n      [\n        64,\n        80\n      ],\n      [\n        64,\n        64\n      ]\n    ],\n    \"0x480\": [\n      [\n        128,\n        320\n      ],\n      [\n        128,\n        192\n      ],\n      [\n        128,\n        160\n      ],\n      [\n        128,\n        128\n      ]\n    ],\n    \"0x490\": [\n      64,\n      1\n    ],\n    \"0x4a0\": [\n      128,\n      1\n    ],\n    \"0x4b0\": [\n      128,\n      32\n    ],\n    \"0x4c0\": [\n      64,\n      80\n    ],\n    \"0x4d0\": [\n      32,\n      1\n    ],\n    \"0x4e0\": [\n      16,\n      16\n    ],\n    \"0x4f0\": [\n      64,\n      1\n    ],\n    \"0x500\": [\n      128,\n      1\n    ]\n  },\n  \"copies_Process\": [\n    {\n      \"source\": \"0x308\",\n      \"destination\": \"0x350\",\n      \"region\": [\n        128,\n        320,\n        1\n      ],\n      \"condition\": \"level<=0\"\n    },\n    {\n      \"source\": \"0x318\",\n      \"destination\": \"0x328\",\n      \"region\": [\n        128,\n        320,\n        1\n      ],\n      \"condition\": \"level>0 and N==1\"\n    },\n    {\n      \"source\": \"0x3b8\",\n      \"destination\": \"0x3b0\",\n      \"region\": [\n        64,\n        160,\n        1\n      ],\n      \"condition\": \"between coarse directional iterations\"\n    },\n    {\n      \"source\": \"0x420\",\n      \"destination\": \"0x418\",\n      \"region\": [\n        128,\n        320,\n        1\n      ],\n      \"condition\": \"between fine directional iterations\"\n    },\n    {\n      \"source\": \"0x548\",\n      \"destination\": \"0x538\",\n      \"region\": [\n        128,\n        320,\n        1\n      ],\n      \"condition\": \"always after FrameCorrelation\"\n    },\n    {\n      \"source\": \"0x3b8\",\n      \"destination\": \"0x540\",\n      \"region\": [\n        64,\n        160,\n        1\n      ],\n      \"condition\": \"always after full temporal copy\"\n    }\n  ]\n}\n"
      },
      {
        "path": "components/ultrasound/convex-decoder/1.0.0/src/linear_dsp.rs",
        "sha256": "d711bf2d2221c23f4213a260e2429d2fac3a086d8fc3078d1acad0f8982cca38",
        "text": "use crate::Result;\nuse std::{fs::File, io::Read, path::Path};\npub(crate) fn read_regular(path: &Path, maximum: u64) -> Result<Vec<u8>> {\n    if !std::fs::symlink_metadata(path)\n        .map_err(|e| format!(\"{}: {e}\", path.display()))?\n        .file_type()\n        .is_file()\n    {\n        return Err(\"Input must be a regular non-symlink file\".into());\n    }\n    let file = File::open(path).map_err(|e| e.to_string())?;\n    if !file.metadata().map_err(|e| e.to_string())?.is_file() {\n        return Err(\"Opened input is not a regular file\".into());\n    }\n    let mut bytes = Vec::new();\n    file.take(maximum.checked_add(1).ok_or(\"Read bound overflow\")?)\n        .read_to_end(&mut bytes)\n        .map_err(|e| e.to_string())?;\n    if bytes.len() as u64 > maximum {\n        return Err(\"Input exceeds bounded read\".into());\n    }\n    Ok(bytes)\n}\nfn word(bytes: &[u8], offset: usize) -> Result<u32> {\n    Ok(u32::from_le_bytes(\n        bytes\n            .get(offset..offset.checked_add(4).ok_or(\"Offset overflow\")?)\n            .ok_or(\"Truncated word\")?\n            .try_into()\n            .unwrap(),\n    ))\n}\nfn floats(bytes: &[u8], count: usize) -> Result<Vec<f32>> {\n    if bytes.len() != count.checked_mul(4).ok_or(\"Float size overflow\")? {\n        return Err(\"Unexpected coefficient length\".into());\n    }\n    let result: Vec<_> = bytes\n        .as_chunks::<4>()\n        .0\n        .iter()\n        .map(|b| f32::from_le_bytes(*b))\n        .collect();\n    if result.iter().any(|f| !f.is_finite()) {\n        return Err(\"Nonfinite input coefficient; no computation attempted\".into());\n    }\n    Ok(result)\n}\n"
      },
      {
        "path": "components/ultrasound/convex-decoder/1.0.0/src/linear_palette.rs",
        "sha256": "0b05f3f2d247222a0f730ee3f361646231c3cb351606bf62adf864788fdf4bc2",
        "text": "pub const MAX_PIXELS: usize = 2048 * 2048;\n"
      },
      {
        "path": "components/ultrasound/convex-decoder/1.0.0/src/linear_post.rs",
        "sha256": "55bc8d05a021a34ff7da6d9f0aaab3e658a0018e875c78f914d0c8bcbaa069e6",
        "text": "pub(crate) fn unorm(value: f32) -> u8 {\n    (value.clamp(0.0, 1.0) * 255.0).round_ties_even() as u8\n}\n"
      },
      {
        "path": "components/ultrasound/convex-decoder/1.0.0/src/rgba_png.rs",
        "sha256": "4d91a880687db02ebdaad20b63e28e653af8b15f943a577c34961ef70d3ff8ad",
        "text": "// SPDX-License-Identifier: AGPL-3.0-or-later\n//! Minimal bounded PNG writer: RGBA8, no interlace, filter0 and stored DEFLATE\n//! blocks (RFC1950/1951; W3C PNG). No color calibration or gamma is invented.\nuse crate::{Result, linear_palette::MAX_PIXELS};\nfn crc(bytes: &[u8]) -> u32 {\n    let mut c = !0u32;\n    for &b in bytes {\n        c ^= b as u32;\n        for _ in 0..8 {\n            c = (c >> 1) ^ (0xedb88320u32 & 0u32.wrapping_sub(c & 1));\n        }\n    }\n    !c\n}\nfn chunk(out: &mut Vec<u8>, kind: &[u8; 4], data: &[u8]) {\n    out.extend_from_slice(&(data.len() as u32).to_be_bytes());\n    let start = out.len();\n    out.extend_from_slice(kind);\n    out.extend_from_slice(data);\n    let checksum = crc(&out[start..]);\n    out.extend_from_slice(&checksum.to_be_bytes());\n}\npub fn encode(width: usize, height: usize, rgba: &[u8]) -> Result<Vec<u8>> {\n    let n = width.checked_mul(height).ok_or(\"PNG dimensions overflow\")?;\n    if width == 0\n        || height == 0\n        || width > 2048\n        || height > 2048\n        || n > MAX_PIXELS\n        || rgba.len() != n * 4\n    {\n        return Err(\"PNG requires exact bounded RGBA8 dimensions1..2048\".into());\n    }\n    let mut filtered = Vec::with_capacity(rgba.len() + height);\n    for row in rgba.chunks_exact(width * 4) {\n        filtered.push(0);\n        filtered.extend_from_slice(row);\n    }\n    let mut z = vec![0x78, 0x01];\n    for (i, b) in filtered.chunks(65535).enumerate() {\n        z.push(u8::from((i + 1) * 65535 >= filtered.len()));\n        z.extend_from_slice(&(b.len() as u16).to_le_bytes());\n        z.extend_from_slice(&(!(b.len() as u16)).to_le_bytes());\n        z.extend_from_slice(b);\n    }\n    let (mut a, mut b) = (1u32, 0u32);\n    for v in filtered {\n        a = (a + v as u32) % 65521;\n        b = (b + a) % 65521;\n    }\n    z.extend_from_slice(&((b << 16) | a).to_be_bytes());\n    let mut out = b\"\\x89PNG\\r\\n\\x1a\\n\".to_vec();\n    let mut ihdr = Vec::new();\n    ihdr.extend_from_slice(&(width as u32).to_be_bytes());\n    ihdr.extend_from_slice(&(height as u32).to_be_bytes());\n    ihdr.extend_from_slice(&[8, 6, 0, 0, 0]);\n    chunk(&mut out, b\"IHDR\", &ihdr);\n    chunk(&mut out, b\"IDAT\", &z);\n    chunk(&mut out, b\"IEND\", &[]);\n    Ok(out)\n}\n#[cfg(test)]\nmod tests {\n    use super::*;\n    #[test]\n    fn png_checksums_and_external_standard_test_vector() {\n        assert_eq!(crc(b\"123456789\"), 0xcbf43926);\n        // Independently generated with Python struct/zlib: one nonopaque RGBA pixel.\n        let expected = \"89504e470d0a1a0a0000000d49484452000000010000000108060000001f15c48900000010494441547801010500faff00010203040019000bb9b0e3eb0000000049454e44ae426082\";\n        let actual = encode(1, 1, &[1, 2, 3, 4]).unwrap();\n        let hex: String = actual.iter().map(|b| format!(\"{b:02x}\")).collect();\n        assert_eq!(hex, expected);\n        assert!(encode(1, 1, &[]).is_err());\n        assert!(encode(0, 1, &[]).is_err());\n        assert!(encode(usize::MAX, 2, &[]).is_err());\n    }\n}\n"
      },
      {
        "path": "components/ultrasound/convex-decoder/1.0.0/src/resources.rs",
        "sha256": "c8dcb773217ae1a6391a6092b902ebedb94bb19691202f24b07e307804aef3e4",
        "text": "// SPDX-License-Identifier: AGPL-3.0-or-later\n//! Bounded resource access shared by native and WASM callers. No USB or network.\nuse crate::Result;\nuse std::{collections::BTreeMap, path::Path};\n\npub type ResourceStore = BTreeMap<String, Vec<u8>>;\npub trait Source {\n    fn read(&self, name: &str, maximum: u64) -> Result<Vec<u8>>;\n    fn exists(&self, name: &str) -> Result<bool>;\n}\npub struct Files<'a>(pub &'a Path);\nimpl Source for Files<'_> {\n    fn read(&self, name: &str, maximum: u64) -> Result<Vec<u8>> {\n        crate::linear_dsp::read_regular(&self.0.join(name), maximum)\n    }\n    fn exists(&self, name: &str) -> Result<bool> {\n        match std::fs::symlink_metadata(self.0.join(name)) {\n            Ok(_) => Ok(true),\n            Err(e) if e.kind() == std::io::ErrorKind::NotFound => Ok(false),\n            Err(e) => Err(format!(\"Cannot establish resource absence: {e}\")),\n        }\n    }\n}\npub struct Memory<'a> {\n    pub files: &'a ResourceStore,\n    pub group: &'a str,\n}\nimpl Source for Memory<'_> {\n    fn read(&self, name: &str, maximum: u64) -> Result<Vec<u8>> {\n        let key = format!(\"{}/{name}\", self.group);\n        let bytes = self\n            .files\n            .get(&key)\n            .ok_or_else(|| format!(\"Missing resource: {key}\"))?;\n        if bytes.len() as u64 > maximum {\n            return Err(format!(\"Resource exceeds bound: {key}\"));\n        }\n        Ok(bytes.clone())\n    }\n    fn exists(&self, name: &str) -> Result<bool> {\n        Ok(self.files.contains_key(&format!(\"{}/{name}\", self.group)))\n    }\n}\npub fn validate(files: &ResourceStore) -> Result<()> {\n    if files.len() > 512 {\n        return Err(\"Resource count exceeds512\".into());\n    }\n    let mut total = 0usize;\n    for (key, value) in files {\n        let (group, name) = key.split_once('/').ok_or(\"Invalid resource key\")?;\n        if ![\"assets\", \"hv\", \"sri\", \"maps\"].contains(&group)\n            || name.is_empty()\n            || !name.as_bytes()[0].is_ascii_alphanumeric()\n            || !name\n                .bytes()\n                .all(|c| c.is_ascii_alphanumeric() || b\"_.-\".contains(&c))\n        {\n            return Err(\"Invalid resource key\".into());\n        }\n        total = total\n            .checked_add(value.len())\n            .ok_or(\"Resource bound overflow\")?;\n        if value.len() > 4 * 1024 * 1024 || total > 16 * 1024 * 1024 {\n            return Err(\"Resource bytes exceed bounds\".into());\n        }\n    }\n    Ok(())\n}\n"
      },
      {
        "path": "components/ultrasound/convex-decoder/1.0.0/examples/replay_memory.rs",
        "sha256": "2409ba64d2a8470976030b020075799aea4782834104567bd6cdf12c1b17edb3",
        "text": "// SPDX-License-Identifier: AGPL-3.0-or-later\n//! Offline host for the SAME library compiled into decoder.wasm. No USB or networking.\nuse odb_convex_decoder::{Session, resources::ResourceStore};\nuse serde_json::{Value, json};\nuse sha2::{Digest, Sha256};\nuse std::{env, fs, path::Path};\nfn main() -> Result<(), Box<dyn std::error::Error>> {\n    let args: Vec<_> = env::args().skip(1).collect();\n    if !(3..=4).contains(&args.len()) {\n        return Err(\n            \"Usage: replay_memory input.json receive-data output-dir [bootstrap.bin]\".into(),\n        );\n    }\n    let input: Value = serde_json::from_slice(&fs::read(&args[0])?)?;\n    let files: ResourceStore = serde_json::from_value(input[\"files\"].clone())?;\n    let mut session = if input[\"purpose\"] == \"reconstruction\" {\n        Session::reconstruction(&input, &files)?\n    } else {\n        Session::new(&input, &files)?\n    };\n    let output = Path::new(&args[2]);\n    fs::create_dir(output)?;\n    if args.len() == 4 {\n        fs::write(\n            output.join(\"commands.json\"),\n            serde_json::to_vec_pretty(&session.bind(&fs::read(&args[3])?)?)?,\n        )?;\n    }\n    let data = Path::new(&args[1]);\n    let manifest: Value = serde_json::from_slice(&fs::read(data.join(\"manifest.json\"))?)?;\n    let mut images = Vec::new();\n    let mut save =\n        |frames: Vec<odb_convex_decoder::Frame>| -> Result<(), Box<dyn std::error::Error>> {\n            for frame in frames {\n                let name = format!(\"{:06}.png\", frame.sequence);\n                fs::write(output.join(&name), &frame.png)?;\n                images.push(json!({\"sequence\":frame.sequence,\"file\":name,\"sha256\":format!(\"{:x}\",Sha256::digest(&frame.png))}));\n            }\n            Ok(())\n        };\n    for row in manifest[\"reads\"].as_array().ok_or(\"Missing reads\")? {\n        let name = row[\"raw_file\"].as_str().ok_or(\"Missing read filename\")?;\n        // Host fixture paths must remain simple local filenames.\n        if Path::new(name).components().count() != 1 {\n            return Err(\"Invalid fixture filename\".into());\n        }\n        save(session.push(&fs::read(data.join(name))?)?)?;\n    }\n    save(session.finish()?)?;\n    fs::write(\n        output.join(\"images.json\"),\n        serde_json::to_vec_pretty(&images)?,\n    )?;\n    println!(\"{} frames from archived DATA; no USB access\", images.len());\n    Ok(())\n}\n"
      },
      {
        "path": "components/ultrasound/convex-decoder/1.0.0/src/selected_profile.rs",
        "sha256": "4c0c5b3e451a42a0ce930bdf51d31f031c318f39b66ffd19d8c194b28cb9bf3b",
        "text": "// SPDX-License-Identifier: AGPL-3.0-or-later\n//! Explicit values consumed by one image setting. Contains no transport commands.\nuse serde_json::{Value, json};\n#[derive(Clone)]\npub struct ImageProfile {\n    pub settings: Value,\n    pub bfsp_coefficients: [f32; 8],\n    pub bfsp_downsample: usize,\n    pub dtgc_tgc: [f32; 1024],\n    pub dtgc_depth: f32,\n    pub dtgc_gain: f32,\n    pub dtgc_dr: f32,\n    pub compound_window: usize,\n    pub compound_coef0: f32,\n    pub compound_threshold_a: f32,\n    pub compound_threshold_b: f32,\n    pub temporal_correlation: f32,\n    pub dsc_parameters: [u8; 40],\n    pub display_map: [u8; 1024],\n}\nimpl ImageProfile {\n    /// Integer bit patterns avoid decimal or JSON float rounding in profile tools.\n    pub fn json(&self) -> Value {\n        json!({\"schema\":\"convex-selected-image-profile-v1\",\"settings\":self.settings,\n            \"bfsp_coefficients_bits\":self.bfsp_coefficients.map(f32::to_bits).to_vec(),\"bfsp_downsample\":self.bfsp_downsample,\n            \"dtgc_tgc_bits\":self.dtgc_tgc.map(f32::to_bits).to_vec(),\"dtgc_depth_bits\":self.dtgc_depth.to_bits(),\n            \"dtgc_gain_bits\":self.dtgc_gain.to_bits(),\"dtgc_dr_bits\":self.dtgc_dr.to_bits(),\n            \"compound_window\":self.compound_window,\"compound_coef0_bits\":self.compound_coef0.to_bits(),\n            \"compound_threshold_a_bits\":self.compound_threshold_a.to_bits(),\"compound_threshold_b_bits\":self.compound_threshold_b.to_bits(),\n            \"temporal_correlation_bits\":self.temporal_correlation.to_bits(),\"dsc_parameters\":self.dsc_parameters.to_vec(),\n            \"display_map\":self.display_map.to_vec()})\n    }\n}\n"
      },
      {
        "path": "components/ultrasound/convex-decoder/1.0.0/build/reproducible-rustc.rs",
        "sha256": "35ad737748a656197b08b1033df4432bd9a0c444955275e4f9ec68d3c09344c1",
        "text": "// SPDX-License-Identifier: AGPL-3.0-or-later\n//! Normalize Cargo's host-dependent metadata for the two locked local crates.\n//! Dependency metadata and every numerical/optimization/compiler option survive.\nuse std::{env, ffi::OsString, process::Command};\n\nfn normalize(args: Vec<OsString>, version: &str) -> Vec<OsString> {\n    let value = |key: &str| {\n        args.windows(2)\n            .find(|v| v[0] == key)\n            .map(|v| v[1].to_string_lossy().into_owned())\n    };\n    let Some(name) = value(\"--crate-name\") else {\n        return args;\n    };\n    if ![\"odb_convex_decoder\", \"probe_open_image\"].contains(&name.as_str()) {\n        return args;\n    }\n    let target = value(\"--target\").unwrap_or_else(|| \"host\".into());\n    let mut cfg: Vec<_> = args\n        .windows(2)\n        .filter(|v| v[0] == \"--cfg\")\n        .map(|v| v[1].to_string_lossy().into_owned())\n        .collect();\n    cfg.sort();\n    let metadata = format!(\n        \"metadata=odb-locked-local-v1:{name}:{version}:{target}:{}\",\n        cfg.join(\";\")\n    );\n    let mut output = Vec::with_capacity(args.len() + 2);\n    let mut i = 0;\n    while i < args.len() {\n        if args[i] == \"-C\"\n            && args\n                .get(i + 1)\n                .is_some_and(|v| v.to_string_lossy().starts_with(\"metadata=\"))\n        {\n            i += 2;\n        } else if args[i].to_string_lossy().starts_with(\"-Cmetadata=\") {\n            i += 1;\n        } else {\n            output.push(args[i].clone());\n            i += 1;\n        }\n    }\n    output.extend([OsString::from(\"-C\"), metadata.into()]);\n    output\n}\n\nfn main() {\n    let mut args = env::args_os().skip(1);\n    let compiler = args\n        .next()\n        .expect(\"RUSTC_WRAPPER requires the compiler path\");\n    let args = normalize(\n        args.collect(),\n        &env::var(\"CARGO_PKG_VERSION\").unwrap_or_default(),\n    );\n    let status = Command::new(compiler)\n        .args(args)\n        .status()\n        .expect(\"Cannot execute rustc\");\n    std::process::exit(status.code().unwrap_or(1));\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n    fn args(values: &[&str]) -> Vec<OsString> {\n        values.iter().map(OsString::from).collect()\n    }\n    #[test]\n    fn compiler_queries_and_dependencies_are_untouched() {\n        for input in [\n            args(&[\"-vV\"]),\n            args(&[\"--crate-name\", \"serde_json\", \"-C\", \"metadata=original\"]),\n        ] {\n            assert_eq!(normalize(input.clone(), \"1\"), input);\n        }\n    }\n    #[test]\n    fn host_metadata_differences_do_not_change_local_crate_identity() {\n        let a = args(&[\n            \"--crate-name\",\n            \"odb_convex_decoder\",\n            \"-C\",\n            \"metadata=aaa\",\n            \"-Cmetadata=bbb\",\n        ]);\n        let b = args(&[\"--crate-name\", \"odb_convex_decoder\", \"-C\", \"metadata=ccc\"]);\n        assert_eq!(normalize(a, \"1.0.0\"), normalize(b, \"1.0.0\"));\n    }\n    #[test]\n    fn versions_targets_and_features_remain_distinct() {\n        let base = args(&[\"--crate-name\", \"odb_convex_decoder\"]);\n        let plain = normalize(base.clone(), \"1\");\n        assert_ne!(plain, normalize(base.clone(), \"2\"));\n        for tail in [[\"--target\", \"wasm32-wasip1\"], [\"--cfg\", \"feature=\\\"ffi\\\"\"]] {\n            let mut changed = base.clone();\n            changed.extend(args(&tail));\n            assert_ne!(plain.last(), normalize(changed, \"1\").last());\n        }\n    }\n    #[test]\n    fn numerical_options_paths_and_feature_order_survive() {\n        let input = args(&[\n            \"--crate-name\",\n            \"probe_open_image\",\n            \"--cfg\",\n            \"b\",\n            \"--cfg\",\n            \"a\",\n            \"path with spaces/lib.rs\",\n            \"-C\",\n            \"opt-level=3\",\n            \"-C\",\n            \"codegen-units=1\",\n        ]);\n        let output = normalize(input.clone(), \"0.1.0\");\n        assert_eq!(&output[..input.len()], input);\n        let mut reordered = input.clone();\n        reordered.swap(3, 5);\n        assert_eq!(output.last(), normalize(reordered, \"0.1.0\").last());\n    }\n}\n"
      }
    ],
    "text": "// SPDX-License-Identifier: AGPL-3.0-or-later\n//! Shared native/WASM in-memory decoder. Hosts own transport, storage and display.\n#![allow(dead_code)]\nmod framing;\nmod selected_profile;\npub use selected_profile::ImageProfile;\npub mod resources;\npub use framing::{\n    HEADER_BYTES, Inspector, Limits, MARKER, PREFIX_BYTES, Parameters, Result, Segment, line_length,\n};\nmod admission;\nmod archive;\nmod convex_bfsp;\nmod convex_command;\nmod convex_compound;\nmod convex_configuration;\nmod convex_dsc;\nmod convex_dtgc;\nmod convex_group;\nmod convex_lifecycle;\nmod convex_messages;\nmod convex_parameters;\nmod convex_pipeline;\nmod convex_producers;\nmod convex_sri;\nmod convex_sri_plan;\nmod linear_dsp;\nmod linear_palette;\nmod linear_post;\nmod rgba_png;\nmod identity {\n    pub fn build_provenance() -> serde_json::Value {\n        crate::archive::source_provenance()\n    }\n}\nuse serde_json::{Value, json};\nuse std::{cell::RefCell, path::Path};\n/// Display policy only; never changes USB configuration or transmit settings.\n#[derive(Clone, Copy, Debug, Default)]\npub enum Palette {\n    #[default]\n    Reference,\n    LinearGray,\n}\n/// Original identity gray transfer: RGB=intensity; fourth channel is the index.\n/// This is a DSC lookup table, not an RGBA image (fourth channel is NOT opacity).\npub fn linear_gray_map() -> Vec<u8> {\n    (0..=255u8).flat_map(|level| [level; 4]).collect()\n}\npub struct Frame {\n    pub sequence: u32,\n    pub png: Vec<u8>,\n}\npub struct RgbaFrame {\n    pub sequence: u32,\n    pub rgba: Vec<u8>,\n}\nstruct ProcessedFrame {\n    sequence: u32,\n    png: Option<Vec<u8>>,\n    rgba: Vec<u8>,\n}\n/// One host-independent session. The caller owns USB, timing, storage and display.\npub struct Session {\n    decoder: Decoder,\n}\npub fn encode_rgba_png(width: usize, height: usize, rgba: &[u8]) -> Result<Vec<u8>> {\n    rgba_png::encode(width, height, rgba)\n}\npub fn decode_message(message: &[u8]) -> Result<Value> {\n    convex_messages::decode(message)\n}\nimpl Session {\n    /// Prepare only the selected image parameters, without file resources.\n    pub fn from_profile(configuration: &Value, profile: ImageProfile) -> Result<Self> {\n        let settings = convex_pipeline::Settings::parse(&configuration[\"settings\"])?;\n        let parameters = Parameters::from_json(&configuration[\"parameters\"])?;\n        let grouping = convex_group::Settings::parse(&configuration[\"grouping\"])?;\n        let resources = convex_pipeline::Resources::from_selected(settings, profile)?;\n        let state = convex_pipeline::State::cpu_zeroed(resources.plan())?;\n        Ok(Self {\n            decoder: Decoder {\n                parser: Inspector::new(Some(parameters), Limits::default())?,\n                organizer: convex_group::Organizer::new(parameters, grouping)?,\n                engine: convex_pipeline::Engine::new(resources, state)?,\n                prepared: None,\n                boundary: false,\n                sequence: 0,\n                attempts: 0,\n                maximum: settings.max_groups,\n            },\n        })\n    }\n    /// Snapshot only values consumed by the selected no-enhancement image path.\n    pub fn selected_image_profile(&self) -> Result<ImageProfile> {\n        self.decoder.engine.resources().selected()\n    }\n\n    pub fn new(configuration: &Value, files: &resources::ResourceStore) -> Result<Self> {\n        Self::with_mode(configuration, files, true)\n    }\n    /// Decode archived DATA without loading transmission, ADC, apodization or HV resources.\n    /// No configuration packets can be obtained from this session.\n    pub fn reconstruction(configuration: &Value, files: &resources::ResourceStore) -> Result<Self> {\n        Self::with_mode(configuration, files, false)\n    }\n    fn with_mode(\n        configuration: &Value,\n        files: &resources::ResourceStore,\n        acquisition: bool,\n    ) -> Result<Self> {\n        let settings = convex_pipeline::Settings::parse(&configuration[\"settings\"])?;\n        let parameters = Parameters::from_json(&configuration[\"parameters\"])?;\n        let grouping = convex_group::Settings::parse(&configuration[\"grouping\"])?;\n        if acquisition && configuration[\"selection\"][\"depth_index\"] != settings.bfsp.depth {\n            return Err(\"Acquisition and image depths differ\".into());\n        }\n        resources::validate(files)?;\n        let palette = match configuration.get(\"display_palette\") {\n            None => Palette::Reference,\n            Some(Value::String(s)) if s == \"reference\" => Palette::Reference,\n            Some(Value::String(s)) if s == \"linear-gray-v1\" => Palette::LinearGray,\n            _ => return Err(\"Unknown display palette\".into()),\n        };\n        let source = |group| resources::Memory { files, group };\n        let prepared = if acquisition {\n            Some(convex_configuration::Prepared::from_source(\n                &source(\"assets\"),\n                &source(\"hv\"),\n                configuration[\"selection\"].clone(),\n            )?)\n        } else {\n            None\n        };\n        let resources = convex_pipeline::Resources::from_source(\n            &source(\"assets\"),\n            &source(\"sri\"),\n            &source(\"maps\"),\n            settings,\n            None,\n            palette,\n        )?;\n        let state = convex_pipeline::State::cpu_zeroed(resources.plan())?;\n        Ok(Self {\n            decoder: Decoder {\n                parser: Inspector::new(Some(parameters), Limits::default())?,\n                organizer: convex_group::Organizer::new(parameters, grouping)?,\n                engine: convex_pipeline::Engine::new(resources, state)?,\n                prepared,\n                boundary: false,\n                sequence: 0,\n                attempts: 0,\n                maximum: settings.max_groups,\n            },\n        })\n    }\n    /// Continuous lifetime with the same per-push/buffer bounds and temporal history.\n    /// Does not issue USB commands, reset history, or change any image/TX parameter.\n    pub fn allow_continuous(&mut self) {\n        self.decoder.parser.allow_continuous();\n        self.decoder.maximum = usize::MAX;\n    }\n    pub fn advance(&mut self, bytes: &[u8]) -> Result<()> {\n        process_output(&mut self.decoder, bytes, false, false, false)?;\n        Ok(())\n    }\n    pub fn push_rgba(&mut self, bytes: &[u8]) -> Result<Vec<RgbaFrame>> {\n        self.rgba(bytes, false)\n    }\n    pub fn finish_rgba(&mut self) -> Result<Vec<RgbaFrame>> {\n        self.rgba(&[], true)\n    }\n    fn rgba(&mut self, bytes: &[u8], finish: bool) -> Result<Vec<RgbaFrame>> {\n        Ok(\n            process_output(&mut self.decoder, bytes, finish, false, true)?\n                .into_iter()\n                .map(|f| RgbaFrame {\n                    sequence: f.sequence,\n                    rgba: f.rgba,\n                })\n                .collect(),\n        )\n    }\n    pub fn ready(&self) -> Value {\n        let settings = self.decoder.engine.resources().settings();\n        json!({\"ready\":true,\"width\":settings.dsc.width,\"height\":settings.dsc.height,\"calibrated\":false})\n    }\n    pub fn bind(&mut self, message: &[u8]) -> Result<Value> {\n        bind_decoder(&mut self.decoder, message)\n    }\n    pub fn push(&mut self, bytes: &[u8]) -> Result<Vec<Frame>> {\n        process(&mut self.decoder, bytes, false)\n    }\n    pub fn finish(&mut self) -> Result<Vec<Frame>> {\n        process(&mut self.decoder, &[], true)\n    }\n}\nstruct Decoder {\n    parser: Inspector,\n    organizer: convex_group::Organizer,\n    engine: convex_pipeline::Engine,\n    prepared: Option<convex_configuration::Prepared>,\n    boundary: bool,\n    sequence: u32,\n    attempts: usize,\n    maximum: usize,\n}\nthread_local! {static DECODER:RefCell<Option<Decoder>>=const{RefCell::new(None)};static OUTPUT:RefCell<Vec<u8>>=const{RefCell::new(Vec::new())};}\nfn init(v: Value) -> Result<Value> {\n    let settings = convex_pipeline::Settings::parse(&v[\"settings\"])?;\n    let parameters = Parameters::from_json(&v[\"parameters\"])?;\n    let grouping = convex_group::Settings::parse(&v[\"grouping\"])?;\n    if v[\"selection\"][\"depth_index\"] != settings.bfsp.depth {\n        return Err(\"Acquisition and image depths differ\".into());\n    }\n    let assets = Path::new(\"/assets\");\n    let prepared =\n        convex_configuration::Prepared::load(assets, Path::new(\"/hv\"), v[\"selection\"].clone())?;\n    let resources = convex_pipeline::Resources::load(\n        assets,\n        Path::new(\"/sri\"),\n        Path::new(\"/maps\"),\n        settings,\n        None,\n    )?;\n    let state = convex_pipeline::State::cpu_zeroed(resources.plan())?;\n    let engine = convex_pipeline::Engine::new(resources, state)?;\n    let parser = Inspector::new(Some(parameters), Limits::default())?;\n    let organizer = convex_group::Organizer::new(parameters, grouping)?;\n    DECODER.with(|d| {\n        *d.borrow_mut() = Some(Decoder {\n            parser,\n            organizer,\n            engine,\n            prepared: Some(prepared),\n            boundary: false,\n            sequence: 0,\n            attempts: 0,\n            maximum: settings.max_groups,\n        })\n    });\n    Ok(\n        json!({\"ready\":true,\"width\":settings.dsc.width,\"height\":settings.dsc.height,\"calibrated\":false}),\n    )\n}\nfn bind_decoder(decoder: &mut Decoder, message: &[u8]) -> Result<Value> {\n    let decoded = convex_messages::decode(message)?;\n    if decoded[\"message_pid\"] != 0 {\n        return Err(\"Configuration requires complete current PID0\".into());\n    }\n    let logic = decoded[\"logic_compile_version\"]\n        .as_u64()\n        .ok_or(\"Missing logic\")? as u32;\n    let low = decoded[\"low_power_mode\"]\n        .as_u64()\n        .ok_or(\"Missing power state\")? as u8;\n    let prepared = decoder\n        .prepared\n        .take()\n        .ok_or(\"Configuration can only be bound once per session\")?;\n    let packets = prepared.bind(logic, low)?.into_packets();\n    Ok(\n        json!({\"packets\":packets.into_iter().map(|(name,bytes)|json!({\"name\":name,\"bytes\":bytes})).collect::<Vec<_>>(),\"message\":decoded}),\n    )\n}\nfn bind(message: &[u8]) -> Result<Value> {\n    DECODER.with(|d| {\n        bind_decoder(\n            d.borrow_mut().as_mut().ok_or(\"Initialize decoder first\")?,\n            message,\n        )\n    })\n}\nfn init_memory(v: Value) -> Result<Value> {\n    // Validate settings before resources, consistently with the reference entry point.\n    convex_pipeline::Settings::parse(&v[\"settings\"])?;\n    let files: resources::ResourceStore =\n        serde_json::from_value(v[\"files\"].clone()).map_err(|e| e.to_string())?;\n    let session = match v.get(\"purpose\").and_then(Value::as_str) {\n        None | Some(\"acquisition\") => Session::new(&v, &files)?,\n        Some(\"reconstruction\") => Session::reconstruction(&v, &files)?,\n        _ => return Err(\"Unknown session purpose\".into()),\n    };\n    let ready = session.ready();\n    DECODER.with(|d| *d.borrow_mut() = Some(session.decoder));\n    Ok(ready)\n}\nfn process(decoder: &mut Decoder, bytes: &[u8], finish: bool) -> Result<Vec<Frame>> {\n    Ok(process_output(decoder, bytes, finish, true, true)?\n        .into_iter()\n        .map(|f| Frame {\n            sequence: f.sequence,\n            png: f.png.unwrap(),\n        })\n        .collect())\n}\nfn process_output(\n    decoder: &mut Decoder,\n    bytes: &[u8],\n    finish: bool,\n    png: bool,\n    render: bool,\n) -> Result<Vec<ProcessedFrame>> {\n    let segments = if finish {\n        decoder.parser.finish()?\n    } else {\n        decoder.parser.push(bytes)?\n    };\n    let mut frames = Vec::new();\n    for segment in segments {\n        let step = decoder.organizer.push(&segment)?;\n        if step\n            .events\n            .iter()\n            .any(|e| e[\"event\"] == \"new_organizer_boundary\")\n        {\n            decoder.boundary = true;\n        }\n        if let Some(group) = step.group {\n            if decoder.attempts >= decoder.maximum {\n                return Err(\"Decoded frame budget exhausted\".into());\n            }\n            let lines = group.bytes();\n            let phase = match admission::audit_candidate(\n                &lines,\n                &group.algorithm_header,\n                decoder.engine.resources().plan(),\n            ) {\n                Ok(p) => p,\n                Err(_) => {\n                    decoder.boundary = true;\n                    continue;\n                }\n            };\n            if decoder.boundary {\n                decoder.engine.state.software_freeze();\n                decoder.boundary = false;\n            }\n            decoder.attempts = decoder\n                .attempts\n                .checked_add(1)\n                .ok_or(\"Attempt count overflow\")?;\n            let output = if !render {\n                decoder.engine.update_only(&lines, phase)?\n            } else if png {\n                decoder.engine.process(&lines, phase)?\n            } else {\n                decoder.engine.process_rgba(&lines, phase)?\n            };\n            if output.attempt.native_status_candidate == Some(0) {\n                decoder.sequence = decoder\n                    .sequence\n                    .checked_add(1)\n                    .ok_or(\"Image sequence overflow\")?;\n                if let Some(rgba) = output.rgba {\n                    frames.push(ProcessedFrame {\n                        sequence: decoder.sequence,\n                        png: output.png,\n                        rgba,\n                    });\n                }\n            }\n        }\n    }\n    Ok(frames)\n}\nfn push(bytes: &[u8], finish: bool) -> Result<Vec<u8>> {\n    DECODER.with(|d| {\n        let mut borrow = d.borrow_mut();\n        let decoder = borrow.as_mut().ok_or(\"Initialize decoder first\")?;\n        let frames = process(decoder, bytes, finish)?;\n        let mut result = (frames.len() as u32).to_le_bytes().to_vec();\n        for frame in frames {\n            result.extend_from_slice(&frame.sequence.to_le_bytes());\n            result.extend_from_slice(&(frame.png.len() as u32).to_le_bytes());\n            result.extend_from_slice(&frame.png);\n        }\n        Ok(result)\n    })\n}\n/// Caller allocates input, invokes one bounded operation and copies output before next call.\n/// 1=reference WASI init, 2=raw, 3=message, 4=bind, 5=finish, 6=in-memory JSON init.\n#[cfg_attr(feature = \"ffi\", unsafe(no_mangle))]\npub extern \"C\" fn odb_alloc(length: usize) -> *mut u8 {\n    if length > 4 * 1024 * 1024 {\n        return std::ptr::null_mut();\n    }\n    let v = vec![0u8; length].into_boxed_slice();\n    Box::into_raw(v) as *mut u8\n}\n/// # Safety\n/// Pointer and length must identify one live allocation returned by odb_alloc.\n#[cfg_attr(feature = \"ffi\", unsafe(no_mangle))]\npub unsafe extern \"C\" fn odb_free(pointer: *mut u8, length: usize) {\n    if !pointer.is_null() {\n        unsafe {\n            drop(Box::from_raw(std::ptr::slice_from_raw_parts_mut(\n                pointer, length,\n            )));\n        }\n    }\n}\n/// # Safety\n/// Pointer must reference length initialized input bytes for this call.\n#[cfg_attr(feature = \"ffi\", unsafe(no_mangle))]\npub unsafe extern \"C\" fn odb_call(operation: u32, pointer: *const u8, length: usize) -> i32 {\n    if length > 4 * 1024 * 1024 || pointer.is_null() {\n        return -1;\n    }\n    let input = unsafe { std::slice::from_raw_parts(pointer, length) };\n    let result = match operation {\n        1 => serde_json::from_slice(input)\n            .map_err(|e| e.to_string())\n            .and_then(init)\n            .map(|v| serde_json::to_vec(&v).unwrap()),\n        6 => serde_json::from_slice(input)\n            .map_err(|e| e.to_string())\n            .and_then(init_memory)\n            .map(|v| serde_json::to_vec(&v).unwrap()),\n        2 => push(input, false),\n        3 => convex_messages::decode(input).map(|v| serde_json::to_vec(&v).unwrap()),\n        4 => bind(input).map(|v| serde_json::to_vec(&v).unwrap()),\n        5 => push(&[], true),\n        _ => Err(\"Unknown decoder operation\".into()),\n    };\n    let (status, bytes) = match result {\n        Ok(v) => (0, v),\n        Err(e) => (-1, e.into_bytes()),\n    };\n    OUTPUT.with(|o| *o.borrow_mut() = bytes);\n    status\n}\n#[cfg_attr(feature = \"ffi\", unsafe(no_mangle))]\npub extern \"C\" fn odb_output_ptr() -> *const u8 {\n    OUTPUT.with(|o| o.borrow().as_ptr())\n}\n#[cfg_attr(feature = \"ffi\", unsafe(no_mangle))]\npub extern \"C\" fn odb_output_len() -> usize {\n    OUTPUT.with(|o| o.borrow().len())\n}\n\n#[cfg(test)]\nmod memory_tests {\n    use super::*;\n    #[test]\n    fn untrusted_memory_keys_and_budgets_are_rejected() {\n        for name in [\n            \"assets/../secret\",\n            \"assets/.hidden\",\n            \"other/x\",\n            \"assets/x/y\",\n            \"https://remote/x\",\n        ] {\n            let files = [(name.into(), vec![])].into_iter().collect();\n            assert!(resources::validate(&files).is_err());\n        }\n        let files = [(\"assets/x\".into(), vec![0; 4 * 1024 * 1024 + 1])]\n            .into_iter()\n            .collect();\n        assert!(resources::validate(&files).is_err());\n        let files = resources::ResourceStore::new();\n        let source = resources::Memory {\n            files: &files,\n            group: \"assets\",\n        };\n        use resources::Source;\n        assert!(source.read(\"A_Probe.bin\", 68).is_err());\n        assert!(!source.exists(\"B_Smooth.bin\").unwrap());\n    }\n    #[test]\n    fn original_palette_is_monotonic_and_keeps_dsc_index() {\n        let map = linear_gray_map();\n        assert_eq!(map.len(), 1024);\n        assert_eq!(&map[..4], &[0, 0, 0, 0]);\n        assert_eq!(&map[1020..], &[255, 255, 255, 255]);\n        for (i, pixel) in map.as_chunks::<4>().0.iter().enumerate() {\n            assert_eq!(*pixel, [i as u8; 4]);\n        }\n    }\n}\n"
  },
  "behavior": "Shared Rust Session for native and browser WASM: incremental framing, group admission, BFSP, DTGC, compound, temporal processing, DSC and PNG. Explicit selected image profiles are supported in memory; enhancement0 can run without unused spatial-filter banks. Hosts own USB, storage and display. The browser adapter supports either ABI6 in-memory resources or ABI7 from compatible built-in-profile runtimes. This registry artifact uses ABI6. Maximum256MiB WASM memory. Warmup, explicit state and bounded processing remain required. Reference replays and cross-target numerical differences are measured separately; no clinical or geometric calibration claim.",
  "ports": {
    "bytes": {
      "direction": "in",
      "kind": "stream",
      "contract": "odb.usb.bytes/1"
    },
    "frames": {
      "direction": "out",
      "kind": "stream",
      "contract": "odb.video.frame/1"
    }
  },
  "parameters": {},
  "fixtures": [],
  "evidence": [],
  "wasm": {
    "imports": [
      {
        "module": "wasi_snapshot_preview1",
        "name": "environ_get",
        "kind": "function"
      },
      {
        "module": "wasi_snapshot_preview1",
        "name": "environ_sizes_get",
        "kind": "function"
      },
      {
        "module": "wasi_snapshot_preview1",
        "name": "fd_close",
        "kind": "function"
      },
      {
        "module": "wasi_snapshot_preview1",
        "name": "fd_fdstat_get",
        "kind": "function"
      },
      {
        "module": "wasi_snapshot_preview1",
        "name": "fd_filestat_get",
        "kind": "function"
      },
      {
        "module": "wasi_snapshot_preview1",
        "name": "fd_prestat_get",
        "kind": "function"
      },
      {
        "module": "wasi_snapshot_preview1",
        "name": "fd_prestat_dir_name",
        "kind": "function"
      },
      {
        "module": "wasi_snapshot_preview1",
        "name": "fd_read",
        "kind": "function"
      },
      {
        "module": "wasi_snapshot_preview1",
        "name": "fd_write",
        "kind": "function"
      },
      {
        "module": "wasi_snapshot_preview1",
        "name": "path_filestat_get",
        "kind": "function"
      },
      {
        "module": "wasi_snapshot_preview1",
        "name": "path_open",
        "kind": "function"
      },
      {
        "module": "wasi_snapshot_preview1",
        "name": "proc_exit",
        "kind": "function"
      }
    ],
    "exports": [
      {
        "name": "memory",
        "kind": "memory"
      },
      {
        "name": "odb_alloc",
        "kind": "function"
      },
      {
        "name": "odb_call",
        "kind": "function"
      },
      {
        "name": "odb_free",
        "kind": "function"
      },
      {
        "name": "odb_output_len",
        "kind": "function"
      },
      {
        "name": "odb_output_ptr",
        "kind": "function"
      }
    ],
    "signature": "odb_call(i32,i32,i32) -> i32",
    "maximum_memory_bytes": 268435456,
    "bytes": 669941,
    "executed": false
  }
}