@alipay/alipay-aipay 1.5.2-beta → 1.5.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (26) hide show
  1. package/README.md +1 -1
  2. package/package.json +3 -2
  3. package/skill/VERSION +1 -1
  4. package/skill/references/integration/flow.md +3 -3
  5. package/skill/references/integration/modules/sandbox/alipay-sandbox-tool.md +1 -1
  6. package/skill/references/normal/alipay-cli-env.md +1 -1
  7. package/skill/references/normal/full-process-routing.md +1 -1
  8. package/skill/references/normal/scripts/onboarding_discovery_runner.mjs +128 -13
  9. package/skill/references/normal/scripts/onboarding_message_runner.mjs +132 -47
  10. package/skill/references/normal/scripts/render_customer_message.mjs +3 -3
  11. package/skill/references/normal/scripts/runtime.mjs +69 -0
  12. package/skill/references/normal/scripts/telemetry.mjs +27 -26
  13. package/skill/references/normal/telemetry.md +4 -4
  14. package/skill/references/onboarding/flow.md +33 -21
  15. package/skill/references/onboarding/modules/app-release.md +3 -1
  16. package/skill/references/onboarding/modules/authorization.md +3 -2
  17. package/skill/references/onboarding/modules/error-handling.md +6 -2
  18. package/skill/references/onboarding/modules/product-sign.md +5 -1
  19. package/skill/references/onboarding/modules/scripts/app.sh +27 -10
  20. package/skill/references/onboarding/modules/scripts/ar_sign_apply.sh +6 -0
  21. package/skill/references/onboarding/modules/scripts/auth.sh +127 -37
  22. package/skill/references/onboarding/modules/scripts/error_handler.sh +108 -20
  23. package/skill/references/onboarding/modules/scripts/service.sh +9 -0
  24. package/skill/references/onboarding/modules/scripts/upload_screenshots.sh +10 -1
  25. package/skill/references/onboarding/modules/service-registration.md +1 -1
  26. package/skill/references/runtime-entry.md +6 -6
@@ -449,7 +449,7 @@ export function emitStageMetricAsync(stage, context = {}, env = process.env) {
449
449
  export function emitMessageMetric(messageId, variantName, variables = {}, context = {}) {
450
450
  try {
451
451
  const event = messageMetricEvent(messageId, variantName, variables, context);
452
- if (event?.stage === 'run.terminal' && telemetryEnabled()) updateExistingRunStateFromEvent(event);
452
+ if (event?.stage === 'run.terminal') updateExistingRunStateFromEvent(event);
453
453
  return emitMetricEvent(event, { stream: null });
454
454
  } catch {
455
455
  return false;
@@ -458,7 +458,6 @@ export function emitMessageMetric(messageId, variantName, variables = {}, contex
458
458
 
459
459
  export function emitTerminalMetric(context = {}) {
460
460
  try {
461
- if (!telemetryEnabled()) return false;
462
461
  const event = stageMetricEvent('run.terminal', context);
463
462
  if (!event) return false;
464
463
  updateExistingRunStateFromEvent(event);
@@ -1251,6 +1250,32 @@ function emitTelemetryError(error) {
1251
1250
  export async function runTelemetryCli(argv = process.argv) {
1252
1251
  try {
1253
1252
  const { command, args } = parseCliArgs(argv);
1253
+ if (command === 'start-run') {
1254
+ assertCliArgs(args, new Set(['root-intent', 'product-type', 'run-id']), 0);
1255
+ const state = createOrReuseRunState(args);
1256
+ if (!writeRunState(state) && telemetryEnabled(process.env)) {
1257
+ recordLocalTelemetryFailure('LOCAL_RUN_STATE_WRITE_FAILED', 'failed to write local telemetry run state');
1258
+ }
1259
+ if (telemetryEnabled(process.env)) {
1260
+ const event = stageMetricEvent('run.intent_detected', {
1261
+ runId: state.run_id,
1262
+ rootIntent: state.root_intent,
1263
+ productType: state.product_type
1264
+ });
1265
+ emitMetricEvent(event);
1266
+ }
1267
+ return 0;
1268
+ }
1269
+ if (command === 'current-run-id') {
1270
+ assertCliArgs(args, new Set(), 0);
1271
+ const state = canReadImplicitRunState(process.env) ? readRunState(process.env) : null;
1272
+ if (state?.run_id) {
1273
+ process.stderr.write(`${internalPrefix}RUN_ID=${state.run_id}\n`);
1274
+ } else {
1275
+ process.stderr.write(`${internalPrefix}RUN_ID_MISSING=true\n`);
1276
+ }
1277
+ return 0;
1278
+ }
1254
1279
  if (command === 'upload-status' && args._.length === 0) {
1255
1280
  assertCliArgs(args, new Set(), 0);
1256
1281
  const status = readUploadStatus(process.env) || { schema_ver: 1, status: 'unknown' };
@@ -1280,30 +1305,6 @@ export async function runTelemetryCli(argv = process.argv) {
1280
1305
  return 0;
1281
1306
  }
1282
1307
  if (!telemetryEnabled(process.env)) return 0;
1283
- if (command === 'start-run') {
1284
- assertCliArgs(args, new Set(['root-intent', 'product-type', 'run-id']), 0);
1285
- const state = createOrReuseRunState(args);
1286
- if (!writeRunState(state)) {
1287
- recordLocalTelemetryFailure('LOCAL_RUN_STATE_WRITE_FAILED', 'failed to write local telemetry run state');
1288
- }
1289
- const event = stageMetricEvent('run.intent_detected', {
1290
- runId: state.run_id,
1291
- rootIntent: state.root_intent,
1292
- productType: state.product_type
1293
- });
1294
- emitMetricEvent(event);
1295
- return 0;
1296
- }
1297
- if (command === 'current-run-id') {
1298
- assertCliArgs(args, new Set(), 0);
1299
- const state = canReadImplicitRunState(process.env) ? readRunState(process.env) : null;
1300
- if (state?.run_id) {
1301
- process.stderr.write(`${internalPrefix}RUN_ID=${state.run_id}\n`);
1302
- } else {
1303
- process.stderr.write(`${internalPrefix}RUN_ID_MISSING=true\n`);
1304
- }
1305
- return 0;
1306
- }
1307
1308
  if (command !== 'stage' || args._.length !== 1) {
1308
1309
  emitTelemetryError(new Error('invalid telemetry arguments'));
1309
1310
  return 0;
@@ -5,17 +5,17 @@
5
5
  ## 运行契约
6
6
 
7
7
  - 固定 stage 枚举、Yuyan 字段和低敏维度以 `scripts/telemetry.mjs` 的 `approvedStages`、事件构造器和测试为准。
8
- - `start-run` 创建或复用 `run_id`;动作 runner/script 使用异步子进程记录 stage。缺少 run、遥测关闭、落盘失败、网络失败和非 2xx 都不得改变业务 stdout、退出语义或 flow 转移。
8
+ - `start-run` 始终创建或复用当前流程 `run_id`;该私有 run context 是 alipay-cli `PLATFORM_ID` 和终态生命周期的运行事实,不依赖事件采集开关。动作 runner/script 在遥测开启时使用异步子进程记录 stage。缺少 run、遥测关闭、落盘失败、网络失败和非 2xx 都不得改变业务 stdout、退出语义或 flow 转移。
9
9
  - 前台只写用户系统临时目录下带 `alipay-aipay` 标识的私有 outbox,并启动后台补传;collector 返回 HTTP 2xx 后才删除记录。维护/测试进程不复用默认 run state,默认不远端上传。
10
- - `PLATFORM_ID` 必须等于当前 `run_id`;模型维度只读 `AIPAY_MODEL`,禁止读取用户项目通用 `MODEL` 推断。
10
+ - `PLATFORM_ID` 必须等于当前流程 `run_id`,遥测开关不得令其缺失或改变;模型维度只读 `AIPAY_MODEL`,禁止读取用户项目通用 `MODEL` 推断。
11
11
  - 遥测内部行统一使用 `ALIPAY_AIPAY_INTERNAL:` 前缀,禁止对客。
12
12
 
13
13
  ## Run 生命周期
14
14
 
15
15
  - 根入口用 `root_intent + product_type` 判定复用或新建;组合不变时不按经过时长失效,`UNKNOWN` 补全为明确产品仍复用同一 `run_id`。只有明确换产品、切换根意图或已有 run 终态才重建;用户只说“重新开始/重新走流程/作废本轮流程”但组合没有变化时继续复用。
16
- - 若宿主提供 `COZE_PROJECT_ID`、`MEOO_PROJECT_ID`,或 `MIAODA` 环境下的 `VITE_APP_ID`/`PLATFORM_ID`,新建 run 直接使用该项目 ID。当前宿主项目 ID 与已有状态不兼容时静默跳过不兼容事件且不改写 run state。
16
+ - 若宿主提供 `COZE_PROJECT_ID`、`MEOO_PROJECT_ID`,或 `MIAODA` 环境下的 `VITE_APP_ID`/`PLATFORM_ID`,新建 run 优先使用该项目 ID,不得被显式 run ID 或本地生成值覆盖。当前宿主项目 ID 与已有状态不兼容时静默跳过不兼容事件且不改写 run state。
17
17
  - `integration_only` 由 checklist 最终消息终止;`full_process` 的 Integration 收口不终止,和 `onboarding_only` 一样由 Onboarding closeout 终止。
18
- - 查看当前主键只使用 `current-run-id`,不得为查看而新建 run。业务脚本继续继承 `PLATFORM_ID=<run_id>`;Agent 不手写环境变量前缀或改写 MCP payload。
18
+ - 查看当前主键只使用 `current-run-id`,不得为查看而新建 run。关闭遥测只停止 `METRIC_EVENT`、outbox、上传和 flush,不停止 run context 的创建、读取与终态记账;业务脚本继续继承 `PLATFORM_ID=<run_id>`。Agent 不手写环境变量前缀或改写 MCP payload。
19
19
 
20
20
  ## 诊断与补传
21
21
 
@@ -7,7 +7,7 @@
7
7
 
8
8
  ## 执行入口与重启原则
9
9
 
10
- 只通过当前 Skill 绝对路径下的统一 runtime 按 marker 加载阶段,本 flow 仍是唯一执行依据:`entry`;非阻塞方案后 `execute --product-type "$PRODUCT_TYPE"`;发现后 `branch-summary`;轮到分支时 `signing|service|application --product-type "$PRODUCT_TYPE"`;最后 `closeout`。禁止整份预读;统一单命令规则继承 `runtime-entry.md`。仅脚本异常、用户要求解释或 phase 明示缺少依据时读取当前一个模块,禁止预读全部分支、凭记忆拼 MCP 或绕过 `auth.sh`。原 flow 保留完整规则供校验。
10
+ 只通过当前 Skill 绝对路径下的统一 runtime 按 marker 加载阶段,本 flow 仍是唯一执行依据:`entry`;非阻塞方案后 `execute --product-type "$PRODUCT_TYPE"`;发现后 `branch-summary`;轮到分支时 `signing|service|application --product-type "$PRODUCT_TYPE"`;最后 `closeout`。`onboarding_only` 根入口和方案后执行可使用 `runtime-entry.md` 登记的 `onboarding-bootstrap`、`onboarding-execute-ready` 组合动作合并无对客 stdout 的胶水调用;组合动作只串行调用这些真实 action,不跨用户输入、页面交付或业务写入,且执行后不得再重复对应原子命令。禁止整份预读;统一单命令规则继承 `runtime-entry.md`。仅脚本异常、用户要求解释或 phase 明示缺少依据时读取当前一个模块,禁止预读全部分支、凭记忆拼 MCP 或绕过 `auth.sh`。原 flow 保留完整规则供校验。
11
11
 
12
12
  每次开始都先校验登录、scope 和 MCC,再查询签约状态、应用候选和适用服务候选,并只依据当前真实结果继续。不得根据历史对话推定外部操作结果。
13
13
 
@@ -42,7 +42,7 @@
42
42
  - `P-DETERMINISTIC-HANDOFF`:flow 已登记脚本或 renderer 时只执行动作发生位置的固定命令;退出码和登记终态标记满足后立即按 flow 转移,禁止追加 jq、cat、grep、curl 或临时脚本重复解析、复核或解释同一结果。失败只走登记恢复分支;项目代码实现和运行验证除外,但不得把沙箱配置或其他敏感文件打印到工具输出。
43
43
  <!-- GENERATED:ONBOARDING-GUARDS:END -->
44
44
 
45
- 生成区块与 `SKILL.md` 红线适用于全部步骤。Onboarding 禁止修改用户项目代码或支付配置文件,只输出需由用户自行应用的配置;CLI 调用均由脚本设置 `PLATFORM`、`PLATFORM_ID`、`PRODUCT`;`aipay|webpay|apppay` 严格映射为 `AIPAY|WEBPAY|APPPAY`,`PRODUCT` 不进入 MCP 请求 JSON;禁止硬编码 `PLATFORM` 或分号拼环境变量。scope/MCC 不匹配只走 `auth.sh mismatch`;logout 未确认成功不得重授权;`AUTH_FLOW:RETRY_WITH_NETWORK` 或输出不可唯一解析只表示当前 Agent 执行环境无法确认结果,必须申请联网权限后重试同一条脚本命令,不得解释为用户本机 logout/login 失败或支付宝业务失败。签约 `request+ctx` 与应用/服务 `request` 由脚本冻结,禁止绕开脚本混用或重组。
45
+ 生成区块与 `SKILL.md` 红线适用于全部步骤。Onboarding 禁止修改用户项目代码或支付配置文件,只输出需由用户自行应用的配置;CLI 调用均由脚本设置 `PLATFORM`、`PLATFORM_ID`、`PRODUCT`;`aipay|webpay|apppay` 严格映射为 `AIPAY|WEBPAY|APPPAY`,`PRODUCT` 不进入 MCP 请求 JSON;禁止硬编码 `PLATFORM` 或分号拼环境变量。scope/MCC 不匹配只走 `auth.sh mismatch`;logout 后置条件未成立不得重授权;`AUTH_FLOW:RETRY_WITH_NETWORK` 或输出不可唯一解析只表示当前 Agent 执行环境无法确认结果,必须申请联网权限后重试同一条脚本命令,不得解释为用户本机 logout/login 失败或支付宝业务失败。签约 `request+ctx` 与应用/服务 `request` 由脚本冻结,禁止绕开脚本混用或重组。
46
46
 
47
47
  ### 标准消息执行规则
48
48
 
@@ -76,7 +76,7 @@ Step 1: 方案规划 → Step 2: 环境检查 → Step 3: 登录授权
76
76
  <!-- ALIPAY_AIPAY_FLOW:ONBOARDING_CORE:END -->
77
77
 
78
78
  <!-- ALIPAY_AIPAY_FLOW:ONBOARDING_ENTRY:START -->
79
- 进入任何产品开通环境检查、产品/MCC 澄清或方案展示前,先执行一次确定性平台入口:
79
+ 进入任何产品开通环境检查、产品/MCC 澄清或方案展示前,先执行一次确定性平台入口。`onboarding_only` 根入口正常使用 `runtime-entry.md` 的 `onboarding-bootstrap --root-intent onboarding_only` 完成本门禁和 entry 加载;原子 fallback 或 `full_process` 衔接 Onboarding 时执行下列命令:
80
80
 
81
81
  ```bash
82
82
  node "<SKILL_DIR>/references/normal/scripts/runtime.mjs" onboarding-message platform-entry
@@ -124,20 +124,26 @@ node "<SKILL_DIR>/references/normal/scripts/runtime.mjs" onboarding-message prod
124
124
 
125
125
  产品明确后,若用户尚未提供经营描述或已知 MCC,只执行 `node "<SKILL_DIR>/references/normal/scripts/runtime.mjs" onboarding-message mcc-clarify --product-type "$PRODUCT_TYPE"`,把 stdout 原文作为当前回复正文发给用户并停止本轮。`mcc-clarify` 只用于首次缺少检索输入;用户已经提供任何可检索描述后不得再次调用。
126
126
 
127
- 已有经营描述或明确类目时,将其作为 `MCC_SEARCH_QUERY` 执行唯一的本地确定性解析和方案展示入口;该命令不调用远程服务:
127
+ 已有经营描述或明确类目时,将其作为 `MCC_SEARCH_QUERY` 执行唯一 MCC 解析和方案展示入口;该命令不调用远程服务。除用户直接提供当前表内完整 MCC 编码且没有场景推断需求外,Agent 必须先只读取一次当前 `modules/mcc-reference.md`,基于用户原始经营描述独立判断实际交付商品/服务、商家角色、平台或直接经营模式、综合或垂直经营以及主要付费对象,只输出受控语义状态 `MATCHED|INSUFFICIENT|UNSUPPORTED` 和 0 到 3 个表内完整 MCC 编码。Agent 不得传入 MCC 名称、适用商家、特殊资质或表外编码,不得先调用旧确定性检索再让字符串候选锚定泛化判断。
128
128
 
129
129
  ```bash
130
+ # 用户直接提供当前表内完整 MCC 编码时
130
131
  node "<SKILL_DIR>/references/normal/scripts/runtime.mjs" onboarding-message mcc-resolve-plan --query "$MCC_SEARCH_QUERY" --product-type "$PRODUCT_TYPE"
132
+
133
+ # 经营描述或非完整 MCC 编码输入时
134
+ node "<SKILL_DIR>/references/normal/scripts/runtime.mjs" onboarding-message mcc-resolve-plan --query "$MCC_SEARCH_QUERY" --product-type "$PRODUCT_TYPE" --agent-mcc-status "$AGENT_MCC_STATUS" [--agent-mcc-codes "$AGENT_MCC_CODES"]
131
135
  ```
132
136
 
133
- 只接受唯一 `ALIPAY_AIPAY_INTERNAL:MCC_RESOLUTION=<json>`:`matchType=UNIQUE` 时必须恰有一条候选,stdout 已直接渲染同一候选绑定的 `onboarding.plan.confirm`,必须原文发送但不停止、不等待回复,随后立即进入 `execute`;`MULTIPLE` 时 runner stdout 已直接渲染固定候选消息,必须原文发送并停止,等待用户回复序号、MCC 二级类目名称或编码;`NONE` 时 runner stdout 已直接渲染独立 `onboarding.mcc.no_match`,必须原文发送并停止。禁止再次调用旧的 `mcc-search`/`mcc-candidates` 组合、自由拼候选表、解释、示例或“是否继续”等近似问法。
137
+ `AGENT_MCC_STATUS` 仅允许 `MATCHED|INSUFFICIENT|UNSUPPORTED`;`MATCHED` 必须提供 1 到 3 个用英文逗号分隔的完整编码,后两者不得提供编码。runner 会重新执行确定性召回并校验 Agent 编码确实存在于当前 MCC 表,名称、适用商家和特殊资质全部从同一表重建;非法、重复、超量、状态与候选数量矛盾或表外编码均为 Skill 契约错误,禁止降级为 Agent 自报结果。只有 `MATCHED` 才允许把确定性候选与 Agent 候选合并推进;`INSUFFICIENT|UNSUPPORTED` 时确定性候选只作为内部诊断记录,不得覆盖语义状态自动输出方案或进入授权。确定性候选最多 5 个,最终合并候选最多 8 个;交集候选优先,其次是确定性强命中、Agent 独立候选和确定性弱命中。按次收费、支付渠道和目标产品只用于产品决策,不能改变 MCC 排名。
138
+
139
+ 只接受唯一 `ALIPAY_AIPAY_INTERNAL:MCC_RESOLUTION=<json>`,其中必须包含 `semanticStatus`、`deterministicCandidateCodes`、`agentCandidateCodes`、`mergedCandidateCodes` 和 `mccTableSummary`:`matchType=UNIQUE` 时必须恰有一条候选,stdout 已直接渲染同一候选绑定的 `onboarding.plan.confirm`,必须原文发送但不停止、不等待回复,随后立即进入 `execute`;`MULTIPLE` 时 runner stdout 已直接渲染固定候选消息,必须原文发送并停止,等待用户回复序号、MCC 二级类目名称或编码;`NONE` 时 runner stdout 已直接渲染独立 `onboarding.mcc.no_match`,必须原文发送并停止。禁止再次调用旧的 `mcc-search`/`mcc-candidates` 组合、自由拼候选表、解释、示例或“是否继续”等近似问法。
134
140
 
135
- 用户回复序号时,只能映射到上一条 `mcc-resolve-plan` stdout 中同一份候选表的对应行,并把该行完整 MCC 编码作为新的 `MCC_SEARCH_QUERY` 再执行同一 `mcc-resolve-plan`;用户回复 MCC 二级类目名称、编码或新的经营描述时也自动作为新查询执行同一入口。`UNIQUE` 直接输出非阻塞方案;`MULTIPLE|NONE` 继续使用 runner 本次真实 stdout。无需固定重试口令,不得猜测或追加近似候选。
141
+ 用户回复序号、当前候选表中的完整 MCC 名称或编码时,只能映射到上一条 `mcc-resolve-plan` stdout 中同一份候选快照的对应行,并把该行完整 MCC 编码作为新的 `MCC_SEARCH_QUERY` 再执行同一精确校验入口,不重新运行 Agent 泛化或扩大候选;候选、MCC 表摘要或原始经营描述变化后旧选择失效。用户提供新的经营描述时才开始新一轮双路召回。`UNIQUE` 直接输出非阻塞方案;`MULTIPLE|NONE` 继续使用 runner 本次真实 stdout。无需固定重试口令,不得猜测或追加近似候选。
136
142
 
137
143
  产品确定后,`salesCode`、`scope` 和材料要求统一取自“一、产品映射”,禁止在本步骤另建映射或改写固定值。
138
144
 
139
145
  **MCC类目**:
140
- - 正常唯一命中使用 runner 返回的表内原值;只有非唯一命中才按需读取 `modules/mcc-reference.md`
146
+ - 用户直接提供当前表内完整 MCC 编码时,由 runner 精确校验并使用表内原值,不读取 `modules/mcc-reference.md` 做 Agent 泛化;其余经营描述无论确定性召回结果为唯一、多候选或无匹配,都必须先按上文只读取一次该文件完成 Agent 语义判断
141
147
  - 示例:互联网综合电商平台 (A0002_B0114)
142
148
  - mccCode 格式:`Axxxx_Bxxxx`
143
149
 
@@ -152,9 +158,9 @@ node "<SKILL_DIR>/references/normal/scripts/runtime.mjs" onboarding-message mcc-
152
158
 
153
159
  方案必须由上方 `mcc-resolve-plan` 或已持有唯一 MCC 事实时的统一 runtime `onboarding-message plan-confirm` 动作生成;禁止直接调用 renderer 或用 `jq/printf` 拼输入。三个产品变体都固定展示企业账号边界和支付宝商家平台链接,不得删减或改写。MCC 名称、编码和特殊资质必须逐字来自 runner 唯一命中或 `mcc-reference.md` 的同一行,并通过 runner 内部 renderer 交叉校验;特殊资质为 `-` 时固定显示“当前类目参考表未列出”,不得解释为企业/个人资格结论。禁止自由补充主体资格、营业执照、审核规则或其他模板未列出的前提。用户明确表示企业账号要通过 Skill 完成产品开通时,改用 `enterprise-unsupported` 并停止产品开通,不得继续生成授权或收集材料。产品或 MCC 事实变化时重新校验并渲染完整方案。字段齐备后不得先输出产品判断、材料预告、企业账号提示或待办;runner stdout 是 Step 1 唯一对客消息,必须把 stdout 原文作为非阻塞消息发给用户,然后直接进入执行,不等待用户回复。
154
160
 
155
- 产品无法可靠识别时只使用上方 `product-clarify`;产品明确但尚无 MCC 检索输入时只使用一次 `mcc-clarify`;已有检索输入后统一使用 `mcc-resolve-plan`,由 runner 直接返回方案、候选或 `onboarding.mcc.no_match`。用户已经明确提供的信息不得重复询问;只有产品和唯一 MCC 事实都通过机器校验后才能执行 `login`。登录后必须先执行 Step 3.1 的只读查询,再根据实际结果收集签约、服务和应用分支的必要资料。
161
+ 产品无法可靠识别时只使用上方 `product-clarify`;产品明确但尚无 MCC 检索输入时只使用一次 `mcc-clarify`;已有检索输入后统一使用 `mcc-resolve-plan`,由 runner 直接返回方案、候选或 `onboarding.mcc.no_match`。不得保留“先运行旧字符串搜索,无匹配后再临时让 Agent 猜”的两阶段对客流程;同一经营描述不得自动循环、重复加载完整 MCC 表或连续输出近似澄清消息。用户已经明确提供的信息不得重复询问;只有产品和唯一 MCC 事实都通过机器校验后才能执行 `login`。登录后必须先执行 Step 3.1 的只读查询,再根据实际结果收集签约、服务和应用分支的必要资料。
156
162
 
157
- **自动推进规则(执行约束,不是对客正文)**:只有产品、MCC 名称、MCC 编码、特殊资质和固定授权范围都由同一条唯一匹配事实交叉校验通过,才允许输出方案并立即执行统一 runtime 的 `flow onboarding execute --product-type "$PRODUCT_TYPE"`。缺少实际入参、结果为多候选/无匹配、字段冲突或校验证据不足时必须停留在 Step 1 澄清,禁止靠默认值推进。产品或 MCC 在进入 loader 前发生变化时重新校验和渲染方案。loader 继续在相同转移位置记录兼容 stage `onboarding.user_confirmed`,该 stage 表示已基于完整确定事实进入执行,不表示收到额外确认回复;禁止手工上报或伪造用户回复。
163
+ **自动推进规则(执行约束,不是对客正文)**:只有产品、MCC 名称、MCC 编码、特殊资质和固定授权范围都由同一条唯一匹配事实交叉校验通过,才允许输出方案并立即执行统一 runtime 的 `onboarding-execute-ready --product-type "$PRODUCT_TYPE"`;原子 fallback 才拆为 `flow onboarding execute --product-type "$PRODUCT_TYPE"` 后接 `env check --product-type "$PRODUCT_TYPE"`。缺少实际入参、结果为多候选/无匹配、字段冲突或校验证据不足时必须停留在 Step 1 澄清,禁止靠默认值推进。产品或 MCC 在进入 loader 前发生变化时重新校验和渲染方案。execute loader 继续在相同转移位置记录兼容 stage `onboarding.user_confirmed`,该 stage 表示已基于完整确定事实进入执行,不表示收到额外确认回复;禁止手工上报或伪造用户回复。
158
164
 
159
165
  <!-- ALIPAY_AIPAY_FLOW:ONBOARDING_ENTRY:END -->
160
166
 
@@ -162,16 +168,18 @@ node "<SKILL_DIR>/references/normal/scripts/runtime.mjs" onboarding-message mcc-
162
168
  <!-- ALIPAY_AIPAY_STAGE:onboarding.user_confirmed -->
163
169
  ### Step 2: 环境检查
164
170
 
165
- Step 1 当前方案已基于完整确定事实输出后,立即进入本 flow 的 `execute` 阶段;阶段 loader 在原位置记录兼容 stage `onboarding.user_confirmed`。随后执行只读环境检查:
171
+ Step 1 当前方案已基于完整确定事实输出后,正常路径执行组合动作;其内部先进入本 flow 的 `execute` 阶段并在原位置记录兼容 stage `onboarding.user_confirmed`,随后执行只读环境检查:
166
172
 
167
173
  ```bash
168
- node "<SKILL_DIR>/references/normal/scripts/runtime.mjs" env check --product-type "$PRODUCT_TYPE"
174
+ node "<SKILL_DIR>/references/normal/scripts/runtime.mjs" onboarding-execute-ready --product-type "$PRODUCT_TYPE"
169
175
  ```
170
176
 
171
177
  - 唯一 `CLI_ENV:READY`:直接进入 Step 3,不读取完整安装文档。
172
178
  - `CLI_ENV:NEEDS_SETUP`:此时才读取 `../normal/alipay-cli-env.md`,按其现有安装、PATH、联网权限和验证规则补齐缺失项,再重跑同一检查;未取得 `READY` 不得进入 Step 3。
173
179
  - 其他输出、非 0 或 marker 冲突:停在本步骤核对脚本,不得猜测环境已就绪。
174
180
 
181
+ 若组合动作本身不可用,原子 fallback 固定为先执行 `node "<SKILL_DIR>/references/normal/scripts/runtime.mjs" flow onboarding execute --product-type "$PRODUCT_TYPE"`,再执行 `node "<SKILL_DIR>/references/normal/scripts/runtime.mjs" env check --product-type "$PRODUCT_TYPE"`;fallback 不得重复 stage 或重复环境检查。
182
+
175
183
  签约脚本仍通过 `error_handler.sh -> common.sh` 初始化 `DEV_TOOL_NAME`、`PLATFORM`、当前 `run_id` 对应的 `PLATFORM_ID` 和当前产品对应的 `PRODUCT`。有任务工具时只在内部记录实际阶段,不手工维护任务数量;只保留当前对话所需最小上下文,不创建业务进度文件。
176
184
 
177
185
  本步骤成功时不输出“环境检查完成”“任务已创建”等对客消息,直接进入 Step 3;只有安装失败、权限不足或缺少必需工具时才输出实际问题和恢复动作。工具能力差异不得导致任务、步骤或完成状态被省略。
@@ -193,6 +201,7 @@ Step 1 的产品/MCC 唯一事实校验和方案送达、Step 2 的环境 READY
193
201
  1. node "<SKILL_DIR>/references/normal/scripts/runtime.mjs" auth init --defer-open --scope "$SCOPE" --sales-code "$SALES_CODE" --mcc-code "$MCC_CODE" --product-name "$PRODUCT_NAME" --mcc-name "$MCC_NAME"
194
202
  ├─ AUTH_FLOW:SKIP → 进入 Step 3.1并复用合法签约查询事实
195
203
  ├─ AUTH_FLOW:READY_TO_OPEN → 输出非阻塞授权页,执行第 2 项
204
+ │ └─ 若同时存在 AUTH_STATE:SAVE_FAILED:授权页 stdout 已送达,后续 open 仅可降级为 AUTH_OPEN:LINK_ONLY;wait/confirm 仍使用本条命令显式上下文继续,禁止重新生成授权页
196
205
  ├─ AUTH_FLOW:SCOPE_MISMATCH / MCC_MISMATCH → 执行第 4 项
197
206
  ├─ AUTH_FLOW:RETRY_WITH_NETWORK → 取得联网权限后重试同一完整命令
198
207
  └─ AUTH_FLOW:FAILED → 停止并按错误输出恢复,禁止进入 Step 3.1
@@ -213,7 +222,8 @@ Step 1 的产品/MCC 唯一事实校验和方案送达、Step 2 的环境 READY
213
222
  ├─ AUTH_FLOW:READY_TO_OPEN → 输出非阻塞授权页并按第 2 项执行 open + wait
214
223
  ├─ AUTH_FLOW:CONTEXT_MISMATCH → 未执行 logout;使用当前已确认的完整参数重新执行第 1 项
215
224
  ├─ AUTH_FLOW:RETRY_WITH_NETWORK → 取得联网权限后重试同一完整命令
216
- └─ mismatch 统一 logout;成功后用正确 scope 重建授权页
225
+ ├─ AUTH_FLOW:LOGOUT_STILL_LOGGED_IN → logout 后置条件未成立;禁止 login、签约查询和其他 onboarding 动作,排除本机登录态后重试第 4 项
226
+ └─ mismatch 统一 logout;后置条件成立后用正确 scope 重建授权页
217
227
  ```
218
228
 
219
229
  `AUTH_FLOW:CONTEXT_MISMATCH` 适用于 `open|wait|confirm|mismatch` 的显式上下文与同一次 init 短时状态不一致;脚本必须在任何 `login --complete/logout` 前停止且不输出对客正文。Agent 不得忽略差异、改用旧状态继续或手工清理状态;必须立即用当前 Step 1 已确认的完整参数重新执行第 1 项。新的 init 先完成固定产品/MCC 机器校验,再安全替换旧短时状态;若 CLI 仍处于登录态,因为签约查询没有权威 MCC 字段,init 必须返回对应 `SCOPE_MISMATCH/MCC_MISMATCH` 并转第 4 项,不得返回 `SKIP`。CLI 未登录时直接生成当前上下文的新授权页。两种分支都不得复用旧 deviceCode 或新增用户确认。
@@ -233,8 +243,8 @@ Step 1 的产品/MCC 唯一事实校验和方案送达、Step 2 的环境 READY
233
243
  授权成功后执行全部适用只读查询,不增加确认。直接从本 flow 目录执行唯一 discovery runner;runner 在内部并发调用现有只读脚本、解析查询语义并隔离普通分支失败,正常成功路径不再预读 `product-sign.md`、`service-registration.md` 或 `app-release.md` 查询章节。不得拆回 Agent 手工并发、改写底层命令或自行合并 MCP:
234
244
 
235
245
  ```bash
236
- # auth.sh 已提供合法可复用签约事实时,追加同一组 --reuse-sign-status/--reuse-sign-flow;否则不传。
237
- node "<SKILL_DIR>/references/normal/scripts/runtime.mjs" onboarding-discovery run --product-type "$PRODUCT_TYPE" --sales-code "$SALES_CODE" [--reuse-sign-status "$SIGN_STATUS" --reuse-sign-flow "$SIGN_FLOW"]
246
+ # auth.sh 已提供合法 AUTH_SIGN_REUSE_RECEIPT 时,优先原样追加 --reuse-sign-receipt;否则不传。
247
+ node "<SKILL_DIR>/references/normal/scripts/runtime.mjs" onboarding-discovery run --product-type "$PRODUCT_TYPE" --sales-code "$SALES_CODE" [--reuse-sign-receipt "$AUTH_SIGN_REUSE_RECEIPT"]
238
248
  ```
239
249
 
240
250
  只接受唯一 `ALIPAY_AIPAY_INTERNAL:DISCOVERY_RESULT=<json>`。runner stdout 保留底层脚本已有的受控错误正文,并在没有全局授权阻断时追加原 `onboarding.discovery.summary` 标准正文;必须原文送达,不得手写、压缩或再次调用 `discovery-summary`。envelope 中每个分支只允许 `SUCCESS|QUERY_FAILED|NOT_APPLICABLE`:成功分支携带原脚本的确定状态和候选,失败不得伪装为空列表;存在 `global_blocker=AUTHORIZATION_INVALID` 时停止查询组,按 Step 3 重新授权,不进入 Step 4。
@@ -243,7 +253,7 @@ node "<SKILL_DIR>/references/normal/scripts/runtime.mjs" onboarding-discovery ru
243
253
 
244
254
  Step 5 直接使用对应 phase 的完整命令;仅出现脚本异常、需要解释登记业务语义或用户明确要求详情时读取当前分支模块,错误恢复时才读取 `error-handling.md`。不得提前加载其他分支,也不重复读取已经读过且未变化的章节。
245
255
 
246
- 1. 签约:若本次成功的 `auth.sh init|wait|confirm` 内部事实同时且唯一包含 `AUTH_SIGN_QUERY_REUSABLE=true`、合法 `SIGN_STATUS` 和匹配当前产品的 `FLOW:*`,把后两项原样传给 runner 复用;三者缺失、冲突、重复或解析失败时不传复用参数,由 runner 执行原 `query_sign_status.sh` 完整命令。复用只省略同一请求的重复调用,不省略签约分支错误检测和状态处理。
256
+ 1. 签约:若本次成功的 `auth.sh init|wait|confirm` 内部事实同时且唯一包含 `AUTH_SIGN_QUERY_REUSABLE=true`、合法 `AUTH_SIGN_REUSE_RECEIPT`,把回执原样传给 runner 复用;回执缺失、冲突、重复或解析失败时不传复用参数,由 runner 执行原 `query_sign_status.sh` 完整命令。兼容窗口内,旧事实 `SIGN_STATUS + FLOW:*` 仍可通过 `--reuse-sign-status "$SIGN_STATUS" --reuse-sign-flow "$SIGN_FLOW"` 传入,`FLOW:` 前缀可带可不带;runner 必须校验 status/flow、productType 和 salesCode 一致,合法 `OTHER_STATUS + FLOW:OTHER_STATUS` 只表示待核验,禁止重复签约。复用只省略同一请求的重复调用,不省略签约分支错误检测和状态处理。
247
257
  2. 服务:仅按量付费由 runner 执行原 `service.sh list`;其他产品 envelope 固定为 `NOT_APPLICABLE`。成功候选只取 envelope 的 `service.candidates`。
248
258
  3. 应用:runner 执行原 `app.sh list --product-type "$PRODUCT_TYPE" --sales-code "$SALES_CODE"`。成功候选和 `WEBAPP|MOBILEAPP` 只取 envelope 的 application 分支;不得宣称返回应用已与当前支付产品绑定。
249
259
 
@@ -253,7 +263,7 @@ Step 5 直接使用对应 phase 的完整命令;仅出现脚本异常、需要
253
263
 
254
264
  所有内部事实行都必须以 `ALIPAY_AIPAY_INTERNAL:` 开头;宿主合并 stdout/stderr 时也逐行剔除。无前缀的相似文本不得作为流程事实;唯一字段缺失、重复或冲突时按结构异常处理。
255
265
 
256
- - MCP 认证失败或产品/scope/MCC 授权不匹配:立即停止查询组,不再调用剩余查询;授权不匹配时调用 Step 3 的 `auth.sh mismatch`,由该命令统一 logout 并重新授权。重新授权后仅恢复尚未执行的查询,保留重新授权前已经成功取得且主体未变化的结果。若无法确认仍为同一账号主体,则重新执行全部适用查询。
266
+ - MCP 认证失败或产品/scope/MCC 授权不匹配:discovery runner 子查询只上报认证失效事实,不在并发子进程内 logout;立即停止查询组,不再处理剩余查询结果。授权不匹配时调用 Step 3 的 `auth.sh mismatch`,由该命令统一 logout 并重新授权。重新授权后仅恢复尚未执行的查询,保留重新授权前已经成功取得且主体未变化的结果。若无法确认仍为同一账号主体,则重新执行全部适用查询。
257
267
  - 单个业务失败、响应结构错误或 MCP 服务失败,但当前会话仍有效:把该分支标记为查询失败,继续其他不依赖该结果的只读查询,最后一次性输出“已取得结果 + 失败分支”摘要。不得把失败视为空列表;应用查询失败时禁止应用复用/创建,服务查询失败时禁止服务复用/新建/修改。
258
268
  - 签约查询失败:只阻断签约分支;可继续应用/服务查询、候选展示、资源决策及其独立资料采集和写操作。不得推断签约状态,不得采集签约截图或签约所需 APP 名称,`signStatus` 和签约 `materialStatus` 保持未设置。签约查询恢复成功后,只有状态为 `NOT_SIGNED` 才进入签约材料类别。应用或服务查询失败也只阻断对应分支;认证失败、授权不匹配或无法确认登录主体一致时仍是全局阻断。
259
269
 
@@ -329,7 +339,7 @@ APP 支付未签约时的签约字段:
329
339
  **脚本**:
330
340
  - `node "<SKILL_DIR>/references/normal/scripts/runtime.mjs" screenshots --product-type "$PRODUCT_TYPE" <img1> <img2> <img3>` - 上传3张截图;用户可拖拽上传图片,Agent 将拖拽后的本地文件路径传给脚本
331
341
 
332
- 上传成功时只把脚本 stdout 的“截图上传成功”原文对客;从带统一前缀的 `SCREENSHOT_HOME_REF`、`SCREENSHOT_SHOP_REF`、`SCREENSHOT_PAY_REF` 内部事实按首页、商品页、支付页顺序记录三个图片引用,严禁对客展示这些引用或 `collect_information` 等内部状态。APP 支付同时保留已校验的 APP 名称。
342
+ 上传成功时只把脚本 stdout 的“截图上传成功”原文对客;从带统一前缀的 `SCREENSHOT_HOME_REF`、`SCREENSHOT_SHOP_REF`、`SCREENSHOT_PAY_REF` 内部事实按首页、商品页、支付页顺序记录三个图片引用,严禁对客展示这些引用或 `collect_information` 等内部状态。三张并行上传遇到认证失效时只允许产生一个全局 `AUTH_FLOW:AUTH_REQUIRED|RETRY_WITH_NETWORK|LOGOUT_STILL_LOGGED_IN` 事实,禁止并发或重复 logout;APP 支付同时保留已校验的 APP 名称。
333
343
 
334
344
  ### Step 5: 产品开通推进
335
345
 
@@ -389,7 +399,7 @@ node "<SKILL_DIR>/references/normal/scripts/runtime.mjs" sign --product apppay -
389
399
  ```
390
400
  <!-- ALIPAY_AIPAY_PRODUCT:END -->
391
401
 
392
- 提交成功后不等待或轮询签约生效,只记录“已提交,等待生效”。服务和应用是否推进只取决于各自前置条件,不取决于本次签约提交是否成功;复用 Step 3.1 和 Step 4 的成功结果,只在会话、主体、候选资源变化或原查询失败时刷新受影响分支,刷新失败不清除其他成功结果。
402
+ 提交成功后不等待或轮询签约生效,只记录“已提交,等待生效”。脚本成功必须同时产生 `SIGN_APPLY_RESULT=SUCCESS` 与对应产品 `FLOW:*_SIGN_CONTINUE`;响应不明且查询无法核验时产生 `SIGN_APPLY_RESULT=UNKNOWN`,本签约分支进入“结果未知/禁止重复提交”待办;明确未发送重试耗尽、业务失败或结构明确失败产生 `SIGN_APPLY_RESULT=FAILED`,本签约分支失败。服务和应用是否推进只取决于各自前置条件,不取决于本次签约提交是否成功;复用 Step 3.1 和 Step 4 的成功结果,只在会话、主体、候选资源变化或原查询失败时刷新受影响分支,刷新失败不清除其他成功结果。
393
403
 
394
404
  <!-- ALIPAY_AIPAY_FLOW:ONBOARDING_SIGNING:END -->
395
405
 
@@ -412,6 +422,8 @@ node "<SKILL_DIR>/references/normal/scripts/runtime.mjs" service save --name "<n
412
422
  node "<SKILL_DIR>/references/normal/scripts/runtime.mjs" service save --service-id "<serviceId>" --name "<name>" --desc "<desc>" --url "<url>" --pricing "<pricing>" --schema "<json>"
413
423
  ```
414
424
 
425
+ `service save` 成功必须产生 `SERVICE_SAVE_RESULT=SUCCESS` 和实际 `SERVICE_ID`;创建/修改响应不明且只读查询无法唯一核验时产生 `SERVICE_SAVE_RESULT=UNKNOWN`,服务分支进入“结果未知/禁止重复保存”待办;明确未发送重试耗尽、业务失败或结构明确失败产生 `SERVICE_SAVE_RESULT=FAILED`,只终止服务分支,不清除签约或应用分支已取得事实。
426
+
415
427
  <!-- ALIPAY_AIPAY_FLOW:ONBOARDING_SERVICE:END -->
416
428
 
417
429
  <!-- ALIPAY_AIPAY_FLOW:ONBOARDING_APPLICATION:START -->
@@ -468,7 +480,7 @@ node "<SKILL_DIR>/references/normal/scripts/runtime.mjs" onboarding-message appl
468
480
 
469
481
  公钥页 stdout 必须先作为独立对客消息送达,再执行 `app.sh open-key-page "<appId>"` 和对应校验;不得把后续 `application.key.pending` 或最终收口合并到同一条对客回复中。自动打开成功、后续轮询成功或后续 stdout 为空都不能替代实际 `confirmPageUrl` 交付。校验生产固定最多 20 次、间隔 2 秒,成功即停;新建分支复用最终安全密钥响应完成双公钥 guard 后提审,禁止重复查询,guard 失败不提审。耗尽才输出 `application.key.pending`;用户随后给出登记的明确肯定回复时,只执行上方对应的 `onboarding_recovery_runner.mjs application-key` 命令,由 runner 校验原始回复并触发一次查询。否定、疑问、取消、修改意见或含糊表达不得触发查询。没有准确依据时不得推定公钥确认页过期、有效期或旧链接失效;只有用户主动反馈当前页面或扫码有问题时,才重新执行上方 `app.sh key` 命令生成新页面并重新进入固定 open + 轮询。写文件失败记录 `MANUAL_CONFIGURATION_REQUIRED` 但不阻塞提审;HarmonyOS 仍只走人工分支。
470
482
 
471
- 用户提供完整公钥后直接调用上方 `app.sh key` 命令;脚本输出非阻塞 `application.key.page` 并校验 URL,Agent 送达 stdout 后立即调用 `app.sh open-key-page` 受控打开,失败只保留同一裸 URL、复制兜底和“扫码完成后请回到 Agent 对话页面”。Agent 不得代写/重渲染,响应不明进入 `UNKNOWN` 且不得生成第二页。
483
+ 用户提供完整公钥后直接调用上方 `app.sh key` 命令;脚本输出非阻塞 `application.key.page` 并校验 URL,Agent 送达 stdout 后立即调用 `app.sh open-key-page` 受控打开,失败只保留同一裸 URL、复制兜底和“扫码完成后请回到 Agent 对话页面”。Agent 不得代写/重渲染,响应不明进入 `UNKNOWN` 且不得生成第二页。应用创建成功必须产生 `APPLICATION_CREATE_RESULT=SUCCESS` 和实际 `APP_ID`;创建响应不明、成功响应缺少合法 `appId` 时产生 `APPLICATION_CREATE_RESULT=UNKNOWN`,不得进入设钥;明确未发送重试耗尽或业务失败产生 `APPLICATION_CREATE_RESULT=FAILED`。公钥确认页生成成功必须产生 `KEY_PAGE_RESULT=READY_TO_OPEN` 和 `KEY_PAGE:READY_TO_OPEN`;响应不明、缺少合法 URL 或页面已生成但标准消息无法安全输出时产生 `KEY_PAGE_RESULT=UNKNOWN`,不得生成第二个页面;若同时存在 `KEY_PAGE_STATE:SAVE_FAILED`,页面 stdout 已送达,`open-key-page` 只可降级为 `KEY_OPEN:LINK_ONLY`,后续 `verify-key|verify-key-and-audit` 仍按显式 `appId/publicKey` 继续。应用提审成功必须产生 `APPLICATION_AUDIT_RESULT=SUBMITTED` 和 `FLOW:AUDIT_SUBMITTED`;响应不明且查询无法核验时产生 `APPLICATION_AUDIT_RESULT=UNKNOWN`,不得重复提审;明确未发送重试耗尽或业务失败产生 `APPLICATION_AUDIT_RESULT=FAILED`。
472
484
 
473
485
  复用应用返回 `FLOW:REUSE_NO_KEY` 时,必须将应用分支标记为未完成,不得输出复用成功,并执行下列命令说明当前应用缺少已确认 RSA2 应用公钥。该消息不增加二次确认:目标 `appId` 已由用户从当前候选中选定,随后直接进入当前应用的设钥准备;如果用户在消息后明确要求重新选择或新建应用,再返回 Step 4 重新决策。取得用户明确提供的完整应用公钥后执行 `node "<SKILL_DIR>/references/normal/scripts/runtime.mjs" app key --product-type "$PRODUCT_TYPE" --defer-open "<同一appId>" "<用户明确提供的完整publicKey>"`;该脚本 stdout 独立送达后立即执行 `node "<SKILL_DIR>/references/normal/scripts/runtime.mjs" app open-key-page "<同一appId>"`,再执行带同一 `--product-type` 的 `verify-key` 有限轮询,确认成功后重新执行带同一 `--product-type` 的 `reuse`,不得跳过应用状态与支付宝公钥检查,也不得改变 `appId/publicKey` 的位置参数形式或替换 ID。
474
486
 
@@ -490,10 +502,10 @@ node "<SKILL_DIR>/references/normal/scripts/runtime.mjs" onboarding-message appl
490
502
  `SIGNING_RESULT`、`SERVICE_RESULT`、`APPLICATION_RESULT` 和 `INTEGRATION_RESULT` 必须使用消息目录允许的状态枚举原文,禁止拼接 `appId`、公钥文件路径、错误码、截图证据或其他自由文本;这些证据只保留在脚本输出、内部事实或人工待办字段中,不能污染分支结果枚举。
491
503
 
492
504
  ```bash
493
- node "<SKILL_DIR>/references/normal/scripts/runtime.mjs" onboarding-message closeout --product-name "$PRODUCT_NAME" --process-result-title "$PROCESS_RESULT_TITLE" --integration-result "$INTEGRATION_RESULT" --sandbox-config-state "$SANDBOX_CONFIG_STATE" --signing-result "$SIGNING_RESULT" --service-result "$SERVICE_RESULT" --application-result "$APPLICATION_RESULT" --remaining-actions "$REMAINING_ACTIONS" --manual-verification-items "$MANUAL_VERIFICATION_ITEMS" --application-operation-app-id "$APPLICATION_OPERATION_APP_ID" --application-operation-actual-status "$APPLICATION_OPERATION_ACTUAL_STATUS" --application-operation-next-action "$APPLICATION_OPERATION_NEXT_ACTION" --next-flow-reminder "$NEXT_FLOW_REMINDER"
505
+ node "<SKILL_DIR>/references/normal/scripts/runtime.mjs" onboarding-message closeout --product-name "$PRODUCT_NAME" --process-result-title "$PROCESS_RESULT_TITLE" --integration-result "$INTEGRATION_RESULT" --signing-result "$SIGNING_RESULT" --service-result "$SERVICE_RESULT" --application-result "$APPLICATION_RESULT" --remaining-actions "$REMAINING_ACTIONS" --next-flow-reminder "$NEXT_FLOW_REMINDER" [--sandbox-config-state "$SANDBOX_CONFIG_STATE"] [--manual-verification-items "$MANUAL_VERIFICATION_ITEMS"] [--application-operation-app-id "$APPLICATION_OPERATION_APP_ID" --application-operation-actual-status "$APPLICATION_OPERATION_ACTUAL_STATUS" --application-operation-next-action "$APPLICATION_OPERATION_NEXT_ACTION"]
494
506
  ```
495
507
 
496
- `onboarding_only` 的代码开发栏写“不在本轮执行范围”,`SANDBOX_CONFIG_STATE` 传空字符串,`MANUAL_VERIFICATION_ITEMS` 传空字符串,并把 `nextFlowReminder` 固定为“还需完成支付产品-代码开发,才能在业务系统中实际发起支付。”。`full_process` 中,代码开发全部通过时填“已完成”并传 `READY`;只有沙箱待配置且其余代码与安全检查通过时填“部分完成,沙箱配置待完成”,并原样传 `CREATE_PENDING|VERIFY_PENDING`;沙箱为 `READY` 且代码开发只剩非阻塞人工待验证项时填“部分完成,人工待验证”,传 `READY`,把代码开发 checklist 的 `manualItems` 原样作为 `MANUAL_VERIFICATION_ITEMS` 传入,并在 `REMAINING_ACTIONS` 中写明“完成下方人工待验证项”或同等实际待办,禁止传“无”;把 `nextFlowReminder` 固定为“代码开发已在本轮执行;后续只按上表实际待办继续。”,该值仅用于 renderer 校验执行模式,`full_process` 最终对客不展示“后续衔接”行。renderer 会校验结果与沙箱状态、人工待验证项一致,并派生恢复口令或人工待验证展示行;该展示不增加确认点或用户回复要求。不得在其 stdout 前后单独追加衔接提醒,不伪造本轮代码修改、沙箱创建或测试结果,也不重复进入 integration。
508
+ `onboarding_only` 的代码开发栏写“不在本轮执行范围”,省略 `--sandbox-config-state` 和 `--manual-verification-items`,并把 `nextFlowReminder` 固定为“还需完成支付产品-代码开发,才能在业务系统中实际发起支付。”。兼容窗口内 runner 仍会把旧空字符串归一化为省略,但新 flow 禁止再要求 Agent 构造空字符串伪值。`full_process` 中,代码开发全部通过时填“已完成”并传 `READY`;只有沙箱待配置且其余代码与安全检查通过时填“部分完成,沙箱配置待完成”,并原样传 `CREATE_PENDING|VERIFY_PENDING`;沙箱为 `READY` 且代码开发只剩非阻塞人工待验证项时填“部分完成,人工待验证”,传 `READY`,把代码开发 checklist 的 `manualItems` 原样作为 `MANUAL_VERIFICATION_ITEMS` 传入,并在 `REMAINING_ACTIONS` 中写明“完成下方人工待验证项”或同等实际待办,禁止传“无”;把 `nextFlowReminder` 固定为“代码开发已在本轮执行;后续只按上表实际待办继续。”,该值仅用于 renderer 校验执行模式,`full_process` 最终对客不展示“后续衔接”行。renderer 会校验结果与沙箱状态、人工待验证项一致,并派生恢复口令或人工待验证展示行;该展示不增加确认点或用户回复要求。不得在其 stdout 前后单独追加衔接提醒,不伪造本轮代码修改、沙箱创建或测试结果,也不重复进入 integration。
497
509
 
498
510
  若 `full_process` 最后一跳紧接着应用创建、审核提交或复用结果,不再单独输出一条 `application.operation.result` 后又立刻输出本收口消息;必须把同样的 `appId`、实际状态和下一步分别记录为 `APPLICATION_OPERATION_APP_ID`、`APPLICATION_OPERATION_ACTUAL_STATUS`、`APPLICATION_OPERATION_NEXT_ACTION`,交给 closeout runner 处理,且 `APPLICATION_OPERATION_ACTUAL_STATUS` 必须与 `APPLICATION_RESULT` 枚举原文一致。应用结果已为“已上线且配置完整”时不再展开“应用分支结果”,由结果表和上线前检查块承接;待审核、待设置公钥、需人工配置、失败或结果未知时合并展示为“应用分支结果”并保留完成态红线。`onboarding_only`、应用分支仍需等待用户补材料/确认,或应用操作结果不是紧邻 Step 6 最终收口时,仍按应用模块原规则输出 `application.operation.result`。合并展示不得改写应用完成条件,待审核、待设置公钥或待人工配置时仍不得表述为应用发布完成。
499
511
 
@@ -60,13 +60,15 @@ node "<SKILL_DIR>/references/normal/scripts/runtime.mjs" onboarding-message mate
60
60
 
61
61
  确认页只展示脚本校验通过的实际 `confirmPageUrl` 裸 URL,禁止二维码链接和 `alipays://` 深链。没有依据时不得推定页面有效期或旧链接失效;只有用户主动反馈当前页面或扫码有问题时才重新生成。
62
62
 
63
+ `app.sh key` 成功必须输出 `KEY_PAGE_RESULT=READY_TO_OPEN` 和 `KEY_PAGE:READY_TO_OPEN`;响应不明、缺少合法 URL 或页面已生成但标准消息无法安全输出时输出 `KEY_PAGE_RESULT=UNKNOWN`,禁止自动生成第二个页面。若页面 stdout 已交付但本地状态保存失败,脚本输出 `KEY_PAGE_STATE:SAVE_FAILED`,后续 `open-key-page` 只能降级为 `KEY_OPEN:LINK_ONLY`,不影响显式 `appId/publicKey` 的后续查询。
64
+
63
65
  RSA2 应用公钥状态只看应用公钥字段,支付宝公钥不能反向证明应用公钥已生效。`verify-key|verify-key-and-audit` 生产最多查询 20 次,未成功的相邻查询间隔 2 秒;耗尽后把明确完成表达交给 `onboarding_recovery_runner.mjs application-key`,每次只查询一次,不重启轮询。
64
66
 
65
67
  ## 提审与结果
66
68
 
67
69
  新建应用公钥确认后使用 `verify-key-and-audit`,复用最终成功的密钥响应完成双公钥 guard 并直接提审,不重复查询、不增加额外确认点。复用应用缺公钥时执行 `verify-key` 后重新 `reuse`。公钥未确认或 guard 失败禁止提审。
68
70
 
69
- `FLOW:AUDIT_SUBMITTED` 只能在提审成功,或只读核验确认应用已进入审核/上线状态后输出;公钥成功但提审失败不得输出组合成功 marker。支付宝公钥实际写入成功才输出路径;本地写入失败记为人工配置待办,但不反向伪造提审失败。
71
+ `APPLICATION_CREATE_RESULT=SUCCESS|FAILED|UNKNOWN` 用于区分创建成功、明确失败和结果未知;创建未知或成功响应缺少合法 `appId` 时不得进入设钥。`APPLICATION_AUDIT_RESULT=SUBMITTED|FAILED|UNKNOWN` 用于区分提审已提交、明确失败和结果未知;未知时不得重复提审。`FLOW:AUDIT_SUBMITTED` 只能在提审成功,或只读核验确认应用已进入审核/上线状态后输出;公钥成功但提审失败不得输出组合成功 marker。支付宝公钥实际写入成功才输出路径;本地写入失败记为人工配置待办,但不反向伪造提审失败。
70
72
 
71
73
  应用分支对客结果只使用:
72
74
 
@@ -18,12 +18,13 @@
18
18
 
19
19
  - `AUTH_FLOW:SKIP|AUTH_SUCCESS`:当前本机登录态、scope 和当前 MCC 上下文均已通过脚本校验。
20
20
  - `AUTH_FLOW:READY_TO_OPEN`:当前授权页已生成并完成白名单及上下文校验,可以交付页面后调用受控 opener。
21
+ - `AUTH_STATE:SAVE_FAILED`:授权页 stdout 已经安全生成并交付,但本地短时状态文件未能保存;不得重新生成页面,后续 opener 只能降级为 `AUTH_OPEN:LINK_ONLY`,`wait|confirm` 仍使用 flow 登记命令的显式上下文。
21
22
  - `AUTH_FLOW:PENDING`:有限轮询耗尽或单次恢复查询尚未得到有效本机登录态;不等于失败,也不证明用户未扫码。
22
23
  - `AUTH_FLOW:EXPIRED`:当前页面实际返回过期,旧页面和旧回复失效,重新执行 flow 登记的 init。
23
- - `AUTH_FLOW:SCOPE_MISMATCH|MCC_MISMATCH`:只能走 `auth.sh mismatch`;logout 未确认成功前不得重新授权。
24
+ - `AUTH_FLOW:SCOPE_MISMATCH|MCC_MISMATCH`:只能走 `auth.sh mismatch`;logout 后置条件未成立前不得重授权;仍登录返回 `AUTH_FLOW:LOGOUT_STILL_LOGGED_IN`。
24
25
  - `AUTH_FLOW:RETRY_WITH_NETWORK`:当前 Agent 环境无法确认结果,申请联网权限后原样重试同一命令;不得解释为用户本机登录失败。
25
26
 
26
- CLI `login --complete` 成功只表示页面侧确认完成,不代表本机已取得可用登录态。脚本仍需复核 `whoami`、scope,并以固定授权 URL 绑定 MCC;当前后端查询没有权威 MCC 返回字段,禁止声称做了响应 MCC 等值比较。
27
+ CLI `login --complete` 成功只表示页面侧确认完成,不代表本机已取得可用登录态。返回成功但状态字段不在白名单时,脚本先用 `whoami` 复核:有效登录继续 scope/MCC 校验,仍未形成登录态则保持 `PENDING`,不可确认则 `RETRY_WITH_NETWORK`。脚本仍需复核 `whoami`、scope,并以固定授权 URL 绑定 MCC;当前后端查询没有权威 MCC 返回字段,禁止声称做了响应 MCC 等值比较。
27
28
 
28
29
  ## 页面与恢复
29
30
 
@@ -6,8 +6,8 @@
6
6
 
7
7
  | 内部分类 | 已验证触发 | 恢复边界 |
8
8
  | --- | --- | --- |
9
- | `MCP_AUTH_ERROR` | HTTP 401、`Authorization is empty`、非法认证信息 | 停止当前及剩余发现查询;校验 logout 成功后重新授权。合法失败阻断;结果不可唯一解析或当前 Agent 无法联网时,只申请联网权限并重试同一动作,不解释为用户本机或支付宝业务失败 |
10
- | `AUTH_MISMATCH` | `mccCode is not auth`、`salesProductCodes is not auth`、`scope is not auth` | 停止当前动作,只进入 `auth.sh mismatch`;logout 未确认成功前禁止重新授权 |
9
+ | `MCP_AUTH_ERROR` | HTTP 401、`Authorization is empty`、非法认证信息 | 停止查询组;logout 后置条件成立后重授权。仍登录则阻断;不可确认或无网络时只重试同一动作,不解释为用户本机或支付宝业务失败 |
10
+ | `AUTH_MISMATCH` | `mccCode is not auth`、`salesProductCodes is not auth`、`scope is not auth` | 停止当前动作,只进 `auth.sh mismatch`;logout 后置条件未成立前禁重授权 |
11
11
  | `MCP_SERVICE_ERROR` / `SERVICE_UNSTABLE` | 已识别连接、网络或服务异常 | 按下方有限重试规则处理;耗尽后记录受影响分支,依赖允许时继续其他独立分支,最终统一收口 |
12
12
  | `ERROR:<code>` | 当前响应中存在可识别业务错误 | 展示登记且脱敏的业务错误,修正业务条件前不重试 |
13
13
  | `CLI_ERROR:<message>` | CLI 失败、异常结构或结果不可唯一解析 | 隐藏原始输出,停止并按登记 CLI 错误恢复,不猜成功或空结果 |
@@ -15,6 +15,8 @@
15
15
 
16
16
  发现阶段的单分支失败不得伪装为空列表,也不得回滚其他已成功分支;认证失效或授权不匹配属于查询组全局阻断,重新授权后恢复尚未执行的查询,主体一致性无法确认时重新查询全部适用状态。
17
17
 
18
+ discovery runner 和截图上传这类并发/分组动作不得让每个子进程各自 logout。子脚本在分组环境下只上报认证失效事实;由 flow 登记的唯一授权恢复入口执行一次 logout 后置条件确认。三张截图同时认证失败时只允许产生一个全局认证恢复 marker。
19
+
18
20
  ## 解包与业务错误
19
21
 
20
22
  `unwrap_mcp` 兼容纯业务 JSON、唯一 MCP `content[0].text` 信封和混合日志。混合输出只从完整闭合结构形成候选;多个信封或 JSON 候选冲突时不选择、不回显原始响应,并由错误检测阻断。每次 MCP 调用先把原 stdout 交给 `handle_error`,返回成功后才调用 `unwrap_mcp` 和当前脚本的业务解析;不得统一假定成功字段位于 `.success`。
@@ -33,6 +35,8 @@
33
35
 
34
36
  `MESSAGE_RENDER_ERROR` 不是写操作是否发出的证据,不得据此自动重写。
35
37
 
38
+ 写动作除既有成功 marker 外,还必须输出动作级结果事实:签约 `SIGN_APPLY_RESULT=SUCCESS|FAILED|UNKNOWN`,服务保存 `SERVICE_SAVE_RESULT=SUCCESS|FAILED|UNKNOWN`,应用创建 `APPLICATION_CREATE_RESULT=SUCCESS|FAILED|UNKNOWN`,公钥确认页 `KEY_PAGE_RESULT=READY_TO_OPEN|FAILED|UNKNOWN`,应用提审 `APPLICATION_AUDIT_RESULT=SUBMITTED|FAILED|UNKNOWN`。`UNKNOWN` 表示禁止自动重复同一写动作,只能按 flow 进入当前分支待办或最终收口。
39
+
36
40
  ## 授权轮询恢复
37
41
 
38
42
  `authorization_pending` 或自动轮询中 `whoami` 尚未形成有效本机登录态时,只由 `auth.sh wait` 在固定最多 12 次、未成功相邻查询间隔 5 秒内继续。耗尽后输出一次 `auth.pending`,等待用户明确表示页面操作已完成;登记表达只执行一次 `auth.sh confirm`,不得重启 `wait` 或自行循环 `login --complete`。`auth_expired` 才重新执行登录流程。
@@ -13,7 +13,7 @@
13
13
 
14
14
  ## 签约状态
15
15
 
16
- `scripts/sign_status_parser.sh` 是授权内查询与独立签约查询的唯一解析实现。只有实际响应包含合法 `resultObj.arInfoList`,并唯一输出匹配的 `SIGN_STATUS`、`FLOW:*` 和 `AUTH_SIGN_QUERY_REUSABLE=true`,授权结果才可复用;结构缺失、冲突或不可唯一解析时必须独立查询。
16
+ `scripts/sign_status_parser.sh` 是授权内查询与独立签约查询的唯一解析实现。只有实际响应包含合法 `resultObj.arInfoList`,并唯一输出匹配的 `SIGN_STATUS`、`FLOW:*`、`AUTH_SIGN_QUERY_REUSABLE=true` 和 `AUTH_SIGN_REUSE_RECEIPT`,授权结果才优先通过回执复用;结构缺失、冲突或不可唯一解析时必须独立查询。兼容窗口内旧 `SIGN_STATUS + FLOW:*` 双参数仍可复用,`FLOW:` 前缀可带可不带,但 runner 必须重新校验产品、salesCode、状态和 flow 一致。
17
17
 
18
18
  | 状态 | 业务处理 |
19
19
  | --- | --- |
@@ -23,6 +23,8 @@
23
23
  | `OTHER_STATUS` | 展示实际状态并待核验,禁止提交 |
24
24
  | `QUERY_FAILED` | 只阻断签约分支,不推断为空或未签约 |
25
25
 
26
+ 合法复用组合固定为:`NOT_SIGNED + 当前产品未签约 FLOW`、`SIGNED_EFFECTIVE|SIGN_SUBMITTED + 当前产品已签约 FLOW`、`OTHER_STATUS + FLOW:OTHER_STATUS`。不得把 `OTHER_STATUS` 映射为已签约或未签约。
27
+
26
28
  现有查询请求不含 MCC,已验证响应也没有权威 MCC 字段。授权链路只能表述为授权 URL 精确绑定目标 MCC;没有新证据时不得增加响应 MCC 比较或修改 MCP payload。
27
29
 
28
30
  ## 材料与提交
@@ -35,4 +37,6 @@
35
37
 
36
38
  提交成功只表示申请已受理,不等于签约生效;服务和应用分支按各自前置条件继续,不依赖本次签约写成功。写操作仅明确 `NOT_SENT` 时可自动重试;`MAYBE_SENT` 必须先用现有签约查询核验,无法确认进入 `UNKNOWN`,禁止重复提交。
37
39
 
40
+ 提交脚本必须输出动作级结果事实:`SIGN_APPLY_RESULT=SUCCESS` 表示提交已受理并继续;`SIGN_APPLY_RESULT=UNKNOWN` 表示响应不明且查询无法核验,签约分支进入未知待办;`SIGN_APPLY_RESULT=FAILED` 表示明确失败或明确未发送重试耗尽。三者不改变 MCP payload,也不能阻断服务和应用的独立前置分支。
41
+
38
42
  签约结果只通过消息目录的 `signing.operation.result` 输出。不得展示未登记审核规则、费率承诺、可收款时间或原始响应;费率、额度和生效问题引导用户在支付宝商家平台查询。
@@ -16,9 +16,9 @@
16
16
  # app reuse --product-type <type> <appId> - 复用已有应用(查询安全密钥)
17
17
  # 返回值:
18
18
  # list: stdout 成功时为空;stderr 输出带统一内部前缀的候选 JSON、FLOW 和候选 ID
19
- # create: 成功在 stderr 输出 APP_ID=xxx;失败 exit 1,返回结构异常时同时输出 FLOW:ERROR
20
- # key: 输出 confirmPageUrl
21
- # audit: 输出审核结果
19
+ # create: 成功在 stderr 输出 APP_ID=xxx;失败 exit 1,返回结构异常时输出 APPLICATION_CREATE_RESULT=UNKNOWN
20
+ # key: 输出 confirmPageUrl;响应不明时输出 KEY_PAGE_RESULT=UNKNOWN,禁止自动生成第二个页面
21
+ # audit: 输出审核结果;响应不明时输出 APPLICATION_AUDIT_RESULT=UNKNOWN,禁止自动重复提审
22
22
  # reuse: stderr 输出 FLOW:REUSE_SUCCESS | FLOW:REUSE_NO_KEY | FLOW:ERROR
23
23
  #=============================================================================
24
24
 
@@ -662,16 +662,17 @@ app_create() {
662
662
  RETRY_RC=$?
663
663
  if [ "$RETRY_RC" -eq 75 ]; then
664
664
  echo "❌ 应用创建响应不明;现有应用列表无法把同类型新应用唯一归属于本次创建,结果标记为 UNKNOWN,禁止自动重复创建"
665
- emit_control "FLOW:ERROR"
665
+ emit_control "APPLICATION_CREATE_RESULT=UNKNOWN"
666
666
  exit 1
667
667
  elif [ "$RETRY_RC" -ne 0 ]; then
668
668
  echo "❌ 应用创建因明确未发送的网络异常在自动重试两次后仍未恢复"
669
- emit_control "FLOW:ERROR"
669
+ emit_control "APPLICATION_CREATE_RESULT=FAILED"
670
670
  exit 1
671
671
  fi
672
672
 
673
673
  # 错误检测
674
674
  if ! handle_error "$RESULT"; then
675
+ emit_control "APPLICATION_CREATE_RESULT=FAILED"
675
676
  exit 1
676
677
  fi
677
678
 
@@ -683,16 +684,18 @@ app_create() {
683
684
  APP_ID=$(echo "$BUSINESS" | jq -r '.resultObj.appId // .data.appId // empty')
684
685
  if ! validate_control_value "$APP_ID"; then
685
686
  echo "❌ 应用创建返回成功,但未解析到 appId,禁止进入公钥设置流程"
686
- emit_control "FLOW:ERROR"
687
+ emit_control "APPLICATION_CREATE_RESULT=UNKNOWN"
687
688
  exit 1
688
689
  fi
689
690
  emit_control "✅ 应用创建成功"
690
691
  emit_control_field "APPLICATION_TYPE" "$APP_APPLICATION_TYPE" || exit 1
691
692
  emit_control_field "APP_ID" "$APP_ID" || exit 1
693
+ emit_control "APPLICATION_CREATE_RESULT=SUCCESS"
692
694
  else
693
695
  ERROR_MSG=$(echo "$BUSINESS" | jq -r '.error.message // .errorMessage // "未知错误"')
694
696
  ERROR_MSG=$(sanitize_customer_error_text "$ERROR_MSG")
695
697
  echo "❌ 应用创建失败: $ERROR_MSG"
698
+ emit_control "APPLICATION_CREATE_RESULT=FAILED"
696
699
  exit 1
697
700
  fi
698
701
  }
@@ -740,14 +743,17 @@ app_key() {
740
743
  RETRY_RC=$?
741
744
  if [ "$RETRY_RC" -eq 75 ]; then
742
745
  echo "❌ 公钥确认页生成响应不明,结果标记为 UNKNOWN;不得自动生成第二个页面"
746
+ emit_control "KEY_PAGE_RESULT=UNKNOWN"
743
747
  exit 1
744
748
  elif [ "$RETRY_RC" -ne 0 ]; then
745
749
  echo "❌ 公钥确认页因明确未发送的网络异常在自动重试两次后仍未恢复"
750
+ emit_control "KEY_PAGE_RESULT=FAILED"
746
751
  exit 1
747
752
  fi
748
753
 
749
754
  # 错误检测
750
755
  if ! handle_error "$RESULT"; then
756
+ emit_control "KEY_PAGE_RESULT=FAILED"
751
757
  exit 1
752
758
  fi
753
759
 
@@ -760,23 +766,29 @@ app_key() {
760
766
 
761
767
  if [ -n "$CONFIRM_PAGE_URL" ]; then
762
768
  RENDERER="${SCRIPT_DIR}/../../../normal/scripts/render_customer_message.mjs"
763
- save_app_key_page_state || exit 1
769
+ if ! save_app_key_page_state; then
770
+ emit_control "KEY_PAGE_STATE:SAVE_FAILED"
771
+ fi
764
772
  MESSAGE_INPUT=$(printf '%s\n' "$APP_ID" "$CONFIRM_PAGE_URL" | jq -Rs '
765
773
  split("\n") as $v | {appId:$v[0],officialUrl:$v[1]}
766
774
  ')
767
775
  if ! printf '%s' "$MESSAGE_INPUT" | ALIPAY_AIPAY_RENDERER_MANAGED_CALLER=app.sh node "$RENDERER" application.key.page --variant READY; then
768
776
  echo "❌ 公钥确认页已生成,但标准消息无法安全输出;结果保持待核验,禁止自动生成第二个页面"
777
+ emit_control "KEY_PAGE_RESULT=UNKNOWN"
769
778
  exit 1
770
779
  fi
780
+ emit_control "KEY_PAGE_RESULT=READY_TO_OPEN"
771
781
  emit_control "KEY_PAGE:READY_TO_OPEN"
772
782
  else
773
783
  echo "❌ 公钥确认页响应缺少 confirmPageUrl,结果标记为 UNKNOWN;不得自动生成第二个页面"
784
+ emit_control "KEY_PAGE_RESULT=UNKNOWN"
774
785
  exit 1
775
786
  fi
776
787
  else
777
788
  ERROR_MSG=$(echo "$BUSINESS" | jq -r '.error.message // .errorMessage // "未知错误"')
778
789
  ERROR_MSG=$(sanitize_customer_error_text "$ERROR_MSG")
779
790
  echo "❌ 公钥设置失败: $ERROR_MSG"
791
+ emit_control "KEY_PAGE_RESULT=FAILED"
780
792
  exit 1
781
793
  fi
782
794
  }
@@ -794,9 +806,8 @@ app_open_key_page() {
794
806
  exit 1
795
807
  fi
796
808
  if ! validate_app_key_state_file; then
797
- echo "❌ 缺少待打开的公钥确认页上下文,请重新执行 app.sh key --defer-open <appId> <publicKey>"
798
- emit_control "FLOW:ERROR"
799
- return 1
809
+ emit_control "KEY_OPEN:LINK_ONLY"
810
+ return 0
800
811
  fi
801
812
  if ! jq -e . "$APP_KEY_STATE_FILE" >/dev/null 2>&1; then
802
813
  echo "❌ 公钥确认页状态文件不是合法 JSON,已停止"
@@ -843,20 +854,24 @@ submit_application_audit() {
843
854
  AUDITING|ON_LINE)
844
855
  emit_control "✅ 应用审核提交已由应用信息查询核验成功"
845
856
  emit_control_field "APP_ID" "$APP_ID" || return 1
857
+ emit_control "APPLICATION_AUDIT_RESULT=SUBMITTED"
846
858
  emit_control "FLOW:AUDIT_SUBMITTED"
847
859
  return 0
848
860
  ;;
849
861
  esac
850
862
  fi
851
863
  echo "❌ 应用提审响应不明且现有状态无法排除传播延迟,结果标记为 UNKNOWN,禁止自动重复提审"
864
+ emit_control "APPLICATION_AUDIT_RESULT=UNKNOWN"
852
865
  exit 1
853
866
  elif [ "$RETRY_RC" -ne 0 ]; then
854
867
  echo "❌ 应用提审因明确未发送的网络异常在自动重试两次后仍未恢复"
868
+ emit_control "APPLICATION_AUDIT_RESULT=FAILED"
855
869
  exit 1
856
870
  fi
857
871
 
858
872
  # 错误检测
859
873
  if ! handle_error "$RESULT"; then
874
+ emit_control "APPLICATION_AUDIT_RESULT=FAILED"
860
875
  exit 1
861
876
  fi
862
877
 
@@ -867,11 +882,13 @@ submit_application_audit() {
867
882
  if [ "$SUCCESS" = "true" ]; then
868
883
  emit_control "✅ 应用审核提交成功"
869
884
  emit_control_field "APP_ID" "$APP_ID" || return 1
885
+ emit_control "APPLICATION_AUDIT_RESULT=SUBMITTED"
870
886
  emit_control "FLOW:AUDIT_SUBMITTED"
871
887
  else
872
888
  ERROR_MSG=$(echo "$BUSINESS" | jq -r '.error.message // .errorMessage // "未知错误"')
873
889
  ERROR_MSG=$(sanitize_customer_error_text "$ERROR_MSG")
874
890
  echo "❌ 提交审核失败: $ERROR_MSG"
891
+ emit_control "APPLICATION_AUDIT_RESULT=FAILED"
875
892
  exit 1
876
893
  fi
877
894
  }