発端
年明け、締め処理の通知が元日に飛んだ。調べると、営業日判定に使っていた祝日テーブルに 2027 年分が入っていなかった。去年それを入れた人は、もう隣の部署にいる。
このバグの嫌なところは、コードが一行も間違っていないことだ。祝日を配列で持ち、 if (!holidays.includes(date)) で弾く。ロジックは正しい。ただ、データに賞味期限があることを、システムのどこにも書く場所がなかった。
cron には祝日という概念がそもそも無い(第 1 弾に書いた)。自前実装には概念はあるが、「このテーブルはいつまで有効か」を表現する型が無い。だからテーブルは黙って腐り、腐ったことは事故で分かる。
「どこまで知っているか」を宣言させる
Kairos では、データを持ち込むテーブルに covering(有効範囲)の宣言が付く。「この列は、この範囲について完全」という主張であり、主張の外を評価すると結果に範囲外註釈が並走する。
2027 年の祝日がまだ手元に無い、という例の状況をそのまま書いてみる。書き方は三通りある——そして三通りのうち二つは罠だ。
罠 その 1: 大きく主張する
holidays2027 = [] covering: 2027..2027 satSun = everyDay |> filter(d => weekday(d) == Sat or weekday(d) == Sun) bizDay = everyDay \ (satSun | holidays2027) bizDay
「2027 年の範囲で、空」。一見正直に見える。2027 年 1 月第 1 週を評価すると:
2027-01-04 2027-01-05 2027-01-06 2027-01-07 2027-01-08 # 被覆サマリ # holidays2027 covering 2027-01-01..2027-12-31 残走路 355 日
警告は何も出ない。当然で、covering: 2027..2027 は「2027 年を完全に把握しており、祝日はゼロ」という主張だからだ。「まだ届いていない」のつもりで書いた式が、言語には「調べ終わった。無かった」と聞こえている。元日(実在の祝日)は営業日として発火し、被覆サマリは「残走路 355 日」——このデータはまだ 355 日ぶん有効という偽の安心を返す。
主張した範囲の中身は、主張した本人しか保証できない。言語は宣言を信じることしかできない。
罠 その 2: 開けっぱなしにする
holidays2027 = [] covering: ..
範囲を書くから嘘になるのなら、開けておけばいいのでは。結果:
2027-01-04 2027-01-05 2027-01-06 2027-01-07 2027-01-08 # 被覆サマリ # holidays2027 covering ..(完結主張) 残走路 ∞
こちらはもっと悪い。covering: .. は「過去も未来も、恒久にこれで完結」という最強の主張で、残走路は ∞ に張り付く。「データが尽きかけたら警告する」という監視をどう組んでも、∞ が閾値を割る日は来ない。腐敗検知の経路が、宣言ひとつで恒久に塞がる。
正解: 知っているところまでしか主張しない
holidays2027 = [] covering: 2026-08-04..2026-08-04
「点はゼロ。保証するのは、確認した今日この日まで」。これが正直な書き方で、出力が変わる:
2027-01-04 2027-01-05 2027-01-06 2027-01-07 2027-01-08 # ⚠ 範囲外 2027-01-04..2027-01-11(holidays2027 covering 2026-08-04..2026-08-04) # 被覆サマリ # holidays2027 covering 2026-08-04..2026-08-04 残走路 -159 日
点列は同じ 5 点。だが今度は ⚠ の範囲外註釈が並走する——「この結果は、祝日データが何も語れない区間で出している」。そして残走路は −159 日。「あと何日で尽きるか」ではなく「もう 159 日ぶん越えている」を、評価のたびに機械可読で告げる。
発火は止まらないことに注意してほしい。データが無いからといってシステムを止めるのはたいてい過剰反応で、土日を除いた点は出続ける。退化するが、退化していることが観測できる——これが求めていた性質だ。
監視は数字一本になる
残走路は「covering の終端 − 評価範囲の終端」。つまり評価がどこまで読むかに対して、データがどれだけ持つかという一本の数字だ。運用はこうなる:
- 残走路 < 75 日 → 「祝日データの更新期限が近い」を警告に流す
- 残走路 < 0 → 結果に註釈が出ている=更新が遅れている
「テーブルを最後に更新したのはいつか」を人間の記憶に頼るのではなく、評価のたびにデータ自身が答える。祝日テーブルが腐る問題は、こうして「事故で気づく」から「尽きる 75 日前に気づく」に変わる。
締め
前回、Kairos に希望する未来として「データが尽きる前に警告が出る」と書いた。その実体がこの二つ——covering(どこまで知っているかの宣言)と残走路(あとどれだけ持つかの数字)だ。仕掛けとしては地味で、派手な機能では全くない。ただ、祝日テーブルを一度でも腐らせたことのある人には、この地味さがいちばん効くと思っている。
(コード例は全て Playground でそのまま動く。言語仕様は kairos-lang.org——現在 RC・1.0 準備中。)

コメント