Misakachain commited on
Commit
0985c38
·
verified ·
1 Parent(s): f91546d

Initial import: PALW proof-of-compute runtime for Qwen3.6-35B-A3B (code + docs, no model weights)

Browse files
This view is limited to 50 files because it contains too many changes.   See raw diff
Files changed (50) hide show
  1. .github/workflows/palw-ci.yml +182 -0
  2. .gitignore +58 -0
  3. .python-version +1 -0
  4. LICENSE +202 -0
  5. LICENSES/llama.cpp-MIT.txt +29 -0
  6. NOTICE +46 -0
  7. README.md +271 -0
  8. SECURITY.md +34 -0
  9. config/qwen3.6-35b-a3b-claude-4.7-base-metadata.sha256 +7 -0
  10. config/qwen3.6-35b-a3b-claude-4.7-profile.json +112 -0
  11. config/runtime-pins.sh +118 -0
  12. docs/SETUP.md +81 -0
  13. docs/architecture.md +291 -0
  14. docs/cuda-receipt-v2-design.md +121 -0
  15. docs/evidence/cuda-v3-full-hook-sm89-2026-07-16.md +204 -0
  16. docs/evidence/cuda-v3-mmvq-hook-sm89-2026-07-15.md +188 -0
  17. docs/evidence/cuda-v3-release-kernel-manifest-sm89-2026-07-16.json +420 -0
  18. docs/evidence/cuda-v3-runtime-entrypoint-info-sm89-2026-07-16.json +90 -0
  19. docs/evidence/cuda-wsl-sm89-2026-07-15.md +175 -0
  20. docs/evidence/metal-hybrid-qwen36-2026-07-19.md +90 -0
  21. docs/evidence/metal-smoke-2026-07-15.md +336 -0
  22. docs/evidence/metal-smoke-schema-v4-2026-07-15.md +75 -0
  23. docs/protocol-v1.md +954 -0
  24. docs/receipt-implementation-qwen36.md +656 -0
  25. docs/receipt-review-remediation.md +214 -0
  26. docs/requirements.md +125 -0
  27. docs/runbook.md +493 -0
  28. docs/security-model.md +269 -0
  29. docs/state-machines.md +551 -0
  30. models/.gitkeep +1 -0
  31. patches/llama.cpp-palw-full.patch +0 -0
  32. patches/llama.cpp-palw-observer.patch +1792 -0
  33. pyproject.toml +12 -0
  34. receipts/final-v5/ab2b3196a6c0935aafd4d563a9d2e1d71d828cc87a378ae77b8e49c102033b68.complete +4 -0
  35. receipts/final-v5/ab2b3196a6c0935aafd4d563a9d2e1d71d828cc87a378ae77b8e49c102033b68.json +63 -0
  36. receipts/final-v5/ab2b3196a6c0935aafd4d563a9d2e1d71d828cc87a378ae77b8e49c102033b68.palw +0 -0
  37. receipts/final-v6/eb51b08c3b86ef5df2cdebcfa9fcef812ec72197b3ad40ae2c5ba68cf4278131.complete +4 -0
  38. receipts/final-v6/eb51b08c3b86ef5df2cdebcfa9fcef812ec72197b3ad40ae2c5ba68cf4278131.json +63 -0
  39. receipts/final-v6/eb51b08c3b86ef5df2cdebcfa9fcef812ec72197b3ad40ae2c5ba68cf4278131.palw +0 -0
  40. receipts/final-v7/8e2dd34b7609d6d7aeec17bff485eb1ae4db31f66dd899a3c3a3e671656053f9.complete +4 -0
  41. receipts/final-v7/8e2dd34b7609d6d7aeec17bff485eb1ae4db31f66dd899a3c3a3e671656053f9.json +87 -0
  42. receipts/final-v7/8e2dd34b7609d6d7aeec17bff485eb1ae4db31f66dd899a3c3a3e671656053f9.palw +0 -0
  43. runtime-palw/Cargo.lock +852 -0
  44. runtime-palw/Cargo.toml +62 -0
  45. runtime-palw/cuda/CMakeLists.txt +168 -0
  46. runtime-palw/cuda/README.md +683 -0
  47. runtime-palw/cuda/abi_contract_test.cpp +723 -0
  48. runtime-palw/cuda/accumulator.cu +411 -0
  49. runtime-palw/cuda/attention_trace.cu +58 -0
  50. runtime-palw/cuda/cuda_trace_test.cu +522 -0
.github/workflows/palw-ci.yml ADDED
@@ -0,0 +1,182 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ name: PALW protocol gates
2
+
3
+ on:
4
+ push:
5
+ pull_request:
6
+ workflow_dispatch:
7
+ inputs:
8
+ run_nvidia_experimental:
9
+ description: Run the non-production CUDA transport test on a labelled self-hosted runner
10
+ required: true
11
+ default: false
12
+ type: boolean
13
+ cuda_architecture:
14
+ description: Exact real SM architecture for the experimental CUDA build
15
+ required: true
16
+ default: 90-real
17
+ type: choice
18
+ options:
19
+ - 80-real
20
+ - 86-real
21
+ - 89-real
22
+ - 90-real
23
+
24
+ permissions:
25
+ contents: read
26
+
27
+ concurrency:
28
+ group: palw-${{ github.workflow }}-${{ github.ref }}-${{ github.event_name }}
29
+ cancel-in-progress: ${{ github.event_name != 'workflow_dispatch' }}
30
+
31
+ env:
32
+ CARGO_TERM_COLOR: always
33
+
34
+ jobs:
35
+ rust-msrv:
36
+ name: Rust 1.81 protocol core
37
+ runs-on: ubuntu-24.04
38
+ timeout-minutes: 20
39
+ steps:
40
+ - name: Check out sources
41
+ uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
42
+ with:
43
+ persist-credentials: false
44
+ - name: Install declared MSRV
45
+ run: rustup toolchain install 1.81.0 --profile minimal --component rustfmt,clippy
46
+ - name: Format
47
+ working-directory: runtime-palw
48
+ run: cargo +1.81.0 fmt --all -- --check
49
+ - name: Lint every target
50
+ working-directory: runtime-palw
51
+ run: cargo +1.81.0 clippy --locked --all-targets -- -D warnings
52
+ - name: Test every target
53
+ working-directory: runtime-palw
54
+ run: cargo +1.81.0 test --locked --all-targets
55
+
56
+ observer-clean-patch:
57
+ name: Pinned llama.cpp clean patch and native targets
58
+ runs-on: ubuntu-24.04
59
+ timeout-minutes: 30
60
+ steps:
61
+ - name: Check out PALW sources
62
+ uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
63
+ with:
64
+ persist-credentials: false
65
+ path: palw
66
+ - name: Check out the exact upstream llama.cpp commit
67
+ uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
68
+ with:
69
+ repository: ggml-org/llama.cpp
70
+ ref: 12127defda4f41b7679cb2477a4b0d65ee6a0c8f
71
+ fetch-depth: 1
72
+ persist-credentials: false
73
+ path: llama.cpp
74
+ - name: Verify and apply the pinned observer patch
75
+ working-directory: llama.cpp
76
+ run: |
77
+ source ../palw/config/runtime-pins.sh
78
+ test "$(git rev-parse HEAD)" = "${PALW_LLAMA_COMMIT}"
79
+ test "$(sha256sum ../palw/${PALW_LLAMA_PATCH_REL} | cut -d' ' -f1)" = "${PALW_LLAMA_PATCH_SHA256}"
80
+ git apply --check ../palw/${PALW_LLAMA_PATCH_REL}
81
+ git apply ../palw/${PALW_LLAMA_PATCH_REL}
82
+ git apply --reverse --check ../palw/${PALW_LLAMA_PATCH_REL}
83
+ - name: Configure deterministic CPU compile contract
84
+ run: >-
85
+ cmake -S llama.cpp -B build/llama-observer-ci
86
+ -DGGML_NATIVE=OFF
87
+ -DGGML_METAL=OFF
88
+ -DGGML_CUDA=OFF
89
+ -DGGML_CPU=ON
90
+ -DGGML_CPU_KLEIDIAI=OFF
91
+ -DGGML_ACCELERATE=OFF
92
+ -DGGML_BLAS=OFF
93
+ -DGGML_LTO=OFF
94
+ -DBUILD_SHARED_LIBS=ON
95
+ -DLLAMA_CURL=OFF
96
+ -DLLAMA_BUILD_TESTS=OFF
97
+ -DLLAMA_BUILD_EXAMPLES=OFF
98
+ -DLLAMA_BUILD_TOOLS=ON
99
+ -DLLAMA_BUILD_SERVER=ON
100
+ -DLLAMA_BUILD_APP=OFF
101
+ -DLLAMA_BUILD_UI=OFF
102
+ -DLLAMA_USE_PREBUILT_UI=OFF
103
+ -DLLAMA_OPENSSL=OFF
104
+ -DLLAMA_BUILD_NUMBER=10015
105
+ -DLLAMA_BUILD_COMMIT=12127def
106
+ -DCMAKE_BUILD_TYPE=Release
107
+ - name: Build every pinned native target
108
+ run: >-
109
+ cmake --build build/llama-observer-ci --parallel 2
110
+ --target llama-palw-observer llama-tokenize llama-cli llama-server
111
+ - name: Require the pinned runtime version and exact patch state
112
+ run: |
113
+ source palw/config/runtime-pins.sh
114
+ ./build/llama-observer-ci/bin/llama-palw-observer --version | grep -F 'version: 10015 (12127def)'
115
+ git -C llama.cpp apply --reverse --check ../palw/${PALW_LLAMA_PATCH_REL}
116
+
117
+ host-abi-sanitizers:
118
+ name: CUDA transport host ABI (ASan + UBSan)
119
+ runs-on: ubuntu-24.04
120
+ timeout-minutes: 15
121
+ steps:
122
+ - name: Check out sources
123
+ uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
124
+ with:
125
+ persist-credentials: false
126
+ - name: Configure host-only contracts
127
+ run: >-
128
+ cmake -S runtime-palw/cuda -B build/palw-cuda-sanitize
129
+ -DPALW_CUDA_TRACE_ENABLE_CUDA=OFF
130
+ -DBUILD_TESTING=ON
131
+ -DCMAKE_BUILD_TYPE=Debug
132
+ -DCMAKE_C_FLAGS=-Wall\ -Wextra\ -Wpedantic\ -Werror\ -fsanitize=address,undefined\ -fno-omit-frame-pointer
133
+ -DCMAKE_CXX_FLAGS=-Wall\ -Wextra\ -Wpedantic\ -Werror\ -fsanitize=address,undefined\ -fno-omit-frame-pointer
134
+ -DCMAKE_EXE_LINKER_FLAGS=-fsanitize=address,undefined
135
+ - name: Build host-only contracts
136
+ run: cmake --build build/palw-cuda-sanitize --parallel
137
+ - name: Test ABI, codec, and closed production gate
138
+ env:
139
+ ASAN_OPTIONS: detect_leaks=1:abort_on_error=1
140
+ UBSAN_OPTIONS: print_stacktrace=1:halt_on_error=1
141
+ run: ctest --test-dir build/palw-cuda-sanitize --output-on-failure -L host
142
+
143
+ cuda-device-experimental:
144
+ name: Experimental CUDA device transport (not R32)
145
+ if: github.event_name == 'workflow_dispatch' && inputs.run_nvidia_experimental
146
+ runs-on: [self-hosted, linux, x64, nvidia]
147
+ timeout-minutes: 30
148
+ env:
149
+ CUDA_VISIBLE_DEVICES: "0"
150
+ steps:
151
+ - name: Check out sources
152
+ uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
153
+ with:
154
+ persist-credentials: false
155
+ - name: Record NVIDIA toolchain and device
156
+ run: |
157
+ nvcc --version
158
+ nvidia-smi
159
+ - name: Require the selected device to match the exact SM class
160
+ env:
161
+ EXPECTED_ARCHITECTURE: ${{ inputs.cuda_architecture }}
162
+ run: |
163
+ compute_capability="$(nvidia-smi -i 0 --query-gpu=compute_cap --format=csv,noheader,nounits | tr -d '[:space:].')"
164
+ actual_architecture="${compute_capability}-real"
165
+ if [[ "${actual_architecture}" != "${EXPECTED_ARCHITECTURE}" ]]; then
166
+ echo "device 0 architecture ${actual_architecture} does not match ${EXPECTED_ARCHITECTURE}" >&2
167
+ exit 1
168
+ fi
169
+ - name: Configure one exact CUDA architecture
170
+ run: >-
171
+ cmake -S runtime-palw/cuda -B build/palw-cuda-device
172
+ -DPALW_CUDA_TRACE_ENABLE_CUDA=ON
173
+ -DPALW_CUDA_PRODUCTION_KERNEL_TRACE=OFF
174
+ -DBUILD_TESTING=ON
175
+ -DCMAKE_BUILD_TYPE=Release
176
+ -DCMAKE_CUDA_ARCHITECTURES=${{ inputs.cuda_architecture }}
177
+ - name: Build experimental CUDA transport
178
+ run: cmake --build build/palw-cuda-device --parallel
179
+ - name: Require both real device tests (skip 77 is a failure here)
180
+ run: |
181
+ ./build/palw-cuda-device/palw_cuda_trace_device_test
182
+ ./build/palw-cuda-device/palw_cuda_producer_device_test
.gitignore ADDED
@@ -0,0 +1,58 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # ── OS / editor ───────────────────────────────────────────────
2
+ .DS_Store
3
+
4
+ # ── Python env / caches ───────────────────────────────────────
5
+ .venv/
6
+ .pytest_cache/
7
+ .ruff_cache/
8
+ __pycache__/
9
+ *.py[cod]
10
+
11
+ # ── Rust build artifacts ──────────────────────────────────────
12
+ # Reproduced with `cargo build --locked` from the committed Cargo.lock.
13
+ runtime-palw/target/
14
+ runtime-palw/target-msrv/
15
+ **/target/
16
+
17
+ # ── CMake / native build outputs ──────────────────────────────
18
+ build/
19
+ runtime-palw/cuda/build-host-*/
20
+ **/CMakeCache.txt
21
+ **/CMakeFiles/
22
+
23
+ # ── Vendored llama.cpp ────────────────────────────────────────
24
+ # NOT committed (nested .git + large blobs). Reconstruct deterministically:
25
+ # git clone https://github.com/ggml-org/llama.cpp.git vendor/llama.cpp
26
+ # git -C vendor/llama.cpp checkout --detach 12127defda4f41b7679cb2477a4b0d65ee6a0c8f
27
+ # git -C vendor/llama.cpp apply ../../patches/llama.cpp-palw-full.patch
28
+ # See docs/SETUP.md.
29
+ vendor/
30
+
31
+ # ── Model weights (fetched at pinned revisions) ───────────────
32
+ # Fetch with scripts/hf_snapshot_download.py; verified against config/runtime-pins.sh hashes.
33
+ models/*
34
+ !models/.gitkeep
35
+ *.gguf
36
+ *.safetensors
37
+
38
+ # ── Runtime SQLite state (may embed sensitive execution state) ─
39
+ *.sqlite3
40
+ *.sqlite3-wal
41
+ *.sqlite3-shm
42
+
43
+ # ── Encrypted receipt bundles — NEVER publish ─────────────────
44
+ # .palw.bundle carries secret openings, signing key material, and registry
45
+ # snapshots (AEAD-sealed). Excluded everywhere by policy.
46
+ *.palw.bundle
47
+
48
+ # ── Receipts: keep only the README-referenced canonical evidence ─
49
+ # Track only the signed canonical receipt (.palw), public JSON (.json), and
50
+ # completion marker (.complete) under final-v5 / final-v6 / final-v7. Everything
51
+ # else (older runs, state DBs, bundles) stays local.
52
+ receipts/*
53
+ !receipts/final-v5/
54
+ !receipts/final-v6/
55
+ !receipts/final-v7/
56
+ receipts/final-v5/palw-state.sqlite3
57
+ receipts/final-v6/palw-state.sqlite3
58
+ receipts/final-v7/palw-state.sqlite3
.python-version ADDED
@@ -0,0 +1 @@
 
 
1
+ 3.12
LICENSE ADDED
@@ -0,0 +1,202 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ Apache License
3
+ Version 2.0, January 2004
4
+ http://www.apache.org/licenses/
5
+
6
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
7
+
8
+ 1. Definitions.
9
+
10
+ "License" shall mean the terms and conditions for use, reproduction,
11
+ and distribution as defined by Sections 1 through 9 of this document.
12
+
13
+ "Licensor" shall mean the copyright owner or entity authorized by
14
+ the copyright owner that is granting the License.
15
+
16
+ "Legal Entity" shall mean the union of the acting entity and all
17
+ other entities that control, are controlled by, or are under common
18
+ control with that entity. For the purposes of this definition,
19
+ "control" means (i) the power, direct or indirect, to cause the
20
+ direction or management of such entity, whether by contract or
21
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
22
+ outstanding shares, or (iii) beneficial ownership of such entity.
23
+
24
+ "You" (or "Your") shall mean an individual or Legal Entity
25
+ exercising permissions granted by this License.
26
+
27
+ "Source" form shall mean the preferred form for making modifications,
28
+ including but not limited to software source code, documentation
29
+ source, and configuration files.
30
+
31
+ "Object" form shall mean any form resulting from mechanical
32
+ transformation or translation of a Source form, including but
33
+ not limited to compiled object code, generated documentation,
34
+ and conversions to other media types.
35
+
36
+ "Work" shall mean the work of authorship, whether in Source or
37
+ Object form, made available under the License, as indicated by a
38
+ copyright notice that is included in or attached to the work
39
+ (an example is provided in the Appendix below).
40
+
41
+ "Derivative Works" shall mean any work, whether in Source or Object
42
+ form, that is based on (or derived from) the Work and for which the
43
+ editorial revisions, annotations, elaborations, or other modifications
44
+ represent, as a whole, an original work of authorship. For the purposes
45
+ of this License, Derivative Works shall not include works that remain
46
+ separable from, or merely link (or bind by name) to the interfaces of,
47
+ the Work and Derivative Works thereof.
48
+
49
+ "Contribution" shall mean any work of authorship, including
50
+ the original version of the Work and any modifications or additions
51
+ to that Work or Derivative Works thereof, that is intentionally
52
+ submitted to Licensor for inclusion in the Work by the copyright owner
53
+ or by an individual or Legal Entity authorized to submit on behalf of
54
+ the copyright owner. For the purposes of this definition, "submitted"
55
+ means any form of electronic, verbal, or written communication sent
56
+ to the Licensor or its representatives, including but not limited to
57
+ communication on electronic mailing lists, source code control systems,
58
+ and issue tracking systems that are managed by, or on behalf of, the
59
+ Licensor for the purpose of discussing and improving the Work, but
60
+ excluding communication that is conspicuously marked or otherwise
61
+ designated in writing by the copyright owner as "Not a Contribution."
62
+
63
+ "Contributor" shall mean Licensor and any individual or Legal Entity
64
+ on behalf of whom a Contribution has been received by Licensor and
65
+ subsequently incorporated within the Work.
66
+
67
+ 2. Grant of Copyright License. Subject to the terms and conditions of
68
+ this License, each Contributor hereby grants to You a perpetual,
69
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
70
+ copyright license to reproduce, prepare Derivative Works of,
71
+ publicly display, publicly perform, sublicense, and distribute the
72
+ Work and such Derivative Works in Source or Object form.
73
+
74
+ 3. Grant of Patent License. Subject to the terms and conditions of
75
+ this License, each Contributor hereby grants to You a perpetual,
76
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
77
+ (except as stated in this section) patent license to make, have made,
78
+ use, offer to sell, sell, import, and otherwise transfer the Work,
79
+ where such license applies only to those patent claims licensable
80
+ by such Contributor that are necessarily infringed by their
81
+ Contribution(s) alone or by combination of their Contribution(s)
82
+ with the Work to which such Contribution(s) was submitted. If You
83
+ institute patent litigation against any entity (including a
84
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
85
+ or a Contribution incorporated within the Work constitutes direct
86
+ or contributory patent infringement, then any patent licenses
87
+ granted to You under this License for that Work shall terminate
88
+ as of the date such litigation is filed.
89
+
90
+ 4. Redistribution. You may reproduce and distribute copies of the
91
+ Work or Derivative Works thereof in any medium, with or without
92
+ modifications, and in Source or Object form, provided that You
93
+ meet the following conditions:
94
+
95
+ (a) You must give any other recipients of the Work or
96
+ Derivative Works a copy of this License; and
97
+
98
+ (b) You must cause any modified files to carry prominent notices
99
+ stating that You changed the files; and
100
+
101
+ (c) You must retain, in the Source form of any Derivative Works
102
+ that You distribute, all copyright, patent, trademark, and
103
+ attribution notices from the Source form of the Work,
104
+ excluding those notices that do not pertain to any part of
105
+ the Derivative Works; and
106
+
107
+ (d) If the Work includes a "NOTICE" text file as part of its
108
+ distribution, then any Derivative Works that You distribute must
109
+ include a readable copy of the attribution notices contained
110
+ within such NOTICE file, excluding those notices that do not
111
+ pertain to any part of the Derivative Works, in at least one
112
+ of the following places: within a NOTICE text file distributed
113
+ as part of the Derivative Works; within the Source form or
114
+ documentation, if provided along with the Derivative Works; or,
115
+ within a display generated by the Derivative Works, if and
116
+ wherever such third-party notices normally appear. The contents
117
+ of the NOTICE file are for informational purposes only and
118
+ do not modify the License. You may add Your own attribution
119
+ notices within Derivative Works that You distribute, alongside
120
+ or as an addendum to the NOTICE text from the Work, provided
121
+ that such additional attribution notices cannot be construed
122
+ as modifying the License.
123
+
124
+ You may add Your own copyright statement to Your modifications and
125
+ may provide additional or different license terms and conditions
126
+ for use, reproduction, or distribution of Your modifications, or
127
+ for any such Derivative Works as a whole, provided Your use,
128
+ reproduction, and distribution of the Work otherwise complies with
129
+ the conditions stated in this License.
130
+
131
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
132
+ any Contribution intentionally submitted for inclusion in the Work
133
+ by You to the Licensor shall be under the terms and conditions of
134
+ this License, without any additional terms or conditions.
135
+ Notwithstanding the above, nothing herein shall supersede or modify
136
+ the terms of any separate license agreement you may have executed
137
+ with Licensor regarding such Contributions.
138
+
139
+ 6. Trademarks. This License does not grant permission to use the trade
140
+ names, trademarks, service marks, or product names of the Licensor,
141
+ except as required for reasonable and customary use in describing the
142
+ origin of the Work and reproducing the content of the NOTICE file.
143
+
144
+ 7. Disclaimer of Warranty. Unless required by applicable law or
145
+ agreed to in writing, Licensor provides the Work (and each
146
+ Contributor provides its Contributions) on an "AS IS" BASIS,
147
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
148
+ implied, including, without limitation, any warranties or conditions
149
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
150
+ PARTICULAR PURPOSE. You are solely responsible for determining the
151
+ appropriateness of using or redistributing the Work and assume any
152
+ risks associated with Your exercise of permissions under this License.
153
+
154
+ 8. Limitation of Liability. In no event and under no legal theory,
155
+ whether in tort (including negligence), contract, or otherwise,
156
+ unless required by applicable law (such as deliberate and grossly
157
+ negligent acts) or agreed to in writing, shall any Contributor be
158
+ liable to You for damages, including any direct, indirect, special,
159
+ incidental, or consequential damages of any character arising as a
160
+ result of this License or out of the use or inability to use the
161
+ Work (including but not limited to damages for loss of goodwill,
162
+ work stoppage, computer failure or malfunction, or any and all
163
+ other commercial damages or losses), even if such Contributor
164
+ has been advised of the possibility of such damages.
165
+
166
+ 9. Accepting Warranty or Additional Liability. While redistributing
167
+ the Work or Derivative Works thereof, You may choose to offer,
168
+ and charge a fee for, acceptance of support, warranty, indemnity,
169
+ or other liability obligations and/or rights consistent with this
170
+ License. However, in accepting such obligations, You may act only
171
+ on Your own behalf and on Your sole responsibility, not on behalf
172
+ of any other Contributor, and only if You agree to indemnify,
173
+ defend, and hold each Contributor harmless for any liability
174
+ incurred by, or claims asserted against, such Contributor by reason
175
+ of your accepting any such warranty or additional liability.
176
+
177
+ END OF TERMS AND CONDITIONS
178
+
179
+ APPENDIX: How to apply the Apache License to your work.
180
+
181
+ To apply the Apache License to your work, attach the following
182
+ boilerplate notice, with the fields enclosed by brackets "[]"
183
+ replaced with your own identifying information. (Don't include
184
+ the brackets!) The text should be enclosed in the appropriate
185
+ comment syntax for the file format. We also recommend that a
186
+ file or class name and description of purpose be included on the
187
+ same "printed page" as the copyright notice for easier
188
+ identification within third-party archives.
189
+
190
+ Copyright 2026 MISAKA-BTC
191
+
192
+ Licensed under the Apache License, Version 2.0 (the "License");
193
+ you may not use this file except in compliance with the License.
194
+ You may obtain a copy of the License at
195
+
196
+ http://www.apache.org/licenses/LICENSE-2.0
197
+
198
+ Unless required by applicable law or agreed to in writing, software
199
+ distributed under the License is distributed on an "AS IS" BASIS,
200
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
201
+ See the License for the specific language governing permissions and
202
+ limitations under the License.
LICENSES/llama.cpp-MIT.txt ADDED
@@ -0,0 +1,29 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ The following MIT License applies to ggml-org/llama.cpp, pinned at commit
2
+ 12127defda4f41b7679cb2477a4b0d65ee6a0c8f. This repository does not vendor the
3
+ llama.cpp source, but patches/llama.cpp-palw-full.patch redistributes
4
+ modifications to llama.cpp source files (a read-only graph observer and
5
+ experimental CUDA trace hooks) under this license.
6
+
7
+ --------------------------------------------------------------------------------
8
+
9
+ MIT License
10
+
11
+ Copyright (c) 2023-2026 The ggml authors
12
+
13
+ Permission is hereby granted, free of charge, to any person obtaining a copy
14
+ of this software and associated documentation files (the "Software"), to deal
15
+ in the Software without restriction, including without limitation the rights
16
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
17
+ copies of the Software, and to permit persons to whom the Software is
18
+ furnished to do so, subject to the following conditions:
19
+
20
+ The above copyright notice and this permission notice shall be included in all
21
+ copies or substantial portions of the Software.
22
+
23
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
24
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
26
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
28
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
29
+ SOFTWARE.
NOTICE ADDED
@@ -0,0 +1,46 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ MISAKA PALW runtime for Qwen3.6-35B-A3B
2
+ Copyright 2026 MISAKA-BTC
3
+
4
+ This product is licensed under the Apache License, Version 2.0 (see LICENSE).
5
+
6
+ ================================================================================
7
+ IMPORTANT — what this project is
8
+ ================================================================================
9
+ This repository is a PROOF-OF-COMPUTE RUNTIME that executes an unmodified
10
+ upstream Qwen3.6-35B-A3B mixture-of-experts model as a local compute worker and
11
+ commits the execution as a signed `ComputeReceiptV1`. It does NOT train,
12
+ fine-tune, or otherwise modify the model, and it is NOT itself a new language
13
+ model. Model weights are not distributed in this repository; they are fetched at
14
+ pinned upstream artifacts (see config/runtime-pins.sh). Production Network
15
+ readiness is NOT claimed — see docs/requirements.md for the In-progress
16
+ requirements.
17
+
18
+ ================================================================================
19
+ Third-party components
20
+ ================================================================================
21
+
22
+ 1. Qwen3.6-35B-A3B (huihui-ai abliterated release)
23
+ Base architecture Copyright Alibaba Cloud, licensed under the Apache License,
24
+ Version 2.0. Abliterated derivative by huihui-ai.
25
+ https://huggingface.co/huihui-ai/Huihui-Qwen3.6-35B-A3B-Claude-4.7-Opus-abliterated
26
+ https://ollama.com/huihui_ai/Qwen3.6-abliterated
27
+ Base metadata revision: ac18882735d037f6074a7630eb68d85db8234c25
28
+ GGUF artifact: Ollama huihui_ai/Qwen3.6-abliterated:35b-Claude-4.7,
29
+ blob sha256 1dc494614bee8a3bc00e79fe5a49da0fc1c36b3b118c4156e223e98e5a0a671b (Q4_K_M)
30
+ The upstream artifact is executed unmodified. Weights are fetched at the
31
+ pinned artifacts above and are not redistributed in this repository.
32
+
33
+ 2. llama.cpp (ggml-org/llama.cpp)
34
+ Copyright (c) 2023-2026 The ggml authors
35
+ Licensed under the MIT License.
36
+ https://github.com/ggml-org/llama.cpp
37
+ Pinned at commit 12127defda4f41b7679cb2477a4b0d65ee6a0c8f.
38
+ patches/llama.cpp-palw-observer.patch redistributes MODIFICATIONS to llama.cpp
39
+ source (a read-only graph observer and qwen35moe loader/graph fixes required
40
+ to run the pinned GGUF) under the MIT License. The llama.cpp source itself is
41
+ not vendored in this repository; it is reconstructed from the pinned commit
42
+ (see docs/SETUP.md). The full MIT license text is included at
43
+ LICENSES/llama.cpp-MIT.txt.
44
+
45
+ Rust crate dependencies retain their own upstream licenses as declared in
46
+ runtime-palw/Cargo.toml and runtime-palw/Cargo.lock.
README.md ADDED
@@ -0,0 +1,271 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # MISAKA PALW Runtime for Qwen3.6-35B-A3B (Claude-4.7, abliterated)
2
+
3
+ > **What this is — please read first.**
4
+ > This repository is a **proof-of-compute runtime** that runs an **unmodified,
5
+ > upstream Qwen3.6-35B-A3B** mixture-of-experts model as a local worker and
6
+ > commits a signed `ComputeReceiptV1` of the execution. The specific worker is
7
+ > `huihui_ai/Qwen3.6-abliterated:35b-Claude-4.7` (the abliterated
8
+ > `Huihui-Qwen3.6-35B-A3B-Claude-4.7-Opus` release). Earlier revisions of this
9
+ > runtime targeted dense Qwen3-8B; that dense profile has since been removed and
10
+ > Qwen3.6-35B-A3B is now the sole supported model.
11
+ > - It is **not** a newly trained or fine-tuned language model. The runtime is a
12
+ > wrapper around the upstream model, not a distinct model.
13
+ > - It does **not** contain or distribute model weights — the GGUF is fetched
14
+ > from the Ollama registry at a pinned blob digest and base metadata from the
15
+ > pinned Hugging Face revision (see [`config/runtime-pins.sh`](config/runtime-pins.sh)).
16
+ > - The model is **abliterated** (its refusal behavior has been reduced upstream).
17
+ > This runtime makes no claim about the model's safety properties; it only
18
+ > attests *that* a pinned computation ran.
19
+ > - It is **not production-ready**. Several protocol requirements
20
+ > (R13/R21/R23/R24/R26/R27/R32/R35) are still *In progress* and production
21
+ > Receipt issuance is intentionally fail-closed (see
22
+ > [`docs/requirements.md`](docs/requirements.md)).
23
+ > - A single self-attested Receipt is **not** a trustless or zero-knowledge
24
+ > proof of physical GPU execution; the design makes no TEE/ZK claims (see
25
+ > [`docs/security-model.md`](docs/security-model.md)).
26
+ >
27
+ > Licensed under Apache-2.0 — see [`LICENSE`](LICENSE) and [`NOTICE`](NOTICE).
28
+ > Third-party attribution (Qwen3.6-35B-A3B, llama.cpp) is in [`NOTICE`](NOTICE).
29
+
30
+ Qwen3.6-35B-A3B(MoE)をローカル計算ワーカーとして実行し、実行内容を
31
+ `ComputeReceiptV1` としてコミットするランタイムです。モデルの学習や
32
+ fine-tuning は行わず、PALW のロジックはすべてランタイム側に置きます。この
33
+ モデルは linear-attention(state-space / gated-delta-net)層と mixture-of-experts
34
+ 層を組み合わせたハイブリッド構成のため、MoE/SSM 演算を**忠実な canonical operation**へ写像し
35
+ (`ExpertRoute`/`ExpertGemm`/`SsmConv`/`GatedDeltaNet` 等)、CU は graph 非依存の
36
+ **semantic ルールセット v3** で commit し、各 GEMM を実 Metal kernel dispatch へ束縛します
37
+ (compute-gate track M1-M5、全て実機検証済み)。
38
+
39
+ このリポジトリは次の三層を分離します。
40
+
41
+ 1. `runtime-palw/`: Receipt、commitment、CU、schedule、検証、永続状態、
42
+ replica/audit/bond policy
43
+ 2. `vendor/llama.cpp/`: commit を固定した Qwen 推論ランタイムと read-only graph observer
44
+ 3. `runtime-palw/cuda/`: 実験的な CUDA V1/V2 trace transport(production 非発行)
45
+
46
+ ## 固定する上流 artifact
47
+
48
+ | Artifact | Upstream | Revision / variant |
49
+ |---|---|---|
50
+ | Base metadata | `huihui-ai/Huihui-Qwen3.6-35B-A3B-Claude-4.7-Opus-abliterated` | `ac18882735d037f6074a7630eb68d85db8234c25` |
51
+ | Local model artifact | Ollama `huihui_ai/Qwen3.6-abliterated:35b-Claude-4.7` | blob `1dc494614bee…a671b`, `Q4_K_M` |
52
+ | Runtime | `ggml-org/llama.cpp` | `12127defda4f41b7679cb2477a4b0d65ee6a0c8f`(PALW patch 適用) |
53
+
54
+ `Q4_K_M` は Qwen 公式配布 artifact をそのまま使用します。量子化は
55
+ `runtime_class_id` と manifest に含め、別の精度・量子化とは照合しません。
56
+
57
+ ## Quickstart — 自分のハードウェアで Qwen3.6 を測定する
58
+
59
+ **誰でも自分の Apple Silicon Mac で** pin された Qwen3.6-35B-A3B を実行し、署名済み Receipt を
60
+ 発行して別 process で検証できます。現状サポートは **Metal arm64**(Apple Silicon)です。手順の正本は
61
+ [`docs/runbook.md`](docs/runbook.md)。前提: Apple Silicon Mac、約 24GB の unified memory 推奨、
62
+ 約 30GB の空き、`git`/CMake/`uv`/`rustup`。
63
+
64
+ ```sh
65
+ # 1. clean checkout から一括導入(llama.cpp @ pinned commit + PALW patch を build、
66
+ # Ollama registry blob から Qwen3.6 GGUF(約24GB)+ base metadata を取得・照合)
67
+ ./scripts/install.sh
68
+ ./scripts/verify-install.sh # 固定 artifact hash / commit / Metal offload を独立検証
69
+
70
+ # 2. audit key(exact 32 raw bytes)を output の外に一度だけ作成
71
+ AUDIT_KEY="$HOME/.config/misaka-palw/audit-keys/local-audit.key"
72
+ install -d -m 700 "$(dirname "$AUDIT_KEY")"; test ! -e "$AUDIT_KEY"
73
+ (umask 077 && openssl rand 32 > "$AUDIT_KEY"); chmod 600 "$AUDIT_KEY"
74
+
75
+ # 3. Receipt 発行(prompt は stdin。ここでは例として capital-of-France を 2 token 生成)
76
+ OUT="receipts/manual-$(date +%Y%m%d-%H%M%S)"
77
+ printf '%s' 'The capital of France is' | runtime-palw/target/release/palw-metal-receipt \
78
+ --prompt-stdin --audit-key-file "$AUDIT_KEY" --output-dir "$OUT" --n-predict 2
79
+
80
+ # 4. 別 process で検証(status=local_restored / trust_scope=embedded_local_snapshot なら成功)
81
+ ID=$(basename "$OUT"/*.palw .palw)
82
+ runtime-palw/target/release/palw-verify-bundle \
83
+ --receipt "$OUT/$ID.palw" --bundle "$OUT/$ID.palw.bundle" \
84
+ --public-json "$OUT/$ID.json" --audit-key-file "$AUDIT_KEY" \
85
+ --state-db "$OUT/palw-state.sqlite3"
86
+ ```
87
+
88
+ 発行される公開 metadata(`<id>.json`)には CU ルールセット v3 の `canonical_compute_units`、
89
+ `semantic_schedule`、実捕捉 `expert_route`、`trace_evidence=metal_kernel`(各 GEMM を実 Metal
90
+ kernel dispatch へ束縛)、および `mint`(常に `eligible=false`、失格理由を自己申告)が含まれます。
91
+ job ID/nonce/salt/signing key は実行ごとに OS CSPRNG で生成されるため Receipt ID は証跡例と一致しません。
92
+ 参照 receipt は [`receipts/final-v7/`](receipts/final-v7)。**この Receipt は mint-grade ではなく、
93
+ mainnet 報酬には外部インフラが別途必要です**(下記「セキュリティ上の境界」)。
94
+
95
+ ## 現在の状態
96
+
97
+ Rust core、Metal graph observer、署名済み Self Local Receipt、schema v4 SQLite
98
+ replay/state registry、adversarial test suite は実装・実行済みです。対象モデルを
99
+ dense Qwen3-8B から hybrid Qwen3.6-35B-A3B(`huihui_ai/Qwen3.6-abliterated:35b-Claude-4.7`)へ
100
+ 移行し、Apple M1 Max(Metal、41/41 layer GPU offload)で実機ロード・推論・Receipt
101
+ 発行・別 process 検証まで確認しています。
102
+
103
+ hybrid モデルは linear-attention(SSM / gated-delta-net)層と mixture-of-experts 層を
104
+ 持つため、次を追加しました。
105
+
106
+ - pinned llama.cpp への qwen35moe loader/graph 互換修正(`vendor/llama.cpp/src/models/qwen35moe.cpp`、
107
+ PALW observer patch に同梱)。3-section mrope、`ssm_dt` naming、per-layer KV-head、
108
+ bundled vision/MTP tensor、per-layer attention reshape を扱う。
109
+ - Rust adapter の hybrid profile(`AdapterProfile::HybridQwen36A3B`): dense 演算は正確な
110
+ canonical operation へ**忠実に**写像する(`MUL_MAT_ID→ExpertGemm`、`ARGSORT→ExpertRoute`、
111
+ `SSM_CONV→SsmConv`、`GATED_DELTA_NET→GatedDeltaNet`、`L2_NORM→L2Norm`、`SUM_ROWS→Reduction`、
112
+ `CONCAT/CONT/CPY→TensorCopy`、`UNARY/SCALE/DIV/CLAMP→Elementwise`)。`VIEW`/`RESHAPE`/`PERMUTE`/
113
+ `TRANSPOSE` は layout-only、未列挙 op は fail-closed。**`Generic` 演算は廃止(M3)。**
114
+ - CU ルールセットは **v3 semantic**(`ComputeUnitRules::v3`): 観測 schedule は commitment-only とし、
115
+ canonical CU は pinned model 構造 + token 数から算出した graph 非依存の semantic 値を署名 commit。
116
+ dense Receipt は v1 のまま identity 不変。
117
+
118
+ Receipt 実装の詳細(observer JSONL v2、adapter 写像、CU 語彙、schedule、manifest、builder/verifier、
119
+ bundle、永続化、CLI 契約、実測値)は
120
+ [`docs/receipt-implementation-qwen36.md`](docs/receipt-implementation-qwen36.md) を正本とします。
121
+
122
+ **この Receipt は mint-grade ではありません。** `assess_mint_eligibility`(`runtime-palw/src/mint.rs`)
123
+ が全 receipt を `eligible=false, weight=0` と判定し、公開 JSON の `mint` ブロックに自己申告します。
124
+ 用途はローカル自己整合 receipt / testnet 計測 / Self-Local 非報酬に限られます。compute-gate track
125
+ (M1-M5、全て実機検証済み)で semantic CU v3 の canonical commitment・`Generic` 廃止・canonical
126
+ semantic schedule 再生成・実 MoE routing 捕捉・**各 GEMM の実 Metal kernel dispatch 束縛
127
+ (`trace_evidence=metal_kernel`、graph-fallback から昇格)** を実装しました。ただし Metal の
128
+ kernel-level trace は launch-geometry 束縛であり、CUDA V3 相当の intra-kernel accumulator proof
129
+ ではないため mint 不適格のまま(honest labeling)。残る失格理由は「Metal kernel-launch-bound sketch,
130
+ not an intra-kernel accumulator proof」/ 非 network-anchored / 非 bonded の 3 件。是正計画は
131
+ [`docs/receipt-review-remediation.md`](docs/receipt-review-remediation.md) を参照してください。
132
+
133
+ Apple M1 Max(macOS Metal)で hybrid モデルから生成した schema-v4 E2E artifact は
134
+ [`receipts/final-v7/8e2dd34b7609d6d7aeec17bff485eb1ae4db31f66dd899a3c3a3e671656053f9.palw`](receipts/final-v7/8e2dd34b7609d6d7aeec17bff485eb1ae4db31f66dd899a3c3a3e671656053f9.palw)、
135
+ 公開測定値は
136
+ [`receipts/final-v7/8e2dd34b7609d6d7aeec17bff485eb1ae4db31f66dd899a3c3a3e671656053f9.json`](receipts/final-v7/8e2dd34b7609d6d7aeec17bff485eb1ae4db31f66dd899a3c3a3e671656053f9.json)
137
+ にあります。Receipt ID は `8e2dd34b…6053f9`、verification bundle ID は `f5b8a296…dcf9db`、
138
+ CU ルールセットは **v3 semantic**(`43a5feef…7870ce`)、`evidence_level=gemm_traced`、
139
+ **`trace_evidence=metal_kernel`**。prompt 5 token + 2 生成 token の実行で observed schedule
140
+ 13,770 件(commitment-only)・GEMM sketch 2,466 件(各々実 Metal kernel dispatch へ束縛)・
141
+ **canonical compute units 41,692(v3 semantic)**、`semantic_schedule`(80 expert-route ops)、
142
+ **実捕捉した `expert_route`(240 record)** を committ し、別 process の `palw-verify-bundle` が
143
+ `status=local_restored` / `trust_scope=embedded_local_snapshot` で再検証しました。
144
+
145
+ dense Qwen3-8B の schema-v4 E2E artifact(Receipt ID `eb51b08c…78131`、bundle
146
+ `359f1bed…096e9`、`receipts/final-v6/`)と schema-v3 artifact(`receipts/final-v5/`)は、
147
+ 移行前の検証証跡として履歴保持します。hybrid モデルの Receipt は実行ごとに OS CSPRNG で
148
+ identity を生成するため ID は再現しません(`docs/runbook.md` の手順で生成・検証)。
149
+
150
+ 現行 release CLI が発行する単位は、署名済み `.palw`、認証付き暗号化
151
+ `.palw.bundle`、検証対象の公開 JSON、schema v4 の SQLite state、最後に作成する
152
+ `misaka.palw.receipt-set.v2` completion marker の一式です。秘密 opening、署名済み
153
+ request/assignment、検証用 registry snapshot は公開 JSON ではなく暗号化 bundle に封入します。
154
+ 公開 metadata は strict `misaka.palw.public-receipt.v2` で、unknown field を拒否し、保持する
155
+ artifact/observer field を authenticated bundle と照合します。`palw-verify-bundle` がこの一式を
156
+ 別 process で復元・再検証します。上記 `final-v5` のDBは旧schema v3であり、当時の検証証跡として
157
+ 保持します。schema v4 sourceはsilent migrationを行わず、旧DBをcurrent stateとしてopenしません。
158
+
159
+ repository-scope の設計・実装・evidence baseline はこの版で固定しますが、これは Production Network
160
+ readiness の完了を意味しません。R13/R21/R23/R24/R26/R27/R35 の未達gateは内部統合と外部境界を
161
+ [`docs/requirements.md`](docs/requirements.md) で分離し、R32 は `In progress` です。以下の CUDA
162
+ producer evidence は移行前 dense Qwen3-8B を対象とした legacy V2 CUDA track の測定記録で、現行 35B の
163
+ main path(Metal、41/41 offload)とは別系統として保持します。Windows WSL2の
164
+ Ubuntu 24.04、RTX 4060 Ti(sm_89)、CUDA Toolkit 13.3.1 / nvcc 13.3.73で、当時の固定 Qwen3-8B GGUFの37/37 layer CUDA
165
+ offloadとbatch 1 graph observerの6/6同一diagnostic streamを確認しました。さらにstandaloneの
166
+ producer-internal FP32 accumulator採取primitiveはsm_89 standalone device gate 7/7と20/20同一diagnostic
167
+ fingerprintを通過しています。vendored llama.cppのQ4_K/Q6_K MMVQ full-K pre-epilogue hookも
168
+ traced llama contextと同じCUDA backendへattachし、FA-off 1-token diagnostic E2Eで253 launch(Q4_K 216 /
169
+ Q6_K 37)を取得します。さらにFA-off eager attentionのQK GEMM 36、softmax 36、PV GEMM 36を同じ
170
+ request-local V3 producerへ統合し、合計361 recordを3回連続で完全取得して同一fingerprintとなること、
171
+ 5 work classそれぞれの先頭拒否がfail closedになることを確認しました。
172
+
173
+ CUDAはadditive 184-byte V2 codec、strict Rust full-stream/dispatch/runtime binder、authority署名と
174
+ runtime/job/schedule/integrationへbindする将来のReceipt V2 evidence candidateに加え、FA-off attentionの
175
+ canonical 3-sublaunch groupingを持つ452-byte V3 schema/binderを実装しています。
176
+ `ComputeReceiptV1`にはこのprovenanceをcommitするfieldがないため、builderとverifierはCUDA
177
+ `KernelSketch`をともにfail closedで拒否します。現行deterministic profileのFA-off eager attentionには
178
+ V3 schema/binderに加え、実QK-score/softmax/value-aggregation work直後の同一stream collectorと
179
+ typed graph associationをsourceへ統合しました。実機361-launch gate、exact mangled entry point、
180
+ runtime CUDA attributes、DSO/fatbin/cubin/section hashを結ぶrelease manifest、361-launchを厳密にbindする
181
+ Receipt/RuntimeManifest/Request/Assignment V2、暗号化Bundle V2、原子的SQLite V2は実装・検証済みです。
182
+ ただしlive C++ smokeはdiagnostic callbackであり、authority提供のcanonical physical-layout IDから
183
+ production署名Receiptを発行する経路ではありません。このため
184
+ `PALW_CUDA_TRACE_PRODUCTION_CAPABLE=0`、`PALW_CUDA_PRODUCER_VENDOR_RUNTIME_INTEGRATED=0`、
185
+ `PALW_CUDA_PRODUCER_RECEIPT_MAPPING_AVAILABLE=0`、`PALW_CUDA_PRODUCER_PRODUCTION_CAPABLE=0`
186
+ のままproduction CUDA Receipt発行は拒否されます。
187
+ 要件別の状態は同requirements matrixを正本とします。
188
+
189
+ Rust crate の宣言 MSRV は 1.81 です。open な transitive range が edition-2024 manifest の
190
+ `zeroize 1.9` / `base64ct 1.8.3` を選ぶと Cargo 1.81 が manifest を読めないため、互換版
191
+ `zeroize 1.8.1` / `base64ct 1.7.3` を exact pin しています。MSRV、host sanitizer、手動
192
+ experimental NVIDIA gate は [`.github/workflows/palw-ci.yml`](.github/workflows/palw-ci.yml)
193
+ にも定義しています。NVIDIA job は production approval や R32 completion を意味しません。
194
+
195
+ ## 開発・検証コマンド
196
+
197
+ 依存ツールとモデル取得用 Python 環境:
198
+
199
+ ```sh
200
+ uv sync --frozen
201
+ ```
202
+
203
+ 固定 artifact、4つの llama.cpp target、Metal device を再検証:
204
+
205
+ ```sh
206
+ ./scripts/verify-install.sh
207
+ ```
208
+
209
+ Rust 1.81 MSRV core gate と release CLI:
210
+
211
+ ```sh
212
+ rustup toolchain install 1.81.0 --profile minimal --component rustfmt,clippy
213
+ cargo +1.81.0 fmt --manifest-path runtime-palw/Cargo.toml --all -- --check
214
+ cargo +1.81.0 clippy --manifest-path runtime-palw/Cargo.toml --locked --all-targets -- -D warnings
215
+ cargo +1.81.0 test --manifest-path runtime-palw/Cargo.toml --locked --all-targets
216
+ cargo +1.81.0 build --release --locked --manifest-path runtime-palw/Cargo.toml \
217
+ --bin palw-metal-receipt --bin palw-verify-bundle
218
+ ```
219
+
220
+ 現行 MSRV test result は 224 passed、2 ignored(226 discovered)です。ignored 2件は pinned Qwen
221
+ model と Metal observer を必要とする実モデル test で、release build と汚染した親環境を使った
222
+ 手動 gate では 2/2 passed です。
223
+
224
+ 実モデル Receipt の生成、SQLite 検査、CUDA host/device gate は
225
+ [`docs/runbook.md`](docs/runbook.md) に記載します。実測証跡は
226
+ [`docs/evidence/metal-smoke-schema-v4-2026-07-15.md`](docs/evidence/metal-smoke-schema-v4-2026-07-15.md)
227
+
228
+ [`docs/evidence/cuda-wsl-sm89-2026-07-15.md`](docs/evidence/cuda-wsl-sm89-2026-07-15.md)
229
+
230
+ [`docs/evidence/cuda-v3-mmvq-hook-sm89-2026-07-15.md`](docs/evidence/cuda-v3-mmvq-hook-sm89-2026-07-15.md)
231
+
232
+ [`docs/evidence/cuda-v3-full-hook-sm89-2026-07-16.md`](docs/evidence/cuda-v3-full-hook-sm89-2026-07-16.md)
233
+ を参照してください。旧 schema-v3 の証跡は
234
+ [`docs/evidence/metal-smoke-2026-07-15.md`](docs/evidence/metal-smoke-2026-07-15.md)
235
+ に履歴として残します。
236
+
237
+ ## セキュリティ上の境界
238
+
239
+ Receipt は prompt、prompt token IDs、generated token IDs、出力 bytes、opening、private key、
240
+ owner salt を公開しません。Receipt CLI は `--prompt-stdin`、`--audit-key-file`、`--output-dir`
241
+ をすべて必須とし、prompt は UTF-8・非空・最大 1 MiB に限定します。argv で prompt を受ける
242
+ 互換入口はありません。Qwen adapter も prompt を tokenizer/native observer の argv に置かず
243
+ 専用 stdin pipe で渡し、通常の Receipt 実行では decoded output bytes を IPC JSONL から省略します。
244
+
245
+ audit key は output directory の外に置く exact 32-byte raw key で、同一 owner、single-link の
246
+ regular file、mode `0400` または `0600` を要求します。output directory は owner-only `0700`、
247
+ bundle と DB は `0600`、公開 `.palw` / JSON / marker は `0644` です。v2 marker は receipt ID、
248
+ bundle ID、公開 JSON の SHA-256 を結ぶ crash-completion signal ですが、秘密鍵付き MAC や
249
+ network authority の署名ではありません。marker 単独を真正性や maturity の根拠にせず、必ず
250
+ bundle verifier と trust policy を通します。
251
+
252
+ 一方、単独ノードが発行する Receipt はそれだけでゼロ知識の計算証明になるものでは
253
+ ありません。PALW の不正耐性は runtime/model digest、署名、k=2 replica、future audit、
254
+ canary、bond/slashing を組み合わせて成立します。Metal の graph fallback は CUDA kernel
255
+ trace ではありません。詳細は [`docs/security-model.md`](docs/security-model.md) を参照してください。
256
+
257
+ ローカル CLI が実行ごとに生成する scheduler/worker signing key、network ID、job ID は、この
258
+ ローカル証跡を相互に bind するための値です。production network の登録済み scheduler、worker
259
+ credential、beacon service、auditor、payment/escrow authority を表すものではありません。
260
+ replication/future auditに加え、scheduler-signed durable canary、authority-signed bond funding/appeal/
261
+ decision、assignment lock/release/slash/health、authority-confirmed External settlementのschema-v4 coreは
262
+ 統合されています。maturityは必要なassignment bondをrelease/linkし、`WorkTicketV2`はmaturity basisと
263
+ External weight grantをbindします。External settlementはterminal confirmation、両bond release、maturity、
264
+ ticketをlocal SQLite transactionでatomicにしますが、実payment railの資金移動そのものとのdistributed
265
+ atomicityは主張しません。これらを運用するproduction authority/governance/payment serviceはrepositoryの
266
+ 完了範囲外です。
267
+
268
+ Work Ticket の maturity は caller が raw flag で登録できません。field/constructor が非公開の
269
+ `MatureEvidence` を Self Local audit の `Mature` state、Self Replicated の typed k=2 pair、または
270
+ authority-confirmed External settlement だけが生成し、SQLite はその証拠、`maturity_basis_id`、
271
+ `mature_epoch`、必要なbond release linkを検査してから一回だけ`WorkTicketV2`へ消費します。
SECURITY.md ADDED
@@ -0,0 +1,34 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Security Policy
2
+
3
+ MisakaLM3-8B (the PALW runtime) is a cryptographic proof-of-compute project —
4
+ it uses Ed25519 signatures, XChaCha20-Poly1305 authenticated encryption, and a
5
+ bond/slashing protocol. We take security reports seriously.
6
+
7
+ ## Reporting a vulnerability
8
+
9
+ Please report vulnerabilities **privately** — do not open a public issue.
10
+
11
+ - **Preferred:** GitHub private security advisory —
12
+ *Security → Advisories → Report a vulnerability* on this repository.
13
+ - **Email:** info@misakachain.com
14
+
15
+ Include a description, the affected files/paths, and a reproduction if possible.
16
+ We aim to acknowledge within a few business days.
17
+
18
+ ## Scope and status
19
+
20
+ This is a **repository-scope research baseline, not a production deployment.**
21
+ Before reporting, please review:
22
+
23
+ - [`docs/security-model.md`](docs/security-model.md) — threat model and the
24
+ explicit, documented trust boundaries. In particular, a single self-attested
25
+ `ComputeReceiptV1` is **not** an independent cryptographic proof that a
26
+ specific physical GPU executed the work; the design makes no TEE/ZK claims,
27
+ and replica/audit tiers provide the compensating controls.
28
+ - [`docs/requirements.md`](docs/requirements.md) — requirements still marked
29
+ *In progress* (R13/R21/R23/R24/R26/R27/R32/R35); production Receipt issuance
30
+ is intentionally fail-closed while these are unmet.
31
+
32
+ Reports that restate these documented boundaries as if they were undisclosed
33
+ vulnerabilities may be closed with a pointer here, but genuine deviations from
34
+ the stated model are in scope and welcome.
config/qwen3.6-35b-a3b-claude-4.7-base-metadata.sha256 ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
 
1
+ af5f5d80880bf4e84c3c9d079dc0cb7839be2c4c9c11de7b48045c4458212dc6 README.md
2
+ 55d4931433fe502b794226ee7f4d206a6bdd436ac9f80eb7d8ebb4c639f9ea0c chat_template.jinja
3
+ 5e75e90b919ad0707bdb2bc609d25946a6ef27036dc2140620d0e6ea4d0d11ec config.json
4
+ 41b9356101ebf8e7519e150dc811f80c4226e727301fbb032b890f006ed0be83 model.safetensors.index.json
5
+ 14932921ca485d458a04dafd8069fbb0a4505622a48208d19ed247115801385b processor_config.json
6
+ 87a7830d63fcf43bf241c3c5242e96e62dd3fdc29224ca26fed8ea333db72de4 tokenizer.json
7
+ a8fd45a0a19ff87cad15511ecb8c576a6907d697018e0f55decb3d1d075a4499 tokenizer_config.json
config/qwen3.6-35b-a3b-claude-4.7-profile.json ADDED
@@ -0,0 +1,112 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "schema": "misaka.palw.model-profile-pin.v2",
3
+ "profile_name": "Qwen3.6-35B-A3B-Claude-4.7-Opus-abliterated-Q4_K_M-Metal-arm64",
4
+ "model": {
5
+ "architecture": "Qwen3_5MoeForConditionalGeneration",
6
+ "model_type": "qwen3_5_moe",
7
+ "gguf_architecture": "qwen35moe",
8
+ "hidden_size": 2048,
9
+ "attention_heads": 16,
10
+ "key_value_heads": 2,
11
+ "layers": 40,
12
+ "full_attention_interval": 4,
13
+ "head_dim": 256,
14
+ "intermediate_size": 512,
15
+ "shared_expert_intermediate_size": 512,
16
+ "expert_count": 256,
17
+ "experts_per_token": 8,
18
+ "linear_key_head_dim": 128,
19
+ "linear_value_head_dim": 128,
20
+ "linear_num_key_heads": 16,
21
+ "linear_num_value_heads": 32,
22
+ "linear_conv_kernel_dim": 4,
23
+ "rope_theta": 10000000,
24
+ "partial_rotary_factor_millionths": 250000,
25
+ "vocabulary_size": 248320,
26
+ "maximum_position_embeddings": 262144,
27
+ "base_dtype": "bfloat16",
28
+ "runtime_quantization": "Q4_K_M"
29
+ },
30
+ "base_artifact": {
31
+ "repository": "huihui-ai/Huihui-Qwen3.6-35B-A3B-Claude-4.7-Opus-abliterated",
32
+ "revision": "ac18882735d037f6074a7630eb68d85db8234c25",
33
+ "download_scope": "metadata-only",
34
+ "files": [
35
+ {
36
+ "path": "README.md",
37
+ "sha256": "af5f5d80880bf4e84c3c9d079dc0cb7839be2c4c9c11de7b48045c4458212dc6"
38
+ },
39
+ {
40
+ "path": "chat_template.jinja",
41
+ "sha256": "55d4931433fe502b794226ee7f4d206a6bdd436ac9f80eb7d8ebb4c639f9ea0c"
42
+ },
43
+ {
44
+ "path": "config.json",
45
+ "sha256": "5e75e90b919ad0707bdb2bc609d25946a6ef27036dc2140620d0e6ea4d0d11ec"
46
+ },
47
+ {
48
+ "path": "model.safetensors.index.json",
49
+ "sha256": "41b9356101ebf8e7519e150dc811f80c4226e727301fbb032b890f006ed0be83"
50
+ },
51
+ {
52
+ "path": "processor_config.json",
53
+ "sha256": "14932921ca485d458a04dafd8069fbb0a4505622a48208d19ed247115801385b"
54
+ },
55
+ {
56
+ "path": "tokenizer.json",
57
+ "sha256": "87a7830d63fcf43bf241c3c5242e96e62dd3fdc29224ca26fed8ea333db72de4"
58
+ },
59
+ {
60
+ "path": "tokenizer_config.json",
61
+ "sha256": "a8fd45a0a19ff87cad15511ecb8c576a6907d697018e0f55decb3d1d075a4499"
62
+ }
63
+ ]
64
+ },
65
+ "inference_artifact": {
66
+ "repository": "registry.ollama.ai/huihui_ai/Qwen3.6-abliterated",
67
+ "tag": "35b-Claude-4.7",
68
+ "revision": "1dc494614bee8a3bc00e79fe5a49da0fc1c36b3b118c4156e223e98e5a0a671b",
69
+ "path": "Qwen3.6-abliterated-35b-Claude-4.7-Q4_K_M.gguf",
70
+ "bytes": 23938321728,
71
+ "sha256": "1dc494614bee8a3bc00e79fe5a49da0fc1c36b3b118c4156e223e98e5a0a671b"
72
+ },
73
+ "runtime": {
74
+ "repository": "https://github.com/ggml-org/llama.cpp.git",
75
+ "commit": "12127defda4f41b7679cb2477a4b0d65ee6a0c8f",
76
+ "reported_version": "10015 (12127def)",
77
+ "supported_profile": "metal-arm64",
78
+ "build_directory": "vendor/llama.cpp/build-palw",
79
+ "targets": [
80
+ "llama-cli",
81
+ "llama-server",
82
+ "llama-tokenize",
83
+ "llama-palw-observer"
84
+ ],
85
+ "cmake_cache": {
86
+ "CMAKE_BUILD_TYPE": "Release",
87
+ "CMAKE_OSX_ARCHITECTURES": "arm64",
88
+ "LLAMA_BUILD_NUMBER": "10015",
89
+ "LLAMA_BUILD_COMMIT": "12127def",
90
+ "GGML_NATIVE": "OFF",
91
+ "GGML_METAL": "ON",
92
+ "GGML_METAL_EMBED_LIBRARY": "ON",
93
+ "GGML_METAL_SHADER_DEBUG": "ON",
94
+ "GGML_CPU_KLEIDIAI": "OFF",
95
+ "GGML_LTO": "OFF",
96
+ "GGML_CUDA": "OFF",
97
+ "BUILD_SHARED_LIBS": "ON",
98
+ "GGML_CPU": "ON",
99
+ "GGML_ACCELERATE": "ON",
100
+ "GGML_BLAS": "ON",
101
+ "GGML_BLAS_VENDOR": "Apple",
102
+ "LLAMA_BUILD_TESTS": "OFF",
103
+ "LLAMA_BUILD_EXAMPLES": "OFF",
104
+ "LLAMA_BUILD_TOOLS": "ON",
105
+ "LLAMA_BUILD_SERVER": "ON",
106
+ "LLAMA_BUILD_APP": "OFF",
107
+ "LLAMA_BUILD_UI": "OFF",
108
+ "LLAMA_OPENSSL": "OFF",
109
+ "LLAMA_USE_PREBUILT_UI": "OFF"
110
+ }
111
+ }
112
+ }
config/runtime-pins.sh ADDED
@@ -0,0 +1,118 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env bash
2
+ # shellcheck shell=bash
3
+ # shellcheck disable=SC2034
4
+ #
5
+ # Immutable upstream and build inputs for the supported PALW Metal profile.
6
+ # This file contains public identifiers only. Never add credentials here.
7
+
8
+ PALW_LLAMA_REPO_URL='https://github.com/ggml-org/llama.cpp.git'
9
+ PALW_LLAMA_COMMIT='12127defda4f41b7679cb2477a4b0d65ee6a0c8f'
10
+ PALW_LLAMA_COMMIT_SHORT='12127def'
11
+ PALW_LLAMA_VERSION='10015'
12
+ PALW_LLAMA_PATCH_REL='patches/llama.cpp-palw-observer.patch'
13
+ PALW_LLAMA_PATCH_SHA256='d155a88b7c11ee74f48011760cb1a37773a694c8cab28258ee108c85e2f9e02c'
14
+
15
+ # Inference artifact: the exact GGUF blob published by the Ollama registry
16
+ # model huihui_ai/Qwen3.6-abliterated, tag 35b-Claude-4.7. The registry blob
17
+ # digest is the SHA-256 of the GGUF itself, so revision == sha256 here.
18
+ PALW_GGUF_REGISTRY='registry.ollama.ai'
19
+ PALW_GGUF_REPO_ID='huihui_ai/Qwen3.6-abliterated'
20
+ PALW_GGUF_OLLAMA_TAG='35b-Claude-4.7'
21
+ PALW_GGUF_REVISION='1dc494614bee8a3bc00e79fe5a49da0fc1c36b3b118c4156e223e98e5a0a671b'
22
+ PALW_GGUF_FILENAME='Qwen3.6-abliterated-35b-Claude-4.7-Q4_K_M.gguf'
23
+ PALW_GGUF_SIZE='23938321728'
24
+ PALW_GGUF_SHA256='1dc494614bee8a3bc00e79fe5a49da0fc1c36b3b118c4156e223e98e5a0a671b'
25
+
26
+ PALW_BASE_REPO_ID='huihui-ai/Huihui-Qwen3.6-35B-A3B-Claude-4.7-Opus-abliterated'
27
+ PALW_BASE_REVISION='ac18882735d037f6074a7630eb68d85db8234c25'
28
+
29
+ PALW_LLAMA_DIR_REL='vendor/llama.cpp'
30
+ PALW_BUILD_DIR_REL='vendor/llama.cpp/build-palw'
31
+ PALW_GGUF_DIR_REL='models/Qwen3.6-abliterated-35b-Claude-4.7'
32
+ PALW_BASE_META_DIR_REL='models/Qwen3.6-35B-A3B-Claude-4.7-base-meta'
33
+ PALW_BASE_META_CHECKSUMS_REL='config/qwen3.6-35b-a3b-claude-4.7-base-metadata.sha256'
34
+ PALW_MODEL_PROFILE_REL='config/qwen3.6-35b-a3b-claude-4.7-profile.json'
35
+
36
+ PALW_BASE_METADATA_FILES=(
37
+ 'README.md'
38
+ 'chat_template.jinja'
39
+ 'config.json'
40
+ 'model.safetensors.index.json'
41
+ 'processor_config.json'
42
+ 'tokenizer.json'
43
+ 'tokenizer_config.json'
44
+ )
45
+
46
+ # The first sixteen entries reproduce the successful build-palw configure
47
+ # command. The final five make the effective Apple/Metal defaults explicit and
48
+ # prevent this profile from silently becoming a CUDA build.
49
+ PALW_METAL_CMAKE_ARGS=(
50
+ '-DCMAKE_BUILD_TYPE=Release'
51
+ '-DCMAKE_OSX_ARCHITECTURES=arm64'
52
+ '-DLLAMA_BUILD_NUMBER=10015'
53
+ '-DLLAMA_BUILD_COMMIT=12127def'
54
+ '-DGGML_NATIVE=OFF'
55
+ '-DGGML_METAL=ON'
56
+ '-DGGML_METAL_EMBED_LIBRARY=ON'
57
+ '-DGGML_METAL_SHADER_DEBUG=ON'
58
+ '-DGGML_CPU_KLEIDIAI=OFF'
59
+ '-DGGML_LTO=OFF'
60
+ '-DLLAMA_BUILD_TESTS=OFF'
61
+ '-DLLAMA_BUILD_EXAMPLES=OFF'
62
+ '-DLLAMA_BUILD_TOOLS=ON'
63
+ '-DLLAMA_BUILD_SERVER=ON'
64
+ '-DLLAMA_BUILD_APP=OFF'
65
+ '-DLLAMA_BUILD_UI=OFF'
66
+ '-DLLAMA_OPENSSL=OFF'
67
+ '-DLLAMA_USE_PREBUILT_UI=OFF'
68
+ '-DGGML_CUDA=OFF'
69
+ '-DBUILD_SHARED_LIBS=ON'
70
+ '-DGGML_CPU=ON'
71
+ '-DGGML_ACCELERATE=ON'
72
+ '-DGGML_BLAS=ON'
73
+ )
74
+
75
+ PALW_METAL_CACHE_EXPECTATIONS=(
76
+ 'CMAKE_BUILD_TYPE=Release'
77
+ 'CMAKE_OSX_ARCHITECTURES=arm64'
78
+ 'LLAMA_BUILD_NUMBER=10015'
79
+ 'LLAMA_BUILD_COMMIT=12127def'
80
+ 'GGML_NATIVE=OFF'
81
+ 'GGML_METAL=ON'
82
+ 'GGML_METAL_EMBED_LIBRARY=ON'
83
+ 'GGML_METAL_SHADER_DEBUG=ON'
84
+ 'GGML_CPU_KLEIDIAI=OFF'
85
+ 'GGML_LTO=OFF'
86
+ 'LLAMA_BUILD_TESTS=OFF'
87
+ 'LLAMA_BUILD_EXAMPLES=OFF'
88
+ 'LLAMA_BUILD_TOOLS=ON'
89
+ 'LLAMA_BUILD_SERVER=ON'
90
+ 'LLAMA_BUILD_APP=OFF'
91
+ 'LLAMA_BUILD_UI=OFF'
92
+ 'LLAMA_OPENSSL=OFF'
93
+ 'LLAMA_USE_PREBUILT_UI=OFF'
94
+ 'GGML_CUDA=OFF'
95
+ 'BUILD_SHARED_LIBS=ON'
96
+ 'GGML_CPU=ON'
97
+ 'GGML_ACCELERATE=ON'
98
+ 'GGML_BLAS=ON'
99
+ 'GGML_BLAS_VENDOR=Apple'
100
+ )
101
+
102
+ PALW_BUILD_TARGETS=(
103
+ 'llama-cli'
104
+ 'llama-server'
105
+ 'llama-tokenize'
106
+ 'llama-palw-observer'
107
+ )
108
+
109
+ readonly PALW_LLAMA_REPO_URL PALW_LLAMA_COMMIT PALW_LLAMA_COMMIT_SHORT
110
+ readonly PALW_LLAMA_VERSION PALW_LLAMA_PATCH_REL PALW_LLAMA_PATCH_SHA256
111
+ readonly PALW_GGUF_REGISTRY PALW_GGUF_REPO_ID PALW_GGUF_OLLAMA_TAG
112
+ readonly PALW_GGUF_REVISION
113
+ readonly PALW_GGUF_FILENAME PALW_GGUF_SIZE PALW_GGUF_SHA256
114
+ readonly PALW_BASE_REPO_ID PALW_BASE_REVISION PALW_LLAMA_DIR_REL
115
+ readonly PALW_BUILD_DIR_REL PALW_GGUF_DIR_REL PALW_BASE_META_DIR_REL
116
+ readonly PALW_BASE_META_CHECKSUMS_REL PALW_MODEL_PROFILE_REL
117
+ readonly -a PALW_BASE_METADATA_FILES PALW_METAL_CMAKE_ARGS
118
+ readonly -a PALW_METAL_CACHE_EXPECTATIONS PALW_BUILD_TARGETS
docs/SETUP.md ADDED
@@ -0,0 +1,81 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # SETUP — リポジトリの再構築手順
2
+
3
+ このリポジトリは **ソース・ドキュメント・パッチ・検証証跡のみ** を追跡します。
4
+ 以下は再現に必要だがサイズ・秘密の理由で追跡しない成果物と、その決定論的な再構築手順です。
5
+
6
+ | 追跡しないもの | 理由 | 再構築方法 |
7
+ |---|---|---|
8
+ | `vendor/llama.cpp/` | ネストした `.git`(~55MB)と大きな `.gguf` を含む | pinned commit + パッチ(下記 §1) |
9
+ | `models/**` (`*.gguf`, `*.safetensors`) | 数 GB のモデル重み | `scripts/hf_snapshot_download.py`(下記 §2) |
10
+ | `runtime-palw/target*/`, `build/`, `runtime-palw/cuda/build-host-*/` | ビルド生成物 | `cargo` / `cmake`(下記 §3) |
11
+ | `*.sqlite3`, `*.palw.bundle` | 実行時状態・暗号化された秘密素材(署名鍵・opening・registry snapshot) | ローカルにのみ保持。**公開しない** |
12
+
13
+ すべての固定値は [`../config/runtime-pins.sh`](../config/runtime-pins.sh)(公開識別子のみ、資格情報を含めない)が正本です。
14
+
15
+ ---
16
+
17
+ ## 1. llama.cpp(vendor)の再構築
18
+
19
+ ```sh
20
+ # 固定リビジョンで clone
21
+ git clone https://github.com/ggml-org/llama.cpp.git vendor/llama.cpp
22
+ git -C vendor/llama.cpp checkout --detach 12127defda4f41b7679cb2477a4b0d65ee6a0c8f
23
+
24
+ # PALW の変更を適用
25
+ git -C vendor/llama.cpp apply ../../patches/llama.cpp-palw-full.patch
26
+ ```
27
+
28
+ パッチは2種類あります。用途で選択してください。
29
+
30
+ | パッチ | 内容 | 用途 |
31
+ |---|---|---|
32
+ | `patches/llama.cpp-palw-observer.patch` | Metal read-only graph observer のみ(`scripts/install.sh` が SHA256 固定で自動適用) | サポート対象の Metal プロファイル再現 |
33
+ | `patches/llama.cpp-palw-full.patch` | 上記 observer に加え、**実験的 CUDA hooks**(`ggml-cuda/mmvq.cu`・`mmvf.cu`・`softmax.cu`・`ggml-cuda.cu`・`common.cuh` の trace hook、`tools/palw-mmvq-smoke/`、`llama-context` binder)を含む上位集合 | この repo の vendor 作業ツリー(CUDA 証跡採取に使用した状態)を完全再現 |
34
+
35
+ `llama.cpp-palw-full.patch` は、CUDA 証跡([`evidence/cuda-v3-full-hook-sm89-2026-07-16.md`](evidence/cuda-v3-full-hook-sm89-2026-07-16.md))を採取した際の vendor ローカル変更 21 ファイルをそのまま固めたものです。CUDA は実験的経路であり production Receipt を発行しません。
36
+
37
+ ---
38
+
39
+ ## 2. モデル重みの取得(固定リビジョン)
40
+
41
+ ```sh
42
+ python scripts/hf_snapshot_download.py
43
+ ```
44
+
45
+ 固定値([`config/runtime-pins.sh`](../config/runtime-pins.sh)):
46
+
47
+ | Artifact | Repo | Revision | 検証 |
48
+ |---|---|---|---|
49
+ | GGUF ランタイム artifact | `huihui_ai/Qwen3.6-abliterated`(Ollama `registry.ollama.ai`, tag `35b-Claude-4.7`) | `1dc494614bee8a3bc00e79fe5a49da0fc1c36b3b118c4156e223e98e5a0a671b` | `Qwen3.6-abliterated-35b-Claude-4.7-Q4_K_M.gguf`, size `23938321728`, SHA256 `1dc494614bee…5a0a671b` |
50
+ | Base metadata | `huihui-ai/Huihui-Qwen3.6-35B-A3B-Claude-4.7-Opus-abliterated` | `ac18882735d037f6074a7630eb68d85db8234c25` | `config/qwen3.6-35b-a3b-claude-4.7-base-metadata.sha256` と照合 |
51
+
52
+ 取得後、`scripts/verify_model_profile.py` がプロファイル定数と GGUF metadata を照合します。
53
+
54
+ ---
55
+
56
+ ## 3. ビルド & 検証
57
+
58
+ ```sh
59
+ # Rust protocol core(MSRV 1.81 固定)
60
+ rustup toolchain install 1.81.0 --profile minimal --component rustfmt,clippy
61
+ cargo +1.81.0 fmt --manifest-path runtime-palw/Cargo.toml --all -- --check
62
+ cargo +1.81.0 clippy --manifest-path runtime-palw/Cargo.toml --locked --all-targets -- -D warnings
63
+ cargo +1.81.0 test --manifest-path runtime-palw/Cargo.toml --locked --all-targets
64
+
65
+ # llama.cpp(Metal observer)+ E2E ヘルパ
66
+ ./scripts/install.sh
67
+ ./scripts/verify-install.sh
68
+ ```
69
+
70
+ CUDA 実験ゲート(NVIDIA 実機が必要)の詳細は [`requirements.md`](requirements.md) の R32/R35 と
71
+ [`evidence/`](evidence/) を参照してください。
72
+
73
+ ---
74
+
75
+ ## 4. 何が公開されているか(このリポジトリの範囲)
76
+
77
+ - **含む**: `runtime-palw/`(Rust protocol core + `cuda/` native ソース + tests)、`docs/`、`scripts/`、`config/`、`patches/`、`.github/`、README、`final-v5`/`final-v6` の canonical 証跡(`.palw` / `.json` / `.complete`)
78
+ - **含まない**: モデル重み、vendor チェックアウト、ビルド生成物、SQLite 状態、**暗号化 bundle(`.palw.bundle`)**
79
+
80
+ このスナップショットは repository-scope の設計・実装・evidence baseline を固定したものであり、
81
+ Production Network readiness を意味しません([`requirements.md`](requirements.md) 参照)。
docs/architecture.md ADDED
@@ -0,0 +1,291 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # PALW Runtime Architecture
2
+
3
+ ## 1. Scope
4
+
5
+ 本実装は Qwen3.6-35B-A3B(hybrid MoE/SSM)の学習済み model artifact と PALW mining logic を分離する。
6
+ model artifact は読み取り専用で開き、Receipt に関係する request、assignment、nonce、
7
+ commitment、署名、永続状態はランタイム側が生成・検証する。model artifact へ書き戻す
8
+ 処理は持たない。
9
+
10
+ 現在、実 model からReceipt発行・検証まで接続しているのは Apple arm64 / Metal の Self Local
11
+ graph-fallback pathである。CUDAではWindows WSL2 Ubuntu 24.04上のRTX 4060 Ti(sm_89)へ固定Qwenを37/37 layer
12
+ offloadしたdiagnostic graph observerに加え、same-backend vendored MMVQ V3 1-token diagnostic E2Eも実行済みだが、
13
+ production Receipt issuance pathではない。
14
+ Metal pathもlocal issuance/verification pathであり、production scheduler、network
15
+ admission/transport、beacon delivery、auditor re-execution、payment rail を含む production service
16
+ 全体が完成したという意味ではない。CUDA directory は実験 transport を実装するが、production
17
+ issuance gate は閉じている。
18
+
19
+ ## 2. Trust and execution layers
20
+
21
+ ### Layer 1 — Rust wrapper、manifest、Receipt
22
+
23
+ `palw-metal-receipt` は固定 artifact と host identity から完全な runtime manifest を作る。
24
+ manifest は GGUF と tokenizer artifact root、実際にロードする observer/dylib 群、llama.cpp
25
+ commit と local patch、CMake cache、OS/compiler/device/Metal identity、許可環境変数、固定
26
+ deterministic policy を binding する。
27
+
28
+ wrapper は必須の `--prompt-stdin` から最大 1 MiB の prompt を読み、argv で prompt を受ける
29
+ `--prompt TEXT` は実装しない。別途、output directory 外に置いた raw 32-byte key file を
30
+ `--audit-key-file` で必須指定する。scheduler key、署名済み `JobRequestV1` と `AssignmentV1`、
31
+ worker key、nonce、salt を OS CSPRNG から生成し、Qwen adapter を呼ぶ。現行 CLI が生成する
32
+ scheduler/worker registry は local fixture であり、production scheduler/governance registry ではない。
33
+ adapter が返したprompt/generated token IDsはprivate local opening、observer evidenceはverification witness
34
+ として保持する。どちらもcanonical Receiptには入れないが、evidenceはbundle public sectionへ含める。
35
+ Receipt 構築後は同じ manifest/evidence/opening で stateless verify、strict canonical round-trip、
36
+ secret scan を行い、成功時だけ canonical envelope、暗号化 verification bundle、公開 JSON、
37
+ durable DB を出力する。
38
+
39
+ worker Receipt、scheduler request/assignment、future beaconのEd25519 pathは`verify_strict`を使う。
40
+ worker signer、scheduler、beacon authorityのregistryはweak/small-order public keyを拒否し、opaqueな
41
+ verified/accepted typestateより前でkey identityとsignatureを確定する。
42
+
43
+ ### Layer 2 — native graph observer と strict Qwen adapter
44
+
45
+ 固定 commit の llama.cpp に `llama-palw-observer` target を加え、
46
+ `ggml_backend_sched_eval_callback` で実際に scheduler へ渡された graph node を順番に観測する。
47
+ graph mode は metadata だけを読み、sketch mode は `MUL_MAT`/`MUL_MAT_ID` の post-compute tensor
48
+ から固定 logical prefix を read-only copy して 256-bit の lossy graph sketch にする。raw tensor
49
+ 値は出力しない。
50
+
51
+ adapter は shell を使わず observer を起動し、prompt を argv ではなく専用 stdin pipe へ渡す。
52
+ 通常の Receipt 実行では `--emit-output-bytes` を指定せず、native JSONL の decoded output bytes
53
+ を空にする。stdout は versioned JSONL、stderr は bounded diagnostic channel として別々に読み、
54
+ prompt/output を error に埋め込まない。tokenizer、observer、host/source identity helper は inherited
55
+ environment を `env_clear` し、`LANG=C` と `LC_ALL=C` だけを復元する。host identity helper は
56
+ absolute executable path を使い、この完全な locale allowlist を manifest に bind する。
57
+
58
+ JSONL parser は header → event* → result の順序と一意性、schema/version、連続 event sequence、
59
+ Qwen3.6-35B-A3B shape/metadata、deterministic policy、41/41 full offload、prefill/decode step、token count、
60
+ tensor/GEMM shape、sketch width、graph-only trace claim を厳格に検査する。`MUL_MAT`、`RMS_NORM`、
61
+ `ROPE`、`SET_ROWS`、`SOFT_MAX`、`GLU`、`MUL`、`CONT`、`ADD`、`GET_ROWS` を versioned canonical
62
+ operation へ変換し、`VIEW`/`RESHAPE`/`PERMUTE` だけを layout metadata として除外する。GLU の
63
+ ような複合 node は複数 operation に展開する。未知 operation、未価格 operation、overflow、
64
+ 欠落/重複 event、CUDA kernel trace を偽る claim は fail-closed である。
65
+
66
+ ### Layer 3 — CUDA trace transport(R32 In progress・非発行)
67
+
68
+ CUDA directory のlegacy device observer は GEMM/attention final output の固定 tile を同一 stream 上で
69
+ sketch し、checked sequence、shape、tile index、V1 canonical 139-byte record、capacity/commit/copy、
70
+ sticky overflow、permanent poison を実装する。additive V2 transport は、declared origin、accumulator
71
+ stage/dtype、sketch scheme、reduction segment、producer dispatch digest を含むexact 184-byte wire
72
+ recordを定義し、native struct memoryやpaddingをwireとして扱わない。
73
+
74
+ これとは別にstandaloneの`palw_cuda_producer_capture_accumulator_f32`は、producerが渡すpre-epilogue
75
+ FP32 accumulatorを同じCUDA stream上でsketchする。exact function pointer/attribute、per-launch nonce、
76
+ record/mask/fault、全tile/segment coverageを検査するtrue-accumulator採取primitiveである。Windows WSL2
77
+ Ubuntu 24.04、
78
+ RTX 4060 Ti(sm_89)、CUDA Toolkit 13.3.1 / nvcc 13.3.73でstandalone/grouped CUDA CTest 8/8と
79
+ producer 20/20同一diagnostic fingerprintを確認した。さらにV3 captureはvendored Q4_K/Q6_K non-fused
80
+ MMVQ specializationのfull-K pre-epilogue位置と、FA-off QK-score/softmax/PV work直後へ接続済みである。
81
+ same-backend Qwen 1-token gateは253 MMVQと108 attention sublaunchの合計361/361 record、exact selected-
82
+ specialization attribute、3回同一diagnostic fingerprint、5 work classの選択launch拒否を確認した。
83
+
84
+ Rust側のV2 decoder/binderはunknown tagと不正なprovenance tupleを拒否し、attentionを含むunfiltered
85
+ 全record streamを、連続launch sequence、狭義増加schedule index、canonical tile/segment order、exact
86
+ MMVQ/flash-attention dispatch、CUDA runtime manifestへbindする。raw recordから得る
87
+ `BoundCudaTranscriptV1`はdiagnostic typestateである。さらにauthority署名、network/job/execution/
88
+ assignment、runtime class/manifest、producer integration、operation scheduleとfull transcriptを検証した
89
+ 場合だけ、public raw constructorを持たない`AuthorityBoundCudaTranscriptV2`からReceipt V2用
90
+ `AuthorityBoundCudaReceiptEvidenceV2`へproducer-accumulator GEMMを射影できる。attention recordはfull
91
+ transcript commitmentには残るが、GEMM evidenceには昇格しない。
92
+
93
+ 現行`ComputeReceiptV1`にはauthority provenance commitmentがないため、V1 builderとverifierはCUDA
94
+ `KernelSketch`をともに拒否する。FlashAttention-onlyのV2 transportで表せなかった固定QwenのFA-off
95
+ eager attentionに対し、additive 452-byte V3 schema/binderはQK-score MMVF、masked/scaled softmax、
96
+ value-aggregation MMVFのcanonical 3-sublaunch bundleを実装済みであり、各実work直後の同一stream collectorと
97
+ typed graph associationもsourceへ統合済みである。361-launch実機E2E、exact symbol/runtime attributesを
98
+ DSO/fatbin/cubin/ELF sectionへ結ぶrelease manifest、complete expected tableを検証する
99
+ Receipt/RuntimeManifest/Request/Assignment V2、暗号化Bundle V2、SQLite V2は実装・検証済みである。
100
+ live C++ callbackはなおdiagnostic IDを使用するため、authority提供のcanonical operation/plan/
101
+ physical-layout IDからproduction署名Receiptを作る経路には接続していない。
102
+
103
+ 固定Qwenは37/37 layerをCUDA offloadし、batch 1 graph observerの6/6同一diagnostic streamと、vendored
104
+ MMVQ/attention producerのsame-backend 361-record diagnostic E2Eを得た。これはhook coverageを証明するが、
105
+ production authority-connected proofではない。
106
+ `PALW_CUDA_TRACE_PRODUCTION_CAPABLE`、`PALW_CUDA_PRODUCER_VENDOR_RUNTIME_INTEGRATED`、
107
+ `PALW_CUDA_PRODUCER_RECEIPT_MAPPING_AVAILABLE`、`PALW_CUDA_PRODUCER_PRODUCTION_CAPABLE`はすべて0で、
108
+ `PALW_CUDA_PRODUCTION_KERNEL_TRACE=ON`はCMake configure errorのままである。したがってR32は
109
+ `In progress`であり、current CUDA evidenceをproduction Receiptへ昇格してはならない。
110
+
111
+ ## 3. Metal execution data flow
112
+
113
+ 1. model、tokenizer、observer/dylib、build/source/host identity から manifest を構築する。
114
+ 2. pinned runtime tokenizer で prompt token IDs を確定し、nonce で salted prompt commitment を作る。
115
+ 3. 署名済み job request と assignment を検証し、model/runtime/shape/evidence policy を固定する。
116
+ 4. observer を fixed policy(`n_ctx=4096`、batch/ubatch/request batch/thread=1、greedy、repack/
117
+ Flash Attention/context shift/speculation/tensor parallel 無効)で実行する。
118
+ 5. adapter が全 event を operation schedule hash chain、canonical CU counter、graph trace chain へ渡す。
119
+ 6. native run 後に manifest を再構築し、実行中の model/runtime artifact 変更がないことを確認する。
120
+ 7. token IDs、stop reason、scheduler-signed shared output nonce から output commitment を作る。
121
+ 8. owner commitment と job/execution nullifier を作り、worker が canonical `ComputeReceiptV1` を署名する。
122
+ 9. verifier が request/assignment/signer、manifest、policy、commitments、CU、schedule、trace、opening を検査する。
123
+ 10. caller-owned audit key から domain-separated AEAD subkey を導出し、request/assignment、worker
124
+ signer record、prompt/output opening、owner salt を XChaCha20-Poly1305 bundle の private sectionへ
125
+ 封入する。public sectionにはreceipt binding、verification epoch、scheduler key snapshot、manifest、
126
+ execution evidenceだけを置く。
127
+ 11. SQLite transaction が receipt ID、execution nullifier、job/slot と original acceptance epoch を
128
+ 一意に予約して `AcceptedReceipt` にする。
129
+ 12. WALを`TRUNCATE` checkpointし、DB connectionをdropしてmain DBを`fsync`する。その後、Receipt、
130
+ bundle、公開JSONをそれぞれ`fsync`し、receipt ID、bundle ID、公開JSON SHA-256を記録するcompletion
131
+ markerを最後に書き、output directoryを`fsync`する。
132
+ 13. Self Local はdurable future-audit transition、Self Replicated はtyped k=2 pair、External はauthority-
133
+ confirmed funded escrow settlementからだけopaque `MatureEvidence`を生成する。
134
+ 14. bonded production pathではmaturity transactionがsourceに必要な1件または2件のassignment bondを
135
+ releaseし、release IDをsourceへlinkする。link数がjob classのrequired replica数と一致しなければ
136
+ Work Ticketを発行しない。
137
+ 15. SQLite が証拠のnetwork/class/CU、`maturity_basis_id`、optional `weight_grant_id`、`mature_epoch`を
138
+ 保存し、そのepoch以後にsourceを一度だけ`WorkTicketV2`へ変換する。
139
+
140
+ output directory はowned non-symlink directoryかつmode `0700`、既存ならemptyでなければならない。
141
+ canonical Receipt、公開JSON、completion markerは`0644`、暗号化bundleとDBは`0600`で`create_new`
142
+ する。cross-file write全体は単一transactionではないため、late failure時に未完成artifactが残る
143
+ 可能性はあるが、marker-last ruleによりmarkerのないsetをverifierがcompleteとして受理しない。markerは
144
+ unkeyed plain textのcrash-completeness signalで、signature/AEAD authenticationではない。
145
+
146
+ ## 4. Identities
147
+
148
+ `model_profile_id` は architecture、tokenizer、trained precision と runtime quantization、shape、
149
+ weight/tokenizer/chat-template artifact root を識別する。実際にロードした GGUF 全体の SHA-256、
150
+ PALW artifact root、bytes、配布 revision も manifest に含める。
151
+
152
+ `runtime_class_id` は backend、runtime commit/source patch、driver/library versions、device class、
153
+ quantization、context/batch/ubatch/thread、sampling、adapter mapping、trace capability を識別する。
154
+
155
+ `runtime_manifest_hash` は実行時の完全 manifest の canonical digest である。同じ class label でも
156
+ binary、dylib、model、source patch、CMake/host identity が違えば manifest 検証で拒否する。
157
+
158
+ `request_commitment` と `signed_assignment_id` は Receipt を scheduler authorization へ binding し、
159
+ `job_nullifier` と `execution_nullifier` は別 domain で replay を防ぐ。Receipt signer の public key
160
+ は registry で解決し、canonical body には key ID だけを置く。
161
+
162
+ `verification_bundle_id` はcomplete encrypted envelopeを識別する。bundle public sectionはworker
163
+ public keyやopeningを公開しない。completion marker v2はreceipt ID、bundle ID、公開JSON SHA-256を
164
+ 記録するが、同じowner権限のwriterはJSONとmarkerを一緒に置換できる。authorityはstrict canonical
165
+ Receiptとauthenticated bundleにあり、markerを署名済みprotocol objectとして扱わない。
166
+
167
+ ## 5. Determinism boundary
168
+
169
+ 浮動小数点の bitwise determinism は runtime class 内だけで検証する。Metal/CUDA、異なる GPU、
170
+ driver、compiler、kernel class をまたいだ一致は要求しない。observer callback は read-only でも
171
+ synchronization と timing を変え得るため、observer mode/capability は runtime class の一部である。
172
+
173
+ 現行 Metal Receipt の `graph_fallback` は順序・shape・logical-prefix sketch を commit するが、
174
+ kernel execution の暗号学的 proof ではない。Self Local の重みは future audit なしに確定しない。
175
+
176
+ ## 6. Durable state and external jobs
177
+
178
+ SQLite registry は WAL、`synchronous=FULL`、foreign key、application ID、schema version 4 を検査する。
179
+ さらにtables/columns/foreign keys/indexだけでなく、全non-internal `sqlite_master`
180
+ `(type,name,tbl_name,sql)`をcanonical化したSHA3-256とcompiled goldenを照合し、同名objectのDDL mutation
181
+ もfail-closedにする。旧schema databaseの暗黙migrationは行わず、unclaimed nonempty DBも拒否する。
182
+
183
+ receipt、nullifier、job slot、replica pair、maturity source、Work Ticket v2、future-audit selection、signed
184
+ beacon provenance、audit replayに加え、authority-signed bond funding/appeal/decision、assignment bond、
185
+ release、slash/health、signed canary precommit、external escrow/payment command/terminalをtransactionで更新する。
186
+ receiptのoriginal `accepted_at_epoch`、pairの`matched_epoch`、signed beaconのepoch/provenance、audit
187
+ replayのaccepted epochをdurableに保持し、restart restore時にcurrent stateless verification epochと
188
+ 区別する。
189
+
190
+ maturity source に caller-supplied raw marker を受け付ける public API はない。Self Localでは、
191
+ authority-verified signed future beaconを保存した後、selected replayの受理・typed projection比較・
192
+ terminal verdict・passing maturity sourceを一transactionで確定する。non-selected auditもwindow経過と
193
+ maturity sourceを一transactionで確定する。`restore_audit` は保存したsigned beaconをcaller-supplied
194
+ network authority registryで再検証し、selection/challengeを再計算する。selected pass/mismatch terminalは
195
+ beacon rowだけのrestoreを`AuditReplayRequired`で拒否し、`restore_selected_audit_with_replay`がdurable
196
+ audit state/challenge、canonical replay、全identity/epochを照合する。さらにprojection verdictを再計算し、
197
+ match bit、submission commitment、completed epochをstored terminal outcomeへ再照合する。
198
+
199
+ `MatureEvidence` のfieldと低水準constructorは非公開で、durable Self Local auditのexact mature
200
+ state、Self Replicated `MatchedReplicaPair`、authority-confirmed External settlementだけが生成経路である。
201
+ `WorkTicketV2`はsourceに加えてaudit/pair/settlementの`maturity_basis_id`と、Externalだけに必須の
202
+ authority-signed `weight_grant_id`をbindする。ticket発行epochの前倒しとsource再消費を拒否する。
203
+
204
+ bond authorityはnetwork-scoped Ed25519 key、validity/revocation、funding/appeal/decision capabilityを検査する。
205
+ verified fundingだけがdurable accountをcreditし、scheduler-signed assignmentだけがfundsをlockする。
206
+ bonded Receiptは`accept_bonded`でactive exact lockを要求する。auditによるpassing maturity(canaryが
207
+ ある場合はterminal completion以後へ遅延)とk=2 pair maturityは、必要なassignmentを同じtransactionで
208
+ release/linkし、ticket issuerはlink countを再検査する。
209
+ typed audit mismatch/timeoutとcanary mismatch/receipt timeoutはslash、pending appeal balance、worker healthを
210
+ 同じtransactionで更新する。immutable targetを持つ複数claimのallocationはfinalized max-envelopeとpending
211
+ extensionへorder-independentに再計算し、v1 Equivocation追加penaltyは0である。authority-signed appealには
212
+ durable verification/acceptance epoch基準のdecision deadlineがあり、signed epochとaccepted epochの両方が
213
+ 期限内のuphold/reverseか、期限経過後のdeterministic default-upholdでterminalになる。unappealed slashも
214
+ appeal deadline後だけfinalizeする。
215
+
216
+ canaryはscheduler-signed precommit、exact signed request/assignment、bond lockを先にdurable保存する。
217
+ `accept_canary`はnormal Receipt acceptanceと`ReceiptSubmitted`をatomicにし、valid openingのpassは
218
+ terminalだけをcommit、mismatchはworker slashへ接続する。receipt deadline欠落はworker fault/slash、
219
+ receipt受理後のopening deadline欠落はscheduler faultとしてworker bondをslashしない。passと
220
+ OpeningMissingではbondをmaturityまで保持し、pending canary中のmaturityを拒否する。terminal canaryが
221
+ あるsourceのmature epochはcanary completion以後へ遅延し、そのmaturity transactionだけがbondを
222
+ `Mature` release/linkする。External Replicatedをhidden canaryにすることはv1で禁止する。
223
+
224
+ External Replicatedはauthority-signed exact funding attestationとfunded demand-weight grantからdurable
225
+ escrowを作り、scheduler-signed requestとk=2 pairをbindする。local payment commandを準備した後、authority-
226
+ verified terminal confirmationだけがterminalを確定できる。`SettlementPrepared` transitionは両worker bondが
227
+ activeでpending/upheld/default-final slashなしとpreflightする。`SettlementPrepared`または
228
+ `RefundPrepared`以後のnon-replay slashをcut offする。
229
+ settlement pathはconfirmation、maturity source、
230
+ 両worker bondのrelease/link、source consumption、`WorkTicketV2`を一つのSQLite transactionでcommitする。
231
+ refund pathはstate 1..3からexpiry後にpairの有無を問わず進め、terminalとeligible assignment bond releaseを
232
+ 一つのSQLite transactionでcommitする。pending claimのbondは解決までreleaseせず、maturity/ticketを生成しない。
233
+ ただし実payment rail上の資金移動とSQLite transactionはdistributed atomicではない。external authorityのfinality claimとkey governanceが
234
+ crate外のtrust boundaryである。
235
+
236
+ ## 7. Restart verification and trust scopes
237
+
238
+ verification bundle はXChaCha20-Poly1305(256-bit key、192-bit random nonce、128-bit tag)を使い、
239
+ canonical public section、receipt/public/nonceへbindしたAAD、encrypted private sectionを1つのstrict
240
+ envelopeにする。audit keyそのものとprivate signing-key seedはserializeしない。key fileはexact 32
241
+ bytes、nonzero、owner一致、single-link regular file、mode `0400`または`0600`を要求し、output/protected
242
+ artifactとのcolocation、symlink、inode alias、path raceを拒否する。
243
+
244
+ local restart APIはbundle内のembedded scheduler/worker snapshotでstateless verificationをやり直した
245
+ うえで、既存DB rowのcanonical Receipt、runtime instance、original acceptance epochへexact restore
246
+ する。CLIはReceipt/bundle/公開JSON/DBが同じowned `0700` directoryにexpected filename/modeで存在する
247
+ こと、marker v2とtyped公開JSON `misaka.palw.public-receipt.v2`全体がverified Receiptとauthenticated bundle manifest/evidenceへ一致
248
+ することも検査する。保持する`artifacts`と`observer_summary`を含む全fieldを照合し、unknown fieldは
249
+ objectの全階層で拒否する。DBにrowがなければinsertへfallbackしない。このmodeはlocal continuityの検証であり、
250
+ embedded snapshotをnetwork authorityとして第三者へ昇格しない。
251
+
252
+ default bundle restoreはoriginal acceptance時のhistorical verification epochを使う。future beacon後の
253
+ audit restoreには`verify_bundle_and_restore_at_epoch`を使い、caller-selected epochをhistorical値以上かつ
254
+ beacon以上へ進める。epoch rollbackは拒否し、durable original acceptance epochは上書きしない。このlocal
255
+ fresh pathはembedded key snapshotsを使い、bundle作成後のrevocationを学習できない。productionではcurrent
256
+ external trust rootsを必須にする`verify_bundle_and_restore_at_epoch_with_trust`を使う。現行
257
+ `palw-verify-bundle` CLIはdefault historical pathだけを呼び、fresh epochはlibrary/service APIで指定する。
258
+
259
+ 第三者向けstateless APIはexpected network、外部scheduler registry、外部worker registry、独立に
260
+ approvedされたmanifest hashを必須にし、embedded snapshotとのexact一致も検査する。default APIは
261
+ historical epoch、`verify_bundle_stateless_at_epoch_with_trust`はrollbackしないcaller-selected fresh epochで
262
+ 署名/validityを検証する。このstateless pathはDB acceptanceを行わない。既存DB continuityも同時に必要な
263
+ production restartは`verify_bundle_and_restore_at_epoch_with_trust`を使う。それでもnetwork admissionは
264
+ 別のservice decisionである。
265
+
266
+ ## 8. Build and CI boundary
267
+
268
+ Rust protocol core は edition 2021、MSRV 1.81 を宣言する。Cargo 1.81 が edition-2024 manifest を
269
+ 読めない transitive-resolution drift を防ぐため、crypto graph の `zeroize 1.8.1` と
270
+ `base64ct 1.7.3` を exact pin し、Clippy/test/release build は lockfile を必須にする。
271
+
272
+ CI は push/PR の pinned llama.cpp clean-checkout patch apply/CPU target build gate、Rust 1.81 all-target
273
+ gate、Linux host ABI sanitizer gateと、手動self-hosted NVIDIA experimental gateに分離する。NVIDIA jobは
274
+ skip code 77をfailureとするが、production capabilityを無効のまま実験transportだけをtestする。
275
+ したがってCI successとR32 production acceptanceは別のstateであり、workflowやhost fixtureからCUDA
276
+ Receipt発行権限を推論しない。
277
+
278
+ 現行sourceのRust all-target gateは224 passed / 2 ignored(226 discovered)である。WSL sm_89ではstandalone/grouped CUDA
279
+ suite 8/8とproducer device binary 20/20同一fingerprintに加え、vendored MMVQ/attention same-backend
280
+ Qwen diagnostic E2Eで361/361 record、3回同一fingerprint、5 work-class negativeを確認した。exact
281
+ release manifestも最終DSOに対してcreate/verify一致した。この実測はexperimental hook goalを完了するが、
282
+ production authority acceptanceではない。
283
+
284
+ production scheduler/network transport、governance-backed scheduler/worker/beacon/bond/external key
285
+ distribution、finalized beacon delivery、independent auditor execution/opening delivery、実payment railと
286
+ authority serviceはこのrepositoryに含まれない。durable coreへ自動接続済みのslash proofはaudit mismatch/
287
+ timeoutとcanary mismatch/receipt timeoutであり、invalid-manifest、equivocation、duplicate-executionの
288
+ production proof constructor/orchestrationは未統合である。CUDAのstandalone true-accumulator primitive、vendored
289
+ MMVQ/FA-off attention hook、same-backend 361-launch diagnostic E2E、release manifest、Receipt/Bundle/
290
+ SQLite V2は成立した。残るproduction範囲は、authority-derived canonical IDを使うlive callback、
291
+ deployed trust root、signed Receipt発行、独立restoreまでのfull-stream production E2Eである。
docs/cuda-receipt-v2-design.md ADDED
@@ -0,0 +1,121 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # CUDA Producer Transcript → Receipt V2 設計
2
+
3
+ ## 現在の安全境界
4
+
5
+ CUDA transport V2 の `ProducerAccumulator` は自己申告tagであり、それ単体はproducer由来の証明ではない。
6
+ また `ComputeReceiptV1` にはauthority証跡をcommitするfieldがない。このためRust側でも次をhard gateとする。
7
+
8
+ - CUDA `KernelSketch` を `build_signed_receipt` へ渡してもV1 Receiptを発行しない。
9
+ - workerがV1 bodyを手組み・署名してもstateless verifierが拒否する。
10
+ - Metal/開発用 `GraphFallback` とCUDA production provenanceは別のまま維持する。
11
+
12
+ ## 実装済みtypestate
13
+
14
+ ```text
15
+ RawCudaTraceRecordV2
16
+ -> bind_cuda_trace_v2
17
+ BoundCudaTranscriptV1
18
+ -> authority署名 + registry/runtime/job/schedule/full-stream検証
19
+ AuthorityBoundCudaTranscriptV2
20
+ -> deterministic mapping v1
21
+ AuthorityBoundCudaReceiptEvidenceV2
22
+ ```
23
+
24
+ `AuthorityBoundCudaTranscriptV2` と `AuthorityBoundCudaReceiptEvidenceV2` にはpublic raw constructorがない。
25
+ authority verificationは次を同時にbindする。
26
+
27
+ - network、job nullifier、execution nullifier
28
+ - signed assignment ID、runtime instance ID、assignment epoch範囲
29
+ - exact runtime class ID、complete runtime manifest hash
30
+ - operation schedule commitmentと全scheduled GEMM/attentionのexact coverage
31
+ - full unfiltered CUDA transcript commitment
32
+ - reviewed producer hook source/binary、entry-point table、accumulator extraction policyから成るintegration ID
33
+ - authority keyのnetwork、validity、revocation、exact integration/runtime approval
34
+
35
+ 射影時はproducer-accumulator GEMMだけを `KernelSketch` eventへ変換する。attention final-output recordは
36
+ GEMM evidenceへ昇格させないが、signed full-transcript commitmentには残る。raw `u64` sketch laneはbit patternを
37
+ 保ったまま既存のcanonical `i64` laneへ写像する。
38
+
39
+ vendored llama.cppのQ4_K/Q6_K MMVQ producerはV3 full-K pre-epilogue hookへ接続済みである。
40
+ same-backend Qwen 1-token diagnostic E2Eは253/253 record、3回同一fingerprintと選択launch拒否の
41
+ fail-closedを確認した。続いてFA-off QK/softmax/PVも接続し、253 MMVQ + 108 attention = 361 recordを
42
+ 3回同一fingerprintで取得した。Q4/Q6/QK/softmax/PV各先頭の拒否もfail closedである。
43
+
44
+ ## V2の非互換とV3 schemaの現状
45
+
46
+ 現行PALW deterministic Qwen profileは `flash_attention=false` で、実scheduleはeager/decomposed
47
+ `Attention` を含む。一方、CUDA V2が表現できるattention dispatchは
48
+ `CudaDispatchV1::LlamaFlashAttention` だけである。`bind_cuda_trace_v2` はattention launchがあるのに
49
+ runtimeがFA-offなら拒否し、authority layerは全scheduled GEMM/attention indexのexact coverageを要求する。
50
+
51
+ したがって次のどちらも通らない。
52
+
53
+ - `LlamaFlashAttention` recordをFA-off runtimeへbindする。
54
+ - attention recordを省略してGEMMだけをauthority-bound transcriptにする。
55
+
56
+ これはlegacy V2の意図したfail-closed状態であり、現行V2 candidateをproduction Qwen Receiptに
57
+ 使用可能とは扱わない。この非互換に対し、additive V3は452-byte record、eager/decomposed attentionの
58
+ exact shape/stage、1 scheduled `Attention`に対するQK-score MMVF、masked/scaled softmax、
59
+ value-aggregation MMVFのcanonical 3-sublaunch grouping、strict schedule/runtime binderを実装済みである。
60
+
61
+ 実eager-attention 3 entry point直後のV3 collectorとtyped graph associationはsourceへ接続済みである。
62
+ 361-launch実機E2E、strict expected table、actual runtime attributes、exact entry symbolとDSO/fatbin/cubinを
63
+ 結ぶrelease-manifest照合、Receipt V2のstateless bindingは実装・検証済みである。ただしlive C++ smokeは
64
+ diagnostic IDを生成し、authority-derived canonical physical-layout IDを受け取るproduction callbackではない。
65
+ したがってcurrent smokeをproduction Qwen Receiptに使用可能とは扱わない。flash attentionをproduction
66
+ deterministic policyで明示的に有効化する
67
+ 別案でも、再現性・algorithm identity・schedule/CU semanticsを別runtime classとして再承認する必要がある。
68
+
69
+ ## 実装済みReceipt V2 schema
70
+
71
+ 現行V1へauthority証跡を後付けすると、証跡を捨てても同じReceipt body/rootを作れてしまう。そこで次を
72
+ V1とtype-confusionしない新しいconsensus schemaとして実装した。
73
+
74
+ 1. `ComputeReceiptV2.receipt_version = 2`
75
+ 2. `trace_provenance_kind`(少なくとも `NoneOrGraph` / `CudaProducerAuthorityV1`)
76
+ 3. `trace_provenance_commitment`
77
+ 4. `RuntimeManifestV2` の `producer_integration_id` と `trace_provenance_policy_id`
78
+ 5. scheduler request/assignmentが選ぶrequired provenance policy
79
+ 6. `SignedReceiptV2` envelope discriminator(V1 bodyとのtype confusionを避ける)
80
+ 7. FA-off用eager/decomposed attention dispatchとsublaunch grouping
81
+
82
+ `trace_provenance_commitment` は実装済みのdomain-separated valueで、次をcommitする。
83
+
84
+ - authority attestation ID / authority key ID
85
+ - producer integration ID
86
+ - full bound transcript commitment
87
+ - mapping version
88
+ - projected trace scheme ID / root / event count
89
+
90
+ verification bundle V2はsigned authority envelope、raw V3 stream、expected launch table、six-entry release
91
+ table、producer integration descriptorを含み、secret openingをXChaCha20-Poly1305で暗号化する。verifierは
92
+ current registryを外部trust rootとして解決し、公式`verify_stateless_v2`でtypestateを再構築する。
93
+ SQLite V2はcomplete proof bytes、provenance commitment、network epoch watermarkを原子的に保存し、restart時に
94
+ body-to-proof binding、replay、rollback、exact restore rowを再検査する。
95
+
96
+ matcher、audit、maturity、WorkTicketはV1/V2を暗黙に同一視せず、V2 production policyが要求されたjobでは
97
+ authority-bound provenanceのstateless/durable verification完了を必須にする。
98
+
99
+ ## 実装済みadversarial gate
100
+
101
+ - missing / duplicate / reordered / metadata-mutated raw record拒否
102
+ - exact dispatch、SM、kernel binary/algorithm identity差分拒否
103
+ - forged authority signature、unknown/revoked/out-of-window key拒否
104
+ - cross-network / cross-job / cross-assignment / cross-runtime replay拒否
105
+ - runtime class、manifest、producer integration、schedule、transcript差分拒否
106
+ - scheduled GEMM/attentionの欠落拒否
107
+ - FA-off runtimeへの唯一のV2 attention dispatch (`LlamaFlashAttention`) binding拒否
108
+ - final-output GEMMのproducer evidence昇格拒否
109
+ - raw CUDA `KernelSketch` のV1 builder/verifier bypass拒否
110
+
111
+ ## 残るproduction blocker
112
+
113
+ - authority registry/governance/KMSサービスとproduction key lifecycle
114
+ - authority-derived canonical operation/plan/physical-layout IDをlive C++ approval callbackへ渡すbridge
115
+ - live raw transcriptから署名Receipt V2を発行し、deployed trust rootで独立restoreするproduction E2E
116
+ - checked-in release manifestとpolicyを承認するgovernance lifecycle
117
+ - NVIDIA実機でのfull-stream fault injectionと認可済みrepeatability/reproducibility matrix
118
+
119
+ authority署名は「登録authorityがこのexact transcriptとintegrationを承認した」ことを証明するが、authority自身が
120
+ producer内部値を正しく観測したことを純粋なEd25519署名だけで暗号学的に証明するものではない。脅威モデルが
121
+ authority compromiseを含む場合は、GPU/host attestation、TEE、または独立再実行proofを追加する。
docs/evidence/cuda-v3-full-hook-sm89-2026-07-16.md ADDED
@@ -0,0 +1,204 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # CUDA V3 full Qwen hook and V2 receipt evidence — SM89 — 2026-07-16
2
+
3
+ ## Scope and status
4
+
5
+ This is the repository evidence for the completed experimental CUDA goal on a
6
+ Windows/WSL2 RTX 4060 Ti host:
7
+
8
+ - a real pinned Qwen3-8B Q4_K_M model executes all 253 quantized MMVQ launches
9
+ for one evaluated token through the vendored V3 producer hook;
10
+ - the flash-attention-off path executes all 72 attention GEMMs (36 QK and 36
11
+ PV), plus 36 grouped softmax capture launches, through the vendored producer;
12
+ - the exact selected CUDA entry points, runtime function attributes, containing
13
+ cubins, fatbin, and loaded DSO are content-addressed by a strict release
14
+ manifest;
15
+ - Receipt, RuntimeManifest, Request/Assignment, encrypted Bundle, and atomic
16
+ SQLite persistence V2 bind and reverify the complete 361-launch profile; and
17
+ - production issuance remains deliberately unavailable. All capability macros
18
+ remain zero and the production CMake configuration fails closed.
19
+
20
+ This evidence does not claim a production CUDA Receipt. The live smoke result
21
+ explicitly reports `diagnostic_only=true` and `receipt_authority=false`. It also
22
+ does not claim multi-token/KV-continuation, FA-on, another GPU architecture, or
23
+ another model/weight profile.
24
+
25
+ No Tailscale address, SSH credential, GPU UUID, or signing secret is recorded in
26
+ this artifact.
27
+
28
+ ## Fixed model, host, and build
29
+
30
+ | Item | Recorded value |
31
+ | --- | --- |
32
+ | Host | Windows 11 / WSL2 Ubuntu |
33
+ | GPU | NVIDIA GeForce RTX 4060 Ti |
34
+ | CUDA architecture | `sm_89` |
35
+ | CUDA compiler | NVCC 13.3.73 |
36
+ | Model | `Qwen3-8B-Q4_K_M.gguf` |
37
+ | Model SHA-256 | `d98cdcbd03e17ce47681435b5150e34c1417f50b5c0019dd560e4882c5745785` |
38
+ | Build type | Release |
39
+ | Build directory | `/root/qwen-8.0/build/llama-palw-full-sm89-v2` |
40
+ | Loaded CUDA DSO | `bin/libggml-cuda.so` |
41
+ | Loaded DSO SHA-256 | `389bda6116c50eea8aebb9e1fcca1cc0145ab7245cb01d688024856c947f8e6f` |
42
+
43
+ The final CMake cache fixes `CMAKE_CUDA_ARCHITECTURES=89`, `GGML_CUDA=ON`,
44
+ `GGML_CUDA_PALW_TRACE=ON`, `GGML_CUDA_FA=OFF`, `GGML_CUDA_GRAPHS=OFF`, and
45
+ `GGML_CUDA_NCCL=OFF`.
46
+
47
+ ## Full real-model launch gate
48
+
49
+ The final smoke executable loaded the real 5,027,783,488-byte model, attached a
50
+ fresh request-local producer context, disabled flash attention, evaluated one
51
+ token at position zero, finalized the stream, and canonically encoded every V3
52
+ record.
53
+
54
+ Three independent positive invocations with the release-manifest cubin digests
55
+ all exited successfully with the following identical result:
56
+
57
+ | Field | Run 1 | Run 2 | Run 3 |
58
+ | --- | ---: | ---: | ---: |
59
+ | Total launches | 361 | 361 | 361 |
60
+ | Accepted | 361 | 361 | 361 |
61
+ | Records | 361 | 361 | 361 |
62
+ | Committed after finalize | 361 | 361 | 361 |
63
+ | Quantized MMVQ | 253 | 253 | 253 |
64
+ | Q4_K MMVQ | 216 | 216 | 216 |
65
+ | Q6_K MMVQ | 37 | 37 | 37 |
66
+ | Attention QK GEMM | 36 | 36 | 36 |
67
+ | Attention softmax | 36 | 36 | 36 |
68
+ | Attention PV GEMM | 36 | 36 | 36 |
69
+ | Canonical-record FNV-1a 64 | `22f3a57e3640a8c6` | `22f3a57e3640a8c6` | `22f3a57e3640a8c6` |
70
+
71
+ Thus the 72 FA-off attention GEMMs are exactly the 36 QK plus 36 PV launches.
72
+ The additional 36 softmax launches make the complete attention producer stream
73
+ 108 records and the complete MMVQ-plus-attention stream 361 records.
74
+
75
+ The FNV-1a value is a compact same-stack diagnostic reproducibility check. The
76
+ cryptographic artifact identity is supplied separately by the SHA-256 release
77
+ manifest; FNV-1a is not used as receipt authority.
78
+
79
+ ## Actual CUDA entry-point authority manifest
80
+
81
+ The release manifest was generated on the RTX host from the final loaded DSO
82
+ using CUDA 13.3 `cuobjdump`. The manifest parser independently extracts the
83
+ embedded cubins, requires an exact mangled-symbol match, parses the raw ELF
84
+ sections, and hashes the containing cubin plus symbol-scoped text and
85
+ `.nv.info` sections.
86
+
87
+ | Entry | Cubin SHA-256 | Registers | Max threads | Static shared bytes | Local bytes |
88
+ | --- | --- | ---: | ---: | ---: | ---: |
89
+ | Q4_K MMVQ | `3f9bfb88b5898b7d59b7fc39a01d7fda3b8ce4e270605b2d4cf29465907dfb64` | 40 | 128 | 384 | 0 |
90
+ | Q6_K MMVQ | `3f9bfb88b5898b7d59b7fc39a01d7fda3b8ce4e270605b2d4cf29465907dfb64` | 40 | 128 | 384 | 0 |
91
+ | Attention QK | `f04b5d1fb574c3558384bb37f261bc63be926cc0bef584b7a527977bd31b7237` | 40 | 1024 | 0 | 0 |
92
+ | Attention softmax | `31d368e4cffc8668bf678aebae93fd79d9b5a4fed626b2a1ce615efa77ce6903` | 22 | 1024 | 0 | 0 |
93
+ | Attention PV | `f04b5d1fb574c3558384bb37f261bc63be926cc0bef584b7a527977bd31b7237` | 34 | 1024 | 0 | 0 |
94
+ | Grouped collector | `09bb6b85776ba02de3b9e5aa457d090208ab25cb276ed63021020ebadc804435` | 44 | 1024 | 0 | 0 |
95
+
96
+ Every entry reported SM architecture, binary version, and PTX version 89. The
97
+ Q4/Q6 entries share one containing cubin, as do QK/PV; their exact symbols and
98
+ scoped ELF sections remain distinct.
99
+
100
+ The canonical artifacts are:
101
+
102
+ - [`cuda-v3-release-kernel-manifest-sm89-2026-07-16.json`](cuda-v3-release-kernel-manifest-sm89-2026-07-16.json)
103
+ - [`cuda-v3-runtime-entrypoint-info-sm89-2026-07-16.json`](cuda-v3-runtime-entrypoint-info-sm89-2026-07-16.json)
104
+
105
+ Recorded identities:
106
+
107
+ | Identity | Value |
108
+ | --- | --- |
109
+ | Release manifest ID (SHA3-256 protocol domain) | `4ededc7c257e13becbf74ebeecdff6c7bfe8ba84d550a6e07aa6cca52d9c7ce7` |
110
+ | DSO `.nv_fatbin` SHA-256 | `0654f8f423f059dccb94abf098fca2b47f106dcc6581f575756e6a985c6fa35c` |
111
+ | Loaded DSO SHA-256 | `389bda6116c50eea8aebb9e1fcca1cc0145ab7245cb01d688024856c947f8e6f` |
112
+
113
+ Creating and then independently verifying the manifest against the same final
114
+ DSO both returned the exact manifest ID above. The checked-in manifest bytes
115
+ have SHA-256
116
+ `849917d9def741ed7920661a57fbcdc16cb32e0c18836d1f454aa0c3e66133bf`,
117
+ identical to the file copied back from the RTX host.
118
+
119
+ The checked-in artifact is also a compile-time Rust integration fixture. The
120
+ strict `CudaReleaseKernelManifestV1` decoder validates its exact six-entry
121
+ authority requirement table, and the Receipt V2 end-to-end test uses that real
122
+ validated table to build, sign, and reverify the complete 361-launch receipt at
123
+ the next epoch. This gate also records the valid CUDA packaging case where an
124
+ extracted, uncompressed cubin is larger than the compressed `.nv_fatbin` bytes;
125
+ all cubins remain nonempty and every scoped section is bounded by its expanded
126
+ cubin size.
127
+
128
+ ## Fail-closed launch gates
129
+
130
+ Five negative invocations rejected the first occurrence of each work class.
131
+ Every invocation stopped llama decoding with the expected failure status; no
132
+ rejected or later launch was accepted.
133
+
134
+ | Reject index | Expected class | Accepted before rejection | Records before rejection |
135
+ | ---: | --- | ---: | ---: |
136
+ | 0 | Q4_K | 0 | 0 |
137
+ | 1 | Q6_K | 1 | 1 |
138
+ | 3 | Attention QK | 3 | 3 |
139
+ | 4 | Attention softmax | 4 | 4 |
140
+ | 5 | Attention PV | 5 | 5 |
141
+
142
+ Each result reported `status=expected_failure` and the matching
143
+ `rejected_class`. This complements the standalone CUDA device fault tests and
144
+ proves that every vendored work path honors the request-local approval boundary.
145
+
146
+ ## Receipt, manifest, bundle, and persistence V2
147
+
148
+ The Rust V2 flow is deliberately distinct from V1 and binds all of the
149
+ following before producing a verified typestate:
150
+
151
+ - signed RuntimeManifest, Request, Assignment, and Receipt V2 domains;
152
+ - network, epoch, authority lifetime, revocation, assignment, worker, job, and
153
+ execution identities;
154
+ - the approved six-entry release table, exact cubin digests, work/capture roles,
155
+ runtime CUDA attributes, and launch geometry;
156
+ - the exact ordered 361-launch transcript and its 216/37/36/36/36 class counts;
157
+ - Qwen3-8B, Q4_K_M, SM89, FA-off, batch-one, one-token policy;
158
+ - schedule, canonical compute units, output commitment, and stable projected
159
+ authority provenance.
160
+
161
+ Bundle V2 stores the full raw transcript and external trust material, encrypts
162
+ secret openings with XChaCha20-Poly1305, and reuses the official stateless V2
163
+ verifier as its only acceptance authority. SQLite V2 has a separate PAL2 schema
164
+ and application ID and atomically stores jobs, receipts, and bundles. It rejects
165
+ receipt, execution, assignment, and job-slot replay; stale network epochs;
166
+ rollback; torn transactions; schema mutation; and non-exact restore rows.
167
+
168
+ The integrated Rust gate discovered 226 tests and completed with 224 passed and
169
+ two ignored pre-existing Metal real-model tests. The CUDA V3, release-manifest,
170
+ protocol V2, receipt V2 flow, encrypted-bundle, restart, and SQLite V2 tests all
171
+ ran and passed. Additional gates passed:
172
+
173
+ - `cargo fmt --all -- --check`;
174
+ - `cargo clippy --locked --all-targets -- -D warnings`;
175
+ - rustdoc with `RUSTDOCFLAGS=-D warnings`;
176
+ - Rust 1.81 `cargo check --locked --all-targets`;
177
+ - Python release-manifest tests: 4/4;
178
+ - Apple host ABI/header/producer/bridge/closed-gate CTests: 5/5; and
179
+ - RTX SM89 ABI, device producer, grouped collector, manifest, and closed-gate
180
+ CTests: 8/8 with no skipped GPU test.
181
+
182
+ ## Production issuance remains closed
183
+
184
+ The following public capability values remain exactly zero:
185
+
186
+ ```text
187
+ PALW_CUDA_TRACE_PRODUCTION_CAPABLE=0
188
+ PALW_CUDA_PRODUCER_VENDOR_RUNTIME_INTEGRATED=0
189
+ PALW_CUDA_PRODUCER_RECEIPT_MAPPING_AVAILABLE=0
190
+ PALW_CUDA_PRODUCER_PRODUCTION_CAPABLE=0
191
+ PALW_CUDA_LLAMA_MMVQ_RECEIPT_MAPPING_AVAILABLE=0
192
+ PALW_CUDA_LLAMA_MMVQ_PRODUCTION_CAPABLE=0
193
+ ```
194
+
195
+ Configuring `PALW_CUDA_PRODUCTION_KERNEL_TRACE=ON` still fails with
196
+ `PALW CUDA production kernel trace is unavailable`, and the closed-gate CTest
197
+ passes on both host and RTX builds.
198
+
199
+ Before a future production gate can open, the diagnostic C++ approval callback
200
+ must consume authority-provided canonical operation/plan/physical-layout IDs,
201
+ the live raw transcript must be passed into the Rust verifier and signed-receipt
202
+ flow, and the resulting bundle must be independently restored under deployed
203
+ trust roots. General multi-token/KV continuation and additional approved
204
+ hardware/model profiles require separate evidence.
docs/evidence/cuda-v3-mmvq-hook-sm89-2026-07-15.md ADDED
@@ -0,0 +1,188 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # CUDA V3 vendored MMVQ hook SM89 diagnostic evidence — 2026-07-15
2
+
3
+ ## Scope and status
4
+
5
+ This is the repository evidence for a one-token, flash-attention-off diagnostic
6
+ run through the vendored llama.cpp Q4_K/Q6_K MMVQ producer hook on an RTX 4060
7
+ Ti. It establishes all of the following on the recorded stack:
8
+
9
+ - the dense Qwen3-8B Q4_K_M graph exposes exactly 253 supported quantized MMVQ
10
+ launches for one evaluated token;
11
+ - the request-local bridge associates those launches in order with the exact
12
+ graph operation token, weight allocation, shape, and quantization;
13
+ - the selected Q4_K and Q6_K producer specializations execute the V3 full-K
14
+ pre-epilogue FP32 accumulator capture and finalize one canonical V3 record per
15
+ launch; and
16
+ - an injected association rejection stops the request at the selected launch
17
+ without accepting later work.
18
+
19
+ This evidence is deliberately **diagnostic only**. Both positive and negative
20
+ results report `diagnostic_only=true` and `receipt_authority=false`. It does not
21
+ establish a complete attention transcript, production kernel-binary authority,
22
+ or a production CUDA Receipt. R13, R32, and R35 therefore remain `In progress`.
23
+
24
+ The earlier layer-offload, graph-observer, and standalone-producer device gates
25
+ remain recorded separately in
26
+ [`cuda-wsl-sm89-2026-07-15.md`](cuda-wsl-sm89-2026-07-15.md).
27
+ No Tailscale address, SSH credential, or GPU UUID is recorded here.
28
+
29
+ ## Fixed inputs and build
30
+
31
+ | Item | Recorded value |
32
+ | --- | --- |
33
+ | GPU | NVIDIA GeForce RTX 4060 Ti |
34
+ | Compute capability | 8.9 (`sm_89`) |
35
+ | CUDA compiler | NVCC 13.3.73 |
36
+ | Vendored llama.cpp base commit | `12127defda4f41b7679cb2477a4b0d65ee6a0c8f` |
37
+ | Model | `Qwen3-8B-Q4_K_M.gguf` |
38
+ | Remote build directory | `/root/qwen-8.0/build/llama-palw-hook-sm89-v1` |
39
+ | Loaded CUDA backend | `bin/libggml-cuda.so` |
40
+ | Loaded CUDA backend SHA-256 | `e8b357569b5845596775226b226eea77b2d3cd34eadc43207820e3c9f3fd6115` |
41
+
42
+ The executable was built with the experimental `GGML_CUDA_PALW_TRACE` path and
43
+ ran with all model layers assigned to the single CUDA backend, batch and ubatch
44
+ equal to one, and flash attention disabled. The relevant invocation was:
45
+
46
+ ```sh
47
+ LD_LIBRARY_PATH=/root/qwen-8.0/build/llama-palw-hook-sm89-v1/bin \
48
+ /root/qwen-8.0/build/llama-palw-hook-sm89-v1/bin/llama-palw-mmvq-smoke \
49
+ --model /root/qwen-8.0/models/Qwen3-8B/Qwen3-8B-Q4_K_M.gguf \
50
+ --kernel-binary-sha256 \
51
+ e8b357569b5845596775226b226eea77b2d3cd34eadc43207820e3c9f3fd6115
52
+ ```
53
+
54
+ The SHA-256 above is the whole loaded `libggml-cuda.so`, supplied explicitly to
55
+ the diagnostic tool. It is useful for identifying this build artifact, but it
56
+ is not an independently attested digest of the exact selected cubin/fatbin entry
57
+ point and is not a production manifest-authority assertion.
58
+
59
+ ## Positive one-token gate
60
+
61
+ The tool first used an untraced discovery context and then attached a fresh V3
62
+ producer context to the exact CUDA backend used by the traced llama context. An
63
+ approval callback required the next preapproved weight pointer, shape, and
64
+ quantization and a unique non-null graph operation token. The backend queried
65
+ `cudaFuncGetAttributes` from the same Q4_K or Q6_K specialization passed to the
66
+ V3 exact launch wrapper. Finalization validated record coverage and identity,
67
+ then encoded each record with the 452-byte canonical V3 codec before computing
68
+ the diagnostic FNV-1a value.
69
+
70
+ Three independent positive invocations all exited successfully with the same
71
+ values:
72
+
73
+ | Field | Run 1 | Run 2 | Run 3 |
74
+ | --- | ---: | ---: | ---: |
75
+ | `discovered` | 253 | 253 | 253 |
76
+ | `q4_k` | 216 | 216 | 216 |
77
+ | `q6_k` | 37 | 37 | 37 |
78
+ | `approved` | 253 | 253 | 253 |
79
+ | `accepted` | 253 | 253 | 253 |
80
+ | `records` | 253 | 253 | 253 |
81
+ | `committed` after finalize | 253 | 253 | 253 |
82
+ | `producer_faults` | 0 | 0 | 0 |
83
+ | `poisoned` | false | false | false |
84
+ | canonical-record FNV-1a 64 | `6618cafb2d66fc5c` | `6618cafb2d66fc5c` | `6618cafb2d66fc5c` |
85
+
86
+ The 253 records decompose exactly into 216 Q4_K and 37 Q6_K MMVQ launches. This
87
+ is one record per approved MMVQ launch in the smoke profile; it is not a claim
88
+ that the uninstrumented attention sublaunches are represented.
89
+
90
+ The exact selected-specialization diagnostics were also identical for Q4_K and
91
+ Q6_K:
92
+
93
+ | Attribute | Q4_K | Q6_K |
94
+ | --- | ---: | ---: |
95
+ | SM architecture | 89 | 89 |
96
+ | CUDA binary version | 89 | 89 |
97
+ | PTX version | 89 | 89 |
98
+ | Registers per thread | 40 | 40 |
99
+ | Maximum threads per block | 128 | 128 |
100
+ | Static shared memory bytes | 384 | 384 |
101
+ | Local memory bytes | 0 | 0 |
102
+
103
+ The bridge additionally checked nonzero, exact producer-variant, work-entry,
104
+ and capture-implementation identities against every finalized record. Those
105
+ source/dispatch-derived identifiers and the runtime attributes constrain this
106
+ diagnostic execution, but only a reviewed release manifest and authority can
107
+ turn them into an approved production identity.
108
+
109
+ The repeated `6618cafb2d66fc5c` value demonstrates same-stack diagnostic
110
+ repeatability for these three invocations. FNV-1a is only a compact diagnostic
111
+ fingerprint; it is not a cryptographic transcript commitment and does not prove
112
+ cross-driver, cross-GPU, or independently reproduced equality.
113
+
114
+ ## Negative association gate
115
+
116
+ The same executable was run with zero-based `--reject-index 17`. The approval
117
+ callback deliberately returned `PALW_CUDA_TRACE_IDENTITY_MISMATCH` for that
118
+ association. Indices 0 through 16 were accepted; index 17 and every later launch
119
+ were not. The process exited zero only because all fail-closed oracle conditions
120
+ matched:
121
+
122
+ | Field | Observed value |
123
+ | --- | ---: |
124
+ | `status` | `expected_failure` |
125
+ | `reject_index` | 17 |
126
+ | llama decode status | -3 |
127
+ | producer unbind status | 8 (`PALW_CUDA_TRACE_IDENTITY_MISMATCH`) |
128
+ | `accepted` | 17 |
129
+ | `records` | 17 |
130
+ | committed records | 0 |
131
+ | fault callbacks | 1 |
132
+ | producer device faults | 0 |
133
+ | producer poisoned | false |
134
+
135
+ This is specifically a scheduler/backend association failure. The single fault
136
+ callback reported an association mismatch, no rejected launch was enqueued, and
137
+ the producer remained unpoisoned because no asynchronous CUDA or device-view
138
+ fault occurred. The result proves ordered fail-closed cancellation at this
139
+ boundary; it does not substitute for separate device-fault and asynchronous
140
+ error-injection gates.
141
+
142
+ ## Complementary final verification gates
143
+
144
+ The source state used for this evidence also passed the following non-smoke
145
+ gates:
146
+
147
+ - Rust/Cargo 1.81.0 with `--locked`: 182 passed and 2 real-model tests ignored
148
+ (184 discovered). The passed tests were library 131, adversarial 12, bonded
149
+ maturity 3, canary durability 2, core flow 3, CUDA V2 contract 13, CUDA V3
150
+ contract 7, external bonded settlement 2, and restart/bundle 9.
151
+ - `cargo fmt --check`, Clippy with warnings denied, and rustdoc with warnings
152
+ denied all passed.
153
+ - The normal host CUDA-contract build passed 5/5 CTests.
154
+ - The AppleClang ASan+UBSan host build passed the same 5/5 CTests with no
155
+ sanitizer report.
156
+ - The RTX 4060 Ti SM89 build passed 7/7 CTests with no skipped device test.
157
+
158
+ These gates validate the codecs, bridge ABI, host failure contracts, standalone
159
+ device primitives, and Rust binding rules around the smoke run. They do not add
160
+ the missing attention or production-authority coverage listed below.
161
+
162
+ ## What remains before production completion
163
+
164
+ This gate closes the experimental vendored MMVQ-hook diagnostic item only. It
165
+ does not close any of the following:
166
+
167
+ 1. Wire the V3 FA-off eager-attention decomposition into the actual QK GEMM,
168
+ masked/scaled softmax, and PV GEMM producer launches and
169
+ prove complete ordered coverage.
170
+ 2. Build the live expected-sublaunch table from the authoritative Qwen schedule
171
+ and bind the complete MMVQ-plus-attention V3 stream through the Rust authority
172
+ typestate. The smoke tool's discovery callback is diagnostic scaffolding.
173
+ 3. Content-address and independently attest the actual release cubin/fatbin and
174
+ reviewed entry-point table, then bind them to the runtime manifest, authority
175
+ registry, governance, and key lifecycle. The whole-DSO hash above is not that
176
+ proof.
177
+ 4. Implement and independently verify the CUDA Receipt/Manifest/Request/Bundle/
178
+ SQLite V2 mapping and persistence path. CUDA evidence remains forbidden in a
179
+ `ComputeReceiptV1` issuance path.
180
+ 5. Pass full-stream fault injection plus approved replica, clean-rebuild,
181
+ cross-driver, and supported-hardware reproducibility matrices.
182
+
183
+ Until those gates close, `PALW_CUDA_LLAMA_MMVQ_RECEIPT_MAPPING_AVAILABLE`,
184
+ `PALW_CUDA_LLAMA_MMVQ_PRODUCTION_CAPABLE`,
185
+ `PALW_CUDA_PRODUCER_RECEIPT_MAPPING_AVAILABLE`,
186
+ `PALW_CUDA_PRODUCER_PRODUCTION_CAPABLE`, and
187
+ `PALW_CUDA_TRACE_PRODUCTION_CAPABLE` remain zero. Production Receipt issuance
188
+ must remain fail-closed.
docs/evidence/cuda-v3-release-kernel-manifest-sm89-2026-07-16.json ADDED
@@ -0,0 +1,420 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "authority_payload": {
3
+ "entries": [
4
+ {
5
+ "cubin": {
6
+ "elf_flags": 100686084,
7
+ "sha256": "f04b5d1fb574c3558384bb37f261bc63be926cc0bef584b7a527977bd31b7237",
8
+ "size": 4229392,
9
+ "target_arch": "sm_89"
10
+ },
11
+ "label": "attention_pv",
12
+ "runtime_attributes": {
13
+ "binary_version": 89,
14
+ "local_memory_bytes": 0,
15
+ "max_threads_per_block": 1024,
16
+ "num_regs": 34,
17
+ "ptx_version": 89,
18
+ "sm_arch": 89,
19
+ "static_shared_memory_bytes": 0
20
+ },
21
+ "scoped_sections": [
22
+ {
23
+ "alignment": 4,
24
+ "flags": 66,
25
+ "name": ".nv.constant0._Z13mul_mat_vec_fI6__halfS0_Li1ELi128ELb0ELb0EEvPKT_PKfPKi31ggml_cuda_mm_fusion_args_devicePfi5uint3iiiSA_iiiSA_iiii",
26
+ "sha256": "076a27c79e5ace2a3d47f9dd2e83e4ff6ea8872b3c2218f66c92b89b55f36560",
27
+ "size": 512,
28
+ "storage": "raw",
29
+ "type": 1
30
+ },
31
+ {
32
+ "alignment": 4,
33
+ "flags": 64,
34
+ "name": ".nv.info._Z13mul_mat_vec_fI6__halfS0_Li1ELi128ELb0ELb0EEvPKT_PKfPKi31ggml_cuda_mm_fusion_args_devicePfi5uint3iiiSA_iiiSA_iiii",
35
+ "sha256": "06f0e251abee94e479087c5853edcb658b1237de93ed1f561d755774e3c2e5ab",
36
+ "size": 500,
37
+ "storage": "raw",
38
+ "type": 1879048192
39
+ },
40
+ {
41
+ "alignment": 16,
42
+ "flags": 67,
43
+ "name": ".nv.shared._Z13mul_mat_vec_fI6__halfS0_Li1ELi128ELb0ELb0EEvPKT_PKfPKi31ggml_cuda_mm_fusion_args_devicePfi5uint3iiiSA_iiiSA_iiii",
44
+ "size": 0,
45
+ "storage": "nobits",
46
+ "type": 8
47
+ },
48
+ {
49
+ "alignment": 128,
50
+ "flags": 6,
51
+ "name": ".text._Z13mul_mat_vec_fI6__halfS0_Li1ELi128ELb0ELb0EEvPKT_PKfPKi31ggml_cuda_mm_fusion_args_devicePfi5uint3iiiSA_iiiSA_iiii",
52
+ "sha256": "1f6a2a6fc1112e02fdec8773ac7bd1055c41e85ae3254e02e12ab487237d4c62",
53
+ "size": 3584,
54
+ "storage": "raw",
55
+ "type": 1
56
+ }
57
+ ],
58
+ "semantic_binding": {
59
+ "capture_implementation_id": "c0a50513fee0ef0470636bf28a61c2f2b901c9cff650bdd2f58bd2fdc2921542",
60
+ "kernel_binary_digest_sha256": "f04b5d1fb574c3558384bb37f261bc63be926cc0bef584b7a527977bd31b7237",
61
+ "producer_variant_id": "e028f4560714ce35de86dc9346f7a23322951bffaa6d96d0f38ccbe6761f6a61",
62
+ "role": "work",
63
+ "work_entry_point_id": "e9d7c24faf7167a4ace7ec61bf721d8eb02e1f368a0293c798fcf12596c12d72"
64
+ },
65
+ "symbol": "_Z13mul_mat_vec_fI6__halfS0_Li1ELi128ELb0ELb0EEvPKT_PKfPKi31ggml_cuda_mm_fusion_args_devicePfi5uint3iiiSA_iiiSA_iiii"
66
+ },
67
+ {
68
+ "cubin": {
69
+ "elf_flags": 100686084,
70
+ "sha256": "f04b5d1fb574c3558384bb37f261bc63be926cc0bef584b7a527977bd31b7237",
71
+ "size": 4229392,
72
+ "target_arch": "sm_89"
73
+ },
74
+ "label": "attention_qk",
75
+ "runtime_attributes": {
76
+ "binary_version": 89,
77
+ "local_memory_bytes": 0,
78
+ "max_threads_per_block": 1024,
79
+ "num_regs": 40,
80
+ "ptx_version": 89,
81
+ "sm_arch": 89,
82
+ "static_shared_memory_bytes": 0
83
+ },
84
+ "scoped_sections": [
85
+ {
86
+ "alignment": 4,
87
+ "flags": 66,
88
+ "name": ".nv.constant0._Z13mul_mat_vec_fI6__halffLi1ELi64ELb0ELb0EEvPKT_PKfPKi31ggml_cuda_mm_fusion_args_devicePfi5uint3iiiSA_iiiSA_iiii",
89
+ "sha256": "076a27c79e5ace2a3d47f9dd2e83e4ff6ea8872b3c2218f66c92b89b55f36560",
90
+ "size": 512,
91
+ "storage": "raw",
92
+ "type": 1
93
+ },
94
+ {
95
+ "alignment": 4,
96
+ "flags": 64,
97
+ "name": ".nv.info._Z13mul_mat_vec_fI6__halffLi1ELi64ELb0ELb0EEvPKT_PKfPKi31ggml_cuda_mm_fusion_args_devicePfi5uint3iiiSA_iiiSA_iiii",
98
+ "sha256": "569beed4bcfdfde971aa30c94dcd9739ad8fd1a3cc1197041a59d400dc7dfe1b",
99
+ "size": 500,
100
+ "storage": "raw",
101
+ "type": 1879048192
102
+ },
103
+ {
104
+ "alignment": 16,
105
+ "flags": 67,
106
+ "name": ".nv.shared._Z13mul_mat_vec_fI6__halffLi1ELi64ELb0ELb0EEvPKT_PKfPKi31ggml_cuda_mm_fusion_args_devicePfi5uint3iiiSA_iiiSA_iiii",
107
+ "size": 0,
108
+ "storage": "nobits",
109
+ "type": 8
110
+ },
111
+ {
112
+ "alignment": 128,
113
+ "flags": 6,
114
+ "name": ".text._Z13mul_mat_vec_fI6__halffLi1ELi64ELb0ELb0EEvPKT_PKfPKi31ggml_cuda_mm_fusion_args_devicePfi5uint3iiiSA_iiiSA_iiii",
115
+ "sha256": "e50f5e46cc7fc13848b9fe520014bed2a52e79745c5c7204a3236a0e5f707a8c",
116
+ "size": 6400,
117
+ "storage": "raw",
118
+ "type": 1
119
+ }
120
+ ],
121
+ "semantic_binding": {
122
+ "capture_implementation_id": "c0a50513fee0ef0470636bf28a61c2f2b901c9cff650bdd2f58bd2fdc2921542",
123
+ "kernel_binary_digest_sha256": "f04b5d1fb574c3558384bb37f261bc63be926cc0bef584b7a527977bd31b7237",
124
+ "producer_variant_id": "0a299134085c7b67bfee9351427fa45a409c684b6533a70d9f41eacdcf805bb4",
125
+ "role": "work",
126
+ "work_entry_point_id": "f1112882f6d45fe2975c0012269229bbb3f5e21cdedfd0c085ccf3f53694b183"
127
+ },
128
+ "symbol": "_Z13mul_mat_vec_fI6__halffLi1ELi64ELb0ELb0EEvPKT_PKfPKi31ggml_cuda_mm_fusion_args_devicePfi5uint3iiiSA_iiiSA_iiii"
129
+ },
130
+ {
131
+ "cubin": {
132
+ "elf_flags": 100686084,
133
+ "sha256": "31d368e4cffc8668bf678aebae93fd79d9b5a4fed626b2a1ce615efa77ce6903",
134
+ "size": 195152,
135
+ "target_arch": "sm_89"
136
+ },
137
+ "label": "attention_softmax",
138
+ "runtime_attributes": {
139
+ "binary_version": 89,
140
+ "local_memory_bytes": 0,
141
+ "max_threads_per_block": 1024,
142
+ "num_regs": 22,
143
+ "ptx_version": 89,
144
+ "sm_arch": 89,
145
+ "static_shared_memory_bytes": 0
146
+ },
147
+ "scoped_sections": [
148
+ {
149
+ "alignment": 4,
150
+ "flags": 66,
151
+ "name": ".nv.constant0._Z12soft_max_f32ILb1ELi256ELi256EfEvPKfPKT2_S1_Pf15soft_max_params",
152
+ "sha256": "076a27c79e5ace2a3d47f9dd2e83e4ff6ea8872b3c2218f66c92b89b55f36560",
153
+ "size": 512,
154
+ "storage": "raw",
155
+ "type": 1
156
+ },
157
+ {
158
+ "alignment": 4,
159
+ "flags": 64,
160
+ "name": ".nv.info._Z12soft_max_f32ILb1ELi256ELi256EfEvPKfPKT2_S1_Pf15soft_max_params",
161
+ "sha256": "282f4482caa1aa8436716905e3ceaaf3e730f51e7daa48514f20788bc2032a37",
162
+ "size": 312,
163
+ "storage": "raw",
164
+ "type": 1879048192
165
+ },
166
+ {
167
+ "alignment": 16,
168
+ "flags": 67,
169
+ "name": ".nv.shared._Z12soft_max_f32ILb1ELi256ELi256EfEvPKfPKT2_S1_Pf15soft_max_params",
170
+ "size": 0,
171
+ "storage": "nobits",
172
+ "type": 8
173
+ },
174
+ {
175
+ "alignment": 128,
176
+ "flags": 6,
177
+ "name": ".text._Z12soft_max_f32ILb1ELi256ELi256EfEvPKfPKT2_S1_Pf15soft_max_params",
178
+ "sha256": "c63ad88792a49ace599f83e605d084cac913a598beca77e4c49540fdf3a598aa",
179
+ "size": 4480,
180
+ "storage": "raw",
181
+ "type": 1
182
+ }
183
+ ],
184
+ "semantic_binding": {
185
+ "capture_implementation_id": "c0a50513fee0ef0470636bf28a61c2f2b901c9cff650bdd2f58bd2fdc2921542",
186
+ "kernel_binary_digest_sha256": "31d368e4cffc8668bf678aebae93fd79d9b5a4fed626b2a1ce615efa77ce6903",
187
+ "producer_variant_id": "e74e46185a1164792446404386c2cf2ed3ae7f6c6726d72e26b1009d7e89c0cc",
188
+ "role": "work",
189
+ "work_entry_point_id": "eb58357f1b039704e68c9c71d9fda49f356b69bc234d18a64914f597caf4cffb"
190
+ },
191
+ "symbol": "_Z12soft_max_f32ILb1ELi256ELi256EfEvPKfPKT2_S1_Pf15soft_max_params"
192
+ },
193
+ {
194
+ "cubin": {
195
+ "elf_flags": 100686084,
196
+ "sha256": "09bb6b85776ba02de3b9e5aa457d090208ab25cb276ed63021020ebadc804435",
197
+ "size": 103016,
198
+ "target_arch": "sm_89"
199
+ },
200
+ "label": "grouped_collector",
201
+ "runtime_attributes": {
202
+ "binary_version": 89,
203
+ "local_memory_bytes": 0,
204
+ "max_threads_per_block": 1024,
205
+ "num_regs": 44,
206
+ "ptx_version": 89,
207
+ "sm_arch": 89,
208
+ "static_shared_memory_bytes": 0
209
+ },
210
+ "scoped_sections": [
211
+ {
212
+ "alignment": 4,
213
+ "flags": 66,
214
+ "name": ".nv.constant0._ZN56_GLOBAL__N__26eae2a6_23_producer_accumulator_cu_094d79ac35collect_grouped_final_output_f32_v3EPKfm33palw_cuda_producer_device_view_v337palw_cuda_producer_actual_identity_v3",
215
+ "sha256": "f4bd841308415de6ed2727462cd66a7333ac8155b4e8e95de0220355189c785c",
216
+ "size": 648,
217
+ "storage": "raw",
218
+ "type": 1
219
+ },
220
+ {
221
+ "alignment": 4,
222
+ "flags": 66,
223
+ "name": ".nv.constant2._ZN56_GLOBAL__N__26eae2a6_23_producer_accumulator_cu_094d79ac35collect_grouped_final_output_f32_v3EPKfm33palw_cuda_producer_device_view_v337palw_cuda_producer_actual_identity_v3",
224
+ "sha256": "106f52bc7d694dadb285f10109d0ce66a4ed1b6751fbc72c1752fec69980f796",
225
+ "size": 128,
226
+ "storage": "raw",
227
+ "type": 1
228
+ },
229
+ {
230
+ "alignment": 4,
231
+ "flags": 64,
232
+ "name": ".nv.info._ZN56_GLOBAL__N__26eae2a6_23_producer_accumulator_cu_094d79ac35collect_grouped_final_output_f32_v3EPKfm33palw_cuda_producer_device_view_v337palw_cuda_producer_actual_identity_v3",
233
+ "sha256": "2a4fe8a0afa52783b1bd49ce5a830a5079112ff9dfa79652195829fa16ea182c",
234
+ "size": 204,
235
+ "storage": "raw",
236
+ "type": 1879048192
237
+ },
238
+ {
239
+ "alignment": 128,
240
+ "flags": 6,
241
+ "name": ".text._ZN56_GLOBAL__N__26eae2a6_23_producer_accumulator_cu_094d79ac35collect_grouped_final_output_f32_v3EPKfm33palw_cuda_producer_device_view_v337palw_cuda_producer_actual_identity_v3",
242
+ "sha256": "37a0bca9a5e01be7a1595146e6b92938499be614bd8ca155ff9781b70121eb4b",
243
+ "size": 75008,
244
+ "storage": "raw",
245
+ "type": 1
246
+ }
247
+ ],
248
+ "semantic_binding": {
249
+ "capture_implementation_id": "c0a50513fee0ef0470636bf28a61c2f2b901c9cff650bdd2f58bd2fdc2921542",
250
+ "kernel_binary_digest_sha256": "09bb6b85776ba02de3b9e5aa457d090208ab25cb276ed63021020ebadc804435",
251
+ "producer_variant_id": null,
252
+ "role": "capture",
253
+ "work_entry_point_id": null
254
+ },
255
+ "symbol": "_ZN56_GLOBAL__N__26eae2a6_23_producer_accumulator_cu_094d79ac35collect_grouped_final_output_f32_v3EPKfm33palw_cuda_producer_device_view_v337palw_cuda_producer_actual_identity_v3"
256
+ },
257
+ {
258
+ "cubin": {
259
+ "elf_flags": 100686084,
260
+ "sha256": "3f9bfb88b5898b7d59b7fc39a01d7fda3b8ce4e270605b2d4cf29465907dfb64",
261
+ "size": 97838152,
262
+ "target_arch": "sm_89"
263
+ },
264
+ "label": "q4_k",
265
+ "runtime_attributes": {
266
+ "binary_version": 89,
267
+ "local_memory_bytes": 0,
268
+ "max_threads_per_block": 128,
269
+ "num_regs": 40,
270
+ "ptx_version": 89,
271
+ "sm_arch": 89,
272
+ "static_shared_memory_bytes": 384
273
+ },
274
+ "scoped_sections": [
275
+ {
276
+ "alignment": 4,
277
+ "flags": 66,
278
+ "name": ".nv.constant0._Z13mul_mat_vec_qIL9ggml_type12ELi1ELb0ELb0EEvPKvS2_PKi31ggml_cuda_mm_fusion_args_devicePfj5uint3jjjS7_jjjS7_jjjj33palw_cuda_producer_device_view_v3",
279
+ "sha256": "030dd256c2a1dda892b0e57157ec52f9ae5fd1e054d0c66380fae1cb6c09c477",
280
+ "size": 696,
281
+ "storage": "raw",
282
+ "type": 1
283
+ },
284
+ {
285
+ "alignment": 4,
286
+ "flags": 66,
287
+ "name": ".nv.constant2._Z13mul_mat_vec_qIL9ggml_type12ELi1ELb0ELb0EEvPKvS2_PKi31ggml_cuda_mm_fusion_args_devicePfj5uint3jjjS7_jjjS7_jjjj33palw_cuda_producer_device_view_v3",
288
+ "sha256": "27ecd0a598e76f8a2fd264d427df0a119903e8eae384e478902541756f089dd1",
289
+ "size": 4,
290
+ "storage": "raw",
291
+ "type": 1
292
+ },
293
+ {
294
+ "alignment": 4,
295
+ "flags": 64,
296
+ "name": ".nv.info._Z13mul_mat_vec_qIL9ggml_type12ELi1ELb0ELb0EEvPKvS2_PKi31ggml_cuda_mm_fusion_args_devicePfj5uint3jjjS7_jjjS7_jjjj33palw_cuda_producer_device_view_v3",
297
+ "sha256": "3898ea58f7ecc3b16c1f753686bd08c3d24fdd296e7bb8ec0be6fd1ec87d08fa",
298
+ "size": 456,
299
+ "storage": "raw",
300
+ "type": 1879048192
301
+ },
302
+ {
303
+ "alignment": 4,
304
+ "flags": 67,
305
+ "name": ".nv.shared._Z13mul_mat_vec_qIL9ggml_type12ELi1ELb0ELb0EEvPKvS2_PKi31ggml_cuda_mm_fusion_args_devicePfj5uint3jjjS7_jjjS7_jjjj33palw_cuda_producer_device_view_v3",
306
+ "size": 384,
307
+ "storage": "nobits",
308
+ "type": 8
309
+ },
310
+ {
311
+ "alignment": 128,
312
+ "flags": 6,
313
+ "name": ".text._Z13mul_mat_vec_qIL9ggml_type12ELi1ELb0ELb0EEvPKvS2_PKi31ggml_cuda_mm_fusion_args_devicePfj5uint3jjjS7_jjjS7_jjjj33palw_cuda_producer_device_view_v3",
314
+ "sha256": "6a2373c1b75fc5baf98f68bddcbf8cb5de0b25044b78076044c2c86cf579fbd0",
315
+ "size": 55680,
316
+ "storage": "raw",
317
+ "type": 1
318
+ }
319
+ ],
320
+ "semantic_binding": {
321
+ "capture_implementation_id": "b9d5fdda45db7cec8c8652fc60ee97a02bb09e83dfee57f2fc2ec52c51abdeb7",
322
+ "kernel_binary_digest_sha256": "3f9bfb88b5898b7d59b7fc39a01d7fda3b8ce4e270605b2d4cf29465907dfb64",
323
+ "producer_variant_id": "bb8334a8f131c5e9bad2902ad4d2e48bbcd2ee6a622feef4b5bb1bb24784e8cb",
324
+ "role": "work",
325
+ "work_entry_point_id": "e67572587d81ebab610881fd51059998702fab2fbd1f5102812be46181fb79b5"
326
+ },
327
+ "symbol": "_Z13mul_mat_vec_qIL9ggml_type12ELi1ELb0ELb0EEvPKvS2_PKi31ggml_cuda_mm_fusion_args_devicePfj5uint3jjjS7_jjjS7_jjjj33palw_cuda_producer_device_view_v3"
328
+ },
329
+ {
330
+ "cubin": {
331
+ "elf_flags": 100686084,
332
+ "sha256": "3f9bfb88b5898b7d59b7fc39a01d7fda3b8ce4e270605b2d4cf29465907dfb64",
333
+ "size": 97838152,
334
+ "target_arch": "sm_89"
335
+ },
336
+ "label": "q6_k",
337
+ "runtime_attributes": {
338
+ "binary_version": 89,
339
+ "local_memory_bytes": 0,
340
+ "max_threads_per_block": 128,
341
+ "num_regs": 40,
342
+ "ptx_version": 89,
343
+ "sm_arch": 89,
344
+ "static_shared_memory_bytes": 384
345
+ },
346
+ "scoped_sections": [
347
+ {
348
+ "alignment": 4,
349
+ "flags": 66,
350
+ "name": ".nv.constant0._Z13mul_mat_vec_qIL9ggml_type14ELi1ELb0ELb0EEvPKvS2_PKi31ggml_cuda_mm_fusion_args_devicePfj5uint3jjjS7_jjjS7_jjjj33palw_cuda_producer_device_view_v3",
351
+ "sha256": "030dd256c2a1dda892b0e57157ec52f9ae5fd1e054d0c66380fae1cb6c09c477",
352
+ "size": 696,
353
+ "storage": "raw",
354
+ "type": 1
355
+ },
356
+ {
357
+ "alignment": 4,
358
+ "flags": 66,
359
+ "name": ".nv.constant2._Z13mul_mat_vec_qIL9ggml_type14ELi1ELb0ELb0EEvPKvS2_PKi31ggml_cuda_mm_fusion_args_devicePfj5uint3jjjS7_jjjS7_jjjj33palw_cuda_producer_device_view_v3",
360
+ "sha256": "b1b0bee5378188f5250138bcce25855f2617f9c55b20b9628e13d367c47404a9",
361
+ "size": 8,
362
+ "storage": "raw",
363
+ "type": 1
364
+ },
365
+ {
366
+ "alignment": 4,
367
+ "flags": 64,
368
+ "name": ".nv.info._Z13mul_mat_vec_qIL9ggml_type14ELi1ELb0ELb0EEvPKvS2_PKi31ggml_cuda_mm_fusion_args_devicePfj5uint3jjjS7_jjjS7_jjjj33palw_cuda_producer_device_view_v3",
369
+ "sha256": "4459a5f5a9d38602c300a8aae11b4f61928cf9613f7520ad41fbf7c3332f5ed6",
370
+ "size": 456,
371
+ "storage": "raw",
372
+ "type": 1879048192
373
+ },
374
+ {
375
+ "alignment": 4,
376
+ "flags": 67,
377
+ "name": ".nv.shared._Z13mul_mat_vec_qIL9ggml_type14ELi1ELb0ELb0EEvPKvS2_PKi31ggml_cuda_mm_fusion_args_devicePfj5uint3jjjS7_jjjS7_jjjj33palw_cuda_producer_device_view_v3",
378
+ "size": 384,
379
+ "storage": "nobits",
380
+ "type": 8
381
+ },
382
+ {
383
+ "alignment": 128,
384
+ "flags": 6,
385
+ "name": ".text._Z13mul_mat_vec_qIL9ggml_type14ELi1ELb0ELb0EEvPKvS2_PKi31ggml_cuda_mm_fusion_args_devicePfj5uint3jjjS7_jjjS7_jjjj33palw_cuda_producer_device_view_v3",
386
+ "sha256": "726ad5b5ce0788fdf358ee8840ae9eb57950ff9b54be15bb1ca3939ea034cd28",
387
+ "size": 55808,
388
+ "storage": "raw",
389
+ "type": 1
390
+ }
391
+ ],
392
+ "semantic_binding": {
393
+ "capture_implementation_id": "b9d5fdda45db7cec8c8652fc60ee97a02bb09e83dfee57f2fc2ec52c51abdeb7",
394
+ "kernel_binary_digest_sha256": "3f9bfb88b5898b7d59b7fc39a01d7fda3b8ce4e270605b2d4cf29465907dfb64",
395
+ "producer_variant_id": "855c0d09acbf494b388b172d67026ea35760d37bfbce7e60725943850f847040",
396
+ "role": "work",
397
+ "work_entry_point_id": "f7c95ceb945af4fc2c510ce2b9e879362fa4fc2effae66b1b7d0f3b3272c3250"
398
+ },
399
+ "symbol": "_Z13mul_mat_vec_qIL9ggml_type14ELi1ELb0ELb0EEvPKvS2_PKi31ggml_cuda_mm_fusion_args_devicePfj5uint3jjjS7_jjjS7_jjjj33palw_cuda_producer_device_view_v3"
400
+ }
401
+ ],
402
+ "hash_algorithm": "sha256",
403
+ "library": {
404
+ "filename": "libggml-cuda.so.0.16.0",
405
+ "nv_fatbin": {
406
+ "sha256": "0654f8f423f059dccb94abf098fca2b47f106dcc6581f575756e6a985c6fa35c",
407
+ "size": 35595224
408
+ },
409
+ "sha256": "389bda6116c50eea8aebb9e1fcca1cc0145ab7245cb01d688024856c947f8e6f",
410
+ "size": 64330104
411
+ },
412
+ "schema": "misaka.palw.cuda-release-kernel-manifest.v1",
413
+ "schema_version": 1,
414
+ "target_arch": "sm_89"
415
+ },
416
+ "manifest_id_sha3_256": "4ededc7c257e13becbf74ebeecdff6c7bfe8ba84d550a6e07aa6cca52d9c7ce7",
417
+ "provenance": {
418
+ "cuobjdump_version": "cuobjdump: NVIDIA (R) fat binary listing tool\nCopyright (c) 2005-2026 NVIDIA Corporation\nBuilt on Tue_Jun_09_02:43:40_PM_PDT_2026\nCuda compilation tools, release 13.3, V13.3.73\nBuild cuda_13.3.r13.3/compiler.38244171_0"
419
+ }
420
+ }
docs/evidence/cuda-v3-runtime-entrypoint-info-sm89-2026-07-16.json ADDED
@@ -0,0 +1,90 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "entries": [
3
+ {
4
+ "binary_version": 89,
5
+ "capture_implementation_id": "b9d5fdda45db7cec8c8652fc60ee97a02bb09e83dfee57f2fc2ec52c51abdeb7",
6
+ "label": "q4_k",
7
+ "local_memory_bytes": 0,
8
+ "max_threads_per_block": 128,
9
+ "num_regs": 40,
10
+ "producer_variant_id": "bb8334a8f131c5e9bad2902ad4d2e48bbcd2ee6a622feef4b5bb1bb24784e8cb",
11
+ "ptx_version": 89,
12
+ "role": "work",
13
+ "sm_arch": 89,
14
+ "static_shared_memory_bytes": 384,
15
+ "work_entry_point_id": "e67572587d81ebab610881fd51059998702fab2fbd1f5102812be46181fb79b5"
16
+ },
17
+ {
18
+ "binary_version": 89,
19
+ "capture_implementation_id": "b9d5fdda45db7cec8c8652fc60ee97a02bb09e83dfee57f2fc2ec52c51abdeb7",
20
+ "label": "q6_k",
21
+ "local_memory_bytes": 0,
22
+ "max_threads_per_block": 128,
23
+ "num_regs": 40,
24
+ "producer_variant_id": "855c0d09acbf494b388b172d67026ea35760d37bfbce7e60725943850f847040",
25
+ "ptx_version": 89,
26
+ "role": "work",
27
+ "sm_arch": 89,
28
+ "static_shared_memory_bytes": 384,
29
+ "work_entry_point_id": "f7c95ceb945af4fc2c510ce2b9e879362fa4fc2effae66b1b7d0f3b3272c3250"
30
+ },
31
+ {
32
+ "binary_version": 89,
33
+ "capture_implementation_id": "c0a50513fee0ef0470636bf28a61c2f2b901c9cff650bdd2f58bd2fdc2921542",
34
+ "label": "attention_qk",
35
+ "local_memory_bytes": 0,
36
+ "max_threads_per_block": 1024,
37
+ "num_regs": 40,
38
+ "producer_variant_id": "0a299134085c7b67bfee9351427fa45a409c684b6533a70d9f41eacdcf805bb4",
39
+ "ptx_version": 89,
40
+ "role": "work",
41
+ "sm_arch": 89,
42
+ "static_shared_memory_bytes": 0,
43
+ "work_entry_point_id": "f1112882f6d45fe2975c0012269229bbb3f5e21cdedfd0c085ccf3f53694b183"
44
+ },
45
+ {
46
+ "binary_version": 89,
47
+ "capture_implementation_id": "c0a50513fee0ef0470636bf28a61c2f2b901c9cff650bdd2f58bd2fdc2921542",
48
+ "label": "attention_softmax",
49
+ "local_memory_bytes": 0,
50
+ "max_threads_per_block": 1024,
51
+ "num_regs": 22,
52
+ "producer_variant_id": "e74e46185a1164792446404386c2cf2ed3ae7f6c6726d72e26b1009d7e89c0cc",
53
+ "ptx_version": 89,
54
+ "role": "work",
55
+ "sm_arch": 89,
56
+ "static_shared_memory_bytes": 0,
57
+ "work_entry_point_id": "eb58357f1b039704e68c9c71d9fda49f356b69bc234d18a64914f597caf4cffb"
58
+ },
59
+ {
60
+ "binary_version": 89,
61
+ "capture_implementation_id": "c0a50513fee0ef0470636bf28a61c2f2b901c9cff650bdd2f58bd2fdc2921542",
62
+ "label": "attention_pv",
63
+ "local_memory_bytes": 0,
64
+ "max_threads_per_block": 1024,
65
+ "num_regs": 34,
66
+ "producer_variant_id": "e028f4560714ce35de86dc9346f7a23322951bffaa6d96d0f38ccbe6761f6a61",
67
+ "ptx_version": 89,
68
+ "role": "work",
69
+ "sm_arch": 89,
70
+ "static_shared_memory_bytes": 0,
71
+ "work_entry_point_id": "e9d7c24faf7167a4ace7ec61bf721d8eb02e1f368a0293c798fcf12596c12d72"
72
+ },
73
+ {
74
+ "binary_version": 89,
75
+ "capture_implementation_id": "c0a50513fee0ef0470636bf28a61c2f2b901c9cff650bdd2f58bd2fdc2921542",
76
+ "label": "grouped_collector",
77
+ "local_memory_bytes": 0,
78
+ "max_threads_per_block": 1024,
79
+ "num_regs": 44,
80
+ "producer_variant_id": null,
81
+ "ptx_version": 89,
82
+ "role": "capture",
83
+ "sm_arch": 89,
84
+ "static_shared_memory_bytes": 0,
85
+ "work_entry_point_id": null
86
+ }
87
+ ],
88
+ "schema": "misaka.palw.cuda-runtime-entrypoint-info.v1",
89
+ "target_arch": "sm_89"
90
+ }
docs/evidence/cuda-wsl-sm89-2026-07-15.md ADDED
@@ -0,0 +1,175 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # CUDA WSL2 SM89 Experimental Evidence — 2026-07-15
2
+
3
+ ## Scope and status
4
+
5
+ This is the canonical repository evidence for the experimental CUDA gate run on
6
+ a Windows/WSL2 RTX 4060 Ti host. It establishes that the pinned Qwen artifact
7
+ runs with full CUDA layer offload, that the diagnostic graph observer is exactly
8
+ repeatable on this stack, and that the standalone producer primitive captures a
9
+ real pre-epilogue FP32 accumulator on an SM89 device.
10
+
11
+ It is **not** a production CUDA Receipt. The vendored llama.cpp Qwen producer is
12
+ not instrumented, the deterministic FA-off attention path is not representable
13
+ by the current V2 dispatch schema, and all production capability macros and the
14
+ production CMake gate remain closed. R32 therefore moves from `Blocked` to
15
+ `In progress`, not to `Complete`.
16
+
17
+ No Tailscale address, SSH credential, or GPU UUID is recorded in this artifact.
18
+
19
+ ## Fixed host and toolchain
20
+
21
+ | Item | Observed value |
22
+ | --- | --- |
23
+ | Host path | Windows 11 + WSL2 Ubuntu 24.04.4 LTS |
24
+ | WSL kernel | 6.18.33.2 |
25
+ | GPU | NVIDIA GeForce RTX 4060 Ti, 8,188 MiB |
26
+ | Compute capability | 8.9 (`sm_89`) |
27
+ | NVIDIA driver | 610.62 |
28
+ | CUDA toolkit package | 13.3.1 |
29
+ | NVCC | 13.3.73 |
30
+ | CUDA architecture gate | exactly `89-real` |
31
+ | llama.cpp commit | `12127defda4f41b7679cb2477a4b0d65ee6a0c8f` |
32
+ | llama.cpp version | `10015 (12127def)` |
33
+
34
+ The build used `/usr/local/cuda/bin/nvcc` and did not rely on a compiler-default
35
+ or multi-architecture fatbin selection. `cuobjdump --list-elf` reported only
36
+ `sm_89.cubin` entries for both device-test executables.
37
+
38
+ ## Pinned model artifact
39
+
40
+ | Item | Value |
41
+ | --- | --- |
42
+ | Repository | `Qwen/Qwen3-8B-GGUF` |
43
+ | Revision | `7c41481f57cb95916b40956ab2f0b139b296d974` |
44
+ | File | `Qwen3-8B-Q4_K_M.gguf` |
45
+ | Size | 5,027,783,488 bytes |
46
+ | SHA-256 | `d98cdcbd03e17ce47681435b5150e34c1417f50b5c0019dd560e4882c5745785` |
47
+
48
+ llama.cpp identified 399 tensors: 145 F32, 217 Q4_K, and 37 Q6_K.
49
+ All 37/37 model layers were offloaded to the RTX GPU. The CUDA model buffer was
50
+ 4,455.34 MiB and the CUDA KV buffer was 576 MiB in the recorded probe.
51
+
52
+ ## Deterministic diagnostic Qwen observer
53
+
54
+ The dedicated observer was invoked with a public `PALW` stdin prompt, two
55
+ predicted tokens, all GPU layers, and `observer=sketch`. Its enforced header
56
+ reported greedy sampling (`temperature=0`, `top_p=1`, `top_k=0`), request batch,
57
+ `n_batch`, and `n_ubatch` all equal to one, parallel/tensor parallel equal to one,
58
+ one CPU thread, context 4096, no context shift, no speculation, no tensor repack,
59
+ and flash attention disabled. CUDA graphs, graph fusion, and graph optimization
60
+ were also disabled for this diagnostic run.
61
+
62
+ Observed result:
63
+
64
+ - 4,338 total observer events: 2,892 prefill and 1,446 decode;
65
+ - 975 graph GEMM events across three evaluated tokens;
66
+ - six independent runs produced exactly the same event stream and result line;
67
+ - event-stream SHA-256:
68
+ `e8ec2574076a46d29a83d2016e657cadb12600ccca0246320d6f32a16c7b0ba3`;
69
+ - result-line SHA-256:
70
+ `6a22c1547efa9d5ba8b0478d11d82b2b817455eee35a7d4eeb2f66c5af9444cd`;
71
+ - retained observer JSONL SHA-256:
72
+ `8884b72be183e704b7238da9734d675bde764fe11b60a17038a69aefd0251ac3`;
73
+ - observer executable SHA-256:
74
+ `f84b67ea4ee5a36a2bd2b04823bbf0ee9abdd47329704457ffa3e5d96e79c38a`;
75
+ - loaded `libggml-cuda` SHA-256:
76
+ `680dc8a64ffc1a35658f6fcc71809d3e0afb11de968abf0d4ba7931c14d8b49a`.
77
+
78
+ This observer still reports `cuda_kernel_trace=false`: its 975 GEMM records are
79
+ graph-level diagnostic fallback evidence, not true producer-accumulator records.
80
+
81
+ The exact measured composition explains the remaining coverage gap:
82
+
83
+ | Operation path | Three-token count | Per token |
84
+ | --- | ---: | ---: |
85
+ | Q4_K quantized linear MMVQ candidate | 648 | 216 |
86
+ | Q6_K quantized linear MMVQ candidate | 111 | 37 |
87
+ | All quantized linear MMVQ | 759 | 253 |
88
+ | FA-off eager-attention F16 `MUL_MAT` | 216 | 72 |
89
+ | Total | 975 | 325 |
90
+
91
+ An MMVQ producer hook can cover the 253 quantized linear GEMMs per token, but it
92
+ cannot claim the 72 eager-attention GEMMs per token.
93
+
94
+ ## Standalone true producer-accumulator primitive
95
+
96
+ The standalone test producer computes segmented dot-product accumulators in
97
+ CUDA registers, calls `palw_cuda_producer_capture_accumulator_f32` before an
98
+ independently variable epilogue/final store, and directly emits canonical V2
99
+ tile-by-K-segment evidence. It validates exact function pointer and
100
+ `cudaFuncGetAttributes`, immutable injected device view, per-launch nonce,
101
+ compiled entry-point/variant identity, 32 exactly-once samples, duplicate/missing
102
+ masks, host-retained metadata, stream/device binding, and codec grid limits.
103
+
104
+ The final CUDA source-tree aggregate is:
105
+
106
+ ```text
107
+ 2fda921624a095687e45aab9afb5ea32c48ca648727c6c5c6f1a923abbd9dc4f
108
+ ```
109
+
110
+ It is calculated by hashing every regular file under `runtime-palw/cuda` in
111
+ byte-sorted pathname order, then SHA-256 hashing the resulting `shasum -a 256`
112
+ lines.
113
+
114
+ An independent clean build in `build/palw-cuda-device-root-final` produced:
115
+
116
+ - CTest: 6/6 passed, zero skipped (host 4, V1 device 1, producer device 1);
117
+ - standalone producer executable: 20/20 independent executions passed;
118
+ - all 20 logs had SHA-256
119
+ `bd5c1f458c7b4f81a1bd76414896de253f61d6b6f99426eefc3b51d9491673e6`;
120
+ - all 20 runs reported diagnostic fingerprint `c1a38ed138200874`;
121
+ - V1 device-test executable SHA-256:
122
+ `401241589d908a92e4bc1f83b90346eb896096e65bcae9b4102f1153ee99bc04`;
123
+ - producer device-test executable SHA-256:
124
+ `e9bb2ad7beb104bdba82a013bbfe9dd4271f36c79d09b10f380c840ced695a8e`;
125
+ - `libpalw_cuda_trace.a` SHA-256:
126
+ `8aef058ce12b746a683d037d70c72c3401940aa7136e46b8340f88229b0c5b9e`.
127
+
128
+ A separate build directory from the same source aggregate produced different
129
+ whole-binary/library SHA-256 values while passing the same 6/6 and 20/20 gates.
130
+ Consequently this evidence does **not** claim byte-for-byte build reproducibility;
131
+ the build-directory/toolchain provenance difference remains to be isolated and
132
+ the approved release artifact must be content-addressed explicitly.
133
+
134
+ The final adversarial review found and closed two pre-release defects: a caller
135
+ could previously change the injected-view argument position at launch, and a
136
+ codec-invalid grid-Y value could be accepted until finalization. The launch now
137
+ uses only the ABI position/count retained at `prepare`, and pure descriptor
138
+ validation shares the codec limits (`grid_x <= 2,147,483,647`,
139
+ `grid_y <= 65,535`). The review found no remaining P1/P2 issue within the stated
140
+ experimental trusted-ABI boundary.
141
+
142
+ ## Host and Rust gates
143
+
144
+ - AppleClang warning-as-error host CTests: 4/4 passed.
145
+ - AppleClang ASan+UBSan host CTests: 4/4 passed with no report.
146
+ - Rust 1.81.0: 173 passed, 2 ignored (175 discovered).
147
+ - Rust CUDA trace contract: 13/13 passed.
148
+ - `cargo fmt --check`, Clippy `-D warnings`, and rustdoc `-D warnings` passed.
149
+ - `ComputeReceiptV1` builder and verifier both reject CUDA `KernelSketch`.
150
+ - Authority verification binds network/job/execution/assignment, runtime,
151
+ producer integration, complete schedule/transcript, validity and revocation;
152
+ its projection is candidate evidence for a future Receipt V2 only.
153
+
154
+ ## Remaining completion gates
155
+
156
+ 1. Instrument the pinned llama.cpp Q4_K and Q6_K unfused MMVQ specializations at
157
+ the true full-K pre-epilogue accumulator point and report the actual selected
158
+ dispatch from request-local state.
159
+ 2. Version the transport/dispatch contract for FA-off eager/decomposed attention
160
+ sublaunch grouping, or approve and revalidate a separate deterministic FA-on
161
+ runtime class.
162
+ 3. Bind reviewed hook source, compiled hook/entry-point table, actual loaded
163
+ cubin, extraction policy, and runtime manifest through production authority
164
+ governance and key lifecycle.
165
+ 4. Implement Receipt/Manifest/Request/Bundle/SQLite V2 and an independent
166
+ verifier that retains the authority provenance commitment.
167
+ 5. Run vendored-Qwen full-stream fault injection and approved replica/cross-driver
168
+ reproducibility matrices.
169
+
170
+ Until all five are complete,
171
+ `PALW_CUDA_PRODUCER_VENDOR_RUNTIME_INTEGRATED`,
172
+ `PALW_CUDA_PRODUCER_RECEIPT_MAPPING_AVAILABLE`,
173
+ `PALW_CUDA_PRODUCER_PRODUCTION_CAPABLE`, and
174
+ `PALW_CUDA_TRACE_PRODUCTION_CAPABLE` remain zero, and
175
+ `PALW_CUDA_PRODUCTION_KERNEL_TRACE=ON` must fail at CMake configure time.
docs/evidence/metal-hybrid-qwen36-2026-07-19.md ADDED
@@ -0,0 +1,90 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Metal E2E evidence — Qwen3.6-35B-A3B (Claude-4.7, abliterated), 2026-07-19
2
+
3
+ このメモは、dense Qwen3-8B から hybrid Qwen3.6-35B-A3B へ移行した後の Metal arm64 実機
4
+ E2E(Receipt 発行 → 別 process 検証)の一次証跡である。
5
+
6
+ ## Host / runtime
7
+
8
+ - Apple M1 Max、macOS(Metal 4)、`uname -m = arm64`
9
+ - pinned llama.cpp `12127defda4f41b7679cb2477a4b0d65ee6a0c8f` + PALW observer patch
10
+ (`patches/llama.cpp-palw-observer.patch`、SHA-256
11
+ `d155a88b7c11ee74f48011760cb1a37773a694c8cab28258ee108c85e2f9e02c`)
12
+ - `llama-palw-observer` は model load 時に `qwen35moe` / 40 layer / 2048 hidden / 248320
13
+ vocab を検証。`load_tensors: offloaded 41/41 layers to GPU` を確認。
14
+
15
+ ## Model artifact
16
+
17
+ - GGUF: Ollama `huihui_ai/Qwen3.6-abliterated:35b-Claude-4.7`、blob/SHA-256
18
+ `1dc494614bee8a3bc00e79fe5a49da0fc1c36b3b118c4156e223e98e5a0a671b`、23,938,321,728 bytes(`Q4_K_M`)
19
+ - Base metadata(7 files): HF `huihui-ai/Huihui-Qwen3.6-35B-A3B-Claude-4.7-Opus-abliterated`
20
+ rev `ac18882735d037f6074a7630eb68d85db8234c25`
21
+
22
+ ## 出力健全性(off-mode 差分)
23
+
24
+ prompt `The capital of France is`(token `[760, 6511, 314, 9338, 369]`)→ 生成
25
+ ` Paris, a city renowned for its iconic`(8 token)。全 41 layer GPU offload。
26
+
27
+ ## 発行 Receipt(sketch-mode、Metal kernel-bound)
28
+
29
+ - output dir: `receipts/final-v7/`
30
+ - Receipt ID: `8e2dd34b7609d6d7aeec17bff485eb1ae4db31f66dd899a3c3a3e671656053f9`
31
+ - Verification bundle ID: `f5b8a2968c4ea266b2cbbabf351a171e0fa2581984eff63362de2640fcdcf9db`
32
+ - public JSON schema: `misaka.palw.public-receipt.v2`、observer JSONL schema **v2**
33
+ - CU ruleset: **v3 semantic**、`43a5feef177b389f976361b22ac9d57da65815261282005bc78d1666a37870ce`
34
+ - `job_class=self_local`、`evidence_level=gemm_traced`、**`trace_evidence=metal_kernel`**
35
+ (M5 で graph-fallback から昇格。各 GEMM を実 Metal compute pipeline + launch geometry へ束縛)
36
+ - `mint`: `eligible=false`、`weight=0`、`class=local_self_consistent_v0_1`
37
+ - `mint.ineligible_reasons`: **「Metal kernel-launch-bound sketch, not an intra-kernel accumulator
38
+ proof」/ 非 network-anchored / 非 bonded の 3 件**(M3 で generic、M5 で graph-fallback の失格理由は
39
+ 解消。Metal trace は launch-geometry 束縛で CUDA V3 相当の accumulator proof ではないため mint 不適格の
40
+ まま — honest labeling)。`mint.mainnet_ready=false`
41
+ - `prefill_tokens=5`、`decode_tokens=2`、`prefill_graph_steps=5`、`decode_graph_steps=1`
42
+ - `schedule_event_count=13770`(commitment-only)、`gemm_events=trace_event_count=2466`
43
+ - **`canonical_compute_units=41692`(v3 semantic、署名 commit)** = `semantic_compute_units_v3`。
44
+ graph 非依存 / fragmentation-proof、verifier が `prefill/decode` から再計算・照合。
45
+ - `semantic_schedule`: commitment `e6fc731e…`、`expert_route_ops=80`、`attention_ops=20`
46
+ (verifier が pinned architecture から独立再生成して照合)
47
+ - **`expert_route`: root `5e4ea70b…`、`route_event_count=240`**(observer が `ffn_moe_topk` を
48
+ post-compute で読み戻した実 MoE routing。封緘 bundle へ commit し公開 JSON へ再構成)
49
+ - 公開 artifact SHA-256:
50
+ - `<id>.palw`: `b602203cc781c67d8c45c915b29edcef30a1aca22f52a7482693f2551f493dca`
51
+ - `<id>.json`: `2bc670c2de4147fa150126cc36a5f35b5c0600f0835b334e3d36de58ccbf5154`
52
+ - prompt / prompt token IDs / generated token IDs / opening / signing key / owner salt は
53
+ 公開 `.palw` / `.json` に含まれない(secret-leakage scan 済み)。
54
+
55
+ ## 別 process 検証
56
+
57
+ `palw-verify-bundle` が `.palw` / `.palw.bundle` / `.json` / `palw-state.sqlite3` を復元・再検証し、
58
+ `status=local_restored`、`trust_scope=embedded_local_snapshot`、`receipt_id` / `bundle_id`
59
+ 一致(exit 0)。
60
+
61
+ ## Hybrid 対応の要点
62
+
63
+ - pinned llama.cpp の qwen35moe loader/graph は 3-section mrope、`ssm_dt` naming、
64
+ per-layer KV-head(layer 0 は linear-attention で `n_head_kv=0`)、bundled vision/MTP
65
+ tensor、full-attention reshape の per-layer head 数を扱うよう修正。
66
+ - Rust adapter(`AdapterProfile::HybridQwen36A3B`): 全演算を**忠実な canonical operation**へ写像
67
+ — `MUL_MAT_ID→ExpertGemm`、`ARGSORT→ExpertRoute{top_k=8}`、`SSM_CONV→SsmConv`、
68
+ `GATED_DELTA_NET→GatedDeltaNet`、`L2_NORM→L2Norm`、`SUM_ROWS→Reduction`、
69
+ `CONCAT/CONT/CPY→TensorCopy`、`UNARY/SCALE/DIV/CLAMP→Elementwise`、`VIEW`/`RESHAPE`/`PERMUTE`/
70
+ `TRANSPOSE` は layout-only。**`Generic` は不使用**。未列挙 op は fail-closed。plain `MUL_MAT` のみ
71
+ accumulator sketch を採取。
72
+ - observer(schema v2)は `ffn_moe_topk`(I32)を post-compute で読み戻し、per-token 選択 expert を
73
+ "route" record として emit。adapter が commitment chain へ fold し `expert_route_root` を封緘。
74
+ - **ggml-metal 計装(M5)**: `ggml_metal_palw_set_dispatch_hook` が全 Metal dispatch を pipeline 名 +
75
+ launch geometry で報告。observer は各 GEMM を ASK→POST window 内の最後���非 `_id` matmul dispatch
76
+ (`kernel_mul_mv_*`)へ束縛(実機で 200/200 window・411/411 GEMM を確認、0 anomaly)。adapter は
77
+ kernel 名 + threads-per-threadgroup を `kernel_id`、threadgroup grid を tile へ束ね
78
+ `TraceEvidenceKind::MetalKernel` を commit。verifier が `TraceCapability::MetalKernel` と照合。
79
+ - 0-element の recurrent state cache tensor は observer が no-compute として skip。
80
+ - 観測 patch: `patches/llama.cpp-palw-observer.patch`、SHA-256
81
+ `d155a88b7c11ee74f48011760cb1a37773a694c8cab28258ee108c85e2f9e02c`。
82
+
83
+ ## 限界
84
+
85
+ Metal の kernel-level trace(`trace_evidence=metal_kernel`)は **launch-geometry 束縛**であり、
86
+ CUDA V3 の intra-kernel accumulator sketch とは異なる(より弱い)。そのため `MetalKernel` は
87
+ `KernelSketch` とは**別の evidence kind**として commit し、CUDA 相当を主張しない(honest labeling)。
88
+ mint は依然不適格(「kernel-launch-bound, not accumulator proof」)。単独ノードの Receipt はそれだけで
89
+ ゼロ知識の計算証明ではない。network/hardware/model-Genesis 依存の未達 gate
90
+ R13/R21/R23/R24/R26/R27/R32/R35 は [`../requirements.md`](../requirements.md) の通り。
docs/evidence/metal-smoke-2026-07-15.md ADDED
@@ -0,0 +1,336 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Metal Smoke / Receipt Evidence — 2026-07-15
2
+
3
+ > **Historical schema-v3 evidence.** This page records the `final-v5` run and its historical
4
+ > test counts; it is not the current schema-v4 acceptance baseline. See
5
+ > [`metal-smoke-schema-v4-2026-07-15.md`](metal-smoke-schema-v4-2026-07-15.md) for current evidence.
6
+
7
+ Host: Mac Studio `Mac13,1`, Apple M1 Max (24 GPU cores), 32 GiB unified memory,
8
+ macOS 26.5 arm64 build `25F71`, Metal 4.
9
+
10
+ ## Pinned artifacts
11
+
12
+ - llama.cpp commit: `12127defda4f41b7679cb2477a4b0d65ee6a0c8f`
13
+ - llama.cpp version: `10015 (12127def)`
14
+ - model repo/revision: `Qwen/Qwen3-8B-GGUF@7c41481f57cb95916b40956ab2f0b139b296d974`
15
+ - base metadata revision: `Qwen/Qwen3-8B@b968826d9c46dd6066d109eabc6255188de91218`
16
+ - model file: `Qwen3-8B-Q4_K_M.gguf`
17
+ - model bytes: `5,027,783,488`
18
+ - model SHA-256: `d98cdcbd03e17ce47681435b5150e34c1417f50b5c0019dd560e4882c5745785`
19
+ - Hub LFS SHA-256/size、local digest/size、revision sidecar は一致した。
20
+ - official base metadata 8ファイルの SHA-256 と profile shape/dtype は固定値と一致した。
21
+
22
+ Binary SHA-256:
23
+
24
+ - `llama-cli`: `98d1680585d450e25a9a4352b33defd04447e9b344e9251ab3e7935e4bf0f57d`
25
+ - `llama-server`: `ad2946371ae4abe62115dc514dee11f4655ed117d718b714b338b00d82e039e0`
26
+ - `llama-tokenize`: `8caaa7f2fb7c74344169cfdec40d6d5f83ee924320534d877128e8cf84a4ef23`
27
+ - `llama-palw-observer`: `c35ee95d261bbb7689199338fa9444b58d03f057cc164e97c4bd6698d456a166`
28
+ (114,720 bytes; fixed upstream commit と local PALW observer patch を含む)
29
+
30
+ `./scripts/verify-install.sh` は origin/commit、model/base metadata、profile、CMake cache、上記4
31
+ target の version/hash、Metal device、37/37 offload、one-token probe を通過した。
32
+
33
+ ## Basic Metal runtime result
34
+
35
+ - Metal device は `MTL0: Apple M1 Max` として検出された。
36
+ - 37/37 model layers が GPU へ offload された。
37
+ - CLI one-token inference は exit 0。測定された prompt processing は 80.5 token/s だった。
38
+ - HTTP server `/health` は `{"status":"ok"}` を返した。
39
+ - `/tokenize` で test text `PALW deterministic receipt` は
40
+ `[73342, 54, 72349, 22567]` になった。
41
+
42
+ 同一 request を cache 無効、temperature 0、top-k 0、top-p 1、seed 0、prediction bound 16 で
43
+ 2回実行した。両方が同じ stop type `limit` と token IDs を返した。
44
+
45
+ ```text
46
+ [271, 73342, 54, 8375, 271, 32313, 11, 358,
47
+ 1184, 311, 7071, 700, 1246, 311, 5486, 419]
48
+ ```
49
+
50
+ これはこの prompt/runtime instance の repeatability evidence であり、cross-driver、cross-device、
51
+ Metal/CUDA 間の bitwise determinism を証明しない。
52
+
53
+ ## Native observer fixed policy
54
+
55
+ 現行 binary の header で次を確認した。
56
+
57
+ ```text
58
+ n_ctx=4096
59
+ n_batch=1
60
+ n_ubatch=1
61
+ request_batch=1
62
+ parallel_sequences=1
63
+ threads=1
64
+ threads_batch=1
65
+ tensor_repack=false
66
+ flash_attention=false
67
+ context_shift=false
68
+ speculation=false
69
+ ```
70
+
71
+ prompt は `--prompt-stdin` で専用 pipe から渡した。通常の Receipt path は
72
+ `--emit-output-bytes` を指定せず、result の `output_bytes=[]` / `output_n_bytes=0` を要求する。
73
+ 以下の非干渉比較だけは token IDs に加えて decoded bytes を比較する QA gate のため、明示的な
74
+ output-byte retention を使った。
75
+
76
+ ## Current observer non-interference matrix
77
+
78
+ ### Short prompt
79
+
80
+ test prompt `PALW`、`n_predict=2` を `off`、`graph`、`sketch` の各 mode で実行した。
81
+ 全 process が exit 0 で、次が完全一致した。
82
+
83
+ - prompt token IDs: `[73342, 54]`
84
+ - generated token IDs: `[19114, 374]`
85
+ - decoded output bytes: `[69, 76, 76, 32, 105, 115]`
86
+ - stop reason: `n_predict`
87
+
88
+ | Mode | Native events | Post-compute sketches |
89
+ |---|---:|---:|
90
+ | `off` | 0 | 0 |
91
+ | `graph` | 4,338 | 0 |
92
+ | `sketch` | 4,338 | 975 |
93
+
94
+ 同じ short prompt を再度全 mode で実行し、同じ token IDs、bytes、stop reason を得た。
95
+
96
+ ### Longer prompt
97
+
98
+ test prompt `PALW deterministic receipt observer non interference`、`n_predict=4` でも全 mode が一致した。
99
+
100
+ - prompt token IDs: `[73342, 54, 72349, 22567, 22067, 2477, 31217]`
101
+ - generated token IDs: `[271, 785, 7286, 498]`
102
+ - decoded output bytes: `[10, 10, 84, 104, 101, 32, 99, 111, 110, 99, 101, 112, 116, 32, 121, 111, 117]`
103
+ - events: off `0`、graph/sketch `14,460`
104
+ - sketches: off/graph `0`、sketch `3,250`
105
+
106
+ short 975件と longer 3,250件の全 sketch は `bits=256`、64桁 hexadecimal だった。header の
107
+ `cuda_kernel_trace` は false で、全 event の `kernel_trace.available=true` は0件、
108
+ `backend=cuda` も0件だった。この matrix は現行 Metal runtime class で callback の output
109
+ non-interference を示す。graph fallback を CUDA kernel trace や暗号学的 proof へ昇格させる
110
+ 証拠ではなく、callback synchronization が timing を変え得る点も残る。
111
+
112
+ final publication 前の追加 QA は prompt `PALW observer non interference`、`n_predict=2` を使い、
113
+ 親 process に GPU/thread/library/token 関連の誤誘導 environment を設定したまま実行した。child は
114
+ allowlist 以外を消去し、off/graph/sketch の token IDs、decoded bytes、stop reason は完全一致した。
115
+ native event は off `0`、graph `8,676`、sketch `8,676` だった。sketch sample count はこの追加 run
116
+ では保存していないため主張しない。
117
+
118
+ ## Signed Self Local Receipt E2E
119
+
120
+ release `palw-metal-receipt` は pinned tokenizer と current observer を実行し、実行前後 manifest
121
+ 一致、strict adapter、全 operation pricing、署名済み request/assignment、Receipt build、stateless
122
+ verification、canonical round-trip、secret scan、SQLite acceptance を一度の fail-closed path で完了した。
123
+ その後の CLI hardening で `--prompt-stdin`、`--audit-key-file`、`--output-dir` を必須とし、
124
+ prompt の非空 UTF-8 / 1 MiB 上限を inference 前に検査するようにした。argv で prompt を受ける
125
+ 互換 option はない。tokenizer/native observer へも専用 stdin pipe で渡す。
126
+
127
+ 現行 publication contract は署名済み `.palw`、公開 JSON、XChaCha20-Poly1305 で認証付き暗号化した
128
+ `.palw.bundle`、schema-v3 `palw-state.sqlite3`、最後に fsync する
129
+ `misaka.palw.receipt-set.v2` completion marker の一式である。audit key は output directory 外の exact
130
+ 32-byte raw file(owner-only `0400` / `0600`)、output directory は `0700`、bundle/DB は `0600`、
131
+ 公開 `.palw` / JSON / marker は `0644` を要求する。公開 JSON schema は strict
132
+ `misaka.palw.public-receipt.v2` である。
133
+
134
+ 正本 artifact:
135
+
136
+ - output directory: `../../receipts/final-v5`(absolute:
137
+ `<REPO>/receipts/final-v5`)、mode `0700`、uid `<UID>`
138
+ - Receipt ID: `ab2b3196a6c0935aafd4d563a9d2e1d71d828cc87a378ae77b8e49c102033b68`
139
+ - verification bundle ID: `6fd4e57a6cbcd6fc1d9138989960b627c9ee4817bc3ac4ce889a1a1b41d7d63b`
140
+ - canonical envelope:
141
+ [`../../receipts/final-v5/ab2b3196a6c0935aafd4d563a9d2e1d71d828cc87a378ae77b8e49c102033b68.palw`](../../receipts/final-v5/ab2b3196a6c0935aafd4d563a9d2e1d71d828cc87a378ae77b8e49c102033b68.palw)
142
+ — 713 bytes、mode `0644`、SHA-256
143
+ `b43cf66c6fe4803e03355a4c1658a3466d1efacc0121759b01b5a9c431251f38`
144
+ - encrypted verification bundle:
145
+ [`../../receipts/final-v5/ab2b3196a6c0935aafd4d563a9d2e1d71d828cc87a378ae77b8e49c102033b68.palw.bundle`](../../receipts/final-v5/ab2b3196a6c0935aafd4d563a9d2e1d71d828cc87a378ae77b8e49c102033b68.palw.bundle)
146
+ — 337,257 bytes、mode `0600`、SHA-256
147
+ `4b40cefba773142f83cd04f047e952732c5f087b09a6ee8511a9eda99ca1acf2`
148
+ - public metrics:
149
+ [`../../receipts/final-v5/ab2b3196a6c0935aafd4d563a9d2e1d71d828cc87a378ae77b8e49c102033b68.json`](../../receipts/final-v5/ab2b3196a6c0935aafd4d563a9d2e1d71d828cc87a378ae77b8e49c102033b68.json)
150
+ — 3,427 bytes、mode `0644`、SHA-256
151
+ `3aa158cacd9c790a85f550e232e1b5b3a5c3f1d81aaa0c5b56b57bb08f1dca22`
152
+ - completion marker:
153
+ [`../../receipts/final-v5/ab2b3196a6c0935aafd4d563a9d2e1d71d828cc87a378ae77b8e49c102033b68.complete`](../../receipts/final-v5/ab2b3196a6c0935aafd4d563a9d2e1d71d828cc87a378ae77b8e49c102033b68.complete)
154
+ — 262 bytes、mode `0644`、SHA-256
155
+ `58d43673f80fa29cd9cab8837d5156ecd4ba42a1d6ab1aacb43365145ea16e39`
156
+ - durable state:
157
+ [`../../receipts/final-v5/palw-state.sqlite3`](../../receipts/final-v5/palw-state.sqlite3)
158
+ — 126,976 bytes、mode `0600`、SHA-256
159
+ `0b1774f89d8fbcd2f0f88771477a173bbae5135b71b5439a090d31f167528702`
160
+
161
+ 全5 artifact は uid `<UID>`、link count `1` で、相互に異なる inode だった。audit key は
162
+ `$HOME/.config/misaka-palw/audit-keys/qwen3-8b-final-20260715.key` の exact 32 bytes、mode
163
+ `0600`、uid `<UID>`、link count `1` を検査した。key bytes は publication set に含めない。
164
+
165
+ Public E2E metrics:
166
+
167
+ | Field | Value |
168
+ |---|---:|
169
+ | prompt/prefill tokens | 4 |
170
+ | generated/decode tokens | 2 |
171
+ | prefill graph steps | 4 |
172
+ | decode graph steps | 1 |
173
+ | canonical scheduled operations | 4,890 |
174
+ | authenticated GEMM groups | 1,625 |
175
+ | graph-trace events | 1,625 |
176
+ | canonical compute units | 12,135 |
177
+
178
+ Identity/root evidence:
179
+
180
+ - runtime manifest hash: `2b9c3cd05942f16b36ab348bc71033c33e8f7aa6872ce4c0c0fcac3ba0212bc1`
181
+ - model profile ID: `0c58c66b03bb471a248cb36be954b42945c6694c148370e6852f674ff98e64d4`
182
+ - runtime class ID: `5b2fd7a56d73aa9757e516f92cbc7b4d43995ebe9ed27e445b9b7ab4cd8c7bc9`
183
+ - shape profile ID: `c4f8ae70ab6fda2707d841a64d79d36cff58509ea7f228eb4c93b693e630d674`
184
+ - schedule commitment: `6ee6163863df1a9a715bb42dc89d7431c13e0cb2538d022d074ca07c11aabab7`
185
+ - graph trace root: `ebfd5d143ee57b1db20751ae4d241479fa9447cd5fcc7052fccce129604b78bc`
186
+ - model PALW root: `ad7d0e950531195bc2cf84f112fee6487777f78120c9a809cf9306c7a7a8684f`
187
+ - tokenizer PALW root: `63839f0ab58084bbaa108a877e52bebd685b2c0616fcfab684a08354dee713dd`
188
+ - trace evidence: `graph_fallback`; required evidence level: `gemm_traced`
189
+
190
+ strict parser が受理した evidence から layout-only metadata を除く 4,890 canonical operation を
191
+ versioned CU table で価格付けした。global LM head の optional layer representation も受理対象を
192
+ 狭めた���示 rule として検証され、unknown/unsupported/unpriced operation はない。公開 JSON parser は
193
+ unknown field を拒否し、retained `artifacts` / `observer_summary` を含む全 field を authenticated
194
+ receipt、bundle manifest/evidence、固定 privacy policy と一致させる。
195
+
196
+ canonical envelope と encrypted bundle の pre-write scan は prompt text、prompt/generated token
197
+ sequence、output nonce、owner salt、scheduler/worker private key bytes の平文出現を検査し、いずれも
198
+ 検出しない。private request/assignment、opening、owner salt、検証用 signer record は bundle の
199
+ authenticated ciphertext に封入する。公開 JSON は prompt/generated tokens、output bytes、nonce、
200
+ salt、private keys を serialized=false と記録し、その全 field を verifier が authenticated receipt、
201
+ bundle manifest/evidence、固定 privacy policy と照合する。提出 prompt に対する published artifact
202
+ directory の fixed-string search も必須である。
203
+
204
+ SQLite verification result:
205
+
206
+ ```text
207
+ PRAGMA application_id -> 1346456663 (PALW)
208
+ PRAGMA user_version -> 3
209
+ PRAGMA integrity_check -> ok
210
+ PRAGMA foreign_key_check -> no rows
211
+ receipts -> 1
212
+ jobs -> 1
213
+ pairs / pair_members -> 0 / 0
214
+ future_audits -> 0
215
+ audit_replays -> 0
216
+ mature_sources -> 0
217
+ work_tickets -> 0
218
+ slash_records -> 0
219
+ external_escrows -> 0
220
+ ```
221
+
222
+ 現行 state contract は `PRAGMA user_version=3`、full `sqlite_master` DDL fingerprint、foreign keys、
223
+ `synchronous=FULL`、WAL checkpoint/truncate を要求する。completion marker 作成前に main DB と全
224
+ artifact/directory entry を fsync するため、portable publication は残存 `-wal` / `-shm` に依存しない。
225
+ legacy schema v1 は暗黙 migrate せず fail-closed に拒否する。
226
+
227
+ 別 process の verifier は exit 0 で次を返した。checkpoint 後に `-wal` / `-shm` は残っていない。
228
+
229
+ ```text
230
+ status=local_restored
231
+ trust_scope=embedded_local_snapshot
232
+ receipt_id=ab2b3196a6c0935aafd4d563a9d2e1d71d828cc87a378ae77b8e49c102033b68
233
+ bundle_id=6fd4e57a6cbcd6fc1d9138989960b627c9ee4817bc3ac4ce889a1a1b41d7d63b
234
+ ```
235
+
236
+ v2 marker は receipt ID、bundle ID、公開 JSON byte 列の SHA-256 を bind する crash-completion signal
237
+ である。keyed MAC や network authority の署名ではなく、directory を変更できる同一 user は再計算
238
+ できるため、marker 単独では authenticity、authorization、maturity を証明しない。separate verifier
239
+ は exact filenames、same private directory、owner/mode/link/inode、bounded read、marker、bundle AEAD、
240
+ 公開 JSON、durable acceptance をまとめて検査する。CLI の local restore は encrypted embedded
241
+ registry snapshot との continuity であり、production network trust root の代替ではない。
242
+
243
+ `pairs=0`、`future_audits=0`、`work_tickets=0` は Self Local Receipt が発行・受理済みでも、
244
+ replication や future audit/challenge maturity をまだ通していないことと整合する。
245
+
246
+ ## Rust and adversarial gates
247
+
248
+ crate の宣言 MSRV は Rust 1.81 である。実際に toolchain 1.81.0 を install して最初に locked
249
+ dependency graph を検査したところ、open transitive range が `zeroize 1.9` と `base64ct 1.8.3`
250
+ を選び、その edition-2024 Cargo manifest を Cargo 1.81 が parse できない不一致を発見した。
251
+ `Cargo.toml` に `zeroize = "=1.8.1"` と `base64ct = "=1.7.3"` を exact pin し、lockfile を
252
+ downgrade した後、次を current tree で実行した。
253
+
254
+ ```sh
255
+ rustup toolchain install 1.81.0 --profile minimal --component rustfmt,clippy
256
+ cd runtime-palw
257
+ cargo +1.81.0 fmt --all -- --check
258
+ cargo +1.81.0 clippy --locked --all-targets -- -D warnings
259
+ cargo +1.81.0 test --locked --all-targets
260
+ ```
261
+
262
+ - library unit tests: 104 passed、2 ignored real-model tests
263
+ - `tests/adversarial.rs`: 11 passed
264
+ - `tests/core_flow.rs`: 3 passed
265
+ - `tests/restart_bundle.rs`: 9 passed
266
+ - total: **127 passed, 2 ignored**(129 discovered)
267
+ - fmt: passed
268
+ - locked all-target Clippy with warnings denied: passed
269
+
270
+ strict public JSON v2 hygiene change と final-v5 発行後に上記 Rust gate をすべて再実行し、同じ結果を得た。
271
+ ignored 2件は pinned Qwen model/Metal observer を必要とする実モデル test である。release build を
272
+ 使い、親 process の GPU/thread/Hugging Face/dynamic-loader environment を意図的に汚染した手動 gate
273
+ では child environment isolation を含めて 2/2 passed した。Clippy pedantic の
274
+ `module_name_repetitions` は versioned public protocol API 名を module 外でも自己記述的にする
275
+ 意図的な naming policy としてだけ allow し、それ以外の warning は `-D warnings` で拒否した。
276
+
277
+ adversarial suite は全 consensus Receipt field、全 request/assignment field、signature/envelope、
278
+ nonce/prompt/output/runtime/network binding、schedule reorder/insert/delete、CU/evidence mismatch、dummy
279
+ signer/assignment、fork/credential/runtime instance、k=2 self/duplicate/reuse、serialized secret leakage、
280
+ replay cardinality を mutation し、fail-closed rejection を確認した。
281
+
282
+ Work Ticket regression gate は `MatureEvidence` の field/low-level constructor が非公開であることに
283
+ 加え、Self Local audit の typed `Mature` state、Self Replicated pair、External escrow settlement だけを
284
+ public 生成経路とする。各 evidence は audit eligible epoch、pair matched epoch、settlement epoch を
285
+ 封入する。durable registration は accepted receipt/pair の network/class/CU と照合し、ticket issue は
286
+ その exact epoch より前を拒否する。raw maturity marker と caller-supplied epoch の public bypass はない。
287
+
288
+ これは core protocol/state-machine の test evidence であり、production service の完了証跡ではない。
289
+ External escrow は payment rail、durable monetary balance/authority、settlement/refund/slash との原子的
290
+ 連携を持たない。future audit は production beacon delivery、auditor、re-execution executor を持たず、
291
+ canary/bond は in-memory state を中心とし、durable balance、health bridge、automatic slash、appeal、
292
+ atomic debit を持たない。demand bonus も整数 weight/cap/terms の core 演算までで、funded demand
293
+ authority と payment settlement は未接続である。ローカル CLI が生成する scheduler/worker key、
294
+ network/job ID を production network 登録 identity と解釈しない。
295
+
296
+ ## CUDA host-only sanitizer evidence
297
+
298
+ この Apple host には `nvcc` と NVIDIA device がないため、CUDA implementation/device CTest は
299
+ compile/run していない。host-only build の CTest は 3/3 passed した。さらに
300
+ `build/palw-cuda-sanitize` を AppleClang 21、Debug、
301
+ `-Wall -Wextra -Wpedantic -Werror -fsanitize=address,undefined -fno-omit-frame-pointer` で構成した。
302
+
303
+ macOS のこの ASan runtime は leak detection を support せず、`detect_leaks=1` 試行は環境理由で
304
+ abort した。`ASAN_OPTIONS=detect_leaks=0:abort_on_error=1` と
305
+ `UBSAN_OPTIONS=halt_on_error=1` で host CTest を再実行し、同じ3/3 が sanitizer report なしで通過した。
306
+
307
+ 1. C++ ABI / canonical codec contract
308
+ 2. C header contract
309
+ 3. production non-issuance nested CMake gate
310
+
311
+ production gate は `PALW_CUDA_PRODUCTION_KERNEL_TRACE=ON` を意図どおり reject した。現在の CUDA
312
+ transport は final-output sketch であり、true partial accumulator、exact kernel identity、NVIDIA
313
+ 実機 evidence がない。よってこの host-only result を R32 completion または CUDA Receipt 発行の
314
+ 根拠には使用しない。
315
+
316
+ ## CI definitions
317
+
318
+ [`../../.github/workflows/palw-ci.yml`](../../.github/workflows/palw-ci.yml) は YAML parse gate を通過し、
319
+ 次を定義する。remote Actions run はこの host では実行していない。
320
+
321
+ - push/pull request: Ubuntu 24.04 へ Rust 1.81.0 を install し、上記 fmt、locked all-target
322
+ Clippy/test を再実行する MSRV job。
323
+ - push/pull request: Linux で host-only CUDA ABI/codec/closed-production-gate を ASan+UBSan、
324
+ leak detection、warning-as-error 付きで実行する job。
325
+ - manual dispatch only: `self-hosted, linux, x64, nvidia` runner と exact real SM architecture で
326
+ experimental CUDA device transport を build/test する job。device 0 の実 compute capability と
327
+ selected `*-real` architecture の一致も configure 前に要求する。
328
+
329
+ manual NVIDIA job は device executable を直接実行するため、return code 77 は CTest skip ではなく
330
+ failure になる。一方で `PALW_CUDA_PRODUCTION_KERNEL_TRACE=OFF` かつ job 名が `not R32` であり、
331
+ 成功しても final-output transport の実験 test にすぎない。CI definition 自体の追加も remote run
332
+ 成功を示さないため、この evidence は R32/R35 completion を主張しない。
333
+
334
+ 全 checkout は action SHA を固定し credential persistence を無効化する。automatic run は同じ
335
+ event/ref で cancel 可能だが、manual NVIDIA run は event 名で別 concurrency group に置き、push に
336
+ よる途中 cancel を受けない。
docs/evidence/metal-smoke-schema-v4-2026-07-15.md ADDED
@@ -0,0 +1,75 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Metal Schema-v4 Receipt Evidence — 2026-07-15
2
+
3
+ この文書は current source から Apple M1 Max で生成した schema-v4 Self Local Receipt set と、
4
+ 同じ tree に対する検証 gate の記録である。current canonical set は
5
+ [`../../receipts/final-v6/`](../../receipts/final-v6/) に置く。以前の schema-v3 実行は
6
+ [`metal-smoke-2026-07-15.md`](metal-smoke-2026-07-15.md) に historical evidence として残す。
7
+
8
+ ## Install / device gate
9
+
10
+ `scripts/install.sh` と `scripts/verify-install.sh` の full device gate は、固定した Qwen3-8B GGUF、
11
+ official base metadata、llama.cpp commit `12127defda4f41b7679cb2477a4b0d65ee6a0c8f`、4 build target の
12
+ revision/hash を照合した。Metal device は Apple M1 Max、Qwen3-8B の 37/37 layers を GPU へ offloadし、
13
+ one-token probe まで通過した。
14
+
15
+ ## Current canonical Receipt set
16
+
17
+ - Receipt ID: `eb51b08c3b86ef5df2cdebcfa9fcef812ec72197b3ad40ae2c5ba68cf4278131`
18
+ - verification bundle ID: `359f1bedaeefc1e140bf8c0dbba11582cb5cc0be428dcd95bc6077721f8096e9`
19
+
20
+ | Artifact | Bytes | SHA-256 |
21
+ |---|---:|---|
22
+ | [`eb51…8131.palw`](../../receipts/final-v6/eb51b08c3b86ef5df2cdebcfa9fcef812ec72197b3ad40ae2c5ba68cf4278131.palw) | 713 | `85ecb4281a1cb4abf26d6e3e70c84bfb3cc2a6dad80e2022ea4a356165345a75` |
23
+ | [`eb51…8131.json`](../../receipts/final-v6/eb51b08c3b86ef5df2cdebcfa9fcef812ec72197b3ad40ae2c5ba68cf4278131.json) | 3,427 | `03bee886144a2c64dd5f4d2207f86c748f5a3e7891b43f82f077f051342c3d0b` |
24
+ | [`eb51…8131.palw.bundle`](../../receipts/final-v6/eb51b08c3b86ef5df2cdebcfa9fcef812ec72197b3ad40ae2c5ba68cf4278131.palw.bundle) | 403,066 | `b475193fcfe1aea3189066790f925cc3682d2ff5a48cdfa061d62db85d0cff78` |
25
+ | [`eb51…8131.complete`](../../receipts/final-v6/eb51b08c3b86ef5df2cdebcfa9fcef812ec72197b3ad40ae2c5ba68cf4278131.complete) | 262 | `f3dc4e142eb602977c1ac065d51297418c8dca3967b6cdb53eb0dfb447d5c77b` |
26
+ | [`palw-state.sqlite3`](../../receipts/final-v6/palw-state.sqlite3) | 282,624 | `8a740c342a12c83ae211edfa8776b93a14ea9369e3d7bd19a1e780e0724c471e` |
27
+
28
+ 公開 JSON は strict `misaka.palw.public-receipt.v2` で、prefill 5 tokens、decode 2 tokens、
29
+ 5,868 canonical operations、1,950 GEMM events、14,562 canonical CUを記録する。主要 binding は次のとおり。
30
+
31
+ - operation schedule commitment: `ad5b7b98c81354be64a9021cb7a20838ccf9d555576fc0743c79286ea29681f6`
32
+ - GEMM trace root: `53c906957957aa34cd5c66fc9ad8c863e541732ead6728e3125d78dff6c133f1`
33
+ - runtime manifest hash: `5920accc3a0a0529c5f0c0a4050d6bf00d4d8fdf2b9772b64af2b4fdac2b84dd`
34
+ - model profile ID: `0c58c66b03bb471a248cb36be954b42945c6694c148370e6852f674ff98e64d4`
35
+ - runtime class ID: `c38307d57c847f3c276247411c563daf50fc7576cf1f6488ab29fe9a56970c5c`
36
+ - shape profile ID: `c4f8ae70ab6fda2707d841a64d79d36cff58509ea7f228eb4c93b693e630d674`
37
+
38
+ ## Separate verification and durable state
39
+
40
+ `palw-verify-bundle` を別 process で実行し、exit 0、`status=local_restored`、
41
+ `trust_scope=embedded_local_snapshot` を得た。これは暗号化 bundle 内の発行時 registry snapshot との
42
+ local continuity であり、外部 network authority や後日の revocation を独立に証明しない。
43
+
44
+ SQLite は application ID `PALW` (`1346456663`)、schema version 4、`integrity_check=ok`、
45
+ foreign-key violationなしだった。receipt/job は1/1、pair、audit、WorkTicket、slash、external settlement
46
+ 関連 state はすべて0である。portable set は最終検証後に `-wal` / `-shm` sidecarを持たない。
47
+
48
+ ## Rust / CUDA gates
49
+
50
+ Rust/Cargo 1.81.0 で `fmt --check`、`check --locked --all-targets`、
51
+ `clippy --locked --all-targets -D warnings`、`test --locked --all-targets` を通過した。通常 suite は
52
+ **166 passed, 2 ignored**(168 discovered)。pinned model と Metal observer を要求する ignored 2件は、
53
+ release build と親環境汚染 gate を有効にした手動実モデル実行で **2/2 passed** した。したがって実行済み
54
+ test は合計168件だが、通常 gate の表記は166 passed / 2 ignoredのままとする。
55
+
56
+ CUDA host-only gate は通常 build 3/3、AppleClang ASan+UBSan 3/3を通過し、production enable configure は
57
+ 意図どおり拒否された。この host に `nvcc` / NVIDIA device はないため device E2E は未実施であり、
58
+ これらはR32 completion evidenceではない。現行 CUDA observerはtrue producer accumulatorとproduction
59
+ exact kernel identityを証明せず、CUDA production Receipt発行はfail-closedのままである。
60
+
61
+ 上記はこのMetal Receiptを固定した時点のgateである。その後のRTX 4060 Ti/SM89
62
+ 実験 gate、standalone true-accumulator primitive、現行Rust test数は
63
+ [`cuda-wsl-sm89-2026-07-15.md`](cuda-wsl-sm89-2026-07-15.md) が正本である。Metal Receiptの
64
+ canonical ID/bytesはこの追加検証で変更しない。
65
+
66
+ ## Scope
67
+
68
+ この証跡は current schema-v4 local Receipt publication、復元、durable acceptance と、Metal runtime classの
69
+ local E2Eを示す。graph fallbackをCUDA kernel traceと同一��せず、local ephemeral signer/embedded snapshotを
70
+ production network authority、maturity、payment railの証明として扱わない。scheduler、beacon、auditor、bond、
71
+ external authority/paymentのproduction service未実装範囲は
72
+ [`../requirements.md`](../requirements.md) の `In progress` / `Blocked` を維持する。repository-scope の
73
+ baselineを固定したことはProduction Network readinessを意味せず、R13/R21/R23/R24/R26/R27/R35の未達gateは
74
+ 内部統合と外部境界をrequirementsで分離する。R32はこの証跡固定時にはhard `Blocked`
75
+ だったが、後続SM89 gateで外部hardware blockerが解消したため現行statusは `In progress`である。
docs/protocol-v1.md ADDED
@@ -0,0 +1,954 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # MISAKA PALW Receipt Protocol V1
2
+
3
+ 本書は `runtime-palw` の現行 Rust 実装を wire protocol の正本として記述する。ここにない
4
+ production 承認、決済連携、attestation を Receipt から推論してはならない。実装と本書が
5
+ 一致しない場合は Receipt を発行しない。
6
+
7
+ ## 1. Primitive types
8
+
9
+ - `Hash32`、commitment、ID、`NetworkId`: 固定 32 byte
10
+ - `u16` / `u32` / `u64` / `i64`: big endian。`i64` は two's-complement
11
+ - `bool`: `u8(0)` または `u8(1)`
12
+ - enum: variant tag `u8` の後に variant 固有 payload
13
+ - Ed25519 public key: 32 byte、signature: 64 byte、algorithm tag: `0`
14
+ - `Option<T>`: `u8(0)`、または `u8(1) || encode(T)`
15
+
16
+ `NetworkId` は UTF-8 名ではなく `Hash32` である。consensus encoding へ `usize`、float、map、
17
+ JSON text、platform enum、暗黙の default を直接入れない。
18
+
19
+ Receipt、scheduler message、future beacon、canary precommit、bond/external authority evidenceのEd25519
20
+ verificationは`verify_strict`を使う。small-order/weak public keyはworker signer、scheduler、beacon、bond、
21
+ external authorityのregistry recordとして拒否し、key IDが一致してもauthorization identityとして扱わない。
22
+
23
+ ## 2. Canonical encoding
24
+
25
+ ```text
26
+ LP(x) = u64be(len(x)) || x
27
+ bytes(x) = LP(x)
28
+ string(s) = LP(utf8(s))
29
+ vector(xs) = u64be(count(xs)) || encode(xs[0]) || ...
30
+ ```
31
+
32
+ 固定長 hash は LP を付けず 32 byte を直接書く。struct は本書に記した順で field を連結する。
33
+ decoder は未知の version/tag、truncated/trailing bytes、invalid UTF-8、非canonical bool/option、
34
+ 上限超過を拒否し、decode 後の再encodeが入力と一致しなければ拒否する。現行 reader の blob
35
+ 上限は 64 MiB、item count 上限は 16,777,216 である。
36
+
37
+ ## 3. Domain-separated hash
38
+
39
+ ```text
40
+ H(tag, part_0, ..., part_n) = SHA3-256(
41
+ LP("MISAKA/PALW") ||
42
+ LP(utf8(tag)) ||
43
+ u16be(schema_version) ||
44
+ LP(part_0) || ... || LP(part_n)
45
+ )
46
+ ```
47
+
48
+ part count 自体は入らないが、すべての part が LP されるため partition は曖昧にならない。
49
+ raw concatenation と domain の流用は禁止する。core V1 が使用する domain は次のとおり。
50
+
51
+ ```text
52
+ model-artifact-leaf/v1 model-artifact-node/v1
53
+ model-profile/v1 runtime-class/v1 runtime-manifest/v1
54
+ shape-profile/v1 cu-ruleset/v1
55
+ job-request/v1 assignment/v1 signer-key/v1
56
+ prompt/v1 output/v1 owner/v1
57
+ job-nullifier/v1 execution-nullifier/v1
58
+ schedule-init/v1 schedule-step/v1 schedule-final/v1
59
+ gemm-trace-scheme/v1 gemm-trace-init/v1 gemm-trace-step/v1
60
+ gemm-trace-final/v1
61
+ receipt-body/v1 receipt-id/v1 receipt-signature/v1
62
+ replica-match/v1 pair-id/v1
63
+ future-beacon/v1 audit-policy/v1
64
+ audit-selection/v1 audit-challenge/v1
65
+ audit-replay-result/v1 audit-replay-submission/v1
66
+ work-ticket/v2 local-maturity-basis/v2 canary/v1
67
+ canary-precommit/v1 durable-slash-offense/v2 bond-release/v1
68
+ bond-funding-attestation/v1 slash-appeal/v1 slash-decision/v1
69
+ slash-default-uphold/v1 external-escrow/v1 external-payment-command/v1
70
+ external-funding-attestation/v1 external-demand-weight-grant/v1
71
+ external-terminal-confirmation/v1
72
+ llama-cuda-dispatch/v1 cuda-kernel-entry/v1
73
+ verification-bundle-receipt/v1 verification-bundle-public/v1
74
+ verification-bundle-aad/v1 verification-bundle-aead-key/v1
75
+ verification-bundle-id/v1
76
+ ```
77
+
78
+ `request/v1` は generic helper `commit_request` に残るが、署名済み `JobRequestV1` の ID には
79
+ 使用しない。job request の唯一の domain は `job-request/v1` である。deterministic policy と
80
+ Qwen Metal profile はさらに `lora-set/v1`、`control-vector-set/v1`、
81
+ `thinking-policy/v1`、`workspace-policy/v1`、`thread-policy/v1`、
82
+ `qwen-native-observer-mapping/v1` 等の artifact domain を runtime identity の内側で使う。
83
+
84
+ ## 4. Artifact and model identity
85
+
86
+ artifact は slash-separated relative path の辞書順で処理する。空、absolute、末尾 `/`、空要素、
87
+ `.`、`..`、backslash、非UTF-8、重複、symlink、非regular file は拒否する。
88
+
89
+ ```text
90
+ leaf_i = H(
91
+ "model-artifact-leaf/v1",
92
+ utf8(relative_path_i),
93
+ u64be(file_size_i),
94
+ file_bytes_i
95
+ )
96
+ ```
97
+
98
+ file は streaming hash するが上式と同じ framing である。各 level の leaf/node が奇数なら
99
+ 末尾を複製し、`H("model-artifact-node/v1", left, right)` で二分木を作る。artifact は空に
100
+ できない。
101
+
102
+ `ModelProfile` canonical order:
103
+
104
+ 1. `architecture: string`
105
+ 2. `base_repository: string`
106
+ 3. `immutable_revision: string`
107
+ 4. `topology: u8` (`0=Dense`, `1=MixtureOfExperts`)
108
+ 5. `tokenizer: string`
109
+ 6. `weight_artifact_root: Hash32`
110
+ 7. `tokenizer_artifact_root: Hash32`
111
+ 8. `chat_template_digest: Hash32`
112
+ 9. `special_tokens_digest: Hash32`
113
+ 10. `hidden_size: u32`
114
+ 11. `attention_heads: u32`
115
+ 12. `kv_heads: u32`
116
+ 13. `head_dim: u32`
117
+ 14. `layer_count: u32`
118
+ 15. `intermediate_size: u32`
119
+ 16. `rope: string`
120
+ 17. `rope_theta: u64`
121
+ 18. `rope_scaling_millionths: u64`
122
+ 19. `native_context_tokens: u32`
123
+ 20. `vocabulary: u32`
124
+ 21. `precision: string`
125
+
126
+ ```text
127
+ model_profile_id = H("model-profile/v1", encode(ModelProfile))
128
+ ```
129
+
130
+ 全 string、artifact hash、次元、RoPE integer parameter は nonzero/nonempty でなければならない。
131
+ `hidden_size / attention_heads == head_dim`、`attention_heads % kv_heads == 0` も検査する。
132
+ Q4 GGUF は fixed inference artifact であり、学習済み base revision と量子化 artifact の双方を
133
+ profile に bind する。
134
+
135
+ ## 5. Runtime class, deterministic policy, and manifest
136
+
137
+ `BackendKind` canonical encoding:
138
+
139
+ - `0=CUDA`: `cuda_version, driver_version, cublas_version, sm_architecture`(各 string)、
140
+ `cublas_policy_digest: Hash32`
141
+ - `1=Metal`: `metal_version, driver_build, gpu_family, language_version`(各 string)、
142
+ `metallib_digest: Hash32`
143
+ - `2=CPU`: `isa_class, blas_version`(各 string)、`affinity_policy_digest: Hash32`
144
+
145
+ `TraceCapability`: `0=None`, `1=GraphFallback`, `2=KernelSketch`。
146
+
147
+ `RuntimeClass` canonical order:
148
+
149
+ 1. `backend: BackendKind`
150
+ 2. `runtime_version: string`
151
+ 3. `runtime_source_repository: string`
152
+ 4. `runtime_source_commit: string`
153
+ 5. `runtime_binary_digest: Hash32`
154
+ 6. `dirty_patch_digest: Hash32`
155
+ 7. `operating_system: string`
156
+ 8. `host_architecture: string`
157
+ 9. `device_class: string`
158
+ 10. `accelerator_api: string`
159
+ 11. `compiler_version: string`
160
+ 12. `build_flags_digest: Hash32`
161
+ 13. `kernel_binary_digest: Hash32`
162
+ 14. `kernel_algorithm_digest: Hash32`
163
+ 15. `accelerator_count: u32`
164
+ 16. `tensor_parallel: u32`
165
+ 17. `split_policy: string`
166
+ 18. `quantization: string`
167
+ 19. `kv_cache_precision: string`
168
+ 20. `flash_attention: bool`
169
+ 21. `tensor_repack: bool`
170
+ 22. `context_size: u32`
171
+ 23. `batch_size: u32`
172
+ 24. `micro_batch_size: u32`
173
+ 25. `thread_count: u32`
174
+ 26. `trace_capability: TraceCapability`
175
+ 27. `deterministic_policy: DeterministicPolicy`
176
+
177
+ `DeterministicPolicy` の nested canonical order は
178
+ `temperature_millionths:u32, top_p_millionths:u32, top_k:u32, batch_size:u32,
179
+ tensor_parallel:u32, parallel_sequences:u32, context_shift_enabled:bool,
180
+ speculative_decoding_enabled:bool, dynamic_fit_enabled:bool, random_seed:u64,
181
+ kernel_graph_id:Hash32, quantization_artifact_id:Hash32, lora_adapters_digest:Hash32,
182
+ control_vectors_digest:Hash32, thinking_policy_digest:Hash32, workspace_policy_digest:Hash32,
183
+ thread_policy_digest:Hash32` である。
184
+
185
+ V1 strict policy は temperature 0、top-p 1,000,000、top-k 0、batch/tensor-parallel/
186
+ parallel-sequences各1、context shift/speculative/dynamic fit無効を要求する。
187
+
188
+ ```text
189
+ runtime_class_id = H("runtime-class/v1", encode(RuntimeClass))
190
+ ```
191
+
192
+ Qwen Metal profile の `kernel_graph_id` は pinned llama.cpp commit、
193
+ `qwen_adapter_mapping_id_v1()`、native graph variant、prefill/decode serialization policyを
194
+ まとめて hash する。したがって graph-to-CU mapping の変更も runtime class を変更する。
195
+
196
+ `ShapeProfile` canonical order は `batch_size:u32, max_context_tokens:u32,
197
+ max_decode_tokens:u32, max_prefill_tokens:u32`。batch は1、各上限は nonzero、prefill/decode
198
+ 各上限は context 以下とする。
199
+
200
+ `RuntimeManifest` canonical order:
201
+
202
+ 1. `manifest_version: u16` (=1)
203
+ 2. `model_profile: ModelProfile`
204
+ 3. `runtime_class: RuntimeClass`
205
+ 4. `shape_profile: ShapeProfile`
206
+ 5. `model_artifact_digest: Hash32`
207
+ 6. `model_artifact_size: u64`
208
+ 7. `runtime_device_digest: Hash32`
209
+ 8. `loaded_libraries_digest: Hash32`
210
+ 9. `environment_allowlist_digest: Hash32`
211
+ 10. `build_provenance_digest: Hash32`
212
+ 11. `schedule_schema_version: u16` (=1)
213
+ 12. `trace_schema_version: u16` (=1)
214
+ 13. `cu_ruleset_id: Hash32`
215
+ 14. `trace_scheme_id: Hash32`
216
+
217
+ `model_artifact_digest == model_profile.weight_artifact_root`、batch/context、CU ruleset を相互検査し、
218
+ `runtime_manifest_hash = H("runtime-manifest/v1", encode(RuntimeManifest))` とする。
219
+
220
+ 現行Qwen Metal issuanceはtokenizer、observer、host/source identity childのinherited environmentを消去し、
221
+ `LANG=C`、`LC_ALL=C`だけを設定する。host/source identity helperはabsolute executable pathを使い、この
222
+ exact mapを`environment_allowlist_digest`へbindする。親processの追加environmentはcompute childへ継承しない。
223
+
224
+ ## 6. Scheduler-signed request and assignment
225
+
226
+ `JobClass`: `0=SelfLocal`, `1=SelfReplicated`, `2=ExternalReplicated`。
227
+ `EvidenceLevel`: `0=Wrapper`, `1=RuntimeObserved`, `2=GemmTraced`。replicated class は
228
+ `GemmTraced` を要求する。
229
+
230
+ `ExecutionConstraintsV1` order:
231
+
232
+ 1. `model_profile_id: Hash32`
233
+ 2. `runtime_class_id: Hash32`
234
+ 3. `shape_profile_id: Hash32`
235
+
236
+ `JobRequestV1` canonical order:
237
+
238
+ 1. `version: u16` (=1)
239
+ 2. `network_id: Hash32`
240
+ 3. `scheduler_job_id: Hash32`
241
+ 4. `job_class: JobClass`
242
+ 5. `prompt_commitment: Hash32`
243
+ 6. `shared_output_nonce: Hash32`
244
+ 7. `constraints: ExecutionConstraintsV1`
245
+ 8. `required_evidence_level: EvidenceLevel`
246
+ 9. `issued_epoch: u64`
247
+ 10. `expires_epoch: u64`
248
+ 11. `external_escrow_reference: Option<Hash32>`
249
+
250
+ `ExternalReplicated` は nonzero escrow reference が必須、それ以外は `None` が必須。
251
+
252
+ ```text
253
+ request_commitment = H("job-request/v1", encode(JobRequestV1))
254
+ ```
255
+
256
+ `AssignmentV1` canonical order:
257
+
258
+ 1. `version: u16` (=1)
259
+ 2. `network_id: Hash32`
260
+ 3. `request_commitment: Hash32`
261
+ 4. `scheduler_job_id: Hash32`
262
+ 5. `job_class: JobClass`
263
+ 6. `replica_slot: u8`
264
+ 7. `worker_credential_id: Hash32`
265
+ 8. `runtime_instance_id: Hash32`
266
+ 9. `assignment_id: Hash32`
267
+ 10. `issued_epoch: u64`
268
+ 11. `expires_epoch: u64`
269
+
270
+ ```text
271
+ assignment_commitment = H("assignment/v1", encode(AssignmentV1))
272
+ ```
273
+
274
+ assignment は network/request/job/class を request と一致させ、validity interval を request 内へ
275
+ 包含させる。Self Local は slot 0、replicated は slot 0/1 のみ。
276
+
277
+ request/assignment envelope は同じ orderを使う。
278
+
279
+ ```text
280
+ u16be(envelope_version=1) ||
281
+ LP(canonical_body) ||
282
+ scheduler_key_id:Hash32 ||
283
+ u8(signature_algorithm=0) ||
284
+ signature:64-byte
285
+ ```
286
+
287
+ signature message はそれぞれ `request_commitment` / `assignment_commitment` そのもの。
288
+ `scheduler_key_id = H("signer-key/v1", scheduler_public_key)`。network-scoped registry は key の
289
+ valid-from/through、revocation、message epoch、weak-key rejectionを検査し、signatureはstrict Ed25519で
290
+ 検証する。miner が job ID、nonce、slot、assignment IDを自己生成したものは authorization record に
291
+ ならない。現行local Receipt CLIが自己生成するscheduler key/snapshotはfixture boundaryであり、
292
+ production scheduler/governance authorizationを表さない。
293
+
294
+ ## 7. Prompt, output, owner, and nullifiers
295
+
296
+ prompt text は commit しない。tokenizerの正確な prompt token列を次で commit する。
297
+
298
+ ```text
299
+ PromptTokens = u64be(count) || concat(u32be(token_id_i))
300
+ prompt_commitment = H(
301
+ "prompt/v1", network_id, scheduler_job_id,
302
+ shared_output_nonce, PromptTokens
303
+ )
304
+ ```
305
+
306
+ `StopReason`:
307
+
308
+ - `0=EndOfSequence(u32 eos_token_id)`
309
+ - `1=LengthLimit`
310
+ - `2=ContextLimit`
311
+ - `3=StopSequence(Hash32 stop_sequence_digest)`
312
+
313
+ `Cancelled` variant は存在しない。cancelled execution から Receipt を発行しない。現行request
314
+ schemaにはstop-sequence list fieldがないため、`StopSequence` digestが特定requestの設定へbindして
315
+ いるかをverifierが別途検査する実装もまだない。
316
+
317
+ ```text
318
+ CanonicalOutput =
319
+ u64be(token_count) || concat(u32be(generated_token_id_i)) || encode(stop_reason)
320
+
321
+ output_commitment = H(
322
+ "output/v1", network_id, job_nullifier,
323
+ shared_output_nonce, CanonicalOutput
324
+ )
325
+ ```
326
+
327
+ k=2 の両slotは signed request の同じ nonceを使う。nonce、prompt IDs、output IDs、owner salt は
328
+ Receipt bodyへ載せず、stateless verifier への private opening とする。
329
+
330
+ ```text
331
+ owner_commitment = H(
332
+ "owner/v1", network_id, owner_salt, owner_ed25519_public_key
333
+ )
334
+
335
+ signer_key_id = H("signer-key/v1", owner_ed25519_public_key)
336
+
337
+ job_nullifier = H(
338
+ "job-nullifier/v1", network_id, scheduler_job_id,
339
+ request_commitment, u8(job_class)
340
+ )
341
+
342
+ execution_nullifier = H(
343
+ "execution-nullifier/v1", job_nullifier, assignment_id,
344
+ u8(replica_slot), worker_credential_id, runtime_instance_id
345
+ )
346
+ ```
347
+
348
+ owner commitment に worker credential は含めない。registry の `SignerRecord` が public key、
349
+ owner commitment、worker credential の対応を供給する。owner salt は registry recordにも含めない。
350
+
351
+ ## 8. Canonical operations and CU
352
+
353
+ `DType`: `0=Fp32`, `1=Fp16`, `2=Bf16`, `3=Int8`, `4=Int4`。
354
+ `QuantizationClass`: `0=None`, `1=Q4K`, `2=Q4KM`, `3=Q5KM`, `4=Q8_0`,
355
+ `5=Iq4Xs`, `255=Artifact(Hash32)`。
356
+
357
+ `GemmShape` order は `m:u32, n:u32, k:u32, batch:u32, dtype:DType,
358
+ quantization:QuantizationClass`。
359
+
360
+ `ComputeOperation` wire tags と payload:
361
+
362
+ | Tag | Variant | Canonical payload order |
363
+ |---:|---|---|
364
+ | 0 | `Gemm` | `GemmShape` |
365
+ | 1 | `Attention` | `query_tokens:u32, key_value_tokens:u32, heads:u32, head_dim:u32, batch:u32, causal:bool` |
366
+ | 2 | `LayerNorm` | `elements:u32, batch:u32` |
367
+ | 3 | `RmsNorm` | `elements:u32, batch:u32` |
368
+ | 4 | `Rotary` | `tokens:u32, heads:u32, head_dim:u32` |
369
+ | 5 | `ExpertRoute` | `tokens:u32, experts:u32, top_k:u32` |
370
+ | 6 | `KvCacheRead` | `bytes:u64` |
371
+ | 7 | `KvCacheWrite` | `bytes:u64` |
372
+ | 8 | `Silu` | `elements:u64` |
373
+ | 9 | `ElementwiseMultiply` | `elements:u64` |
374
+ | 10 | `Softmax` | `elements:u64` |
375
+ | 11 | `ElementwiseAdd` | `elements:u64` |
376
+ | 12 | `TensorCopy` | `bytes:u64` |
377
+ | 13 | `EmbeddingLookup` | `elements:u64` |
378
+
379
+ Dense modelでは `ExpertRoute` を拒否する。Qwen adapter mapping V1 は `MUL_MAT`、`RMS_NORM`、
380
+ `ROPE`、`SET_ROWS`、`SOFT_MAX`、`GLU`、`MUL`、`CONT`、`ADD`、`GET_ROWS` を上記 operationへ
381
+ 変換し、`VIEW/RESHAPE/PERMUTE`だけを layout metadata として除外する。その他は fail-closed。
382
+
383
+ `ComputeUnitRules::v1()` は全variantを integer-only、checked `u128`、明示ceil、minimum 1で
384
+ 再計算する。ruleset descriptor の hash が `cu_ruleset_id`。observer申告の cost は受け取らない。
385
+
386
+ ## 9. Ordered operation schedule
387
+
388
+ `ExecutionPhase`: `0=Prefill`、`1=Decode(u32 step)`。
389
+ `ScheduledOperation` canonical order:
390
+
391
+ 1. `index: u64`(0から連続)
392
+ 2. `phase: ExecutionPhase`
393
+ 3. `layer_id: Option<u32>`(`None` は global LM head 等)
394
+ 4. `operation: ComputeOperation`
395
+
396
+ ```text
397
+ s0 = H("schedule-init/v1", job_nullifier, shape_profile_id, cu_ruleset_id)
398
+ si = H("schedule-step/v1", s(i-1), u64be(i), encode(event_i))
399
+ schedule_root = H("schedule-final/v1", sn, u64be(event_count))
400
+ ```
401
+
402
+ index、chain、decode stepの単調性、model layer range、Dense/MoE制約を verifier が再検査する。
403
+ 挿入、削除、並べ替えはCU合計が同じでもrootを変える。
404
+
405
+ ## 10. GEMM trace
406
+
407
+ `TraceEvidenceKind` の wire tag は `0=Absent`, `1=GraphFallback`, `2=KernelSketch`。
408
+ `trace_scheme_id_v1` は
409
+ `H("gemm-trace-scheme/v1", fixed_scheme_descriptor)` である。
410
+
411
+ `AccumulatorSketch` は `i64be lane[4]`。`TileIndex` は `m:u32, n:u32, k:u32`。
412
+ `GemmTraceEvent` canonical order:
413
+
414
+ 1. `index: u64`
415
+ 2. `schedule_index: u64`
416
+ 3. `kernel_sequence: u64`
417
+ 4. `tile_linear_index: u32`
418
+ 5. `tile_count: u32`
419
+ 6. `evidence_kind: TraceEvidenceKind`
420
+ 7. `phase: ExecutionPhase`
421
+ 8. `layer_id: Option<u32>`(`None` は global LM head)
422
+ 9. `kernel_id: Hash32`
423
+ 10. `shape: GemmShape`
424
+ 11. `tile: TileIndex`
425
+ 12. `accumulator_sketch: [i64;4]`
426
+
427
+ ```text
428
+ t0 = H("gemm-trace-init/v1", job_nullifier, trace_scheme_id)
429
+ ti = H("gemm-trace-step/v1", t(i-1), u64be(i), encode(trace_event_i))
430
+ trace_root = H(
431
+ "gemm-trace-final/v1", tn,
432
+ u64be(trace_event_count), u64be(gemm_group_count)
433
+ )
434
+ ```
435
+
436
+ 各scheduled GEMMは1つのcontiguous groupとなる。groupのschedule indexは狭義増加、全event index/
437
+ kernel sequenceは0から連続、group内metadataは一致、kernel IDはnonzero、全groupで evidence kindを
438
+ 混在させない。`GraphFallback` は各GEMM exactly 1 synthetic tile、`KernelSketch` は1個以上の
439
+ native tileを許す。trace group数はschedule内GEMM数と一致し、各eventのschedule index、phase、
440
+ optional layer、shapeを元scheduleと照合する。
441
+
442
+ 現行 Qwen Metal adapter が発行できる trace は `GraphFallback` だけであり、CUDA claimへ昇格しない。
443
+ CUDA C ABIは既存final-output V1 recordに加え、declared origin、accumulator stage/dtype、sketch scheme、
444
+ reduction segment、producer variant IDを持つexact 184-byte V2 wire recordを定義する。Rustのstrict
445
+ decoder/binderは全unfiltered record streamをexpected launch sequence、schedule、tile/segment order、exact
446
+ MMVQ/flash-attention dispatch、CUDA runtime manifestへbindする。raw `ProducerAccumulator`はtransport上の
447
+ declared tagにすぎず、`BoundCudaTranscriptV1`はdiagnostic typestateである。
448
+ さらにadditive V3は452-byte recordと、FA-off attentionのQK-score MMVF、masked/scaled softmax、
449
+ value-aggregation MMVFからなるcanonical 3-sublaunch grouping、strict schedule/runtime binderを実装する。
450
+
451
+ 別のauthority layerはsigned attestationをnetwork/job/execution/assignment、runtime class/manifest、
452
+ producer integration、operation schedule、full unfiltered transcriptへexact bindし、public raw constructorを
453
+ 持たない`AuthorityBoundCudaTranscriptV2`を作る。そこからproducer-accumulator GEMMだけを
454
+ `AuthorityBoundCudaReceiptEvidenceV2`へdeterministically射影する。attention
455
+ final-output recordはsigned full-transcript commitmentに残すがGEMM evidenceへは昇格しない。
456
+
457
+ `ComputeReceiptV1`にはauthority provenance commitmentがないため、V1 builderはCUDA
458
+ `KernelSketch`の発行を拒否し、workerがV1 bodyを手組み・署名してもverifierが拒否する。standaloneの
459
+ true FP32 producer-accumulator採取primitiveはRTX 4060 Ti sm_89でdevice suite 7/7と20/20同一
460
+ diagnostic fingerprintを確認した。最終grouped suiteは8/8である。vendored llama.cppのQ4_K/Q6_K MMVQと
461
+ FA-off QK/softmax/PV producerも接続済みで、same-backend Qwen 1-token diagnostic E2Eは361/361 record、
462
+ 3回同一fingerprint、5 work-class rejectionを確認した。ただしproduction Receipt authorityではない。
463
+
464
+ 現行deterministic profileはFA-offで、legacy V2が表すattention dispatchは
465
+ `LlamaFlashAttention`だけである。この非互換に対するV3 sublaunch/grouping schema/binderは実装済みだが、
466
+ 実eager-attention 3-stage hook、361-launch実機E2E、release manifest、Receipt/Bundle/SQLite V2も
467
+ 実装・検証済みである。live callbackへのauthority-derived canonical expected table接続は未完了である。public headerは
468
+ `PALW_CUDA_TRACE_PRODUCTION_CAPABLE=0`、`PALW_CUDA_PRODUCER_VENDOR_RUNTIME_INTEGRATED=0`、
469
+ `PALW_CUDA_PRODUCER_RECEIPT_MAPPING_AVAILABLE=0`、`PALW_CUDA_PRODUCER_PRODUCTION_CAPABLE=0`で、production
470
+ CMake optionもfailするため、R32は`In progress`でもproduction CUDA `KernelSketch` Receiptを発行してはならない。
471
+
472
+ ## 11. Compute Receipt and signature
473
+
474
+ `ComputeReceiptV1` は正確に30 fieldで、canonical orderは次のとおり。
475
+
476
+ 1. `receipt_version: u16` (=1)
477
+ 2. `network_id: Hash32`
478
+ 3. `request_commitment: Hash32`
479
+ 4. `scheduler_job_id: Hash32`
480
+ 5. `signed_assignment_id: Hash32`(assignment body の `assignment_id`)
481
+ 6. `replica_slot: u8`
482
+ 7. `model_profile_id: Hash32`
483
+ 8. `runtime_class_id: Hash32`
484
+ 9. `runtime_manifest_hash: Hash32`
485
+ 10. `shape_profile_id: Hash32`
486
+ 11. `cu_ruleset_id: Hash32`
487
+ 12. `trace_scheme_id: Hash32`
488
+ 13. `trace_evidence: TraceEvidenceKind`
489
+ 14. `operation_schedule_commitment: Hash32`
490
+ 15. `schedule_event_count: u64`
491
+ 16. `canonical_compute_units: u64`
492
+ 17. `prefill_tokens: u32`
493
+ 18. `decode_tokens: u32`
494
+ 19. `output_commitment: Hash32`
495
+ 20. `gemm_trace_root: Hash32`
496
+ 21. `trace_event_count: u64`
497
+ 22. `owner_commitment: Hash32`
498
+ 23. `worker_credential_id: Hash32`
499
+ 24. `job_nullifier: Hash32`
500
+ 25. `execution_nullifier: Hash32`
501
+ 26. `job_class: JobClass`
502
+ 27. `evidence_level: EvidenceLevel`
503
+ 28. `timestamp: u64`(informational only)
504
+ 29. `issued_epoch: u64`
505
+ 30. `expires_epoch: u64`
506
+
507
+ body-local evidence invariants:
508
+
509
+ - `Wrapper`: schedule count、trace count、CUは0、trace kindはAbsent
510
+ - `RuntimeObserved`: schedule countとCUはnonzero、trace countは0、trace kindはAbsent
511
+ - `GemmTraced`: schedule count、trace count、CUはnonzero、trace kindはnon-Absent
512
+ - replicated class: evidence levelはGemmTraced
513
+
514
+ trace無しでも `gemm_trace_root` は zero ではなく、同jobで初期化した empty trace root である。
515
+
516
+ ```text
517
+ body_id = H("receipt-body/v1", network_id, encode(body))
518
+ receipt_id = H("receipt-id/v1", network_id, encode(body))
519
+ signature_message = H("receipt-signature/v1", network_id, encode(body))
520
+ ```
521
+
522
+ `SignedReceiptV1` canonical order:
523
+
524
+ ```text
525
+ u16be(envelope_version=1) ||
526
+ LP(encode(body)) ||
527
+ signer_key_id:Hash32 ||
528
+ u8(signature_algorithm=0) ||
529
+ ed25519_signature:64-byte
530
+ ```
531
+
532
+ 現行 `receipt_id` は署名byteを含まず、同じbodyなら同じIDである。signature は worker keyで上記
533
+ messageを署名する。verifier は signer registry、scheduler-derived assignment authorization、
534
+ manifest、private prompt/output opening、schedule/CU/traceをすべて照合する。signer registryはnonzero
535
+ owner/credentialとnon-weak keyだけを受け、Receipt signatureはstrict Ed25519で検証する。
536
+
537
+ ## 12. Stateless verification and durable acceptance
538
+
539
+ stateless path:
540
+
541
+ 1. signed envelope と body をstrict canonical decode
542
+ 2. body structure、network、assignment epoch
543
+ 3. scheduler署名検証済み authorization recordとの全binding
544
+ 4. worker signer key、owner commitment、credential、Receipt signature
545
+ 5. model/runtime/manifest/shape/CU/trace identity
546
+ 6. job/execution nullifier再導出
547
+ 7. token shape bounds
548
+ 8. schedule、CU、traceをwitnessから再計算
549
+ 9. prompt/output private openingとtoken countを再計算
550
+
551
+ 型は `UnverifiedReceipt -> StatelesslyVerifiedReceipt`。その後 `StateStore::accept` が SQLite
552
+ transactionで replay/cardinality keyを予約した場合だけ `AcceptedReceipt` になる。Matcher と
553
+ canary submission は `AcceptedReceipt` を要求する。first acceptance時のstateless
554
+ `verified_at_epoch`をdurable `accepted_at_epoch`として保存する。restart後の`restore_accepted`は新しい
555
+ stateless verification epochとoriginal acceptance epochを区別し、canonical signed Receiptとauthorized
556
+ runtime instanceがstored rowとexact一致するときだけtypestateを復元する。stored acceptanceはbody
557
+ issued/expiry内かつcurrent `verified_at_epoch`以下でなければならず、rollbackを拒否する。
558
+
559
+ durable storeはapplication ID `PALW`、schema version 4、foreign keys、WAL、`synchronous=FULL`を要求する。
560
+ exact table set/column order/foreign-key count/indexに加え、non-internal `sqlite_master`の全
561
+ `(type,name,tbl_name,sql)`をcanonical encodeしたSHA3-256 fingerprintをcompiled goldenと照合する。
562
+ 旧schemaのsilent migrationとobjectを持つunclaimed DBは拒否する。receiptのaccepted epoch、pairのmatched
563
+ epoch、signed future beaconのclaimed epoch、audit replayのissued/accepted epochは8-byte big-endian
564
+ BLOBとして保存する。beacon verification時のcaller current epochは別columnへ固定せず、restore時の
565
+ current `AcceptedReceipt.verified_at_epoch`でregistry validity/revocationとともに再検証する。
566
+
567
+ ## 13. Replica matching
568
+
569
+ `MatchProjectionV1` canonical order:
570
+
571
+ 1. `job_nullifier`
572
+ 2. `request_commitment`
573
+ 3. `job_class`
574
+ 4. `model_profile_id`
575
+ 5. `runtime_class_id`
576
+ 6. `runtime_manifest_hash`
577
+ 7. `shape_profile_id`
578
+ 8. `cu_ruleset_id`
579
+ 9. `canonical_compute_units`
580
+ 10. `prefill_tokens`
581
+ 11. `decode_tokens`
582
+ 12. `operation_schedule_commitment`
583
+ 13. `schedule_event_count`
584
+ 14. `output_commitment`
585
+ 15. `trace_scheme_id`
586
+ 16. `trace_evidence`
587
+ 17. `gemm_trace_root`
588
+ 18. `trace_event_count`
589
+
590
+ network、scheduler job ID、assignment/slot、owner/credential/runtime instance/execution nullifier、
591
+ evidence level、timestamp/epoch、signature はprojectionに入らない。ただしjob nullifierとrequest
592
+ commitmentはnetwork-boundであり、durable pair保存時には両memberのnetworkをexplicitに照合する。
593
+ 2 Receipt は未失効、slot集合`{0,1}`、異なるexecution、signer key、credential、owner、assignment、
594
+ runtime instanceでなければならない。pairing `current_epoch`は両bodyのissued epoch、両receiptのoriginal
595
+ accepted epochとcurrent stateless verified epoch以上、両expiry以下でなければならない。
596
+
597
+ ```text
598
+ match_commitment = H("replica-match/v1", encode(projection))
599
+ pair_id = H(
600
+ "pair-id/v1", network_id,
601
+ min(execution_nullifier_a, execution_nullifier_b),
602
+ max(execution_nullifier_a, execution_nullifier_b),
603
+ match_commitment
604
+ )
605
+ ```
606
+
607
+ `MatchedReplicaPair` はpairing呼出し時の`current_epoch`をprivate `matched_epoch`として保持する。
608
+ このepochはprojection/pair IDには入らないが、Self Replicated用のpublic maturity constructorが
609
+ `MatureEvidence.mature_epoch`へ封入する。durable pair recordのcanonical bytesには`matched_epoch`を
610
+ 含め、memberのstored issued/accepted/expiry epochと再照合する。
611
+
612
+ ## 14. Audit, Work Ticket, canary, bond, and external identities
613
+
614
+ `FutureBeaconV1` canonical orderは`version:u16 (=1), network_id:Hash32, epoch:u64,
615
+ value:Hash32`。`beacon_id = H("future-beacon/v1", encode(body))`。signed envelopeは次のorderである。
616
+
617
+ ```text
618
+ u16be(envelope_version=1) ||
619
+ LP(encode(FutureBeaconV1)) ||
620
+ authority_key_id:Hash32 ||
621
+ u8(signature_algorithm=0) ||
622
+ ed25519_signature:64-byte
623
+ ```
624
+
625
+ signature messageは`beacon_id`。network-scoped authority registryはbeacon epochのvalidity、verification
626
+ epoch時点のrevocation、key ID、weak keyを検査し、strict Ed25519成功後だけraw constructorを持たない
627
+ `VerifiedFutureBeacon`へ昇格する。claimed beacon epochはverification epoch以下でなければならない。
628
+
629
+ future audit selection:
630
+
631
+ ```text
632
+ sample = H(
633
+ "audit-selection/v1", network_id, receipt_id,
634
+ u64be(beacon_epoch), beacon
635
+ )
636
+ selected iff sample_as_big_endian_u256 < selection_threshold:Hash32
637
+
638
+ challenge_id = H(
639
+ "audit-challenge/v1", network_id, receipt_id, sample
640
+ )
641
+ ```
642
+
643
+ `AuditRecord::new`はexact `AcceptedReceipt`を受け、network、receipt ID、body issued epoch、durable
644
+ accepted epoch、scheduler job、job nullifier、request commitmentをbindする。beacon epochはissued epochと
645
+ accepted epochの両方より後でなければならない。v1 policyはselection threshold `2^252`(一様digestの
646
+ 1/16)、response window 2 epoch、challenge window 5 epochの固定値で、全値を`audit-policy/v1` IDへ
647
+ commitする。
648
+
649
+ `StateStore::store_audit_selection`はpolicy ID、original issued/accepted epoch、canonical signed beacon、
650
+ beacon ID/value/authority key ID、challenge/deadlineまたはnon-selected mature epochを保存する。restore時は
651
+ current authority registryでsigned beaconを再検証し、sample/challenge/deadlineを再計算する。
652
+
653
+ selected replayはdistinctな`StatelesslyVerifiedReceipt`をaudit専用にacceptする。same network/job/requestを
654
+ 要求し、receipt/execution/assignment/runtime instance/signer key/worker credential/owner commitmentはoriginal
655
+ と異ならなければならない。replay issued epochはbeaconより後、durable replay accepted epochはissued/
656
+ current stateless verified epoch以上かつdeadline以下である。`VerifiedReplayVerdict`が両
657
+ `MatchProjectionV1`を比較してresult commitmentとmatch outcomeを作るため、callerはraw
658
+ `projection_matches:bool`を注入できない。
659
+
660
+ selected pathはaudit replay identityの一回予約、terminal mismatchまたはpass、pass時のSelf Local
661
+ maturity sourceを1 SQLite transactionで確定する。non-selected pathもwindow maturityとsourceを1
662
+ transactionで確定する。beacon delivery/finality、auditor assignment、model re-execution、opening配送は
663
+ このwire/state coreの外部service boundaryである。
664
+
665
+ `restore_audit`はnon-replay state/terminalをrestoreするが、selected pass/mismatch terminalは
666
+ `AuditReplayRequired`で拒否する。この場合は`restore_selected_audit_with_replay`を使い、durable audit
667
+ state/challenge、stored canonical replay、全identity/epochを照合する。さらにprojection verdictを再計算し、
668
+ match bit、submission commitment、completed epochをstored terminal outcomeへexact比較する。
669
+
670
+ `WorkTicketV2` のIDを除くcanonical body orderは次のとおり。
671
+
672
+ 1. `version:u16 (=2)`
673
+ 2. `network_id:Hash32`
674
+ 3. `source_id:Hash32`
675
+ 4. `maturity_basis_id:Hash32`
676
+ 5. `weight_grant_id:Option<Hash32>`
677
+ 6. `job_class:JobClass`
678
+ 7. `weight_policy_version:u32`
679
+ 8. `canonical_compute_units:u64`
680
+ 9. `weight_bps:u32`
681
+ 10. `weighted_compute_units:u64`
682
+ 11. `issued_epoch:u64`
683
+
684
+ ```text
685
+ weighted_CU = ceil(CU * weight_bps / 10_000)
686
+ ticket_id = H("work-ticket/v2", network_id, encode(ticket_body_without_ticket_id))
687
+ ```
688
+
689
+ V1 default weight は Self Local challenge 2,500、audit pass 5,000、replicated 10,000、external
690
+ demand bonus最大5,000 bps。これは算術/型変換の実装値であり、production network admission の
691
+ 証明ではない。
692
+
693
+ `MatureEvidence` はwire objectではなく、fieldと低水準constructorを非公開にしたtyped gateである。
694
+ 生成経路、`maturity_basis_id`、`mature_epoch`は次の3つだけ。
695
+
696
+ - Self Local: exact `AcceptedReceipt + AuditRecord::Mature`。domain `local-maturity-basis/v2`で
697
+ audit basis/epochをbindし、audit stateが保持するmature epochを使う
698
+ - Self Replicated: `MatchedReplicaPair`。pair IDをmaturity basis、pairのmatched epochを使う
699
+ - External Replicated: authority-verified terminal settlement。confirmation IDをmaturity basis、authority-
700
+ signed grant IDを必須weight grant、confirmation epochをmature epochとして使う
701
+
702
+ `StateStore::register_mature_evidence(&MatureEvidence)` はstored receipt/pairのnetwork、class、CUとopaque
703
+ evidenceを照合し、Self Localではstored durable auditのstate/basis/epochも照合する。External evidenceは
704
+ このAPIから拒否し、後述のsettlement transactionだけが登録できる。primary Self Local audit pathと
705
+ Self Replicated pathは、source登録と同じtransactionで必要な1件/2件のactive assignment bondを`Mature`
706
+ releaseし、`mature_source_assignments`へrelease IDをlinkする。unbonded/不足/terminal lockならtransactionを
707
+ rollbackする。ticket issuerもjob classのrequired replica数とlink数を再検査する。
708
+ `issue_work_ticket` は `issued_epoch >= mature_epoch` を要求し、SQLite ticket pathも保存epochに対して
709
+ 同じ条件を検査してから1 sourceをatomicに消費する。既消費sourceの通常pathは`SourceAlreadyConsumed`、
710
+ External settlementのexact replayはstored ticketを返す。
711
+
712
+ canary expected projection commitment:
713
+
714
+ ```text
715
+ H("canary/v1", network_id, canary_id, request_commitment,
716
+ u64be(opening_epoch), canary_salt, encode(expected_match_projection))
717
+ ```
718
+
719
+ `CanaryPrecommitBodyV1`は `version, network_id, canary_id, scheduler_job_id, request_commitment,
720
+ signed_assignment_id, worker_credential_id, expected_commitment, created_epoch, receipt_deadline_epoch,
721
+ opening_epoch, opening_deadline_epoch` をcanonical encodeし、
722
+ `precommit_id = H("canary-precommit/v1", encode(body))`をschedulerがEd25519署名する。strict envelopeは
723
+ body、scheduler key ID、algorithm、signatureを持つ。scheduler registryのnetwork、key validity/revocation、
724
+ strict signatureと、exact signed request/assignment/worker bindingを検査した後だけ
725
+ `VerifiedCanaryPrecommit`になる。External Replicated canaryはv1で禁止する。
726
+
727
+ windowは `assignment.issued <= created <= receipt_deadline <= assignment.expires < opening_epoch <=
728
+ opening_deadline`。canary markerはReceiptにない。verified precommitはactive bonded assignmentとcanonical
729
+ signed envelopeをschema-v4 DBへ保存する。`accept_canary`はbonded normal Receipt acceptanceと
730
+ `ReceiptSubmitted`を同じtransactionでcommitする。valid opening passはterminalだけをcommitし、valid
731
+ commitmentのprojection mismatchはtyped `CanaryFailure` slashをatomicに適用する。receipt deadline経過は
732
+ worker faultでslashし、receipt受理後のopening deadline経過はscheduler faultとしてworkerをslashしない。
733
+ passとOpeningMissingではassignment bondをactiveのまま保持する。pending canaryがあるsourceのmaturityは
734
+ 拒否し、terminal後はmature epochをcanary completion epoch以上へ遅延する。Self Localでは遅延後のepochで
735
+ `local-maturity-basis/v2`も再計算する。その後のmaturity transactionがbondを`Mature` releaseしてsourceへ
736
+ linkするため、canary terminal単独ではWork Ticketを発行できない。
737
+
738
+ in-memory helperのslash offense:
739
+
740
+ ```text
741
+ Evidence = u64be(unique_sorted_count) || concat(sorted_unique_evidence_id)
742
+ offense_id = H(
743
+ "slash-offense/v1", network_id, worker_credential_id,
744
+ assignment_id, u8(reason), u32be(policy_version), Evidence
745
+ )
746
+ ```
747
+
748
+ reason tagは `1=InvalidManifest`, `2=AuditMismatch`, `3=Equivocation`,
749
+ `4=DuplicateExecution`, `5=CanaryFailure`, `6=AuditTimeout`。
750
+
751
+ durable slashはcaller-selected attachment集合ではなくcrate-private `TypedSlashEvidence`のprimary proofを
752
+ authority identityに使う。
753
+
754
+ ```text
755
+ offense_id = H(
756
+ "durable-slash-offense/v2", network_id, worker_credential_id,
757
+ assignment_id, u8(reason), primary_proof_id, u32be(policy_version)
758
+ )
759
+ ```
760
+
761
+ audit mismatch/timeoutとcanary mismatch/receipt timeoutはproof IDをstate transition自身から導出して、
762
+ slash claim、derived allocation、assignment remainder、pending appeal bucket、health eventを同じtransactionで
763
+ 更新する。claimはinitial assignment amountからreason別bpsをceilしたimmutable targetを持つ。v1の
764
+ Equivocation追加penaltyは0である。複数claimを単純���算せず、finalized(signed/default uphold)targetの
765
+ max-envelopeを先に割り当て、pending claimはそのenvelopeを超えるextensionだけを受ける。同じassignmentへの
766
+ late equal/weaker claimのallocationは既存envelopeに覆われるなら0、stronger claimはdeltaだけとなる。
767
+ reverse後も全claimから再計算するため、ingestion順序でslash総額は変わらない。standard policyのappeal
768
+ windowはdurable `applied_epoch`から100 epoch。nonappealed slashはinclusive deadlineの後だけfinalizeする。
769
+ typed proofが示す`fault_event_epoch`とstoreがclaimを受理する`applied_epoch`は別で、
770
+ `locked_epoch <= fault_event_epoch <= applied_epoch`とaccount transition epochの単調性を要求する。
771
+
772
+ partial claimのremainderはactive lockとして残る。pendingまたはuphold/default-final claimを持つassignmentは
773
+ maturity/Work Ticketの根拠にならない。全claim解決後、audit mismatch/
774
+ timeout terminalはclaimがreverseされても残額を`SlashResolved` releaseする。canary mismatch/receipt-timeout
775
+ terminalはmatching `CanaryFailure` claimがuphold/default-finalの場合だけ同releaseを許し、External refundも
776
+ release terminalになる。reversed canary claimだけではreleaseしない。未使用または
777
+ acceptedだがunpairedのSelf Replicated assignmentだけは、pending canary/slashがなくsigned expiryを過ぎた
778
+ 場合に`Expired` releaseできる。paired、Self Local、その他used assignmentはこのexpiry bypassを持たない。
779
+ pendingで全targetをallocateしたstate 2にもdistinct late claimを保存できるが、fully finalized/exhaustedの
780
+ state 3は新claimを拒否する。terminal epoch/proofは全immutable claimをoffense ID順に並べ、各effective epochの
781
+ maxと完全なterminal fact setから導出する。audit/canary terminalとExternal prepared/terminal stateは
782
+ 後出しclaimのcutoffであり、特にExternal `SettlementPrepared`または`RefundPrepared`以後は新しい
783
+ non-replay slashを受けない。
784
+
785
+ bond funding、slash appeal、slash decisionはそれぞれversion 1 canonical bodyとsigned envelopeを持つ。
786
+ funding bodyはnetwork/worker/funding event/asset/exact amount/finalized epoch、appeal bodyはnetwork/worker/
787
+ offense/assignment/appeal ID/submitted epoch、decision bodyはnetwork/appeal/offense/outcome/decided epochを
788
+ bindする。network-scoped bond authority registryはkey validity/revocation、funding/appeal/decision capability、
789
+ weak key、strict Ed25519を検査し、raw constructorを持たないverified typestateだけをstoreへ渡す。
790
+
791
+ appeal submissionはstored pending slashとinclusive appeal deadlineを照合する。signed `submitted_epoch`と
792
+ registry verification epochの両方が`applied_epoch..=appeal_deadline`内でなければならず、後者をdurable
793
+ `accepted_epoch`として保存する。decision deadlineは`accepted_epoch + 100`である。authority-signed
794
+ `Uphold`/`Reverse`はsigned `decided_epoch`とdecision verification/acceptance epochの両方がdeadline以下で
795
+ だけ受理し、claim statusを更新してassignment全claimのallocationをatomicに再計算する。期限を過ぎても
796
+ decisionがなければ`finalize_stale_slash_appeal(current_epoch > decision_deadline)`がdomain-separated
797
+ default decisionを作ってdeterministically upholdする。offenseごとのappealは1件だけで、first stored
798
+ signed/default decisionが勝つ。stored canonical appeal/decisionのexact replayは期限後もidempotent、distinct
799
+ second appealやconflicting later decisionはfatalである。
800
+
801
+ `ExternalEscrowTermsV1` canonical order は `version:u16, network_id, escrow_nonce,
802
+ funding_authorization_id, prompt_commitment, ExecutionConstraintsV1, required_reward:u64,
803
+ demand_bonus_amount:u64, demand_bonus_bps:u32, protocol_fee:u64, failure_reserve:u64,
804
+ issued_epoch:u64, expires_epoch:u64`。
805
+
806
+ ```text
807
+ escrow_reference = H("external-escrow/v1", encode(terms))
808
+ ```
809
+
810
+ external authorityはnetwork-scoped Ed25519 keyにfunding、demand-weight、terminal capabilityを分離する。
811
+ key validity/revocation、weak key、strict signatureを検査し、次のraw constructorを持たないtypestateを作る。
812
+
813
+ - `VerifiedFundingAttestation`: escrow reference、funding authorization ID、asset、exact finalized amount/epoch
814
+ - `VerifiedDemandWeightGrant`: escrow/funding attestation、grant/policy/asset、funded bonus amount/bps、
815
+ issued/expiry interval(v1 bonus上限5,000 bps)
816
+ - `VerifiedTerminalConfirmation`: escrow、payment command、rail confirmation、asset、exact settlement/refund
817
+ distribution、confirmed epoch
818
+
819
+ schema-v4 durable external pathはexact funding+grantから`Funded` escrowを作り、scheduler-signed
820
+ External request、typed k=2 pair、stable payment commandへ進む。settlement confirmationはcommand/distribution/
821
+ pair/asset/epochを照合し、terminal state、maturity source、両worker assignment bondのrelease/link、
822
+ `WorkTicketV2` insert、source consumptionを一SQLite transactionでcommitする。refund commandはstate 1..3
823
+ (`Funded|Assigned|EvidenceReady`)からterms expiry後に作成でき、pairの有無を問わない。refund confirmationは
824
+ terminalとeligible assignment bond releaseを一SQLite transactionでcommitし、maturity/ticketを作らない。
825
+ pending slash claimを持つbondは解決までreleaseせず、解決後に残額だけをreleaseできる。exact confirmation replayは
826
+ idempotentで、逆terminal、amount、identityのconflictを拒否する。
827
+
828
+ settlement commandを`SettlementPrepared`へcommitする同じ`BEGIN IMMEDIATE` transactionで、pair両assignmentが
829
+ active state 0かつpending/upheld/default-final slash claimなしであることをpreflightする。
830
+ `SettlementPrepared`と`RefundPrepared`(state 4/5)はどちらもnon-replayのlate slashを拒否するため、
831
+ terminal準備とslashの順序で結果が変わらない。
832
+
833
+ これはexternal authorityが「rail上のfinality」を正しく署名するというtrust boundaryである。crateは
834
+ payment railを操作せず、rail transactionとSQLite commitのdistributed atomicityを主張しない。
835
+
836
+ ## 15. Encrypted verification bundle and restart restoration
837
+
838
+ `VerificationBundleV1`はcanonical Receiptのprivate openingをrestart後もstrict verifyするためのartifactで、
839
+ Receipt wire format自体は変更しない。audit keyはcaller-owned raw 32 bytes、nonzeroで、bundleには含めない。
840
+
841
+ public sectionのcanonical order:
842
+
843
+ 1. `version:u16 (=1)`
844
+ 2. `receipt_binding:Hash32`
845
+ 3. `receipt_id:Hash32`
846
+ 4. `verification_epoch:u64`
847
+ 5. scheduler key snapshot: `network_id, verifying_key, valid_from_epoch, valid_through_epoch,
848
+ revoked_at_epoch:Option<u64>`
849
+ 6. `LP(RuntimeManifest canonical bytes)`
850
+ 7. `LP(portable ExecutionEvidence canonical bytes)`(schedule/CU/trace witness)
851
+
852
+ worker public keyはpublic sectionへ置かない。private sectionのcanonical order:
853
+
854
+ 1. `LP("MISAKA/PALW/PRIVATE-OPENING")`, `version:u16 (=1)`, `public_digest:Hash32`
855
+ 2. `LP(SignedJobRequestV1)`, `LP(SignedAssignmentV1)`
856
+ 3. worker `verifying_key`, `owner_commitment`, `worker_credential_id`
857
+ 4. `output_nonce`, `u64be(prompt_token_count)`, `u32be(prompt_token_id_i)*`
858
+ 5. `LP(CanonicalOutput)`(generated token IDsとstop reason)
859
+ 6. `owner_salt`
860
+
861
+ private signing-key seedはどのsectionにもserializeしない。
862
+
863
+ ```text
864
+ receipt_binding = H("verification-bundle-receipt/v1", canonical_signed_receipt)
865
+ public_digest = H("verification-bundle-public/v1", canonical_public_section)
866
+ aead_key = H("verification-bundle-aead-key/v1", raw_audit_key)
867
+ aad = H(
868
+ "verification-bundle-aad/v1",
869
+ "XCHACHA20-POLY1305;KEY=256;NONCE=192;TAG=128",
870
+ receipt_binding, public_digest, nonce, canonical_public_section
871
+ )
872
+ ```
873
+
874
+ envelope canonical order:
875
+
876
+ ```text
877
+ LP("MISAKA/PALW/VERIFICATION-BUNDLE") ||
878
+ u16be(version=1) || u16be(cipher=1) ||
879
+ receipt_binding || public_digest || nonce:24-byte ||
880
+ LP(canonical_public_section) || LP(XChaCha20-Poly1305 ciphertext_and_tag)
881
+ ```
882
+
883
+ nonceはOS CSPRNGのnonzero 192-bit値、AEAD keyは256 bit、tagは128 bit。envelopeは64 MiB、public
884
+ sectionは48 MiB、private plaintextは16 MiBを上限とし、strict decode/re-encode、receipt/public binding、
885
+ AEAD authenticationを検査する。
886
+
887
+ ```text
888
+ bundle_id = H("verification-bundle-id/v1", canonical_complete_envelope)
889
+ ```
890
+
891
+ local restart pathはembedded scheduler/worker snapshotsを使ってcomplete stateless verificationを再実行し、
892
+ 既存schema-v4 DB rowのcanonical Receipt/runtime instance/original acceptance epochへexact restoreする。
893
+ missing DB rowを新規acceptしない。これはlocal continuity modeであり、embedded snapshotはthird-party
894
+ network authorityではない。
895
+
896
+ bundle public sectionのhistorical `verification_epoch`はoriginal acceptance時点をbindする。
897
+ `verify_bundle_and_restore_at_epoch`はcaller-selected current epochがhistorical値以上であることを要求し、
898
+ 同じbundle/openingをfresh epochで再検証したうえでoriginal durable acceptance epochを保持してrestoreする。
899
+ ただし、このlocal APIはembedded snapshotsを使うためbundle作成後のrevocationを学習できない。future audit
900
+ restoreではcurrent epochをbeacon以上にする。rollbackは拒否する。現行
901
+ `palw-verify-bundle` CLIはhistorical default pathで、fresh epoch overrideはlibrary APIだけが公開する。
902
+
903
+ external stateless pathはexpected network、independent scheduler registry、independent signer registry、
904
+ approved manifest hashを必須にし、embedded snapshotとのexact equalityも検査する。default APIはhistorical
905
+ epoch、`verify_bundle_stateless_at_epoch_with_trust`はrollbackしないcaller-selected fresh epochで検証する。
906
+ DB reservationを行わず、network acceptanceを主張しない。production restartではcurrent external trust rootsと
907
+ 既存DB continuityを同時に検査する`verify_bundle_and_restore_at_epoch_with_trust`を使う。
908
+
909
+ Receipt CLIは`--prompt-stdin --audit-key-file RAW_32_BYTE_KEY`を必須とし、`--prompt TEXT`を受けない。
910
+ key fileはoutput directory外のowner-owned single-link regular file、mode `0400`/`0600`、exact 32 bytesで
911
+ なければならない。issuance output directoryは`0700`、Receipt/公開JSON/completion markerは`0644`、
912
+ bundle/DBは`0600`。DB WALを`TRUNCATE` checkpointしてmain DBを`fsync`し、各artifactを`fsync`した後、
913
+ `misaka.palw.receipt-set.v2` markerへ`receipt_id`、`bundle_id`、公開JSON bytesのSHA-256を記録して最後に
914
+ 書き、directoryを`fsync`する。local verifier CLIは`--public-json`も必須とし、protected artifactsが同じ
915
+ owned `0700` directoryにexpected filename/modeで存在すること、marker、typed公開JSON
916
+ `misaka.palw.public-receipt.v2`全体を検査する。
917
+ 保持する`artifacts`と`observer_summary`はauthenticated bundle manifest/evidenceから再構成してexact照合し、
918
+ extra JSON fieldはobjectの全階層で拒否する。
919
+ marker-lastはpartial setをcompleteとして受理しないためのgateであり、cross-file atomic transactionでも
920
+ authenticity proofでもない。markerはunkeyed plain textなのでsame-owner writerはJSONとmarkerを一緒に
921
+ 置換できるが、改変JSONはReceipt/bundleとの照合に失敗する。canonical Receipt/authenticated bundleだけが
922
+ protocol authorityである。
923
+
924
+ ## 16. Security and issuance boundary
925
+
926
+ trace root は approved observer が報告したeventへのcommitmentであり、単独のproof of executionでは
927
+ ない。intended production safety modelはpinned build、signed assignment、independent replica、future
928
+ audit、bond/slashing、durable uniquenessを組み合わせるが、個別primitive/state machineの存在はそれらが
929
+ operationally統合済みであることを意味しない。
930
+
931
+ schema-v4 coreはscheduler-signed canary precommit、authority-signed bond funding/appeal/decision、durable
932
+ assignment lock/release/slash/health、authority-signed external funding/grant/terminalを実装する。bonded receipt
933
+ acceptance、audit/canaryのtyped slash、maturity時bond release/link、WorkTicketV2 gate、External terminalから
934
+ maturity/ticketまでのlocal atomic transactionも実装済みである。
935
+
936
+ ただしproduction scheduler/network transport、governance-backed scheduler/worker/beacon/bond/external key
937
+ distribution、finalized beacon delivery、independent auditor execution/opening delivery、実payment railと
938
+ authority serviceはこのrepositoryにない。署名済みfunding/terminalは外部factのauthenticated statementで
939
+ あり、crate単体が実collateralやrail movementを独立証明するものではない。railとSQLiteはdistributed
940
+ atomic transactionではない。durable slashへ自動接続済みのproofはaudit mismatch/timeoutとcanary
941
+ mismatch/receipt timeoutで、invalid-manifest、equivocation、duplicate-executionのproduction proof
942
+ constructor/orchestrationは未統合である。legacy in-memory `BondLedger`/`CanaryRecord`/`ExternalEscrow` helperの
943
+ raw mutation APIをproduction authority pathとして使ってはならない。
944
+
945
+ 現時点で実モデルReceiptを発行できるのはApple Metal `GraphFallback` runtime classである。CUDAは
946
+ RTX 4060 Ti sm_89 / CUDA Toolkit 13.3.1 / nvcc 13.3.73で固定Qwen 37/37 layer offload、graph observer
947
+ 6/6、standalone true-accumulator primitiveの最終grouped device suite 8/8とproducer 20/20同一fingerprintに
948
+ 加え、vendored MMVQ/FA-off attention same-backend 1-token diagnostic E2Eで361/361 recordと3回同一
949
+ fingerprintを実測済みである。exact entry/cubin/DSO release manifest、Receipt/RuntimeManifest/Request/
950
+ Assignment V2、暗号化Bundle V2、SQLite V2も実装・検証済みである。これはproduction `KernelSketch`
951
+ acceptanceではなく、authority-derived canonical IDを使うlive callbackとauthority governanceは未完了である。
952
+ V1 builder/verifierとproduction macro/CMake gateはfail closedを維持するため、
953
+ これらが完了するまでproduction CUDA Receipt/Work Ticketを発行しない。TEE attestationやZK/VCは
954
+ 実装範囲外である。
docs/receipt-implementation-qwen36.md ADDED
@@ -0,0 +1,656 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # MISAKA PALW Receipt 実装仕様 — Qwen3.6-35B-A3B (hybrid MoE)
2
+
3
+ 本書は、対象モデルを dense Qwen3-8B から hybrid **Qwen3.6-35B-A3B**
4
+ (`huihui_ai/Qwen3.6-abliterated:35b-Claude-4.7`、abliterated) へ移行した後の
5
+ `ComputeReceiptV1` 発行・検証パイプラインの実装仕様である。記述は現行 Rust/C++
6
+ ソースを正本とし、実装と本書が一致しない場合は Receipt を発行しない
7
+ ([`protocol-v1.md`](protocol-v1.md) と同じ原則)。本書に無い production 承認・決済連携・
8
+ attestation を Receipt から推論してはならない。
9
+
10
+ 対象モデルは linear-attention(state-space / gated-delta-net)層と mixture-of-experts
11
+ 層を組み合わせた hybrid 構成であり、dense Qwen3-8B 用の厳格な canonical operation
12
+ mapping では表現できない演算を含む。そのため本移行では **(1)** pinned llama.cpp への
13
+ qwen35moe loader/graph 互換修正、**(2)** dense vocabulary に対応の無い演算を output-element
14
+ 数で committ する generic operation と CU ルールセット v2、**(3)** profile 駆動の hybrid
15
+ adapter/manifest、を追加した。移行完了後、dense Qwen3-8B 経路(profile / manifest builder /
16
+ constants / tests)は撤去され、Qwen3.6-35B-A3B が唯一の対象モデルとなった。
17
+
18
+ 行番号 anchor は執筆時点のものであり、正本はソースである。
19
+
20
+ > **compute-gate track 更新(2026-07-19、実機検証済み)。** 上記 (2) の「generic operation + CU
21
+ > ルールセット v2」は**後続の compute-gate track で置換された**。現行 receipt は **(M1)** CU を
22
+ > semantic ルールセット v3 で canonical commit(`canonical_compute_units = 41692`)、**(M3)** generic
23
+ > 演算を廃止し全 MoE/SSM op を忠実な canonical 演算(`ExpertGemm`/`ExpertRoute`/`SsmConv`/
24
+ > `GatedDeltaNet`/`L2Norm`/`Reduction`/`Elementwise`)へ写像、**(M2)** canonical semantic schedule を
25
+ > 再生成・commit、**(M4/#6)** observer が実 MoE routing(`ffn_moe_topk`)を捕捉し `expert_route_root`
26
+ > を封緘 bundle へ commit(observer schema v2)、**(M5/#5)** ggml-metal を計装して各 GEMM を実 Metal
27
+ > kernel dispatch + launch geometry へ束縛し `trace_evidence=metal_kernel` を commit(graph-fallback
28
+ > から昇格、実機で 200/200・411/411 検証)。§0–§2 の一部記述(CU v2 / generic / SCHEMA_VERSION 1 /
29
+ > MUL_MAT_ID=metadata / graph_fallback)は旧版で、現行の正確な値は §10・§11 と
30
+ > [`receipt-review-remediation.md`](receipt-review-remediation.md) を参照。**6 つの compute gate は
31
+ > 全て実機検証済み。** Metal の kernel-level trace は launch-geometry 束縛であり CUDA V3 相当の
32
+ > intra-kernel accumulator proof ではない(honest labeling、mint は依然不適格)。
33
+
34
+ ---
35
+
36
+ ## 0. 全体アーキテクチャとデータフロー
37
+
38
+ 三層構成:
39
+
40
+ 1. `vendor/llama.cpp/`(commit 固定 + PALW patch): 推論ランタイムと read-only graph observer
41
+ `llama-palw-observer`。
42
+ 2. `runtime-palw/`(Rust): adapter、canonical CU、schedule、commitment、manifest、receipt
43
+ builder/verifier、verification bundle、schema-v4 SQLite。
44
+ 3. `config/` / `patches/`: 固定 artifact pin、model profile pin、llama.cpp patch。
45
+
46
+ Receipt 発行(`palw-metal-receipt`)のデータフロー:
47
+
48
+ ```
49
+ prompt(stdin)
50
+
51
+ ├─ build_qwen36_35b_metal_manifest ─────────► RuntimeManifest(MoE topology, CU v3 semantic)
52
+
53
+ ├─ llama-tokenize ──────────────────────────► prompt_token_ids
54
+
55
+ ├─ llama-palw-observer --observer sketch ───► JSONL(header/event*/result)
56
+ │ │(read-only graph callback、sketch)
57
+ │ ▼
58
+ │ qwen_adapter(HybridQwen36A3B)
59
+ │ │ header 検証 + op→ComputeOperation 写像 + GEMM sketch
60
+ │ ▼
61
+ │ RuntimeObserver → ExecutionEvidence(schedule + GEMM trace + CU total, ruleset=v3 semantic)
62
+
63
+ ├─ build_signed_receipt ────────────────────► ComputeReceiptV1(署名)
64
+ ├─ verify_stateless(cu_rules=v3) ───────────► 自己検証
65
+ ├─ seal_verification_bundle(XChaCha20) ─────► <id>.palw.bundle
66
+ ├─ StateStore(schema v4).accept ────────────► palw-state.sqlite3
67
+ └─ 書き出し: <id>.palw / <id>.json / <id>.palw.bundle / <id>.complete
68
+ ```
69
+
70
+ 別 process 検証(`palw-verify-bundle`)は artifact set・完了 marker を検査し、bundle を復号・
71
+ 再検証(`verify_bundle_and_restore`)して `status=local_restored` /
72
+ `trust_scope=embedded_local_snapshot` を出力する。
73
+
74
+ ---
75
+
76
+ ## 1. 対象モデルと固定 artifact
77
+
78
+ 正本: [`config/runtime-pins.sh`](../config/runtime-pins.sh)(公開識別子のみ、末尾で全て `readonly`)。
79
+
80
+ ### 1.1 推論 GGUF(Ollama registry blob)
81
+
82
+ | 変数 | 値 |
83
+ |---|---|
84
+ | `PALW_GGUF_REGISTRY` | `registry.ollama.ai` |
85
+ | `PALW_GGUF_REPO_ID` | `huihui_ai/Qwen3.6-abliterated` |
86
+ | `PALW_GGUF_OLLAMA_TAG` | `35b-Claude-4.7` |
87
+ | `PALW_GGUF_REVISION` = `PALW_GGUF_SHA256` | `1dc494614bee8a3bc00e79fe5a49da0fc1c36b3b118c4156e223e98e5a0a671b` |
88
+ | `PALW_GGUF_FILENAME` | `Qwen3.6-abliterated-35b-Claude-4.7-Q4_K_M.gguf` |
89
+ | `PALW_GGUF_SIZE` | `23938321728`(bytes) |
90
+
91
+ Ollama registry の blob digest は GGUF 本体の SHA-256 に等しいため `revision == sha256`。
92
+ content 検証だけで pin 全体の照合になる。
93
+
94
+ ### 1.2 base metadata(Hugging Face、7 files)
95
+
96
+ `PALW_BASE_REPO_ID = huihui-ai/Huihui-Qwen3.6-35B-A3B-Claude-4.7-Opus-abliterated`、
97
+ `PALW_BASE_REVISION = ac18882735d037f6074a7630eb68d85db8234c25`。
98
+ files: `README.md`、`chat_template.jinja`、`config.json`、`model.safetensors.index.json`、
99
+ `processor_config.json`、`tokenizer.json`、`tokenizer_config.json`。
100
+ sha256 は [`config/qwen3.6-35b-a3b-claude-4.7-base-metadata.sha256`](../config/qwen3.6-35b-a3b-claude-4.7-base-metadata.sha256)
101
+ および profile pin の `base_artifact.files[]` と一致する。
102
+
103
+ ### 1.3 llama.cpp
104
+
105
+ `PALW_LLAMA_COMMIT = 12127defda4f41b7679cb2477a4b0d65ee6a0c8f`(build 10015)、
106
+ patch = [`patches/llama.cpp-palw-observer.patch`](../patches/llama.cpp-palw-observer.patch)、
107
+ `PALW_LLAMA_PATCH_SHA256 = d155a88b7c11ee74f48011760cb1a37773a694c8cab28258ee108c85e2f9e02c`。
108
+ Metal build は `-DGGML_METAL=ON -DGGML_CUDA=OFF`、`arm64`、target
109
+ `llama-cli/llama-server/llama-tokenize/llama-palw-observer`。
110
+
111
+ ### 1.4 Ollama download 経路(`install.sh :: download_gguf_if_needed`)
112
+
113
+ 1. `gguf_content_matches`(存在 + size + sha256)が成立すれば再利用。
114
+ 2. mismatch する既存 file は上書きせず die。
115
+ 3. URL = `https://$PALW_GGUF_REGISTRY/v2/$PALW_GGUF_REPO_ID/blobs/sha256:$PALW_GGUF_REVISION`
116
+ (OCI/Docker registry の blob-by-digest endpoint)。
117
+ 4. `curl -fSL -C -`(再開可能)で `.partial` に取得。
118
+ 5. size と sha256 を照合してから `mv` で atomic に確定。
119
+ 6. base metadata は従来通り HF(`hf_snapshot_download.py`、token を strip し Xet を無効化)。
120
+
121
+ ---
122
+
123
+ ## 2. 決定論的実行と native observer
124
+
125
+ 正本: `vendor/llama.cpp/tools/palw-observer/palw-observer.cpp`(以下 OBS)。単一リクエストの
126
+ 非対話 runner で、public な `llama`/`ggml` API のみ使用。versioned JSONL を stdout に、
127
+ llama/ggml のログを stderr に書く。
128
+
129
+ ### 2.1 強制される決定論的実行ポリシー
130
+
131
+ `n_ctx = PALW_CONTEXT_TOKENS = 4096`、`n_batch = n_ubatch = 1`、`n_seq_max = 1`、
132
+ `n_threads = n_threads_batch = 1`、greedy sampler、`flash_attn = DISABLED`、
133
+ `type_k = type_v = F16`、`split_mode = NONE`、`use_mmap = true`。context 初期化後に
134
+ 実 context を読み直し、この不変条件を満たさなければ exit 3。prompt は `--prompt-stdin`
135
+ 専用 pipe で渡し(argv に置かない)、prefill/decode とも 1 token ずつ `llama_batch_get_one`
136
+ で評価する。`prompt_tokens + n_predict > 4096` は context-shift せず失敗。
137
+
138
+ ### 2.2 model profile gate(`validate_qwen36_35b_a3b_profile`)
139
+
140
+ model load 直後に、`general.architecture == "qwen35moe"`、`n_layer == 40`、`n_embd == 2048`、
141
+ `n_vocab == 248320`、decoder-only(encoder 無し)のみ受理。不一致は header/result を一切
142
+ emit せず exit 3。
143
+
144
+ ### 2.3 JSONL プロトコル
145
+
146
+ `SCHEMA_NAME = "misaka.palw.runtime_observer"`、`SCHEMA_VERSION = 2`(route record 追加)。1 実行は
147
+ **header 1** → **event 0..N** → **result 1**。各行は個別に flush。
148
+
149
+ - **header**: `observer`(off/graph/sketch)、`trace_variant`、`cuda_kernel_trace:false`、
150
+ `model{path,description,tensor_size_bytes,parameter_count,file_type,n_ctx_train,n_embd,
151
+ n_layer,n_head,n_head_kv,n_vocab,rope_type,rope_freq_scale_train,metadata[]}`、
152
+ `runtime{ggml_version,ggml_commit,system_info,supports_gpu_offload,requested_gpu_layers,
153
+ devices[]}`、`execution_policy{...上記決定論ポリシー...}`、
154
+ `observation_policy{read_only:true, graph_metadata_stage:"ask", sketch_bits:256,
155
+ sketch_probe:"gemm_output_contiguous_prefix_64", raw_activation_values_published:false,
156
+ tile_variant:"graph_fallback_logical_prefix_v1", kernel_trace_claim:"none"}`。
157
+ - **event**: `event_seq`(単調増加、最終値 = result の `event_count`)、`phase`
158
+ (prefill/decode)、`phase_step`、`stage`(ask_metadata / post_compute_sketch)、`layer`
159
+ (名前から導出、無ければ null)、`categories[]`、`tensor{name,op,type,shape[4],n_bytes}`、
160
+ `sources[]`。MUL_MAT には `gemm{variant:"ggml_graph_op_v1",m,n,k,batch_shape}`。sketch
161
+ 時のみ `sketch{}`/`tile{}`/`kernel_trace{}`。
162
+ - **result**: `status`、`stop_reason`(n_predict/eog/…)、`prompt_token_ids[]`、
163
+ `generated_token_ids[]`、`output_bytes[]`(`--emit-output-bytes` 時のみ非空)、
164
+ `output_n_bytes`、`event_count`。
165
+
166
+ ### 2.4 observer モードと sketch scheme
167
+
168
+ - `off`: callback 無し、event 0。
169
+ - `graph`: 各非空 valid node に対し `ask_metadata` を 1 件 emit。tensor data は一切読まない。
170
+ - `sketch`: 非 MUL_MAT node は `ask_metadata`。`MUL_MAT` node のみ post-compute で
171
+ `ggml_backend_tensor_get` により先頭最大 64 要素を読み、**sign/bucket sketch** を採取して
172
+ `post_compute_sketch` を emit。
173
+
174
+ sketch(`sign_bucket_256_v1`): 各要素を 1 nibble(bit3 = 符号、bit0..2 = 3-bit 絶対値
175
+ bucket)にし、64 nibble = **256 bit**。bucket 境界は `0, 2⁻⁸, 2⁻⁴, 2⁻², 1, 4, 16, ∞`。生の
176
+ 活性値は決して serialize しない。`kernel_trace{available:false, backend:"none",
177
+ claim:"not_a_cuda_kernel_trace"}` を常に付し、graph 観測を CUDA kernel 証拠へ昇格しない。
178
+
179
+ ### 2.5 observer 側の hybrid 対応(3 点)
180
+
181
+ 1. **`is_gemm` を `GGML_OP_MUL_MAT` のみに限定**。`GGML_OP_MUL_MAT_ID`(indirect expert
182
+ GEMM)は sketch せず通常の metadata node として emit する。
183
+ 2. **0-element(recurrent state cache)tensor を skip**。gated-delta-net / SSM 層は初期状態が
184
+ 空の state cache を gather し、合法な 0-element node を生む。これは compute を伴わないため
185
+ error にせず skip。
186
+ 3. **`validate_tensor` が空 tensor を許容**(name/type/op の範囲検査後に短絡)。
187
+
188
+ ### 2.6 qwen35moe.cpp loader/graph 修正(5 点)
189
+
190
+ pinned commit `12127def` の `src/models/qwen35moe.cpp` は本モデルを load/run できないため、
191
+ PALW comment 付きで以下を修正(observer patch に同梱):
192
+
193
+ 1. **3-section mrope zero-pad**: `rope.dimension_sections` を可変配列として読み、size 3 or 4 を
194
+ 許容して zero-fill+copy。新しい HF→GGUF 変換の `[t,h,w]`(末尾 0 省略)を受理。
195
+ 2. **`ssm_dt` bias の suffix 両対応**: `blk.N.ssm_dt.bias` を `TENSOR_NOT_REQUIRED` で試し、
196
+ 無ければ suffix 無し `blk.N.ssm_dt` を required で load。
197
+ 3. **KV 射影幅に `n_embd_k_gqa_max()`**: `LLAMA_LOAD_LOCALS` は layer 0 から `n_embd_k/v_gqa`
198
+ を導出するが、layer 0 は linear-attention 層で `n_head_kv==0`。full-attention trunk 層と
199
+ MTP 層の tensor 生成で per-layer 最大値を使う。
200
+ 4. **sibling tensor(`v.*` / `mtp.*`)の計上**: Ollama 同梱 GGUF は vision tower と(MTP 未
201
+ 有効時)MTP sub-model を同梱する。text runtime はこれらを構築しないため、該当 prefix の
202
+ tensor 分だけ `n_created`/`size_data` を調整し `done_getting_tensors` を通す。存在する
203
+ tensor のみ 1 回ずつ計上するため、text tensor の欠落は依然として検出される。
204
+ 5. **`build_layer_attn` の per-layer `n_head(il)`/`n_head_kv(il)`**: graph base は layer 0 から
205
+ head 数を初期化するため、full-attention の Q/K/V reshape と RoPE を per-layer 値で shadow。
206
+
207
+ ---
208
+
209
+ ## 3. Rust adapter — hybrid 経路
210
+
211
+ 正本: `runtime-palw/src/qwen_adapter.rs`。`AdapterProfile { HybridQwen36A3B }`(唯一の profile)
212
+ を `NativeParseConfig`/`NativeRunConfig` の `profile` field で選択し、
213
+ `parse_native_jsonl_with_stderr` が header 検証 / event 変換 / vocab 上限を hybrid 経路で処理する。
214
+ 旧 dense 経路は撤去済み。
215
+
216
+ ### 3.1 hybrid 定数と識別子
217
+
218
+ `QWEN36_35B_LAYERS=40`、`QWEN36_35B_VOCAB=248320`、`QWEN36_35B_EMBED=2048`、
219
+ `QWEN36_35B_CONTEXT=262144`、`QWEN36_35B_PARAMETERS=35_951_822_704`、
220
+ `QWEN36_ARCHITECTURE="qwen35moe"`、共有の `Q4_K_M_FILE_TYPE=15`、`QWEN_RUNTIME_CONTEXT=4096`。
221
+
222
+ `qwen36_adapter_mapping_id_v1()` は domain `"qwen36-native-observer-mapping/v1"` の
223
+ `domain_hash`。payload は各 op の写像を列挙し `cu-ruleset=v2;graph-fallback-only` を含む。dense
224
+ の `"qwen-native-observer-mapping/v1"`(`soft_max=attention`)とは別 hash。
225
+
226
+ ### 3.2 header 検証(`validate_header_hybrid`)
227
+
228
+ deterministic execution policy と observation policy は **dense と同一**の厳格さで検証する。
229
+ model-shape だけを MoE 向けに一般化する:
230
+
231
+ - `parameter_count == 35_951_822_704`、`file_type == 15`、`n_ctx_train == 262144`、
232
+ `n_embd == 2048`、`n_layer == 40`、`n_vocab == 248320`、`rope_freq_scale_train == 1.0`。
233
+ - **dense と違い `n_head`/`n_head_kv`/`rope_type` は pin しない**(MoE は per-layer で可変、
234
+ layer-0 KV-head を制約しない)。
235
+ - 必須 metadata: `general.architecture=qwen35moe`、`general.file_type=15`、
236
+ `general.quantization_version=2`、`qwen35moe.context_length=262144`、
237
+ `qwen35moe.embedding_length=2048`、`qwen35moe.block_count=40`、
238
+ `qwen35moe.expert_count=256`、`qwen35moe.expert_used_count=8`。dense と逆に **expert
239
+ metadata を要求**する(dense は expert metadata を拒否)。
240
+ - graph/sketch 時は `supports_gpu_offload && requested_gpu_layers==999 && GPU device 存在`。
241
+
242
+ ### 3.3 op → canonical operation 写像(`convert_event_hybrid`)
243
+
244
+ 各 ggml op を canonical `ComputeOperation` へ写像する。dense と異なり、正確な canonical
245
+ 対応がある演算はそれへ、対応の無い演算は `Generic{op_class, elements}` へ写す。fail-closed。
246
+
247
+ | ggml op | canonical operation |
248
+ |---|---|
249
+ | `MUL_MAT` | `Gemm`(`convert_gemm_hybrid`、sketch 採取) |
250
+ | `RMS_NORM` | `RmsNorm { elements=shape[0], batch=Πshape[1..] }` |
251
+ | `ROPE` | `Rotary { head_dim=shape[0], heads=shape[1], tokens=Πshape[2..] }` |
252
+ | `SOFT_MAX` | `Softmax { elements=Πshape }`(dense は Attention 再構成) |
253
+ | `GLU` | `Silu{elements}` + `ElementwiseMultiply{elements}` |
254
+ | `MUL` | `ElementwiseMultiply { elements }` |
255
+ | `ADD` | `ElementwiseAdd { elements }` |
256
+ | `GET_ROWS` | `EmbeddingLookup { elements }` |
257
+ | `SET_ROWS` | `KvCacheWrite { bytes = tensor.n_bytes }` |
258
+ | `CONT` \| `CPY` | `TensorCopy { bytes = tensor.n_bytes }` |
259
+ | `VIEW` \| `RESHAPE` \| `PERMUTE` \| `TRANSPOSE` | layout-only(schedule に載せない) |
260
+ | その他 | `Generic { op_class=hybrid_generic_op_class(op), elements=Πshape }`。未列挙は拒否 |
261
+
262
+ `hybrid_generic_op_class`(不変な op→u32 表): `MUL_MAT_ID=1`、`UNARY=2`、`SCALE=3`、
263
+ `L2_NORM=4`、`SUM_ROWS=5`、`DIV=6`、`CLAMP=7`、`ARGSORT=8`、`SSM_CONV=9`、
264
+ `GATED_DELTA_NET=10`、`CONCAT=11`。これ以外は `None` → `InvalidEvent`(fail-closed)。
265
+
266
+ ### 3.4 GEMM 変換(`convert_gemm_hybrid`)
267
+
268
+ `gemm{}` metadata の相互整合(`m==left.shape[1]`、`n==right.shape[1]`、`k==left.shape[0]`、
269
+ `left.shape[0]==right.shape[0]`、output shape 一致)を検証する。dense と異なり **固定 geometry
270
+ や dtype allowlist は課さない**。quantization は `left.kind` から `q4_K→Q4KM`、`q6_K→Q6K`、
271
+ その他→`None`。sketch 時は `validate_graph_fallback_sketch`(sketch/tile/kernel_trace の値を
272
+ 厳格検証)後、64 hex を 4 lane の big-endian `i64` へ復元し `on_gemm_group` で trace に記録。
273
+ kernel_id domain は `"qwen36-graph-fallback-probe/v1"`。
274
+
275
+ ### 3.5 GPU offload marker とプライバシ
276
+
277
+ `scan_stderr_markers` は `"offloaded N/N layers to gpu"` を **N が正で左右一致なら任意の N** で
278
+ 検出する(dense 37/37、hybrid 41/41 を model 非依存で受理)。不一致は
279
+ `IncompleteGpuOffload`。prompt は `OsStr` の stdin のみ、error payload は `&'static str`/数値
280
+ のみ、`QwenObserverOutput` は `Debug` 未実装、`zeroize_private_material` が prompt/生成
281
+ token/QA bytes を zeroize。
282
+
283
+ ---
284
+
285
+ ## 4. 正準演算語彙と CU ルールセット
286
+
287
+ 正本: `runtime-palw/src/compute_units.rs`。
288
+
289
+ ### 4.1 `ComputeOperation`(canonical serialize discriminant)
290
+
291
+ `0 Gemm(GemmShape)`、`1 Attention`、`2 LayerNorm`、`3 RmsNorm`、`4 Rotary`、`5 ExpertRoute`、
292
+ `6 KvCacheRead`、`7 KvCacheWrite`、`8 Silu`、`9 ElementwiseMultiply`、`10 Softmax`、
293
+ `11 ElementwiseAdd`、`12 TensorCopy`、`13 EmbeddingLookup`、**`14 Generic{op_class:u32,
294
+ elements:u64}`**(本移行で追加)。0..5 は `u32` 次元、6..13 は単一 `u64`。追加は additive で
295
+ 既存 variant の byte は不変。
296
+
297
+ `Generic` は「dense に cost 規則の無い演算(gated-delta-net、SSM conv、MoE routing 等)を
298
+ 意味を歪めず、output 要素数で忠実に committ する」ための variant。`op_class` は演算種別の
299
+ 安定 ID、cost は output 要素数のみに依存する。**v2 のみが pricing し、v1 は拒否する**ため
300
+ 既存 dense receipt と ruleset identity は不変。
301
+
302
+ ### 4.2 CU ルールセット v1/v2
303
+
304
+ `CU_RULESET_VERSION_V1=1`、`CU_RULESET_VERSION_V2=2`。`ruleset_id()` は
305
+ `domain_hash("cu-ruleset/vX", X, [payload])`。payload の唯一の差分は v2 が `ceil;min1` の前に
306
+ **`generic=2/4096;`** を挿入する点(domain も `/v2`)。よって
307
+ `v1().ruleset_id() != v2().ruleset_id()`。`matching_ruleset_id(&Hash32)` は `[v1(),v2()]` から
308
+ 一致する ruleset を返す(本移行で追加、bundle 経路が使用)。
309
+
310
+ cost 式(`cost()`、`scaled_cost = max(1, ceil(work·units/reference))`、全て checked):
311
+
312
+ | op | work | reference | units |
313
+ |---|---|---|---|
314
+ | `Gemm` | m·n·k·batch | 4096³ | 120 |
315
+ | `Attention` | q·kv·heads·head_dim·batch | 4096·4096·32·128 | 80 |
316
+ | `LayerNorm`/`RmsNorm` | elements·batch | 4096 | 8 |
317
+ | `Rotary` | tokens·heads·head_dim | 4096 | 4 |
318
+ | `ExpertRoute` | tokens·experts·top_k | 4096 | 16 |
319
+ | `KvCacheRead`/`Write`/`TensorCopy` | bytes | 1 MiB | 1 |
320
+ | `Silu`/`ElementwiseMultiply`/`ElementwiseAdd` | elements | 4096 | 2 |
321
+ | `Softmax` | elements | 4096 | 4 |
322
+ | `EmbeddingLookup` | elements | 4096 | 1 |
323
+ | **`Generic`** | elements | 4096 | 2 (**v2 限定**、v1 は `UnsupportedOperation`) |
324
+
325
+ `ComputeUnitCounter.record` は cost を checked-add し、overflow 時は state を変えず
326
+ `CostError::Overflow`(fail-closed)。
327
+
328
+ ---
329
+
330
+ ## 5. Model profile pin と RuntimeManifest 構築
331
+
332
+ 正本: `runtime-palw/src/qwen_profile.rs`、`runtime-palw/src/manifest.rs`、
333
+ [`config/qwen3.6-35b-a3b-claude-4.7-profile.json`](../config/qwen3.6-35b-a3b-claude-4.7-profile.json)。
334
+
335
+ ### 5.1 profile pin(schema v2)
336
+
337
+ `schema = "misaka.palw.model-profile-pin.v2"`、
338
+ `profile_name = "Qwen3.6-35B-A3B-Claude-4.7-Opus-abliterated-Q4_K_M-Metal-arm64"`。
339
+ `model{}` は MoE の全 shape(architecture `Qwen3_5MoeForConditionalGeneration`、model_type
340
+ `qwen3_5_moe`、gguf_architecture `qwen35moe`、hidden 2048、heads 16、kv 2、layers 40、
341
+ head_dim 256、intermediate 512、expert_count 256、experts_per_token 8、rope_theta 10000000、
342
+ vocab 248320、max_pos 262144、bfloat16、Q4_K_M、ほか linear_* 等)を持つ。`base_artifact`
343
+ は 7 files(各 sha256)、`inference_artifact` は Ollama repo/tag/**64-hex blob revision**/bytes/
344
+ sha256、`runtime` は commit と cmake_cache。deserialize struct は serde `deny_unknown_fields`
345
+ (`HybridProfilePin`/`HybridModelPin`/`HybridInferenceArtifactPin`。dense との差は `tag` field)。
346
+
347
+ ### 5.2 `validate_hybrid_pin`
348
+
349
+ schema/profile_name 一致、model 全 shape 一致、`download_scope=="metadata-only"`、
350
+ `supported_profile=="metal-arm64"`、`targets` に `llama-palw-observer`、`commit.len()==40`、
351
+ `base.revision.len()==40`、**`inference.revision.len()==64`**(Ollama blob digest)、
352
+ `inference.bytes!=0`。metadata files は 7 件で各 sha256 を streaming 照合
353
+ (`verify_base_metadata_hybrid`)。
354
+
355
+ ### 5.3 `build_qwen36_35b_metal_manifest`
356
+
357
+ host(arm64、8 field 非空)と environment(`LANG`/`LC_ALL` のみ)を検証し、GGUF の size/sha256、
358
+ tokenizer(`tokenizer.json`+`tokenizer_config.json` の 2 件)を artifact 化する。以下の digest を
359
+ `domain_hash` で計算し RuntimeManifest に committ する(dense と domain string が異なる主要点):
360
+
361
+ - `chat_template_digest`(`chat-template/v1`): **`chat_template.jinja` file bytes**
362
+ (dense は tokenizer_config 内の文字列)。
363
+ - `special_tokens_digest`(`special-token-semantics/v1`): tokenizer_config + config.json
364
+ (generation は `Value::Null`)。
365
+ - `kernel_graph_id`(`qwen36-35b-llama-graph/v1`): commit + `qwen36_adapter_mapping_id_v1()`
366
+ + `ggml_sched_ask_metadata_v1` + prefill/decode 直列。
367
+ - `kernel_algorithm_digest`(`kernel-algorithm-policy/v1`): 末尾に `;moe-hybrid;cu-ruleset=v2`。
368
+ - ほか `loaded_libraries_digest`、`build_flags_digest`、`dirty_patch_digest`、
369
+ `environment_allowlist_digest`、`runtime_device_digest`、`runtime_program_digest`、
370
+ `build_provenance_digest`。
371
+
372
+ `ModelProfile` は **topology = MixtureOfExperts**、`kv_heads=2`、**`head_dim=256`(hidden/heads
373
+ = 2048/16 = 128 とは decouple)**、`rope="Qwen3.5-iMRoPE"`、`native_context_tokens=262144`、
374
+ `vocabulary=248320`。`RuntimeClass` は Q4_K_M、flash-attn off、`context_size=4096`、batch=1。
375
+ `RuntimeManifest.cu_ruleset_id = ComputeUnitRules::v2().ruleset_id()`。
376
+
377
+ ### 5.4 manifest validator の緩和(hybrid を受理する 2 点)
378
+
379
+ - `ModelProfile::validate` は旧来の `head_dim == hidden/heads` 検査を**削除**した。head_dim を
380
+ 独立 field として committ し cross-check しないため、`head_dim=256` と `2048/16=128` が
381
+ 共存できる。`hidden % heads == 0`(2048%16)、`heads % kv == 0`(16%2)は維持。
382
+ - `RuntimeManifest::validate` は `cu_ruleset_id` が **v1 または v2** の ruleset_id なら受理する。
383
+
384
+ ---
385
+
386
+ ## 6. Receipt body・commitment・署名
387
+
388
+ 正本: `runtime-palw/src/receipt.rs`、`runtime-palw/src/builder.rs`、`runtime-palw/src/observer.rs`。
389
+
390
+ ### 6.1 `ComputeReceiptV1`(署名される canonical wire 順)
391
+
392
+ 30 field を固定順で encode し、その byte 列が全 digest(`signing_digest`/`body_id`/
393
+ `receipt_id`)の入力になる。主要 field: `receipt_version(=1)`、`network_id`、
394
+ `request_commitment`、`scheduler_job_id`、`signed_assignment_id`、`replica_slot`、
395
+ `model_profile_id`、`runtime_class_id`、`runtime_manifest_hash`、`shape_profile_id`、
396
+ **`cu_ruleset_id = evidence.cu_ruleset_id()`**、`trace_scheme_id`、`trace_evidence`、
397
+ `operation_schedule_commitment`、`schedule_event_count`、`canonical_compute_units`、
398
+ `prefill_tokens`、`decode_tokens`、`output_commitment`、`gemm_trace_root`、`trace_event_count`、
399
+ `owner_commitment`、`worker_credential_id`、`job_nullifier`、`execution_nullifier`、`job_class`、
400
+ `evidence_level`、`timestamp`、`issued_epoch`、`expires_epoch`。
401
+
402
+ `validate_structure` は署名前後で 17 digest の非零、`prefill_tokens!=0`、
403
+ `issued<=expires`、job_class ごとの replica_slot 範囲、evidence_level ごとの count 整合
404
+ (GemmTraced は schedule/trace/CU が全て非零かつ `trace_evidence!=Absent`)を検査する。
405
+
406
+ ### 6.2 `build_signed_receipt`
407
+
408
+ `manifest.validate`、CUDA KernelSketch 拒否、scheduler 署名(request+assignment)検証、worker
409
+ credential binding、request constraints と manifest ID の一致、evidence↔shape/job binding、
410
+ prompt opening と `prefill_tokens` 一致、output count 一致、を検査後に commitment
411
+ (`commit_prompt_tokens`/`commit_output`/`commit_owner`/`derive_job_nullifier`/
412
+ `derive_execution_nullifier`)を計算し、body を Ed25519 署名(`signing_digest` は network-id
413
+ salt 付き canonical bytes)。builder は `cu_ruleset_id` を **evidence の値そのまま** committ する
414
+ (独自に ruleset を再導出しない)。
415
+
416
+ ### 6.3 evidence 生成(`RuntimeObserver` → `ExecutionEvidence`)
417
+
418
+ observer は `job_nullifier`/`shape_profile_id`/`ComputeUnitRules`/`EvidenceLevel` に束縛される。
419
+ `schedule = OperationSchedule::new(..., rules.ruleset_id())`、trace は GemmTraced 時のみ生成。
420
+ 状態機械は `AwaitingPrefill→Prefill→Decode{step}`、decode step は厳密連番、任意の event error で
421
+ 恒久 poison。`finalize_with_generated_tokens` は `generated == decode_tokens+1`(先頭 token は
422
+ prefill logits から sample)を要求。GemmTraced 不変条件として **schedule の GEMM 数 ==
423
+ trace group 数**。`ExecutionEvidence.cu_ruleset_id = counter.rules().ruleset_id()`(本移行では
424
+ v2)がそのまま receipt へ流れる。
425
+
426
+ ---
427
+
428
+ ## 7. Stateless 検証(`verify_stateless`)
429
+
430
+ 正本: `runtime-palw/src/verifier.rs`。`VerificationContext { network_id, current_epoch,
431
+ manifest, cu_rules, signer_registry, assignment_authorizations }` を取り、順に:
432
+
433
+ 1. `validate_structure`、network/epoch。
434
+ 2. assignment 解決と全 field binding、assignment policy(`required_evidence_level==evidence_level`)。
435
+ 3. signer 解決、owner/worker commitment、**Ed25519 署名**(weak-key 拒否 + `verify_strict`)。
436
+ 4. `manifest.validate`、CUDA KernelSketch 拒否。
437
+ 5. `model_profile_id`/`runtime_class_id`/`runtime_manifest_hash`/`shape_profile_id` を manifest
438
+ から独立再計算して照合。
439
+ 6. **CU-ruleset triple-bind**: `body.cu_ruleset_id == context.cu_rules.ruleset_id()` **かつ**
440
+ `== manifest.cu_ruleset_id`(不一致は `CuRulesetMismatch`)。本移行では三者とも v2。
441
+ 7. `trace_scheme_id` bind、`job_nullifier`/`execution_nullifier` の再導出照合、`verify_shape`。
442
+ 8. `verify_execution_evidence`: evidence metadata・schedule integrity/commitment 照合後、
443
+ **`context.cu_rules` で schedule を最初から再 pricing** し `canonical_compute_units` を
444
+ 照合(claim を信用しない)。per-entry で layer 範囲、dense topology の expert-route 拒否、
445
+ decode phase 順序を検査。GemmTraced は `verify_trace`(trace binding、capability 一致、
446
+ GEMM 数 == trace group 数、per-event の schedule 対応)。
447
+ 9. output nonce / prompt opening / output opening / output count。
448
+
449
+ hybrid では topology が MixtureOfExperts のため expert-route の dense 拒否は発火しない(なお
450
+ 本 adapter は `MUL_MAT_ID` を `Generic` に写すので ExpertRoute op 自体を生成しない)。
451
+
452
+ ---
453
+
454
+ ## 8. Verification bundle と ruleset 選択の 3 修正
455
+
456
+ 正本: `runtime-palw/src/verification_bundle.rs`。
457
+
458
+ ### 8.1 `seal_verification_bundle`
459
+
460
+ owner opening を照合し、**封印前に receipt を完全に再 stateless 検証**する(state-store は
461
+ 変更しない)。公開部 `BundlePublicV1`(receipt_binding、receipt_id、verification_epoch、
462
+ scheduler-key record、`manifest.canonical_bytes()`、`PortableEvidenceV1`)は認証済み cleartext。
463
+ 秘密部 `BundlePrivateV1`(署名済み request/assignment、signer record、output opening =
464
+ output_nonce + prompt/output token IDs、owner salt)は **XChaCha20-Poly1305** で AEAD 暗号化
465
+ (AAD で receipt_binding/public_digest/nonce/public_bytes を束縛、AEAD 鍵は audit key の
466
+ `domain_hash` 派生で raw key を直接使わない)。`bundle_id` は完全な暗号化 envelope 全体の
467
+ `domain_hash`。
468
+
469
+ ### 8.2 CU ルールセット選択の 3 修正(v2 対応)
470
+
471
+ | # | 位置 | 修正 |
472
+ |---|---|---|
473
+ | 1 | seal 経路 | `cu_rules = ComputeUnitRules::matching_ruleset_id(&context.manifest.cu_ruleset_id)`(旧: v1 固定) |
474
+ | 2 | `verify_bundle_stateless_inner` | `matching_ruleset_id(&bundle.public.manifest.cu_ruleset_id)`(旧: v1 固定) |
475
+ | 3 | `PortableEvidenceV1::encode_canonical` | ruleset **version** を evidence に合わせて書く(`matching_ruleset_id(evidence.cu_ruleset_id()).map_or(0, version)`。旧: v1 固定)。decode は `for_version` で読む |
476
+
477
+ これらが無いと、v2 evidence が bundle 内で v1 として round-trip し `CuRulesetMismatch` になる。
478
+ 併せて `manifest.rs` の validate が v1|v2 を受理し、`matching_ruleset_id` を追加した。producing CLI
479
+ は `ComputeUnitRules::v2()` を bind する。
480
+
481
+ ### 8.3 portable evidence の round-trip
482
+
483
+ encode は version・level・prefill/decode・**ruleset version**・job_nullifier・shape_profile_id・
484
+ schedule entries・trace groups・claimed CU・claimed ruleset を書く。decode は `RuntimeObserver`
485
+ で schedule/trace/CU を **再導出**(serialize 済み total を信用しない)し、再構成 evidence の
486
+ `canonical_compute_units`/`cu_ruleset_id` が claimed と一致することを要求する。bounds:
487
+ `MAX_EVIDENCE_EVENTS=250000`、`MAX_BUNDLE_BYTES=64MiB`。
488
+
489
+ ---
490
+
491
+ ## 9. 永続化(SQLite schema v4)と CLI 契約
492
+
493
+ ### 9.1 StateStore(schema v4)
494
+
495
+ `APPLICATION_ID="PALW"`、`SCHEMA_VERSION=4`。`open` は parent dir 解決 + `SQLITE_OPEN_NOFOLLOW`、
496
+ `foreign_keys=ON`、`synchronous=FULL`、`journal_mode=WAL`、application/schema 照合、および
497
+ `sqlite_master` の **DDL fingerprint**(SHA3-256 golden 照合)。`accept` は `BEGIN IMMEDIATE` で
498
+ duplicate receipt / duplicate execution_nullifier / job-class 整合 / slot 充填を強制し、
499
+ `jobs`(PK `(network_id,job_nullifier)`、WITHOUT ROWID)と `receipts`(PK `receipt_id`、
500
+ `execution_nullifier` UNIQUE、`UNIQUE(network_id,job_nullifier,replica_slot)`、FK RESTRICT)へ
501
+ transaction で insert する。復元経路 `restore_accepted` は read-only で既存 row を byte 照合する。
502
+
503
+ ### 9.2 `palw-metal-receipt`(発行 CLI)
504
+
505
+ 必須: `--prompt-stdin`、`--audit-key-file`(**exact 32 raw bytes**、owner-only single-link
506
+ `0400`/`0600`、output dir 外)、`--output-dir`(新規/空、owner-only `0700`)。任意: `--n-predict`
507
+ (`1..=1024`、default 2)。prompt は UTF-8 非空 ≤1 MiB。run flow は §0 の通り。`canonical_source_patch`
508
+ は `tools/CMakeLists.txt` と `src/models/qwen35moe.cpp` の modified、`tools/palw-observer/` の
509
+ untracked のみを許容する(他は拒否 = fail-closed)。出力 artifact:
510
+
511
+ | file | mode | 内容 |
512
+ |---|---|---|
513
+ | `<id>.palw` | 0644 | 署名済み canonical receipt |
514
+ | `<id>.json` | 0644 | 公開 metadata(`misaka.palw.public-receipt.v2`、strict field) |
515
+ | `<id>.palw.bundle` | 0600 | XChaCha20 暗号化 bundle |
516
+ | `palw-state.sqlite3` | 0600 | schema v4 state |
517
+ | `<id>.complete` | 0644 | `misaka.palw.receipt-set.v2` 完了 marker(**最後**に fsync 付きで作成) |
518
+
519
+ ### 9.3 `palw-verify-bundle`(検証 CLI)
520
+
521
+ 必須: `--receipt`/`--bundle`/`--public-json`/`--audit-key-file`/`--state-db`。artifact set の
522
+ mode/owner/single-link/同一 private dir、完了 marker の binding、bounded read、`decode_strict`、
523
+ `validate_artifact_names`(receipt_id は bundle 由来)、`verify_bundle_and_restore`(§8 の復号・
524
+ 再検証・schema-v4 復元)、`verify_public_metadata`(公開 JSON を authenticated 値と field 単位で
525
+ 照合)。正常時 `status=local_restored` / `trust_scope=embedded_local_snapshot`。この trust scope
526
+ は bundle 内 registry snapshot による continuity を示すのみで、network authority の代替ではない。
527
+
528
+ ---
529
+
530
+ ## 10. E2E 実測(reference receipt)
531
+
532
+ Apple M1 Max(macOS Metal 4、arm64)。observer は load 時に qwen35moe/40/2048/248320 を検証し
533
+ `offloaded 41/41 layers to GPU`。出力健全性: `The capital of France is`
534
+ (`[760,6511,314,9338,369]`)→ ` Paris, a city renowned for its iconic`。
535
+
536
+ reference artifact は [`receipts/final-v7/`](../receipts/final-v7)、evidence 詳細は
537
+ [`docs/evidence/metal-hybrid-qwen36-2026-07-19.md`](evidence/metal-hybrid-qwen36-2026-07-19.md)。
538
+ 公開 receipt(`misaka.palw.public-receipt.v2`)の主要値:
539
+
540
+ | field | 値 |
541
+ |---|---|
542
+ | `receipt_id` | `8e2dd34b7609d6d7aeec17bff485eb1ae4db31f66dd899a3c3a3e671656053f9` |
543
+ | `verification_bundle_id` | `f5b8a2968c4ea266b2cbbabf351a171e0fa2581984eff63362de2640fcdcf9db` |
544
+ | `cu_ruleset_id`(**v3 semantic**) | `43a5feef177b389f976361b22ac9d57da65815261282005bc78d1666a37870ce` |
545
+ | `job_class` / `evidence_level` / `trace_evidence` | `self_local` / `gemm_traced` / **`metal_kernel`** |
546
+ | `prefill_tokens` / `decode_tokens` | `5` / `2` |
547
+ | `prefill_graph_steps` / `decode_graph_steps` | `5` / `1` |
548
+ | `schedule_event_count`(= canonical_operations、commitment-only) | `13770` |
549
+ | `trace_event_count`(= gemm_events) | `2466` |
550
+ | `canonical_compute_units`(**v3 semantic、署名 commit**) | `41692` |
551
+ | `semantic_compute_units_v3`(= canonical_compute_units) | `41692` |
552
+ | `semantic_schedule.commitment` / `.expert_route_ops` | `e6fc731e…` / `80` |
553
+ | `expert_route.root` / `.route_event_count`(実捕捉) | `5e4ea70b…` / `240` |
554
+ | `mint.eligible` / `mint.weight` / `mint.mainnet_ready` | `false` / `0` / `false` |
555
+ | `mint.ineligible_reasons` | Metal kernel-launch-bound / 非 network-anchored / 非 bonded の 3 件(generic+graph-fallback は解消) |
556
+ | `model_profile_id` | `b6b83a274a889fc5dfa2044b9158111b3849f880a05eb7ebcf560d036515d472` |
557
+ | `runtime_class_id` | `8f6f536118a72be70dab2028535c3bb95e3de9a3bac0e9b81cf78677ae902a9c` |
558
+ | `artifacts.llama_commit` / `model_bytes` | `12127def…` / `23938321728` |
559
+
560
+ privacy: prompt / prompt token IDs / 生成 token IDs / opening / signing key / owner salt は公開
561
+ `.palw` / `.json` に**含まれない**(全 9 flag が非公開/暗号化)。別 process の `palw-verify-bundle`
562
+ が `status=local_restored`、`trust_scope=embedded_local_snapshot`、receipt_id/bundle_id 一致、
563
+ exit 0 で再検証済み。発行は実行ごとに OS CSPRNG で identity を生成するため receipt_id は再現しない。
564
+
565
+ ---
566
+
567
+ ## 11. セキュリティ境界・正直な限界
568
+
569
+ - **この Receipt は mint-grade ではない。** 現行の `evidence_level=gemm_traced` /
570
+ `trace_evidence=graph_fallback` は**強い計算証明ではない**。`runtime-palw/src/mint.rs` の
571
+ `assess_mint_eligibility` が現行 runtime の全 receipt を `eligible=false, weight=0,
572
+ class="local_self_consistent_v0_1"` と判定し、公開 JSON の `mint` ブロックに失格理由と共に
573
+ 自己申告する(`palw-verify-bundle` が再構成して照合)。用途は「ローカル自己整合 receipt /
574
+ testnet 計測 / Self-Local 非報酬」に限られる。mint-grade 化の是正計画は
575
+ [`receipt-review-remediation.md`](receipt-review-remediation.md) を参照���
576
+ - Metal の graph-fallback sketch は **CUDA kernel trace ではない**。
577
+ - 単独ノードが発行する Receipt は、それだけでゼロ知識の計算証明ではない。PALW の不正耐性は
578
+ runtime/model digest、署名、k=2 replica、future audit、canary、bond/slashing の組み合わせで
579
+ 成立する。
580
+ - **`Generic` 演算は廃止済み(M3)。** hybrid の全 MoE/SSM op を忠実な canonical 演算へ写像
581
+ (`MUL_MAT_ID→ExpertGemm`、`ARGSORT→ExpertRoute`、`SSM_CONV→SsmConv`、`GATED_DELTA_NET→GatedDeltaNet`、
582
+ `L2_NORM→L2Norm`、`SUM_ROWS→Reduction`、`CONCAT→TensorCopy`、`UNARY/SCALE/DIV/CLAMP→Elementwise`)。
583
+ 実機 receipt の schedule は `contains_generic_operation()==false`。
584
+ - **Semantic CU v3 は canonical commitment(M1、mainnet compute measure)。** `semantic_cu.rs` の
585
+ `qwen36_semantic_compute_units(prefill, generated)` は CU を **observed graph からではなく pinned
586
+ model 構造 + token 数**から算出(active-parameter FLOPs + causal attention 項、丸めは最後に 1 回)。
587
+ 現行 receipt の `canonical_compute_units` は **この semantic 値(41692)を `cu_ruleset_id=v3` で署名
588
+ commit** する(v2 の graph 値ではない)。fragmentation-proof / backend 非依存で、verifier は
589
+ `prefill_tokens`/`decode_tokens` から同値を再計算・照合。
590
+ - **canonical semantic schedule(M2、#7 構造半分)。** `semantic_schedule.rs` が pinned architecture +
591
+ token 数から canonical op schedule と commitment を決定的に再生成し、公開 JSON `semantic_schedule`
592
+ に束縛。verifier が独立再生成して照合。
593
+ - **実 MoE routing の捕捉(M4/#6)。** observer が `ffn_moe_topk`(I32)を post-compute で読み戻し、
594
+ per-token 選択 expert を封緘 bundle の `expert_route_root` へ commit、公開 JSON `expert_route` として
595
+ 発行・再構成。実機で 240 route record を捕捉。
596
+ - **kernel-level trace(#5、M5、完了・実機検証済み)。** ggml-metal を計装して各 GEMM を実 Metal
597
+ kernel dispatch + launch geometry へ束縛(200/200・411/411、0 anomaly)。`trace_evidence=metal_kernel`
598
+ (graph-fallback から昇格)、`TraceEvidenceKind/TraceCapability::MetalKernel` を新設し verifier が照合。
599
+ **launch-geometry 束縛であり CUDA V3 相当の intra-kernel accumulator proof ではない**ため
600
+ `KernelSketch` とは別 kind で commit(over-claim しない)。mint 失格理由は「Metal kernel-launch-bound
601
+ sketch, not an intra-kernel accumulator proof」に置換(mint 不適格のまま)。accumulator-level は
602
+ Metal shader 計装が残件。
603
+ - **mainnet-readiness。** `assess_mainnet_readiness` が compute / network / hardware / model-Genesis の
604
+ 全 gate を列挙し、外部 gate を Met と偽らない。現状 `mint.mainnet_ready=false`。mainnet 報酬適格性は
605
+ deployed network authority / global nullifier / epoch beacon / bond authority / 複数世代実機 /
606
+ 公式モデル Genesis を要し、この repository の完了範囲外である(remediation の外部ブロック項参照)。
607
+ - 未達 gate R13/R21/R23/R24/R26/R27/R32/R35 は [`requirements.md`](requirements.md) の通り
608
+ `In progress`。本移行はこれらの production 完了を意味しない。
609
+
610
+ ### 既知の drift とテスト網羅(2026-07-19 時点)
611
+
612
+ - **hybrid adapter の専用 unit test** は fixture test を追加済み(`hybrid_generic_op_class` 表、
613
+ mapping id 識別、MoE/SSM op 写像、unknown op fail-closed、q6_K trace、dense header 拒否)。
614
+ CU fragmentation invariant や公式 Transformers との differential 等の残りは
615
+ [`receipt-review-remediation.md`](receipt-review-remediation.md) の follow-up。
616
+ - `validate_hybrid_pin` は dense と異なり `base_artifact`/`inference_artifact` の repository
617
+ 文字列を pin せず、deserialize する MoE/linear-attention の追加 dim(`linear_*`、
618
+ `shared_expert_intermediate_size`、`full_attention_interval`、`partial_rotary_factor_millionths`)
619
+ を committ manifest には使わない(`deny_unknown_fields` 受理のためだけに存在)。
620
+
621
+ ---
622
+
623
+ ## 12. 再現手順
624
+
625
+ ```sh
626
+ # 1. 導入(GGUF は Ollama registry、base metadata は HF)
627
+ ./scripts/install.sh
628
+
629
+ # 2. Rust gate(MSRV 1.81)
630
+ cd runtime-palw
631
+ cargo +1.81.0 fmt --all -- --check
632
+ cargo +1.81.0 clippy --locked --all-targets -- -D warnings
633
+ cargo +1.81.0 test --locked --all-targets
634
+ cargo +1.81.0 build --release --locked --bin palw-metal-receipt --bin palw-verify-bundle
635
+ cd ..
636
+
637
+ # 3. Receipt 発行(audit key は 32-byte raw、output dir 外に一度だけ作成)
638
+ OUT="receipts/manual-$(date +%Y%m%d-%H%M%S)"
639
+ AUDIT_KEY="$HOME/.config/misaka-palw/audit-keys/local-audit.key"
640
+ install -d -m 700 "$(dirname "$AUDIT_KEY")"; test ! -e "$AUDIT_KEY"
641
+ (umask 077 && /usr/bin/openssl rand 32 > "$AUDIT_KEY"); chmod 600 "$AUDIT_KEY"
642
+ runtime-palw/target/release/palw-metal-receipt \
643
+ --prompt-stdin --audit-key-file "$AUDIT_KEY" --output-dir "$OUT" --n-predict 2 \
644
+ < /path/to/private-prompt.txt
645
+
646
+ # 4. 別 process 検���
647
+ RECEIPT="$(find "$OUT" -maxdepth 1 -type f -name '*.palw' -print)"; ID="$(basename "$RECEIPT" .palw)"
648
+ runtime-palw/target/release/palw-verify-bundle \
649
+ --receipt "$OUT/$ID.palw" --bundle "$OUT/$ID.palw.bundle" \
650
+ --public-json "$OUT/$ID.json" --audit-key-file "$AUDIT_KEY" \
651
+ --state-db "$OUT/palw-state.sqlite3"
652
+ # 期待: status=local_restored / trust_scope=embedded_local_snapshot / exit 0
653
+ ```
654
+
655
+ GGUF の SHA-256 を発行前後に 4 回計算するため、1 回の発行は約 5 分要する(24GB × 4)。
656
+ これは hang ではない。
docs/receipt-review-remediation.md ADDED
@@ -0,0 +1,214 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Receipt security review — remediation plan
2
+
3
+ 本書は、Qwen3.6-35B-A3B hybrid receipt 実装に対する外部レビュー(16 項目)への対応方針を
4
+ 正直に記録する。レビューの結論は妥当であり、本書もそれを採用する。
5
+
6
+ > **ローカル Receipt v0.1 として freeze 可。PALW mint-grade Receipt としては freeze 不可。**
7
+
8
+ `trace_evidence = graph_fallback` は依然 **kernel trace ではない**(#5、下記 external/remaining)。
9
+ ただし後述の compute-gate track により、CU は graph-independent な semantic commitment になり、
10
+ `Generic` 演算は廃止され、MoE expert routing は実捕捉されるようになった。
11
+
12
+ ## compute-gate track — 実機検証済み(2026-07-19、Apple M1 Max)
13
+
14
+ 「mainnet 報酬用途まで進めて」の goal に対し、この repository で完結できる **in-repo compute gate** を
15
+ 実装し、すべて Metal 実機で発行→別 process 検証まで確認した。**捏造していない。**
16
+
17
+ - **M1 — semantic CU v3 を canonical commitment 化(#2 の実体)。** receipt の
18
+ `canonical_compute_units` は v2 graph 値(104628)ではなく **semantic 値(41692)を `cu_ruleset_id=v3`
19
+ で署名 commit**する。observer/verifier/portable-evidence が同一 helper で束縛し、verifier は
20
+ `prefill/decode` から再計算。`compute.semantic_cu` gate が honest に Met。
21
+ - **M2 — canonical semantic schedule 再生成(#7 の構造半分)。** `semantic_schedule.rs` が pinned
22
+ architecture + token 数から canonical op schedule と commitment(`e6fc731e…` 参照)を決定的に再生成、
23
+ authenticated public receipt に束縛。verifier が独立再生成し照合。
24
+ - **M3 — `Generic` 演算の廃止(#3)。** hybrid の全 MoE/SSM op を **忠実な canonical 演算**へ写像
25
+ (`MUL_MAT_ID→ExpertGemm`、`ARGSORT→ExpertRoute{top_k=8}`、`SSM_CONV→SsmConv`、
26
+ `GATED_DELTA_NET→GatedDeltaNet`、`L2_NORM→L2Norm`、`SUM_ROWS→Reduction`、`CONCAT→TensorCopy`、
27
+ `UNARY/SCALE/DIV/CLAMP→Elementwise`)。実 op stream(ARGSORT=256 experts、MUL_MAT_ID=8 experts-used
28
+ で検証)に接地。`contains_generic_operation()==false` となり mint の generic 失格理由が消える。
29
+ - **M4/#6 — 実 MoE routing の observer 捕捉。** observer が `ffn_moe_topk`(I32)を post-compute で
30
+ 読み戻し、per-token 選択 expert を "route" record として emit(schema v2)。adapter が各 routing を
31
+ commitment chain へ fold し `expert_route_root` を封緘 bundle へ束縛、公開 JSON の `expert_route`
32
+ として発行・再構成。実機で **240 route record** を捕捉(例: layer0 token0 →
33
+ `[112,107,106,181,238,57,43,200]`)。
34
+
35
+ **6 つの compute gate は全て実機検証済み(#5 も完了):**
36
+ - **#5 Metal kernel-level trace(M5、完了・実機検証済み)。** ggml-metal を計装
37
+ (`ggml_metal_palw_set_dispatch_hook`)して全 Metal dispatch を pipeline 名 + launch geometry で捕捉し、
38
+ 各 GEMM を ASK→POST window 内の実 matmul dispatch へ束縛(実機で 200/200 window・411/411 GEMM、
39
+ 0 anomaly で健全性を確認)。`trace_evidence=metal_kernel`(graph-fallback から昇格)、
40
+ `TraceEvidenceKind::MetalKernel` / `TraceCapability::MetalKernel` を新設。`compute.kernel_level_trace`
41
+ は Met、mint の「graph-fallback」失格理由は解消。**ただし launch-geometry 束縛であり CUDA V3 相当の
42
+ intra-kernel accumulator proof ではない**ため、`KernelSketch` とは別 kind として commit し
43
+ (over-claim しない)、mint 失格理由は「Metal kernel-launch-bound sketch, not an intra-kernel
44
+ accumulator proof」に置換(依然 mint 不適格)。より強い accumulator-level は Metal shader 計装が残件。
45
+
46
+ ### #5 Metal kernel-level trace — 調査済み実装スペック(未実装、on-device 反復が必要)
47
+
48
+ vendored ggml-metal を調査した結果、honest な kernel-level trace の具体経路と blocker を確定した
49
+ (hand-wave ではない)。
50
+
51
+ - **決定論的に commit 可能な唯一の kernel-level 信号は launch geometry**(dispatch した Metal
52
+ pipeline 名 + threadgroup/grid 次元)。GPU timestamp / hardware counter は run ごとに変動し
53
+ reproducible でないため commit 不可。
54
+ - **捕捉点**: `ggml/src/ggml-metal/ggml-metal-ops.cpp :: ggml_metal_op_mul_mat` の
55
+ `ggml_metal_encoder_set_pipeline` / `ggml_metal_encoder_dispatch_threadgroups(enc, tg0..2, tptg0..2)`
56
+ (~line 570/589)。pipeline は `ggml_metal_pipelines_get(ppls, name)` で name 既知。
57
+ - **必要な変更(observer tool だけでなく ggml-metal *backend library* の改変)**:
58
+ 1. ggml-metal に per-dispatch hook API(`ggml_metal_palw_set_dispatch_hook(fn, ctx)`)を追加し、
59
+ `ggml_metal_op_mul_mat` から `{pipeline_name, tg0..2, tptg0..2, seq}` を callback。
60
+ 2. observer が hook を登録し、eval callback の ask→post 区間で発生した dispatch を当該 node に
61
+ 相関付けて **kernel-level sample(per-dispatch geometry)** として emit。
62
+ 3. Rust: Metal runtime class の `TraceCapability` を `KernelSketch` にし、observer が
63
+ `TraceEvidenceKind::KernelSketch`(group あたり複数 sample)を emit。verifier は
64
+ capability↔evidence を照合。
65
+ 4. `libggml-metal.dylib` を再ビルド(observer 単体より広い)。
66
+ - **blocker(誠実な理由で本 session 内で安全に完了・検証できない)**: eval-callback の node 粒度と
67
+ Metal の実 dispatch 粒度は 1:1 保証が無い(fuse / 並行 encoding の可能性)。この相関を誤ると
68
+ **偽の kernel-level 主張**になり得る。正しさは on-device の反復検証を要する。**相関の健全性が
69
+ 実機で確証できるまで `TraceEvidenceKind::KernelSketch` へ切替えない**(graph_fallback のまま)。
70
+ stub で KernelSketch を emit することは**しない**。
71
+
72
+ ## この変更で実施した是正(done now、初期)
73
+
74
+ - **mint-eligibility ゲートと weight 0 の明示(レビュー #1 の最小版)。** `runtime-palw/src/mint.rs`
75
+ に `assess_mint_eligibility(trace_evidence, contains_generic)` を追加。現行 runtime が発行する
76
+ receipt は常に `eligible=false, weight=0, class="local_self_consistent_v0_1"` となり、
77
+ 失格理由(graph-fallback、generic、非 network-anchored、非 bonded)を列挙する。公開 JSON に
78
+ `mint` ブロックとして自己申告し、`palw-verify-bundle` が authenticated 値から再構成して照合する。
79
+ これにより `gemm_traced` という肩書きを mint-grade と誤認する事故を防ぐ。**EvidenceLevel enum
80
+ 自体の rename(#1 の完全版)は wire/consensus 変更のため v2 で行う(下記 planned)。**
81
+ - **Semantic CU ルールセット v3(レビュー #2 の中核、graph-independent 化)。**
82
+ `runtime-palw/src/semantic_cu.rs` に `qwen36_semantic_compute_units(prefill, generated)` を追加。
83
+ CU を **observed graph からではなく pinned model 構造 + token 数**から算出する:
84
+ `CU = ceil((per_token_active_flops·N + attn_flops_per_kv·N(N+1)/2) / 1e6)`、N=prefill+generated。
85
+ active-parameter FLOPs(全 attention/delta 射影 + 8 routed + 1 shared expert + delta state +
86
+ output head)+ causal attention 項。**fragmentation-proof(graph 分割で不変)/ backend 非依存**で、
87
+ verifier は receipt の `prefill_tokens`/`decode_tokens` だけから同値を再計算できる(公開 JSON の
88
+ `semantic_compute_units_v3` として自己申告・照合)。`ComputeUnitRules::v3()` は per-op pricing を
89
+ 拒否し独立の `ruleset_id` を持つ。**これは #2「CU を profile から独立算出」の実体である**が、
90
+ 現行 receipt の canonical CU を v3 へ切り替える(v2→v3 の commitment 変更)は planned。
91
+ - **mainnet-readiness ゲート。** `mint.rs::assess_mainnet_readiness` が compute / network / hardware /
92
+ model-Genesis の全 gate を列挙し、達成(Met)/ in-repo pending / 外部ブロック(ExternalNetwork /
93
+ ExternalHardware / ExternalModelGenesis)を厳密に分類する。**外部 gate を Met と偽らない。**
94
+ 現状 `ready=false`(公開 JSON の `mint.mainnet_ready=false`)。
95
+ - **hybrid adapter の直接 unit test(レビュー #16 の一部)。** `hybrid_generic_op_class` 表、
96
+ mapping id の識別、MoE/SSM op → canonical 写像、unknown op の fail-closed、q6_K trace、
97
+ dense header の拒否を fixture test 化。
98
+
99
+ ## 現行 runtime の判定(mint gate)
100
+
101
+ ```
102
+ graph-fallback trace → mint 不可(kernel proof でない) ← #5 未達で残存
103
+ embedded local snapshot → mint 不可(network-anchored でない) ← 外部
104
+ ephemeral 署名 identity → mint 不可(bonded credential でない) ← 外部
105
+ ```
106
+ (「Generic 演算を含む」失格理由は M3 で解消。実機 receipt の `mint.ineligible_reasons` は上記 3 件のみ。)
107
+
108
+ 運用レベル(レビューの表を採用):
109
+
110
+ | レベル | 条件 | Work weight |
111
+ |---|---|---|
112
+ | Local prototype | 現行 graph-fallback | 0 |
113
+ | Testnet telemetry | 現行 graph-fallback + signed assignment | 0 |
114
+ | Testnet replica | challenge + k=2 + semantic CU v3 | 低 |
115
+ | Mint candidate | route/state trace + exact schedule + global nullifier | 1.0 候補 |
116
+ | Mainnet | cross-runtime audit, bond, canary, 全 gate 通過 | governed |
117
+
118
+ ## 是正方針(全 16 項目)
119
+
120
+ ### A. in-repo で実施可能な follow-up(次段)
121
+
122
+ - **#2 Generic pricing 廃止 → semantic CU v3。** **[アルゴリズム実装済み]** `semantic_cu.rs` が
123
+ `model_profile + prefill/generated token` から FLOP ベースで CU を独立算出する(attention / delta /
124
+ routed+shared expert / delta state / output head を active-parameter FLOPs で価格付け、丸めは最後に
125
+ 1 回)。fragmentation-proof / backend 非依存。receipt は公開 JSON に `semantic_compute_units_v3` を
126
+ 自己申告する。**残(planned):** receipt の canonical CU commitment を v2(graph)から v3(semantic)へ
127
+ 切り替え、`Generic` を CU=0 の commitment-only へ降格、verifier が canonical CU を semantic 値で
128
+ bind する(現在は informational な自己申告 + verifier 再計算照合まで)。
129
+ - **#3 主要計算の trace。** `MUL_MAT_ID`(Expert GEMM)、ExpertRoute Top-K、shared expert、
130
+ Gated DeltaNet state を trace 対象に含める。`trace_scheme_id` を `hybrid-execution-trace/v2` に
131
+ 更新し、現 `gemm_trace_root` スロットへ統合 root
132
+ `H(gemm_root || expert_route_root || deltanet_state_root || schedule_root)` を格納。API/文書上は
133
+ `execution_trace_root` と呼ぶ。observer に router 出力を捕捉する観測モードを追加する必要がある。
134
+ - **#5(in-repo 部分)完全な architecture profile を `model_profile_id` へ committ。** 現在
135
+ deserialize のみで committ していない `linear_*` / `shared_expert_intermediate_size` /
136
+ `full_attention_interval` / `partial_rotary_factor` に加え、delta/attention layer bitmap、
137
+ routed=8 + shared=1 の構成、`tensor_inventory_root` を profile v2 として commit。validation は
138
+ architecture 別に分岐し、`head_dim == hidden/heads` の緩和を dense validator へ波及させない。
139
+ - **#7 `decode_tokens` の意味を明確化。** wire は `decode_tokens = generated_token_count`、
140
+ `decode_eval_steps = decode_tokens - 1`(先頭 token は prefill logits から sample)。0/1 token
141
+ 境界の test を追加(observer.rs に既存の等価 test あり)。
142
+ - **#8 offload 判定の強化。** hybrid profile に `expected offload units = 41` を固定し、任意の
143
+ N/N を受理しない。ただし stderr marker は自己申告 telemetry であり mint validity へは使わない
144
+ (現行は既に mint 不可なので影響は無いが、tightening として実施予定)。
145
+ - **#9 replica output commitment 規則の凍結。** A/B 比較のため、共有 `output_salt =
146
+ H(job_assignment || epoch_challenge)` 方式、または独立 salt + matcher が opening を突き合わせて
147
+ `ReplicaMatchCertificate` を発行する方式の**どちらか**を明文化する。
148
+ - **#12 暗号化 bundle の情報分離と KDF 強化。** 公開部を root/commitment/count のみにし、個別
149
+ schedule entry・sketch・expert route は暗号化部へ移す。per-bundle subkey を HKDF で
150
+ `network || receipt_id || schema_version` を context に導出、nonce は bundle ごとに OS CSPRNG、
151
+ audit key ID と rotation epoch を保存、master 漏洩で全履歴が解読されない per-job data key。
152
+ 現行の `domain_hash(audit_key)` は KDF として不十分と明記。
153
+ - **#16(残り)テスト網羅の完成(mint 前 gate)。** 全 op mapping fixture、unknown op 拒否、
154
+ 巨大 shape/overflow、event 欠落・重複・順序変更、`MUL_MAT_ID`/shared expert/DeltaNet state、
155
+ JSONL parser fuzz、canonical encode/decode property、**CU fragmentation invariant**
156
+ (「同一 semantic operation を複数 event に分割しても CU は増えない」)、公式 Transformers との
157
+ differential、M1/M4 cross-device。
158
+
159
+ ### B. 外部インフラ/ハードウェア依存で本 repo・本セッションでは完結不可(honest boundary)
160
+
161
+ これらは既存の R13/R21/R23/R24/R26/R27/R32/R35 と同じく、この repository の完了範囲外である
162
+ ([`requirements.md`](requirements.md)、[[palw-honest-boundary]] と整合)。**捏造しない。**
163
+
164
+ - **#4 challenge-in-context と global nullifier。** epoch beacon と network-wide global nullifier
165
+ set(consensus 側)が必要。設計としては
166
+ `job_nullifier = H("palw-job-nullifier/v2" || network_id || challenge_epoch || epoch_beacon ||
167
+ request_commitment || scheduler_job_id)` とし、CSPRNG/owner salt を nullifier へ入れない
168
+ (入れると同一仕事の nullifier を量産できる)。`current_epoch - challenge_epoch <= W` を mint 時
169
+ 検査。**receipt_id を毎回変えることは replay 防止ではない**(むしろ量産を容易にする)。ローカル
170
+ SQLite は自 DB 内の重複しか防がない。
171
+ - **#6 cross-device 決定論の実証。** M1 Max ×2 / M4 Pro ×2 / 複数 macOS build / 複数 prompt 長 /
172
+ 16・256・1024 output / 4096 近傍 prefill / EOS 有無 / expert-routing 境界 / top1-top2 margin の
173
+ 小さい prompt。初期は M1 class と M4 class を別 `runtime_class_id` にする。実測では M1/M4 の
174
+ logits 差(token は一致)があり、MoE router の微差が Expert 選択差へ拡大しうるため dense より
175
+ cross-generation の影響が大きい。複数実機が必要。
176
+ - **#10 network verification。** `embedded_local_snapshot` は network authority の代替ではない。
177
+ UI/CLI 表示は `self_consistent_unanchored` / `local_snapshot_verified` /
178
+ `not_network_certified` を推奨。mint には scheduler key の chain inclusion proof、credential の
179
+ activation/revocation proof、set activation proof、global nullifier 未使用証明が別途必要。
180
+ - **#11 persistent bonded credential と署名。** ephemeral receipt key を persistent worker
181
+ credential が authorize する `EphemeralWorkerDelegation` を導入し、slashing は必ず persistent
182
+ credential/bond に到達させる。PALW が耐量子署名を不変条件とするなら Ed25519 単独は不整合で、
183
+ ML-DSA(NIST FIPS 204)の dual-sign または PQ profile が必要。bond authority は repo 外。
184
+ - **#13 Genesis 正本モデル。** 対象は公式 Qwen ではなく第三者の abliterated 変換(model card 自身
185
+ が crude PoC / safety 大幅削減 / production 非推奨と明記)。hash pin は改ざん耐性のみで内容の
186
+ 安全性・正当変換は保証しない。Genesis canonical model は公式 `Qwen/Qwen3.6-35B-A3B` から
187
+ 決定的生成した GGUF(official revision / converter commit / conversion+quant command /
188
+ `tensor_inventory_root` / output SHA-256 / two-party reproducibility attestation)にすべき。
189
+ abliterated 版は `experimental_unfiltered_model_profile_id` として production set と分離する。
190
+ - **#14 consensus governance。** wire 不変でも `Generic` 追加・CU v2・validator 緩和は mint 可否と
191
+ 報酬額を変える(`wire unchanged ≠ consensus unchanged`)。`cu_ruleset_id` を class-as-data として
192
+ chain registry に `set_id / activation_epoch / deactivation_epoch / ruleset code hash /
193
+ model profile hash / allowed evidence levels / mint weight` として登録し、activation 前の
194
+ receipt は mint 不可にする。`matching_ruleset_id([v1,v2])` はコード上の選択であって governance
195
+ ではない。
196
+
197
+ ### C. 可用性(#15)
198
+
199
+ - **GGUF を receipt ごとに 4 回 hash しない。** install 時と process 起動時に full SHA-256、各
200
+ receipt では検証済み file descriptor/inode を再利用、周期的に full rehash。TOCTOU 回避のため
201
+ content-addressed read-only directory、`O_NOFOLLOW`、hash と load で同一 fd、inode/device/size/
202
+ mtime 再確認、実行中の置換禁止。現行の 1 発行約 5 分は利用者の忍耐を攻撃している。
203
+
204
+ ## 最優先 5 点(mint-grade 化の前提)
205
+
206
+ 1. graph-fallback を mint から除外し weight 0 にする → **mint gate として実施済み**
207
+ (EvidenceLevel enum の rename は v2)。**graph-fallback 自体の解消(kernel trace)は #5 で未達。**
208
+ 2. `Generic` pricing を廃止し profile 由来の semantic CU v3 へ移す → **M1 で canonical commitment 化
209
+ 完了(実機検証済み)**。
210
+ 3. ExpertRoute / `MUL_MAT_ID` / shared expert / DeltaNet state を trace 対象へ入れる → **M3(Generic
211
+ 廃止・忠実 canonical 写像)+ M4(実 routing 捕捉)で完了(実機検証済み)**。
212
+ 4. challenge-in-context と global nullifier を必須化する → B(#4、外部・未達)。
213
+ 5. Qwen3.6 の完全な architecture profile と cross-device conformance を凍結する → A(#5 arch profile)
214
+ + B(#6 cross-device、外部ハード必要)。**Metal kernel-level trace(#5)は on-device 実装が残る。**
docs/requirements.md ADDED
@@ -0,0 +1,125 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Specification Completion Matrix
2
+
3
+ この表は設計書 v0.1 の要求を、実装 artifact と検証 gate に分解した正本である。
4
+ `Complete` は列挙したacceptance criteriaがすべて実装・統合・検証済みで、既知の内部未実装と必須外部gateが
5
+ 残らない場合だけ付与する。`In progress` は少なくとも1つのcriterion、内部実装、統合、またはevidenceが未完了で、
6
+ 明示的なhard blockerだけで状態を表していない場合である。`Blocked` は必須criterionに利用不能な外部hardware/
7
+ environment/serviceによるhard blockerがある状態を示し、内部実装が完了したという意味ではない。内部gapと外部
8
+ blockerが共存する場合はverification列で分離し、production発行はfail-closedに停止する。
9
+
10
+ 本ファイル群は repository-scope の設計・実装・evidence baseline を固定した版である。ただし、これを
11
+ Production Network readiness や全要件の `Complete` への昇格とは解釈しない。
12
+
13
+ current Metal E2E(hybrid Qwen3.6-35B-A3B、41/41 offload、`trace_evidence=metal_kernel`)の正本は
14
+ [`evidence/metal-hybrid-qwen36-2026-07-19.md`](evidence/metal-hybrid-qwen36-2026-07-19.md)、canonical Receipt は
15
+ [`../receipts/final-v7/8e2dd34b7609d6d7aeec17bff485eb1ae4db31f66dd899a3c3a3e671656053f9.palw`](../receipts/final-v7/8e2dd34b7609d6d7aeec17bff485eb1ae4db31f66dd899a3c3a3e671656053f9.palw)
16
+ である。移行前 dense Qwen3-8B の schema-v4 証跡([`evidence/metal-smoke-schema-v4-2026-07-15.md`](evidence/metal-smoke-schema-v4-2026-07-15.md)、`final-v6/eb51b08c…4278131`)と historical schema-v3 証跡は
17
+ [`evidence/metal-smoke-2026-07-15.md`](evidence/metal-smoke-2026-07-15.md) と
18
+ [`../receipts/final-v5/ab2b3196a6c0935aafd4d563a9d2e1d71d828cc87a378ae77b8e49c102033b68.palw`](../receipts/final-v5/ab2b3196a6c0935aafd4d563a9d2e1d71d828cc87a378ae77b8e49c102033b68.palw)
19
+ に保持する。current sourceは旧DBをsilent migrate/openしない。
20
+
21
+ Windows/WSL2 上の RTX 4060 Ti (`sm_89`) で実行した CUDA 実験 gate の正本は
22
+ [`evidence/cuda-wsl-sm89-2026-07-15.md`](evidence/cuda-wsl-sm89-2026-07-15.md) である。この証跡は
23
+ Qwen の 37/37 layer offload、diagnostic observer の反復性、standalone producer-accumulator
24
+ primitive の実device gateを示す。続くvendored Q4_K/Q6_K MMVQ hookのone-token実device gateは
25
+ [`evidence/cuda-v3-mmvq-hook-sm89-2026-07-15.md`](evidence/cuda-v3-mmvq-hook-sm89-2026-07-15.md)
26
+ に履歴として保持する。MMVQ、FA-off attention、release manifest、Receipt/Bundle/SQLite V2までを含む
27
+ 現行の正本は
28
+ [`evidence/cuda-v3-full-hook-sm89-2026-07-16.md`](evidence/cuda-v3-full-hook-sm89-2026-07-16.md)
29
+ である。いずれもproduction Receipt発行の証明ではない。
30
+
31
+ | ID | Requirement | Implementation evidence | Verification gate / result | Status |
32
+ |---|---|---|---|---|
33
+ | R01 | Qwen3.6-35B-A3B 学習済み base を再学習しない | `../config/qwen3.6-35b-a3b-claude-4.7-profile.json`, `../scripts/install.sh` | Ollama blob revision、GGUF size/hash、base metadata 7件照合 | Complete |
34
+ | R02 | mining logic を runtime 側へ分離 | `../runtime-palw/`, read-only CLI path | model を変更せず実行前後 manifest が一致した実モデル E2E | Complete |
35
+ | R03 | prompt 受付と runtime tokenizer token 数 | wrapper `--prompt-stdin`、Qwen adapter | 1 MiB/single-source gate、stdin child path、known vectors、live prefill=5/decode=2 | Complete |
36
+ | R04 | runtime manifest 取得・hash | `manifest.rs`, `qwen_profile.rs`, `artifact.rs` | canonical/mutation/rebuild test、実 hash `5920accc…2b84dd` | Complete |
37
+ | R05 | model profile 全固定 field | `manifest.rs`, `qwen_profile.rs` | official config/GGUF metadata fixture と mutation test | Complete |
38
+ | R06 | runtime class 全固定 field | `manifest.rs`, `qwen_profile.rs` | build/host/policy/artifact mutation が identity を変更 | Complete |
39
+ | R07 | deterministic policy 強制 | `deterministic.rs`, native header validation | invalid matrix、live `n_ctx=4096`/batch/ubatch/thread=1 | Complete |
40
+ | R08 | read-only observer | `observer.rs`, llama scheduler callback | 現行 binary で off/graph/sketch の token/output byte が短・長 prompt とも一致 | Complete |
41
+ | R09 | prefill/decode/layer/GEMM/attention/route/KV 観測 | native observer + strict Qwen adapter | dense profile、phase coverage、全 native event の live validation | Complete |
42
+ | R10 | complete/versioned canonical CU | `compute_units.rs`, adapter mapping v1 | unknown/overflow/全 op pricing test、live 5,868 ops = 14,562 CU | Complete |
43
+ | R11 | ordered operation schedule commitment | `scheduler.rs`, `adversarial.rs` | reorder/insert/delete/shape/CU mutation を拒否 | Complete |
44
+ | R12 | GEMM trace chain | `trace.rs`, graph fallback adapter | golden/mutation test、live 1,950 GEMM trace events/root | Complete |
45
+ | R13 | tile/shape/kernel/accumulator sketch | Metal graph fallback + CUDA V1 device observer / standalone V2 producer primitive + V3 schema/Rust binder + vendored MMVQ/FA-off attention hook | SM89でone-token 253 MMVQと72 attention GEMM+36 softmaxを合計361件取得し3回同一fingerprint。actual entry attributes/cubin release manifestとV2 bindingを検証済み。実機のlive 361×452B V3 transcriptを`--emit-records`で採取しRust `RawCudaTraceRecordV3::decode_strict`へ直接投入、authority-canonical recordsとfield単位で比較。**live callbackがauthority由来canonical identityを消費する接続を実装・実機検証済み:** smokeに`--authority-ids`を追加し、Rustが決定論的に導出した361×128B canonical identity table(operation/plan/physical-layout/attention-group)をcallbackがstampする。実機再実行で当該4 fieldのdivergenceが361/361/361/108→0/0/0/0となることを確認(env-gated test `live_rtx_transcript_is_authority_canonical_and_drives_the_receipt`、diagnostic/authority両モードで実データ固定)。残差はsketch(実GPU値、synthetic fixtureとの差)とkernel-identity 36件のみ。残: production authority serviceがこのidentity tableをlive供給する統合と、live-transcript attestation下でのReceipt発行 | In progress |
46
+ | R14 | salted output commitment | `commitment.rs`, `builder.rs` | opening、nonce/token/stop/output mutation test | Complete |
47
+ | R15 | owner commitment | `commitment.rs`, public schema | salt/key opening test、canonical/public Receipt secret scan | Complete |
48
+ | R16 | job/execution nullifier | `commitment.rs`, `state_store.rs` | domain/uniqueness/replay/restart/concurrency test | Complete |
49
+ | R17 | full `ComputeReceiptV1` fields | `receipt.rs`, `builder.rs` | strict round-trip、field mutation、713-byte live canonical envelope | Complete |
50
+ | R18 | Receipt signer | signed Ed25519 envelope + signer registry | sign/verify/tamper/version/key/algorithm/registry test。CLI の一時 key は production network 登録 identity ではない | Complete |
51
+ | R19 | Self Local validation | `verifier.rs`, `audit.rs`, `work_ticket.rs` | required evidence/opening/weight test + signed live Self Local Receipt | Complete |
52
+ | R20 | Self Replicated k=2 exact match | `matcher.rs`, `adversarial.rs` | compared-field/owner/credential/instance/self-pair/reuse mutation test | Complete |
53
+ | R21 | External Replicated request/escrow/settlement/bonus | `external_authority.rs` + schema-v4 escrow/command/terminal | signed exact funding/grant/terminal、scheduler request、k=2、state1..3 expiry refund、両prepared stateのslash cutoff、local atomic settlement+maturity+2 bond release+ticketを検証。prepared confirmation timeout/superseding terminal/recoveryは内部未実装。実rail/authority serviceとdistributed atomicityは外部 | In progress |
54
+ | R22 | future beacon selection | `audit.rs`, `future_beacon.rs` | signed network-scoped beacon、post-issuance full 256-bit selection、replay/revocation/durable transition test。delivery/governance service は外部 | Complete |
55
+ | R23 | re-execution match and maturity | `audit.rs`, durable replay、opaque `MatureEvidence` | pass/mismatch/timeout/restart/tamper gate は完了。production auditor、re-execution executor、beacon delivery orchestration なし | In progress |
56
+ | R24 | mature Receipt から Work Ticket のみ | opaque basis/grant + `WorkTicketV2` + mature-source bond links | raw bypass、epoch前倒し、required 1/2 bond release、unbonded rollback、再消費、restart、External atomic issueを検証。production admission/orchestrationは外部 | In progress |
57
+ | R25 | Self Local 0.25–0.5 weight policy | integer basis-point `WeightPolicyV1` | boundary、challenge/audited distinction、governance version test | Complete |
58
+ | R26 | replicated 1.0 と demand bonus | `WorkTicketV2`, signed demand-weight grant, atomic External settlement | weight/bonus cap/terms/grant bindingとsettled ticketを整数演算で検証。production grant governanceと実bonus railは外部 | In progress |
59
+ | R27 | canary、bond、slashing | `bond_authority.rs`, signed canary, schema-v4 bond/slash/appeal/health, `slash_proof.rs` typed-proof constructors | signed funding/lock、atomic canary pass/mismatch/timeout attribution、pass/OpeningMissing後のmaturity遅延・lock保持、order-independent slash allocation、accepted-epoch基準appeal/decision deadline・default-uphold、eligible unpaired expiry、conservation/restartを実装。`InvalidManifest`/`Equivocation`/`DuplicateExecution`のtyped-proof constructorとdurable orchestration (`StateStore::apply_fault_proof`) を`slash_proof.rs`に実装し、verifierと同一のsigner/assignment authority registryで署名済み受領を検証、worker-credentialをbondに束縛、offense idはorder-independentかつidempotent。unit 12 + integration 6でpositive/fail-closed/worker-mismatchを検証。残るは実authority serviceからの署名素材供給とgovernance/key distributionという外部境界のみ | In progress |
60
+ | R28 | fake token/runtime/output rejection | `verifier.rs`, `adversarial.rs` | nonce/prompt/output/runtime/request/network mutation suite | Complete |
61
+ | R29 | fork/dummy/schedule rewrite rejection | `matcher.rs`, `canary.rs`, `adversarial.rs` | dummy signer/assignment、fork identity、schedule mutation suite | Complete |
62
+ | R30 | Receipt duplication rejection | `state_store.rs` | receipt/nullifier/slot uniqueness、restart、race、rollback tests | Complete |
63
+ | R31 | Metal runtime class local E2E | pinned llama.cpp/Qwen3.6-35B-A3B、strict hybrid adapter、release issuer + separate verifier | 41/41 offload、schema-v4 encrypted/restored Receipt `8e2dd34b…6053f9`(`trace_evidence=metal_kernel`)、verifier exit 0 | Complete |
64
+ | R32 | CUDA runtime class compile/E2E | Qwen CUDA 37/37 offload + deterministic observer、V1/V2/V3 device transport、vendored MMVQ/FA-off attention hook、release manifest、Receipt/Bundle/SQLite V2 | RTX 4060 Ti/SM89で361-launch positive 3/3、Q4/Q6/QK/softmax/PV各reject-index、exact runtime attrs/cubin/DSO manifest、V2 stateless/restart/replay/rollbackを検証。live 361-record transcriptをRust verifierへ直接投入する経路を実装(smoke `--emit-records` + `RawCudaTraceRecordV3` decode + `build_with_material`)し、live recordのReceipt buildがfail-closedであることを実データで確認。**未統合:** (A) callbackがauthority由来canonical operation/plan/physical-layout IDを消費する接続(R13、上記4 identity fieldがdiverge)、(B) 配備済みgovernance/trust root(KMS)と承認済みNVIDIA replica/reproducibility matrix。1台のRTXは(B)を満たさない。production CMake gateは(A)(B)の両方を理由に発行拒否 | **In progress** |
65
+ | R33 | prompt/output/key/salt 非漏えい | stdin-only adapter、XChaCha20-Poly1305 `.palw.bundle`、strict key/file gate | canonical/bundle secret scan、strict public JSON v2 cross-check、separate-process restore、prompt text scan | Complete |
66
+ | R34 | operational install/reproduce docs | install/verify scripts、lockfiles、exact MSRV dependency pins、本 runbook | pinned clean procedure、4 target、Rust 1.81 locked gate 実行済み | Complete |
67
+ | R35 | tests、fmt、clippy、sanitizers | Rust 1.81 suite、CUDA host sanitizer + SM89 device CTests、vendored full-stream smoke、`../.github/workflows/palw-ci.yml` | 242 passed/2 ignored(244 discovered)、fmt/clippy/rustdoc/MSRV check、host 5/5、SM89 8/8、361-launch positive 3回 + 5 work-class negative、manifest Python 4/4を通過。remote CI、production authority E2E、replica/cross-driver reproducibility matrixは未達 | In progress |
68
+
69
+ ## 現行 gate summary
70
+
71
+ - Rust MSRV: Rust/Cargo 1.81.0 を実 install。open transitive range による edition-2024 manifest
72
+ incompatibility を `zeroize=1.8.1` / `base64ct=1.7.3` exact pin で解消し、`--locked` で検証。
73
+ library 144 passed + real-model 2 ignored、`tests/adversarial.rs` 12、`tests/bonded_maturity.rs` 3、
74
+ `tests/canary_durable.rs` 2、`tests/core_flow.rs` 3、`tests/cuda_trace_contract.rs` 13、
75
+ `tests/cuda_attestation_v3.rs` 10、`tests/cuda_release_manifest.rs` 9、
76
+ `tests/cuda_trace_v3_contract.rs` 9、`tests/external_bonded_settlement.rs` 2、
77
+ `tests/protocol_v2.rs` 14、`tests/receipt_v2_flow.rs` 6、`tests/restart_bundle.rs` 9、
78
+ `tests/slash_proof.rs` 6 passed、
79
+ 合計 **242 passed, 2 ignored**(244 discovered)。ignored 2件は
80
+ release/汚染親環境の手動 gate で
81
+ 2/2 passed。fmt と
82
+ `clippy --locked --all-targets -D warnings`、`rustdoc -D warnings` を通過。
83
+ - Metal: installer full device gateで全pin、Apple M1 Max、41/41 GPU offloadを再検証し、current final-v7
84
+ hybrid Qwen3.6-35B-A3B Self Local Receipt(`8e2dd34b…6053f9`、`trace_evidence=metal_kernel`)を署名、stateless verify、
85
+ strict round-trip、schema-v4 SQLite acceptまで完了。移行前 dense Qwen3-8B の final-v6、および
86
+ historical final-v5は当時の証跡としてのみ保持し、旧DBをsilent migrateしない。
87
+ - Persistence: V1 current sourceはapplication `PALW`、schema v4、full DDL fingerprint、foreign keys、
88
+ `synchronous=FULL`、WAL checkpointを検査する。receipt/audit/pairに加え、signed bond authority、assignment
89
+ lock/release/slash/appeal/health、signed canary、external authority/command/terminal、maturity bond links、
90
+ WorkTicketV2をrestart/rollback/adversarial testで検証する。checked-in final-v6 DBはcurrent schema v4、
91
+ final-v5 DBはhistorical schema v3であり、後者はcurrent verifier sourceのcontinuity inputではない。
92
+ CUDA V2は別application `PAL2`、別schemaでjob/receipt/encrypted bundleを原子的に保存し、receipt/
93
+ execution/assignment/job-slot replay、epoch rollback、torn transaction、schema mutationを拒否する。
94
+ - Bundle: private verification material は認証付き暗号化し、別 process verifier が exact filename、
95
+ owner/mode/link/inode、v2 marker、strict public JSON v2、current schema-v4 acceptance をfail-closedに照合する。
96
+ marker は非 keyed の crash-completion signal であり、単独の authenticity/authority evidence ではない。
97
+ - CUDA host: 通常host buildとAppleClang ASan+UBSanでABI C++、C header、V2/V3 golden codec、
98
+ producer descriptor、llama bridge、production rejection gateが各5/5通過し、Rust
99
+ `cuda_trace_contract` 13/13、`cuda_trace_v3_contract` 9/9、release manifest 9/9、
100
+ Receipt V2 flow 6/6もstrict
101
+ stream/binding/authority/adversarial caseを通過。
102
+ - CUDA device: Windows/WSL2のRTX 4060 Ti (`sm_89`)、CUDA toolkit 13.3.1/NVCC 13.3.73で
103
+ host 5 + device/collector 3 CTestsが8/8 non-skippedで通過。standalone producerはtrue segmented FP32
104
+ pre-epilogue accumulatorを取得し20回の独立実行が同一diagnostic fingerprintとなった。
105
+ Qwen observerも37/37 layer CUDA offload、`n_batch=n_ubatch=1`で同一event/result stream 6/6を確認。
106
+ さらにV3 hookをvendored Q4_K/Q6_K MMVQとFA-off QK/softmax/PVへ統合し、one-token
107
+ 361件(Q4_K 216、Q6_K 37、QK/softmax/PV各36)のpositive 3/3が同一canonical-record
108
+ fingerprintとなること、5 work classの先頭rejectionが各位置でfail closedになることを確認した。
109
+ exact symbol/runtime attributes/cubin/DSO release manifestもcreate/verify一致した。ただしlive smokeは
110
+ `diagnostic_only=true` / `receipt_authority=false` で、production署名Receiptではない。
111
+ - CI: workflow YAML は parse 済みで、push/PR の Rust 1.81 gate と Linux host ASan+UBSan、手動
112
+ self-hosted NVIDIA experimental job を定義する。remote Actions は未実行。V1 observer と
113
+ standalone producer の両device executableで return 77 を failure 扱いにするが、この job は
114
+ 明示的に `not R32` であり、定義だけでは
115
+ R32/R35 completion evidence にならない。
116
+
117
+ ## Completion rule
118
+
119
+ 文書 baseline を固定しても、
120
+ R13、R21、R23、R24、R26、R27、R32、R35 が `Complete` になり、true CUDA
121
+ producer accumulator/kernel identity、production scheduler/beacon/auditor/bond/external authority/payment services、
122
+ vendored Qwenのauthority-connected production E2E、認可済みreplica/reproducibility matrix
123
+ の証跡が揃うまで、設計書全体を完了とは扱わない。host
124
+ fixture、library-level state-machine test、skipped device test、Metal graph fallback は production
125
+ service や CUDA production gate の代替にならない。
docs/runbook.md ADDED
@@ -0,0 +1,493 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Qwen3.6-35B-A3B / llama.cpp 導入・検証 Runbook
2
+
3
+ この runbook は、固定済みの Qwen3.6-35B-A3B artifact と llama.cpp を clean checkout から
4
+ Apple Silicon の Metal runtime class へ導入し、署名済み Self Local Receipt を発行する
5
+ 手順を定義する。実モデル Receipt 発行まで実機検証済みなのは **Metal arm64**
6
+ である。CUDA は Windows/WSL2 の RTX 4060 Ti で Qwen offload、diagnostic observer、
7
+ standalone producer-accumulator primitive、same-backend vendored MMVQ V3 1-token diagnostic E2Eまで
8
+ 実機検証したが、実験 transport として分離しproduction Receipt は発行しない。
9
+
10
+ 対象モデルは Ollama registry の `huihui_ai/Qwen3.6-abliterated:35b-Claude-4.7`
11
+ (abliterated Qwen3.6-35B-A3B、GGUF `Q4_K_M`)である。これは linear-attention
12
+ (state-space / gated-delta-net)層と mixture-of-experts 層を組み合わせた hybrid 構成で、
13
+ pinned llama.cpp には qwen35moe loader/graph の互換修正
14
+ (`src/models/qwen35moe.cpp`)を PALW patch として加えている。
15
+
16
+ 固定値の正本は次の3ファイルである。
17
+
18
+ - `../config/runtime-pins.sh`: repository、revision、path、CMake 値、build target
19
+ - `../config/qwen3.6-35b-a3b-claude-4.7-base-metadata.sha256`: base metadata 7ファイルの SHA-256
20
+ - `../config/qwen3.6-35b-a3b-claude-4.7-profile.json`: 人間可読な model/runtime profile pin
21
+
22
+ ## 1. Metal arm64(現在サポート)
23
+
24
+ ### 1.1 前提条件
25
+
26
+ - Apple Silicon Mac(`uname -m` が `arm64`)。GGUF を全 GPU offload するため十分な
27
+ unified memory を推奨(Qwen3.6-35B-A3B `Q4_K_M` は約 24 GB。M1 Max 32GB で 41/41 layer
28
+ offload を確認済み)
29
+ - Xcode Command Line Tools または Xcode(C/C++/Metal toolchain を含む)
30
+ - `git`、CMake、`uv`、`rustup`
31
+ - 最低約 30 GB の空き領域(GGUF は 23,938,321,728 bytes = 約 24 GB)
32
+ - Ollama registry(`registry.ollama.ai`)と Hugging Face、GitHub への HTTPS 接続
33
+
34
+ macOS、SDK、AppleClang、GPU/Metal identity は runtime manifest に記録する。CMake 入力と
35
+ 上流 commit を固定しても、異なる toolchain が生成した binary の byte 列まで同一とは限らない。
36
+ そのため検証 script は各 binary の SHA-256 を表示し、Receipt 用 manifest は実際にロードした
37
+ observer と dylib 群を content-address する。
38
+
39
+ ### 1.2 clean checkout からの一括導入
40
+
41
+ project root で次を実行する。
42
+
43
+ ```sh
44
+ ./scripts/install.sh
45
+ ```
46
+
47
+ 変更予定だけを確認する場合は次を使う。installer は `eval` を使わず、実行予定の引数を
48
+ escape して表示する。
49
+
50
+ ```sh
51
+ ./scripts/install.sh --dry-run
52
+ ```
53
+
54
+ build host に Metal device がない場合だけ、file gate に用途を限定して probe を省略できる。
55
+
56
+ ```sh
57
+ ./scripts/install.sh --skip-device
58
+ ```
59
+
60
+ `--skip-device` は artifact の正しさを検査しても、Metal runtime class の実行可能性を証明
61
+ しない。実運用 node の acceptance では省略してはならない。並列数は必要に応じて
62
+ `--jobs N` で指定する。
63
+
64
+ installer は次を順番に行う。
65
+
66
+ 1. `uv sync --frozen` で lock 済み Python 環境を用意する。
67
+ 2. `ggml-org/llama.cpp` を clone し、commit
68
+ `12127defda4f41b7679cb2477a4b0d65ee6a0c8f` へ detached checkout し、
69
+ `patches/llama.cpp-palw-observer.patch`(qwen35moe loader/graph 修正 + observer +
70
+ ggml-metal kernel-dispatch hook)を適用する。
71
+ 3. **Ollama registry blob** から Qwen3.6-35B-A3B GGUF を取得する。model は
72
+ `huihui_ai/Qwen3.6-abliterated`、tag `35b-Claude-4.7`、URL は
73
+ `https://registry.ollama.ai/v2/huihui_ai/Qwen3.6-abliterated/blobs/sha256:$PALW_GGUF_REVISION`。
74
+ blob digest は GGUF 本体の SHA-256 に等しく、size(23,938,321,728)と SHA-256 を照合してから
75
+ atomic に確定する(`Qwen3.6-abliterated-35b-Claude-4.7-Q4_K_M.gguf`)。
76
+ 4. base metadata(7 files: `README.md`/`chat_template.jinja`/`config.json`/
77
+ `model.safetensors.index.json`/`processor_config.json`/`tokenizer.json`/
78
+ `tokenizer_config.json`)を HF `huihui-ai/Huihui-Qwen3.6-35B-A3B-Claude-4.7-Opus-abliterated`
79
+ revision `ac18882735d037f6074a7630eb68d85db8234c25` から取得する。
80
+ 5. `vendor/llama.cpp/build-palw` を Metal profile で configure し、`llama-cli`、
81
+ `llama-server`、`llama-tokenize`、`llama-palw-observer` の4 target を build する。
82
+ 6. install gate をすべて検証する。
83
+
84
+ > **モデルについて:** 対象は第三者の *abliterated* 変換(refusal 挙動を上流で削減)です。この
85
+ > runtime はモデルの安全性を主張せず、「pin された計算が走ったこと」だけを attest します。
86
+ > Genesis 正本モデルは公式 `Qwen/Qwen3.6-35B-A3B` からの決定的再変換にすべきで、この点は
87
+ > [`receipt-review-remediation.md`](receipt-review-remediation.md) #13 の残件です。
88
+
89
+ Hugging Face 取得は `uv` 環境の `huggingface_hub.snapshot_download` を使い、`revision` と
90
+ `allow_patterns` を指定する。download subprocess では `HF_HUB_DISABLE_XET=1`、implicit token
91
+ 無効化を使い、`HF_TOKEN` と `HUGGING_FACE_HUB_TOKEN` を除外する。script に token を書かず、
92
+ `set -x` で実行しない。
93
+
94
+ ### 1.3 固定 Metal build / execution profile
95
+
96
+ 主な CMake pin は次のとおりである。全項目は `../config/runtime-pins.sh` を正本とする。
97
+
98
+ ```text
99
+ CMAKE_BUILD_TYPE=Release
100
+ CMAKE_OSX_ARCHITECTURES=arm64
101
+ GGML_NATIVE=OFF
102
+ GGML_METAL=ON
103
+ GGML_METAL_EMBED_LIBRARY=ON
104
+ GGML_METAL_SHADER_DEBUG=ON
105
+ GGML_CPU_KLEIDIAI=OFF
106
+ GGML_LTO=OFF
107
+ GGML_CUDA=OFF
108
+ BUILD_SHARED_LIBS=ON
109
+ GGML_CPU=ON
110
+ GGML_ACCELERATE=ON
111
+ GGML_BLAS=ON
112
+ GGML_BLAS_VENDOR=Apple
113
+ LLAMA_BUILD_TESTS=OFF
114
+ LLAMA_BUILD_EXAMPLES=OFF
115
+ LLAMA_BUILD_TOOLS=ON
116
+ LLAMA_BUILD_SERVER=ON
117
+ LLAMA_BUILD_APP=OFF
118
+ LLAMA_BUILD_UI=OFF
119
+ LLAMA_OPENSSL=OFF
120
+ LLAMA_USE_PREBUILT_UI=OFF
121
+ ```
122
+
123
+ `llama-palw-observer` は `n_ctx=4096`、`n_batch=1`、`n_ubatch=1`、request batch=1、
124
+ parallel sequence=1、CPU thread と batch thread=1 を強制する。greedy sampling、固定 seed、
125
+ context shift/speculation/tensor parallel 無効、tensor repack 無効、Flash Attention 無効である。
126
+ prompt と prediction bound の合計が 4096 を超える実行は shift せず失敗する。Metal と CUDA で
127
+ 同じ build directory や CMake cache を共有してはならない。
128
+
129
+ ### 1.4 独立 install 検証
130
+
131
+ ```sh
132
+ ./scripts/verify-install.sh
133
+ ```
134
+
135
+ 検証 gate は次のとおりである。
136
+
137
+ - llama.cpp origin と full commit が pin と一致する。
138
+ - GGUF が 23,938,321,728 bytes かつ SHA-256
139
+ `1dc494614bee8a3bc00e79fe5a49da0fc1c36b3b118c4156e223e98e5a0a671b` である
140
+ (Ollama blob digest = GGUF 本体 SHA-256)。
141
+ - GGUF の revision sidecar、base metadata 7ファイル(HF `huihui-ai/...abliterated` rev
142
+ `ac18882735…`)の SHA-256 と revision が一致する。
143
+ - `config.json` の shape/dtype が profile pin
144
+ (`config/qwen3.6-35b-a3b-claude-4.7-profile.json`)と一致する。
145
+ - `CMakeCache.txt` の全必須値と source directory が一致する。
146
+ - 4 binary が `version: 10015 (12127def)` を報告し、それぞれの SHA-256 を取得できる。
147
+ - Metal device `MTL0` が発見・選択され、Qwen3.6-35B-A3B の 41/41 layers が GPU へ offload される。
148
+ - 固定 prompt による one-token probe が exit 0 になる。
149
+
150
+ `llama-palw-observer` binary の size/SHA-256 は toolchain と適用 patch(qwen35moe 修正 + observer +
151
+ ggml-metal kernel-dispatch hook)に依存して build ごとに変わり得るため固定 pin しない。正本は
152
+ `patches/llama.cpp-palw-observer.patch`(SHA-256 は `config/runtime-pins.sh` の
153
+ `PALW_LLAMA_PATCH_SHA256`)であり、Receipt 用 manifest は実際にロードした observer/dylib を
154
+ content-address する。worktree の HEAD は固定 commit のままで、patch の canonical digest を manifest
155
+ に含める。予期しない untracked/変更 file があれば Receipt CLI は fail-closed する。
156
+
157
+ device を使えない CI で file gate だけ確認する場合は、用途を限定して次を使う。
158
+
159
+ ```sh
160
+ ./scripts/verify-install.sh --skip-device
161
+ ```
162
+
163
+ 現行 Qwen3.6-35B-A3B の full device gate は Apple M1 Max の Metal device、**41/41 layer offload**、
164
+ 固定した artifact hash と upstream revision の全照合を通過した。現行 Receipt の一次証跡(発行
165
+ → 別 process 検証、`trace_evidence=metal_kernel`)は
166
+ [`evidence/metal-hybrid-qwen36-2026-07-19.md`](evidence/metal-hybrid-qwen36-2026-07-19.md)
167
+ に、移行前 dense Qwen3-8B の記録は
168
+ [`evidence/metal-smoke-schema-v4-2026-07-15.md`](evidence/metal-smoke-schema-v4-2026-07-15.md)
169
+ に記録する。
170
+
171
+ ### 1.5 native observer と strict Qwen adapter の手動確認
172
+
173
+ observer へ prompt を渡すときは argv ではなく stdin を使う。通常実行は
174
+ `--emit-output-bytes` を付けないため、JSONL result の `output_bytes` は空である。JSONL には
175
+ private な token IDs が含まれるため、その stdout を公開 artifact として保存してはならない。
176
+
177
+ ```sh
178
+ printf '%s' 'PALW' | \
179
+ vendor/llama.cpp/build-palw/bin/llama-palw-observer \
180
+ --model models/Qwen3.6-abliterated-35b-Claude-4.7/Qwen3.6-abliterated-35b-Claude-4.7-Q4_K_M.gguf \
181
+ --prompt-stdin --n-predict 2 --n-gpu-layers 999 --observer sketch
182
+ ```
183
+
184
+ Rust adapter は dedicated stdin pipe を作り、native stdout を versioned JSONL として厳格に読む。
185
+ schema、header/event/result の順序と個数、連続 sequence、Qwen3.6-35B-A3B shape、上記 deterministic
186
+ policy、full GPU offload marker、phase/token count、sketch width、trace claim の不一致を拒否する。
187
+ 既知の Qwen graph operation はすべて canonical CU operation へ変換し、layout-only metadata
188
+ だけを明示的に除外する。未知 operation、未価格 operation、CUDA kernel を偽る graph event は
189
+ fail-closed である。
190
+
191
+ ### 1.6 Rust 1.81 MSRV gate と release CLI
192
+
193
+ crate は `rust-version = "1.81"` を宣言する。検証中、crypto stack の open transitive range が
194
+ `zeroize 1.9` と `base64ct 1.8.3` を選び、両 crate の edition-2024 manifest を Cargo 1.81 が
195
+ parse できない矛盾を検出した。`Cargo.toml` は互換版 `zeroize = "=1.8.1"` と
196
+ `base64ct = "=1.7.3"` を exact pin し、`Cargo.lock` も同じ version に固定する。
197
+ 依存解決の再現性を検査するため clippy/test/build は `--locked` を必須にする。
198
+
199
+ ```sh
200
+ rustup toolchain install 1.81.0 --profile minimal --component rustfmt,clippy
201
+ cd runtime-palw
202
+ cargo +1.81.0 fmt --all -- --check
203
+ cargo +1.81.0 clippy --locked --all-targets -- -D warnings
204
+ cargo +1.81.0 test --locked --all-targets
205
+ cargo +1.81.0 build --release --locked \
206
+ --bin palw-metal-receipt --bin palw-verify-bundle
207
+ cd ..
208
+ ```
209
+
210
+ 現行のRust all-target結果は合計 **224 passed, 2 ignored**(226 discovered)である。ignored 2件は
211
+ pinned model/observer を必要とし、通常 CI が model download や Metal 実機を暗黙に要求しないため
212
+ 分離している。release build と汚染した親環境を使う手動 gate では 2/2 passed である。実モデル
213
+ Receipt E2E は本 runbook の次節と evidence 文書で別に検証する。
214
+
215
+ pedantic Clippy の `module_name_repetitions` だけは、protocol の versioned public API 名を module
216
+ 外でも自己記述的に保つ設計判断として crate level で allow する。他の warning は
217
+ `-D warnings` で失敗させる。
218
+
219
+ 実モデルで新しい Self Local Receipt set を生成する。audit key は exact 32-byte raw key とし、
220
+ output directory の外に一度だけ安全に作成・保管する。key file は current user 所有の single-link
221
+ regular file、mode `0400` または `0600` でなければならない。既存 key をこの手順で上書きしない。
222
+
223
+ ```sh
224
+ set -eu
225
+ OUT="receipts/manual-$(date +%Y%m%d-%H%M%S)"
226
+ PROMPT_FILE="/path/to/private-prompt.txt"
227
+ AUDIT_KEY="$HOME/.config/misaka-palw/audit-keys/local-audit.key"
228
+
229
+ install -d -m 700 "$(dirname "$AUDIT_KEY")"
230
+ test ! -e "$AUDIT_KEY"
231
+ (umask 077 && /usr/bin/openssl rand 32 > "$AUDIT_KEY")
232
+ chmod 600 "$AUDIT_KEY"
233
+
234
+ runtime-palw/target/release/palw-metal-receipt \
235
+ --prompt-stdin --audit-key-file "$AUDIT_KEY" \
236
+ --output-dir "$OUT" --n-predict 2 < "$PROMPT_FILE"
237
+ ```
238
+
239
+ `--prompt-stdin`、`--audit-key-file`、`--output-dir` はすべて必須である。prompt は UTF-8、非空、
240
+ 最大 1 MiB を要求し、argv で prompt を受ける互換 option はない。source の省略、重複 option、
241
+ 上限超過、zero/all-zero または不正 permission の audit key は inference または publication 前に
242
+ 拒否する。wrapper は受け取った prompt を pinned tokenizer と native observer の専用 stdin pipe
243
+ へ渡す。output directory は新規または空で、symlink ではなく current user 所有でなければならず、
244
+ CLI が mode `0700` を強制する。
245
+
246
+ job ID、nonce、salt、scheduler/worker signing key、network ID は OS CSPRNG からローカル実行ごとに
247
+ 生成されるため、Receipt ID は証跡例と同一にならない。これらの一時 identity は receipt set 内の
248
+ binding を検証するためのものであり、production network の登録済み scheduler/worker authority や
249
+ credential ではない。private signing key は publication 後に保持しない。
250
+
251
+ CLI は実行前後で model/runtime manifest を再構築して artifact 変更を検出し、署名済み request と
252
+ assignment、prompt/output opening、全 observer evidence、CU、schedule、graph trace を stateless
253
+ verify する。canonical binary を strict decode で round-trip し、secret scan を通過した後だけ
254
+ SQLite transaction で receipt/job/nullifier を受理する。private request/assignment、opening、owner
255
+ salt、検証用 signer record は XChaCha20-Poly1305 の `.palw.bundle` に認証付き暗号化する。Self Local
256
+ Receipt はこの時点では Work Ticket ではなく、future audit または challenge-window maturity が
257
+ 別途必要である。
258
+
259
+ 正常終了時の directory は同一 Receipt ID を basename とする次の set になる。
260
+
261
+ - `<id>.palw` (`0644`): 署名済み canonical public envelope
262
+ - `<id>.json` (`0644`): strict `misaka.palw.public-receipt.v2` metadata。unknown field を拒否し、
263
+ verifier が retained field を authenticated receipt/bundle と照合
264
+ - `<id>.palw.bundle` (`0600`): audit key で認証付き暗号化した private verification material
265
+ - `palw-state.sqlite3` (`0600`): application/schema identity と full DDL fingerprint を検査する schema v4 state
266
+ - `<id>.complete` (`0644`): `misaka.palw.receipt-set.v2` completion marker
267
+
268
+ CLI は WAL を main DB へ checkpoint/truncate し、DB と各 artifact を fsync して directory entry を
269
+ 永続化した後、marker を最後に作成・fsync する。したがって portable set は `-wal` / `-shm` file に
270
+ 依存しない。旧schemaや未知/legacy DBを暗黙にmigrateせずfail-closedに拒否する。
271
+
272
+ marker は receipt ID、bundle ID、公開 JSON byte 列の SHA-256 を bind し、crash 後に「前提 file を
273
+ 永続化してから publication を完了した」ことを示す。ただし marker 自体は keyed MAC でも network
274
+ authority の署名でもなく、directory を変更できる同一 user は再計算できる。marker 単独を artifact
275
+ authenticity、network authorization、maturity の根拠にしてはならない。
276
+
277
+ 別 process で artifact set を復元・再検証する。次は CLI が表示した ID を `.palw` basename から
278
+ 取得する単発 set 用の例である。
279
+
280
+ ```sh
281
+ RECEIPT="$(find "$OUT" -maxdepth 1 -type f -name '*.palw' -print)"
282
+ ID="$(basename "$RECEIPT" .palw)"
283
+
284
+ runtime-palw/target/release/palw-verify-bundle \
285
+ --receipt "$OUT/$ID.palw" \
286
+ --bundle "$OUT/$ID.palw.bundle" \
287
+ --public-json "$OUT/$ID.json" \
288
+ --audit-key-file "$AUDIT_KEY" \
289
+ --state-db "$OUT/palw-state.sqlite3"
290
+ ```
291
+
292
+ verifier は artifact の exact filename、同一 private directory、owner、mode、link count、distinct inode、
293
+ bounded read/path race、v2 marker、公開 JSON の全 field、暗号化 bundle の authentication、署名・
294
+ assignment・manifest・evidence/opening、既存 DB acceptance を照合する。正常時は
295
+ `status=local_restored` と `trust_scope=embedded_local_snapshot` を出力する。この local mode は
296
+ 発行時に暗号化した registry snapshot との continuity を示すだけで、後日の network revocation や
297
+ 外部 authority を独立に取得しない。production verifier は library の external-trust API へ current
298
+ network ID、scheduler/signer registry、approved manifest hash を別経路から与える必要がある。
299
+
300
+ 後段のticketingではrawな「mature」登録APIを使用しない。field/constructorが非公開の
301
+ `MatureEvidence`はSelf Local audit `Mature`またはSelf Replicated typed `MatchedReplicaPair`だけが
302
+ generic pathへ渡せる。Externalはgeneric registrationを拒否し、authority-confirmed durable settlement
303
+ transactionだけがmaturityを作る。`WorkTicketV2`はsourceに加えて`maturity_basis_id`と、Externalに必須の
304
+ authority-signed `weight_grant_id`をbindする。
305
+
306
+ production bonded pathではauthority-signed fundingをcreditし、scheduler-signed assignmentごとにlockして、
307
+ Receiptを`accept_bonded`で受理する。maturity登録はSelf Localで1件、replicatedで2件のactive assignment
308
+ bondを同じtransactionでrelease/linkする。`issue_ticket`はrequired link数、`issued_epoch >= mature_epoch`、
309
+ source未消費を再検査する。External settlementはsigned terminal confirmation、terminal、2 bond releases/
310
+ links、maturity、ticketを1 SQLite transactionでcommitする。External refundはstate 1..3からexpiry後にpairの
311
+ 有無を問わず進め、terminalとeligible bond releaseをatomicにcommitするがticketを作らない。pending claimの
312
+ bondは解決までreleaseしない。
313
+
314
+ expiry releaseは未使用assignmentに加え、acceptedでもまだpairを持たないSelf Replicatedだけをsigned expiry後に
315
+ 許す。pending canary/slash、paired receipt、Self Local、その他used assignmentはexpiry bypassを拒否する。
316
+ slash claimはinitial bond基準のimmutable targetを持ち、overlapを加算せずfinalized max-envelopeとpending
317
+ extensionへorder-independentにallocateする。appeal/decision windowはsigned claimed epochだけでなく、authority
318
+ registryでのverification/acceptance epochも期限内であることを要求する。Externalの
319
+ `SettlementPrepared` transitionは両assignmentがactiveでslash claimなしとpreflightする。
320
+ `SettlementPrepared`または`RefundPrepared`以後のnon-replay slashを拒否する。両prepared state後のauthority confirmation timeoutや
321
+ superseding terminalはないため、production運用はauthority availabilityとprepared-state recovery手順を
322
+ crate外で用意する。
323
+
324
+ これらはcore APIとdurable transitionの手順であり、production service一式を含まない。repository内には
325
+ network scheduler/worker registry service、beacon delivery/governance、auditor/re-execution executor、
326
+ bond/external authority governance service、payment railがない。signed funding/terminalは外部factの
327
+ authenticated statementであり、実collateral/rail movementをcrateが独立証明しない。railとSQLiteは
328
+ distributed atomic transactionではない。
329
+ したがって library test の成功やローカル生成 identity を production maturity/payment evidence として
330
+ 扱わず、該当する要件は [`requirements.md`](requirements.md) の `In progress` のままである。
331
+
332
+ 永続 store を検査する。
333
+
334
+ ```sh
335
+ sqlite3 "$OUT/palw-state.sqlite3" \
336
+ 'PRAGMA user_version; PRAGMA integrity_check; PRAGMA foreign_key_check;
337
+ SELECT COUNT(*) FROM receipts; SELECT COUNT(*) FROM jobs;'
338
+ ```
339
+
340
+ current sourceの正常な単発実行はschema version `4`、`ok`、foreign-key violationなし、receipt `1`、job
341
+ `1`を返す。
342
+ store は `SQLITE_OPEN_NOFOLLOW`、WAL、`synchronous=FULL`、foreign keys、full sqlite_master DDL
343
+ fingerprint、transactional uniqueness を強制し、restart、競合 accept、rollback、pair/ticket/slash/
344
+ external terminal state を Rust test で検証する。
345
+
346
+ current schema-v4 証跡は `../receipts/final-v6/` にあり、Receipt ID は
347
+ `eb51b08c3b86ef5df2cdebcfa9fcef812ec72197b3ad40ae2c5ba68cf4278131`、bundle ID は
348
+ `359f1bedaeefc1e140bf8c0dbba11582cb5cc0be428dcd95bc6077721f8096e9` である。canonical
349
+ envelope 713 bytes、bundle 403,066 bytes、公開 JSON 3,427 bytes、marker 262 bytes、SQLite
350
+ 282,624 bytes。SHA-256 は順に `85ecb4281a1cb4abf26d6e3e70c84bfb3cc2a6dad80e2022ea4a356165345a75`、
351
+ `b475193fcfe1aea3189066790f925cc3682d2ff5a48cdfa061d62db85d0cff78`、
352
+ `03bee886144a2c64dd5f4d2207f86c748f5a3e7891b43f82f077f051342c3d0b`、
353
+ `f3dc4e142eb602977c1ac065d51297418c8dca3967b6cdb53eb0dfb447d5c77b`、
354
+ `8a740c342a12c83ae211edfa8776b93a14ea9369e3d7bd19a1e780e0724c471e` である。separate verifier は
355
+ exit 0、`status=local_restored`、`trust_scope=embedded_local_snapshot` を返した。DB は application
356
+ `PALW` (`1346456663`)、schema v4、`integrity_check=ok`、foreign-key violationなし、receipt=1、job=1、
357
+ pair/audit/ticket/slash/external state=0で、最終検証後に `-wal` / `-shm` は残っていない。詳細は
358
+ [`evidence/metal-smoke-schema-v4-2026-07-15.md`](evidence/metal-smoke-schema-v4-2026-07-15.md)
359
+ を参照する。
360
+
361
+ historical schema-v3証跡は`../receipts/final-v5/`にあり、Receipt IDは
362
+ `ab2b3196a6c0935aafd4d563a9d2e1d71d828cc87a378ae77b8e49c102033b68`、bundle ID は
363
+ `6fd4e57a6cbcd6fc1d9138989960b627c9ee4817bc3ac4ce889a1a1b41d7d63b` である。canonical
364
+ envelope 713 bytes、bundle 337,257 bytes、公開 JSON 3,427 bytes、marker 262 bytes、SQLite
365
+ 126,976 bytes。separate verifier は exit 0、`status=local_restored`、
366
+ `trust_scope=embedded_local_snapshot` を返した。生成当時のDBはapplication `PALW`、schema v3、
367
+ `integrity_check=ok`、foreign-key violation なし、receipt=1、job=1、その他 state table=0 で、
368
+ 最終 verifier 後に `-wal` / `-shm` は残っていない。詳細は
369
+ [`evidence/metal-smoke-2026-07-15.md`](evidence/metal-smoke-2026-07-15.md) を参照する。
370
+ current schema-v4 sourceはこの旧DBをsilent migrate/openしないため、final-v5をcurrent verifierのcontinuity
371
+ testへ流用しない。final-v6は新しいempty output directoryから生成したcurrent E2E証跡である。
372
+
373
+ ### 1.7 冪等性と異常 artifact の扱い
374
+
375
+ installer は commit、content hash、size、Hub revision が一致する artifact を再利用する。既存の
376
+ GGUF または metadata が期待 hash と異なる場合は、上書きや削除をせず停止する。対象を調査・
377
+ 保全し、必要なら別名へ移してから再実行する。
378
+
379
+ ```sh
380
+ mv models/Qwen3.6-abliterated-35b-Claude-4.7/Qwen3.6-abliterated-35b-Claude-4.7-Q4_K_M.gguf \
381
+ models/Qwen3.6-abliterated-35b-Claude-4.7/Qwen3.6-abliterated-35b-Claude-4.7-Q4_K_M.gguf.rejected
382
+ ./scripts/install.sh
383
+ ```
384
+
385
+ 途中で停止した Hugging Face の `.incomplete` cache は download library が再開に利用するため、
386
+ 手動削除を前提にしない。Git worktree が固定 commit 以外で dirty な場合も自動 checkout しない。
387
+
388
+ ## 2. CUDA(実験的・production 非発行)
389
+
390
+ `../runtime-palw/cuda/`の汎用device observerはGEMM/attention deterministic final-output tile sketch、
391
+ checked C ABI/canonical V1 codec、capacity/sequence/stream/poison stateを実装する。additive V2 transportは
392
+ origin、accumulator stage/dtype、sketch scheme、reduction segment、producer variant IDを含むexact
393
+ 184-byte canonical recordを定義し、Rustが全unfiltered streamをexpected dispatch/runtimeへstrict bindする。
394
+
395
+ standalone V2 producer primitiveは、実のCUDA test kernel内でFP32 segmented accumulatorをepilogue/store前に
396
+ 捕捉する。exact function pointer/attributes、launch nonce、compiled identity、sample coverage、fault maskを
397
+ fail-closedに検証する。Rustはさらにnetwork-scoped authority attestationをjob/execution、assignment、
398
+ runtime manifest/class/instance、producer integration、operation schedule、full transcript、epochへ署名bindする。
399
+
400
+ vendored llama.cppのQ4_K/Q6_K MMVQ producerはV3 full-K pre-epilogue hookへ接続済みである。
401
+ same-backend Qwen 1-token diagnostic E2Eで253/253 record(Q4_K 216 / Q6_K 37)、3回同一
402
+ fingerprintを確認した。FA-off attentionのcanonical 3-sublaunch grouping/strict binderと、実QK-score/
403
+ softmax/value-aggregation直後collector/typed associationも接続し、QK 36、softmax 36、PV 36を加えた
404
+ 361/361 recordを3回同一fingerprintで取得した。Q4/Q6/QK/softmax/PV各先頭の選択launch拒否も
405
+ fail closedである。exact entry symbols/runtime attributes/cubin/DSO release manifest、361 expected tableを
406
+ 検証するReceipt/RuntimeManifest/Request/Assignment V2、暗号化Bundle V2、SQLite V2も実装済みである。
407
+ ただしlive callback���diagnostic IDであり、production authorityからのReceipt発行には使用しない。
408
+ `ComputeReceiptV1` への変換はbuilder/verifierの両方が拒否する。
409
+
410
+ CUDA のない host では ABI、codec、header、production rejection gate だけを検証する。
411
+
412
+ ```sh
413
+ cmake -S runtime-palw/cuda -B build/palw-cuda-host \
414
+ -DPALW_CUDA_TRACE_ENABLE_CUDA=OFF -DBUILD_TESTING=ON
415
+ cmake --build build/palw-cuda-host
416
+ ctest --test-dir build/palw-cuda-host --output-on-failure -L host
417
+ ```
418
+
419
+ AppleClang host ABI/codec を ASan+UBSan でも確認する場合は次を使う。この macOS ASan は leak
420
+ detection 非対応のため `detect_leaks=0` とし、これは LeakSanitizer の代替証跡ではない。
421
+
422
+ ```sh
423
+ cmake -S runtime-palw/cuda -B build/palw-cuda-sanitize \
424
+ -DPALW_CUDA_TRACE_ENABLE_CUDA=OFF -DBUILD_TESTING=ON \
425
+ -DCMAKE_BUILD_TYPE=Debug \
426
+ -DCMAKE_C_FLAGS='-Wall -Wextra -Wpedantic -Werror -fsanitize=address,undefined -fno-omit-frame-pointer' \
427
+ -DCMAKE_CXX_FLAGS='-Wall -Wextra -Wpedantic -Werror -fsanitize=address,undefined -fno-omit-frame-pointer'
428
+ cmake --build build/palw-cuda-sanitize
429
+ ASAN_OPTIONS=detect_leaks=0:abort_on_error=1 \
430
+ UBSAN_OPTIONS=halt_on_error=1 \
431
+ ctest --test-dir build/palw-cuda-sanitize --output-on-failure -L host
432
+ ```
433
+
434
+ production 発行を有効化する構成は意図どおり失敗しなければならない。
435
+
436
+ ```sh
437
+ cmake -S runtime-palw/cuda -B build/palw-cuda-production \
438
+ -DPALW_CUDA_PRODUCTION_KERNEL_TRACE=ON
439
+ ```
440
+
441
+ NVIDIA host での実験 transport の device test は次で行う。exact CUDA toolkit、driver、NVCC、
442
+ cuBLAS、GPU model/compute capability、単一 `CMAKE_CUDA_ARCHITECTURES`、test 出力を保存する。
443
+
444
+ ```sh
445
+ cmake -S runtime-palw/cuda -B build/palw-cuda -DBUILD_TESTING=ON \
446
+ -DCMAKE_CUDA_ARCHITECTURES=89-real
447
+ cmake --build build/palw-cuda
448
+ ctest --test-dir build/palw-cuda --output-on-failure
449
+ ```
450
+
451
+ 現行証跡はWindows/WSL2、RTX 4060 Ti (`sm_89`)、driver 610.62、CUDA toolkit 13.3.1 /
452
+ NVCC 13.3.73で取得した。standalone CTestsは7/7 non-skipped、standalone producerは
453
+ 20回の独立実行で同一encoded-transcript diagnostic fingerprintとなった。同じhostのQwenは
454
+ 37/37 layerをGPU offloadし、dedicated observerは`n_batch=n_ubatch=1`で6/6同一event/result
455
+ streamを返した。最終grouped suiteは8/8 non-skipped、vendored MMVQ/attention same-backend gateは
456
+ 361/361 V3 recordと3回同一fingerprintを返した。
457
+ 詳細は[`evidence/cuda-wsl-sm89-2026-07-15.md`](evidence/cuda-wsl-sm89-2026-07-15.md)と
458
+ [`evidence/cuda-v3-mmvq-hook-sm89-2026-07-15.md`](evidence/cuda-v3-mmvq-hook-sm89-2026-07-15.md)と
459
+ [`evidence/cuda-v3-full-hook-sm89-2026-07-16.md`](evidence/cuda-v3-full-hook-sm89-2026-07-16.md)に固定する。
460
+
461
+ これによりNVIDIA実機不足というR32の外部blockerは解消したが、R32自体は未完了である。
462
+ vendored MMVQ/FA-off attention diagnostic hook、361-launch実機E2E、release manifest、Receipt V2/
463
+ bundle/persistenceは完了したが、R32のproduction完了にはauthority-derived canonical physical-layout IDを
464
+ 使うlive callback、deployed trust roots、署名Receiptの独立restore、認可済みreplica/reproducibility matrixが
465
+ 必要である。CUDA は Metal と異なる
466
+ `runtime_class_id` とし、cross-runtime determinism が別途証明されるまで k=2 replica として
467
+ 直接照合しない。
468
+
469
+ ## 3. CI gate 定義
470
+
471
+ [`../.github/workflows/palw-ci.yml`](../.github/workflows/palw-ci.yml) は checkout action を
472
+ commit SHA で固定し、credential persistence を無効化し、read-only contents permission を設定する。
473
+ push/PR は同じ event/ref の旧 run を cancel するが、manual NVIDIA run は event 名で分離して
474
+ cancel しない。push / pull request では次の2 job を定義する。
475
+
476
+ 1. Ubuntu 24.04 に Rust 1.81.0、rustfmt、Clippy を install し、`fmt`、
477
+ `clippy --locked --all-targets -D warnings`、`test --locked --all-targets` を実行する。
478
+ 2. Linux host-only CUDA ABI/codec/production-rejection gate を ASan+UBSan、leak detection 有効、
479
+ warning-as-error で build/test する。
480
+
481
+ 手動 `workflow_dispatch` で `run_nvidia_experimental=true` を選んだ場合だけ、
482
+ `self-hosted, linux, x64, nvidia` label の runner で exact real SM architecture を指定し、experimental
483
+ CUDA transport を build/test する。`CUDA_VISIBLE_DEVICES=0` に固定し、`nvidia-smi` の実 compute
484
+ capability が選択した single `*-real` architecture と一致しなければ configure 前に失敗する。
485
+ V1 observer と standalone producer の両device executableを CTest 経由ではなく直接実行
486
+ するため、device/driver 不在を表す return code 77 は skip ではなく job failure になる。
487
+
488
+ この manual job は `PALW_CUDA_PRODUCTION_KERNEL_TRACE=OFF` であり、workflow 名にも `not R32` を
489
+ 明記する。成功すれば final-output observer と standalone true-accumulator primitive を検査
490
+ できるが、repositoryの別実測で完了したMMVQ hookを���のmanual job自体は検査しない。
491
+ repositoryの別実測で完了したvendored-Qwen MMVQ+attention full stream、release manifest、Receipt V2も
492
+ このjob自体は検査しない。またproduction authority接続と必要なrepeatability matrixは満たさない。
493
+ workflow 定義の存在自体も runner での成功証跡ではないため、R32/R35 の未達 gate を解除しない。
docs/security-model.md ADDED
@@ -0,0 +1,269 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Security Model
2
+
3
+ ## Protected assets
4
+
5
+ - model artifact、tokenizer、runtime binary/dylib/source patch の同一性
6
+ - prompt、prompt/generated token IDs、decoded output、owner key、commitment opening、audit key の秘匿性
7
+ - token count、operation schedule、canonical CU、graph/kernel trace の完全性
8
+ - scheduler request/assignment、job/execution nullifier、Receipt の一回性
9
+ - replica、audit、escrow、bond/slashing、Work Ticket の状態遷移
10
+
11
+ ## Trust and issuance boundary
12
+
13
+ 単一の自己申告 Receipt は、悪意ある host に対する独立な暗号学的 proof ではない。本プロトコルは
14
+ 次を組み合わせて不正コストを上げる。
15
+
16
+ - content-address された model/runtime manifest と Ed25519 scheduler/worker signature
17
+ - 同一 runtime class 内の独立 credential/runtime instance による k=2 exact match
18
+ - Receipt 発行後の future beacon による再実行 audit
19
+ - authority-signed funding、scheduler-signed assignment lock、conserved durable bond accounting、appeal
20
+ - scheduler-signed hidden precommitを期限後に開き、worker/scheduler timeoutを分離するdurable canary
21
+ - transactional replay、pair、audit、bond/slash/health、maturity、WorkTicketV2、external settlement registry
22
+
23
+ schema-v4 coreではこれらの多くがSQLite transactionで接続された。bonded Receipt acceptance、audit/canary
24
+ slash、maturity時bond release/link、External settlementからticketまでのlocal atomicityを持つ。ただし
25
+ production scheduler/auditor/authority/payment service全体をrepository内で実装したわけではない。
26
+
27
+ 現行 Metal Self Local path は signed Receipt を発行できるが、evidence は `graph_fallback` であり
28
+ CUDA kernel proof ではない。mature weight には future audit または challenge window が必要である。
29
+ 現行CLIはscheduler/worker keyとregistry snapshotをlocalに生成するため、その出力だけからproduction
30
+ scheduler authorizationやnetwork admissionを推論してはならない。
31
+
32
+ future-audit state、signed beacon provenance、audit replay、passing maturityはSQLiteへdurableに保存する。
33
+ ただしfinalized beaconの取得/governance、独立auditorへのassignment、model re-execution、private opening
34
+ deliveryは外部serviceのtrust boundaryである。crate内のlocal authority registryはnetwork consensusや
35
+ beacon finalityを実装しない。
36
+
37
+ CUDA code はadditive 184-byte V2 codecとstrict full-stream/dispatch/runtime binderを持つが、raw recordの
38
+ declared producer originはtransport metadataであってproofではない。authority署名をnetwork/job/execution/
39
+ assignment、runtime class/manifest、producer integration、operation schedule commitment、全scheduled
40
+ GEMM/attention coverage、full transcriptへbindし、producer
41
+ accumulator GEMMだけをReceipt V2 evidenceへ射影するtypestateも実装した。ただしV1にはこの
42
+ provenanceをcommitするfieldがないため、builderとverifierはCUDA `KernelSketch`をともに拒否する。
43
+ この署名は登録authorityによるexact transcript/integrationの承認をauthenticateするが、authorityの正しさや
44
+ GPU register由来を単独で暗号学的に証明しない。
45
+
46
+ standaloneのproducer-internal FP32 accumulator採取primitiveはWSL2 Ubuntu 24.04上のRTX 4060 Ti(sm_89)、CUDA Toolkit
47
+ 13.3.1 / nvcc 13.3.73で最終grouped device suite 8/8とproducer 20/20同一diagnostic fingerprintを通過した。固定Qwenも
48
+ 37/37 layer CUDA offloadとgraph observer 6/6同一diagnostic streamを確認済みである。vendored llama.cppの
49
+ Q4_K/Q6_K MMVQ producerはV3 full-K pre-epilogue hookへ接続済みで、same-backend 1-token diagnostic
50
+ E2Eは253/253 recordを取得する。V3 schema/binderはFA-off eager attentionのcanonical groupingを表現し、
51
+ 3 stageのwork直後collectorとtyped associationも接続済みである。合計361 launchを3回同一fingerprintで
52
+ 取得し、5 work classの拒否を確認した。exact symbol/runtime attributes/cubin/DSO release manifest、
53
+ Receipt/RuntimeManifest/Request/Assignment V2、暗号化Bundle V2、SQLite V2も実装・検証済みである。
54
+ ただしlive callbackはauthority-derived canonical physical-layout IDではなくdiagnostic IDを使用するため、
55
+ trace/producer production capability、vendor integration、Receipt mappingの各macroは0、production
56
+ CMake optionはconfigure時に失敗する。したがって
57
+ R32は`In progress`だがCUDA Receiptは発行不可である。
58
+
59
+ host OS、driver、GPU firmware まで敵対的とみなす場合は、TEE attestation または ZK/VC を追加
60
+ しなければならない。この v1 はその主張を行わない。
61
+
62
+ ## Threat controls
63
+
64
+ | Threat | Primary controls | Fail condition |
65
+ |---|---|---|
66
+ | Fake token count | pinned runtime tokenizer IDs、prefill/decode graph step consistency、opening、audit | count/token vector/phase step が不一致 |
67
+ | Fake runtime | model/binary/dylib/source/build/host digest、manifest ID、allowlist | digest、class、実行前後 manifest が不一致 |
68
+ | Fake output | salted output commitment、signed shared nonce、replica/audit opening | nonce、token、stop reason、再実行 output が不一致 |
69
+ | Replay | domain-separated job/execution nullifier、SQLite unique constraint | receipt/nullifier/job slot が既に受理済み |
70
+ | Forked runtime | manifest digest、signed assignment、canary、independent runtime instance | 未許可 digest、credential/instance 重複、canary failure |
71
+ | Dummy execution | strict non-empty event stream、full event/token coverage、trace、replica/audit | event 欠落、unknown op、required evidence 不足 |
72
+ | Schedule rewrite | ordered hash chain、event count、CU、Receipt signature | reorder/insert/delete/shape mutation で chain または CU 不一致 |
73
+ | Receipt duplication | receipt/execution/job-slot uniqueness、pair/ticket one-shot state | duplicate accept、pair reuse、二重 ticket 化 |
74
+ | Trace forgery | manifest capability、strict graph claim、trace root/count、replica/audit | CUDA claim、scheme、root、count、tile metadata が不一致 |
75
+ | Secret leakage | stdin child pipe、output-byte omission、private opening schema、pre-write scan | canonical Receipt に prompt/token/key/nonce/salt bytes が出現 |
76
+ | Bundle substitution | receipt/public/AAD binding、XChaCha20-Poly1305 tag、strict decode | receipt/bundle/public digest、nonce、tagが不一致 |
77
+ | Incomplete output set | checkpoint/fsync、marker-last、core JSON field cross-check | marker欠落・ID/hash不一致(marker自体はunkeyedでauthenticity controlではない) |
78
+ | Local trust escalation | DB exact restoreとexternal anchored stateless pathの分離 | embedded key snapshotだけで第三者authorityを主張 |
79
+ | CUDA async failure | permanent poison、committed-count barrier、production gate | poisoned/pending/overflow context または非発行 capability |
80
+ | External funding/weight forgery | network-scoped authority capability、signed exact funding/grant、canonical replay ID | key/network/asset/amount/grant/epoch/signature不一致 |
81
+ | External double settlement | stable payment command、signed terminal confirmation、single durable terminal | command/distribution/pair/amount/epoch不一致、逆terminal、conflicting replay |
82
+ | Canary false slash | scheduler-signed precommit、atomic receipt acceptance、fault-party timeout attribution | precommit/request/assignment/window不一致、opening未到達、scheduler opening timeout |
83
+ | Bond funding/slash replay | signed funding event、typed primary proof、conservation reconciliation、appeal state | event/offense/canonical payload conflict、account/assignment/evidence不一致 |
84
+ | Dependency/MSRV drift | exact crypto pins、lockfile、Rust 1.81 all-target CI | lock変更、MSRV manifest parse失敗、lint/test failure |
85
+ | Premature Work Ticket | opaque maturity basis、required bond release links、WorkTicketV2、atomic one-shot issue | raw claim、epoch前倒し、bond link不足、grant不一致、source再消費 |
86
+
87
+ ## Cryptographic rules
88
+
89
+ - hash は SHA3-256 とし、用途ごとの domain separation と version を必須にする。
90
+ - 可変長 field は canonical length-prefix し、曖昧な連結を禁止する。
91
+ - Receipt、manifest、request、assignment、future beacon、canary precommit、bond/external authority
92
+ evidence、verification bundle はstrict versioned canonical formだけを署名・hash/AEAD binding対象にする。
93
+ - output nonce、owner salt、private key seed は OS CSPRNG から 32 bytes 生成し、zero を拒否する。
94
+ - replica 用 output nonce は scheduler-signed request で共通指定し、worker による差し替えを防ぐ。
95
+ - prompt commitment も signed shared nonce、network、job、runtime tokenizer IDs に binding する。
96
+ - key ID、algorithmと署名をenvelopeに明記し、public keyはregistryから解決する。Receipt、scheduler
97
+ message、future beacon、canary precommit、bond/external authorityのEd25519検証は`verify_strict`を使い、
98
+ small-order/weak public keyを各registryへの登録時と検証時に拒否する。bond authorityはfunding/appeal/
99
+ decision、external authorityはfunding/demand-weight/terminalのcapabilityを分離する。
100
+ - verification bundle はXChaCha20-Poly1305(256-bit derived key、192-bit random nonce、128-bit tag)を
101
+ 使い、receipt binding、public digest、nonce、canonical public sectionをAADへbindする。caller-owned
102
+ raw audit keyとprivate signing-key seedはbundleへserializeしない。
103
+ - replay/cardinality/terminal transition は process-local set ではなく durable transaction で確定する。
104
+ - MSRV gate、Clippy、test、release build は committed lockfile を使い、open transitive range が
105
+ toolchain 非互換 manifest を silent に選ばないようにする。
106
+
107
+ ## Privacy rules
108
+
109
+ canonical Receipt と公開 JSON に prompt、raw output、prompt/generated token IDs、owner public key、
110
+ output nonce、owner salt、private key、accumulator 全体を含めない。公開 JSON は commitment、digest、
111
+ non-secret identifier/counter/protocol label、CU、artifact/observer summary、filename、privacy flagを記録する。
112
+ 後述のlocal verifierがsemanticに照合するのはその一部である。
113
+
114
+ Receipt CLI は必須の `--prompt-stdin` を使い、UTF-8/非空/1 MiB 上限を inference 前に検査する。
115
+ `--prompt TEXT` は廃止され、unknown optionとして拒否する。CLIはさらに `--audit-key-file` を必須とし、
116
+ exact 32-byte nonzero key、owner、single link、regular-file、mode `0400`/`0600`、symlink/path race/inode
117
+ alias/output directory内配置をfail-closedに検査する。
118
+ Rust adapter は prompt を tokenizer/native child argv、stderr、error text に置かず専用 stdin pipe
119
+ で渡す。通常の Receipt 実行は native observer の `--emit-output-bytes` を使わないため decoded
120
+ output bytes は IPC result にも含まれない。ただし native JSONL は wrapper 内部で
121
+ prompt/generated token IDs を opening として運ぶため、この local pipe と process memory は
122
+ trusted privacy boundary である。debug QA で output bytes を明示的に有効化した stream を公開
123
+ ログへ流してはならない。
124
+
125
+ verification bundleのpublic sectionにはreceipt binding/ID、verification epoch、scheduler public-key
126
+ snapshot、manifest、execution evidenceを置く。worker public keyを含むsigner record、signed
127
+ request/assignment、output nonce、prompt/generated token IDs、stop reason、owner saltはencrypted private
128
+ sectionだけに置く。private signing-key seedとaudit keyはoutput artifactへ保持/serializeしない。CLI はcanonical bytesの
129
+ strict round-tripとprompt/token/key/nonce/salt scanを通過してからだけ`create_new`で書く。audit keyの
130
+ rotation/backup、bundle/openingのretention/deletionはcallerの運用責任で、このcrateに自動retention policy
131
+ はない。
132
+
133
+ tokenizer、observer、host/source identity helperは inherited environment を消去し、`LANG=C` と
134
+ `LC_ALL=C`だけを設定する。このallowlistはmanifestへbindされ、host identity helperはabsolute pathで
135
+ 起動する。ただしsame-user debugger、process memory reader、malicious host kernelからlocal openingや
136
+ audit keyを保護するattestationは提供しない。
137
+
138
+ ## Durable-state rules
139
+
140
+ SQLite store は WAL、`synchronous=FULL`、foreign key、application ID、schema version 4を検証する。
141
+ table/column/foreign-key/index集合に加え、non-internal `sqlite_master` の完全な
142
+ `(type,name,tbl_name,sql)`列をcanonical SHA3-256 fingerprintで照合する。旧schemaをsilent migrateせず、
143
+ 既存objectを持つunclaimed DBも拒否する。Receipt ID、execution nullifier、job/replica slot、pair
144
+ membership、future audit/replay、bond funding/account/assignment/release/slash/appeal/health、signed canary、
145
+ maturity source/assignment link、Work Ticket v2、external escrow/payment command/terminalをunique constraintと
146
+ transactionで守る。
147
+
148
+ raw maturity flag を受ける public store API は持たない。original receiptの`accepted_at_epoch`、pairの
149
+ `matched_epoch`、signed beaconのclaimed epoch/key ID/canonical envelope、audit replayのissued/accepted
150
+ epochを保存し、epoch rollbackを拒否する。beaconを検証したcaller current epochは保存せず、restore時に
151
+ current `AcceptedReceipt.verified_at_epoch`とauthority registryから再確立する。selected auditは
152
+ audit-specific replay identityの一回予約、typed
153
+ projection verdict、terminal state、passing maturity sourceを同一transactionで確定し、non-selected
154
+ auditもwindow maturityとsource登録を同一transactionで確定する。bond rowがあるaudit pathとSelf
155
+ Replicated pathはmaturityと同じtransactionでrequired assignment bondをrelease/linkする。Work Ticketは
156
+ その`mature_epoch`より前には発行できず、job classに必要なrelease link数を満たすsourceだけを一度消費する。
157
+
158
+ bond fundingはauthority-verified typestateだけをcreditし、funding event ledgerとaccount buckets、active
159
+ assignment remaining、pending/finalized slash、healthをread/transition時にreconcileする。lockはexact
160
+ scheduler-signed assignmentにbindする。bonded assignmentのReceiptをgeneric `accept`で受けず、
161
+ `accept_bonded`または`accept_canary`のatomic pathを要求する。audit mismatch/timeoutとcanary mismatch/
162
+ receipt timeoutはtransition自身からtyped primary proofを作り、slash accountingを同じtransactionに含める。
163
+ 各claimはinitial bond基準のimmutable targetを持ち、finalized max-envelopeを優先してpending extensionだけを
164
+ allocateする。overlapを加算せず、equal/weaker/strongerの到着順やreverse後にも全claimから再計算する。
165
+ v1のEquivocation追加penaltyは0である。
166
+
167
+ authority-verified appealはpending offense/worker/assignment/deadlineへexact bindする。signed submissionと
168
+ appeal verification/acceptance epochをappeal window内に��求し、decision windowは後者から開始する。signed
169
+ decision epochとdecision verification/acceptance epochもdeadline内でなければならない。期限経過後は
170
+ default-uphold、appealがなければappeal deadline後のfinalizationだけを認める。exact canonical replayは
171
+ idempotent、同じbusiness IDのconflicting payloadはfatalである。
172
+
173
+ pendingまたはuphold/default-final claimを持つassignmentからmaturity/ticketを生成しない。全claim解決後、
174
+ audit mismatch/timeout terminalはclaim reversal時も残額を`SlashResolved`
175
+ releaseする。canary fault terminalはmatching claimがuphold/default-finalの場合だけreleaseでき、reversed
176
+ canary claim単独では解放しない。External refundもrelease terminalであり、state 1..3からexpiry後にpairの
177
+ 有無を問わず確定できる。eligible bond残額はrefund terminalでreleaseするが、pending claimを持つbondは解決まで
178
+ lockedに残す。expiry releaseは未使用またはaccepted-unpaired SelfReplicatedだけを許し、pending canary/slash、paired、Self Local、その他used
179
+ assignmentを拒否する。`fault_event_epoch`とdurable `applied_epoch`を分離し、terminal epoch/proofは
180
+ offense-sortedな完全claim/terminal fact setとmax effective epochからcanonicalに導出する。
181
+
182
+ scheduler-signed canary precommitはactive lockとcanonical envelopeを保存する。normal Receipt insertと
183
+ `ReceiptSubmitted`はatomicである。pass terminal、mismatch/slash、receipt-missing worker slash、opening-
184
+ missing scheduler fault/no-worker-slashをそれぞれ一transactionで確定する。passとopening-missingはbondを
185
+ releaseせず、pending canary中のmaturityを拒否する。terminal後のmature epochをcanary completion以後へ
186
+ 遅延し、maturity transactionだけが`Mature` release/linkを行う。
187
+
188
+ External settlementはauthority-verified funding/grant、scheduler request、k=2 pair、stable command、signed
189
+ terminal confirmationを順にbindする。settlement confirmationはterminal、maturity、両worker bond release/
190
+ link、WorkTicketV2を一SQLite transactionでcommitする。refundはterminalとeligible bond releaseをatomicに
191
+ commitするが、maturity/ticketを生成せず、pending claimのbondは解決までreleaseしない。
192
+ `SettlementPrepared` transitionは両bondがactiveでpending/upheld/default-final slashなしと同じtransactionで
193
+ preflightする。`SettlementPrepared`または`RefundPrepared`以後のnon-replay slashを拒否する。
194
+
195
+ restartでは`restore_audit`がselected pass/mismatch terminalを`AuditReplayRequired`で拒否する。
196
+ `restore_selected_audit_with_replay`だけがstored challenge/canonical replayと全identity/epochを再照合し、
197
+ 再計算したmatch bit、submission commitment、completed epochをdurable terminalへexact比較する。
198
+
199
+ DB file の possession は signer authorization を代替しない。受理前の stateless verifier が署名、
200
+ request/assignment、manifest/evidence/opening を検証し、その typestate と canonical bytes だけを
201
+ store へ渡す。
202
+
203
+ 発行時はowned non-symlink output directoryを`0700`に固定し、Receipt/公開JSON/completion markerを
204
+ `0644`、暗号化bundle/DBを`0600`にする。DBはWAL `TRUNCATE` checkpoint、connection drop、main-file
205
+ `fsync`を完了してからpublic artifactsを書き、各fileを`fsync`した後にmarkerを最後に作ってdirectoryを
206
+ `fsync`する。marker v2はreceipt ID、bundle ID、公開JSON SHA-256を記録する。これはcross-file atomic
207
+ renameではないためlate failureでpartial setは残り得るが、local verifierは全protected artifactの
208
+ same-directory/expected filename/mode/owner/type/link count、exact marker、typed公開JSON
209
+ `misaka.palw.public-receipt.v2`全体がsigned Receiptと
210
+ authenticated bundle manifest/evidenceへ一致しないsetを拒否する。unknown fieldも全階層で拒否する。
211
+
212
+ markerはunkeyed plain textでsignature/AEAD protectionを持たず、same-owner writerは公開JSONとmarkerを
213
+ 一緒に置換できる。しかしverifierは保持する`artifacts`と`observer_summary`を含むtyped文書全体を
214
+ authenticated dataから再構成してexact照合するため、markerを書き直しても改変JSONは受理されない。
215
+ marker/JSONはcompletenessとhuman-readable projectionのboundaryであり、canonical Receiptとauthenticated
216
+ bundleのauthorityを代替しない。
217
+
218
+ `verify_bundle_and_restore`はembedded snapshotsで再検証した後、既存DB rowへのexact continuityだけを
219
+ 認め、missing rowをinsertしない。第三者用`verify_bundle_stateless_with_trust`は外部scheduler/signer
220
+ registry、expected network、approved manifest hashを必須とし、embedded snapshotをauthorityにしない。
221
+ 後者はbundle-bound historical `verification_epoch`でのstateless verificationであり、present-time network
222
+ acceptanceやdurable replay reservationではない。
223
+
224
+ fresh APIはcaller-selected epochがbundleのhistorical verification epoch���上であることを要求する。
225
+ `verify_bundle_and_restore_at_epoch`はlocal embedded snapshotsでfresh `AcceptedReceipt`を作りoriginal durable
226
+ acceptance epochを保持するが、bundle作成後のrevocationは学習できない。
227
+ `verify_bundle_stateless_at_epoch_with_trust`はexternal rootsでfresh stateless typestateを作るがDB continuityを
228
+ 検査しない。production restartではcurrent external rootsと既存DB rowを同時に検査する
229
+ `verify_bundle_and_restore_at_epoch_with_trust`を使う。future audit restoreではepochをbeacon以上にし、
230
+ present-time network admissionは別途判断する。現行CLIはhistorical default restoreだけを呼び、fresh epochは
231
+ library/service APIで指定する。
232
+
233
+ ## Residual risks
234
+
235
+ - greedy decode でも driver/kernel/toolchain 差により bitwise output が変わり得る。
236
+ - Metal graph-level logical-prefix sketch は lossy で、CUDA kernel/accumulator trace より弱い。
237
+ - observer callback の read-only access は timing と synchronization を変え得る。
238
+ - k=2 replica が同一所有者・同一障害 domain なら共謀耐性がない。
239
+ - external registry/finality serviceが供給するfuture beaconが予測・操作可能ならaudit samplingが弱くなる。
240
+ - auditor scheduling、model re-execution、opening deliveryはcrate外であり、durable audit stateだけでは
241
+ independent replayの運用を保証しない。
242
+ - bond/external authority registryのproduction governance、key distribution、revocation deliveryはcrate外で、
243
+ 同梱in-memory registryはnetwork consensusではない。
244
+ - signed funding/terminal evidenceはauthorityのstatementをauthenticateするが、実collateralやpayment railを
245
+ crateが独立観測したproofではない。rail movementとlocal SQLite commitはdistributed atomicではない。
246
+ - External `SettlementPrepared`/`RefundPrepared`後にauthority confirmationが来ない場合のtimeoutや
247
+ superseding terminalはなく、prepared stateのoperational recoveryは外部serviceに依存する。
248
+ - durable canaryはscheduler opening欠落をscheduler faultとしてworker slashから分離するが、production
249
+ schedulerのprecommit/opening deliveryとavailabilityはcrate外である。
250
+ - durable slashへ自動接続済みなのはaudit mismatch/timeoutとcanary mismatch/receipt timeoutである。
251
+ invalid-manifest、equivocation、duplicate-executionのproduction typed proof/orchestrationは未統合である。
252
+ - legacy in-memory `BondLedger`、`CanaryRecord`、`ExternalEscrow` helperはraw caller mutationを許すため、
253
+ schema-v4 signed/durable authority pathの代用にしてはならない。
254
+ - `future_audits.state=4`はpublic transitionではdeadlineを保持するが、SQL constraint単独では
255
+ `deadline_epoch NOT NULL`を要求しない。constraint-validなDB corruptionはload/release時にfail closedとなるが、
256
+ schema-level hardening余地が残る。
257
+ - CU table は実時間・電力を表さず、versioned governance の対象である。
258
+ - encrypted bundleはaudit keyを取得したsame-user/malicious hostからopeningを守らず、key backup/rotation/
259
+ retentionも自動化しない。
260
+ - CI workflowやRTX実機でのvendored MMVQ diagnostic hook/E2E成功も、FA-off attentionの361-launch実機coverage、
261
+ production-approved kernel manifest identity、authority-bound full-stream verification、Receipt V2を代替せず、
262
+ R32 production acceptance authorityを与えない。
263
+
264
+ production scheduler/network transport、governance key distribution、beacon/authority service、payment rail、
265
+ NVIDIA CUDAのfull production issuance pathも未統合である。
266
+
267
+ これらは runtime class 分離、independent identity、future beacon finality、versioned CU policy、
268
+ bond/slashing、source統合済みFA-off attention hookの実機full-stream検証、release manifest authorityと
269
+ attestation/proof layerで緩和する。
docs/state-machines.md ADDED
@@ -0,0 +1,551 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # PALW State Machines and Policy V1
2
+
3
+ 本書は現行 `runtime-palw` が実際に持つtypestate、legacy in-memory helper、schema-v4 SQLite stateを
4
+ 区別して記述する。receipt/audit/canary/bond/external/maturityの主要transitionはdurable transactionで接続
5
+ されたが、production scheduler/auditor/authority/payment service全体を実装した単一lifecycle daemonはない。
6
+
7
+ ## 1. Receipt verification and durable acceptance
8
+
9
+ 実装済みの型遷移:
10
+
11
+ ```text
12
+ canonical bytes / SignedReceiptV1
13
+ |
14
+ v
15
+ UnverifiedReceipt
16
+ | verify_stateless(...)
17
+ v
18
+ StatelesslyVerifiedReceipt
19
+ | StateStore::accept (SQLite transaction)
20
+ v
21
+ AcceptedReceipt
22
+ ```
23
+
24
+ `verify_stateless` は body/signature、scheduler-derived assignment authorization、manifest、
25
+ schedule/CU/trace、prompt/output openingを検証する。`StateStore::accept` はその後にのみ receipt ID、
26
+ execution nullifier、job class、replica slotと`accepted_at_epoch`を永続予約し、成功した値だけを
27
+ `AcceptedReceipt`へ昇格する。process restart後は同じcanonical signed receiptとruntime instanceで
28
+ 再度stateless verifyし、`restore_accepted`でoriginal acceptance epochを保持したtypestateを復元する。
29
+ この値はrestart時の`verified_at_epoch`と区別される。
30
+
31
+ exact assignmentのbond rowが存在するReceiptをgeneric `accept`へ渡すと
32
+ `BondedReceiptRequiresAtomicAcceptance`になる。production bonded pathはactive lockとのworker/request/
33
+ assignment/class/slot/runtime/epoch bindingを同じtransactionで検査する`accept_bonded`を使う。canaryは
34
+ 後述の`accept_canary`を使い、Receipt insertとcanary state更新の間のcrash gapを作らない。
35
+
36
+ 現行DBには `Received`、`Rejected`、`AwaitingBeacon` 等のreceipt lifecycle列はない。したがって
37
+ genericな `Received -> ... -> Ticketed` CAS machineやtransition logは未実装である。拒否は各APIの
38
+ errorであり、Rejected rowを保存しない。
39
+
40
+ ### Self Local path
41
+
42
+ ```text
43
+ AcceptedReceipt
44
+ -> AuditRecord::new
45
+ -> authority-signed future beacon verify/apply
46
+ -> StateStore::store_audit_selection
47
+ -> StateStore::complete_selected_audit
48
+ または StateStore::mature_unselected_audit
49
+ -> assignment bond release/link(bonded path)
50
+ -> StateStore::issue_ticket -> WorkTicketV2
51
+ ```
52
+
53
+ `AuditRecord::new` はexact `AcceptedReceipt`からnetwork、receipt ID、issued/accepted epoch、job/requestを
54
+ bindする。beacon適用後のselectionとsigned beacon provenanceは`future_audits`へ保存する。selected path
55
+ では`complete_selected_audit`がaudit-specific replay identity、typed projection verdict、terminal state、
56
+ passing maturity sourceを1 transactionで確定する。non-selected pathでは
57
+ `mature_unselected_audit`がchallenge-window maturityとsource登録を1 transactionで確定する。
58
+ rawなprojection match boolやlocal maturity markerをstoreへ渡すpublic APIはない。bonded sourceならpassing
59
+ maturityと同じtransactionでassignmentを`Mature` releaseしてsourceへlinkし、mismatch/timeoutならtyped
60
+ slashを同じtransactionで適用する。historical unbonded Self Local rowはmatureになり得るが、required bond
61
+ release linkがないためWork Ticket発行gateを通らない。
62
+
63
+ ただしfinalized future beaconの取得/governance、independent auditor assignment、model再実行、encrypted
64
+ opening配送は外部serviceのtrust boundaryである。durable state machineがそれらのproduction serviceを
65
+ 実装したことにはならない。
66
+
67
+ ### Restart verification bundle
68
+
69
+ Receipt CLI は `--prompt-stdin` とoutput directory外の `--audit-key-file` を必須にする。argv promptの
70
+ `--prompt TEXT`は存在しない。bundle public sectionはreceipt binding/ID、verification epoch、scheduler
71
+ key snapshot、manifest、execution evidenceを含み、worker public keyを含むsigner record、signed
72
+ request/assignment、prompt/output opening、owner saltはXChaCha20-Poly1305 private sectionへ暗号化する。
73
+
74
+ 発行setはoutput directory `0700`、Receipt/公開JSON/marker `0644`、bundle/DB `0600`。DBをWAL
75
+ `TRUNCATE` checkpointし、DBと各fileを`fsync`した後、receipt ID、bundle ID、公開JSON SHA-256を記録する
76
+ marker v2を最後に書く。cross-file atomic commitではないため途中artifactは残り得るが、markerのない
77
+ setはcompleteではない。markerはunkeyed plain textで、crash-completeness signal以上のauthorityを持たない。
78
+
79
+ local `verify_bundle_and_restore` はembedded key snapshotsでstateless verificationをやり直し、既存DBの
80
+ exact accepted rowだけをrestoreする。local CLIは`--public-json`も必須とし、全artifactのsame private
81
+ directory/expected filename/mode、marker v2、typed公開JSON `misaka.palw.public-receipt.v2`全体を検査する。保持する`artifacts`と
82
+ `observer_summary`はauthenticated bundle manifest/evidenceから再構成してexact照合し、extra fieldは
83
+ ��階層で拒否する。same-owner writerはJSONとmarkerを一緒に置換できるが、改変JSONはこの照合を通らない。
84
+ canonical Receipt/authenticated bundleをauthorityとする。missing rowを
85
+ insertしない。external
86
+ `verify_bundle_stateless_with_trust`はexpected network、external scheduler/signer registry、approved
87
+ manifest hashを必須にするDBなしのpathで、embedded snapshotsをauthorityにせず、bundle-bound historical
88
+ `verification_epoch`を検証する。present-time admissionとdurable acceptは行わない。
89
+
90
+ future beacon後のrestoreには`verify_bundle_and_restore_at_epoch`がcaller-selected epochをhistorical値
91
+ 以上へ進め、original durable acceptance epochを保持したfresh `AcceptedReceipt`を返す。ただしembedded
92
+ snapshotはlater revocationを学習しない。productionはcurrent external rootsとDB continuityを同時に検査する
93
+ `verify_bundle_and_restore_at_epoch_with_trust`を使う。statelessだけなら
94
+ `verify_bundle_stateless_at_epoch_with_trust`を使う。全fresh APIはepoch rollbackを拒否する。現行verifier
95
+ CLIはhistorical default pathだけを呼ぶため、fresh epochはlibrary/service APIで指定する。
96
+
97
+ ### Replicated path
98
+
99
+ ```text
100
+ AcceptedReceipt(slot 0) + AcceptedReceipt(slot 1)
101
+ -> K2Matcher::match_pair
102
+ -> MatchedReplicaPair
103
+ -> StateStore::store_pair
104
+ -> MatureEvidence::from_self_replicated_pair
105
+ -> StateStore::register_mature_evidence
106
+ -> assignment bonds 2件をatomic release/link
107
+ -> StateStore::issue_ticket -> WorkTicketV2
108
+ ```
109
+
110
+ matcher は2 Receiptのprojectionとreceipt/execution/signer/credential/owner/assignment/runtime-instanceの
111
+ 独立性を検査する。`current_epoch`は両receiptのissued、original accepted、current verified epoch以上、
112
+ expiry以下でなければならない。DBはpair本体と2 memberを同一transactionで保存する。
113
+ `MatchedReplicaPair` はmatchに使った`current_epoch`をprivate `matched_epoch`として保持し、durable
114
+ canonical pairにもcommitする。public constructorがその値をmaturity epochとしてopaque evidenceへ
115
+ 封入する。rawなpair maturity登録APIは存在せず、`register_mature_evidence`はstored pairの
116
+ network/class/CU/matched epochとtyped evidenceを照合する。さらにpair member 2件からassignment IDを再取得し、
117
+ 両方がauthority-funded active lockでなければsource登録transaction全体をrollbackする。成功時は2件を
118
+ `Mature` releaseしてsourceへlinkする。replay/restart時は同じlinksを再利用し、ticketは一回だけ発行できる。
119
+
120
+ External Replicatedではpublic maturity registrationを拒否し、authority-confirmed durable settlement
121
+ transactionだけがmaturity、2件のbond release/link、WorkTicketV2を作る。詳細は第6節を参照する。
122
+
123
+ ## 2. Scheduler messages
124
+
125
+ 現行実装は job/assignment の operational lifecycle table を持たない。実装されているのは immutable
126
+ signed-message validation である。
127
+
128
+ ```text
129
+ JobRequestV1 --scheduler Ed25519--> SignedJobRequestV1
130
+ |
131
+ +-- exact network/model/runtime/shape/evidence/epoch/escrow policy
132
+ v
133
+ AssignmentV1 --scheduler Ed25519--> SignedAssignmentV1
134
+ |
135
+ +-- request binding, slot, credential, runtime instance, epoch containment
136
+ v
137
+ AssignmentAuthorizationRecord
138
+ ```
139
+
140
+ - scheduler key は network-scoped registry、valid-from/through、revocationで検証する。Ed25519は
141
+ `verify_strict`を使い、weak/small-order key recordを拒否する。
142
+ - Self Localはslot 0、replicatedはslot 0/1だけ。
143
+ - replicated requestは`GemmTraced`を要求する。
144
+ - assignment validity intervalはrequest interval内でなければならない。
145
+ - receipt verifierはassignmentのepochをexact一致でbindし、current epochが範囲外なら拒否する。
146
+
147
+ `Requested/Scheduled/Running/Cancelled` 状態、scheduler queue、assignment cancellation、renewalは
148
+ このcrateの状態機械にはない。cancelled stop reasonもwire protocolにはない。現行Receipt CLIはlocal
149
+ scheduler keyを自己生成するため、production scheduler/network transportとの統合は別途必要である。
150
+
151
+ ## 3. Future audit
152
+
153
+ `AuditRecord` の実装済み遷移:
154
+
155
+ ```text
156
+ AwaitingBeacon
157
+ | apply_beacon(VerifiedFutureBeacon)
158
+ +--> NotSelected { mature_epoch }
159
+ | | StateStore::mature_unselected_audit(current >= mature_epoch)
160
+ | +--> Mature { ChallengeWindowElapsed } + mature source (atomic)
161
+ |
162
+ +--> Selected { challenge/beacon authority/deadline }
163
+ | complete_selected_audit(distinct StatelesslyVerifiedReceipt)
164
+ | before/equal deadline; typed projection match
165
+ +--> Mature { SelectedAuditPassed } + replay + source (atomic)
166
+ |
167
+ | typed projection mismatch before/equal deadline
168
+ +--> FailedMismatch + replay (atomic)
169
+ |
170
+ | expire_selected_audit(current_epoch > deadline)
171
+ +--> FailedTimeout
172
+ ```
173
+
174
+ `SignedFutureBeaconV1`はversion/network/epoch/value body��authority key ID、Ed25519 signatureをstrict
175
+ canonical decodeする。network-scoped authority registryはkey validity/revocation/weak keyを検査し、
176
+ `verify_strict`成功後だけraw constructorを持たない`VerifiedFutureBeacon`を返す。beacon epochはverification
177
+ 時点以下かつoriginal receiptのissued epochとdurable accepted epochの両方より後でなければならない。
178
+ beacon finalityとauthority registry governanceはcaller側serviceの責任である。
179
+
180
+ selection は `(network, receipt, beacon_epoch, beacon_value)` の256-bit digestと固定256-bit thresholdの
181
+ strict `<` 比較。v1 thresholdは一様digestの1/16、selected response windowは2 epoch、non-selected
182
+ challenge windowは5 epochで、完全なfixed policyをpolicy IDへhashする。`store_audit_selection`はoriginal
183
+ receiptのissued/accepted epoch、job/request binding、policy ID、beacon ID/value/authority key、canonical
184
+ signed beacon、challenge/deadlineまたはmature epochを保存する。
185
+
186
+ selected replayはnormal receipt slotへacceptせず、audit-specific `audit_replays` table/typestateへ一度だけ
187
+ 予約する。replayはbeacon後にissuedされ、submit epochがreplay issued/current stateless verified epoch以上、
188
+ deadline以下でなければならない。originalとreplayはsame network/job/requestかつdistinct receipt、execution
189
+ nullifier、assignment、runtime instance、signer key、worker credential、owner commitmentである。
190
+ `VerifiedReplayVerdict`自身が両`MatchProjectionV1`を比較するため、external callerはraw match boolを作れない。
191
+
192
+ restart時の`restore_audit`はstored rowとoriginal `AcceptedReceipt`をexact照合し、canonical signed beaconを
193
+ current authority registryで再検証し、selection/challenge/deadlineを再計算する。selected pass/mismatch
194
+ terminalは`restore_audit`単独では`AuditReplayRequired`になり、
195
+ `restore_selected_audit_with_replay`がaudit rowとcanonical replay、全identity、issued/accepted epochを
196
+ restoreし、match bit、submission commitment、completed epochをstored terminalへexact比較する。
197
+ なお、prompt/opening配送、auditor assignment、model実行そのもの、auditor service identityはこのcrate外
198
+ である。
199
+
200
+ ## 4. Canary
201
+
202
+ canary は通常の signed request/assignment/Receipt を使い、Receipt bodyに markerを追加しない。
203
+ 期待projectionはsalt付きcommitmentだけを先に公開する。v1ではSelf Local/Self Replicatedだけを許し、
204
+ paid External Replicated requestをhidden scheduler probeに転用しない。
205
+
206
+ ```text
207
+ SignedCanaryPrecommitV1
208
+ | scheduler registry + request + assignment + active bond verify
209
+ v
210
+ AwaitingReceipt (durable)
211
+ | accept_canary(StatelesslyVerifiedReceipt), now <= receipt_deadline
212
+ +--> ReceiptSubmitted + normal Receipt row (atomic)
213
+ | | valid opening, opening_epoch <= now <= opening_deadline
214
+ | +--> Passed, no slash (bond remains locked)
215
+ | +--> FailedMismatch + typed CanaryFailure slash (atomic)
216
+ | |
217
+ | +-- now > opening_deadline
218
+ | --> TimedOut { OpeningMissing, scheduler fault }, no slash
219
+ | (bond remains locked)
220
+ |
221
+ +-- now > receipt_deadline
222
+ --> TimedOut { ReceiptMissing, worker fault } + typed CanaryFailure slash
223
+ ```
224
+
225
+ precommit bodyはnetwork、canary/job/request/assignment/worker、expected commitment、created/receipt/opening
226
+ windowをbindし、`canary-precommit/v1` IDをschedulerがstrict Ed25519署名する。registry keyはbody creation
227
+ からopening deadlineまで有効で、verification epoch時点にrevokedであってはならない。完全なorderingは
228
+ 次である。
229
+
230
+ ```text
231
+ assignment.issued <= created <= receipt_deadline <= assignment.expires
232
+ < opening_epoch <= opening_deadline
233
+ ```
234
+
235
+ `register_verified_canary`はcanonical signed precommitをactive healthy assignment bondへbindし、同じ
236
+ assignmentの既存Receipt、別canary、External classを拒否する。`accept_canary`はnetwork、worker、job、
237
+ request、assignmentとdeadlineを検査し、normal replay/cardinality reservationと`ReceiptSubmitted`を
238
+ `BEGIN IMMEDIATE` transactionで確定する。
239
+
240
+ 不正なsalt/projection openingはstateを変えずerrorとし、schedulerの壊れたopeningをworker slashへ
241
+ 変換しない。valid commitment opening後のprojection mismatchだけがworker faultである。receipt欠落は
242
+ worker action欠落、opening欠落はscheduler action欠落とdurableに記録し、後者はworkerを不健康化/
243
+ slashしない。passとOpeningMissingはassignment bondをreleaseせず、pending canaryがある間はmaturityを
244
+ 拒否する。terminal後のsource maturityはcanary completion epoch以上へ遅延し、そのmaturity transactionが
245
+ bondを`Mature` release/linkする。明示expiryは未使用またはaccepted-unpaired SelfReplicatedだけに許し、
246
+ pending canary/slash、paired、Self Local、その他used assignmentを拒否する。terminal proof、fault party、
247
+ deadline、projection digestをschema constraintとload時のsemantic validationで再検査する。
248
+ legacy in-memory `CanaryRecord` helperは残るが、production authority pathはこのsigned/durable APIである。
249
+
250
+ ## 5. Bond and slashing
251
+
252
+ authoritative pathはschema-v4 SQLite accountである。network-scoped bond authority registryはEd25519 keyの
253
+ validity/revocationとfunding/appeal/decision capabilityを分離する。`VerifiedBondFunding`はnetwork、worker、
254
+ funding event、asset、exact amount/finality epochをbindし、canonical signed envelopeだけをcreditできる。
255
+ same event/envelope replayはidempotent、same IDのconflicting payloadはfatalである。
256
+
257
+ ```text
258
+ authority-signed finalized funding
259
+ -> available
260
+ -> lock_verified_assignment(scheduler-signed request + assignment)
261
+ -> locked assignment
262
+ +-- verified maturity --> Released + mature-source link
263
+ +-- eligible signed expiry --> Released
264
+ +-- typed fault --> immutable claim + derived pending allocation + unhealthy
265
+ +-- no appeal after deadline --> finalized_slashed
266
+ +-- verified appeal
267
+ +-- signed Uphold --> finalized_slashed
268
+ +-- signed Reverse --> allocation recompute
269
+ +-- decision deadline elapsed --> default Uphold
270
+ ```
271
+
272
+ assignment lockはexact scheduler-signed request/assignmentをcurrent registryで検証し、uniqueかつjob class
273
+ minimum以上、account healthy、epoch内でなければならない。bonded assignmentのReceiptはgeneric acceptを
274
+ 拒否し、active lockを同一transactionで検査する。release reasonは`Mature`、`Expired`、
275
+ `CancelledBeforeExecution`、`SlashResolved`である。public durable pathで自動生成するのはmaturity、未使用または
276
+ accepted-unpaired SelfReplicatedのexpiry、全slash claim解決後のtyped fault/refund terminal releaseである。
277
+ pending canary/slash、paired receipt、Self Local、その他used assignmentはexpiry releaseを拒否する。
278
+
279
+ account snapshot/transitionは次に加え、funding event合計、active assignment remaining、slash status別合計、
280
+ healthをDB ledgerから再計算する。
281
+
282
+ ```text
283
+ available + locked + pending_slashed + finalized_slashed == total_funded
284
+ sum(assignment.remaining_amount) == locked
285
+ sum(verified funding event.amount) == total_funded
286
+ sum(pending/final slash.allocated_amount) == pending_slashed/finalized_slashed
287
+ ```
288
+
289
+ default policy:
290
+
291
+ | SlashReason tag | Reason | Assignment bond slash | Additional penalty |
292
+ |---:|---|---:|---:|
293
+ | 1 | `InvalidManifest` | 100% | 0 |
294
+ | 2 | `AuditMismatch` | 100% | 0 |
295
+ | 3 | `Equivocation` | 100% | 0 |
296
+ | 4 | `DuplicateExecution` | 50% | 0 |
297
+ | 5 | `CanaryFailure` | 100% | 0 |
298
+ | 6 | `AuditTimeout` | policy値、default 25% | 0 |
299
+
300
+ 割合はinitial assignment amountにceil適用したimmutable claim targetである。allocationは全claimから
301
+ order-independentに再計算する。finalized(uphold/default uphold)のmax-envelopeを優先し、pendingはその
302
+ extensionだけを受けるため、overlapを加算しない。late equal/weaker claimは既存envelopeに覆われれば0、
303
+ stronger claimはdeltaだけをallocateする。reverseも同じ再計算を行う。partial target後のremainderはactive
304
+ lockとして残り、pendingまたはuphold/default-final claimを持つassignmentはmaturity/Work Ticketを生成しない。
305
+ reverseはそのclaim allocationを0へ再配分するが、既存finalized envelopeをpendingへ戻さない。全claim解決後、
306
+ audit mismatch/timeout terminalはreverse時も`SlashResolved` releaseし、canary fault terminalはmatching claimが
307
+ uphold/default-finalの場合だけreleaseする。reversed canary claim単独ではreleaseしない。External refundも
308
+ release terminal、eligible unpaired SelfReplicatedはexpiry、別のstronger claimは追加deltaへ進める。
309
+ durable offense IDはreason、assignment、worker、policy、typed primary
310
+ proofへbindし、attachment追加は同じoffenseへidempotent mergeする。audit mismatch/timeoutとcanary
311
+ mismatch/receipt timeoutはstate transition自身がproofを作るため、callerはreason/raw hashからこれらの
312
+ slashを捏造できない。invalid manifest、equivocation、duplicate executionのproduction proof wiringは未完了。
313
+
314
+ `fault_event_epoch`はtyped proofが示す発生時刻、`applied_epoch`はdurable claim受理時刻として別に保存する。
315
+ late equal/weaker/stronger claimはpending-full state 2にも保存できるが、fully finalized/exhausted state 3は
316
+ 新claimを拒否する。terminal epoch/proofはoffense ID順の全claim、各effective epochのmax、typed terminal fact
317
+ setからcanonicalに導出する。audit/canary terminalとExternal prepared/terminalは新evidence cutoffで、
318
+ Externalは`SettlementPrepared`または`RefundPrepared`以後のnon-replay slashを拒否する。
319
+
320
+ standard policyのappeal deadlineはdurable slash `applied_epoch`から100 epochである。signed
321
+ `submitted_epoch`とappeal verification epochの両方をinclusive window内に要求し、後者をdurable
322
+ `accepted_epoch`として保存する。decision deadlineはそのaccepted epochから100である。
323
+ `VerifiedSlashAppeal`はnetwork/worker/offense/assignment/appeal ID/submitted epochをbindする。
324
+ `VerifiedSlashDecision`はappeal/offense、`Uphold|Reverse`、decided epochをbindし、signed decided epochと
325
+ decision verification/acceptance epochの両方をdeadline以下でだけ受理する。`current_epoch > decision_deadline`なら
326
+ `finalize_stale_slash_appeal`がdeterministic default-upholdをcommitする。appealなしは
327
+ `current_epoch > appeal_deadline`でだけfinalizeできる。balance、slash/appeal/assignment terminal、health
328
+ eventは各transactionで全claim allocationから再導出する。offenseごとにappealは1件でfirst stored
329
+ signed/default decisionが勝ち、exact canonical replayだけは期限後もno-opである。
330
+
331
+ legacy `BondLedger`はlocal arithmetic/test helperとして残り、raw initial balance/deposit/reasonを受ける。
332
+ productionではこれをauthority-signed durable pathの代わりに使わない。authority署名も実collateralを
333
+ crateが独立観測した証明ではなく、production registry/funding serviceは外部trust boundaryである。
334
+
335
+ ## 6. External escrow
336
+
337
+ durable External Replicated pathは3種類のnetwork-scoped authority evidenceを要求する。
338
+
339
+ - exact finalized `VerifiedFundingAttestation`
340
+ - funding attestationとfunded bonusへbindした`VerifiedDemandWeightGrant`
341
+ - stable payment commandとexact distributionへbindした`VerifiedTerminalConfirmation`
342
+
343
+ authority keyはfunding/demand-weight/terminal capability、validity/revocation、strict Ed25519を検査する。
344
+ durable transitionは次である。
345
+
346
+ ```text
347
+ Verified exact funding + Verified demand grant
348
+ -> Funded
349
+ -> Assigned(scheduler-signed External request)
350
+ -> EvidenceReady(typed k=2 pair)
351
+ -> SettlementPrepared(stable payment command)
352
+ -> Settled + maturity + 2 bond releases/links + WorkTicketV2 (atomic)
353
+
354
+ Funded | Assigned | EvidenceReady (state 1..3), now > terms expiry
355
+ -> RefundPrepared(stable payment command)
356
+ -> Refunded + eligible assignment bond releases (atomic; no maturity/ticket)
357
+ ```
358
+
359
+ funding attestation amountとterminal distribution totalは次にexact一致する。
360
+
361
+ ```text
362
+ required_reward + demand_bonus_amount + protocol_fee + failure_reserve
363
+ ```
364
+
365
+ bonus amountはbase rewardに対するpayout cap、bonus bpsはweight cap(default +5,000)以内で、grantの
366
+ asset/funding/amount/bps/intervalをtermsへexact bindする。assignmentはnetwork-scoped scheduler signature、
367
+ ExternalReplicated class、escrow reference、prompt commitment、constraints、epoch containmentを検査する。
368
+
369
+ EvidenceReadyにはtyped `MatchedReplicaPair`が必要で、network、request commitment、class、CU、expiryを
370
+ 照合する。settlement commandはworkerへbase+bonus、protocol fee、failure reserveのrequester refundを
371
+ exact配分する。`SettlementPrepared`をcommitする`BEGIN IMMEDIATE` transactionは両assignmentがactive state 0で
372
+ pending/upheld/default-final slashなしとpreflightする。`SettlementPrepared`と`RefundPrepared`はいずれも
373
+ 以後のnon-replay slashをcut offする。authority
374
+ confirmation後、terminal、maturity basis/weight grant、両worker assignmentの
375
+ Mature release/link、WorkTicketV2 insert、source consumptionを1transactionでcommitする。どちらかのbondが
376
+ missing/nonactiveならsettlement transactionはrollbackし、escrowだけをworker bondの代用にしない。exact
377
+ confirmation replayはstored ticketを返す。refund commandはstate 1..3のいずれからもterms expiry後に作れ、
378
+ required total全額をrequesterへ返す。pair/EvidenceReadyの存在はrefundを妨げない。confirmed refundはterminalと
379
+ 関連するeligible active assignment bondの残額releaseを同じtransactionでcommitし、maturity/ticketは生じない。
380
+ pending slash claimがあるassignmentはreleaseせず、claimがuphold/reverse/defaultのいずれかへ解決した後にだけ
381
+ 残額をresolved-terminal releaseできる。finalized slash allocationはrelease対象に戻さない。
382
+
383
+ legacy in-memory `ExternalEscrow` helperは残るが、production authority pathはこのdurable APIである。crateは
384
+ 実payment railを操作せず、terminal authorityがrail finalityを正しく署名することを信頼する。rail movement
385
+ とSQLite commitはdistributed atomicではなく、dispute/rail recovery/governance serviceもcrate外である。
386
+ `SettlementPrepared`/`RefundPrepared`後にauthority confirmationが永久に来ない場合のtimeout/superseding
387
+ terminalも未実装であり、prepared stateのoperational recoveryは外部service boundaryである。
388
+
389
+ ## 7. Work Ticket and weight
390
+
391
+ typed maturity source:
392
+
393
+ - Self Local: primary durable pathは`mature_unselected_audit`または`complete_selected_audit`がaudit
394
+ terminalと同じtransactionでsourceを���録する。bondedならassignmentをrelease/linkする。typed
395
+ constructorを使う場合もstored durable auditのexact state/basis/epochと再照合する
396
+ - Self Replicated: `MatureEvidence::from_self_replicated_pair(MatchedReplicaPair)`。
397
+ maturity epochはmatcherが記録した`matched_epoch`。2 assignment bondを同じtransactionでrelease/linkする
398
+ - External Replicated: authority-confirmed settlement transactionだけ。confirmation ID/epochとauthority-
399
+ signed weight grantをbindし、2 assignment bondをrelease/linkして即時ticketをcommitする
400
+
401
+ `MatureEvidence`のfieldと低水準constructorはpublicではないため、外部callerはsource/class/CU/
402
+ maturity reason/demand bonus/basis/grant/epochを自己申告できない。`StateStore::register_mature_evidence`は
403
+ opaque proofをdurable receipt/pair/audit stateと再照合し、Externalはこのgeneric APIから拒否する。
404
+
405
+ `WeightPolicy::v1()`:
406
+
407
+ | Evidence basis | `weight_bps` | `weighted_CU` |
408
+ |---|---:|---|
409
+ | Self Local, challenge window elapsed | 2,500 | `ceil(CU*2500/10000)` |
410
+ | Self Local, selected audit passed | 5,000 | `ceil(CU*5000/10000)` |
411
+ | Self Replicated pair | 10,000 | `CU` |
412
+ | External Replicated pair | 10,000 + funded demand bps(最大5,000) | 同じceil式 |
413
+
414
+ `WorkTicketV2`はversion、network、source、`maturity_basis_id`、optional `weight_grant_id`、job class、
415
+ policy version、CU、weight、issued epochを`work-ticket/v2` IDへhashする。Self classのgrantは必ずNone、
416
+ Externalはzero bonusでもauthority grant IDが必須である。
417
+
418
+ `StateStore::issue_ticket`は`issued_epoch >= stored mature_epoch`、required replica数と
419
+ `mature_source_assignments` release link数を検査し、ticket insertと`consumed_ticket_id`更新を同じ
420
+ transactionで行う。通常pathの二回目は`SourceAlreadyConsumed`になる。Externalだけはterminal confirmation
421
+ transaction内で同じissuerを呼び、exact terminal replay時はstored ticketを返す。
422
+
423
+ このweight変換はproduction network admissionやCUDA approvalそのものではない。bond gateはworker
424
+ collateral lifecycleを閉じるが、runtime classがproduction approvedか、authority registryがnetwork
425
+ governanceに採用されたかは別のadmission/service decisionである。
426
+
427
+ ## 8. Durable SQLite invariants
428
+
429
+ `StateStore` は application ID `PALW`、schema version 4、`foreign_keys=ON`、`WAL`、
430
+ `synchronous=FULL`、30秒busy timeoutを要求し、mutationは`BEGIN IMMEDIATE` transactionで行う。
431
+ SQLite integerがsignedであるため、consensus `u64` は8-byte big-endian BLOBとして保存する。旧schema
432
+ の暗黙migrationはなく、既存objectを持つapplication/user version 0 DBもclaimしない。
433
+
434
+ open時はexact table set、column order、foreign-key count、required indexに加え、全non-internal
435
+ `sqlite_master (type,name,tbl_name,sql)`をcanonical encodeしたSHA3-256をcompiled v4 goldenと照合する。
436
+ 同じtable/column名を保ったconstraint/index/DDL mutationも拒否する。portable snapshot/markerの前には
437
+ `wal_checkpoint(TRUNCATE)`がbusy 0かつ全frame checkpoint済みであることを要求する。
438
+
439
+ ### Receipt and job
440
+
441
+ - `receipt_id` はDB全体でunique
442
+ - `execution_nullifier` はDB全体でunique
443
+ - `(network_id, job_nullifier, replica_slot)` はunique
444
+ - `(network_id, job_nullifier)` ごとのjob classは不変
445
+ - Self Localはslot 0のみ、replicatedはslot 0/1のみ
446
+ - canonical signed envelopeとauthorized runtime instanceを保存し、restart restore時にexact一致
447
+ - `accepted_at_epoch`はfirst stateful acceptanceのstateless verification epochを保存し、restart時の
448
+ `verified_at_epoch`で上書きしない
449
+ - restoreは`issued_epoch <= accepted_at_epoch <= expires_epoch`かつ
450
+ `accepted_at_epoch <= current verified_at_epoch`を要求し、epoch rollbackを拒否
451
+ - assignment bond rowが存在するReceiptはgeneric acceptを拒否し、active exact lockとのatomic acceptanceを要求
452
+
453
+ ### Pair
454
+
455
+ - pair candidateはprojection digest/pair IDを再計算
456
+ - member 2件が両方accepted、同network/job/class、未失効でcandidate metadataと一致し、相互の
457
+ execution nullifierは異なる
458
+ - `(network_id, job_nullifier)` は最大1 pair
459
+ - receiptは最大1 pairのmember
460
+ - pair rowと2 member rowは1transaction。partial pairはcommitされない
461
+ - exact canonical replayはidempotent、同ID異内容はconflict
462
+ - `matched_epoch`はmemberのissued/accepted epoch以上かつexpiry以下で、durable canonical pairにcommit
463
+
464
+ ### Future audit and replay
465
+
466
+ - original accepted receiptはSelf Localで、stored network/job/request/issued/accepted epochとexact一致
467
+ - applied beaconはoriginal issued/accepted epochより後、verification時点以下で、canonical signed envelope、
468
+ beacon ID/value/authority key IDを保存
469
+ - restore時はcurrent authority registryのvalidity/revocation/strict Ed25519 verificationを再適用し、
470
+ selection、challenge ID、deadlineを再計算
471
+ - selected challenge/original receiptごとにaudit replayは最大1件。replay receipt/execution/assignmentは
472
+ `audit_replays` table内でunique(normal `receipts` tableとのglobal uniquenessではない)
473
+ - replay issued epochはbeaconより後、accepted epochはissued/current verification以上かつdeadline以下
474
+ - selected passはreplay insert、audit terminal/maturity、Self Local mature sourceを1transaction
475
+ - bonded selected passは同じtransactionでassignment release/link。selected mismatchはreplay insert、failed
476
+ terminal、typed slashを1transaction。timeoutと競合して片方だけcommitし、bonded timeoutもtyped slash
477
+ - non-selected maturityはaudit terminal、Self Local mature source、bondedならrelease/linkを1transaction
478
+
479
+ ### Mature source and ticket
480
+
481
+ - `source_id` はDB全体でunique
482
+ - public registrationは`MatureEvidence`のみ。raw source/class/reason/epoch登録APIはない
483
+ - receipt sourceはaccepted Self Localとexact network/class/CUが一致し、typed maturity reasonを持つ
484
+ - pair sourceはstored replicated pairとexact network/class/CUが一致する
485
+ - `maturity_basis_id`は全classに必須、`weight_grant_id`はExternalだけに必須
486
+ - demand bonusはExternal Replicatedだけ、maturity epochはtyped evidence/terminal confirmationから保存
487
+ - sourceとrequired assignment release IDを`mature_source_assignments`でlink。countはrequired replica数と一致
488
+ - `source_id` はwork ticketでもunique
489
+ - ticket issued epochはstored maturity epoch以上
490
+ - ticket insertとsource consumed更新は1transaction
491
+
492
+ ### Bond, canary, slash, and external terminal
493
+
494
+ - funding event、assignment、release、offense、appeal、canary、external authority evidence/terminalのbusiness
495
+ IDはunique。canonical exact replayだけidempotent
496
+ - bond accountはavailable/locked/pending/finalized合計、funding ledger、active assignment、slash status、healthをreconcile
497
+ - slash claimはfault/applied epoch、immutable target、derived allocationを分離し、offense-sorted complete setから
498
+ assignment terminal epoch/proofを再導出
499
+ - assignment terminal rowはremaining 0、terminal epoch/proofを必須とし、network/worker foreign keyでbind
500
+ - canary precommitはsigned envelopeのbody/key ID、assignment/worker/request/windowとstored rowを再照合
501
+ - canary terminalはpass/mismatch/receipt timeout/opening timeoutごとのrequired/forbidden fieldとfault partyをconstraint
502
+ - appealは`submitted <= accepted <= appeal_deadline`、decisionは`decided <= accepted <= decision_deadline`。
503
+ pendingだけdecisionを受け、期限後default upholdは別terminal state
504
+ - external keyは`(network_id, escrow_reference)`。funding/grant/command/confirmation IDの再利用を拒否
505
+ - terminalは`Settled`または`Refunded`のどちらか一方で、command/confirmation distribution totalはfunded totalとexact一致
506
+ - settlementはterminal/maturity/bond links/ticketを1transaction、refundはterminalとeligible bond releaseを
507
+ 1transactionでcommitする。pending claim分のbondは解決までlocked、conflicting replayはfatal
508
+
509
+ future audit/replayのrow、signed beacon、selection/challenge、replay terminal outcomeを再検証するrestore
510
+ APIと、bundleからrollbackなしでfresh later-epoch `AcceptedReceipt`を作るAPIは実装されている。bond/canary/
511
+ external rowはverified typestateのcanonical signed bytesを保存し、load時にbody-to-row binding/ledger invariantsを
512
+ 再検査するが、production registry governanceやexternal rail finalityをDB自身が再取得するわけではない。
513
+
514
+ ## 9. Metal GraphFallback and CUDA R32 in-progress non-issuance
515
+
516
+ 現行 Qwen3.6-35B-A3B Metal runtime classは `TraceCapability::GraphFallback`。sketch modeでも各scheduled GEMM
517
+ に1 synthetic graph tileを作るだけで、CUDA kernel/tile evidenceを名乗らない。
518
+
519
+ `TraceCapability::KernelSketch` とwire tagは将来互換のため存在する。CUDAはadditive exact 184-byte V2
520
+ recordとRust strict full-stream/dispatch/runtime binderを持つが、raw declared accumulator originはproofではない。
521
+ authority署名、registry/runtime/job、operation schedule commitment、scheduled GEMM/attention coverage、
522
+ full transcriptを検証した場合だけ
523
+ `BoundCudaTranscriptV1 -> AuthorityBoundCudaTranscriptV2 -> AuthorityBoundCudaReceiptEvidenceV2`
524
+ と進む、public raw constructorのないtypestateを実装した。V3 authority typestateは別versionの
525
+ Receipt V2 builder/verifier、暗号化Bundle V2、SQLite V2 state machineへ接続されている。V1 builder/verifierは
526
+ 引き続きCUDA `KernelSketch`をfail closedで拒否する。
527
+
528
+ Windows WSL2 Ubuntu 24.04のRTX 4060 Ti(sm_89)、CUDA Toolkit 13.3.1 / nvcc 13.3.73では、固定Qwenの37/37
529
+ layer offloadとbatch 1 graph observer 6/6同一diagnostic streamを確認した。standaloneのtrue FP32
530
+ producer-accumulator採取primitiveも最終grouped device suite 8/8とproducer 20/20同一diagnostic
531
+ fingerprintを通過した。vendored llama.cpp Q4_K/Q6_K MMVQ producerはV3 full-K pre-epilogue hookへ
532
+ 接続済みで、same-backend Qwen 1-token diagnostic E2Eは253 MMVQ recordを取得する。
533
+
534
+ FlashAttention-onlyのV2で表せなかったFA-off attentionに対し、V3 schema/binderはcanonical
535
+ 3-sublaunch groupingと実entry point直後collector/typed associationを実装する。253 MMVQにQK/softmax/PV
536
+ 各36を加えた361-launch実機E2E、5 work-class negative、exact release manifest、V2 stateless verification、
537
+ encrypted bundle、atomic persistence/restart/replay/rollback gateは完了した。live callbackへの
538
+ authority-derived canonical physical-layout ID接続はproduction境界として未統合である。
539
+ `PALW_CUDA_TRACE_PRODUCTION_CAPABLE=0`、`PALW_CUDA_PRODUCER_VENDOR_RUNTIME_INTEGRATED=0`、
540
+ `PALW_CUDA_PRODUCER_RECEIPT_MAPPING_AVAILABLE=0`、`PALW_CUDA_PRODUCER_PRODUCTION_CAPABLE=0`で、
541
+ production CMake gateは意図的にfatalのままである。
542
+
543
+ したがってR32は`In progress`であり、完了するまでproduction CUDA Receiptを発行せず、CUDA
544
+ `KernelSketch`を根拠に
545
+ production Work Ticketを発行しない。Metal GraphFallbackのlocal/development receiptと、production
546
+ CUDA approvalは別gateである。
547
+
548
+ さらにproduction scheduler/network、governance-backed signer/beacon/bond/external registryとauthority
549
+ service、finalized beacon delivery、independent auditor re-execution、payment railは未統合である。invalid-
550
+ manifest/equivocation/duplicate-executionのdurable typed slash proof wiringも残る。個別typestateやSQLite
551
+ transitionの実装をproduction lifecycle service全体の完成と読み替えない。
models/.gitkeep ADDED
@@ -0,0 +1 @@
 
 
1
+
patches/llama.cpp-palw-full.patch ADDED
The diff for this file is too large to render. See raw diff
 
patches/llama.cpp-palw-observer.patch ADDED
@@ -0,0 +1,1792 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ diff --git a/ggml/include/ggml-metal.h b/ggml/include/ggml-metal.h
2
+ index 433838f0..213e148d 100644
3
+ --- a/ggml/include/ggml-metal.h
4
+ +++ b/ggml/include/ggml-metal.h
5
+ @@ -56,6 +56,21 @@ GGML_BACKEND_API void ggml_backend_metal_capture_next_compute(ggml_backend_t bac
6
+
7
+ GGML_BACKEND_API ggml_backend_reg_t ggml_backend_metal_reg(void);
8
+
9
+ +// PALW kernel-level dispatch hook.
10
+ +//
11
+ +// When set (process-global), the callback is invoked for every Metal compute
12
+ +// dispatch with the bound pipeline (kernel) name and the launch geometry
13
+ +// (threadgroup grid tg0..2 and threads-per-threadgroup tptg0..2). This lets the
14
+ +// PALW observer produce a kernel-level execution trace bound to the actual GPU
15
+ +// kernel dispatches rather than to graph-node outputs. Pass NULL to disable.
16
+ +typedef void (*ggml_metal_palw_dispatch_cb)(
17
+ + void * user_data,
18
+ + const char * pipeline,
19
+ + int tg0, int tg1, int tg2,
20
+ + int tptg0, int tptg1, int tptg2);
21
+ +
22
+ +GGML_BACKEND_API void ggml_metal_palw_set_dispatch_hook(ggml_metal_palw_dispatch_cb cb, void * user_data);
23
+ +
24
+ #ifdef __cplusplus
25
+ }
26
+ #endif
27
+ diff --git a/ggml/src/ggml-metal/ggml-metal-device.m b/ggml/src/ggml-metal/ggml-metal-device.m
28
+ index 80e47f2c..3e36c08d 100644
29
+ --- a/ggml/src/ggml-metal/ggml-metal-device.m
30
+ +++ b/ggml/src/ggml-metal/ggml-metal-device.m
31
+ @@ -1,5 +1,6 @@
32
+ #import "ggml-metal-device.h"
33
+
34
+ +#import "ggml-metal.h"
35
+ #import "ggml-impl.h"
36
+ #import "ggml-backend-impl.h"
37
+
38
+ @@ -72,6 +73,9 @@ void ggml_metal_cv_set_bool(ggml_metal_cv_t cv, bool value, int32_t idx) {
39
+
40
+ struct ggml_metal_pipeline {
41
+ id<MTLComputePipelineState> obj;
42
+ +
43
+ + // PALW: stable kernel (pipeline) name, captured for kernel-level tracing.
44
+ + char name[128];
45
+ };
46
+
47
+ ggml_metal_pipeline_t ggml_metal_pipeline_init(void) {
48
+ @@ -79,6 +83,7 @@ ggml_metal_pipeline_t ggml_metal_pipeline_init(void) {
49
+
50
+ *res = (struct ggml_metal_pipeline) {
51
+ /*.obj =*/ nil,
52
+ + /*.name =*/ {0},
53
+ };
54
+
55
+ return res;
56
+ @@ -443,6 +448,8 @@ struct ggml_metal_pipeline_with_params ggml_metal_library_compile_pipeline(ggml_
57
+
58
+ res.pipeline = ggml_metal_pipeline_init();
59
+ res.pipeline->obj = obj;
60
+ + // PALW: record the stable kernel name for kernel-level dispatch tracing.
61
+ + snprintf(res.pipeline->name, sizeof(res.pipeline->name), "%s", name);
62
+
63
+ ggml_metal_pipelines_add(lib->pipelines, name, res.pipeline);
64
+ }
65
+ @@ -458,8 +465,23 @@ struct ggml_metal_pipeline_with_params ggml_metal_library_compile_pipeline(ggml_
66
+
67
+ struct ggml_metal_encoder {
68
+ id<MTLComputeCommandEncoder> obj;
69
+ +
70
+ + // PALW: name of the pipeline currently bound, for kernel-level dispatch tracing.
71
+ + const char * cur_pipeline;
72
+ };
73
+
74
+ +// PALW: process-global kernel-dispatch hook. When set, it is invoked for every
75
+ +// Metal compute dispatch with the bound pipeline (kernel) name and the launch
76
+ +// geometry (threadgroup grid + threads-per-threadgroup). Used by the PALW
77
+ +// observer to produce a kernel-level (not graph-fallback) execution trace.
78
+ +static ggml_metal_palw_dispatch_cb g_palw_dispatch_cb = NULL;
79
+ +static void * g_palw_dispatch_ud = NULL;
80
+ +
81
+ +void ggml_metal_palw_set_dispatch_hook(ggml_metal_palw_dispatch_cb cb, void * user_data) {
82
+ + g_palw_dispatch_cb = cb;
83
+ + g_palw_dispatch_ud = user_data;
84
+ +}
85
+ +
86
+ ggml_metal_encoder_t ggml_metal_encoder_init(ggml_metal_cmd_buf_t cmd_buf_raw, bool concurrent) {
87
+ ggml_metal_encoder_t res = calloc(1, sizeof(struct ggml_metal_encoder));
88
+
89
+ @@ -491,6 +513,8 @@ void ggml_metal_encoder_debug_group_pop (ggml_metal_encoder_t encoder) {
90
+
91
+ void ggml_metal_encoder_set_pipeline(ggml_metal_encoder_t encoder, struct ggml_metal_pipeline_with_params pipeline) {
92
+ [encoder->obj setComputePipelineState:pipeline.pipeline->obj];
93
+ + // PALW: remember the bound kernel name so dispatches can be attributed to it.
94
+ + encoder->cur_pipeline = pipeline.pipeline->name;
95
+ }
96
+
97
+ void ggml_metal_encoder_set_bytes(ggml_metal_encoder_t encoder, void * data, size_t size, int idx) {
98
+ @@ -506,6 +530,11 @@ void ggml_metal_encoder_set_threadgroup_memory_size(ggml_metal_encoder_t encoder
99
+ }
100
+
101
+ void ggml_metal_encoder_dispatch_threadgroups(ggml_metal_encoder_t encoder, int tg0, int tg1, int tg2, int tptg0, int tptg1, int tptg2) {
102
+ + // PALW: report the kernel-level dispatch (bound pipeline + launch geometry).
103
+ + if (g_palw_dispatch_cb) {
104
+ + g_palw_dispatch_cb(g_palw_dispatch_ud, encoder->cur_pipeline ? encoder->cur_pipeline : "",
105
+ + tg0, tg1, tg2, tptg0, tptg1, tptg2);
106
+ + }
107
+ [encoder->obj dispatchThreadgroups:MTLSizeMake(tg0, tg1, tg2) threadsPerThreadgroup:MTLSizeMake(tptg0, tptg1, tptg2)];
108
+ }
109
+
110
+ diff --git a/src/models/qwen35moe.cpp b/src/models/qwen35moe.cpp
111
+ index 7b0876cb..4d955261 100644
112
+ --- a/src/models/qwen35moe.cpp
113
+ +++ b/src/models/qwen35moe.cpp
114
+ @@ -6,7 +6,18 @@ void llama_model_qwen35moe::load_arch_hparams(llama_model_loader & ml) {
115
+ ml.get_key(LLM_KV_EXPERT_SHARED_FEED_FORWARD_LENGTH, hparams.n_ff_shexp, false);
116
+ ml.get_key(LLM_KV_ATTENTION_LAYERNORM_RMS_EPS, hparams.f_norm_rms_eps);
117
+
118
+ - ml.get_key_or_arr(LLM_KV_ROPE_DIMENSION_SECTIONS, hparams.rope_sections, 4, true);
119
+ + // PALW: newer HF->GGUF conversions write 3 mrope sections ([t, h, w]) and
120
+ + // omit the trailing zero; older conversions write 4. Accept both forms and
121
+ + // zero-pad so the pinned runtime loads current upstream GGUF artifacts.
122
+ + {
123
+ + std::vector<int32_t> sections;
124
+ + ml.get_arr(LLM_KV_ROPE_DIMENSION_SECTIONS, sections, true);
125
+ + if (sections.size() != 3 && sections.size() != 4) {
126
+ + throw std::runtime_error("rope.dimension_sections must have 3 or 4 entries");
127
+ + }
128
+ + std::fill(hparams.rope_sections.begin(), hparams.rope_sections.end(), 0);
129
+ + std::copy(sections.begin(), sections.end(), hparams.rope_sections.begin());
130
+ + }
131
+
132
+ // Load linear attention (gated delta net) parameters
133
+ ml.get_key(LLM_KV_SSM_CONV_KERNEL, hparams.ssm_d_conv);
134
+ @@ -73,8 +84,13 @@ void llama_model_qwen35moe::load_arch_tensors(llama_model_loader & ml) {
135
+ layer.attn_post_norm = create_tensor(tn(LLM_TENSOR_ATTN_POST_NORM, "weight", il), { n_embd }, flags);
136
+
137
+ if (!hparams.is_recr(il)) {
138
+ - // Attention layers
139
+ - create_tensor_qkv(layer, il, n_embd, n_embd_head_k * n_head * 2, n_embd_k_gqa, n_embd_v_gqa, flags);
140
+ + // Attention layers. The LLAMA_LOAD_LOCALS macro derives the global
141
+ + // n_embd_k_gqa/n_embd_v_gqa from layer 0, which in this MoE is a
142
+ + // linear-attention (recurrent) layer with n_head_kv == 0. Use the
143
+ + // uniform full-attention KV projection width instead.
144
+ + const int64_t n_embd_k_gqa_attn = hparams.n_embd_k_gqa_max();
145
+ + const int64_t n_embd_v_gqa_attn = hparams.n_embd_v_gqa_max();
146
+ + create_tensor_qkv(layer, il, n_embd, n_embd_head_k * n_head * 2, n_embd_k_gqa_attn, n_embd_v_gqa_attn, flags);
147
+ layer.wo = create_tensor(tn(LLM_TENSOR_ATTN_OUT, "weight", il), { n_embd_head_k * n_head, n_embd }, flags);
148
+
149
+ // Q/K normalization for attention layers
150
+ @@ -86,7 +102,12 @@ void llama_model_qwen35moe::load_arch_tensors(llama_model_loader & ml) {
151
+ layer.wqkv = create_tensor(tn(LLM_TENSOR_ATTN_QKV, "weight", il), { n_embd, key_dim * 2 + value_dim }, TENSOR_NOT_REQUIRED);
152
+ layer.wqkv_gate = create_tensor(tn(LLM_TENSOR_ATTN_GATE, "weight", il), { n_embd, value_dim }, TENSOR_NOT_REQUIRED);
153
+ layer.ssm_conv1d = create_tensor(tn(LLM_TENSOR_SSM_CONV1D, "weight", il), { hparams.ssm_d_conv, conv_dim }, flags);
154
+ - layer.ssm_dt = create_tensor(tn(LLM_TENSOR_SSM_DT, "bias", il), { hparams.ssm_dt_rank }, flags);
155
+ + // PALW: some conversions store the delta-time bias without the
156
+ + // ".bias" suffix ("blk.N.ssm_dt"). Accept both spellings.
157
+ + layer.ssm_dt = create_tensor(tn(LLM_TENSOR_SSM_DT, "bias", il), { hparams.ssm_dt_rank }, flags | TENSOR_NOT_REQUIRED);
158
+ + if (!layer.ssm_dt) {
159
+ + layer.ssm_dt = create_tensor(tn(LLM_TENSOR_SSM_DT, il), { hparams.ssm_dt_rank }, flags);
160
+ + }
161
+ layer.ssm_a = create_tensor(tn(LLM_TENSOR_SSM_A_NOSCAN, il), { hparams.ssm_dt_rank }, flags);
162
+ layer.ssm_beta = create_tensor(tn(LLM_TENSOR_SSM_BETA, "weight", il), { n_embd, n_v_heads }, flags);
163
+ layer.ssm_alpha = create_tensor(tn(LLM_TENSOR_SSM_ALPHA, "weight", il), { n_embd, n_v_heads }, flags);
164
+ @@ -116,7 +137,11 @@ void llama_model_qwen35moe::load_arch_tensors(llama_model_loader & ml) {
165
+ layer.attn_norm = create_tensor(tn(LLM_TENSOR_ATTN_NORM, "weight", il), { n_embd }, 0);
166
+ layer.attn_post_norm = create_tensor(tn(LLM_TENSOR_ATTN_POST_NORM, "weight", il), { n_embd }, 0);
167
+
168
+ - create_tensor_qkv(layer, il, n_embd, n_embd_head_k * n_head * 2, n_embd_k_gqa, n_embd_v_gqa, 0);
169
+ + // The MTP layer index has no entry in the per-layer n_head_kv array, so
170
+ + // derive the KV projection width from the full-attention trunk layers.
171
+ + const int64_t n_embd_k_gqa_mtp = hparams.n_embd_k_gqa_max();
172
+ + const int64_t n_embd_v_gqa_mtp = hparams.n_embd_v_gqa_max();
173
+ + create_tensor_qkv(layer, il, n_embd, n_embd_head_k * n_head * 2, n_embd_k_gqa_mtp, n_embd_v_gqa_mtp, 0);
174
+ layer.wo = create_tensor(tn(LLM_TENSOR_ATTN_OUT, "weight", il), { n_embd_head_k * n_head, n_embd }, 0);
175
+ layer.attn_q_norm = create_tensor(tn(LLM_TENSOR_ATTN_Q_NORM, "weight", il), { n_embd_head_k }, 0);
176
+ layer.attn_k_norm = create_tensor(tn(LLM_TENSOR_ATTN_K_NORM, "weight", il), { n_embd_head_k }, 0);
177
+ @@ -147,6 +172,24 @@ void llama_model_qwen35moe::load_arch_tensors(llama_model_loader & ml) {
178
+ for (int i = n_layer; i < n_layer_all; ++i) {
179
+ load_block_mtp(i);
180
+ }
181
+ +
182
+ + // PALW: the Ollama-packaged Qwen3.6-35B-A3B GGUF bundles the multimodal
183
+ + // vision tower ("v.*") and, when the next-token/MTP head is not enabled by
184
+ + // hyperparameters, the MTP sub-model ("mtp.*") in the same file. The pinned
185
+ + // text runtime never builds those sibling sub-models, so account for their
186
+ + // tensors here; otherwise done_getting_tensors() rejects the load for
187
+ + // having created fewer tensors than the file contains. This does not weaken
188
+ + // the check for a genuinely missing text tensor: only tensors that exist in
189
+ + // the file under these sibling prefixes are counted, exactly once each.
190
+ + for (const auto & entry : ml.weights_map) {
191
+ + const std::string & name = entry.first;
192
+ + const bool is_vision = name.rfind("v.", 0) == 0;
193
+ + const bool is_mtp = name.rfind("mtp.", 0) == 0;
194
+ + if (is_vision || is_mtp) {
195
+ + ml.size_data -= ggml_nbytes(entry.second.tensor);
196
+ + ml.n_created++;
197
+ + }
198
+ + }
199
+ }
200
+
201
+ std::unique_ptr<llm_graph_context> llama_model_qwen35moe::build_arch_graph(const llm_graph_params & params) const {
202
+ @@ -287,6 +330,12 @@ ggml_tensor * llama_model_qwen35moe::graph::build_layer_attn(
203
+ const int64_t n_embd_head = hparams.n_embd_head_v();
204
+ GGML_ASSERT(n_embd_head == hparams.n_embd_head_k());
205
+
206
+ + // PALW: the llm_graph_context base initializes n_head/n_head_kv from layer
207
+ + // 0, which in this hybrid MoE is a linear-attention layer with n_head_kv 0.
208
+ + // Use the per-layer counts for the full-attention reshapes below.
209
+ + const int64_t n_head = hparams.n_head(il);
210
+ + const int64_t n_head_kv = hparams.n_head_kv(il);
211
+ +
212
+ // Order: joint QG projection, QG split, Q norm, KV projection, K norm, RoPE, attention
213
+
214
+ // Qwen3Next uses a single Q projection that outputs query + gate
215
+ diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt
216
+ index 780df326..a1f04870 100644
217
+ --- a/tools/CMakeLists.txt
218
+ +++ b/tools/CMakeLists.txt
219
+ @@ -28,6 +28,7 @@ else()
220
+ endif()
221
+ add_subdirectory(tokenize)
222
+ add_subdirectory(parser)
223
+ + add_subdirectory(palw-observer)
224
+ add_subdirectory(tts)
225
+ add_subdirectory(mtmd)
226
+ if (GGML_RPC)
227
+ diff --git a/tools/palw-observer/CMakeLists.txt b/tools/palw-observer/CMakeLists.txt
228
+ new file mode 100644
229
+ index 00000000..40e3ffd8
230
+ --- /dev/null
231
+ +++ b/tools/palw-observer/CMakeLists.txt
232
+ @@ -0,0 +1,9 @@
233
+ +set(TARGET llama-palw-observer)
234
+ +
235
+ +add_executable(${TARGET} palw-observer.cpp)
236
+ +target_link_libraries(${TARGET} PRIVATE llama llama-common-base ${CMAKE_THREAD_LIBS_INIT})
237
+ +target_compile_features(${TARGET} PRIVATE cxx_std_17)
238
+ +
239
+ +if(LLAMA_TOOLS_INSTALL)
240
+ + install(TARGETS ${TARGET} RUNTIME)
241
+ +endif()
242
+ diff --git a/tools/palw-observer/README.md b/tools/palw-observer/README.md
243
+ new file mode 100644
244
+ index 00000000..efd1823b
245
+ --- /dev/null
246
+ +++ b/tools/palw-observer/README.md
247
+ @@ -0,0 +1,66 @@
248
+ +# PALW native graph observer
249
+ +
250
+ +`llama-palw-observer` is a non-interactive, single-request Qwen3.6-35B-A3B runner.
251
+ +It uses only the public llama and ggml APIs and writes versioned JSONL records to
252
+ +stdout. Runtime and model logs are written to stderr.
253
+ +
254
+ +## Build and run
255
+ +
256
+ +```sh
257
+ +cmake --build build-palw --target llama-palw-observer -j
258
+ +build-palw/bin/llama-palw-observer \
259
+ + --model /path/to/Qwen3.6-abliterated-35b-Claude-4.7-Q4_K_M.gguf \
260
+ + --prompt "Hello" \
261
+ + --n-predict 8 \
262
+ + --observer graph
263
+ +```
264
+ +
265
+ +The runner fixes greedy sampling, request batch, logical/physical token batch,
266
+ +parallel sequences, tensor parallelism, and CPU thread counts to one. It also
267
+ +disables context shifting, speculation, Flash Attention, and split-model tensor
268
+ +parallelism. The prompt is therefore evaluated one token at a time. The context
269
+ +is sized before execution and the run fails instead of shifting when the prompt
270
+ +and prediction bound exceed the model training context.
271
+ +
272
+ +The accepted model profile is hybrid Qwen3.6-35B-A3B (mixture-of-experts):
273
+ +architecture `qwen35moe`, 40 layers, 2048 hidden elements, and a 248320-token
274
+ +vocabulary, decoder-only. Per-layer head counts vary (the model alternates
275
+ +linear-attention/state-space layers with full-attention layers), so head counts
276
+ +are not part of the accepted profile. Other profiles fail before a header or
277
+ +inference result is emitted. Legitimate zero-element recurrent-state-cache graph
278
+ +nodes are skipped rather than treated as errors.
279
+ +
280
+ +## Observer modes
281
+ +
282
+ +- `off` installs no scheduler callback.
283
+ +- `graph` emits metadata for every graph node from the callback's `ask` stage.
284
+ + It never requests tensor data.
285
+ +- `sketch` emits the same metadata and requests post-compute data only for plain
286
+ + `MUL_MAT` nodes (indirect expert GEMM, `MUL_MAT_ID`, is emitted as an ordinary
287
+ + metadata node, not sketched). It copies at most the first 64 contiguous output
288
+ + elements through `ggml_backend_tensor_get`. Each element becomes one
289
+ + hexadecimal nibble: one sign bit and a fixed three-bit magnitude bucket. The
290
+ + resulting 64 hex digits are a 256-bit sketch. Raw activation values are never
291
+ + serialized.
292
+ +
293
+ +Nibble bit 3 is the sign bit. Bits 0-2 use these absolute-value buckets: zero,
294
+ +`(0, 2^-8)`, `[2^-8, 2^-4)`, `[2^-4, 2^-2)`, `[2^-2, 1)`, `[1, 4)`,
295
+ +`[4, 16)`, and `[16, infinity)`. Fewer than 64 available elements are padded
296
+ +with zero nibbles.
297
+ +
298
+ +Every stdout line has `schema`, `schema_version`, and `record`. A successful run
299
+ +contains one `header`, zero or more `event` records, and one `result`. The result
300
+ +contains prompt token IDs, sampled token IDs (including an EOG token when one is
301
+ +sampled), the non-special generated output bytes, and the stop reason.
302
+ +
303
+ +## Limits
304
+ +
305
+ +This target is a runtime-observation prototype, not a PALW receipt generator.
306
+ +It does not calculate canonical compute units, sign receipts, form commitments,
307
+ +or trace CUDA kernels. The sketch tile is explicitly identified as
308
+ +`graph_fallback_logical_prefix_v1`, and `kernel_trace.claim` is
309
+ +`not_a_cuda_kernel_trace`. Scheduler callbacks add synchronization and can
310
+ +change timing, but they must not change token IDs or output bytes. The sketch is
311
+ +lossy observation data, not a cryptographic proof. Graph topology and floating
312
+ +point results can vary across backends or hardware, so byte identity is only
313
+ +claimed for repeated runs of the same pinned model, runtime, and backend class.
314
+ diff --git a/tools/palw-observer/palw-observer.cpp b/tools/palw-observer/palw-observer.cpp
315
+ new file mode 100644
316
+ index 00000000..83fc243b
317
+ --- /dev/null
318
+ +++ b/tools/palw-observer/palw-observer.cpp
319
+ @@ -0,0 +1,1473 @@
320
+ +#include "ggml-backend.h"
321
+ +#include "ggml.h"
322
+ +#include "ggml-metal.h"
323
+ +#include "llama.h"
324
+ +#include "build-info.h"
325
+ +
326
+ +#include <algorithm>
327
+ +#include <array>
328
+ +#include <charconv>
329
+ +#include <clocale>
330
+ +#include <cmath>
331
+ +#include <cstdint>
332
+ +#include <cstdio>
333
+ +#include <cstring>
334
+ +#include <exception>
335
+ +#include <limits>
336
+ +#include <memory>
337
+ +#include <string>
338
+ +#include <string_view>
339
+ +#include <utility>
340
+ +#include <vector>
341
+ +
342
+ +namespace {
343
+ +
344
+ +constexpr const char * SCHEMA_NAME = "misaka.palw.runtime_observer";
345
+ +// Schema v2 adds "route" records: the real mixture-of-experts Top-K expert
346
+ +// selection (the `ffn_moe_topk` tensor) read back post-compute. Consumers that
347
+ +// only understand v1 must reject v2.
348
+ +constexpr int SCHEMA_VERSION = 2;
349
+ +constexpr size_t SKETCH_SAMPLES = 64;
350
+ +// Upper bound on selected-expert indices read back from one routing tensor:
351
+ +// n_expert_used (Top-K) * n_tokens for a single mixture-of-experts layer.
352
+ +constexpr size_t MAX_ROUTE_INDICES = 262144;
353
+ +
354
+ +// PALW #5 diagnostic: empirically map Metal kernel dispatches to graph nodes so
355
+ +// the node<->dispatch correlation can be validated before it is committed as a
356
+ +// kernel-level trace. Enabled only when PALW_TRACE_DIAG is set in the env.
357
+ +static bool g_diag_enabled = false;
358
+ +constexpr uint32_t PALW_CONTEXT_TOKENS = 4096;
359
+ +
360
+ +enum class observer_mode {
361
+ + off,
362
+ + graph,
363
+ + sketch,
364
+ +};
365
+ +
366
+ +struct options {
367
+ + std::string model_path;
368
+ + std::string prompt;
369
+ + int32_t n_predict = -1;
370
+ + int32_t n_gpu_layers = 999;
371
+ + observer_mode mode = observer_mode::off;
372
+ + bool prompt_set = false;
373
+ + bool prompt_stdin = false;
374
+ + bool emit_output_bytes = false;
375
+ +};
376
+ +
377
+ +struct model_metadata {
378
+ + std::vector<std::pair<std::string, std::string>> entries;
379
+ +};
380
+ +
381
+ +static const char * mode_name(observer_mode mode) {
382
+ + switch (mode) {
383
+ + case observer_mode::off: return "off";
384
+ + case observer_mode::graph: return "graph";
385
+ + case observer_mode::sketch: return "sketch";
386
+ + }
387
+ + return "invalid";
388
+ +}
389
+ +
390
+ +static void log_callback(ggml_log_level level, const char * text, void *) {
391
+ + const char * label = "unknown";
392
+ + switch (level) {
393
+ + case GGML_LOG_LEVEL_NONE: label = "none"; break;
394
+ + case GGML_LOG_LEVEL_DEBUG: label = "debug"; break;
395
+ + case GGML_LOG_LEVEL_INFO: label = "info"; break;
396
+ + case GGML_LOG_LEVEL_WARN: label = "warn"; break;
397
+ + case GGML_LOG_LEVEL_ERROR: label = "error"; break;
398
+ + case GGML_LOG_LEVEL_CONT: label = "cont"; break;
399
+ + }
400
+ + std::fprintf(stderr, "[llama:%s] %s", label, text ? text : "");
401
+ +}
402
+ +
403
+ +static void print_usage(const char * argv0) {
404
+ + std::fprintf(stderr,
405
+ + "usage: %s --model MODEL (--prompt TEXT|--prompt-stdin) --n-predict N "
406
+ + "[--observer off|graph|sketch] [--n-gpu-layers N] [--emit-output-bytes]\n",
407
+ + argv0);
408
+ +}
409
+ +
410
+ +static bool parse_i32(const char * value, int32_t min_value, int32_t max_value, int32_t & result) {
411
+ + if (!value || value[0] == '\0') {
412
+ + return false;
413
+ + }
414
+ + int32_t parsed = 0;
415
+ + const char * end = value + std::strlen(value);
416
+ + const auto converted = std::from_chars(value, end, parsed);
417
+ + if (converted.ec != std::errc() || converted.ptr != end || parsed < min_value || parsed > max_value) {
418
+ + return false;
419
+ + }
420
+ + result = parsed;
421
+ + return true;
422
+ +}
423
+ +
424
+ +static bool take_value(int argc, char ** argv, int & i, const char * option, const char *& value) {
425
+ + if (i + 1 >= argc) {
426
+ + std::fprintf(stderr, "error: %s requires a value\n", option);
427
+ + return false;
428
+ + }
429
+ + value = argv[++i];
430
+ + return true;
431
+ +}
432
+ +
433
+ +static bool parse_options(int argc, char ** argv, options & opts, bool & help, bool & version) {
434
+ + help = false;
435
+ + version = false;
436
+ + for (int i = 1; i < argc; ++i) {
437
+ + const std::string_view arg(argv[i]);
438
+ + const char * value = nullptr;
439
+ + if (arg == "--help" || arg == "-h") {
440
+ + help = true;
441
+ + return true;
442
+ + } else if (arg == "--version") {
443
+ + version = true;
444
+ + return true;
445
+ + } else if (arg == "--model" || arg == "-m") {
446
+ + if (!take_value(argc, argv, i, argv[i], value)) {
447
+ + return false;
448
+ + }
449
+ + opts.model_path = value;
450
+ + } else if (arg == "--prompt" || arg == "-p") {
451
+ + if (opts.prompt_stdin) {
452
+ + std::fprintf(stderr, "error: --prompt and --prompt-stdin are mutually exclusive\n");
453
+ + return false;
454
+ + }
455
+ + if (!take_value(argc, argv, i, argv[i], value)) {
456
+ + return false;
457
+ + }
458
+ + opts.prompt = value;
459
+ + opts.prompt_set = true;
460
+ + } else if (arg == "--prompt-stdin") {
461
+ + if (opts.prompt_set || opts.prompt_stdin) {
462
+ + std::fprintf(stderr, "error: prompt input may be selected only once\n");
463
+ + return false;
464
+ + }
465
+ + opts.prompt_stdin = true;
466
+ + } else if (arg == "--emit-output-bytes") {
467
+ + opts.emit_output_bytes = true;
468
+ + } else if (arg == "--n-predict" || arg == "-n") {
469
+ + if (!take_value(argc, argv, i, argv[i], value) ||
470
+ + !parse_i32(value, 0, 65536, opts.n_predict)) {
471
+ + std::fprintf(stderr, "error: --n-predict must be an integer in [0, 65536]\n");
472
+ + return false;
473
+ + }
474
+ + } else if (arg == "--n-gpu-layers" || arg == "-ngl") {
475
+ + if (!take_value(argc, argv, i, argv[i], value) ||
476
+ + !parse_i32(value, -1, 100000, opts.n_gpu_layers)) {
477
+ + std::fprintf(stderr, "error: --n-gpu-layers must be an integer in [-1, 100000]\n");
478
+ + return false;
479
+ + }
480
+ + } else if (arg == "--observer") {
481
+ + if (!take_value(argc, argv, i, argv[i], value)) {
482
+ + return false;
483
+ + }
484
+ + const std::string_view mode(value);
485
+ + if (mode == "off") {
486
+ + opts.mode = observer_mode::off;
487
+ + } else if (mode == "graph") {
488
+ + opts.mode = observer_mode::graph;
489
+ + } else if (mode == "sketch") {
490
+ + opts.mode = observer_mode::sketch;
491
+ + } else {
492
+ + std::fprintf(stderr, "error: --observer must be off, graph, or sketch\n");
493
+ + return false;
494
+ + }
495
+ + } else {
496
+ + std::fprintf(stderr, "error: unknown argument: %s\n", argv[i]);
497
+ + return false;
498
+ + }
499
+ + }
500
+ +
501
+ + if (opts.model_path.empty()) {
502
+ + std::fprintf(stderr, "error: --model is required\n");
503
+ + return false;
504
+ + }
505
+ + if (opts.prompt_stdin) {
506
+ + std::array<char, 8192> buffer = {};
507
+ + while (true) {
508
+ + const size_t count = std::fread(buffer.data(), 1, buffer.size(), stdin);
509
+ + if (count != 0) {
510
+ + if (opts.prompt.size() > static_cast<size_t>(std::numeric_limits<int32_t>::max()) - count) {
511
+ + std::fprintf(stderr, "error: stdin prompt exceeds the tokenizer API bound\n");
512
+ + return false;
513
+ + }
514
+ + opts.prompt.append(buffer.data(), count);
515
+ + }
516
+ + if (count != buffer.size()) {
517
+ + if (std::ferror(stdin)) {
518
+ + std::fprintf(stderr, "error: failed to read prompt from stdin\n");
519
+ + return false;
520
+ + }
521
+ + break;
522
+ + }
523
+ + }
524
+ + opts.prompt_set = true;
525
+ + }
526
+ + if (!opts.prompt_set) {
527
+ + std::fprintf(stderr, "error: --prompt is required (an explicitly empty prompt is allowed)\n");
528
+ + return false;
529
+ + }
530
+ + if (opts.n_predict < 0) {
531
+ + std::fprintf(stderr, "error: --n-predict is required\n");
532
+ + return false;
533
+ + }
534
+ + if (opts.prompt.size() > static_cast<size_t>(std::numeric_limits<int32_t>::max())) {
535
+ + std::fprintf(stderr, "error: prompt exceeds the tokenizer API bound\n");
536
+ + return false;
537
+ + }
538
+ + return true;
539
+ +}
540
+ +
541
+ +static void append_json_string(std::string & out, std::string_view value) {
542
+ + static constexpr char hex[] = "0123456789abcdef";
543
+ + out.push_back('"');
544
+ + for (const unsigned char c : value) {
545
+ + switch (c) {
546
+ + case '"': out += "\\\""; break;
547
+ + case '\\': out += "\\\\"; break;
548
+ + case '\b': out += "\\b"; break;
549
+ + case '\f': out += "\\f"; break;
550
+ + case '\n': out += "\\n"; break;
551
+ + case '\r': out += "\\r"; break;
552
+ + case '\t': out += "\\t"; break;
553
+ + default:
554
+ + if (c < 0x20) {
555
+ + out += "\\u00";
556
+ + out.push_back(hex[c >> 4]);
557
+ + out.push_back(hex[c & 0x0f]);
558
+ + } else {
559
+ + out.push_back(static_cast<char>(c));
560
+ + }
561
+ + break;
562
+ + }
563
+ + }
564
+ + out.push_back('"');
565
+ +}
566
+ +
567
+ +static void append_bool(std::string & out, bool value) {
568
+ + out += value ? "true" : "false";
569
+ +}
570
+ +
571
+ +template<typename T>
572
+ +static void append_integer(std::string & out, T value) {
573
+ + out += std::to_string(value);
574
+ +}
575
+ +
576
+ +static void append_float(std::string & out, double value) {
577
+ + if (!std::isfinite(value)) {
578
+ + out += "null";
579
+ + return;
580
+ + }
581
+ + char buffer[64];
582
+ + const int n = std::snprintf(buffer, sizeof(buffer), "%.9g", value);
583
+ + if (n <= 0 || static_cast<size_t>(n) >= sizeof(buffer)) {
584
+ + out += "null";
585
+ + return;
586
+ + }
587
+ + out.append(buffer, static_cast<size_t>(n));
588
+ +}
589
+ +
590
+ +static bool write_json_line(const std::string & line) {
591
+ + if (std::fwrite(line.data(), 1, line.size(), stdout) != line.size() ||
592
+ + std::fputc('\n', stdout) == EOF || std::fflush(stdout) != 0) {
593
+ + std::fprintf(stderr, "error: failed to write JSONL to stdout\n");
594
+ + return false;
595
+ + }
596
+ + return true;
597
+ +}
598
+ +
599
+ +static void append_record_prefix(std::string & out, const char * record) {
600
+ + out += "{\"schema\":\"";
601
+ + out += SCHEMA_NAME;
602
+ + out += "\",\"schema_version\":";
603
+ + append_integer(out, SCHEMA_VERSION);
604
+ + out += ",\"record\":";
605
+ + append_json_string(out, record);
606
+ +}
607
+ +
608
+ +static size_t bounded_name_length(const char * name) {
609
+ + size_t length = 0;
610
+ + while (length < GGML_MAX_NAME && name[length] != '\0') {
611
+ + ++length;
612
+ + }
613
+ + return length;
614
+ +}
615
+ +
616
+ +static std::string_view tensor_name(const ggml_tensor * tensor) {
617
+ + if (!tensor) {
618
+ + return {};
619
+ + }
620
+ + return std::string_view(tensor->name, bounded_name_length(tensor->name));
621
+ +}
622
+ +
623
+ +static std::string lowercase(std::string_view value) {
624
+ + std::string result;
625
+ + result.reserve(value.size());
626
+ + for (const unsigned char c : value) {
627
+ + if (c >= 'A' && c <= 'Z') {
628
+ + result.push_back(static_cast<char>(c - 'A' + 'a'));
629
+ + } else {
630
+ + result.push_back(static_cast<char>(c));
631
+ + }
632
+ + }
633
+ + return result;
634
+ +}
635
+ +
636
+ +static bool has_text(std::string_view value, std::string_view needle) {
637
+ + return value.find(needle) != std::string_view::npos;
638
+ +}
639
+ +
640
+ +static void collect_related_names(const ggml_tensor * tensor, std::vector<std::string_view> & names) {
641
+ + if (!tensor) {
642
+ + return;
643
+ + }
644
+ + if (!tensor_name(tensor).empty()) {
645
+ + names.push_back(tensor_name(tensor));
646
+ + }
647
+ + if (tensor->view_src && !tensor_name(tensor->view_src).empty()) {
648
+ + names.push_back(tensor_name(tensor->view_src));
649
+ + }
650
+ + for (int i = 0; i < GGML_MAX_SRC; ++i) {
651
+ + const ggml_tensor * src = tensor->src[i];
652
+ + if (!src) {
653
+ + continue;
654
+ + }
655
+ + if (!tensor_name(src).empty()) {
656
+ + names.push_back(tensor_name(src));
657
+ + }
658
+ + if (src->view_src && !tensor_name(src->view_src).empty()) {
659
+ + names.push_back(tensor_name(src->view_src));
660
+ + }
661
+ + }
662
+ +}
663
+ +
664
+ +static bool related_names_contain(const ggml_tensor * tensor, std::string_view needle) {
665
+ + std::vector<std::string_view> names;
666
+ + collect_related_names(tensor, names);
667
+ + for (const auto name : names) {
668
+ + if (has_text(lowercase(name), needle)) {
669
+ + return true;
670
+ + }
671
+ + }
672
+ + return false;
673
+ +}
674
+ +
675
+ +static bool parse_decimal_at(std::string_view name, size_t offset, int & value) {
676
+ + if (offset >= name.size() || name[offset] < '0' || name[offset] > '9') {
677
+ + return false;
678
+ + }
679
+ + uint64_t parsed = 0;
680
+ + size_t i = offset;
681
+ + while (i < name.size() && name[i] >= '0' && name[i] <= '9') {
682
+ + parsed = parsed * 10 + static_cast<unsigned>(name[i] - '0');
683
+ + if (parsed > static_cast<uint64_t>(std::numeric_limits<int>::max())) {
684
+ + return false;
685
+ + }
686
+ + ++i;
687
+ + }
688
+ + value = static_cast<int>(parsed);
689
+ + return true;
690
+ +}
691
+ +
692
+ +static bool parse_layer_from_name(std::string_view name, int & layer) {
693
+ + const size_t dash = name.rfind('-');
694
+ + if (dash != std::string_view::npos && dash + 1 < name.size()) {
695
+ + int parsed = -1;
696
+ + if (parse_decimal_at(name, dash + 1, parsed)) {
697
+ + size_t end = dash + 1;
698
+ + while (end < name.size() && name[end] >= '0' && name[end] <= '9') {
699
+ + ++end;
700
+ + }
701
+ + if (end == name.size()) {
702
+ + layer = parsed;
703
+ + return true;
704
+ + }
705
+ + }
706
+ + }
707
+ +
708
+ + const size_t block = name.find("blk.");
709
+ + if (block != std::string_view::npos && parse_decimal_at(name, block + 4, layer)) {
710
+ + return true;
711
+ + }
712
+ +
713
+ + if (has_text(lowercase(name), "cache_")) {
714
+ + const size_t marker = name.rfind("_l");
715
+ + if (marker != std::string_view::npos && parse_decimal_at(name, marker + 2, layer)) {
716
+ + return true;
717
+ + }
718
+ + }
719
+ + return false;
720
+ +}
721
+ +
722
+ +static int tensor_layer(const ggml_tensor * tensor) {
723
+ + int layer = -1;
724
+ + if (parse_layer_from_name(tensor_name(tensor), layer)) {
725
+ + return layer;
726
+ + }
727
+ + std::vector<std::string_view> names;
728
+ + collect_related_names(tensor, names);
729
+ + for (const auto name : names) {
730
+ + if (parse_layer_from_name(name, layer)) {
731
+ + return layer;
732
+ + }
733
+ + }
734
+ + return -1;
735
+ +}
736
+ +
737
+ +static void append_shape(std::string & out, const ggml_tensor * tensor) {
738
+ + out.push_back('[');
739
+ + for (int i = 0; i < GGML_MAX_DIMS; ++i) {
740
+ + if (i != 0) {
741
+ + out.push_back(',');
742
+ + }
743
+ + append_integer(out, tensor->ne[i]);
744
+ + }
745
+ + out.push_back(']');
746
+ +}
747
+ +
748
+ +static void append_token_ids(std::string & out, const std::vector<llama_token> & tokens) {
749
+ + out.push_back('[');
750
+ + for (size_t i = 0; i < tokens.size(); ++i) {
751
+ + if (i != 0) {
752
+ + out.push_back(',');
753
+ + }
754
+ + append_integer(out, tokens[i]);
755
+ + }
756
+ + out.push_back(']');
757
+ +}
758
+ +
759
+ +class graph_observer {
760
+ +public:
761
+ + graph_observer(observer_mode mode, int32_t n_layers) : mode_(mode), n_layers_(n_layers) {}
762
+ +
763
+ + void set_phase(const char * phase, int64_t step) {
764
+ + phase_ = phase;
765
+ + phase_step_ = step;
766
+ + }
767
+ +
768
+ + bool failed() const {
769
+ + return failed_;
770
+ + }
771
+ +
772
+ + const std::string & error() const {
773
+ + return error_;
774
+ + }
775
+ +
776
+ + uint64_t event_count() const {
777
+ + return event_sequence_;
778
+ + }
779
+ +
780
+ + static bool callback(ggml_tensor * tensor, bool ask, void * user_data) noexcept {
781
+ + auto * observer = static_cast<graph_observer *>(user_data);
782
+ + try {
783
+ + return observer->on_tensor(tensor, ask);
784
+ + } catch (const std::exception & exception) {
785
+ + observer->fail(std::string("observer exception: ") + exception.what());
786
+ + } catch (...) {
787
+ + observer->fail("observer exception: unknown");
788
+ + }
789
+ + return false;
790
+ + }
791
+ +
792
+ +private:
793
+ + observer_mode mode_;
794
+ + int32_t n_layers_;
795
+ + std::string phase_ = "uninitialized";
796
+ + int64_t phase_step_ = -1;
797
+ + uint64_t event_sequence_ = 0;
798
+ + bool failed_ = false;
799
+ + std::string error_;
800
+ +
801
+ + // Kernel-level dispatch capture (Metal). Every compute dispatch is appended
802
+ + // here by the backend hook; each GEMM node is then attributed to the actual
803
+ + // matmul kernel dispatch that produced it (validated 1:1 on-device).
804
+ + struct kdispatch {
805
+ + std::string kernel;
806
+ + int tg[3];
807
+ + int tptg[3];
808
+ + };
809
+ + std::vector<kdispatch> dispatches_;
810
+ + size_t processed_dispatches_ = 0;
811
+ + bool have_kernel_ = false;
812
+ + kdispatch current_kernel_{};
813
+ +
814
+ +public:
815
+ + // Called by the ggml-metal dispatch hook for every compute dispatch.
816
+ + void on_dispatch(const char * kernel, int tg0, int tg1, int tg2, int tptg0, int tptg1, int tptg2) {
817
+ + kdispatch d;
818
+ + d.kernel = kernel ? kernel : "";
819
+ + d.tg[0] = tg0; d.tg[1] = tg1; d.tg[2] = tg2;
820
+ + d.tptg[0] = tptg0; d.tptg[1] = tptg1; d.tptg[2] = tptg2;
821
+ + dispatches_.push_back(std::move(d));
822
+ + if (g_diag_enabled) {
823
+ + std::fprintf(stderr, "PALW_DIAG dispatch #%zu pipeline=%s tg=%d,%d,%d tptg=%d,%d,%d\n",
824
+ + dispatches_.size(), kernel ? kernel : "", tg0, tg1, tg2, tptg0, tptg1, tptg2);
825
+ + }
826
+ + }
827
+ +
828
+ + static void dispatch_hook(void * user_data, const char * pipeline,
829
+ + int tg0, int tg1, int tg2, int tptg0, int tptg1, int tptg2) {
830
+ + static_cast<graph_observer *>(user_data)->on_dispatch(
831
+ + pipeline, tg0, tg1, tg2, tptg0, tptg1, tptg2);
832
+ + }
833
+ +
834
+ +private:
835
+ + // Attributes the just-computed GEMM node to the last matmul (non-expert-id)
836
+ + // dispatch in its ASK->POST window. Expert GEMMs use distinct `*_id_*`
837
+ + // kernels and are excluded. Returns false (fail-closed) if none is found.
838
+ + bool resolve_gemm_kernel() {
839
+ + have_kernel_ = false;
840
+ + for (size_t i = dispatches_.size(); i > processed_dispatches_; --i) {
841
+ + const std::string & k = dispatches_[i - 1].kernel;
842
+ + const bool is_matmul =
843
+ + (k.find("mul_mv") != std::string::npos || k.find("mul_mm") != std::string::npos) &&
844
+ + k.find("_id") == std::string::npos;
845
+ + if (is_matmul) {
846
+ + current_kernel_ = dispatches_[i - 1];
847
+ + have_kernel_ = true;
848
+ + break;
849
+ + }
850
+ + }
851
+ + processed_dispatches_ = dispatches_.size();
852
+ + if (!have_kernel_) {
853
+ + fail("no matmul kernel dispatch found for GEMM node");
854
+ + return false;
855
+ + }
856
+ + return true;
857
+ + }
858
+ +
859
+ + void fail(std::string message) {
860
+ + if (!failed_) {
861
+ + failed_ = true;
862
+ + error_ = std::move(message);
863
+ + std::fprintf(stderr, "observer error: %s\n", error_.c_str());
864
+ + }
865
+ + }
866
+ +
867
+ + bool validate_tensor(const ggml_tensor * tensor, bool validate_op) {
868
+ + if (!tensor) {
869
+ + fail("null graph tensor");
870
+ + return false;
871
+ + }
872
+ + if (bounded_name_length(tensor->name) == GGML_MAX_NAME) {
873
+ + fail("graph tensor name is not terminated");
874
+ + return false;
875
+ + }
876
+ + const int type = static_cast<int>(tensor->type);
877
+ + if (type < 0 || type >= static_cast<int>(GGML_TYPE_COUNT)) {
878
+ + fail("graph tensor type is outside public ggml bounds");
879
+ + return false;
880
+ + }
881
+ + if (validate_op) {
882
+ + const int op = static_cast<int>(tensor->op);
883
+ + if (op < 0 || op >= static_cast<int>(GGML_OP_COUNT)) {
884
+ + fail("graph op is outside public ggml bounds");
885
+ + return false;
886
+ + }
887
+ + }
888
+ +
889
+ + // An empty (zero-element) tensor is valid graph metadata for recurrent
890
+ + // state gathers and carries no storage to validate.
891
+ + if (is_empty(tensor)) {
892
+ + return true;
893
+ + }
894
+ +
895
+ + uint64_t elements = 1;
896
+ + for (int i = 0; i < GGML_MAX_DIMS; ++i) {
897
+ + const uint64_t dimension = static_cast<uint64_t>(tensor->ne[i]);
898
+ + if (elements > static_cast<uint64_t>(std::numeric_limits<int64_t>::max()) / dimension) {
899
+ + fail("graph tensor element count overflows int64");
900
+ + return false;
901
+ + }
902
+ + elements *= dimension;
903
+ + }
904
+ + if (elements != static_cast<uint64_t>(ggml_nelements(tensor)) || ggml_nbytes(tensor) == 0) {
905
+ + fail("graph tensor storage bounds are inconsistent");
906
+ + return false;
907
+ + }
908
+ + return true;
909
+ + }
910
+ +
911
+ + bool validate_node(const ggml_tensor * tensor) {
912
+ + if (!validate_tensor(tensor, true)) {
913
+ + return false;
914
+ + }
915
+ + for (int i = 0; i < GGML_MAX_SRC; ++i) {
916
+ + if (tensor->src[i] && !validate_tensor(tensor->src[i], false)) {
917
+ + return false;
918
+ + }
919
+ + }
920
+ + const int layer = tensor_layer(tensor);
921
+ + if (layer >= n_layers_) {
922
+ + fail("graph layer id exceeds model layer count");
923
+ + return false;
924
+ + }
925
+ + if (is_gemm(tensor)) {
926
+ + if (!tensor->src[0] || !tensor->src[1]) {
927
+ + fail("GEMM node is missing an input");
928
+ + return false;
929
+ + }
930
+ + if (tensor->src[0]->ne[0] != tensor->src[1]->ne[0] ||
931
+ + tensor->ne[0] != tensor->src[0]->ne[1] ||
932
+ + tensor->ne[1] != tensor->src[1]->ne[1]) {
933
+ + fail("GEMM dimensions are inconsistent");
934
+ + return false;
935
+ + }
936
+ + }
937
+ + return true;
938
+ + }
939
+ +
940
+ + // Only the plain dense GEMM is sketched. Indirect expert GEMM
941
+ + // (GGML_OP_MUL_MAT_ID) is emitted as an ordinary metadata node; its
942
+ + // batched, id-indexed output layout is committed by the adapter as a
943
+ + // generic compute operation rather than an accumulator sketch.
944
+ + static bool is_gemm(const ggml_tensor * tensor) {
945
+ + return tensor->op == GGML_OP_MUL_MAT;
946
+ + }
947
+ +
948
+ + static bool is_empty(const ggml_tensor * tensor) {
949
+ + for (int i = 0; i < GGML_MAX_DIMS; ++i) {
950
+ + if (tensor->ne[i] <= 0) {
951
+ + return true;
952
+ + }
953
+ + }
954
+ + return false;
955
+ + }
956
+ +
957
+ + // The mixture-of-experts Top-K selection tensor: the concrete list of expert
958
+ + // indices chosen per token. Captured post-compute so the receipt commits the
959
+ + // real routing, not merely that routing of some shape occurred. Matched by
960
+ + // the llama.cpp `cb` label and the I32 index type.
961
+ + static bool is_route_tensor(const ggml_tensor * tensor) {
962
+ + return tensor->type == GGML_TYPE_I32 &&
963
+ + has_text(lowercase(tensor_name(tensor)), "ffn_moe_topk");
964
+ + }
965
+ +
966
+ + std::vector<std::string> categories(const ggml_tensor * tensor) const {
967
+ + std::vector<std::string> result;
968
+ + if (is_gemm(tensor)) {
969
+ + result.emplace_back("gemm");
970
+ + }
971
+ + if (tensor->op == GGML_OP_NORM || tensor->op == GGML_OP_RMS_NORM ||
972
+ + tensor->op == GGML_OP_GROUP_NORM || tensor->op == GGML_OP_L2_NORM) {
973
+ + result.emplace_back("norm");
974
+ + }
975
+ + if (tensor->op == GGML_OP_ROPE || tensor->op == GGML_OP_ROPE_BACK) {
976
+ + result.emplace_back("rope");
977
+ + }
978
+ + if (tensor->op == GGML_OP_FLASH_ATTN_EXT || tensor->op == GGML_OP_FLASH_ATTN_BACK ||
979
+ + related_names_contain(tensor, "attn") || related_names_contain(tensor, "qcur") ||
980
+ + related_names_contain(tensor, "kcur") || related_names_contain(tensor, "vcur") ||
981
+ + related_names_contain(tensor, "kq")) {
982
+ + result.emplace_back("attention");
983
+ + }
984
+ + if (related_names_contain(tensor, "cache_") || related_names_contain(tensor, "_cache")) {
985
+ + result.emplace_back("kv_cache");
986
+ + }
987
+ + if (result.empty()) {
988
+ + result.emplace_back("other");
989
+ + }
990
+ + return result;
991
+ + }
992
+ +
993
+ + static int magnitude_bucket(float value) {
994
+ + const float magnitude = std::fabs(value);
995
+ + if (magnitude == 0.0f) return 0;
996
+ + if (magnitude < 0.00390625f) return 1;
997
+ + if (magnitude < 0.0625f) return 2;
998
+ + if (magnitude < 0.25f) return 3;
999
+ + if (magnitude < 1.0f) return 4;
1000
+ + if (magnitude < 4.0f) return 5;
1001
+ + if (magnitude < 16.0f) return 6;
1002
+ + return 7;
1003
+ + }
1004
+ +
1005
+ + bool make_sketch(const ggml_tensor * tensor, std::string & sketch, size_t & copied_bytes, size_t & sampled) {
1006
+ + if (!tensor->buffer || !ggml_is_contiguous(tensor)) {
1007
+ + fail("GEMM output is not backed by a contiguous public backend tensor");
1008
+ + return false;
1009
+ + }
1010
+ +
1011
+ + size_t element_size = 0;
1012
+ + switch (tensor->type) {
1013
+ + case GGML_TYPE_F32: element_size = sizeof(float); break;
1014
+ + case GGML_TYPE_F16: element_size = sizeof(ggml_fp16_t); break;
1015
+ + case GGML_TYPE_BF16: element_size = sizeof(ggml_bf16_t); break;
1016
+ + default:
1017
+ + fail("GEMM output type is unsupported by sign/bucket sketch v1");
1018
+ + return false;
1019
+ + }
1020
+ +
1021
+ + const uint64_t n_elements = static_cast<uint64_t>(ggml_nelements(tensor));
1022
+ + sampled = static_cast<size_t>(std::min<uint64_t>(SKETCH_SAMPLES, n_elements));
1023
+ + if (sampled > std::numeric_limits<size_t>::max() / element_size) {
1024
+ + fail("GEMM sketch copy bound overflows size_t");
1025
+ + return false;
1026
+ + }
1027
+ + copied_bytes = sampled * element_size;
1028
+ + if (copied_bytes > ggml_nbytes(tensor)) {
1029
+ + fail("GEMM sketch copy exceeds tensor storage");
1030
+ + return false;
1031
+ + }
1032
+ +
1033
+ + std::vector<uint8_t> host(copied_bytes);
1034
+ + ggml_backend_tensor_get(tensor, host.data(), 0, copied_bytes);
1035
+ +
1036
+ + static constexpr char hex[] = "0123456789abcdef";
1037
+ + sketch.assign(SKETCH_SAMPLES, '0');
1038
+ + for (size_t i = 0; i < sampled; ++i) {
1039
+ + float value = 0.0f;
1040
+ + if (tensor->type == GGML_TYPE_F32) {
1041
+ + std::memcpy(&value, host.data() + i * element_size, sizeof(value));
1042
+ + } else if (tensor->type == GGML_TYPE_F16) {
1043
+ + ggml_fp16_t packed;
1044
+ + std::memcpy(&packed, host.data() + i * element_size, sizeof(packed));
1045
+ + value = ggml_fp16_to_fp32(packed);
1046
+ + } else {
1047
+ + ggml_bf16_t packed;
1048
+ + std::memcpy(&packed, host.data() + i * element_size, sizeof(packed));
1049
+ + value = ggml_bf16_to_fp32(packed);
1050
+ + }
1051
+ + if (!std::isfinite(value)) {
1052
+ + fail("GEMM sketch encountered a non-finite output");
1053
+ + return false;
1054
+ + }
1055
+ + const unsigned nibble = (std::signbit(value) ? 8u : 0u) |
1056
+ + static_cast<unsigned>(magnitude_bucket(value));
1057
+ + sketch[i] = hex[nibble];
1058
+ + }
1059
+ + return true;
1060
+ + }
1061
+ +
1062
+ + void append_tensor_metadata(std::string & out, const ggml_tensor * tensor) const {
1063
+ + out += "\"name\":";
1064
+ + append_json_string(out, tensor_name(tensor));
1065
+ + out += ",\"op\":";
1066
+ + append_json_string(out, ggml_op_name(tensor->op));
1067
+ + out += ",\"type\":";
1068
+ + append_json_string(out, ggml_type_name(tensor->type));
1069
+ + out += ",\"shape\":";
1070
+ + append_shape(out, tensor);
1071
+ + out += ",\"n_bytes\":";
1072
+ + append_integer(out, ggml_nbytes(tensor));
1073
+ + }
1074
+ +
1075
+ + bool emit_event(const ggml_tensor * tensor, const char * stage,
1076
+ + const std::string * sketch, size_t copied_bytes, size_t sampled) {
1077
+ + std::string line;
1078
+ + line.reserve(2048);
1079
+ + append_record_prefix(line, "event");
1080
+ + line += ",\"event_seq\":";
1081
+ + append_integer(line, event_sequence_++);
1082
+ + line += ",\"observer\":";
1083
+ + append_json_string(line, mode_name(mode_));
1084
+ + line += ",\"phase\":";
1085
+ + append_json_string(line, phase_);
1086
+ + line += ",\"phase_step\":";
1087
+ + append_integer(line, phase_step_);
1088
+ + line += ",\"stage\":";
1089
+ + append_json_string(line, stage);
1090
+ +
1091
+ + const int layer = tensor_layer(tensor);
1092
+ + line += ",\"layer\":";
1093
+ + if (layer < 0) {
1094
+ + line += "null";
1095
+ + } else {
1096
+ + append_integer(line, layer);
1097
+ + }
1098
+ +
1099
+ + line += ",\"categories\":[";
1100
+ + const auto node_categories = categories(tensor);
1101
+ + for (size_t i = 0; i < node_categories.size(); ++i) {
1102
+ + if (i != 0) {
1103
+ + line.push_back(',');
1104
+ + }
1105
+ + append_json_string(line, node_categories[i]);
1106
+ + }
1107
+ + line += "],\"tensor\":{";
1108
+ + append_tensor_metadata(line, tensor);
1109
+ + line += "},\"sources\":[";
1110
+ + bool first_source = true;
1111
+ + for (int i = 0; i < GGML_MAX_SRC; ++i) {
1112
+ + if (!tensor->src[i]) {
1113
+ + continue;
1114
+ + }
1115
+ + if (!first_source) {
1116
+ + line.push_back(',');
1117
+ + }
1118
+ + first_source = false;
1119
+ + line.push_back('{');
1120
+ + append_tensor_metadata(line, tensor->src[i]);
1121
+ + line.push_back('}');
1122
+ + }
1123
+ + line.push_back(']');
1124
+ +
1125
+ + if (is_gemm(tensor)) {
1126
+ + line += ",\"gemm\":{\"variant\":\"ggml_graph_op_v1\",\"m\":";
1127
+ + append_integer(line, tensor->src[0]->ne[1]);
1128
+ + line += ",\"n\":";
1129
+ + append_integer(line, tensor->src[1]->ne[1]);
1130
+ + line += ",\"k\":";
1131
+ + append_integer(line, tensor->src[0]->ne[0]);
1132
+ + line += ",\"batch_shape\":[";
1133
+ + append_integer(line, tensor->ne[2]);
1134
+ + line.push_back(',');
1135
+ + append_integer(line, tensor->ne[3]);
1136
+ + line += "]}";
1137
+ + }
1138
+ +
1139
+ + if (sketch) {
1140
+ + line += ",\"sketch\":{\"version\":\"sign_bucket_256_v1\",\"bits\":256,";
1141
+ + line += "\"encoding\":\"hex\",\"probe\":\"contiguous_prefix_64_v1\",";
1142
+ + line += "\"sample_count\":";
1143
+ + append_integer(line, sampled);
1144
+ + line += ",\"copied_bytes\":";
1145
+ + append_integer(line, copied_bytes);
1146
+ + line += ",\"value\":";
1147
+ + append_json_string(line, *sketch);
1148
+ + line += "},\"tile\":{\"variant\":\"graph_fallback_logical_prefix_v1\",";
1149
+ + line += "\"linear_offset\":0,\"linear_elements\":";
1150
+ + append_integer(line, sampled);
1151
+ + if (have_kernel_) {
1152
+ + // Kernel-level binding: the actual Metal compute pipeline (kernel)
1153
+ + // and its launch geometry that produced this GEMM output. This is
1154
+ + // launch-geometry + output-sketch bound to a real GPU dispatch,
1155
+ + // not a CUDA-style intra-kernel accumulator sketch.
1156
+ + line += "},\"kernel_trace\":{\"available\":true,\"backend\":\"metal\",";
1157
+ + line += "\"claim\":\"metal_kernel_launch_bound_v1\",\"kernel\":";
1158
+ + append_json_string(line, current_kernel_.kernel);
1159
+ + line += ",\"threadgroups\":[";
1160
+ + append_integer(line, current_kernel_.tg[0]);
1161
+ + line.push_back(',');
1162
+ + append_integer(line, current_kernel_.tg[1]);
1163
+ + line.push_back(',');
1164
+ + append_integer(line, current_kernel_.tg[2]);
1165
+ + line += "],\"threads_per_threadgroup\":[";
1166
+ + append_integer(line, current_kernel_.tptg[0]);
1167
+ + line.push_back(',');
1168
+ + append_integer(line, current_kernel_.tptg[1]);
1169
+ + line.push_back(',');
1170
+ + append_integer(line, current_kernel_.tptg[2]);
1171
+ + line += "]}";
1172
+ + } else {
1173
+ + line += "},\"kernel_trace\":{\"available\":false,\"backend\":\"none\",";
1174
+ + line += "\"claim\":\"not_a_cuda_kernel_trace\"}";
1175
+ + }
1176
+ + }
1177
+ +
1178
+ + line.push_back('}');
1179
+ + if (!write_json_line(line)) {
1180
+ + fail("stdout JSONL write failed");
1181
+ + return false;
1182
+ + }
1183
+ + return true;
1184
+ + }
1185
+ +
1186
+ + // Reads the mixture-of-experts Top-K selection tensor back from the compute
1187
+ + // backend and emits a "route" record carrying the real per-token selected
1188
+ + // expert indices. ne[0] is the number of experts selected per token (Top-K);
1189
+ + // the remaining dimensions are the token count.
1190
+ + bool emit_route(const ggml_tensor * tensor) {
1191
+ + if (!tensor->buffer) {
1192
+ + fail("route tensor has no backend buffer");
1193
+ + return false;
1194
+ + }
1195
+ + const uint64_t experts_used = static_cast<uint64_t>(tensor->ne[0]);
1196
+ + const uint64_t tokens = static_cast<uint64_t>(tensor->ne[1]) *
1197
+ + static_cast<uint64_t>(tensor->ne[2]) * static_cast<uint64_t>(tensor->ne[3]);
1198
+ + const uint64_t total = experts_used * tokens;
1199
+ + if (experts_used == 0 || tokens == 0 || total > MAX_ROUTE_INDICES) {
1200
+ + fail("route tensor shape is out of bounds");
1201
+ + return false;
1202
+ + }
1203
+ +
1204
+ + // Read each selected index using the tensor's byte strides, so a strided
1205
+ + // Top-K view of the argsort output is captured correctly.
1206
+ + std::vector<int32_t> indices;
1207
+ + indices.reserve(static_cast<size_t>(total));
1208
+ + for (uint64_t t = 0; t < tokens; ++t) {
1209
+ + for (uint64_t e = 0; e < experts_used; ++e) {
1210
+ + const size_t offset = static_cast<size_t>(e) * tensor->nb[0] +
1211
+ + static_cast<size_t>(t) * tensor->nb[1];
1212
+ + if (offset + sizeof(int32_t) > ggml_nbytes(tensor)) {
1213
+ + fail("route tensor read exceeds tensor storage");
1214
+ + return false;
1215
+ + }
1216
+ + int32_t value = 0;
1217
+ + ggml_backend_tensor_get(tensor, &value, offset, sizeof(int32_t));
1218
+ + indices.push_back(value);
1219
+ + }
1220
+ + }
1221
+ +
1222
+ + std::string line;
1223
+ + line.reserve(1024);
1224
+ + append_record_prefix(line, "route");
1225
+ + line += ",\"event_seq\":";
1226
+ + append_integer(line, event_sequence_++);
1227
+ + line += ",\"observer\":";
1228
+ + append_json_string(line, mode_name(mode_));
1229
+ + line += ",\"phase\":";
1230
+ + append_json_string(line, phase_);
1231
+ + line += ",\"phase_step\":";
1232
+ + append_integer(line, phase_step_);
1233
+ + const int layer = tensor_layer(tensor);
1234
+ + line += ",\"layer\":";
1235
+ + if (layer < 0) {
1236
+ + line += "null";
1237
+ + } else {
1238
+ + append_integer(line, layer);
1239
+ + }
1240
+ + line += ",\"experts_used\":";
1241
+ + append_integer(line, experts_used);
1242
+ + line += ",\"tokens\":";
1243
+ + append_integer(line, tokens);
1244
+ + line += ",\"selected_experts\":[";
1245
+ + for (size_t i = 0; i < indices.size(); ++i) {
1246
+ + if (i != 0) {
1247
+ + line.push_back(',');
1248
+ + }
1249
+ + append_integer(line, indices[i]);
1250
+ + }
1251
+ + line += "]}";
1252
+ + if (!write_json_line(line)) {
1253
+ + fail("stdout JSONL write failed");
1254
+ + return false;
1255
+ + }
1256
+ + return true;
1257
+ + }
1258
+ +
1259
+ + bool on_tensor(ggml_tensor * tensor, bool ask) {
1260
+ + if (failed_ || mode_ == observer_mode::off) {
1261
+ + return false;
1262
+ + }
1263
+ + // Recurrent (state-space / gated-delta-net) layers gather an initially
1264
+ + // empty state cache, producing legitimate zero-element graph nodes. They
1265
+ + // perform no compute, so they are skipped rather than treated as errors.
1266
+ + if (tensor && is_empty(tensor)) {
1267
+ + return false;
1268
+ + }
1269
+ + if (!validate_node(tensor)) {
1270
+ + return false;
1271
+ + }
1272
+ +
1273
+ + if (g_diag_enabled && is_gemm(tensor)) {
1274
+ + std::fprintf(stderr, "PALW_DIAG %s MUL_MAT node=%.*s layer=%d dispatch#=%zu\n",
1275
+ + ask ? "ASK " : "POST", (int) tensor_name(tensor).size(), tensor_name(tensor).data(),
1276
+ + tensor_layer(tensor), dispatches_.size());
1277
+ + }
1278
+ +
1279
+ + if (ask) {
1280
+ + if (mode_ == observer_mode::graph) {
1281
+ + emit_event(tensor, "ask_metadata", nullptr, 0, 0);
1282
+ + return false;
1283
+ + }
1284
+ + if (is_gemm(tensor)) {
1285
+ + return true;
1286
+ + }
1287
+ + // Sketch mode also reads back the mixture-of-experts Top-K selection
1288
+ + // so the receipt commits the real routing content.
1289
+ + if (is_route_tensor(tensor)) {
1290
+ + return true;
1291
+ + }
1292
+ + emit_event(tensor, "ask_metadata", nullptr, 0, 0);
1293
+ + return false;
1294
+ + }
1295
+ +
1296
+ + if (mode_ != observer_mode::sketch) {
1297
+ + fail("unexpected post-compute callback");
1298
+ + return false;
1299
+ + }
1300
+ + if (is_route_tensor(tensor)) {
1301
+ + return emit_route(tensor);
1302
+ + }
1303
+ + if (!is_gemm(tensor)) {
1304
+ + fail("unexpected post-compute callback");
1305
+ + return false;
1306
+ + }
1307
+ +
1308
+ + // Bind this GEMM to the actual Metal matmul kernel dispatch that produced
1309
+ + // it before sketching its output.
1310
+ + if (!resolve_gemm_kernel()) {
1311
+ + return false;
1312
+ + }
1313
+ + std::string sketch;
1314
+ + size_t copied_bytes = 0;
1315
+ + size_t sampled = 0;
1316
+ + if (!make_sketch(tensor, sketch, copied_bytes, sampled)) {
1317
+ + return false;
1318
+ + }
1319
+ + return emit_event(tensor, "post_compute_sketch", &sketch, copied_bytes, sampled);
1320
+ + }
1321
+ +};
1322
+ +
1323
+ +static bool get_model_string(const llama_model * model, int32_t index, bool key, std::string & value) {
1324
+ + std::vector<char> buffer(256);
1325
+ + for (int attempt = 0; attempt < 3; ++attempt) {
1326
+ + const int32_t length = key
1327
+ + ? llama_model_meta_key_by_index(model, index, buffer.data(), buffer.size())
1328
+ + : llama_model_meta_val_str_by_index(model, index, buffer.data(), buffer.size());
1329
+ + if (length < 0) {
1330
+ + return false;
1331
+ + }
1332
+ + if (static_cast<size_t>(length) < buffer.size()) {
1333
+ + value.assign(buffer.data(), static_cast<size_t>(length));
1334
+ + return true;
1335
+ + }
1336
+ + buffer.resize(static_cast<size_t>(length) + 1);
1337
+ + }
1338
+ + return false;
1339
+ +}
1340
+ +
1341
+ +static bool read_model_metadata(const llama_model * model, model_metadata & metadata) {
1342
+ + const int32_t count = llama_model_meta_count(model);
1343
+ + if (count < 0 || count > 100000) {
1344
+ + std::fprintf(stderr, "error: model metadata count is outside bounds\n");
1345
+ + return false;
1346
+ + }
1347
+ + metadata.entries.reserve(static_cast<size_t>(count));
1348
+ + for (int32_t i = 0; i < count; ++i) {
1349
+ + std::string key;
1350
+ + std::string value;
1351
+ + if (!get_model_string(model, i, true, key) || !get_model_string(model, i, false, value)) {
1352
+ + std::fprintf(stderr, "error: failed to read model metadata index %d\n", i);
1353
+ + return false;
1354
+ + }
1355
+ + metadata.entries.emplace_back(std::move(key), std::move(value));
1356
+ + }
1357
+ + return true;
1358
+ +}
1359
+ +
1360
+ +static const std::string * find_metadata(const model_metadata & metadata, const char * key) {
1361
+ + for (const auto & entry : metadata.entries) {
1362
+ + if (entry.first == key) {
1363
+ + return &entry.second;
1364
+ + }
1365
+ + }
1366
+ + return nullptr;
1367
+ +}
1368
+ +
1369
+ +static bool validate_qwen36_35b_a3b_profile(const llama_model * model, const model_metadata & metadata) {
1370
+ + const std::string * architecture = find_metadata(metadata, "general.architecture");
1371
+ + const llama_vocab * vocab = llama_model_get_vocab(model);
1372
+ + if (!architecture || *architecture != "qwen35moe" ||
1373
+ + llama_model_n_layer(model) != 40 ||
1374
+ + llama_model_n_embd(model) != 2048 ||
1375
+ + llama_vocab_n_tokens(vocab) != 248320 ||
1376
+ + llama_model_has_encoder(model) || !llama_model_has_decoder(model)) {
1377
+ + std::fprintf(stderr,
1378
+ + "error: model is not the supported Qwen3.6-35B-A3B MoE profile "
1379
+ + "(qwen35moe, 40 layers, 2048 hidden, 248320 vocab); observed "
1380
+ + "arch=%s layers=%d embd=%d head=%d head_kv=%d vocab=%d\n",
1381
+ + architecture ? architecture->c_str() : "(none)",
1382
+ + llama_model_n_layer(model),
1383
+ + llama_model_n_embd(model),
1384
+ + llama_model_n_head(model),
1385
+ + llama_model_n_head_kv(model),
1386
+ + llama_vocab_n_tokens(vocab));
1387
+ + return false;
1388
+ + }
1389
+ + return true;
1390
+ +}
1391
+ +
1392
+ +static const char * device_type_name(enum ggml_backend_dev_type type) {
1393
+ + switch (type) {
1394
+ + case GGML_BACKEND_DEVICE_TYPE_CPU: return "cpu";
1395
+ + case GGML_BACKEND_DEVICE_TYPE_GPU: return "gpu";
1396
+ + case GGML_BACKEND_DEVICE_TYPE_IGPU: return "igpu";
1397
+ + case GGML_BACKEND_DEVICE_TYPE_ACCEL: return "accelerator";
1398
+ + case GGML_BACKEND_DEVICE_TYPE_META: return "meta";
1399
+ + }
1400
+ + return "unknown";
1401
+ +}
1402
+ +
1403
+ +static bool emit_header(const options & opts, const llama_model * model, const llama_context * context,
1404
+ + const model_metadata & metadata, size_t prompt_tokens) {
1405
+ + char description[1024] = {};
1406
+ + const int32_t description_length = llama_model_desc(model, description, sizeof(description));
1407
+ + if (description_length < 0 || static_cast<size_t>(description_length) >= sizeof(description)) {
1408
+ + std::fprintf(stderr, "error: model description exceeds header bound\n");
1409
+ + return false;
1410
+ + }
1411
+ +
1412
+ + std::string line;
1413
+ + line.reserve(32768);
1414
+ + append_record_prefix(line, "header");
1415
+ + line += ",\"observer\":";
1416
+ + append_json_string(line, mode_name(opts.mode));
1417
+ + line += ",\"trace_variant\":";
1418
+ + if (opts.mode == observer_mode::off) {
1419
+ + append_json_string(line, "none");
1420
+ + } else if (opts.mode == observer_mode::graph) {
1421
+ + append_json_string(line, "ggml_sched_ask_metadata_v1");
1422
+ + } else {
1423
+ + append_json_string(line, "ggml_sched_fixed_prefix_sketch_v1");
1424
+ + }
1425
+ + line += ",\"cuda_kernel_trace\":false";
1426
+ +
1427
+ + line += ",\"model\":{\"path\":";
1428
+ + append_json_string(line, opts.model_path);
1429
+ + line += ",\"description\":";
1430
+ + append_json_string(line, description);
1431
+ + line += ",\"tensor_size_bytes\":";
1432
+ + append_integer(line, llama_model_size(model));
1433
+ + line += ",\"parameter_count\":";
1434
+ + append_integer(line, llama_model_n_params(model));
1435
+ + line += ",\"file_type\":";
1436
+ + append_integer(line, static_cast<int>(llama_model_ftype(model)));
1437
+ + line += ",\"n_ctx_train\":";
1438
+ + append_integer(line, llama_model_n_ctx_train(model));
1439
+ + line += ",\"n_embd\":";
1440
+ + append_integer(line, llama_model_n_embd(model));
1441
+ + line += ",\"n_layer\":";
1442
+ + append_integer(line, llama_model_n_layer(model));
1443
+ + line += ",\"n_head\":";
1444
+ + append_integer(line, llama_model_n_head(model));
1445
+ + line += ",\"n_head_kv\":";
1446
+ + append_integer(line, llama_model_n_head_kv(model));
1447
+ + line += ",\"n_vocab\":";
1448
+ + append_integer(line, llama_vocab_n_tokens(llama_model_get_vocab(model)));
1449
+ + line += ",\"rope_type\":";
1450
+ + append_integer(line, static_cast<int>(llama_model_rope_type(model)));
1451
+ + line += ",\"rope_freq_scale_train\":";
1452
+ + append_float(line, llama_model_rope_freq_scale_train(model));
1453
+ + line += ",\"metadata\":[";
1454
+ + for (size_t i = 0; i < metadata.entries.size(); ++i) {
1455
+ + if (i != 0) {
1456
+ + line.push_back(',');
1457
+ + }
1458
+ + line += "{\"key\":";
1459
+ + append_json_string(line, metadata.entries[i].first);
1460
+ + line += ",\"value\":";
1461
+ + append_json_string(line, metadata.entries[i].second);
1462
+ + line.push_back('}');
1463
+ + }
1464
+ + line += "]}";
1465
+ +
1466
+ + line += ",\"runtime\":{\"ggml_version\":";
1467
+ + append_json_string(line, ggml_version());
1468
+ + line += ",\"ggml_commit\":";
1469
+ + append_json_string(line, ggml_commit());
1470
+ + line += ",\"system_info\":";
1471
+ + append_json_string(line, llama_print_system_info());
1472
+ + line += ",\"supports_gpu_offload\":";
1473
+ + append_bool(line, llama_supports_gpu_offload());
1474
+ + line += ",\"requested_gpu_layers\":";
1475
+ + append_integer(line, opts.n_gpu_layers);
1476
+ + line += ",\"devices\":[";
1477
+ + const size_t device_count = ggml_backend_dev_count();
1478
+ + for (size_t i = 0; i < device_count; ++i) {
1479
+ + if (i != 0) {
1480
+ + line.push_back(',');
1481
+ + }
1482
+ + const ggml_backend_dev_t device = ggml_backend_dev_get(i);
1483
+ + ggml_backend_dev_props properties = {};
1484
+ + ggml_backend_dev_get_props(device, &properties);
1485
+ + line += "{\"name\":";
1486
+ + append_json_string(line, properties.name ? properties.name : "");
1487
+ + line += ",\"description\":";
1488
+ + append_json_string(line, properties.description ? properties.description : "");
1489
+ + line += ",\"type\":";
1490
+ + append_json_string(line, device_type_name(properties.type));
1491
+ + line += ",\"memory_free_observed\":";
1492
+ + append_integer(line, properties.memory_free);
1493
+ + line += ",\"memory_total\":";
1494
+ + append_integer(line, properties.memory_total);
1495
+ + line.push_back('}');
1496
+ + }
1497
+ + line += "]}";
1498
+ +
1499
+ + line += ",\"execution_policy\":{\"sampling\":\"greedy\",\"temperature\":0,";
1500
+ + line += "\"top_p\":1,\"top_k\":0,\"batch\":1,\"request_batch\":1,\"n_batch\":";
1501
+ + append_integer(line, llama_n_batch(context));
1502
+ + line += ",\"n_ubatch\":";
1503
+ + append_integer(line, llama_n_ubatch(context));
1504
+ + line += ",\"parallel\":1,\"parallel_sequences\":";
1505
+ + append_integer(line, llama_n_seq_max(context));
1506
+ + line += ",\"tensor_parallel\":1,\"split_mode\":\"none\",\"scheduler_parallel\":false,";
1507
+ + line += "\"tensor_repack\":false,";
1508
+ + line += "\"context_shift\":false,\"speculation\":false,\"flash_attention\":false,";
1509
+ + line += "\"threads\":1,\"threads_batch\":1,\"n_predict\":";
1510
+ + append_integer(line, opts.n_predict);
1511
+ + line += ",\"n_ctx\":";
1512
+ + append_integer(line, llama_n_ctx(context));
1513
+ + line += ",\"prompt_tokens\":";
1514
+ + append_integer(line, prompt_tokens);
1515
+ + line += ",\"tokenization\":{\"add_special\":true,\"parse_special\":true}}";
1516
+ +
1517
+ + line += ",\"observation_policy\":{\"read_only\":true,";
1518
+ + line += "\"graph_metadata_stage\":\"ask\",\"sketch_bits\":256,";
1519
+ + line += "\"sketch_probe\":\"gemm_output_contiguous_prefix_64\",";
1520
+ + line += "\"raw_activation_values_published\":false,";
1521
+ + line += "\"tile_variant\":\"graph_fallback_logical_prefix_v1\",";
1522
+ + line += "\"kernel_trace_claim\":\"none\"}";
1523
+ + line.push_back('}');
1524
+ + return write_json_line(line);
1525
+ +}
1526
+ +
1527
+ +static bool tokenize_prompt(const llama_vocab * vocab, const std::string & prompt,
1528
+ + std::vector<llama_token> & tokens) {
1529
+ + const int32_t length = static_cast<int32_t>(prompt.size());
1530
+ + const int32_t required = llama_tokenize(vocab, prompt.data(), length, nullptr, 0, true, true);
1531
+ + if (required == std::numeric_limits<int32_t>::min()) {
1532
+ + std::fprintf(stderr, "error: tokenizer result overflow\n");
1533
+ + return false;
1534
+ + }
1535
+ + const int32_t count = required < 0 ? -required : required;
1536
+ + if (count <= 0) {
1537
+ + std::fprintf(stderr, "error: prompt tokenization produced no tokens\n");
1538
+ + return false;
1539
+ + }
1540
+ + tokens.resize(static_cast<size_t>(count));
1541
+ + const int32_t actual = llama_tokenize(vocab, prompt.data(), length,
1542
+ + tokens.data(), count, true, true);
1543
+ + if (actual != count) {
1544
+ + std::fprintf(stderr, "error: prompt tokenization was not stable across sizing calls\n");
1545
+ + return false;
1546
+ + }
1547
+ + return true;
1548
+ +}
1549
+ +
1550
+ +static bool append_token_piece(const llama_vocab * vocab, llama_token token,
1551
+ + std::vector<uint8_t> & output) {
1552
+ + std::array<char, 64> small = {};
1553
+ + int32_t length = llama_token_to_piece(vocab, token, small.data(), small.size(), 0, false);
1554
+ + if (length >= 0) {
1555
+ + output.insert(output.end(), small.begin(), small.begin() + length);
1556
+ + return true;
1557
+ + }
1558
+ + if (length == std::numeric_limits<int32_t>::min()) {
1559
+ + return false;
1560
+ + }
1561
+ + const int32_t required = -length;
1562
+ + std::vector<char> buffer(static_cast<size_t>(required));
1563
+ + length = llama_token_to_piece(vocab, token, buffer.data(), required, 0, false);
1564
+ + if (length != required) {
1565
+ + return false;
1566
+ + }
1567
+ + output.insert(output.end(), buffer.begin(), buffer.end());
1568
+ + return true;
1569
+ +}
1570
+ +
1571
+ +static bool emit_result(const options & opts, const char * status, const char * stop_reason,
1572
+ + const std::vector<llama_token> & prompt_tokens,
1573
+ + const std::vector<llama_token> & generated_tokens,
1574
+ + const std::vector<uint8_t> & output_bytes,
1575
+ + const graph_observer & observer, const std::string & error) {
1576
+ + std::string line;
1577
+ + line.reserve(1024 + prompt_tokens.size() * 12 + generated_tokens.size() * 12 + output_bytes.size() * 4);
1578
+ + append_record_prefix(line, "result");
1579
+ + line += ",\"status\":";
1580
+ + append_json_string(line, status);
1581
+ + line += ",\"observer\":";
1582
+ + append_json_string(line, mode_name(opts.mode));
1583
+ + line += ",\"stop_reason\":";
1584
+ + append_json_string(line, stop_reason);
1585
+ + line += ",\"prompt_token_ids\":";
1586
+ + append_token_ids(line, prompt_tokens);
1587
+ + line += ",\"generated_token_ids\":";
1588
+ + append_token_ids(line, generated_tokens);
1589
+ + line += ",\"output_bytes\":[";
1590
+ + const size_t published_output_bytes = opts.emit_output_bytes ? output_bytes.size() : 0;
1591
+ + for (size_t i = 0; i < published_output_bytes; ++i) {
1592
+ + if (i != 0) {
1593
+ + line.push_back(',');
1594
+ + }
1595
+ + append_integer(line, static_cast<unsigned>(output_bytes[i]));
1596
+ + }
1597
+ + line += "],\"output_n_bytes\":";
1598
+ + append_integer(line, published_output_bytes);
1599
+ + line += ",\"event_count\":";
1600
+ + append_integer(line, observer.event_count());
1601
+ + if (!error.empty()) {
1602
+ + line += ",\"error\":";
1603
+ + append_json_string(line, error);
1604
+ + }
1605
+ + line.push_back('}');
1606
+ + return write_json_line(line);
1607
+ +}
1608
+ +
1609
+ +struct backend_guard {
1610
+ + ~backend_guard() {
1611
+ + llama_backend_free();
1612
+ + }
1613
+ +};
1614
+ +
1615
+ +} // namespace
1616
+ +
1617
+ +int main(int argc, char ** argv) {
1618
+ + std::setlocale(LC_NUMERIC, "C");
1619
+ + llama_log_set(log_callback, nullptr);
1620
+ +
1621
+ + options opts;
1622
+ + bool help = false;
1623
+ + bool version = false;
1624
+ + if (!parse_options(argc, argv, opts, help, version)) {
1625
+ + print_usage(argv[0]);
1626
+ + return 2;
1627
+ + }
1628
+ + if (version) {
1629
+ + std::fprintf(stderr, "version: %d (%s)\n", llama_build_number(), llama_commit());
1630
+ + return 0;
1631
+ + }
1632
+ + if (help) {
1633
+ + print_usage(argv[0]);
1634
+ + return 0;
1635
+ + }
1636
+ +
1637
+ + llama_backend_init();
1638
+ + backend_guard backend_cleanup;
1639
+ + ggml_backend_load_all();
1640
+ +
1641
+ + llama_model_params model_params = llama_model_default_params();
1642
+ + model_params.n_gpu_layers = opts.n_gpu_layers;
1643
+ + model_params.split_mode = LLAMA_SPLIT_MODE_NONE;
1644
+ + model_params.main_gpu = 0;
1645
+ + model_params.use_mmap = true;
1646
+ + model_params.use_mlock = false;
1647
+ + model_params.check_tensors = true;
1648
+ + model_params.use_extra_bufts = false;
1649
+ +
1650
+ + using model_ptr = std::unique_ptr<llama_model, decltype(&llama_model_free)>;
1651
+ + model_ptr model(llama_model_load_from_file(opts.model_path.c_str(), model_params), llama_model_free);
1652
+ + if (!model) {
1653
+ + std::fprintf(stderr, "error: failed to load model\n");
1654
+ + return 3;
1655
+ + }
1656
+ +
1657
+ + model_metadata metadata;
1658
+ + if (!read_model_metadata(model.get(), metadata) || !validate_qwen36_35b_a3b_profile(model.get(), metadata)) {
1659
+ + return 3;
1660
+ + }
1661
+ +
1662
+ + const llama_vocab * vocab = llama_model_get_vocab(model.get());
1663
+ + std::vector<llama_token> prompt_tokens;
1664
+ + if (!tokenize_prompt(vocab, opts.prompt, prompt_tokens)) {
1665
+ + return 3;
1666
+ + }
1667
+ +
1668
+ + const uint64_t required_context = prompt_tokens.size() + static_cast<uint64_t>(opts.n_predict);
1669
+ + if (required_context > PALW_CONTEXT_TOKENS ||
1670
+ + PALW_CONTEXT_TOKENS > static_cast<uint64_t>(llama_model_n_ctx_train(model.get()))) {
1671
+ + std::fprintf(stderr, "error: prompt plus n-predict exceeds the fixed PALW context bound\n");
1672
+ + return 3;
1673
+ + }
1674
+ +
1675
+ + graph_observer observer(opts.mode, llama_model_n_layer(model.get()));
1676
+ + llama_context_params context_params = llama_context_default_params();
1677
+ + context_params.n_ctx = PALW_CONTEXT_TOKENS;
1678
+ + context_params.n_batch = 1;
1679
+ + context_params.n_ubatch = 1;
1680
+ + context_params.n_seq_max = 1;
1681
+ + context_params.n_outputs_max = 1;
1682
+ + context_params.n_threads = 1;
1683
+ + context_params.n_threads_batch = 1;
1684
+ + context_params.flash_attn_type = LLAMA_FLASH_ATTN_TYPE_DISABLED;
1685
+ + context_params.type_k = GGML_TYPE_F16;
1686
+ + context_params.type_v = GGML_TYPE_F16;
1687
+ + context_params.embeddings = false;
1688
+ + context_params.offload_kqv = true;
1689
+ + context_params.no_perf = true;
1690
+ + context_params.op_offload = true;
1691
+ + context_params.kv_unified = false;
1692
+ + if (opts.mode != observer_mode::off) {
1693
+ + context_params.cb_eval = graph_observer::callback;
1694
+ + context_params.cb_eval_user_data = &observer;
1695
+ + g_diag_enabled = std::getenv("PALW_TRACE_DIAG") != nullptr;
1696
+ + // Capture every Metal kernel dispatch so GEMMs can be bound to the actual
1697
+ + // kernel + launch geometry that produced them (kernel-level trace).
1698
+ + if (opts.mode == observer_mode::sketch) {
1699
+ + ggml_metal_palw_set_dispatch_hook(graph_observer::dispatch_hook, &observer);
1700
+ + }
1701
+ + }
1702
+ +
1703
+ + using context_ptr = std::unique_ptr<llama_context, decltype(&llama_free)>;
1704
+ + context_ptr context(llama_init_from_model(model.get(), context_params), llama_free);
1705
+ + if (!context) {
1706
+ + std::fprintf(stderr, "error: failed to initialize context\n");
1707
+ + return 3;
1708
+ + }
1709
+ + if (llama_n_batch(context.get()) != 1 || llama_n_ubatch(context.get()) != 1 ||
1710
+ + llama_n_seq_max(context.get()) != 1 || llama_n_ctx(context.get()) != PALW_CONTEXT_TOKENS ||
1711
+ + llama_n_threads(context.get()) != 1 || llama_n_threads_batch(context.get()) != 1) {
1712
+ + std::fprintf(stderr, "error: runtime did not honor the deterministic execution policy\n");
1713
+ + return 3;
1714
+ + }
1715
+ +
1716
+ + if (!emit_header(opts, model.get(), context.get(), metadata, prompt_tokens.size())) {
1717
+ + return 4;
1718
+ + }
1719
+ +
1720
+ + std::vector<llama_token> generated_tokens;
1721
+ + std::vector<uint8_t> output_bytes;
1722
+ + generated_tokens.reserve(static_cast<size_t>(opts.n_predict));
1723
+ +
1724
+ + for (size_t i = 0; i < prompt_tokens.size(); ++i) {
1725
+ + observer.set_phase("prefill", static_cast<int64_t>(i));
1726
+ + llama_token token = prompt_tokens[i];
1727
+ + const int32_t decode_status = llama_decode(context.get(), llama_batch_get_one(&token, 1));
1728
+ + if (decode_status != 0) {
1729
+ + const std::string error = "llama_decode prefill status " + std::to_string(decode_status);
1730
+ + emit_result(opts, "error", "decode_error", prompt_tokens, generated_tokens,
1731
+ + output_bytes, observer, error);
1732
+ + return 5;
1733
+ + }
1734
+ + if (observer.failed()) {
1735
+ + emit_result(opts, "error", "observer_error", prompt_tokens, generated_tokens,
1736
+ + output_bytes, observer, observer.error());
1737
+ + return 5;
1738
+ + }
1739
+ + }
1740
+ +
1741
+ + using sampler_ptr = std::unique_ptr<llama_sampler, decltype(&llama_sampler_free)>;
1742
+ + sampler_ptr sampler(llama_sampler_init_greedy(), llama_sampler_free);
1743
+ + if (!sampler) {
1744
+ + emit_result(opts, "error", "sampler_error", prompt_tokens, generated_tokens,
1745
+ + output_bytes, observer, "failed to initialize greedy sampler");
1746
+ + return 5;
1747
+ + }
1748
+ +
1749
+ + const char * stop_reason = "n_predict";
1750
+ + for (int32_t i = 0; i < opts.n_predict; ++i) {
1751
+ + const llama_token token = llama_sampler_sample(sampler.get(), context.get(), -1);
1752
+ + if (token < 0 || token >= llama_vocab_n_tokens(vocab)) {
1753
+ + emit_result(opts, "error", "sampler_error", prompt_tokens, generated_tokens,
1754
+ + output_bytes, observer, "greedy sampler returned an out-of-range token");
1755
+ + return 5;
1756
+ + }
1757
+ + generated_tokens.push_back(token);
1758
+ + if (llama_vocab_is_eog(vocab, token)) {
1759
+ + stop_reason = "eog";
1760
+ + break;
1761
+ + }
1762
+ + if (!append_token_piece(vocab, token, output_bytes)) {
1763
+ + emit_result(opts, "error", "detokenize_error", prompt_tokens, generated_tokens,
1764
+ + output_bytes, observer, "failed to convert generated token to bytes");
1765
+ + return 5;
1766
+ + }
1767
+ + if (i + 1 == opts.n_predict) {
1768
+ + break;
1769
+ + }
1770
+ +
1771
+ + observer.set_phase("decode", i);
1772
+ + llama_token mutable_token = token;
1773
+ + const int32_t decode_status = llama_decode(context.get(), llama_batch_get_one(&mutable_token, 1));
1774
+ + if (decode_status != 0) {
1775
+ + const std::string error = "llama_decode generation status " + std::to_string(decode_status);
1776
+ + emit_result(opts, "error", "decode_error", prompt_tokens, generated_tokens,
1777
+ + output_bytes, observer, error);
1778
+ + return 5;
1779
+ + }
1780
+ + if (observer.failed()) {
1781
+ + emit_result(opts, "error", "observer_error", prompt_tokens, generated_tokens,
1782
+ + output_bytes, observer, observer.error());
1783
+ + return 5;
1784
+ + }
1785
+ + }
1786
+ +
1787
+ + if (!emit_result(opts, "ok", stop_reason, prompt_tokens, generated_tokens,
1788
+ + output_bytes, observer, {})) {
1789
+ + return 4;
1790
+ + }
1791
+ + return 0;
1792
+ +}
pyproject.toml ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ [project]
2
+ name = "misaka-palw-runtime"
3
+ version = "0.1.0"
4
+ description = "Model acquisition tooling for the MISAKA PALW Qwen3.6-35B-A3B runtime"
5
+ readme = "README.md"
6
+ requires-python = ">=3.12,<3.13"
7
+ dependencies = [
8
+ "huggingface-hub[hf-xet]>=0.30,<2",
9
+ ]
10
+
11
+ [tool.uv]
12
+ package = false
receipts/final-v5/ab2b3196a6c0935aafd4d563a9d2e1d71d828cc87a378ae77b8e49c102033b68.complete ADDED
@@ -0,0 +1,4 @@
 
 
 
 
 
1
+ misaka.palw.receipt-set.v2
2
+ receipt_id=ab2b3196a6c0935aafd4d563a9d2e1d71d828cc87a378ae77b8e49c102033b68
3
+ bundle_id=6fd4e57a6cbcd6fc1d9138989960b627c9ee4817bc3ac4ce889a1a1b41d7d63b
4
+ public_json_sha256=3aa158cacd9c790a85f550e232e1b5b3a5c3f1d81aaa0c5b56b57bb08f1dca22
receipts/final-v5/ab2b3196a6c0935aafd4d563a9d2e1d71d828cc87a378ae77b8e49c102033b68.json ADDED
@@ -0,0 +1,63 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "artifacts": {
3
+ "llama_commit": "12127defda4f41b7679cb2477a4b0d65ee6a0c8f",
4
+ "model_bytes": 5027783488,
5
+ "model_palw_root": "ad7d0e950531195bc2cf84f112fee6487777f78120c9a809cf9306c7a7a8684f",
6
+ "tokenizer_palw_root": "63839f0ab58084bbaa108a877e52bebd685b2c0616fcfab684a08354dee713dd"
7
+ },
8
+ "canonical_compute_units": 12135,
9
+ "canonical_receipt_file": "ab2b3196a6c0935aafd4d563a9d2e1d71d828cc87a378ae77b8e49c102033b68.palw",
10
+ "completion_marker": "ab2b3196a6c0935aafd4d563a9d2e1d71d828cc87a378ae77b8e49c102033b68.complete",
11
+ "cu_ruleset_id": "d8ef60255b3ba7ab12062942771b3e0ac9a674f151c3c321fe82c7d1fe52d299",
12
+ "decode_tokens": 2,
13
+ "durable_state_database": "palw-state.sqlite3",
14
+ "encrypted_verification_bundle": "ab2b3196a6c0935aafd4d563a9d2e1d71d828cc87a378ae77b8e49c102033b68.palw.bundle",
15
+ "evidence_level": "gemm_traced",
16
+ "execution_nullifier": "da2977c18f045718d8027301d8045e979db7d17b38d288daf6b897a4ebd0bad2",
17
+ "expires_epoch": 100,
18
+ "gemm_trace_root": "ebfd5d143ee57b1db20751ae4d241479fa9447cd5fcc7052fccce129604b78bc",
19
+ "issued_epoch": 1,
20
+ "job_class": "self_local",
21
+ "job_nullifier": "bb669cc73bb376766555e99592399a93b713ab190f3f9447a1f79046c19a0cbb",
22
+ "model_profile_id": "0c58c66b03bb471a248cb36be954b42945c6694c148370e6852f674ff98e64d4",
23
+ "network_id": "5314ef28b17106c232db89c7ada20d4e72f7d20bb95a7025c5c9abcec19055d9",
24
+ "observer_summary": {
25
+ "canonical_operations": 4890,
26
+ "decode_graph_steps": 1,
27
+ "gemm_events": 1625,
28
+ "prefill_graph_steps": 4
29
+ },
30
+ "operation_schedule_commitment": "6ee6163863df1a9a715bb42dc89d7431c13e0cb2538d022d074ca07c11aabab7",
31
+ "output_commitment": "ab778d40a2e00f8d047a5e5c79924e3667aad43c12af9aceea95044843353de8",
32
+ "owner_commitment": "eb8102e4a86b9636e528caa80926b17b5b2044a9d2c7ccf8bbcd650cefe0c406",
33
+ "prefill_tokens": 4,
34
+ "privacy": {
35
+ "decoded_output_bytes_retained": false,
36
+ "generated_tokens_public": false,
37
+ "output_nonce_public": false,
38
+ "owner_salt_encrypted": true,
39
+ "owner_salt_public": false,
40
+ "private_signing_keys_retained": false,
41
+ "prompt_output_opening_encrypted": true,
42
+ "prompt_tokens_public": false,
43
+ "signed_assignment_encrypted": true,
44
+ "signed_request_encrypted": true
45
+ },
46
+ "receipt_id": "ab2b3196a6c0935aafd4d563a9d2e1d71d828cc87a378ae77b8e49c102033b68",
47
+ "replica_slot": 0,
48
+ "request_commitment": "fbed17891d3e8e326e18ba00dbdec05de729b33c2f271581a03988b214c615e1",
49
+ "runtime_class_id": "5b2fd7a56d73aa9757e516f92cbc7b4d43995ebe9ed27e445b9b7ab4cd8c7bc9",
50
+ "runtime_manifest_hash": "2b9c3cd05942f16b36ab348bc71033c33e8f7aa6872ce4c0c0fcac3ba0212bc1",
51
+ "schedule_event_count": 4890,
52
+ "scheduler_job_id": "407bacfe3d8ad3dcfa7ba0ab15f7d16b95473d6c43f26755fa08dd2617fdf447",
53
+ "schema": "misaka.palw.public-receipt.v2",
54
+ "shape_profile_id": "c4f8ae70ab6fda2707d841a64d79d36cff58509ea7f228eb4c93b693e630d674",
55
+ "signed_assignment_id": "2aa43b4369cbd2f584898764aefc99005afb81bc633882dddf6525022f0e9c68",
56
+ "signer_key_id": "af0ff7daae66f1fc903775994351e8c099b1fa2e9495f1d84f4a0d8ba08d5d91",
57
+ "timestamp_millis": 1784101608591,
58
+ "trace_event_count": 1625,
59
+ "trace_evidence": "graph_fallback",
60
+ "trace_scheme_id": "809191d894ecc9d0ec53b1b2da9eafa5856eb26c6bfc641ea6405c041130d8a0",
61
+ "verification_bundle_id": "6fd4e57a6cbcd6fc1d9138989960b627c9ee4817bc3ac4ce889a1a1b41d7d63b",
62
+ "worker_credential_id": "ff0bc29f4f856fb7dec1c39e8f4dcd7e20990917b04242a6bfa87d05e9ca341e"
63
+ }
receipts/final-v5/ab2b3196a6c0935aafd4d563a9d2e1d71d828cc87a378ae77b8e49c102033b68.palw ADDED
Binary file (713 Bytes). View file
 
receipts/final-v6/eb51b08c3b86ef5df2cdebcfa9fcef812ec72197b3ad40ae2c5ba68cf4278131.complete ADDED
@@ -0,0 +1,4 @@
 
 
 
 
 
1
+ misaka.palw.receipt-set.v2
2
+ receipt_id=eb51b08c3b86ef5df2cdebcfa9fcef812ec72197b3ad40ae2c5ba68cf4278131
3
+ bundle_id=359f1bedaeefc1e140bf8c0dbba11582cb5cc0be428dcd95bc6077721f8096e9
4
+ public_json_sha256=03bee886144a2c64dd5f4d2207f86c748f5a3e7891b43f82f077f051342c3d0b
receipts/final-v6/eb51b08c3b86ef5df2cdebcfa9fcef812ec72197b3ad40ae2c5ba68cf4278131.json ADDED
@@ -0,0 +1,63 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "artifacts": {
3
+ "llama_commit": "12127defda4f41b7679cb2477a4b0d65ee6a0c8f",
4
+ "model_bytes": 5027783488,
5
+ "model_palw_root": "ad7d0e950531195bc2cf84f112fee6487777f78120c9a809cf9306c7a7a8684f",
6
+ "tokenizer_palw_root": "63839f0ab58084bbaa108a877e52bebd685b2c0616fcfab684a08354dee713dd"
7
+ },
8
+ "canonical_compute_units": 14562,
9
+ "canonical_receipt_file": "eb51b08c3b86ef5df2cdebcfa9fcef812ec72197b3ad40ae2c5ba68cf4278131.palw",
10
+ "completion_marker": "eb51b08c3b86ef5df2cdebcfa9fcef812ec72197b3ad40ae2c5ba68cf4278131.complete",
11
+ "cu_ruleset_id": "d8ef60255b3ba7ab12062942771b3e0ac9a674f151c3c321fe82c7d1fe52d299",
12
+ "decode_tokens": 2,
13
+ "durable_state_database": "palw-state.sqlite3",
14
+ "encrypted_verification_bundle": "eb51b08c3b86ef5df2cdebcfa9fcef812ec72197b3ad40ae2c5ba68cf4278131.palw.bundle",
15
+ "evidence_level": "gemm_traced",
16
+ "execution_nullifier": "1ff2d8035bee73c268c9ab39ea493f6f6112c28c1508a9e4ed972a09124ed5a8",
17
+ "expires_epoch": 100,
18
+ "gemm_trace_root": "53c906957957aa34cd5c66fc9ad8c863e541732ead6728e3125d78dff6c133f1",
19
+ "issued_epoch": 1,
20
+ "job_class": "self_local",
21
+ "job_nullifier": "848144497db27d8e39d38d1e41bf05cd7cc54fbd7e4267dc16db6c5cb0c81e73",
22
+ "model_profile_id": "0c58c66b03bb471a248cb36be954b42945c6694c148370e6852f674ff98e64d4",
23
+ "network_id": "5314ef28b17106c232db89c7ada20d4e72f7d20bb95a7025c5c9abcec19055d9",
24
+ "observer_summary": {
25
+ "canonical_operations": 5868,
26
+ "decode_graph_steps": 1,
27
+ "gemm_events": 1950,
28
+ "prefill_graph_steps": 5
29
+ },
30
+ "operation_schedule_commitment": "ad5b7b98c81354be64a9021cb7a20838ccf9d555576fc0743c79286ea29681f6",
31
+ "output_commitment": "6dab6a439df562c1da3dc54c4d0390b951631d0b54cfce023fa7429541c63acf",
32
+ "owner_commitment": "784f01145a243ff47af1e5a8f10900e70d8923208f754ad44818ba062ca4c4b3",
33
+ "prefill_tokens": 5,
34
+ "privacy": {
35
+ "decoded_output_bytes_retained": false,
36
+ "generated_tokens_public": false,
37
+ "output_nonce_public": false,
38
+ "owner_salt_encrypted": true,
39
+ "owner_salt_public": false,
40
+ "private_signing_keys_retained": false,
41
+ "prompt_output_opening_encrypted": true,
42
+ "prompt_tokens_public": false,
43
+ "signed_assignment_encrypted": true,
44
+ "signed_request_encrypted": true
45
+ },
46
+ "receipt_id": "eb51b08c3b86ef5df2cdebcfa9fcef812ec72197b3ad40ae2c5ba68cf4278131",
47
+ "replica_slot": 0,
48
+ "request_commitment": "baa38c80930d4af9186c4b708d2cbfef2f1ee789caef11dcd3c5a66dfbe11921",
49
+ "runtime_class_id": "c38307d57c847f3c276247411c563daf50fc7576cf1f6488ab29fe9a56970c5c",
50
+ "runtime_manifest_hash": "5920accc3a0a0529c5f0c0a4050d6bf00d4d8fdf2b9772b64af2b4fdac2b84dd",
51
+ "schedule_event_count": 5868,
52
+ "scheduler_job_id": "5425d9aa3d39fa5d80275d60a498274979bff103cc7a8214bf2418f4c3b6d81b",
53
+ "schema": "misaka.palw.public-receipt.v2",
54
+ "shape_profile_id": "c4f8ae70ab6fda2707d841a64d79d36cff58509ea7f228eb4c93b693e630d674",
55
+ "signed_assignment_id": "022501b13963fa70d45d86dae37386f0ed41bb9ae79646beb1fc41fca159e4f6",
56
+ "signer_key_id": "d1c014d205033b8b7e01a712bce01d57afd1fa8a0d96f4bf1809c551827b31ef",
57
+ "timestamp_millis": 1784111006188,
58
+ "trace_event_count": 1950,
59
+ "trace_evidence": "graph_fallback",
60
+ "trace_scheme_id": "809191d894ecc9d0ec53b1b2da9eafa5856eb26c6bfc641ea6405c041130d8a0",
61
+ "verification_bundle_id": "359f1bedaeefc1e140bf8c0dbba11582cb5cc0be428dcd95bc6077721f8096e9",
62
+ "worker_credential_id": "99663e6ddd5e0e38684beebf9d9c46872e960745bf9ab66bfbaa92e60af822d5"
63
+ }
receipts/final-v6/eb51b08c3b86ef5df2cdebcfa9fcef812ec72197b3ad40ae2c5ba68cf4278131.palw ADDED
Binary file (713 Bytes). View file
 
receipts/final-v7/8e2dd34b7609d6d7aeec17bff485eb1ae4db31f66dd899a3c3a3e671656053f9.complete ADDED
@@ -0,0 +1,4 @@
 
 
 
 
 
1
+ misaka.palw.receipt-set.v2
2
+ receipt_id=8e2dd34b7609d6d7aeec17bff485eb1ae4db31f66dd899a3c3a3e671656053f9
3
+ bundle_id=f5b8a2968c4ea266b2cbbabf351a171e0fa2581984eff63362de2640fcdcf9db
4
+ public_json_sha256=2bc670c2de4147fa150126cc36a5f35b5c0600f0835b334e3d36de58ccbf5154
receipts/final-v7/8e2dd34b7609d6d7aeec17bff485eb1ae4db31f66dd899a3c3a3e671656053f9.json ADDED
@@ -0,0 +1,87 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "artifacts": {
3
+ "llama_commit": "12127defda4f41b7679cb2477a4b0d65ee6a0c8f",
4
+ "model_bytes": 23938321728,
5
+ "model_palw_root": "f94585e843a993db3ff8f34232b72128784cb074942d3263a05d5da6dc25ef06",
6
+ "tokenizer_palw_root": "a5b09fef67156eaeb5b98e0c406a304c7b0fca75861bd2d7c02b4185a64ce762"
7
+ },
8
+ "canonical_compute_units": 41692,
9
+ "canonical_receipt_file": "8e2dd34b7609d6d7aeec17bff485eb1ae4db31f66dd899a3c3a3e671656053f9.palw",
10
+ "completion_marker": "8e2dd34b7609d6d7aeec17bff485eb1ae4db31f66dd899a3c3a3e671656053f9.complete",
11
+ "cu_ruleset_id": "43a5feef177b389f976361b22ac9d57da65815261282005bc78d1666a37870ce",
12
+ "decode_tokens": 2,
13
+ "durable_state_database": "palw-state.sqlite3",
14
+ "encrypted_verification_bundle": "8e2dd34b7609d6d7aeec17bff485eb1ae4db31f66dd899a3c3a3e671656053f9.palw.bundle",
15
+ "evidence_level": "gemm_traced",
16
+ "execution_nullifier": "1ea89b576f78cbbbc1f878b8f786e2aa6158b9d3a9762b43146207ddba85e16e",
17
+ "expert_route": {
18
+ "root": "5e4ea70ba91658e6a24cf3da00ac747eae4985ea5f0dc8f46009cc827bbc1c9e",
19
+ "route_event_count": 240
20
+ },
21
+ "expires_epoch": 100,
22
+ "gemm_trace_root": "78f6f15a768bcfa90597c2ee1cb25c4e08beb32f869e5dfb45f43fc9bb6d84f7",
23
+ "issued_epoch": 1,
24
+ "job_class": "self_local",
25
+ "job_nullifier": "2d8b5b9d5ea6699c47b06c1defb044f9a6582b216cd438a172ee6af92fd8bfb9",
26
+ "mint": {
27
+ "class": "local_self_consistent_v0_1",
28
+ "eligible": false,
29
+ "ineligible_reasons": [
30
+ "trace is a Metal kernel-launch-bound sketch, not an intra-kernel accumulator proof",
31
+ "assignment is an embedded local snapshot, not a network-anchored challenge-bound assignment",
32
+ "signing identity is ephemeral and not bonded to a persistent worker credential"
33
+ ],
34
+ "mainnet_ready": false,
35
+ "weight": 0
36
+ },
37
+ "model_profile_id": "b6b83a274a889fc5dfa2044b9158111b3849f880a05eb7ebcf560d036515d472",
38
+ "network_id": "5314ef28b17106c232db89c7ada20d4e72f7d20bb95a7025c5c9abcec19055d9",
39
+ "observer_summary": {
40
+ "canonical_operations": 13770,
41
+ "decode_graph_steps": 1,
42
+ "gemm_events": 2466,
43
+ "prefill_graph_steps": 5
44
+ },
45
+ "operation_schedule_commitment": "eb29962a094774e4de78c426cd653249540aab371a0a69372f0a4b4371696322",
46
+ "output_commitment": "16d16907a410297aec0f01527c89304461fc1390f8afa49c091b63b1d422b9e0",
47
+ "owner_commitment": "64c702b1d90842b85e4e554cc18413a04c1309db0f47c300e4102d9e042c5284",
48
+ "prefill_tokens": 5,
49
+ "privacy": {
50
+ "decoded_output_bytes_retained": false,
51
+ "generated_tokens_public": false,
52
+ "output_nonce_public": false,
53
+ "owner_salt_encrypted": true,
54
+ "owner_salt_public": false,
55
+ "private_signing_keys_retained": false,
56
+ "prompt_output_opening_encrypted": true,
57
+ "prompt_tokens_public": false,
58
+ "signed_assignment_encrypted": true,
59
+ "signed_request_encrypted": true
60
+ },
61
+ "receipt_id": "8e2dd34b7609d6d7aeec17bff485eb1ae4db31f66dd899a3c3a3e671656053f9",
62
+ "replica_slot": 0,
63
+ "request_commitment": "d9a4994816b1bf29f561cbe181e57c086a89a17a0407cc0e9c8960cf223f16b8",
64
+ "runtime_class_id": "8f6f536118a72be70dab2028535c3bb95e3de9a3bac0e9b81cf78677ae902a9c",
65
+ "runtime_manifest_hash": "8a07a1767a7e503259f9b157d932454ce790f428f7b8d271d4b472f1f5103963",
66
+ "schedule_event_count": 13770,
67
+ "scheduler_job_id": "ea681cd4d99163aec502aba3d23513197f861ce4e6495243c85a404f910f823e",
68
+ "schema": "misaka.palw.public-receipt.v2",
69
+ "semantic_compute_units_v3": 41692,
70
+ "semantic_schedule": {
71
+ "attention_ops": 20,
72
+ "commitment": "e6fc731e80e9b1135beced7f178dd8c9eda542507cb4c143451b523c361ead34",
73
+ "expert_route_ops": 80,
74
+ "forward_passes": 2,
75
+ "gemm_ops": 82,
76
+ "total_ops": 764
77
+ },
78
+ "shape_profile_id": "c4f8ae70ab6fda2707d841a64d79d36cff58509ea7f228eb4c93b693e630d674",
79
+ "signed_assignment_id": "94dec962b00f395a8ef349f4227f2bdebc716f261b7ce8a88e17efe31c5778b8",
80
+ "signer_key_id": "b2d968277c5e5464a273c92c5d501565367117b68c7d949823bd2403f77601ed",
81
+ "timestamp_millis": 1784446365200,
82
+ "trace_event_count": 2466,
83
+ "trace_evidence": "metal_kernel",
84
+ "trace_scheme_id": "809191d894ecc9d0ec53b1b2da9eafa5856eb26c6bfc641ea6405c041130d8a0",
85
+ "verification_bundle_id": "f5b8a2968c4ea266b2cbbabf351a171e0fa2581984eff63362de2640fcdcf9db",
86
+ "worker_credential_id": "94351cf05b8fa9c4a6b2a31a492ba08f0931cb659a44ae06d7d39ebd2cf0bff0"
87
+ }
receipts/final-v7/8e2dd34b7609d6d7aeec17bff485eb1ae4db31f66dd899a3c3a3e671656053f9.palw ADDED
Binary file (713 Bytes). View file
 
runtime-palw/Cargo.lock ADDED
@@ -0,0 +1,852 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # This file is automatically @generated by Cargo.
2
+ # It is not intended for manual editing.
3
+ version = 3
4
+
5
+ [[package]]
6
+ name = "aead"
7
+ version = "0.5.2"
8
+ source = "registry+https://github.com/rust-lang/crates.io-index"
9
+ checksum = "d122413f284cf2d62fb1b7db97e02edb8cda96d769b16e443a4f6195e35662b0"
10
+ dependencies = [
11
+ "crypto-common 0.1.7",
12
+ "generic-array",
13
+ ]
14
+
15
+ [[package]]
16
+ name = "ahash"
17
+ version = "0.8.12"
18
+ source = "registry+https://github.com/rust-lang/crates.io-index"
19
+ checksum = "5a15f179cd60c4584b8a8c596927aadc462e27f2ca70c04e0071964a73ba7a75"
20
+ dependencies = [
21
+ "cfg-if",
22
+ "once_cell",
23
+ "version_check",
24
+ "zerocopy",
25
+ ]
26
+
27
+ [[package]]
28
+ name = "arrayref"
29
+ version = "0.3.9"
30
+ source = "registry+https://github.com/rust-lang/crates.io-index"
31
+ checksum = "76a2e8124351fda1ef8aaaa3bbd7ebbcb486bbcd4225aca0aa0d84bb2db8fecb"
32
+
33
+ [[package]]
34
+ name = "arrayvec"
35
+ version = "0.7.8"
36
+ source = "registry+https://github.com/rust-lang/crates.io-index"
37
+ checksum = "d3fb67a6e08acf24fdeccbac2cb6ac4305825bd1f117462e0e6f2f193345ad56"
38
+
39
+ [[package]]
40
+ name = "autocfg"
41
+ version = "1.5.1"
42
+ source = "registry+https://github.com/rust-lang/crates.io-index"
43
+ checksum = "f2032f911046de80f0a198e0901378627c33f59ea0ac00e363d481118bd70a53"
44
+
45
+ [[package]]
46
+ name = "base64ct"
47
+ version = "1.7.3"
48
+ source = "registry+https://github.com/rust-lang/crates.io-index"
49
+ checksum = "89e25b6adfb930f02d1981565a6e5d9c547ac15a96606256d3b59040e5cd4ca3"
50
+
51
+ [[package]]
52
+ name = "bitflags"
53
+ version = "2.13.0"
54
+ source = "registry+https://github.com/rust-lang/crates.io-index"
55
+ checksum = "b4388bee8683e3d04af747c73422af53102d2bd24d9eadb6cbc100baef4b43f8"
56
+
57
+ [[package]]
58
+ name = "blake2b_simd"
59
+ version = "1.0.4"
60
+ source = "registry+https://github.com/rust-lang/crates.io-index"
61
+ checksum = "b79834656f71332577234b50bfc009996f7449e0c056884e6a02492ded0ca2f3"
62
+ dependencies = [
63
+ "arrayref",
64
+ "arrayvec",
65
+ "constant_time_eq",
66
+ ]
67
+
68
+ [[package]]
69
+ name = "block-buffer"
70
+ version = "0.10.4"
71
+ source = "registry+https://github.com/rust-lang/crates.io-index"
72
+ checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71"
73
+ dependencies = [
74
+ "generic-array",
75
+ ]
76
+
77
+ [[package]]
78
+ name = "cc"
79
+ version = "1.2.67"
80
+ source = "registry+https://github.com/rust-lang/crates.io-index"
81
+ checksum = "e17dd265a7d0f31ef544e1b20e03add05d3b45b491b633b10d67145d2acc1a38"
82
+ dependencies = [
83
+ "find-msvc-tools",
84
+ "shlex",
85
+ ]
86
+
87
+ [[package]]
88
+ name = "cfg-if"
89
+ version = "1.0.4"
90
+ source = "registry+https://github.com/rust-lang/crates.io-index"
91
+ checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801"
92
+
93
+ [[package]]
94
+ name = "chacha20"
95
+ version = "0.9.1"
96
+ source = "registry+https://github.com/rust-lang/crates.io-index"
97
+ checksum = "c3613f74bd2eac03dad61bd53dbe620703d4371614fe0bc3b9f04dd36fe4e818"
98
+ dependencies = [
99
+ "cfg-if",
100
+ "cipher",
101
+ "cpufeatures 0.2.17",
102
+ ]
103
+
104
+ [[package]]
105
+ name = "chacha20poly1305"
106
+ version = "0.10.1"
107
+ source = "registry+https://github.com/rust-lang/crates.io-index"
108
+ checksum = "10cd79432192d1c0f4e1a0fef9527696cc039165d729fb41b3f4f4f354c2dc35"
109
+ dependencies = [
110
+ "aead",
111
+ "chacha20",
112
+ "cipher",
113
+ "poly1305",
114
+ "zeroize",
115
+ ]
116
+
117
+ [[package]]
118
+ name = "cipher"
119
+ version = "0.4.4"
120
+ source = "registry+https://github.com/rust-lang/crates.io-index"
121
+ checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad"
122
+ dependencies = [
123
+ "crypto-common 0.1.7",
124
+ "inout",
125
+ "zeroize",
126
+ ]
127
+
128
+ [[package]]
129
+ name = "cmov"
130
+ version = "0.5.4"
131
+ source = "registry+https://github.com/rust-lang/crates.io-index"
132
+ checksum = "0c9ea0ac24bc397ab3c98583a3c9ba74fa56b09a4449bbe172b9b1ddb016027a"
133
+
134
+ [[package]]
135
+ name = "const-oid"
136
+ version = "0.9.6"
137
+ source = "registry+https://github.com/rust-lang/crates.io-index"
138
+ checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8"
139
+
140
+ [[package]]
141
+ name = "const-oid"
142
+ version = "0.10.2"
143
+ source = "registry+https://github.com/rust-lang/crates.io-index"
144
+ checksum = "a6ef517f0926dd24a1582492c791b6a4818a4d94e789a334894aa15b0d12f55c"
145
+
146
+ [[package]]
147
+ name = "constant_time_eq"
148
+ version = "0.4.2"
149
+ source = "registry+https://github.com/rust-lang/crates.io-index"
150
+ checksum = "3d52eff69cd5e647efe296129160853a42795992097e8af39800e1060caeea9b"
151
+
152
+ [[package]]
153
+ name = "cpufeatures"
154
+ version = "0.2.17"
155
+ source = "registry+https://github.com/rust-lang/crates.io-index"
156
+ checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280"
157
+ dependencies = [
158
+ "libc",
159
+ ]
160
+
161
+ [[package]]
162
+ name = "cpufeatures"
163
+ version = "0.3.0"
164
+ source = "registry+https://github.com/rust-lang/crates.io-index"
165
+ checksum = "8b2a41393f66f16b0823bb79094d54ac5fbd34ab292ddafb9a0456ac9f87d201"
166
+ dependencies = [
167
+ "libc",
168
+ ]
169
+
170
+ [[package]]
171
+ name = "crypto-common"
172
+ version = "0.1.7"
173
+ source = "registry+https://github.com/rust-lang/crates.io-index"
174
+ checksum = "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a"
175
+ dependencies = [
176
+ "generic-array",
177
+ "rand_core 0.6.4",
178
+ "typenum",
179
+ ]
180
+
181
+ [[package]]
182
+ name = "crypto-common"
183
+ version = "0.2.2"
184
+ source = "registry+https://github.com/rust-lang/crates.io-index"
185
+ checksum = "ce6e4c961d6cd6c9a86db418387425e8bdeaf05b3c8bc1411e6dca4c252f1453"
186
+ dependencies = [
187
+ "getrandom 0.4.3",
188
+ "hybrid-array",
189
+ "rand_core 0.10.1",
190
+ ]
191
+
192
+ [[package]]
193
+ name = "ctutils"
194
+ version = "0.4.2"
195
+ source = "registry+https://github.com/rust-lang/crates.io-index"
196
+ checksum = "7d5515a3834141de9eafb9717ad39eea8247b5674e6066c404e8c4b365d2a29e"
197
+ dependencies = [
198
+ "cmov",
199
+ ]
200
+
201
+ [[package]]
202
+ name = "curve25519-dalek"
203
+ version = "4.1.3"
204
+ source = "registry+https://github.com/rust-lang/crates.io-index"
205
+ checksum = "97fb8b7c4503de7d6ae7b42ab72a5a59857b4c937ec27a3d4539dba95b5ab2be"
206
+ dependencies = [
207
+ "cfg-if",
208
+ "cpufeatures 0.2.17",
209
+ "curve25519-dalek-derive",
210
+ "digest 0.10.7",
211
+ "fiat-crypto",
212
+ "rustc_version",
213
+ "subtle",
214
+ "zeroize",
215
+ ]
216
+
217
+ [[package]]
218
+ name = "curve25519-dalek-derive"
219
+ version = "0.1.1"
220
+ source = "registry+https://github.com/rust-lang/crates.io-index"
221
+ checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3"
222
+ dependencies = [
223
+ "proc-macro2",
224
+ "quote",
225
+ "syn",
226
+ ]
227
+
228
+ [[package]]
229
+ name = "der"
230
+ version = "0.7.10"
231
+ source = "registry+https://github.com/rust-lang/crates.io-index"
232
+ checksum = "e7c1832837b905bbfb5101e07cc24c8deddf52f93225eee6ead5f4d63d53ddcb"
233
+ dependencies = [
234
+ "const-oid 0.9.6",
235
+ "zeroize",
236
+ ]
237
+
238
+ [[package]]
239
+ name = "der"
240
+ version = "0.8.1"
241
+ source = "registry+https://github.com/rust-lang/crates.io-index"
242
+ checksum = "a69dedd701da44b0536442edf09c81a64b0ab97a7a4a5e3d1971f00027cbc63d"
243
+ dependencies = [
244
+ "const-oid 0.10.2",
245
+ "zeroize",
246
+ ]
247
+
248
+ [[package]]
249
+ name = "digest"
250
+ version = "0.10.7"
251
+ source = "registry+https://github.com/rust-lang/crates.io-index"
252
+ checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292"
253
+ dependencies = [
254
+ "block-buffer",
255
+ "crypto-common 0.1.7",
256
+ ]
257
+
258
+ [[package]]
259
+ name = "digest"
260
+ version = "0.11.3"
261
+ source = "registry+https://github.com/rust-lang/crates.io-index"
262
+ checksum = "f1dd6dbb5841937940781866fa1281a1ff7bd3bf827091440879f9994983d5c2"
263
+ dependencies = [
264
+ "crypto-common 0.2.2",
265
+ ]
266
+
267
+ [[package]]
268
+ name = "ed25519"
269
+ version = "2.2.3"
270
+ source = "registry+https://github.com/rust-lang/crates.io-index"
271
+ checksum = "115531babc129696a58c64a4fef0a8bf9e9698629fb97e9e40767d235cfbcd53"
272
+ dependencies = [
273
+ "pkcs8 0.10.2",
274
+ "signature 2.2.0",
275
+ ]
276
+
277
+ [[package]]
278
+ name = "ed25519-dalek"
279
+ version = "2.2.0"
280
+ source = "registry+https://github.com/rust-lang/crates.io-index"
281
+ checksum = "70e796c081cee67dc755e1a36a0a172b897fab85fc3f6bc48307991f64e4eca9"
282
+ dependencies = [
283
+ "curve25519-dalek",
284
+ "ed25519",
285
+ "rand_core 0.6.4",
286
+ "serde",
287
+ "sha2",
288
+ "subtle",
289
+ "zeroize",
290
+ ]
291
+
292
+ [[package]]
293
+ name = "fallible-iterator"
294
+ version = "0.3.0"
295
+ source = "registry+https://github.com/rust-lang/crates.io-index"
296
+ checksum = "2acce4a10f12dc2fb14a218589d4f1f62ef011b2d0cc4b3cb1bba8e94da14649"
297
+
298
+ [[package]]
299
+ name = "fallible-streaming-iterator"
300
+ version = "0.1.9"
301
+ source = "registry+https://github.com/rust-lang/crates.io-index"
302
+ checksum = "7360491ce676a36bf9bb3c56c1aa791658183a54d2744120f27285738d90465a"
303
+
304
+ [[package]]
305
+ name = "fiat-crypto"
306
+ version = "0.2.9"
307
+ source = "registry+https://github.com/rust-lang/crates.io-index"
308
+ checksum = "28dea519a9695b9977216879a3ebfddf92f1c08c05d984f8996aecd6ecdc811d"
309
+
310
+ [[package]]
311
+ name = "find-msvc-tools"
312
+ version = "0.1.9"
313
+ source = "registry+https://github.com/rust-lang/crates.io-index"
314
+ checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582"
315
+
316
+ [[package]]
317
+ name = "generic-array"
318
+ version = "0.14.7"
319
+ source = "registry+https://github.com/rust-lang/crates.io-index"
320
+ checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a"
321
+ dependencies = [
322
+ "typenum",
323
+ "version_check",
324
+ ]
325
+
326
+ [[package]]
327
+ name = "getrandom"
328
+ version = "0.2.17"
329
+ source = "registry+https://github.com/rust-lang/crates.io-index"
330
+ checksum = "ff2abc00be7fca6ebc474524697ae276ad847ad0a6b3faa4bcb027e9a4614ad0"
331
+ dependencies = [
332
+ "cfg-if",
333
+ "libc",
334
+ "wasi",
335
+ ]
336
+
337
+ [[package]]
338
+ name = "getrandom"
339
+ version = "0.4.3"
340
+ source = "registry+https://github.com/rust-lang/crates.io-index"
341
+ checksum = "300e883d756b2e4ec94e02791f39b04b522276138852cfc41d9fb7e904106099"
342
+ dependencies = [
343
+ "cfg-if",
344
+ "libc",
345
+ "r-efi",
346
+ "rand_core 0.10.1",
347
+ ]
348
+
349
+ [[package]]
350
+ name = "hashbrown"
351
+ version = "0.14.5"
352
+ source = "registry+https://github.com/rust-lang/crates.io-index"
353
+ checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1"
354
+ dependencies = [
355
+ "ahash",
356
+ ]
357
+
358
+ [[package]]
359
+ name = "hashlink"
360
+ version = "0.9.1"
361
+ source = "registry+https://github.com/rust-lang/crates.io-index"
362
+ checksum = "6ba4ff7128dee98c7dc9794b6a411377e1404dba1c97deb8d1a55297bd25d8af"
363
+ dependencies = [
364
+ "hashbrown",
365
+ ]
366
+
367
+ [[package]]
368
+ name = "hex"
369
+ version = "0.4.3"
370
+ source = "registry+https://github.com/rust-lang/crates.io-index"
371
+ checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
372
+
373
+ [[package]]
374
+ name = "hybrid-array"
375
+ version = "0.4.13"
376
+ source = "registry+https://github.com/rust-lang/crates.io-index"
377
+ checksum = "818356c5132c1fede50f837ca96afbe78ff42413047f4abb886217845e1b6c8c"
378
+ dependencies = [
379
+ "ctutils",
380
+ "typenum",
381
+ ]
382
+
383
+ [[package]]
384
+ name = "inout"
385
+ version = "0.1.4"
386
+ source = "registry+https://github.com/rust-lang/crates.io-index"
387
+ checksum = "879f10e63c20629ecabbb64a8010319738c66a5cd0c29b02d63d272b03751d01"
388
+ dependencies = [
389
+ "generic-array",
390
+ ]
391
+
392
+ [[package]]
393
+ name = "itoa"
394
+ version = "1.0.18"
395
+ source = "registry+https://github.com/rust-lang/crates.io-index"
396
+ checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682"
397
+
398
+ [[package]]
399
+ name = "keccak"
400
+ version = "0.1.6"
401
+ source = "registry+https://github.com/rust-lang/crates.io-index"
402
+ checksum = "cb26cec98cce3a3d96cbb7bced3c4b16e3d13f27ec56dbd62cbc8f39cfb9d653"
403
+ dependencies = [
404
+ "cpufeatures 0.2.17",
405
+ ]
406
+
407
+ [[package]]
408
+ name = "keccak"
409
+ version = "0.2.0"
410
+ source = "registry+https://github.com/rust-lang/crates.io-index"
411
+ checksum = "9e24a010dd405bd7ed803e5253182815b41bf2e6a80cc3bfc066658e03a198aa"
412
+ dependencies = [
413
+ "cfg-if",
414
+ "cpufeatures 0.3.0",
415
+ ]
416
+
417
+ [[package]]
418
+ name = "libc"
419
+ version = "0.2.186"
420
+ source = "registry+https://github.com/rust-lang/crates.io-index"
421
+ checksum = "68ab91017fe16c622486840e4c83c9a37afeff978bd239b5293d61ece587de66"
422
+
423
+ [[package]]
424
+ name = "libsqlite3-sys"
425
+ version = "0.30.1"
426
+ source = "registry+https://github.com/rust-lang/crates.io-index"
427
+ checksum = "2e99fb7a497b1e3339bc746195567ed8d3e24945ecd636e3619d20b9de9e9149"
428
+ dependencies = [
429
+ "cc",
430
+ "pkg-config",
431
+ "vcpkg",
432
+ ]
433
+
434
+ [[package]]
435
+ name = "memchr"
436
+ version = "2.8.3"
437
+ source = "registry+https://github.com/rust-lang/crates.io-index"
438
+ checksum = "cf8baf1c55e62ffcace7a9f06f4bd9cd3f0c4beb022d3b367256b91b87513d98"
439
+
440
+ [[package]]
441
+ name = "ml-dsa"
442
+ version = "0.1.1"
443
+ source = "registry+https://github.com/rust-lang/crates.io-index"
444
+ checksum = "add6b9d92e496f16f4526d68ff29da1483aba4b119baeab8bed3b9e3544a6f3d"
445
+ dependencies = [
446
+ "const-oid 0.10.2",
447
+ "crypto-common 0.2.2",
448
+ "ctutils",
449
+ "hybrid-array",
450
+ "module-lattice",
451
+ "pkcs8 0.11.0",
452
+ "shake",
453
+ "signature 3.0.0",
454
+ ]
455
+
456
+ [[package]]
457
+ name = "module-lattice"
458
+ version = "0.2.3"
459
+ source = "registry+https://github.com/rust-lang/crates.io-index"
460
+ checksum = "0c61b87c9683ab7cb1c6871d261ad5479b6b10ceb52c4352aaca3b5d35a8febe"
461
+ dependencies = [
462
+ "ctutils",
463
+ "hybrid-array",
464
+ "num-traits",
465
+ ]
466
+
467
+ [[package]]
468
+ name = "num-traits"
469
+ version = "0.2.19"
470
+ source = "registry+https://github.com/rust-lang/crates.io-index"
471
+ checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841"
472
+ dependencies = [
473
+ "autocfg",
474
+ ]
475
+
476
+ [[package]]
477
+ name = "once_cell"
478
+ version = "1.21.4"
479
+ source = "registry+https://github.com/rust-lang/crates.io-index"
480
+ checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50"
481
+
482
+ [[package]]
483
+ name = "opaque-debug"
484
+ version = "0.3.1"
485
+ source = "registry+https://github.com/rust-lang/crates.io-index"
486
+ checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381"
487
+
488
+ [[package]]
489
+ name = "pkcs8"
490
+ version = "0.10.2"
491
+ source = "registry+https://github.com/rust-lang/crates.io-index"
492
+ checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7"
493
+ dependencies = [
494
+ "der 0.7.10",
495
+ "spki 0.7.3",
496
+ ]
497
+
498
+ [[package]]
499
+ name = "pkcs8"
500
+ version = "0.11.0"
501
+ source = "registry+https://github.com/rust-lang/crates.io-index"
502
+ checksum = "451913da69c775a56034ea8d9003d27ee8948e12443eae7c038ba100a4f21cb7"
503
+ dependencies = [
504
+ "der 0.8.1",
505
+ "spki 0.8.0",
506
+ ]
507
+
508
+ [[package]]
509
+ name = "pkg-config"
510
+ version = "0.3.33"
511
+ source = "registry+https://github.com/rust-lang/crates.io-index"
512
+ checksum = "19f132c84eca552bf34cab8ec81f1c1dcc229b811638f9d283dceabe58c5569e"
513
+
514
+ [[package]]
515
+ name = "poly1305"
516
+ version = "0.8.0"
517
+ source = "registry+https://github.com/rust-lang/crates.io-index"
518
+ checksum = "8159bd90725d2df49889a078b54f4f79e87f1f8a8444194cdca81d38f5393abf"
519
+ dependencies = [
520
+ "cpufeatures 0.2.17",
521
+ "opaque-debug",
522
+ "universal-hash",
523
+ ]
524
+
525
+ [[package]]
526
+ name = "proc-macro2"
527
+ version = "1.0.106"
528
+ source = "registry+https://github.com/rust-lang/crates.io-index"
529
+ checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934"
530
+ dependencies = [
531
+ "unicode-ident",
532
+ ]
533
+
534
+ [[package]]
535
+ name = "quote"
536
+ version = "1.0.46"
537
+ source = "registry+https://github.com/rust-lang/crates.io-index"
538
+ checksum = "dfbc457d0c7a0759a614551b11a6409e5951f6c7537be1f1b7682b9ae9230368"
539
+ dependencies = [
540
+ "proc-macro2",
541
+ ]
542
+
543
+ [[package]]
544
+ name = "r-efi"
545
+ version = "6.0.0"
546
+ source = "registry+https://github.com/rust-lang/crates.io-index"
547
+ checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf"
548
+
549
+ [[package]]
550
+ name = "rand_core"
551
+ version = "0.6.4"
552
+ source = "registry+https://github.com/rust-lang/crates.io-index"
553
+ checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
554
+ dependencies = [
555
+ "getrandom 0.2.17",
556
+ ]
557
+
558
+ [[package]]
559
+ name = "rand_core"
560
+ version = "0.10.1"
561
+ source = "registry+https://github.com/rust-lang/crates.io-index"
562
+ checksum = "63b8176103e19a2643978565ca18b50549f6101881c443590420e4dc998a3c69"
563
+
564
+ [[package]]
565
+ name = "runtime-palw"
566
+ version = "0.1.0"
567
+ dependencies = [
568
+ "base64ct",
569
+ "blake2b_simd",
570
+ "chacha20poly1305",
571
+ "ed25519-dalek",
572
+ "getrandom 0.2.17",
573
+ "hex",
574
+ "ml-dsa",
575
+ "rusqlite",
576
+ "serde",
577
+ "serde_json",
578
+ "sha2",
579
+ "sha3",
580
+ "thiserror",
581
+ "zeroize",
582
+ ]
583
+
584
+ [[package]]
585
+ name = "rusqlite"
586
+ version = "0.32.1"
587
+ source = "registry+https://github.com/rust-lang/crates.io-index"
588
+ checksum = "7753b721174eb8ff87a9a0e799e2d7bc3749323e773db92e0984debb00019d6e"
589
+ dependencies = [
590
+ "bitflags",
591
+ "fallible-iterator",
592
+ "fallible-streaming-iterator",
593
+ "hashlink",
594
+ "libsqlite3-sys",
595
+ "smallvec",
596
+ ]
597
+
598
+ [[package]]
599
+ name = "rustc_version"
600
+ version = "0.4.1"
601
+ source = "registry+https://github.com/rust-lang/crates.io-index"
602
+ checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92"
603
+ dependencies = [
604
+ "semver",
605
+ ]
606
+
607
+ [[package]]
608
+ name = "semver"
609
+ version = "1.0.28"
610
+ source = "registry+https://github.com/rust-lang/crates.io-index"
611
+ checksum = "8a7852d02fc848982e0c167ef163aaff9cd91dc640ba85e263cb1ce46fae51cd"
612
+
613
+ [[package]]
614
+ name = "serde"
615
+ version = "1.0.228"
616
+ source = "registry+https://github.com/rust-lang/crates.io-index"
617
+ checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e"
618
+ dependencies = [
619
+ "serde_core",
620
+ "serde_derive",
621
+ ]
622
+
623
+ [[package]]
624
+ name = "serde_core"
625
+ version = "1.0.228"
626
+ source = "registry+https://github.com/rust-lang/crates.io-index"
627
+ checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad"
628
+ dependencies = [
629
+ "serde_derive",
630
+ ]
631
+
632
+ [[package]]
633
+ name = "serde_derive"
634
+ version = "1.0.228"
635
+ source = "registry+https://github.com/rust-lang/crates.io-index"
636
+ checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79"
637
+ dependencies = [
638
+ "proc-macro2",
639
+ "quote",
640
+ "syn",
641
+ ]
642
+
643
+ [[package]]
644
+ name = "serde_json"
645
+ version = "1.0.150"
646
+ source = "registry+https://github.com/rust-lang/crates.io-index"
647
+ checksum = "e8014e44b4736ed0538adeecded0fce2a272f22dc9578a7eb6b2d9993c74cfb9"
648
+ dependencies = [
649
+ "itoa",
650
+ "memchr",
651
+ "serde",
652
+ "serde_core",
653
+ "zmij",
654
+ ]
655
+
656
+ [[package]]
657
+ name = "sha2"
658
+ version = "0.10.9"
659
+ source = "registry+https://github.com/rust-lang/crates.io-index"
660
+ checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283"
661
+ dependencies = [
662
+ "cfg-if",
663
+ "cpufeatures 0.2.17",
664
+ "digest 0.10.7",
665
+ ]
666
+
667
+ [[package]]
668
+ name = "sha3"
669
+ version = "0.10.9"
670
+ source = "registry+https://github.com/rust-lang/crates.io-index"
671
+ checksum = "77fd7028345d415a4034cf8777cd4f8ab1851274233b45f84e3d955502d93874"
672
+ dependencies = [
673
+ "digest 0.10.7",
674
+ "keccak 0.1.6",
675
+ ]
676
+
677
+ [[package]]
678
+ name = "shake"
679
+ version = "0.1.0"
680
+ source = "registry+https://github.com/rust-lang/crates.io-index"
681
+ checksum = "09057cb2149ad4cbd2da1e26b351f9a4c354219421229c69c3063e6f61947c4a"
682
+ dependencies = [
683
+ "digest 0.11.3",
684
+ "keccak 0.2.0",
685
+ "sponge-cursor",
686
+ ]
687
+
688
+ [[package]]
689
+ name = "shlex"
690
+ version = "2.0.1"
691
+ source = "registry+https://github.com/rust-lang/crates.io-index"
692
+ checksum = "f8fadd59c855ef2080decdef8ff161eb6661b86933c9d82e5ba29dc602a55aba"
693
+
694
+ [[package]]
695
+ name = "signature"
696
+ version = "2.2.0"
697
+ source = "registry+https://github.com/rust-lang/crates.io-index"
698
+ checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de"
699
+ dependencies = [
700
+ "rand_core 0.6.4",
701
+ ]
702
+
703
+ [[package]]
704
+ name = "signature"
705
+ version = "3.0.0"
706
+ source = "registry+https://github.com/rust-lang/crates.io-index"
707
+ checksum = "28d567dcbaf0049cb8ac2608a76cd95ff9e4412e1899d389ee400918ca7537f5"
708
+ dependencies = [
709
+ "digest 0.11.3",
710
+ "rand_core 0.10.1",
711
+ ]
712
+
713
+ [[package]]
714
+ name = "smallvec"
715
+ version = "1.15.2"
716
+ source = "registry+https://github.com/rust-lang/crates.io-index"
717
+ checksum = "8ed6a63f02c8539c91a8685a86f4099661ba3da017932f6ebbea6de3f0fa7c90"
718
+
719
+ [[package]]
720
+ name = "spki"
721
+ version = "0.7.3"
722
+ source = "registry+https://github.com/rust-lang/crates.io-index"
723
+ checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d"
724
+ dependencies = [
725
+ "base64ct",
726
+ "der 0.7.10",
727
+ ]
728
+
729
+ [[package]]
730
+ name = "spki"
731
+ version = "0.8.0"
732
+ source = "registry+https://github.com/rust-lang/crates.io-index"
733
+ checksum = "1d9efca8738c78ee9484207732f728b1ef517bbb1833d6fc0879ca898a522f6f"
734
+ dependencies = [
735
+ "base64ct",
736
+ "der 0.8.1",
737
+ ]
738
+
739
+ [[package]]
740
+ name = "sponge-cursor"
741
+ version = "0.1.0"
742
+ source = "registry+https://github.com/rust-lang/crates.io-index"
743
+ checksum = "3a0219bd7d979d58245a4f41f695e1ac9f8befdffadd7f61f1bae9e39abc6620"
744
+
745
+ [[package]]
746
+ name = "subtle"
747
+ version = "2.6.1"
748
+ source = "registry+https://github.com/rust-lang/crates.io-index"
749
+ checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292"
750
+
751
+ [[package]]
752
+ name = "syn"
753
+ version = "2.0.119"
754
+ source = "registry+https://github.com/rust-lang/crates.io-index"
755
+ checksum = "872831b642d1a07999a962a351ed35b955ea2cfc8f3862091e2a240a84f17297"
756
+ dependencies = [
757
+ "proc-macro2",
758
+ "quote",
759
+ "unicode-ident",
760
+ ]
761
+
762
+ [[package]]
763
+ name = "thiserror"
764
+ version = "2.0.18"
765
+ source = "registry+https://github.com/rust-lang/crates.io-index"
766
+ checksum = "4288b5bcbc7920c07a1149a35cf9590a2aa808e0bc1eafaade0b80947865fbc4"
767
+ dependencies = [
768
+ "thiserror-impl",
769
+ ]
770
+
771
+ [[package]]
772
+ name = "thiserror-impl"
773
+ version = "2.0.18"
774
+ source = "registry+https://github.com/rust-lang/crates.io-index"
775
+ checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5"
776
+ dependencies = [
777
+ "proc-macro2",
778
+ "quote",
779
+ "syn",
780
+ ]
781
+
782
+ [[package]]
783
+ name = "typenum"
784
+ version = "1.20.1"
785
+ source = "registry+https://github.com/rust-lang/crates.io-index"
786
+ checksum = "b6f5e870be6c3b371b77fe0ee0bafb859fa4964b4404c27de1d380043c4dda20"
787
+
788
+ [[package]]
789
+ name = "unicode-ident"
790
+ version = "1.0.24"
791
+ source = "registry+https://github.com/rust-lang/crates.io-index"
792
+ checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75"
793
+
794
+ [[package]]
795
+ name = "universal-hash"
796
+ version = "0.5.1"
797
+ source = "registry+https://github.com/rust-lang/crates.io-index"
798
+ checksum = "fc1de2c688dc15305988b563c3854064043356019f97a4b46276fe734c4f07ea"
799
+ dependencies = [
800
+ "crypto-common 0.1.7",
801
+ "subtle",
802
+ ]
803
+
804
+ [[package]]
805
+ name = "vcpkg"
806
+ version = "0.2.15"
807
+ source = "registry+https://github.com/rust-lang/crates.io-index"
808
+ checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426"
809
+
810
+ [[package]]
811
+ name = "version_check"
812
+ version = "0.9.5"
813
+ source = "registry+https://github.com/rust-lang/crates.io-index"
814
+ checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
815
+
816
+ [[package]]
817
+ name = "wasi"
818
+ version = "0.11.1+wasi-snapshot-preview1"
819
+ source = "registry+https://github.com/rust-lang/crates.io-index"
820
+ checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b"
821
+
822
+ [[package]]
823
+ name = "zerocopy"
824
+ version = "0.8.54"
825
+ source = "registry+https://github.com/rust-lang/crates.io-index"
826
+ checksum = "b7cbbc0a705a0fd05cc3676525980d2bf5a9bc4adac6d6475209a7887cf59d19"
827
+ dependencies = [
828
+ "zerocopy-derive",
829
+ ]
830
+
831
+ [[package]]
832
+ name = "zerocopy-derive"
833
+ version = "0.8.54"
834
+ source = "registry+https://github.com/rust-lang/crates.io-index"
835
+ checksum = "e2e817b7b52d0c7358d3246da9d69935ebb18116b2b102b4230dac079b4862f5"
836
+ dependencies = [
837
+ "proc-macro2",
838
+ "quote",
839
+ "syn",
840
+ ]
841
+
842
+ [[package]]
843
+ name = "zeroize"
844
+ version = "1.8.1"
845
+ source = "registry+https://github.com/rust-lang/crates.io-index"
846
+ checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde"
847
+
848
+ [[package]]
849
+ name = "zmij"
850
+ version = "1.0.23"
851
+ source = "registry+https://github.com/rust-lang/crates.io-index"
852
+ checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b"
runtime-palw/Cargo.toml ADDED
@@ -0,0 +1,62 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ [package]
2
+ name = "runtime-palw"
3
+ version = "0.1.0"
4
+ edition = "2021"
5
+ rust-version = "1.81"
6
+ description = "Deterministic PALW receipt core for Qwen runtimes"
7
+ license = "Apache-2.0"
8
+
9
+ [workspace]
10
+
11
+ [[bin]]
12
+ name = "palw-worker"
13
+ path = "src/bin/palw-worker.rs"
14
+ required-features = ["ml-dsa"]
15
+ [[bin]]
16
+ name = "palw-integer-receipt"
17
+ path = "src/bin/palw-integer-receipt.rs"
18
+ required-features = ["ml-dsa"]
19
+
20
+ [[bin]]
21
+ name = "palw-verify-integer"
22
+ path = "src/bin/palw-verify-integer.rs"
23
+ required-features = ["ml-dsa"]
24
+
25
+
26
+ [dependencies]
27
+ chacha20poly1305 = { version = "=0.10.1", features = ["std"] }
28
+ ed25519-dalek = { version = "2.1", features = ["rand_core"] }
29
+ getrandom = "0.2"
30
+ rusqlite = { version = "0.32", features = ["bundled"] }
31
+ serde = { version = "1", features = ["derive"] }
32
+ serde_json = "1"
33
+ sha2 = "0.10"
34
+ sha3 = "0.10"
35
+ thiserror = "2"
36
+ # The crypto stack leaves these transitive ranges open. Newer releases use an
37
+ # edition-2024 Cargo manifest, so pin compatible versions to preserve MSRV 1.81.
38
+ base64ct = "=1.7.3"
39
+ # `curve25519-dalek` accepts any zeroize 1.x release, but zeroize 1.9's
40
+ # manifest requires Cargo's edition-2024 support. Keep the declared 1.81 MSRV
41
+ # honest by constraining the transitive resolver to the last compatible line.
42
+ zeroize = "=1.8.1"
43
+ blake2b_simd = "1"
44
+ ml-dsa = { version = "0.1.0-pre.2", optional = true }
45
+
46
+ [dev-dependencies]
47
+ hex = "0.4"
48
+
49
+ [lints.rust]
50
+ unsafe_code = "forbid"
51
+ missing_docs = "warn"
52
+
53
+ [lints.clippy]
54
+ all = { level = "warn", priority = -1 }
55
+ pedantic = { level = "warn", priority = -1 }
56
+ missing_errors_doc = "allow"
57
+ missing_panics_doc = "allow"
58
+ module_name_repetitions = "allow"
59
+ similar_names = "allow"
60
+
61
+ [features]
62
+ ml-dsa = ["dep:ml-dsa"]
runtime-palw/cuda/CMakeLists.txt ADDED
@@ -0,0 +1,168 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ cmake_minimum_required(VERSION 3.24)
2
+ project(misaka_palw_cuda_trace LANGUAGES C CXX)
3
+
4
+ include(CTest)
5
+
6
+ option(PALW_CUDA_TRACE_ENABLE_CUDA "Build the CUDA trace implementation" ON)
7
+ option(
8
+ PALW_CUDA_PRODUCTION_KERNEL_TRACE
9
+ "Enable production receipt issuance from native CUDA kernel evidence"
10
+ OFF
11
+ )
12
+
13
+ if(PALW_CUDA_PRODUCTION_KERNEL_TRACE)
14
+ message(FATAL_ERROR
15
+ "PALW CUDA production kernel trace is unavailable. "
16
+ "The live diagnostic callback does not consume authority-derived canonical operation, plan, "
17
+ "and physical-layout identities, and deployed governance/trust plus an approved NVIDIA "
18
+ "replica/reproducibility matrix are unavailable; "
19
+ "R32 remains closed.")
20
+ endif()
21
+
22
+ add_executable(palw_cuda_trace_abi_contract
23
+ abi_contract_test.cpp
24
+ record_codec.cpp
25
+ )
26
+ target_include_directories(palw_cuda_trace_abi_contract PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}")
27
+ target_compile_features(palw_cuda_trace_abi_contract PRIVATE cxx_std_17)
28
+ target_compile_definitions(palw_cuda_trace_abi_contract PRIVATE
29
+ PALW_CUDA_TRACE_NO_CUDA_HEADERS=1
30
+ PALW_CUDA_TRACE_GOLDEN_FIXTURE_PATH="${CMAKE_CURRENT_SOURCE_DIR}/fixtures/trace_record_v2.hex"
31
+ PALW_CUDA_TRACE_GOLDEN_FIXTURE_V3_PATH="${CMAKE_CURRENT_SOURCE_DIR}/fixtures/trace_record_v3.hex"
32
+ )
33
+
34
+ add_executable(palw_cuda_trace_c_header_contract header_c_contract_test.c)
35
+ target_include_directories(palw_cuda_trace_c_header_contract PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}")
36
+ target_compile_features(palw_cuda_trace_c_header_contract PRIVATE c_std_11)
37
+ target_compile_definitions(palw_cuda_trace_c_header_contract PRIVATE PALW_CUDA_TRACE_NO_CUDA_HEADERS=1)
38
+ if(MSVC)
39
+ target_compile_options(palw_cuda_trace_c_header_contract PRIVATE /W4 /WX)
40
+ else()
41
+ target_compile_options(palw_cuda_trace_c_header_contract PRIVATE
42
+ -Wall -Wextra -Wpedantic -Werror)
43
+ endif()
44
+
45
+ add_executable(palw_cuda_producer_contract
46
+ producer_contract_test.cpp
47
+ producer_contract.cpp
48
+ record_codec.cpp
49
+ )
50
+ target_include_directories(palw_cuda_producer_contract PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}")
51
+ target_compile_features(palw_cuda_producer_contract PRIVATE cxx_std_17)
52
+ target_compile_definitions(palw_cuda_producer_contract PRIVATE PALW_CUDA_TRACE_NO_CUDA_HEADERS=1)
53
+
54
+ add_executable(palw_cuda_llama_mmvq_bridge_contract
55
+ llama_mmvq_bridge_contract_test.cpp
56
+ )
57
+ target_include_directories(palw_cuda_llama_mmvq_bridge_contract PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}")
58
+ target_compile_features(palw_cuda_llama_mmvq_bridge_contract PRIVATE cxx_std_17)
59
+ target_compile_definitions(palw_cuda_llama_mmvq_bridge_contract PRIVATE PALW_CUDA_TRACE_NO_CUDA_HEADERS=1)
60
+ if(MSVC)
61
+ target_compile_options(palw_cuda_llama_mmvq_bridge_contract PRIVATE /W4 /WX)
62
+ else()
63
+ target_compile_options(palw_cuda_llama_mmvq_bridge_contract PRIVATE
64
+ -Wall -Wextra -Wpedantic -Werror)
65
+ endif()
66
+
67
+ if(BUILD_TESTING)
68
+ add_test(NAME palw_cuda_trace_abi_contract COMMAND palw_cuda_trace_abi_contract)
69
+ add_test(NAME palw_cuda_trace_c_header_contract COMMAND palw_cuda_trace_c_header_contract)
70
+ add_test(NAME palw_cuda_producer_contract COMMAND palw_cuda_producer_contract)
71
+ add_test(NAME palw_cuda_llama_mmvq_bridge_contract COMMAND palw_cuda_llama_mmvq_bridge_contract)
72
+ add_test(
73
+ NAME palw_cuda_trace_production_gate
74
+ COMMAND "${CMAKE_COMMAND}"
75
+ "-DSOURCE_DIR=${CMAKE_CURRENT_SOURCE_DIR}"
76
+ "-DBINARY_DIR=${CMAKE_CURRENT_BINARY_DIR}/production-gate-check"
77
+ -P "${CMAKE_CURRENT_SOURCE_DIR}/production_gate_test.cmake"
78
+ )
79
+ set_tests_properties(palw_cuda_trace_abi_contract PROPERTIES LABELS "host;abi;palw")
80
+ set_tests_properties(palw_cuda_trace_c_header_contract PROPERTIES LABELS "host;abi;palw")
81
+ set_tests_properties(palw_cuda_producer_contract PROPERTIES LABELS "host;producer;palw")
82
+ set_tests_properties(palw_cuda_llama_mmvq_bridge_contract PROPERTIES LABELS "host;abi;producer;palw")
83
+ set_tests_properties(palw_cuda_trace_production_gate PROPERTIES LABELS "host;gate;palw")
84
+ endif()
85
+
86
+ if(NOT PALW_CUDA_TRACE_ENABLE_CUDA)
87
+ message(STATUS "PALW CUDA implementation disabled; only the host ABI contract target is available")
88
+ return()
89
+ endif()
90
+
91
+ include(CheckLanguage)
92
+ check_language(CUDA)
93
+ if(NOT CMAKE_CUDA_COMPILER)
94
+ message(FATAL_ERROR
95
+ "PALW CUDA trace requires nvcc/CUDA. "
96
+ "Use -DPALW_CUDA_TRACE_ENABLE_CUDA=OFF only for the host ABI contract gate.")
97
+ endif()
98
+ enable_language(CUDA)
99
+ find_package(CUDAToolkit REQUIRED)
100
+
101
+ add_library(palw_cuda_trace STATIC
102
+ accumulator.cu
103
+ attention_trace.cu
104
+ gemm_trace.cu
105
+ producer_accumulator.cu
106
+ producer_contract.cpp
107
+ record_codec.cpp
108
+ )
109
+
110
+ target_include_directories(palw_cuda_trace PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}")
111
+ target_link_libraries(palw_cuda_trace PUBLIC CUDA::cudart)
112
+ target_compile_features(palw_cuda_trace PUBLIC cxx_std_17)
113
+ set_target_properties(palw_cuda_trace PROPERTIES
114
+ CUDA_STANDARD 17
115
+ CUDA_STANDARD_REQUIRED ON
116
+ CUDA_SEPARABLE_COMPILATION ON
117
+ POSITION_INDEPENDENT_CODE ON
118
+ )
119
+
120
+ target_compile_options(palw_cuda_trace PRIVATE
121
+ $<$<COMPILE_LANGUAGE:CUDA>:--fmad=false;--prec-div=true;--prec-sqrt=true>
122
+ )
123
+
124
+ if(BUILD_TESTING)
125
+ target_compile_definitions(palw_cuda_trace PRIVATE PALW_CUDA_TRACE_TESTING=1)
126
+ add_executable(palw_cuda_trace_device_test cuda_trace_test.cu)
127
+ target_include_directories(palw_cuda_trace_device_test PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}")
128
+ target_link_libraries(palw_cuda_trace_device_test PRIVATE palw_cuda_trace CUDA::cudart)
129
+ target_compile_features(palw_cuda_trace_device_test PRIVATE cxx_std_17)
130
+ target_compile_definitions(palw_cuda_trace_device_test PRIVATE PALW_CUDA_TRACE_TESTING=1)
131
+ set_target_properties(palw_cuda_trace_device_test PROPERTIES
132
+ CUDA_STANDARD 17
133
+ CUDA_STANDARD_REQUIRED ON
134
+ )
135
+ add_test(NAME palw_cuda_trace_device COMMAND palw_cuda_trace_device_test)
136
+ set_tests_properties(palw_cuda_trace_device PROPERTIES
137
+ LABELS "cuda;gpu;palw"
138
+ SKIP_RETURN_CODE 77
139
+ )
140
+
141
+ add_executable(palw_cuda_producer_device_test producer_accumulator_test.cu)
142
+ target_include_directories(palw_cuda_producer_device_test PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}")
143
+ target_link_libraries(palw_cuda_producer_device_test PRIVATE palw_cuda_trace CUDA::cudart)
144
+ target_compile_features(palw_cuda_producer_device_test PRIVATE cxx_std_17)
145
+ set_target_properties(palw_cuda_producer_device_test PROPERTIES
146
+ CUDA_STANDARD 17
147
+ CUDA_STANDARD_REQUIRED ON
148
+ )
149
+ add_test(NAME palw_cuda_producer_device COMMAND palw_cuda_producer_device_test)
150
+ set_tests_properties(palw_cuda_producer_device PROPERTIES
151
+ LABELS "cuda;gpu;producer;palw"
152
+ SKIP_RETURN_CODE 77
153
+ )
154
+
155
+ add_executable(palw_cuda_grouped_capture_info grouped_capture_info.cu)
156
+ target_include_directories(palw_cuda_grouped_capture_info PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}")
157
+ target_link_libraries(palw_cuda_grouped_capture_info PRIVATE palw_cuda_trace CUDA::cudart)
158
+ target_compile_features(palw_cuda_grouped_capture_info PRIVATE cxx_std_17)
159
+ set_target_properties(palw_cuda_grouped_capture_info PROPERTIES
160
+ CUDA_STANDARD 17
161
+ CUDA_STANDARD_REQUIRED ON
162
+ )
163
+ add_test(NAME palw_cuda_grouped_capture_info COMMAND palw_cuda_grouped_capture_info)
164
+ set_tests_properties(palw_cuda_grouped_capture_info PROPERTIES
165
+ LABELS "cuda;gpu;producer;manifest;palw"
166
+ SKIP_RETURN_CODE 77
167
+ )
168
+ endif()
runtime-palw/cuda/README.md ADDED
@@ -0,0 +1,683 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # PALW CUDA trace backend
2
+
3
+ This directory contains five related but deliberately separate experimental
4
+ contracts:
5
+
6
+ - the CUDA device observer writes V1 records for deterministic, fixed-width
7
+ GEMM and attention tile sketches over the final contiguous `float` output;
8
+ - the standalone producer API writes V2 records from FP32 accumulator values
9
+ passed directly by an instrumented producer kernel before epilogue/output
10
+ storage, and launches only one registered exact CUDA function pointer; and
11
+ - an additive V2 C ABI/codec can carry declared accumulator provenance,
12
+ reduction-segment metadata, and a producer-variant digest, and the Rust
13
+ runtime can strictly decode and bind a complete V2 stream to expected
14
+ dispatch and runtime metadata;
15
+ - an additive 452-byte V3 codec and Rust binder carry exact schedule/group,
16
+ launch-geometry, work-entry, and capture identities and represent the three
17
+ FA-off eager-attention sublaunch roles; and
18
+ - an opt-in, request-local llama.cpp bridge instruments the exact unfused,
19
+ single-column Q4_K/Q6_K MMVQ specializations at their full-K pre-epilogue
20
+ FP32 accumulator point plus the FA-off QK/softmax/PV paths, and fails closed
21
+ on association/identity mismatch.
22
+
23
+ The standalone hook is a real device-side accumulator capture primitive: its
24
+ device test computes segmented dot-product accumulators in registers, captures
25
+ them before an independently variable epilogue, and emits V2 without reading the
26
+ final output. It requires exactly 32 canonical samples per tile and K segment,
27
+ rejects duplicate/missing samples, and detects a stale launch nonce or a compiled
28
+ producer identity mismatch. The existing generic GEMM/attention observer remains
29
+ V1 final-output-only.
30
+
31
+ The vendored MMVQ bridge is available for diagnostic collection, but this does
32
+ **not** make the Qwen path production- or Receipt-capable. The exact launch
33
+ wrapper checks one CUDA function pointer, current SM, and exact
34
+ `cudaFuncGetAttributes` values, then uses that same pointer in `cudaLaunchKernel`.
35
+ The producer supplies compiled dispatch/work/capture IDs to the device hook,
36
+ while the host descriptor supplies a committed binary digest. Binding those
37
+ identifiers to the actual release cubin is implemented by the strict release
38
+ manifest; governance approval remains an authority responsibility. CUDA does not expose a trustworthy
39
+ current-entry-point identity to an arbitrary device helper.
40
+
41
+ The CUDA implementation is fail-closed. Compiling with `nvcc`, passing both
42
+ non-skipped real-device CTests, and passing a reproducibility matrix on the exact
43
+ supported NVIDIA hardware/software manifest are necessary but not sufficient
44
+ for production approval; R32 also requires the FA-off eager-attention producer
45
+ hooks, release binding, Receipt V2 mapping, and complete MMVQ-plus-attention
46
+ device E2E. Those fixed-profile experimental gates are complete; R32 production
47
+ approval still requires the live canonical authority callback, deployed trust
48
+ roots, and replica/reproducibility evidence.
49
+ The no-CUDA CTests prove the C/C++ ABI and canonical codecs. Rust host tests add
50
+ strict V2/V3 decoding and expected-stream binding, but neither host test suite
51
+ proves where a device sketch originated or which kernel actually ran.
52
+ The public headers fix their production-capable macros to zero. Configuring
53
+ with `-DPALW_CUDA_PRODUCTION_KERNEL_TRACE=ON` always fails: this transport cannot
54
+ be enabled for production receipt issuance.
55
+
56
+ The historical MMVQ-only SM89 results are in
57
+ [`../../docs/evidence/cuda-v3-mmvq-hook-sm89-2026-07-15.md`](../../docs/evidence/cuda-v3-mmvq-hook-sm89-2026-07-15.md):
58
+ three positive one-token runs each finalized 253 records (216 Q4_K, 37 Q6_K)
59
+ with fingerprint `6618cafb2d66fc5c`, and a zero-based index-17 rejection stopped
60
+ at 17 accepted records. The current full-stream evidence is
61
+ [`../../docs/evidence/cuda-v3-full-hook-sm89-2026-07-16.md`](../../docs/evidence/cuda-v3-full-hook-sm89-2026-07-16.md):
62
+ three 361/361 runs, 253 MMVQ plus 108 attention records, five work-class
63
+ rejections, and the exact release manifest. The tool reports
64
+ `diagnostic_only=true` and `receipt_authority=false` in both modes.
65
+
66
+ ## Standalone V2 producer-accumulator contract
67
+
68
+ `palw_cuda_producer_trace.h` exposes the host session/launch ABI and
69
+ `palw_cuda_producer_trace.cuh` exposes
70
+ `palw_cuda_producer_capture_accumulator_f32`. The capture call belongs inside
71
+ the producer, at the declared K-segment boundary, while the FP32 accumulator is
72
+ still a register/local value and before epilogue or final store. A producer
73
+ thread calls it exactly once for every logical output and segment. Unsampled
74
+ outputs are ignored; the fixed sample-position function selects 32 ordinals per
75
+ tile, including repeated positions for small tiles.
76
+
77
+ Segment boundaries are canonical, contiguous, and nonempty. Integrations use
78
+ `palw_cuda_producer_segment_begin/end(k, segment, count)`, which partitions the
79
+ full `[0, k)` range by integer quotient/remainder without overlap or gaps.
80
+ `reduction_segment_count > k` is rejected. The audited dispatch variant must
81
+ commit this partition contract; the standalone helper cannot detect a producer
82
+ that computes a different semantic range and then lies about the segment index.
83
+
84
+ Records are initialized and stored in canonical order:
85
+
86
+ ```text
87
+ tile_index = tile_row * tile_grid_columns + tile_column
88
+ record_index = base_record
89
+ + tile_index * reduction_segment_count
90
+ + reduction_segment_index
91
+ ```
92
+
93
+ For each record, a 32-bit atomic sample mask proves every selected ordinal was
94
+ seen. A second mask makes duplicate observation fatal. Sketch lanes use a
95
+ commutative integer XOR of canonicalized FP32 contributions tagged with sample,
96
+ logical row/column, and segment; scheduling cannot change the result. The hook
97
+ never loads the final-output buffer. `-0.0` and NaN payloads use the same
98
+ canonicalization as V1.
99
+
100
+ `palw_cuda_producer_trace_prepare` validates GEMM shape, canonical record count,
101
+ strict logical sequence, strictly increasing nonzero request-local nonce, exact
102
+ SM, launch geometry, nonzero identity digests, and exact CUDA-reported binary/
103
+ PTX/register/max-thread attributes. It initializes records on the bound stream
104
+ and returns a library-owned device view. `palw_cuda_producer_trace_launch`
105
+ rejects a function pointer different from the prepared pointer and launches the
106
+ prepared pointer itself. It also injects the immutable prepared device view at
107
+ the kernel-argument index registered with the audited ABI during `prepare`;
108
+ `launch` has no free index/count input. A caller-provided substitute view is
109
+ therefore never marshalled to the kernel. Finalization synchronizes and accepts records only if
110
+ every sample was observed exactly once and no view, nonce, index, identity, or
111
+ metadata fault occurred. Every copied V2 semantic metadata field is re-encoded
112
+ and compared with the host-retained immutable launch expectation; only the four
113
+ data-dependent sketch lanes may differ. Any integrity failure permanently poisons the context;
114
+ copied bytes are diagnostic only.
115
+
116
+ The three identity domains are intentionally separate:
117
+
118
+ - `producer_variant_id` commits the canonical dispatch descriptor and is in V2;
119
+ - `entry_point_id` commits the fully specialized producer entry-point contract;
120
+ - `kernel_binary_digest` commits the release cubin/fatbin artifact.
121
+
122
+ The wrapper proves which registered CUDA function pointer it launched in the
123
+ current trusted process. It cannot derive either digest from a function pointer,
124
+ prove that a caller-provided digest matches loaded machine code, or prove that
125
+ an unreviewed producer passed a semantically genuine accumulator. Production
126
+ therefore additionally needs audited vendored integration, release-binary
127
+ attestation, actual-dispatch coverage, and the closed Receipt mapping gate.
128
+
129
+ ## V1 device observer and deterministic record order
130
+
131
+ The observer launch is enqueued immediately after the operation being observed,
132
+ on the same CUDA stream. One CUDA block and one active thread handle each logical
133
+ output tile. For a tile grid with columns `grid_x`, the canonical tile index is:
134
+
135
+ ```text
136
+ tile_index = tile_row * grid_x + tile_column
137
+ record_index = base_record + tile_index
138
+ ```
139
+
140
+ Each thread writes directly to that record index. CUDA block scheduling therefore
141
+ cannot reorder records. A tile reads 32 fixed logical positions, canonicalizes
142
+ `-0.0` to `+0.0` and every NaN payload to one quiet-NaN bit pattern, and produces
143
+ four integer mixing lanes. It uses no floating-point reduction and no atomics.
144
+
145
+ This makes the observer deterministic for identical output bits and metadata on
146
+ the same supported stack. It does not make an upstream GEMM or attention kernel
147
+ numerically deterministic. A legitimate upstream bit change is expected to
148
+ change a sketch, and cross-GPU repeatability has not yet been established.
149
+
150
+ The current launch path writes `palw_cuda_trace_record` with schema V1. V2 has a
151
+ separate ordering contract: the Rust binder requires logical launches in
152
+ consecutive zero-based order, and within each launch requires tile-major then
153
+ reduction-segment-major order. The C codec validates each record's tile and
154
+ segment consistency; the Rust binder validates the cross-record ordering. The
155
+ current CUDA observer does not produce those V2 records.
156
+
157
+ ## Validated V1 device contracts
158
+
159
+ All dimensions must be nonzero and fit in `uint32_t`. Common validation also
160
+ rejects null or misaligned pointers, address and multiplication overflow, a row
161
+ stride smaller than the logical width, out-of-range layer/phase/dtype/quantization
162
+ tags, invalid tile geometry, more than `UINT32_MAX` tiles, CUDA grid limits, a
163
+ nonconsecutive sequence, a second CUDA stream, pending copies, and insufficient
164
+ record capacity.
165
+
166
+ The `float` pointer is the sketch transport. `dtype` records the logical operation
167
+ dtype and may therefore differ from the transport type.
168
+
169
+ GEMM uses ggml's contiguous storage for a logical `[m, n]` result:
170
+
171
+ ```text
172
+ storage [batch][n][m], m is contiguous
173
+ output_rows n * batch
174
+ output_columns m
175
+ row_stride >= m
176
+ m, n, k, batch nonzero and <= UINT32_MAX
177
+ ```
178
+
179
+ Attention uses:
180
+
181
+ ```text
182
+ storage [batch][query_tokens][heads * head_dim]
183
+ output_rows query_tokens * batch
184
+ output_columns heads * head_dim
185
+ row_stride >= output_columns
186
+ causal exactly 0 or 1
187
+ causal KV length key_value_tokens >= query_tokens
188
+ decode query length exactly 1
189
+ ```
190
+
191
+ Prefill requires `decode_step == 0`; decode requires a step that fits in
192
+ `uint32_t`. Attention always records quantization `NONE`.
193
+
194
+ ## State, rollback, and poison semantics
195
+
196
+ One context is permanently bound to the first CUDA stream used with it and is
197
+ not thread-safe. The required sequence starts at zero.
198
+
199
+ | Event | Count/sequence effect | Resulting state |
200
+ | --- | --- | --- |
201
+ | Validation failure | No change | Reusable |
202
+ | Sequence mismatch | No change | Reusable |
203
+ | Capacity failure | No reservation and no sequence consumption | Sticky overflow |
204
+ | Immediate observed/trace launch error | No reservation for that launch | Permanently poisoned |
205
+ | Successful immediate trace launch | Reserves every tile and consumes one sequence | Queued, not committed |
206
+ | Successful synchronize | Commits all accepted launches and completes a pending copy | Reusable |
207
+ | Asynchronous stream failure at synchronize | Existing reservations remain diagnostic only | Permanently poisoned |
208
+ | D2H enqueue failure | No new copy becomes usable | Permanently poisoned |
209
+
210
+ `palw_cuda_trace_count` reports accepted/reserved records, including queued work.
211
+ `palw_cuda_trace_committed_count` advances only after a successful
212
+ `palw_cuda_trace_synchronize`. An immediate failure rolls back implicitly because
213
+ the host counters advance only after `cudaGetLastError` reports success. An
214
+ asynchronous failure cannot safely roll back already queued device writes, so the
215
+ context is poisoned and every later launch, copy, synchronize, or reset fails
216
+ closed with `PALW_CUDA_TRACE_POISONED`. Destroy it, fail the enclosing inference
217
+ request, and rebuild the affected CUDA backend/stream before a later request;
218
+ allocating only a fresh trace context is not proof that an asynchronous device
219
+ failure was recovered. If synchronization fails after a D2H enqueue, do not
220
+ consume or release the host buffer until that backend/stream teardown completes.
221
+
222
+ Overflow is also a receipt failure. It can be cleared only by synchronizing any
223
+ work accepted before the overflow and then resetting. Reset clears counts,
224
+ sequence, and overflow, but does not change the permanent stream binding and can
225
+ never clear CUDA poison. Destroying a context or releasing a host copy buffer
226
+ while work is pending is a caller error.
227
+
228
+ ## Canonical V1/V2/V3 encoding: never hash native memory
229
+
230
+ `palw_cuda_trace_record` has a checked native ABI size of 144 bytes, including a
231
+ reserved byte and native tail padding. `palw_cuda_trace_record_v2` has a checked
232
+ native ABI size of 192 bytes and more padding between fields. None of that
233
+ padding is transport or consensus data. Hashing or serializing either raw struct
234
+ is forbidden.
235
+
236
+ `palw_cuda_trace_encode_record_v1` validates a schema-V1 record and writes
237
+ exactly 139 big-endian bytes, field by field, in this order:
238
+
239
+ ```text
240
+ 9 * u64 kernel_sequence .. key_value_tokens
241
+ 4 * u64 sketch lanes
242
+ 7 * u32 layer_id .. output_columns
243
+ 1 * u16 schema_version
244
+ 5 * u8 kind, phase, dtype, quantization, causal
245
+ ```
246
+
247
+ The additive `palw_cuda_trace_encode_record_v2` requires schema V2 and writes the
248
+ same 139-byte semantic prefix followed by:
249
+
250
+ ```text
251
+ 3 * u8 declared_origin, accumulator_stage, accumulator_dtype
252
+ 1 * u16 sketch_scheme
253
+ 2 * u32 reduction_segment_index, reduction_segment_count
254
+ 32 bytes producer_variant_id
255
+ ```
256
+
257
+ The result is exactly 184 bytes. The V1 reserved byte and all native padding are
258
+ excluded from both encodings. V2 does not replace V1: the generic observer and
259
+ its copy API still use the V1 native record. The standalone producer session has
260
+ a separate V2 device buffer/finalizer and never relabels a V1 observation.
261
+
262
+ Both the C++ codec and Rust decoder reject unknown tags, zero producer-variant
263
+ IDs, and inconsistent provenance tuples. Final-output records must use no
264
+ accumulator stage or dtype, the final-output sketch scheme, and zero reduction
265
+ segment fields. A producer-accumulator declaration is accepted only for GEMM,
266
+ FP32 scalar-accumulator sketches, an approved pre-reduction or full-K stage, and
267
+ a valid nonempty segment range; full-K evidence must be a single segment.
268
+
269
+ These checks establish canonical syntax and internal consistency only. In
270
+ particular, the C codec cannot prove that `producer_variant_id` is canonical or
271
+ that `declared_origin` is true.
272
+
273
+ V3 is a separate additive schema with a checked 464-byte native record and an
274
+ exact 452-byte canonical encoding. It extends the V2 semantic prefix with exact
275
+ schedule and attention-group ownership, sublaunch role/count, physical layout
276
+ and launch geometry, and operation/group/plan/layout/work/capture identities.
277
+ The V3 codec never serializes native padding. Neither V1 nor V2 Receipt code may
278
+ reinterpret a V3 record.
279
+
280
+ ## Rust V2/V3 stream binding
281
+
282
+ `runtime-palw/src/cuda_trace.rs` provides `RawCudaTraceRecordV2::decode_strict`
283
+ for exactly one 184-byte record and `decode_cuda_trace_v2_stream` for a
284
+ concatenated exact-size stream. `bind_cuda_trace_v2` then validates the complete,
285
+ unfiltered stream before any possible GEMM-only projection. It requires:
286
+
287
+ - an immutable, nonempty expected-launch table with consecutive zero-based
288
+ logical launch sequences and strictly increasing schedule indices;
289
+ - exact record count and contiguous tile/segment order for every GEMM and
290
+ attention launch;
291
+ - equality of operation shape, phase/decode step, layer, tile geometry,
292
+ provenance tuple, segment count, and canonical dispatch-variant digest;
293
+ - the initial profile of one CUDA accelerator, tensor parallelism one, no tensor
294
+ repack, batch one for bound operations, and flash attention enabled whenever
295
+ an attention launch is expected; and
296
+ - an exact supported dispatch descriptor: currently unfused single-column
297
+ llama.cpp MMVQ metadata or a pinned flash-attention specialization digest.
298
+
299
+ For a validated expected dispatch, `derive_cuda_kernel_id` binds the runtime
300
+ manifest's kernel binary digest, kernel algorithm digest, source commit, CUDA SM
301
+ architecture, and canonical dispatch descriptor. This is a host-side identity
302
+ derivation from trusted expected metadata. Until the vendored producer reports
303
+ and is checked against the actual selected specialization, it is not proof of
304
+ the kernel entry point that executed.
305
+
306
+ The result, `BoundCudaTranscriptV1`, intentionally exposes only the immutable
307
+ raw records, bound launch ranges, expected descriptors, and derived producer
308
+ kernel IDs. Raw or merely bound records have no conversion to receipt evidence
309
+ and cannot authorize receipt issuance or upgrade `TraceCapability`.
310
+
311
+ `runtime-palw/src/cuda_attestation.rs` adds a separate, no-public-constructor
312
+ authority typestate. A network-scoped Ed25519 authority envelope commits the
313
+ exact job/execution, signed assignment, runtime instance/class/manifest,
314
+ reviewed producer integration, operation schedule, full unfiltered transcript,
315
+ and epochs. Registry verification checks validity, revocation, and exact
316
+ runtime/integration approval, then requires every scheduled GEMM and attention
317
+ index exactly once. Only the resulting `AuthorityBoundCudaTranscriptV2` may be
318
+ projected to `AuthorityBoundCudaReceiptEvidenceV2`, and that projection includes
319
+ only true producer-accumulator GEMMs while retaining the full transcript
320
+ commitment. The newer V3 authority and `receipt_v2_flow` bind the complete fixed
321
+ 361-launch profile into the implemented Receipt V2. The V1 builder
322
+ and verifier both reject CUDA `KernelSketch`, including a hand-built/resigned V1
323
+ body, because V1 has no field for the authority provenance commitment.
324
+
325
+ The deterministic Qwen profile currently has flash attention disabled. In the
326
+ measured three-token graph stream, 975 GEMMs split into 759 quantized MMVQ
327
+ events (253/token: Q4_K 648 and Q6_K 111 total) and 216 eager-attention F16
328
+ `MUL_MAT` events (72/token). The V3 schema and Rust binder now represent each
329
+ FA-off eager group as QK-score GEMM, masked/scaled softmax, and PV GEMM
330
+ sublaunches with separate covered schedule indices. The vendored QK-score,
331
+ masked/scaled softmax, and PV work paths now enqueue the grouped collector on
332
+ the same stream and are associated from typed graph metadata. The resulting
333
+ 361-launch MMVQ-plus-attention stream passed three real-model device runs with
334
+ identical fingerprints and five work-class rejection gates. The implemented V2
335
+ verifier binds a strict authority-provided expected table; the live diagnostic
336
+ callback does not yet receive that canonical authority table.
337
+
338
+ ## Build and test gates
339
+
340
+ The normal configuration requires CUDA and fails instead of silently compiling a
341
+ stub. It builds the experimental transport and its tests, not a production
342
+ receipt path:
343
+
344
+ ```sh
345
+ cmake -S runtime-palw/cuda -B build/palw-cuda -DBUILD_TESTING=ON
346
+ cmake --build build/palw-cuda
347
+ ctest --test-dir build/palw-cuda --output-on-failure
348
+ ```
349
+
350
+ The explicit production gate is intentionally closed:
351
+
352
+ ```sh
353
+ cmake -S runtime-palw/cuda -B build/palw-cuda-production \
354
+ -DPALW_CUDA_PRODUCTION_KERNEL_TRACE=ON
355
+ # FATAL_ERROR: vendored integration/Receipt mapping/reproducibility remain incomplete
356
+ ```
357
+
358
+ Production builds must additionally set one exact `CMAKE_CUDA_ARCHITECTURES`
359
+ value that matches the committed runtime class (for example `90-real` for an
360
+ approved `sm_90` class); compiler-default or fat-binary ambiguity is not an
361
+ acceptable reproducibility gate.
362
+
363
+ On a machine without CUDA, the V1/V2 header, layout, enum-tag, canonical codec,
364
+ golden-fixture, and closed production-gate contracts can be tested:
365
+
366
+ ```sh
367
+ cmake -S runtime-palw/cuda -B build/palw-cuda-host \
368
+ -DPALW_CUDA_TRACE_ENABLE_CUDA=OFF -DBUILD_TESTING=ON
369
+ cmake --build build/palw-cuda-host
370
+ ctest --test-dir build/palw-cuda-host --output-on-failure -L host
371
+ ```
372
+
373
+ The Rust cross-language contract is independent of CUDA hardware:
374
+
375
+ ```sh
376
+ cargo +1.81 test --locked --test cuda_trace_contract
377
+ ```
378
+
379
+ It decodes the shared V2 golden bytes also produced and checked by the C++ codec
380
+ test, and exercises strict
381
+ length/tag/provenance validation, complete GEMM-plus-attention stream binding,
382
+ missing/duplicate/reordered/mutated failures, launch/schedule constraints,
383
+ dispatch compatibility, runtime-class restrictions, and manifest/SM/dispatch
384
+ kernel-ID derivation. These are transport and metadata-binding tests, not device
385
+ producer tests.
386
+
387
+ One device CTest exercises the final-output V1 observer. It covers GEMM and
388
+ attention record count/order, same-stream
389
+ repeatability, sampled mutation sensitivity and tile isolation, dtype/phase/
390
+ quantization/shape/stride/tile validation, causal and decode constraints,
391
+ capacity/reset behavior, exact sequence enforcement, stream binding, copy and
392
+ commit states, permanent launch-failure poison, and recovery only through a new
393
+ trace context for the injected non-sticky invalid-configuration error. It
394
+ returns CTest skip code 77 if no CUDA device/driver is available. A
395
+ future R32 production review must treat a skipped device test as **not
396
+ verified**, not as a pass.
397
+
398
+ The second device CTest exercises the standalone V2 producer primitive with a
399
+ real segmented GEMM test kernel. It proves that an epilogue-only mutation changes
400
+ final output but not pre-epilogue evidence, while an input/accumulator mutation
401
+ does change evidence. It also rejects the wrong launch pointer, a compiled
402
+ identity mismatch, and an uninstrumented producer with incomplete coverage.
403
+ It proves that a producer-side V2 metadata overwrite is rejected by the
404
+ host-retained expectation and that a substituted caller view is replaced by the
405
+ prepared view. This is a primitive-level test kernel, not the vendored Qwen
406
+ producer E2E.
407
+
408
+ ### Verification in this checkout (2026-07-15)
409
+
410
+ - The host-only configuration built with AppleClang 21 using
411
+ `-Wall -Wextra -Wpedantic -Werror`; all five host CTests passed (5/5), including
412
+ pure producer-descriptor validation and
413
+ the nested configuration test that proves the production gate rejects this
414
+ transport.
415
+ - The same five host CTests passed under AppleClang AddressSanitizer and
416
+ UndefinedBehaviorSanitizer (5/5) with no sanitizer report.
417
+ - The default CUDA-required configuration failed at configure time as intended:
418
+ no CUDA compiler was found.
419
+ - `nvcc` and an NVIDIA device are unavailable on this Apple arm64 host. On the
420
+ separate Windows/WSL2 NVIDIA gate, an RTX 4060 Ti (`sm_89`), driver 610.62,
421
+ CUDA toolkit 13.3.1/NVCC 13.3.73, and `CMAKE_CUDA_ARCHITECTURES=89-real` built
422
+ the final grouped build passed all eight CTests, including three non-skipped
423
+ device/collector tests.
424
+ The standalone producer test then passed 20 separate executions with the same
425
+ encoded-transcript diagnostic fingerprint `c1a38ed138200874` each time. This
426
+ is primitive-level SM89 evidence, not vendored Qwen E2E or a cross-stack
427
+ reproducibility matrix.
428
+ - `cargo +1.81 test --locked --test cuda_trace_contract` passed all thirteen Rust
429
+ V2 codec/binding/authority-typestate tests on this host. Those host tests do
430
+ not replace producer device evidence.
431
+ - `cargo +1.81 test --locked --test cuda_trace_v3_contract` passed all nine V3
432
+ codec, identity, dispatch, FA-off grouping, and binding contract tests. The
433
+ complete locked Rust 1.81.0 gate passed 224 tests, with 2 real-model tests
434
+ ignored (226 discovered); fmt, Clippy `-D warnings`, and rustdoc `-D warnings`
435
+ also passed.
436
+ - The final opt-in vendored V3 build on the same RTX 4060 Ti/NVCC 13.3.73 stack
437
+ passed three one-token positive runs with 361/361 committed records and the
438
+ same `22f3a57e3640a8c6` canonical-record diagnostic fingerprint: Q4_K 216,
439
+ Q6_K 37, and QK/softmax/PV 36 each. Rejecting the first Q4_K, Q6_K, QK,
440
+ softmax, or PV launch stopped at the exact selected position. A strict release
441
+ manifest bound six exact symbols, runtime attributes, cubins, fatbin, and the
442
+ loaded DSO. This is complete vendored hook diagnostic E2E, not production
443
+ Receipt-authority E2E.
444
+
445
+ ## Historical V2 integration design and current V3 delta
446
+
447
+ The original design below was pinned to vendored llama.cpp commit
448
+ `12127defda4f41b7679cb2477a4b0d65ee6a0c8f`. Its default-off build boundary,
449
+ request-local state, exact association, graph/fusion/concurrency rejection, and
450
+ fail-closed principles now inform the active V3 MMVQ diagnostic bridge. Code
451
+ snippets and V2 type names in this section are retained as the historical
452
+ baseline, not as a literal description of the current V3 call sites. Attention
453
+ producer integration and Receipt/Bundle/SQLite V2 are now implemented; the
454
+ production authority callback and issuance gate remain future work.
455
+
456
+ ### Opt-in build boundary
457
+
458
+ Add a default-off `GGML_CUDA_PALW_TRACE` CMake option. Only when it is enabled,
459
+ require a `PALW_CUDA_TRACE_SOURCE_DIR`, add this directory with
460
+ `EXCLUDE_FROM_ALL`, link `palw_cuda_trace` into `ggml-cuda`, and define the hook:
461
+
462
+ ```cmake
463
+ option(GGML_CUDA_PALW_TRACE "Enable fail-closed PALW CUDA observation" OFF)
464
+ set(PALW_CUDA_TRACE_SOURCE_DIR "" CACHE PATH "PALW CUDA trace source")
465
+
466
+ if (GGML_CUDA_PALW_TRACE)
467
+ if (NOT IS_DIRECTORY "${PALW_CUDA_TRACE_SOURCE_DIR}")
468
+ message(FATAL_ERROR "GGML_CUDA_PALW_TRACE requires PALW_CUDA_TRACE_SOURCE_DIR")
469
+ endif()
470
+ set(PALW_CUDA_TRACE_ENABLE_CUDA ON CACHE BOOL "" FORCE)
471
+ add_subdirectory("${PALW_CUDA_TRACE_SOURCE_DIR}"
472
+ "${CMAKE_CURRENT_BINARY_DIR}/palw-trace" EXCLUDE_FROM_ALL)
473
+ target_link_libraries(ggml-cuda PRIVATE palw_cuda_trace)
474
+ target_compile_definitions(ggml-cuda PRIVATE GGML_CUDA_PALW_TRACE=1)
475
+ endif()
476
+ ```
477
+
478
+ `GGML_CUDA_PALW_TRACE` in this design is an experimental data-collection hook
479
+ only. Any receipt-issuing build must additionally require
480
+ `PALW_CUDA_TRACE_PRODUCTION_CAPABLE == 1` and enable
481
+ `PALW_CUDA_PRODUCTION_KERNEL_TRACE`; both checks intentionally fail today.
482
+
483
+ The final patch must also verify compatible dynamic/static CUDA-runtime linkage
484
+ for both llama.cpp link modes. With the option off, the existing target, ABI, and
485
+ runtime behavior must remain unchanged.
486
+
487
+ ### Per-request registration API
488
+
489
+ Do not use global mutable metadata and do not infer layer or phase from tensor
490
+ names. Add an optional PALW state object to `ggml_backend_cuda_context` in
491
+ `ggml/src/ggml-cuda/common.cuh`. Before graph compute, the runtime observer
492
+ registers an immutable table keyed by `const ggml_tensor *` with one entry per
493
+ expected CUDA node. It must contain the same information represented by Rust
494
+ `ExpectedCudaLaunchV1`:
495
+
496
+ ```text
497
+ node pointer, expected op and exact dispatch descriptor, logical launch sequence,
498
+ schedule index, layer, phase/decode step, logical dtype, quantization, causal,
499
+ tile geometry, declared provenance tuple, expected reduction segment count
500
+ ```
501
+
502
+ The table is sorted by logical launch sequence, starts at zero, has strictly
503
+ increasing schedule indices, contains no duplicate node, and has a precomputed
504
+ expected record total. A request also owns the trace context, pinned host record
505
+ buffer, observed-node bitmap, and sticky PALW status. Beginning a request rejects
506
+ a reused/poisoned state or an unsupported execution mode. Finalization requires
507
+ every registered node exactly once and no unexpected eligible node.
508
+
509
+ ### Central call sites
510
+
511
+ In `ggml/src/ggml-cuda/ggml-cuda.cu`, place hooks in the central dispatcher after
512
+ the final producer returns:
513
+
514
+ ```cpp
515
+ case GGML_OP_MUL_MAT: {
516
+ const auto variant = ggml_cuda_mul_mat(ctx, dst->src[0], dst->src[1], dst);
517
+ ggml_cuda_palw_after_node(ctx, dst, variant); // same stream, after producer
518
+ break;
519
+ }
520
+
521
+ case GGML_OP_FLASH_ATTN_EXT: {
522
+ const auto variant = ggml_cuda_flash_attn_ext(ctx, dst);
523
+ ggml_cuda_palw_after_node(ctx, dst, variant); // same ctx.stream()
524
+ break;
525
+ }
526
+ ```
527
+
528
+ Those dispatcher hooks establish complete operation coverage and report the
529
+ selected dispatch; they cannot by themselves observe a producer accumulator.
530
+ True accumulator sampling must be instrumented inside the selected producer
531
+ kernel at the declared stage, with the dispatcher hook checking that the
532
+ expected node and specialization emitted exactly the required V2 records.
533
+
534
+ This location is important. `ggml_cuda_mul_mat` near line 1731 has early returns
535
+ for FWHT, cuBLAS, MMVF, MMF, MMVQ, and MMQ variants; hooking inside only one
536
+ variant would silently omit records. The dispatcher cases are near lines 2119
537
+ and 2224 in the pinned commit.
538
+
539
+ The shown return value is part of the required patch: every producer path must
540
+ report the actually selected stable dispatch token. The implemented Rust V1
541
+ dispatch contract is deliberately narrower than llama.cpp's full selector: it
542
+ accepts only an unfused, single-column MMVQ specialization with exact weight
543
+ type, small-K flag, architecture parameter table, warp count, and rows per
544
+ block, or a flash-attention descriptor with a nonzero exact specialization
545
+ digest. FWHT, cuBLAS, MMVF, MMF, MMQ, fused MMVQ, and any unclassified attention
546
+ specialization must fail closed until a versioned descriptor supports them.
547
+
548
+ The hook must compare the actual token with the registered expected dispatch and
549
+ place the canonical dispatch digest into every V2 record. Rust already derives a
550
+ host-side `producer_kernel_id` from the committed kernel binary and algorithm
551
+ digests, runtime source commit, SM architecture, and validated dispatch. A
552
+ coarse "GEMM" or "attention" label is insufficient, and that derivation does not
553
+ prove actual execution until the device integration supplies and authenticates
554
+ the selected specialization.
555
+
556
+ Some logical dispatches run an ordered bundle of conversion, GEMM/attention,
557
+ and fixup kernels rather than one entry point. The current singular Rust
558
+ `kernel_id` contract cannot silently represent such a bundle. Either restrict
559
+ the approved runtime to a proven single-producer path, hook and record each
560
+ actual kernel under a revised grouping contract, or version the receipt schema
561
+ with an explicit ordered-bundle identity.
562
+
563
+ The bridge accepts only contiguous `GGML_TYPE_F32` destination tensors and uses
564
+ overflow-checked dimensions:
565
+
566
+ | Operation | PALW mapping from ggml |
567
+ | --- | --- |
568
+ | GEMM | `m = dst->ne[0]`, `n = dst->ne[1]`, `k = src0->ne[0]`, `batch = dst->ne[2] * dst->ne[3]`, rows `n * batch`, columns/stride `m` |
569
+ | Flash attention | `query_tokens = Q->ne[1]`, `key_value_tokens = K->ne[1]`, `heads = Q->ne[2] = dst->ne[1]`, `head_dim = V->ne[0] = dst->ne[0]`, `batch = Q->ne[3] = dst->ne[3]`, rows `query_tokens * batch`, columns/stride `heads * head_dim` |
570
+
571
+ The registered descriptor supplies causal policy, logical dtype, quantization,
572
+ phase, layer, and decode step. A non-null attention mask is not sufficient proof
573
+ of causality. Any tensor/layout/descriptor disagreement fails the request before
574
+ the trace launch.
575
+
576
+ The hook stores a PALW error in the backend context. Change
577
+ `ggml_cuda_graph_evaluate_and_capture` to return failure immediately after the
578
+ current `ggml_cuda_compute_forward` call if that sticky status is non-OK, and
579
+ have `ggml_backend_cuda_graph_compute` return `GGML_STATUS_FAILED`. Do not reuse
580
+ the existing `false` return from `ggml_cuda_compute_forward`, because that path
581
+ currently means "unsupported op" and is followed by `GGML_ASSERT(ok)`.
582
+
583
+ The current `palw_cuda_trace_copy_async` path copies only native V1 final-output
584
+ records. A producer integration must add a separately reviewed V2 device-buffer
585
+ and copy path; relabeling or wrapping a copied V1 record as producer-accumulator
586
+ evidence is forbidden. After graph submission, finalization must synchronize the
587
+ same stream, check committed count and exact node/record coverage, encode every
588
+ V2 record, strictly decode it in Rust, and call `bind_cuda_trace_v2`. Any hook,
589
+ CUDA, overflow, coverage, codec, decoder, or binding error fails the request.
590
+ Even success produces diagnostic bound transport only. It must next pass the
591
+ authority verification described above; a successful authority-bound projection
592
+ still suppresses V1 receipt issuance. Current V3 authority evidence is accepted
593
+ only by the separately versioned Receipt V2 flow.
594
+
595
+ The CUDA `kernel_sequence` is a zero-based **logical launch** sequence. Every
596
+ tile belonging to one registered GEMM or attention launch carries the same raw
597
+ sequence, and attention launches consume sequence values. This deliberately does
598
+ not match the current Rust `GemmTraceSample.kernel_sequence`, which is a
599
+ zero-based sequence over GEMM tile events only. `bind_cuda_trace_v2` now performs
600
+ the complete unfiltered validation: launch sequences are consecutive, each
601
+ registered launch owns one contiguous tile/segment range, every record in that
602
+ range has matching metadata and dispatch digest, and all expected GEMM and
603
+ attention launches are present exactly once. Filtering or resequencing first
604
+ could hide a missing or reordered attention launch and remains forbidden.
605
+
606
+ Raw or merely bound CUDA records must never be passed to `GemmTrace::push_group`
607
+ or represented as `TraceEvidenceKind::KernelSketch`. Only the authority-verified
608
+ typestate can create the implemented future-V2 projection, which commits its
609
+ signed attestation, full transcript, integration, mapping version, and projected
610
+ trace. It does not make that trace valid V1 evidence. Production issuance still
611
+ requires governance approval of the exact binary/manifest, a live callback fed
612
+ by canonical authority IDs, deployed trust roots, and reproducibility evidence.
613
+
614
+ ### Execution modes that must be disabled or rejected initially
615
+
616
+ The first production integration must be deliberately narrow:
617
+
618
+ - Disable CUDA graph capture/replay while PALW is active. A captured sketch
619
+ launch bakes `base_record` and sequence arguments, while a replay skips the
620
+ host dispatcher, so replay would overwrite records. The pinned tree recognizes
621
+ `GGML_CUDA_DISABLE_GRAPHS`, but the patch should make graph enablement return
622
+ false directly when PALW state is active.
623
+ - Disable graph fusion while PALW is active by returning zero from
624
+ `ggml_cuda_try_fuse`. The pinned tree also has `GGML_CUDA_DISABLE_FUSION=1` for
625
+ prototype runs. Fused MUL_MAT paths around lines 3224-3715 bypass the central
626
+ dispatcher hooks.
627
+ - Require `curr_stream_no == 0` and a single CUDA device. The graph optimization
628
+ path can use multiple streams when `GGML_CUDA_GRAPH_OPT=1`; an initial PALW
629
+ request must reject it. Supporting concurrency later requires one context per
630
+ stream plus a separately specified deterministic merge order.
631
+ - Require the initial Rust V2 binding profile's fixed `batch == 1`. The strict
632
+ record decoder and standalone C transport can represent larger batches, but
633
+ `ExpectedCudaLaunchV1` rejects them.
634
+ - Support the exact unfused, single-column MMVQ dense path only. Reject other
635
+ `GGML_OP_MUL_MAT` variants, `GGML_OP_MUL_MAT_ID`, and unexpected CPU/offload
636
+ paths until each has an explicit versioned dispatch descriptor. This is
637
+ suitable for the dense Qwen target, not MoE.
638
+ - For the FA-off runtime, require exact hooks for QK-score GEMM, masked/scaled
639
+ softmax, and PV GEMM under the V3 grouping contract. Never
640
+ claim full attention coverage while any stage is uninstrumented. A separately
641
+ approved FA-on class would require its own exact fused specialization binding.
642
+
643
+ These restrictions are receipt integrity requirements, not performance hints.
644
+ Removing one requires a new tested ordering and coverage contract.
645
+
646
+ ## Known limits before production approval
647
+
648
+ - The vendored Q4_K/Q6_K MMVQ hook captures a diagnostic full-K pre-epilogue
649
+ FP32 accumulator. The FA-off QK MMVF, F32 masked/scaled softmax, and PV MMVF
650
+ work paths enqueue the grouped collector on the same stream. The 361-launch
651
+ device E2E and exact release manifest are evidence, but the live callback still
652
+ uses diagnostic rather than authority-provided canonical physical-layout IDs.
653
+ - The launch wrapper checks an exact function pointer and attributes, but CUDA
654
+ cannot derive/attest the release binary digest or semantic accumulator stage
655
+ from that pointer; reviewed source, binary attestation, and manifest binding
656
+ are still required.
657
+ - The 32 public sample positions and integer mixer are deterministic evidence,
658
+ not a cryptographic proof that every output element was computed. Hashing the
659
+ resulting record with SHA3 does not recover unsampled coverage; replication,
660
+ future audit, and an approved sampling/security analysis remain mandatory.
661
+ - Raw or merely bound transcripts cannot establish `KernelSketch` provenance.
662
+ Only the V3 authority typestate may enter Receipt V2; CUDA `KernelSketch`
663
+ remains forbidden in `ComputeReceiptV1`.
664
+ - Cross-architecture and cross-driver reproducibility is unproven.
665
+ - CUDA graph replay, fusion, concurrent streams, multi-GPU merge, MoE
666
+ `MUL_MAT_ID`, and attention variants outside the pinned FA-off QK-score /
667
+ masked-scaled-softmax / PV specializations are intentionally unsupported by
668
+ the proposed first integration.
669
+ - Existing llama.cpp `CUDA_CHECK`/`GGML_ABORT` process-fatal behavior is outside
670
+ this library; a service-grade integration must audit whether those paths need
671
+ conversion to request-scoped errors.
672
+
673
+ R32 remains in progress until the integration proves every accepted event came
674
+ from the exact authority-approved release kernel entry point (or an explicitly
675
+ versioned ordered-kernel-bundle identity) through the live canonical authority
676
+ callback and passes replica/reproducibility gates under deployed trust roots.
677
+ FA-off attention coverage, device E2E, the release manifest, and Receipt V2 are
678
+ complete for the fixed diagnostic profile. The external NVIDIA
679
+ hardware blocker is resolved by the SM89 gate above; the remaining blockers are
680
+ authority/governance integration and production evidence.
681
+ Host-side V2/V3 transport and expected-metadata binding do not satisfy those
682
+ conditions. The production CMake gate and capability macro must not be opened
683
+ before they do.
runtime-palw/cuda/abi_contract_test.cpp ADDED
@@ -0,0 +1,723 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #include "palw_cuda_trace.h"
2
+
3
+ #include <array>
4
+ #include <cstddef>
5
+ #include <cstdint>
6
+ #include <cstdio>
7
+ #include <cstring>
8
+ #include <fstream>
9
+ #include <string>
10
+ #include <type_traits>
11
+ #include <vector>
12
+
13
+ #if !defined(PALW_CUDA_TRACE_GOLDEN_FIXTURE_PATH)
14
+ #error "PALW_CUDA_TRACE_GOLDEN_FIXTURE_PATH is required"
15
+ #endif
16
+ #if !defined(PALW_CUDA_TRACE_GOLDEN_FIXTURE_V3_PATH)
17
+ #error "PALW_CUDA_TRACE_GOLDEN_FIXTURE_V3_PATH is required"
18
+ #endif
19
+
20
+ static_assert(PALW_CUDA_TRACE_ABI_VERSION == 1U);
21
+ static_assert(PALW_CUDA_TRACE_SCHEMA_VERSION == 1U);
22
+ static_assert(PALW_CUDA_TRACE_SCHEMA_VERSION_V1 == 1U);
23
+ static_assert(PALW_CUDA_TRACE_SCHEMA_VERSION_V2 == 2U);
24
+ static_assert(PALW_CUDA_TRACE_SCHEMA_VERSION_V3 == 3U);
25
+ static_assert(PALW_CUDA_TRACE_RECORD_ENCODED_SIZE_V1 == 139U);
26
+ static_assert(PALW_CUDA_TRACE_RECORD_ENCODED_SIZE_V2 == 184U);
27
+ static_assert(PALW_CUDA_TRACE_RECORD_ENCODED_SIZE_V3 == 452U);
28
+ static_assert(PALW_CUDA_TRACE_PRODUCTION_CAPABLE == 0U);
29
+ static_assert(sizeof(palw_cuda_trace_record) == 144U);
30
+ static_assert(alignof(palw_cuda_trace_record) == 8U);
31
+ static_assert(std::is_standard_layout_v<palw_cuda_trace_record>);
32
+ static_assert(std::is_trivial_v<palw_cuda_trace_record>);
33
+ static_assert(offsetof(palw_cuda_trace_record, kernel_sequence) == 0U);
34
+ static_assert(offsetof(palw_cuda_trace_record, sketch) == 72U);
35
+ static_assert(offsetof(palw_cuda_trace_record, layer_id) == 104U);
36
+ static_assert(offsetof(palw_cuda_trace_record, schema_version) == 132U);
37
+ static_assert(offsetof(palw_cuda_trace_record, kind) == 134U);
38
+ static_assert(offsetof(palw_cuda_trace_record, reserved) == 139U);
39
+ static_assert(sizeof(palw_cuda_trace_record_v2) == 192U);
40
+ static_assert(alignof(palw_cuda_trace_record_v2) == 8U);
41
+ static_assert(std::is_standard_layout_v<palw_cuda_trace_record_v2>);
42
+ static_assert(std::is_trivial_v<palw_cuda_trace_record_v2>);
43
+ static_assert(offsetof(palw_cuda_trace_record_v2, base) == 0U);
44
+ static_assert(offsetof(palw_cuda_trace_record_v2, declared_origin) == 144U);
45
+ static_assert(offsetof(palw_cuda_trace_record_v2, accumulator_stage) == 145U);
46
+ static_assert(offsetof(palw_cuda_trace_record_v2, accumulator_dtype) == 146U);
47
+ static_assert(offsetof(palw_cuda_trace_record_v2, sketch_scheme) == 148U);
48
+ static_assert(offsetof(palw_cuda_trace_record_v2, reduction_segment_index) == 152U);
49
+ static_assert(offsetof(palw_cuda_trace_record_v2, reduction_segment_count) == 156U);
50
+ static_assert(offsetof(palw_cuda_trace_record_v2, producer_variant_id) == 160U);
51
+ static_assert(sizeof(palw_cuda_trace_record_v3) == 464U);
52
+ static_assert(alignof(palw_cuda_trace_record_v3) == 8U);
53
+ static_assert(std::is_standard_layout_v<palw_cuda_trace_record_v3>);
54
+ static_assert(std::is_trivial_v<palw_cuda_trace_record_v3>);
55
+ static_assert(offsetof(palw_cuda_trace_record_v3, covered_schedule_index) == 192U);
56
+ static_assert(offsetof(palw_cuda_trace_record_v3, layer_present) == 216U);
57
+ static_assert(offsetof(palw_cuda_trace_record_v3, query_heads) == 220U);
58
+ static_assert(offsetof(palw_cuda_trace_record_v3, grid_x) == 240U);
59
+ static_assert(offsetof(palw_cuda_trace_record_v3, operation_instance_id) == 268U);
60
+ static_assert(offsetof(palw_cuda_trace_record_v3, capture_implementation_id) == 428U);
61
+ static_assert(PALW_CUDA_TRACE_OK == 0);
62
+ static_assert(PALW_CUDA_TRACE_PENDING == 6);
63
+ static_assert(PALW_CUDA_TRACE_INCOMPLETE == 7);
64
+ static_assert(PALW_CUDA_TRACE_IDENTITY_MISMATCH == 8);
65
+ static_assert(PALW_CUDA_TRACE_PRODUCER_FAULT == 9);
66
+ static_assert(PALW_CUDA_TRACE_GEMM == 1);
67
+ static_assert(PALW_CUDA_TRACE_ATTENTION == 2);
68
+ static_assert(PALW_CUDA_TRACE_PREFILL == 0);
69
+ static_assert(PALW_CUDA_TRACE_DECODE == 1);
70
+ static_assert(PALW_CUDA_TRACE_DTYPE_FP32 == 0);
71
+ static_assert(PALW_CUDA_TRACE_DTYPE_INT4 == 4);
72
+ static_assert(PALW_CUDA_TRACE_QUANTIZATION_Q4_K_M == 2);
73
+ static_assert(PALW_CUDA_TRACE_QUANTIZATION_IQ4_XS == 5);
74
+ static_assert(PALW_CUDA_TRACE_QUANTIZATION_Q6_K == 6);
75
+ static_assert(PALW_CUDA_TRACE_ORIGIN_FINAL_OUTPUT == 0);
76
+ static_assert(PALW_CUDA_TRACE_ORIGIN_PRODUCER_ACCUMULATOR == 1);
77
+ static_assert(PALW_CUDA_TRACE_ACCUMULATOR_STAGE_NONE == 0);
78
+ static_assert(PALW_CUDA_TRACE_ACCUMULATOR_STAGE_FULL_K_PRE_EPILOGUE == 2);
79
+ static_assert(PALW_CUDA_TRACE_ACCUMULATOR_DTYPE_FP32 == 0);
80
+ static_assert(PALW_CUDA_TRACE_ACCUMULATOR_DTYPE_NONE == 255);
81
+ static_assert(PALW_CUDA_TRACE_SKETCH_FINAL_OUTPUT_TILE_F32_V1 == 1);
82
+ static_assert(PALW_CUDA_TRACE_SKETCH_SCALAR_ACCUMULATOR_F32_V1 == 2);
83
+ static_assert(PALW_CUDA_TRACE_ATTENTION_STAGE_NONE == 0);
84
+ static_assert(PALW_CUDA_TRACE_ATTENTION_STAGE_EAGER_QK_SCORE_MMVF == 1);
85
+ static_assert(PALW_CUDA_TRACE_ATTENTION_STAGE_EAGER_MASKED_SCALED_SOFTMAX == 2);
86
+ static_assert(PALW_CUDA_TRACE_ATTENTION_STAGE_EAGER_VALUE_AGGREGATION_MMVF == 3);
87
+
88
+ namespace {
89
+
90
+ int fail(const char * message) {
91
+ std::fprintf(stderr, "ABI contract failure: %s\n", message);
92
+ return 1;
93
+ }
94
+
95
+ palw_cuda_trace_record make_record() {
96
+ palw_cuda_trace_record record{};
97
+ record.kernel_sequence = 0x0102030405060708ULL;
98
+ record.m = 2;
99
+ record.n = 3;
100
+ record.k = 4;
101
+ record.batch = 1;
102
+ record.sketch[0] = 0x1112131415161718ULL;
103
+ record.sketch[1] = 0x2122232425262728ULL;
104
+ record.sketch[2] = 0x3132333435363738ULL;
105
+ record.sketch[3] = 0x4142434445464748ULL;
106
+ record.layer_id = 7;
107
+ record.tile_rows = 3;
108
+ record.tile_columns = 2;
109
+ record.output_rows = 3;
110
+ record.output_columns = 2;
111
+ record.schema_version = PALW_CUDA_TRACE_SCHEMA_VERSION;
112
+ record.kind = PALW_CUDA_TRACE_GEMM;
113
+ record.phase = PALW_CUDA_TRACE_PREFILL;
114
+ record.dtype = PALW_CUDA_TRACE_DTYPE_FP32;
115
+ record.quantization = PALW_CUDA_TRACE_QUANTIZATION_Q4_K_M;
116
+ return record;
117
+ }
118
+
119
+ palw_cuda_trace_record_v2 make_record_v2() {
120
+ palw_cuda_trace_record_v2 record{};
121
+ record.base = make_record();
122
+ record.base.kernel_sequence = 0;
123
+ record.base.schema_version = PALW_CUDA_TRACE_SCHEMA_VERSION_V2;
124
+ record.declared_origin = PALW_CUDA_TRACE_ORIGIN_PRODUCER_ACCUMULATOR;
125
+ record.accumulator_stage = PALW_CUDA_TRACE_ACCUMULATOR_STAGE_FULL_K_PRE_EPILOGUE;
126
+ record.accumulator_dtype = PALW_CUDA_TRACE_ACCUMULATOR_DTYPE_FP32;
127
+ record.sketch_scheme = PALW_CUDA_TRACE_SKETCH_SCALAR_ACCUMULATOR_F32_V1;
128
+ record.reduction_segment_count = 1;
129
+ for (size_t index = 0; index < sizeof(record.producer_variant_id); ++index) {
130
+ record.producer_variant_id[index] = static_cast<uint8_t>(0x80U + index);
131
+ }
132
+ return record;
133
+ }
134
+
135
+ void fill_id(uint8_t (&identity)[32], uint8_t seed) {
136
+ for (size_t index = 0; index < 32U; ++index) {
137
+ identity[index] = static_cast<uint8_t>(seed + index);
138
+ }
139
+ }
140
+
141
+ palw_cuda_trace_record_v3 make_record_v3() {
142
+ palw_cuda_trace_record_v3 record{};
143
+ record.base = make_record_v2();
144
+ record.base.base.schema_version = PALW_CUDA_TRACE_SCHEMA_VERSION_V3;
145
+ record.base.base.m = 256U;
146
+ record.base.base.n = 1U;
147
+ record.base.base.k = 128U;
148
+ record.base.base.batch = 32U;
149
+ record.base.base.query_tokens = 1U;
150
+ record.base.base.key_value_tokens = 3U;
151
+ record.base.base.tile_rows = 32U;
152
+ record.base.base.tile_columns = 256U;
153
+ record.base.base.output_rows = 32U;
154
+ record.base.base.output_columns = 256U;
155
+ record.base.base.dtype = PALW_CUDA_TRACE_DTYPE_FP32;
156
+ record.base.base.quantization = PALW_CUDA_TRACE_QUANTIZATION_NONE;
157
+ record.base.base.causal = 1U;
158
+ record.base.declared_origin = PALW_CUDA_TRACE_ORIGIN_FINAL_OUTPUT;
159
+ record.base.accumulator_stage = PALW_CUDA_TRACE_ACCUMULATOR_STAGE_NONE;
160
+ record.base.accumulator_dtype = PALW_CUDA_TRACE_ACCUMULATOR_DTYPE_NONE;
161
+ record.base.sketch_scheme = PALW_CUDA_TRACE_SKETCH_FINAL_OUTPUT_TILE_F32_V1;
162
+ record.base.reduction_segment_count = 0U;
163
+ record.covered_schedule_index = 14U;
164
+ record.attention_owner_schedule_index = 15U;
165
+ record.sublaunch_count = 3U;
166
+ record.layer_present = 1U;
167
+ record.attention_group_present = 1U;
168
+ record.attention_stage = PALW_CUDA_TRACE_ATTENTION_STAGE_EAGER_QK_SCORE_MMVF;
169
+ record.grouping_version = PALW_CUDA_TRACE_GROUPING_VERSION_V1;
170
+ record.query_heads = 32U;
171
+ record.key_value_heads = 8U;
172
+ record.head_dim = 128U;
173
+ record.logical_batch = 1U;
174
+ record.physical_key_value_tokens = 256U;
175
+ record.grid_x = 256U;
176
+ record.grid_y = 32U;
177
+ record.grid_z = 1U;
178
+ record.block_x = 64U;
179
+ record.block_y = 1U;
180
+ record.block_z = 1U;
181
+ record.dynamic_shared_memory_bytes = 128U;
182
+ fill_id(record.operation_instance_id, 0x10U);
183
+ fill_id(record.attention_group_instance_id, 0x30U);
184
+ fill_id(record.decomposition_plan_id, 0x50U);
185
+ fill_id(record.physical_layout_id, 0x70U);
186
+ fill_id(record.work_entry_point_id, 0x90U);
187
+ fill_id(record.capture_implementation_id, 0xb0U);
188
+ return record;
189
+ }
190
+
191
+ palw_cuda_trace_record_v3 make_direct_q6_record_v3() {
192
+ palw_cuda_trace_record_v3 record{};
193
+ record.base = make_record_v2();
194
+ record.base.base.schema_version = PALW_CUDA_TRACE_SCHEMA_VERSION_V3;
195
+ record.base.base.layer_id = 0U;
196
+ record.base.base.quantization = PALW_CUDA_TRACE_QUANTIZATION_Q6_K;
197
+ record.covered_schedule_index = 253U;
198
+ record.sublaunch_count = 1U;
199
+ record.grid_x = 2U;
200
+ record.grid_y = 1U;
201
+ record.grid_z = 1U;
202
+ record.block_x = 32U;
203
+ record.block_y = 4U;
204
+ record.block_z = 1U;
205
+ fill_id(record.operation_instance_id, 0x11U);
206
+ fill_id(record.decomposition_plan_id, 0x51U);
207
+ fill_id(record.physical_layout_id, 0x71U);
208
+ fill_id(record.work_entry_point_id, 0x91U);
209
+ fill_id(record.capture_implementation_id, 0xb1U);
210
+ return record;
211
+ }
212
+
213
+ uint8_t hex_nibble(char value) {
214
+ if (value >= '0' && value <= '9') {
215
+ return static_cast<uint8_t>(value - '0');
216
+ }
217
+ if (value >= 'a' && value <= 'f') {
218
+ return static_cast<uint8_t>(value - 'a' + 10);
219
+ }
220
+ return 0xffU;
221
+ }
222
+
223
+ std::vector<uint8_t> load_golden_fixture(const char * path) {
224
+ std::ifstream input(path);
225
+ std::string hex;
226
+ input >> hex;
227
+ if (!input || hex.size() % 2U != 0U) {
228
+ return {};
229
+ }
230
+ std::vector<uint8_t> bytes;
231
+ bytes.reserve(hex.size() / 2U);
232
+ for (size_t index = 0; index < hex.size(); index += 2U) {
233
+ const uint8_t high = hex_nibble(hex[index]);
234
+ const uint8_t low = hex_nibble(hex[index + 1U]);
235
+ if (high > 0x0fU || low > 0x0fU) {
236
+ return {};
237
+ }
238
+ bytes.push_back(static_cast<uint8_t>((high << 4U) | low));
239
+ }
240
+ return bytes;
241
+ }
242
+
243
+ } // namespace
244
+
245
+ int main() {
246
+ palw_cuda_trace_record first = make_record();
247
+ palw_cuda_trace_record second = first;
248
+
249
+ auto * native_bytes = reinterpret_cast<uint8_t *>(&second);
250
+ for (size_t i = 140; i < sizeof(second); ++i) {
251
+ native_bytes[i] = static_cast<uint8_t>(0xa0U + i);
252
+ }
253
+
254
+ std::array<uint8_t, PALW_CUDA_TRACE_RECORD_ENCODED_SIZE_V1> encoded_first{};
255
+ std::array<uint8_t, PALW_CUDA_TRACE_RECORD_ENCODED_SIZE_V1> encoded_second{};
256
+ if (palw_cuda_trace_encode_record_v1(
257
+ &first, encoded_first.data(), encoded_first.size()) != PALW_CUDA_TRACE_OK ||
258
+ palw_cuda_trace_encode_record_v1(
259
+ &second, encoded_second.data(), encoded_second.size()) != PALW_CUDA_TRACE_OK) {
260
+ return fail("valid record did not encode");
261
+ }
262
+ if (encoded_first != encoded_second) {
263
+ return fail("native tail padding affected canonical encoding");
264
+ }
265
+
266
+ const std::array<uint8_t, 8> expected_sequence = {1, 2, 3, 4, 5, 6, 7, 8};
267
+ if (std::memcmp(encoded_first.data(), expected_sequence.data(), expected_sequence.size()) != 0) {
268
+ return fail("u64 encoding is not big-endian");
269
+ }
270
+
271
+ second.reserved = 1;
272
+ if (palw_cuda_trace_encode_record_v1(
273
+ &second, encoded_second.data(), encoded_second.size()) !=
274
+ PALW_CUDA_TRACE_INVALID_ARGUMENT) {
275
+ return fail("nonzero reserved byte was accepted");
276
+ }
277
+ second = first;
278
+ second.dtype = 255;
279
+ if (palw_cuda_trace_encode_record_v1(
280
+ &second, encoded_second.data(), encoded_second.size()) !=
281
+ PALW_CUDA_TRACE_INVALID_ARGUMENT) {
282
+ return fail("unknown dtype was accepted");
283
+ }
284
+ second = first;
285
+ second.quantization = 255;
286
+ if (palw_cuda_trace_encode_record_v1(
287
+ &second, encoded_second.data(), encoded_second.size()) !=
288
+ PALW_CUDA_TRACE_INVALID_ARGUMENT) {
289
+ return fail("unknown quantization was accepted");
290
+ }
291
+ second = first;
292
+ second.schema_version = PALW_CUDA_TRACE_SCHEMA_VERSION_V2;
293
+ if (palw_cuda_trace_encode_record_v1(
294
+ &second, encoded_second.data(), encoded_second.size()) !=
295
+ PALW_CUDA_TRACE_INVALID_ARGUMENT) {
296
+ return fail("V2 schema tag was accepted by the V1 codec");
297
+ }
298
+ second = first;
299
+ second.schema_version = PALW_CUDA_TRACE_SCHEMA_VERSION_V3;
300
+ if (palw_cuda_trace_encode_record_v1(
301
+ &second, encoded_second.data(), encoded_second.size()) !=
302
+ PALW_CUDA_TRACE_INVALID_ARGUMENT) {
303
+ return fail("V3 schema tag was accepted by the V1 codec");
304
+ }
305
+ second = first;
306
+ second.quantization = PALW_CUDA_TRACE_QUANTIZATION_Q6_K;
307
+ if (palw_cuda_trace_encode_record_v1(
308
+ &second, encoded_second.data(), encoded_second.size()) !=
309
+ PALW_CUDA_TRACE_INVALID_ARGUMENT) {
310
+ return fail("V3-only Q6_K tag was accepted by the V1 codec");
311
+ }
312
+ second = first;
313
+ second.decode_step = 1;
314
+ if (palw_cuda_trace_encode_record_v1(
315
+ &second, encoded_second.data(), encoded_second.size()) !=
316
+ PALW_CUDA_TRACE_INVALID_ARGUMENT) {
317
+ return fail("invalid prefill step was accepted");
318
+ }
319
+ second = first;
320
+ second.tile_index = 1;
321
+ if (palw_cuda_trace_encode_record_v1(
322
+ &second, encoded_second.data(), encoded_second.size()) !=
323
+ PALW_CUDA_TRACE_INVALID_ARGUMENT) {
324
+ return fail("invalid tile index was accepted");
325
+ }
326
+ second = first;
327
+ second.output_columns = 3;
328
+ if (palw_cuda_trace_encode_record_v1(
329
+ &second, encoded_second.data(), encoded_second.size()) !=
330
+ PALW_CUDA_TRACE_INVALID_ARGUMENT) {
331
+ return fail("invalid GEMM output shape was accepted");
332
+ }
333
+ second = first;
334
+ second.batch = 2;
335
+ second.output_rows = 6;
336
+ if (palw_cuda_trace_encode_record_v1(
337
+ &second, encoded_second.data(), encoded_second.size()) != PALW_CUDA_TRACE_OK) {
338
+ return fail("valid batched GEMM output shape was rejected");
339
+ }
340
+ second = first;
341
+ second.m = static_cast<uint64_t>(UINT32_MAX) + 1U;
342
+ if (palw_cuda_trace_encode_record_v1(
343
+ &second, encoded_second.data(), encoded_second.size()) !=
344
+ PALW_CUDA_TRACE_INVALID_ARGUMENT) {
345
+ return fail("oversized GEMM dimension was accepted");
346
+ }
347
+
348
+ palw_cuda_trace_record attention = first;
349
+ attention.kernel_sequence = 1;
350
+ attention.m = 2;
351
+ attention.n = 8;
352
+ attention.k = 3;
353
+ attention.query_tokens = 2;
354
+ attention.key_value_tokens = 3;
355
+ attention.tile_rows = 1;
356
+ attention.tile_columns = 4;
357
+ attention.output_rows = 2;
358
+ attention.output_columns = 8;
359
+ attention.kind = PALW_CUDA_TRACE_ATTENTION;
360
+ attention.dtype = PALW_CUDA_TRACE_DTYPE_FP16;
361
+ attention.quantization = PALW_CUDA_TRACE_QUANTIZATION_NONE;
362
+ attention.causal = 1;
363
+ if (palw_cuda_trace_encode_record_v1(
364
+ &attention, encoded_second.data(), encoded_second.size()) != PALW_CUDA_TRACE_OK) {
365
+ return fail("valid attention record did not encode");
366
+ }
367
+ attention.key_value_tokens = 1;
368
+ attention.k = 1;
369
+ if (palw_cuda_trace_encode_record_v1(
370
+ &attention, encoded_second.data(), encoded_second.size()) !=
371
+ PALW_CUDA_TRACE_INVALID_ARGUMENT) {
372
+ return fail("invalid causal attention shape was accepted");
373
+ }
374
+ attention = first;
375
+ attention.kernel_sequence = 1;
376
+ attention.m = 2;
377
+ attention.n = 8;
378
+ attention.k = 3;
379
+ attention.query_tokens = 2;
380
+ attention.key_value_tokens = 3;
381
+ attention.tile_rows = 1;
382
+ attention.tile_columns = 4;
383
+ attention.output_rows = 2;
384
+ attention.output_columns = 8;
385
+ attention.kind = PALW_CUDA_TRACE_ATTENTION;
386
+ attention.phase = PALW_CUDA_TRACE_DECODE;
387
+ attention.dtype = PALW_CUDA_TRACE_DTYPE_FP16;
388
+ attention.quantization = PALW_CUDA_TRACE_QUANTIZATION_NONE;
389
+ attention.causal = 1;
390
+ if (palw_cuda_trace_encode_record_v1(
391
+ &attention, encoded_second.data(), encoded_second.size()) !=
392
+ PALW_CUDA_TRACE_INVALID_ARGUMENT) {
393
+ return fail("multi-query-token decode attention was accepted");
394
+ }
395
+ if (palw_cuda_trace_encode_record_v1(
396
+ &first, encoded_first.data(), encoded_first.size() - 1U) !=
397
+ PALW_CUDA_TRACE_INVALID_ARGUMENT) {
398
+ return fail("short destination was accepted");
399
+ }
400
+
401
+ palw_cuda_trace_record_v2 first_v2 = make_record_v2();
402
+ palw_cuda_trace_record_v2 second_v2 = first_v2;
403
+ auto * native_v2_bytes = reinterpret_cast<uint8_t *>(&second_v2);
404
+ for (size_t index = 140U; index < 144U; ++index) {
405
+ native_v2_bytes[index] = static_cast<uint8_t>(0x50U + index);
406
+ }
407
+ native_v2_bytes[147] = 0xaaU;
408
+ native_v2_bytes[150] = 0xbbU;
409
+ native_v2_bytes[151] = 0xccU;
410
+
411
+ std::array<uint8_t, PALW_CUDA_TRACE_RECORD_ENCODED_SIZE_V2> encoded_first_v2{};
412
+ std::array<uint8_t, PALW_CUDA_TRACE_RECORD_ENCODED_SIZE_V2> encoded_second_v2{};
413
+ if (palw_cuda_trace_encode_record_v2(
414
+ &first_v2, encoded_first_v2.data(), encoded_first_v2.size()) !=
415
+ PALW_CUDA_TRACE_OK ||
416
+ palw_cuda_trace_encode_record_v2(
417
+ &second_v2, encoded_second_v2.data(), encoded_second_v2.size()) !=
418
+ PALW_CUDA_TRACE_OK) {
419
+ return fail("valid V2 producer-accumulator record did not encode");
420
+ }
421
+ if (encoded_first_v2 != encoded_second_v2) {
422
+ return fail("native V2 padding affected canonical encoding");
423
+ }
424
+
425
+ const std::vector<uint8_t> golden_v2 = load_golden_fixture(PALW_CUDA_TRACE_GOLDEN_FIXTURE_PATH);
426
+ if (golden_v2.size() != encoded_first_v2.size() ||
427
+ std::memcmp(golden_v2.data(), encoded_first_v2.data(), encoded_first_v2.size()) != 0) {
428
+ return fail("V2 canonical encoding did not match the shared golden fixture");
429
+ }
430
+
431
+ second_v2 = first_v2;
432
+ std::memset(second_v2.producer_variant_id, 0, sizeof(second_v2.producer_variant_id));
433
+ if (palw_cuda_trace_encode_record_v2(
434
+ &second_v2, encoded_second_v2.data(), encoded_second_v2.size()) !=
435
+ PALW_CUDA_TRACE_INVALID_ARGUMENT) {
436
+ return fail("zero V2 producer variant ID was accepted");
437
+ }
438
+ second_v2 = first_v2;
439
+ second_v2.declared_origin = 255U;
440
+ if (palw_cuda_trace_encode_record_v2(
441
+ &second_v2, encoded_second_v2.data(), encoded_second_v2.size()) !=
442
+ PALW_CUDA_TRACE_INVALID_ARGUMENT) {
443
+ return fail("unknown V2 declared origin was accepted");
444
+ }
445
+ second_v2 = first_v2;
446
+ second_v2.accumulator_stage = PALW_CUDA_TRACE_ACCUMULATOR_STAGE_NONE;
447
+ if (palw_cuda_trace_encode_record_v2(
448
+ &second_v2, encoded_second_v2.data(), encoded_second_v2.size()) !=
449
+ PALW_CUDA_TRACE_INVALID_ARGUMENT) {
450
+ return fail("producer origin without an accumulator stage was accepted");
451
+ }
452
+ second_v2 = first_v2;
453
+ second_v2.accumulator_dtype = PALW_CUDA_TRACE_ACCUMULATOR_DTYPE_FP16;
454
+ if (palw_cuda_trace_encode_record_v2(
455
+ &second_v2, encoded_second_v2.data(), encoded_second_v2.size()) !=
456
+ PALW_CUDA_TRACE_INVALID_ARGUMENT) {
457
+ return fail("non-FP32 scalar accumulator scheme was accepted");
458
+ }
459
+ second_v2 = first_v2;
460
+ second_v2.reduction_segment_count = 0U;
461
+ if (palw_cuda_trace_encode_record_v2(
462
+ &second_v2, encoded_second_v2.data(), encoded_second_v2.size()) !=
463
+ PALW_CUDA_TRACE_INVALID_ARGUMENT) {
464
+ return fail("producer origin without reduction segments was accepted");
465
+ }
466
+ second_v2 = first_v2;
467
+ second_v2.reduction_segment_index = 1U;
468
+ if (palw_cuda_trace_encode_record_v2(
469
+ &second_v2, encoded_second_v2.data(), encoded_second_v2.size()) !=
470
+ PALW_CUDA_TRACE_INVALID_ARGUMENT) {
471
+ return fail("out-of-range reduction segment was accepted");
472
+ }
473
+ second_v2 = first_v2;
474
+ second_v2.reduction_segment_count = 2U;
475
+ if (palw_cuda_trace_encode_record_v2(
476
+ &second_v2, encoded_second_v2.data(), encoded_second_v2.size()) !=
477
+ PALW_CUDA_TRACE_INVALID_ARGUMENT) {
478
+ return fail("full-K accumulator was split into multiple reduction segments");
479
+ }
480
+ second_v2 = first_v2;
481
+ second_v2.base.schema_version = PALW_CUDA_TRACE_SCHEMA_VERSION_V1;
482
+ if (palw_cuda_trace_encode_record_v2(
483
+ &second_v2, encoded_second_v2.data(), encoded_second_v2.size()) !=
484
+ PALW_CUDA_TRACE_INVALID_ARGUMENT) {
485
+ return fail("V1 schema tag was accepted by the V2 codec");
486
+ }
487
+ second_v2 = first_v2;
488
+ second_v2.base.schema_version = PALW_CUDA_TRACE_SCHEMA_VERSION_V3;
489
+ if (palw_cuda_trace_encode_record_v2(
490
+ &second_v2, encoded_second_v2.data(), encoded_second_v2.size()) !=
491
+ PALW_CUDA_TRACE_INVALID_ARGUMENT) {
492
+ return fail("V3 schema tag was accepted by the V2 codec");
493
+ }
494
+
495
+ second_v2 = first_v2;
496
+ second_v2.declared_origin = PALW_CUDA_TRACE_ORIGIN_FINAL_OUTPUT;
497
+ second_v2.accumulator_stage = PALW_CUDA_TRACE_ACCUMULATOR_STAGE_NONE;
498
+ second_v2.accumulator_dtype = PALW_CUDA_TRACE_ACCUMULATOR_DTYPE_NONE;
499
+ second_v2.sketch_scheme = PALW_CUDA_TRACE_SKETCH_FINAL_OUTPUT_TILE_F32_V1;
500
+ second_v2.reduction_segment_index = 0U;
501
+ second_v2.reduction_segment_count = 0U;
502
+ if (palw_cuda_trace_encode_record_v2(
503
+ &second_v2, encoded_second_v2.data(), encoded_second_v2.size()) !=
504
+ PALW_CUDA_TRACE_OK) {
505
+ return fail("valid V2 final-output declaration did not encode");
506
+ }
507
+ second_v2.reduction_segment_count = 1U;
508
+ if (palw_cuda_trace_encode_record_v2(
509
+ &second_v2, encoded_second_v2.data(), encoded_second_v2.size()) !=
510
+ PALW_CUDA_TRACE_INVALID_ARGUMENT) {
511
+ return fail("final-output declaration with a reduction segment was accepted");
512
+ }
513
+ if (palw_cuda_trace_encode_record_v2(
514
+ &first_v2, encoded_first_v2.data(), encoded_first_v2.size() - 1U) !=
515
+ PALW_CUDA_TRACE_INVALID_ARGUMENT) {
516
+ return fail("short V2 destination was accepted");
517
+ }
518
+
519
+ second_v2 = first_v2;
520
+ second_v2.base.quantization = PALW_CUDA_TRACE_QUANTIZATION_Q6_K;
521
+ if (palw_cuda_trace_encode_record_v2(
522
+ &second_v2, encoded_second_v2.data(), encoded_second_v2.size()) !=
523
+ PALW_CUDA_TRACE_INVALID_ARGUMENT) {
524
+ return fail("V3-only Q6_K tag was accepted by the V2 codec");
525
+ }
526
+
527
+ palw_cuda_trace_record_v3 first_v3 = make_record_v3();
528
+ palw_cuda_trace_record_v3 second_v3 = first_v3;
529
+ std::array<uint8_t, PALW_CUDA_TRACE_RECORD_ENCODED_SIZE_V3> encoded_first_v3{};
530
+ std::array<uint8_t, PALW_CUDA_TRACE_RECORD_ENCODED_SIZE_V3> encoded_second_v3{};
531
+ if (palw_cuda_trace_encode_record_v3(
532
+ &first_v3, encoded_first_v3.data(), encoded_first_v3.size()) !=
533
+ PALW_CUDA_TRACE_OK) {
534
+ return fail("valid V3 eager-QK record did not encode");
535
+ }
536
+ auto * native_v3_bytes = reinterpret_cast<uint8_t *>(&second_v3);
537
+ for (size_t index = 460U; index < sizeof(second_v3); ++index) {
538
+ native_v3_bytes[index] = static_cast<uint8_t>(0xc0U + index);
539
+ }
540
+ if (palw_cuda_trace_encode_record_v3(
541
+ &second_v3, encoded_second_v3.data(), encoded_second_v3.size()) !=
542
+ PALW_CUDA_TRACE_OK) {
543
+ return fail("valid V3 record with nonzero native tail padding did not encode");
544
+ }
545
+ if (encoded_first_v3 != encoded_second_v3) {
546
+ return fail("native V3 tail padding affected canonical encoding");
547
+ }
548
+ const std::vector<uint8_t> golden_v3 =
549
+ load_golden_fixture(PALW_CUDA_TRACE_GOLDEN_FIXTURE_V3_PATH);
550
+ if (golden_v3.size() != encoded_first_v3.size() ||
551
+ std::memcmp(golden_v3.data(), encoded_first_v3.data(), encoded_first_v3.size()) != 0) {
552
+ return fail("V3 canonical encoding did not match the shared golden fixture");
553
+ }
554
+ if (palw_cuda_trace_encode_record_v3(
555
+ &first_v3, encoded_first_v3.data(), encoded_first_v3.size() - 1U) !=
556
+ PALW_CUDA_TRACE_INVALID_ARGUMENT) {
557
+ return fail("short V3 destination was accepted");
558
+ }
559
+
560
+ palw_cuda_trace_record_v3 softmax_v3 = first_v3;
561
+ softmax_v3.base.base.kind = PALW_CUDA_TRACE_ATTENTION;
562
+ softmax_v3.base.base.k = 1U;
563
+ softmax_v3.covered_schedule_index = 15U;
564
+ softmax_v3.sublaunch_index = 1U;
565
+ softmax_v3.attention_stage =
566
+ PALW_CUDA_TRACE_ATTENTION_STAGE_EAGER_MASKED_SCALED_SOFTMAX;
567
+ softmax_v3.grid_x = 1U;
568
+ softmax_v3.block_x = 256U;
569
+ softmax_v3.dynamic_shared_memory_bytes = 1152U;
570
+ if (palw_cuda_trace_encode_record_v3(
571
+ &softmax_v3, encoded_second_v3.data(), encoded_second_v3.size()) !=
572
+ PALW_CUDA_TRACE_OK) {
573
+ return fail("valid V3 eager-softmax record did not encode");
574
+ }
575
+
576
+ palw_cuda_trace_record_v3 kqv_v3 = first_v3;
577
+ kqv_v3.base.base.m = 128U;
578
+ kqv_v3.base.base.k = 256U;
579
+ kqv_v3.base.base.tile_columns = 128U;
580
+ kqv_v3.base.base.output_columns = 128U;
581
+ kqv_v3.covered_schedule_index = 16U;
582
+ kqv_v3.sublaunch_index = 2U;
583
+ kqv_v3.attention_stage =
584
+ PALW_CUDA_TRACE_ATTENTION_STAGE_EAGER_VALUE_AGGREGATION_MMVF;
585
+ kqv_v3.grid_x = 128U;
586
+ kqv_v3.block_x = 128U;
587
+ if (palw_cuda_trace_encode_record_v3(
588
+ &kqv_v3, encoded_second_v3.data(), encoded_second_v3.size()) !=
589
+ PALW_CUDA_TRACE_OK) {
590
+ return fail("valid V3 eager-KQV record did not encode");
591
+ }
592
+
593
+ palw_cuda_trace_record_v3 direct_q6 = make_direct_q6_record_v3();
594
+ if (palw_cuda_trace_encode_record_v3(
595
+ &direct_q6, encoded_second_v3.data(), encoded_second_v3.size()) !=
596
+ PALW_CUDA_TRACE_OK) {
597
+ return fail("valid direct Q6_K V3 record did not encode");
598
+ }
599
+
600
+ struct V3IdentityZeroMutation {
601
+ size_t offset;
602
+ const char * failure_message;
603
+ };
604
+ constexpr size_t producer_variant_id_offset =
605
+ offsetof(palw_cuda_trace_record_v3, base) +
606
+ offsetof(palw_cuda_trace_record_v2, producer_variant_id);
607
+ constexpr std::array<V3IdentityZeroMutation, 7> grouped_required_identities{{
608
+ {producer_variant_id_offset, "zero grouped V3 producer variant ID was accepted"},
609
+ {offsetof(palw_cuda_trace_record_v3, operation_instance_id),
610
+ "zero grouped V3 operation instance ID was accepted"},
611
+ {offsetof(palw_cuda_trace_record_v3, attention_group_instance_id),
612
+ "zero grouped V3 attention group instance ID was accepted"},
613
+ {offsetof(palw_cuda_trace_record_v3, decomposition_plan_id),
614
+ "zero grouped V3 decomposition plan ID was accepted"},
615
+ {offsetof(palw_cuda_trace_record_v3, physical_layout_id),
616
+ "zero grouped V3 physical layout ID was accepted"},
617
+ {offsetof(palw_cuda_trace_record_v3, work_entry_point_id),
618
+ "zero grouped V3 work entry-point ID was accepted"},
619
+ {offsetof(palw_cuda_trace_record_v3, capture_implementation_id),
620
+ "zero grouped V3 capture implementation ID was accepted"},
621
+ }};
622
+ for (const V3IdentityZeroMutation & mutation : grouped_required_identities) {
623
+ second_v3 = first_v3;
624
+ std::memset(reinterpret_cast<uint8_t *>(&second_v3) + mutation.offset, 0, 32U);
625
+ if (palw_cuda_trace_encode_record_v3(
626
+ &second_v3, encoded_second_v3.data(), encoded_second_v3.size()) !=
627
+ PALW_CUDA_TRACE_INVALID_ARGUMENT) {
628
+ return fail(mutation.failure_message);
629
+ }
630
+ }
631
+
632
+ constexpr std::array<V3IdentityZeroMutation, 6> direct_required_identities{{
633
+ {producer_variant_id_offset, "zero direct V3 producer variant ID was accepted"},
634
+ {offsetof(palw_cuda_trace_record_v3, operation_instance_id),
635
+ "zero direct V3 operation instance ID was accepted"},
636
+ {offsetof(palw_cuda_trace_record_v3, decomposition_plan_id),
637
+ "zero direct V3 decomposition plan ID was accepted"},
638
+ {offsetof(palw_cuda_trace_record_v3, physical_layout_id),
639
+ "zero direct V3 physical layout ID was accepted"},
640
+ {offsetof(palw_cuda_trace_record_v3, work_entry_point_id),
641
+ "zero direct V3 work entry-point ID was accepted"},
642
+ {offsetof(palw_cuda_trace_record_v3, capture_implementation_id),
643
+ "zero direct V3 capture implementation ID was accepted"},
644
+ }};
645
+ for (const V3IdentityZeroMutation & mutation : direct_required_identities) {
646
+ second_v3 = direct_q6;
647
+ std::memset(reinterpret_cast<uint8_t *>(&second_v3) + mutation.offset, 0, 32U);
648
+ if (palw_cuda_trace_encode_record_v3(
649
+ &second_v3, encoded_second_v3.data(), encoded_second_v3.size()) !=
650
+ PALW_CUDA_TRACE_INVALID_ARGUMENT) {
651
+ return fail(mutation.failure_message);
652
+ }
653
+ }
654
+ second_v3 = direct_q6;
655
+ fill_id(second_v3.attention_group_instance_id, 0xd0U);
656
+ if (palw_cuda_trace_encode_record_v3(
657
+ &second_v3, encoded_second_v3.data(), encoded_second_v3.size()) !=
658
+ PALW_CUDA_TRACE_INVALID_ARGUMENT) {
659
+ return fail("nonzero direct V3 attention group instance ID was accepted");
660
+ }
661
+
662
+ second_v3 = first_v3;
663
+ second_v3.sublaunch_count = 2U;
664
+ if (palw_cuda_trace_encode_record_v3(
665
+ &second_v3, encoded_second_v3.data(), encoded_second_v3.size()) !=
666
+ PALW_CUDA_TRACE_INVALID_ARGUMENT) {
667
+ return fail("self-declared V3 attention count shrink was accepted");
668
+ }
669
+ second_v3 = first_v3;
670
+ second_v3.attention_stage = PALW_CUDA_TRACE_ATTENTION_STAGE_EAGER_VALUE_AGGREGATION_MMVF;
671
+ if (palw_cuda_trace_encode_record_v3(
672
+ &second_v3, encoded_second_v3.data(), encoded_second_v3.size()) !=
673
+ PALW_CUDA_TRACE_INVALID_ARGUMENT) {
674
+ return fail("V3 attention role swap was accepted");
675
+ }
676
+ second_v3 = first_v3;
677
+ second_v3.attention_owner_schedule_index = UINT64_MAX;
678
+ second_v3.covered_schedule_index = UINT64_MAX - 1U;
679
+ if (palw_cuda_trace_encode_record_v3(
680
+ &second_v3, encoded_second_v3.data(), encoded_second_v3.size()) !=
681
+ PALW_CUDA_TRACE_INVALID_ARGUMENT) {
682
+ return fail("uncompletable V3 UINT64_MAX attention owner was accepted");
683
+ }
684
+ second_v3 = first_v3;
685
+ second_v3.key_value_heads = 3U;
686
+ if (palw_cuda_trace_encode_record_v3(
687
+ &second_v3, encoded_second_v3.data(), encoded_second_v3.size()) !=
688
+ PALW_CUDA_TRACE_INVALID_ARGUMENT) {
689
+ return fail("V3 attention head factorization mutation was accepted");
690
+ }
691
+ second_v3 = first_v3;
692
+ second_v3.physical_key_value_tokens = 512U;
693
+ if (palw_cuda_trace_encode_record_v3(
694
+ &second_v3, encoded_second_v3.data(), encoded_second_v3.size()) !=
695
+ PALW_CUDA_TRACE_INVALID_ARGUMENT) {
696
+ return fail("V3 logical/physical KV mismatch was accepted");
697
+ }
698
+ second_v3 = first_v3;
699
+ second_v3.block_x = 1U;
700
+ second_v3.block_z = 128U;
701
+ if (palw_cuda_trace_encode_record_v3(
702
+ &second_v3, encoded_second_v3.data(), encoded_second_v3.size()) !=
703
+ PALW_CUDA_TRACE_INVALID_ARGUMENT) {
704
+ return fail("impossible V3 CUDA block-z dimension was accepted");
705
+ }
706
+ second_v3 = first_v3;
707
+ second_v3.base.base.schema_version = PALW_CUDA_TRACE_SCHEMA_VERSION_V2;
708
+ if (palw_cuda_trace_encode_record_v3(
709
+ &second_v3, encoded_second_v3.data(), encoded_second_v3.size()) !=
710
+ PALW_CUDA_TRACE_INVALID_ARGUMENT) {
711
+ return fail("V2 schema tag was accepted by the V3 codec");
712
+ }
713
+ second_v3 = first_v3;
714
+ second_v3.base.base.schema_version = PALW_CUDA_TRACE_SCHEMA_VERSION_V1;
715
+ if (palw_cuda_trace_encode_record_v3(
716
+ &second_v3, encoded_second_v3.data(), encoded_second_v3.size()) !=
717
+ PALW_CUDA_TRACE_INVALID_ARGUMENT) {
718
+ return fail("V1 schema tag was accepted by the V3 codec");
719
+ }
720
+
721
+ std::puts("PALW CUDA trace V1/V2/V3 ABI and canonical codec contract: ok");
722
+ return 0;
723
+ }
runtime-palw/cuda/accumulator.cu ADDED
@@ -0,0 +1,411 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #include "palw_cuda_trace_internal.cuh"
2
+
3
+ #include <cuda_runtime.h>
4
+
5
+ #include <cstdint>
6
+ #include <limits>
7
+ #include <new>
8
+
9
+ namespace {
10
+
11
+ constexpr uint32_t kMaxGridX = 2147483647U;
12
+ constexpr uint32_t kMaxGridY = 65535U;
13
+
14
+ constexpr uint64_t kSketchSeed[4] = {
15
+ 0x243f6a8885a308d3ULL,
16
+ 0x13198a2e03707344ULL,
17
+ 0xa4093822299f31d0ULL,
18
+ 0x082efa98ec4e6c89ULL,
19
+ };
20
+
21
+ __device__ __forceinline__ uint64_t mix64(uint64_t value) {
22
+ value ^= value >> 30;
23
+ value *= 0xbf58476d1ce4e5b9ULL;
24
+ value ^= value >> 27;
25
+ value *= 0x94d049bb133111ebULL;
26
+ return value ^ (value >> 31);
27
+ }
28
+
29
+ __device__ __forceinline__ uint32_t canonical_float_bits(float value) {
30
+ uint32_t bits = __float_as_uint(value);
31
+ const uint32_t magnitude = bits & 0x7fffffffU;
32
+ if (magnitude == 0U) {
33
+ return 0U;
34
+ }
35
+ if ((bits & 0x7f800000U) == 0x7f800000U && (bits & 0x007fffffU) != 0U) {
36
+ return 0x7fc00000U;
37
+ }
38
+ return bits;
39
+ }
40
+
41
+ __global__ void accumulator_sketch_f32(
42
+ const float * output,
43
+ uint64_t row_stride,
44
+ palw_cuda_trace_record * records,
45
+ palw_cuda_trace_launch launch) {
46
+ const uint32_t tile_column = blockIdx.x;
47
+ const uint32_t tile_row = blockIdx.y;
48
+ const uint64_t tiles_per_row =
49
+ (static_cast<uint64_t>(launch.output_columns) + launch.tile_columns - 1U) /
50
+ launch.tile_columns;
51
+ const uint64_t tile_index = static_cast<uint64_t>(tile_row) * tiles_per_row + tile_column;
52
+ if (threadIdx.x != 0U || tile_index >= launch.tile_count) {
53
+ return;
54
+ }
55
+
56
+ const uint64_t row_begin_64 = static_cast<uint64_t>(tile_row) * launch.tile_rows;
57
+ const uint64_t column_begin_64 = static_cast<uint64_t>(tile_column) * launch.tile_columns;
58
+ const uint64_t row_end_64 = row_begin_64 + launch.tile_rows < launch.output_rows
59
+ ? row_begin_64 + launch.tile_rows
60
+ : launch.output_rows;
61
+ const uint64_t column_end_64 = column_begin_64 + launch.tile_columns < launch.output_columns
62
+ ? column_begin_64 + launch.tile_columns
63
+ : launch.output_columns;
64
+ const uint32_t row_begin = static_cast<uint32_t>(row_begin_64);
65
+ const uint32_t column_begin = static_cast<uint32_t>(column_begin_64);
66
+ const uint32_t height = static_cast<uint32_t>(row_end_64 - row_begin_64);
67
+ const uint32_t width = static_cast<uint32_t>(column_end_64 - column_begin_64);
68
+
69
+ uint64_t sketch[4] = {kSketchSeed[0], kSketchSeed[1], kSketchSeed[2], kSketchSeed[3]};
70
+ #pragma unroll
71
+ for (uint32_t sample = 0; sample < 32U; ++sample) {
72
+ const uint32_t row = row_begin + ((sample * 13U + 3U) % height);
73
+ const uint32_t column = column_begin + ((sample * 7U + 1U) % width);
74
+ const uint32_t bits = canonical_float_bits(
75
+ output[static_cast<uint64_t>(row) * row_stride + column]);
76
+ const uint64_t tagged =
77
+ mix64(static_cast<uint64_t>(bits) | (static_cast<uint64_t>(sample) << 32)) ^
78
+ mix64(static_cast<uint64_t>(row)) ^
79
+ mix64(static_cast<uint64_t>(column) << 1);
80
+ const uint32_t lane = sample & 3U;
81
+ sketch[lane] = mix64(sketch[lane] ^ tagged);
82
+ }
83
+
84
+ palw_cuda_trace_record record{};
85
+ record.kernel_sequence = launch.kernel_sequence;
86
+ record.tile_index = tile_index;
87
+ record.decode_step = launch.decode_step;
88
+ record.m = launch.m;
89
+ record.n = launch.n;
90
+ record.k = launch.k;
91
+ record.batch = launch.batch;
92
+ record.query_tokens = launch.query_tokens;
93
+ record.key_value_tokens = launch.key_value_tokens;
94
+ #pragma unroll
95
+ for (uint32_t lane = 0; lane < 4U; ++lane) {
96
+ record.sketch[lane] = sketch[lane];
97
+ }
98
+ record.layer_id = launch.layer_id;
99
+ record.tile_row = tile_row;
100
+ record.tile_column = tile_column;
101
+ record.tile_rows = launch.tile_rows;
102
+ record.tile_columns = launch.tile_columns;
103
+ record.output_rows = launch.output_rows;
104
+ record.output_columns = launch.output_columns;
105
+ record.schema_version = PALW_CUDA_TRACE_SCHEMA_VERSION;
106
+ record.kind = launch.kind;
107
+ record.phase = launch.phase;
108
+ record.dtype = launch.dtype;
109
+ record.quantization = launch.quantization;
110
+ record.causal = launch.causal;
111
+ records[launch.base_record + tile_index] = record;
112
+ }
113
+
114
+ void poison_context(palw_cuda_trace_context * context, cudaError_t error) {
115
+ context->poisoned = 1;
116
+ context->last_cuda_error = static_cast<int32_t>(error);
117
+ }
118
+
119
+ palw_cuda_trace_status reject_failed_context(const palw_cuda_trace_context * context) {
120
+ if (context->poisoned != 0) {
121
+ return PALW_CUDA_TRACE_POISONED;
122
+ }
123
+ if (context->overflowed != 0) {
124
+ return PALW_CUDA_TRACE_CAPACITY_EXCEEDED;
125
+ }
126
+ return PALW_CUDA_TRACE_OK;
127
+ }
128
+
129
+ bool bind_or_match_stream(palw_cuda_trace_context * context, cudaStream_t stream) {
130
+ if (context->stream_bound != 0) {
131
+ return context->stream == stream;
132
+ }
133
+ context->stream = stream;
134
+ context->stream_bound = 1;
135
+ return true;
136
+ }
137
+
138
+ palw_cuda_trace_status consume_pending_cuda_error(palw_cuda_trace_context * context) {
139
+ const cudaError_t error = cudaPeekAtLastError();
140
+ if (error == cudaSuccess) {
141
+ return PALW_CUDA_TRACE_OK;
142
+ }
143
+ (void) cudaGetLastError();
144
+ poison_context(context, error);
145
+ return PALW_CUDA_TRACE_CUDA_ERROR;
146
+ }
147
+
148
+ bool valid_address_range(
149
+ const float * output,
150
+ uint32_t output_rows,
151
+ uint32_t output_columns,
152
+ uint64_t row_stride) {
153
+ const uintptr_t base = reinterpret_cast<uintptr_t>(output);
154
+ if ((base % alignof(float)) != 0U) {
155
+ return false;
156
+ }
157
+ const uint64_t row_offset = static_cast<uint64_t>(output_rows - 1U);
158
+ const uint64_t column_offset = static_cast<uint64_t>(output_columns - 1U);
159
+ if (row_offset != 0U && row_stride > (UINT64_MAX - column_offset) / row_offset) {
160
+ return false;
161
+ }
162
+ const uint64_t last_element = row_offset * row_stride + column_offset;
163
+ if (last_element > std::numeric_limits<size_t>::max() / sizeof(float)) {
164
+ return false;
165
+ }
166
+ const uint64_t last_byte_offset = last_element * sizeof(float);
167
+ const uintptr_t pointer_max = std::numeric_limits<uintptr_t>::max();
168
+ return base <= pointer_max - (sizeof(float) - 1U) &&
169
+ last_byte_offset <= pointer_max - base - (sizeof(float) - 1U);
170
+ }
171
+
172
+ } // namespace
173
+
174
+ bool palw_cuda_trace_valid_dtype(uint8_t dtype) {
175
+ return dtype <= PALW_CUDA_TRACE_DTYPE_INT4;
176
+ }
177
+
178
+ bool palw_cuda_trace_valid_quantization(uint8_t quantization) {
179
+ return quantization <= PALW_CUDA_TRACE_QUANTIZATION_IQ4_XS;
180
+ }
181
+
182
+ bool palw_cuda_trace_valid_phase(uint8_t phase, uint64_t decode_step) {
183
+ if (phase == PALW_CUDA_TRACE_PREFILL) {
184
+ return decode_step == 0U;
185
+ }
186
+ return phase == PALW_CUDA_TRACE_DECODE && decode_step <= UINT32_MAX;
187
+ }
188
+
189
+ extern "C" palw_cuda_trace_status palw_cuda_trace_create(
190
+ uint64_t capacity,
191
+ palw_cuda_trace_context ** out_context) {
192
+ if (capacity == 0U || out_context == nullptr ||
193
+ capacity > std::numeric_limits<size_t>::max() / sizeof(palw_cuda_trace_record)) {
194
+ return PALW_CUDA_TRACE_INVALID_ARGUMENT;
195
+ }
196
+ *out_context = nullptr;
197
+ auto * context = new (std::nothrow) palw_cuda_trace_context{};
198
+ if (context == nullptr) {
199
+ return PALW_CUDA_TRACE_CUDA_ERROR;
200
+ }
201
+ const cudaError_t error = cudaMalloc(
202
+ reinterpret_cast<void **>(&context->device_records),
203
+ static_cast<size_t>(capacity) * sizeof(palw_cuda_trace_record));
204
+ if (error != cudaSuccess) {
205
+ delete context;
206
+ return PALW_CUDA_TRACE_CUDA_ERROR;
207
+ }
208
+ context->capacity = capacity;
209
+ context->last_cuda_error = static_cast<int32_t>(cudaSuccess);
210
+ *out_context = context;
211
+ return PALW_CUDA_TRACE_OK;
212
+ }
213
+
214
+ extern "C" void palw_cuda_trace_destroy(palw_cuda_trace_context * context) {
215
+ if (context != nullptr) {
216
+ (void) cudaFree(context->device_records);
217
+ delete context;
218
+ }
219
+ }
220
+
221
+ extern "C" palw_cuda_trace_status palw_cuda_trace_reset(palw_cuda_trace_context * context) {
222
+ if (context == nullptr) {
223
+ return PALW_CUDA_TRACE_INVALID_ARGUMENT;
224
+ }
225
+ if (context->poisoned != 0) {
226
+ return PALW_CUDA_TRACE_POISONED;
227
+ }
228
+ if (context->copy_pending != 0 || context->committed_record != context->next_record ||
229
+ context->committed_kernel_sequence != context->next_kernel_sequence) {
230
+ return PALW_CUDA_TRACE_PENDING;
231
+ }
232
+ context->next_record = 0;
233
+ context->committed_record = 0;
234
+ context->next_kernel_sequence = 0;
235
+ context->committed_kernel_sequence = 0;
236
+ context->overflowed = 0;
237
+ context->last_cuda_error = static_cast<int32_t>(cudaSuccess);
238
+ return PALW_CUDA_TRACE_OK;
239
+ }
240
+
241
+ extern "C" uint64_t palw_cuda_trace_count(const palw_cuda_trace_context * context) {
242
+ return context == nullptr ? 0U : context->next_record;
243
+ }
244
+
245
+ extern "C" uint64_t palw_cuda_trace_committed_count(const palw_cuda_trace_context * context) {
246
+ return context == nullptr ? 0U : context->committed_record;
247
+ }
248
+
249
+ extern "C" int palw_cuda_trace_overflowed(const palw_cuda_trace_context * context) {
250
+ return context == nullptr ? 1 : context->overflowed;
251
+ }
252
+
253
+ extern "C" int palw_cuda_trace_poisoned(const palw_cuda_trace_context * context) {
254
+ return context == nullptr ? 1 : context->poisoned;
255
+ }
256
+
257
+ extern "C" int32_t palw_cuda_trace_last_cuda_error(const palw_cuda_trace_context * context) {
258
+ return context == nullptr ? -1 : context->last_cuda_error;
259
+ }
260
+
261
+ extern "C" palw_cuda_trace_status palw_cuda_trace_synchronize(
262
+ palw_cuda_trace_context * context,
263
+ cudaStream_t stream) {
264
+ if (context == nullptr) {
265
+ return PALW_CUDA_TRACE_INVALID_ARGUMENT;
266
+ }
267
+ if (context->poisoned != 0) {
268
+ return PALW_CUDA_TRACE_POISONED;
269
+ }
270
+ if (!bind_or_match_stream(context, stream)) {
271
+ return PALW_CUDA_TRACE_INVALID_ARGUMENT;
272
+ }
273
+ const palw_cuda_trace_status pending_error = consume_pending_cuda_error(context);
274
+ if (pending_error != PALW_CUDA_TRACE_OK) {
275
+ return pending_error;
276
+ }
277
+ const cudaError_t error = cudaStreamSynchronize(stream);
278
+ if (error != cudaSuccess) {
279
+ poison_context(context, error);
280
+ return PALW_CUDA_TRACE_CUDA_ERROR;
281
+ }
282
+ context->committed_record = context->next_record;
283
+ context->committed_kernel_sequence = context->next_kernel_sequence;
284
+ context->copy_pending = 0;
285
+ return PALW_CUDA_TRACE_OK;
286
+ }
287
+
288
+ extern "C" palw_cuda_trace_status palw_cuda_trace_copy_async(
289
+ palw_cuda_trace_context * context,
290
+ palw_cuda_trace_record * host_records,
291
+ uint64_t host_capacity,
292
+ cudaStream_t stream) {
293
+ if (context == nullptr || host_records == nullptr) {
294
+ return PALW_CUDA_TRACE_INVALID_ARGUMENT;
295
+ }
296
+ const palw_cuda_trace_status context_status = reject_failed_context(context);
297
+ if (context_status != PALW_CUDA_TRACE_OK) {
298
+ return context_status;
299
+ }
300
+ if (context->copy_pending != 0) {
301
+ return PALW_CUDA_TRACE_PENDING;
302
+ }
303
+ if (host_capacity < context->next_record || !bind_or_match_stream(context, stream)) {
304
+ return PALW_CUDA_TRACE_INVALID_ARGUMENT;
305
+ }
306
+ const palw_cuda_trace_status pending_error = consume_pending_cuda_error(context);
307
+ if (pending_error != PALW_CUDA_TRACE_OK) {
308
+ return pending_error;
309
+ }
310
+ const size_t bytes = static_cast<size_t>(context->next_record) * sizeof(palw_cuda_trace_record);
311
+ const cudaError_t error = cudaMemcpyAsync(
312
+ host_records,
313
+ context->device_records,
314
+ bytes,
315
+ cudaMemcpyDeviceToHost,
316
+ stream);
317
+ if (error != cudaSuccess) {
318
+ poison_context(context, error);
319
+ return PALW_CUDA_TRACE_CUDA_ERROR;
320
+ }
321
+ context->copy_pending = 1;
322
+ return PALW_CUDA_TRACE_OK;
323
+ }
324
+
325
+ palw_cuda_trace_status palw_cuda_trace_launch_f32(
326
+ palw_cuda_trace_context * context,
327
+ cudaStream_t stream,
328
+ const float * output,
329
+ uint64_t row_stride,
330
+ const palw_cuda_trace_launch * requested) {
331
+ if (context == nullptr || output == nullptr || requested == nullptr) {
332
+ return PALW_CUDA_TRACE_INVALID_ARGUMENT;
333
+ }
334
+ const palw_cuda_trace_status context_status = reject_failed_context(context);
335
+ if (context_status != PALW_CUDA_TRACE_OK) {
336
+ return context_status;
337
+ }
338
+ if (context->copy_pending != 0) {
339
+ return PALW_CUDA_TRACE_PENDING;
340
+ }
341
+ if (requested->output_rows == 0U || requested->output_columns == 0U ||
342
+ requested->tile_rows == 0U || requested->tile_columns == 0U ||
343
+ row_stride < requested->output_columns || requested->layer_id > PALW_CUDA_TRACE_MAX_LAYER_ID ||
344
+ !palw_cuda_trace_valid_phase(requested->phase, requested->decode_step) ||
345
+ !palw_cuda_trace_valid_dtype(requested->dtype) ||
346
+ !palw_cuda_trace_valid_quantization(requested->quantization) ||
347
+ requested->kind < PALW_CUDA_TRACE_GEMM || requested->kind > PALW_CUDA_TRACE_ATTENTION ||
348
+ !valid_address_range(output, requested->output_rows, requested->output_columns, row_stride)) {
349
+ return PALW_CUDA_TRACE_INVALID_ARGUMENT;
350
+ }
351
+ if (requested->kernel_sequence != context->next_kernel_sequence ||
352
+ requested->kernel_sequence == UINT64_MAX) {
353
+ return PALW_CUDA_TRACE_SEQUENCE_MISMATCH;
354
+ }
355
+ /* A wrong stream is invalid and must not make an otherwise-full context overflow-sticky. */
356
+ if (context->stream_bound != 0 && context->stream != stream) {
357
+ return PALW_CUDA_TRACE_INVALID_ARGUMENT;
358
+ }
359
+
360
+ const uint64_t grid_x =
361
+ (static_cast<uint64_t>(requested->output_columns) + requested->tile_columns - 1U) /
362
+ requested->tile_columns;
363
+ const uint64_t grid_y =
364
+ (static_cast<uint64_t>(requested->output_rows) + requested->tile_rows - 1U) /
365
+ requested->tile_rows;
366
+ if (grid_x == 0U || grid_y == 0U || grid_x > kMaxGridX || grid_y > kMaxGridY ||
367
+ grid_y > UINT64_MAX / grid_x) {
368
+ return PALW_CUDA_TRACE_INVALID_ARGUMENT;
369
+ }
370
+ const uint64_t tile_count = grid_x * grid_y;
371
+ if (tile_count > UINT32_MAX) {
372
+ return PALW_CUDA_TRACE_INVALID_ARGUMENT;
373
+ }
374
+ if (context->next_record > context->capacity ||
375
+ tile_count > context->capacity - context->next_record) {
376
+ context->overflowed = 1;
377
+ return PALW_CUDA_TRACE_CAPACITY_EXCEEDED;
378
+ }
379
+ if (!bind_or_match_stream(context, stream)) {
380
+ return PALW_CUDA_TRACE_INVALID_ARGUMENT;
381
+ }
382
+ const palw_cuda_trace_status pending_error = consume_pending_cuda_error(context);
383
+ if (pending_error != PALW_CUDA_TRACE_OK) {
384
+ return pending_error;
385
+ }
386
+
387
+ palw_cuda_trace_launch launch = *requested;
388
+ launch.base_record = context->next_record;
389
+ launch.tile_count = tile_count;
390
+ dim3 launch_grid(static_cast<uint32_t>(grid_x), static_cast<uint32_t>(grid_y), 1U);
391
+ #if defined(PALW_CUDA_TRACE_TESTING)
392
+ if (context->test_force_launch_failure != 0) {
393
+ context->test_force_launch_failure = 0;
394
+ /* A zero-width grid forces a real, immediate CUDA launch-configuration error. */
395
+ launch_grid.x = 0U;
396
+ }
397
+ #endif
398
+ accumulator_sketch_f32<<<
399
+ launch_grid,
400
+ dim3(1U, 1U, 1U),
401
+ 0,
402
+ stream>>>(output, row_stride, context->device_records, launch);
403
+ const cudaError_t error = cudaGetLastError();
404
+ if (error != cudaSuccess) {
405
+ poison_context(context, error);
406
+ return PALW_CUDA_TRACE_CUDA_ERROR;
407
+ }
408
+ context->next_record += tile_count;
409
+ context->next_kernel_sequence += 1U;
410
+ return PALW_CUDA_TRACE_OK;
411
+ }
runtime-palw/cuda/attention_trace.cu ADDED
@@ -0,0 +1,58 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #include "palw_cuda_trace_internal.cuh"
2
+
3
+ extern "C" palw_cuda_trace_status palw_cuda_trace_attention_f32(
4
+ palw_cuda_trace_context * context,
5
+ cudaStream_t stream,
6
+ const float * output,
7
+ uint32_t output_rows,
8
+ uint32_t output_columns,
9
+ uint64_t row_stride,
10
+ uint64_t kernel_sequence,
11
+ uint32_t layer_id,
12
+ uint8_t phase,
13
+ uint64_t decode_step,
14
+ uint64_t query_tokens,
15
+ uint64_t key_value_tokens,
16
+ uint64_t heads,
17
+ uint64_t head_dim,
18
+ uint64_t batch,
19
+ uint8_t dtype,
20
+ uint8_t causal,
21
+ uint32_t tile_rows,
22
+ uint32_t tile_columns) {
23
+ if (context != nullptr && context->poisoned != 0) {
24
+ return PALW_CUDA_TRACE_POISONED;
25
+ }
26
+ if (context != nullptr && context->overflowed != 0) {
27
+ return PALW_CUDA_TRACE_CAPACITY_EXCEEDED;
28
+ }
29
+ if (query_tokens == 0U || key_value_tokens == 0U || heads == 0U || head_dim == 0U ||
30
+ batch == 0U || causal > 1U || query_tokens > UINT32_MAX ||
31
+ key_value_tokens > UINT32_MAX || heads > UINT32_MAX || head_dim > UINT32_MAX ||
32
+ batch > UINT32_MAX || head_dim > UINT64_MAX / heads ||
33
+ query_tokens > UINT64_MAX / batch || query_tokens * batch != output_rows ||
34
+ heads * head_dim != output_columns ||
35
+ (causal != 0U && key_value_tokens < query_tokens) ||
36
+ (phase == PALW_CUDA_TRACE_DECODE && query_tokens != 1U)) {
37
+ return PALW_CUDA_TRACE_INVALID_ARGUMENT;
38
+ }
39
+ palw_cuda_trace_launch launch{};
40
+ launch.kernel_sequence = kernel_sequence;
41
+ launch.decode_step = decode_step;
42
+ launch.m = query_tokens;
43
+ launch.n = heads * head_dim;
44
+ launch.k = key_value_tokens;
45
+ launch.batch = batch;
46
+ launch.query_tokens = query_tokens;
47
+ launch.key_value_tokens = key_value_tokens;
48
+ launch.layer_id = layer_id;
49
+ launch.output_rows = output_rows;
50
+ launch.output_columns = output_columns;
51
+ launch.tile_rows = tile_rows;
52
+ launch.tile_columns = tile_columns;
53
+ launch.kind = PALW_CUDA_TRACE_ATTENTION;
54
+ launch.phase = phase;
55
+ launch.dtype = dtype;
56
+ launch.causal = causal;
57
+ return palw_cuda_trace_launch_f32(context, stream, output, row_stride, &launch);
58
+ }
runtime-palw/cuda/cuda_trace_test.cu ADDED
@@ -0,0 +1,522 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #include "palw_cuda_trace_internal.cuh"
2
+
3
+ #include <cuda_runtime.h>
4
+
5
+ #include <array>
6
+ #include <cstdint>
7
+ #include <cstdio>
8
+ #include <cstring>
9
+ #include <vector>
10
+
11
+ static_assert(PALW_CUDA_TRACE_PRODUCTION_CAPABLE == 0U);
12
+
13
+ namespace {
14
+
15
+ #define REQUIRE(condition, message) \
16
+ do { \
17
+ if (!(condition)) { \
18
+ std::fprintf(stderr, "CUDA trace test failure at line %d: %s\n", __LINE__, message); \
19
+ return false; \
20
+ } \
21
+ } while (false)
22
+
23
+ #define REQUIRE_STATUS(expression, expected) \
24
+ do { \
25
+ const palw_cuda_trace_status actual_status = (expression); \
26
+ if (actual_status != (expected)) { \
27
+ std::fprintf( \
28
+ stderr, \
29
+ "CUDA trace test failure at line %d: status %d, expected %d\n", \
30
+ __LINE__, \
31
+ static_cast<int>(actual_status), \
32
+ static_cast<int>(expected)); \
33
+ return false; \
34
+ } \
35
+ } while (false)
36
+
37
+ class stream_guard {
38
+ public:
39
+ bool create() {
40
+ return cudaStreamCreateWithFlags(&stream_, cudaStreamNonBlocking) == cudaSuccess;
41
+ }
42
+
43
+ ~stream_guard() {
44
+ if (stream_ != nullptr) {
45
+ (void) cudaStreamDestroy(stream_);
46
+ }
47
+ }
48
+
49
+ cudaStream_t get() const {
50
+ return stream_;
51
+ }
52
+
53
+ private:
54
+ cudaStream_t stream_ = nullptr;
55
+ };
56
+
57
+ class device_float_buffer {
58
+ public:
59
+ bool allocate(size_t elements) {
60
+ elements_ = elements;
61
+ return cudaMalloc(reinterpret_cast<void **>(&data_), elements * sizeof(float)) == cudaSuccess;
62
+ }
63
+
64
+ ~device_float_buffer() {
65
+ if (data_ != nullptr) {
66
+ (void) cudaFree(data_);
67
+ }
68
+ }
69
+
70
+ bool copy_from(const std::vector<float> & values, cudaStream_t stream) {
71
+ return values.size() <= elements_ &&
72
+ cudaMemcpyAsync(
73
+ data_,
74
+ values.data(),
75
+ values.size() * sizeof(float),
76
+ cudaMemcpyHostToDevice,
77
+ stream) == cudaSuccess;
78
+ }
79
+
80
+ float * get() const {
81
+ return data_;
82
+ }
83
+
84
+ private:
85
+ float * data_ = nullptr;
86
+ size_t elements_ = 0;
87
+ };
88
+
89
+ class pinned_records {
90
+ public:
91
+ bool allocate(size_t count) {
92
+ count_ = count;
93
+ return cudaMallocHost(
94
+ reinterpret_cast<void **>(&records_),
95
+ count * sizeof(palw_cuda_trace_record)) == cudaSuccess;
96
+ }
97
+
98
+ ~pinned_records() {
99
+ if (records_ != nullptr) {
100
+ (void) cudaFreeHost(records_);
101
+ }
102
+ }
103
+
104
+ palw_cuda_trace_record * get() const {
105
+ return records_;
106
+ }
107
+
108
+ uint64_t capacity() const {
109
+ return static_cast<uint64_t>(count_);
110
+ }
111
+
112
+ private:
113
+ palw_cuda_trace_record * records_ = nullptr;
114
+ size_t count_ = 0;
115
+ };
116
+
117
+ class context_guard {
118
+ public:
119
+ bool create(uint64_t capacity) {
120
+ return palw_cuda_trace_create(capacity, &context_) == PALW_CUDA_TRACE_OK;
121
+ }
122
+
123
+ ~context_guard() {
124
+ palw_cuda_trace_destroy(context_);
125
+ }
126
+
127
+ palw_cuda_trace_context * get() const {
128
+ return context_;
129
+ }
130
+
131
+ private:
132
+ palw_cuda_trace_context * context_ = nullptr;
133
+ };
134
+
135
+ using encoded_record = std::array<uint8_t, PALW_CUDA_TRACE_RECORD_ENCODED_SIZE_V1>;
136
+ using sketch = std::array<uint64_t, 4>;
137
+
138
+ palw_cuda_trace_status launch_gemm(
139
+ palw_cuda_trace_context * context,
140
+ cudaStream_t stream,
141
+ const float * output,
142
+ uint64_t sequence,
143
+ uint8_t phase = PALW_CUDA_TRACE_PREFILL,
144
+ uint64_t decode_step = 0,
145
+ uint8_t dtype = PALW_CUDA_TRACE_DTYPE_FP32,
146
+ uint8_t quantization = PALW_CUDA_TRACE_QUANTIZATION_Q4_K_M,
147
+ uint32_t output_rows = 4,
148
+ uint32_t output_columns = 6,
149
+ uint64_t row_stride = 6,
150
+ uint64_t m = 6,
151
+ uint64_t n = 2,
152
+ uint64_t k = 3,
153
+ uint64_t batch = 2,
154
+ uint32_t tile_rows = 2,
155
+ uint32_t tile_columns = 4) {
156
+ return palw_cuda_trace_gemm_f32(
157
+ context,
158
+ stream,
159
+ output,
160
+ output_rows,
161
+ output_columns,
162
+ row_stride,
163
+ sequence,
164
+ 5,
165
+ phase,
166
+ decode_step,
167
+ m,
168
+ n,
169
+ k,
170
+ batch,
171
+ dtype,
172
+ quantization,
173
+ tile_rows,
174
+ tile_columns);
175
+ }
176
+
177
+ palw_cuda_trace_status launch_attention(
178
+ palw_cuda_trace_context * context,
179
+ cudaStream_t stream,
180
+ const float * output,
181
+ uint64_t sequence,
182
+ uint8_t phase = PALW_CUDA_TRACE_PREFILL,
183
+ uint64_t decode_step = 0,
184
+ uint64_t query_tokens = 2,
185
+ uint64_t key_value_tokens = 2,
186
+ uint64_t heads = 2,
187
+ uint64_t head_dim = 4,
188
+ uint64_t batch = 1,
189
+ uint8_t dtype = PALW_CUDA_TRACE_DTYPE_FP16,
190
+ uint8_t causal = 1,
191
+ uint32_t output_rows = 2,
192
+ uint32_t output_columns = 8,
193
+ uint64_t row_stride = 8,
194
+ uint32_t tile_rows = 1,
195
+ uint32_t tile_columns = 4) {
196
+ return palw_cuda_trace_attention_f32(
197
+ context,
198
+ stream,
199
+ output,
200
+ output_rows,
201
+ output_columns,
202
+ row_stride,
203
+ sequence,
204
+ 5,
205
+ phase,
206
+ decode_step,
207
+ query_tokens,
208
+ key_value_tokens,
209
+ heads,
210
+ head_dim,
211
+ batch,
212
+ dtype,
213
+ causal,
214
+ tile_rows,
215
+ tile_columns);
216
+ }
217
+
218
+ bool encode_records(
219
+ const palw_cuda_trace_record * records,
220
+ size_t count,
221
+ std::vector<encoded_record> & encoded) {
222
+ encoded.resize(count);
223
+ for (size_t i = 0; i < count; ++i) {
224
+ if (palw_cuda_trace_encode_record_v1(
225
+ &records[i], encoded[i].data(), encoded[i].size()) != PALW_CUDA_TRACE_OK) {
226
+ return false;
227
+ }
228
+ }
229
+ return true;
230
+ }
231
+
232
+ sketch record_sketch(const palw_cuda_trace_record & record) {
233
+ return {record.sketch[0], record.sketch[1], record.sketch[2], record.sketch[3]};
234
+ }
235
+
236
+ float float_from_bits(uint32_t bits) {
237
+ float value = 0.0f;
238
+ std::memcpy(&value, &bits, sizeof(value));
239
+ return value;
240
+ }
241
+
242
+ bool run_device_tests() {
243
+ stream_guard stream;
244
+ stream_guard other_stream;
245
+ device_float_buffer output;
246
+ pinned_records records;
247
+ context_guard context;
248
+ context_guard small_context;
249
+ context_guard recovered_context;
250
+
251
+ REQUIRE(stream.create(), "failed to create primary stream");
252
+ REQUIRE(other_stream.create(), "failed to create secondary stream");
253
+ REQUIRE(output.allocate(24), "failed to allocate output");
254
+ REQUIRE(records.allocate(32), "failed to allocate pinned records");
255
+ REQUIRE(context.create(32), "failed to create trace context");
256
+
257
+ std::vector<float> values(24);
258
+ for (size_t i = 0; i < values.size(); ++i) {
259
+ values[i] = static_cast<float>(i + 1U) * 0.25f;
260
+ }
261
+
262
+ REQUIRE(output.copy_from(values, stream.get()), "failed to upload baseline output");
263
+ REQUIRE_STATUS(launch_gemm(context.get(), stream.get(), output.get(), 0), PALW_CUDA_TRACE_OK);
264
+ REQUIRE_STATUS(
265
+ launch_attention(context.get(), stream.get(), output.get(), 1),
266
+ PALW_CUDA_TRACE_OK);
267
+ REQUIRE(palw_cuda_trace_count(context.get()) == 8U, "unexpected reserved record count");
268
+ REQUIRE(
269
+ palw_cuda_trace_committed_count(context.get()) == 0U,
270
+ "records committed before synchronization");
271
+ REQUIRE_STATUS(
272
+ palw_cuda_trace_copy_async(context.get(), records.get(), 7, stream.get()),
273
+ PALW_CUDA_TRACE_INVALID_ARGUMENT);
274
+ REQUIRE_STATUS(
275
+ palw_cuda_trace_synchronize(context.get(), other_stream.get()),
276
+ PALW_CUDA_TRACE_INVALID_ARGUMENT);
277
+ REQUIRE(palw_cuda_trace_count(context.get()) == 8U, "copy/stream rejection changed count");
278
+ REQUIRE_STATUS(palw_cuda_trace_reset(context.get()), PALW_CUDA_TRACE_PENDING);
279
+ REQUIRE_STATUS(
280
+ palw_cuda_trace_copy_async(
281
+ context.get(), records.get(), records.capacity(), stream.get()),
282
+ PALW_CUDA_TRACE_OK);
283
+ REQUIRE_STATUS(
284
+ palw_cuda_trace_copy_async(
285
+ context.get(), records.get(), records.capacity(), stream.get()),
286
+ PALW_CUDA_TRACE_PENDING);
287
+ REQUIRE_STATUS(launch_gemm(context.get(), stream.get(), output.get(), 2), PALW_CUDA_TRACE_PENDING);
288
+ REQUIRE_STATUS(palw_cuda_trace_synchronize(context.get(), stream.get()), PALW_CUDA_TRACE_OK);
289
+ REQUIRE(
290
+ palw_cuda_trace_committed_count(context.get()) == 8U,
291
+ "successful synchronize did not commit records");
292
+
293
+ for (uint64_t i = 0; i < 4U; ++i) {
294
+ const auto & record = records.get()[i];
295
+ REQUIRE(record.kernel_sequence == 0U, "GEMM sequence mismatch");
296
+ REQUIRE(record.tile_index == i, "GEMM tile index mismatch");
297
+ REQUIRE(record.tile_row == i / 2U && record.tile_column == i % 2U, "GEMM tile order mismatch");
298
+ REQUIRE(record.kind == PALW_CUDA_TRACE_GEMM, "GEMM kind mismatch");
299
+ }
300
+ for (uint64_t i = 0; i < 4U; ++i) {
301
+ const auto & record = records.get()[4U + i];
302
+ REQUIRE(record.kernel_sequence == 1U, "attention sequence mismatch");
303
+ REQUIRE(record.tile_index == i, "attention tile index mismatch");
304
+ REQUIRE(
305
+ record.tile_row == i / 2U && record.tile_column == i % 2U,
306
+ "attention tile order mismatch");
307
+ REQUIRE(record.kind == PALW_CUDA_TRACE_ATTENTION, "attention kind mismatch");
308
+ }
309
+
310
+ std::vector<encoded_record> baseline;
311
+ REQUIRE(encode_records(records.get(), 8, baseline), "failed to encode baseline records");
312
+ std::array<sketch, 4> baseline_gemm_sketches{};
313
+ for (size_t i = 0; i < baseline_gemm_sketches.size(); ++i) {
314
+ baseline_gemm_sketches[i] = record_sketch(records.get()[i]);
315
+ }
316
+
317
+ REQUIRE_STATUS(palw_cuda_trace_reset(context.get()), PALW_CUDA_TRACE_OK);
318
+ REQUIRE(output.copy_from(values, stream.get()), "failed to restore baseline output");
319
+ REQUIRE_STATUS(launch_gemm(context.get(), stream.get(), output.get(), 0), PALW_CUDA_TRACE_OK);
320
+ REQUIRE_STATUS(
321
+ launch_attention(context.get(), stream.get(), output.get(), 1),
322
+ PALW_CUDA_TRACE_OK);
323
+ REQUIRE_STATUS(
324
+ palw_cuda_trace_copy_async(
325
+ context.get(), records.get(), records.capacity(), stream.get()),
326
+ PALW_CUDA_TRACE_OK);
327
+ REQUIRE_STATUS(palw_cuda_trace_synchronize(context.get(), stream.get()), PALW_CUDA_TRACE_OK);
328
+ std::vector<encoded_record> repeated;
329
+ REQUIRE(encode_records(records.get(), 8, repeated), "failed to encode repeated records");
330
+ REQUIRE(repeated == baseline, "same-stream trace was not repeatable");
331
+
332
+ std::vector<float> canonical_values_a(24);
333
+ std::vector<float> canonical_values_b(24);
334
+ for (size_t i = 0; i < canonical_values_a.size(); ++i) {
335
+ if ((i & 1U) == 0U) {
336
+ canonical_values_a[i] = float_from_bits(0x00000000U);
337
+ canonical_values_b[i] = float_from_bits(0x80000000U);
338
+ } else {
339
+ canonical_values_a[i] = float_from_bits(0x7fc00001U + static_cast<uint32_t>(i));
340
+ canonical_values_b[i] = float_from_bits(0xff800001U + static_cast<uint32_t>(i));
341
+ }
342
+ }
343
+ REQUIRE_STATUS(palw_cuda_trace_reset(context.get()), PALW_CUDA_TRACE_OK);
344
+ REQUIRE(output.copy_from(canonical_values_a, stream.get()), "failed to upload canonical set A");
345
+ REQUIRE_STATUS(launch_gemm(context.get(), stream.get(), output.get(), 0), PALW_CUDA_TRACE_OK);
346
+ REQUIRE_STATUS(
347
+ palw_cuda_trace_copy_async(
348
+ context.get(), records.get(), records.capacity(), stream.get()),
349
+ PALW_CUDA_TRACE_OK);
350
+ REQUIRE_STATUS(palw_cuda_trace_synchronize(context.get(), stream.get()), PALW_CUDA_TRACE_OK);
351
+ std::vector<encoded_record> canonical_a;
352
+ REQUIRE(encode_records(records.get(), 4, canonical_a), "failed to encode canonical set A");
353
+
354
+ REQUIRE_STATUS(palw_cuda_trace_reset(context.get()), PALW_CUDA_TRACE_OK);
355
+ REQUIRE(output.copy_from(canonical_values_b, stream.get()), "failed to upload canonical set B");
356
+ REQUIRE_STATUS(launch_gemm(context.get(), stream.get(), output.get(), 0), PALW_CUDA_TRACE_OK);
357
+ REQUIRE_STATUS(
358
+ palw_cuda_trace_copy_async(
359
+ context.get(), records.get(), records.capacity(), stream.get()),
360
+ PALW_CUDA_TRACE_OK);
361
+ REQUIRE_STATUS(palw_cuda_trace_synchronize(context.get(), stream.get()), PALW_CUDA_TRACE_OK);
362
+ std::vector<encoded_record> canonical_b;
363
+ REQUIRE(encode_records(records.get(), 4, canonical_b), "failed to encode canonical set B");
364
+ REQUIRE(canonical_a == canonical_b, "signed-zero or NaN payload changed a sketch");
365
+
366
+ REQUIRE_STATUS(palw_cuda_trace_reset(context.get()), PALW_CUDA_TRACE_OK);
367
+ values[7] += 17.0f;
368
+ REQUIRE(output.copy_from(values, stream.get()), "failed to upload mutated output");
369
+ REQUIRE_STATUS(launch_gemm(context.get(), stream.get(), output.get(), 0), PALW_CUDA_TRACE_OK);
370
+ REQUIRE_STATUS(
371
+ palw_cuda_trace_copy_async(
372
+ context.get(), records.get(), records.capacity(), stream.get()),
373
+ PALW_CUDA_TRACE_OK);
374
+ REQUIRE_STATUS(palw_cuda_trace_synchronize(context.get(), stream.get()), PALW_CUDA_TRACE_OK);
375
+ REQUIRE(
376
+ record_sketch(records.get()[0]) != baseline_gemm_sketches[0],
377
+ "sampled mutation did not change its tile sketch");
378
+ for (size_t i = 1; i < baseline_gemm_sketches.size(); ++i) {
379
+ REQUIRE(
380
+ record_sketch(records.get()[i]) == baseline_gemm_sketches[i],
381
+ "mutation changed an unrelated tile sketch");
382
+ }
383
+
384
+ REQUIRE_STATUS(palw_cuda_trace_reset(context.get()), PALW_CUDA_TRACE_OK);
385
+ REQUIRE_STATUS(
386
+ launch_gemm(
387
+ context.get(), stream.get(), output.get(), 0, PALW_CUDA_TRACE_PREFILL, 0, 255),
388
+ PALW_CUDA_TRACE_INVALID_ARGUMENT);
389
+ REQUIRE_STATUS(
390
+ launch_gemm(
391
+ context.get(), stream.get(), output.get(), 0, PALW_CUDA_TRACE_PREFILL, 0,
392
+ PALW_CUDA_TRACE_DTYPE_FP32, 255),
393
+ PALW_CUDA_TRACE_INVALID_ARGUMENT);
394
+ REQUIRE_STATUS(
395
+ launch_gemm(
396
+ context.get(), stream.get(), output.get(), 0, PALW_CUDA_TRACE_PREFILL, 1),
397
+ PALW_CUDA_TRACE_INVALID_ARGUMENT);
398
+ REQUIRE_STATUS(
399
+ launch_gemm(
400
+ context.get(), stream.get(), output.get(), 0, PALW_CUDA_TRACE_PREFILL, 0,
401
+ PALW_CUDA_TRACE_DTYPE_FP32, PALW_CUDA_TRACE_QUANTIZATION_Q4_K_M, 3),
402
+ PALW_CUDA_TRACE_INVALID_ARGUMENT);
403
+ REQUIRE_STATUS(
404
+ launch_gemm(
405
+ context.get(), stream.get(), output.get(), 0, PALW_CUDA_TRACE_PREFILL, 0,
406
+ PALW_CUDA_TRACE_DTYPE_FP32, PALW_CUDA_TRACE_QUANTIZATION_Q4_K_M,
407
+ 4, 6, 5),
408
+ PALW_CUDA_TRACE_INVALID_ARGUMENT);
409
+ REQUIRE_STATUS(
410
+ launch_gemm(
411
+ context.get(), stream.get(), output.get(), 0, PALW_CUDA_TRACE_PREFILL, 0,
412
+ PALW_CUDA_TRACE_DTYPE_FP32, PALW_CUDA_TRACE_QUANTIZATION_Q4_K_M,
413
+ 4, 6, 6, 6, 2, 3, 2, 0, 4),
414
+ PALW_CUDA_TRACE_INVALID_ARGUMENT);
415
+ REQUIRE_STATUS(
416
+ launch_attention(
417
+ context.get(), stream.get(), output.get(), 0, PALW_CUDA_TRACE_DECODE, 0),
418
+ PALW_CUDA_TRACE_INVALID_ARGUMENT);
419
+ REQUIRE_STATUS(
420
+ launch_attention(
421
+ context.get(), stream.get(), output.get(), 0, PALW_CUDA_TRACE_PREFILL, 0,
422
+ 2, 1),
423
+ PALW_CUDA_TRACE_INVALID_ARGUMENT);
424
+ REQUIRE_STATUS(
425
+ launch_attention(
426
+ context.get(), stream.get(), output.get(), 0, PALW_CUDA_TRACE_PREFILL, 0,
427
+ 2, 2, 2, 4, 1, PALW_CUDA_TRACE_DTYPE_FP16, 1, 3),
428
+ PALW_CUDA_TRACE_INVALID_ARGUMENT);
429
+ REQUIRE_STATUS(
430
+ launch_attention(
431
+ context.get(), stream.get(), output.get(), 0, PALW_CUDA_TRACE_PREFILL, 0,
432
+ 2, 2, 2, 4, 1, PALW_CUDA_TRACE_DTYPE_FP16, 2),
433
+ PALW_CUDA_TRACE_INVALID_ARGUMENT);
434
+ REQUIRE(palw_cuda_trace_count(context.get()) == 0U, "invalid arguments mutated count");
435
+ REQUIRE(palw_cuda_trace_poisoned(context.get()) == 0, "invalid arguments poisoned context");
436
+
437
+ REQUIRE_STATUS(launch_gemm(context.get(), stream.get(), output.get(), 1), PALW_CUDA_TRACE_SEQUENCE_MISMATCH);
438
+ REQUIRE(palw_cuda_trace_count(context.get()) == 0U, "sequence mismatch mutated count");
439
+ REQUIRE_STATUS(launch_gemm(context.get(), stream.get(), output.get(), 0), PALW_CUDA_TRACE_OK);
440
+ REQUIRE_STATUS(launch_gemm(context.get(), stream.get(), output.get(), 0), PALW_CUDA_TRACE_SEQUENCE_MISMATCH);
441
+ REQUIRE(palw_cuda_trace_count(context.get()) == 4U, "sequence mismatch changed reserved count");
442
+ REQUIRE_STATUS(palw_cuda_trace_synchronize(context.get(), stream.get()), PALW_CUDA_TRACE_OK);
443
+ REQUIRE_STATUS(palw_cuda_trace_reset(context.get()), PALW_CUDA_TRACE_OK);
444
+
445
+ REQUIRE_STATUS(
446
+ launch_gemm(context.get(), other_stream.get(), output.get(), 0),
447
+ PALW_CUDA_TRACE_INVALID_ARGUMENT);
448
+ REQUIRE(palw_cuda_trace_count(context.get()) == 0U, "wrong stream mutated count");
449
+
450
+ REQUIRE(small_context.create(3), "failed to create small trace context");
451
+ REQUIRE_STATUS(
452
+ launch_gemm(small_context.get(), stream.get(), output.get(), 0),
453
+ PALW_CUDA_TRACE_CAPACITY_EXCEEDED);
454
+ REQUIRE(palw_cuda_trace_overflowed(small_context.get()) == 1, "overflow flag was not sticky");
455
+ REQUIRE(palw_cuda_trace_count(small_context.get()) == 0U, "capacity failure reserved records");
456
+ REQUIRE_STATUS(
457
+ launch_gemm(small_context.get(), stream.get(), output.get(), 0),
458
+ PALW_CUDA_TRACE_CAPACITY_EXCEEDED);
459
+ REQUIRE_STATUS(palw_cuda_trace_reset(small_context.get()), PALW_CUDA_TRACE_OK);
460
+ REQUIRE(palw_cuda_trace_overflowed(small_context.get()) == 0, "reset did not clear overflow");
461
+ REQUIRE_STATUS(
462
+ launch_gemm(
463
+ small_context.get(), stream.get(), output.get(), 0, PALW_CUDA_TRACE_PREFILL, 0,
464
+ PALW_CUDA_TRACE_DTYPE_FP32, PALW_CUDA_TRACE_QUANTIZATION_Q4_K_M,
465
+ 4, 6, 6, 6, 2, 3, 2, 4, 2),
466
+ PALW_CUDA_TRACE_OK);
467
+ REQUIRE(palw_cuda_trace_count(small_context.get()) == 3U, "exact capacity count mismatch");
468
+ REQUIRE_STATUS(
469
+ palw_cuda_trace_synchronize(small_context.get(), stream.get()),
470
+ PALW_CUDA_TRACE_OK);
471
+
472
+ context.get()->test_force_launch_failure = 1;
473
+ REQUIRE_STATUS(launch_gemm(context.get(), stream.get(), output.get(), 0), PALW_CUDA_TRACE_CUDA_ERROR);
474
+ REQUIRE(palw_cuda_trace_poisoned(context.get()) == 1, "launch failure did not poison context");
475
+ REQUIRE(palw_cuda_trace_count(context.get()) == 0U, "failed launch reserved records");
476
+ REQUIRE(palw_cuda_trace_last_cuda_error(context.get()) != 0, "poison lost CUDA error");
477
+ REQUIRE_STATUS(launch_gemm(context.get(), stream.get(), output.get(), 0), PALW_CUDA_TRACE_POISONED);
478
+ REQUIRE_STATUS(
479
+ launch_attention(context.get(), stream.get(), output.get(), 0),
480
+ PALW_CUDA_TRACE_POISONED);
481
+ REQUIRE_STATUS(palw_cuda_trace_reset(context.get()), PALW_CUDA_TRACE_POISONED);
482
+ REQUIRE_STATUS(
483
+ palw_cuda_trace_copy_async(
484
+ context.get(), records.get(), records.capacity(), stream.get()),
485
+ PALW_CUDA_TRACE_POISONED);
486
+ REQUIRE_STATUS(palw_cuda_trace_synchronize(context.get(), stream.get()), PALW_CUDA_TRACE_POISONED);
487
+
488
+ REQUIRE(recovered_context.create(4), "failed to recreate after poison");
489
+ REQUIRE_STATUS(
490
+ launch_gemm(
491
+ recovered_context.get(), stream.get(), output.get(), 0, PALW_CUDA_TRACE_PREFILL, 0,
492
+ PALW_CUDA_TRACE_DTYPE_FP32, PALW_CUDA_TRACE_QUANTIZATION_Q4_K_M,
493
+ 4, 6, 6, 6, 2, 3, 2, 2, 4),
494
+ PALW_CUDA_TRACE_OK);
495
+ REQUIRE_STATUS(
496
+ palw_cuda_trace_synchronize(recovered_context.get(), stream.get()),
497
+ PALW_CUDA_TRACE_OK);
498
+
499
+ std::puts("PALW experimental CUDA GEMM/attention transport device gate: ok");
500
+ return true;
501
+ }
502
+
503
+ } // namespace
504
+
505
+ int main() {
506
+ int device_count = 0;
507
+ const cudaError_t count_status = cudaGetDeviceCount(&device_count);
508
+ if (count_status == cudaErrorNoDevice || count_status == cudaErrorInsufficientDriver ||
509
+ (count_status == cudaSuccess && device_count == 0)) {
510
+ std::fprintf(stderr, "SKIP: CUDA trace device gate requires an NVIDIA CUDA device\n");
511
+ return 77;
512
+ }
513
+ if (count_status != cudaSuccess) {
514
+ std::fprintf(stderr, "cudaGetDeviceCount failed: %s\n", cudaGetErrorString(count_status));
515
+ return 1;
516
+ }
517
+ if (cudaSetDevice(0) != cudaSuccess) {
518
+ std::fprintf(stderr, "cudaSetDevice(0) failed\n");
519
+ return 1;
520
+ }
521
+ return run_device_tests() ? 0 : 1;
522
+ }