Fullseye 設計判斷集(由原始碼中的 ★ 註解產生)
日本語 · English · 简体中文 · 繁體中文 · 한국어 · Deutsch
本倉庫把「為什麼是這樣」寫在原始碼註解裡。其中標了 ★ 的是真正管用的部分——量出來的結論、踩過的坑、這樣做的理由。本頁由它們機械彙集而成,正本在原始碼一側,因此兩者不會走樣。
翻譯進度:610 / 681 條。未翻譯的條目照原文(日文)顯示——悄悄回退到原文會看著像已翻譯,所以沒譯就明說沒譯。
accel_match.py
- L170 — ★視窗必須比範本大,否則完全重疊的位置數會變為零 → r = T//2 + f(粗誤差) + win。
acoustics.py
- L1173 — ★
med == 0 一律當作 inf 處理——連 peak 也為 0 時(靜音、頻帶內什麼都沒有)也報告「無限突出的峰」。正如 docstring 所述,這兩個數本是對「即使什麼都沒有也會回傳峰頻率」的誠實性指標,卻偏偏朝最會說謊的方向擺動。0/0 的答案是 0.0。(2026-09-05:在 Linux / numpy 2.5.2 上暴露。舊版只是濾波殘差略有殘留使 med > 0,缺陷一直就在。)
- L1181 — ★全域中位數在收窄頻帶時會顛倒順序(純雜訊 11375 對真正的缺陷 9433。2026-09-06 實測,見 _local_prominence 的表)。做與頻寬無關的判定時用這個。既有的兩個保持含義不變而保留——同名而內容改變,比增加一個更危險。
- L1789 — ★
med == 0 一律當作 inf 處理——連 peak 也為 0 時(靜音、頻帶內什麼都沒有)也報告「無限突出的峰」。正如 docstring 所述,這兩個數本是對「即使什麼都沒有也會回傳峰頻率」的誠實性指標,卻偏偏朝最會說謊的方向擺動。0/0 的答案是 0.0。(2026-09-05:在 Linux / numpy 2.5.2 上暴露。舊版只是濾波殘差略有殘留使 med > 0,缺陷一直就在。)
annotate.py
- L3095 — ★標點(。、)本應不旋轉而是靠向右上,但這裡不靠——與其默默近似做不到的事,不如寫進 docstring 留存。直排中靠向右上的字(標點)。橫排時位於字左下的點,直排時來到右上——排版之道是移動位置而非旋轉。Windows 的
@ 前綴字型(GDI 按 face 名選擇的直排字面)在字型側做了這件事。Pillow 以檔案路徑開啟字型,搆不到 @ 字面,HarfBuzz 的 direction="ttb" 也會因是否安裝 Raqm 而結果不同(本機 Pillow 12.3.0 的 features.check("raqm") 為 False)。遵循選擇跨平台一致者的方針,這裡用合成來靠位。
api.py
- L587 — ★
annotate.overlay_mask 有意不暴露到頂層。同名的 imgio.overlay_mask 已作為 fs.overlay_mask 公開,其參數與含義都不同(imgio = 原始 RGB、mask>0.5、fill/margin / annotate = 角色名的顏色、也可用權重 [0,1]、拒絕形狀不匹配)。在同名上載入不同的約定,呼叫方收到的不是例外而是看似合理卻不同的圖。公開 API 的破壞性變更不擅自做,故帶角色的那個用 fs.annotate.overlay_mask 取用。
- L1346 — ★ 目前對彩色影像沒有正確的呼叫方式:整批傳入會混色,按通道呼叫 3 次會讓自正規化的 op 把每個通道除以各自的最大值,破壞通道間的比值(灰階邊緣法的角度誤差從自建 Sobel 的 1.03 度 -> 每圖 4.17 度 -> 每通道 27.86 度,零點 29.14 度)。倒向哪一邊是合約的決定,所以這裡不改動任何一個預設數值,僅在
on_error="raise" 時拒絕,預設則記入台帳使其可見。詳情與選項見 docs/KNOWN_ISSUES.md。
astrostack.py
- L156 — ★假設檢定:我們預測「只要能裝進一條快取行(64B)就不值得搬移」,但猜錯了。float32 的臨界點在 K≈17-19,接近 64B(K=16),但 float64 的實際臨界點是 K≈23-25(約 200B),而預測是 K=8。決定它的是元素個數而非位元組數 —— 每個元素的取出開銷佔主導。數量少時搬移反而更慢(float64 K=5 時慢 1.4 倍),所以臨界點必不可少。
-
| L379 — ★MAD 塌縮為 0 但影像並不平坦 = 量化(2026-09-08,poc_thermal_radiometry 踩到的)。整數 DN 下 |
x-med |
也是整數,所以能回傳的 sigma 只能是 1.4826 的倍數 —— σ=0.5 的實拍等效回傳 0.0,σ=1.0 與 σ=1.983 都給出同一個 1.4826。悄悄回傳 0 會讓閾值與背景相同,下游(star_detect)什麼都找不到。這裡是回傳數值的入口,所以不 raise 而是發出提示(呼叫者可以選 method=”clip”)。refuse 是出答案一側 = star_detect 的職責。 |
- L586 — ★ 散粒雜訊的唯一入口。photons_per_unit=1 時「期望值 = lambda」。
- L675 — ★ field_seed 固定(同一片天空),只變動 seed(不同的觀測)。
- L746 — ★在 2026-09-08 之前這個門的註釋寫著「完全平坦 = 無法測量雜訊」。錯的是前提 —— σ 變成 0 還有另一條路徑,即整數 DN 下 MAD 塌縮的情況(σ=0.5 等效的實拍為 0.0)。對不平坦的影像回傳空並非保守的答案,而是錯誤的答案;實際上植入 200x200 整數幀的 2 個點目標被回傳為 0 個。於是分開路徑:平坦則回傳空(沒有星),不平坦則拒絕。
- L1606 — ★平手時選擇原始票數更多的 bin。3x3 平滑從真峰的左右兩側看都得到相同的和,所以只用平滑值取 argmax 可能選中「峰旁邊的空 bin」—— 實測正是如此:真實位移 (-0.087, +0.996) 的 7 + 4 票在 bin 邊界被一分為二,而其中心偏了一個 bin 變成0 票(frame_align 誤以為「沒有重疊」而 fail-closed)。1e-6 的權重遠小於平滑值的步長(1/9),所以在真有差異時不會改變排序。
- L1629 — ★2026-09-08:同時回傳第二高峰的高度。星野只有一個峰,但重複結構(網點、光柵、織物)中,等高的峰會沿格矢方向平移排列,無論選哪個都會「全體贊成」= inlier_ratio 變成 1.00。贊成率並不是「答案正確的機率」,所以用另一個數來給出是否只有一個峰(0 = 單峰,接近 1 = 還有其他等價候選)。
backend_safe.py
- L436 — ★feature op 回傳的是 numpy 純量而非 ndarray,所以上面的分支從未見到它:NaN/Inf 的測量值(例如對退化影格呼叫 sk_blur_effect 內部的 0/0)會直接從 api.apply 流出。把非有限純量也洗到 sort 回退,使所宣告的「有限、sort 有效」保證對 feature/contour 純量也真正成立。
backends.py
- L23 — ★
_safe 回退是最後手段,並且可能掩蓋已死的 op。當 out_sort==”image” 時 backend_safe.fallback 回傳裁切後的輸入,於是一個對任何輸入其函式庫呼叫都會拋例外的 wrapper,在進化 / difftest / coverage 看來就像一個能運作的恆等 op 而非失敗。執行時的健壯性得以保留,但退化是可偵測的:每一個被吞掉的例外都記錄到共享的回退台帳,strict 模式下則改為重新拋出。2026-09-02:把台帳 / strict 開關下移到 backend_safe,使其他 23 個 backend 檔案(各有私有的 _safe)都向同一處報告——在此之前,24 個 wrapper 族中只有本模組會記錄任何東西。下面的名字作為供從此處匯入的呼叫方與測試使用的薄別名保留。
- L812 — LBP 編碼。★在 2026-09-08 之前
b 其實什麼都沒做,method 固定為 'default'(非旋轉不變)。在實拍紋理(brick / grass / gravel)上測量,各向異性材料在旋轉下移動的量是材料間距離的 9.64 倍,換成 'uniform' 後降到 1.72 倍(examples/poc_real_texture_invariance.py)。不能選就無從降低,所以分配了 b。做成閾值表是當同一軸上分支增多時的規約(不用巢狀 if)。b=0.5(預設)照舊為 'default'。
- L1028 — ★向 cv2 傳入 bool 陣列會讓
cv2.Laplacian 破壞堆積,進而在後續無關的 op 處讓行程崩潰(2026-09-05 Fable 評審,我在 Windows 上 100 次內自行重現了 SIGSEGV,exit 127)。facade 會把 dtype 對齊到合約,但 op.fn 直接路徑(測試、coverage、進化迴圈)是直通的。在族的入口對齊為 float64。
backends_auto.py
- L594 — ★不改變畫布(reshape=False)+ 邊框外鏡射(mode=”reflect”)。角度為 -45°..+45°(a=0.5 時為 0°)。四角會折返映入原圖,所以對像單據校正(deskew)那樣「想用背景色填充框外」的用途,直接用並不合適(這是已知的設計判斷而非 bug — 詳情與取捨見
ops._rotate_img 的 docstring)。
- L617 — ★但回傳值的 shape 要保持在與輸入相同的畫布上。這個 registry 的 image 有「段間無條件銜接」的合約,改變 shape 會讓評估器無法與目標影像對齊而崩潰(實測:目標尺寸版回傳 (70,50) 的瞬間,
test_evolve_is_reproducible_given_seed 以 “operands could not be broadcast together with shapes (70,50) (64,64)” 失敗)。於是把重取樣到 Ht x Wt 的像放在畫布左上角,邊距填 0,超出部分裁掉 —— 「影像現在是 Ht x Wt 像素」這一點照舊可見。
- L1111 — ★2026-09-02:它回傳的是
np.where 的整數像素座標本身,雖自稱 sub_pix 卻沒有次像素精度。新增了透過拋物線擬合沿法線方向的精化(與 core ops._edges_sub_pix 相同的共享輔助函式。同名 op 在註冊表中後者勝出,所以實際執行的是這個 —— 只改 core 無效)。實測(真實位置在列 20.37 的合成階躍邊緣,a=0.2):舊實作回傳的列為 {20.0, 21.0},平均絕對誤差 0.500 px,精化後為 {20.324, 20.370},0.0228 px(約 22 倍改善)。點的個數與連通分量的劃分不變(座標只移動不到 1 px)。
- L1270 — ★當 b >= 0.75 時取 4 個方向(0/45/90/135 度)的平均。預設 b=0.5 照舊只有 0 度,所以現有結果一個 bit 都不會變。是否有效取決於 a(共生距離)(poc_real_texture_invariance 第 6 節,3 種實拍素材):對各向同性素材在中短距離有效,對各向異性的 brick 僅在距離 4 有效(擺幅/解析度 3.13 -> 1.54)。距離 1 時 brick
- L1275 — 反而惡化(0.30 -> 0.56)。★根源在於拉長距離會讓解析度本身塌縮,0.0328 -> 0.0122。
- L1482 — ★2026-09-02:這兩個共享
{"kind": "zoom"},因此是完全相同的實作,而且兩者都沒有用 b(實測:同一輸入的最大差 0.0,b=0 與 b=1 之差 0.0)。在 HALCON 中 factor 版取兩個倍率,size 版取目標尺寸,是不同的東西,所以拆分 kind,讓實態與名稱相符。
- L1555 — ★2026-09-02:舊規格是 out_sort=feature / metric=”area”,實體是
np.mean(mask) = 在影像中所占的面積比。由於 HALCON 的 area_center 是回傳 (Area, Row, Column) 的 op,存在雙重不一致:(1) 不回傳中心 (2) 面積是比率而非像素數(= 依賴解析度)。單個純量無法滿足這個名字,所以像 ncc_locate 一樣做成 match sort 的 1-D 向量,回傳 (面積比, 行, 列)。match / feature 都是終端 sort(候選僅為 identity),所以基因組->op 的映射不動。
backends_decomp.py
- L142 — ★把 BLAS 的執行緒上限在迴圈外只施加一次。這裡是把限制在 work_max=64 的方陣最多 SVD 60 次的地方,佔用本 repo 分解時間的大半(一次套件 30.7 秒 / 分解合計 31.4 秒,svd 23,987 次 = 98%)。64x64 的 SVD 用 24 執行緒比 1 執行緒慢 3.9 倍 —— 因為分解中的 GEMM 太小,同步開銷超過計算量(表見 fsthreads 的 docstring)。每次都包裹會把機制的 2.4us 付 60 次,所以放在迴圈外。
- L206 — ★
ev[0] 是代數上最大的特徵值,而非絕對值最大的。在明亮的脊上主曲率為負,所以 ev[0] 是絕對值較小的那個,給出脊上為 0、兩側為 1 的相反響應(2026-09-05 Fable 評審,實測 [1, .64, 0, 0, 0, 0, .64, 1])。按說明取絕對值最大者。
backends_r3.py
- L46 — ★在 2026-09-05 之前用
except Exception: out = None 吞掉了例外。註冊時外層施加了 backend_safe.guard,但在內層消除例外後外層什麼都看不到 —— 即使 strict mode 也不拋例外,台帳裡也不留痕。這是 2026-09-02「24 族中只有 1 族到達台帳」稽核的漏網(Fable 的對抗評審作為第 5 族指出)。讓例外原樣向外拋出:外層 guard 記錄它,落到符合 sort 的值,strict 則重新拋出。
backends_scipy.py
- L198 — ★當 lambda >= ~12 時 scipy 拋出「boundary conditions did not converge」,guard 的 fallback 變成了恆等(舊的 1+40a 在 a>=0.3、含預設 0.5 有 7 成為恆等。2026-09-05 Fable 評審)。說明也對齊到 1〜11。
backends_typed.py
- L505 — ★在 2026-09-05 之前透過操作 sys.path 讀取
tools/chain_fuzz(未隨附)。在 wheel 中會失敗,而下面的 build() 悄悄回傳 [],所以 tb_* 143 個 op 消失了。
blob2d.py
- L287 — ★注意符號:頂點按 (row, col) 順序排列,所以
_monotone_chain 回傳的朝向是(把 row 視為 x 的)逆時針 = 螢幕上為順時針。內側是外積非負的一側(寫成 <= 0 會讓所有物體 solidity 為 0)。
- L587 — ★僅靠侵蝕只會出現一側。編號較小的物體,即使旁邊來了編號較大的物體,鄰域最小值仍是自己,因而被判為「內部」(2026-09-06 實測:在 1 與 2 相接的列,1 一側的輪廓消失了)。同時看膨脹就得到「鄰域中有與自己不同的編號」這一對稱判定。
calib.py
- L178 — ★2026-09-06 實測了這個門在實機相機上不會觸發。在無畸變的合成資料上按設計工作(傾斜 0 度時比 3.8e-14,0.05 度時 8.6e-10,均拒絕)。但加入現實的桶形畸變 k1=-0.18 後,平面單應模型本身就不再吻合,比值與傾斜無關地釘在 1.9e-06 附近(0 度 1.916e-06 / 0.05 度 1.935e-06 / 0.2 度 2.005e-06)。
- L184 — ★僅當兩個條件同時滿足時:存在畸變,以及視點間板子橫向移動。只要滿足其一,門就按設計鳴響(切分見 tests/test_calib.py 的 3 條)。而實際的校正會話是手持移動板子拍攝的,所以兩者必然同時滿足。也不是提高閾值就能解決 —— 有畸變時,完全退化 1.92e-06 與傾斜 2 度 4.42e-06 之差只有 2.3 倍,畫不出分界線。因此:* 閾值保持不變(對已去畸變的點能正確生效)* 把比值本身作為
orientation_rank_ratio 回傳 * 讓實際攔截的後段門說出「請傾斜板子」(下)。無法修復,那就把判斷材料交給使用者。
caltab.py
- L188 — ★這個門抓不到的東西:對單張平面靶標的內參誤差(尤其是 fx/fy 之比)。單個平面的 homography 只對內參施加兩個約束(Zhang 2000),所以錯誤的 fy 大多被這裡求解的位姿 6 自由度吸收,殘差可能留在閾值之下。實測 2026-09-05:即使把 fy 從 500 -> 300 弄錯,Linux/scipy 1.18 上 RMS 也只有 0.90 px(正確 K 則為 0.14 px)。同樣的輸入在 Windows/舊 scipy 上變成 6.39 px,僅憑最佳化收斂點的不同就「能偵測到或偵測不到」。若想驗證內參,請取 3 個以上視點或使用非平面靶標。這裡有效的是「位姿無法吸收」的不一致(對應關係錯誤、非平面板)。
champion_to_macro.py
- L193 — ★強制執行招牌式的誠實主張(「DNA op 只在鎖定的 holdout 上勝過手工基線時才添加」)——此前這個旗標只是印出來卻從不設門,於是比手工更差的巨集也能被註冊,並被下一輪進化選中。除非顯式覆寫,門會拒絕它。
- L87 — ★不保證位元一致(2026-09-05 更正)。數學上按行獨立,但
U @ w 是 BLAS 的 GEMM,所以歸約的劃分與向量化路徑會隨行數 M 變化,捨入可能改變。實測:一旦給 CI 的 py3.11 作業加入 torch(= 一旦載入了另一個 OpenMP 執行時),分塊與否結果就不一致。保證的是數值上的一致(數個 ULP),而非 bit 一致。
demops.py
- L97 — ★不提供用中位數等填補的選項。填補會造出不存在的平原,不拋例外地放水通過。但效果的大小要如實寫下。在同一份實測資料(東京灣岸 1024x1024,缺測 3.83%)上比較 3 種方式的最大匯水單元數:出流口 312,108 (29.8%) / 中位數填補 338,188 (32.3%) / 牆 315,023 (30.0%)。填補大約誇大 8%,但「一個單元匯聚全體的 3 成」這件事本身就是此地形的實際(平坦的填海地確實會匯向一處)。最初只看填補就寫「這個數字是填補的產物」是誇張,取了對照後效果就縮小了。不放填補選項,是因為會無法區分哪裡是真實地形、哪裡是填補,而非因為數字會以數量級變化。
- L605 — ★這個慢是在 PoC(examples/poc_dem_terrain.py)中 513^2 的天空可視率花了 41.9 秒才第一次注意到。測試只用了小格子,確認了「能動」但沒確認「能用」。
- L686 — ★2026-09-08 修正(
poc_stockpile_volume 發現)。當視線的取樣經 np.rint 捨入到目標單元自身時,就會把該單元的高度當作「途中地形」來與自己比較。由於 t < 1,分母 dist*t 很小,(z-eye)/(dist*t) > (z-eye)/dist 在 z > eye 時必為真 —— 高於視線的單元幾乎都自遮擋了。實測(修正前):平地上高 10 m 的柱子在 25 m 外、視線 2 m 處回傳「看不見」,只有低於視線的 1 m 柱子「看得見」。凸立體的最高點從外部必然可見,所以這在幾何上是錯的。取樣落在目標單元上的那次不計入。
- L746 — ★台帳聲明
points = (N, 3)。傳入純量會變成 (3,),與聲明不符,所以總是摺疊為 (N, 3)(2026-09-06 由 fuzzer 的 TYPEMISS 暴露。加入 6 個地心座標 op 後沒有跑 fuzzer)。若想保持格子形式的 (H, W, 3),請用 :func:dem_geocentric_grid。
-
| L795 — ★漸屈線內側的大地緯度不唯一 -> 不悄悄回傳超出範圍的緯度,而是拒絕。橢圓 x²/a² + z²/b² = 1 的漸屈線為 (a·x)^(2/3) + (b·z)^(2/3) = (a²-b²)^(2/3)。只有等號外側才是「法線唯一確定」的區域(2/3 次冪非負,所以符號取 |
z |
)。 |
evis_fullseye_bridge.py
- L152 (ja) — ★The sky is “infinitely” far (measured: 998 in a world whose animal is 0.3 across), and with the sky in view the 3rd/92nd percentiles straddle it, so the panel collapses to two flat colours — sky and everything-else. depth_max cuts the band at a distance that means something for this body, so the scene gets the colour range instead of the sky.
- L171 (ja) — ★ego_camera(モデル自身の目)でも eye パネルを出す。ここを ego>=0 だけで見ていたので、 ハエの複眼から描いたのに複眼の絵がコマに入らなかった(2026-09-14 実測)。
- L180 (ja) — ★drop frame 0: the event panel has no previous frame to difference against, so it is blank by construction. Keeping it makes the first thing a reader sees a black panel, which reads as “the events never fired” (measured: frame 0 has 960 lit pixels, frame 20 has 35,550). The stats below still count every frame that was rendered.
- L189 (ja) — ★distances carry the MODEL’s unit, not metres: the fly world is cm/g/s, so reporting “6.96m” for a 7 cm walk is a lie the caller cannot see.
unit names it honestly.
examplefig.py
- L139 — ★
colorize_depth 回傳 float [0,1]。用 np.asarray(..., np.uint8) 接收會把所有 0.x 截斷為 0,變成全黑(2026-09-06 踩到)。
- L171 — ★不要丟掉範例的正文。圖出不來固然遺憾,但數字必須給出。
- L210 — ★這裡不能甩給 :func:
_to_rgb8。它把 (H,W) 傳給 colorize_depth,但在其中會逐幀正規化,所以全為 0 的幀和全為 1 的幀會出同樣的顏色(2026-09-09 被測試抓到)。只有顯式傳入值域,尺度才會統一為一個。
- L275 — ★Pillow 會把與前一幀完全相同的幀摺疊為一幀(那部分時間會加到前一幀的顯示時間上,所以動作速度不變)。寫完後計數,若與傳入的數不同就在台帳裡兩者都留下 —— 以免把嘴上說「72 幀的 GIF」而內容只有 40 幀的情況悄悄放過。
- L339 — ★2026-09-08:面板小時標題放不下,
annotate_figure_grid(正確地)拒絕,於是有一張圖悄悄消失了。29×19 的 core 格子或 24×24 的縮小圖在 PoC 裡很常見,可錯誤卻說「把標題縮短」—— 實際的修法是「把面板放大」。兩位負責人獨立地掉進同一個坑(有過看板的 scene 圖消失一張的例子),所以不讓每個呼叫者各自寫放大,而在這裡只做一次最近鄰放大。用最近鄰是為了在放大時不造出值(插值會在圖上產生並不存在的中間值,偽彩會說謊)。
examples/acoustic_condition_monitoring.py
- L467 — ★拋物線插值仍殘留向整數拉的偏差(因為峰是 sinc 狀的,無法用二次完全逼近)。從 0 掃到 1 實測偏差,展示它呈 S 形 —— 若止步於「讀到了次樣本」,這個偏差就會悄悄搭在結果裡。
examples/annotate_paper_tour.py
- L51 — ★EXTEND:把 text 和 path 替換為你自己圖的文字與折線 (x, y)
examples/blas_thread_budget.py
- L117 — ★這是要點。96x96 並不是「因為小所以快」,而是一個正因為小才使多執行緒反而吃虧的尺寸。在迴圈外放置一次(若每次迭代都包裹,就要把限流機制本身的開銷付 30 次)。
examples/blob_split_tour.py
- L98 — ★實測(honest):高度 2 < h 的條上也會立起種子。blob_seeds 以殘差
f - R > 0 作為種子,但若對每個分量以背景 0 重建,峰高 M < h 的分量得到 R = M - h < 0,於是殘差在該分量的全部像素乃至背景 1 px 的邊緣都為正(skimage 的 h_maxima 以 殘差 >= h 剔除)。不修改實作,僅作報告。此處去掉條的種子,驗算「無種子團塊」的路徑。
- L129 — ★實測(honest):割縫並不落在交線上,而是編號較大的種子一側沿谷底吃進。blob_split 逐級膨脹,將”同時被兩個區域觸及的像素”賦給 grey_dilation 的 max(=較大編號),因此經 8 連通的斜向鏈式傳播,編號較大的區域沿谷線侵入數列。互換種子編號,侵入方向也隨之互換(是編號的偏置,而非幾何)。不修改實作,僅作報告。
- L153 — ★實測(honest):若按教科書的 h-maxima,當 h 超過「較低山峰的凸起(16 - 鞍部 10.07 = 5.93)」時,兩個種子就會融合為一。blob_seeds 以殘差 > 0 作為種子,故殘差 = min(h, 凸起) > 0 恆成立,較低山峰的種子不會在該 h 處消失。融合發生在 h 超過「較高山峰 - 鞍部(22 - 10.07 = 11.93)」時——它所參照的山峰正好相反。
examples/coherence_scanning.py
- L166 — 6) ★ 與相移法的對照 # —————————————————————— #
examples/dem_geodesy_tour.py
- L49 — ★若不把儲存庫根目錄加入路徑,就找不到
demops(本例不 import fullseye,因此路徑掛鉤不生效)。
- L61 — ★EXTEND: 替換為你自己圖磚的西北角(此處在東京附近)。
- L131 — ★誠實的分解:Bowring 的單次迭代在橢球面上為 1e-9 m,但高度越高誤差越大(實測 8848 m 處 8e-7 m,20 km 處 4e-6 m)。docstring 中的「1e-12 度 / 1e-7 m」是近地表值,在平流層高度並不成立。用於地形(高程 < 9 km)時為 1e-6 m,此處將閾值設為 1e-5 m。
- L160 — ★EXTEND: 將 dem 替換為真實資料(第 0 列為北)。此處為已知的斜面。
examples/dem_terrain_analysis_tour.py
- L46 — ★若不把儲存庫根目錄加入路徑,就找不到
demops(本例不 import fullseye,因此路徑掛鉤不生效)。
- L59 — ★EXTEND: 單元尺寸 [m]。真實資料用 dem_cell_size_webmercator(zoom, 緯度) 求得。
- L158 — ★誠實的觀察:當斜面中途存在缺測時,其正北的鄰元即便是 outlet 也不落向缺測,而是流向西南(有有限落差的方向)。實作是「僅當別無下降去處時才落向缺測」,比 docstring 的「允許流向缺測」更窄。此處僅列印,不 assert。
examples/piv_flow_from_particles.py
- L27 — ★由於要 import repo 根目錄下的模組(pivops),把 repo 根目錄放到最前,使其從 checkout 直接執行即可通過。與其他範例相同的做法。沒有它,
py -3.11 examples/<name>.py 會因 ModuleNotFoundError 而失敗(2026-09-09 實測:在缺少執行門的 83 本中,失敗的僅此類型的 2 本)。
examples/poc_allsky_cloud_cover.py
- L104 — ★最後 3 個是薄雲(光學厚度不同)。提高閾值時,越薄的越先掉落——第 4 節的階梯即由此產生。
- L142 — ★立體角權重。dΩ/dA = sinθ/(f²θ) —— 等距投影的雅可比。
- L524 — ★2026-09-08:”equidistant” 變得會命中一維的
create_funct_1d_array(從等間隔樣本建構函數)——這是讓 ops1d 可經 op_find 檢索的副作用,與投影模型無關。僅僅是詞相同,空缺並未填補,因此改為查看”不在投影族中”的形式(不以詞的匹配來判定)。
examples/poc_asbuilt_wall_deviation.py
- L497 — ★遺漏的不是傾倒而是鼓脹。predict_bulge 以閉式返回的一次係數量,會原封不動地變成偽傾倒與偽平面內偏擺。
- L555 — ★向閉式傳入包含被鼓脹吸收的部分(§6)的有效傾倒。若不包含,則僅 f=0 的單點偏差 1.2 mrad,看似預測失準。
- L660 — ★僅雜訊的地板。在鼓脹為零的壁面上以同樣方式讀取,就得到這個。
examples/poc_astro_photometry.py
- L322 — ★ 這裡曾錯過一次:以為「scale=2 所以亮度也是 1/4」,寫成 flux/4,得出 -74.89 %。守恆律(上文 6.1e-14)把它剔除了。每像素亮度變為 1/4,但星的總和不變。
- L423 — ★ 這裡曾放棄過一次 assert:上表的 rms(1 次合成、孤立星 8 個)給出良 6 幀 0.306 % vs 良 12 幀 0.324 % = 0.947 倍。這並非對理論 1.414 的反證,而是意味著那個 rms 是”逐星的系統偏差”與”雜訊”之和,8 個樣本無法單獨取出雜訊。與第 1 段相同,累積迭代並減去逐星均值後,才只剩雜訊。
examples/poc_barcode_1d.py
- L806 — (d) ★measure_pos 的邊緣數量對 sigma 非單調依賴。
examples/poc_battery_ct_degradation.py
- L316 — ★
sdf_offset 僅為純量,故要按場偏移就需扭曲格點後再評估。
- L334 — ★為避免疊層穿透罐體,將其局部壓縮到撓曲端板所允許的高度(真實電芯中電極也會被加壓而收縮)。若不這樣做,在較高的氣體空隙處,端部層會被罐體吞蝕,層數比較失效(最初就是這樣)。
- L612 — ★以「上升邊的數量」來數層。若按
vol_wall_thickness 的成對(上升 -> 下降)來數,只要在罐內表面緊內側多出 1 條下降邊,配對就錯位,健全電芯也會從 17 -> 16 掉落。
examples/poc_battery_electrode_tortuosity.py
- L136 — ★不在公開路徑上的處理:體素空間的 6 鄰接圖。fullseye 擁有 3-D 的 # 連通分量(vol_label)與距離變換(vol_distance_transform),但 # 沒有處理「穿過空隙的路徑」的入口(測地距離、輸運)。 # ————————————————————————— #
- L248 — ★若直接傳入 64 voxel 的切片,面板寬度僅 64 px,標題文字放不下,整幅圖就會失敗(examplefig 不會默默放棄)。
- L269 — ★若把固相保持為 0,則 log10(耗散) 為負,於是固相被塗得最亮(2026-09-08 曾這樣出過一次)。將固相對齊到空隙的最低 2 %。
examples/poc_beam_modal_video.py
- L629 — ★衝突:在 fps 48.5 時,照明的混疊正好落在 f_1 = 3.00 Hz 上
examples/poc_bev_sensor_fusion.py
- L135 — 已放置。★這並非裝飾:* 若把面放在單元邊界上,面的回波會因雜訊向鄰元溢出一半,僅靠 discretisation 就使擬合率跌到 0.5。* 若把面放在單元中心,這次輪到真值因浮點捨入而時進時出(確實踩到:側壁回波所在列偏離真值,133 個偽佔據單元中大半即為此)。放在兩者之間則兩種情況都不發生。
h 避開 0.2 m 的倍數——以顯示高度的量化。lx/ly 取 0.1 m 的奇數倍。
- L564 — ★誤差是繞世界 z 軸(=與 place 相同)。寫成
R_wc @ rz 就變成繞光軸的 roll,重投影誤差會化為 1/5(2026-09-07 踩到:得出 0.98 px,與幾何預測 f·tanθ 不符而暴露)。
examples/poc_bilateral_asymmetry.py
- L585 — ★保持為可直接通過孔 D 之門的形式(margin 先塌陷,角度隨後跳變)。
examples/poc_bump_coplanarity.py
- L147 — ★真實的低階缺陷(die-attach 空洞 = 中央平緩下沉)。故意不做成嚴格的二次——若為二次,擬合按定義會吸收 100 %,「能被吸收多少」這一問題便變得自明。
-
| L306 — ★先以 ±SPEC_UM 進行 clip 再傳入。examplefig 的發散配色按每個面板以 max |
v |
正規化,若不 clip,3 幅的顏色含義就不一致。 |
- L445 — 6. ★過度扣除之害 —— 會吸收真實的低階缺陷 # ————————————————————————— #
- L540 — (e) ★經台帳的 surface_form_error 只返回 PV 的 float
examples/poc_cad_scan_deviation.py
- L434 — ★台帳的 out 配接器把 dict 截斷為 (R, t),故 rmse 傳不到
- L893 — 第 6 章:★缺陷牽動配準 —— 以向剛體 6 維的投影來預測 # ————————————————————————— #
- L1099 — ★不加入缺陷 —— 若加入,第 6 章的 datum 偏移(0.107 mm)會成為點位移的基墊,與「因初始角度而破壞的量」混在一起。
- L1252 — ★對真值為 0 的對照組給出「%」,會因除以 0 而得到無意義的巨大數值。面積仍以 mm^2 並列,僅在真值有意義時才附上 %。
- L1263 — ★不要把單次執行的差異讀作「起效了」 —— 變動種子並與離散度比較
- L1353 — ★缺口一旦被填補就會觸發的 assert。它確實在 2026-09-07 觸發,於是重寫了這一行:在收到「無法建構圓柱孔、倒角與圓角」的意見後,加入了 plane / cylinder / torus / capsule。意見改變了工具,所以留下記錄後繼續前進。
examples/poc_camera_calibration.py
- L150 — ── 校正(自製的最小捆綁調整。★ 缺口 (e))──────────────────────────────────── #
- L176 — ★ 缺口 (d):camera_calibration 的影像點是 (row, col)。project_points 是 (x, y)。
- L304 — ★ 缺口 (b):reprojection_error 不知道畸變。即使傳入真值也不會變成 0。
- L525 — 2. ★ 主角:重投影 RMS 幾乎相同,但 fx 誤差卻相差一個數量級以上
- L533 — 3. ★ 抵消機制:fx 的比值與 Z 的比值一致
- L539 — 4b. ★ 誠實的失敗記錄:在窄視場 + 0.30 px 雜訊下,將主點固定在影像中心的零點 B 比去估計它更正確(確實存在無法超越的條件)
- L555 — ★ 缺口 (c):由於是畸變點,攔下它的不是退化門,而是後段的非有限 K 門。還要確認其文案中包含「請傾斜標定板」(2026-09-06 新增)。
- L563 — 5b. ★ 缺口 (c3):閉式解會因畸變而系統性偏離(僅用作初值)
- L567 — 6. ★ 缺口 (b):reprojection_error 不知道畸變 -> 即使傳入真值也很大
- L573 — 7. ★ 缺口 (a):內參估計從外觀層(facade)看不到
examples/poc_cell_counting.py
- L853 — ★可指定的最小 h 為 0.05 x max(距離變換)。影像中只要有一個大細胞,就會抬高整幅影像的 h 下限(由 op 規格造成的耦合)。
- L1041 — ★這個 PoC 的標題。在偏差曲線穿過 0 的位置,分割誤差並不是一個谷。
- L1330 — ★過度合併與漏檢是兩回事 —— 即使黏連也並未「消失」
- L1358 — ★最優 h 隨密度變化(在偏差準則或一對一準則中必有其一會變化)
- L1361 — (5) ★確實存在計數正確但分割全錯的點:偏差不到 3 %,但仍殘留大量分割誤差,一對一對應也遠離最佳。
- L1387 — ★可指定的最小 h 隨尺寸比一同上升(由工具規格造成的尺度耦合)
- L1427 — (10) ★用機器確認工具的缺口「仍然存在」(一旦修好就會失敗 = 好的失敗方式)(a) 進化 op 的距離變換按最大值正規化
examples/poc_change_detection_misreg.py
- L947 — ★一張圖:殘餘偏移 vs 偽陽性(掃掠曲線 + 配準結果的點)
examples/poc_cold_chain_excursion.py
- L568 — ★尋找峰值的窗口只到下一次門開合之前。若取得過寬,在 τ 較大處會捕捉到下一個脈衝的上升沿,看起來像「懸崖不會到來」(2026-09-08 用 200 分鐘的窗口踩過:y=53 的實測拉長到了 153 分鐘)。
- L947 — ★把視線方向(D 軸)設為寬度。若保持 (t, y, x) 直接投影,D = 時間 720,只會得到細長的 (H, W) = (60, 12) 影像。
- L1006 — ★區分「命中」是靠約定還是偶然:將每個點擾動 ±1 m 後計數。
examples/poc_colocalization_crosstalk.py
- L355 — ★拖尾損失的預測:閾值 T 以下的 Gaussian 尾部不會進入區域。峰值 p 的點中,區域內的螢光為 1 − (T − 基座)/p(2-D Gaussian 體積的閉式解)。基座 = 細胞質 + 背景(+ 滲入部分),p 會被 PSF 壓縮為 σ_ves²/(σ_ves²+σ_psf²) 倍。
examples/poc_colormap_readability.py
- L343 — ★從階梯列中能讀出的差是 Δ + 1 個像素寬的斜坡 —— 忘了這一點就會把懸崖高估 2 倍(最初這樣寫,得到 0.57 vs 實測 0.30)
- L406 — ★用真實梯度去除。不除的話,就會把「場變化陡峭的地方」當作邊界來計數
- L657 — ★超過顏色數會被預設拒絕(本 PoC 指出後當天變為 fail-closed)。這裡的目的是測量「循環會怎樣」,所以顯式設定 cycle=True —— 強制顯式本身就是對策。
- L732 — ★因本 PoC 的指出當天修復。名單的判據僅為「明度的單調性」,所以明度雖單調但色差步進粗糙的 cividis 卻自稱「安全」。現在色差的均勻性也納入判據,cividis 已移至 CVD_SAFE。
examples/poc_compound_eye.py
- L301 (ja) — ★PoC の門(tests/test_poc_scripts_run.py)は exit 0 に加えて “PASS” の印字を 要求する(合否を計算したのに捨てる門を防ぐ規約)。以前は “OK:” と書いていて、 台帳に登録した瞬間に「exit 0 だが PASS を印字していない」で落ちた。
examples/poc_crop_phenotyping.py
- L209 — ★亂數務必以 (n_plant, NESTED_MAX) 的形狀預先抽取。若按葉數改變抽取數量,亂數序列會錯位,n_leaf 僅加 1 就會變成另一片群落(2026-09-07:植被率相對葉數不再單調,無法測量懸崖)。
- L525 — ★
grid_coords 放置的是體素中心(中心間距 = span/res,而不是 span/(res-1))。最初乘以 span/(res-1),在球上產生了 +12 % 面積、+18 % 體積的誤差 —— 單位弄錯會「錯得很像模像樣」。
- L971 — ★真值和葉角分布都取自本節所觀察的群落本身。若沿用基準條件(7 片葉)的 k,就會因上層葉越發直立的梯度而使真值偏移。
- L980 — ★最大的平面未必是地面(群落鬱閉後,冠層的一部分會成為最大)。將第一個平面直接當作地面的版本給出了 1.69 m 的高程(2026-09-07 踩過)。只有加入取最低平面的規則後才穩定下來。
- L1007 — ★對照組:將同一公式套用於真實法線(緩衝區所持有的)。
- L1136 — ★
occupancy_grid 的軸是 (x, y, z)。render_volume_projection 會以軸 0 作為視線方向進行壓縮,所以若想要天頂圖,需交換為 (z, y, x)。不交換就呼叫會得到「本想當側視圖的天頂圖」(默默出錯的類型)。
examples/poc_ct_fidelity.py
- L342 — ★這個 PoC 的標題。可以用眼睛看到 FBP 與零點 A(水平線)和零點 B 相交的地方。橫軸是投影數(左側稀疏)。橫軸取 log —— 相交發生在稀疏一側(12~45 條),線性軸下會擠到左端,關鍵處讀不出來。
- L407 — ★2026-09-06 已填補。以前固定的是損壞行為 =「檢測器加倍會使質量虧損改善 2 倍以上」。現在固定兩點:(1) 質量本來就是守恆的 (2) 不隨檢測器數量變化(因為 n_detectors 是檢測器的寬度,而非取樣的精細度,所以只要目標能容納,增加的部分只是多出空 bin)。
examples/poc_ct_void_morphology.py
- L233 — ★用晶粒佔據來替代時,在粗體素下 50 µm 厚的晶粒會落在體素中心之間,基準本身消失(在 60 µm、相位 2/3 時實際變成了 0 個)。
- L558 — ★把全 nan(任何相位都無法測量)傳給 np.nanmean 會發出警告。「無法測量」不是求平均的對象,所以在此顯式設為 nan。
- L634 — ★繪製前先剔除 nan(無法測量的點)—— 折線 op 會拒絕非有限值。
- L808 — ★缺口填補後就會觸發。2026-09-07 觸發,於是重寫了本節 —— 在收到「esdf 接受長度為 3 的 voxel_size,但繪製其輸出的一側卻僅限立方」的意見後,query_distance(和 occupancy_grid)改為接受按軸的 res。
- L917 — ★體積率即使在粗體素下也得以保持,先失效的是形狀指標(預測落空的一側)
examples/poc_datacenter_thermal_field.py
- L221 — ★2026-09-08:此 PoC 記錄了「沒有從散亂點建構場的入口」,因此加入了
fs.interp_scattered。落在凸包之外的點由 op 以遮罩返回,因此無需用 isfinite 去猜測(即使把 fill_value 設為有限值也不會出錯)。
- L862 — ★破壞門來驗證「假峰 0」是否真的在計數。
examples/poc_dem_terrain.py
- L42 — ★若不把儲存庫根目錄加入路徑,就找不到
demops(本例不 import fullseye,因此路徑掛鉤不生效)。
examples/poc_dfm_thickness_overhang.py
- L284 — ★朝向(正反面)由纏繞順序決定,但 marching cubes 的纏繞順序會隨輸入的符號約定而翻轉。若是封閉網格,則由帶符號體積唯一確定 —— 用公式而非目視來決定。
- L379 — ★不要把格點原點對齊到牆面。在 3.0 處切割會使牆面正好落在 voxel 邊界上,8 個掃掠點全部誤差 0.000 mm,得出「不會發生量化」的錯誤結論(2026-09-07 曾經這樣寫過)。實際的網格劃分器不會把格點對齊到零件的面,因此採用不對齊的原點。
- L455 — ★不要只在「T/h 為整數」的點上掃掠 h。整數比時佔用體素的數量恰好為 T/h 個,誤差 0.000 mm 排成一列,看起來像「不會發生量化」(2026-09-07 曾經這樣寫過)。要連續地掃掠 h。
- L705 — ★不要納入正好 45 度的傾斜方向 —— 板背面 2349.7 mm^2 自身也會貼附到閾值上,「哪個朝向更好」的表格會被階差的問題所劫持。
- L824 — ★當孔被填塞時觸發的 assert。它在 2026-09-07 觸發,於是重寫了這一行 —— 因收到「沒有逐面的面積」的指摘,加入了 face_areas / mesh_volume / boundary_vertices。記錄下已被填塞並繼續前進。
examples/poc_dic_strain.py
- L104 — ★用從基準影像確定的單一常數進行正規化。若按每幅影像的最大值來除,只要形變使最大值稍有移動,整體亮度就會改變,從而給假設亮度不變的估計器(Lucas-Kanade / Horn-Schunck)疊加無關的誤差。
- L211 — ★固定所見:由於形變不是插值而是斑點的重繪,整數移位應當嚴格一致。若此處崩潰,則第 2 節及以後的「真值」將不再是真值,也就分不清測量的是估計器還是我們自己的插值器。
- L247 — ★固定所見:三者都必須以數量級取勝於僅回答「沒有移動」的零點。哪怕有一個跌破 10 倍,該估計器在此場景下就不堪用。
- L282 — ★固定所見。(1)piv 的偏差在掃掠全域內都小於 lk / hs。※「小一個數量級」只在第 2 節 u=0.37 的單點成立(0.0002 vs 0.0042 = 21 倍),而掃掠的最大值之間約為 6 倍(piv 0.0015 / lk 0.0088)。這裡把最大值之間保守地固定為 2 倍。
- L365 — ★固定所見。(1)lk 與 piv 將 100 µε 以 ±30 µε 的精度回收(實測 +9.1 / +0.4)。
- L369 — (2) ★hs 對 100 µε 只返回 22 µε —— 上面的「符號和數量級會出來」不適用於 hs(正則化把均勻應變本身抹平了)。由於主張與實測不符,故以實測為準固定下來。
- L413 — ★固定所見。(1)2 度的旋轉在微小應變下如理論所料成為約 -609 µε 的謊言(材料並未伸長)。相當於鋼的降伏應變 2000 µε 的三成。
- L438 — ★在均勻梯度(ε 關於 x 為一次)下不會變鈍 —— 因為對稱窗的最小二乘會嚴格返回一次函數的斜率。要看到窗的效果,需要帶曲率的應變場。切口尖端的應變集中正是如此,因此植入高斯形的集中。
- L484 — ★固定所見。(1)lk 的峰值隨窗寬單調下降(正是空間解析度的極限)。
- L522 — ★只切一個角來計數,會隨窗的取法變動 2 倍。使用全部窗的平均。
- L577 — ★固定所見:把斑點加粗後偏差單調減小。第 3 節看到的 lk 偏差並非只是估計器的性質,散斑的取樣不足占了一半。若此處不再單調,「0.01 px」主張的依據便會崩掉一根。
examples/poc_die_tilt_tsv_overlay.py
- L167 — 格點的展布。★若不包含 erf 的尾部(±4σ),在傾斜的裸晶上外周的通孔會在每個 z 上被以不同方式切割,產生虛假的傾斜。
- L241 — ★經由台帳的 vol_label 與 docstring 不同,只返回 labels(
(labels, n) 的 n 被丟掉了。第 9 節的 (f))。
- L297 — ★這裡不要減去 MU_SI。探針在通孔之外穿過的是空氣(0),因此原始值直接與材料的佔有率成正比。若減去並 clip,邊緣平緩的部分會被壓到 0,長度從 100.0 -> 98.1 µm(-1.9 %)。
- L484 — ★減去對照組,只提取「傾斜所增加的部分」(消除估計器的系統誤差)。
- L634 — (f) ★同一個 op 會因呼叫路徑不同而返回值的內容不同。
examples/poc_dimensional_inspection.py
- L521 — ★rms 是否可信 —— 對抗性地只把一個點向外移動。
- L1553 — ★2026-09-06「被埋沒」的狀態得到解決。以前是
n_reach == 0(固定其到達不了)。現在固定其能夠到達。
examples/poc_document_scan.py
- L271 — ★直接把 sobel_dir 作用於二值遮罩,會把梯度方向量化到 0/90 度,一點一票的帶方向 Hough 就會坍縮到那兩條線上(實測:4 條線中有 2 條正好是 0.00 / 90.00 度)。先模糊再測方向。
examples/poc_fabric_defect.py
- L83 — ★遮罩的面積故意調成大致相同。合併後的 AUC 接近以陽性像素數加權的平均,因此若其中一方大一個數量級,「合併後被隱藏」就不會發生。
- L119 — ★遮罩半徑按 σ 的倍率分別設定 —— 為了讓面積相當。若面積相差一個數量級,就會變成「合併後的 AUC 即面積較大者的 AUC」,本 PoC 想測的「合併後被隱藏」就被偷換成「面積大的一方獲勝」這另一回事。
examples/poc_fiber_orientation.py
- L376 — 第 2 節。★★樸素的平均在 180 度週期下崩潰 # ————————————————————————— #
- L469 — 第 4 節。★★不選擇權重的話,取向度必定偏小 # ————————————————————————— #
- L499 — ★由於角度是週期量,用 colorize_depth 上色會使 0 度與 179 度成為完全相反的顏色。fullseye 中沒有循環 LUT 的名字,但把 (cos2θ, sin2θ) 傳給 colorize_flow 就能得到二倍角的循環 LUT(見末尾「工具的漏洞」(f))。
- L693 — ★存在「coherence」這個名字,但那是訊號處理中的雙訊號相干性(另一回事)。
- L724 — (e) ★同一族的兩個在輸入檢查上不一致。
examples/poc_fly_vision.py
- L623 (ja) — ★ラミナ段(DC 落とし)を省くと相関が落ちる、を固定する。落ちなくなったら fly_emd_response の側で DC が消えている(仕様変更)なので、この対照を見直す。
- L650 (ja) — ★PoC の門(tests/test_poc_scripts_run.py)は exit 0 に加えて “PASS” の印字を 要求する(合否を計算したのに捨てる門を防ぐ規約)。
examples/poc_focus_stacking.py
- L491 — 1. 圖是有效的。★門檻為 +3 dB——半導體實拍影像大部分是平滑金屬(晶粒、引線),這些區域單張就已合焦,因此 AIF 的提升不如全面高頻的合成圖樣那麼大(這是現場的真實情況;舊的全面紋理場景曾得到 +14 dB)。
examples/poc_forensics_roc.py
- L396 — ★漏洞 (a) 是「常數圖」,因此畫成圖就無需去讀數字。
- L523 — ★本 PoC 的標題。最強檢測器的曲線,只按一次儲存按鈕就跌到對角線(乃至更低)。
- L677 — (4) ★漏洞 (a):op 的 argmin 讀出,對再儲存過的影像實質上是常數圖。AUC 恰好為 0.5 = 與隨機無法區分。
- L704 — (9) ★漏洞 (b):8 像素格。僅當差為 8 的倍數時才猜中(無再儲存)。
examples/poc_gear_tooth_metrology.py
- L199 — 成像系統的模糊。★2-D 高斯模糊沒有直接傳 σ 的入口,因此從進化 op 的旋鈕 a 反算 σ = 0.3 + 2.7 a 後傳入(見末尾「工具的漏洞」(c))。
examples/poc_geodetic_height_frames.py
- L408 — ★往返無法排除「兩者朝同一方向出錯」。要與獨立實作相互對照。
-
| L437 — ★預測(在測量前列印):坡度為 atan |
∇H |
。使用 h 則為 atan |
∇H+∇N |
。 |
- L464 — ★把預測與實測的最大差異區分為「模型誤差」還是「離散化」。把網格單元細化。
-
| L584 — ★預測(閉式):下坡方向轉過 90 度以上 ⇔ ∇H·(∇H+∇N) < 0 ⇔ |
∇H |
^2 + ∇H·∇N < 0。測量前先算出比率。 |
-
| L644 — ★第二個(才是真正關鍵的)閉式。視線由兩端的 h 連成,所以 N 的線性部分在視線和地面上疊加量相同而抵消。剩下的是 N 偏離弦的量 = |
N’’ |
d^2 / 8。此處 N’’ 為 2C(cos^2θ - sin^2θ),所以 |
N’’ |
<= 2C。 |
- L1106 — ★只有
vertical 時 op_find 回傳 5 條。沒有一條相關(如 boundary_vertices 的詞幹匹配)—— 不能靠數量就說「存在」。
examples/poc_interferometry_step.py
- L159 — 3) ★重複測量 — 區分偏差與離散 # —————————————————————— #
- L202 — 4) ★與零點(包絡線的最大取樣)的比較 # —————————————————————— #
- L274 — 6) ★雜訊掃描 — 在何處無法測量 # —————————————————————— #
- L314 — ★離散小並不能證明正確
examples/poc_leak_localization.py
- L591 — ★預測 C 的檢定 —— 細密地變動漏水位置,把小數部分打散
- L726 — ★對照組 —— 只把反射左右對調。若偏差方向反轉,就能說原因是「較遠的接頭決定偏差方向」。
examples/poc_lidar_terrain_change.py
- L406 — ★無法測量的 core 面積完全不計入土方量。也回傳按有效率反除後的值 —— 不反除就會把「悄悄缺失的土方量」當成正確值。
- L694 — ★接近真值的數字未必「正確」—— 把方向相反的兩個誤差分開計數
- L823 — ★有效 core 太少時,LoD 不算作「已測量」(2 個點的標準差能算出數字但沒有意義)。
- L826 — ★若在此處抽稀,C2C 就會去測「抽稀後的點間距」,密度依賴隨之消失(最初寫成統一到 6000 點時,任何密度下都成了恆定的 0.42 m)。
- L946 — — ★ 對齊掉多少,變化就消失多少 ————————————– #
examples/poc_lightfield_depth.py
- L594 — 2b. ★ 缺口 (d):docstring 說是 0-d,實際是 (1,)
- L610 — 6. ★ 缺口 (a):預設 linear 會把 1.15 拉向 1.0,cubic 不會
- L634 — 10. ★ 缺口 (e) 已於 2026-09-06 堵上。已改寫為固定住已堵上的狀態這一側(以前是 assert「會發出警告」)。
examples/poc_livestock_body_volume.py
- L1032 — ★3 台與 6 台的切線集合完全一致(平行投影下相對的 2 台相同)
- L1040 — ★奇數的 13 台勝過偶數的 16 台
- L1054 — ★3-D 凸包無法替代「截面的凸包」(會把胸圍大幅偏離)
- L1057 — ★2 倍律:胸圍誤差隨體重翻倍(殘差為 2 次項)
examples/poc_machine_condition_fusion.py
- L184 — (聯軸器, 軸承A, 軸承B, 整機) 的發熱 [W]。★正常、不平衡、鬆動是故意做成相同的 —— 從原理上無法用熱區分的 3 種模式。
- L202 — ★和軸承一樣熱。不同的只有擴散範圍(兩個軸承 + 整機)。
- L1028 — ★2026-09-08:這裡原本自己手寫了 numpy 的 rfft —— 因為讀到「台帳裡沒有單邊幅值譜的入口」,但
fs.spectrum 一直都在(只是沒在台帳裡出現)。這是只看一層就斷定「沒有」的例子,故改為使用 op 的寫法。
- L1162 — ★2026-09-08:這裡原本寫著「台帳裡沒有 spectrum」,但
fs.spectrum 從一開始就在(dsp 的 1-D 層)。缺的只有「在台帳(fs.ledger)裡出現」和「每個 op 的筆記」;這個 PoC 只查了一層就斷定「沒有」,自己手寫了 numpy 的 rfft。現在把 ops1d 接入台帳後,兩邊都能查到。
examples/poc_mesh_quality_repair.py
- L602 — ★讓它飽和顯示。原始差異最大 %.2f mm,直接上色會使 99 %% 的像素為 0 而全黑,成為「跑了但什麼都沒出來」的圖。
- L816 — ★用雙對數繪製。線性軸下誤差會擠到粗糙一側的 1 個點,斜率(=誤差律)完全無法讀出(2026-09-07 曾這樣畫過一次)。
- L832 — ★直接疊加累積分布會使 4 條都擠在 0.9 以上而無法讀取。移動的是上尾,故以分位點 0.5〜0.99 為橫軸,縱軸畫「該分位點的曲率」(逆累積的上半)。
- L568 — ★實測比這更慢。遮罩上實際被抹去的晶界像素比例 f_eff 小於 f(模糊會把相鄰的黑漏到縫隙兩端各 1 px,局部閾值將其拾取),故與用 f_eff 重新推得的預測 ΔG0 + 6.64 log10(1-f_eff) 對比。
examples/poc_multibeam_bathymetry.py
- L518 — 合成回波的部分角數目。★把它設為 61 時,在 70 度處相鄰部分角的到達時間相差 330 µs,超過脈衝寬 64 µs,於是包絡變成梳齒,幅度檢測會拾取其中一個齒(檢測偏差為 -1131 µs)。用直方圖建構到達時間的密度並與脈衝卷積更正確。
- L546 — ★不要把下限裁到 0 —— 正下方波束會只剩一側,照亮的帶寬減半(曾以腳印減半的形式踩過一次坑)。
- L703 — ★把橫軸除以該波束自身的回波長度。以原始 µs 疊加會讓 70 度(21 ms)獨佔座標軸,使正下方與 45 度擠成一條豎線。
- L706 — ★
plot_series 會拒絕 xlim 之外的點(因為它們貼在邊框上,看著像真資料)。裁剪是呼叫方的職責,故先裁剪。
- L1125 — ★不要看重疊的正中間 —— 那裡兩條測線的擺角相同,誤差疊加量相同而差為零。要取整個帶內的最大值。
- L1196 — ★縱軸取高度(= −深度)。直接用深度繪製會上下顛倒,使「微笑」形狀看起來像「愁眉」。
- L1267 — ★縱軸為 −深度。直接用深度繪製會得到海面在下、海底在上的顛倒圖。
- L1301 — ★
op_find 以詞幹部分匹配來命中,所以即便數量不為 0,內容也可能無關(“footprint” → sk_median_disk)。要看到最上層的名字再說「沒有」。
- L1428 — ★全路徑的懸崖比預測更靠前。差異來自幅度檢測的偏差(閉式中沒有的量)
examples/poc_nuclei_ploidy.py
- L686 — ★確實存在方向相反的兩個失誤相互抵消、偽裝成「與真值完全一致」的列
examples/poc_pallet_load_utilization.py
- L232 — ★甲板上的點會因雜訊上浮到 +3σ,所以用地板閾值截斷。不加這一步,即使是零溢出的貨物也會出現 0.006 m3 的「溢出」。
- L479 — ★g = w 正好相等時,就變成了「格子是否碰巧對齊」的賭局。
examples/poc_panorama_drift.py
- L108 — ★缺口 (a):以下 4 個在 fs 門面和 fs.op 中都沒有出現
examples/poc_particle_sizing.py
- L213 — ★只用一個種子時,這條曲線的起伏就只是波動。用 4 個種子把均值和離散度分開後,再說它「越過」了。
- L428 — ★對照組 —— 只把既未融合也未斷裂的團塊,與該團塊所成像的那個粒子本身一對一地比對。若真值一側用全部粒子,「越大的粒子越容易融合」這種選取偏差就會混入,與取樣偏差無法區分(起初就是這麼寫的,弄錯了)。
examples/poc_particle_tracking.py
- L702 — ★返回的不是遮罩,而是 (N, 3) 的 (z, y, x) 座標(2-D 的
local_max / sk_local_maxima 返回影像,所以族內不一致。第 10 節的缺口 (g))。起初用 count_nonzero 計數,把數量級搞錯了。
- L777 — ★為把向上 3.4 倍、向下 0.93 倍裝進一張圖,縱軸取 log10 比值。0 表示「正好是真值」。若保持線性,向下的偏差會被壓扁而看不見。
- L792 — ★疊加原始 MSD 時,4Dτ 的直線支配一切,看不出差異。改用除以真值的比值後,偏離 1.0 的方式(=損壞方式)就能從形狀上讀出。
examples/poc_photoelasticity.py
- L160 — ★固定所見:這是對 fullseye 的 Mueller op 的嚴格驗算,即使讓 δ 以 15 度步長走一圈、θ 取 5 種,也在機器精度上一致(實測 2.2e-16)。若此處鬆動,第 3 節之後測的就不是「讀取流程」,而是 op 的 bug。
- L181 — ★也固定應力場本身的驗算。若積分得到的力與載荷不一致,就不是「真值」;中心值應在代數上等同於閉式 8P/(πDh)。
- L207 — ★固定零點的水平。之後所有的「◯倍」都以這 1.09 MPa 作分母,所以此處一動,比較的含義就變了。
- L231 — ★固定所見:從單張暗場圖只讀整數條紋的樸素方法,連零點的 2 倍都贏不了。因為解析度被 fσ/h = 1.78 MPa 的步長所限。與第 4 節相移(誤差降到機器精度)的對比是本 PoC 的骨架。
- L286 — ★因為在零雜訊下從同一強度公式反解,θ 應嚴格還原(從 4 張平面偏振求 4θ 的代數本身就是逆映射)。
- L308 — ★固定所見。(1) 一致率超過 95 %,但達不到 100 %。其餘是被 (δ,θ) ↔ (-δ,θ+90°) 二義性翻轉符號的像素,單波長單次測量原理上無法消除。就把「既非幾乎吻合,也非完全吻合」這個所見原樣固定下來。
- L371 — ★固定所見。(1) 沒有退偏(Stokes 幅值嚴格為 1)。這是第 5 節主張「調變下降的不是光量,而是相位靈敏度」的依據。
- L377 — (2) ★★實測說的恰恰是「傳入遮罩就能修好」這一樸素期待的反面:無遮罩 97.0 % / 排除欠取樣 97.1 % / 連低調變也排除則降到 81.9 %。因為抽掉低調變像素會使區域被割裂,skimage 的 unwrap 會為每個島選取不同的 2π 偏移。「兩者都可用遮罩排除」作為預報正確,作為處方卻錯誤。固定實測值。
- L442 — ★固定所見。(1) 若既無雜訊也無量化,δ 從明場/暗場之比中嚴格還原。
- L445 — (2) ★「僅」8 bit 量化的誤差,與「僅」雜訊 σ=0.002 的誤差同量級(實測 0.00277 vs 0.00305)。相機的位元深度與雜訊一樣重要。
examples/poc_pigment_unmixing.py
- L860 — ★「不要歸結為一個數字」的根據本身。同一行中 1.000 與 0.013 並列。
- L1082 — ★把沒能取勝這件事也留在圖裡。沒有任何一條復原落在零點線以下。
examples/poc_pipe_wall_loss.py
- L423 — ★健全區要選「沒有任何缺陷落入的 z」。起初我把 z=20..60 寫成健全區,但那正好在管底腐蝕的正上方(壁厚 4.5 mm)。
- L471 — ★r_in/r_out 以像素(體素)為單位。若按 mm 傳入,會取樣到視野之外,返回值全為 0(無聲無息。起初就因此出了一張全黑的圖)。
- L817 — ★由於按每個面板歸一化,先裁到同一範圍再傳入(不裁的話只有 E0 按 ±4 mm、其餘按 ±1 mm 上色,無法比較)。
- L1040 — ★缺口一被堵上就會響。2026-09-07 響了,於是重寫了本節 —— 因收到「按 mm 傳入會毫無例外地全返回 0」的指摘,當環落在視野之外時改為 fail-closed。記錄它從「返回空並沉默」變為「拒絕並告知」。
examples/poc_print_registration.py
- L151 — 網點線數 [lpi](商業印刷的慣用值)。★故意避開整數比:取 1200/150 = 8.00 px 時,所有網點都落在相同的小數位置,取樣相位對齊,合成器就出現偽影(實測重心每個小數偏移跳動 1.4 px)。實際掃描中,解析度也幾乎不會是線數的整數倍。
- L405 — ★臺帳的入口會為匹配宣告的 out 型別而丟棄 info,所以要用
.raw(這個坑在 fullseye/init.py 的註解裡帶實測記著)。
- L855 — ★FM 一側不收窄搜尋範圍(收窄也不改變結果,但為了堵住「AM 的折返是因為搜尋範圍」這種藉口)。
- L1242 — ★兩級失效的點,必定是粗略值超過單元半徑的點(固定包含關係)
- L1277 (ja) — ★2026-09-13: ‘lattice’ だけ例外を 1 つ許す。flyvision 族の
fly_hex_lattice(複眼の六角格子)が この語を含んで CI で鳴った(run 34751219513)。あれは網点の格子ではないので印刷の穴は 残ったまま —— 例外は名指しで 1 件に限り、それ以外が現れたら今までどおり鳴る。 「語で引く穴の固定」は、無関係の族が同じ語を使った瞬間に偽陽性になる、という実例。
- L1316 — ★基準也加入雜訊 —— 零雜訊影像會讓 star_detect 因「0 顆星」而拋出 ValueError(這本身就是正確的 fail-closed)。
- L1339 — ★2026-09-08:因本 PoC 的指摘而修正了 op 一側。在 docstring 中帶實測數字寫明「不能用於重複結構」,並讓它把投票的第二高峰 / 最高峰作為
vote_margin 返回。用贊成率無法區分的兩者,用這個數就能區分。
examples/poc_print_warpage_risk.py
- L364 — ★新生成的層被放在「當時已經翹曲的面上」(單元的誕生在變形後的構型中進行)。若忘了在此初始化,只有後長出的層保持零位移,用列平均測得的翹曲變成 1/4(2026-09-07 踩過)。力學(K 與 f)在公稱格子上,故不變。
- L808 — ★頸部整個消失。部件會分成兩塊,所以不能求解。
examples/poc_pv_thermal_survey.py
- L381 — ★MOD_SHELTER 是一個健全但吹不到風的模組。在第 3 節,它在全域平均基準下會變成「故障」。
- L482 — ★模組編號要按每個編號的面積比決定。對編號取平均再取整,會使邊界像素變成相鄰編號(或 0),從而破壞逐模組處理。
- L711 — ★模組中位數的代價 —— 對整個模組的異常盲目
- L1169 — ★
apply_cmap 若不傳 vmin/vmax,就會按該陣列的 min/max歸一化(導致每個條件下顏色含義不同),所以務必傳入。
examples/poc_real_coin_metrology.py
- L136 — ★即使數目相符,也未必數的是同一樣東西。要確認 1 個圓恰好落入 1 個成分(一對一)—— 不做這一步,「24 = 24」也會碰巧成立(1 個兩片黏連的團塊 + 1 個雜點,仍是 24)。
examples/poc_real_deblur_honesty.py
- L199 — ★要守護的不是「誰獲勝」,而是獲勝者隨度量而不同這件事。若把方法名固定,就會變成「僅因實作變好」就失敗的門。
examples/poc_real_defect_floor.py
- L156 — 振幅的步長。★它本身就是一個旋鈕。若太粗,極限會被捨入到同一格點,從而把「σ 越大差距越大」這類由步長製造的差異誤讀為真實(2026-09-09,在 34 級時 σ=1.5 與 σ=3.0 的中位數都捨入到 3.20)。
examples/poc_recycling_sorting.py
- L520 — ★在掃描之前,先從代數給出預測並列印出來。
examples/poc_registration_basin.py
- L656 — ★當使用者認為「法線明明是有的」而顯式傳入
estimate_normals 時。這裡是缺口的殘餘,比預設值差 14 個數量級。
- L836 — ★缺口 1 已於 2026-09-06 封堵。此 assert 已改寫為固定已封堵的狀態一側(以前固定的是損壞狀態:
d_fixed < 1e-6 < d_default = 已損壞)。若損壞方式回歸,這裡會失敗。
- L847 — ★缺口 2 已於 2026-09-06 封堵。以前是
< 0.9 * len(ka)(固定損壞狀態)。現在固定的是保持預設即可完全一致。
examples/poc_rotation_invariance_audit.py
- L115 — ★HALCON 風格的區域矩不變量。與用於 3-D 點雲的
moment_invariants 不同(僅憑名稱選擇會要求 (N,3) 而失敗)。
- L208 — ★當分母接近 0 時,相對偏差失去意義。對於接近圓形的形狀,Hu[1] 的真值接近 0,因此若默默用 % 來表述,就會變成「偏差 30 %」。
- L220 — ★預測落空之處。寫的時候我以為「對灰階插值後再二值化會更粗糙」,但在周長方面結果相反。
- L262 — ★由於背景是單色,輪廓用有彩度的顏色繪製。灰色沒有彩度,因此有彩度的顏色能靠色相與任何灰階區分——比反色更可靠,而且一眼就能看出「這是疊加的線」。反色真正發揮作用是在背景為彩色、「無論選哪種顏色都可能衝突」的時候。
examples/poc_safety_clearance.py
- L114 — ★軀幹由並排放置兩個膠囊體構成。若用單個圓柱體,截面會變成圓形,肩部(距軀幹中心 ±0.19 m)會脫離軀幹的陰影——真實軀幹的截面是寬 0.50 m / 深 0.30 m 的扁平形狀,伸出的手臂從背後看會被軀幹遮住。
- L126 — ★X0 與速度經過挑選,使得「每次試驗中真實分離距離始終為正(不接觸)」且「在危險帶停留足夠長的時間」——若讓其快走,會在數幀內穿過危險帶,用於統計漏檢的樣本就不夠。
- L673 — ★若在保留遮擋的情況下改變密度,遮擋偏差(+0.12 m)會疊加到每一行上,使密度的影響看不出來。逐個關閉因素正是對照組的作用。
- L683 — ★雜訊與抽稀只抽一次時,漏檢率會上下波動幾個 %。跑 3 次取平均。
- L840 — ★按行批量評估(逐個儲存格的 Python 迴圈會跑 15000 次)。
- L1079 — ★體積 op 是 (depth,row,col)。grid_coords 是 (nx,ny,nz),所以要轉置。
examples/poc_scan_to_bim_asbuilt.py
- L658 — ★施加 trim 會持續只挑選「擬合良好的點」,落入 RMSE 0.13 mm 的另一個解(實測:trim=0.9 時吸入角為 0.17 mrad,無 trim 時為 0.62 mrad)。在 as-built 檢查中,缺陷本身就是較大的殘差,所以 trim 會把缺陷丟棄。
- L950 — ★把標題主張放進一張圖:完好無損的天花板,僅因對齊方式就顯得傾斜
examples/poc_sea_ice_concentration.py
- L232 — 2. ★零基準 vs 線性混合分解 # ————————————————————————— #
- L252 — 3. ★★團塊大小(周長)決定偏差 # ————————————————————————— #
- L291 — 4. ★★偏差的符號隨密接度反轉(抵消點) # ————————————————————————— #
- L353 — 6. ★當端元偏移 5 % 時 # ————————————————————————— #
- L380 — 7. ★★第 3 成分(薄冰) # ————————————————————————— #
- L490 — (b) spec_unmix 是存在的(★在寫「沒有」之前查了 3 層)
examples/poc_search_sweep_width.py
- L829 — ★形狀的作用方式因搜尋類型而異。統一掃描寬度,只比較曲線形狀。
- L869 — ★用漏檢率 1-P 來繪製。若用 P 本身,會貼在右上角、被圖例框擋住而看不見(實際上就曾被擋住一次才察覺)。圖要先看「是否讀得出來」再定——即使數字正確,被擋住就傳達不了。
- L1089 — ★可重現性檢查:由於種子和幀數都與 §3 不同,看在相同條件下會變動多少。
- L1266 — ★要超過零基準(在假陽性率對齊的前提下)。增益是保守的——「即便零基準也能達到 174 m」才是本節的發現,因此固定的是這一點。
- L1272 — ★落空的預測:減去整體背景是仿射變換,因此實質上等同於零基準
- L1286 — ★落空的預測:在實測的 p 下,平行搜尋在 C=1 時達不到 1.000
- L1290 — ★形狀只對平行搜尋有效:統一掃描寬度後,隨機一致而平行分裂
- L1293 — ★落空的預測:本以為平坦的曲線更強,結果反而更弱(因為拖尾長)
- L1296 — (6) ★W 加倍 與 t 加倍 等價
- L1304 — (8) ★看守者:誤檢集中在正下方。僅憑閾值 W 就會大幅變動
- L1322 — ★填補缺口一側的門(2026-09-08)。由於給 op_find 加了日文段,並在 star_detect 的 docstring 中寫了領域中立的描述詞,因此固定在日文查詢中能排在前列。若退化,這裡會報警。
- L1327 — ★唯獨「點 檢測」至今仍不出現——單字「點」也必然出現在 cv_canny / frei_amp 這類輪廓 op 的說明中,因此同分並列把它擠了出去。不掩蓋這一侷限:日文段只有在「兩字及以上的詞起作用」時才拾取得到。
examples/poc_solar_el_inspection.py
- L366 — ★校正線也要通過同一成像系統(模糊)。未經模糊直接貼上的校正線,其響應比真實裂紋強 2.4 倍,使陡崖偏向粗的一側(2026-09-07 踩到過)。
examples/poc_solar_limb_darkening.py
- L317 — 2. ★零基準(50 % 法)vs 梯度最大 vs 減光模型 # ————————————————————————— #
- L367 — 3. ★★掃描減光係數 u —— 不是成比例而是折彎 # ————————————————————————— #
- L391 — ★對照組——關閉模糊後,剩下的只有幾何(50 % 面的位置)
- L427 — 4. ★★模糊的作用符號隨閾值改變(抵消點) # ————————————————————————— #
- L488 — 5. ★黑點 —— 3 % 的離群點會使半徑變動 # ————————————————————————— #
examples/poc_star_astrometry.py
- L264 — 圖像合成(★ 缺口:fullseye 中沒有在指定座標放置星點的公開 op) # ————————————————————————- #
- L1243 — ★ 「每次小」和「總體小」是不同的主張。
- L1348 — ★「均勻·孤立」的偏差為 0.0000 是理所當然的 —— 板解正是用那 24 個擬合的,所以最小二乘讓殘差的均值為 0。要看未使用的星上的誤差,需逐個剔除後重新求解。
examples/poc_stockpile_volume.py
- L698 — ★度量不同,勝者會互換:體積用水平底面,重心用平面擬合
- L714 — ★落空的預測:插值不是偏小而是偏大
- L717 — ★相互抵消:含插值的外周使誤差看起來小,只用可見點時又回來
- L726 — ★工具的漏洞。dem_viewshed 修好後這裡會報警(這正是目的)
- L728 — ★2026-09-08:因這個 PoC 的指摘修好了 op,所以現在可見才是正確的。固定它與自建的視線判定一致、且接近閉式解(若再壞則報警)。
examples/poc_strain_history.py
- L507 — ★閉式預測。中央 = (w²-1)/24 x d²(速度)/dt²(平滑化的鈍化),因果 = 返回延遲 (w-1)/2 的過去速度。
- L578 — ★不製作把歷史本身疊加的圖 —— 真值·累積·直接用肉眼無法區分(誤差為真值的 0.1〜3 %),只會成為看起來「吻合得很好」的圖。只輸出能看見所測量之物的圖。
examples/poc_structure_4d_deterioration.py
- L349 — ★遮蔽以設計形狀(
p_nom)判定。當數 mm〜數十 mm 的劣化使 surface 進入自遮蔽的盒子內側時,缺損最深處會整體缺測,製造出「越深的缺損越看不見」的虛假場面(2026-09-07 踩到:缺損谷 -21 mm 的 core 全變成 NaN)。
- L437 — ★
fit_plane_3d 的法線符號是任意的。對齊到真正的外向(掃描器一側)。
- L507 — ★經由台帳只返回宣告的 out 類型(pose),所以用
.raw 全部接收。
- L696 — ★實際嘗試「若密度不同是問題,那就統一它」(voxel_grid_downsample)
- L1257 — ★直接從點雲統計可觀測的資訊量本身(正規方程的對角分量)
- L1299 — ★先取量測方法本身的地板 —— 無劣化、無姿態誤差,只測兩次。
examples/poc_surface_roughness.py
- L272 — ★真值要 在宣告頻帶之後 定義。真值不是粗糙度成分本身,而是「用 λc 截取之後的粗糙度成分」。若這裡用原始的 rough_true,即使按正確步驟量測也會偏 -23%,那 23% 會與取樣誤差混在一起。不含頻帶的「粗糙度真值」並不存在 —— 這也是第 2 節的主張。
examples/poc_template_tracking.py
- L93 — ★ 漏洞 (a):沒有返回相關圖的公開 op,所以借用 private。在第 0 章檢驗其與公開 op
fs.op.ncc_locate 一致後再使用。
- L326 — ★ 漏洞 (d):若是公開 op,這裡會靜默返回 [0,0,0]。改為明確返回失敗。
- L1138 — (2) 零點存在地板 —— 整數座標的量化(★ 漏洞 b)
- L1168 — (9) ★ 主題:可信度的強項與弱項會隨條件反轉
- L1172 — ★ 各自擅長的崖是相反的 = 無法把其中任一個選作可信度
examples/poc_thermal_radiometry.py
- L507 — ★前向是直接積分,逆向是校正表。用同一張表往返會平凡地得到誤差 0,就不算測到了地板。
- L528 — ★Case-0 之所以嚴格為 0,是因為 350.0 K 恰好落在表的節點上。偏離節點就能看到插值誤差 —— 把 0 稱作地板就是謊言。
- L757 — ★橫軸是相對周圍的升高。若保持 T_obj,發散會塌縮成左端的一條豎線,讀不出關鍵的「從哪裡開始跳」。
- L767 — ★
plot_series 會拒絕框外的點(因為它們會貼在框上,看起來像真實資料)。發散的一側由呼叫方先行裁掉。
- L821 — ★橫軸是絕對的 Δε。若用相對 Δε/ε 作圖,三條會完全重合(因為如 §2 所述 ε 從式中消去)—— 作為圖什麼也說不出。
- L1154 — ★guard band 用的是上側的伸出。因為我們想判為合格的是「真值不在閾值之上」,所以在區間的上端裁切。若用下側 off[0],會裁得過淺(分布右偏多少就淺多少)—— 曾這樣寫過一次,因誤合格沒有減少才察覺。
- L1257 — ★同樣的取錯,在 ε=0.10 的面上 L_obj 會跌為負而拋出異常。也就是說「停下還是靜默出錯」不是由取錯決定,而是由場面決定。
- L1331 — ★發熱部要做成平台。若做成山峰,「螺栓與周圍同溫」不成立,就無法區分表觀的谷是因發射率還是因溫度。
- L1378 — ★校正消除了偏差,但把雜訊放大 1/ε 倍。這就是圖 (d) 中只有螺栓發糙的原因。
- L1450 — ★
op_find 以詞幹的部分匹配來抓取。blackbody 返回 4 條,但內容是 cv_blackhat 等形態學,與熱輻射毫無關係。看數量就判「有」會出錯。先看到開頭的名字再說。
- L1600 — 3. ★落空的預測:絕對誤差溫度越高越大
- L1602 — ★即使改變度量,發射率的誤差也不會隨上升比發散(在 Δε/ε 處封頂)
- L1605 — ★發散的是反射表觀溫度這一側(升高越小越跳)
- L1618 — 6. ★★涵蓋率。在地板(ρ=0)處 RSS 與 MC 都是 95 %,加入相關後 RSS 會下降
- L1622 — ★MC 一側穩定在 94.4〜94.6 %(並非恰好 95 %)。區間端點由 40000 次試驗的百分位決定,故有取樣誤差,現實中還混有量化。把這些都包含在內地說「MC 是準的」。
- L1638 — 7. ★漏判偏向一側(對稱的 ±k·u 會漏掉偏斜的分布)
- L1642 — 8. ★★guard band:誤合格為 忽略 > RSS > MC,誤不合格則相反
- L1662 — ★校正消除偏差,代價是把雜訊放大 1/ε 倍(接近 ε 之比 9.5)
examples/poc_thermography_ndt.py
- L61 — ★觀測時間要取得足夠長——超過健全部的 t* (6.8 s)。太短的話健全部的膝會跑到窗外,TSR 會把健全部答成「窗邊緣的深度」(實測中卡在 2.82 mm)。
- L126 — ★僅此處為近似。由於一維解不含橫向擴散,故在每個時刻以擴散長 σ(t)=√(2αt) 的高斯在面內做模糊。物理的標度律是對的,但不滿足邊界處的質量守恆。
- L142 — TSR 搜尋 t* 的範圍。★排除兩端不是裝飾 —— 高次多項式的 2 階導數在端點必然發散(Runge)。不排除的話 argmax 會貼在第一格或最後一格,深度貼在視窗兩端的 2 個值上(實測,2026-09-06)。次數掃過 4–11,最終定為 8(4–5 時 1.5 mm 以深會貼在端點,8 以上與 9/11 給出相同答案)。
- L177 — ★把 t* 捨入到格點步長會讓深度呈階梯狀量子化(64 點時為 5 % 步長)。用 3 個點擬合拋物線,求出 ln t 的次格點位置。
- L235 — ★固定所見。這裡是近似零的驗算,一旦崩壞就說明實作壞了。
- L249 — ★估計器本身的偏差。完全不經過影像,對嚴格的 1 維曲線施加
tsr_depth。這裡產生的誤差就是「多項式擬合的下限」,從第 3 節以後的偏差中減去它,剩下的才是橫向擴散與雜訊的貢獻。
- L267 — ★固定所見:下限不為零但很小。從兩側夾住 —— 若變為零,第 3 節的重新解讀(「即使不經過影像的曲線也會偏差數 %」,±5 % 與下限幾乎相同)就不成立;若變大,就無法把第 3 節以後的偏差歸因於橫向擴散。
- L302 — ★固定所見。這 2 行同時成立正是本節的主張本身。(1) 把 16 個歸併成 1 條平均後,TSR 輸給「始終回答 1.50 mm」的零點基線。
- L332 — ★固定所見。(1) 直徑為深度 4 倍以上的右下三角在數 % 內命中(與第 1 節的下限幾乎相同)。
- L362 — ★對照組:關閉橫向擴散的同一場景。這樣就能區分「橫向擴散的錯」和「像素不足/取不到遮罩的錯」。只看一邊就歸咎於物理,是這類實驗最常見的錯誤。
- L409 — ★固定對照組的所見:關閉橫向擴散後,16 個全部落入 ±8 %。這 1 行就是「壞掉的原因只有橫向擴散一個,既不是像素粗糙也不是取遮罩的方式」的依據。放鬆它,第 3 節的結論就會退回到『提高解析度就能修復』的誤讀。
- L419 — ★如果上面的推理(視窗末端的擴散長度起作用)正確,那麼截斷視窗就能修復。立下假設後,務必安排 1 個能證偽它的實驗。 —————————————————————— #
- L440 — ★固定這個 PoC 最重的所見 ——「縱橫比的極限」不是物理,而是擬合時間視窗的選法。(1) 視窗 4 秒時,8 個小的全部落入 ±20 %(實測最差 -14 %)。
- L528 — ★固定所見:若加熱均勻,原始單幀檢出最多,而 TSR 的 2 階導數一個也檢不出。「對深度估計有效但不適合檢測」= 同一工具未必對兩者都有效,正是本節的主張本身。
- L575 — ★燈的映入。帶有與缺陷同尺度結構的正是這一個。
- L602 — ★固定所見。(1) 會破壞它的只有 (c) 的與缺陷同尺度的不均勻。(b) 的平緩傾斜幾乎不破壞原始單幀 —— 這裡正是「預料落空」之處,所以明確確認 (b) 不低於 (a)。
- L683 — ★也給預設的 cube 加入 NETD。雜訊為零時,健全區的面內起伏嚴格為 0,SNR 會變成 1e9 這樣無意義的數(實測後修正)。
examples/poc_timelapse_growth.py
- L472 — ★把格子相位振 5 種,把偏差(均值)與離散(幅度)分開計數。
- L610 — 2) ★Y 字 —— 沿著穿過合體組中心的行切割體積
examples/poc_traffic_counting.py
- L256 — ★在畫面左右被截斷的行,其重心會被拉偏。也測量剔除它們的版本。
examples/poc_tree_ring_dendro.py
- L229 — ★斜著讀像素圖時,邊界處的編號會以 k, k+1, k, k+1 抖動(最近鄰的階梯)。少於 5 個樣本(1.25 px)的短游程被吸收進前一個值 —— 放任不管的話真值邊界會多出 1–2 條,變成「年數吻合方向 18 + 不吻合 13 = 31 > 24」。
- L336 — ★用 threshold=0 全取,階高自己測。measure_pos 的 amplitude(梯度瓣兩端之差)在木紋使梯度不再單調時會停在階梯中途,把 0.14 的階梯返回成 0.05(在第 8 節計數)。
- L345 — ★用於換算回 px 的外緣半徑取自測量的那一行。若用整個 15° 扇形的中位數,偏心生長會讓外緣在扇形內移動 10 px 以上,於是外側的年輪全部錯位(最初就那麼寫,把年輪 18–35 整段丟掉了)。
- L543 — ★即使在年數弄錯的方向,寬度相關性是否仍高 —— 年數與寬度的相關是不同的量
examples/poc_vegetation_cover.py
- L320 — 所以這裡降到綠、紅 2 個波段來求解。★工具的漏洞。
- L543 — ★是否落在對角線上,正是「能否以分數形式作答」本身。二值方法的線會變成階梯,在混合像素的帶上大幅偏離對角線。
- L755 — ★用圖展示「只有數字對上了」。第 3 張和第 2 張幾乎沒有共同像素,卻只有白色像素的數量是平衡的。
- L953 — (7) ★PPI 在雜訊下崩壞 —— 即使純像素占 6 成以上也拾取不到葉子。而雜訊為零時在同一場景命中 = 斷崖的原因不是純像素不足。
- L993 — (11) ★這個 PoC 發現並在 fullseye 0.1.10 中修復的漏洞。三個 Otsu 對同一輸入返回了不同答案 —— 僅把同一影像乘以 4095,判定就偏移了 otsu 13.34 pp / cv_otsu 13.92 pp,只有 sk_otsu 是仿射不變的。原因是
ops._otsu 和 backends._u8 中的 np.clip(v, 0, 1)(0..255 的 float 會使全部像素飽和而變成「全部前景」)。現在三者都不隨倍率而變。cv_otsu 殘留的 0.5 pp 是因為 OpenCV 內部量子化為 8 bit,這是與 docstring 一致的行為。門是 tests/test_value_range_saturation.py。
- L1007 — (12) ★工具的漏洞:spec_unmix 拒絕 B=3(彩色影像)= 沒有求解 RGB 的路徑
- L1013 — (12b) ★確實存在只有覆蓋率數字對上、而一個像素都沒命中的場景。這 1 行就是「不要歸約成 1 個數字」最強的依據。
examples/poc_veiling_glare.py
- L229 — ★fullseye 側的核對:艾里斑 → psf_to_mtf 是否與閉式一致
examples/poc_vessel_network.py
- L263 — ★漲落要在模糊之後加。先加的話 PSF 會把它抹平,閾值邊界仍保持乾淨(最初就那麼寫,即使把振幅提高到 0.35 也一根毛刺都沒出現)。
- L452 — 節 2-3. ★★毛刺從何而來 / 修剪閾值依賴於解析度 # ————————————————————————— #
- L560 — 節 4. ★★直徑的估計 —— 在分叉附近必然過大 # ————————————————————————— #
- L620 — 節 5. ★★Murray 指數 —— 直徑的 1 成會變成指數的 1 # ————————————————————————— #
- L751 — 節 6. ★交叉的對照組 / 因解析度而丟失的枝 # ————————————————————————— #
- L890 — (c) ★skeleton_prune3d 不是「修剪短枝」,而是「把所有枝都縮短」
- L903 — (d) ★fs.skeleton_nodes 的 docstring 說是「座標」,卻只返回端點
examples/poc_warehouse_flow.py
- L145 — ★「等人」4 件 x (7.5 + 緩行 2.5) 與「通道干擾」8 件 x (2.5 + 緩行 2.5) 都向零點加上 40.0 秒 —— 是故意湊齊的。未必與現實一致,但「相同數字出自不同原因」可用 1 例展示。
- L160 — 零點的「靜止」閾值 [m/s]。★若不放得遠高於雜訊製造的表觀速度(σ√2/Δt = 0.085 m/s @ Δt=0.25 秒),就會把靜止的人誤判為移動,使零點減少(取 0.15 m/s 時,Δt=0.25 秒下零點減半,得出「拍得越細滯留越少」的假結論)。
- L239 — ★只要有任意 1 台能看到就算可見,所以進入盲區是所有攝影機都被遮擋的高度 = 各攝影機極限的最大值。這裡我取成了 min,導致預測偏差 0.5 m。
- L329 — ★排隊者的抵達時刻要從實際開始作業的時刻來確定(用估算來定就偏差了 20 秒,等待的柱與作業的柱沒有重疊)。
- L342 — ★相遇的位置必須在貨架列的正旁邊。不在貨架與貨架之間的交叉通道兩側敖開、空餘寬度有 1.9 m,不會被歸類為「窄通道」(最初的實作讓他們在主通道的高度相遇,10 件中有 4 件落入「其他」)。
- L435 — ★做成了合併而非交換(swap)—— 交換不會破壞「在同一根柱中,較晚開始的一方是等待方」這一時間嵌套(只是角色互換,兩個角色都被正確填入)。會被破壞的是當兩個人看起來像一個人時。
- L594 — ★只保留靜止的芯。柱由兩人份的足跡構成,有 1.8 m,因此穿行者的中心也會有 2〜3 幀落入柱內(實測中這製造出「只有一個人的干涉」,10 件中落掉了 8 件)。將持續停留在距中位數 :data:
CORE_R 以內的最長連續段作為芯。
- L846 — ★按多人成分來計數會使「通道上有 10 人通過的列」變厚而混雜,所以在同一個人內部比較「等待期間」與「行走期間」。
- L1257 — 標記的大小。★由於在同一貨架前會發生「等待補貨」與「缺貨」,所以從大的標記開始畫,把小的標記疊在上面。若以相同大小繪製,後畫的會完全遮住先畫的,圖上 5 件看起來只有 2 件。
examples/poc_water_level.py
- L346 — 2. ★零點 vs 單應性 # ————————————————————————— #
- L389 — 3. ★符號會隨錨點(anchor)的位置而改變 # ————————————————————————— #
- L422 — 4. ★波動 —— 穩健(robust)只在存在離群值時才有效 # ————————————————————————— #
- L459 — 5. ★★反射 —— 系統性地偏低 # ————————————————————————— #
- L622 — (d) 卡尺(caliper)是存在的(★正要寫「沒有」時,翻了 3 層後找到了)
examples/poc_web_roll_periodicity.py
- L123 — ★第 1 nip 與第 2 nip 的周長差故意只有 15.7 mm(為了第 6 節的懸崖)。
- L158 — 只對第 6 節(懸崖)提高試驗次數。★在 24 次試驗時,報告率在 12000 mm 為 100 %、在 14000 mm 為 88 %,出現了非單調,「檢測懸崖」的位置隨小樣本波動而移動(在 120 次試驗時 12000 mm 穩定在 93 %,能保持 100 % 的是 17000 mm 以上)。只有主張懸崖位置的那一節,用地板不晃動的試驗次數來測量。
- L253 — ★op 不做取整地返回頂點(超過 ±0.5 就是「那裡不是極大」的資訊)。由於這個 PoC 也評估梳狀的諧波 bin,所以在這裡顯式取整。
- L802 — ★地板不是 0。在 24 次試驗中,最長的 2 個點偶然為 0 %,使得「保持 0 % 的最短 L」這一判定通過了,但在 120 次試驗中,即便最長 20000 mm 也殘留 2 %。先測量地板,再決定以地板的多少倍稱為懸崖(不把 0 % 用於判定)。
- L1057 — ★改為 120 次試驗後就不再正好是 100 % 了(97 / 98 %)。24 次試驗的「100 %」只是分母小而已。看著地板把它設在 95 %。
examples/poc_weld_bead_scan_angle.py
- L485 — ★候選是「回到母材面高度的點」,因此溝槽之外平坦的母材也都會成為候選。只有確認在內側 CHECK_IN mm 處存在焊縫金屬(自母材面起有 CHECK_DEV 以上的凹陷)後,才認定為趾 —— 沒有這道門,候選就會滑落到母材上,腳長會向外飛出 1.7 mm。
- L489 — ★門的深度要取得比最深的溝槽還深。最初設為 -0.6 mm 時,深度 0.45 mm(垂直方向為 0.74 mm)的溝槽穿過了門,16 個斷面中有 1 個偏離了 2.2 mm。
- L572 — ★僅存活斷面的真值均值。查看彙總中漏掉了什麼。
- L999 — ★只有凸起(餘高)偏離了預測。原因是趾部的蔓延(因為 τ 是絕對值閾值)。
- L1193 — ★溝槽隨角度逐漸消失的樣子(以自母材面的凹陷來看)
examples/profile_shape_inspection.py
- L25 — ★由於要 import repo 根目錄下的模組(profileops),把 repo 根目錄放在最前,使其從 checkout 直接執行也能通過。與其他範例做法相同。沒有它,
py -3.11 examples/<name>.py 會以 ModuleNotFoundError 失敗(2026-09-09 實測:在沒有執行門的 83 個中,失敗的只有這種類型的 2 個)。
examples/representation_roundtrip.py
- L175 — (c) 高斯 -> voxel 的質量。★曾經弄錯過的數字
examples/shape2d_morph_descriptor_tour.py
- L64 — ★EXTEND: 替換為你自己的輪廓提取結果(
{"shape": (H,W), "cs": [ (N,2) (row,col), ... ]})
examples/shapestat_landmark_tour.py
- L71 — ★EXTEND: 把你自己的地標 (N,3) 放入 s(點的排列須一一對應)
- L123 — ★EXTEND: 把你自己的群 (K,N,3) 放入 scrambled(位置、朝向、大小可以各不相同)
- L221 — ★EXTEND: 把你自己的地標按「先全部左邊,再以相同順序放右邊」排列並放入 lm
- L276 — ★EXTEND: 把 surf 設為你自己的曲面點(網格頂點、點雲),normals 設為其帶朝向的法線
- L299 — ★EXTEND: 替換為你自己的群 (K,N,3)(點的排列須在個體之間一一對應)
examples/voxel_labels_color.py
- L81 — 1) ★顏色的穩定性 —— 這個族存在的理由 # —————————————————————— #
- L152 — 4) ★各向異性 spacing # —————————————————————— #
examples_3d/alpha_shape_topology.py
- L149 — ★判別性斷言:alpha shape 保留孔洞 = 幾乎不包含軸探針。null 方法(凸包)以包含率 ≈1 在此條件下 FAIL(= 具判別性)。
examples_3d/ct_hand_radiograph.py
- L34 — 實際呼叫來確認。★直到 2026-09-05,這個範例寫著「若 azimuth=elevation=0 則與 np.sum(axis=0) 一致」,卻一次也沒確認過。而且由於 op → example 的索引把 hasattr 的字串誤認作呼叫,「一個範例都沒有的 op」被隱藏在 100% 覆蓋率之中。
examples_3d/geometry_metrology.py
- L186 — ★以數字給出與無限直線版本的差異(同樣的 2 條線段)
examples_3d/hull_bounds.py
- L237 — — 面板 C: ★新增 min_enclosing_sphere(貼合)vs 樸素球(過大)—
- L272 — ★(1) 新增 op — min_enclosing_sphere: 已知球上半徑復原 + 包含所有點 + 近乎最小 ============================================================
- L296 — ★(2) 新增 op 的 beat-null — 在非對稱點雲上比樸素球更小、近乎最小、偏安全側 ============================================================
examples_3d/mesh_props.py
- L404 — ★把繞序翻轉,體積的符號就反轉 = 符號本身就是朝向的檢驗
examples_3d/metrics_eval.py
- L234 — ★最近鄰距離說謊,是在「變化為零只是重新測了一遍」的時候。把同一斜面以不同密度、不同位置重新採集,最近鄰會沿著表面抓住相鄰的點,於是產生約為點間距量級的偽變化。M3C2 向法線方向投影,所以那個分量被去掉了。(寫這個 PoC 之前的預測「C2C 在法線偏移下也會偏大」是錯的 —— 只是把平行面沿法線方向移動的話,最近鄰距離也幾乎是真值。說謊出現在沿表面重新採集這一側。)
examples_3d/sdf_csg.py
- L167 — ★陷阱:即使
res 是純量,它也是每個軸的體素數,所以當 bounds 非各向同性時體素就不是立方體(這裡 x,y 為 0.125、z 為 0.0625)。用 h**3 計算體積會正好差 2 倍 —— 實際在本例中給出 295.00,相對閉式解 148.03 有 99 % 的誤差,下面的 assert 報警了。
examples_3d/space_carving.py
- L117 — ★使用
carve_look_at(2026-09-08)。與 look_at 是相同實作,但能從公開層引用的名字是這個 —— fs.look_at 是 render3d 的 gluLookAt 版本(4x4、−Z 朝前),是另一回事,傳入其 M[:3,:3], M[:3,3] 會使所有點落到相機後方,不拋例外地返回空的 hull。
examples_3d/structured_light_scan.py
- L122 — ★ 座標系陷阱:
look_at 以 gluLookAt 約定(相機朝向 -Z,+Y 向上)建構位姿,但 render_mesh 先把該 Vc 改寫為 (x, -y, -z) 再乘以 K(= 與 depth_to_points / K 相同的 CV 約定,depth 為 +Z 朝前)。三角測量是在 CV 約定這一側閉合的,所以位姿也要先施加 FLIP 再合成。跳過這一步,投影器就會朝向相機背後,而 depth 會保持在「看似合理的量級」卻全部錯誤(第一次執行正是如此:RMSE 78 mm = 與零點無法區分)。
fast.py
- L254 — ★不要發布 uint8 的 gaussian。
cv2.GaussianBlur 的 8U 路徑使用 8 bit 定點內核,因此與 float64 core 的差異為 1.174/255(實測,本 module 的 6 張門圖 x PARITY_AB 5 點的最大值),不滿足「一致到 1/255」。box 為 0.494/255,median / 形態學為 0.000/255,故只發布這些。若需要快速的 uint8 gaussian,請以「到 2/255」的另一契約明確地追加。
- L294 — ★此處列出的全部都是通過了 :func:
parity 門的項。追加時務必遵守「實作 -> 跑門 -> 通過則收錄」的順序。
- L320 — ★不收錄
edges_image(作為 HALCON 名與 canny 相同)。registry 中的這個名字是 backends_auto 的 skimage canny(帶真正的 hysteresis),與 core 的 canny 是不同的演算法。不一致率 1.0(實測)。 – HALCON 名的 twin(在 registry 中以相同實作、別名登記的 op)———- 與 accel._TWIN_ALIASES 同一思路。門是針對 registry 中該名字的實作來跑的,因此實作一旦偏離就會落榜而不被收錄。
- L372 — ★不可用「觀測到的輸出是否為 {0,1}」來判定 – 即便是連續 op,在常數影像上輸出也會全為 0,從而被誤判為二值、使基準擅自變嚴(實作過程中踩到過)。判定要用 registry 中宣告的 out_sort。
feat_fpfh.py
- L304 — ★2026-09-07:位姿計算是 numpy(FPFH、RANSAC、Kabsch 都是 numpy),torch 僅用於包裹回傳值。因此在不裝 torch 的 CI(py3.10 / 3.12)上,這個 op 會整體 ImportError,PoC 隨之失敗。若有 torch 則一如既往回傳 Tensor,沒有則回傳相同數值的 numpy(數值不變)。
flyvision.py
- L187 (ja) — ★ The cap is on the product, not on either factor, because the accident it prevents is the cross term: a modest 900-ommatidium eye and a modest 512x512 image are each unremarkable and together are 236M float64 = 1.9 GB.
fscript.py
- L1269 (ja) — ★2026-09-14: ここは
FsTypeError だけを捕まえていた。逆さの区間と未知の feature を契約どおり FsValueError(= FS_E_INVALID_ARG)にした結果、 fscript の利用者には Python の生の例外が漏れるようになっていた —— 例外の種類を増やしたら、それを言語境界で受けている場所を必ず一掃する ([[feedback_same_bug_class_recurs_check_siblings]])。
fslib.py
- L559 (ja) — ★2026-09-14: ここは長らく borderType 既定 =
BORDER_REFLECT_101 (d c b | a b c d — 境界の画素を重複させない折り返し)だった。numpy backend の ndi.gaussian_filter の既定は mode='reflect' = d c b a | a b c d (境界の上で折り返す)で、同じ「reflect」という語が別物を指す。 実測(512x512, sigma=1.0, 乱数): 内部は 4.6e-08 まで一致するのに、端の画素だけ 最大 0.13 = 値域の 13% ずれていた。内部しか見ない検査では原理的に出ない。 connection の 4/8 連結と同じクラスの欠陥(兄弟コードを一掃した 2 件目)。 契約は numpy 側(既存の進化レシピのオラクル)に合わせて BORDER_REFLECT。
- L615 (ja) — ★2026-09-14: ここは長らく
ndi.label(mask) = 4 連結の既定だった。 cv2 backend は connectedComponentsWithStats(..., 8, ...) で 8 連結なので、 同じ op が backend によって違う物体数を返していた —— 8x8 の市松模様で numpy 32 個 / cv2 1 個。レシピの答えが「どちらの backend が選ばれたか」で 変わるという、いちばん静かな壊れ方。C ABI を Rust で 2 度目に実装して 突き合わせたときに見つかった(fullseye_abi.h の fs_connection に 8 連結と明記した)。回帰は tests/test_fslib.py が backend 横断で見る。
- L630 (ja) — ★2026-09-14: ここは
(mask, 8, cv2.CV_32S) と位置引数で書いてあった。 読むと「8 連結を明示している」ように見えるが、cv2 5.0.0 で実測すると connectedComponentsWithStats(a, 4, CV_32S) も (a, 8, CV_32S) も同じ答え を返す —— 位置引数は connectivity として解釈されておらず、既定の 8 に たまたま一致していただけ。既定が変われば黙って 4 連結になる。 コードが主張している意図を API が守っていない形なので、キーワードで固定する。 (差分ファジングの変異解析で 4 連結を注入したのに一切検出されず、掘ったら 注入のほうが効いていなかった、という経路で見つかった。)
- L723 (ja) — ★契約 R-1(fullseye_abi.h): 失敗した演算子は「何も見つからなかった」演算子と 区別できなければならない。逆さの区間は呼び手の間違いであって、「空を寄こせ」 という正当な指定ではない —— 黙って空の Region を返すと、しきい値の計算を 間違えたレシピが「不良ゼロ」として通る。2026-09-14、同じ契約の Rust 実装が FS_E_INVALID_ARG を返すのにこちらは空を返す、という差分で見つかった。
- L743 (ja) — ★契約 R-1:
threshold で直したのと同じ欠陥が兄弟に残っていた。逆さの区間は 呼び手の間違いであって「空を寄こせ」という指定ではない —— 黙って 0 個を返すと、 面積の下限と上限を取り違えたレシピが「該当なし = 良品」として通る。 2026-09-14、Rust 実装が FS_E_INVALID_ARG を返すのにこちらは 0 個を返す差分で発見。
fsruntime.py
- L284 — ★判定 recipe 在每一種 profile(不限於工業)下都只能使用精選的、以 fslib 為後端的 builtin。其他任何呼叫都是透過
fscript._call_registry_op → api.RT 解析的 650-op 進化註冊表 op,其 _safe wrapper 是 fail-OPEN(吞掉 op 失敗並回傳無害的「無缺陷」值)。這個面絕不能作為 recipe 的算子——studio / 參考執行時也會判定部件——所以使用它的 recipe 在載入時被拒絕(docs/FSCRIPT_DECISION.md 1.6b)。
fullseye/__init__.py
- L531 — ★與宣告 out 型別對齊的 adapter,會丟棄回傳元組的 op 的第 2 項及以後(
drizzle_resample 的 wht、piv_cross_correlate 的 info)。當被丟棄的一側需要用到時,從台帳入口就搆不著。2026-09-06,某超解析度 PoC 寫成 flow, info = fs.ledger.piv_cross_correlate(...),沿第 1 軸拆開 (2,R,C),把 dy 的第 2 列當作 dx 使用,使偏移估計從 0.12 -> 0.74 像素(不拋例外)。用 .raw 可搆到原始回傳:fs.ledger.piv_cross_correlate.raw(a, b)。
fullseye/mcp/catalog.py
- L104 (ja) — ★5 層。最初は 4 層で組み、「索引にもレジストリにも facade にも無いノート」が 480 枚残った。残骸かと思ったら 480 / 480 が
fullseye.ledger で解決した (型付き台帳。レジストリでは tb_project、台帳では project のように接頭辞が 違う)。「無い」と言う前に全層を引く —— 4 層目まで引いて止めていたら、実在する 480 個の機能を残骸と呼んでいた。
- L318 (ja) — ★同点の割り方は
api.find_op と同じにする: 別名を複数 op が共有するとき name == halcon の正典を先に。次に層が多い(実行もノートもある)方。 実測 2026-09-15: “gauss” で gauss_filter(正典)と gaussian が同点になり、 名前順だと _ < i で前者が先に来た —— 偶然そうなっていたのを規則にした。
fullseye/mcp/diagnose.py
- L87 (ja) — ★順序が答えを変える(2026-09-15 実測):
ones + inf は有限部の std が 0 なので 「定数」が先に当たり、0..715 の配列は 99.9 % が ≥ 1 なので「飽和」が先に当たった。 より根本的な異常を先に言う: 非有限 → 定数 → 範囲外 → 飽和 → 平坦。
- L106 (ja) — ★飽和・平坦は image / color だけ。region は 0/1 が契約なので「飽和」ではない —— リファクタで region を含めてしまい、
--demo で otsu の出力が「飽和」と判定されて 小図が昇格した(2026-09-15 実測)。region の定数(空 / 全面)は上で拾う。
fullseye/mcp/handles.py
- L47 (ja) — ★thumb_dir を渡されたときに作っていなかった(mkdtemp のときだけ存在する)。 小図の保存が FileNotFoundError で落ち、テスト 4 件で発覚(2026-09-15)。
g1_policy_bridge.py
- L33 — ★不要把本地絕對路徑燒進發布物(2026-09-05 的稽核中,非公開的兄弟專案名出現在了 PyPI 的 wheel 裡)。預設值透過環境變數給出。Unitree G1 的場景 XML。指向 MuJoCo Menagerie 的
unitree_g1/scene.xml。
- L61 — ★安全邊界。
pickle 在 load 期間可呼叫任意 callable,因此若讓 find_class 直接放行,則僅僅打開檢查點就會執行程式碼。RL 的檢查點是以從他人處取得為前提的產物,所以這是現實的威脅。(2026-09-05 實測:放行版會直接回傳 os.system / subprocess.Popen / builtins.eval,並能在 load() 期間實際建立檔案。)此處列出的僅是 brax PPO 檢查點實際引用的數值類。出現缺失時加入本清單(例外訊息會印出模組名)。
honest_summary.py
- L58 — ★把未通過功能門的 auto op 從招牌數字中排除——此前它們只是被 [warn] 印出卻仍被計入,用門所拒絕的 op 虛增了「已過功能門」的 parity 數。
- L77 — ★2026-09-08:這一行原本寫著 – “= %d evolvable registry ops + %d n-ary capability ops (disjoint).” 實測為 979 + 17 = 979,即 n-ary 的 17 個是
reg_counted 的子集(nary_names - reg_counted 為空)。標題的 979 是正確的,但唯獨這條明細行看起來像「加法」,讀者一加就成了 996。數字雖對,但形式上說明在撒謊,故已修正。明細能否作為和成立,由 tests/test_honest_summary_arithmetic.py 每次檢查。
imgevolve.py
- L50 — ★不要吞掉它(2026-09-06 的對抗性評審)。
imgops_nary 是只需 numpy 和 scipy 的一級 module,因此 import 失敗意味著「損壞的 checkout」,而非「該環境沒有的功能」。以前是 except Exception: pass,又因為這個函數同時兼任生成器和檢查器,CI 可以在保持綠色的情況下發布一個整整消失了 17 個 op 的索引。
imgio.py
- L99 — ★判定有兩個(2026-09-08,當天內已修正)。最初只用「CIE L* 的折返為 0 次」來選,但
poc_colormap_readability 實測到 cividis 折返 0 次卻立起了色差的脊。即便明度單調,若色差步進不均勻,平滑的場中也會看見不存在的分界 – 它以片面的基準自稱「安全」。實測(512 級,相鄰色差的 max / median,以及超過中位數 1.6 倍的局部最大的個數): ========== ========== ============== ========== 映射 / L* 折返 / dE max/median / 脊的條數 ========== ========== ============== ========== gray 0 1.33 0 viridis 0 1.38 0 plasma 0 1.38 0 magma 0 1.48 0 inferno 0 1.50 0 cividis 0 2.23 1 turbo 1 1.78 1 ========== ========== ============== ========== 剔除 cividis 是因為本 repo 的近似 LUT 過粗,而非公開的 cividis 本身的問題(其 6 個控制點在逐次映射中最少)。為希望顧及色覺特性來選擇的人,準備了 :data:CVD_SAFE。tests/test_pseudocolour_family.py 每次都測量兩個基準。
- L124 — 據稱即便有色覺特性(P/D 型)也能讀出順序的映射。★
cividis 的近似 LUT 只有 6 個控制點,色差步進過粗,不滿足 :data:PERCEPTUAL_SAFE 的基準(實測 dE max/median 2.23)。增加控制點即可同時進入兩者 – 由於手抄一手資料的數值有筆誤的前科,故在能核實出處前暫緩。
matappear.py
- L167 — ★傳入 0 維(純量)時,
r.shape[-1] 會拋出裸的 IndexError(在 2026-09-04 的對抗性稽核中被揪出)。分光反射率至少帶有波長軸 – 純量不是「每個波長的值」,因此在守衛處明確拒絕。
- L296 — ★真實光柵會向兩側繞射(若溝槽對稱,+/-m 的效率幾乎相同)。此處若不把 +/- 兩側都放進去,則視光源與視線的位置關係,解可能全為負,「只保留正 lambda」的濾波器就會全部丟棄而漆黑一片。實測:與溝槽正交照射的 CD(delta-sin = -0.55),m=+1,+2 在 lambda<0 處全部消失,m=-2 的 440 nm 才是正解。
match3d.py
- L297 — ★2026-09-07:改用 numpy 的 FFT。式子相同(float32 的 fftn -> 僅相位 -> ifftn 的實部 -> argmax),沒有任何地方需要用 torch。在不裝 torch 的 CI(py3.10 / 3.12)上,這個 op 會變成 ImportError,PoC 隨之失敗。
- L1633 — ★2026-09-07:把主體改寫為 numpy。這個 ICP 是最近鄰搜尋用 cKDTree、位姿更新用 3x3 的 SVD,沒有一件事需要 torch,卻把 torch 設為必需。在不裝 torch 的 CI(py3.10 / 3.12)上,4 個 PoC 以
ImportError: this operator needs the optional 'torch' backend 落敗而暴露(本地有 torch 所以沒能察覺 – 「門要立在事故發生的地方」的實例)。數值是相同的 float64 式,因此結果不因環境而變。回傳型別為相容而保留:有 torch 則 torch.Tensor,沒有則 numpy.ndarray(數值相同)。若請求 “cpu” 以外的 device 則 fail-closed。
- L1848 — ★2026-09-07:把主體改寫為 numpy。最近鄰搜尋、6x6 的正規方程、Rodrigues 都是 CPU 上的小型線性代數,本無需 torch,卻被設為必需。在不裝 torch 的 CI(py3.10 / 3.12)上,PoC 以 ImportError 落敗而暴露。式子是相同的 float64,故結果不變(實測與 torch 版之差在 R/t 上為 0、RMSE 上為 0)。
- L2810 — ★2026-09-07:若環在影像之外則 fail-closed。
r_in/r_out 以像素為單位,故若按 mm 傳入,會讀到視野之外,並無例外地回傳全部 0(在 poc_pipe_wall_loss 輸出一張漆黑的圖後暴露)。若沒有一個半徑小於從中心到影像四角的最大距離,則回傳值只可能為空。
- L2821 — ★2026-09-07:把 grid_sample(bilinear, align_corners=True, zeros padding)替換為 scipy 的 map_coordinates(order=1, mode=”constant”, cval=0) – 同樣的雙線性插值,在不裝 torch 的 CI(py3.10 / 3.12)上也能跑。實測差異最大為 6.0e-06(值域 0..1 的隨機影像;float32 與 float64 的捨入之差)。
- L2866 — ★2026-09-07:出於與 polar_unwrap 相同的理由,替換為 map_coordinates(雙線性、範圍外 0)。無 torch 也能跑。實測差異最大為 7.6e-06。
- L3117 — ★2026-09-07:把 affine_grid + grid_sample(align_corners=False, zeros padding)替換為 numpy 的座標計算 + scipy 的 map_coordinates(order=1)。torch 僅用於雙線性重取樣,在不裝 torch 的環境(CI 的 py3.10 / 3.12)中這個 op 會變成 ImportError。約定原樣照抄:輸出體素 (d,h,w) 的歸一化座標為 ((i+0.5)/N)2-1,旋轉後用 (g+1)/2N-0.5 換回輸入的像素座標(align_corners=False 的定義)。grid 的最末軸為 (x, y, z) = (W, H, D) 的順序。與 torch 版的實測差異最大為 7.6e-06。
- L624 (ja) — ★ここを「もう片端が次数 3 以上」と書いていた最初の版は、実測で 一度も発火しなかった: ヒゲの根元が枝の端点クラスタと 26 近傍で 融合して次数 2 になる配置が普通にあり、その場合に素通りしていた (「刈った」と報告しながら 0 本という、いちばん静かな失敗)。
occupancy.py
- L223 — ★2026-09-07:讓
res 接受逐軸的值(也可長度 3)。若限定為立方,則像鳥瞰格(薄 z x 寬 xy)這樣扁平的體積,連不需要的軸也被強制用同一步進(poc_bev_sensor_fusion 實測:409.6 萬體素中只用了 8.1 %)。同族的 grid_coords 一開始就接受逐軸的 res – 對齊了入口與出口契約寬度不同的問題。傳入純量的既有呼叫方不變。
- L317 — ★2026-09-07:讓
res 接受逐軸的值(也可長度 3)。此前用 int(res) 只允許立方格,而 esdf 接受長度 3 的各向異性 voxel_size,可用 world 座標去引其輸出的這一側卻限定為立方,成了只有一側狹窄的契約。在像 CT 的薄接合層 (30,180,180) 這樣的格子上會直接卡住(在 poc_ct_void_morphology 中實測)。傳入純量的既有呼叫方不變。
opassist.py
- L50 — ★2026-09-08:ops1d(dsp 16 + funct1d 23)已註冊,卻既未出現在 docs,也未出現在 op_run / op_assist / op_find – 「註冊了」和「查得到」是兩回事。加入 opdocs 後,這道門便對查不到的一側鳴響。
- L242 — ★設計(2026-09-04,使用者「能處理各種容器類型固然更好,但統一感也很重要」):最初在
kind 裡混入了 “seq” 和 “matrix” – 即值的類型(數值、整數還是選項)與容器的形狀(1 個、向量還是矩陣)在同一個欄位裡相互競爭。從 UI 看,「int 的 3 向量」無法表達,而唯獨矩陣的結構位於 seq 鍵之下,處理各不相同。將此處正交化,kind 只放值類型,容器一律放入 container。純量也不作例外({"form": "scalar", "shape": ()}),因此 UI 可以把分支寫成一條。
- L357 — ★最長匹配。若按從短到長看,
sigma_per_mm 會命中 _mm 而變成 “mm”(實際是 1/mm)。單位一錯,UI 的數字就會悄悄變成別的東西。
- L454 — ★要點在此:有些參數其預設值並非以 tuple 給出。
center=None(可省略的 (row,col))、必需的 trans(3 向量)、k_cam(3x3 矩陣)… 只看預設值就會看成「一個數值」,UI 便只出一個 spin box 而崩潰。用名字補足結構。
- L610 — ★實測發現:向
prism_min_deviation_deg 的波長輸入傳入 0..1 的通用 signal,會被「波長須為正值」拒絕,變成一個範例跑不動的 op。若已知單位,以該量的合理範圍作種,更接近「一按就動」。
- L730 — 日文(CJK)的連綴。★
_WORD_RE 為 [a-z0-9]+,因此日語查詢一個詞都取不到(對日語輸入而言 _WORD_RE.findall(...) == [])。詞幹那一段失效,而部分匹配是連空白一起去找字串,所以日語的多詞查詢在結構上必定 0 命中 – 在一款 docstring 大半為日語、以 6 種語言分發的產品裡。2026-09-08 由 poc_search_sweep_width 踩到而查明(經 op_find 查「點檢出」/「光斑檢出」/「小目標」的日語查詢均為 0 命中,而帶次像素質心的點目標檢出只有 star_detect,卻無法從日語抵達)。
- L783 — 視為詞幹一致的公共前綴長度。★取 4 會把 “median”/”medial” 及 “contrast”/”contour” 連到一起;切在 5,則 “correlation”/”correlate”(8)、”segmentation”/”segment”(7)、”rotation”/”rotate”(5)、”gaussian”/”gauss”(5) 能被拾取,而上述兩組不會。
- L793 — 公共前綴之後允許的詞尾。★僅憑前綴長度判定會把 “median”/”medial” 連起來(共有 5 個字元的 “media”)。看詞尾是否像屈折詞尾,則 “correlation”/”correlate”(ion / e)通過,而 “median”/”medial”(n / l)與 “corner”/”cornea”(r / a)落選。
- L889 — ★下限。沒有它時,”zzz-nothing-matches” 會回傳
histogram_match(因為 “matches” 與 match_* 詞幹一致)。若命中詞的權重不足整條查詢的 15 %,則視為「未命中」。實測:”digital image correlation” 為 0.19(通過),”zzz-nothing-matches” 為 0.10(丟棄)。
ops.py
- L628 — ★端點用端點值填充。以前是
np.convolve(x, k, "same"),它會把兩端的 w 個點與零平均 – 輪廓的起點和終點被朝原點 (0,0) 方向拖動最多 50 px 以上,形成一幅 140 條輪廓的紅色條紋向左上收斂的圖(2026-09-06,第一次逐 op 作圖時發現;數值測試中平均偏差 0.3 px,看不出來)。
- L1498 — ★記錄在退化輸入下會連整個行程一起崩潰的原生側 op 的台帳(2026-09-05)。
guard 只能捕獲 Python 的例外。一旦在 C/C++ 內部越界寫入,就到此為止,並連使用者的整條流水線一起消失 – fail-soft 最糟的破法。除了在入口攔截別無他法,故帶理由列在此處,並在註冊時設卡。各平台行為不同正是此台帳存在的理由。下面 3 個在 Linux(Ubuntu 24.04 / Python 3.12 / PyPI 的 wheel)上會崩,但在 Windows 上以相同輸入一件都未重現。原生建置不同,邊界的破壞方式也不同,所以「這類輸入就沒事」的精細劃線不可信 – 對退化輸入一律拒絕。不是「修好就刪」,而是在能確認上游已修復後再刪(這不是我們自己的程式碼,故刪除條件不同)。
ops3d.py
- L375 — ★out 不是 image2d 而是 rgbimage(2026-09-02 實測)。docstring 與實作都是「RGB (size, size, 3) float [0,1]」,唯獨這一行自稱是 2-D 的亮度圖。直到放入 mesh 的種子,這個 op 才被執行,型別謂詞以 TYPEMISS「declared ‘image2d’ but returned ndarray(512,512,3)」將其暴露(在此之前,因把 (V,F) 拆成 2 個位置參數的形式,它一次都沒被執行過)。其餘 3 個 render_* op(ambient_occlusion / cast_shadow / supersample_mesh)如實測為 2-D,故保持 image2d 即可 – 撒謊的僅此一行。
- L465 (ja) — ★新しい sort は作らない: ノード表と枝表は「単位も意味も違う 2 つの表」で、 タプルで返して adapter に
r[0] と書くと 枝表を黙って捨てる (pose_error / m3c2_distance で繰り返した失敗の型)。1 つの dict に 両方を入れれば宣言 ‘table’ が実返りと一致し、捨てるものが無い。
- L616 — ★2026-09-08 追加。此前用於雕刻的位姿輔助(visualhull.look_at)從任何公開層都引不到,而抓到同名的 render3d.look_at(gluLookAt、-Z 朝前)就會無一例外地得到空的 hull(poc_livestock_body_volume)。
- L637 (ja) — ★ out は image2d ではなく keypoints(2026-09-15 実測)。実返りは 像面上の (N,2) 画素座標で、入力 (160,3) に対し (160,2) が出る —— 画像ではない。同じ型の嘘を “render” 節の
project_points で 2026-09-02 に既に直しているのに(「旧宣言 ‘image2d’ は型の嘘で、 pnp3d 側の ‘image2d’ 宣言と噛み合って PnP を壊していた」)、 この 1 行だけが兄弟一掃から取り残されていた。 例外にならないのは _sort_ok が image に ndim == 2 しか求めず、 (N,2) が「幅 2 の画像」として黙って通るから。値域も画素座標 (実測 16.0 .. 47.9)で [0,1] ではなく、image を名乗る限り 下流の閾値 op に渡ると意味を失う。
- L727 — ★曾擱置的理由(a)「points 候選清單變短而悄悄改寫既有 champion」,已隨 backends_typed.TYPE_TO_SORT 把 coordgrid -> points 摺疊而消失:2-D 橋的 tb_sphere_sdf / tb_box_sdf 帶有 INPUT_ADAPTERS._points_to_grid,確實會從點雲生成座標場,所以那邊的 “points” 宣告並非謊言(實測:傳入 (64,3) 會回傳 (16,16,16) = 是活的)。撒謊的只是 3-D 台帳那一側。
- L882 — ★axis=1。
pairs 的正典是 (N,2)(實測:消費側 6 個 op 明確拒絕 (2,N))。當謂詞還是 lambda v: True 時,這裡生成的是 (2,n),把「任何消費側都無法接收的形狀」當作宣告型別來自稱
- L920 — ★position 的正典是 [z, y, x] 的 3 個分量。不是靠多數表決,而是執行消費側來定的:refine_translation_lk / refine_lm 在傳入 4 個分量時,會以 “init_pos must have exactly 3 components [z, y, x] (got 4)” fail-closed(實測)。生成器也是 (8.0, 8.0, 8.0) 的 3 分量。然而 match_* 系列按 docstring 回傳 [score, d, h, w] 的 4 個分量,若宣告 out 仍為 “position” 就放行,後段的精化 op 會全軍覆沒 = 型別的謊言。由於 score 本身是誠實資訊,函數一側不刪(get() 保持 4 分量),而在自稱台帳型別的 call() 一側只取出座標(與 project_points 同樣處理)。
opsastrostack.py
- L85 — ★ 作為替代,我們明確拒絕原始的 (N,H,W) ndarray。無論是 video (T,H,W) / voxel (D,H,W) / histcube (H,W,T) / zscan,3-D 陣列都能通過同一結構檢查,即使弄錯也不會拋異常,而是返回一個「看似合理卻錯誤的合成結果」——這與 photon 族將 histcube 從 voxel 中分離是完全相同的危險。但這裡並非增加類型,而是透過要求它「必須是 list」來獲得同樣的防禦。一旦寫成 list(volume),呼叫方就宣告了「首軸是幀軸」。 * image2d —— 合成結果、drizzle 輸出、單幀。均為 2-D 的 float64,現有的 2-D op(濾波、閾值、morphology、psf_to_mtf)可保持語義不變地使用。它甚至並非非負(會出現 κ-σ 合成的殘差以及樣條插值的負值邊緣),所以自稱為 counts 反而是謊言。 * keypoints ——
star_detect 的返回是 (N, 2) 的 (row, col)。TYPE_CHECKS 中的 keypoints 是「(N,3) 或任意 2-D 陣列」,故直接適用,並由 psf_fit / aperture_photometry 消費。
-
L101 — ★ 這裡不是 pairs:pairs 的正典是 reprconv 側的 6 個 op 所確定的「(x, y) 對」,而這裡是圖像座標的 (row, col),與 fit_transform / mosaic 是同一規約。混用會導致列與行互換(與本 repo 已知的陷阱同形:features.match_keypoints 返回 (x,y),而 fit_transform 要求 (row,col))。自稱 keypoints 至少能共享「圖像上的點」這一約定。 * indices —— lucky_select 返回的採用幀的索引(1-D int)。就是既有詞彙本身。[frames[i] for i in idx] 即可還原為 images。 * measurement —— noise_sigma 是單個實純量。 * matrix —— frame_align 的 (3,3) 齊次變換。與 transforms / fit_transform / mosaic 所處理的是同一物,沒有理由另造專用詞。 * table —— dict / list of dict(品質、PSF 擬合、測光)。TYPE_CHECKS 中的 table 為 list |
dict,故兩者都適用。不分離的代價(honest):若非天體圖像序列進入 images 池,frame_align 找不到星,會以 ValueError 停止。由於這是 fail-closed,所以不是「發現為零」,而是「到達了但被正確拒絕」,但從鏈式 fuzzer 的角度看,align 系的 2 個 op 可能只淪為 CONTRACT。由於會出現與 photon 族分離 counts 的原因相同的症狀(7/17 從未被執行),若實測確實如此,那時將「含點像的圖像序列」另立一池的判斷才被正當化——不預先增加類型(在本 repo,順序是:只有在出現「混用會變成謊言」的證據之後才增加類型)。 |
opsdem.py
- L35 — ★ 誠實的侷限:
depth 池也可能納入相機透視投影產生的深度。透視深度中,1 px 在地面上對應多少公尺會隨深度而變,所以用恆定的 cell_size 計算的坡度會看似合理卻錯誤。那為何不分類型——這並非類型弄錯,而是與錯誤給定 cell_size 同一類的錯誤,而 cell_size 已被設為必需參數(不設預設值)。增加類型也無法防止非正射深度(謂詞最多只能看到「2-D 的實數陣列」),反而會造出一個沒有任何 op 持有種子的 dem 池,使全部 13 個 op 永久未被執行。與其假裝用類型防住了防不住的東西,不如用必需參數與 docstring 明示,並選擇在 fuzzer 中真正運行它。 * 只有 dem_fill_sinks 的輸出是 depth —— 填窪的結果仍是高程柵格,直接進入 dem_flow_direction。此處若宣告為 image2d,則族內的鏈(填 → 流)會因類型而斷開。 * dem_flow_direction 是 labels —— 返回是 int8 的 0-7 與 -1(無流出方向),是無序意義的編號。自稱 mask 會被當作二值,自稱 image2d 會使 3 與 4 的平均具有意義。它直接符合 labels 謂詞(整數 dtype,1-3 維)。 * dem_stream_network 是二值但為 image2d —— 內容是 float64,除 0.0/1.0 外還帶有缺測的 nan,不滿足 mask 謂詞(bool 或整數 dtype)。若設為 bool,則「非河道」與「本就無值」將無法區分,故讓類型遷就實作。 * 其餘全部為 image2d —— 坡度[度]、坡向[度]、曲率[1/m]、山體陰影[0,1]、起伏[m]、地平線仰角[度]、天空可視因子[0,1]、可視[0/1]。均為 2-D 的實數場,現有的 2-D op(平滑、閾值、morphology、偽彩色、圖注)可保持語義不變地使用。值域未必是 [0,1],但這與 astrostack 的合成結果處境相同:在本 repo,image2d 並非亮度的約定,而是「2-D 的實數場」的約定。類別 → [(op 名, module, [輸入類別], 輸出類別)]
opsflyvision.py
- L62 (ja) — ★ 重みは公開しない:
fly_hex_resample の個眼×画素の重み行列は functools.lru_cache で内部にだけ保持し、op の入出力型には現さない —— 出すと「画素座標系に依存する巨大な派生物」が型プールを汚し、下流の 2-D op が それを画像と取り違えて黙って処理してしまう(zscan を video に渡すと通る、と 同じ事故の型)。出さないことでこの取り違えを構造的に不可能にする。
opsimgforensics.py
- L206 — ★
phash 的謂詞中,看 dtype 才是本體。若只用 ndim == 1,就與既有的 signal 完全重疊,分離的意義隨之消失。
- L208 — ★
fingerprint 的謂詞在形狀上無法與 image2d 區分。只能靠零均值性來切分,而那是執行時的統計式猜測,所以謂詞也帶有同樣的弱點(因此才用類型來分離)。請把這一弱點留在謂詞的註解裡。
- L224 — ★
fingerprint 的種子必須始終經由 sensor_fingerprint 生成。若直接放 rng.standard_normal((H, W)),那是白噪聲而非指紋,比對將永遠返回「無關聯」=以為增加了檢驗面,實則未增加。
- L227 — ★
images 的種子必須是相同 shape 且2 張以上。只有 1 張時,sensor_fingerprint 會持續 fail-closed 而一次也不運行。
- L242 — ★
jpeg_ghost_quality 的 qualities=None 假定為「40..95 步長 5 的 12 個」,所以若 images 的種子不是 12 張,必然拋 ValueError。這是有意的 fail-closed(不返回索引與品質錯位的圖),故請在 fuzzer 側對齊張數。
- L246 — ★
watermark_* 的 bits 必須不超過容量(LL 的 8x8 塊數)。64x64 的 image2d + level 1 的 LL 為 32x32 = 16 塊。
opsinterferometry.py
- L96 — ★ 未搭載到既有
signal 上,是實測的結果。最初判斷「csi_signal_simulate ([] -> signal) 會把真正的干涉訊號注入池中,故可到達」,但用該配線跑鏈式 fuzzer 時,在 600 條鏈(300x長度6 + 300x長度8)中 csi_peak_position 與 chromatic_confocal_height 一次也沒有被執行(記錄僅有 7 條 CONTRACT)。原因是 signal 種子是帶負值的正弦波,入口 op 在同一鏈中被先抽到的機率很低。這與 opsphoton 在 counts 上踩過的陷阱完全一致,作為 fail-closed 完美生效的結果,「發現為零」看起來像穩健。在以 sweep 為專用池的同條件重測中,9 個 op 全部被執行。混用 2 種類型也不會讓弄錯悄然通過,這一點由各自專用的判別來保障(兩者都以閉式測得閾值):- 把頻譜傳給 csi_peak_position → carrier_tolerance。干涉訊號的載波立於 2/λ(Nyquist 的 0.333),而共焦峰為 0.010。實測中同一檢查也能捕獲 1000 倍的單位錯誤。- 把干涉訊號傳給 chromatic_confocal_height → max_carrier_fraction。共焦響應的 AC 分量只有低頻(實測 0.010 / 0.010 / 0.015),而干涉訊號是 0.333。入口 = csi_signal_simulate / chromatic_confocal_simulate(兩者均無參數即可產生),出口 = csi_envelope (-> signal) 與 2 個 measurement op。
opsoptics.py
- L125 (ja) — ★ pupil_blur は「画像 × カーネル」の一般畳み込み(filters_freq.convol_fft) ではない —— PSF の標本間隔 λN/oversample を検出器ピッチへ面積積分して から畳む、その単位合わせが本体。だから PSF を作る側に置く。
- L140 — ★ 不是 normals(點雲的 (N,3) 法線),而是 normalmap。二者形狀相似,但傳入 (N,3) 會被 _normal_map 以 ValueError 拒絕。此處若宣告為 normals,便是「可以傳入點雲法線」的謊言,鏈式 fuzzer 每次都會以 CONTRACT 結束,從而一次也不執行此族(=化為發現為零)。
opsphoton.py
- L85 — ★ 需注意:由於 counts 是 1-D 的 float64 陣列本身,所以「呼叫」dsp / funct1d 毫無妨礙(類型詞彙是為鏈式 fuzzer 的 pool 分離,而非 Python 的可呼叫性)。反向橋 = 將 signal 非負化為 counts 的路徑,參見下方的「橋」註記。 * countrate —— SPAD 的計數率序列(Hz)(1-D,非負)。與 counts 同為「非負的 1-D」,但是不同的量,故另立一池。理由有兩點,都基於實測:(a) 單位相差 7 個數量級。counts 池的值域約為 0-250 計數,把它傳給 spad_deadtime_apply(dead_time_ns=50) 得 250 Hz x 50 ns = 1.25e-5 → 無一例外返回無限接近恆等映射的值。op 雖「到達」,但死時間的物理(飽和、1/tau 的 fail-closed、麻痹型的非單射性)從未被踏及。這與把 histcube 搭載到 voxel 上時相同,是「看似合理卻錯誤的通過」,既不出 CONTRACT 也不出 TYPEMISS。(b) 物理不同。死時間作用於檢測器的率流,而非對 TCSPC 的時間 bin 直方圖逐 bin 作用(對直方圖正確的畸變模型是 Coates = tcspc_coates_correct)。若歸為同一詞彙,演化搜尋會把「對直方圖施加死時間校正」這一物理上錯誤的鏈學作正當的類型連接。countrate 是明知只有 apply <-> correct 2 個 op 的狹窄 sort(與 jones 有 2 op、stokes 有 3 op 同級)。不過這 2 個 op 互為嚴格逆,故池內有往返不變量在循環。 * histcube —— 逐像素的到達時刻直方圖立方體 (H, W, T),時間軸在最後。既有的
voxel 是「3-D 陣列」,TYPE_CHECKS 也僅 ndim == 3,故結構上會通過。但 voxel 是 (D, H, W) 的空間格,軸義不同:把 (D,H,W) 的體積當作 histcube 傳入,dtof_cube_depth 會把 W 讀作時間軸,返回的不是異常而是「看似合理卻錯誤的深度圖」(實測:均勻體積下全像素 0.0075 m)。此外,扁平的 histcube 在 dtof_cube_depth 側也會被判為 empty 而靜默不通過(雙重防禦)。橋(針對狹窄 sort 的對策,實作未竟=待親判斷):可成為 signal -> counts 之橋的是「把任意實數 1-D 視為非負的光子率輪廓並作 Poisson 取樣」的 op(photon_sample 的 1-D 版)。將負值的處理設為顯式參數便不成為靜默整流,也不破壞紀律。既有的非負輸出 1-D op(funct1d.abs_funct_1d 實測 min 0.0023,dsp.envelope 實測 min 0.749,兩者均保證非負),若該橋存在,則是 signal -> counts 的自然前段。詳見報告。
opspiv.py
- L25 — * ★ 我們新設了
flow2d。既有的 flow_dense 的謂詞是 ndim == 4 and shape[0] == 3(3-D 場景流),故 2-D 的 (2, h, w) 本就不適用。借用其名,就等於台帳一邊宣告「返回 3 個分量」一邊返回 2 個分量,使宣告成謊言。它滿足本 repo 增加類型的條件(「若沒有持有種子的 op,將永久未被執行」):生成為 7 個 op(cross_correlate / multipass / deform_pass / ensemble_correlate / replace_outliers / to_velocity / sample_at_windows),消費為 13 個 op(含場量 8、可視化 2、檢定 2、評估 3 的重疊),族內的生成與消費是閉合的。
- L35 — ★ 我們必給它一個出口(
visualise 的 2 個 op)—— 能造卻看不見的類型會在鏈中途成為死路,產生「狹窄 sort」。雙向的 fail-closed 也已實測確認:把 2-D 流傳給 reprconv.flow_magnitude 會拋 ValueError(點名以「取 (3, D, H, W)」拒絕),把 3-D 場景流傳給 piv_vorticity 會拋 ValueError。 * 輸入的圖像對是 image2d —— 粒子圖像本身就是 2-D 的實數場,現有的 2-D op(平滑、閾值、背景差、圖注)可保持語義不變地使用。不保證亮度落在 [0,1],但這與 astrostack 的合成結果處境相同。 * piv_outlier_mask 是 mask —— bool 的 2-D,與謂詞一致。與因帶 nan 而無法自稱 mask 的 dem_stream_network 不同,這裡已把缺測摺疊到 True(外點)一側,故以 bool 閉合。 * 統計是 table(dict)。piv_error_stats / piv_peak_locking。 * 轉速度的 piv_to_velocity 的輸出也是 flow2d —— 單位從 px/frame 變為 m/s 但類型相同。此處誠實寫明:類型守不住單位。故把兩種尺度都設為必需參數(與 demops 的 cell_size 同一判斷)。也曾考慮按單位分類型,但那會成為只有 1 個 op 生成 m/s、無一 op 消費的類型——違反「出證據後再增加」的順序,故未採納。
opsrangedoppler.py
- L108 — ★ 訂正的記錄:本模組初稿寫作「在 real 中速度的符號會遺失」,但那是錯的(僅對只有距離軸的 1-D 實訊號成立,兩軸齊全後符號會被保留)。測試先破而發覺。真正遺失的是「一對中哪一個是真的」、振幅的一半,以及無模糊測距範圍的一半。
_as_beat_cube 在 dtype 階段拒絕,並點名修法(顯式構造解析訊號)。 ————————————————————————– 為避免狹窄 sort 的入口與出口(對已實測教訓的應對) ————————————————————————– 本 repo 實際踩過 2 個陷阱:① 無 op 產生的類型永久不可達(score 是 434 op 中唯一 1 件 blocked 的那件),② 搭載到既有池會每次 fail-closed 被彈,看起來像「發現為零」(photon 族 7/17 未被執行的那件)。beatcube 對兩者都作了處置:入口(產生 beatcube 的 op):fmcw_beat_simulate(僅參數,無輸入類型)fmcw_window_apply(beatcube -> beatcube)出口(返回既有 sort 的 op):range_doppler_map -> image2d(最大池)fmcw_range_profile -> signal beamform_delay_sum -> signal beamform_doa -> table 入口是「僅參數之源」這一點與 tcspc_simulate(無輸入類型 -> counts)同形,故鏈式 fuzzer 需要與 counts 相同的專用生成器(對親的交辦事項;生成器的實體已在報告中經執行確認載明)。出口落入 image2d 與 signal,是本 repo 最大級的 2 個池,故不會成為 jones(2 op)或 countrate(2 op)那樣閉合的狹窄 sort。
opsreprconv.py
- L257 — ★
flow 無法用單一謂詞寫就。因密 (3,D,H,W) 與散在 (N,3) 同名共存,若謂詞同時放行兩者則什麼都守不住,若定於一方則既有 4 op 中必有其一成為 TYPEMISS。分離才是正確的(與將 video 從 voxel 分離同一判斷),但那是改寫既有 op 宣告的工作,超出本模組職責,故此處僅留提案。
opsvolcolor.py
- L63 — ★ 但既有的
labels 謂詞為 ndim >= 1,2-D 的標籤圖像與 3-D 的標籤體積同居。本模組的 11 個 op 被傳入 2-D 時全部拋 ValueError(fail-closed),故弄錯絕不會悄然通過。危險在於相反面:在只有 2-D 種子的池中,會在一次也不執行的情況下看起來像「發現為零」—— 與 opsphoton 在 counts 上踩過的陷阱同形。配線側務必注入 3-D 標籤種子(參見下方「親配線時」)。 * voxel —— vol_label_overlay 疊加的原灰度體積,以及 vol_label_color_flicker 接收的二值體積。二者都是 (D,H,W) 的既有 voxel 詞彙本身,沒有理由另造新詞。 * rgbimage —— 斷面與投影的返回 (H,W,3)。既有的 rgbimage 消費 op(鏡面分離、色變換、保存)可保持語義地使用。這裡是 rgbvolume 詞彙的出口,故新詞彙不成死胡同。 * matrix —— vol_label_palette 的返回 (n+1, 3)。就是 2-D 的實矩陣本身。 * table —— 形狀統計 / 圖例 / 閃爍測量 / 帶色網格的集合。
- L77 — ★ 未為「帶色網格的集合」另造新詞,是實測的結果。最初打算加
colormeshes,但把既有的 table 消費 op 全部過一遍,將 vol_labels_to_meshes 的返回傳入(2026-09-02 實測,橫跨 ops3d / ops1d / opsmath / opsoptics / opslightfield / opsphoton / opsacoustics / opsinterferometry / opscadmap),能吃 table 的 op 只有 3 件(abcd_matrix / wavefront_stats / istft),且 3 件都以 ValueError fail-closed。即不滿足「混用會悄然出錯」的條件。給不滿足者添詞,只會多出一個消費者為零的新詞彙 = 多一個死胡同(docs/OP_COMBINATION_MATRIX.md 的判斷基準)。此外,若想把單個網格作為 mesh sort 流向下游,用 [(m["vertices"], m["faces"]) for m in result] 剝出 —— 因這是丟棄顏色的操作,故不在 adapter 中隱式進行。 ————————————————————————– 一個新詞彙及其理由(基於實測) ————————————————————————– * rgbvolume —— (D, H, W, 3) 的帶色體積。既有 lightfield 的謂詞只是 ndim == 4,故色體積完全滿足 lightfield。實測(2026-09-02,將 (8, 16, 16, 3) 的色體積傳給 lightfield 的 op):- lf_refocus / lf_subaperture / lf_epi / lf_depth_from_focus 這 4 個 op 既不出異常也不出 NaN,返回有限的 (16, 3)(各自自稱「重聚焦像」「部分開口像」「EPI」「深度」)。是把 z 軸讀作角度軸 V、y 軸讀作角度軸 U 而得的無意義有限值。- 只有 lf_all_in_focus 因參數不足給出 TypeError(不是類型問題)。反向(把光場傳給 vol_label_slice_rgb)會因 shape[3] != 3 而 fail-closed。安全的只有一側,故不能依賴執行時檢查。與將 zscan 從 video 分離同一判斷。入口 = vol_colorize_labels (labels -> rgbvolume) 與 vol_label_overlay (voxel + labels -> rgbvolume),出口 = vol_label_slice_rgb / vol_label_mpr_rgb (-> rgbimage)。產 2、吃 2,故不成死胡同。
pcseg.py
- L448 — ★
full_matrices=True(預設)會分配 (N, N) 的 U 並丟棄。2026-09-06 實測:20000 點為 3.73 s / 3.2 GB,而 full_matrices=False 為 0.876 ms(4263 倍),且 Vt 逐位一致。10 萬點則會因 80 GB 而崩。同型也存在於 pcseg.fit_plane / measure / ops / camera / pnp3d(都在丟棄 U)。靜態門是 tests/test_svd_full_matrices.py。
pivops.py
- L470 — ★ 相關峰立不起來的窗(無紋理、全面一樣)返回 nan —— 不返回 0 是為了不把「未動」與「不明」混同。但有幾成是 nan 只能從返回值得知,此前的形態是等到
flow.mean() 變為 nan 才察覺(2026-09-06)。在此計數。實測:均勻背景上只有 16x16 方塊的圖像,98 窗中僅 16 窗為有限(0.163)。全面紋理則為 1.000。
ppf.py
- L126 — ★ 素樸的 PCA 法線符號任意,旋轉後有四成的點會翻轉。由於 PPF 的特徵是法線之間的角度,翻轉則鍵會改變。實測(400 點,繞 z 軸):用素樸法線時鍵的一致率在 0/37/90/143 度為 100 / 73.6 / 69.4 / 67.2 %,用定向法線則全部 100 %。與
pointcloud.fpfh 踩過的同一個洞,在同一天一併修好。
problems.py
- L147 — ★一個確定性的全域洗牌(基點固定,因此 train/holdout/locked 索引同一個置換),按 seed 的角色分成三個互不相交的帶(evolve.run 取 train=seed、holdout=seed+10000、locked=seed+20000,於是 seed//10000 mod 3 選出帶)。舊的
off = seed % pool 在 pool 整除 10000 時總是把三個視窗塌縮到同一批影格——一個靜默的 train↔holdout↔locked 洩漏,使過擬合 train 的 champion 看起來「在純 holdout 上勝過手工」。純粹的三分需要 pool >= 3n;更小的 pool 無法給出乾淨的 holdout,所以我們拒絕而非靜默洩漏。
profileops.py
- L269 — ★ 最初寫作「曲率較大的一側」,在 NACA 2412 上把後緣判成了前緣。三點圓的曲率,在上下面幾乎相切的後緣處會比前緣的圓度更大——「前緣是圓的」這一直覺,用輪廓上的 3 點來測時會逆轉。
- L276 — ★ 後緣張開時,最遠的 2 點會拾取後緣的某一角而使弦傾斜。改在縫隙的中點重取,再把前緣定為「離該中點最遠的點」。不這樣做,即使對稱翼也會出現相當於後緣半縫隙的彎度(實測 0.001257)。
- L642 — ★ 比對前用同一取法重取。弦的框架(尤其是後緣中點)會略依賴點的放置方式,故把生輪廓與重取輪廓相互對照時,即使同一形狀也會引入 0.02 度的旋轉與 7.8e-4 的平移——這本身就成了偏差的地板(實測 rms 6.05e-4)。要比較的東西須置於同一擂台。
- L653 — ★ 不作點對點,而作點對折線測量。即便按等弧長重取,兩者的相位也不一致,故若以編號取對應,則相位錯移會直接成為偏差(實測:拿同一形狀與自身比,rms 為 6.05e-4——與想檢測的缺陷同一數量級)。
realdata.py
- L38 — ★ 只有
public 列為真者,方可用於公開發布的圖。僅限研究、教育目的且需註明引用者,帶有 cite。
- L90 — ★ skimage 只持有隨附的子集,其餘在執行時經 pooch 去取。取不到的在本 repo 中不使用(PoC 若依賴網路,出問題時便分不清是實作還是網路所致)。
reprconv.py
- L149 — ★ 轉為整數 dtype 時,須在轉換前檢查生值。敵對檢查發現的洞(2026-09-02):
np.asarray(nan, dtype=int64) 不出異常而返回 INT_MIN,轉換後 dtype.kind == 'i',故會跳過下面的非有限檢查。像 3.7 這樣的非整數也會被靜默截為 3——索引偏了 1 的結果,無異常地返回。這正是轉換 op 的謊言本身。
- L1080 — ★ 真實 bug 的回歸點。最初此處為
np.maximum(sigma, finfo.tiny)。在重複點處 sigma = 2.2e-308,gaussians_to_voxel 的 sigma ** 3 下溢為 0,導致 0 除 -> NaN。本想「避開 0」,卻替換成了會在下游產生 NaN 的值(體積的一部分在無異常下變為 NaN = 典型的靜默出錯)。重複點意味著「間隔無法測量」,故不以哨兵填補,而是 fail-closed。
rust/fullseye_core/examples/python_ctypes.py
- L42 (ja) — ★第 5 引数 fs_dtype_t。2026-09-14 までヘッダにだけ在って実装と FFI 宣言に 無かった引数。ctypes は引数の数を検査しないので、抜けても黙って動く。
sample_data.py
- L147 — ★ 加入的理由:在展示 111-113 中再次出現「合成只能造出自己已知的壞法」(有 6 張實拍出現 9 件不良的前例)。PoC 保持離線閉合,只把替換為實數據的入口置於台帳。commercial=”check” 及以上者,須先讀源的頁面再用。
scene_registry.py
- L19 (ja) — ★配布物にローカル絶対パスを焼き込まない。ここは自分のマシンの作業物を指していた ので、他人が pip install した環境では黙って落ちる(しかも「場面が無い」ではなく 「その場面だけ静かに欠ける」形で)。環境変数で受け、未設定ならその場面を登録しない = 在ると偽らない。
loco_mujoco は入っていれば自分で在り処を知っているので探す。
sdf_ops.py
- L293 — ★ 加入的理由基於實測:
poc_dfm_thickness_overhang 與 poc_cad_scan_deviation 報告稱 # 「機械部件由圓柱孔、倒角、圓角構成,但基元只有球與 # 長方體,故無法用 CSG 拼裝」,兩者都各自手寫了逐面的解析式。此處的 4 個全部為閉式且嚴格(外側為到最近表面的 # 歐氏距離,內側為到最近面的負值),故此後可僅用 CSG 拼出帶真值的合成部件。 # ————————————————————————— #
specops.py
- L810 — ★ 這是一個同時依賴染色與成像系統的值,並非萬能常數——若在自家載玻片上定量,請拍單染載玻片並用 :func:
stain_vectors_from_patches 重新測量。
- L842 — ★ 第 3 根是「餘量」。僅 2 根時 2x3 無逆矩陣,用偽逆則殘差會被靜默分配給這 2 根。立起正交的第 3 根,把無處可去的密度匯集到那裡(=日後可作為殘差讀取)。
studio.py
- L273 — ★ 直接右鍵點擊圖本身(使用者 2026-09-06:「若能右鍵把作為圖顯示的東西複製到剪貼簿就好了」)。這是本 repo 的 Studio UI 規約——顯示系也須能從右鍵完成一整套。可與下方按鈕列做同樣的事(不要二者取其一)。
- L6119 — ★ 圖的承接盤。範例經
examplefig 往此處寫 PNG。不傳環境變數的執行(CLI)中一張都不寫,故只有從畫廊執行時才出圖(範例的數值與速度不變)。
- L6275 — ★ 圖的承接盤。範例經
examplefig 往此處寫 PNG。不傳環境變數的執行(CLI)中一張都不寫,故只有從畫廊執行時才出圖(範例的數值與速度不變)。
tests/conftest.py
- L28 — ★ 把 Studio 的設定在整個工作階段內逃逸到一次性 ini。 # ————————————————————————— #
QSettings("Fullseye", "Studio") 會寫入原生儲存庫(Windows 上為登錄檔 HKCU\Software\Fullseye\Studio)。我們此前把隔離放在各個測試檔案裡,故被遺漏的檔案汙染了使用者的真實登錄檔。2026-09-05 的稽核確認了實害:10 個 recent_files 中有 8 個是 pytest 的暫時路徑,system\operator_timeout_ms 等實值也殘留著。(隔離只在 3 個檔案中的 2 個裡,test_studio_params.py 是素通的。)不再逐個添加,而是作為工作階段 autouse 在此只放一個。環境變數是 studio._settings() 唯一查看的入口,故此舉覆蓋全部測試。
- L44 — ★ 需要 optional backend 的測試的宣告。 # ————————————————————————— # CI 的註記長期寫著「不安裝 torch/kornia(對應測試 graceful skip)」,但 2026-09-05 的實測顯示那並非事實——目標測試並未 skip,而是以
ImportError: this operator needs the optional 'torch' backend 失敗(14 件)。只有註記,卻沒有用機器核實它的機制。此處把宣告匯入單一入口。目標是雙向:* 無 backend 的環境 → skip(讓註記成為事實)* 理應有 backend 的環境 → 不許 skip,令其失敗(FULLSEYE_REQUIRE_OPTIONAL=1。CI 的 py3.11 作業會立起它)只有單向時,真正的回歸會悄然化為 skip(與 feedback_failsoft_hides_permanently_dead_ops 同形)。
- L192 (ja) — ★2026-09-14 追加。ここまで探針バンクは 6 sort しか無く、901 op のうち 151 本 (16.8 %)が契約ゲート 3 本(例外を投げない / 非有限を出さない / 決定的)を 一度も実行されていなかった ——
PROBELESS_OPS_BUDGET = 151 というラチェットで 本数だけ凍結し、「本来の直しは BANKS を全 in_sort へ広げること」と自分で書いて あった。その本来の直しをここで入れる。 形の出どころは推測ではない: backends_bridge._EMPTY_OF が 12 sort すべての 正準の最小値を宣言しており(そこが sort の定義そのもの)、problems.py の _points_stack / _signal_stack などが実データの作り方を持っている。 各バンクは既存の作法に合わせ、普通の値・定数 0・定数 1・退化形を混ぜる (定数と退化形が「走った」と「意味のある出力」を分ける —— [[feedback_ran_is_not_meaningful_output]])。 ————————————————————————— #
- L215 (ja) — ★点群は連結なものと非連結なものの両方を置く。
tb_geodesic_distances が 不達を inf で表すのは契約どおりで、ops.NONFINITE_IS_MEANINGFUL に 「1.0 に潰すと『届かない』が『近い』に化ける」と宣言済み。 ここで一度 normal をわざと連結にして有限性ゲートを緑にしかけたが、 それは欠陥を隠す方向だった —— 直すべきは門が台帳を見ていないこと。 normal は橋でつないだ現実的な形、two_clusters は非連結を撃つ探針。
- L263 (ja) — ★特異行列は必ず置く。 一度ここから外しかけたが、それは誤りだった ——
tb_mat_cond が特異行列で inf を返すのは契約どおりで、ops.py の NONFINITE_IS_MEANINGFUL に「厳密に特異な行列は s_min=0 なので inf が 正しい答え。有限に潰すと『十分に良条件』と読めてしまう」と既に宣言済み だった。落ちていたのは op ではなく、有限性ゲートがその台帳を見ていない こと。探針を削って緑にするのは、欠陥を隠す行為。 (同じ註に 2026-09-05 の教訓が書いてある ——「自分の probe では特異行列を 作っていなかったので tb_mat_cond を取りこぼした」。探針から外すのは その取りこぼしをわざと再現することになる。)
- L381 (ja) — ★新規(2026-09-14): ここまで探針が無く、契約ゲートを一度も通っていなかった 5 sort = 101 op。残る 6 sort(video / qimage / cimage / lightfield / beatcube = 50 op)は形が複素・4-D で退化形の設計に手間が要るため、 一度に全部入れて切り分け不能にしないよう次の段で足す。
tests/test_abi_apply.py
- L78 (ja) — ★target dir は 別に切る。最初は
target/release(既定)に建ててそこから直接ロードして いたが、同じプロセスで後に走る test_rust_abi_parity.py が cargo build --release (feature なし)で同じ DLL を書き換えようとし、ロード済みでロックされているので ビルドに失敗 → 36 件が黙って SKIP になった([[feedback_zero_findings_may_mean_never_executed]])。 建てる場所を分け、ロードは tmp へのコピーから行う。
- L49 (ja) — ★このパーサは「タグから最初の
; まで」を宣言とみなす。だからタグと 宣言のあいだに ; を含む散文があると、宣言が見つからず collection 中に 死ぬ —— そして pytest はファイル 1 つの collection エラーで スイート全体を中断する(2026-09-14 実測: Interrupted: 1 error during collection で 12,000 件が 1 件も走らず、それでも runner の exit code は 0)。 [[feedback_test_import_kills_collection]] と同じ族なので、何が悪くて どう直すかをここで言う。黙って「malformed」とだけ言うと、壊した本人が ヘッダの書式規則に気づけない。
- L234 (ja) — ★2026-09-14:
FsValueError を足した。それまで例外は 2 種しか無く、 種の違う失敗が同じ status に潰れていた —— 逆さの区間は契約では FS_E_INVALID_ARG なのに FsTypeError(= FS_E_TYPE)を投げていた。 差分テストが「どちらも拒否した」までしか見ていなかったので素通りした。
tests/test_abi_signatures_match.py
- L82 (ja) — ★
[A] + [B] * 3 のような式で書かれた argtypes がある。最初この形を 数えられず fs_measure_all を「1 引数」と誤読して門が 3 件赤になった —— 門のパーサが弱いのを実装の欠陥と読まない。 行末までを 1 宣言として 取り、[...] の各塊の要素数に * N の倍数を掛けて合計する。
- L180 (ja) — ★
cl に .h を直接渡してはいけない —— MSVC は拡張子で言語を決めるので 「ソースファイルの種類は認識できません」と警告だけ出して rc=0 を返す。 検査が 1 行も走っていないのに緑になる、最悪の形 ([[feedback_ran_is_not_meaningful_output]]。2026-09-14 に実際そう読みかけた)。 #include する小さな .c / .cpp を作って /Zs(構文検査のみ)を掛ける。
- L190 (ja) — ★引用は 1 段も挟まない。
subprocess にリストで渡すと Python が 引数を再クォートし、内側の " が \" に化けて cmd に届く (実測のエラー: '\"C:\Program Files...\vcvars64.bat\"' は認識されて いません)。バッチファイルに書き出して、それを叩くのが確実。
tests/test_annotate_bold_italic.py
- L59 — ★ 疊打只會橫向變粗。上下變粗的描邊會把和文字的內白填滿(2026-09-09 實測:11pt 的「量 值 面積」變成了黑塊)。
tests/test_astrostack.py
- L1053 — ★ 2026-09-08:新增了第 3 個返回值 vote_margin(第 2 高的峰 / 第 1 高)。若為星野,峰只有一個,故應當小——這一點也在此固定。
tests/test_backends_typed_liveness.py
- L57 — ★ 就這一件而言,記錄有3 處——此處、
gen_op_figures.DOMAIN_MISMATCH,以及 op 自身 0/60 的實測。即便如此,「已註冊卻一次也不運行」的狀態仍在持續。知道某事與在判定中使用它是兩回事(KNOWN_ISSUES §42)。
tests/test_blob2d.py
- L442 — ★三個物體必須都是不同的形狀。把相同形狀排列起來的種子會讓 circularity 和 holes 都返回相同的值,因而漏掉「無論轉哪個旋鈕都返回相同數值的 op」。
tests/test_caltab.py
- L121 — ★閘門是否觸發依賴於環境,所以不作斷言。只檢查值未被隱藏地返回。
tests/test_ci_wheel_check_paths.py
- L68 — ★不看 returncode。這項檢查的對象是參數的解析,而不是 wheel 的內容。內容的判定依賴於環境 —— 實測 2026-09-05:在透過 PYTHONPATH 暴露原始碼的環境中,由於腳本會把 repo 根目錄從 sys.path 移除,部分模組無法 import 而報 NG(在 pip install 的環境中不會發生)。因為這裡看了 returncode,在 Linux 上這項檢查以「路徑解析問題」的形式落敗。
tests/test_collection_sizes.py
- L64 — ★OPS3D 是 {op 名: 元資料 dict} 的扁平表。用
sum(len(v) for v in values()) 計數會得到各 op 元資料鍵數的總和(2,492),差點把一個沒有意義的數字刻進台賬(2026-09-08,在寫入前查看結構時發現)。
- L85 — ★2026-09-08 新增:兩個用於累積說明的台賬。說明最容易悄悄減少,所以在這裡計數(docs/CAPABILITIES.md 與 docs/HARDENING.md 的來源)。
- L260 — ★這裡棘手的是,這個測試所守護的缺陷在 Windows 上不會重現。實測 2026-09-05:在 Linux(Ubuntu 24.04 / py3.12 / PyPI wheel)上 3 個 op 對退化輸入 SIGSEGV。把相同的輸入送到 Windows 上一個也沒崩潰。所以「本地是綠的」不能作為依據,必須保持在一種能在兩個環境上驗證台賬是否正確生效的形式。 ————————————————————————— #
- L267 — ★
ops.NATIVE_CRASHES_ON_DEGENERATE 的對照。它必須與本體 1:1 一致。只改一邊就會落敗 —— 從本體刪除,或往本體添加,都要求在這裡同時改寫(= 由人確認意圖)。為什麼需要對照:在閘門的變異測試(2026-09-05)中,即使從本體刪除 cv_cc_count,檢查「台賬裡的 op 都擁有關卡」的測試依舊通過。從台賬刪掉的 op 也會從迴圈的對象中消失,所以整條檢查路徑連同它一起消失。所守護的 SIGSEGV 僅限 Linux,在 Windows 上碰巧會返回像樣的值,所以最後一道防線也不起作用。只有與獨立資訊源(這一組)的等價,才能在 Windows 上也捕捉到兩個方向。與 test_the_two_nonfinite_ledgers_agree 同形。
tests/test_demops.py
- L440 — ★返回始終是 (N, 3)。即使傳入純量,得到的也是 (1, 3) 而非 (3,) —— 因為台賬聲明 points = (N, 3)(2026-09-06,fuzzer 的 TYPEMISS 暴露了不一致,於是把實作對齊到聲明)。
tests/test_docs_index_numbers.py
- L37 — ★op 集合隨環境變化(Linux CI 沒有 torch/kornia/mahotas/xfeatures2d,共 859 op;本地是 885)。把本地生成的文件與活的 registry 比對的檢查,只有在滿配環境下才有意義 —— 與 test_opdocs 相同的約定,未齊全就 skip(原因裡會給出缺少的 backend 名)。在 2026-09-07 的 CI 上,有 22 項在這裡落敗。與環境無關的檢查(檔案的存在、內容的量、圖的存在)照常運行。
tests/test_docs_index_reachable.py
- L42 — ★op 集合隨環境變化(Linux CI 沒有 torch/kornia/mahotas/xfeatures2d,共 859 op;本地是 885)。把本地生成的文件與活的 registry 比對的檢查,只有在滿配環境下才有意義 —— 與 test_opdocs 相同的約定,未齊全就 skip(原因裡會給出缺少的 backend 名)。在 2026-09-07 的 CI 上,有 22 項在這裡落敗。與環境無關的檢查(檔案的存在、內容的量、圖的存在)照常運行。
- L80 — ★只看 Markdown 語法是不夠的。
docs/GALLERY.md 在表格中有 14 處使用 <img src="...">,樸素地掃描 ]( 一個也看不到(在 Codex 的對抗性審查中發現,2026-09-06)。也要看原始 HTML。
- L189 — ★允許標記重複,就會讓一個舊表格殘留下來卻依然變綠。生成器只改寫第一個 start–end,所以第二個會永遠保持舊的並持續被發布(Codex 的對抗性審查,2026-09-06)。
- L210 — ★以前用「有 20 行且能看到 4 個維度名」就通過,但那樣即使掉了幾百個 op 也會變綠(Codex 的對抗性審查,2026-09-06)。要與每個維度的實數一個不落地核對。
- L249 — ★輸出差異在哪裡。不輸出的話,就無法追蹤那種只在整套測試裡才落敗的順序依賴問題(如 registry 污染)。
- L312 — ★只有件數和名字,型別契約(in_sort/out_sort)、類別、HALCON 對應、tier 都會保持陳舊卻變綠(Codex 的對抗性審查,2026-09-06)。RAG 會讀 in_sort/out_sort 來挑選型別能連接的 op,所以那裡陳舊就會自信滿滿地提出連不上的鏈。要連內容一起核對。
- L457 — ★檢查產物「是否有內容」—— 只看一致的門,即使兩邊都為空也會變綠 # ————————————————————————— # 2026-09-06 的實測。低於它就落敗(提高是自由的)。
tests/test_dsp.py
- L338 — ★最大值是諧波:period / (1/f_max_bin) 落在整數附近
tests/test_example_scripts_run.py
- L48 — ★2026-09-09,在加入這個門後的第一次 CI 上,7 個在 py3.12 上落敗(py3.11 是綠的)。CI 故意只在 py3.11 安裝 torch / kornia / mahotas / opencv-contrib,其他版本不裝。測試側本已有名為
requires_backend 的宣告機制,但跑範例的門卻沒有它 —— 機制存在,和所有路徑都經過它,是兩回事。gallery2d_* 是「把該族的 op 全部跑一遍」的畫廊,所以它的契約本身依賴於裝了哪些 backend(它直寫 op 名並與 registry 核對,缺一個就以「OPS 裡多餘」落敗)。所以按族宣告。剩下 2 個直接用 torch(fit_zernike / match_logpolar_z)。在滿配環境(CI 的 py3.11,FULLSEYE_REQUIRE_OPTIONAL=1)裡 skip 會變成失敗,所以宣告過多和漏宣告兩個方向都會落敗。
- L87 — ★不傳 PYTHONPATH(這個門的要點)。使用者不會設置環境變數。
tests/test_flyvision.py
- L328 (ja) — ★ The MTF identity is a small-footprint approximation and is NOT claimed
- L329 (ja) — ★ far from the optical axis: at ~35 deg elevation the measured transfer
- L330 (ja) — ★ already departs from exp(-…) by more than the on-axis tolerance. This
- L331 (ja) — ★ assert pins that hole so a future “curvature-corrected” resample has a
- L332 (ja) — ★ failing test to turn green rather than a silent regression to argue about.
tests/test_fslib.py
- L330 (ja) — backend 横断の一致 —— ★2026-09-14 に実際に壊れていたところ ————————————————————————— #
tests/test_fullseye_3dgs.py
- L78 (ja) — ★道具の有無と資産の有無は別。ここは mujoco の有無だけを見ていたので、 Menagerie が無い環境では
scene_registry.resolve() が返す None を掴んで TypeError になった。同ファイルの test_scene_resolution_via_registry は 既に資産の skip を持っており、作法が兄弟に適用されていなかった。
tests/test_gaits.py
- L99 (ja) — ★2026-09-14: ここは
resolve() の戻りを検査せず spec["xml"] を引いていた。 scene_registry が実在しない場面に None を返す設計(資産が無い環境では 正しい振る舞い)なので、資産チェックアウトが無いと TypeError で落ちる。 同じファイル群の test_fullseye_3dgs.py は既にこの skip 作法を持っていた —— 作法が兄弟に適用されていなかった ([[feedback_same_bug_class_recurs_check_siblings]])。
tests/test_glassmirror.py
- L91 — ★與直覺相反:以為「銅比金紅」,寫了 cu[2] < au[2] 結果落敗。就算按公開值,相對於 Au 的 R(450 nm) ≈ 0.40,Cu ≈ 0.56,藍色是銅更多(= 金是更飽和的黃)。錯的是這邊的先入之見,而不是表。
- L175 — ★把波長作為第 1 參數的理由(台賬的「首個是資料」約定)。以前把陣列傳給頂角會拋出裸的 TypeError。
tests/test_honest_summary_arithmetic.py
- L41 — 改成「沒有就說明理由並 skip」—— ★2026-09-08 的 CI 在這裡變紅:把本地有的東西也當成 CI 裡有,就只有本地變綠(與
feedback_gate_computed_a_verdict_then_discarded_it 同型)。
tests/test_mcp_images.py
- L312 (ja) — ★最初
ones + inf にしていて、有限部が定数なので免除 op でも「定数」判定になり 落ちた —— それは診断器が正しい。確かめたいのは「免除 op なら非有限を異常と 言わない」だけなので、有限部に変化のある入力にする。
tests/test_mcp_server.py
- L57 (ja) — ★引数名を
name にしていて _call(4, "fullseye_op_help", name="gaussian") が TypeError になり、subprocess の実 stdio 往復が 1 度も走らないまま 23 件が緑だった(2026-09-15)。走らなかった検査は無いのと同じ。
- L105 (ja) — ★最初
gaussian が先頭と決めつけて落ちた。gauss_filter と gaussian は同じ HALCON 別名を共有する別 op で、api.find_op は name == halcon の正典を優先する。 検索もその規約に揃えたので、正典が先頭・gaussian が上位に居ることを見る。
- L249 (ja) — ★以前の被験者は台帳経由で索引に入ったこと(= 索引が台帳を数えている)も見る
- L316 (ja) — ★同日実測: 4 層で 480 枚が「どこにも無いノート」に見えたが、5 層目(ledger)で 480 / 480 が解決した。ここが 0 でなくなったら、まず引き忘れた層を疑うこと ([[feedback_search_all_tiers_before_declaring_a_gap]])。ノートの残骸と決めつけない。
tests/test_no_local_paths_in_shipped_code.py
- L22 — ★
tomllib 是從 Python 3.11 才有的。在模組頂部做裸 import 會在 3.10 上中斷收集,一個測試也不跑 —— 2026-09-05 用 hypothesis 踩了同樣的坑之後,緊接著在這項檢查裡又復現了(CI py3.10 collection error)。import 失敗一定降為 skip。
- L53 (ja) — ★2026-09-14 追加: MSVC の標準インストール先。
fullseye_3dgs._find_cl_dir() が cl.exe を探すための候補として持っている。これは「私のマシンの作業物を 指している」のではなく「Visual Studio インストーラが決める場所」なので、 環境変数に追い出しても他人の環境で当たりやすくはならない(むしろ探索が 効かなくなる)。glob で実在を確かめてから使い、無ければ None を返す作りに なっていることを確認済み。 ※ _WIN_ABS は空白入りの語を 2 つ目までしか拾わないので、切り出される断片は C:\Program Files\Microsoft までになる。許可文字列は実際に切り出される形に 合わせる —— 正規表現の結果を見ずに「あるべき文字列」を書いて外した(2026-09-14)。
tests/test_op_contract_property.py
- L32 — ★在沒有 hypothesis 的環境裡,這一個檔案的 import 失敗會讓整體停下 —— pytest 會因 collection error 中斷,不再跑剩下的(2026-09-05,CI 在 2 分鐘內死掉,一個測試也沒跑)。降為 skip,別把別的也拖下水。
tests/test_op_contracts.py
- L52 (ja) — ★2026-09-14 実測: 901 op 中 151 本(16.8 %) がこの状態で、空ループを 1 周 しただけで緑を返していた —— 「門が判定を計算した直後に捨てる」の親戚で、 こちらは 判定を一度も計算しない。まず skip で見えるようにし、
test_probeless_ops_do_not_grow で本数を台帳に固定する(減る分には通る)。
- L56 (ja) — ★2026-09-14: 本来の直しを入れて 151 → 0 にした。 上に「本来の直しは
conftest.BANKS を全 in_sort へ広げること」と自分で書いておきながら、 ラチェットで本数を凍結したまま 9 日が過ぎていた —— 台帳は免罪符になりやすい ([[feedback_never_weaken_the_probe_to_get_green]])。 足したのは 11 sort: points(56) / signal(27) / video(16) / qimage(11) / cimage(9) / counts(8) / lightfield(8) / rgbimage(6) / matrix(4) / beatcube(4) / keypoints(2) = 151 op。形は推測ではなく backends_bridge._EMPTY_OF (12 sort すべての正準の最小値)と problems.py の入力生成器から取った。 これで 901 op すべてが 3 つの契約ゲートを実際に通る。 0 になった以上、このラチェットの役目は「増えたら落とす」に変わった。 新しい in_sort を足した人は conftest.BANKS に探針も足すこと —— 足さないと その op たちは「登録されているのに一度も実行されない」状態に戻る。
- L98 (ja) — ★非有限がその op の意味を運んでいるものは、この門の対象外。判断は ここで持たず
ops.NONFINITE_IS_MEANINGFUL を単一の正本として引く (test_backends_typed_liveness.KNOWN_NONFINITE_BY_CONTRACT が同じ表の 写しで、一致は別の検査が見ている。3 つ目の写しを作らない)。 2026-09-14: 探針バンクを 6 sort 広げたとき、ここで tb_mat_cond(特異行列の 条件数 = inf)と tb_geodesic_distances(不達 = inf)が落ちた。一度 探針から特異行列と非連結点群を外して緑にしかけたが、それは誤り —— 台帳は「inf が正しい答え」と既に宣言しており、落ちていたのは門がその 台帳を見ていないことだった。探針を削って緑にするのは欠陥を隠す行為で、 しかも同じ台帳の註に「自分の probe では特異行列を作っていなかったので tb_mat_cond を取りこぼした」という 2026-09-05 の教訓が書いてある。
tests/test_op_discovery.py
-
| L229 — ★它甚至不是原樣通過:回退會截斷到影像契約 [0,1] 後返回。負半部變成 0 的訊號看起來像「濾波後的訊號」,所以這會悄悄地撒謊。max |
差 |
= 1.0,最小值 -1.0 -> 0.0。 |
tests/test_op_example_coverage.py
- L58 — ★從配布物一側計數母集合的 ratchet(2026-09-06)# ————————————————————————— # 2026-09-06 的實測。這是「不讓它比這個數更差」的止動,而非目標值。台賬 1,002 個 op 中,進入範例索引的只有 349 個,上面那兩個「100 %」之所以成立,是因為母集合三層裡只有兩層。經過與按族的分解 = docs/KNOWN_ISSUES.md §38。
- L32 — ★op 集合隨環境變化(Linux CI 沒有 torch/kornia/mahotas/xfeatures2d,共 859 op;本地是 885)。把本地生成的文件與活的 registry 比對的檢查,只有在滿配環境下才有意義 —— 與 test_opdocs 相同的約定,未齊全就 skip(原因裡會給出缺少的 backend 名)。在 2026-09-07 的 CI 上,有 22 項在這裡落敗。與環境無關的檢查(檔案的存在、內容的量、圖的存在)照常運行。
- L203 — ★2026-09-08:把依賴第三方後端版本的 op 從台賬裡剔除、單獨計數。這個台賬寫於「做圖的環境」,驗證於「跑測試的環境」。cv2 的實作隨版本變化,所以本地(opencv 5.0)不起作用的旋鈕在 CI(opencv-contrib 4.x)裡起作用 —— 實測
xcv_grabcut 的 b 就是如此。台賬只能主張在任何環境都成立的東西。依賴版本的部分不主張(擁有狹窄但正確的台賬,勝過擁有撒謊的台賬)。
tests/test_op_probe_ledger.py
- L76 — ★2026-09-08 加入。在那之前這個門只為 image / region / color / volume 這 4 類構造輸入,讓
contour 65 / points 57 / signal 26 / video 16 … 217 個 op(registry 901 個的 24 %)作為 “uncallable” 素通。「門站在正確的位置」和「門把全部都通過」是兩回事 —— 拓寬的第一次就暴露出 tb_angle_3points 在探針下一次也跑不起來(註冊是 points->feature,實體卻取 3 個向量)。
- L192 — ★2026-09-08 的 CI(py3.10 / py3.12,無 torch)在這裡變紅 —— 因為把探針拓寬到全 sort 的第一次,首次到達了需要 torch 的 op(
tb_points_to_voxel)。「壞了」和「這個環境裡沒有」是不同的判定,混在一起就會把環境差異當成實作的 bug。在滿配環境(FULLSEYE_REQUIRE_OPTIONAL=1)裡照舊按失敗處理。
tests/test_opdocs.py
- L212 — ★2026-09-03:由於所有 backend 的 _safe 都匯聚到了 backend_safe.guard,所以按 guard 立起的結構化標記來判定,而不是按 qualname 的字串匹配(guard 也會在 qualname 裡留下 “_safe(…)”,但那是給顯示用的)。
- L1178 — ★沒找到的原因:
ops.REGISTRY(899)與 2-D 筆記(899)一致,所以只要從 registry 一側計數就會看起來「零缺失」。曾經這樣下結論並搞錯了。所以這個門從跨 tier 的索引一側計數(memory: feedback_search_all_tiers_before_declaring_a_gap)。 ————————————————————————— #
tests/test_packaging_foundation.py
- L170 — ★2026-09-07:本地 wheel 上帶著 sample_sources_ai 的 42 MB(共 96 MB)。原因是舊的 build/lib/ 快取(從 package-data 移除前的殘骸被重新打包進去)。這是讀設定的檢查抓不到的事故,所以由 tools/ci_wheel_check.py(unshipped_present)與 ci.yml 的大小上限去看 wheel 實物。目錄也被移到了 package 外(tools/fops_article/)。這裡要求明示排除(作為保險)。
tests/test_pivops.py
- L621 — ★只看名字級別的
PARAM_HINTS,會讓門比 fuzzer 更窄。chain_fuzz._bind_args 還會看按 op 名狙擊的 OP_PARAM_HINTS,所以這裡也要兩邊都看(2026-09-06:把 dic 的 window / method 放進 OP_PARAM_HINTS 後,其實已經能綁定,卻只有這裡落敗)。
tests/test_poc_scripts_run.py
- L57 — ★2026-09-08:放棄固定的 6,改為匹配 CPU 數。在共享 runner(2–4 vCPU)上,6 路平行只會把每一條拖慢,總時間並不縮短,等 PoC 增到 84 個時,每個 job 都撞上了 pytest 的 900 秒 timeout(py3.10 / 3.12)。本地(12 核)照舊以 6 或以上運行。
- L73 — ★
PYTHONPATH 不傳(2026-09-09)。長期以來一直傳 PYTHONPATH=<repo>,但那是使用者不會做的設置,意味著門離事故發生的地方偏了一步 —— 由於同樣的盲點,examples/piv_flow_from_particles.py 等一直停留在「從 checkout 直接運行就 ModuleNotFoundError」(那一側連運行的門都沒有,所以沒被察覺。test_example_scripts_run.py)。PoC 一側 116 個裡有 108 個自己把 repo 根目錄加進 sys.path,剩下 8 個只 import fullseye,所以去掉後全數通過(已實測)。
- L91 — ★失敗時也返回 stdout 的末尾。PoC 會把所見和「哪項檢查落敗」印到 stdout 後再 SystemExit(1),所以只有 stderr 的話,你只能知道空的「exit 1」而別無所知(2026-09-07 的 CI,py3.10 poc_ct_fidelity)。
- L100 — ★2026-09-07:這裡長期返回 0,從而素通了下面的
assert code == 0 —— 一個剛算完合否就丟棄的門(實測:有 3 個 PoC 從不列印 PASS —— poc_dic_strain / poc_photoelasticity / poc_thermography_ndt)。改為返回 -2 讓它落敗。
- L122 — ★這個門把 84 個 PoC 一次性集中運行(session fixture)。這段時間會計到第一個測試上,所以 pyproject 的預設 timeout(900 秒)在共享 runner 上會落敗。只在這裡放寬 —— 放寬預設會連帶鈍化其他測試的掛起檢測。
tests/test_public_reachability.py
- L71 (ja) — ★2026-09-14: この 13 本は 2026-09-05 から wheel に入っていなかったもので、 py-modules へ足した結果ここに現れた。演算子としては
unified._3DGS_OPS が _lazy_call(モジュール名, 関数名) で文字列から登録しているので、利用者には fullseye.op.<名前> 経由で届く。ここに残る 1〜6 本は各モジュールのデモ入口 (render_*_gif など)で、op ではなく絵を作る側。だから内部専用に置く。 —— 「配布から消えていた」を直すと「公開経路から見えない」が現れる、という 二段構えだった([[feedback_registered_only_gates_miss_unregistered]])。
- L88 (ja) — ★2026-09-15: 33 行すべてが公開経路(fullseye.<名前> / .ledger / .op)に届くように なっており、2 番目の検査が「この表から行を消すこと」と 33 件を挙げた。 消した 33: transforms / mosaic / fit_transform / tools_geom / matrix / shapematch / objmodel3d / matching3d / matching / calib / caltab / calibration3d / contours_xld / contours_xld2 / image_channels / filters_freq / filters_flow / regions_setops / regions_gen / region_morph / morph_minkowski / segmentation / image_gen / image_paint / misc_vision / imgops_nary / scattered / inspection / pipeline3d / watershed3d / mesh_decimate / sample_data / scale。 表は空でも残す —— 「出すべきなのに出ていない」ものが次に現れたときの器。名前>
tests/test_raster.py
- L26 — ★裸的 import 在缺失該項的環境裡會中斷整個收集(實測 2026-09-05)。
tests/test_rust_abi_parity.py
- L402 (ja) — ★契約では FS_E_INVALID_ARG(引数が定義域の外)であって FS_E_TYPE ではない。
FsValueError を足すまでは両方 FsTypeError で、Rust が 1 を返すのに Python は 2 相当を投げる、という状態コードの食い違いが残っていた。
tests/test_shapestats.py
- L196 — ★讓平面自由,一側均勻的展開就會被整個吸收掉(實測 4.9e-35)。中點只移動一半,平面也跟著移過去,所以不會作為左右差殘留下來。這是這個定義的極限,而非缺陷 —— 想看的話就從外部給定平面,或加一個在正中線上的地標(midline)。
tests/test_studio.py
- L920 — ★
setDefaultFormat 只對無參建構函式生效,而 Studio 的 QSettings("Fullseye", "Studio") 固定指向 registry —— 這個 fixture 什麼都沒隔離(2026-09-05,registry 裡殘留了 pytest 的路徑)。用環境變數把本體一側的入口 studio._settings() 指向 ini。
- L2029 — ★直接建構
QSettings("Fullseye", "Studio") 會繞過隔離,寫入使用者的登錄檔(2026-09-05 的稽核確認了實際危害)。設定入口保持為一個。
tests/test_studio_logic.py
- L22 — ★舊的 setDefaultFormat 方式對 Studio 的 QSettings(org, app) 不起作用。將本體的入口 studio._settings() 指向 ini(整個 session)。
tests/test_studio_ops_browser.py
- L11 — ★裸 import 在缺少 matplotlib 的環境中會中斷整個收集(pytest 因一次 import 失敗就不再執行其餘全部)。2026-09-05 實測。
tests/test_videostream.py
-
| L319 — ★Collins (VSAM 2000):兩者都以當前影格為基準。到 2026-09-05 為止,這個測試期望連續對 |
f[t-1]-f[t-2] |
,把實作的錯誤當作規範固定了下來(對等速運動的均勻物體始終全為零 – 見下面的迴歸測試)。 |
- L43 — ★目錄、提示和轉接器以出貨模組
typed_catalog 為正本(2026-09-05)。以前它們住在這裡,backends_typed 把 tools/ 加進 sys.path 來讀取 – 結果在 wheel 中 tb_* 143 op 悄然消失。把方向反了過來。
- L256 — 事件位置(點過程)– point_spectrum 的入口。★不要只用均勻隨機:沒有週期成分就一次也不會觸及「尋找週期的 op」的有意義行為,所以用把 12 個無關事件混入週期 17.0 序列的結構化資料作種子(隨機-only 的測試會隱藏結構缺陷,是本 repo 的規律)。
- L864 — ★混有非有限值的點雲會讓 KD 樹的建構本身以生的 ValueError 崩潰(scipy:”data must be finite”)。池的設計是記錄 NONFINITE 後仍保留值,所以髒點雲來到這裡是預期之內 – 由建構方防範。2026-09-06 實際踩到:新的族增加後連鎖的走法變了,在 seed 3_000_0xx 命中這條路徑,fuzzer 自身停止了(不是 op 的缺陷而是工具的缺陷。無法綁定的輸入約定為跳過而非拋出例外)。
- L1557 — ★到 2026-09-02 為止一直是
lambda v: True = 因為述詞被計為「有」,反而比沒有更糟(點檢腳本也會把它計為「有述詞」)。實測下它連 None / 42 / 字串 / dict 都放行。正典是透過全部執行消費側 6 個 op(reprconv 的 pairs_to_signal / pairs_to_image2d / pairs_to_table / angles_to_normals / shape_index_to_curvature / polar_to_cscalar)來確定的:6 個 op 都只接受上面兩種形狀,其餘的都以 “pairs: must be (N, 2) or a 2-tuple of equal-length 1-D arrays” 變成指名的 fail-closed(實測)。因為不接受 (2,N),把 2-tuple 用 np.stack 壓成 (2,N) 的 3 個 adapter 改成了 axis=1。長度不同的兩條(histogram 的 counts/edges)也不是「對」,予以拒絕。
- L1667 — ★「恰好 2 個元素」與 pose(用
len >= 2 允許 info)是刻意不同的。實測 2026-09-02:把 mesh 作為單個引數接收的 4 個既有 consumer(face_normals / vertex_normals / mesh_area / vertex_curvature)對 3-tuple 會送出 “mesh must be a 2-element tuple (vertices, faces)”,cadmap 的 _mesh 和 render3d._mesh_arrays 也只接受 2 個元素。也就是說 本 repo 的 mesh sort 正典是 2-tuple,多餘的元素不是「資訊更多」,而是讓下游全滅的型別層面的謊言。唯一的例外 voxel_to_mesh(回傳 (v, f, n))現在在 ops3d.RESULT_ADAPTERS 中取出正典的排列(與 gicp / vol_label 同樣處理)。
- L25 — ★把這個腳本自身的所在位置從 sys.path 中移除。 Python 會把腳本的目錄放到 sys.path[0],所以從 checkout 的
tools/ 啟動時,即使在 wheel 側的 venv 中也能 import 到 tools/ 下(未隨附的 chain_fuzz 等),於是就在「能看到 wheel 裡沒有的東西」的狀態下計數。2026-09-05 的複查中,這個門漏掉了 tb_* 143 op 的缺失正是因為這個。同時也把 cwd 移到空的暫存目錄(cwd 是 checkout 的話會發生同樣的事)。
- L34 — ★在移動 cwd 之前記住原來的 cwd,此後把所有引數路徑都相對它來解析。2026-09-05 實測:preflight 傳的是絕對路徑所以本地能通過,ci.yml 傳的是相對路徑,於是 dump 被寫棄到暫存 dir,compare 以 FileNotFoundError 崩潰 – 門在正式的呼叫路徑上一次也沒有執行比較。這是「門要立在事故發生的地方」的第 3 次。不是去修呼叫方,而是讓它即使用相對路徑呼叫也能正確運作,把這一整類關掉。
- L139 — ★2026-09-08:也看 editable 側。在此之前
a["failed_backends"] 只是收集,誰也沒讀 – 在同一輪裡作為與 examplefig 的圖失敗同型別的漏洞被揪出。editable 的 venv 有很多 optional 依賴,所以 backend 可能因版本不一致而 import 失敗。這時 wheel 側只是「因為依賴不存在,一開始就不在」,不記錄失敗,這個比較仍然綠著通過。掉落的 backend 的 op 就從登錄檔裡悄然消失。
- L92 — ★這裡會犯兩次錯。fuzzer 的
run_chain(1)把輸入型 any 當作「總是齊備」(從池中任意抽取),(2)在 OP_ARG_BUILDERS 中註冊的 op 自行組建引數。不把這兩點算進去,就會把實際上每次都在執行的 op 報告為「結構上不可達」(實際上對 fuse_to_voxel / register_cross 誤報了)。可達性不是由「只看型」決定的 – 一部分可達路徑在程式碼這一側。
- L89 (ja) — ★2026-09-14 追加。45,000 ケースを 3 秒で「食い違いなし」と言われたとき、 信じるのではなく自分が printf で挙げた「踏んでいない座標」を足す。 一致したときこそ探針を疑う([[feedback_one_probe_input_is_not_coverage]])。
- L185 (ja) — ★2026-09-14: ここは長らく値域だけを振って画素は 0..1 のままだった。相対しきい値は 値域を通して解決されるので、値域 (100,300) では絶対値 100〜300 と比べられ、 100% が空になっていた(実測: (100,300) は 780/780 が 0 画素、全体でも 63% が 物体 0 個)。4000 ケースが 0.6 秒で「食い違いなし」だったのは頑健だからではなく、 connection も measure_all もほとんど踏んでいなかったから ([[feedback_zero_findings_may_mean_never_executed]])。値域を名乗らせるなら 画素もその値域で描く。
- L198 (ja) — ★しきい値は画像に実在する値から引く。独立に引いていたときは 41% が 「選択 0 画素」で、物体が 2 個以上あるのは 14% だけだった ——
connection の 分岐(斜め接触・入れ子・多数)をほとんど踏んでいない。乱数で撒くと空ばかりに なるのは、しきい値も探針の一部だから ([[feedback_one_probe_input_is_not_coverage]]: 探針は入力画像だけではない)。 2 割は「当てずっぽう」のまま残す —— 空・全面・範囲外という端も要る。
- L236 (ja) — ★R-3 の相対→絶対の写像と画像の形。契約の関数なのに観測していなかった。
- L265 (ja) — ★
fs_region_runs は契約が「領域表現の唯一の窓」と呼ぶもの。それを 観測していなかった —— 面積と本数が合っていても、run の切り方が違えば run-length と dense mask は別物として振る舞う(隣接 run を結合するか、 行内の並びは昇順か)。観測していない性質はケース数では出ない。
- L295 (ja) — ★並びそのものを観測する。
sorted して比べていたので、物体の順序を逆にする 変異が 3,000 ケースで 1 件も殺せなかった(2026-09-14 の変異解析)。契約は 「最初の run の (row, col) 昇順」と明記しているのに、門がどこにも無かった —— 観測していないものは、どれだけケースを撒いても出てこない。
- L337 (ja) — ★R-3 の相対→絶対の写像そのものを観測する(契約
fs_image_absolute)。
- L351 (ja) — ★種別を捨てない。ここは長らく固定値 1 だったので、
_status_of を 書いて compare にコード比較まで足したのに、Python 側が常に 1 を 名乗るせいで状態コードの食い違いが構造的に出なかった(変異 m8 が 3,000 ケースで殺せなかった正体)。観測を足したつもりで足しきれて いない、という [[feedback_gate_computed_a_verdict_then_discarded_it]] の型。
- L381 (ja) — ★コードの値まで見る。「どちらも拒否した」で止めていたので、 契約が FS_E_INVALID_ARG(1)と決めている所で Python が FS_E_TYPE(2) 相当を投げていても素通りしていた(2026-09-14 に実際そうだった)。
- L390 (ja) — ★許容差は値域に対する相対で取る。絶対値で 1e-5 と決めていたら、 値域 (100,300) の画像で 1.04e-05 の差が「食い違い」として報告された —— が、切り分けると Rust vs scipy は float64 のままなら 8.53e-14、 float32 を経由した途端 1.04e-05。つまり
fslib の astype(np.float32) の丸めで、欠陥ではなく私の測り方の欠陥だった(値域比で見ると どの値域でも一様に 1.4〜5.2e-08 = float32 の相対精度)。 [[feedback_second_instance_artifact_not_physics]] と同じ型 —— 驚く結果は物理(実装の違い)で説明する前に道具を疑う。
tools/gen_blas_article_figs.py
- L93 — ★用半透明鋪出 1 執行緒最快的區間。為不遮住線條先放置它,並把 alpha 保持得低(帶子本身主張太強的話,線條的比較會變得難讀)。
- L37 — 分類的英文名。★即使在英文版中也只有標題還是日文(實測 7 行)– 內文用
title_en / _summary_en 翻譯過了,卻忘了翻譯標題,成了「切換了卻混著日文」的典型。此處沒有的分類照原文輸出(不擅自造譯)。
- L45 — ★對照表放在與運算子文件不同的檔案裡。若用
opdocs.T,取用的原文會進入 opdocs.SEEN_STRINGS,現有的「框架譯文有缺口」門就會把這 604 條全部算作缺口而使 CI 變紅——那道門是為了讓框架文案在五種語言上齊全,而這裡是「譯到哪算哪」的性質。混在同一張表裡,會讓一邊的規矩毀掉另一邊。
- L79 — ★一塊 = 從含有 ★ 的行開始、以相同縮排接續的
# 註解行的連續。也拾取 Sphinx 風的 #: 註解。只剝掉 # 和空白,開頭會留下一個 :
- L81 — 殘下來,產物裡就會出現「: ★…」(實際出現過)。
: 也在這裡剝掉。
- L105 — ★下一個 ★ 到來時切成另一塊(保持一塊一個主張)。
- L197 — ★不翻譯標記,固定為
_(ja)_。按語言翻譯它會讓機器無法計數 – tools/i18n_status.py 是數「沒有標記的日文」的工具,所以標記若隨語言變化,593 行就會變成「隱藏的日文」(實際變了)。ja 是語言代碼,也向讀者傳達「這是日文」。
- L280 — ★筆記的集合從台帳取(不去列舉檔案)。2026-09-06 的對抗式複查(Codex)中,glob 檔案並數 stem 的版本混入了一個
docs/ops/SAMPLES.md(不是 op 筆記),於是索引是 1,842、RAG 指南是 1,843,同時公開了互相矛盾的數字。筆記從 records 以 1:1 生成,所以 records 裡的名字就是「有筆記的名字」的定義本身。與檔案的一致由 tests/test_docs_index_reachable.py 另行檢查(偵測消失/多餘)。
- L290 — ★用
__all__ 而非 dir(fullseye)。dir 包含模組屬性(os / sys / warnings / annotations),而且在別的測試 import 之後會增加一個(1094 → 1095),所以漂移門只在整套件裡失敗(2026-09-06)。公開面是門面在 __all__ 中宣告的 1,091 個名字。
- L339 — ★索引不只是給人的,也是 AI 的檢索面(2026-09-06 使用者的指出「索引也是被當作 RAG 使用的部分吧?」)。op 筆記兼作 AI 編碼輔助的檢索語料,所以在索引裡明示機器讀取的入口。把只有一半的東西寫成「全部 op」,RAG 就會對剩下的一半自信滿滿地弄錯 – 所以
_honest() 的實測行不從本節移除。
- L490 (ja) — ★2026-09-14: 長らく かな だけを見ていたので、「Studio 北極星」「実測記録」 のように 漢字だけで書かれた題に印が付かなかった —— 非日本語版の読者は それを英語の題だと思ってクリックする(印を付けないのは「読めない」という 事実を隠すことで、無訳より悪い、というのがこの関数の趣旨そのもの)。 題は常に日本語版ファイルから取る(
_doc_title(rel))ので、漢字を足しても 中国語の題を誤って日本語と呼ぶことは起きない。
- L655 (ja) — ★Qiita 投稿用の frontmatter(— で挟んだ YAML)は題ではない。中の
title: 行は 下の走査では見出しにも読み飛ばし対象にも当たらず、そのまま索引の見出しになって しまう(「title: ‘…’」と並ぶ)。挟まれた範囲ごと読み飛ばす。
- L94 — ★status=fixed 卻沒有門的不放行 – 是為了讓這個台帳自身不製造出「只留下修好了的記錄、卻止不住復發」的狀態。
- L194 — ★連結目標(
docs/hardening/*.md)是用日文寫的。替換成英文標題就成了謊言,所以標題照原樣輸出並附上 (ja) – 非日文版讀者需要的不是「翻譯過的標題」,而是「這是讀不了的」這個事實。標記固定為 tools/i18n_status.py 能數的形式。
- L41 — ★這裡不是「只是個常數」:線積分 p = Σ μ·Δx 超過 10 時,exp(-p) 就低於光子數 1,對數飽和而 p 觸頂(photon starvation)。最初的版本把 μ 放成 0.55–1.0「/像素」,於是 p 達到 30,復原 μ 偏低 50–84%。零點(簡單反投影)反而在 Dice 上勝出,才因此察覺。
- L166 — ★每種材質的數字是 召回率(recall)。是「在該材質標籤內拾取到的比例」,而不是 Dice(因為不數落在標籤外的偽陽性,若稱作 Dice 必然趨近 1.0)。整體的漏取/多取由下面的 precision / recall 另行給出。
- L65 — ★纏繞順序朝外。反過來法線就朝內,render_beauty 會不拋例外地回傳全黑(最初的版本就是這樣,只有薄膜的球是黑的)。
- L153 — ★這是下界。因為它只看 op 名是否在
tests/ 中以 literal 出現,所以掃台帳跑遍全部 op 的掃掠型測試(for name in ledger: ...)不計入。要讀作「沒有指名的測試」而非「沒有測試」。
- L105 — ★2026-09-08:在這張表裡的
tb_angle_3points 和 tb_indices_to_labels,不是「在圖的定義域之外」,而是 不該放到橋上的 op。前者取 3 條向量,所以單條點雲無法呼叫;後者回傳 1-D,卻把宣告的 out 定為 labels(→ volume = ndim 3)。兩者都保持註冊著卻一次也沒執行過,fail-soft 回傳著貌似合理的值。移到 backends_typed._OP_BRIDGE_SKIP,並從這張表裡移除 – 有「出不了圖」的記錄,卻在任何地方都沒有「無法執行」本身的記錄(有兩道門,只有一道察覺到了)。
- L115 (ja) — ★2026-09-13: op が evolute 検証を得て厳格化。ECEF は地球表面(中心から ~6.4M m)の 座標を要るが、画像由来の合成点は原点付近で必ず楕円体の evolute 内に落ちるため 正しく拒否される(実データでは動く。合成入力では図を作れない恒久的な定義域ミスマッチ)。
- L127 — ★2026-09-07(使用者指示「不必彙總成一張。分階段的、有多個條件的分開出」「有些東西用偽彩色更好懂」「複雜的甚至可以用動畫 GIF」)。在主圖
<op>.png 之外,再加:<op>.a.jpg / <op>.b.jpg — 把旋鈕撥到 0.1 / 0.5 / 0.9 的 3 張(僅當輸出變化時。不變化就在 manifest 寫理由)<op>.chain.jpg — 有前置 op 的 op 的階段圖(影像 → 中間 → 輸出)<op>.gif — 當輸出是影片 / 光場 / 體積時,依次展示影格 / 視點 / 切片(靜圖 <op>.png 為完成形,GIF 是追加。Studio 的 QTextBrowser 顯示第 1 格)。偽彩色只施加於量的場(距離·相位·朝向·深度·曲率 …)的輸出,並在標題寫 (viridis)。濾波類保持灰色(不呈現為會變色的 op)。
- L730 — ★「跑了」和「出了有意義的輸出」是兩回事(2026-09-07,使用者指出「out 全黑是怎麼回事?」)。把空陣列算作「有圖」,黑板就成了圖。空就記為空,並在筆記裡寫理由。
- L592 — ★2026-09-02:highpass / bandpass_image 現在遵循「把 0 映射到 0.5 的 [0,1]」的約定回傳。以前它們把帶符號陣列稱作 image 回傳,在儲存·段間 clip 時負的那一半(約 50% 的像素)被無聲地壓成 0。把修好這件事用實測而非推測記錄下來:最小值和負像素的比例。
- L727 — ★2026-09-02:estimate_noise 現在以 σ 的單位回傳(以前在 σ>=0.08 時貼到 1.0,對相差 3 倍的 σ 回傳相同的值)。擺出直線 y=x,好用眼睛確認「回傳值是否就是 σ 本身」。
- L840 — ★_panel_grid 的標籤不換行,一旦超出寬度就會和相鄰的相撞而讀不了(tile 262px / font 19-17px,所以一行 ≈ 12 個全形字元為上限)。把倍率的含義放到標題和副標題裡,面板上只放簡短的名字和數字。
- L1184 — ★2026-09-02:
area_center 現在如其名回傳 (面積比, 行, 列) 3 個分量(此前只有面積比 1 個純量,不回傳中心)。3 個分量都做了 [0,1] 正規化以不依賴解析度,所以要還原到像素:行 ×(H-1) / 列 ×(W-1)。這裡把還原後的中心打到圖上,做成能一眼看出回傳值確實是中心的形式。
- L1712 — ★逐點呼叫 apply_cmap 的話,會在那一個點之內正規化,於是全都變成同一種顏色。只做一次張開 0..1 的 LUT,從中查取。
- L1950 — ★2026-09-02:gabor 現在採用除以核的 L1 範數的固定尺度,回傳可跨 op 比較的絕對值。此前它除以「該影像中的最大絕對值」,於是每個朝向都除以不同的除數,把響應的大小本身 = 朝向的判別力壓垮了。作為代價,回傳值落在 [0,1] 低端的狹窄區間(這 3 種花樣裡平均 0.007–0.030),所以直接貼上去 3 張都是全黑。圖用 1–99%tile 拉伸來顯示,標籤的數字給出拉伸前的實測值(與 freq_sweep 的 highpass 面板相同的約定)。
- L2065 — ★2026-09-02:3 個 op 變成了各自獨立的實作。以前 3 個都搭在 geom “zoom” 上,相互的最大差為 0.0 / 4.9e-14(= 相同),而且 3 個的 b 都是死的。現在 zoom_image_factor = 縱橫 2 個倍率 / zoom_image_size = 目標尺寸 / rescale_img = 等方倍率 + 內插階數。畫布 shape 都保持為輸入原樣。
- L411 — ★雜訊用 :func:
astrostack.noise_sigma(背景的穩健 σ)來測。用「與真值的殘差 RMS」的話,連 PSF 的偏移都會進到殘差裡 – 這個實驗特意逐影格改變 FWHM,所以選法一變,合成後的 PSF 就變了,殘差增大到底是因為雜訊還是因為像變了就分不清了(實測該值從 25.2 -> 61.3,但其中大部分並不是雜訊)。背景 σ 不依賴於星的形狀。
- L471 — ★「最大差」在單影格下不動 – 因為只要召回率不足 1,漏掉的 1 個像素就會原樣壓住最大值。用有多少像素仍大幅偏離正解和偏離的總量,去除的效果就會如實顯現。
- L713 — ★ 依原始尺寸排列時,”偵測到 2 個” 無法用肉眼確認(在 44x44 之內,相距 1.6 像素的一對只會成為幾個像素大的一團)。為了不做出只讓讀者相信偵測器說法的圖,圍繞每對裁出相同的物理範圍並放大。
- L844 — ★ 誤差圖塗的是大小而非符號。最初的版本用發散配色,但本實驗的誤差始終為正,於是變成”正 = right 的藍色”,得到相反的含義——損壞的狀態被塗上了”正確”的顏色。這裡想向讀者傳達的不是方向而是”錯了多少”,所以只用 wrong 的單一顏色改變濃淡(為了不讓含義只由顏色承載,同時並列標注符號和數值)。
- L573 — 5. ★跨越各種表示走一圈(變換的連鎖正是謊言出現之處) # ————————————————————————— #
- L599 — ★ “是殼而非實體” 不可用最大值投影來斷言 —— MIP 取的是深度方向的最大值,所以即便是薄殼內部也看起來是填滿的(實際上曾經那樣畫過,差點給出”體積 5768 -> 殼 5608”這種幾乎無差別的數字)。內部是否殘留,用中心斷面和內部填充率來說明。
- L896 — ★ 條紋所張成的像面的實際尺寸。設為 1.0 mm 時,208 取樣/mm = Nyquist 104 cyc/mm,於是 200 cyc/mm 的條紋變成了 8 cyc/mm 的粗條紋(圖自己在混疊)。若為 0.25 mm 則是 832 取樣/mm,即便是最高頻率 200 cyc/mm,一個週期也有 4.16 像素,足夠了。
- L1151 — ★ 把兩個量疊在一張圖上,取決於尺度的取法,兩條曲線可能偶然完全重合(最初的版本正是如此,看起來與”兩個獨立軸”的主張完全相反)。調尺度把它們拉開是矇混,所以把面板縱向分開——圖的結構本身就說”這是不同的軸”。
- L1299 — ★ 峰值取自整行。以前寫成
line[c - s : c + s + 1],當 s 超過 c 時,起點變成負索引,於是 Python 只切出末尾 56 像素,把 0.6167 當作”峰值”返回(實際最大值是 0.9834)。正規化崩壞,曲線在 1.0 處封頂,dip/peak 也在 1.9x Rayleigh 處錯誤地給出 0.0067。
- L1581 — ★ “模糊在 1 像素以內”的範圍不從格點上採。掃掠步長為 3.9 mm,而景深只有 0.74 mm,所以格點上一點都落不進(最初的版本就因 min() 變空而崩潰)。用二分法直接求邊界本身。
- L1600 — ★ 誇張倍率是 縱向 像素/mm ÷ 橫向 像素/mm。最初的版本寫成了倒數,在拉伸了 8 倍的圖上顯示”0.13 倍”(向讀者傳達了完全相反的資訊)。
- L2090 — ★ 分成上下兩欄。疊在一張圖上時,單位不同的兩條線(像素數與偵測率)會被讀成落在同一縱軸上(實際上看起來正是如此)。
- L42 — ★ 在缺少這一步的期間,:func:
_called 對 (op 名 × example) 的所有組合呼叫 :func:_strip_prose,每次都用 ast.parse + tokenize 重新解析整個原始碼。實測 2026-09-05:2-D 881 op × 73 本 + 3-D 347 op × 118 本 + ledger 494 op × 73 本 = 約 14 萬次完整解析,一次 opdocs.py md 要花 10 分鐘(toc 和 html 也重建同一索引,所以完整再生成是 30 分鐘級)。散文剝離每個原始碼一次就夠了 —— 因為它不依賴 op 名。
- L105 — ★2026-09-08: ops1d(dsp 16 + funct1d 23)雖已註冊,卻 在 docs/ops 下沒有一張筆記 —— 它出現在 OP_CATALOG 中,但因為沒有每個 op 的筆記(型別契約、陷阱、相關 op),從 RAG 語料庫中整個缺失。是在
poc_web_roll_periodicity 給 dsp 添了 2 個時發現的。
- L790 — ★n 元(多輸入)層。到 2026-09-09 為止有 17 個運算子連一份說明都沒有(
add_image、sub_image、bit_and、reduce_domain、union2…)。它們以 tier=nary 出現在 OP_INDEX.json,但 docs/ops/ 下沒有說明,因此永遠無法從 RAG 語料中檢索到。漏掉的原因很清楚:這裡只走訪 ops.REGISTRY,而 ops.REGISTRY(899)與 2-D 說明數(899)相等,從註冊表一側數就顯得毫無缺漏。只有跨層去數才會暴露。
- L832 — ★2026-09-07:
OPS3D[...]["doc"] 是註冊時只切出 docstring 的第 1 行的產物(ops3d._build)。在筆記的”用法”裡用它,無論實作寫了幾段都會變成一行 —— “用法只有一行的 op 494 本”中的 3-D 部分正是這個截斷造成的(docstring 本身很長的 op 很多)。和臺帳 dim 一樣,把函式的 docstring 整個讀進來。
- L855 — ★ 橋接 op(
tb_<name>)與臺帳的 <name> 實作相同,範例以臺帳名書寫。到 2026-09-06 為止有 147 本是”零範例”,但那只是沒有數到以別名存在、呼叫同一實作的範例而已。繼承臺帳一側的範例,並在筆記中明確寫上”原 op 的範例”(以免說謊)。
- L1075 — ★n 元運算子無法透過
fullseye.apply 呼叫——那是單張影像的模型。在這裡寫單圖的呼叫方式會讓說明說謊:說明唯一的職責就是告訴別人怎麼呼叫,所以錯誤的呼叫方式比沒有更糟。公開入口是 fullseye.FullseyeGraph。
- L1094 — ★2026-09-07: 先寫公開路徑。這裡只寫了實作模組的直接 import,沒有出現使用者實際使用的
fullseye.ledger.<名>(除 2-D 以外的全部 1,244 op)。PoC 反覆報告”fs.<名> 裡沒有",問題不在於名字缺失,而在於**入口沒有寫**。名>
- L1455 — ★ 入口用 6 種語言呈現(2026-09-09)。葉子(Studio 的 op 說明)有 6 種語言 10,191 頁,然而通往那裡的索引卻只有日語 —— 譯文存在卻到不了,這種形式的缺失。框架的文案放在
T() 上,所以對照翻譯的空洞由既有的門(test_chrome_translation_table_has_no_holes)來看守。
- L1500 — ★ 這裡長期只指向
2d/guides/,從未把讀者引向光學、PIV、斷層成像等 30 個族的指南(2026-09-09 修正)。
- L119 — ★ 如果
build/lib 裡殘留著上次的 staging 副本,setuptools 會原樣把它塞進 wheel(2026-09-05 實測:從 py-modules 中移除的模組仍留在 wheel 裡,門的變異測試竟然通過了)。這與 release.yml 從 clean checkout 建置的理由相同。這裡也一樣,建置前務必清除。
- L313 — ★ 不帶
--full 呼叫 --only suite 會得到 0 個項目,以前會說”全部 PASS”並以 rc=0 返回(2026-09-05 評審中實測)。什麼都沒檢查卻放行的門,比沒有門更糟。
- L54 — ★唯一位於
tools/ 之外的生成物。正因如此才被漏掉——只要按 tools/*.py 去找產生器,就永遠找不到它。
- L77 — * ★而且危險:剛生成的文章用相對路徑寫圖像。公開版是改成
raw.githubusercontent.com 絕對 URL 後的(Qiita 用相對路徑不顯示圖像 —— memory feedback_qiita_svg_path_and_cache)。只跑生成器,那些絕對 URL 會回退 42 行。要跑就一直跑到文章的公開步驟為止。 排除項要按檔名寫。用散文歸納(”wing*_gallery 的 10 本”)機器無法比對,下面的 unclassified() 就不工作了。
- L167 — ★位於
tools/ 之外的生成物。只走訪 tools/*.py 永遠發現不了它,實際上 docs/OP_INDEX.json 就一直被漏掉。
typed_catalog.py
- L217 — ★ 預設值本身很重的情況另作處理 —— 在 docstring 裡寫了費用表,並在 docs/KNOWN_ISSUES.md 中作為”未解決”保留。這裡減輕是為了通過檢查,而不是為了掩蓋慢。fourier_smooth(points, keep) 的 keep 是沒有預設值的必需參數。若無法綁定,就會以”參數組不起來”被永久跳過,在覆蓋率表中只作為未到達出現(2026-09-06 首次計測時 13 op 中只有這 1 本掉了)。表面粗糙度。約束為 2dx <= lambda_lo < lambda_hi <= ndx / 0<hurst<1 / sq>0 / n>=8。次像素計測。測量線的生成 op 不取輸入,所以全部參數都需要提示。
- L271 — ★ 不加這一步,surface_params 每次都會 fail-closed 被拒絕,單看覆蓋率這一個數字像是”能呼叫”,實際卻從未執行。
- L459 — ★ 法線不要平行於軸。若與軸平行,距離場只沿一個軸變化,圖的生成器做的”堆疊切片的 GIF”會塌成一幀(2026-09-08 實測)。傾斜的法線則所有切片都會變化。長度不起作用(op 會正規化),所以傳入未正規化的向量,把這個規格也展示出來。
visionlab.py
- L53 — ★
float("50") 會成功,所以僅僅讓它通過 float(),字串就會作為毫米矇混過關。visiondesign 一側會攔截,但若在這裡先轉成 float,在到達那個校驗之前就已經變成數值了(敵對性驗證實測:VisionSystem(focal_mm=”50”) 通過了)。容器一側也要持同樣的規律。
visualhull.py
- L123 — ★ 一個不剩地所有點都在相機後方 = 幾乎肯定是姿態的規約不符(2026-09-08,poc_livestock_body_volume 踩到)。這個函式要求 OpenCV 規約(+Z 朝前),但公開層中帶
look_at 名字的是 render3d 的 gluLookAt 版(−Z 朝前的 4x4)。傳入它的 M[:3,:3], M[:3,3] 會讓全部 voxel 被判為後方,無一例外地返回空的輪廓,得到空的 hull。默默返回空,就和”雕刻完畢”分不清了,所以唯獨這裡要出聲(也有有效的場景 —— 物體在視角後方 —— 所以不 raise 而只停在警告)。
world_render.py
- L69 (ja) — ★
resolve() は実在しない場面に None を返す(資産が無い環境では正しい)。 検査せずに spec["xml"] を引くと TypeError: 'NoneType' object is not subscriptable という、原因を何も語らない例外になる —— 呼び手には 「何が無いのか」と「どう直すのか」を返す。
© 2026 Kazufumi Furuse — Fullseye operator documentation. Licensed under Apache-2.0.