sensor source code 内の 数値リテラルを 出所別に分類 する静的 lens。
harvest_lag v0.1 → v0.9 の empirical evidence ({50} が sensor 内 3 箇所 → 0 箇所) から抽出。
「保証は外部からしか来ない」 arc の 時間軸に効く部品 — 未来の author (人間 or LLM) が 恣意的な magic number を silently 増やすと 検出される。
| Class | 検出 heuristic | 意味 |
|---|---|---|
| fallback-named | const UPPER_SNAKE = <num> の右辺 | 命名された policy 定数 (集約済) |
| fallback-nullish | x ?? <num> の右辺 | inline default (名前無しだが 出所明示) |
| format | .toFixed(N) / .slice(A, B) / .padStart(N) / parseInt(x, N) / template ${...} | 表示・切出し用 (business logic ではない) |
| format-ratio | / 3_600_000 等の 物理単位 divisor | 物理定数 (ms→h 等、 load-bearing だが arbitrariness ではない) |
| guard-small | -1 / 0 / 1 / 2 の guard・index・increment | 制御 boundary (arbitrariness ではない) |
| allowed | 行末 // arbitrariness-audit: allow <rationale> | opt-out escape hatch (理由文 必須) |
| declared | それ以外の inline literal | LEAK candidate — sensor 内で 名前無く 使われる arbitrary な数 |
PASS ⇔ declared == 0
(全 inline literal が fallback / format / guard / allowed のいずれかに分類)
FAIL ⇔ declared > 0
(arbitrariness leak を location 別に列挙)
scripts/checker/arbitrariness-audit.ts — 分類 engine + CLI (regex 単純 heuristic、 AST 不使用) test/step1632-arbitrariness-audit-test.ts — 28/28 PASS (11 section) package.json: "test:step1632": "tsx test/step1632-arbitrariness-audit-test.ts" "checker:arbitrariness-audit": "tsx scripts/checker/arbitrariness-audit.ts"
$ npm run checker:arbitrariness-audit -- scripts/comparator/gauges/harvest_lag_v02.ts
arbitrariness_audit v0.1-spike
scanned 1 file(s), 27 literal(s)
fallback-named : 4
fallback-nullish : 1
format : 5
guard-small : 17
format-ratio : 0
allowed : 0
declared (LEAK) : 0
verdict: PASS
JSON 出力は --json。 CLI exit code = 0 (PASS) / 1 (FAIL) / 2 (usage error) — CI に組み込み可能。
| File | named | nullish | format | guard | ratio | declared | Verdict |
|---|---|---|---|---|---|---|---|
harvest_lag.ts (v0.1、 時刻 delta) |
3 | 0 | 0 | 4 | 1 | 0 | PASS |
harvest_lag_v02.ts (v0.9-oracle-tri-state 現行、 集約 完了状態) |
4 | 1 | 5 | 17 | 0 | 0 | PASS |
v0.9 の 4 named fallback = DEFAULT_DECLARED_RETENTION=50 + DEFAULT_FRESH_RATIO=0 + DEFAULT_AGING_RATIO=0.10 + DEFAULT_LAGGING_RATIO=0.50。
1 nullish = opts.maxLagDays ?? 3 (chat-Claude Q2 で 要件由来と 確定した 数)。
declared = 0 = 「置いた数が sensor から 消えた」 状態が 静的 lens で 実測 verify された。
test Section 7 = 意図的な leak function tooManyLiterals(x) { return x * 42 + 7; } は
{declared: 2, verdict: FAIL} として 正しく 検出 (値 42 と 7 が leak として location 別に列挙)。
将来 誰かが sensor に inline literal を silently 追加した場合、 test:step1632 が fail する 抽象 — refactor guard の 基盤。
${...} interpolation は real code として拾う)。auditPath(dir) で 再帰 scan 可能だが、 exempt list は 現状 test/ のみ hard-coded。本 tool は LLM が call 単位で 自己保証 できない 4 部品の 拡張 「時間軸に効く部品」 (item 5(a)) の 実装。 LLM は 単 call で 「置いた数」 を 分類できても、 次の call で それが 保たれる 保証は 出せない。 静的 lens として repo に 常駐する 部品だけが 時間を 跨いで 「declared == 0」 を invariant として 保持できる。
接続面: 前 turn で 藤本さん + 私が 議論した 「型付けが 本丸」 の 前段 = 「型を 書く前に 『置いた数』 を 集約させる」 部品。
harvest_lag arc は これが operational に 機能する 実測例 (chat-Claude 9-11 往復で {50} の 三箇所住処が 順次 撤廃された)。
本 tool は 「今の 状態」 を 判定。 STEP 1624 で 書かれた 「actualRetention 5 値変動 + windowCompared=derived 不変 assert」 pattern を 一般化する tool が 第 2 段。
未来の author が 病理 shape (v0.2 の Math.min(oracleReturned, actualRetention)) に silently 戻すと test が 落ちる — 抽象 refactor guard 生成器。
arbitrariness_audit と 相補: 前者が spatial (今の 状態)、 後者が temporal (過去の 病理 の 再入 阻止)。
scripts/checker/arbitrariness-audit.ts (single file, ~240 lines)test/step1632-arbitrariness-audit-test.ts (28/28 PASS, 11 section)scripts/comparator/gauges/harvest_lag_v02.ts (v1.0 状態、 declared=0)