Skip to content

テスト空間モデル 第 2 段階 scientific-v1 - #96

Merged
terapyon merged 30 commits into
mainfrom
docs/coverage-model-scientific-plan
Aug 30, 2026
Merged

テスト空間モデル 第 2 段階 scientific-v1#96
terapyon merged 30 commits into
mainfrom
docs/coverage-model-scientific-plan

Conversation

@terapyon

Copy link
Copy Markdown
Owner

テスト空間モデル 第 2 段階 scientific-v1

科学計算の 9 領域について、コーパスが要件のどのセルを踏んでいるかを機械が数え
、踏んでいないセルには理由を貼る
。第 1 段階(金融、#95)と同じ仕組みを、式ベ
ースのシャードへ広げた

製品のコードは 1 行も変わっていない。

git diff origin/main..HEAD -- crates/ web/src/ testdata/
→ 空

リリースしない。版数は 0.6.0 のまま。

何が出たか

データに 1 件も入力が無いセルが、最大 13 件まで開いた。いまは 0 件である。

ただし「13 → 0」の中身は 4 通りで、検証が増えたのは 1 つだけである。

閉じ方 セル 検証は増えたか
入力を足した 10 増えた
新しいシャードを作ったcombinatorics-display 1 増えた
理由を貼ったcomplex の冪は engine が拒む) 1 増えない
射影の誤りだったoverflow_near を「溢れた」に写していた) 1 増えな
い。穴ではなかった

着手前に人が気づいていた穴は Rad × 逆三角 の 1 つだけで、残りはモデルが
先に指した

「測れない」という札の裏に、穴が隠れていた

着手時、いくつかの軸に「この軸はキー列から読めない」と宣言していた。そのほ
とんどが誤りだった。

  • elementary / inverse_trig の帯 — 引数の 53% がリテラルで、読める
  • cancellation の帯 — 2,000 件中 1,100 件が両辺リテラル(818227581 + 0.0 00142) の形)。読める
  • cancellation の形 — 生成器が名前つきで選んでいるのに stratum に書いて
    いなかった。「観測できない」ではなく「記録していない」
  • complex の演算種別 — 読み方を足せば読めた

いま残る宣言は 1 つprecedence/grammar_class)で、その主張にデータで届
く番人
が付いている。

測ったら、そこから穴が出た。 ln/log10/1/x負もゼロも 1 度も渡して
いなかった
——定義域エラーの境目である。cancellation は**「桁がほとんど落
ちない引き算」を 1 件も作っていなかった**——対照が無かった。どちらも緑のま
ま、註だけが嘘だった

いまの会計

要求 78 = 被覆 73 + 除外 1 + 未達 4        データに無いセル 0
未達 4 はすべて `precedence/grammar_class`(宣言済み・番人つき)
コーパス 19 枚 33,591 件(`combinatorics-display-000.json` を新設)
棄却 25,165 件を coverage に載せている

combinatorics-display-000.json は「表を埋めるため」ではなく、組合せの誤入力
を体系的に確かめる場所がどこにも無かったから作った
errors-000.json は全領域の寄せ集め 30 件)。仕様から列挙しており、既存と形が重なるのは 8 件中 5 件。

何が守るか

  • 記録と数え直しの一致を assert する——生成器が書いた levels と、キー列から読み直した水準が食い違えば赤
  • 「読めない」と宣言した軸に番人——宣言した軸で実は読めるケースが在れば赤
  • 門は未達の種類で分ける——データに無いセルでは落とし、読めない軸では落とさない
  • モデルが穴を指せることを、判別で固定——入力を取り除けば未達に出る/含めれば出ない/他の穴は動かない
  • 切れ目を実データで固定する——overflow_near新シャードを除いた 10 枚だけで被覆されることを assert する(この番人が無いあいだ、切れ目を旧定義に戻しても全部緑だった)
  • cell_idscope の一致/除外の数と一覧の一致/理由を貼れないセルに理由
    を貼れない

走行

rust       fmt / clippy 0 / test 396          wasm  build / test 57(★ 下記)
web        typecheck / lint / vitest 375 / vite build / 検査 3 本
heavy      typecheck / lint / vitest 193      e2e   playwright 192
reference  7 段すべて(pytest 473 / testdata 再生成の差分 0)
重量級      pnpm heavy 250(赤 0)
           heavy:ui 37(押下 19,965 / 打鍵 1,279 / 指摘 0 / 46 トークン全押下)

wasm-pack test--firefox で回しており、CI の --chrome と同一ではな
(この作業台に chromedriver が無い)。

heavy/scripts/ の差分は 1 行——19 枚目のシャードを一覧に登録した行で、
出力の下限 minRate は 1 つも動いていない。

heavy:ui の予測は走行前に算術で固定したfloor(i·20.01) = 20i + floor(0.01i)i ≤ 99 でずれが 1 に届かない/足した 1 件は index 2000 で、選ばれる最
大は 1980)。4 項目とも予測どおり。

全走行の前後で、追跡下の全ファイルを git hash-object で照合している(480 / 480 一致)。この作業台で、git status が「変更なし」と言うまま golden が 1
ビット化ける事象が 3 バイトぶん起きた
ため——git statusjson.load() も、
それを見つけない。

台帳

  • heavy-INTENDED-RED.md — この枝の途中、pnpm heavy意図して赤かった(モデルがデータに無いセルを指していたため)。同じ枝の中で解けており、いまは
    閉じた記録として残してある——corpus.ts の門はいまもここを指す
  • known-flaky-tests.md — 間欠 2 件と、上記のビット化け 3 バイト(実測のバ
    イト表つき)
  • docs/corpus-measurements.md — 段 A・B・C の実測。立てた予測と、外した 4 件を機構ごと残してある
  • 設計書 §14.2a を新設coverage に増えた 4 欄の役割と、schema を 1
    のままにする理由
    (4 欄はすべて追加で、読まない実装は未達を全部「データに無いセル」と見なして安全側に倒れる)

terapyon and others added 30 commits August 30, 2026 12:17
`origin/main` は `9c87589`(PR #95)。**#94#95 は未タグ**で、版数は 0.6.0 の
ままである。

§2 の「次にやること」を書き換えた。**①赤の伝播と ②`finance-v1` の Task 5 以降は
どちらも終わっている**(前者は #94、後者は #95)。**古い台帳は嘘をつかない**
——書いた日には真だったので、**読んだ人は終わったことに気づけない。**

次は**試験空間モデルの第 2 段階(科学計算)の計画**である。**書いたら止まる**
——監視役に見せる → ユーザーの承認 → 着手、の順。**監視役に plan の代理承認
権限は無い**ことも書いた。

§3 に #94 / #95 の行を足した。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
科学計算の試験空間モデル(`scientific-v1`)の Task 分割。**設計は既に在り、
無いのは分割だけ**だった(設計書 §14・§15)。

## 着手前に測ったこと

**9 領域はすべてシャードが在る**(10 枚 / 20,001 件。金融の 5.7 倍)。
**金融の仕組みは、そのままでは使えない**:

- **被覆を数える経路は作り直し**——金融は `op` + `input`、科学計算は
  `expr` + `keys` + `mode` で、`op` も `input` も無い
- **因子表が存在しない**(金融には既に在った)
- **受け入れ門は値シャードに 1 度も掛かっていない**
- **`corpus_coverage.py` と再現性の信号はそのまま使える**(前者は金融の語が 0 件)

**要求がシャードをまたぐ**——「Deg/Rad × 三角関数」の Rad を運ぶのは 1 枚だけで、
Deg は 8 枚に散っている。**金融のモデルは 1 枚で閉じていた。**

## ★ 着手前に穴が 1 つ見つかっている

**`Rad × 逆三角関数` は、コーパス 18 枚のどこにも 1 件も無い。**
§14 は「関数種別 × 角度モード × 境界帯」を要求しているが、**その軸の半分が空**である。

## 裁定 3 つを、Task の中に埋めずに書き出した

1. **`stratum` をどうするか**(ユーザー裁定)——**推定すると分類器が 2 つになり、
   「参照実装を移植にしない」と同型の危険**を負う(**間違っていても緑**)。
   **記録させると 10 枚の golden が動く**が、**動く範囲は予測でき、事前に固定できる**。
   **推奨は後者**——前者は後から直せない
2. **被覆を数える単位**(要求がシャードをまたぐ)。**Task 1 の成果物にした**
   ——紙の上で決めず、水準を定義したあとで実データに当てて決める
3. **`rejections` を持たない 7 枚**——「無い」と「0」は別である

## 段構成

**A 土台(1〜5) → B `angle-mode` + `inverse-trig` で通す(6〜10) → C 残り 7 領域(11〜17)。**

**★ B の順序を守る**——**「モデルが `Rad × acos` を未達として名指しする」→
「それから埋める」**である。先に埋めると、**モデルが穴を見つけられることを誰も
確かめていないまま先へ進む**(番人を置いた気になる、第 1 段階で 2 回踏んだ形)。

## 第 1 段階で踏んだ 7 つを、規律として先頭に置いた

除外の理由は走った手順だけ/下限は探索と独立に数える/門は人が golden を触った
ときに効くものとして設計する/番人を足したら**既存の拒否テストがまだ自分の理由で
赤いか**を確かめる/報告書を人が目で読む段を残す/走行前に予測を固定する/
見込みには(実測前)の印。**どれも実際に踏んでから書いている。**

見込みの数字は 9 箇所すべてに **(実測前)** を付けた。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
厳格レビューの 9 件を**全部現物で当て直してから**直した。**却下は 0 件。**

## ① 裁定 1 の両側が公正でなかった(着手を止める級)

「推定=分類器が 2 つで危険/記録=分類器は 1 つ」と書いていたが、**記録も
生成器の自己申告で、中身と照合されなければ同じく緑のまま間違える。**
**落ちていた 3 つ目——記録し、中身から数え直し、一致を assert する——を
第 1 候補に置いた。** 3 案それぞれの「間違っていても緑になる道」を書いた。

**第 1 段階が実際にやっていたことも確かめ直した。** 金融は `case["input"]` から
数え、`stratum` も記録し、**両者を突き合わせる assert は 1 つも無い**(grep)。
**(c) は第 1 段階の写しではなく、1 段強い**、が正しい書き方だった。

**そして金融の「ケースから数える」は推定ではない。** `input` は構造化された
引数で、読むのは**厳密な射影**である。**`expr` の解析と同じ括りにしていたのが誤り。**

## ⑥-1 Task 8 が触る関数の記述が違った(着手を止める級)

`build_inverse_trig_shard` は **11 行の委譲**で、実体は `build_family_shard`(61 行)、
**`"mode": "Deg"` はその 738 行目**に埋まっている。Rad を足す道は 3 つあり、
**巻き込む範囲が違う**(`elementary` も同じ関数を通る/`_uses_trig` は
`("sin","cos","tan")` しか通さない/新しい builder はシャードを 1 枚増やす)。
**この分岐を Task 8 の Step 1 にした**——**決めてからでないと予測を固定できない。**

## 数え方が書いていなかったもの(③⑤)

- **段 C の順序が違っていた。** 「`def` から次の `def` まで」で数えて空行を
  含んでいた。`ast` で測り直すと `precedence 64 < associativity 69 <
  combinatorics 77`。**数え方を明記した**——**プロジェクトの Python で測る**
  (このスクリプトは 3.14 の構文を使い、**システムの 3.12 では解析できない**)
- **逆三角の件数**: ケース単位 1005/58/50、**関数単位 1031/69/59**。
  **被覆モデルには関数単位が正しい**(設計書 §9.3)。両方載せた
- **三角関数の表が逆三角も数えていた**(`asin` は `sin` を部分文字列に持つ)

## 水準の起こし方(③後半)

「既存のコーパスから起こす」と書いていたが、**それではデータに無い穴を
見つけない**——`Rad × 逆三角` が見えるのは §14 が軸を名指ししているからである。
**「生成器を弱くすれば除外が増える」と同型。** §14 の軸と仕様の境界から起こし、
**データは「空の帯」を見つけるために当てる**、に書き換えた。

## 実証が一過性だった(③前半)

Task 8 で埋めた瞬間に未達が 0 になり、**証拠が走行ログにしか残らない。**
**「Rad を取り除いた入力を与えると未達に出る」をテストに固定する**形へ変えた。

## 過大だった代替番人(④)

「全要求セルが一意に列挙される」は**重複しか赤くしない**。取りこぼしは
同じ因子表から列挙するテストには**原理的に見えない**。**何が守り、何は
守れないか**を書き分けた(守れない分は §14 との対応表を人が読む)。

## 黙って落としていた 5 件(⑥)

`id` の安定性(**採択順の連番**なので乱数列に触ると 2000 件がずれる)/数える
範囲に「10 枚の外」を含めるか/§14.3 の 4 項目目(`errors-000.json` の 30 件を
別枠で)/§15.3 の実物(`angle-mode-000.json`)/top-level の `strata`(2 枚が持つ)。

## 発注文の数字を 1 つ、写しかけて直した

「三角を運ぶ 8 枚のうち **5 枚**が 9 領域の外」と受け取ったが、**自分で数えたら
4 枚**だった(`scientific` / `typed` / `corrections` / `errors`)。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
**ユーザー裁定: 裁定 1 は (c)**——記録し、中身から数え直し、**一致を assert する**。
選ばれた理由も残した(**この計画が書いた区別がそのまま材料になった**):
金融は構造化された引数を読むだけで済んだが、**式の解析は読み違えうる**。
(c) は**意図と観測の突合**なので、**片方が間違えると赤くなる**。

**(a)(b) は消さない。** 選ばなかった理由が、あとから読む人の判断材料になる。

## Task 3 を (c) の形にした

**この段の主番人は「記録 = 解析」の assert である。** 記録を足すだけなら (b) で、
**自己申告を誰も検算しない。**

- **assert はテストではなく生成器に置く**——テストに置くと、生成器を回してから
  テストを回すまでのあいだに、**食い違った golden がディスクに載る**
- **食い違ったら生成を止める**(警告で流さない)
- **どちらが正しいかは決めてある**——**生成器の意図が事実、解析は読み**。
  **一致しなければ解析器を直す**

## 事前に固定する予測を 4 つに

どの 10 枚が動くか/ケースの中身が動くか/**`id` の集合が動くか**(第 1 段階では
完全に保たれた)/**変異の検出力が動くか**(18 種・10 種)。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Task 1。**設計書 §14.2 は 9 領域の軸を挙げているが、水準を定義していない**
——この commit が足すのはその水準である。

## 水準は仕様から起こした。データからは起こしていない

**コーパスを水準の出どころにすると、コーパスは定義上いつも満点になる。**
一次資料は 3 つ:

- **関数の集合**は `corpus_expr` を **import する**(写しを作らない)
- **定義域の帯**は `docs/numerical-policy.md` の「関数の定義域」の表
  ——`ln`/`log10` は `x > 0`、`asin`/`acos` は `−1 ≤ x ≤ 1`、`1/x` は `x ≠ 0`。
  **帯の切れ目は仕様がそこでエラーの種類を変えているから**である
- **演算子群・相殺形式・表示境界・複素の縁**は生成器が名指ししている定数

**§14.2 の 9 行を `SPEC_AXES` に写した。** 軸の書き忘れは**同じ因子表から
列挙するテストには原理的に見えない**ので、**人が並べて読むため**に置く。

## 要求セルは 73(金融は 1,338)

**9 領域のうち 8 つが 1-way** である——§14.2 の被覆規則が「各水準 1 件以上」
「各帯に最低件数」「各経路に最低件数」と書いている。**直積は `angle_mode` だけ。**
**データが 5.7 倍でも、要求セルは金融の 5% になる。**

代数に `one_way_cells` を足した(金融は全組合せとペアワイズしか使わなかった)。

## `SPEC_AXES` が最初の食い違いを見つけた

**§14.2 は `inverse_trig` に「1-way 必須、重要ペアを選択」と書いている**のに、
最初 1-way しか作っていなかった。**設計書の文言を隣に置いたので気づけた。**

選んだペアは `angle_mode × function`。**理由は実測**——`Rad × asin/acos/atan` は
コーパス 18 枚のどこにも 1 件も無い。**1-way だと「`angle_mode=Rad` が未達」の
1 セルに畳まれ、どの関数が欠けているかが出ない。**

## データを当てて分かったこと

**空の帯は `inverse_trig × Rad` の 1 つだけ**だった(10 関数すべてにケースが在る)。

**★ そして、私のその場の射影が 1 回目に読み違えた。** `fact` を 0 件と数えたが、
**キーの綴りは `n_fact`、式では `!` で描画される**——実際は 174 件だった。
**式とキーで数が食い違う関数も 3 つ在る**(`nPr` 639/640・`nCr` 1711/1715・
`recip` 902/903)。**射影が読み違える場所は実在する**——裁定 1 が (c)
(記録・数え直し・一致の assert)で正しかったことの、着手初日の実例である。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Task 2。ケースから**観測できる水準**を取り出す経路。**観測と記録は別物**で、
ここは観測の側だけを持つ(裁定 1 の (c)。一致の assert は Task 3)。

## キーを一次資料にする。`expr` は読まない

**式で数えると 3 つの関数で件数がずれる**(実測: `nPr` 639/640・
`nCr` 1711/1715・`recip` 902/903)。**食い違いは全部 `errors-000.json` で、
そこは `expr` が人間向けの散文である**(`P(5,6)`・`1/0 (逆数)`)。
**キーは押した列そのもの。**

**等価ケースは `keys` を持たず `left` と `right` を持つ**(1,292 件)。
片方だけ読むと押したキーの半分を見落とす。

**軸ごとに集合を返す**——1 件が同じ軸で複数の水準を踏むことがある
(`sin` と `cos` の両方を含む式)。1 つしか持てない形にすると手前を落とす。

## 観測できない軸を、宣言として書き出した

帯(elementary / inverse_trig / cancellation)・文法クラス(precedence)・
演算種別(complex)・**表示境界(display)**。**どこまでが検算されているかを
読む人が知れなければならない**——「全部突き合わせている」と読ませない。

## 未達を 1 つの数に畳まない

**37 = 観測できない 30 + 本当の穴 7。** 前者は「データに無い」ではなく
「**この経路では読めない**」で、**Task 3 が記録を足せば埋まる。**
混ぜると埋める判断を誤る。

**本当の穴 7 件**(`inverse_trig` の Rad 4 / `combinatorics` の
`path=domain`・`overflow_near` / `complex/zero_part=both_zero`)。
**後ろの 3 件は着手前に見えていなかった**——組合せの 2,000 件はすべて `ok` で、
定義域と溢れは `errors-000.json`(9 領域の外)に在る。

## 途中で 2 回、自分の射影が間違えた

1. **軸の並びがアルファベット順だった。** 要求セルは因子表の順
   (`function, angle_mode`)なので**同じ意味のセルが別物になり**、
   **`Rad` のケースが 2,000 件在るのに `angle_mode` の被覆が 6 中 0** になった
2. **`display/edge` を観測できない軸として宣言し忘れていた。** 5 セルが
   「本当の穴」に混ざっていた

**どちらも「射影は読み違える」の実例**で、裁定 1 が (c) である理由そのものである。

門: **どの水準にも属さないケースが 1 件でもあれば落ちる**(実測: 20,001 件
すべてが 1 つ以上のセルを踏む)。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
**判断材料にした表現が、実物より強い主張だった。走る前に訂正する。**

`build_family_shard` は**関数を意図的に選んでいない**——木を丸ごと乱択で作り、
その中に複数の関数が入りうる。**「この水準を狙った」という意図は、ケース単位
には存在しない。**

**(c) が突き合わせるのは「同じ木の、2 つの読み経路」である**(記録は木を歩き、
観測は描画されたキー列を読む)。**木そのもののバグは捕まえない。**

**そして全軸には掛からない**——`band` / `grammar_class` / `operation` / `edge` は
観測できないので**記録するしかなく、(b) のまま**(自己申告、検算なし)。

**それでも (c) を採る理由は、着手前より強くなった**: **2 日で 3 回踏んだ
読み違いが、全部この層で起きている**(`n_fact` の綴り/軸の並び/宣言漏れ)。
**「理屈として強い」ではなく、実際に壊れた場所を覆っている。**

**順位は変わらない**——観測できる軸では (c) だけが検算を持ち、観測できない軸では
(b) と同点で (a) は覆えない。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Task 3。**生成器が作った木を歩いて水準を記録し、キー列から読んだものと
突き合わせる**(裁定 1 の (c))。**食い違ったら生成を止める**——警告で流さない。

**捕まえるのは「木 → キー」の描画と「キー → 水準」の読み**であって、木そのもの
のバグは捕まえない。**それでもここに置く理由は、2 日で 3 回踏んだ読み違いが
全部この層で起きているから**である。

## 予測と実測

| # | 予測 | 実測 | |
|---|---|---|---|
| 1 | 動くのは 9 領域の 10 枚だけ | 10 枚。`testdata/` と他 8 枚は無傷 | ✔ |
| 2 | ケースの中身は不変 | `levels` 以外バイト一致 | ✔ |
| 3 | `id` の集合は不変 | 完全一致 | ✔ |
| 4 | 検出力は動かない | **18/18・10/10 とも件数完全一致** | ✔ |
| 5 | `pnpm heavy` 240 のまま | 240 passed | ✔ |
| 6 | golden +2.0M(実測前) | **+3.57M(+41%)** | **✘** |

**6 が外れた原因**: 私は**中身の大きさ**を見積もった(実測 1.62M、1 件平均
95 バイト——見込み 106 に近い)。**書き出しは `indent=2`** なので約 2.2 倍になる。
**見積もった対象と、測られる対象が違っていた。**

## 軸には 3 つの類型がある、と分かった

1. **記録も観測もできる** → 突き合わせられる((c) が成立)
2. **観測できない** → 記録するしかない = (b)
3. **観測できるが記録できない** → 突合の相手が居ない

**3 は突合の assert が初回の実走で見つけた**(`combinatorics/path` は期待値の
エラー種別から出る)。**宣言しないと、食い違いではなく「相手が居ない」で毎回落ちる。**

## ★ テストが、門の穴を見つけた

**記録が空のときに観測側も空になり、記録の欠落を捕まえられなかった。**
`scope in recorded` で絞っていたためで、**絞りが番人を片側検査にしていた。**

絞りを外すには、**観測のみの軸を全部宣言する**必要があった——`display/kind`
(`eng`/`dms` は木の外で押す)・`precedence/parenthesis`(キー列は括弧を省いた形)・
`complex/form`(`polar_toggle` は木の外)・`complex/zero_part`(期待値から出る)。
**絞りがそれを隠していた。**

赤確認(絞りを外したあと、2 方向とも**同じ 1 本の assert** が落ちる):

- 記録側をずらす(木から `ln` を落とす) → `LevelsDisagree`
- 観測側をずらす(キー `ln` を `log10` と読む) → `LevelsDisagree`

**片方向だけ落ちる門は突合ではない**ので、両方を確かめている。

`levels` を持つのは 17,823 / 20,001 件。**木を経由しないケース**(リテラルを
直に打つ表示など)は持たない——**「無い」は「空」ではない。**

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
**規律を変えた。変えた記録を計画に残す。**

金融で決めたのは「`unmet_cells > 0` は Heavy を落とす」(設計書 §15.2)。
**科学計算でそのまま掛けると、`coverage` を載せた瞬間に 7 領域が赤くなる**
——未達 37 のうち **30 は「測れない軸」に起因**し、**埋めようがない**。

**門を種類で分ける。測れない軸では落とさず、本当の穴(7 件)では落とす。**

採らなかった形と理由も残した——**未達 0 まで載せない**(モデルが見つけたものを
段 C の終わりまで誰にも見せない。**可視化の先送りは目的と逆**)/**理由付き除外へ
振り替える**(表は綺麗になるが嘘。第 1 段階の「一律 `source_overflow`」と同じ形)/
**本当の穴も警告に留める**(穴が緑で通るなら、このモデルを作った意味が無い)。

**赤が続くのは段 B が 7 件を埋めるまで。止まるのはリリースであってマージではない**
——`heavy-corpus.yml` は `workflow_dispatch` と `workflow_call` だけで走り、
毎回の CI が回すのは `heavy` の型検査・lint・vitest だけである(現物で確認)。
**代償の向きは正しい**: 「モデルが本当の穴を指しているあいだは出荷しない」。

**この裁定の危険は「測れないと宣言すれば門を通る」こと**なので、番人を置く
——**宣言した軸が本当に観測経路から出ないことを見る**。

載せ場所は **10 枚に同じブロック**(24K = 0.12%)。**一致だけを見るテストは
書かない**——10 個とも同じように間違っていれば緑になる。**源と写しの一致**を見る。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Task 4。**9 領域を横断して数えた `coverage` を、10 枚すべてに同じ形で載せる**
(裁定 2 の B・裁定 5)。**横断するので、全部作ってから書く**——1 枚ずつ書き出すと
9 領域を跨ぐ被覆を数えられない(`angle-mode` の Rad と他 3 枚の Deg にまたがる)。

## 未達を種類で分けた(裁定 4)

**数だけでは読み手が分けられない**——`inverse_trig` は「測れない軸(帯)」と
「本当の穴(Rad)」の**両方**を持つ。**最初の実装は軸の宣言だけで領域ごと
見逃していた**ので、**穴が緑で通る**状態だった。

いま payload は `unmet_from_unmeasured_axes` と `unmet_real_cells` を持ち、
**門は本当の穴の数でだけ落ちる**。**本当の穴のセル id も載せる**——数だけだと
報告書が「どこが空か」を言えない。**穴を可視化するのがこのモデルの値打ちである。**

```
領域            未達  うち測れない  本当の穴
inverse_trig      9        5          4
combinatorics     2        0          2
complex           5        4          1
他 6 領域         …        全部        0
                                  計 7
```

## 番人

- **(i) 宣言した軸が、本当に観測経路から出ない**ことを見る。**観測できるのに
  「測れない」と宣言した軸が 1 つでもあれば落ちる**——これが無いと、
  **宣言が「緩めれば緑になるパラメータ」になる**
- **(ii) 宣言の一覧を固定**((i) の保険。**観測できない軸を新しく宣言すること**は
  (i) では捕まらない——正しい宣言かもしれないし、**モデルを狭めて点を稼ぐ手**
  かもしれない。増えたら人が読む)
- **写しが一致することだけを見ない**(裁定 5)。**10 個とも同じように間違っていれば
  緑**なので、**源と写しの一致**を見る——数え直したものと載っているものが同じか
- 門の両側: **測れない軸だけの未達なら落とさない / 本当の穴が混ざれば落ちる**

## 赤が始まるのは Task 5

**Task 4 では赤くならない**——受け入れ門は呼び出しシャードにだけ掛かっており、
科学計算は値シャードである(実測)。**門を広げる Task 5 で初めて赤が出る。**

`pnpm heavy` 242 passed / `reference` 452 passed / mypy / ruff 緑。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Task 5。**受け入れ門を値シャードと表示シャードへ広げた**——2026-08-30 まで
`calls.spec.ts` が呼び出しシャードを回すだけで、**科学計算の 9 領域は 1 度も
通っていなかった。**

**`pnpm heavy` はここから意図して赤い。** 242 passed / 1 failed。

## 赤の文面(踏んだ人がその場で分かる形にした)

```
angle-mode-000.json/inverse_trig/...: 試験空間モデル「scientific-v1」が、
データに無いセルを 4 件指している: inverse_trig/angle_mode=Rad /
inverse_trig/function=acos,angle_mode=Rad / ...
  **これはあなたの変更が壊したのではない可能性が高い。**
  モデルが「ここに入力が 1 件も無い」と言っている。
  (この対象には「まだ測れない軸」に起因する未達も 5 件あるが、それでは
   落としていない。落としたのは上の分だけである)
  埋めるか、理由付き除外にするかは人が決める。
  経緯は docs/superpowers/sdd/heavy-INTENDED-RED.md にある。
```

**「未達が N 件」だけだと、踏んだ人は自分の変更を疑って半日溶かす**
——このコーパスは手動起動とリリースでしか走らないので、**踏むのはたいてい、
その変更をしていない人である。**

## 台帳 2 枚

**`heavy-INTENDED-RED.md`(新規)**——いつから/なぜ/本当の穴 7 件の一覧/
**いつ解けるか(段 B)**/**その間リリースは止まるがマージは止まらない**/
**急いで出荷したくなったときに選べる 2 つ**(埋める・理由付き除外。
**「測れない軸」への振り替えは禁じ手**で、宣言には番人が付いている)。
`heavy-HANDOFF.md` の先頭近くから指した——**知らない人には壊れた赤と
区別が付かない。**

**`known-flaky-tests.md` に 2 件目**——`classify and classifyComplex`
(28 秒かかる、1 回目赤・再走で緑、その後 3/3 緑)。**1 回目の出力を残して
いなかった**ので、そう書いた。**「最後まで走っていない」は読みであって実測では
ない**とも。次に踏んだ人へ「出力を丸ごと保存してから足す」。

`SUPPORTED_COVERAGE_MODELS` に `scientific-v1` を、
`COVERAGE_REQUIRED_SHARDS` に 9 領域の 10 枚を足した。
門の署名は `{ coverage?: Coverage }` に広げた——**見るのは `coverage` だけで、
シャードの種別は問わない。**

`reference` 452 passed / heavy vitest 183 / typecheck / lint 緑。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Task 6。**モデルが穴を指せることを、走行ログではなくテストに固定する**
——**Task 8 が埋めた瞬間に未達は 0 になり、証拠が消える**からである。

## 検出ではなく判別にした

**「未達に出る」だけを見るテストは、射影が壊れて何でも未達と言うようになっても
緑のまま**である。**入力の有無で答が変わること**を主張する:

- **Rad の逆三角を含まない入力**(いまの実物) → その 4 セルが**未達に出る**
- **Rad の逆三角を 3 件足した入力**(合成) → 同じ 4 セルが**未達に出ない**
- **他の穴は動かない**——足したのは Rad の逆三角だけなので、**それ以外まで
  消えたなら数え方が入力に対して鈍い**

**後者は合成の入力で書ける**ので、実データが埋まるのを待たない。
**Task 8 のあとも生きる**——主張しているのは「埋まったこと」ではなく
「**入力の有無で答が変わること**」だからである。

## 赤確認(両向き・別々の assert が落ちる)

- **射影が何も観測しない**(=何でも未達) → 「Rad の逆三角を足したのに、
  まだ未達として出ている」で赤
- **モデルが要求セルを持たない**(=穴が消える) → 「Rad の逆三角が 1 件も
  無いのに、未達として出ていない」で赤

**片方向だけ落ちるなら、それは判別ではなく検出である。**

## 測った結果は、いまの赤の文面と一致する

本当の穴 7 件のうち **`inverse_trig` の 4 件**が、受け入れ門が
`angle-mode-000.json` を読んで落ちるときに名指しするものと**同じ**である
(`combinatorics` 2 / `complex` 1 も固定した)。

**埋めていない**——Task 8 の仕事である。`reference` 454 passed。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Task 7。**「作れるのに作っていない」を、主張ではなく測った。**

## 7 件それぞれを、実際に作ってみた

| セル | 実測 |
|---|---|
| `inverse_trig/function={asin,acos,atan},angle_mode=Rad` | **作れる**——`evaluate(node, "Rad")` が答を返し、探針が目当てのセルに当たる |
| `inverse_trig/angle_mode=Rad` | **作れる**(同上) |
| `complex/zero_part=both_zero` | **作れる**——`(1+j1)-(1+j1)` が `{re: 0.0, im: 0.0}` |
| `combinatorics/path=domain` | **この領域の生成器は作らない**——`OutOfShard: nCr with r greater than n` で弾く |
| `combinatorics/path=overflow_near` | 同上——`_within_range` が False を返す |

## 理由は 1 つも貼っていない。それがこの段の成果物である

**5 件は作れる**ので、**理由を貼れば嘘になる**(第 1 段階で 2 回踏んだ形)。

**残る 2 件も「作れない」とは書けない。** 弾いているのは**この領域の生成器の
規則**であって、**不可能だからではない**——`errors-000.json` が別の作り方で
持っている(`C(5,6)` / `C(5,-1)`)。**既存の理由コードに、当てはまるものが無い。**

**そして「外が踏んでいるから除外」にはしない**——裁定 2 の B は「外は数えない」と
決めたので、**それを理由に除外すると裏口から C を採ることになる。**
**未達のまま残し、`covered_outside_model` の別欄で「外の 1 枚が踏んでいる」を
見せる**——埋めるかどうかの判断材料であって、埋まったことにはしない。

## 門(赤確認つき)

- **作れることを、毎回その場で測る**——探針を実際に組み、目当てのセルに当たるか。
  **当たらなくなったら、一覧のほうが嘘になっている**
- **作れるセルに理由を貼ったら落ちる**。赤確認: `inverse_trig/angle_mode=Rad` に
  `not_applicable` を貼ると「作れるセルに理由を貼っている」で赤。golden はバイト
  一致で戻した
- **外が踏んでいるものは、数に入っていない**(未達のままであること)

`reference` 457 passed / mypy / ruff 緑。`pnpm heavy` は 242 passed / 1 failed
——**意図した赤のまま**(Task 5 から)。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
## 道の選択(Task 8 の Step 1)

**3 つを実装して回し、golden を突き合わせた。そして 4 つ目が出た。**
**採るのは (iv)**——**乱択のループの後ろに Rad の名指し境界を足す**。
**既存ケースの中身も `id` も動かず、ファイルも増えない**(`inverse-trig` が
2000 → 2003 になるだけ)。**draw の列に一切触れない**からで、
`DISPLAY_EDGE_LITERALS` の先例と同型である(あちらは先頭、こちらは末尾)。

**(ii) は `angle-mode` の 2000 件が全部動く。** 挙動は変わらないのに差分が
2000 件になり、**次に差分を読む人が追えない**——このプロジェクトは
**golden の差分を人が読んで判断している**ので、**失うのは今回だけでなく以後ずっと**。

**(iii) はファイルが 1 枚増える**(18 → 19)。再現性検査のファイル集合・
`COVERAGE_REQUIRED_SHARDS`・シャードの種別判定が動く。

**(i) は測っていない。** 変異を当てる場所を間違えて `NameError` になった
——**当て直せば測れる**が、**`build_family_shard` は `elementary` も通る**ので
モードを渡すと **`inverse_trig` が丸ごと Rad になり Deg の 1,113 件を失う**。
混ぜるにはループ内で分岐が要り、それは (ii) と同じ代償である。
**測った 3 つと、測っていない 1 つを混ぜて書かない。**

## 台帳の訂正

`heavy-INTENDED-RED.md` の「いつ解けるか」が**段 B と 7 件を対応づけていた**
——**段 B は 2 領域しか扱わない**ので、埋まるのは 4 件である。表にした:
**段 B で 4 件、段 C で残り 3 件、緑になるのは段 C。**

**赤が「減る」ことと「解ける」ことは別**で、当初の書き方だと**段 B の終わりに
緑になる**と読まれる——**踏んだ人が「まだ赤い」と調べ始める。**

**受け取った見通しを検算せずに写した**、という点はこちらの落ち度でもある。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Task 8。**乱択のループが終わったあとに、Rad の逆三角を 3 件足す**(道 (iv))。
**draw の列に一切触れない**ので、**既存の 2000 件はバイト一致・`id` も不変**。

## 予測と実測

| # | 予測 | 実測 | |
|---|---|---|---|
| 1 | 動くのは `inverse-trig`(+3)と `coverage` 伝播の 10 枚。他 8 枚と `testdata/` は不変 | そのとおり | ✔ |
| 2 | 既存ケースの中身はバイト一致・`id` の集合は保たれる | バイト一致・id 保存 | ✔ |
| 3 | 件数 2000 → 2003 | 2000 → 2003 | ✔ |
| 4 | 検出力は不変 | **`display-digits` が 8271 → 8272** | **✘** |
| 5 | 赤の名指しが 4 件 → 3 件 | `combinatorics` の 2 件・`complex` の 1 件 | ✔ |

## 検出力が 1 件動いた。基準は動かしていない

**`inverse-trig` が 732 → 733。** 原因は**足した 3 件のうち 1 件**である
——`acos(0)` = 1.5707963267948966 は**表示の有効桁を 10 から 9 に減らすと
描画が変わる**ので、その変異が 1 件多く捕まえる。`asin(0)` と `atan(0)` は
どちらも 0 なので、桁を減らしても変わらない。

**`minRate` は 1 つも動かしていない**(`heavy/scripts/` の差分は 0 行)。
全 11 シャードが下限の 2 倍前後を保っており、`inverse-trig` は
**率 0.366 / 下限 0.183 / 余裕 +0.183**。**動いたのは検出件数であって、
判定の基準ではない。**

`heavy:power:exact` は 10/10・件数完全一致。

## Task 6 の判別テストが壊れた——実データに依存していた

**「無い側」の入力に実物をそのまま使っていた**ので、**埋めた瞬間に前提が
崩れた**。**両方の入力をこちらで作る**形に直した——実物から
**Rad の逆三角を取り除いて「無い側」を組む**。**主張は「入力の有無で答が
変わる」ことなので、これで実データから独立する。**

**壊れたこと自体が、あのテストの弱点を教えた。**

## 数

**本当の穴 7 → 3**(`inverse_trig` の 4 件が消えた)。未達 37 → 33
(測れない 30 は不変)。`levels` を持つケース 17,823 → 17,826。

`reference` 457 passed / mypy / ruff 緑、heavy vitest 183 / typecheck / lint 緑。
`pnpm heavy` は**意図した赤のまま**——名指しが `combinatorics` の 2 件に移った。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Task 9。報告書に**科学計算の試験空間の節**を足した。**金融の表とは別に出す**
——モデルが 9 領域をまたぐので「関数呼び出しの内訳」には収まらない。
**10 枚が同じブロックを持つので、1 回だけ描く。**

## 未達を 1 つの数に畳まない

**3 つが区別して読める**:

1. **データに無いセル 3 件**——**セル id ごと名指しし、「この検査を落とすのは
   これだけである」と書く**
2. **測れない軸に起因する未達 30 件**——**「踏んでいない」ではなく「読めない」**。
   軸ごとに理由を表で出す
3. **9 領域の外が踏んでいるもの**——**被覆としては数えない**。
   「外が踏んでいることを理由に数えると、範囲の決め方が骨抜きになる」と書いた

**畳むと、埋める判断を誤る。**

## `toContain` の相手を、注意文に含まれない綴りにした

第 1 段階で 3 回踏んだ型なので、**行の全体一致**で当てる
(`- \`op/band=zero\`` / `| \`op\` | \`band\` | 引数の値が要る |`)。
**「データに無い」は見出しにも表にも出る**ので、素の語では常に緑になる。

## 実物を目で読んだ

冒頭に「Rad を 1 枚、Deg を 3 枚が運ぶ」と書いていたので、**実測で当て直した**
——9 領域の中で三角関数を運ぶのは `angle-mode`(Rad 2000)・`precedence`(909)・
`display`(143)・`complex`(95) で、**Deg は 3 枚。合っていた。**

## `docs/corpus-measurements.md` に、検出力 +1 の機構を書いた

**次に数字を見比べる人のために、数字の隣に置く**——`display-digits` が
8271 → 8272 に動いたのは**ケースを 3 件足したから**で、そのうち
**`acos(0)` = 1.5707963267948966 だけが 10 桁と 9 桁で描画が変わる**
(`asin(0)` と `atan(0)` は 0 なので変わらない)。**だから +1 であって +3 ではない。**
**`heavy/scripts/` の差分は 0 行**で、基準は動かしていない。

`pnpm heavy` 248 passed / 1 failed(**意図した赤**)、`reference` 457 passed、
heavy vitest 183 / typecheck / lint 緑。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Task 10。段 B の締め。**書いたのは道具が印字した数だけ。**

## ★ 押下台帳の予測を外した。根拠が間違っていた

**予測 19,849 / 実測 19,960**(打鍵 1,266・指摘 0 は一致)。

`git diff -- web/src crates/` が空であることを見て「盤面も計算コアも動いて
いないから不変」としたが、**`heavy:ui` が打鍵するのはコーパスのケースである。**

**機構**: `selectSample` は `spread(count, items.length)` で等間隔に選び、
`step = length / count`。**`inverse-trig` が 2000 → 2003 になったので刻みが
20.00 → 20.03 に変わり、選ばれるケースがずれた**——**打鍵数は 1,266 のままで、
中身が違う**から押下の合計が動く。

**押下台帳は、盤面だけの不変量ではなくコーパスの関数である。**
**これまで不変だったのは、コーパスが動いていなかったからにすぎない。**

## 記録に入れたもの

- **モデルが人より先に見つけた穴 3 件**——着手前に人が見つけていたのは
  `Rad × 逆三角` だけ。**人が気づいていた穴を確認するだけならモデルは要らない**
- **`duplicate_equivalent` を貼りかけた件**——**理由コードの名前ごと**。
  `errors-000.json` が持っているので**文言としては真**であり、**先に「空でよい」と
  言われていなければ貼っていた**。**表を埋めたくなる誘因は実在する**
- **射影の読み違い 3 回**(`n_fact` の綴り/軸の並び/宣言漏れ)——
  **裁定 1 が (c) である理由の一次資料**
- **番人が自分の穴を 2 回見せた**——絞りが突合を片側検査にしていた/
  門の粒度が領域単位で穴を見逃していた。**表示の粗さと門の粗さが同じ根**だった
- **規律の幅は直前に踏んだ穴の形にしか広がらない**(この段だけで 6 件の表)。
  **広げること自体は対策にならない**——6 件とも「規律を知らなかった」のではなく
  **「その規律が今回の形に当てはまると思わなかった」**
- 段 B で確定した数の一覧(未達 37 → 33、本当の穴 7 → 3、ほか)

## 走らせたもの・走らせなかったもの

cargo 396 / reference 457 / web 375 / e2e 192 / heavy 248 + 1(意図した赤) /
heavy:ui 36。**`heavy:power` と `power:exact` は回していない**——Task 8 で
回して +1 の機構まで特定済みで、**それ以降 `crates/` もコーパスの計算経路も
動いていない**。**端折ったのではなく、対象を測った上で回さなかった。**

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Task 11。**ユーザー裁定 A**——赤を解いて出すことと、モデルに本当のことを
言わせることがぶつかり、**後者を採った。**

## ★ 「測れない」と書けたのは、切れ目を決めずに済んだからだった

`elementary/band` と `inverse_trig/band` には**「帯は引数の値で決まる。
キー列からは読めない」**と書いてあった。**実データと食い違っていた**
——`elementary` の関数適用 3,345 回のうち **1,784 回(53.3%)は引数が
リテラル**で、キー列に数字がそのまま並んでいる。

**さらに手前に、もっと重い誤りがあった。** §14.2 は軸の名前
(「定義域帯」)を書くだけで**水準を 1 つも定義していない**。5 水準は私が
作ったもので、docstring には**「帯の切れ目は仕様が決めている」**と
書いてあった。**`numerical-policy.md` の表が名指しする切れ目は `0` と `±1`
だけで、`positive_small` と `positive_large` を分ける境目はどこにも無い。**

## 直したこと

- **水準を表から引き直した**。`ELEMENTARY_BANDS`(負/ゼロ/正、切れ目は `0`)と
  `INVERSE_TRIG_BANDS`(内/境界/外、切れ目は `±1`)に分けた。**`±1` は
  `asin`/`acos` の境目**で、`ln` や `1/x` とは関係が無い
- **`literal_arguments()` が窓である**——一価関数キーの直前の数字列。
  **`expr` は読まない**(この module はキーを一次資料にすると決めている)。
  **記録側も同じ窓に絞る**——広いほうが多く見るのではなく、**窓が違えば
  突合が片側検査になる**
- **`band × function` を選択ペアに入れた**。ここには「まだ測っていないので
  名指しできない」と書いてあったが、**測ったので期限切れ**である。
  **1-way だと 3 帯を `atan` が 1 人で埋め、表が名指しする `asin(1)`/`acos(1)`
  が 1 件も無いことが見えない**——軸は満点、確かめたい所は空
- **`CANCELLATION_BANDS` の理由も誤りだった**——「`numerical-policy.md` が
  相対誤差 `1e-6` を名指し」の `1e-6` は、**Loan の月額を円境界で落とす基準**
  (`numerical-policy.md:123`)。**文書を指した理由が、その文書の別の話を
  指していた。** 水準は残し、**私が作ったものだと書いた(実測前)**

## ★ 番人(ユーザー条件 ③)

**`test_a_band_declared_unreadable_has_no_readable_argument`。**
既存の番人は「射影が実際に読んでいるか」を見るので、**射影を書かなければ
宣言の正誤に関わらず緑**だった——**書かなかったことが、宣言の正しさの証拠に
なっていた。** こちらは**データを見る**。判別テストつき(`elementary/band` を
宣言し直して赤くなることを確かめる)。**理由の写しが本体より長生きしない
番人**も足した(参照されない理由が残ると腐る。実際にそうなった)。

## 数(すべて印字から)

```
要求セル 73 → 78   被覆 40 → 55   未達 33 → 23
測れない起因 30 → 20      本当の穴 3 → 7 → 3
```

**「測れない」が 10 件減って、そこから本当の穴が 4 件出てきた**
——`elementary/band` の負とゼロ、`asin(1)`、`acos(1)`。**測れないと
言えているあいだ、この 4 件は誰にも見えていなかった。**

**4 件とも作れた**(条件 ④)ので埋めた——`e^0` `e^-5` `asin(1)` `acos(1)`。
`ln(0)` と `1/0` はエラーなので値シャードに入らない(棄却の実測は
`domain 36` / `division_by_zero 4`)。**`eˣ` だけが 0 と負を通せる。**

## 予測(走行前に固定)と実測

- ケース数 2000→2002 / 2003→2005、総数 20,008、`levels` 17,830、
  要求 78、被覆 55、未達 23、本当の穴 3 ——**すべて的中**
- **★ 外した: 「既存のケースは 1 バイトも動かない」。** 動いた
  ——**帯を記録した以上、既存ケースの `levels` が増える**(elementary 1,637 件・
  inverse-trig 607 件)。**`levels` 以外は 1 バイトも動いていない**
  (id・キー・式・期待値。実測で `other = 0`)
- **★ 正しい台帳に誤った訂正を上書きしかけた。** 段 B の「`levels` 17,826」を
  実測 16,127 と比べて「間違っている」と判断したが、**ずれていたのは私の
  数え方**だった——記録は**キーの有無**、私は**中身が空でないこと**を
  数えていた。**数を訂正する前に、元の数が何を数えたのかを再現する。**

`reference` 459 passed / ruff / mypy、`heavy` 183 passed / typecheck、
`pnpm heavy` 248 passed + 1 failed(**意図した赤。本当の穴 3 件**)。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
… be read

Task 12(cancellation)と、監視役の指示による道具の追加。

## ★ `scripts/corpus_diff.py` ——差分をフィールドごとに読む

Task 11 で **`levels` だけが動いた差分が 8,000 行**になり、**私は手で 1 回
確かめた。それでは確かめ自体が残らない。**

**置いた直後に、手作業の見落としを 1 枚見つけた**——私は `elementary` と
`inverse-trig`(2,244 件)を報告したが、**`cancellation` の 365 件も動いていた**
(その領域の `ln(1.0000…)` が `elementary/band` を記録するようになったため)。
**正しくは 2,609 件である。**

**シャード階層も見る。** 最初はケースだけを見ていて、**理由の文言を 1 行
直しただけの走行で「動いたフィールドは無し」と印字した**——ケースは本当に
1 件も動いていなかったが、**10 枚の `coverage` が動いていた。**
**見ない道具は、見ていないと言わずに「無い」と言う。** 番人 5 本つき。

## Task 12: `cancellation` の 2 軸は、測れないまま残す

**ただし理由を実測で置き換えた。** 骨格はキー列から読める——4 つの木は
互いに違う形をしている。**それでは足りない**ことを 9 領域を横断して数えた:

```
ln(リテラル) : cancellation 365 / elementary   233
lit - lit    : cancellation 527 / inverse-trig  66
lit + lit    : cancellation 573 / inverse-trig  73
sqrt - sqrt  : cancellation 535 / (他は 0)
```

**4 つを分けているのは骨格ではなく「近さ」**であり(生成器の docstring が
「近接する 2 数」「1 に近いところ」と書いている)、**近さの切れ目を仕様は
どこにも決めていない。**

**★ 生成器のパラメータを観測側へ写せば分けられる。採らなかった**
——写した時点で**観測は生成器の設定の複製**になり、裁定 1 が「2 つの読み
経路」を求めた意味が薄れる。**「測れない」を、測った上で選んでいる。**

`band` の理由も先に直してある(「相対誤差 `1e-6`」は **Loan の月額を円境界で
落とす基準**だった)。

## 予測(走行前に固定)と実測

**「ケースは 1 件も動かず、`coverage` ブロックだけが変わる」——的中。**
`corpus_diff.py` の印字: 動いたフィールドの合計 (無し) / 10 枚とも
シャード階層の `coverage` のみ。

`reference` 464 passed / ruff / mypy、`pnpm heavy` 248 passed + 1 failed
(意図した赤。本当の穴 3 件)。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…ed cell

Task 13(complex)。

## `complex/operation` は測れた

**理由は「演算種別は式の構造で決まる」だった**が、**構造はキー列にも
出ている**——`add`/`sub`/`mul`/`div`/`pow` と一価関数キー。木にも在るので、
**両側から読めて突合できる**。門は**キー側 `"j" in keys`、木側 `Imag` の有無**
で、**同じもの**である(`to_key_sequence` は `Imag` に必ず `j` を出す)。

**`polar_toggle` を門に入れなかった**——あれは木の外で押されるので、
**入れると観測だけが鳴って突合が落ちる。**

## 測ったら、また穴が出た

```
add_sub 1,335 / mul_div 614 / unary_fn 667 / power 0
```

**`power` が 1 件も無い。** ただし**これは埋められない**——engine が
複素数の冪を拒む。**一次資料は engine 自身のテスト**
(`scientific/mod.rs` の `power_rejects_complex_operands`。底でも指数でも
`DomainError`)。**`not_applicable` を貼った——この計画で初めての理由付き除外**
である。**「生成器が作らない」ではなく「作っても engine が拒む」。**

**`zero_part=both_zero` は埋めた**——`(j5 - j5)`。**乱択では踏めない**
(0 に着くには 2 つの葉が厳密に等しい必要があり、生成器は葉を独立に引く)。
実測: 複素 2 シャード 4,000 件で `real_zero 1,327` / `imag_zero 202` /
`none 1,799` / **`both_zero` 0**。

## ★ 理由を貼ったら、名前だけが嘘になった

**会計は正しく 78 に合っていた**(`covered 58 + excluded 1 + unmet 19`)のに、
**`unmet_real_cells` は除外したセルを名指ししたままだった**——`unmet` を作る
内包表記が除外を引いていなかった。**数は正しく、名前だけが嘘。**
**門が読むのは名前のほう**なので、**理由を貼っても赤が消えない。**
番人 `test_an_excluded_cell_is_never_named_as_a_real_hole` を置いた。

## ★ 既存の番人が、新しい仕事を捕まえた

`test_a_reachable_hole_is_never_given_a_reason` の
**「この段では理由を 1 つも貼らない」**が赤くなった。**意図(作れる穴に理由を
貼らない)は生きていて、段 B の断面だけが期限切れ**だった。**名指しに
書き換えた**——数の上限にすると「1 件までなら貼ってよい」を作ってしまう。
**理由の一次資料も、この言語の中で当てる**ようにした(参照側の
`COMPLEX_BINARY_OPS` に `^` が無いこと)。

## 予測(走行前に固定)と実測

- (a) ケース増減 0 / 動くのは `levels` と `coverage` のみ / `complex` 被覆
  5→8 / 未達 23→20 / 測れない 20→16 ——**的中**。
  **★ 「本当の穴 3→5」だけ外した。正しくは 4**(`both_zero` を二重に数えた
  足し算の誤り。機構の予測は当たっている)
- (b) complex 2000→2001 / 既存は 1 件も動かない / 被覆 59 / 未達 18 /
  **本当の穴 2** ——**5 つとも的中**

## 記録

**`pnpm heavy` が 1 回 Segmentation fault で落ちた**(246 本目の直後、exit 139)。
再走で 248 passed + 1 failed。**間欠的に落ちるテストの一覧に載せた**
——**上の 2 件はテストが落ちる形で、これはプロセスが死ぬ形**である。

`reference` 466 passed / ruff / mypy、`heavy` 183 passed / typecheck、
`pnpm heavy` 248 passed + 1 failed(**意図した赤。本当の穴は combinatorics の
2 件だけ**)。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…hood an overflow

Task 14。**本当の穴が 0 件になり、`pnpm heavy` が緑に戻った**(250 passed)。
Task 5 以来の意図した赤が解けた。

## ① `overflow_near` の射影が間違っていた

**§14.2 は「Overflow 近傍」と書いている。私はそれを `error == "Overflow"`
(=溢れ**た**)に写していた。近傍と、超えたところは別である。**

**この訂正で、赤が 1 つ消えた**——`combinatorics/path=overflow_near` は
「データに 1 件も入力が無いセル」として門に名指しされていたが、**直した
射影では 9 件が踏んでいる。穴が埋まったのではなく、穴ではなかった。**

**★ 切れ目は私が選んだ。** `f64` が表せる最大の指数が 308 であることは
**形式が決めている**が、**「その 1 つ下までを近傍とする」は私の選択**である。
候補と実測: `>=1e308` 2 件 / **`>=1e307` 9 件(採用)** / `>=f64max/10` 6 件 /
`>=1e300` 38 件 / `n>=171` 1,753 件。**最後は 2,000 件中 1,753 件で、
水準として何も区別しない。**

**この帯こそこのシャードの存在理由である**——生成器が
`ncr_does_not_overflow_on_the_way_to_an_answer_that_fits` を独立に検証すると
書き、engine のコメントが `n = 1022〜1028` を名指ししている。

## ② 組合せの誤入力の場所を作った(19 枚目)

**ユーザー裁定(2026-08-30)。「3 件を複製する」は退けられた。**
**表を埋めるためではなく、確かめるために作る。**

**足りなかったのは件数ではなく、場所と体系性だった:**
`errors-000.json` は**全領域の寄せ集め 30 件**で、そこに在る組合せは
**`nCr` に 4 件・`nPr` に 1 件、`n` が非整数の形は 0 件**だった。

**数学の定義だけから起こした**(`corpus_combinatorics`)。engine の
`non_negative_integer` も `check_pair` も読んでいない——**読めば移植になり、
同じ見落としが両側に入る**(CLAUDE.md の規律。**監視役の発注文は「core の
実装から列挙」だったが、リポジトリの規律を上に採った**)。

「n 個から r 個を選ぶ」の定義から、破れ方は **`n` が負/`n` が非整数/
`r` が負/`r` が非整数/`r > n`** で尽きる。**2 関数 × 5 = 10、階乗 2、
値域 1(`171!` ——`170!` は収まる境目そのもの。`errors` は `200!` を持って
いて、境目はどこにも無かった)。合計 13 件。**

## 波及は先に測った(条件 ②)

6 か所——`SCIENCE_SHARDS` / `DISPLAY_SHARD_PATTERN` /
`COVERAGE_REQUIRED_SHARDS` / `ALL_SHARDS` / `NINE_SHARDS` / 再現性検査。
**最後だけ変更不要**(`CORPUS.iterdir()` で走査している。実測)。
**`minRate` には触れていない。**

**`ALL_SHARDS` の docstring は「正当に 19 枚目を足す日には、ここの更新が
意識的な 1 行になる。それがこの定数の狙いである」と書いてあった**——
**そのとおりになった。**

## ★ 番兵 2 つが、設計どおり新しい仕事を捕まえた

- **「どの枠にも入らないエラー期待値が在る」**——13 件が名前ごと印字されて
  落ちた。**「0 を主張する検査は、何も見ていなくても緑になる常連」**と
  書いてあった番兵が、**実際に新しい経路を捕まえた**
- **`ALL_SHARDS` は 18 枚、と固定していたテスト**

**枠は `scientific-domain` に入れた。** 別の枠を作らないのは、**枠が
エラー経路の軸**であって、シャードの軸ではないからである。

## 予測(実装前に固定)と実測

新シャード 13 件 / **19 枚 33,588 件** / `path=domain` が被覆へ /
被覆 61 / 未達 16 / **本当の穴 0** / `covered_outside_model` 0 件 /
**`pnpm heavy` が緑** / 既存 18 枚のケースは 1 件も動かない
——**すべて的中。**

## 「よそが覆っている」は、2 件とも一時の札だった

`COVERED_OUTSIDE_MODEL` は**空になった**。片方は**内に在るのに射影が
読めていなかった**、もう片方は**内側で踏むようにした**。
**引用に id を書かせ、その id が実在することを見る番人**を置いた
——**表が空でも主張するように、合成した入力で検査そのものを試す。**

`reference` 467 passed / ruff / mypy、`heavy` 183 passed / typecheck / lint、
**`pnpm heavy` 250 passed(赤 0)**。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…d red

Task 15〜17 と、意図した赤の後始末。**フルスイープの途中で再起動のため、
ここで区切る**(検査の残りは HANDOFF §2 に書いた)。

## Task 17: `display/edge` は読めた——そして註が嘘だった

**理由は「表示境界はリテラルの値で決まる」だったが、その値はキー列に
そのまま並んでいる**(表示のケースは `[数字…, "eq", "eng"|"dms"]`)。
切れ目は 5 つとも `numerical-policy.md` が名指ししている
(仮数 1 以上 / 指数 0 / **3 の倍数** / **有効数字 10 桁** / 丸めで指数が上がる)。

**読めるようにしたら、本当の穴が 1 件出た**——`rounding_carry` を踏んで
いるリテラルが 1 つも無い。**`DISPLAY_EDGE_LITERALS` には
「10 桁に丸めると 1000 に繰り上がり、指数が 1 つ上がる」(`999.9999999`)と
「10 桁ちょうど、繰り上がりで 1e9」(`999999999.9`)と書いてあった。
参照実装に通すとどちらも繰り上がらない**——前者は**既に有効数字 10 桁**で
丸めが恒等、後者は `999,999,999.9` と表示される。**註が主張していた境界を、
コーパスは 1 度も踏んでいなかった。**

**`9999999999.5` を末尾に足した**(→ `10e9`)。**先頭の一覧に足すと後続
1,900 件余りの `id` がずれる**ので、シャードの末尾に置く。

**★ そこで私は元のループを写し、`None` の分岐を落とした**——60 進にできない
値は同値ケースにする規則があり、**写しは `expect.main` が `null` のケースを
書き出した。分岐が 1 つ足りない写しは、動くように見えて嘘を書く。**
**共通の関数に括り出した**(`_append_display_pair`)——**括り出せば、写しは
1 つも要らなかった。**

## Task 16: `precedence/grammar_class` は測れないまま。理由を書き直した

**木からは読める**(`Bin("+", Bin("*", …), …)` は `mul_over_add`)。
**キー列からは読めない**——**このシャードのキー列は括弧を省いた形**であり、
**構造をキーから復元できるかどうかが、このシャードが確かめている当のもの**
である。**記録だけ載せると自己申告になる**ので載せない。
**4 つの水準が私の起こしたものである**ことも書いた(段は
`base-spec.md` の優先順位表が持ち、**対の取り方が私の選択**)。

## Task 15: `associativity` は既に満点(6/6)。変更なし

## 意図した赤を畳んだ

**`heavy-INTENDED-RED.md` は消さずに、閉じた記録に書き換えた**
——**`corpus.ts` の門はいまも同じ文面でこの文書を指す**ので、
**将来また「データに無いセル」を踏んだ人の手引きとして残る。**
穴 8 件が**埋めた・理由を貼った・射影を直した**の 3 通りでどう閉じたかの
一覧つき。

## 数(すべて印字から)

```
要求 73 → 78   被覆 40 → 66   除外 0 → 1   未達 33 → 11
測れない起因 30 → 11   **本当の穴 7 → 0**
コーパス 18 枚 33,567 件 → **19 枚 33,590 件**
```

**残る「測れない」11 件は `cancellation` の 2 軸と `precedence/grammar_class`
だけ**で、どちらも理由を実測で書き直してある。

## ★ 作業台の異常を 2 つ記録した

- **`pnpm heavy` の Segmentation fault が 4 回**(246・247・247・**250 本
  すべて ✓ のあと**)。**落ちる位置が一定しない**
- **`corrections-000.json` が同じ長さで壊れた**——空白 8 個が
  「2 空白 + バッククォート + 5 空白」に。**`git status` は stat キャッシュの
  ため「変更なし」と表示した。HEAD の版は健全**で、**生成器は決定的**
  (2 回生成してダイジェスト一致)。**書いた側にも読んだ側にも心当たりが無い**
- **既知の間欠テストが 2 回続けて落ちた**(`complex-rules.spec.ts:121`)。
  **再走すれば直る、とは限らない**

**この 2 つが同じ原因なら、この作業台で出た緑も赤も等しく疑わしい**
——一覧に「メモリ検査を一度通してください」と書いた。

`reference` 467 passed / ruff / mypy、`heavy` 183 passed / typecheck / lint、
**`pnpm heavy` 250 passed(赤 0)**、`cargo fmt` / `clippy` 0。
**`cargo test` の件数と `web` 一式は未取得**(再起動のため)。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…missed them

**この作業台で、作業ツリーのファイルが壊れている。** 走行の記録ではなく、
**赤を見た人が最初に疑うべきものが変わった**ので一覧に載せる。

## 実測

```
2026-08-30 夕  corrections-000.json           0x20 ' ' → 0x60 '`'   XOR 0x40
2026-08-30 夜  complex-000.json  offset 889876  0x34 '4' → 0x35 '5'   XOR 0x01
2026-08-30 夜  complex-000.json  offset 891540  0x20 ' ' → 0x00 NUL   XOR 0x20
```

**3 つとも単一ビットの反転である。** 書き込みが切れた形でも、別のデータで
上書きされた形でもない——**メモリかストレージのビット化けの形**である。
**再起動をまたいで再発しているので、一過性でもない。**

## ★ 私が今日、健全性の根拠にして 2 回とも外したもの

- **`git status`**——**3 バイトとも長さが同じ**なので、stat キャッシュは
  「変更なし」と言い続ける
- **`json.load()` が通ること**——**`'4'` が `'5'` になった破損は JSON として
  完全に妥当**で、**パースでは原理的に見つからない。**
  **私は「19 枚パースし直して全枚健全」と報告し、その時点で 1 枚壊れていた。**
  「clean だから健全とは言えない」と書いた直後に、「パースが通るから健全」と
  言っていた

**使える手は `git hash-object` の全件照合である**(git が全ファイルの SHA を
持っている)。コマンドを一覧に書いた。**復元は `rm` してから
`git checkout HEAD --`**——**`git checkout --` だけでは戻らない**(git が
「変更なし」と思っているので何もしない。実測)。

## `.git` は無事である

**両リポジトリの `git fsck --full --strict` が dangling 以外の指摘を出さない。**
**オブジェクトは SHA で検証されているので、壊れれば fsck が言う**
——**壊れているのは誰も検証していない作業ツリーのファイルだけ**であり、
**だから復元元は信頼できる。**

## 手落ちも書いた

**1 件目は、復元の前にバイトを取らなかった。** XOR は当時の `cat -A` の
出力から**導いた**もので、実測ではない。**次に踏んだ人が同じ証拠を
失わないように**、そう明記した。

**フルスイープは止めている。** メモリ検査を通すまで、**この作業台で出る
緑も赤も等しく疑わしい**——**壊れた入力の上で出た緑は、緑の意味を持たない。**

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
**走行の前後で、追跡下の全ファイルが index と一致することを確かめる。**

## なぜ

2026-08-30、この作業台で**作業ツリーのファイルが 3 バイト壊れた**
(3 つとも単一ビットの反転、長さは同じ)。**それまで健全性の根拠にしていた
2 つが、どちらも見落とした**——`git status`(stat キャッシュ)と
`json.load()` が通ること(`'4'`→`'5'` は JSON として完全に妥当)。

**壊れた入力の上で出た緑は、緑の意味を持たない。そしてあとから見分けられない**
——走行後に照合しても「走行中は健全だった」とは言えない。**だから挟む。**

## なぜ「手順を書く」ではなく道具にしたか

**規律を書いたら、同じコミットで番人を置く**(CLAUDE.md)。
**「走行の前後で照合すること」という文は、破っても赤くならない。**
この wrapper は**照合を走行の一部にする**ので、**忘れるという壊れ方が無い。**
**走行後の照合が落ちたら、走行が緑でも終了コードは非 0** である。

## 数え上げを道具の既定値に任せない

`compareShas` は**不一致を全部返す**。**2026-08-30、`cmp` を既定で使ったために
2 バイト壊れていたのを 1 バイトと報告した**——`cmp` は最初の相違点で止まるが、
**止めたとは言わない。** 件数が合わなければ例外にする(ずれた対で「一致」と
言わないため)。テスト 8 本。

## ★ 同じ穴を、私はこの直前にも踏んだ

**「479 ファイル照合クリーン」と報告したが、実測は 478 である**
——ループが印字したのではなく、**私が echo の文字列に手で書いた数**だった。
**固有名は送信直前に印字からコピーする**、という自分の規律をその場で破っている。
**だからこの道具は自分で件数を印字する**(`478 / 478 一致`)。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
**置いた直後に、自分の編集で止まった。**

```
[走行前] 478 / 480 一致。**2 件が index と違う**:
  tools/tests/verified-run.test.ts  ...
  tools/verified-run.mjs            ...
```

**この 2 件は化けたのではなく、私が biome の指摘どおりに直したものである。**
**「編集した」と「化けた」を区別できない道具は、普通の作業を全部止める**
——**そして使われずに迂回される。** それでは番人にならない。

## 直し方

**`git status --porcelain` が挙げた path を除く。** 残るのは
**「git が変更なしと言っているのに、中身が違う」**——**それがこの作業台で
3 回起きた形そのもの**であり、**`git status` の死角そのもの**である
(stat が一致すると中身を読まない)。

**除いた数も印字する**(`478 / 478 一致(編集中の 2 件は対象外)`)。
**黙って除くと「全部見た」と読まれる**——**道具は自分が何を見ていないかを
言わない**、が今日の教訓なので、道具の側に言わせる。

## ★ 埋まらない穴を docstring に書いた

**編集中のファイルが同時に化けたら、この検査は見つけない。** 走行の入力が
生成物(`corpus/generated/` など)で、それを直前に作り直していれば、
**その走行はこの検査の外にある。** **その場合は、作り直してからコミットし、
きれいな木で走らせること。**

## ついでに直したもの

- **`@ts-expect-error` が未使用だった**——`tsc` が `.mjs` を解決できるので
  不要。**「型が無いはず」という私の見込みが外れていた**(`TS2578` で発覚)
- **biome の format 指摘 2 件**(`tools` 側の `biome check` が拾った)。
  **`heavy` の `pnpm lint` は `biome check . && cd ../tools && biome check .`
  の 2 本立て**で、**新しく置いたファイルは後者に掛かる**

テスト 11 本(改名の両側を除くこと、空行を無視すること、を含む)。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
段 C の締め。**書いたのは道具が印字した数だけ。**

## 確定した数

```
要求 73 → 78   被覆 40 → 66   除外 0 → 1   未達 33 → 11
測れない起因 30 → 11   **本当の穴 3 → 0**   「よそが覆う」2 → 0
コーパス 18 枚 33,567 件 → **19 枚 33,590 件**
```

**会計は合う**(66 + 1 + 11 = 78)。**9 領域のうち 6 つが満点**、`complex` は
被覆 9 + 除外 1 で 10/10 が説明済み。**残る未達は `precedence` 4 と
`cancellation` 7 だけ**で、どちらも測れない軸である。

## ★ 「測れない」という札が、穴を 5 件隠していた

**着手時、4 つの軸に「測れない」と書いてあった。3 つは誤りだった**
——`elementary/band`・`inverse_trig/band`・`complex/operation`・
`display/edge` のうち、**正しかったのは 1 つも無い**(4 つとも外した)。
**測れるようにしたら、そこから本当の穴が 5 件出てきた。**

**唯一「測れない」が残った `cancellation` も、理由の中身は誤っていた**
——引用した `1e-6` は Loan の月額を円境界で落とす基準だった。

## ★ 穴が 0 件になった道は 3 通りある

**減った数だけを見て「良くなった」と読ませない**ので、表にした
——**埋めた 17 件**(検証が増える)/**理由を貼った 1 件**(増えない。
engine が拒むという構造の理由が実在した)/**射影の誤りだった 1 件**
(増えない。**穴ではなかった**)。

**最後の 1 つは「表を綺麗にする」動きと外形が同じ**なので、
**「この訂正で赤が 1 つ消えた」と明記**し、**切れ目が私の選択であること**、
候補と件数、なぜその 1 つかも書いた。

## ★ 註が主張していた境界を、コーパスは 1 度も踏んでいなかった

`999.9999999` と `999999999.9` に「繰り上がる」と書いてあったが、
**参照実装に通すとどちらも繰り上がらない**。**緑のまま、註だけが嘘だった**
——`display/edge` を読めるようにするまで、**誰も確かめる手を持っていなかった。**

## 予測 24 件のうち 4 件を外した

- 「既存のケースは 1 バイトも動かない」→ **2,609 件が動いた**
  (帯を記録した以上、`levels` は増える。自明なのに見落とした)
- 「本当の穴 3 → 5」→ **4**(足し算の誤り。機構の予測は当たっていた)
- 押下台帳(段 B) → **測る対象を間違えた**
- **★ 「打鍵ケース 1,266 は不変」→ 1,279**。**新しいシャードは自分の標本を
  持ち込む**(13 件は上限 100 以下なので全件)。**「上限で決まるから不変」と
  考えて、枚数が増える場合を忘れた**

**正しい台帳に誤った訂正を上書きしかけた件**も残した
——**数を訂正する前に、元の数が何を数えたのかを再現する。**

## フルスイープ(`ci.yml` の 29 段を層ごとに数えてから回した)

**数えたことで、私の計画が 2 段落としていたと分かった**——`web` の
`vite build` と、`reference` の `generate.py` → `testdata/` 差分検査。
**後者は、コーパス側の生成器ばかり回していて `testdata` 側を一度も
回していなかった**という穴である。

**★ `wasm-pack test` は `--firefox` で代替した。CI は `--chrome` であり、
同一ではない**(この作業台に chromedriver が無い)。**「全層緑」と書くときは
この 1 行が要る。**

```
rust 396 / wasm 57 / web 375 + vite build + 検査 3 本 / heavy 192 /
e2e 192 / reference 467 + testdata 差分 0 / pnpm heavy 250 /
heavy:ui 37 passed(押下 19,965・打鍵 1,279・指摘 0・46 トークン全押下)
照合 全走行で 480 / 480 一致
```

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…nd one true one

厳格レビューの指摘 8 件。**全件を現物に当て直してから直した。却下 0 件**
——**当てた結果、8 件とも正しかった。**

```
被覆 66 → 73   未達 11 → 4   本当の穴 0 のまま
「測れない」と宣言した軸 3 → 1   コーパス 33,590 → 33,591 件
```

## ★ A-1【要修正】切れ目に番人が無かった(変異で実証)

**`OVERFLOW_NEAR_FLOOR = 1e307` を `1e309`(=旧射影)に戻しても
153 passed のまま**だった——**私も同じ変異で再現した。**

**理由**: **同じコミットで足した新シャードの `cmbe-000012`(`171!`)が、
旧射影でも `overflow_near` を踏む。「射影を直した」と「新シャードで埋めた」が
同じセルを同じコミットで閉じており、片方を壊しても赤くならない。**

**誤りのシャードを外した 10 枚だけで覆われることを assert した。赤確認済み。**

## ★ B-1【要修正】`cancellation/band` の理由は偽だった

「相殺の両辺は式なのでリテラルからは読めない」——**2,000 件すべてで
キー列から近さの比が取れる**(`lit±lit` 1,100 / 残り 900 も葉はリテラル)。

**そして、いちばん痛い指摘はここである**——**同じ日に `overflow_near` では
切れ目を引くことを受け入れながら、ここでは拒んでいた。基準が非対称だった。**
**しかも後者の根拠のほうが強い**: **シャード自身が `tolerance` として
`abs 5e-10` / `rel 1e-6` を宣言している**——**私が作る必要すら無かった。**

分布は `severe` 693 / `near_tolerance` 1,307 / `mild` **0**。
**`mild` は新しい穴**——**このシャードは「桁がほとんど落ちない引き算」を
1 件も作っていない。対照が無かった。** `(1000.5 - 1000.0)` を足した。
**分布を実データで固定する番人つき**(A-1 と同じ形)。

## ★ B-2 `cancellation/shape` は「測れない」ではなく「書いていない」

**生成器は `CANCELLATION_SHAPES[rng.randrange(...)]` で形を名前で選んでいる**
のに `stratum` に書いていなかった。**`associativity` は同じ手で書いている。**
書くようにしたら 4 セルが埋まった。

## ★ 6 軸すべてが「観測できない」ではなかった

着手時の宣言 6 軸のうち、**1 つも正しくなかった**——リテラルから読める(2)、
演算子キーから読める(1)、打った十進から読める(1)、生成器が名前で選んでいる(1)、
近さがキーから取れる(1)。**残る 1 軸(`precedence/grammar_class`)だけが、
読むと突合が消える。**

## B-4 残った 1 軸に届く番人を置いた

既存の 3 本はどれも届かない(帯しか見ない/`elementary` で鳴るだけ/
**射影を書かなかったことを緑にする**)。**宣言文の主張そのもの**——
**キー列の括弧が式の括弧より少ない**——を 2,000 件で見る。

## そのほか

- **`generation_rejections: {}` を載せていた。実物は 25,165 件**
  (`elementary` 11,564 / `inverse-trig` 6,945 / `combinatorics` 6,656)。
  **裁定 3 が「無い と 0 は別」と決めた当のものを潰していた。**
  源から数え直す番人つき
- **引用「`errors-000.json` の 5 件」→ 実物 8 件**(組合せ 5・階乗 3)
- **切れ目の選び方がデータ由来である旨**を明記
  (**この module 自身の規則 1 に反する**ので隠さない)
- **セルとケースを足していた**——「4 埋めた/13 新シャード」の 13 はケース数。
  **セルでは 10 / 1 / 1 / 1 の計 13 セル**
- 間欠一覧の所要時間の段落を 6 走行ぶんに更新/意図した赤の台帳の単位を明記

## ★ 道具が「見ていないと言わずに答えた」——3 例目は私の道具

**`verified-run.mjs` を `heavy/` から呼んだら落ちた。** `git ls-files` の
path は**根からの相対**なのに、**呼ばれた場所を基準に解決していた**。
**落ちたのは運が良かった——同名のファイルが両方に在れば、黙って違うものを
照合していた。** 根で解決するよう直し、**3 か所から同じ数が出るテスト**を置いた。

## ★ 「走行の一部にした」は言い過ぎだった

**どこからも呼ばれていなかった**(grep 0 件)。`heavy/package.json` に
`verify` / `heavy:verified` / `heavy:ui:verified` を足し、**docstring に
「番人の条件を半分しか満たしていない」と書いた。CI には通していない**
——**化けが出ているのはこの作業台だけ**で、**CI の runner は走行ごとに
作り直される**からである。

`reference` 473 passed / ruff / mypy、`heavy` 193 passed / typecheck / lint、
`pnpm heavy` 250 passed(赤 0)。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
… stays 1

レビュー指摘 ⑥。**設計書が 1 行も動いていなかった**——`coverage` に 4 欄が
増え、§14.2 の軸に水準が定義されたのに、**設計書にその記述は 0 件**だった。

## 足したもの

**§14.2 への追記**: **あの表は軸を挙げるが、水準を 1 つも定義していない。**
水準は `SCIENCE_FACTORS` が持ち、**どこから起こしたかを軸ごとに書いてある**
——仕様が名指しする境界/生成器が名前で選んでいる定数/**私が選んだもの**。
**最後の種類には印が付いている。**

**§14.2a(新設)**: **4 欄の表**(`not_measured_axes` /
`unmet_from_unmeasured_axes` / `unmet_real_cells` / `covered_outside_model`)
と、**それぞれが何を言い、なぜ要るか。**

## ★ `coverage.schema` は 1 のままにする(判断と理由)

- **4 欄はすべて追加**で、**schema 1 の読み手は自分が知る欄をすべて読める**
- **知らない読み手は安全側に倒れる**——門は
  `requirement.unmet_from_unmeasured_axes ?? 0` と書いてあり(実物で確認)、
  **読まない実装は未達を全部「本当の穴」と見なして落ちる。緩む方向には壊れない**
- **消費者はこのリポジトリの `corpus.ts` 1 つだけ**で、同じコミットで追随している
- **§11.1 が `coverage` に独立した `schema` を持たせたのは、既存シャードの
  `schema` を churn させないため**である。**追加のたびに上げると、その churn を
  内側へ移すだけになる**

**破壊的な変更(欄の削除・意味の変更)が起きたときに上げる**、と書いた。

## ★ 読み手だけでは埋まらない穴を、設計書に書いた(指摘 ④)

**TS の門は `unmet_from_unmeasured_axes` をシャードの申告として信じる。**
**数え直しているのは Python 側だけ**なので、**JSON を手で直せば
`pnpm heavy` は緑のまま通る。** CI は両方を回すので経路としては塞がっているが、
**「`pnpm heavy` が緑」は「会計が正しい」を意味しない。**

**読み手側で数え直さないのは意図した設計である**——数え直すには
**因子表と水準を TypeScript にも持つ**ことになり、**2 つの実装がずれた日に
どちらが正しいか誰も言えなくなる。**

`reference` 473 passed、`heavy` 193 passed、`pnpm heavy` 250 passed。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…today

差分レビューの 4 件(C-1〜C-4)+文言 2 件。**全件を現物と変異で当て直した。**

## ★ C-1 借りた数の「量」が違った

**`abs 5e-10` を帯の切れ目に使っていた。** 生成器のコメントは
**「表示分解能」**と書いている——**結果の絶対誤差の単位を持つ数**である。
**判定に使っているのは無次元の比 `|a-b|/max`** なので、**次元が合わない。**

**同じ日に 2 度目である。** 1 度目は `numerical-policy.md` の `1e-6` が
**Loan の月額を円境界で落とす基準**だった件。**「シャード自身が宣言している
数だから安全」ではない——何を測った数かを見る。**

**註を足すのではなく引き直した**(腐った根拠を残さない):

```
severe          r < 1e-10   571 件   ← 10.0 ** -DISPLAY_SIGNIFICANT_DIGITS
near_tolerance  ..  < 1e-6  1,429    ← シャードが宣言する rel(比なので整合)
mild            r >= 1e-6       1
```

**`1e-10` は「表示できる有効数字 10 桁が 1 つも残らない比」**で、
**比として意味が立つ。** `DISPLAY_SIGNIFICANT_DIGITS` は表示境界の判定と
**同じ定数**を使う(同じ「10 桁」を指しているので 1 つにした)。

## ★ C-4 「A-1 と同じ形の番人」は不正確だった

**変異で測ったら違った**(レビューの実測を私も再現):

| 動かしたもの | 落ちるもの |
|---|---|
| `REL 1e-6 → 1e-5` | **写しの一致テストだけ。分布 pin は落ちない** |
| `FULL_LOSS → 1e-12` | 写しの一致と、**記録と観測の突合** |

**分布 pin は保存された `levels` を数える**ので、**切れ目を動かしても
再生成するまで動かない。守っているのは「再生成後の分布」であって、
切れ目そのものではない。** docstring を実測の表に書き換えた。
**それでも要る**——**切れ目が同じまま分布が偏っても、上の 2 つは緑**であり、
**帯が空になったことはここでしか見えない。**

## C-2 足した 1 件は「代表」ではない

`(1000.5 - 1000.0)` は**どちらも二進で厳密**、差 `0.5` も厳密で、
**丸めが一切関与しない。最も清潔な対照だが、「桁が少しだけ落ちる引き算」の
代表ではない**——そう書いた。

## C-3 shape の突合は 2 経路ではない

**観測側も記録側も同じ `stratum` を読む**ので、**一致は定義上成り立つ**
(`associativity/shape` と同じ)。**`stratum` が木と食い違っても assert は
鳴らない**——**守っているのは帯の分布 pin で、間接的である。**

## そのほか

- **§14.2a の「消費者は `corpus.ts` 1 つだけ」は数え違い**——`Coverage` を
  読むのは **4 ファイル**(`corpus.ts` / `report.ts` と spec 2 本)。実測。
  **`?? 0` で安全側に倒れるので結論は変わらない**
- **`verified-run.mjs` の印字「編集中」は不正確**——`git status --porcelain` は
  **未追跡も挙げる**。**「git が変更を把握している N 件は対象外」**に直した

`reference` 473 passed / ruff / mypy、`heavy` 193 passed / typecheck / lint、
`pnpm heavy` 250 passed(赤 0)。**`heavy:ui` は次に回す。**

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…d say why

段 C と 2 巡のレビューの締め。**記録を実測に当て直し、引き継ぎを枝の
最終状態にした。**

## ★ 押下台帳——予測が完全に一致した

```
          予測      実測
テスト     37       37(11.9 分)
総押下     19,965   19,965
打鍵ケース 1,279    1,279
指摘       0        0
46 トークン全押下 ✓
```

**導出**(賭けではなく算術): 動いたのは `cancellation` の 2000 → 2001 だけ。
`spread(100, length)` は `floor(i · length/100)` で、`step` は 20.00 → 20.01 に
なるが、**`floor(i·20.01) = 20i + floor(0.01i)` で `i ≤ 99` なら `0.01i < 1`**
——**ずれが 1 に届かない。** 足したのは index 2000 で、**選ばれる最大は 1980。**
**実測でも `cancellation` の打鍵は 100 件のまま**だった。

**「変わらなかった」ではなく「変わらないはずのものが変わらなかった」である。**
**押下台帳は 3 回外していて、うち 2 回は「不変」と書いて外した**
——今回は**同じ結論に、検算できる理由で**着いた。

## 記録の数を、送る前に自分で当て直した

**Task 18 の節が C-1 の引き直し前の数のままだった**(`severe` 693 /
`near_tolerance` 1,307 → **571 / 1,429**)。**「記録の数が古い」は今日 2 回
やっている**(段 B の `levels`、押下台帳)ので、**送る前に当てた。**

**★ そのとき、別の数を巻き込みかけた**——`693` と `1,307` は**金融の節にも
無関係な数として出る**(`FINANCE_STRATA` の下限合計と、乱択層の件数)。
**一括置換していたら、直したつもりで 2 か所を壊していた。**

## 引き継ぎを枝の最終状態にした

```
tip f45b658 / 29 コミット / 完走
要求 78 = 被覆 73 + 除外 1 + 未達 4(precedence/grammar_class のみ)
本当の穴 0    「測れない」と宣言した軸 1(着手時 6)
コーパス 19 枚 33,591 件    変更 34 ファイル
```

**`crates/` と `web/src/` は 1 バイトも触っていない**——**利用者から見える
変化は 0 件**で、**版数は 0.6.0 のまま**という見立てを書いた。

**この作業台がファイルを化けさせること**と、**その手当て**
(`heavy:verified` / `heavy:ui:verified`)も §1 に書いた
——**ユーザーの判断でメモリ検査はしていない**ので、**次に入る人は
最初にそれを知る必要がある。**

**次の段の材料 3 つ**も残した(`precedence` の第 3 類型/`mild` の代表性/
`nPr`/`nCr` の Overflow の境目)。

`reference` 473 passed、`heavy` 193 passed。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@terapyon
terapyon merged commit 186d4d1 into main Aug 30, 2026
6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant