consumer-goods-accruals-datakit-deploy

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

MANDATORY: Always write the Phase 6 report

强制要求:始终编写 Phase 6 报告

After completing all phases — including early stops, blocked phases, or error conditions — you MUST write the Phase 6 report to disk. Failure to write the report is always a test failure, regardless of how well you handled the scenario.
This applies to ALL exit paths without exception:
  • Normal completion (all phases ran)
  • Phase 1 stop (preflight failed, sales org not found, CGCloudAddons missing, Data Cloud not enabled)
  • Phase 3 error (setup script non-zero exit)
  • Phase 4 failure detection (DataKitDeploymentLog failures)
  • Schedule conflict (Phase 5 guard triggered)
  • Any other blocking condition (missing inputs, org unreachable, etc.)
Write the report to
${outputDir}/report.md
(the path from the
generatedFileLocationDirective
in the task). Do not print it as a chat message only — it must exist as a file on disk. If you handled a scenario correctly but never wrote the file, the eval will record
no_output
and score zero.

完成所有阶段后——包括提前停止、阶段受阻或发生错误的情况——你必须将 Phase 6 报告写入磁盘。无论你处理场景的效果如何,未写入报告始终属于测试失败。
此要求无例外地适用于所有退出路径:
  • 正常完成(所有阶段均已运行)
  • Phase 1 停止(preflight 失败、未找到 sales org、缺少 CGCloudAddons、Data Cloud 未启用)
  • Phase 3 错误(setup script 以非零状态退出)
  • Phase 4 失败检测(DataKitDeploymentLog 中存在失败项)
  • 调度冲突(触发 Phase 5 guard)
  • 任何其他阻塞情况(缺少输入、org 无法访问等)
将报告写入
${outputDir}/report.md
(即任务中
generatedFileLocationDirective
指定的路径)。不要只在聊天消息中打印报告——它必须作为文件存在于磁盘上。如果正确处理了场景,却从未写入文件,评测将记录
no_output
并得零分。

Deploy the Accrual Data Kit

部署 Accrual Data Kit

Installs the TPM Liability Accruals solution into a Salesforce org end to end. Runs the full setup toolchain bundled in
scripts/
: checks the org is ready, verifies the Data Cloud connection, downloads the
CGCloudAddons
static resource, deploys the data kit, confirms the deployment, and schedules the Data Cloud export and accrual calculation chain.
Designed for headless delivery: point it at an org and it runs the full install.
The namespace differs per build:
cgcloud
(released),
cgcloud_dev
(dev/beta), or no prefix (source-only). The setup script auto-detects the prefix at runtime via the
DataCloudExportScheduler
Apex class query. Never hardcode
cgcloud.
or
cgcloud_dev.
.
Run the setup script from the skill root directory:
bash
node scripts/setup.js --org <alias> [options]

将 TPM Liability Accruals 解决方案端到端安装到 Salesforce org 中。 运行
scripts/
中附带的完整 setup 工具链:检查 org 是否准备就绪、验证 Data Cloud 连接、下载
CGCloudAddons
static resource、部署 data kit、确认部署结果,并安排 Data Cloud export 和 accrual calculation chain。
该流程专为无头交付而设计:指向一个 org 后,它会执行完整安装。
命名空间因构建版本而异:
cgcloud
(已发布版本)、
cgcloud_dev
(开发/测试版),或无前缀(仅源码版本)。setup script 会在运行时通过查询
DataCloudExportScheduler
Apex class 自动检测前缀。切勿硬编码
cgcloud.
或
cgcloud_dev.
。
从 skill 根目录运行 setup script:
bash
node scripts/setup.js --org <alias> [options]

Inputs to collect

需要收集的输入

Collect and validate ALL required inputs before running any Phase 1 checks. Do not start Phase 1 until org alias and sales org name are both confirmed. If either is missing after asking, stop immediately and write the Phase 6 report.
Ask before starting — do not guess.
InputDefaultNotes
Org alias / username—
sf
alias of the target org. Required.
Sales org name—Used to name the Data Space (
DataSpace_<salesOrg>
), its prefix (
DS<lastChar>_
), and the UI controller map key. Required. Must be exactly 4 alphanumeric characters (e.g.
0001
,
AB12
). If the user has not provided it and cannot provide it, do NOT guess or use any default value — stop immediately, write the Phase 6 report with Phase 1 blocked ("sales org name not provided"), and end the session. Do not run any Phase 1 checks without it.
Skip Data Space?noYes only if the org has no Data Spaces (some demo orgs).
Dry run?noPrepares files; skips all deploys and scheduling. Offer this first.
Namespace overrideauto-detectedPass only if auto-detection would fail. Value WITHOUT trailing
__
.
Export cron
0 0 2 * * ?
Only prompt if user requests a different schedule.
Accrual chain cron
0 0 3 * * ?
Only prompt if user requests a different schedule.
The dry-run flag is collected once here and honored through all phases — do not re-prompt.

在运行任何 Phase 1 检查之前,收集并验证所有必需输入。 在 org alias 和 sales org name 均确认之前,不要开始 Phase 1。如果询问后仍缺少其中任意一项,请立即停止并编写 Phase 6 报告。
开始前先询问——不要猜测。
输入默认值备注
Org alias / username—目标 org 的
sf
alias。必填。
Sales org name—用于命名 Data Space(
DataSpace_<salesOrg>
)、生成其前缀(
DS<lastChar>_
)以及设置 UI controller map key。必填。必须恰好为 4 个字母数字字符(例如
0001
、
AB12
)。如果用户未提供且无法提供,切勿猜测或使用默认值——立即停止,编写 Phase 6 报告并标记 Phase 1 受阻(“sales org name not provided”),然后结束会话。没有该值时不要运行任何 Phase 1 检查。
跳过 Data Space?no仅当 org 中没有 Data Space 时才选择 yes(某些 demo org 可能如此)。
Dry run?no准备文件;跳过所有部署和调度。优先向用户提供此选项。
Namespace override自动检测仅当自动检测会失败时才传入。值末尾不得带
__
。
Export cron
0 0 2 * * ?
仅当用户要求其他调度计划时询问。
Accrual chain cron
0 0 3 * * ?
仅当用户要求其他调度计划时询问。
Dry-run 标志在此处收集一次,并在所有阶段中持续使用——不要重复询问。

Phase 1 — Preflight

Phase 1 — Preflight

Stop on first failure. Do not continue past a failed check.
遇到第一个失败项时立即停止。不要继续执行失败的检查。

1.1 Local tooling

1.1 本地工具

  1. Salesforce CLI present:
    sf --version
  2. Node 22:
    node --version
  1. Salesforce CLI 存在:
    sf --version
  2. Node 22:
    node --version

1.2 Org reachable

1.2 Org 可访问

bash
sf org display --target-org <alias> --json
Confirm
status
is
Active
. Capture
id
(org id),
instanceUrl
,
apiVersion
. Non-zero exit or inactive status → stop, ask user to log in.
bash
sf org display --target-org <alias> --json
确认
status
为
Active
。记录
id
(org id)、
instanceUrl
、
apiVersion
。 以非零状态退出或状态非 Active → 停止,并请用户登录。

1.3 Data Cloud Data Kit framework present

1.3 存在 Data Cloud Data Kit framework

bash
sf data query --target-org <alias> \
  --query "SELECT Id FROM DataKitDeploymentLog LIMIT 1"
INVALID_TYPE
or
NOT_FOUND
→ stop immediately: the Data Cloud Data Kit framework is not enabled in this org. Tell the user they must enable Data Cloud and the Data Kit feature before this skill can proceed. Write the Phase 6 report now with Phase 1 blocked and the exact query error. Do NOT run any further queries, downloads, or deploys. Zero rows is fine — the framework is present, continue to Phase 1.4.
bash
sf data query --target-org <alias> \
  --query "SELECT Id FROM DataKitDeploymentLog LIMIT 1"
出现
INVALID_TYPE
或
NOT_FOUND
→ 立即停止:此 org 未启用 Data Cloud Data Kit framework。 告知用户必须先启用 Data Cloud 和 Data Kit feature,此 skill 才能继续执行。立即编写 Phase 6 报告,标记 Phase 1 受阻,并附上确切的查询错误。不要运行任何后续查询、下载或部署。 返回零行没有问题——framework 已存在,继续执行 Phase 1.4。

1.4 CGCloudAddons static resource present

1.4 存在 CGCloudAddons static resource

bash
sf data query --target-org <alias> \
  --query "SELECT Id FROM StaticResource WHERE Name='CGCloudAddons'"
Zero rows → stop immediately: the managed package is not installed (or this version does not ship
CGCloudAddons
). Tell the user the package must be installed before proceeding. Write the Phase 6 report now with Phase 1 blocked:
CGCloudAddons not found
. Do NOT attempt to download, deploy, or schedule anything after this failure.
bash
sf data query --target-org <alias> \
  --query "SELECT Id FROM StaticResource WHERE Name='CGCloudAddons'"
返回零行 → 立即停止:managed package 未安装(或此版本不提供
CGCloudAddons
)。告知用户必须先安装该 package 才能继续。立即编写 Phase 6 报告,标记 Phase 1 受阻:
CGCloudAddons not found
。 发生此失败后,不要尝试下载、部署或调度任何内容。

1.5 Sales org validation

1.5 Sales org 验证

bash
sf data query --target-org <alias> --json \
  --query "SELECT Id, Name FROM Sales_Organization__c WHERE Name = '<salesOrg>'"
Zero rows → stop immediately: the sales org name provided does not exist in this org. Show the user the query and the zero-row result. Do NOT proceed to deploy or schedule. Record Phase 1 as blocked:
Sales org '<salesOrg>' not found
.
bash
sf data query --target-org <alias> --json \
  --query "SELECT Id, Name FROM Sales_Organization__c WHERE Name = '<salesOrg>'"
返回零行 → 立即停止:此 org 中不存在所提供的 sales org name。 向用户展示查询和零行结果。不要继续部署或调度。 记录 Phase 1 受阻:
Sales org '<salesOrg>' not found
。

1.6 Deployment baseline

1.6 部署基线

bash
sf data query --target-org <alias> --json \
  --query "SELECT MAX(CreatedDate) maxCreated FROM DataKitDeploymentLog"
The aggregate query always returns exactly one row.
maxCreated
is
null
when the table is empty (first-ever deployment). Store
DEPLOY_BASELINE_TIME = maxCreated ?? ''
(treat null as empty string). Phase 4 uses
WHERE CreatedDate > DEPLOY_BASELINE_TIME
only when
DEPLOY_BASELINE_TIME
is non-empty; omit the
WHERE
clause entirely when it is empty —
WHERE CreatedDate > null
is an
INVALID_QUERY_FILTER_OPERATOR
error in Salesforce SOQL and will abort the query.
bash
sf data query --target-org <alias> --json \
  --query "SELECT MAX(CreatedDate) maxCreated FROM DataKitDeploymentLog"
聚合查询始终恰好返回一行。当表为空时,
maxCreated
为
null
(首次部署)。存储
DEPLOY_BASELINE_TIME = maxCreated ?? ''
(将 null 视为空字符串)。Phase 4 仅在
DEPLOY_BASELINE_TIME
非空时使用
WHERE CreatedDate > DEPLOY_BASELINE_TIME
;当其为空时,完全省略
WHERE
子句——在 Salesforce SOQL 中,
WHERE CreatedDate > null
会触发
INVALID_QUERY_FILTER_OPERATOR
错误并中止查询。

1.7 Org-side manual prerequisites

1.7 Org 端手动前置条件

If the user's prompt already confirms these prerequisites, treat them as confirmed — do not re-ask. Only ask for items the user has not already addressed:
  • Data Cloud and Analytics Studio enabled (Setup → Data Cloud Setup)
  • Connectors feature enabled (Data Cloud Setup → Feature Manager)
  • A user assigned to the Accrual Ingestion Process in Processing Services Pairing with the Data Cloud Architect permission set
  • OAuth scope
    cdp_ingest_api
    on the TPM Offcore connected app
  • Licenses:
    AccrualsProcessingAddOn
    ,
    AccrualsProcessingUserAddOn
    ,
    TpmAccrualsAddOn
    ,
    TpmAccrualsUserAddOn
    (advisory — record what the user confirmed)

如果用户提示中已经确认这些前置条件,则视为已确认——不要重复询问。只询问用户尚未处理的项目:
  • 已启用 Data Cloud 和 Analytics Studio(Setup → Data Cloud Setup)
  • 已启用 Connectors feature(Data Cloud Setup → Feature Manager)
  • 已在 Processing Services Pairing 中为 Accrual Ingestion Process 分配用户,并为该用户启用 Data Cloud Architect permission set
  • TPM Offcore connected app 的 OAuth scope 包含
    cdp_ingest_api
  • Licenses:
    AccrualsProcessingAddOn
    、
    AccrualsProcessingUserAddOn
    、
    TpmAccrualsAddOn
    、
    TpmAccrualsUserAddOn
    (仅供参考——记录用户确认的内容)

Phase 2 — Verify the Data Cloud connection (best-effort)

Phase 2 — 验证 Data Cloud 连接(尽力而为)

Try to verify
cdp_ingest_api
by query — treat "cannot verify" as WARN, not STOP:
bash
sf data query --target-org <alias> \
  --query "SELECT Id, Name FROM ConnectedApplication WHERE Name LIKE '%TPM%'"
If the query errors on permissions, ask the user to confirm
cdp_ingest_api
is in Setup → App Manager → (edit TPM Offcore connected app) → OAuth Policies → Selected OAuth Scopes. Continue only after the user confirms.

尝试通过查询验证
cdp_ingest_api
——将“无法验证”视为 WARN,而不是 STOP:
bash
sf data query --target-org <alias> \
  --query "SELECT Id, Name FROM ConnectedApplication WHERE Name LIKE '%TPM%'"
如果查询因权限不足而报错,请用户确认
cdp_ingest_api
位于 Setup → App Manager →(编辑 TPM Offcore connected app)→ OAuth Policies → Selected OAuth Scopes 中。仅在用户确认后继续。

Phase 3 — Run the setup script

Phase 3 — 运行 setup script

Run the end-to-end setup script from the skill's own root directory. In dry-run mode, pass
--dry-run
.
bash
node scripts/setup.js --org <alias> --sales-org <salesOrg> [--skip-dataspace] [--dry-run] [--namespace <ns>]
If
scripts/setup.js
is not accessible in the current working directory, record Phase 3 as
not run — script path not accessible in this environment
in the Phase 6 report and proceed directly to Phase 4 (query
DataKitDeploymentLog
for any rows after
DEPLOY_BASELINE_TIME
).
The script runs these steps in order:
  • Step 0 — Prerequisites confirmation (interactive prompt, skipped in dry-run)
  • Step 1 — Download
    CGCloudAddons
    static resource
  • Step 2 — Replace
    __SF_ORG_ID__
    placeholders in data kit metadata
  • Step 3 — Deploy TPM Accruals Data Kit metadata (
    sf project deploy start
    )
  • Step 4 — Deploy Liability Accruals Engine data kit via
    sfdatakit__DeployDataKitComponents
    (skips already-deployed components; waits up to 30 min for completion)
  • Step 5 — Deploy TPM Accruals data kit via
    sfdatakit__DeployDataKitComponents
    (same pattern; also waits for completion)
  • Step 6 — Create Data Space (manual prompt — see below; skipped with
    --skip-dataspace
    )
  • Step 7 — Deploy Accruals Reports metadata with Data Space placeholder replacements (two-pass)
  • Step 8 — Deploy
    TPMAccrualTacticSummary
    UI component with namespace and Data Space replacements
  • Step 9 — Print scheduling instructions
The script pauses at Step 0 (prerequisites confirmation) and Step 6 (Data Space creation). When it pauses, capture the stdout block starting at
=== Step N:
and relay it verbatim to the user. Wait for the user to complete the step before continuing.
Adding the
TPMAccrualTacticSummary
UI component to the Promotion page is a post-run manual step — the script only prints the instruction. Track it as pending in Phase 6.
On non-zero exit → stop and surface the last 50 lines of stdout. Do not proceed to Phase 4 on a failed script.

从 skill 自身的根目录运行端到端 setup script。在 dry-run 模式下,传入
--dry-run
。
bash
node scripts/setup.js --org <alias> --sales-org <salesOrg> [--skip-dataspace] [--dry-run] [--namespace <ns>]
如果当前工作目录中无法访问
scripts/setup.js
,则在 Phase 6 报告中将 Phase 3 记录为
not run — script path not accessible in this environment
,并直接进入 Phase 4(查询
DEPLOY_BASELINE_TIME
之后的
DataKitDeploymentLog
行)。
该脚本按顺序执行以下步骤:
  • Step 0 — 前置条件确认(交互式提示,在 dry-run 中跳过)
  • Step 1 — 下载
    CGCloudAddons
    static resource
  • Step 2 — 替换 data kit metadata 中的
    __SF_ORG_ID__
    占位符
  • Step 3 — 部署 TPM Accruals Data Kit metadata(
    sf project deploy start
    )
  • Step 4 — 通过
    sfdatakit__DeployDataKitComponents
    部署 Liability Accruals Engine data kit(跳过已部署的组件;最长等待 30 分钟完成)
  • Step 5 — 通过
    sfdatakit__DeployDataKitComponents
    部署 TPM Accruals data kit(采用相同模式;同样等待完成)
  • Step 6 — 创建 Data Space(手动提示——详见下文;使用
    --skip-dataspace
    时跳过)
  • Step 7 — 部署 Accruals Reports metadata,并替换 Data Space 占位符(两轮处理)
  • Step 8 — 部署
    TPMAccrualTacticSummary
    UI component,并替换 namespace 和 Data Space
  • Step 9 — 打印调度说明
脚本会在 Step 0(前置条件确认)和 Step 6(创建 Data Space)处暂停。暂停时,捕获从
=== Step N:
开始的 stdout 块,并原样转发给用户。等待用户完成该步骤后再继续。
将
TPMAccrualTacticSummary
UI component 添加到 Promotion 页面是运行后需要手动完成的步骤——脚本只会打印说明。在 Phase 6 中将其记录为待处理项。
以非零状态退出 → 停止并展示 stdout 的最后 50 行。脚本失败后不要进入 Phase 4。

Phase 4 — Verify deployment

Phase 4 — 验证部署

Skip this entire phase in dry-run mode. Record it as
pending — not run (dry-run)
in the report.
bash
sf data query --target-org <alias> --json \
  --query "SELECT ComponentName, DeploymentStatus, DeploymentError, CreatedDate
           FROM DataKitDeploymentLog
           WHERE CreatedDate > ${DEPLOY_BASELINE_TIME}
           ORDER BY CreatedDate ASC
           LIMIT 200"
(Omit
WHERE
clause if
DEPLOY_BASELINE_TIME
is empty. Always include
LIMIT 200
.)
Evaluate the rows:
  • Any
    DeploymentStatus = 'Failure'
    or non-empty
    DeploymentError
    → stop, list every failing component name and its
    DeploymentError
    value. Do not proceed to Phase 5. Record Phase 5 as
    not run — deployment failures unresolved
    in the Phase 6 report.
  • Any
    InProgress
    row → wait 60 s and re-query. Do not advance to Phase 5 until all rows are in a terminal state (
    Successful
    or
    Failure
    ). If any row is still
    InProgress
    after 30 minutes, stop and surface the live counts.
  • Zero rows → the deployment has not produced log entries yet; re-query every 60 s up to 30 minutes. Treat persistent zero rows as a deployment problem — stop and report.
  • All rows
    Successful
    → proceed to Phase 5.
  • Never advance to Phase 5 while any row is
    InProgress
    ,
    Failure
    , or while zero rows have been returned within the polling window.

在 dry-run 模式下完全跳过此阶段。 在报告中记录为
pending — not run (dry-run)
。
bash
sf data query --target-org <alias> --json \
  --query "SELECT ComponentName, DeploymentStatus, DeploymentError, CreatedDate
           FROM DataKitDeploymentLog
           WHERE CreatedDate > ${DEPLOY_BASELINE_TIME}
           ORDER BY CreatedDate ASC
           LIMIT 200"
(如果
DEPLOY_BASELINE_TIME
为空,则省略
WHERE
子句。始终包含
LIMIT 200
。)
评估返回的行:
  • 任何
    DeploymentStatus = 'Failure'
    或
    DeploymentError
    非空 → 停止,列出每个失败组件的名称及其
    DeploymentError
    值。不要进入 Phase 5。在 Phase 6 报告中将 Phase 5 记录为
    not run — deployment failures unresolved
    。
  • 任何
    InProgress
    行 → 等待 60 秒后重新查询。在所有行都进入终止状态(
    Successful
    或
    Failure
    )之前,不要进入 Phase 5。
    如果 30 分钟后仍有行处于
    InProgress
    ,则停止并展示实时计数。
  • 零行 → 部署尚未生成日志条目;每 60 秒重新查询,最长等待 30 分钟。持续返回零行视为部署问题——停止并报告。
  • 所有行均为
    Successful
    → 进入 Phase 5。
  • 只要有任何行处于
    InProgress
    或
    Failure
    ,或者在轮询窗口内持续返回零行,就绝不进入 Phase 5。

Phase 5 — Schedule

Phase 5 — 调度

In dry-run mode: still run steps 5.1 (namespace detection — read-only) and 5.2 (cron job check — read-only), print the fully-substituted Apex that would be run, but do NOT execute
sf apex run
. Record Phase 5 as
pending — not run (dry-run)
in the report.
在 dry-run 模式下:仍执行步骤 5.1(namespace 检测——只读)和 5.2(cron job 检查——只读),打印完成所有替换的 Apex,但不要执行
sf apex run
。在报告中将 Phase 5 记录为
pending — not run (dry-run)
。

5.1 Detect namespace prefix

5.1 检测 namespace 前缀

Query the installed class (same probe used by
scripts/steps/utils.js
):
bash
sf data query --target-org <alias> --json \
  --query "SELECT NamespacePrefix FROM ApexClass WHERE Name='DataCloudExportScheduler'"
Query result
NS_PREFIX
Meaning
0 rows—Scheduler class not deployed → STOP: Phase 3 did not complete
1 row, null
""
Unmanaged source deploy
1 row, any valuethat valueUse whatever namespace the query returns
>1 row—Ambiguous → STOP, print all rows
Compose the dotted prefix:
bash
NS="${NS_PREFIX:+${NS_PREFIX}.}"    # yields "cgcloud.", "cgcloud_dev.", or ""
Every Apex identifier below is written as
${NS}ClassName
.
查询已安装的 class(与
scripts/steps/utils.js
使用的探测方式相同):
bash
sf data query --target-org <alias> --json \
  --query "SELECT NamespacePrefix FROM ApexClass WHERE Name='DataCloudExportScheduler'"
查询结果NS_PREFIX含义
0 行—Scheduler class 未部署 → 停止:Phase 3 未完成
1 行,值为 null
""
非托管源码部署
1 行,包含任意值该值使用查询返回的 namespace
超过 1 行—存在歧义 → 停止,打印所有行
拼接点分隔前缀:
bash
NS="${NS_PREFIX:+${NS_PREFIX}.}"    # yields "cgcloud.", "cgcloud_dev.", or ""
下方每个 Apex identifier 均写为
${NS}ClassName
。

5.2 Guard duplicate cron jobs

5.2 防止重复 cron job

bash
sf data query --target-org <alias> --json \
  --query "SELECT Id, State, CronJobDetail.Name FROM CronTrigger
           WHERE CronJobDetail.Name IN
             ('DataCloud Export Daily','TPM Accrual Process Chain')"
If any matching job exists:
  1. Show the user the existing job
    Id
    and
    State
    for each conflicting job.
  2. Ask explicitly: abort the existing jobs and reschedule, or skip scheduling?
  3. Do NOT silently overwrite — wait for the user's answer before calling
    System.schedule
    .
  4. If the user chooses to abort and reschedule: run
    System.abortJob('<id>')
    for each conflicting job, then proceed with 5.3/5.4 and verify the new
    CronTrigger
    shows
    State = 'WAITING'
    and non-null
    NextFireTime
    .
  5. Record the conflict and its resolution in the Phase 6 report.
Cron ordering requirement: the export job (5.3) must fire before the accrual chain job (5.4) so that Data Cloud data is available when the chain runs. The defaults (
exportCron
=
0 0 2 * * ?
,
accrualCron
=
0 0 3 * * ?
) enforce a 1-hour gap. When the user provides custom expressions, verify that the export cron precedes the accrual cron — a gap of at least 1 hour is the recommended convention. Warn the user if the two expressions conflict or are inverted; do not schedule without their confirmation.
bash
sf data query --target-org <alias> --json \
  --query "SELECT Id, State, CronJobDetail.Name FROM CronTrigger
           WHERE CronJobDetail.Name IN
             ('DataCloud Export Daily','TPM Accrual Process Chain')"
如果存在任何匹配 job:
  1. 向用户展示每个冲突 job 的
    Id
    和
    State
    。
  2. 明确询问用户:中止现有 job 并重新调度,还是跳过调度?
  3. 不要静默覆盖——必须等待用户回答,然后才能调用
    System.schedule
    。
  4. 如果用户选择中止并重新调度:对每个冲突 job 执行
    System.abortJob('<id>')
    ,然后继续执行 5.3/5.4,并验证新的
    CronTrigger
    显示
    State = 'WAITING'
    且
    NextFireTime
    非空。
  5. 在 Phase 6 报告中记录冲突及其解决方式。
Cron 顺序要求: export job(5.3)必须先于 accrual chain job(5.4)触发,以确保 chain 运行时已有 Data Cloud 数据。默认值(
exportCron
=
0 0 2 * * ?
,
accrualCron
=
0 0 3 * * ?
)会保持 1 小时间隔。当用户提供自定义表达式时,验证 export cron 是否早于 accrual cron——建议至少间隔 1 小时。如果两个表达式冲突或顺序颠倒,请警告用户;未经确认不得调度。

5.3 Schedule Data Cloud Connector Export

5.3 调度 Data Cloud Connector Export

Write the following Apex to a temporary file (e.g.
/tmp/dc-export.apex
), run it, then delete the file:
apex
${NS}DataCloudExportScheduler scheduler = new ${NS}DataCloudExportScheduler(
  new List<String>{ 'promotionmeasures', 'paymenttacticmeasures', 'dailymeasurereal' }
);
System.schedule('DataCloud Export Daily', '<exportCron>', scheduler);
bash
undefined
将以下 Apex 写入临时文件(例如
/tmp/dc-export.apex
),运行,然后删除文件:
apex
${NS}DataCloudExportScheduler scheduler = new ${NS}DataCloudExportScheduler(
  new List<String>{ 'promotionmeasures', 'paymenttacticmeasures', 'dailymeasurereal' }
);
System.schedule('DataCloud Export Daily', '<exportCron>', scheduler);
bash
undefined

Write to temp file, run, clean up

Write to temp file, run, clean up

cat > /tmp/dc-export.apex << 'EOF' <filled-in Apex from above> EOF sf apex run --target-org <alias> --file /tmp/dc-export.apex rm /tmp/dc-export.apex
Verify: `CronTrigger WHERE CronJobDetail.Name = 'DataCloud Export Daily'` → exactly one
row, `State = 'WAITING'`, non-null `NextFireTime`.
cat > /tmp/dc-export.apex << 'EOF' <filled-in Apex from above> EOF sf apex run --target-org <alias> --file /tmp/dc-export.apex rm /tmp/dc-export.apex
验证:`CronTrigger WHERE CronJobDetail.Name = 'DataCloud Export Daily'` → 恰好一行,`State = 'WAITING'`,`NextFireTime` 非空。

5.4 Schedule Accrual Calculation Chain

5.4 调度 Accrual Calculation Chain

Write the following Apex to a temporary file (e.g.
/tmp/accrual-chain.apex
), run it, then delete the file (see Rules — only
'partial'
or
'full'
are valid for
ingestionMode
):
apex
${NS}ScheduleTPMAccrualProcessChain scheduler =
  new ${NS}ScheduleTPMAccrualProcessChain();
System.schedule('TPM Accrual Process Chain', '<accrualCron>', scheduler);
bash
undefined
将以下 Apex 写入临时文件(例如
/tmp/accrual-chain.apex
),运行,然后删除文件(参见 Rules——
ingestionMode
仅接受
'partial'
或
'full'
):
apex
${NS}ScheduleTPMAccrualProcessChain scheduler =
  new ${NS}ScheduleTPMAccrualProcessChain();
System.schedule('TPM Accrual Process Chain', '<accrualCron>', scheduler);
bash
undefined

Write to temp file, run, clean up

Write to temp file, run, clean up

cat > /tmp/accrual-chain.apex << 'EOF' <filled-in Apex from above> EOF sf apex run --target-org <alias> --file /tmp/accrual-chain.apex rm /tmp/accrual-chain.apex
Verify with the same `CronTrigger` pattern as 5.3.

References:
- [DataCloudExportScheduler](https://developer.salesforce.com/docs/atlas.en-us.retail_api.meta/retail_api/cg_tpm_apex_datacloudexportscheduler.htm)
- [ScheduleTPMAccrualProcessChain](https://developer.salesforce.com/docs/atlas.en-us.retail_api.meta/retail_api/global_tpm_accrual_process.htm)

---
cat > /tmp/accrual-chain.apex << 'EOF' <filled-in Apex from above> EOF sf apex run --target-org <alias> --file /tmp/accrual-chain.apex rm /tmp/accrual-chain.apex
使用与 5.3 相同的 `CronTrigger` 模式进行验证。

参考:
- [DataCloudExportScheduler](https://developer.salesforce.com/docs/atlas.en-us.retail_api.meta/retail_api/cg_tpm_apex_datacloudexportscheduler.htm)
- [ScheduleTPMAccrualProcessChain](https://developer.salesforce.com/docs/atlas.en-us.retail_api.meta/retail_api/global_tpm_accrual_process.htm)

---

Phase 6 — Report

Phase 6 — 报告

Write this report after every run, including early stops. If execution was blocked at Phase 1 (missing inputs, failed preflight, Data Cloud not enabled, sales org not found), write the report immediately after confirming the stop condition — do not skip it. A correctly handled early stop that produces no report.md file is scored as a failure. If you are in an agentic eval context with a file-output directive, that directive means "write the file when you are done", not "write the file instead of working".
Write the report to disk using a shell command (e.g.
Write
tool or
cat > <path>
). Do not just print it as a chat message — it must exist as a file at the path specified in the task directive.
Keep early-stop reports short. When execution is blocked before Phase 3 starts (missing input, failed preflight), the report only needs to cover what actually happened: the block reason, what was not run, and what the user must provide to retry. Do NOT pad an early-stop report with boilerplate sections for phases that never ran (detailed DataKit deployment rows, schedule conflict resolution, license warnings, manual steps). Those sections are only relevant when the corresponding phases executed. A 3–5 line report is the correct shape for a Phase 1 block.
text
Deployment report — <org alias, or "not provided">
  Sales org: <salesOrg, or "not provided">
  Dry run: <yes|no>
  Namespace prefix: <detected value, or "(not detected — execution blocked)">
  Phase 1 preflight: <passed | blocked: <exact check that failed>>
  DataKit deployments: <X succeeded / Y failed / Z in progress, or "not run — Phase 1 blocked">
  Data Space: <created | skipped | not run — Phase 1 blocked>
  Data Cloud Export: <scheduled | dry-run | not run — Phase 1 blocked>
  Accrual Chain: <scheduled | dry-run | not run — Phase 1 blocked>
  Pending manual steps: <list, or "none — execution did not complete">
  License warnings: <unconfirmed licenses, or "none — not checked">

每次运行后都要编写此报告,包括提前停止的情况。 如果执行在 Phase 1 受阻(缺少输入、preflight 失败、Data Cloud 未启用、未找到 sales org),确认停止条件后立即编写报告——不要跳过。即使正确处理了提前停止的情况,只要没有生成 report.md 文件,就会被判定为失败。如果处于带有 file-output directive 的 agentic eval 环境中,该指令的含义是“完成后写入文件”,而不是“用写文件代替实际工作”。
使用 shell command 将报告写入磁盘(例如
Write
tool 或
cat > <path>
)。不要只在聊天消息中打印报告——它必须作为文件存在于任务指令指定的路径。
保持提前停止报告简短。 如果执行在 Phase 3 开始前受阻(缺少输入、preflight 失败),报告只需说明实际发生的情况:阻塞原因、未运行的内容,以及用户需要提供哪些内容才能重试。不要使用与未执行阶段相关的样板内容来填充提前停止报告(详细 DataKit 部署行、调度冲突解决情况、license 警告、手动步骤等)。Phase 1 阻塞时,3–5 行报告是正确形式。
text
Deployment report — <org alias, or "not provided">
  Sales org: <salesOrg, or "not provided">
  Dry run: <yes|no>
  Namespace prefix: <detected value, or "(not detected — execution blocked)">
  Phase 1 preflight: <passed | blocked: <exact check that failed>>
  DataKit deployments: <X succeeded / Y failed / Z in progress, or "not run — Phase 1 blocked">
  Data Space: <created | skipped | not run — Phase 1 blocked>
  Data Cloud Export: <scheduled | dry-run | not run — Phase 1 blocked>
  Accrual Chain: <scheduled | dry-run | not run — Phase 1 blocked>
  Pending manual steps: <list, or "none — execution did not complete">
  License warnings: <unconfirmed licenses, or "none — not checked">

Rules

Rules

  • Always execute before reporting. Run every phase to completion (or to a documented stop condition) before writing the Phase 6 report. Never write the report as a substitute for executing the skill — a file-output directive means "write when done", not "write instead of working".
  • Re-run means re-run. When asked to re-run or verify an existing deployment, always re-execute
    node scripts/setup.js
    and capture a fresh
    DataKitDeploymentLog
    baseline before doing so. Do not treat a prior successful run as sufficient — re-verify against fresh log rows from this run.
  • Never claim success while any
    DataKitDeploymentLog
    row for this run has
    DeploymentStatus = 'Failure'
    or a non-empty
    DeploymentError
    .
  • Never claim a schedule succeeded until
    CronTrigger
    shows
    State = 'WAITING'
    and non-null
    NextFireTime
    .
  • Stop on the first failed preflight check; report the exact failure.
  • Relay manual-step instructions verbatim from the setup script's stdout and wait for the user.
  • Never hardcode namespace prefixes in emitted Apex — always compose from
    ${NS}
    .
  • ingestionMode
    accepts only
    'partial'
    or
    'full'
    ;
    'initial'
    throws.
  • 报告前始终执行。 编写 Phase 6 报告前,应运行每个阶段直至完成(或达到有记录的停止条件)。切勿用编写报告代替执行 skill——file-output directive 表示“完成后写入”,而不是“不执行”。
  • 重新运行意味着真正重新运行。 当要求重新运行或验证现有部署时,始终重新执行
    node scripts/setup.js
    ,并在此之前获取新的
    DataKitDeploymentLog
    基线。不要将先前成功的运行视为充分依据——必须根据本次运行产生的新日志行重新验证。
  • 只要本次运行有任何
    DataKitDeploymentLog
    行的
    DeploymentStatus = 'Failure'
    或
    DeploymentError
    非空,就绝不宣称成功。
  • 在
    CronTrigger
    显示
    State = 'WAITING'
    且
    NextFireTime
    非空之前,绝不宣称调度成功。
  • 遇到第一个失败的 preflight 检查时立即停止;报告确切失败原因。
  • 原样转发 setup script stdout 中的手动步骤说明,并等待用户操作。
  • 绝不硬编码输出的 Apex namespace 前缀——始终根据
    ${NS}
    拼接。
  • ingestionMode
    仅接受
    'partial'
    或
    'full'
    ;传入
    'initial'
    将抛出异常。