Effectと承認
外部システムへの書き込みが、どうプレビューされ、ポリシーや人が判断し、適用され、応答が失われたときに突き合わされるか。
このページは、外部システムを変えるプログラムを書く作者と、何を書き込んでよいかを決める運用者のためのものです。Effectをどう書くか、プレビューに何が表示されるか、RunがいつCheckpointで止まるか、誰が判断するか、そしてCLIやコードからどう承認・拒否するかを説明します。
Effectを書く
Effectは、プログラムが外部システムを変える唯一の手段です。解約リスクのプログラムは、Effectで終わります。
|> EFFECT UPDATE salesforce.Account
ID id SET (
Churn_Risk__c = risk.value.level,
Risk_Reason__c = risk.value.reason
);EFFECT UPDATE <対象> ID <列> SET (...) は、流れ込んできたレコードを1件ずつ受け取り、ID の列にある識別子を持つレコードを、列挙した項目で更新します。ほかの形も、プログラムの最後という同じ位置に置きます。UPSERT と DELETE は同じように ID でレコードを指定し、INSERT は書き込む列を列挙し、STORE はコンテンツ(SERIALIZE やファイルの読み取りから来たもの)をオブジェクトとして、またはレコードをテーブルに保存し、COMMAND はConnectorが宣言する操作(メールの送信、抽出の更新など)を実行します。それぞれの形はプログラムを書くにあり、何が使えるかは各Connectorのページにあります。見慣れたSQLの形も、同じEffectです。
UPDATE salesforce.Account
SET Churn_Risk__c = 'high'
WHERE Id = @account_id;どちらの形で書いても、Effectは同じようにプレビューされ、判断され、記録されます。Effectのないプログラムは、どこにも何も変えません。
プレビュー
Effectを適用する前に、ActQLは何をするかを正確に計算し、それをプレビューとして記録します。どのレコードの、どの項目を、どの値にするかです。プレビューは、ActQLが適用しようとする対象と変更内容を固定し、承認はそのプレビューに結び付きます。適用の直前に、Hostは権限と、プレビューが前提にしている条件をもう一度確認します。変わっていれば、古い承認は使い回しません。承認は、外部システムでの成功を保証するものではありません。競合、拒否、非同期の完了、応答の喪失は、そのあとで扱います(承認のあとに起こりうること)。
プレビューにどこまで表示できるかは、Connectorによって違います。
| 強さ | プレビューが持つもの | 適用されるか |
|---|---|---|
full_diff | 正確な対象、いまの値、新しい値 | はい |
targeted | 正確な対象と新しい値 | はい |
書き込む前にレコードを読めるConnectorなら full_diff になります。レコードを正確に指定できるものの、先に読めないConnectorなら targeted です。targeted が適用されるのは、承認時の条件を適用時にもConnectorが検証できる場合(バージョンのガード、条件付きリクエスト)に限ります。これより弱い強さはありません。送る前に対象を特定できないEffectは宣言できません。
誰が判断するか
ポリシーは、Runの受け付け時と、Runが越える保護された境界のそれぞれ、つまり各読み取り、各LLMの呼び出し、各Effectの送信直前に確認されます。ポリシーはHostの設定であって、プログラムの一部ではありません(ローカルとリモートのHostを参照)。
- 実行アカウントの設定が、Effectを
allow、deny、delegateのどれかに振り分けます。 - delegateされたEffectは委譲先に届きます。ローカルのHostでは
effect_policy、組み込みのHostでは自分の判断コード、リモートのHostでは背後の承認サービスです。委譲先は permit、reject、defer のどれかを返します。
allow と、その場の permit は、止まらずにEffectを適用します。deny と、その場の reject は、Effectを送らずにRunを止めます。defer が、Checkpointを作ります。
書き込む内容で振り分けるのが、普通のやり方です。組み込みのHostでは、connect() の decide オプションが委譲先になります。
const client = await connect({
mode: 'local', installation: {directory: '.actql'},
decide: async (decision) => {
if (decision.kind !== 'effect_set') return 'permit';
const touchesAmounts = decision.preview.fields.includes('Amount');
if (!touchesAmounts && decision.preview.items.length <= 100) return 'permit';
return 'defer';
},
});影響の小さい書き込みはそのまま通し、それ以外は人を待ちます。プログラムの実績が積み上がれば、ルールを広げられます。委譲先が答えるのは、書き込みを進めるかどうかだけです。プレビューを編集することはできず、答えられなかった委譲先は何も送らせません。
Checkpoint
deferされた判断は、プレビューを付けたままRunをCheckpointで止め、run は次のように返します。
$ actql run churn-risk.aql
Run run_…
Status waiting_checkpoint
Checkpoint ckpt_…
Effect update (Salesforce Account)
Items 2
Changes
Acme Corp Churn_Risk__c low → high
Risk_Reason__c (empty) → falling usage and a competitor evaluation
Globex Inc Churn_Risk__c medium → high
Risk_Reason__c (empty) → support tickets about pricingrun が入力を促すことはありません。Checkpointは永続的で、プロセスが終了しても、誰かが解決するまでRunは待ち続けます。actql status run_… でいつでも同じ表示が見られ、--json を付ければ承認用のアプリ向けにデータとして返ります。
--stop-before commit は、ポリシーが許可するはずの場合でも、最初のEffectの前に必ずCheckpointを作ります。新しいプログラムが何をするかを確かめるときに使います。
actql run churn-risk.aql --profile mock --stop-before commit承認と拒否
CLIからは次のとおりです。
$ actql approve ckpt_… --signer ops-approver
Checkpoint ckpt_… approved
Run run_… resuming
$ actql reject ckpt_… --signer ops-approver
Checkpoint ckpt_… rejected
Run run_… cancelledコードからは、同じ2つの呼び出しです。
const state = await execution.wait(); // 'waiting_checkpoint'
await client.approve(state.checkpoint.id); // または client.reject(...)
const done = await execution.wait(); // 'succeeded'state = execution.wait()
client.approve(state.checkpoint.id)
done = execution.wait()承認すると、同じRunがCheckpointから続きます。すでに読んだもの、LLMに聞いたもの、計算したものをやり直すことはありません。承認が及ぶのは、表示されたプレビューそのものです。その中の項目すべてに及び、その外には及びません。同じStageで宣言されたEffectは1つのEffect Setになり、まとめてプレビューされ、1つのCheckpointで承認されます。後続のStageのEffectは、それぞれ自分のCheckpointを持ちます。
approve --wait は、次の安定した状態まで待ってそれを表示するので、スクリプトで便利です。Hostに signers を設定している場合、CLIからの承認は --signer で承認者を指定します。承認者を設定していないローカルのHostでは、actql init がStoreに作ったローカルの署名鍵で承認が記録されます。この鍵が示すのはマシンのユーザーであって、本人確認された人ではありません。本番のHostでは、判断を検証できる承認者を設定します。組み込みのHostでは、クライアントを通して承認者が識別されます。
操作もEffectです
メールを送る、メッセージを投稿する、ジョブを開始する。これらもレコードの書き込みと同じEffectで、EFFECT COMMAND で宣言し(プログラムを書く)、同じポリシー、プレビュー、Checkpointを通ります。プレビューには、操作が送ろうとしている内容が出ます。
$ actql run churn-digest.aql
Run run_…
Status waiting_checkpoint
Checkpoint ckpt_…
Effect command slack.post → #revenue (C0123456789)
Items 1
Message
High churn risk today:
• Acme Corp: falling usage and a competitor evaluation
• Globex Inc: support tickets about pricingメールなら、プレビューにはすべての宛先、件名、本文が並びます。承認のあと、操作の項目は、システムが要求を受け付ければ accepted、結果を確認できれば applied、分からなければ unknown で終わります。Gmailが受け付けたメールが、相手に届いたとは限りません。
承認のあとに起こりうること
- 対象が変わっていた。 適用の直前に、Hostは承認と、承認が出されたときの条件を確認します。
full_diffのプレビューがいまの値と一致しなくなっていれば、古い承認は使い回されません。その項目はconflictを理由にfailedで終わり、Hostのポリシーによっては新しいプレビューを作って、あらためて承認を求めることがあります。 - 書き込みが失敗した、または結果が分からない。 承認は許可であって、完了ではありません。項目はそれぞれ
applied、accepted、failed、unknownのどれかで終わり、不明な結果は再送ではなく突き合わせで解決します。Runのライフサイクルと復旧を参照してください。 - 一部の項目は適用され、ほかは適用されなかった。 システムをまたぐトランザクションはありません。Runはどの項目が適用されたかを記録し、不明なものがなくなった時点で
failedになるので、どこで止まったかを正確に確認できます。
次に読む
- Runのライフサイクルと復旧:状態、結果、突き合わせ
- ローカルとリモートのHost:アカウント設定、委譲先、承認者
- Connector:各Connectorが提供するEffectと、そのプレビューの強さ
Source: actql/actql/docs/guides/effects-and-approvals.md at d904416674e4 · Edit on GitHub