# 校準檢查點：停止（2026-09-14）

**結論：校準做了兩輪，兩輪都在網格階段停止。**
第 0 輪（原設計）沒有任何參數組合同時通過 B1 與 B2，依規格 §13／§14 停止；
使用者之後核准一輪有文獻根據的重設計（第 1 輪：O1、O4、O7，見 §6），並事先約定「重跑校準後 B2 若在整個網格仍過不了，專案就永久停止」。
第 1 輪的官方校準仍然 180/180 格 B2a 失敗，**依這條停止規則，本專案到此停止。**
正式的學習組 vs 對照組實驗（Task 21）沒有跑，本專案不對「果蠅有沒有學會」下任何結論。

使用者的決定，依時間順序：

1. 第 0 輪之後（A + D）：誠實記錄停止（本文件），另外讓頁面在明確標示「未通過生物學校準」的試玩模式下可以玩。
2. 之後（選項 2）：只做一輪重設計（O1 幾何角張度、O4 LPLC2 徑向選擇性、O7 拿掉 LOOM → LOOM 連接），重跑校準；B2 仍在整個網格失敗就停止。

相關檔案：

| 檔案 | 內容 |
|---|---|
| [`results/round0-calibration.json`](../../results/round0-calibration.json) | 第 0 輪校準報告（`verdict: FAIL`、`abort.stage: grid`、180 個網格點的篩選紀錄；原本叫 `results/calibration.json`，內容沒改） |
| [`results/round0-calibrate.log`](../../results/round0-calibrate.log) | 第 0 輪執行紀錄 |
| [`results/round0-calibration-gate.txt`](../../results/round0-calibration-gate.txt) | 第 0 輪決策規則（`tools/calibrationGate.mjs`）的輸出 |
| [`results/calibration.json`](../../results/calibration.json) | 第 1 輪（重設計後）校準報告（`verdict: FAIL`、`abort.stage: grid`、180 個網格點的篩選紀錄） |
| [`results/calibrate.log`](../../results/calibrate.log) | 第 1 輪執行紀錄 |
| [`results/calibration-gate.txt`](../../results/calibration-gate.txt) | 第 1 輪決策規則的輸出 |
| [`results/demo-params.json`](../../results/demo-params.json) | 試玩模式參數的完整推導紀錄，在第 1 輪紀錄上重跑（**不是**校準結果） |

## 1. 第 0 輪：跑了什麼

```bash
node tools/calibrate.mjs --circuit data --out results/calibration.json --jobs 12 > results/calibrate.log 2>&1
```

（當時寫到 `results/calibration.json`／`results/calibrate.log`／`results/calibration-gate.txt`；第 1 輪之前改名成 `results/round0-*`，內容沒改。）

- 完整預設流程（`CALIBRATION_PROTOCOL`）：B1 用 3 個種子 × 60 秒、B7 完整 200 回合。沒有縮短任何一項。
- 迴路：當時的 `data/fly-circuit.*`，4,960 個神經元、262,089 條連接、57,448 條可塑連接。
- 網格：`sGlobal` {0.5, 0.75, 1.0, 1.25, 1.5, 2.0} × `fBg` {28…38} × KC 背景頻率 {16.3, 24.45, 32.6, 40.75, 48.9} Hz = 180 格。
- 流程先做篩選（每格 B1 種子 1 × 5 秒，B1 通過才跑 B2a），通過篩選的格子才跑完整 B1 與 B2a–B2e。
  **180 格全部在篩選時就沒通過 B2a**，所以完整階段是 0 格，程式在 12 個 worker 上 37.8 秒後於 `grid` 階段停止，並寫出部分報告。

決策規則的判定（`results/round0-calibration-gate.txt`）：

```
ok: false, mustStop: true, stage: "grid", failed: ["B2a"], candidateCount: 0
B1 與 B2 在 180 個網格點中都無法同時通過（每個檢查的失敗次數：{"B1":0,"B2a":180,"B2b":0,"B2c":0,"B2d":0,"B2e":0}；篩選階段沒跑到的檢查不計）。停止，並回報使用者。…
```

## 2. 第 0 輪：數字

**B1（靜止，背景開、可塑性關）篩選：180/180 通過。** 兩個 Giant Fiber 都是 0 次放電，KC 平均放電率 0–0.24 Hz（門檻 < 0.5 Hz）。
這是篩選用的 B1（種子 1 × 5 秒）；完整的 B1（3 個種子 × 60 秒）只在通過篩選的格子上跑，這次沒有任何格子走到那一步。

**B2a（r/v = 40 ms 的標準逼近，10°→90°）：180/180 失敗。** 兩個 GF 都會放電，但太早：

| sGlobal | 首次放電角張度 | 30 格的 KC 放電率 | 一次逼近的 GF 放電次數 |
|---|---|---|---|
| 0.5 | 10.53° | 0–0.238 Hz | 145 |
| 0.75 | 10.48° | 0–0.158 Hz | 442–449 |
| 1.0 | 10.43° | 0–0.119 Hz | 662–665 |
| 1.25 | 10.43° | 0–0.093 Hz | 725 |
| 1.5 | 10.41° | 0–0.078 Hz | 746–747 |
| 2.0 | 10.38° | 0–0.059 Hz | 776–777 |

要求是 25°–90°。圓盤從 10° 開始擴張，大約 20 ms 後 GF 就放電；同一個 `sGlobal` 下與 `fBg`、KC 頻率完全無關，
`sGlobal` 從 0.5 到 2.0 也只差 0.15°。

Task 20 PART A 另外抽查了三個格子的完整 B2（0.5/28、1.0/32、2.0/38；同一套程式，數字可重現，但**不是**這次校準報告的一部分）：

- B2b（尺寸不變性）通過：首次放電角張度的極差約 1.4°（全部都在 10–12°）。
- **B2c（單調性）方向相反**：r/v 越慢，GF 放電越多（例如 1.0/32：438 → 663 → 892），規格要求單調下降。
- B2d（負對照）只在 2.0/38 失敗：後退時 GF 放電 2 次；另外兩格是 0。

## 3. 第 0 輪為什麼失敗（診斷；以下數字全部來自草稿腳本，**不是校準結果**）

診斷用的是與 `calibrate.mjs` 相同方式建的參數（fBg 32、KC 32.6 Hz、sGlobal 1.0 與 0.5、種子 1），
加上儀器化的引擎／視野副本；副本完全重現了上面的數字（10.53／10.43／10.38°、438／663／892、2.0/38 的 2 次後退放電）。

1. **LOOM → GF 是一觸即發（主要原因）。** sGlobal 0.5 時，只要權重最大的一個 LOOM 細胞以 150 Hz 放電、
   或兩個中位數權重的細胞、或 8 個中位數細胞以 20 Hz 放電，就足以讓 GF 放電；sGlobal 1.0 時一個中位數細胞就夠。
   開迴路下，sGlobal 0.5、r/v 40 時，視野驅動造成的 GF 去極化在 10.5° 就有 17–21 mV、到 40° 有 103–120 mV
   （放電門檻 7 mV；文獻中的逼近反應約 2.4 mV）。
2. **規格 §6 的 LPLC2 轉換一開始就全開。** `150 Hz × min(1, θ̇ / 50°/s) × (c > 0)` 讓約 40 個 LPLC2（左 23／右 17）
   在圓盤開始擴張的 1 ms 內就放電（r/v 10 時 47 個，其中 27 個飽和）；從約 15° 起在所有 r/v 下驅動都是飽和的。
   帶動 GF 的 LPLC2 感受野中心離圓盤中心 3.6–41°，多數回報的是大致正確的擴張速度。
3. `θ_i = 2R√c_i` 的 √c 奇異點是真的，但影響小：拿掉它，首次放電只從 10.5° 移到 10.7°。
4. **B2c 為什麼反過來。** 從 10.5° 到 90° 的驅動幾乎與 r/v 無關，所以越慢的逼近（擴張 104／417／834 ms）放電越多；
   sGlobal ≥ 1 時 20,254 條興奮性 LOOM → LOOM 連接讓 LOOM 族群持續放電，碰撞後又多出約 370 次 GF 放電
   （0.5/32 時維持 500 ms 期間只有約 14 次，1.0/32 時約 374 次）。
5. **B2d 的 2 次放電**：後退時視野給 LOOM 的驅動是 0；這 2 次來自 VPN_MB（對暗區比例變化不分正負）→ RELAY（DNp70 等）→ GF。
6. 僅供診斷：sGlobal 0.5 時把 LPLC2 靜音，B2a（58.7°）、B2c（8/8/7）、B2e（47.7°）都會通過，但 B2b 反而失敗。

## 4. 有文獻根據的修改選項（第 0 輪之後的草稿測試；參數 0.5/32/32.6 與 1.0/32/32.6）

| 選項 | 要改規格 | 草稿結果 |
|---|---|---|
| O1 幾何角張度（不用 √c） | §6 | B2a 10.7°／10.5°，對失敗沒有影響 |
| O3 θ̇ 低通濾波 | §6 + 一個自由時間常數 | 更差（放棄） |
| O4 LPLC2 徑向選擇性（Klapoetke 2017） | §6 | O1+O4 在 0.5：B2a 21.5°（其他種子 14.3°、18.4°），B2c 9/26/41 仍失敗，B2e 20° 失敗；在 1.0：14–15° |
| O7 拿掉 LOOM → LOOM 連接 | §4 | 去掉維持期放電（1.0 時 B2c 50/142/217），但 B2a 不變；O1+O4+O7 在 0.5：21.5°，B2c 9/22/33，B2e 20° |
| O5 依文獻定 LPLC2 輸出強度 | §6（會讓 B2 部分變成循環論證） | 未試 |
| O6 誠實停止 | 無 | — |

有原則的修改最好也只把首次放電推到 14–22°，仍不及 25°。診斷的建議是 O6；使用者先決定 A + D（誠實停止 + 明確標示的試玩模式），
之後又決定用 O1 + O4 + O7 做一輪重設計（§6）。

## 5. 第 0 輪之後「誠實停止」代表什麼

- **沒有做的事**：沒有放寬 B1–B7 任何一項、沒有擴大網格、沒有動世界參數，也沒有看任何遊戲分數。
  第 0 輪時也沒有改視野模型或迴路選取（O1／O4／O7 當時只在草稿裡；第 1 輪才由使用者核准寫進規格與程式，見 §6）。
  KC→KC 為 0、世界速度 ×10、可塑性含增強分支都維持使用者的決定。
- `brain/params.js` 的五個校準值維持 `null`；η 與 β 的校準階段（B4–B7）因為網格沒有通過而沒有執行。
- `tools/run_experiment.mjs` 開跑前會用決策規則（`tools/calibrationGate.mjs` 的 `assertCalibrationUsable`）檢查校準報告，沒通過（包括縮短流程的 PASS 與沒有 verdict 的檔案）就拒絕；只有明確加上 `--allow-failed-calibration` 才會照跑，而且輸出的 `config.calibrationGate` 會記下「未通過、已略過」。所以正式實驗（Task 21）沒有跑。
  規格 §11 事先固定的判定規則（最後 20 回合配對差 > 0 且階層式 bootstrap 95% 信賴區間不含 0）**沒有被套用**，
  不宣稱「有學習證據」，也不宣稱「沒有學習證據」。
- 要繼續就必須先由使用者決定規格 §6（或 §4）的修改，再從頭跑完整校準，不能沿用舊報告挑一個格子。第 1 輪就是這樣做的（§6）。

## 6. 重設計第 1 輪

### 改了什麼（使用者核准；規格 §2、§4.2、§6，commit 5757fbd、78dbead、18f6562）

1. **O1 幾何角張度**：視野裡每個 LOOM 細胞看到的角張度 θ_i，改成物體與感受野圓盤交集、沿物體邊緣移動方向的寬度
   （圓盤取中心連線上的弦長，方塊取兩軸寬度較小者），不再用 `2R√c_i`。θ̇_i 取「上一格已經存在」且擴張最快的那個物體。
   管子等方塊取兩軸寬度較小者，所以水管上下緣垂直掃過時寬度幾乎不變、θ̇ ≈ 0，不會驅動逼近偵測。
2. **O4 LPLC2 徑向選擇性**（Klapoetke et al. 2017 的簡化）：LPLC2 只有在感受野中心落在寬度正在變大的物體裡面時才被驅動；
   LC4 不受這條規則影響（仍用覆蓋率門檻）。這不只限於真正擴張的物體：大物體平移時，越過感受野中心往外移的那條邊
   也會讓感受野裡的寬度變大，一樣會驅動 LPLC2。
3. **O7 拿掉 LOOM → LOOM**：LC4/LPLC2 → LC4/LPLC2 的 20,254 條連接（67,833 個突觸）和 KC→KC 一樣設為 0、不寫進連接檔。
   迴路變成 4,960 個神經元、**241,835 條連接**、57,448 條可塑連接；角色數、可塑連接、獎懲 DAN 數都沒變。

### 跑了什麼

```bash
node tools/calibrate.mjs --circuit data --out results/calibration.json --jobs 12 > results/calibrate.log 2>&1
```

同一套完整預設流程、同一個 180 格網格、同一套篩選規則。**180 格全部在篩選時就沒通過 B2a**，
完整階段 0 格，12 個 worker 上 33.7 秒後於 `grid` 階段停止並寫出部分報告（exit 1）。

決策規則的判定（`results/calibration-gate.txt`，和第 0 輪用同一段指令）：

```
ok: false, mustStop: true, stage: "grid", failed: ["B2a"], candidateCount: 0
B1 與 B2 在 180 個網格點中都無法同時通過（每個檢查的失敗次數：{"B1":0,"B2a":180,"B2b":0,"B2c":0,"B2d":0,"B2e":0}；篩選階段沒跑到的檢查不計）。停止，並回報使用者。…
```

### 數字（全部來自 `results/calibration.json` 的 `grid.screen`）

**B1 篩選：180/180 通過。** 兩個 GF 都 0 次放電；KC 放電率和第 0 輪逐格相同（0–0.238 Hz）。

**B2a（r/v 40 ms）：180/180 失敗。** 兩個 GF 在每一格都會放電；首次放電變晚了，但沒有任何一格到 25°：

| sGlobal | 首次放電角張度 | 擴張開始後幾 ms | 30 格的 KC 放電率 | 一次逼近的 GF 放電次數 | 第 0 輪（角張度／放電次數） |
|---|---|---|---|---|---|
| 0.5 | **21.55°** | 247 | 0–0.238 Hz | 22 | 10.53°／145 |
| 0.75 | 15.43° | 162 | 0–0.158 Hz | 26 | 10.48°／442–449 |
| 1.0 | 14.79° | 149 | 0–0.119 Hz | 29 | 10.43°／662–665 |
| 1.25 | 14.70° | 147 | 0–0.093 Hz | 32 | 10.43°／725 |
| 1.5 | 14.37° | 140 | 0–0.078 Hz | 29–30 | 10.41°／746–747 |
| 2.0 | 11.33° | 54 | 0–0.059 Hz | 31 | 10.38°／776–777 |

同一個 `sGlobal` 下，30 格的首次放電角張度仍然完全相同（與 `fBg`、KC 頻率無關）。r/v 40 時圓盤要在擴張開始後約 277 ms 才到 25°；
最好的一格（0.5）在 247 ms、21.55° 就放電。0.5 是網格軸的下限，規格不允許擴大網格。

**B2b–B2e：沒有進正式紀錄**（沒有格子通過篩選，完整階段沒有跑）。下面是草稿檢查的數字，**不是校準結果**：
用 `calibrate.mjs` 自己的 `executeJob({kind: 'fullCell'})`、種子 1、可塑性關，在已提交的程式與迴路上跑。

| 格子（sGlobal/fBg/KC） | B2a | B2b（10／40／80 首次放電，極差） | B2c（10／40／80 放電次數） | B2d（後退／靜止／變暗） | B2e |
|---|---|---|---|---|---|
| 0.5/32/32.6（Task 22a） | 21.5° 失敗 | 27.9／21.5／25.7°，6.3° 通過 | 9／22／33 **失敗**（越慢越多） | 0／0／0 通過 | 20.0° 失敗 |
| 0.5/38/32.6（Task 22b，試玩格） | 和上一列完全相同 | 同上 | 同上 | 同上 | 同上 |
| 1.0/32/32.6（Task 22a） | 14.8° 失敗 | 19.1／14.8／15.5°，4.4° 通過 | 14／29／46 **失敗** | 0／0／0 通過 | 14.3° 失敗 |

草稿與正式紀錄吻合：草稿的 B2a 21.5°／14.8° 就是正式篩選的 21.55°／14.79°；而草稿又與第 0 輪之後原型腳本裡 O1+O4+O7 那幾列逐項相同，
表示程式碼做的正是原型測過的東西。

### 結論（停止規則）

第 1 輪與第 0 輪一樣，B1 在整個網格都通過、B2a 在整個網格都失敗，決策規則 `mustStop: true`。
依使用者事先同意的停止規則，**本專案到此停止**：不再修改規格或模型、沒有放寬 B1–B7、沒有擴大網格，
`brain/params.js` 的五個校準值維持 `null`，B4–B7 的校準階段沒有執行，正式實驗（Task 21）沒有跑，
§11 的判定規則沒有被套用，不宣稱有或沒有學習證據。

## 7. 試玩模式（D）：用什麼參數、它們沒通過什麼

試玩模式讓頁面在 `brain/params.js` 仍未校準時也能玩，但**這組參數沒有通過生物學校準，不代表真果蠅，也不做學習結論**。
數值放在 `PARAMS.demo`，由 `tools/demoParams.mjs` 只從生物學紀錄與規格敘述推出（完全不看遊戲分數），全部過程記在 `results/demo-params.json`。
第 1 輪之後用同一套規則在新的 `results/calibration.json` 上重跑：和第 0 輪的檔案相比只有產生時間與迴路連接數（262,089 → 241,835）不同，
選到的格子、每一階 η 與 625 組聯合搜尋全部相同，所以數值沒變。

| 欄位 | 試玩值 | 怎麼來的 | 沒通過什麼 |
|---|---|---|---|
| `gain.sGlobal` | 0.5 | 規則：網格軸的最小值；B1 篩選在這裡全部通過（兩輪都是）。第 0 輪時另外附註「0.5 時維持期的 GF 放電少很多（約 14 次，1.0 時約 374 次，來自 LOOM → LOOM 連接）」；第 1 輪已經拿掉這些連接，**這條附註不再適用**，但規則本來就不靠它，照原規則套用 | B2 仍失敗（第 1 輪 B2a 21.55°；第 0 輪 10.53°） |
| `background.rateHz.KC` | 32.6 Hz | Task 14 選格規則 (a)：最接近 Turner 2008 的 32.6 Hz | — |
| `background.fBg` | 38 | 選格規則 (b) 套在 sGlobal 0.5 的 B1 篩選紀錄上：KC 放電率最接近 0.1 Hz（0.101 Hz；篩選是 1 個種子 × 5 秒；兩輪紀錄相同）；38 是網格軸的上限 | — |
| `plasticity.etaLtd` | 3.16228 | 在這個格子上跑 `calibrate.mjs` 自己的 B4/B5 搜尋（25 階梯、依序再 625 組聯合搜尋、γ 系列懲罰分區）：**沒有任何一組同時通過 B4 與 B5**（27 組過 B4、39 組過 B5，沒有一組兩個都過）；取離兩個通過帶中心最近的一組（以半帶寬為單位的距離 4.31） | **B4 失敗**（w/w⁰ 0.337，要求 0.10–0.25） |
| `plasticity.etaLtp` | 10 | 同上；10 是階梯的最上層；η_LTP/η_LTD = 3.16（文獻比值約 2.9，只報告不選） | **B5 失敗**（w/w⁰ 1.055，要求 1.6–2.0） |
| `plasticity.betaDaAlone` | 1e-4 s⁻¹ | 規格 §5.2 給的量級下限；**假設值** | B7 沒有跑 |

B2d 的 0 次放電在哪裡量的：第 0 輪是 0.5/28（Task 20 PART A）與 0.5/32（診斷），不是試玩格 0.5/38；
第 1 輪的草稿在 0.5/32 與試玩格 0.5/38 都是 0。B6、B7 都沒有在試玩參數上跑過。

試玩時果蠅的樣子，照實記錄、**沒有因此改任何參數**。下面分清楚哪些來自瀏覽器、哪些來自 Node 重播
（Node 重播＝同一套模組、`withDemoParams(PARAMS)`、同樣的 6 隻果蠅與種子、本機大腦 port、真實迴路）：

- **第 0 輪模型**
  - 瀏覽器（Chromium headless shell，真實迴路）：按下試玩按鈕到可以開始約 0.15–0.19 秒、6 個 worker；
    大腦時間／真實時間 0.96–0.99×（60 fps）；45 秒內跑了 29 回合，IndexedDB 裡六隻果蠅每回合都是 0 根管子。
  - Node 重播前 6 回合：六隻果蠅從回合開始約 0.1 秒（第 5–7 格）起幾乎每一格都拍翅（每回合 28–31 次），一路往上衝，
    大約 0.58 秒（第 35–37 格）時撞上第一根管子的上段而死；學習組與對照組的差別只在一兩次拍翅。
- **第 1 輪模型**
  - Node 重播 20 回合：第一次拍翅在第 7–14 格（約 0.12–0.23 秒）；回合開始的第一秒內平均每秒拍 45 次（每隻每回合 37–50 次／秒，
    約每 4 格拍 3 次），一路往上衝。第一根管子的前緣在第 34 格到達果蠅。第一根管子的開口靠近畫面上方時多半穿過去（1 根），
    接著在第 54–62 格（約 0.9–1.0 秒）撞到畫面頂端；其他時候在第 35–38 格（約 0.6 秒）撞上管子上段（0 根）。
    每回合 0 或 1 根管子，兩組平均都是 0.4 根、存活 43.75 格；每一回合、每一對的學習組與對照組管子數、存活格數與拍翅次數都相同，
    只有 GF 放電次數最多差 2。
  - 瀏覽器（同上環境）：開機到可以開始 1.1 秒、6 個 worker；30 秒跑 16 回合，讀數 0.98–1.00×；
    IndexedDB 裡每回合每隻果蠅的管子數與 Node 重播的前 16 回合完全一致；Console 沒有 error。

拍翅由模型裡的哪些放電造成、為什麼開口高低會決定結果，這裡沒有逐格量測，不下因果結論。

## 8. 與這次停止無關、但仍待使用者決定的候選（Task 20 PART A 報告 §2）

- 規格 §4.3 分區比對：β'2p 的 DAN（PAM05，20 個）配不到 β'2mp 的 MBON（MBON03／04，2,888 條可塑連接）；
  `MBON19(a2p3p)` 解析時丟了 α3p；`MBON26(b'2d)` 的小寫 `b` 沒被解析。都沒有改規則。
- 收到 VPN_MB 輸入的 KC 在匯出的迴路裡是 330 個，規格 §2 寫 337。差別不是選取：337 算的是選出的 132 個 VPN_MB 全部的突觸；其中 8 個（章魚胺 6、血清素 1、多巴胺 1）訊號為 0，它們的連接在匯出時被濾掉，只從它們收到輸入的 7 個 KC 在迴路裡就沒有視覺輸入（2026-09-14 最終審查時用 `data/raw/` 重算：132 個 → 337 個 KC、11,157 突觸；訊號不為 0 的 124 個 → 330 個 KC、10,905 突觸）。
