Qwen3.6-35B-A3B-PALW-runtime / docs /receipt-implementation-qwen36.md
MISAKA-BTC
sync to MisakaLM3-8B a56c808: search replay, worker, and a build that can start
31ad728
|
Raw
History Blame Contribute Delete
40.8 kB
# MISAKA PALW Receipt 実装仕様 — Qwen3.6-35B-A3B (hybrid MoE)
本書は、対象モデルを dense Qwen3-8B から hybrid **Qwen3.6-35B-A3B**
(`huihui_ai/Qwen3.6-abliterated:35b-Claude-4.7`、abliterated) へ移行した後の
`ComputeReceiptV1` 発行・検証パイプラインの実装仕様である。記述は現行 Rust/C++
ソースを正本とし、実装と本書が一致しない場合は Receipt を発行しない
([`protocol-v1.md`](protocol-v1.md) と同じ原則)。本書に無い production 承認・決済連携・
attestation を Receipt から推論してはならない。
対象モデルは linear-attention(state-space / gated-delta-net)層と mixture-of-experts
層を組み合わせた hybrid 構成であり、dense Qwen3-8B 用の厳格な canonical operation
mapping では表現できない演算を含む。そのため本移行では **(1)** pinned llama.cpp への
qwen35moe loader/graph 互換修正、**(2)** dense vocabulary に対応の無い演算を output-element
数で committ する generic operation と CU ルールセット v2、**(3)** profile 駆動の hybrid
adapter/manifest、を追加した。移行完了後、dense Qwen3-8B 経路(profile / manifest builder /
constants / tests)は撤去され、Qwen3.6-35B-A3B が唯一の対象モデルとなった。
行番号 anchor は執筆時点のものであり、正本はソースである。
> **compute-gate track 更新(2026-07-19、実機検証済み)。** 上記 (2) の「generic operation + CU
> ルールセット v2」は**後続の compute-gate track で置換された**。現行 receipt は **(M1)** CU を
> semantic ルールセット v3 で canonical commit(`canonical_compute_units = 41692`)、**(M3)** generic
> 演算を廃止し全 MoE/SSM op を忠実な canonical 演算(`ExpertGemm`/`ExpertRoute`/`SsmConv`/
> `GatedDeltaNet`/`L2Norm`/`Reduction`/`Elementwise`)へ写像、**(M2)** canonical semantic schedule を
> 再生成・commit、**(M4/#6)** observer が実 MoE routing(`ffn_moe_topk`)を捕捉し `expert_route_root`
> を封緘 bundle へ commit(observer schema v2)、**(M5/#5)** ggml-metal を計装して各 GEMM を実 Metal
> kernel dispatch + launch geometry へ束縛し `trace_evidence=metal_kernel` を commit(graph-fallback
> から昇格、実機で 200/200・411/411 検証)。§0–§2 の一部記述(CU v2 / generic / SCHEMA_VERSION 1 /
> MUL_MAT_ID=metadata / graph_fallback)は旧版で、現行の正確な値は §10・§11 と
> [`receipt-review-remediation.md`](receipt-review-remediation.md) を参照。**6 つの compute gate は
> 全て実機検証済み。** Metal の kernel-level trace は launch-geometry 束縛であり CUDA V3 相当の
> intra-kernel accumulator proof ではない(honest labeling、mint は依然不適格)。
---
## 0. 全体アーキテクチャとデータフロー
三層構成:
1. `vendor/llama.cpp/`(commit 固定 + PALW patch): 推論ランタイムと read-only graph observer
`llama-palw-observer`
2. `runtime-palw/`(Rust): adapter、canonical CU、schedule、commitment、manifest、receipt
builder/verifier、verification bundle、schema-v4 SQLite。
3. `config/` / `patches/`: 固定 artifact pin、model profile pin、llama.cpp patch。
Receipt 発行(`palw-metal-receipt`)のデータフロー:
```
prompt(stdin)
├─ build_qwen36_35b_metal_manifest ─────────► RuntimeManifest(MoE topology, CU v3 semantic)
├─ llama-tokenize ──────────────────────────► prompt_token_ids
├─ llama-palw-observer --observer sketch ───► JSONL(header/event*/result)
│ │(read-only graph callback、sketch)
│ ▼
│ qwen_adapter(HybridQwen36A3B)
│ │ header 検証 + op→ComputeOperation 写像 + GEMM sketch
│ ▼
│ RuntimeObserver → ExecutionEvidence(schedule + GEMM trace + CU total, ruleset=v3 semantic)
├─ build_signed_receipt ────────────────────► ComputeReceiptV1(署名)
├─ verify_stateless(cu_rules=v3) ───────────► 自己検証
├─ seal_verification_bundle(XChaCha20) ─────► <id>.palw.bundle
├─ StateStore(schema v4).accept ────────────► palw-state.sqlite3
└─ 書き出し: <id>.palw / <id>.json / <id>.palw.bundle / <id>.complete
```
別 process 検証(`palw-verify-bundle`)は artifact set・完了 marker を検査し、bundle を復号・
再検証(`verify_bundle_and_restore`)して `status=local_restored` /
`trust_scope=embedded_local_snapshot` を出力する。
---
## 1. 対象モデルと固定 artifact
正本: [`config/runtime-pins.sh`](../config/runtime-pins.sh)(公開識別子のみ、末尾で全て `readonly`)。
### 1.1 推論 GGUF(Ollama registry blob)
| 変数 | 値 |
|---|---|
| `PALW_GGUF_REGISTRY` | `registry.ollama.ai` |
| `PALW_GGUF_REPO_ID` | `huihui_ai/Qwen3.6-abliterated` |
| `PALW_GGUF_OLLAMA_TAG` | `35b-Claude-4.7` |
| `PALW_GGUF_REVISION` = `PALW_GGUF_SHA256` | `1dc494614bee8a3bc00e79fe5a49da0fc1c36b3b118c4156e223e98e5a0a671b` |
| `PALW_GGUF_FILENAME` | `Qwen3.6-abliterated-35b-Claude-4.7-Q4_K_M.gguf` |
| `PALW_GGUF_SIZE` | `23938321728`(bytes) |
Ollama registry の blob digest は GGUF 本体の SHA-256 に等しいため `revision == sha256`
content 検証だけで pin 全体の照合になる。
### 1.2 base metadata(Hugging Face、7 files)
`PALW_BASE_REPO_ID = huihui-ai/Huihui-Qwen3.6-35B-A3B-Claude-4.7-Opus-abliterated`
`PALW_BASE_REVISION = ac18882735d037f6074a7630eb68d85db8234c25`
files: `README.md``chat_template.jinja``config.json``model.safetensors.index.json`
`processor_config.json``tokenizer.json``tokenizer_config.json`
sha256 は [`config/qwen3.6-35b-a3b-claude-4.7-base-metadata.sha256`](../config/qwen3.6-35b-a3b-claude-4.7-base-metadata.sha256)
および profile pin の `base_artifact.files[]` と一致する。
### 1.3 llama.cpp
`PALW_LLAMA_COMMIT = 12127defda4f41b7679cb2477a4b0d65ee6a0c8f`(build 10015)、
patch = [`patches/llama.cpp-palw-observer.patch`](../patches/llama.cpp-palw-observer.patch)、
`PALW_LLAMA_PATCH_SHA256 = d155a88b7c11ee74f48011760cb1a37773a694c8cab28258ee108c85e2f9e02c`
Metal build は `-DGGML_METAL=ON -DGGML_CUDA=OFF``arm64`、target
`llama-cli/llama-server/llama-tokenize/llama-palw-observer`
### 1.4 Ollama download 経路(`install.sh :: download_gguf_if_needed`)
1. `gguf_content_matches`(存在 + size + sha256)が成立すれば再利用。
2. mismatch する既存 file は上書きせず die。
3. URL = `https://$PALW_GGUF_REGISTRY/v2/$PALW_GGUF_REPO_ID/blobs/sha256:$PALW_GGUF_REVISION`
(OCI/Docker registry の blob-by-digest endpoint)。
4. `curl -fSL -C -`(再開可能)で `.partial` に取得。
5. size と sha256 を照合してから `mv` で atomic に確定。
6. base metadata は従来通り HF(`hf_snapshot_download.py`、token を strip し Xet を無効化)。
---
## 2. 決定論的実行と native observer
正本: `vendor/llama.cpp/tools/palw-observer/palw-observer.cpp`(以下 OBS)。単一リクエストの
非対話 runner で、public な `llama`/`ggml` API のみ使用。versioned JSONL を stdout に、
llama/ggml のログを stderr に書く。
### 2.1 強制される決定論的実行ポリシー
`n_ctx = PALW_CONTEXT_TOKENS = 4096``n_batch = n_ubatch = 1``n_seq_max = 1`
`n_threads = n_threads_batch = 1`、greedy sampler、`flash_attn = DISABLED`
`type_k = type_v = F16``split_mode = NONE``use_mmap = true`。context 初期化後に
実 context を読み直し、この不変条件を満たさなければ exit 3。prompt は `--prompt-stdin`
専用 pipe で渡し(argv に置かない)、prefill/decode とも 1 token ずつ `llama_batch_get_one`
で評価する。`prompt_tokens + n_predict > 4096` は context-shift せず失敗。
### 2.2 model profile gate(`validate_qwen36_35b_a3b_profile`)
model load 直後に、`general.architecture == "qwen35moe"``n_layer == 40``n_embd == 2048`
`n_vocab == 248320`、decoder-only(encoder 無し)のみ受理。不一致は header/result を一切
emit せず exit 3。
### 2.3 JSONL プロトコル
`SCHEMA_NAME = "misaka.palw.runtime_observer"``SCHEMA_VERSION = 2`(route record 追加)。1 実行は
**header 1****event 0..N****result 1**。各行は個別に flush。
- **header**: `observer`(off/graph/sketch)、`trace_variant``cuda_kernel_trace:false`
`model{path,description,tensor_size_bytes,parameter_count,file_type,n_ctx_train,n_embd,
n_layer,n_head,n_head_kv,n_vocab,rope_type,rope_freq_scale_train,metadata[]}`、
`runtime{ggml_version,ggml_commit,system_info,supports_gpu_offload,requested_gpu_layers,
devices[]}`、`execution_policy{...上記決定論ポリシー...}`、
`observation_policy{read_only:true, graph_metadata_stage:"ask", sketch_bits:256,
sketch_probe:"gemm_output_contiguous_prefix_64", raw_activation_values_published:false,
tile_variant:"graph_fallback_logical_prefix_v1", kernel_trace_claim:"none"}`。
- **event**: `event_seq`(単調増加、最終値 = result の `event_count`)、`phase`
(prefill/decode)、`phase_step``stage`(ask_metadata / post_compute_sketch)、`layer`
(名前から導出、無ければ null)、`categories[]`、`tensor{name,op,type,shape[4],n_bytes}`、
`sources[]`。MUL_MAT には `gemm{variant:"ggml_graph_op_v1",m,n,k,batch_shape}`。sketch
時のみ `sketch{}`/`tile{}`/`kernel_trace{}`。
- **result**: `status``stop_reason`(n_predict/eog/…)、`prompt_token_ids[]`、
`generated_token_ids[]`、`output_bytes[]`(`--emit-output-bytes` 時のみ非空)、
`output_n_bytes``event_count`
### 2.4 observer モードと sketch scheme
- `off`: callback 無し、event 0。
- `graph`: 各非空 valid node に対し `ask_metadata` を 1 件 emit。tensor data は一切読まない。
- `sketch`: 非 MUL_MAT node は `ask_metadata`。`MUL_MAT` node のみ post-compute で
`ggml_backend_tensor_get` により先頭最大 64 要素を読み、**sign/bucket sketch** を採取して
`post_compute_sketch` を emit。
sketch(`sign_bucket_256_v1`): 各要素を 1 nibble(bit3 = 符号、bit0..2 = 3-bit 絶対値
bucket)にし、64 nibble = **256 bit**。bucket 境界は `0, 2⁻⁸, 2⁻⁴, 2⁻², 1, 4, 16, ∞`。生の
活性値は決して serialize しない。`kernel_trace{available:false, backend:"none",
claim:"not_a_cuda_kernel_trace"}` を常に付し、graph 観測を CUDA kernel 証拠へ昇格しない。
### 2.5 observer 側の hybrid 対応(3 点)
1. **`is_gemm` を `GGML_OP_MUL_MAT` のみに限定**。`GGML_OP_MUL_MAT_ID`(indirect expert
GEMM)は sketch せず通常の metadata node として emit する。
2. **0-element(recurrent state cache)tensor を skip**。gated-delta-net / SSM 層は初期状態が
空の state cache を gather し、合法な 0-element node を生む。これは compute を伴わないため
error にせず skip。
3. **`validate_tensor` が空 tensor を許容**(name/type/op の範囲検査後に短絡)。
### 2.6 qwen35moe.cpp loader/graph 修正(5 点)
pinned commit `12127def` の `src/models/qwen35moe.cpp` は本モデルを load/run できないため、
PALW comment 付きで以下を修正(observer patch に同梱):
1. **3-section mrope zero-pad**: `rope.dimension_sections` を可変配列として読み、size 3 or 4 を
許容して zero-fill+copy。新しい HF→GGUF 変換の `[t,h,w]`(末尾 0 省略)を受理。
2. **`ssm_dt` bias の suffix 両対応**: `blk.N.ssm_dt.bias` を `TENSOR_NOT_REQUIRED` で試し、
無ければ suffix 無し `blk.N.ssm_dt` を required で load。
3. **KV 射影幅に `n_embd_k_gqa_max()`**: `LLAMA_LOAD_LOCALS` は layer 0 から `n_embd_k/v_gqa`
を導出するが、layer 0 は linear-attention 層で `n_head_kv==0`。full-attention trunk 層と
MTP 層の tensor 生成で per-layer 最大値を使う。
4. **sibling tensor(`v.*` / `mtp.*`)の計上**: Ollama 同梱 GGUF は vision tower と(MTP 未
有効時)MTP sub-model を同梱する。text runtime はこれらを構築しないため、該当 prefix の
tensor 分だけ `n_created`/`size_data` を調整し `done_getting_tensors` を通す。存在する
tensor のみ 1 回ずつ計上するため、text tensor の欠落は依然として検出される。
5. **`build_layer_attn` の per-layer `n_head(il)`/`n_head_kv(il)`**: graph base は layer 0 から
head 数を初期化するため、full-attention の Q/K/V reshape と RoPE を per-layer 値で shadow。
---
## 3. Rust adapter — hybrid 経路
正本: `runtime-palw/src/qwen_adapter.rs`。`AdapterProfile { HybridQwen36A3B }`(唯一の profile)
を `NativeParseConfig`/`NativeRunConfig` の `profile` field で選択し、
`parse_native_jsonl_with_stderr` が header 検証 / event 変換 / vocab 上限を hybrid 経路で処理する。
旧 dense 経路は撤去済み。
### 3.1 hybrid 定数と識別子
`QWEN36_35B_LAYERS=40`、`QWEN36_35B_VOCAB=248320`、`QWEN36_35B_EMBED=2048`、
`QWEN36_35B_CONTEXT=262144`、`QWEN36_35B_PARAMETERS=35_951_822_704`、
`QWEN36_ARCHITECTURE="qwen35moe"`、共有の `Q4_K_M_FILE_TYPE=15`、`QWEN_RUNTIME_CONTEXT=4096`。
`qwen36_adapter_mapping_id_v1()` は domain `"qwen36-native-observer-mapping/v1"` の
`domain_hash`。payload は各 op の写像を列挙し `cu-ruleset=v2;graph-fallback-only` を含む。dense
の `"qwen-native-observer-mapping/v1"`(`soft_max=attention`)とは別 hash。
### 3.2 header 検証(`validate_header_hybrid`)
deterministic execution policy と observation policy は **dense と同一**の厳格さで検証する。
model-shape だけを MoE 向けに一般化する:
- `parameter_count == 35_951_822_704`、`file_type == 15`、`n_ctx_train == 262144`、
`n_embd == 2048`、`n_layer == 40`、`n_vocab == 248320`、`rope_freq_scale_train == 1.0`。
- **dense と違い `n_head`/`n_head_kv`/`rope_type` は pin しない**(MoE は per-layer で可変、
layer-0 KV-head を制約しない)。
- 必須 metadata: `general.architecture=qwen35moe`、`general.file_type=15`、
`general.quantization_version=2`、`qwen35moe.context_length=262144`、
`qwen35moe.embedding_length=2048`、`qwen35moe.block_count=40`、
`qwen35moe.expert_count=256`、`qwen35moe.expert_used_count=8`。dense と逆に **expert
metadata を要求**する(dense は expert metadata を拒否)。
- graph/sketch 時は `supports_gpu_offload && requested_gpu_layers==999 && GPU device 存在`。
### 3.3 op → canonical operation 写像(`convert_event_hybrid`)
各 ggml op を canonical `ComputeOperation` へ写像する。dense と異なり、正確な canonical
対応がある演算はそれへ、対応の無い演算は `Generic{op_class, elements}` へ写す。fail-closed。
| ggml op | canonical operation |
|---|---|
| `MUL_MAT` | `Gemm`(`convert_gemm_hybrid`、sketch 採取) |
| `RMS_NORM` | `RmsNorm { elements=shape[0], batch=Πshape[1..] }` |
| `ROPE` | `Rotary { head_dim=shape[0], heads=shape[1], tokens=Πshape[2..] }` |
| `SOFT_MAX` | `Softmax { elements=Πshape }`(dense は Attention 再構成) |
| `GLU` | `Silu{elements}` + `ElementwiseMultiply{elements}` |
| `MUL` | `ElementwiseMultiply { elements }` |
| `ADD` | `ElementwiseAdd { elements }` |
| `GET_ROWS` | `EmbeddingLookup { elements }` |
| `SET_ROWS` | `KvCacheWrite { bytes = tensor.n_bytes }` |
| `CONT` \| `CPY` | `TensorCopy { bytes = tensor.n_bytes }` |
| `VIEW` \| `RESHAPE` \| `PERMUTE` \| `TRANSPOSE` | layout-only(schedule に載せない) |
| その他 | `Generic { op_class=hybrid_generic_op_class(op), elements=Πshape }`。未列挙は拒否 |
`hybrid_generic_op_class`(不変な op→u32 表): `MUL_MAT_ID=1`、`UNARY=2`、`SCALE=3`、
`L2_NORM=4`、`SUM_ROWS=5`、`DIV=6`、`CLAMP=7`、`ARGSORT=8`、`SSM_CONV=9`、
`GATED_DELTA_NET=10`、`CONCAT=11`。これ以外は `None` → `InvalidEvent`(fail-closed)。
### 3.4 GEMM 変換(`convert_gemm_hybrid`)
`gemm{}` metadata の相互整合(`m==left.shape[1]`、`n==right.shape[1]`、`k==left.shape[0]`、
`left.shape[0]==right.shape[0]`、output shape 一致)を検証する。dense と異なり **固定 geometry
や dtype allowlist は課さない**。quantization は `left.kind` から `q4_K→Q4KM`、`q6_K→Q6K`、
その他→`None`。sketch 時は `validate_graph_fallback_sketch`(sketch/tile/kernel_trace の値を
厳格検証)後、64 hex を 4 lane の big-endian `i64` へ復元し `on_gemm_group` で trace に記録。
kernel_id domain は `"qwen36-graph-fallback-probe/v1"`。
### 3.5 GPU offload marker とプライバシ
`scan_stderr_markers` は `"offloaded N/N layers to gpu"` を **N が正で左右一致なら任意の N** で
検出する(dense 37/37、hybrid 41/41 を model 非依存で受理)。不一致は
`IncompleteGpuOffload`。prompt は `OsStr` の stdin のみ、error payload は `&'static str`/数値
のみ、`QwenObserverOutput``Debug` 未実装、`zeroize_private_material` が prompt/生成
token/QA bytes を zeroize。
---
## 4. 正準演算語彙と CU ルールセット
正本: `runtime-palw/src/compute_units.rs`
### 4.1 `ComputeOperation`(canonical serialize discriminant)
`0 Gemm(GemmShape)``1 Attention``2 LayerNorm``3 RmsNorm``4 Rotary``5 ExpertRoute`
`6 KvCacheRead``7 KvCacheWrite``8 Silu``9 ElementwiseMultiply``10 Softmax`
`11 ElementwiseAdd``12 TensorCopy``13 EmbeddingLookup`**`14 Generic{op_class:u32,
elements:u64}`**(本移行で追加)。0..5 は `u32` 次元、6..13 は単一 `u64`。追加は additive で
既存 variant の byte は不変。
`Generic` は「dense に cost 規則の無い演算(gated-delta-net、SSM conv、MoE routing 等)を
意味を歪めず、output 要素数で忠実に committ する」ための variant。`op_class` は演算種別の
安定 ID、cost は output 要素数のみに依存する。**v2 のみが pricing し、v1 は拒否する**ため
既存 dense receipt と ruleset identity は不変。
### 4.2 CU ルールセット v1/v2
`CU_RULESET_VERSION_V1=1`、`CU_RULESET_VERSION_V2=2`。`ruleset_id()` は
`domain_hash("cu-ruleset/vX", X, [payload])`。payload の唯一の差分は v2 が `ceil;min1` の前に
**`generic=2/4096;`** を挿入する点(domain も `/v2`)。よって
`v1().ruleset_id() != v2().ruleset_id()``matching_ruleset_id(&Hash32)``[v1(),v2()]` から
一致する ruleset を返す(本移行で追加、bundle 経路が使用)。
cost 式(`cost()``scaled_cost = max(1, ceil(work·units/reference))`、全て checked):
| op | work | reference | units |
|---|---|---|---|
| `Gemm` | m·n·k·batch | 4096³ | 120 |
| `Attention` | q·kv·heads·head_dim·batch | 4096·4096·32·128 | 80 |
| `LayerNorm`/`RmsNorm` | elements·batch | 4096 | 8 |
| `Rotary` | tokens·heads·head_dim | 4096 | 4 |
| `ExpertRoute` | tokens·experts·top_k | 4096 | 16 |
| `KvCacheRead`/`Write`/`TensorCopy` | bytes | 1 MiB | 1 |
| `Silu`/`ElementwiseMultiply`/`ElementwiseAdd` | elements | 4096 | 2 |
| `Softmax` | elements | 4096 | 4 |
| `EmbeddingLookup` | elements | 4096 | 1 |
| **`Generic`** | elements | 4096 | 2 (**v2 限定**、v1 は `UnsupportedOperation`) |
`ComputeUnitCounter.record` は cost を checked-add し、overflow 時は state を変えず
`CostError::Overflow`(fail-closed)。
---
## 5. Model profile pin と RuntimeManifest 構築
正本: `runtime-palw/src/qwen_profile.rs`、`runtime-palw/src/manifest.rs`、
[`config/qwen3.6-35b-a3b-claude-4.7-profile.json`](../config/qwen3.6-35b-a3b-claude-4.7-profile.json)。
### 5.1 profile pin(schema v2)
`schema = "misaka.palw.model-profile-pin.v2"`
`profile_name = "Qwen3.6-35B-A3B-Claude-4.7-Opus-abliterated-Q4_K_M-Metal-arm64"`
`model{}` は MoE の全 shape(architecture `Qwen3_5MoeForConditionalGeneration`、model_type
`qwen3_5_moe`、gguf_architecture `qwen35moe`、hidden 2048、heads 16、kv 2、layers 40、
head_dim 256、intermediate 512、expert_count 256、experts_per_token 8、rope_theta 10000000、
vocab 248320、max_pos 262144、bfloat16、Q4_K_M、ほか linear_* 等)を持つ。`base_artifact`
は 7 files(各 sha256)、`inference_artifact` は Ollama repo/tag/**64-hex blob revision**/bytes/
sha256、`runtime` は commit と cmake_cache。deserialize struct は serde `deny_unknown_fields`
(`HybridProfilePin`/`HybridModelPin`/`HybridInferenceArtifactPin`。dense との差は `tag` field)。
### 5.2 `validate_hybrid_pin`
schema/profile_name 一致、model 全 shape 一致、`download_scope=="metadata-only"`
`supported_profile=="metal-arm64"``targets``llama-palw-observer``commit.len()==40`
`base.revision.len()==40`**`inference.revision.len()==64`**(Ollama blob digest)、
`inference.bytes!=0`。metadata files は 7 件で各 sha256 を streaming 照合
(`verify_base_metadata_hybrid`)。
### 5.3 `build_qwen36_35b_metal_manifest`
host(arm64、8 field 非空)と environment(`LANG`/`LC_ALL` のみ)を検証し、GGUF の size/sha256、
tokenizer(`tokenizer.json`+`tokenizer_config.json` の 2 件)を artifact 化する。以下の digest を
`domain_hash` で計算し RuntimeManifest に committ する(dense と domain string が異なる主要点):
- `chat_template_digest`(`chat-template/v1`): **`chat_template.jinja` file bytes**
(dense は tokenizer_config 内の文字列)。
- `special_tokens_digest`(`special-token-semantics/v1`): tokenizer_config + config.json
(generation は `Value::Null`)。
- `kernel_graph_id`(`qwen36-35b-llama-graph/v1`): commit + `qwen36_adapter_mapping_id_v1()`
+ `ggml_sched_ask_metadata_v1` + prefill/decode 直列。
- `kernel_algorithm_digest`(`kernel-algorithm-policy/v1`): 末尾に `;moe-hybrid;cu-ruleset=v2`。
- ほか `loaded_libraries_digest`、`build_flags_digest`、`dirty_patch_digest`、
`environment_allowlist_digest`、`runtime_device_digest`、`runtime_program_digest`、
`build_provenance_digest`。
`ModelProfile` は **topology = MixtureOfExperts**、`kv_heads=2`、**`head_dim=256`(hidden/heads
= 2048/16 = 128 とは decouple)**、`rope="Qwen3.5-iMRoPE"`、`native_context_tokens=262144`、
`vocabulary=248320`。`RuntimeClass` は Q4_K_M、flash-attn off、`context_size=4096`、batch=1。
`RuntimeManifest.cu_ruleset_id = ComputeUnitRules::v2().ruleset_id()`。
### 5.4 manifest validator の緩和(hybrid を受理する 2 点)
- `ModelProfile::validate` は旧来の `head_dim == hidden/heads` 検査を**削除**した。head_dim を
独立 field として committ し cross-check しないため、`head_dim=256` と `2048/16=128` が
共存できる。`hidden % heads == 0`(2048%16)、`heads % kv == 0`(16%2)は維持。
- `RuntimeManifest::validate` は `cu_ruleset_id` が **v1 または v2** の ruleset_id なら受理する。
---
## 6. Receipt body・commitment・署名
正本: `runtime-palw/src/receipt.rs`、`runtime-palw/src/builder.rs`、`runtime-palw/src/observer.rs`。
### 6.1 `ComputeReceiptV1`(署名される canonical wire 順)
30 field を固定順で encode し、その byte 列が全 digest(`signing_digest`/`body_id`/
`receipt_id`)の入力になる。主要 field: `receipt_version(=1)`、`network_id`、
`request_commitment`、`scheduler_job_id`、`signed_assignment_id`、`replica_slot`、
`model_profile_id`、`runtime_class_id`、`runtime_manifest_hash`、`shape_profile_id`、
**`cu_ruleset_id = evidence.cu_ruleset_id()`**、`trace_scheme_id`、`trace_evidence`、
`operation_schedule_commitment`、`schedule_event_count`、`canonical_compute_units`、
`prefill_tokens`、`decode_tokens`、`output_commitment`、`gemm_trace_root`、`trace_event_count`、
`owner_commitment`、`worker_credential_id`、`job_nullifier`、`execution_nullifier`、`job_class`、
`evidence_level`、`timestamp`、`issued_epoch`、`expires_epoch`。
`validate_structure` は署名前後で 17 digest の非零、`prefill_tokens!=0`、
`issued<=expires`、job_class ごとの replica_slot 範囲、evidence_level ごとの count 整合
(GemmTraced は schedule/trace/CU が全て非零かつ `trace_evidence!=Absent`)を検査する。
### 6.2 `build_signed_receipt`
`manifest.validate`、CUDA KernelSketch 拒否、scheduler 署名(request+assignment)検証、worker
credential binding、request constraints と manifest ID の一致、evidence↔shape/job binding、
prompt opening と `prefill_tokens` 一致、output count 一致、を検査後に commitment
(`commit_prompt_tokens`/`commit_output`/`commit_owner`/`derive_job_nullifier`/
`derive_execution_nullifier`)を計算し、body を Ed25519 署名(`signing_digest` は network-id
salt 付き canonical bytes)。builder は `cu_ruleset_id` を **evidence の値そのまま** committ する
(独自に ruleset を再導出しない)。
### 6.3 evidence 生成(`RuntimeObserver` → `ExecutionEvidence`)
observer は `job_nullifier`/`shape_profile_id`/`ComputeUnitRules`/`EvidenceLevel` に束縛される。
`schedule = OperationSchedule::new(..., rules.ruleset_id())`、trace は GemmTraced 時のみ生成。
状態機械は `AwaitingPrefill→Prefill→Decode{step}`、decode step は厳密連番、任意の event error で
恒久 poison。`finalize_with_generated_tokens``generated == decode_tokens+1`(先頭 token は
prefill logits から sample)を要求。GemmTraced 不変条件として **schedule の GEMM 数 ==
trace group 数**`ExecutionEvidence.cu_ruleset_id = counter.rules().ruleset_id()`(本移行では
v2)がそのまま receipt へ流れる。
---
## 7. Stateless 検証(`verify_stateless`)
正本: `runtime-palw/src/verifier.rs`。`VerificationContext { network_id, current_epoch,
manifest, cu_rules, signer_registry, assignment_authorizations }` を取り、順に:
1. `validate_structure`、network/epoch。
2. assignment 解決と全 field binding、assignment policy(`required_evidence_level==evidence_level`)。
3. signer 解決、owner/worker commitment、**Ed25519 署名**(weak-key 拒否 + `verify_strict`)。
4. `manifest.validate`、CUDA KernelSketch 拒否。
5. `model_profile_id`/`runtime_class_id`/`runtime_manifest_hash`/`shape_profile_id` を manifest
から独立再計算して照合。
6. **CU-ruleset triple-bind**: `body.cu_ruleset_id == context.cu_rules.ruleset_id()` **かつ**
`== manifest.cu_ruleset_id`(不一致は `CuRulesetMismatch`)。本移行では三者とも v2。
7. `trace_scheme_id` bind、`job_nullifier`/`execution_nullifier` の再導出照合、`verify_shape`
8. `verify_execution_evidence`: evidence metadata・schedule integrity/commitment 照合後、
**`context.cu_rules` で schedule を最初から再 pricing** し `canonical_compute_units` を
照合(claim を信用しない)。per-entry で layer 範囲、dense topology の expert-route 拒否、
decode phase 順序を検査。GemmTraced は `verify_trace`(trace binding、capability 一致、
GEMM 数 == trace group 数、per-event の schedule 対応)。
9. output nonce / prompt opening / output opening / output count。
hybrid では topology が MixtureOfExperts のため expert-route の dense 拒否は発火しない(なお
本 adapter は `MUL_MAT_ID` を `Generic` に写すので ExpertRoute op 自体を生成しない)。
---
## 8. Verification bundle と ruleset 選択の 3 修正
正本: `runtime-palw/src/verification_bundle.rs`。
### 8.1 `seal_verification_bundle`
owner opening を照合し、**封印前に receipt を完全に再 stateless 検証**する(state-store は
変更しない)。公開部 `BundlePublicV1`(receipt_binding、receipt_id、verification_epoch、
scheduler-key record、`manifest.canonical_bytes()`、`PortableEvidenceV1`)は認証済み cleartext。
秘密部 `BundlePrivateV1`(署名済み request/assignment、signer record、output opening =
output_nonce + prompt/output token IDs、owner salt)は **XChaCha20-Poly1305** で AEAD 暗号化
(AAD で receipt_binding/public_digest/nonce/public_bytes を束縛、AEAD 鍵は audit key の
`domain_hash` 派生で raw key を直接使わない)。`bundle_id` は完全な暗号化 envelope 全体の
`domain_hash`。
### 8.2 CU ルールセット選択の 3 修正(v2 対応)
| # | 位置 | 修正 |
|---|---|---|
| 1 | seal 経路 | `cu_rules = ComputeUnitRules::matching_ruleset_id(&context.manifest.cu_ruleset_id)`(旧: v1 固定) |
| 2 | `verify_bundle_stateless_inner` | `matching_ruleset_id(&bundle.public.manifest.cu_ruleset_id)`(旧: v1 固定) |
| 3 | `PortableEvidenceV1::encode_canonical` | ruleset **version** を evidence に合わせて書く(`matching_ruleset_id(evidence.cu_ruleset_id()).map_or(0, version)`。旧: v1 固定)。decode は `for_version` で読む |
これらが無いと、v2 evidence が bundle 内で v1 として round-trip し `CuRulesetMismatch` になる。
併せて `manifest.rs` の validate が v1|v2 を受理し、`matching_ruleset_id` を追加した。producing CLI
`ComputeUnitRules::v2()` を bind する。
### 8.3 portable evidence の round-trip
encode は version・level・prefill/decode・**ruleset version**・job_nullifier・shape_profile_id・
schedule entries・trace groups・claimed CU・claimed ruleset を書く。decode は `RuntimeObserver`
で schedule/trace/CU を **再導出**(serialize 済み total を信用しない)し、再構成 evidence の
`canonical_compute_units`/`cu_ruleset_id` が claimed と一致することを要求する。bounds:
`MAX_EVIDENCE_EVENTS=250000`、`MAX_BUNDLE_BYTES=64MiB`。
---
## 9. 永続化(SQLite schema v4)と CLI 契約
### 9.1 StateStore(schema v4)
`APPLICATION_ID="PALW"`、`SCHEMA_VERSION=4`。`open` は parent dir 解決 + `SQLITE_OPEN_NOFOLLOW`、
`foreign_keys=ON`、`synchronous=FULL`、`journal_mode=WAL`、application/schema 照合、および
`sqlite_master` の **DDL fingerprint**(SHA3-256 golden 照合)。`accept` は `BEGIN IMMEDIATE` で
duplicate receipt / duplicate execution_nullifier / job-class 整合 / slot 充填を強制し、
`jobs`(PK `(network_id,job_nullifier)`、WITHOUT ROWID)と `receipts`(PK `receipt_id`、
`execution_nullifier` UNIQUE、`UNIQUE(network_id,job_nullifier,replica_slot)`、FK RESTRICT)へ
transaction で insert する。復元経路 `restore_accepted` は read-only で既存 row を byte 照合する。
### 9.2 `palw-metal-receipt`(発行 CLI)
必須: `--prompt-stdin``--audit-key-file`(**exact 32 raw bytes**、owner-only single-link
`0400`/`0600`、output dir 外)、`--output-dir`(新規/空、owner-only `0700`)。任意: `--n-predict`
(`1..=1024`、default 2)。prompt は UTF-8 非空 ≤1 MiB。run flow は §0 の通り。`canonical_source_patch`
`tools/CMakeLists.txt``src/models/qwen35moe.cpp` の modified、`tools/palw-observer/`
untracked のみを許容する(他は拒否 = fail-closed)。出力 artifact:
| file | mode | 内容 |
|---|---|---|
| `<id>.palw` | 0644 | 署名済み canonical receipt |
| `<id>.json` | 0644 | 公開 metadata(`misaka.palw.public-receipt.v2`、strict field) |
| `<id>.palw.bundle` | 0600 | XChaCha20 暗号化 bundle |
| `palw-state.sqlite3` | 0600 | schema v4 state |
| `<id>.complete` | 0644 | `misaka.palw.receipt-set.v2` 完了 marker(**最後**に fsync 付きで作成) |
### 9.3 `palw-verify-bundle`(検証 CLI)
必須: `--receipt`/`--bundle`/`--public-json`/`--audit-key-file`/`--state-db`。artifact set の
mode/owner/single-link/同一 private dir、完了 marker の binding、bounded read、`decode_strict`
`validate_artifact_names`(receipt_id は bundle 由来)、`verify_bundle_and_restore`(§8 の復号・
再検証・schema-v4 復元)、`verify_public_metadata`(公開 JSON を authenticated 値と field 単位で
照合)。正常時 `status=local_restored` / `trust_scope=embedded_local_snapshot`。この trust scope
は bundle 内 registry snapshot による continuity を示すのみで、network authority の代替ではない。
---
## 10. E2E 実測(reference receipt)
Apple M1 Max(macOS Metal 4、arm64)。observer は load 時に qwen35moe/40/2048/248320 を検証し
`offloaded 41/41 layers to GPU`。出力健全性: `The capital of France is`
(`[760,6511,314,9338,369]`)→ ` Paris, a city renowned for its iconic`
reference artifact は [`receipts/final-v7/`](../receipts/final-v7)、evidence 詳細は
[`docs/evidence/metal-hybrid-qwen36-2026-07-19.md`](evidence/metal-hybrid-qwen36-2026-07-19.md)。
公開 receipt(`misaka.palw.public-receipt.v2`)の主要値:
| field | 値 |
|---|---|
| `receipt_id` | `8e2dd34b7609d6d7aeec17bff485eb1ae4db31f66dd899a3c3a3e671656053f9` |
| `verification_bundle_id` | `f5b8a2968c4ea266b2cbbabf351a171e0fa2581984eff63362de2640fcdcf9db` |
| `cu_ruleset_id`(**v3 semantic**) | `43a5feef177b389f976361b22ac9d57da65815261282005bc78d1666a37870ce` |
| `job_class` / `evidence_level` / `trace_evidence` | `self_local` / `gemm_traced` / **`metal_kernel`** |
| `prefill_tokens` / `decode_tokens` | `5` / `2` |
| `prefill_graph_steps` / `decode_graph_steps` | `5` / `1` |
| `schedule_event_count`(= canonical_operations、commitment-only) | `13770` |
| `trace_event_count`(= gemm_events) | `2466` |
| `canonical_compute_units`(**v3 semantic、署名 commit**) | `41692` |
| `semantic_compute_units_v3`(= canonical_compute_units) | `41692` |
| `semantic_schedule.commitment` / `.expert_route_ops` | `e6fc731e…` / `80` |
| `expert_route.root` / `.route_event_count`(実捕捉) | `5e4ea70b…` / `240` |
| `mint.eligible` / `mint.weight` / `mint.mainnet_ready` | `false` / `0` / `false` |
| `mint.ineligible_reasons` | Metal kernel-launch-bound / 非 network-anchored / 非 bonded の 3 件(generic+graph-fallback は解消) |
| `model_profile_id` | `b6b83a274a889fc5dfa2044b9158111b3849f880a05eb7ebcf560d036515d472` |
| `runtime_class_id` | `8f6f536118a72be70dab2028535c3bb95e3de9a3bac0e9b81cf78677ae902a9c` |
| `artifacts.llama_commit` / `model_bytes` | `12127def…` / `23938321728` |
privacy: prompt / prompt token IDs / 生成 token IDs / opening / signing key / owner salt は公開
`.palw` / `.json` に**含まれない**(全 9 flag が非公開/暗号化)。別 process の `palw-verify-bundle`
が `status=local_restored`、`trust_scope=embedded_local_snapshot`、receipt_id/bundle_id 一致、
exit 0 で再検証済み。発行は実行ごとに OS CSPRNG で identity を生成するため receipt_id は再現しない。
---
## 11. セキュリティ境界・正直な限界
- **この Receipt は mint-grade ではない。** 現行の `evidence_level=gemm_traced` /
`trace_evidence=graph_fallback` は**強い計算証明ではない**。`runtime-palw/src/mint.rs` の
`assess_mint_eligibility` が現行 runtime の全 receipt を `eligible=false, weight=0,
class="local_self_consistent_v0_1"` と判定し、公開 JSON の `mint` ブロックに失格理由と共に
自己申告する(`palw-verify-bundle` が再構成して照合)。用途は「ローカル自己整合 receipt /
testnet 計測 / Self-Local 非報酬」に限られる。mint-grade 化の是正計画は
[`receipt-review-remediation.md`](receipt-review-remediation.md) を参照。
- Metal の graph-fallback sketch は **CUDA kernel trace ではない**。
- 単独ノードが発行する Receipt は、それだけでゼロ知識の計算証明ではない。PALW の不正耐性は
runtime/model digest、署名、k=2 replica、future audit、canary、bond/slashing の組み合わせで
成立する。
- **`Generic` 演算は廃止済み(M3)。** hybrid の全 MoE/SSM op を忠実な canonical 演算へ写像
(`MUL_MAT_ID→ExpertGemm`、`ARGSORT→ExpertRoute`、`SSM_CONV→SsmConv`、`GATED_DELTA_NET→GatedDeltaNet`、
`L2_NORM→L2Norm`、`SUM_ROWS→Reduction`、`CONCAT→TensorCopy`、`UNARY/SCALE/DIV/CLAMP→Elementwise`)。
実機 receipt の schedule は `contains_generic_operation()==false`。
- **Semantic CU v3 は canonical commitment(M1、mainnet compute measure)。** `semantic_cu.rs`
`qwen36_semantic_compute_units(prefill, generated)` は CU を **observed graph からではなく pinned
model 構造 + token 数**から算出(active-parameter FLOPs + causal attention 項、丸めは最後に 1 回)。
現行 receipt の `canonical_compute_units`**この semantic 値(41692)を `cu_ruleset_id=v3` で署名
commit** する(v2 の graph 値ではない)。fragmentation-proof / backend 非依存で、verifier は
`prefill_tokens`/`decode_tokens` から同値を再計算・照合。
- **canonical semantic schedule(M2、#7 構造半分)。** `semantic_schedule.rs` が pinned architecture +
token 数から canonical op schedule と commitment を決定的に再生成し、公開 JSON `semantic_schedule`
に束縛。verifier が独立再生成して照合。
- **実 MoE routing の捕捉(M4/#6)。** observer が `ffn_moe_topk`(I32)を post-compute で読み戻し、
per-token 選択 expert を封緘 bundle の `expert_route_root` へ commit、公開 JSON `expert_route` として
発行・再構成。実機で 240 route record を捕捉。
- **kernel-level trace(#5、M5、完了・実機検証済み)。** ggml-metal を計装して各 GEMM を実 Metal
kernel dispatch + launch geometry へ束縛(200/200・411/411、0 anomaly)。`trace_evidence=metal_kernel`
(graph-fallback から昇格)、`TraceEvidenceKind/TraceCapability::MetalKernel` を新設し verifier が照合。
**launch-geometry 束縛であり CUDA V3 相当の intra-kernel accumulator proof ではない**ため
`KernelSketch` とは別 kind で commit(over-claim しない)。mint 失格理由は「Metal kernel-launch-bound
sketch, not an intra-kernel accumulator proof」に置換(mint 不適格のまま)。accumulator-level は
Metal shader 計装が残件。
- **mainnet-readiness。** `assess_mainnet_readiness` が compute / network / hardware / model-Genesis の
全 gate を列挙し、外部 gate を Met と偽らない。現状 `mint.mainnet_ready=false`。mainnet 報酬適格性は
deployed network authority / global nullifier / epoch beacon / bond authority / 複数世代実機 /
公式モデル Genesis を要し、この repository の完了範囲外である(remediation の外部ブロック項参照)。
- 未達 gate R13/R21/R23/R24/R26/R27/R32/R35 は [`requirements.md`](requirements.md) の通り
`In progress`。本移行はこれらの production 完了を意味しない。
### 既知の drift とテスト網羅(2026-07-19 時点)
- **hybrid adapter の専用 unit test** は fixture test を追加済み(`hybrid_generic_op_class` 表、
mapping id 識別、MoE/SSM op 写像、unknown op fail-closed、q6_K trace、dense header 拒否)。
CU fragmentation invariant や公式 Transformers との differential 等の残りは
[`receipt-review-remediation.md`](receipt-review-remediation.md) の follow-up。
- `validate_hybrid_pin` は dense と異なり `base_artifact`/`inference_artifact` の repository
文字列を pin せず、deserialize する MoE/linear-attention の追加 dim(`linear_*`、
`shared_expert_intermediate_size`、`full_attention_interval`、`partial_rotary_factor_millionths`)
を committ manifest には使わない(`deny_unknown_fields` 受理のためだけに存在)。
---
## 12. 再現手順
```sh
# 1. 導入(GGUF は Ollama registry、base metadata は HF)
./scripts/install.sh
# 2. Rust gate(MSRV 1.85)
cd runtime-palw
cargo +1.85.0 fmt --all -- --check
cargo +1.85.0 clippy --locked --all-targets -- -D warnings
cargo +1.85.0 test --locked --all-targets
cargo +1.85.0 build --release --locked --bin palw-metal-receipt --bin palw-verify-bundle
cd ..
# 3. Receipt 発行(audit key は 32-byte raw、output dir 外に一度だけ作成)
OUT="receipts/manual-$(date +%Y%m%d-%H%M%S)"
AUDIT_KEY="$HOME/.config/misaka-palw/audit-keys/local-audit.key"
install -d -m 700 "$(dirname "$AUDIT_KEY")"; test ! -e "$AUDIT_KEY"
(umask 077 && /usr/bin/openssl rand 32 > "$AUDIT_KEY"); chmod 600 "$AUDIT_KEY"
runtime-palw/target/release/palw-metal-receipt \
--prompt-stdin --audit-key-file "$AUDIT_KEY" --output-dir "$OUT" --n-predict 2 \
< /path/to/private-prompt.txt
# 4. 別 process 検証
RECEIPT="$(find "$OUT" -maxdepth 1 -type f -name '*.palw' -print)"; ID="$(basename "$RECEIPT" .palw)"
runtime-palw/target/release/palw-verify-bundle \
--receipt "$OUT/$ID.palw" --bundle "$OUT/$ID.palw.bundle" \
--public-json "$OUT/$ID.json" --audit-key-file "$AUDIT_KEY" \
--state-db "$OUT/palw-state.sqlite3"
# 期待: status=local_restored / trust_scope=embedded_local_snapshot / exit 0
```
GGUF の SHA-256 を発行前後に 4 回計算するため、1 回の発行は約 5 分要する(24GB × 4)。
これは hang ではない。