From 5d55e14858fd74368e395722d47bb70edfe5543a Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 15 Sep 2026 13:21:29 +0000 Subject: [PATCH 01/12] =?UTF-8?q?=E3=83=86=E3=83=AC=E3=83=A1=E3=83=88?= =?UTF-8?q?=E3=83=AA=E3=82=92=E6=9C=AC=E7=95=AA=E3=81=A7=E3=82=AA=E3=83=97?= =?UTF-8?q?=E3=83=88=E3=82=A4=E3=83=B3=E5=8F=AF=E8=83=BD=E3=81=AB=E3=81=99?= =?UTF-8?q?=E3=82=8B=E5=A0=B4=E5=90=88=E3=81=AE=E3=83=AA=E3=82=B9=E3=82=AF?= =?UTF-8?q?=E8=A9=95=E4=BE=A1=E3=82=92=E3=83=89=E3=82=AD=E3=83=A5=E3=83=A1?= =?UTF-8?q?=E3=83=B3=E3=83=88=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01QzKkzvpiWBmFsBJvBTCc2Q --- docs/README.md | 1 + docs/telemetry-production-optin-risk.md | 156 ++++++++++++++++++++++++ 2 files changed, 157 insertions(+) create mode 100644 docs/telemetry-production-optin-risk.md diff --git a/docs/README.md b/docs/README.md index db9abf419..df0f2c65f 100644 --- a/docs/README.md +++ b/docs/README.md @@ -13,6 +13,7 @@ - [本番リリース PR でのバージョン更新](./bump-version-on-release-pr.md) - [AI コードレビュー (GPT-5.6 Sol)](./ai-code-review-workflow.md) - [Firebase Test Lab の Robo テスト](./test-lab-robo.md) +- [テレメトリの本番オプトイン: リスク評価](./telemetry-production-optin-risk.md) - [AIエージェント設計書](./spec/ai-agent/architecture.md) - [リモートTTS(iOS)設計書](./spec/tts/remote-tts.md) - [オンデバイスTTS(VOICEVOX / iOS)設計書](./spec/tts/on-device-tts-ios.md) diff --git a/docs/telemetry-production-optin-risk.md b/docs/telemetry-production-optin-risk.md new file mode 100644 index 000000000..46cf64e16 --- /dev/null +++ b/docs/telemetry-production-optin-risk.md @@ -0,0 +1,156 @@ +# テレメトリの本番オプトイン: リスク評価 + +試験的機能として canary 限定で動いているテレメトリを、本番 (App Store / Google Play +配布ビルド) でもオプトイン可能にする場合に何が起きるかを整理したもの。実装前の +意思決定用メモであり、この文書の時点でコードには一切手を付けていない。 + +結論として、**プライバシーポリシーの改定は必須**で、かつそれだけでは足りない。 +コード側の前提を 3 点変えないと本番投入は危険。 + +## 現状のゲート + +```text +isTelemetryEnabledByBuild = isDevApp && ENABLE_EXPERIMENTAL_TELEMETRY === 'true' +``` + +- `src/utils/telemetryConfig.ts`: ビルド時定数。canary (dev アプリ) でのみ true +- `src/screens/AppSettings.tsx`: 試験的機能の導線自体が `isDevApp` でガードされている +- `src/screens/ExperimentalSettings.tsx`: ユーザー側トグル。既定は false (オプトイン) +- `src/components/Permitted.tsx`: MMKV (`STORAGE_KEYS.TELEMETRY_ENABLED`) から復元 + +つまり「本番でオプトイン」は、ビルド時ゲートを外すことと、試験的機能画面の +`isDevApp` ガードを外す (あるいはトグルを通常の設定画面へ出す) ことの両方を指す。 + +## オプトインすると実際に何が送信されるか + +| 経路 | 中身 | 頻度 | +| --- | --- | --- | +| `sendLocation` | 緯度・経度 (生の精度)、accuracy、速度、lineId / stationId、移動状態、バッテリー残量・充電状態、端末モデル名、アプリバージョン (ビルド番号込)、OS、channel、sessionId | 最短 1 秒に 1 回 (`TELEMETRY_THROTTLE_MS = 1000`) | +| `sendLogEvent` / `sendInteractionEvent` | アプリ内ログ、`app_launch` などの操作イベント | 随時 | +| `useConsoleTelemetry` | `console.log` / `debug` / `warn` / `error` の全出力 | 5 秒ごとにフラッシュ | + +送信先はいずれも `EXPERIMENTAL_TELEMETRY_ENDPOINT_URL`。GraphQL ミューテーション +(`/graphql`) と、コンソールテレメトリだけが使う REST (`/api/log`) の 2 系統がある。 + +### 同意文言と取得範囲のズレ + +トグルの説明は `telemetryDescription` (`assets/translations/ja.json:351`, +`assets/translations/en.json:350`) の「お使いの端末の地理的座標を解析用サーバに +送信します」だけ。バッテリー・端末モデル・ログ本文・操作イベントは説明されて +いない。同意を取る地点の文言が実際の取得範囲を下回っているので、ポリシーと +あわせてこの文言も直す必要がある。 + +## プライバシーポリシーとの矛盾 + +現行ポリシー (`https://trainlcd.app/privacy-policy` / 最終更新 令和 8 年 8 月 13 日) +には、本番テレメトリと正面から矛盾する記述が 2 つある。 + +1. **「位置情報はサーバー上に保管されることはありません」** + 本番テレメトリは位置ログを解析基盤に永続化して集計するのが目的なので、この + 一文はそのままでは事実に反する。「解析目的で送信された位置情報は、利用者が + 明示的に有効化した場合に限り N 日間保管される」という趣旨へ書き換える。 +1. **「位置情報を、広告の配信や利用者様の行動の追跡 (トラッキング) のために + 利用することは一切ありません」** + 広告目的でないのは事実だが、1Hz の連続測位ログは移動軌跡そのもので、 + sessionId によりプロセス単位で連結できる。「やらないこと」だけを書くのでは + なく、「セッション単位の移動軌跡を解析目的で保管する。ただし個人の特定・ + 広告配信・アプリ横断の追跡には利用しない」と、やることを書いた上で否定する + 形にする。 + +### 新設が必要な項目 + +現行ポリシーに項目自体が無く、追記が要るもの。 + +- 取得項目の追加: バッテリー残量・充電状態、端末モデル名、アプリバージョン、 + アプリ内ログ本文、操作イベント +- 保管期間の明示: 現状は「一定の期間」で数値が無い。位置ログは日数を切る +- オプトアウト導線: 「端末の設定から停止できる」だけでなく、アプリ内設定から + 個別に無効化できることを明記する +- 外部サービス: テレメトリ基盤 (THQ) の記載が無い。ホスティング先が国外なら + 越境移転 (個人情報保護法 28 条 / 外的環境の把握) の開示が要る +- 開示・削除請求への応答方針: 後述のとおり、現設計では技術的に応じられない + +## コード側で先に直すべき 3 点 + +### 1. コンソールテレメトリは本番に出さない + +`useConsoleTelemetry` は `console.*` を丸ごと横取りして送るため、サードパーティ製 +ライブラリのエラー、ディープリンク URL、ユーザー入力を含む例外メッセージが、 +何が入るか分からないまま送信される。`sanitizeTelemetryMessage` の防御は正規表現 +4 本 (`src/utils/sanitizeTelemetryMessage.ts`) で、キー名が想定外の秘密情報や生の +JWT は素通りする。 + +加えて `/api/log` への送信ペイロードには `channel` も `sessionId` も入っていない +ため、本番ログと canary ログが基盤側で区別できない。 + +対応は、本番では `FxConsoleTelemetry` (`src/screens/Main.tsx`) をマウントしない。 +出すなら `warn` / `error` 限定かつ送信元を許可リストで絞る作りに変えてから。 + +### 2. 静的 Bearer トークンをやめる + +`EXPERIMENTAL_TELEMETRY_TOKEN` は react-native-dotenv でバンドルへインライン展開 +されるので、IPA / APK から抽出できる。canary は配布先が限られるため許容できて +いたが、本番は公開配布であり、偽の位置イベントを無制限に流し込める。データ汚染と +コスト攻撃が成立する。 + +`src/lib/session.ts` に installId を短期セッショントークンへ交換する仕組み +(`/auth/token`) が既にあるので、これに乗せ替えるのが筋。 + +### 3. リモートキルスイッチを付ける + +現在のゲートはビルド時定数なので、事故ってもストア審査を通さないと止められない。 +`REMOTE_CONFIG_KEYS.AI_AGENT_ENABLED` に「障害・コスト超過時にサーバー側から機能を +止められるようにするキルスイッチ」という先例があるので、同じ形で +`telemetry_enabled` を追加する。 + +## その他のリスク + +### ストア申告 + +App Store のプライバシーラベルに「Precise Location → Analytics」、Google Play の +データセーフティに「位置情報 (任意) ・診断情報」の追加申告が要る。申告漏れは +審査差し戻しや公開停止の対象になる。ATT はアプリ横断の追跡もデータブローカーへの +提供も無いので不要のはずだが、「Tracking に使わない」という前提を崩さないこと。 + +### 開示・削除請求に応じられない + +`sessionId` はプロセスごとの使い捨て UUID (`src/hooks/useTelemetrySender.ts` の +`getOrCreateSessionId`) で端末に残らないため、利用者から削除を求められても、 +どれがその人のデータか特定できない。匿名性が高いのは利点だが、EU 圏の利用者が +いるなら GDPR 17 条への回答として「特定不能なので対応不可 (Art.11)」を説明できる +状態にしておくか、削除可能にするなら installId 紐づけへ変える (= 匿名性は下がる) +かを先に決める必要がある。 + +### コストと電池 + +1 秒 1 リクエストで、バッチングもリトライ制御も無い。30 分乗車で 1 ユーザーあたり +1,800 リクエスト。canary の母数では問題にならなかった数字が、本番の DAU では桁が +変わる。本番はサンプリング (対象ユーザーの N 分の 1) か送信間隔の緩和 (5〜10 秒) +が現実的。省電力測位モードの効果を毎秒の通信で部分的に打ち消す点も検討が要る。 + +### 同意のスコープクリープ + +MMKV に `'true'` が永続化されるだけなので、将来取得項目を増やしたときに古い同意が +そのまま流用される。同意バージョンを持たせ、範囲を広げるときは再同意を取る設計に +しておく。 + +## 推奨する出し方 + +段階を踏むなら、次の構成で本番へ出す。 + +- 位置イベントのみ (コンソールテレメトリとインタラクションイベントは canary 据え置き) +- サンプリングまたは送信間隔の緩和 +- Remote Config によるキルスイッチ +- セッショントークン認証 + +プライバシーポリシーはこの「位置イベントのみ」の範囲で書き換え、取得項目を +増やすときに改めて改定する。 + +## 未確認事項 + +- バックグラウンド測位中も JS が動いている間は送信が継続するはず。「アプリを + 閉じている間も送られている」状態になっていないかは実機での確認が要る +- 本文中のポリシー引用は公開ページの取得結果に基づく。改定作業では原文の文言を + 直接確認すること +- テレメトリ基盤 (THQ) のホスティングリージョンと実際の保管期間は未確認で、 + 越境移転の記載要否と保管期間の数値はそれ次第 From fa3974948c60e0a0695a73982542501f6cd98891 Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 15 Sep 2026 13:32:33 +0000 Subject: [PATCH 02/12] =?UTF-8?q?=E3=83=86=E3=83=AC=E3=83=A1=E3=83=88?= =?UTF-8?q?=E3=83=AA=E6=9C=AC=E7=95=AA=E3=82=AA=E3=83=97=E3=83=88=E3=82=A4?= =?UTF-8?q?=E3=83=B3=E3=81=AE=E3=83=AA=E3=82=B9=E3=82=AF=E8=A9=95=E4=BE=A1?= =?UTF-8?q?=E3=81=AB=E3=83=AC=E3=83=93=E3=83=A5=E3=83=BC=E6=8C=87=E6=91=98?= =?UTF-8?q?=E3=82=92=E5=8F=8D=E6=98=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01QzKkzvpiWBmFsBJvBTCc2Q --- docs/telemetry-production-optin-risk.md | 37 ++++++++++++++++++------- 1 file changed, 27 insertions(+), 10 deletions(-) diff --git a/docs/telemetry-production-optin-risk.md b/docs/telemetry-production-optin-risk.md index 46cf64e16..a89585d34 100644 --- a/docs/telemetry-production-optin-risk.md +++ b/docs/telemetry-production-optin-risk.md @@ -21,6 +21,11 @@ isTelemetryEnabledByBuild = isDevApp && ENABLE_EXPERIMENTAL_TELEMETRY === 'true' つまり「本番でオプトイン」は、ビルド時ゲートを外すことと、試験的機能画面の `isDevApp` ガードを外す (あるいはトグルを通常の設定画面へ出す) ことの両方を指す。 +これとは別に、送信先 URL (`EXPERIMENTAL_TELEMETRY_ENDPOINT_URL`) が空なら、下に挙げる +送信経路はいずれも早期 return する。コンソールテレメトリの場合は `console.*` の差し替え自体が +行われない。ビルド時ゲートを外しても、本番ビルドへ URL を焼き込まない限り送信は +起きない。 + ## オプトインすると実際に何が送信されるか | 経路 | 中身 | 頻度 | @@ -66,9 +71,14 @@ isTelemetryEnabledByBuild = isDevApp && ENABLE_EXPERIMENTAL_TELEMETRY === 'true' - 保管期間の明示: 現状は「一定の期間」で数値が無い。位置ログは日数を切る - オプトアウト導線: 「端末の設定から停止できる」だけでなく、アプリ内設定から 個別に無効化できることを明記する -- 外部サービス: テレメトリ基盤 (THQ) の記載が無い。ホスティング先が国外なら - 越境移転 (個人情報保護法 28 条 / 外的環境の把握) の開示が要る -- 開示・削除請求への応答方針: 後述のとおり、現設計では技術的に応じられない +- 外部サービス: テレメトリ基盤 (THQ) の記載が無い。国外で取り扱う場合は次の 2 つを + 分けて扱う + - 個人情報保護法 28 条は「外国にある第三者への提供」の規定で、同意取得または + 所定の情報提供を求める。THQ を自前で運用していて第三者提供に当たらないなら + 適用されない。委託・第三者提供のどちらに当たるかは契約形態の確認が要る + - 外国で取り扱う場合の「外的環境の把握」は 28 条ではなく安全管理措置の要件で、 + 提供形態に関わらず、所在リージョンを把握したうえで公表内容へ反映する +- 開示・削除請求への応答方針: 後述のとおり、特定可能性の評価と手順の決めが要る ## コード側で先に直すべき 3 点 @@ -112,14 +122,21 @@ App Store のプライバシーラベルに「Precise Location → Analytics」 審査差し戻しや公開停止の対象になる。ATT はアプリ横断の追跡もデータブローカーへの 提供も無いので不要のはずだが、「Tracking に使わない」という前提を崩さないこと。 -### 開示・削除請求に応じられない +### 開示・削除請求への対応方針 `sessionId` はプロセスごとの使い捨て UUID (`src/hooks/useTelemetrySender.ts` の -`getOrCreateSessionId`) で端末に残らないため、利用者から削除を求められても、 -どれがその人のデータか特定できない。匿名性が高いのは利点だが、EU 圏の利用者が -いるなら GDPR 17 条への回答として「特定不能なので対応不可 (Art.11)」を説明できる -状態にしておくか、削除可能にするなら installId 紐づけへ変える (= 匿名性は下がる) -かを先に決める必要がある。 +`getOrCreateSessionId`) で端末に残らない。ただし「端末に ID が残らない」ことだけを +根拠に特定不能と決めつけない。送信されるのは連続した移動軌跡と時刻・端末モデル・ +アプリバージョンなので、保管側の他の情報と突き合わせれば特定できる場合がある。 +まず照合可能性の評価が要る。 + +そのうえで方針を決める。GDPR 17 条の削除請求に対して 11 条 (特定を要しない取扱い) +を援用できるのは、特定できないことを管理者が示せる場合に限られ、請求者が特定に +足る追加情報を出してきたときは同条を理由に一律で断れない。請求を受けたときの手順 +(申請内容との照合、対象データの特定、削除可否と理由の記録、特定できない場合の説明、 +追加情報が出てきたときの再評価) を決めておく。削除に応じられる形にするなら +installId 紐づけへ変える選択肢もあるが、匿名性は下がる。基盤側の論点として +TrainLCD/THQ#37 に起票済み。 ### コストと電池 @@ -153,4 +170,4 @@ MMKV に `'true'` が永続化されるだけなので、将来取得項目を - 本文中のポリシー引用は公開ページの取得結果に基づく。改定作業では原文の文言を 直接確認すること - テレメトリ基盤 (THQ) のホスティングリージョンと実際の保管期間は未確認で、 - 越境移転の記載要否と保管期間の数値はそれ次第 + 国外取扱いに関する記載の要否と保管期間の数値はそれ次第 From be4b6c3b8bda8daeb51ede3c4d087990b1b3afe3 Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 15 Sep 2026 13:35:23 +0000 Subject: [PATCH 03/12] =?UTF-8?q?=E3=82=B3=E3=83=B3=E3=82=BD=E3=83=BC?= =?UTF-8?q?=E3=83=AB=E3=83=86=E3=83=AC=E3=83=A1=E3=83=88=E3=83=AA=E3=81=AE?= =?UTF-8?q?=E9=80=81=E4=BF=A1=E5=85=88=E3=81=8C=E5=9F=BA=E7=9B=A4=E3=81=AB?= =?UTF-8?q?=E5=AD=98=E5=9C=A8=E3=81=97=E3=81=AA=E3=81=84=E4=BA=8B=E5=AE=9F?= =?UTF-8?q?=E3=82=92=E3=83=AA=E3=82=B9=E3=82=AF=E8=A9=95=E4=BE=A1=E3=81=B8?= =?UTF-8?q?=E8=BF=BD=E8=A8=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01QzKkzvpiWBmFsBJvBTCc2Q --- docs/telemetry-production-optin-risk.md | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/docs/telemetry-production-optin-risk.md b/docs/telemetry-production-optin-risk.md index a89585d34..2021cd9ab 100644 --- a/docs/telemetry-production-optin-risk.md +++ b/docs/telemetry-production-optin-risk.md @@ -37,6 +37,13 @@ isTelemetryEnabledByBuild = isDevApp && ENABLE_EXPERIMENTAL_TELEMETRY === 'true' 送信先はいずれも `EXPERIMENTAL_TELEMETRY_ENDPOINT_URL`。GraphQL ミューテーション (`/graphql`) と、コンソールテレメトリだけが使う REST (`/api/log`) の 2 系統がある。 +ただし後者は**受け口が無い**。THQ (`TrainLCD/THQ`) のルータに定義されているルートは +`/`、`/ws`、`/healthz`、`/graphql` の 4 つだけで、`/api/log` は存在しない +(`src/server.rs`)。クライアント側はカスケードエラーを防ぐため送信失敗を握り潰すので、 +404 が返っていても誰も気づかない。つまりコンソールログは現状、送信しているつもりで +全て捨てられている可能性が高い。上の表はコードが送ろうとしている内容であって、 +実際に基盤へ届いている内容ではない。基盤側の方針決めは TrainLCD/THQ#38。 + ### 同意文言と取得範囲のズレ トグルの説明は `telemetryDescription` (`assets/translations/ja.json:351`, @@ -93,6 +100,11 @@ JWT は素通りする。 加えて `/api/log` への送信ペイロードには `channel` も `sessionId` も入っていない ため、本番ログと canary ログが基盤側で区別できない。 +なお前述のとおり、その `/api/log` は THQ に存在しない。**今は漏れていないが、 +リスクが消えているわけではない**: 受け口を作った瞬間、あるいは前段に振り先を +用意した瞬間に、上記の内容が無制御で流れ出す。本番へ出す前に、コンソール経路を +`sendLogEvent` へ寄せるか、経路ごと落とすかを決めておく。 + 対応は、本番では `FxConsoleTelemetry` (`src/screens/Main.tsx`) をマウントしない。 出すなら `warn` / `error` 限定かつ送信元を許可リストで絞る作りに変えてから。 @@ -171,3 +183,6 @@ MMKV に `'true'` が永続化されるだけなので、将来取得項目を 直接確認すること - テレメトリ基盤 (THQ) のホスティングリージョンと実際の保管期間は未確認で、 国外取扱いに関する記載の要否と保管期間の数値はそれ次第 +- `/api/log` が 404 になっているという記述は THQ のルータ定義から導いたもので、 + エンドポイント URL の前段にリバースプロキシが居て別サービスへ振っている可能性は + 未確認。実際のレスポンスを 1 回見れば確定する From 8e2df1ed9e8cf5d2dc4de733a1a3063a0dc809e9 Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 15 Sep 2026 13:42:14 +0000 Subject: [PATCH 04/12] =?UTF-8?q?=E3=83=AA=E3=82=B9=E3=82=AF=E8=A9=95?= =?UTF-8?q?=E4=BE=A1=E3=81=AE=E6=9C=AA=E7=A2=BA=E5=AE=9A=E3=81=AA=E8=A8=98?= =?UTF-8?q?=E8=BF=B0=E3=82=92=E5=AE=9F=E8=A3=85=E3=81=A8=E3=83=9D=E3=83=AA?= =?UTF-8?q?=E3=82=B7=E3=83=BC=E5=8E=9F=E6=96=87=E3=81=8B=E3=82=89=E7=A2=BA?= =?UTF-8?q?=E5=AE=9A=E3=81=97=E3=81=9F=E5=86=85=E5=AE=B9=E3=81=B8=E7=BD=AE?= =?UTF-8?q?=E3=81=8D=E6=8F=9B=E3=81=88?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01QzKkzvpiWBmFsBJvBTCc2Q --- docs/telemetry-production-optin-risk.md | 44 ++++++++++--------------- 1 file changed, 17 insertions(+), 27 deletions(-) diff --git a/docs/telemetry-production-optin-risk.md b/docs/telemetry-production-optin-risk.md index 2021cd9ab..c9c8d1203 100644 --- a/docs/telemetry-production-optin-risk.md +++ b/docs/telemetry-production-optin-risk.md @@ -40,9 +40,9 @@ isTelemetryEnabledByBuild = isDevApp && ENABLE_EXPERIMENTAL_TELEMETRY === 'true' ただし後者は**受け口が無い**。THQ (`TrainLCD/THQ`) のルータに定義されているルートは `/`、`/ws`、`/healthz`、`/graphql` の 4 つだけで、`/api/log` は存在しない (`src/server.rs`)。クライアント側はカスケードエラーを防ぐため送信失敗を握り潰すので、 -404 が返っていても誰も気づかない。つまりコンソールログは現状、送信しているつもりで -全て捨てられている可能性が高い。上の表はコードが送ろうとしている内容であって、 -実際に基盤へ届いている内容ではない。基盤側の方針決めは TrainLCD/THQ#38。 +404 が返っていても誰も気づかない。コンソールログは送っているつもりで捨てられている。 +上の表はコードが送ろうとしている内容であって、実際に基盤へ届いている内容ではない。 +基盤側の方針決めは TrainLCD/THQ#38。 ### 同意文言と取得範囲のズレ @@ -57,7 +57,8 @@ isTelemetryEnabledByBuild = isDevApp && ENABLE_EXPERIMENTAL_TELEMETRY === 'true' 現行ポリシー (`https://trainlcd.app/privacy-policy` / 最終更新 令和 8 年 8 月 13 日) には、本番テレメトリと正面から矛盾する記述が 2 つある。 -1. **「位置情報はサーバー上に保管されることはありません」** +1. **「取得した位置情報は、駅の判定のために一時的に TinyKitten の管理するサーバーへ + 送信されますが、サーバー上に保管されることはありません。」** 本番テレメトリは位置ログを解析基盤に永続化して集計するのが目的なので、この 一文はそのままでは事実に反する。「解析目的で送信された位置情報は、利用者が 明示的に有効化した場合に限り N 日間保管される」という趣旨へ書き換える。 @@ -78,13 +79,11 @@ isTelemetryEnabledByBuild = isDevApp && ENABLE_EXPERIMENTAL_TELEMETRY === 'true' - 保管期間の明示: 現状は「一定の期間」で数値が無い。位置ログは日数を切る - オプトアウト導線: 「端末の設定から停止できる」だけでなく、アプリ内設定から 個別に無効化できることを明記する -- 外部サービス: テレメトリ基盤 (THQ) の記載が無い。国外で取り扱う場合は次の 2 つを - 分けて扱う - - 個人情報保護法 28 条は「外国にある第三者への提供」の規定で、同意取得または - 所定の情報提供を求める。THQ を自前で運用していて第三者提供に当たらないなら - 適用されない。委託・第三者提供のどちらに当たるかは契約形態の確認が要る - - 外国で取り扱う場合の「外的環境の把握」は 28 条ではなく安全管理措置の要件で、 - 提供形態に関わらず、所在リージョンを把握したうえで公表内容へ反映する +- 保管先: テレメトリ基盤 (THQ) の記載が無い。THQ は TinyKitten が管理する国内の + サーバで動き、Cloudflare 経由で公開している。保管も国内で完結し、第三者への + 提供も無いので、外国にある第三者への提供 (個人情報保護法 28 条) と、外国で + 取り扱う場合の「外的環境の把握」(安全管理措置) はどちらも論点にならない。 + 経路に入る Cloudflare は現行ポリシーが既に外部サービスとして記載している - 開示・削除請求への応答方針: 後述のとおり、特定可能性の評価と手順の決めが要る ## コード側で先に直すべき 3 点 @@ -101,9 +100,9 @@ JWT は素通りする。 ため、本番ログと canary ログが基盤側で区別できない。 なお前述のとおり、その `/api/log` は THQ に存在しない。**今は漏れていないが、 -リスクが消えているわけではない**: 受け口を作った瞬間、あるいは前段に振り先を -用意した瞬間に、上記の内容が無制御で流れ出す。本番へ出す前に、コンソール経路を -`sendLogEvent` へ寄せるか、経路ごと落とすかを決めておく。 +リスクが消えているわけではない**: 受け口を作った瞬間に上記の内容が無制御で流れ出す。 +本番へ出す前に、コンソール経路を `sendLogEvent` へ寄せるか、経路ごと落とすかを +決めておく。 対応は、本番では `FxConsoleTelemetry` (`src/screens/Main.tsx`) をマウントしない。 出すなら `warn` / `error` 限定かつ送信元を許可リストで絞る作りに変えてから。 @@ -153,7 +152,10 @@ TrainLCD/THQ#37 に起票済み。 ### コストと電池 1 秒 1 リクエストで、バッチングもリトライ制御も無い。30 分乗車で 1 ユーザーあたり -1,800 リクエスト。canary の母数では問題にならなかった数字が、本番の DAU では桁が +1,800 リクエスト。送信は画面を見ている間に限らない。`index.js` の `TaskManager` +タスクが `handleTrackingLocation` 経由で `locationAtom` を更新し、 +`FxTelemetrySender` がそれを購読しているため、バックグラウンド測位が動いている +あいだは測位のたびに送信が続く。canary の母数では問題にならなかった数字が、本番の DAU では桁が 変わる。本番はサンプリング (対象ユーザーの N 分の 1) か送信間隔の緩和 (5〜10 秒) が現実的。省電力測位モードの効果を毎秒の通信で部分的に打ち消す点も検討が要る。 @@ -174,15 +176,3 @@ MMKV に `'true'` が永続化されるだけなので、将来取得項目を プライバシーポリシーはこの「位置イベントのみ」の範囲で書き換え、取得項目を 増やすときに改めて改定する。 - -## 未確認事項 - -- バックグラウンド測位中も JS が動いている間は送信が継続するはず。「アプリを - 閉じている間も送られている」状態になっていないかは実機での確認が要る -- 本文中のポリシー引用は公開ページの取得結果に基づく。改定作業では原文の文言を - 直接確認すること -- テレメトリ基盤 (THQ) のホスティングリージョンと実際の保管期間は未確認で、 - 国外取扱いに関する記載の要否と保管期間の数値はそれ次第 -- `/api/log` が 404 になっているという記述は THQ のルータ定義から導いたもので、 - エンドポイント URL の前段にリバースプロキシが居て別サービスへ振っている可能性は - 未確認。実際のレスポンスを 1 回見れば確定する From 3e7c3aeac49020688566a40dad3a5b414676bc11 Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 15 Sep 2026 13:44:40 +0000 Subject: [PATCH 05/12] =?UTF-8?q?=E3=83=AA=E3=82=B9=E3=82=AF=E8=A9=95?= =?UTF-8?q?=E4=BE=A1=E3=81=8B=E3=82=89=E8=A3=8F=E4=BB=98=E3=81=91=E3=81=AE?= =?UTF-8?q?=E7=84=A1=E3=81=84=E8=A8=98=E8=BF=B0=E3=82=92=E5=A4=96=E3=81=97?= =?UTF-8?q?=E3=80=81=E3=83=93=E3=83=AB=E3=83=89=E8=A8=AD=E5=AE=9A=E3=81=8B?= =?UTF-8?q?=E3=82=89=E7=A2=BA=E8=AA=8D=E3=81=A7=E3=81=8D=E3=82=8B=E4=BA=8B?= =?UTF-8?q?=E5=AE=9F=E3=81=AB=E6=8F=83=E3=81=88=E3=82=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01QzKkzvpiWBmFsBJvBTCc2Q --- docs/telemetry-production-optin-risk.md | 35 ++++++++++++++----------- 1 file changed, 20 insertions(+), 15 deletions(-) diff --git a/docs/telemetry-production-optin-risk.md b/docs/telemetry-production-optin-risk.md index c9c8d1203..cd808b1e6 100644 --- a/docs/telemetry-production-optin-risk.md +++ b/docs/telemetry-production-optin-risk.md @@ -90,11 +90,14 @@ isTelemetryEnabledByBuild = isDevApp && ENABLE_EXPERIMENTAL_TELEMETRY === 'true' ### 1. コンソールテレメトリは本番に出さない -`useConsoleTelemetry` は `console.*` を丸ごと横取りして送るため、サードパーティ製 -ライブラリのエラー、ディープリンク URL、ユーザー入力を含む例外メッセージが、 -何が入るか分からないまま送信される。`sanitizeTelemetryMessage` の防御は正規表現 -4 本 (`src/utils/sanitizeTelemetryMessage.ts`) で、キー名が想定外の秘密情報や生の -JWT は素通りする。 +`useConsoleTelemetry` は `console.*` を横取りして送る。`babel.config.js` は +production 環境のビルドで `transform-remove-console` を有効にし、`warn` / `error` +以外の `console.*` を除去するので、本番ビルドでこの経路に乗るのは警告とエラーに +なる。それでもサードパーティ製ライブラリのエラーや、ディープリンク URL・ユーザー +入力を含む例外メッセージは `console.error` で出るため、何が入るかは制御できない。 +`sanitizeTelemetryMessage` の防御は正規表現 4 本 +(`src/utils/sanitizeTelemetryMessage.ts`) で、キー名が想定外の秘密情報や生の JWT は +素通りする。 加えて `/api/log` への送信ペイロードには `channel` も `sessionId` も入っていない ため、本番ログと canary ログが基盤側で区別できない。 @@ -109,10 +112,12 @@ JWT は素通りする。 ### 2. 静的 Bearer トークンをやめる -`EXPERIMENTAL_TELEMETRY_TOKEN` は react-native-dotenv でバンドルへインライン展開 -されるので、IPA / APK から抽出できる。canary は配布先が限られるため許容できて -いたが、本番は公開配布であり、偽の位置イベントを無制限に流し込める。データ汚染と -コスト攻撃が成立する。 +`EXPERIMENTAL_TELEMETRY_TOKEN` は Babel プラグイン (`babel.config.js` の +`module:react-native-dotenv`) がビルド時に値へ置き換えるので、トークンはバンドルの +中身そのものになる。canary は配布先が限られるため許容できていたが、本番は公開配布 +なので、アプリを入手した第三者は正規クライアントと同じ資格情報を持つことになる。 +書き込み権限を端末ごとに絞れないため、汚染された位置ログを後から見分ける手段も +無い。 `src/lib/session.ts` に installId を短期セッショントークンへ交換する仕組み (`/auth/token`) が既にあるので、これに乗せ替えるのが筋。 @@ -128,10 +133,10 @@ JWT は素通りする。 ### ストア申告 -App Store のプライバシーラベルに「Precise Location → Analytics」、Google Play の -データセーフティに「位置情報 (任意) ・診断情報」の追加申告が要る。申告漏れは -審査差し戻しや公開停止の対象になる。ATT はアプリ横断の追跡もデータブローカーへの -提供も無いので不要のはずだが、「Tracking に使わない」という前提を崩さないこと。 +App Store のプライバシーラベルと Google Play のデータセーフティは、アプリが実際に +収集する内容と一致している必要がある。位置情報を解析目的で収集する状態になるので、 +申告内容を見直す。ATT が必要かどうかは「アプリ横断の追跡に使うか」「データブローカー +へ提供するか」で決まるため、そこを広げない設計を前提にする。 ### 開示・削除請求への対応方針 @@ -151,8 +156,8 @@ TrainLCD/THQ#37 に起票済み。 ### コストと電池 -1 秒 1 リクエストで、バッチングもリトライ制御も無い。30 分乗車で 1 ユーザーあたり -1,800 リクエスト。送信は画面を見ている間に限らない。`index.js` の `TaskManager` +送信はスロットルで最大 1 秒 1 リクエストに制限されるだけで、バッチングもリトライ +制御も無い。毎秒の測位が続けば 30 分乗車で 1 ユーザーあたり 1,800 リクエストになる。送信は画面を見ている間に限らない。`index.js` の `TaskManager` タスクが `handleTrackingLocation` 経由で `locationAtom` を更新し、 `FxTelemetrySender` がそれを購読しているため、バックグラウンド測位が動いている あいだは測位のたびに送信が続く。canary の母数では問題にならなかった数字が、本番の DAU では桁が From 4bde5de2b73f69c18d99f20b344a788b4ab40fb4 Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 15 Sep 2026 13:46:12 +0000 Subject: [PATCH 06/12] =?UTF-8?q?=E3=82=B3=E3=83=B3=E3=82=BD=E3=83=BC?= =?UTF-8?q?=E3=83=AB=E7=B5=8C=E8=B7=AF=E3=81=AE=E8=A8=98=E8=BF=B0=E3=82=92?= =?UTF-8?q?=E3=83=AB=E3=83=BC=E3=82=BF=E5=AE=9A=E7=BE=A9=E3=81=8B=E3=82=89?= =?UTF-8?q?=E8=A8=80=E3=81=88=E3=82=8B=E7=AF=84=E5=9B=B2=E3=81=AB=E9=99=90?= =?UTF-8?q?=E5=AE=9A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01QzKkzvpiWBmFsBJvBTCc2Q --- docs/telemetry-production-optin-risk.md | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/docs/telemetry-production-optin-risk.md b/docs/telemetry-production-optin-risk.md index cd808b1e6..e3027fadc 100644 --- a/docs/telemetry-production-optin-risk.md +++ b/docs/telemetry-production-optin-risk.md @@ -37,12 +37,12 @@ isTelemetryEnabledByBuild = isDevApp && ENABLE_EXPERIMENTAL_TELEMETRY === 'true' 送信先はいずれも `EXPERIMENTAL_TELEMETRY_ENDPOINT_URL`。GraphQL ミューテーション (`/graphql`) と、コンソールテレメトリだけが使う REST (`/api/log`) の 2 系統がある。 -ただし後者は**受け口が無い**。THQ (`TrainLCD/THQ`) のルータに定義されているルートは -`/`、`/ws`、`/healthz`、`/graphql` の 4 つだけで、`/api/log` は存在しない -(`src/server.rs`)。クライアント側はカスケードエラーを防ぐため送信失敗を握り潰すので、 -404 が返っていても誰も気づかない。コンソールログは送っているつもりで捨てられている。 -上の表はコードが送ろうとしている内容であって、実際に基盤へ届いている内容ではない。 -基盤側の方針決めは TrainLCD/THQ#38。 +ただし後者には対応するルートが無い。THQ (`TrainLCD/THQ`) のルータに定義されて +いるのは `/`、`/ws`、`/healthz`、`/graphql` の 4 つで、`/api/log` は含まれない +(`src/server.rs`)。GraphQL 側には同じ役割の `sendLogEvent` があり、そちらは +`sessionId` / `appVersion` / `platform` / `channel` も受け取れる。クライアント側は +カスケードエラーを防ぐため送信結果を見ないので、この不一致はアプリ側からは +分からない。どちらへ寄せるかの方針決めは TrainLCD/THQ#38。 ### 同意文言と取得範囲のズレ @@ -102,10 +102,9 @@ production 環境のビルドで `transform-remove-console` を有効にし、`w 加えて `/api/log` への送信ペイロードには `channel` も `sessionId` も入っていない ため、本番ログと canary ログが基盤側で区別できない。 -なお前述のとおり、その `/api/log` は THQ に存在しない。**今は漏れていないが、 -リスクが消えているわけではない**: 受け口を作った瞬間に上記の内容が無制御で流れ出す。 -本番へ出す前に、コンソール経路を `sendLogEvent` へ寄せるか、経路ごと落とすかを -決めておく。 +前述のとおり、この経路の送信先 `/api/log` は THQ のルータに無い。受け口を用意すれば +上記の内容がそのまま流れ込むので、本番へ出す前にコンソール経路を `sendLogEvent` へ +寄せるか、経路ごと落とすかを決めておく。 対応は、本番では `FxConsoleTelemetry` (`src/screens/Main.tsx`) をマウントしない。 出すなら `warn` / `error` 限定かつ送信元を許可リストで絞る作りに変えてから。 From 182ab1e1bcee75b0fcbb37844fef623c7e021223 Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 15 Sep 2026 13:52:28 +0000 Subject: [PATCH 07/12] =?UTF-8?q?=E5=85=AC=E9=96=8B=E7=89=A9=E3=81=AB?= =?UTF-8?q?=E6=9B=B8=E3=81=84=E3=81=A6=E3=82=88=E3=81=84=E6=A0=B9=E6=8B=A0?= =?UTF-8?q?=E3=82=92=E5=AE=9A=E3=82=81=E3=82=8BPublishing=20gate=E3=82=92?= =?UTF-8?q?=E8=87=AA=E5=8B=95=E5=8C=96=E3=82=A8=E3=83=BC=E3=82=B8=E3=82=A7?= =?UTF-8?q?=E3=83=B3=E3=83=88=E5=90=91=E3=81=91=E6=89=8B=E5=BC=95=E3=81=8D?= =?UTF-8?q?=E3=81=AB=E8=BF=BD=E5=8A=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01QzKkzvpiWBmFsBJvBTCc2Q --- AGENTS.md | 42 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/AGENTS.md b/AGENTS.md index 1dc2f9c88..39e8a5072 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -37,6 +37,40 @@ This handbook defines how automation agents collaborate safely and effectively o - Do not treat CI after a push as a substitute for local validation before the commit or push. +### Publishing gate + +docs/・README・PR のタイトルと本文・レビュー返信・issue(他リポジトリのものを含む) +は、push や投稿をした時点で取り消せない公開物になる。TrainLCD のリポジトリは公開 +されており、書いた内容はそのまま作者の設計判断として読まれる。文を足す前に次を +満たすこと。 + +- **出典の無い主張を書かない。** 書いてよいのは、(a) リポジトリのコードや設定 + ファイル、(b) 実際に取得した一次情報(公開ページの原文、仕様書)、(c) メンテナの + 回答、のいずれかに辿れる内容だけ。辿れないものは書かずにタスクスレッドで聞く。 + 記憶から書いた製品仕様・ストアの審査要件・条文の要旨は、原文を当たるまでは + 出典の無い主張として扱う。 +- **「未確認」「〜かもしれない」で逃げない。** アプリ・基盤・ポリシーはいずれも + 同じメンテナのものなので、自分たちの構成が不明である旨を公開物に書くのは事実に + 反するうえ、調べていないようにしか読めない。分からないことは書かず、聞けば済む。 + ソースから確定できるものは、聞く前に読んで確定させる。 +- **実装から言えることと、運用の結果を混同しない。** 「ルータに定義が無い」はコード + の事実、「リクエストが届いていない」は運用の結果で、前者から後者は導けない。片方 + しか確かめていないなら、確かめた方だけを書く。仮説を立てて別リポジトリを探しに + 行く前に、確定済みの事実で足りるかを見直す。 +- **引用は一次情報から取る。** 日付・条文・公開文書の文言は、要約ではなく原文を + 当たる。要約ツールの出力をそのまま引用として貼らない。 +- **メンテナに質問中の事項は公開しない。** 確認を出したなら、その答えに依存する + 記述は回答を得るまで書かない。質問と並行して公開すると、回答前に誤りが出回る。 +- **運用上の秘匿情報は粒度を落とす。** サーバの設置場所やネットワーク構成など、 + 目的に対して不要な粒度は書かない。公開済みのプライバシーポリシーと同じ粒度に + 留める。 +- **レビューボットの指摘も検証してから従う。** 指摘が誤っていることもある。原文や + コードで裏を取り、違う対応を採るならその理由を返信に書く。裏取りをせずに指摘の + 文面をそのまま本文へ反映しない。 + +公開済みの文に誤りや裏付けの無い記述を見つけたら、質問の回答を待たずにまず当該 +記述を削除・修正して push する。 + ## Repository Map - `src/`: Expo React Native app code. @@ -166,6 +200,14 @@ This repository is managed with **Git**, and agents drive version control throug - [ ] Update cross-references (README, docs/) to prevent drift. - [ ] Spell-check or self-review for clarity and typos. +**Before publishing prose (docs, PR body, review replies, issues)** + +- [ ] Every claim traces to repository code, a primary source you fetched, or a maintainer answer. +- [ ] No "未確認" / "かもしれない" hedges about our own app, backend, or policy; unknowns are questions, not sentences. +- [ ] Code-level facts and runtime outcomes are not conflated. +- [ ] Quotes come from the original text, not from a summary. +- [ ] Nothing depends on a question you have asked and not yet had answered. + **For workflow, release, or CI updates** - [ ] Cross-check `.github/workflows/` for consistency. From 282c9f8ea3fbaab7a846e0815586277935439993 Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 15 Sep 2026 13:53:39 +0000 Subject: [PATCH 08/12] =?UTF-8?q?=E3=82=B9=E3=83=AD=E3=83=83=E3=83=88?= =?UTF-8?q?=E3=83=AB=E3=81=8C=E4=BD=8D=E7=BD=AE=E9=80=81=E4=BF=A1=E3=81=AE?= =?UTF-8?q?=E3=81=BF=E3=81=AB=E5=8A=B9=E3=81=8F=E3=81=93=E3=81=A8=E3=82=92?= =?UTF-8?q?=E3=83=AA=E3=82=B9=E3=82=AF=E8=A9=95=E4=BE=A1=E3=81=AB=E6=98=8E?= =?UTF-8?q?=E8=A8=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01QzKkzvpiWBmFsBJvBTCc2Q --- docs/telemetry-production-optin-risk.md | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/docs/telemetry-production-optin-risk.md b/docs/telemetry-production-optin-risk.md index e3027fadc..9316b5d92 100644 --- a/docs/telemetry-production-optin-risk.md +++ b/docs/telemetry-production-optin-risk.md @@ -155,8 +155,11 @@ TrainLCD/THQ#37 に起票済み。 ### コストと電池 -送信はスロットルで最大 1 秒 1 リクエストに制限されるだけで、バッチングもリトライ -制御も無い。毎秒の測位が続けば 30 分乗車で 1 ユーザーあたり 1,800 リクエストになる。送信は画面を見ている間に限らない。`index.js` の `TaskManager` +スロットル (`TELEMETRY_THROTTLE_MS`) が効くのは `sendLocation` だけで、最大 1 秒 1 +リクエストに制限されるものの、バッチングもリトライ制御も無い。毎秒の測位が続けば +30 分乗車で 1 ユーザーあたり 1,800 リクエストになる。他の経路はこの制限の外にあり、 +`sendLogEvent` / `sendInteractionEvent` は呼ばれるたびに送信し、コンソール経路は +5 秒ごとのフラッシュでキューに溜まったログ 1 件につき 1 リクエストを出す。送信は画面を見ている間に限らない。`index.js` の `TaskManager` タスクが `handleTrackingLocation` 経由で `locationAtom` を更新し、 `FxTelemetrySender` がそれを購読しているため、バックグラウンド測位が動いている あいだは測位のたびに送信が続く。canary の母数では問題にならなかった数字が、本番の DAU では桁が From 77d16291247a23d176ca0435f69a5ce663e3c52d Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 15 Sep 2026 13:55:18 +0000 Subject: [PATCH 09/12] =?UTF-8?q?=E5=85=AC=E9=96=8B=E6=B8=88=E3=81=BF?= =?UTF-8?q?=E3=81=AE=E8=A8=98=E8=BF=B0=E3=81=AE=E8=A8=82=E6=AD=A3=E3=81=AF?= =?UTF-8?q?=E8=87=AA=E5=B7=B1=E5=88=A4=E6=96=AD=E3=81=A7=E3=81=AF=E3=81=AA?= =?UTF-8?q?=E3=81=8F=E5=A0=B1=E5=91=8A=E3=81=A8=E6=8C=87=E7=A4=BA=E3=82=92?= =?UTF-8?q?=E7=B5=8C=E3=82=8B=E8=A6=8F=E5=89=87=E3=81=B8=E4=BF=AE=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01QzKkzvpiWBmFsBJvBTCc2Q --- AGENTS.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index 39e8a5072..ffbf5f095 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -68,8 +68,10 @@ docs/・README・PR のタイトルと本文・レビュー返信・issue(他 コードで裏を取り、違う対応を採るならその理由を返信に書く。裏取りをせずに指摘の 文面をそのまま本文へ反映しない。 -公開済みの文に誤りや裏付けの無い記述を見つけたら、質問の回答を待たずにまず当該 -記述を削除・修正して push する。 +公開済みの文に誤りや裏付けの無い記述を見つけたら、直すより先にタスクスレッドで +報告する。どの記述が・なぜ問題で・どう直すつもりかを示し、メンテナの指示を得てから +push する。自分の判断で書き換えて push しない。誤りに気づいてから公開が止まるまでの +時間は、勝手に直す速さではなく、報告の速さで縮める。 ## Repository Map From 050fb21d683b444d5886043dc9a3991a4d7973f4 Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 15 Sep 2026 14:27:38 +0000 Subject: [PATCH 10/12] =?UTF-8?q?=E5=85=AC=E9=96=8B=E6=B8=88=E3=81=BF?= =?UTF-8?q?=E3=81=AE=E8=A8=98=E8=BF=B0=E3=82=92=E8=A8=82=E6=AD=A3=E3=81=99?= =?UTF-8?q?=E3=82=8B=E9=9A=9B=E3=81=AE=E6=89=BF=E8=AA=8D=E5=AF=BE=E8=B1=A1?= =?UTF-8?q?=E3=82=92push=E4=BB=A5=E5=A4=96=E3=81=AE=E5=85=AC=E9=96=8B?= =?UTF-8?q?=E6=93=8D=E4=BD=9C=E3=81=AB=E3=82=82=E5=BA=83=E3=81=92=E3=82=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01QzKkzvpiWBmFsBJvBTCc2Q --- AGENTS.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index ffbf5f095..5c97f2f0f 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -69,9 +69,10 @@ docs/・README・PR のタイトルと本文・レビュー返信・issue(他 文面をそのまま本文へ反映しない。 公開済みの文に誤りや裏付けの無い記述を見つけたら、直すより先にタスクスレッドで -報告する。どの記述が・なぜ問題で・どう直すつもりかを示し、メンテナの指示を得てから -push する。自分の判断で書き換えて push しない。誤りに気づいてから公開が止まるまでの -時間は、勝手に直す速さではなく、報告の速さで縮める。 +報告する。どの記述が・なぜ問題で・どう直すつもりかを示し、メンテナの指示を得てから、 +push・PR 本文の編集・Issue の編集・訂正コメントやレビュー返信の投稿など、訂正内容を +公開する操作を行う。自分の判断で訂正内容を公開しない。誤りに気づいてから公開が +止まるまでの時間は、勝手に直す速さではなく、報告の速さで縮める。 ## Repository Map From 755e535a6856a317497fc8868987910d047c1e40 Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 15 Sep 2026 14:29:08 +0000 Subject: [PATCH 11/12] =?UTF-8?q?=E8=A8=82=E6=AD=A3=E3=81=AE=E9=80=9F?= =?UTF-8?q?=E3=81=95=E3=82=92=E4=B8=80=E5=BE=8B=E3=81=AB=E6=B1=82=E3=82=81?= =?UTF-8?q?=E3=82=8B=E8=A8=98=E8=BF=B0=E3=82=92=E5=89=8A=E9=99=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01QzKkzvpiWBmFsBJvBTCc2Q --- AGENTS.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index 5c97f2f0f..8c8bbd7be 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -71,8 +71,7 @@ docs/・README・PR のタイトルと本文・レビュー返信・issue(他 公開済みの文に誤りや裏付けの無い記述を見つけたら、直すより先にタスクスレッドで 報告する。どの記述が・なぜ問題で・どう直すつもりかを示し、メンテナの指示を得てから、 push・PR 本文の編集・Issue の編集・訂正コメントやレビュー返信の投稿など、訂正内容を -公開する操作を行う。自分の判断で訂正内容を公開しない。誤りに気づいてから公開が -止まるまでの時間は、勝手に直す速さではなく、報告の速さで縮める。 +公開する操作を行う。自分の判断で訂正内容を公開しない。 ## Repository Map From 10788b4af1ae38042d6da241f868621f7f240d17 Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 15 Sep 2026 14:30:50 +0000 Subject: [PATCH 12/12] =?UTF-8?q?AGENTS.md=E3=81=AE=E5=A4=89=E6=9B=B4?= =?UTF-8?q?=E3=82=92=E5=88=A5PR=E3=81=B8=E5=88=86=E9=9B=A2=E3=81=99?= =?UTF-8?q?=E3=82=8B=E3=81=9F=E3=82=81=E3=81=93=E3=81=AE=E3=83=96=E3=83=A9?= =?UTF-8?q?=E3=83=B3=E3=83=81=E3=81=8B=E3=82=89=E5=8F=96=E3=82=8A=E9=99=A4?= =?UTF-8?q?=E3=81=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01QzKkzvpiWBmFsBJvBTCc2Q --- AGENTS.md | 44 -------------------------------------------- 1 file changed, 44 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index 8c8bbd7be..1dc2f9c88 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -37,42 +37,6 @@ This handbook defines how automation agents collaborate safely and effectively o - Do not treat CI after a push as a substitute for local validation before the commit or push. -### Publishing gate - -docs/・README・PR のタイトルと本文・レビュー返信・issue(他リポジトリのものを含む) -は、push や投稿をした時点で取り消せない公開物になる。TrainLCD のリポジトリは公開 -されており、書いた内容はそのまま作者の設計判断として読まれる。文を足す前に次を -満たすこと。 - -- **出典の無い主張を書かない。** 書いてよいのは、(a) リポジトリのコードや設定 - ファイル、(b) 実際に取得した一次情報(公開ページの原文、仕様書)、(c) メンテナの - 回答、のいずれかに辿れる内容だけ。辿れないものは書かずにタスクスレッドで聞く。 - 記憶から書いた製品仕様・ストアの審査要件・条文の要旨は、原文を当たるまでは - 出典の無い主張として扱う。 -- **「未確認」「〜かもしれない」で逃げない。** アプリ・基盤・ポリシーはいずれも - 同じメンテナのものなので、自分たちの構成が不明である旨を公開物に書くのは事実に - 反するうえ、調べていないようにしか読めない。分からないことは書かず、聞けば済む。 - ソースから確定できるものは、聞く前に読んで確定させる。 -- **実装から言えることと、運用の結果を混同しない。** 「ルータに定義が無い」はコード - の事実、「リクエストが届いていない」は運用の結果で、前者から後者は導けない。片方 - しか確かめていないなら、確かめた方だけを書く。仮説を立てて別リポジトリを探しに - 行く前に、確定済みの事実で足りるかを見直す。 -- **引用は一次情報から取る。** 日付・条文・公開文書の文言は、要約ではなく原文を - 当たる。要約ツールの出力をそのまま引用として貼らない。 -- **メンテナに質問中の事項は公開しない。** 確認を出したなら、その答えに依存する - 記述は回答を得るまで書かない。質問と並行して公開すると、回答前に誤りが出回る。 -- **運用上の秘匿情報は粒度を落とす。** サーバの設置場所やネットワーク構成など、 - 目的に対して不要な粒度は書かない。公開済みのプライバシーポリシーと同じ粒度に - 留める。 -- **レビューボットの指摘も検証してから従う。** 指摘が誤っていることもある。原文や - コードで裏を取り、違う対応を採るならその理由を返信に書く。裏取りをせずに指摘の - 文面をそのまま本文へ反映しない。 - -公開済みの文に誤りや裏付けの無い記述を見つけたら、直すより先にタスクスレッドで -報告する。どの記述が・なぜ問題で・どう直すつもりかを示し、メンテナの指示を得てから、 -push・PR 本文の編集・Issue の編集・訂正コメントやレビュー返信の投稿など、訂正内容を -公開する操作を行う。自分の判断で訂正内容を公開しない。 - ## Repository Map - `src/`: Expo React Native app code. @@ -202,14 +166,6 @@ This repository is managed with **Git**, and agents drive version control throug - [ ] Update cross-references (README, docs/) to prevent drift. - [ ] Spell-check or self-review for clarity and typos. -**Before publishing prose (docs, PR body, review replies, issues)** - -- [ ] Every claim traces to repository code, a primary source you fetched, or a maintainer answer. -- [ ] No "未確認" / "かもしれない" hedges about our own app, backend, or policy; unknowns are questions, not sentences. -- [ ] Code-level facts and runtime outcomes are not conflated. -- [ ] Quotes come from the original text, not from a summary. -- [ ] Nothing depends on a question you have asked and not yet had answered. - **For workflow, release, or CI updates** - [ ] Cross-check `.github/workflows/` for consistency.