actor-aware ポリシーを展開すると何がうまくいかなくなるのか?
actor-aware ポリシーは、誰が、または何が実行しているかに基づいて、アプリケーションの応答を変えます。適切に運用できれば、利用者には滑らかな体験を提供し、正当な agent には構造化された経路を与え、本当に必要な箇所だけに摩擦を加えられます。運用を誤ると、実利用者を締め出し、顧客が依存している integration を壊し、誰にも説明できない support ticket を生みます。
違いは、policy logic にあることはまれです。rollout にあります。(policy model 自体については、人間と AI agent のための app-level policy の設計を参照してください。) このガイドでは、どの route に対してもチームが実行できる段階的な手順を説明します。まず observe し、次に preview し、一部に対して enforce し、その後に広げます。各段階には明確な終了条件と、すぐ戻せる方法があります。
3つの mode
各 policy は、route ごとに次の3つの mode のいずれかで動作すると考えてください。
- Observe. classification は記録されます。アプリケーションの応答は、それがなかった場合とまったく同じです。
- Preview. policy は評価され、その decision は記録されますが、適用されません。実際には何が起きたかではなく、起きるはずだったことが見えます。
- Enforce. decision は実際の request に適用されます。
mode はアプリケーション全体ではなく、route と policy の組み合わせに属します。documentation ページを enforce しながら、checkout はまだ observe のままにできます。
Step 1: 基準値が分かるまで observe する
すべての route を observe mode で開始します。少なくとも次を収集してください。
- route と method,
- actor class (Human, Human + AI, Agent, Unknown) とその basis (verified, declared, inferred, unknown)。これは application traffic の分類体系で定義されています。
- response status と、たとえば "account created" や "search returned results" のような、route の簡単な outcome marker。
通常の週次サイクルと、その期間に出荷する release をすべて含められるだけの時間、十分に実行します。次に、関心のある各 route について基準値を書き出します。class mix、Unknown rate、class ごとの outcome rate です。以後のすべてをこの数値と比較します。
終了条件: 候補となる各 route について、誰が使っているか、class ごとに outcome がどう違うかを説明できる。
Step 2: policy を data として書く
policy は、if 文が散らばっているより、data として管理したほうが review、test、rollback が容易です。
type ActorClass = "human" | "human_ai" | "agent" | "unknown";
type Basis = "verified" | "declared" | "inferred" | "unknown";
type Action = "allow" | "adapt" | "challenge" | "review" | "limit";
type Mode = "observe" | "preview" | "enforce";
interface Rule {
actor: ActorClass | "*";
basis?: Basis[];
action: Action;
}
interface RoutePolicy {
route: string;
mode: Mode;
enforcePercent: number;
rules: Rule[];
fallback: Action;
}
export const policies: RoutePolicy[] = [
{
route: "GET /api/catalog",
mode: "preview",
enforcePercent: 0,
rules: [
{ actor: "agent", basis: ["verified"], action: "allow" },
{ actor: "agent", basis: ["declared", "inferred"], action: "limit" },
],
fallback: "allow",
},
];各 policy には明示的な fallback があります。これは Unknown result、timeout、どの rule でもカバーされない case に使う action です。これを意図的に選ぶことが、プロセス全体で最も重要な安全判断です。
Step 3: 1か所で評価する
単一の evaluation function にすると、mode をまたいでも behavior を一貫させられます。
export function decide(policy: RoutePolicy, actor: ActorClass, basis: Basis): Action {
for (const rule of policy.rules) {
const actorMatch = rule.actor === "*" || rule.actor === actor;
const basisMatch = !rule.basis || rule.basis.includes(basis);
if (actorMatch && basisMatch) return rule.action;
}
return policy.fallback;
}その後で mode を適用します。
export function applyPolicy(policy: RoutePolicy, actor: ActorClass, basis: Basis, requestKey: string) {
const decision = decide(policy, actor, basis);
const inSlice = bucket(requestKey) < policy.enforcePercent;
const enforced = policy.mode === "enforce" && inSlice;
record({ route: policy.route, mode: policy.mode, actor, basis, decision, enforced });
return enforced ? decision : "allow";
}
function bucket(key: string): number {
let h = 0;
for (const c of key) h = (h * 31 + c.charCodeAt(0)) >>> 0;
return h % 100;
}stable bucket とは、同じ session または client が enforce 対象の slice の内外で固定されることを意味します。これにより、request ごとに behavior が切り替わることを防げます。
Step 4: enforce する前に false positive をどう測るか?
1つの route を preview に移します。これで、すべての request が、本来受けるはずだった decision を記録するようになります。ここで policy が正しいかどうかが分かります。
false positive とは、policy が制限しようとしたが、本来は許可されるべきだった request のことです。classification だけでは測れません。なぜなら、classification 自体が検証対象だからです。独立した正当利用の signal と照らし合わせて測定してください。
- signed-in user が作業内容を保存するなど、request が通常の正常な flow を完了した,
- client が既知の partner integration か、提供対象として合意済みの verified operator である,
- support ticket または user report が影響を受けた route に言及している,
- 制限されるはずだった request のサンプルを手動 review した。
サンプルは手作業で review してください。policy が challenge するはずだった実際の request を20件読むことは、範囲が広すぎる rule を見つける最速の方法です。
終了条件: 制限されるはずだった対象の大半が、実際に制限したい traffic で占められており、見つけた false positive の各カテゴリについて説明できる。
Step 5: 一部に対して enforce する
route を小さな enforcePercent 付きで enforce に切り替えます。slice は、ミスが影響する request を少なくしつつ、1日か2日で測定可能な signal が出る程度には十分大きく保ちます。
基準値として設定したのと同じ metric を監視します。
- route 上の class ごとの outcome rate,
- error rate と challenge completion rate,
- route に言及する support volume,
- evaluation が request path 上にあるため latency。
enforce した slice で Human traffic の outcome が残りと比べて低下した場合は、拡大する前に停止して調査してください。
Step 6: 段階的に広げる
たとえば、小さな割合から4分の1、次に2分の1、最後に全 traffic へと、段階的に slice を増やします。各段階で、通常のサイクルが見えるだけの時間を確保します。前段階が適切に行われていれば、拡大作業は目立たないものになります。それが目標です。
fallback と failure behavior の決め方
evidence がない場合や evaluation を実行できない場合に何が起きるかを、事前に決めておきます。
- Fail open は、request が actor context なしの場合と同じように進むことを意味します。public page、documentation、読み取り専用の catalog endpoint のような低リスク route に使います。
- Fail closed は、再認証や review queue など、既存のより強い check を適用することを意味します。すでにそのような check がある high-impact action に使います。
timeout や error が Human result を生むようには絶対にしないでください。足りない evidence は Unknown であり、Unknown は route の fallback を取ります。私たちの Unknown が AI traffic の分類で有効な result である理由 に関する投稿では、この rule が重要な理由を説明しています。
async function actorWithTimeout(evaluate: () => Promise<{ actor: ActorClass; basis: Basis }>) {
const timeout = new Promise<{ actor: ActorClass; basis: Basis }>((resolve) =>
setTimeout(() => resolve({ actor: "unknown", basis: "unknown" }), 150),
);
return Promise.race([evaluate(), timeout]);
}policy をすばやく rollback するには?
rollback は deploy ではなく、configuration change であるべきです。team がすばやく編集できる store に policy を保持し、次の action を即時にできるようにします。
- route を preview に戻し、measurement は維持したまま enforcement を止める。
enforcePercentを zero にする。- 他の rule に触れずに、単一の rule を無効化する。
すべての policy change について、誰がいつ変更したかを記録します。outcome が動いたとき、最初の問いは常に何が変わったかです。
人に関する consequential decision を避ける
actor classification は、interaction に関する evidence を表します。人そのものに対する判断ではありません。推定された class を、雇用、信用、教育、住居、または essential service へのアクセスに影響する decision の唯一の basis にしないでください。そのような flow では、actor context を使って outcome を決めるのではなく、人の review に回すなど、process を選ぶために使ってください。
enforce する前に伝える
automated client に影響する policy は、それを運用する人や会社にも影響します。少しの communication で、多くの support work を防げます。
- automated access の rule を公開する。 どの route が開いているか、どの limit が適用されるかを明示し、HTTP Message Signatures (RFC 9421) と IETF の Web Bot Auth protocol draft を使った signed request で client が自分を識別する方法を示します。
- partner と integrator に事前に知らせる。 既知の integration が preview 中に restricted slice に入る場合は、enforce する前に所有者へ連絡してください。
- 有用な response を返す。 policy が request を制限または challenge する場合は、たとえば
429 Too Many RequestsとRetry-Afterのような明確な status code と、documentation への link を返します。Problem Details 形式の machine-readable body は、automated client に構造化された理由を与えます。よくできた agent は、なぜそうなったかを理解すれば適応します。 - support team に evidence を渡す。 blocked request に関する ticket が来たとき、support は engineering に聞かなくても route、class、basis、policy decision を確認できる必要があります。
変更を告知し、その理由を説明する team は、黙って rule を切り替える team よりも驚きを大幅に減らせます。そして、適応する client は時間の経過とともに識別しやすくなります。
各 route のチェックリスト
- class mix、Unknown rate、outcome の基準値を記録済み。
- 明示的な fallback 付きで policy を data として記述済み。
- preview を実行し、サンプルを review し、false positive のカテゴリを説明済み。
- 小さな slice で enforcement を開始し、metric を監視済み。
- failure behavior を選択済み: fail open または fail closed。
- 拡大前に rollback を test 済み。
Proof of Actor がどこに当てはまるか
Proof of Actor は、この process を中心に設計されています。Observation が default であり、すべての result には basis が付与され、Route policy は、あなた自身の code で route ごとに定義し enforce できます。Detect、Understand、Route の順です。
自社 application での rollout を私たちの team と一緒に進める場合は、early access に申し込むを参照してください。end-to-end の decision flow については、Proof of Actor の仕組みをお読みください。
出典
- RFC 6585: Additional HTTP Status Codes, Section 4:
429 Too Many Requestsstatus code - RFC 9110: HTTP Semantics, Retry-After: client に再試行のタイミングを伝える方法
- RFC 9457: Problem Details for HTTP APIs: machine-readable な error body
- RFC 9421: HTTP Message Signatures: automated client が request に署名する方法
- draft-ietf-webbotauth-httpsig-protocol: signed automated traffic のための IETF Web Bot Auth draft (2026年11月時点で作業中)