memory ブラウザーなら警告し、devセッションシークレットはよく知られた定数です。evaluateReadiness はそれらの警告をそれぞれ hard gate に変えます。これは起動チェックと GET /ready ルートの両方を支える単一の純粋関数であり、同じ8つのチェックが1つの信頼できる情報源から2つの利用側を駆動します。
これは Service の深い readiness probe であり、エンジンの liveness check ではありません。
/health(エンジンアプリがマウントします)は「プロセスが起動しているか」に答えます。/ready は「このデプロイが本当に本番トラフィックを処理して安全か」に答えます。Postgres が接続されていること、シークレットが永続化されていること、実認証があること、などです。同じチェックリストが2つのゲートを駆動する仕組み
起動ゲート — server.ts
起動時に、注入されたスナップショットが
production: true(JT_ENV=production)を示している場合、サーバーは evaluateReadiness を1回実行します。失敗したゲートが1つでもあると、すべての失敗をログに出し、process.exit(1) を呼び出します。つまり、プロセスは起動しません。ゲートを修正しない限り、本番タスクは docker run を越えられません。チェックリスト
これをローンチ前のランブックにコピーしてください。各行は、evaluateReadiness が実際に評価するゲートです(docs/11 §12)。
1. Browser backend が "memory" ではない
1. Browser backend が "memory" ではない
ゲート:
browserBackend === "memory"。発火条件: E2B_API_KEY と JT_LOCAL_BROWSER のどちらも設定されておらず、selectBrowserCapability がインメモリの fake にフォールバックする。何を防ぐか: 記録されたすべての Flow が実行されたように見えます。手順は完了し、抽出は値を返します。しかし、ブラウザーは一度も開かれていません。memory バックエンドでの本番デプロイは、もっともらしく見えるものの完全に fake なオートメーションを提供してしまいます。修正: E2B_API_KEY(推奨。Runごとにサンドボックス化された microVM)または JT_LOCAL_BROWSER=1(セルフホストの Chromium プール、docs/11 §3.2)を設定します。2. 実際のマスターキーまたは KMS が設定されている
2. 実際のマスターキーまたは KMS が設定されている
ゲート:
!masterKeyOrKmsConfigured。発火条件: JINBA_MASTER_KEY(64-hex)が未設定かつ JINBA_KMS_KEY_ARN が未設定で、envelope(envelope.ts)が一時的なプロセスローカルキーにフォールバックする。何を防ぐか: 一時キーで暗号化されたすべてのシークレットは、プロセスが再起動した瞬間、または2つ目のレプリカが独自のランダムキーで起動した瞬間に読めなくなります。ECS のローリングデプロイにより、顧客は保存済みのすべての資格情報から静かに締め出されます。修正: 単一インスタンスのデプロイでは、JINBA_MASTER_KEY に永続的な 64-hex 値を設定します。レプリカ間で実際のキー管理を行う場合は、JINBA_KMS_KEY_ARN(+ JINBA_KMS_ENCRYPTED_MASTER_KEY、docs/11 §5.1)を接続します。3. JT_SESSION_SECRET が dev デフォルトではない
3. JT_SESSION_SECRET が dev デフォルトではない
ゲート:
sessionSecretIsDevDefault。発火条件: JT_SESSION_SECRET が、ソースから見えるリテラル定数 "jt-dev-session-secret" のままになっている。何を防ぐか: (公開)ソースを読んだ人なら誰でも署名シークレットを知ることができ、任意のユーザーの有効なセッションクッキーを偽造できます。これは単に弱いデフォルトではなく、完全な認証バイパスです。修正: JT_SESSION_SECRET に、そのデプロイに固有のランダム値を設定します。4. Dev-session auto-issue が無効化されている
4. Dev-session auto-issue が無効化されている
ゲート:
!realAuthWired。発火条件: 認証なしで自動プロビジョニングされる devセッション(ensureDevSession)がまだ有効になっている。つまり、この環境で resolveAllowDevSession が true を返す。何を防ぐか: 保護されたルート(または GET /api/session)に到達した未認証の呼び出し元に、完全な権限を持つ owner セッションが静かに渡されます。タブを開いた人は誰でも、ログインなしで組織全体にアクセスできます。修正: デプロイされた任意の JT_ENV では、JT_DEV_AUTH を未設定のままにします(かつ JT_DISABLE_DEV_SESSION も未設定にします)。resolveAllowDevSession は、明示的に設定された dev / test / ci 以外の JT_ENV を、すでにデフォルトで OFF として扱います。JT_DEV_AUTH=true は明示的な escape hatch です。公開デプロイでは決して設定してはいけません。5. wrapper store が Postgres として解決されている
5. wrapper store が Postgres として解決されている
ゲート: 修正:
wrapperStore !== "postgres"。発火条件: JT_DATABASE_URL / DATABASE_URL が未設定(または使える場所を指していない)で、buildServiceDeps がオンディスク SQLite にフォールバックする。何を防ぐか: SQLite は単一ノードで、タスクの一時ファイルシステム上に存在します。ECS タスクの置き換え(デプロイ、スポット中断、autoscale-in)により、他の場所に存在しないすべてのオートメーション、デプロイ記録、監査ログ行が失われます。これは1を含む任意のレプリカ数で hard gate です。単一の本番レプリカであっても、再起動時にすべてのメタデータを失ってはいけません。このゲートが報告するのは、URL 環境変数が設定されているかどうかだけではなく、composition root が実際に構築した store です。到達できないホストを指す
DATABASE_URL があり、静かにフォールスルーした場合でも、このゲートは発火します。wrapperStoreKind は buildServiceDeps が実際に構築したものを反映するためです。JT_DATABASE_URL(または DATABASE_URL)を RDS Postgres に向けます(docs/11 §4.1)。6. §6 のギャップを閉じないまま Replicas が >1 になっていない
6. §6 のギャップを閉じないまま Replicas が >1 になっていない
ゲート:
replicaCount > 1 && !multiReplicaGapsClosed。replicaCount <= 1 では不活性です。単一インスタンスには、自身と不一致を起こすレプリカ間状態がありません。multiReplicaGapsClosed が true になるのは、docs/11 §6 の単一プロセスギャップのうち、3つすべてが閉じられている場合だけです。- 共有 Redis rate limiter / pub-sub relay(
JT_REDIS_URL/REDIS_URL)、 - スケジュール発火元がローカル croner ではなく、署名付き EventBridge tick であること(
JT_INTERNAL_TICK_SECRET)、 - エンジン store(runs/journal)もプロセスごとの SQLite ではなく Postgres であること(
BROWSERFLOW_DATABASE_URL/DATABASE_URL)。
api_desired_count を1より大きくする前に、Redis、署名付き tick エンドポイント、Postgres のエンジン store を接続します。そのうえで、JT_REPLICA_COUNT を一致するよう設定します。7. E2B capability.close() が接続されている
7. E2B capability.close() が接続されている
ゲート:
browserBackend === "e2b" && !e2bCloseWired。E2B がアクティブなバックエンドの場合だけ評価されます。ローカル Playwright バックエンドは対象外です。何を防ぐか: 明示的に閉じられない E2B sandbox は、それを開いた Run が終了した後も課金を継続します(かつブラウザーセッションも生き続けます)。Run の量に応じて増幅するリークです。現在のソースでは、
e2bCloseWired は buildServiceDeps 内で true にハードコードされています(run gateway は現在 capability.close() を無条件に接続しており、docs/11 §3.1 が当初指摘していたギャップを閉じています)。これはもう環境変数からは読み取られません。このゲートは回帰ガードとして evaluateReadiness に残されています。将来 gateway の変更で E2B sandbox を閉じなくなったとき、静かに出荷されるのではなく、このチェックが再び発火するようにするためです。8. ALB idle timeout が SSE/WS window を満たしている
8. ALB idle timeout が SSE/WS window を満たしている
ゲート:
albIdleTimeoutSeconds < sseWindowSeconds。サービス自身の値は固定です。server.ts は Bun の idleTimeout: 255(Bun の最大値)を設定し、遅いモデルターンや human-in-the-loop の一時停止をまたいでも、オーサリング SSE と live-view WS を維持します。何を防ぐか: idle timeout が 255s より短い ALB(または任意のリバースプロキシ)は、長時間生きるオーサリング / Run ストリームを途中で切断します。ALB のデフォルト idle timeout は 60s で、この window を大きく下回ります。修正: ALB ターゲットグループの idle timeout を >= 300s に保ち(Terraform 変数の検証で強制されます)、JT_ALB_IDLE_TIMEOUT_S を同じ値に設定して、/ready が現実を反映するようにします。/ready がチェックしない docs/11 §12 の2項目
docs/11-production-deployment-aws.md §12 には10個のチェックリスト項目があります。evaluateReadiness はそのうち8個を自動化します。残り2つはこのゲートでは評価されません。環境変数ではなく、手動レビューが必要です。
- Browser tier SG can reach instance metadata / private CIDRs (SSRF) — ネットワーク / セキュリティグループのレビュー(docs/11 §8)です。サービスが自身について観測できる runtime condition ではありません。
- Any log line carries a resolved secret value — コードレビュー / テストスイート上の懸念(
assertNoSecretLeak、docs/11 §8)です。起動時スナップショットで検証できるものではありません。
関連
Service(コントロールプレーン)
/ready が守っているアーキテクチャです。API、registry、scheduler、secrets broker、run store が含まれます。マネージドシークレット
ゲート2の背後にある境界の不変条件です。なぜマスターキー / KMS ゲートが重要になる場所にシークレット値が保存されないのかを説明します。
Access control & audit
実認証(ゲート4)によって意味を持つ RBAC と監査証跡です。
可観測性
ゲート5の永続的な Postgres store に依存する Run inspector です。