Skip to content

Releases: pooza/makoto2

v0.2.2

Choose a tag to compare

@pooza pooza released this 16 Aug 05:55
4390cf8

⚠⚠ 監視を繋ぐための版。⚠ /healthzmain に入るまで 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 の上限ではないので、全体の締め切りは #920.3)へ分けた。

検証

bydosystemctl restart して確認(手順 4・省略不可)。

  • 3 つの口が 200・未知のパスが 404、⚠ ss127.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

Choose a tag to compare

@pooza pooza released this 15 Aug 16:01
7b5a4a9

⚠ 監視を繋ぐ前に、監視される側を直すためのパッチ。

⚠⚠ **どちらも 0.2.0 のリリース前レビューで赤にし、「監視がまだ 1 本も繋がっていない」を理由に非ブロック化して繰り越したもの。**⚠ 本番 rubicon が 2026-08-15 に稼働を始め、次が監視の接続(pooza/chubo2#98#15)なので、その前に入れる。

#78makoto 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 statusposting: の行が増えた

#79 — 不正なバイト列を含む例外でログ経路自体が落ちていた

⚠ **PostingJobScheduler の両方の rescue を貫通して stderr へ抜け、bin/makoto_daemon.rb/dev/null に落とすので 1 行も残らなかった。**⚠⚠ 常駐は生き続け、makoto status は健全のまま。

**呼び出し側 6 箇所ではなく、Makoto::Logger#create_message(出口 1 つ)で受けた。**⚠ 6 箇所を直す形は 7 箇所目が生えた瞬間に、しかも静かに破れる。

⚠⚠ レビューで出た 3 件(すべて実在した)

  1. 同じ枠の失敗を二重に数えていた — ⚠ 成功は冪等キーで畳まれるのに失敗だけ畳まれず、落ちた枠 1 つで閾値を 2 つ消費「投稿の側で冪等にしたものは、観測の側でも冪等にする」
  2. 🔴 痕跡の書き込みが不可分でなかった — ⚠ File.write は切り詰めてから書くので、読んだ側が壊れた JSON を掴み stale? が true。⚠⚠ makoto status が 1 を返して monit が正常な常駐を再起動する形で、#78 自身が窓を広げていた(1 時間に 1 回 → ライブ当日 160 回)。実測で 2,000 回中 625 回が nil
  3. 🔴 秘密がマスクを迂回して漏れる経路を、#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

Choose a tag to compare

@pooza pooza released this 15 Aug 12:58
b3262c9

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 status0 健全 / 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

⚠ 既知の残り

  • ⚠⚠ announcement の原稿が 0 件#14)。機構は動くが 11/1 に何も出ない
  • 本番(rubicon)はレシピ未適用pooza/chubo2#104
  • 監視(monit / Uptime Kuma)が未接続pooza/chubo2#98#15

v0.1.0

Choose a tag to compare

@pooza pooza released this 31 Jul 02:43
0f66218

**基盤の決定と土台。**未決事項を確定し、台詞コーパスを実データとして載せ、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 のため、これが機能的な締め切りです。