質問と出題の意図
3つのリージョンにまたがる20,000台のサーバーインスタンスで使用されるマルチテナント型フィーチャーフラグシステムを設計してください。プロジェクト全体で50,000個のフラグを保持し、1ミリ秒未満の追加p99レイテンシで毎秒500万回のインプロセス評価を処理し、公開された変更をp99で5秒以内に伝播させ、15分間のコントロールプレーン障害中も評価を継続できるようにします。型付きバリエーション、ターゲティング、決定論的なパーセンテージロールアウト、監査ログ、承認フロー、緊急停止スイッチをサポートする必要があります。
提示された数値は面接用の前提条件であり、プロダクトのベンチマークではありません。各ランタイムは最大500個の関連フラグを購読し、シリアライズされたフラグ定義の平均サイズは2 KB、コントロールプレーンの書き込みピークは毎秒100回、サーバーサイドの評価ルールには機密属性が含まれる可能性があると仮定します。クライアント・モバイルへの配信、実験統計、汎用設定サービスなどは、基本要件ではなくフォローアップの範疇とします。
この質問は、シニアバックエンド、プラットフォーム、インフラストラクチャ、リリースエンジニアリング、システムデザインの面接に適しています。ここから得られる再現可能な教訓は、リクエストパスをローカルかつ高可用に保ちながら、管理パスを厳格に統制できるということです。この分離が、その後のほぼすべての設計判断を決定づけます。
面接官が評価しているポイント
第1のシグナルは、候補者がデプロイとリリース、およびコントロールプレーンとデータプレーンを明確に分離しているかです。ダッシュボードとデータベースがフラグ定義を管理します。アプリケーションSDKは、バージョン管理されたルールセットをプロセス内で評価します。フラグチェックのたびにリモートRPCを実行すると、管理系の障害やネットワークレイテンシがすべてのプロダクトリクエストに影響を及ぼしてしまいます。
第2のシグナルは、セマンティクスの正確さです。フラグの評価には、フラグキー、環境、型付きフォールバック、評価コンテキストが必要です。順序付きルール、明示的なターゲット、パーセンテージ割り当て、デフォルトルールには決定論的な優先順位がなければなりません。「リクエストの10%にランダムに機能を付与する」という設計は、ユーザーがリクエストやリージョンをまたいで安定した体験を得る必要がある場合には誤りです。
第3のシグナルは、障害時の設計です。ラストノウングッド(last-known-good:直近の正常な状態)を維持することでコントロールプレーン障害時も評価を継続できますが、古い(staleな)設定を使い続けるリスクも明示的に伴います。優れた回答では、起動時の挙動、許容される最大の古さ(staleness)、ギャップの修復、無効な更新の拒絶、緊急停止時の挙動、表示変更と危険な書き込みパスでのデフォルト値の違いなどが定義されます。
第4のシグナルは、運用上の責任範囲(ガバナンス)です。フラグの編集は本番環境の変更そのものです。認証、認可、環境分離、楽観的並行性制御、バリデーション、承認ポリシー、改ざん不可能な監査ログ、段階的公開、ロールバック、所有権(オーナーシップ)、廃止(リタイア)プロセスなどを設計に含める必要があります。
回答前に確認すべき明確化のための質問
- 評価はどこで実行されますか? サーバーサイドSDKは完全なルールセットを受け取ってローカルで評価できます。ブラウザやモバイルクライアントは機密性の高いターゲティングルールを安全に受け取れないため、フィルタリングされたモデルまたはリモート評価モデルが必要です。
- 5秒の目標は何を測定したものですか? 公開が成功してから、健全な購読済みサーバーインスタンスの99%がそのバージョンを適用するまでの時間と定義します。オフラインのインスタンスや、サポートされる鮮度ウィンドウから外れたクライアントには別のセマンティクスが必要です。
- フォールバックの規約はどうなっていますか? SDKが有効なスナップショットを一度もロードしていない場合、アプリケーションコードが提供する型付きデフォルト値を返します。初期化後は、合意されたstaleウィンドウの間、ラストノウングッドバージョンを使用できます。
- 同一の対象(subject)は常に同じコホートに属する必要がありますか? パーセンテージロールアウトには、安定したターゲティングキーと決定論的なハッシュ入力が必要です。安定性が重要な場合、匿名セッションには永続的な識別子が必要です。
- ルールに機密データを含めることはできますか? セグメントIDや機密性のない属性を使用することが推奨されます。サーバーサイド配信は保護されたルールを保持できますが、ブラウザ配信でシークレット、内部許可リスト、認可ロジックを露出させてはなりません。
- 緊急停止スイッチの重要度はどの程度ですか? 5秒の伝播SLOは有用ですが、瞬間的ではありません。真に破壊的な操作には、依然としてサーバーサイドの認可と独立した安全制御が必要です。
30秒の回答フレームワーク
「プラットフォームを、統制されたコントロールプレーンとローカルの評価プレーンに分割します。コントロールプレーンは、不変のスナップショットとパッチのバリデーション、バージョン管理、監査、公開を行います。サーバーSDKは最新の有効なルールを保持し、ターゲット、順序付きルール、ロールアウト、デフォルトをプロセス内で評価します。初期化前や無効な状態ではコード側のフォールバックを返します。決定論的なロールアウトは、安定したサブジェクトキーを環境、フラグキー、ソルトとともにハッシュ化します。ストリームで更新をプッシュし、ポーリングでギャップを修復するため、コントロールプレーンの障害がリクエストパスに影響することはありません。伝播速度、SDK間の結果一致、コホートの安定性、stale時の挙動、障害発生時のロールバックをテストします。」
ステップごとの解決策
ステップ1: 要件を明示的な規約に変換する
機能要件は、フラグの作成、編集、承認、公開、無効化、廃止、ブール値・文字列・数値・構造化データのバリエーション定義、サブジェクトまたはセグメントのターゲティング、パーセンテージ割り当て、デバッグ用の評価詳細の返却です。非機能要件は、ローカルp99が1ミリ秒未満、5秒のp99伝播、リージョン間での決定論的な結果、15分間の管理系障害中も評価を継続できることです。
コンポーネントを図示する前に、3つの境界を定義します。
- 公開されたバージョンは不変(immutable)です。以降の編集は別のドラフトおよびバージョンを作成します。
- 伝播SLOは、オフラインのデバイスではなく、健全に接続されたサーバーインスタンスに適用されます。
- 最終的なフォールバック値はアプリケーション側が保持します。型チェック、初期化、または評価が失敗した際に、プラットフォーム側が勝手に値を生成することはありません。
基本設計において、ラストノウングッド状態は少なくとも要求された15分間は有効であり続けます。フラグの公開された stale_after の境界を過ぎると、その stale_action に応じてラストノウングッドによる評価を継続するか、コードのフォールバックを使用するかが選択され、SDKはstale理由を返します。セキュリティに敏感なパスや破壊的なパスでは、古い有効化ルールを暗黙的に適用し続けるのではなく、フォールバックを選択する必要があります。
これにより、プロダクトのポリシーがインフラの内部に隠蔽されるのを防ぎます。決済処理の移行では古いパスへのフォールバックがデフォルトになり、セキュリティ機能では無効化がデフォルトになる場合があります。どちらも同じプラットフォームを使用しながら、異なるアプリケーション規約を持ちます。
ステップ2: コントロールプレーンと評価データプレーンを分離する
コントロールプレーンには、管理APIとUI、アイデンティティおよびロール検証、スキーマ・ルールバリデータ、承認ワークフロー、リレーショナルな信頼できる情報源(source of truth)、追記専用(append-only)の監査ログ、スナップショットビルダー、パブリッシャーが含まれます。書き込みは評価に比べて低頻度であるため、マイクロ秒単位のレイテンシよりも正確性、レビュー容易性、復元可能性が重要になります。
データプレーンには、リージョナルストリームリレー、スナップショットストレージ、ポーリングエンドポイント、SDKローカルストアおよび評価器が含まれます。サーバーSDKはリージョナルストリームを開き、不変のスナップショットをロードし、バージョン管理されたパッチを適用して、ネットワーク呼び出しなしで評価を実行します。ストリームが切断された場合、SDKは直近の有効な状態を保持し、ジッター付きポーリングを行います。パッチのバージョンが飛んでいる場合やチェックサム検証に失敗した場合、SDKはそのパッチを破棄して完全なスナップショットを再要求します。
データプレーンの配信は、主要なコントロールデータベースから独立させてください。パブリッシャーは、リレーに通知する前に永続的でバージョン管理された成果物(アーティファクト)を書き込みます。これにより、データベースやダッシュボードに障害が発生しても、既存の評価を停止させることなく新規の編集のみを停止できます。
ステップ3: データモデルとAPIを定義する
フラグ定義には最低限以下が必要です。
FlagDefinition {
tenant_id, project_id, environment, flag_key
version, value_type, variations[], off_variation
ordered_rules[], default_rule, salt
stale_after, stale_action
state, owner, expires_at
}
Rule {
rule_id, conditions[], outcome
}
Outcome = fixed_variation | weighted_variations[]多くのフラグが1つのコホートを参照する可能性があるため、セグメントは個別にバージョン管理されます。監査エントリには、実行者、日時、理由、期待される以前のバージョン、変更前後の参照、承認情報、公開結果が記録されます。未承認の編集が評価に漏れないよう、ドラフトは公開成果物から分離して保持します。
代表的なAPIは以下の通りです。
PUT /v1/projects/{project}/environments/{env}/flags/{key}
body: draft definition, expectedVersion
POST /v1/projects/{project}/environments/{env}/flags/{key}:publish
body: draftVersion, reason, approvalToken
GET /v1/sdk/bootstrap?project={project}&env={env}&after={version}
GET /v1/sdk/stream?project={project}&env={env}期待されるバージョン(expected version)を指定することで、2人の編集者が互いの変更を暗黙的に上書きすることを防ぎます。管理用認証情報をSDK用認証情報として流用してはなりません。テナント、プロジェクト、環境、許可された配信モードが、すべての認可判定に含まれます。
ステップ4: 評価とパーセンテージロールアウトを決定論的にする
すべてのSDKでドキュメント化された共通の順序を使用します。
- フラグの存在、環境、型、ターゲティングが有効かどうかを確認する。
- 明示的なサブジェクトまたはセグメントのターゲットを適用する。
- 順序付きルールを評価し、最初に一致したルールを採用する。
- 固定バリエーションまたは重み付けロールアウトを解決する。
- いずれにも一致しない場合はデフォルトルールを使用する。
- 評価が有効な型付き結果を生成できない場合は、エラー理由とともにアプリケーションフォールバックを返す。
重み付けロールアウトでは、安定した入力からバケットを算出します。
bucket = H(tenant_id || environment || flag_key || salt || targeting_key) mod 100000バケットを累積バリエーション範囲にマッピングします。同一の入力であれば、すべてのインスタンスおよびリージョンで同じ結果が得られます。ソルトとアルゴリズムバージョンを公開定義に含めることで、挙動の再現性が保たれます。既存の連続した範囲を拡張することで、すでに含まれているサブジェクトを維持できますが、任意の重み再調整やハッシュ入力の変更を行うとユーザーが別のグループに移動する可能性があります。レビュー時にその影響を明示してください。
同一のパーセンテージを持つ2つの独立したフラグであっても、フラグキーがハッシュ計算に含まれるため、同じサブジェクトが選択されるとは限りません。複数のフラグを単一のコホートとして連動させる必要がある場合は、共有のバージョン付きセグメントをターゲットにするか、明示的な実験キー(experiment key)を使用します。安定したサブジェクトIDが存在する場合、メールアドレスのような可変フィールドをハッシュ化してはなりません。
ステップ5: スナップショットと増分変更を安全に配信する
スナップショットビルダーは、プロジェクトと環境のスコープを解決し、参照されるセグメントと前提条件を検証し、ルールを決定論的にソートし、カノニカルな成果物をシリアライズして、バージョンとチェックサムを付与します。トランザクションによって公開メタデータとアウトボックス(outbox)レコードをコミットし、非同期パブリッシャーが成果物を保存してリージョナルリレーに通知します。これにより、配信がスケジュールされないままフラグだけがコミットされる事態を防ぎます。
SDKの起動シーケンスは以下の通りです。
- 設定されている場合、永続化された有効なラストノウングッドスナップショットをロードする。
- 最寄りのリレーから最新のフルまたは差分アーティファクトを取得する。
- 型、バージョン、チェックサムの検証を行った後のみ、メモリ内スナップショットをアトミックに置き換える。
- プロバイダーの準備完了(ready)をマークし、ローカル評価の提供を開始する。
- 更新用のストリームを開いたまま維持し、修復パスとしてポーリングを行う。
アクティブなルールセットをインプレースで直接変更してはなりません。新しい不変スナップショットを構築し、1つの参照をアトミックに切り替えることで、並行するリクエストが完全な古いバージョンまたは完全な新しいバージョンのいずれかのみを参照できるようにします。適用されたバージョンと評価理由は、診断用詳細情報に記録します。
ステップ6: 正常系よりも先に障害セマンティクスを設計する
| 障害の種類 | 評価の挙動 | 復旧方法 |
|---|---|---|
| コントロールAPIまたはデータベースの停止 | stale_after まで最新の有効なスナップショットを使用し、その後はフラグのstaleアクションに従う | 編集をブロックし、コントロールプレーンを復旧。検証完了後にのみ新バージョンを公開 |
| ストリームの切断 | ローカル状態を使用し、更新ステータスをstaleとしてマーク | ジッター付きで再接続。ギャップ発生後はポーリングして完全なスナップショットを要求 |
| SDKがスナップショットなしで起動 | 型付きコードフォールバックを返却 | 無関係なアプリケーションの起動を永続的にブロックすることなくブートストラップをリトライ |
| 無効または順序が狂ったパッチ | 現在のバージョンを維持 | パッチを拒絶してアラートを発報し、カノニカルなスナップショットを取得 |
| 誤ったルールの公開 | 既存の評価は内部的に整合しているが意図と異なる | ロールアウトを停止し、以前の正常な定義を監査ログ付きの新バージョンとして公開 |
| リージョナルリレーの停止 | ローカルでの処理を継続し、別のリレーまたはポーリングエンドポイントを試行 | 再接続トラフィックを制限し、同期的なブートストラップストームを回避 |
緊急停止スイッチには、監査されない可変の裏ルートではなく、優先レーンを備えた同じ永続的な公開パスを使用します。事前承認された非常時(break-glass)ポリシーの下でのみ通常の承認待ちをスキップできますが、実行者、理由、以前のバージョン、結果は必ず記録されます。5秒の伝播目標は、切断されたすべてのインスタンスが即座に切り替わることを保証するものではないため、破壊的な操作には独立した強制制御が必要です。
ステップ7: 設定が権限の源泉になってしまうのを防ぐ
管理ロールは、テナント、プロジェクト、環境ごとに分離します。本番環境の編集には2人目の承認者を必須とし、開発環境の編集は直接公開できるようにします。認証情報を暗号化し、SDKキーをローテーションし、管理API呼び出しにレートリミットを設け、サーバーキーでフラグの編集ができないように徹底します。追記専用の監査ログと不変の成果物により、インシデントの再現・調査が可能になります。
クライアントへの配信はサーバーへの配信とは異なる方法で扱います。ブラウザやモバイルデバイスにはクライアント公開が明示的に承認されたフラグのみを送信し、可能な限りそのコンテキスト向けに評価済みの値を送信します。ユーザーはクライアントの状態を検査または変更できるため、フラグは表示の変更には使えますが、認可の付与、決済のバイパス、サーバーサイドのエンタイトルメントチェックの代替として使用することはできません。評価コンテキスト内の個人特定可能フィールドを最小限に抑え、テレメトリ識別子を仮名化します。
すべての一時的なリリースフラグにオーナーと廃止条件を設定します。ロールアウト完了後は、まず採用されたコードパスを恒久化し、次にフラグの評価を停止し、コード参照が完全に削除された後に定義を削除します。そうしないと、古い分岐やフラグ同士の相互作用によってテストマトリクスが無制限に拡大してしまいます。
ステップ8: キャパシティを再確認し設計を検証する
購読フラグが500個(平均2 KB)の場合、1つのランタイムスナップショットは約1 MBです。20,000台のインスタンスが一斉に起動すると、プロトコルやレプリケーションのオーバーヘッドを除いても約20 GBのデータ転送が発生します。カノニカルな成果物をリージョナルリレーやオブジェクトストレージの背後に配置し、条件付きバージョンリクエストを使用し、再接続にジッターを持たせ、ブートストラップの並行数を制限します。20,000台のインスタンスに2 KBの変更をファンアウトする場合の論理ペイロードは約40 MBであり、増分配信は完全なリフレッシュよりも大幅に低コストです。
毎秒500万回の評価から、同期的に毎秒500万回のネットワークイベントを送信してはなりません。200バイトのイベントであっても毎秒約1 GB、レプリケーション前で1日あたり86.4 TBに達します。通常の診断情報はバッファリング、バッチ処理、サンプリング、または集約を行います。完全な割り当てイベントは実験規約で必須とされる場合のみ保持し、テレメトリは評価を遅延させることなく非クリティカルなイベントを破棄できる有界キュー(bounded queue)に流します。
検証項目はスループットだけにとどまりません。
- すべてのSDK実装に対して同一のゴールデンルールとコンテキストを実行し、値、バリアント、理由、エラー時の挙動を比較する。
- バケットの決定論性、近似分布、および既存のロールアウト範囲拡張時の安定性をプロパティベーステストで検証する。
- ルール数とセグメントサイズに応じたローカルのp50およびp99を測定し、公開から適用までの遅延を個別に測定する。
- ストリームの切断、コントロールデータベースの停止、パッチの破損、バージョンの欠落、認証情報の失効、全インスタンスの一斉再起動などをシミュレートする。
- 小規模なカナリアコホートに誤ったルールを公開し、ヘルスアラームを発報させ、ロールバックによって監査された新しいバージョンが作成・伝播されることを検証する。
- テナント分離、本番環境の承認、クライアント公開フィルタリング、監査ログの完全性、フラグ廃止フローを検証する。
優れた回答の例
「基本システムのスコープをサーバーサイド評価に絞って説明します。3リージョンに20,000台のインスタンスが存在しますが、コントロールプレーンの書き込みは毎秒100回にすぎないため、2つのトラフィックパス間で可用性の依存関係を持つべきではありません。管理サービスはドラフトと不変の公開バージョンをリレーショナルデータベースに保存します。公開のたびに型、ルール参照、権限を検証し、期待される直前バージョンを確認し、監査レコードとアウトボックスエントリを書き込み、プロジェクトおよび環境ごとのカノニカルな成果物を構築します。
リージョナルリレーがその成果物を配信します。各SDKはラストノウングッドスナップショットをロードし、ストリーム経由で更新を受信し、ギャップ修復のためにポーリングを行います。新しい不変スナップショットをアトミックにインストールしてローカルで評価を行うため、コントロールプレーンがダウンしている場合でも、リクエストレイテンシを目標のp99で1ミリ秒未満に抑えることができます。ラストノウングッドは少なくとも15分間有効であり、公開されたstale境界を超えた後は、リスクポリシーに従ってその値を維持するか型付きコードフォールバックを使用します。ローカルバージョン、鮮度、評価理由は可観測(observable)です。
評価順序は、無効状態、明示的ターゲット、順序付きルール、重み付け結果、デフォルトの順です。パーセンテージロールアウトでは、テナント、環境、フラグ、ソルト、安定したターゲティングキーを100,000個のバケットにハッシュ化するため、すべてのインスタンスで同一の判定が行われます。ハッシュ入力の変更はマイグレーションとして扱います。同一のコホートを必要とする複数のフラグには、偶然の一致に頼るのではなく共有セグメントを使用します。
最大のバーストはクラスタ全体のブートストラップ時であり、1 MBのスコープ付きスナップショットに20,000インスタンスを掛けると約20 GBになります。スナップショットをリージョン単位で配信し、差分を送信し、再接続にジッターを加え、リトライを制限します。評価テレメトリは、毎秒500万回の同期イベント記録がプロダクトパスを脅かすのを防ぐため、バッチ化およびサンプリングされます。最後に、SDK間の適合性、伝播p99、再起動ストーム、stale時の動作、破損・欠落バージョン、カナリアロールバック、break-glass監査、テナント分離、クライアント公開をテストします。すべての構成変更の統制と復元可能性を維持しながら、リクエスト評価がローカルかつ決定論的に行われ続ける状態を作ることがこのシステムのゴールです。」
よくある落とし穴
- 評価のたびに中央サービスを呼び出す → プロダクトのレイテンシと可用性がフラグサービスに依存してしまう → バージョン管理されたルールをサーバーSDKに配布し、プロセス内で評価する。
- リクエストごとにユーザーをランダムに選択する → 同一ユーザーがバリアント間を行き来し、実験データが汚染される → 安定したターゲティングキーを、フラグ固有のドキュメント化された入力とともにハッシュ化する。
- ラストノウングッドを永続的に正しいものとして扱う → 切断されたインスタンスが安全でない古いルールを無期限に提供し続ける可能性がある → 鮮度の可観測性、再接続・修復動作、およびアプリケーションの安全なフォールバックを定義する。
- サーバーのルールセットをブラウザに送信する → ユーザーに機密性の高いセグメントや認証情報を閲覧される恐れがある → クライアントに安全なフラグのみをフィルタリングするかリモートで評価し、認可はサーバー側で強制する。
- 共有ルールオブジェクトをインプレースで更新する → 並行するリクエストが部分的に適用された設定を参照してしまう → 完全な不変スナップショットを検証し、参照をアトミックに切り替える。
- すべての評価を同期的にログ出力する → テレメトリがリクエストパスの中で最も高負荷な依存関係になる → バッチ処理、サンプリング、集約を行い、非クリティカルなイベントを適切にドロップする。
- 緊急変更を監査なしで実行する → 最速の復旧パスが追跡不可能な本番環境のバックドアになる → 事前承認されたbreak-glassポリシーと不変の監査ログを備えた優先公開レーンを使用する。
- フラグを廃止(削除)しない → 不要になったコード分岐やフラグ同士の相互作用によりテストコストが肥大化する → オーナーを割り当て、採用されたコードパスが恒久化した後に定義を削除する。
フォローアップの質問と回答
フォローアップ1: ブラウザやモバイルSDKをどのようにサポートしますか?
完全なサーバー用ルールセットを配信してはなりません。クライアントへの公開が許可されたフラグを明示し、管理用認証情報を渡すのではなくアプリケーションとして認証し、フィルタリングされた値またはコンテキスト固有の評価済み結果を返します。オフライン利用のためにバージョンと鮮度ステータスを付与して値をキャッシュします。クライアント側のフラグはUI/UXのヒントにすぎず、サーバー側で権限、購入状態、クォータ、その他のセキュリティ判定を独立して検証します。
フォローアップ2: 複数のフラグで完全に同一のロールアウトコホートを維持するにはどうすればよいですか?
フラグキーごとにハッシュ入力が変わるため、パーセンテージを同じにするだけでは不十分です。共通の実験IDによってキー付けされた共有のバージョン付きセグメントまたは実験割り当てを作成し、各フラグからそれを参照します。セグメントと依存するフラグのバージョンを一貫して公開し、公開範囲を広げる前にコホートメンバーシップが安定していることをテストします。
フォローアップ3: セグメントに1,000万人のメンバーがいる場合はどう対応しますか?
完全なメンバーリストをすべてのスナップショットに埋め込んではなりません。メンバーシップをコンパクトなバージョン付き成果物として表現するか、サブジェクトハッシュでシャーディングするか、評価器が参照できる属性を事前計算します。ブルームフィルタ(Bloom filter)は不要な検索トラフィックを削減できますが、偽陽性(false positive)が存在するため、単独の認可メカニズムとして使用することはできません。メモリ使用量、検索レイテンシ、更新時のデータ増幅、staleなメンバーシップを通常のルールとは個別に測定します。
フォローアップ4: 緊急停止スイッチは瞬間的に反映できますか?
切断されたプロセスに対して即座に変更を反映できる分散公開システムは存在しません。緊急変更に優先度を付与し、リージョナルストリームをウォームに保ち、確認応答(ACK)を測定し、遅延しているバージョンに対してアラートを発報します。破壊的な操作に対しては、書き込みエンドポイントの無効化、権限の失効、ゲートウェイでのブロックなど、サーバー側で強制される保護機能とフラグを組み合わせます。フラグは復旧速度を向上させますが、厳格な安全境界の代替にはなりません。
フォローアップ5: ハッシュアルゴリズムをどのように移行しますか?
公開される各フラグにアルゴリズムバージョンとソルトを保存します。旧バージョンと新バージョンの評価器をシャドウモードで実行し、割り当ての変動を測定します。変動が許容範囲内であれば段階的な移行を公開し、そうでない場合はロールアウトが完了するまで既存のサブジェクト割り当てをセグメントまたはマイグレーションテーブルに保持します。バージョン間で不整合が発生するため、SDKのハッシュ実装を予告なく変更してはなりません。
フォローアップ6: フラグの循環依存をどのように防ぎますか?
公開処理時に前提条件のグラフを構築し、深さ優先探索(DFS)で循環が検出された場合はそのバージョンを拒絶します。非循環であっても異常に複雑なグラフがレイテンシ要件を侵害しないよう、前提条件の最大深度と評価処理の合計上限を設定します。成果物に参照フラグのバージョンを含め、SDK間で評価順序をテストし、診断用詳細情報に依存チェーンを表示します。