目次
ガイド

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を参照)。

  1. 実行アカウントの設定が、Effectを allow、deny、delegate のどれかに振り分けます。
  2. 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 pricing

run が入力を促すことはありません。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 になるので、どこで止まったかを正確に確認できます。

次に読む

Source: actql/actql/docs/guides/effects-and-approvals.md at d904416674e4 · Edit on GitHub