1. 页面概览
1.1 是什么
「Action 测试」页面(页面标题「Action 写路径测试」)是 LightFoundry 提供的 Action 唯一写路径测试台。在 Foundry 本体体系中,业务数据的写入只能通过对象类型上声明的 Action(动作)完成——Action 携带 param_schema(参数模式)、validation_rules(提交前校验规则)、write_back_config(回写声明,含 SQL 模板与乐观锁配置)等定义,经过后端 writepath 安全流水线(Schema 校验 → 校验规则 → RBAC → 记录级 → 属性级 → 审计 → 幂等 + 事务)后才能落库。
本页面的源码位于 action/web/src/views/ActionTesterPage.vue,共约 395 行。它做的事情是把某个对象类型上的 Action 以可交互表单的形式暴露出来:选择对象与动作后,前端按 param_schema 动态生成参数表单(含必填标记、类型标注、枚举下拉),填好参数与幂等键后点击「执行(VALIDATE_AND_EXECUTE)」即可真实触发写路径;同时提供「重放上次执行」按钮演示幂等重放(replayed)语义。
页面顶部注释块概括了核心设计:选择对象与动作 → 按 param_schema 生成参数表单 → 执行(VALIDATE_AND_EXECUTE,idempotency_key 自动生成/手动输入);幂等演示:记录上次执行的 idempotency_key,「重放上次执行」复现 replayed。因此本页既是开发调试工具,也是幂等与写路径机制的演示窗口——这正是本手册第 5、6 章重点展开的内容。
1.2 核心价值
| 能力 | 说明 | 对应操作 |
|---|---|---|
| 对象/动作选择 | 从对象列表进入,加载该对象声明的全部动作 | 「对象类型」「动作」双下拉 |
| 参数表单自动生成 | 按 param_schema 动态渲染字段(类型/枚举/必填) | 参数表单区 |
| 写路径真实执行 | 以 VALIDATE_AND_EXECUTE 模式执行动作,先校验再落库 | 「执行(VALIDATE_AND_EXECUTE)」 |
| 幂等键管理 | 自动生成或手动输入 idempotency_key(运行模式必填) | 「生成」按钮 + 输入框 |
| 幂等重放演示 | 复用上次执行的幂等键再次提交,复现 replayed 状态 | 「重放上次执行」 |
| 结果透视 | 结构化展示 status/mode/rows_affected/affected_records/validation_result/edits/operation_id/replayed_from_run_id | 「执行结果」卡片 |
1.3 一句话总结
2. 访问入口
2.1 路由与菜单
| 项目 | 值 |
|---|---|
| 路由 path | /foundry/actions(文档 slug 为 action-tester,与 markdown/index.md 规划一致) |
| 路由 name | FoundryActions |
| 侧边栏入口 | FoundryLayout 侧边栏「Action 测试」 |
| 父路由 | /foundry(组件 FoundryLayout) |
| 前端源码 | action/web/src/views/ActionTesterPage.vue |
| 路由注册文件 | action/web/src/router/index.js(约 221-225 行) |
访问方式:登录后从 Foundry 左侧菜单点击「Action 测试」,或直接访问 /foundry/actions。
2.2 认证与权限
- 路由
meta.requiresAuth: true;API 认证使用aip_token(localStorage),由client.js请求拦截器自动附加Authorization: Bearer <aip_token>。 - 权限点是动作级 RBAC:后端
stepRBAC会校验当前用户对action:<name>权限点是否被授权(AuthorizeUser(ctx, userID, username, "action:"+action.Name)),越权执行返回FORBIDDEN(HTTP 403,状态forbidden)。 - 由于本页是真实写路径,执行动作会真实修改数据源业务数据,请使用演示/测试环境,切勿在共享生产数据源上随意执行。
- 401 时客户端拦截器清 token 并跳
/login。
2.3 端口与 API 前缀
- Foundry 后端端口:18081;Vite 代理
/api前缀到该后端。 - API 基础前缀:
/api/v1(client.js的baseURL)。 - 本页请求落在
/api/v1/ontology/...。
3. 界面布局
本页为四张纵向卡片流:
┌─────────────────────────────────────────────────────┐
│ Action 写路径测试 │
│ ┌─────────────────────────────────────────────────┐ │
│ │ [alert 提示条(出现时展示,右上角"关闭")] │ │
│ └─────────────────────────────────────────────────┘ │
│ ┌─ 选择对象与动作 ─────────────────────────────────┐ │
│ │ 对象类型 [下拉] 动作 [下拉] │ │
│ │ action_name — description [edit_type 标签] │ │
│ └─────────────────────────────────────────────────┘ │
│ ┌─ 参数(按 param_schema 生成)────────────────────┐ │
│ │ 提示:ValidationRules 提交前校验...(B7-6) │ │
│ │ 字段名*(type) [输入框/枚举下拉] │ │
│ │ idempotency_key(运行模式必填)[输入框][生成] │ │
│ │ [执行(VALIDATE_AND_EXECUTE)] [重放上次执行] │ │
│ │ 上次执行幂等键:<key> │ │
│ └─────────────────────────────────────────────────┘ │
│ ┌─ 执行结果(result 存在时展示)───────────────────┐ │
│ │ status / mode / rows_affected / affected_records │ │
│ │ validation_result.result / edits.changed_records │ │
│ │ operation_id / replayed_from_run_id │ │
│ │ validation(JSON) result(JSON) │ │
│ └─────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────┘
| 板块 | 职责 |
|---|---|
| 页面标题区 | 显示「Action 写路径测试」 |
| Alert 提示条 | 展示执行/重放/加载的成败信息;执行成功但业务失败(如 validation_failed)用 alert-info,真成功用 alert-success |
| 选择对象与动作卡片 | 双下拉(对象类型 / 动作)+ 动作描述区(名称、描述、edit_type 标签) |
| 参数表单卡片 | 按 param_schema 动态渲染;含校验规则提示条、幂等键输入区、执行/重放按钮、上次幂等键提示 |
| 执行结果卡片 | 结构化网格展示执行响应各字段 + 可选 validation/result JSON 区块 |
4. 交互元素详解
4.1 对象类型下拉框
| 项目 | 说明 |
|---|---|
| 位置 | 选择卡片左半格 |
| 含义 | 选择要测试动作所属的对象类型 |
| 选项文案 | {{ item.object_type.name }}(#{{ item.object_type.id }})(以内部 id 标注) |
| 操作效果 | @change="handleSelectObject":重置动作选择与结果,然后请求该对象详情并填充动作列表 |
| 触发的后端调用 | GET /ontology/objects/:id(返回对象详情含 actions 数组) |
4.2 动作下拉框
| 项目 | 说明 |
|---|---|
| 位置 | 选择卡片右半格 |
| 含义 | 选择要执行的动作 |
| 选项文案 | {{ a.name }}(动作名) |
| 操作效果 | @change="handleSelectAction":找到选中动作并重置结果/参数;随后为每个 schema 字段初始化空值 |
| 动作描述区 | 选中后显示 {{ selectedAction.name }}(加粗)+ 描述 + edit_type 标签(如 modify) |
4.3 参数表单(按 param_schema 生成)
| 项目 | 说明 |
|---|---|
| 生成逻辑 | schemaFields computed:取 selectedAction.param_schema 的 properties 与 required,每个字段输出 {name, type, enum, required} |
| 标签渲染 | {{ field.name }} + 必填时红色 * + 类型标注 ({{ field.type }}) |
| 输入控件 | 字段有 enum(非空数组)时渲染下拉(占位「请选择」+ 枚举选项);type=boolean 渲染 true/false 下拉(选中值即 JSON 布尔 true/false,不再提交字符串);其余渲染 input(:type 统一 text,number/integer 加 inputmode=decimal),placeholder 为该字段 type |
| 默认值 | 选择动作后初始化:boolean 为「请选择」(null),其余为 '';提交时空值/空串/null 一律省略不发送(不显式传 null,避免后端按 param_schema 严格类型校验误报) |
| 校验规则提示 | 卡片顶部黄色提示条(rule-hint)说明:动作配置的 ValidationRules(如 amount > 0 && status == 'open')将在写入前校验,不通过时拒绝执行并返回 validation_rules 失败信息(B7-6) |
4.4 idempotency_key 输入与「生成」按钮
| 项目 | 说明 |
|---|---|
| 含义 | 幂等键(运行模式必填),用于识别"同一次业务操作" |
| 输入框 | placeholder="自动生成或手动输入" |
| 「生成」按钮 | generateKey():优先 crypto.randomUUID(),不可用时回退 'demo-' + Date.now() + '-' + Math.random().toString(36).slice(2, 10) |
| 必填性 | handleExecute 前置校验:!idempotencyKey.value.trim() 时 alert「运行模式需要 idempotency_key(可点击"生成")」并中止 |
| 后端强制 | 服务端 handleActionExecute 对非 VALIDATE 模式同样强制:idempotency_key is required for run modes (RUN/ASYNC/VALIDATE_AND_EXECUTE) |
4.5 执行(VALIDATE_AND_EXECUTE)按钮
| 项目 | 说明 |
|---|---|
| 含义 | 以 VALIDATE_AND_EXECUTE 模式执行选中动作:先完整校验(VALIDATE 语义),通过后落库执行 |
| 可用条件 | :disabled="busy" |
| 前置校验 | 未选动作 alert「请先选择动作」;幂等键为空 alert「运行模式需要 idempotency_key(可点击"生成")」 |
| 请求体 | {action_name, object_type_id, params, idempotency_key, mode: 'VALIDATE_AND_EXECUTE'} |
| 触发的后端调用 | POST /ontology/actions/:name/execute |
| 操作效果 | 成功后写入 result、记录 lastKey = idempotencyKey,alert「执行完成:{status}」(success 用 alert-success,其余 alert-info) |
4.6 重放上次执行按钮
| 项目 | 说明 |
|---|---|
| 含义 | 复用上次执行的 idempotency_key 再次提交,复现幂等重放(replayed) |
| 可用条件 | :disabled="busy || !lastKey";title="使用上次执行的 idempotency_key 再次提交,复现幂等重放" |
| 操作效果 | idempotencyKey = lastKey 后以同一 key 重新执行;后端发现幂等键已处理,返回 status: replayed + 首次执行结果;alert「重放完成:{status}」(一律 alert-success) |
| 结果字段 | replayed_from_run_id 标注首次执行的 run id;edits.changed_records 回放首次执行的 rows_affected |
4.7 上次执行幂等键提示与执行结果卡片
| 项目 | 说明 |
|---|---|
| 上次执行幂等键 | v-if="lastKey",文案「上次执行幂等键:<code>{{ lastKey }}</code>」 |
| 结果网格 | 8 格:status(按状态着色,success 绿/replayed 蓝/validation_failed 黄/conflict 红/forbidden·record_denied 红)、mode、rows_affected、affected_records(空显示 -)、validation_result.result(空显示 -)、edits.changed_records(空显示 -)、operation_id(空显示 -)、replayed_from_run_id(空显示 -) |
| validation 区块 | result.validation 非空时展示 JSON.stringify(validation, null, 2) |
| result 区块 | result.result 非空时展示 JSON.stringify(result, null, 2)(即 ExecuteResponse.result) |
5. 后端关联
5.1 API 客户端
| 项目 | 值 |
|---|---|
| 客户端文件 | action/web/src/api/client.js |
| baseURL | /api/v1(Vite 代理到 Foundry 后端 18081) |
| 超时 | 30000ms |
| 请求拦截器 | localStorage aip_token → Authorization: Bearer <aip_token> |
| 响应拦截器 | HTTP 401 → 清 token 跳 /login |
| 导出 | export default apiClient |
5.2 端点表
| 方法 | 路径 | 请求体 | 说明 |
|---|---|---|---|
| GET | /ontology/objects | — | 对象类型列表 |
| GET | /ontology/objects/:id | — | 对象详情(含 actions 数组) |
| POST | /ontology/actions/:name/execute | {action_name, object_type_id, params, idempotency_key, mode} | 执行动作(mode 默认 VALIDATE_AND_EXECUTE) |
| POST | /ontology/actions/:name/validate | 同上(mode 强制 VALIDATE) | 仅校验不落盘(本页未使用,API 可用) |
| GET | /ontology/actions/runs/:id | — | ASYNC 模式运行状态轮询(operation_id 形如 run_<数字>;本页为同步执行,未使用) |
execute 请求体字段:action_name(或路径参数 :name)、object_type_id、params(map)、idempotency_key、mode(VALIDATE/RUN/ASYNC/VALIDATE_AND_EXECUTE)。
5.3 响应结构
validation_failed/forbidden/conflict 等)时后端仍返回响应体(含 mode/status/validation/edits/latest_state 等),HTTP 状态取错误的 ierr 状态(如 422/403/409);幂等重放(ACTION_IDEMPOTENT_REPLAY)时返回 200 语义并携带首次结果。前端 doExecute 因此在 catch 中特殊处理:if (err.response?.data?.data) return err.response.data.data,把错误响应体里的 data 也当作结果返回。执行成功响应:
{
"code": 0,
"data": {
"mode": "VALIDATE_AND_EXECUTE",
"status": "success",
"validation": {},
"validation_result": { "result": "VALID", "criteria_results": [] },
"edits": { "changed_records": 1 },
"affected_records": 1,
"rows_affected": 1,
"latest_state": { ... },
"result": { ... },
"operation_id": "run_42",
"replayed_from_run_id": ""
}
}
幂等重放响应(status=replayed,HTTP 200):
{
"code": 0,
"data": {
"mode": "VALIDATE_AND_EXECUTE",
"status": "replayed",
"validation_result": { "result": "VALID" },
"replayed_from_run_id": "42",
"operation_id": "run_42",
"result": { ... 首次执行结果 ... },
"edits": { "changed_records": 1 }
}
}
5.4 关联模块表
| 后端包/文件 | 职责 |
|---|---|
foundry/writepath/pipeline.go | 写路径执行器:ExecuteRequest/ExecuteResponse 契约、5 步流水线(Schema→RBAC→记录级→属性级→审计→幂等+事务)、Mode/Status/错误码常量、WriteBackConfig/OptimisticLock 结构、乐观锁预检 |
foundry/writepath/idempotency.go | 幂等登记:Begin(查重/登记 pending/回放)、Finish(标记结果)、ActionRunResult |
foundry/writepath/step_validation_rules.go | 提交前校验规则(B7-6):ValidationRule{expr, message},失败聚合,坏表达式 fail-closed |
foundry/server/ontology_handlers.go | handleActionExecute/handleActionValidate/handleActionRunStatus、actionExecuteRequest、writeActionResponse、buildExecuteRequest |
foundry/ontology/models.go | OntologyAction(param_schema/validation_rules/write_back_config/requires_approval/idempotency_key_field/edit_type) |
foundry/server/seed.go | 演示数据动作:update_customer_credit/update_order_status/flag_order_risk 等 |
5.5 关键机制(写路径五步流水线 + 幂等 + 乐观锁)
0 模式分派
Execute 按 mode 分派——VALIDATE 走 validate()(仅步骤 1-4 + 冲突预检,不落盘不幂等);RUN/ASYNC 走 run()(全流程);VALIDATE_AND_EXECUTE 先 validate() 通过(Status==success)再 run()。
流水线步骤(run 全流程)
| 步 | 名称 | 校验内容 | 失败返回 |
|---|---|---|---|
| 1 | Schema 校验 | param_schema JSON Schema 校验参数;布尔参数先归一(JSON 布尔/字符串/数值 true/false 与 1/0 均可,字符串大小写不敏感,B1) | validation_failed(422,VALIDATION_FAILED) |
| 1b | ValidationRules | 表达式条件(vars = action params + record 现值);空规则零开销跳过;失败聚合全部 message;坏表达式 fail-closed | validation_failed(422,VALIDATION_FAILED) |
| 2 | 逐动作 RBAC | AuthorizeUser(..., "action:"+name) | forbidden(403,FORBIDDEN) |
| 3 | 记录级权限 | 目标记录集 SELECT 主键 + RLS 可见性;任一记录不可见整批拒绝 | record_denied(403,RECORD_ACCESS_DENIED) |
| 3b | 属性级写权限 | 回写涉及属性逐属性判定,缺 EditProperty/EditPolicyProperty 拒绝 | forbidden(403,PROPERTY_EDIT_DENIED) |
| 4 | 强制审计 | ACTION_EXECUTE 事件(含 action_name/params(脱敏)/idempotency_key/mode/prior_state) | 不阻断 |
| 5 | 幂等+事务 | Begin 登记 pending → 构建 SQL → 乐观锁 → 连接器回写 → Finish 标记 | 见下文 |
幂等(补偿式登记)
action_runs 表(foundry 库)与数据源回写(外部库)无法跨库事务,采用"先登记 pending → 外部执行 → 标记结果"补偿式。idempotency_key 有唯一索引;Begin 先查已存在 → 返回 ACTION_IDEMPOTENT_REPLAY(HTTP 409)并附首次结果,writeActionResponse 检测到 status==replayed 时把 HTTP 状态降为 200。并发竞态下 CreateActionRun 用 OnConflict{DoNothing:true} 吞冲突并重查幂等键兜底(run.ID=0 场景 BUG-2 已修复)。
乐观锁(G2)
write_back_config.optimistic_lock 支持两种形态——true(默认列 updated_at、参数 expected_updated_at)或 {column, expected_param}。SQL 模板中写入 AND updated_at=:expected_updated_at,预检(optimisticConflictCheck)与执行时行数 0 命中即判定冲突,返回 conflict(409,ACTION_CONFLICT)。演示数据用毫秒精度 strftime('%Y-%m-%d %H:%M:%f','now') 写回,避免同秒乐观锁盲区。
Status 常量与错误码
Status:success / validation_failed / forbidden / conflict / record_denied / replayed / rejected。错误码:VALIDATION_FAILED / FORBIDDEN / RECORD_ACCESS_DENIED / PROPERTY_EDIT_DENIED / ACTION_CONFLICT / ACTION_IDEMPOTENT_REPLAY / WRITE_CONFIG_ERROR。
审计口径
stepAudit 调用 LogEventRef(userID, "ACTION_EXECUTE", "ontology_action", action.Name, "ACTION_EXECUTE", details, string(result));details 含 action_name、params(经 maskParams 脱敏)、idempotency_key、mode,有 prior_rows 时含 prior_state;validate/run 各失败分支也分别记录对应 status 的审计。
6. 核心流程详解
6.1 主流程:执行一个动作
- 页面挂载执行
fetchObjects(),GET /ontology/objects填充对象下拉。 - 选择对象 →
handleSelectObject():- 重置
selectedActionName/selectedAction/result/paramValues; GET /ontology/objects/:id,把返回data.data.actions填入动作下拉;失败 alert「加载动作失败:...」。
- 重置
- 选择动作 →
handleSelectAction():selectedAction = actions.find(a => a.name === selectedActionName);- 重置结果与参数,按
schemaFields初始化空值。
- 填写参数;必要时点「生成」产生幂等键或手动输入。
- 点击「执行(VALIDATE_AND_EXECUTE)」→
handleExecute():- 前置校验(选动作/幂等键)→
doExecute(name, 'VALIDATE_AND_EXECUTE'); doExecute组装params(number/integer 空值转null)、body{action_name, object_type_id, params, idempotency_key, mode},POST /ontology/actions/:name/execute;- 成功或业务失败(
err.response.data.data)均把res.data.data返回; result = resp,lastKey = idempotencyKey,alert「执行完成:{status}」。
- 前置校验(选动作/幂等键)→
- 「执行结果」卡片展示各字段;非空
validation/result以 JSON 区块展开。
6.2 分支流程:重放(幂等演示)
- 首次执行成功后
lastKey已记录,页面出现「上次执行幂等键:<key>」。 - 点击「重放上次执行」→
handleReplay():idempotencyKey = lastKey,同一动作、同一 key 再次VALIDATE_AND_EXECUTE。 - 后端
Begin发现幂等键已处理 → 返回status: replayed(HTTP 200)+ 首次结果;前端 alert「重放完成:replayed」,结果卡片中replayed_from_run_id显示首次 run id。 - 演示意义:同一业务操作重复提交不会产生第二次数据变更,
rows_affected回放首次值而非重新执行。
6.3 状态机/终态语义
| status | 含义 | 典型触发 | 数据是否落库 |
|---|---|---|---|
| success | 执行成功 | 校验与权限全过、乐观锁命中、回写成功 | 是 |
| validation_failed | 参数/校验规则失败 | 必填缺失、类型不符、ValidationRules 表达式不成立 | 否 |
| forbidden | RBAC/属性级权限拒绝 | 无 action:<name> 权限、缺属性写权限 | 否 |
| record_denied | 记录级越权 | 目标记录 RLS 不可见 | 否 |
| conflict | 乐观锁冲突 | expected_updated_at 与当前行不一致 | 否 |
| replayed | 幂等重放 | 同一 idempotency_key 重复提交 | 否(返回首次结果) |
| rejected | 动作被拒(预留) | 审批/策略拒绝类场景 | 否 |
6.4 执行时序(VALIDATE_AND_EXECUTE 单请求)
前端 POST /ontology/actions/:name/execute
→ Executor.Execute(mode=VALIDATE_AND_EXECUTE)
→ validate(): 1 Schema → 1b Rules → 2 RBAC → 3 记录级 → 3b 属性级 → 4 审计 → 5 乐观锁预检
→ 通过则 run(): 1-4 同上 → 5 Begin(idempotency_key 查重/登记) → buildWriteSQL
→ ConnectorFor(dataSourceID) 取连接器 → 编辑态落盘/血缘/事件(可选)→ 回写执行
→ Finish 标记 success/failed → 响应
7. 权限与安全
- 认证:
aip_tokenBearer;/ontology/...全在protected组。 - 逐动作 RBAC:权限点
action:<name>;未授权返回FORBIDDEN。跨产品 JWT 场景下user_id在本库查不到角色时经username兜底反查同名用户(ExecuteRequest.Username)。 - 数据级安全:记录级(RLS 可见性,写侧不 SQL 改写,改 SELECT 主键 + 可见性判定)与属性级(
EditProperty/EditPolicyProperty三分)双重防护。 - 写操作防护:幂等键唯一索引防止重复业务操作;乐观锁防止并发覆盖;前端
busy锁 + 结果展示便于核对。 - 强制审计:每次执行(含各失败分支与重放)都落
ACTION_EXECUTE审计事件,参数经maskParams脱敏,不落敏感参数明文。 - 可追溯:
operation_id(run_<id>)可关联action_runs表记录与审计日志;ASYNC 模式下还可通过GET /ontology/actions/runs/:id轮询终态。
8. 常见问题与排错
问题 1:执行后 status 为 validation_failed,参数看起来都对
现象:alert「执行完成:validation_failed」,结果卡 validation 区块有错误明细。
原因:参数未满足 param_schema(必填缺失/类型不符)或 validation_rules 表达式不成立(如 amount > 0 但传了 0)。
排查步骤:
- 展开结果卡片的
validationJSON 区块,看具体字段错误; - 核对必填标记
*与类型标注(number字段空值会被转null); - 检查动作的
validation_rules(可在对象 YAML 导出中查看)条件是否满足; - 用「重放上次执行」不会改变结果——先修正参数重新执行。
问题 2:执行报 forbidden,但页面能正常加载动作列表
现象:alert「执行失败:...user ... is not authorized for action ...」或「执行完成:forbidden」。
原因:当前用户缺少 action:<name> 权限点(RBAC),或属性级写权限不足(PROPERTY_EDIT_DENIED)。
排查步骤:
- 在后台/RBAC 配置中给当前用户授权对应动作权限点;
- 若错误含具体属性名,确认用户对回写涉及的属性具备写权限;
- 用管理员账号重试区分"权限配置问题"还是"动作本身问题"。
问题 3:执行返回 conflict(乐观锁冲突)
现象:status 为 conflict,error_code 为 ACTION_CONFLICT。
原因:expected_updated_at 参数与目标行当前 updated_at 不一致,说明期间数据被其他请求修改。
排查步骤:
- 重新查询目标行的最新
updated_at填入expected_updated_at; - 确认演示数据写回使用毫秒精度时间戳(秒级
CURRENT_TIMESTAMP有同秒盲区); - 若频繁冲突,检查是否有其他写路径同时修改同一行。
问题 4:幂等键报错 / 重放不是 replayed
现象:执行时报"idempotency_key is required...",或重放后 status 不是 replayed。
原因:运行模式(RUN/ASYNC/VALIDATE_AND_EXECUTE)强制要求幂等键;重放时若 lastKey 为空(首次执行失败未记录)则按钮禁用;若重放键与上次不一致(被手动修改),会被当作新操作执行而非重放。
排查步骤:
- 点击「生成」自动产生 key 后执行;
- 确认「上次执行幂等键」提示存在后再点「重放上次执行」;
- 重放时不要手动改动幂等键输入框;
- 若需验证幂等,用同一 key 连续执行两次,第二次应得到
replayed。
问题 5:动作下拉为空 / 加载动作失败
现象:选择对象后「动作」下拉无选项,alert「加载动作失败:...」。
原因:GET /ontology/objects/:id 失败,或该对象没有声明任何动作。
排查步骤:
- 检查 Network 面板该请求的状态码与错误信息;
- 确认对象详情响应
data.actions非空(对象需先声明动作); - 用「YAML 导入导出」页导出该对象 YAML 检查
actions段; - 若是 401,重新登录。
9. 已知缺陷与边界
| 缺陷/边界 | 说明 |
|---|---|
| 同步执行、无轮询 | 前端用 VALIDATE_AND_EXECUTE 同步等待;ASYNC 模式与 runs/:id 轮询端点后端已支持,但本页未暴露 UI |
| mode 固定 | 页面固定 VALIDATE_AND_EXECUTE,未提供 VALIDATE(纯校验)切换入口(API 支持 /actions/:name/validate) |
return_edits 契约不生效 | 请求体虽接受 return_edits,但 writepath.ExecuteRequest 尚无该字段,透传跳过(MVP 仅接受不产明细) |
| 结果展示无分页/折叠 | validation/result JSON 全量展开,超长结果可能撑高页面 |
| 参数类型覆盖有限 | param_schema 的 format/嵌套 object/数组等高级类型未在表单中专门渲染(已覆盖:enum 下拉 / boolean true-false 下拉 / text 输入) |
| 无数据源选择 | 动作回写目标由 write_back_config.data_source_id 决定,页面不能切换数据源 |
注:执行/重放提示语义混淆已于 2026-09-06 修复(按实际返回 status 判定成功/失败:success/replayed 标绿,其余失败以 alert-error 标红展示)。
注:type=boolean 参数此前落入 text 输入框,提交的字符串("true"/"1" 等)被后端严格类型校验判为不符,导致测试页无法执行;已于 2026-09-07 修复(#IKDX27)——前端对 boolean 渲染 true/false 下拉(提交 JSON 布尔),后端 normalizeBoolParams 补充字符串形态布尔归一兜底直接 API 调用。