From b5e1f14e609441b1a30f3685a499477cb0924cad Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 12 Aug 2026 06:26:35 +0000 Subject: [PATCH] =?UTF-8?q?docs:=20=E3=82=B3=E3=83=BC=E3=83=89=E4=B8=AD?= =?UTF-8?q?=E3=81=AE=E3=82=B3=E3=83=A1=E3=83=B3=E3=83=88=E3=82=92=E6=97=A5?= =?UTF-8?q?=E6=9C=AC=E8=AA=9E=E6=8A=80=E8=A1=93=E6=96=87=E6=9B=B8=E3=81=A8?= =?UTF-8?q?=E3=81=97=E3=81=A6=E8=AA=AD=E3=81=BF=E3=82=84=E3=81=99=E3=81=8F?= =?UTF-8?q?=E6=95=B4=E3=81=88=E3=82=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 並列の中黒(・)を「や」「、」「/」などの自然な表記に置き換える - 英数字の前後スペースの揺れ(約47分、1実行間隔、botの 等)を統一する - 文として書かれたコメントの句点の欠落を補い、表記を揃える - 「通知ロスト」を既存の「取りこぼし」に用語統一する - 「取得・送信した集合」を「取得して送信した集合」に言い換える - 過去の文言への言及(「更新があったみたいです」)を過去の経緯と分かる形にする Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_01Cy4duNrxDkhNCiZtwoL45F --- spec/discord/models_spec.cr | 4 ++-- spec/github/models_spec.cr | 6 +++--- spec/notify/usecase_spec.cr | 2 +- spec/slack/models_spec.cr | 2 +- src/discord/models.cr | 6 +++--- src/discord/repository.cr | 2 +- src/github/models.cr | 18 +++++++++--------- src/github/repository.cr | 18 +++++++++--------- src/github/usecase.cr | 4 ++-- src/notify/usecase.cr | 8 ++++---- 10 files changed, 35 insertions(+), 35 deletions(-) diff --git a/spec/discord/models_spec.cr b/spec/discord/models_spec.cr index 413700d..5811476 100644 --- a/spec/discord/models_spec.cr +++ b/spec/discord/models_spec.cr @@ -56,7 +56,7 @@ describe Discord::Embed do end it "drops empty url / icon fields so Discord does not reject them" do - # アラートは footer_icon: "" で来るため、空文字は nil として出さない + # アラートは footer_icon: "" で来るため、空文字は nil として出さない。 message = Notify::Message.new( author_name: "octocat", author_link: "", @@ -72,7 +72,7 @@ describe Discord::Embed do embed.author.as(Discord::Author).icon_url.should be_nil embed.footer.as(Discord::Footer).icon_url.should be_nil - # 空文字フィールドはシリアライズされない + # 空文字フィールドはシリアライズされない。 parsed = JSON.parse(embed.to_json) parsed["footer"].as_h.has_key?("icon_url").should be_false end diff --git a/spec/github/models_spec.cr b/spec/github/models_spec.cr index e833cfa..e353faa 100644 --- a/spec/github/models_spec.cr +++ b/spec/github/models_spec.cr @@ -52,7 +52,7 @@ describe Github::Subject do end it "returns empty for types without a comment body when no comment url is present" do - # CI 完了通知(CheckSuite)などは subject.url を本文取得に使わない + # CI 完了通知(CheckSuite)などは subject.url を本文取得に使わない。 subject_from("CheckSuite", url: "https://api.github.com/repos/o/r/check-suites/1").comment_url.should eq "" end @@ -99,7 +99,7 @@ describe Github::Subject do end it "returns nil for types whose trailing number is not a GitHub issue/PR number" do - # Release は末尾が数値 ID でも #番号 表示は誤解を招くため付けない + # Release は末尾が数値 ID でも #番号 表示は誤解を招くため付けない。 subject_from("Release", url: "https://api.github.com/repos/o/r/releases/5").number.should be_nil end @@ -206,7 +206,7 @@ describe Github::Notification do end it "keeps the assign message when the fetched payload carries no comment count" do - # 本文取得に失敗した場合など、判断材料が無いときは初回向け文言のままにする + # 本文取得に失敗した場合など、判断材料が無いときは初回向け文言のままにする。 pull_request_without_comment_signal.reason_message(subject_detail).should eq "アサインされました" end end diff --git a/spec/notify/usecase_spec.cr b/spec/notify/usecase_spec.cr index 3b205ba..ba46e71 100644 --- a/spec/notify/usecase_spec.cr +++ b/spec/notify/usecase_spec.cr @@ -101,7 +101,7 @@ describe Notify::Usecase do it "未送信通知と同一タイムスタンプの通知を巻き込んで既読化しない" do # 先頭 2 件が同時刻。チャンク境界がその間に落ちても、境界 t(1) は排他的 # なので未送信側の t(1) は既読化されない(送信済み側の t(1) も未読に残り - # 次回再送されるが、ロストよりも稀な重複を許容する)。 + # 次回再送されるが、取りこぼしよりも稀な重複を許容する)。 notifications = [notif("2026-01-01T00:00:01Z"), notif("2026-01-01T00:00:01Z"), notif("2026-01-01T00:00:02Z")] repo = run(notifications, ChunkPoster.new([1, 1, 1])) do |usecase| usecase.check_notifications diff --git a/spec/slack/models_spec.cr b/spec/slack/models_spec.cr index afaa922..40fe260 100644 --- a/spec/slack/models_spec.cr +++ b/spec/slack/models_spec.cr @@ -16,7 +16,7 @@ describe Slack::Attachment do attachment = Slack::Attachment.from_message(message) attachment.pretext.should eq " hello" - # fallback は生の pretext を保持する + # fallback は生の pretext を保持する。 attachment.fallback.should eq "hello" end diff --git a/src/discord/models.cr b/src/discord/models.cr index 60be7c3..8d6d12f 100644 --- a/src/discord/models.cr +++ b/src/discord/models.cr @@ -62,8 +62,8 @@ module Discord posts end - # botのセリフ(pretext)を content に出力する。embed には pretext 相当の欄が - # 無いため、Slack と同様に「botの発言行」として embed の外(content)へ出す + # bot のセリフ(pretext)を content に出力する。embed には pretext 相当の欄が + # 無いため、Slack と同様に「bot の発言行」として embed の外(content)へ出す # (issue #95)。メンションは embed 内では機能しないため content 先頭に # @everyone を添える。チャンク内で重複するセリフは uniq でまとめ、content は # 2000 文字上限があるため truncate する。 @@ -105,7 +105,7 @@ module Discord end def self.from_message(message : Notify::Message) : Embed - # pretext(botのセリフ)は Post の content 側に出すため、description には + # pretext(bot のセリフ)は Post の content 側に出すため、description には # 含めずコメント本文のみとする(二重表示を避ける / issue #95)。 description = message.text.try(&.presence) diff --git a/src/discord/repository.cr b/src/discord/repository.cr index 5a1d366..faa639e 100644 --- a/src/discord/repository.cr +++ b/src/discord/repository.cr @@ -43,7 +43,7 @@ module Discord # 通知が複数投稿に分割される場合、前半チャンク送信後に後半が 429/5xx で # 失敗すると既読化されず、次回実行で前半が重複投稿される。これを避けるため - # レート制限・一時的な 5xx は Retry-After に従って再送する。 + # レート制限(429)と一時的な 5xx は Retry-After に従って再送する。 retryable = res.status.code == 429 || res.status.server_error? if retryable && attempt < MAX_SEND_ATTEMPTS sleep retry_after(res) diff --git a/src/github/models.cr b/src/github/models.cr index 7c85228..43f1efd 100644 --- a/src/github/models.cr +++ b/src/github/models.cr @@ -1,7 +1,7 @@ require "json" module Github - # PR の CI・自動チェックの集計状態(issue #105)。 + # PR の CI などの自動チェックの集計状態(issue #105)。 # check runs(GitHub Actions 等)と commit status の 2 系統をまとめて表す。 enum ChecksState Success # 全て完了し、ブロックする結果が無い @@ -23,7 +23,7 @@ module Github end # メンションを抑止すべき状態か。 - # 成功・チェック未設定・取得失敗ではメンションする。取得できなかった場合に + # 成功、チェック未設定、取得失敗のいずれでもメンションする。取得できなかった場合に # 抑止すると通知の見逃しにつながるため、安全側(誤メンションを許容)に倒す。 def blocks_mention? : Bool failure? || pending? @@ -44,8 +44,8 @@ module Github # "ci_activity", } - # reason(なぜ自分に通知されたか)ごとの表示文言。update? による - # 「更新があったみたいです」一辺倒だと通知理由が伝わらないため、reason を + # reason(なぜ自分に通知されたか)ごとの表示文言。以前は update? に応じた + # 「更新があったみたいです」の一辺倒で通知理由が伝わらなかったため、reason を # 文面に反映する(issue #96)。GitHub 側の reason 追加に耐えるよう、 # 未知の reason は reason_message で汎用文言にフォールバックする。 REASON_MESSAGES = { @@ -64,7 +64,7 @@ module Github # 「一度きりの出来事」を指す reason 向けの、2 回目以降の文言。 # # GitHub の reason は「そのスレッドを購読している理由」であってイベント種別 - # ではないため、一度レビュー依頼/アサインされた PR・Issue は、以降のコメントや + # ではないため、一度レビュー依頼やアサインを受けた PR / Issue は、以降のコメントや # 更新もすべて同じ reason で届く。REASON_MESSAGES だけだと常に「レビューを依頼 # されました」「アサインされました」になり通知理由が実態と合わないので、 # 初回ではないと判断できる通知は文言を差し替える(issue #104)。 @@ -110,7 +110,7 @@ module Github # # Subject#commented?(latest_comment_url が subject.url と異なる)だけでは # 取りこぼす。latest_comment_url は通知を発生させたイベント側を反映することが - # あり、コメント済みのスレッドでも push・レビュー・アサイン変更が起点の通知では + # あり、コメント済みのスレッドでも push やレビュー、アサイン変更が起点の通知では # subject.url に戻る。またレビューコメントは latest_comment_url に現れない # ことがあるため、レビュー上でだけ議論されている PR は常に初回扱いになる。 # 結果、コメントの付いた PR でも「アサインされました」のままになる(issue #116)。 @@ -129,7 +129,7 @@ module Github detail.commented? end - # CI・自動チェックの状態でメンションを抑止する対象か(issue #105)。 + # CI などの自動チェックの状態でメンションを抑止する対象か(issue #105)。 # レビューできる状態になっていない PR で `@channel` / `@everyone` を撃たない # ことが目的なので、PR の通知はすべて対象にする。 # @@ -146,7 +146,7 @@ module Github subject.type == Subject::Type::PULL_REQUEST end - # 通知の pretext(botのセリフ)。`[] ` 形式。 + # 通知の pretext(bot のセリフ)。`[] ` 形式。 # detail は reason_message にそのまま渡す(issue #116)。 def pretext(detail : Comment? = nil) : String "[#{subject.type}] #{reason_message(detail)}" @@ -292,7 +292,7 @@ module Github end # スレッドにコメントが 1 件以上付いているか(issue #116)。 - # 件数が取れない場合(コメントオブジェクト・本文取得失敗・本文なし通知)は + # 件数が取れない場合(コメントオブジェクト、本文取得失敗、本文なし通知)は # 判断材料が無いので false を返し、呼び出し側で初回向け文言に倒す。 def commented? : Bool total = (comments || 0) + (review_comments || 0) diff --git a/src/github/repository.cr b/src/github/repository.cr index f7cd4ef..7ea6e06 100644 --- a/src/github/repository.cr +++ b/src/github/repository.cr @@ -6,7 +6,7 @@ require "../runtime/lambda" module Github class NotificationRepository PER_PAGE = 100 # GitHub /notifications の per_page 上限 - MAX_PAGES = 20 # 暴走防止の取得ページ数上限(= 最大 2000 件) + MAX_PAGES = 20 # 暴走防止の取得ページ数上限(=最大 2000 件) def initialize(@token : String) uri = URI.parse "https://api.github.com" @@ -30,7 +30,7 @@ module Github # 安定させる。上限より新しい通知は取得対象から外れるが、次回実行で取得される。 # before は呼び出し側から受け取る。全件送信後の既読化境界(last_read_at)に # 同じ値を使うことで、取得フィルタ(updated < before)と既読化(updated < - # last_read_at)が同じ排他的比較になり、「取得・送信した集合」と「既読化される + # last_read_at)が同じ排他的比較になり、「取得して送信した集合」と「既読化される # 集合」を一致させられる(issue #100)。 # # 取得しきれない場合(途中ページの一時失敗 5xx/401、またはページ数上限到達)は、 @@ -38,13 +38,13 @@ module Github # スキップして次回に委ねる。 def find_notifications_unread(before : Time) : Array(Notification) # ウォームスタート間で使い回した keep-alive 接続が GitHub 側の古い - # レプリカに固定され、未読があるのに空応答が約47分続く事象を観測した + # レプリカに固定され、未読があるのに空応答が約 47 分続く事象を観測した # (issue #102)。実行のたびに接続を張り直して固定を解き、古い応答を - # 読み続ける時間を最長でも1実行間隔(1分)に抑える。同一実行内の - # ページング・コメント取得・既読化ではそのまま再利用される + # 読み続ける時間を最長でも 1 実行間隔(1 分)に抑える。同一実行内の + # ページングやコメント取得、既読化ではそのまま再利用される # (close 後の接続は次のリクエストで自動的に張り直される)。 - # TLS ハンドシェイクが毎実行1回増えるが、毎分・数百 ms の処理なので - # 通知が長時間届かないリスクより軽いと判断した。 + # TLS ハンドシェイクが毎実行 1 回増えるが、毎分の実行が数百 ms で済む + # 処理なので、通知が長時間届かないリスクより軽いと判断した。 @github.close notifications = [] of Notification @@ -137,7 +137,7 @@ module Github # 100 を超えるチェックは想定しにくいためページングはしない(issue #105)。 CHECKS_PER_PAGE = 100 - # PR の CI・自動チェックの集計状態を返す(issue #105)。 + # PR の CI などの自動チェックの集計状態を返す(issue #105)。 # # check runs(GitHub Actions 等)と commit status(外部 CI 等)は別系統で、 # 片方にしか結果が出ないことがあるため両方を見て厳しい方を採る。 @@ -187,7 +187,7 @@ module Github end # チェック状態の取得用 GET。1 件の取得失敗で通知全体を巻き添えにしないよう、 - # 例外・エラー応答はログだけ残して nil を返す(issue #105)。 + # 例外もエラー応答もログだけ残して nil を返す(issue #105)。 private def get_body(path : String) : String? res = begin diff --git a/src/github/usecase.cr b/src/github/usecase.cr index b8d4983..7a9b861 100644 --- a/src/github/usecase.cr +++ b/src/github/usecase.cr @@ -32,8 +32,8 @@ module Github # メンション(`@channel` / `@everyone`)を付けるか。 # - # mention 系 reason であることに加え、PR は CI・自動チェックが失敗中・実行中 - # でないことを条件にする。まだレビューできる状態ではない PR でチャンネル全体を + # mention 系 reason であることに加え、PR は CI などの自動チェックが失敗中でも + # 実行中でもないことを条件にする。まだレビューできる状態ではない PR でチャンネル全体を # 叩かないため(issue #105)。通知そのものは抑止しない。 private def mention?(notify : Notification) : Bool return false unless notify.mention? diff --git a/src/notify/usecase.cr b/src/notify/usecase.cr index a4a1852..bacaab3 100644 --- a/src/notify/usecase.cr +++ b/src/notify/usecase.cr @@ -13,7 +13,7 @@ module Notify def check_notifications # 取得スナップショット。取得フィルタ(before)と全件送信後の既読化境界 - # (last_read_at)に同じ値を使うことで、取得・送信した集合と既読化される + # (last_read_at)に同じ値を使うことで、取得して送信した集合と既読化される # 集合を一致させる(issue #100)。 # 秒に切り詰めるのは、両者の一致をシリアライズ精度(現状はどちらも秒単位の # RFC 3339)に依存させないため。サブセカンドの解釈差による取りこぼしを @@ -45,15 +45,15 @@ module Notify # # PUT /notifications の last_read_at は排他的境界で、updated_at < last_read_at # のスレッドだけが既読化される(等値は未読のまま残る。issue #100 で実 API - # 検証済み)。これを前提に境界を選ぶ: + # 検証済み)。これを前提に境界を選ぶ。 # - 未送信が残る場合: 境界は未送信先頭の updated_at。排他的なので未送信先頭 # 自身は巻き込まれず、それより前に更新された送信済みは全て既読化される。 # 同一秒がチャンク境界を跨いだ送信済み分は未読に残り次回再送される - # (稀な重複を許容して通知ロストを避ける) + # (稀な重複を許容して通知の取りこぼしを避ける)。 # - 全件送信済みの場合: 境界は取得スナップショット fetched_at。送信済み最新の # updated_at を境界にすると排他的比較でその通知自身が既読化されず毎分再送 # され続けるため(issue #100 の症状)、取得フィルタと同じ fetched_at まで - # 進める。スナップショット以降の新着は未読のまま次回取得される + # 進める。スナップショット以降の新着は未読のまま次回取得される。 private def mark_read_through(notifications : Array(Github::Notification), sent_count : Int32, fetched_at : Time) return if sent_count <= 0