インターフェースがテキストメッセージであるプロダクト
アプリをインストールしたりウェブサイトを訪問したりするのは面倒ですが、誰でもテキストは送れます。そこに魅力があります。ただし、チャネルを自分で所有しているわけではありません。米国のキャリアが所有しており、コンテンツポリシーと承認プロセスがあり、永久に拒否される可能性があります。そのゲートがプロダクトの許容範囲を決定するため、最初に取り組む必要があります。
ステップ0 — ゲート。設計の後ではなく、前に行うこと
2025年2月以降、米国のキャリアは未登録のA2Pトラフィックを完全にブロックするため、1件のメッセージを送信する前にブランドとキャンペーンの承認が必要です。毎回、最新のエラードキュメントを読み直してください。キャリアポリシーは変更されます。
| コード | トリガー | 再申請? |
|---|---|---|
| 30953 | 露骨/性的示唆のある文言、または「ポルノ、エスコート、デート、アダルトエンターテイメントコンテンツ」をホストするリンク先サイト | 不可 |
| 30885 | 「高リスク」 — 欺瞞的なマーケティング、またはトラフィックを偽って報告する登録 | 不可 |
| 30898 | 1つのEINに多すぎるブランド、または重複とみなされる登録 | 理由があれば可 |
ルール:最初の返信でプロダクトのコンテンツカテゴリを声に出して述べ、それがそのリストに載っているかどうかを言う。 カテゴリ(例:デート)が拒否ルールのキーワードそのものである場合、それを5分目で見つけると、アーキテクチャ、ランディングコピー、フォールバック計画が変わります。SHAFTは略語です:Sex(性)、Hate(憎悪)、Alcohol(アルコール)、Firearms(銃器)、Tobacco(タバコ) — さらにCannabis(大麻)、デートもこれに準じます。
ルール:サイドプロジェクトは、既存の会社のEINではなく、個人事業主(Sole Proprietor)ブランドとして登録する。 リスクパターンは税ID(30898)に従うため、サイドプロジェクトでの拒否がメインビジネスの送信能力に影響してはいけません。個人事業主は税IDのない個人を対象としており、スループットは低いですが、ベータ版には十分です。
ルール:キャンペーン承認を得るために偽のランディングページを作成してはいけない。 実際のトラフィックを隠すページはまさに30885のパターンであり、1つの番号のリスクを、今後登録するすべての番号のリスクに変えます。確率を率直に述べ、オーナーに決定を委ねてください。
サービスを、それが機械的に何をするかによって説明する。 そしてそれが真実である場合に限ります(例:ジャーナリングと小グループの説明責任、それがメッセージの内容である場合)。真実の説明がゲートを通らない場合、答えはより良い婉曲表現ではなく、異なるチャネルです。
審査では、指摘できる事実が報われます:受信のみのオプトイン、会話量、繰り返しメッセージ内のリンクなし、すべてに先立つSTOP処理、入り口での露骨なコンテンツ拒否。
ステップ0.5 — ブリーフを意図ではなく「数字」と「オブジェクト」として読む
創業者のブリーフをそのままREADME.mdとして保持し、CLAUDE.mdにそれがすべてのエンジニアリングドキュメントよりも優先されると記載する。
ルール:ステートマシンを書く前に、ブリーフ内のすべての期間と、それが作用するすべての名詞をリストアップする。2つの期間が存在する場合、それらは2つの機能である。 「友達の返信が作者に届くまでの1週間の遅延」と「作者自身の更新に関する2週間のロック」というブリーフは、「エントリ」に対する1つの7日間保留に簡単に統合できます — どちらの遅延も対象としていなかった1つのオブジェクト — そして、その統合からすべての下流のエラーが発生します。
ルール:すべての遅延のオブジェクトに名前を付ける — 「誰から保留されているか」。 友達から保留されているのと、作者から保留されているのは、正反対のプロダクトです。
ルール:ブリーフの文字通りの設計をチャネルで強制できない場合、その旨を述べ、代替案を示す。強制できる方を黙って選んではいけない。 (グループチャットの作成者はそのメンバーでもあるため、どのコードもグループの返信を彼らから差し控えることはできません。)これは前提の決定であり、前提の決定はオーナーのものです。
一貫性のある誤読は、誤読のように感じられない。 置き換えられた設計段落を取り消し線付きでそのまま残し、削除しない。後のセッションに、ブリーフがどのように誤読されたかを示します。
ステップ1 — チャネルでできることとできないこと
- コードからのグループテキストは機能します。 Twilio Conversationsは、+1ロングコードのみでグループMMSをサポートします — フリーダイヤルやショートコードは不可 — 最大自分自身の番号を含む10人の参加者まで。記憶に基づいて別の主張をしないでください。
- グループMMS SMS参加者はAddressを持ち、ProxyAddressはありません。そのため、1つの番号ですべてのルームにサービスを提供できますが、参加者/プロキシの一意性ルール(50425)には、プロキシなしの参加者に対する文書化された動作がありません。1つの番号と1つの参加者セットを共有する多数の同時ルームを決して設計しないでください。 1人につき1つの永続的なルームは、安定した参加者セットを持ちます。
- WebページはiPhoneのアドレス帳を読めません。 Contact Picker APIはChrome on Androidのみです。「連絡先を同期」は機能しません。代わりに、ユーザーが転送する行を用意します — 受信者の受信テキストが、キャリアが求める同意記録になります。
- Telegramボットはグループを作成したり、誰かをグループに追加したりできません。 また、プライバシーモードがオンの場合、自分宛てのコマンドのみを認識します。どちらも役に立ちます:作成者はすでに存在するチャットにボットを追加し、一般的な雑談が入力と誤認されることはありません。ボットの作成には@BotFatherで人間の操作が必要です(APIはありません)。トークンを要求してください。
- WhatsApp Cloud APIにはグループメッセージング機能はありません。
- iMessage API(Sendblue、LoopMessage)は青いバブルと実際のグループチャットを提供しますが、回線あたり月額約100ドルと初期費用がかかります。
ステップ2 — チャネル喪失に耐えるアーキテクチャ
チャネルは拒否される可能性があるため、トランスポートは1つのファイルでなければなりません:
machine.js 純粋関数: (context, event) -> {replies, effects} I/Oなし、クロックなし
engine.js コンテキストのアセンブリ -> machine -> effects パス全体
effects.js createEffects({db, channel}) 決定を実行
twilio.js / telegram.js 交換可能
api/*.js engine.js へのシンラッパー 約10行
sim/ インメモリDB + コンソールチャネル
- 決定コアは
nowを引数として受け取り、ネットワークに触れない。 このクラスのプロダクトのバグはすべてシーケンスバグです(2回起動するリマインダー、空のルームへのメッセージ、届かない保留アイテム)。そして、それらはライブネットワークと7日間のタイマーに対してテストできません。 - アダプターはエフェクトレイヤーでインポートではなく引数として渡される。 これはシミュレーターとフォールバックチャネルの両方に必要なリファクタリングです。
- HTTPハンドラー内にロジックを書かない。
api/telegram.js内にチャネル固有のオンボーディングを書くとテスト不可能です。抽出してください。
ステップ3 — テストするだけでなく、駆動する
node sim/drive.js スクリプト駆動:完全なループ、時間ジャンプ、ガード
node sim/drive.js --repl 任意の番号として入力;/as <n> /jump <days> /state
- シミュレーターはプロダクションパスを実行しなければならない。 並列コピーではダメです。
- 最初の駆動では、単体テストでは到達できないいくつかの実際の欠陥が明らかになることを想定してください:誰もいないのに自分自身にあいさつするルーム、1週間後の日付の裸の曜日、どのアイテムのことか言わないリマインダー、全員が退出したルーム。
- テストがレッドになったら、まずテストを確認する。 (
Sun, Aug 30のカンマを許可しない日付正規表現、別の正当なメッセージで発動するdoesNotMatchなど)。 - ストアがスタンプしたタイムスタンプから判断したり表示したりしない。 ストアは
created_atを実際のクロックから書き込みます。エンジンの注入されたnowからではありません。そのため、時間ジャンプ下では嘘をつき(過去の日付を表示します)。マシンが書き込んだカラムからのみ判断し、関連する日付は1つの保存アンカーにぶら下げてください。
ステップ4 — ロック画面のためのコピー
1つのファイルにすべての送信文字列を保持します。
- 絵文字なし、感嘆符なし、マーケティングなし。
- 1〜2日以上先の日付には、決して裸の曜日を使わない。
Sun Aug 30。 - すべてのキーワードで句読点と大文字小文字を許容する —
Wait.とYes!が機能しなければならない。 - キーワードを含む散文は依然として散文です:「we should wait and see」はWAITではありません。正規化されたメッセージ全体をマッチさせ、部分文字列ではマッチさせない。
- STOP / HELP / START は、すべてのアプリケーション状態とすべてのモデル呼び出しの前に解析される。 そのため、オプトアウトが他の場所のバグやAPI障害によって壊れることはありません。
- モデルがコンテンツをガードする場合、フェイルクローズする:チェックを実行できない場合、何も送信せず、その旨を伝える。
ステップ5 — モデルがユーザーコンテンツを書き換える場合、信頼する前に実行する
ユーザーエントリから第三者名を除去するガードは、完全に読めても次のことを行う可能性があります:
- 事実を作り出す — 「Jane Doe」を「自然なハンドル」に置き換えるよう指示されたとき、アプリについて何も言及されていないのに「the girl from the app」と書きました。受信者は作り話を事実として読みます。
- 過剰修正して実際の詳細を削除する — 「Jane from the run club」が「her」になりました。
ルール:指示は、モデルが何を発明してはいけないか、何を削除してはいけないかを述べなければならない。 機能する形式:置換をソースに基づかせ、フレーズ全体ではなくトークンを置換し、文がすでに述べている詳細を再利用するよりも中立的なフォールバックを優先する。
ルール:各ライブモデルの欠陥をオプトインテストとして固定し、APIキーなしではスキップする。 これにより、プロンプト編集がすべてのテスト実行でコストを増大させることなく、黙って後退することを防ぎます。ガード呼び出しごとに2〜5秒を見積もってください。
コスト(桁は概算。ライブで確認すること)
+1ロングコードは月額1〜2ドル。SMSは1セグメントあたり1セント未満(双方向)。MMSは数セント。個人事業主登録は数ドルの初期費用と少額の月額キャンペーン料金。Telegramは無料。
質問する vs. 決定する
- 質問する: 永久拒否される可能性があることを承知で正直な登録を提出するか、Telegramで始めるか(費用と不可逆的な結果)。プロダクトの本質を変えるものすべて。
- 決定する: アーキテクチャ、コピーの声、ステートマシン、テストカバレッジ、最初にどのアダプターを使うか、日付形式、ガードの動作。
何かがブロックされていると報告する前に、すべての候補となる認証情報を列挙してください。 (ディスクに1つの使い果たされたAPIキーがあるからといって、別の動作するキーがないとは限りません。)
関連項目: build-remote-mcp-server(別の「ネイティブサーフェス」パターン)。