Releases: pooza/makoto2
Release list
v0.2.2
⚠⚠ 監視を繋ぐための版。⚠ /healthz が main に入るまで Uptime Kuma からは叩けなかった(本番 rubicon が追うのは main)ので、#15(デプロイと死活監視)がこのリリース待ちで止まっていた。
監視の口として /healthz を生やした(#84)
⚠⚠ **makoto status は箱の中からしか呼べない。**死活の判断そのものは Health にあるのに、**外から確かめる手段が無かった。**⚠ monit は fleet 全体で退役方向で、⚠⚠ Kuma のモニタは 99 本すべてが http(push の前例はゼロ)。
| 口 | 503 になる条件 | ⚠ 監視の扱い |
|---|---|---|
/healthz |
Health#errors(=終了コード 1) |
復旧させてよい |
/healthz/posting |
投稿が続けて落ちている | ⚠⚠ 人が見る。復旧を叩かせない |
/healthz/orphans |
孤児がある//proc が読めない |
⚠⚠ 人が見る。復旧を叩かせない |
- ⚠⚠ **投稿の警告と孤児を同じ口に載せない。**⚠ 投稿の警告は sticky(消えるのは「次に 1 本投稿できたとき」だけ)なので、同じ口だと赤のまま残っている間に本物の孤児が埋もれる
- ⚠⚠ **別プロセスにしない。**常駐が落ちれば口も閉じるので、TCP の接続が失敗すること自体が「死んでいる」の検知になる
- 🔴 **答えているのが pid ファイルの常駐でなければ 3 つとも 503。**⚠ 古い常駐がポートを掴んだまま新しい常駐が動く形では、⚠⚠ 孤児の口さえ緑になっていた
- ⚠⚠ **これは「inbound は開けない」を緩める判断。**⚠ 緩めるのは LAN 限定・読み取り専用の死活の口だけで、既定は
127.0.0.1(管理コンソールを作らない決定は変えていない)
cure-api が落ちてもライブの並びが変わらない(#88)
⚠⚠ LiveProgram はその日の並びを最初の枠で 1 回だけ組むので、⚠ 12:02 の一瞬の不通が「その日はゲストコーナーが無い」になっていた — 8 時間ぶんが 1 回のリクエストで決まる。
**引けた名義をローカルの写しに残し、引けないときはそれを使う。**⚠ これは状態ではなく写しなので、「進行位置は状態ではなく計算で出す」とは衝突しない。
- ⚠⚠ カバーが「静かに 0 件」になる経路を全部塞いだ — 引けない / 1 件も一致しない / 要求数に満たないの 3 つを別々の警告に
- ⚠ カバーの選曲を
CoverSelectorに分けた(本編は整列、カバーは母集合を絞ってから抽選で軸が違う)
投稿が枠を跨いで滞留しない(#90)
⚠⚠ /http/timeout/seconds: 30 が投稿・cure-api に効いていなかった(HTTParty に渡していたのは upload だけで、実効は Net::HTTP 既定の 60 秒)。**再送 3 回と合わせて 1 本の投稿が最悪 182 秒 = ライブの枠間隔 180 秒とほぼ同じ。**→ 92 秒
**あわせて /scheduler/tolerance = 30s。**⚠ tick と同値だと余裕が構造的にゼロで、⚠⚠ ライブの枠間隔 180 秒は tick の 10 秒の整数倍なので、位相ずれは 160 枠すべてに同じように効く。
⚠⚠ timeout は wall-clock の上限ではないので、全体の締め切りは #92(0.3)へ分けた。
検証
bydo で systemctl restart して確認(手順 4・省略不可)。
- 3 つの口が 200・未知のパスが 404、⚠
ssは127.0.0.1:4567のみで LAN からは届かない(既定が閉じている) - ⚠⚠ 10 回叩いて
healthzのログは 0 行(正常な応答は書かない) - 11/1〜11/4 の下見が 4 日とも 163 行。11/4 は ⚠ 本編 125 曲 / カバー 8 曲 / MC 26 枠 26 本
- 🔴 ⚠⚠ cure-api を落として下見をやり直しても 1 行も変わらない(
diff= 0)。⚠ 黙って代わらない(falling back to the stored copyを記録) - ⚠ 投稿は 1 通も出していない(
statusesは 15 のまま) - ✅ lint /
config:lint/ 395 tests 0 failures(v0.2.1 の 357 から +38)・Dependabot の open アラート 0 件
Full Changelog: v0.2.1...v0.2.2
v0.2.1
⚠ 監視を繋ぐ前に、監視される側を直すためのパッチ。
⚠⚠ **どちらも 0.2.0 のリリース前レビューで赤にし、「監視がまだ 1 本も繋がっていない」を理由に非ブロック化して繰り越したもの。**⚠ 本番 rubicon が 2026-08-15 に稼働を始め、次が監視の接続(pooza/chubo2#98 → #15)なので、その前に入れる。
#78 — makoto status が「投稿が実際に出たか」を見ていなかった
⚠⚠ jobs は起動時に決まる登録の本数なので、160 枠すべてが失敗しても jobs: 5 のまま exit 0 だった。
枠の結末を 3 つに分けて、失敗の側だけを数える。
| 枠の結末 | 記録 |
|---|---|
| 投稿できた | failures を 0 に戻す |
| ⚠ 本文が無い | 何も記録しない(中立) |
⚠ source が落ちた/投稿が失敗した |
failures を 1 つ進める |
- 🔴 **「本文が無い」を中立に置くのが肝。**⚠ 失敗に数えると原稿がまだ無いだけの日(8/15〜10/31 の 2 か月半)が延々と警告になり、⚠⚠ 成功に数えると「設定を消すと枠の中で例外が上がる」形(#77)が中立に紛れる
- ⚠⚠ 異常(1)ではなく警告(2)。投稿が落ちる原因(トークンの失効・設定の欠落・
sourceの不具合・Mastodon 側の障害)はどれも再起動で直らないので、1 にすると検知 → 再起動 → また失敗のループになる - ⚠
makoto statusにposting:の行が増えた
#79 — 不正なバイト列を含む例外でログ経路自体が落ちていた
⚠ **PostingJob → Scheduler の両方の rescue を貫通して stderr へ抜け、bin/makoto_daemon.rb が /dev/null に落とすので 1 行も残らなかった。**⚠⚠ 常駐は生き続け、makoto status は健全のまま。
**呼び出し側 6 箇所ではなく、Makoto::Logger#create_message(出口 1 つ)で受けた。**⚠ 6 箇所を直す形は 7 箇所目が生えた瞬間に、しかも静かに破れる。
⚠⚠ レビューで出た 3 件(すべて実在した)
- 同じ枠の失敗を二重に数えていた — ⚠ 成功は冪等キーで畳まれるのに失敗だけ畳まれず、落ちた枠 1 つで閾値を 2 つ消費。「投稿の側で冪等にしたものは、観測の側でも冪等にする」
- 🔴 痕跡の書き込みが不可分でなかった — ⚠
File.writeは切り詰めてから書くので、読んだ側が壊れた JSON を掴みstale?が true。⚠⚠makoto statusが 1 を返して monit が正常な常駐を再起動する形で、#78 自身が窓を広げていた(1 時間に 1 回 → ライブ当日 160 回)。実測で 2,000 回中 625 回が nil - 🔴 秘密がマスクを迂回して漏れる経路を、#79 の修正自身が作っていた — ⚠⚠ 修正前は syslog で落ちて「ログごと消えて」いたものが、scrub で出力できるようになった結果、秘密がそのまま書かれる。「ログが消える」を「秘密が漏れる」に変えていた
検証
- ✅ ステージング検証(手順 4・省略不可) —
bydoで検知そのものを動かした。3 枠落としてcode=2、同じ枠は二重に数えず、1 本出ればcode=0 - ✅ ⚠ #79 のログが実際に
/var/log/makoto2.logに残り、同じ行のtoken: SECRETはログ全体で 0 件 - ✅ 11/1〜11/4 の 4 日ぶんの下見が 0.2.0 と同一(11/3 は前日増量 8/8、11/4 は 160/160)
- ✅ lint / config:lint / 357 tests 0 failures(0.2.0 の 314 から +43)
- ⚠ 投稿は 1 通も出していない
Full Changelog: v0.2.0...v0.2.1
v0.2.0
11/4 バースデーライブ本体と、無人で動かすための土台。
⚠⚠ **0.1.0 は「main にタグを打つところまで」で稼働していなかった。**0.2.0 で初めて実際に動くものが main に載る。
63 コミット / 64 ファイル / +7,690 −215。
バースデーライブ(#13)
- 枠は 4 つ — 前日増量 / 開始告知 / 8 時間 160 枠の進行 / 終了告知
- ⚠⚠ セットリストは抽選ではなく整列。****発売日で並べるだけでキュアソード関連 11 曲が中間点をまたぐ位置に固まるので、⚠ 特別扱いを 1 つも書かずに元ネタの構成が再現される
- ⚠ 進行位置は状態ではなく計算で出す。落ちて戻ってきても位置がずれない
- ⚠ カバーはプリキュア歌手の持ち歌に限る(cure-api の
/singers)。⚠⚠ 曲データの分類は当てにならないので名義の側で落とす
無人で動かすための土台
- 常駐 1 本+内蔵スケジューラ(#10 / #47)
- ⚠ 死活監視の口 —
makoto statusが 0 健全 / 1 異常 / 2 警告で返す(#15) - 原稿の上書き機構(5 段・「具体的なものが勝つ」・#12)、11/1 からの予告(#14)
- 曲データのデータ層への取り込みと重み付き抽選(#9 / #11)
- ⚠ 原稿をファイルから取り込む(#50)
2026-08-15 のリハーサルから出た 8 件
⚠⚠ ステージングで初めて 8 時間の進行を流し、そこから 8 件が出た。
童謡の間引き・ハッシュタグ・カバーの単独名義(#63 / #64 / #65)、孤児判定(#54 / #61)、⚠ 下見で MC の本文が読めるように(#62)、供給元の誤記の訂正表と音楽記号の正規化(#58 / #74)、⚠⚠ MC の並びが台本の進行と噛み合っていなかった(#69 / #73)。
⚠ #69 / #73 は連鎖で出た。#63 が 8 曲間引く → MC 枠 17→25 で台本が巻き戻る。#58 が 1 曲たたむ → 26 枠で 後半。 が蝶番の前に出る。⚠⚠ どちらも「曲数を触ると MC の枠数が動く」という同じ構造。
リリース前レビュー(5 観点・独立実行)
⚠⚠ 独立した 2 人が別々の道筋で同じ赤に当たった。
- ✅ #77 — 「設定を消せば止まる」というコメントが嘘だった。⚠ キーが無ければ例外で、⚠⚠
config:lintは通るのに 160 枠が沈黙する形 - ⏭ #78 / #79 — ⚠ 監視が未接続なので非ブロック化して繰越
- ⏭ #80 — 黄 12 件・緑 11 件
検証
- ✅ ステージング(
bydo)へデプロイ。⚠ リハーサルで st2.precure.ml へ 15 投稿・全て HTTP 200・落ちた枠ゼロ - ✅ 11/1〜11/4 の 4 日ぶんを下見(投稿せず)— 11/3 は前日増量 8/8、11/4 は 160/160。⚠ 11/1〜11/3 にライブ本体が 1 本も漏れていない
- ✅ lint / config:lint / 314 tests 0 failures
⚠ 既知の残り
v0.1.0
**基盤の決定と土台。**未決事項を確定し、台詞コーパスを実データとして載せ、Mastodon への投稿が 1 通通るところまで。
⚠ **稼働はしていません。**ステージング検証とデプロイは実施していません(下記)。
決めたこと
| 決定 | |
|---|---|
| スタック(#2) | Ruby + ginseng-* 系 gem。常駐プロセス 1 本 + プロセス内スケジューラ |
| LLM(#3) | Anthropic Claude claude-opus-5。全機能で同じモデル |
| データストア(#4) | SQLite + Sequel |
| CI(#6) | GitHub Actions で rubocop / rake config:lint / rake test |
⚠ 台詞コーパス 561 件(6,969 文字)はシステムプロンプトに収まることを実測で確認したため、ベクトル検索も RAG 基盤も採りません。
作ったもの
- リポジトリの骨組み(#5) —
bin/makoto(Thor の CLI)、bin/makoto_daemon.rb(start / stop / restart / status)、syslog への JSON ログ、スケジューラのハートビート - Mastodon への投稿疎通(#7) —
makoto whoami/makoto post。恒久的な失敗と一時的な失敗を分けて上げる - 台詞コーパスのスキーマと投入(#8) —
makoto corpus import/stat。何度実行しても同じ結果になる
実データの件数
docs/makoto-legacy.md の記載と一致。
quote: 956
応答可: 561(キュアソード 165 / 剣崎真琴 395 / ちびキュアソード 1)
message: 388(morning 237 / template 109 / birthday 23 / calling 13 / holiday 6)
リリース前レビュー
赤 0 件。黄 5 件は #33 へ繰越。セキュリティレビューは bundler-audit・Dependabot ともに脆弱性 0 件。
⚠ ステージング検証とデプロイを省略しています
検証先の環境がまだ存在しないため。bydo はレシピ未適用で、MAKOTO 本体のデプロイレシピも未着手(pooza/chubo2#98)。
環境が無いことによる一度きりの例外で、前例にしません。0.2.0 以降は bydo が整うまでリリースしません。
開発中に塞いだ穴
- ⚠
tmp/db/makoto.dbが git に追跡されていた — そのままコーパスを投入すると、第三者の著作物である台詞 956 件が public リポジトリに乗る経路だった - ⚠ Sequel の例外メッセージは ASCII-8BIT — 台詞を含む SQL が失敗すると
Encoding::CompatibilityErrorになり、エラー処理自体が落ちて本当のエラーが隠れる - ⚠ テストの通信遮断が
super依存だった — サブクラスがsetupを定義した瞬間に無言で外れる。投稿するボットなので、外れるとテストが実サーバーに書き込む - ⚠ 投稿の再送で二重投稿 — Mastodon が受理した後に応答だけ失われると、再送が同じ投稿をもう 1 つ作る。
Idempotency-Keyを全試行で使い回すよう修正
次
0.2.0 は 11/4 バースデーライブ(SONGBIRD PARTY 2026)。予告開始が 11/1 のため、これが機能的な締め切りです。