メインコンテンツへスキップ

条件付き代理承認を実機で通す:Granular Delegation(後編)


    これは代理承認を2本に分けた後編です。前編は 代理承認は承認レコードを増やさない:sys_user_delegate です。そこでは、標準の代理承認(sys_user_delegate)が approvals など4区分の「全か無か」であることを確認しました。部署やリスクといった条件では絞り込めず、その理由はテーブル設計そのものにありました。そのうえで「粒度制御用の Granular Delegation プラグインを有効化すると何が変わるか」を後編で扱う、と予告していました。この記事はその回収です。

    後編でやったことは1つです。「委任元の承認のうち、High リスクの変更(change_request)の承認だけを、別のユーザーに委任する」という条件付き代理承認を、PDI(Zurich)で実際に動くところまで通しました。委任元 Luke Wilson は承認待ちを63件(High 37 / Moderate 24 / risk空 2)抱えています。このうち High の37件だけが委任先 Abel Tuter に見え、Moderate は見えず、承認レコードは1件も複製されない。ここまでを実機で確認しています。

    先に結論を書きます。

    • 条件付き代理承認は、Granular Delegation プラグインで実現できます。委任ルール(対象テーブル+条件)を作り、粒度委任レコードに紐づける構成です。

    • あわせて押さえておく仕様が2つあります。1つはセットアップの必須部品(Service と、委任可能テーブルの登録)。もう1つは、委任のマッピングが「最近更新されたレコード」だけを対象にするという時間ウィンドウです。委任を設定しても、7日以上前から滞留している承認待ちは委任されません。

    • 承認レコードを複製せず読み取り時に見せる、という前編のモデルは粒度でも一貫しています。

    この記事で分かること

    • Granular Delegation 有効化で増えるテーブル群と、条件が「委任レコード」ではなく「ルール」側に載ること

    • 承認委任の判定ロジック(approver ベース・親レコード解決・条件評価・User Criteria)の実際

    • 実機で通したセットアップ手順(テーブル登録 → ルール → Service → User Criteria → 委任 → ルール紐づけ)

    • マッピングの時間ウィンドウ(既定7日)という仕様と、その実証

    • 対照実験の結果(High 37件だけ委任され、同時に touch した Moderate は委任されない=条件フィルタの証明)

    • 新規承認は自動で委任されること、クラシックUIで委任分を見せる読み取り側のスイッチ

    この記事の内容は ServiceNow の PDI(Personal Developer Instance)Zurich(ズーリッヒ)リリースに Granular Delegation プラグインを有効化して確認した個人メモです。本番環境やカスタマイズ済み環境では挙動・件数が異なる場合があります。


    プラグイン有効化で何が変わるか

    有効化したのは Granular Delegation(com.glide.granular_service_delegation / v1.0.0)です。有効化すると、前編で見た切替プロパティ glide.approval.delegation.version が v3(標準+粒度の両経路)になり、委任のデータモデルが大きく変わります。


    画像

    標準では sys_user_delegate 1テーブルに「誰が・誰に・いつまで・何を」がすべて入っていました。粒度モデルでは、これが複数テーブルに分かれます。


    画像
    • ルール定義系 … sys_delegation_rule(委任ルールの本体)、sys_delegation_rule_table(委任可能テーブルの登録先)、sys_delegation_rule_category(Service)

    • 委任レコード系 … sys_granular_delegate(委任元・委任先・期間。approvals などの区分はここには無く、ルール側に移った)

    • リンク系 … sys_m2m_delegate_rule(委任⇔ルール)、委任元/委任先それぞれの User Criteria リンク

    • 実体化 … sys_granular_delegate_m2m(Delegate Record。委任対象レコードの実体がここに入る)

    前編の結論は「条件を入れる場所がテーブルに無い」でした。粒度モデルは、条件を持つ「ルール」を委任本体から分離することでこの制約を解いています。

    なお、名前の似た com.snc.role_delegation(Role Delegation)は開発・ロール委任の別機能です。承認の代理とは関係ありません。


    条件付き委任のモデル(ルール・条件・User Criteria)

    条件付き委任の骨格は「ルール」です。1つのルールが「どのテーブルの、どの条件に合うレコードを、承認・割り当てのどちらとして委任してよいか」を表します。


    画像

    今回作ったルールは次の1本です。

    • table … change_request

    • condition … risk=2(High リスクのみ)

    • approvals … true(承認を委任対象にする)


    画像

    ここで注意すべき仕様が1つあります。ルールのフォームには *"The table and condition above will apply to the parent approving record for approvals"* と明記されています。つまり承認を委任する場合、ルールの table と condition は承認レコード(sysapproval_approver)に対して評価されません。評価対象は、その親=承認対象のレコード(change_request)です。承認テーブルを直接 table に指定するのは誤りです。

    「誰がこのルールで委任できるか(委任元)」「誰が受けられるか(委任先)」は User Criteria で絞ります。ルールと User Criteria をつなぐのは、委任元用・委任先用の2本の m2m です。判定エンジン(後述)を読むと、委任元側の User Criteria が1件も無いルールは「誰でも委任可」として扱われます。


    実機セットアップ手順


    画像
    1. 委任可能テーブルの登録 … sys_delegation_rule_table に change_request を active で登録します。未登録のままルールを作ると、Business Rule「Check table」に弾かれます(実測: REST で 403 abort)。

    2. 委任ルールの作成 … sys_delegation_rule でルールを1本作ります。table=change_request / condition=risk=2 / approvals=true です。

    3. Service の紐づけ … ルールには Service(sys_delegation_rule_category)が必須です。BR「Require at least one service」が効いています。Service を作り、ルールに紐づけます。ここに罠が1つあり、紐づけの実体はルールの categories フィールドではなく m2m テーブル sys_m2m_delegation_rule_category です。

    4. User Criteria … 委任元・委任先の資格。今回はユーザー指定の User Criteria を両側に付けました(省略すると委任元は「誰でも可」)。

    5. 粒度委任の作成 … 「Granular Delegate」フォームで User=Luke Wilson / Delegate=Abel Tuter / 期間を入れて保存。


    画像
    1. ルールの紐づけ … 保存後に出る「Delegation Rules」関連リストで、作成済みルールを紐づけます。このリンク挿入をトリガに、非同期の Business Rule「Map new rule for delegate」が動きます。そこから sn_delegation.DelegationMapper が呼ばれ、委任対象を実体化します。


    判定エンジンの中身(global.Delegation を読む)

    委任の合否を決めるロジックは、グローバルの Script Include global.Delegation で読めます。マッピング本体の sn_delegation.DelegationMapper はスコープ保護で読めませんが、判定側は読めます。canDelegateRecord / getMatchingRules の流れは次のとおりです。

    1. 対象が承認(sysapproval_approver)の場合、state が approved / rejected / cancelled / not_required なら対象外。そして approver = 委任元であること。承認委任は「承認者」ベースです(割り当て委任は assigned_to ベース。ここが対になっています)。

    2. 承認の source_table と document_id から親レコード(change_request)を解決します。

    3. ルールを「table = 親レコードのテーブル、approvals=true、active」で検索します。そのうえで、ルールの condition を親レコードに対して評価します(GlideFilter)。実測でも、risk=High の変更に紐づく承認は true、Moderate は false でした。

    4. 委任元 User Criteria があれば UserCriteriaLoader.userMatches で判定。無ければ通過です。

    この判定を通った承認が、sys_granular_delegate_m2m(Delegate Record)に「委任先+対象レコード」として実体化されます。読み取り時には DelegationUtil が既存の承認レコードの sys_id を返します。承認レコードの複製は起きません。前編の「読み取り時に見せる」モデルは、粒度でもそのままです。


    マッピングの時間ウィンドウ:古い滞留承認は委任されない

    マッピングには、設定画面には出てこない対象範囲の仕様があります。実体化の対象になるのは「最近更新されたレコード」だけです。


    画像
    • delegation 系のプロパティに com.glide.delegation.default_days_since_update = 7 があります。関連BRの実装から、値は最大30にクランプされます。

    • マッピングは、この日数以内に更新されたレコードだけを実体化の対象にします。ウィンドウ外の承認は、ルールや委任の設定がすべて正しくても実体化されません。

    • 今回の PDI のデモ承認は最終更新が 2024-08-29 でした。この状態で委任を設定しても実体化は0件で、ウィンドウ外のレコードが対象にならないことを確認できます。

    このウィンドウの挙動を、次の手順で実証しました。Luke の承認待ちのうち、High の37件すべてと、対照群として Moderate の3件、計40件に作業メモを追記しました。sys_updated_on を現在化してから、再マッピングを実行しました。


    画像
    • 実体化(Delegate Record): 37件=touch した High とちょうど一致

    • Abel に見える委任承認: 37件・すべて High

    • 同時に touch した Moderate 3件は委任されない … 時間ウィンドウだけでなく、条件フィルタ(risk=High)が正しく効いていることの対照実験です

    • Abel が approver の承認レコード: 0件のまま … 複製なしの証明


    画像

    さらに、委任が有効な状態で Luke 宛の承認を1件新しく作ると、手動の再マッピングなしで自動的に実体化されました(37→38件)。運用上は次のようになります。

    • 委任期間中に新しく発生する承認 → 自動で委任される。

    • 委任を設定した時点で、すでに7日以上更新されていない滞留承認 → 委任されない。

    「休暇前に委任を設定しておく」という典型的な使い方では、新しく来る承認は問題なく委任先に流れます。一方で、設定前から溜まっていた古い承認待ちは、静かに委任から漏れます。エラーも警告も出ません。委任を入れるときは、委任元の承認待ち一覧を確認し、古い滞留分は先に処理するか、レコードを更新してウィンドウ内に入れる運用が要ります。


    読み取りUI側にもスイッチがある

    実体化ができても、クラシックUIの承認一覧にはもう1段スイッチがあります。

    • 承認一覧のクエリを委任分まで広げる Business Rule「approval query」(sysapproval_approver)があります。これは before-query 型で、既定は inactive でした(前編で触れたとおり)。今回はこれを有効化して、委任分が一覧クエリに乗ることを確認しました。

    • ただし標準の「My Approvals」モジュールはフィルタが approver=自分(v1形)のため、BR を有効化してもこのモジュールには委任分は出ません。approver 条件を外した一覧で見るか、モジュール側のフィルタ改修が必要です。公式コミュニティの導入事例(Finance の承認委任)でも「My Approvals モジュールを更新した」と明記されています。

    • なお Granular Delegation の想定表示先は Employee Center の To-do/承認ウィジェット(employee ユーザー向け)です。fulfiller 向けのクラシックUIで使う場合は、この読み取り側の設計を最初から織り込んでおくのが安全です。


    相談への最終回答(前編+後編)

    前編の冒頭で挙げた、実務で行き詰まりやすい論点への回答をまとめます。

    1. 条件付き代理承認(部署・リスク・種別など)のアーキテクチャ … Granular Delegation が正攻法です。条件は「ルール」(対象の親テーブル+condition)に持たせ、委任元/委任先の資格は User Criteria で絞ります。承認レコードは複製せず、実体化(Delegate Record)+読み取り時展開で見せます。

    2. リアルタイムな承認の付け替え … そもそも付け替えは発生しません。委任の作成・削除・期間変更に応じて再マッピングが走り、読み取り時に見える範囲が変わるだけです。ワークフロー実行コンテキストに手を入れる必要はありません。

    3. 標準+プラグインで要件を満たせるか … 満たせます(本記事で実証)。ただし2つの前提を織り込むこと。(a) マッピングの時間ウィンドウ(既定7日)により古い滞留承認は委任されない。(b) クラシックUIで委任分を見せるには読み取り側(approval query BR・一覧フィルタ)の整備が要る。

    4. カスタム実装するなら許容すべき制約 … 3点あります。承認レコードを複製しない、Flow の承認セットを壊さない(前編)、保護されたスコープ内部(DelegationMapper 等)の実装詳細に依存しない、の3つです。


    ServiceNow における粒度代理承認のポイント

    • 条件付き代理承認は Granular Delegation プラグインで実現できます。条件は委任レコードではなくルール(sys_delegation_rule: table+condition)が持ちます。

    • 承認委任の判定は approver ベースで、ルールの table / condition は親の承認対象レコード(change_request 等)に対して評価されます。承認テーブルを table に直接指定するのは誤りです。

    • セットアップは「テーブル登録 → ルール → Service(必須) → User Criteria → 委任 → ルール紐づけ」。Service の紐づけ実体は m2m(sys_m2m_delegation_rule_category)です。

    • 委任対象は sys_granular_delegate_m2m(Delegate Record)に実体化され、読み取り時は既存承認の sys_id を返すだけ。承認レコードは複製されません。

    • 最大の運用上の罠はマッピングの時間ウィンドウ(com.glide.delegation.default_days_since_update・既定7日)です。新規承認は自動で委任されますが、設定前から滞留していた古い承認は静かに委任から漏れます。

    • クラシックUIで委任分を見せるには、BR「approval query」(既定 inactive)の有効化と一覧フィルタの見直しが必要です。


    実機で気づいたこと

    • 時間ウィンドウで委任から漏れた承認は、エラーも警告も一切出ません。設定をどれだけ正しく組んでも、画面のどこにも「この承認は古いので委任されていません」という表示は出てこないので、委任がうまく効いていないという相談を受けたら、まずルールや User Criteria ではなく、委任元の承認待ちがいつ更新されたかを疑うところから始めたほうが早そうです。

    • 今回この時間ウィンドウの仕様に気づけたのは、たまたま PDI のデモ承認の最終更新日が2024年と古かったからでした。もしデモデータが常に最新の日付で作られていたら、委任がすぐ効いてしまい、古い滞留承認が漏れるという制約自体に気づかないまま検証を終えていたかもしれません。動作確認をするときは、対象データの鮮度も検証条件の1つだと意識したほうがよさそうです。

    • プロパティを見ていると、default_days_since_update とは別に default_days_since_inactive という項目も存在していました。名前から推測すると委任先や委任元が非アクティブになったときの扱いに関わりそうですが、今回の検証では default_days_since_update の挙動しか確認しておらず、こちらが何を制御するのかまでは追い切れていません。似た名前のプロパティが複数あるときは、名前だけで役割を決めつけないほうがよさそうです。


    次に読むなら

    承認全体の申請経路や停止ポイントを俯瞰するなら、ServiceNow 承認(Approval)完全ガイド:申請はどこで誰に回り、なぜ止まるのか を先に読んでください。前提となる仕組みは、前編で扱っています。前編(代理承認は承認レコードを増やさない:sys_user_delegate) を参照してください。承認の構造は 承認は1人1レコード(sysapproval_approver) です。承認運用を設計として決める領域(承認経路・却下時の影響・パラメータ)は承認運用設計書側の対象です。


    用語

    • Granular Delegation:条件付き委任を実現するプラグイン(com.glide.granular_service_delegation)

    • Delegation Rule(sys_delegation_rule):委任ルール。対象の親テーブル+condition+approvals/assignments

    • Service(sys_delegation_rule_category):ルールの必須分類。m2m(sys_m2m_delegation_rule_category)で紐づく

    • Granular Delegate(sys_granular_delegate):粒度委任レコード(委任元・委任先・期間)

    • Delegate Record(sys_granular_delegate_m2m):委任対象の実体化先(delegate+document+rule)

    • マッピング/materialize:DelegationMapper が委任対象を Delegate Record に書き出す処理

    自分の環境で確認するときのURL

    自分のインスタンス名を先頭に付けると、同じ画面が開けます。

    委任可能テーブル : sys_delegation_rule_table_list.do
    委任ルール       : sys_delegation_rule_list.do
    粒度委任         : sys_granular_delegate_list.do
    Delegate Record : sys_granular_delegate_m2m_list.do
    Delegation Log  : syslog_delegation_list.do
    切替プロパティ    : sys_properties_list.do?sysparm_query=nameLIKEdelegation

    検証の設定値

    • ルール: table=change_request / condition=risk=2 / approvals=true(1本のみ。sysapproval_approver 直指定の誤形ルールは検証後削除)

    • Service: Change management (demo) を m2m で紐づけ

    • User Criteria: ユーザー指定型(Luke / Abel)を委任元・委任先の両m2mへ

    • 委任: User=Luke Wilson / Delegate=Abel Tuter(Granular Delegate・UI作成)

    実測値

    • Luke の requested 変更承認: 63件(High 37 / Moderate 24 / risk空 2)。最終更新 2024-08-29(=ウィンドウ外)

    • touch 後の実体化: High 37件(対照群 Moderate 3件は実体化されず)

    • 新規承認の自動マップ: 手動処理なしで 37→38件

    • Abel が approver の承認: 終始 0件(複製なし)

    • プロパティ: glide.approval.delegation.version=v3 / com.glide.delegation.default_days_since_update=7 / com.glide.delegation.default_days_since_inactive=7

    判定エンジン(読解できた範囲)

    • global.Delegation(グローバル・読解可能): canDelegateRecord / getMatchingRules が「approver=委任元 → source_table+document_id で親解決 → table=親テーブルのルール → condition を親に評価 → 委任元UC(0件なら誰でも可)」の順で判定

    • sn_delegation.DelegationMapper / DelegationUtil(スコープ保護・読解不可): 挙動は BR・ログ・再現実験から確定

    • 関連BR: Map new rule for delegate(リンク挿入時の実体化)/Remap user・delegate・start・ends(委任変更時の再実体化)/Check table・Require at least one service・Check delegation meets user criteria(ルール/リンクの検証)/approval query(読み取り拡張・既定 inactive)


    検証範囲とおことわり

    • 確認した範囲:プラグイン有効化後のテーブル群と切替プロパティ、判定エンジン global.Delegation の実コード、セットアップ一式(テーブル登録・ルール・Service・User Criteria・委任・リンク)、実体化の再現実験(時間ウィンドウ・対照群・新規承認の自動マップ・複製なし)、読み取りBRの有効化。すべて PDI(Zurich / 2026-07-28)で実測しています。

    • 確認していない範囲(断定しません):sn_delegation スコープ内部(DelegationMapper / DelegationUtil)の実装詳細、時間ウィンドウの内部適用箇所(挙動は再現実験で確定)、Employee Center ウィジェットでの表示、HRSD など他プロダクトでの挙動、本番規模の性能。

    • 検証のためにこの PDI では、承認40件への作業メモ追記(更新日時の現在化)、検証用承認1件の追加、BR「approval query」の有効化を行っています。OOTB の既定値はそれぞれ本文に明記したとおりです。

    今回は PDI + Granular Delegation 有効化を前提に、条件付き代理承認を動くところまで確認しました。実環境では、既存のカスタマイズ・データの鮮度・UI 構成によって見え方が変わります。

     
     
    ServiceNowのPDI(Personal Developer Instance)を実機で観察して、Noteに記事を書いています 実装・運用・教育の現場視点で淡々と記録中です リクエストがあればその記事も書きます 個人の観察日記です

    あなたへのおすすめ