code-copilot 指令、项目记忆、编码规范、流程开发 Skill、前端设计 Skill与自动化测试标准。unified-capability-open-platform 的 Spec、测试规格和执行日志。JAVA_HOME=/opt/homebrew/Cellar/openjdk@17/17.0.13/libexec/openjdk.jdk/Contents/Home。v20.19.0;生产构建使用 NODE_OPTIONS=--max-old-space-size=8192。-Penable-tests,并核对 Surefire Tests run 非 0。以下命令均在 forge-server/ 执行,并使用上述 Java 17 环境:
mvn -pl :forge-plugin-capability-control-plane,:forge-plugin-capability-identity,:forge-plugin-capability-secure-actions,:forge-plugin-capability-flow-actions,:forge-plugin-capability-open-gateway -am -DskipTests test-compile
mvn -Penable-tests -pl :forge-plugin-capability-control-plane -Dtest=CapabilityOpenApiDocumentServiceTest,CapabilityCallGuideServiceTest test
mvn -Penable-tests -pl :forge-plugin-capability-secure-actions -Dtest=SystemServiceDefinitionRegistryTest,SystemServiceCapabilityPublisherTest,SystemServiceOpenGatewayAdapterTest test
mvn -Penable-tests -pl :forge-plugin-capability-flow-actions -Dtest=FlowProcessStartSystemServiceTest,FlowActionExecutionAdapterTest test
mvn -Penable-tests -pl :forge-plugin-capability-identity -Dtest=CapabilityAccessTokenServiceTest test
mvn -Penable-tests -pl :forge-plugin-capability-open-gateway -Dtest=BusinessActionOpenGatewayAdapterTest,OpenGatewayCapabilityResolverTest,CapabilityInvokeOrchestratorTest,OpenGatewayAuthenticatorTest test
mvn -pl :forge-admin-server -am -DskipTests compile
结果:
| 范围 | 结果 | 覆盖结论 |
|---|---|---|
关联模块 test-compile |
✅ 36/36 Reactor 模块成功 | 主码与新增测试源码均完成编译 |
| Control Plane 定向测试 | ✅ 6/6 | Markdown/OpenAPI 文档、调用指南 readiness 与安全示例 |
| Secure Actions 定向测试 | ✅ 10/10 | 注册表重复/未知定义失败关闭、发布参数白名单、系统服务网关适配 |
| Flow Actions 定向测试 | ✅ 11/11 | 流程固定快照、变量白名单、USER 委托、模型漂移拒绝及既有流程动作兼容 |
| Identity 定向测试 | ✅ 7/7 | OpenAPI/MCP audience 严格隔离 |
| Open Gateway 定向测试 | ✅ 20/20 | 适配器分派、未知来源、Bearer resource 校验和异常映射 |
| 定向测试合计 | ✅ 54/54 | 本轮 P0 核心后端差异全部通过 |
| Admin 聚合编译 | ✅ 47/47 Reactor 模块成功 | 主应用依赖和自动装配可编译 |
MCP 委托身份集成测试另行执行:
mvn -Penable-tests -pl :forge-starter-crypto,:forge-plugin-capability-identity -am -Dtest=McpDelegatedIdentityIntegrationTest -Dsurefire.failIfNoSpecifiedTests=false test
结果:✅ McpDelegatedIdentityIntegrationTest 3/3,通过 USER 委托身份上下文集成回归。
执行五个目标插件的全量测试时,Control Plane 为 ✅ 41/41;Identity 共 49 个用例,其中首轮 46 个普通测试通过,3 个 McpDelegatedIdentityIntegrationTest 在 Spring Context 初始化阶段失败。失败信息为:
自动密钥文件包含不允许的配置键: forge.capability.identity.authorization-code-pepper
根因不是产品逻辑失败,而是该次 Reactor 未包含当前工作区的 forge-starter-crypto,测试类路径解析到了本地 Maven 仓库中的旧版 Starter。将 :forge-starter-crypto 显式加入同一 Reactor 后,3/3 集成测试通过。首轮命令在 Identity 处停止,后续 Secure Actions、Flow Actions、Open Gateway 全量模块被 Maven 标为 skipped;不将它们记作全量通过,仅采用 3.2 节已经实际通过的定向用例作为本轮证据。
CapabilityGrantPolicyTest 的 Surefire 报告显示 Time elapsed: 925.9 s,但测试命令实际墙钟仅数秒且 6/6 通过,判定为测试计时元数据异常,不是性能结论。目标测试日志中的 WARN/ERROR 来自故障映射和失败关闭用例的预期分支。
以下命令在 forge-admin-ui/、Node v20.19.0 下执行:
pnpm exec eslint src/views/ai/capability/catalog.vue src/views/ai/capability/grant.vue src/views/ai/capability/components/CapabilityRegisterModal.vue src/views/ai/capability/components/CapabilityCallGuideModal.vue
NODE_OPTIONS=--max-old-space-size=8192 pnpm build
结果:
UserSelectModal 组件命名冲突、静态/动态导入导致无法拆分 chunk、CSS 使用 // 注释;均不属于本轮功能错误。V1.0.77 与差异静态检查:
rg -n '\$\{[^}]+\}' forge-server/db/migration/V1.0.77__add_capability_system_service_permissions.sql
git diff --check
结果:✅ V1.0.77 无 Flyway ${...} 占位符,权限资源使用 tenant_id=1 与 NOT EXISTS 防重复;git diff --check 无空白错误。全迁移目录扫描发现的 ${...} 仅位于既有 V1.0.72 消息模板文本,与本变更无关。
forge_schema_history 或权限资源落库结果。CapabilityOpenApiDocumentService 时抛出 No default constructor found。@Autowired,保留必需依赖的构造器注入,不增加可能产生空依赖的无参构造器。ApplicationContextRunner + @Import 容器装配测试,真实经过 Spring Bean 创建路径。| 范围 | 命令 | 结果 |
|---|---|---|
| 失败基线 | mvn -Penable-tests -pl :forge-plugin-capability-control-plane -Dtest=CapabilityOpenApiDocumentServiceTest test |
按预期复现:3 个用例中新增容器测试 1 个失败,异常与用户日志一致 |
| 定向复跑 | 同上 | ✅ 3/3,Spring Context 正常创建文档服务 |
| Control Plane 全量 | mvn -Penable-tests -pl :forge-plugin-capability-control-plane test |
✅ 42/42,Failures 0、Errors 0、Skipped 0 |
| Admin 聚合编译 | mvn -pl :forge-admin-server -am -DskipTests compile |
✅ 47/47 Reactor 模块,BUILD SUCCESS;仅保留既有 deprecated/unchecked 编译警告 |
OpenGatewayAuthenticator 时找不到 CapabilityAccessTokenService。open-gateway.enabled=true、identity.enabled=false 的半开启组合,网关已创建但令牌服务未装配。identityEnabled || gatewayEnabled 计算有效 Identity 状态,避免运行态可用但页面误报 OAuth 不可用。验证命令均在 forge-server/ 下使用 JDK 17 执行:
mvn -Penable-tests -pl :forge-plugin-capability-identity -Dtest=CapabilityIdentityAutoConfigurationTest test
mvn -Penable-tests -pl :forge-plugin-capability-open-gateway -Dtest=OpenGatewayAutoConfigurationTest test
mvn -Penable-tests -pl :forge-plugin-capability-control-plane -Dtest=CapabilityCallGuideServiceTest test
mvn -Penable-tests -pl :forge-plugin-capability-control-plane,:forge-plugin-capability-identity,:forge-plugin-capability-open-gateway test
mvn -pl :forge-admin-server -am -DskipTests compile
git diff --check
| 范围 | 结果 |
|---|---|
| Identity 失败基线 | 新增网关强制 Identity 用例按预期失败:2 个用例中 1 个找不到 CapabilityAccessTokenService |
| Identity 定向复跑 | ✅ 2/2,网关开启且 Identity 显式关闭时仍提供 Token Service |
| Open Gateway 联合装配 | ✅ 1/1,同时创建 Token Service、认证器和调用编排器 |
| 调用指南失败基线 | 新增有效 Identity 状态用例按预期失败:5 个用例中 1 个 ready=false |
| 调用指南定向复跑 | ✅ 5/5,OAuth 状态及示例与真实运行态一致 |
| 三模块全量测试 | ✅ Control Plane 43/43、Identity 50/50、Open Gateway 21/21,共 114/114 |
| Admin 聚合编译 | ✅ 47/47 Reactor 模块,BUILD SUCCESS |
| 差异静态检查 | ✅ git diff --check 无空白错误 |
INTERNAL_ERROR WARN,均为既有故障映射测试的预期分支,不是测试失败。{data, algorithm} 加密信封,而当前后端已关闭 API 解密,Spring 因此只能绑定出空业务 DTO。postEncrypt 显式敏感请求在提交前重新读取 /crypto/config。服务端关闭加密时发送普通 DTO;开启时继续强制密钥协商与加密;配置无法确认时失败关闭。授权 DTO 同时补充字段级中文校验消息。useDict 将请求失败返回的空数组写入全局缓存,单次瞬时失败会持续到 SPA 整体刷新;同时数据库缺少来源类型、行为类型两个字典。Promise.allSettled 逐项处理,仅缓存成功结果,失败项自动重试一次且不覆盖已成功数据;授权弹窗支持刷新字典并在流程操作未翻译时禁止提交。新增 V1.0.78 字典迁移,能力目录表格/详情和系统服务摘要统一读取字典。useDict、能力目录/授权/注册组件、授权 DTO、V1.0.78 迁移及本变更文档。CapabilityAccessTokenService,但 Token Controller 等公开组件仍只判断 identity.enabled=true,形成“服务已装配、路由未注册”的半开启状态。CapabilityIdentityRequiredCondition;Identity 或 Open Gateway 任一开启时,自动配置、Token/OAuth 路由、UserInfo、MCP 身份上下文、调用审计和 Token 清理任务采用同一装配语义。/ai/capability/enable/{id},重新启用前校验当前版本存在且为 PUBLISHED;前端停用状态显示绿色“启用”操作并二次确认。subject_token_type 做 Token Exchange。sub 到 Forge 普通用户;原始 sub 不落库,只保存 SHA-256 与脱敏提示。运行时禁止管理员身份,并实时加载用户状态、租户、组织和角色。alg/kid/iss/aud/client_id/sub/iat/exp/jti,使用 Redis 防重放;验签、防重放或目录基础设施不可用时失败关闭,OIDC 与客户端断言不得回退。kid 和版本;PKCS#8 私钥通过加密响应只展示一次。轮换和停用同步递增客户端 credential_version,撤销旧客户端 Token。V1.0.79__add_capability_client_user_assertion.sql,全部新增字段使用 information_schema 防重复,未写入任何密钥或真实用户标识。/oauth2/token 未登录属于 OAuth 公开端点的正常状态;fdu_ 是 Capability 短期 Token,不是 Sa-Token。通用操作日志切面在网关控制器执行前尝试读取 Sa-Token 用户,造成“token 无效”堆栈,但真实网关认证随后已成功。/oauth2/token、/oauth2/revoke 与能力开放网关路径,凭据和业务报文继续由专用安全审计治理。sourceType/behavior 提示。BUSINESS_ACTION/ACTION、SYSTEM_SERVICE/ACTION 和已开启的 FLOW_ACTION/FLOW 可进入测试;旧的未知来源或关闭的流程执行器会提前给出中文修复建议。sub 只需绑定一次,后续所有 Token Exchange 复用。该边界用于阻止客户端任意指定 Forge 用户;受信 OIDC 模式仍可按已验证手机号完成首次自动映射。git diff --check 无新增空白错误,目标文件未发现冲突标记,运行结果待用户验证。sysJobConfigMapper 时失败,异常链最终落在 MybatisPlusAutoConfiguration -> DataScopeInterceptor -> DataScopeServiceImpl -> SysDataScopeConfigMapper -> sqlSessionFactory 的循环依赖;jobAutoRegistrar 只是最先触发 Mapper 创建的入口。DataScopeInterceptor,自动配置方法又直接注入依赖 Mapper 的 IDataScopeService,导致 SqlSessionFactory 尚未完成创建时反向请求自身。DataScopeAutoConfiguration 改为注入 ObjectProvider<IDataScopeService>,通过 Supplier 将 Service 解析延迟到普通业务 SQL 真正进入数据权限拦截器时;数据权限模块自己的 Mapper 仍在解析 Supplier 前直接跳过,避免递归。保留原 Service 构造器以兼容现有调用和测试,延迟服务未就绪时明确失败关闭。DataScopeInterceptor 不再保存直接 Service 引用,运行时调用统一通过延迟取值;git diff --check 无空白错误。AiCapabilityExternalIdentityMapper.selectActive 查询报 访问租户表[ai_capability_external_identity]时缺少租户上下文,Token 端点返回 temporarily_unavailable。tenantId 建立上下文。首个异常出现在外围身份映射;继续执行还会影响 Token 签发、Bearer 校验和撤销等租户表访问。CapabilityTenantContext,在已验证客户端或 Token 的租户内执行安全数据访问,强制 ignoreTenant=false、跳过不适用于认证基础设施的用户数据权限,并嵌套安全地恢复租户、忽略标记和数据权限标记。token_exchange,不再误显示 unknown。git diff --check 无空白错误,目标 Java/XML 未发现冲突标记。MyBatisSystemException,开放网关返回“能力审计服务暂时不可用”;日志中没有出现对应审计 UPDATE 的 Preparing 记录。AiCapabilityInvocationLogMapper.updateResultByRequestIdentity 使用 MySQL NULL 安全等号 <=> 比较可空的 service_user_id。租户拦截器会先通过 JSqlParser 改写 SQL,而当前解析器不支持该运算符,因此 SQL 尚未发送到数据库就失败。service_user_id = ? OR (service_user_id IS NULL AND ? IS NULL) 的标准等价表达式,保留 USER 委托时 service_user_id=NULL 的身份匹配语义;数据库字段原本已允许 NULL,无需新增迁移。访问租户表[ai_capability_invocation_log]时缺少租户上下文。完整堆栈确认调用来自 CapabilityInvokeOrchestrator.failure(),而外层 try-with-resources 已先关闭开放网关上下文。OpenGatewayContextBridge 内,失败审计位于其关闭之后,导致相同审计方法在不同路径具有不同租户语义。CapabilityInvocationAuditService 对 record、recordOrUpdate、冲突查询和分页统一以已校验的显式 tenantId 建立受控上下文,强制 ignoreTenant=false,跳过不适用于审计基础设施的用户 DataScope,并在 finally 中恢复原租户、租户忽略和 DataScope 标记。未把审计表加入租户忽略名单。PINNED 基准版本切换到当前版本,或改为 FOLLOW_MAJOR。服务端按目标版本重新校验字段/操作策略,不自动修改现有固定授权。1.0.1 已发布成功并包含新的流程绑定,但所选客户端授权仍为 PINNED + 1.0.0;调用指南和开放网关按授权解析旧版本,因此测试继续命中旧流程快照并返回 FLOW_BINDING_MISMATCH。发布能力版本本身不会自动修改既有授权,这是版本安全策略,不是发布失败。FLOW_ACTION 同时比较授权版本与当前版本的 bindingId、flowModelKey、publishedObjectVersion;快照变化时在真实调用前显示中文阻断原因并禁用在线测试。recordId=121212 进入低代码业务对象查询后未找到当前委托用户可见的请假记录。START 的职责是为已保存记录启动流程,不会创建请假申请,因此原始业务拒绝是正确的。FLOW_ACTION 和操作类型,在在线测试请求区明确提示 recordId 必须来自已保存业务记录、记录受实际委托用户数据权限约束、START 不创建记录;示例改用 <REAL_RECORD_ID>,避免把随机数字误当可执行示例。arguments={};下载的外围接入示例同步包含请求前提。RESOURCE_NOT_FOUND,保留统一文案防止记录存在性枚举;在线测试摘要直接展示服务端错误码和原因,不再只提示 HTTP 状态或误报 SCHEMA_INVALID。FLOW_ACTION/SUBMIT。外围系统请求只提交 data 业务字段;Forge 使用可信 USER 委托身份补齐申请人、归属人、租户、组织、审计和初始单据状态,在一次调用中创建低代码业务记录并启动已发布主流程。原 START 改为“发起已有记录流程”,继续只接受真实 recordId。recordId/businessKey/processInstanceId/flowModelKey/flowStatus。recordId 检查点使用同一 REQUIRES_NEW 事务。流程启动失败后,复用相同 Idempotency-Key 只会使用检查点记录,不会重复建单;稳定业务键继续用于远端流程成功、本地回填失败后的恢复。recordId。requestId 输出入口、认证、授权、输入准备、Schema、策略、审计预留、适配器执行、幂等命中、成功和失败日志。失败日志增加 failureStage/resultCode/httpStatus/schemaPath/durationMs/exceptionType;5xx 保留异常堆栈,4xx 不打印堆栈。日志不记录 Authorization、Token、Secret、签名、Nonce、Idempotency-Key 原文或请求/响应 Body。V1.0.81__add_capability_flow_submit_operation.sql,增加“提交业务申请”字典项并设为默认,将 START 展示名改为“发起已有记录流程”;内置数据 tenant_id=1,写入具备防重复保护。git diff --check,目标目录未发现冲突标记;流程动作与能力审计 Mapper 已移除 MySQL NULL 安全等号运算符,安全日志关键字检查未发现业务报文或凭据输出。SecureActionStepValidator 返回“受控业务动作缺少执行步骤”。status != 0,而真实发布还要求已发布快照存在非空执行步骤,且当前仅允许 UPDATE_FIELD/CREATE_RECORD;页面与服务端判断事实不一致。/ai/capability/business-action/registration-source,从同一份不可变发布快照返回动作、可写字段、发布版本及可发布诊断。SecureActionStepValidator 继续作为发布和运行时安全边界,同时输出可复用诊断;直接调用发布接口仍会拒绝空步骤、不支持步骤和嵌套步骤。git diff --check 通过;本轮目标 Java/Vue/JS/文档未发现冲突标记;新增差异未发现打印 Token、Secret、签名、Nonce 或请求/响应 Body 的日志。HR/LEAVE_APPLICATION 当前状态为 PUBLISHED,最新发布版本为 v39;当前设计与 v39 快照中的 add/新增 均为 actionType=OPEN_PAGE、actionConfig={}。因此不是动作丢失或未重新发布,而是页面按钮没有服务端执行步骤。START_FLOW 归入流程入口;无执行步骤的新增/编辑/删除等页面操作不再显示成业务自动化;COMMAND/TRIGGER 和已有执行步骤的兼容动作继续保留。OPEN_PAGE 标记为“页面操作,不能直接开放”;申请对象可以在诊断区直接切换到 FLOW_ACTION/SUBMIT,由 Forge 一次完成创建记录和发起流程。OPEN_PAGE 或 START_FLOW 空步骤动作时返回对应语义和正确注册路径,安全白名单及失败关闭策略不变。git diff --check,未发现新增空白错误。FlowActionCapabilityController.publish 在目录保存前被 CapabilitySchemaValidator 拒绝,路径为 $.properties.recordId.pattern;说明流程动作发布器生成了能力内核未实现的 Schema 关键字。pattern 外,SUBMIT 字段还可能生成 format/multipleOf/default/example,数组字段原先生成空 items={},均与内核“每个节点必须显式声明受支持 type”的规则冲突。FlowActionExecutionAdapter.parseRecordId 强制校验。items 显式声明受控元素类型,避免再次出现无类型 Schema 节点。SUBMIT/START/APPROVE/REJECT,其中 SUBMIT 为默认值;本次错误不是字典缺失。git diff --check,并确认流程动作发布源码不再生成上述未支持关键字。forge_schema_history 中 v1.0.81 执行成功;ai_capability_flow_operation 存在启用的 SUBMIT、START、APPROVE、REJECT,SUBMIT 的 dict_sort=1/is_default=Y。useDict,其模块级 dictCache 在整个 SPA 生命周期内无过期时间;组件后续挂载会直接复用旧列表。字典 /system/dict/data/list 调用 selectDictDataList 直接查库,本次不是 Redis 字典缓存或 Flyway 漏执行。git diff --check,目标 Vue 文件未发现冲突标记。failureStage=INPUT_SCHEMA_VALIDATION,但外部响应为 HTTP 503“开放API幂等服务暂不可用”,堆栈只保留二次创建的 BusinessException,没有原始校验原因和字段路径。OpenApiIdempotencyManager.execute 在 Redis 加锁后仍用同一个宽泛 catch (RuntimeException) 包围 action.get();CapabilitySchemaValidationException 属于运行时异常,因此被错误重写为幂等基础设施故障。REDIS_CLIENT/LOCK_ACQUIRE/SNAPSHOT_LOAD/DUPLICATE_SNAPSHOT_LOAD/SNAPSHOT_WRITE 输出 phase、scope 和完整异常链,不记录幂等键或业务报文。Schema 失败返回中文原因,并在响应 data 中返回 failureStage/schemaPath。price 均仍为 varchar/TEXT/input,现有能力 1.0.0 因而按不可变来源快照正确生成了 string;能力平台没有权限按字段名猜成整数。saveSelectedField 时错误检查了仅代表移动端抽屉显示状态的 propertyVisible,导致用户已经选择整数后点击顶部保存并未调用字段更新接口。int(11)、bigint unsigned、decimal(18,2)、tinyint(1),并识别 NUMBER/MONEY/SWITCH 及数字组件语义。1.0.0;旧契约继续不可变,类型修正只会通过后续对象发布和能力新版本生效。ADAPTER_EXECUTION 后返回 SCHEMA_INVALID,具体消息为“字段不存在: dpe”;输入 Schema 和客户端字段授权已经通过。HR/LEAVE_APPLICATION、ai_crud_config 和最新发布设计版本均为版本 40,运行模型和发布快照都存在业务字段 dpe;该字段显式映射到物理列 field_input4,hr_leave_application.field_input4 真实存在且类型为 varchar(128)。DynamicCrudService.insertInternal 的允许字段来自发布模型,但写入列映射只读取数据库元数据并做 camelCase/snake_case 推导,把业务字段 dpe 错当成同名物理列,忽略了模型中的 columnName=field_input4。LowcodeFieldSchema.field -> columnName,覆盖查询、普通写入、内部动作写入、关联主表、单号、脱敏和导出;读取链路补充物理列到业务字段的兼容别名。git diff --check,目标 Java 和变更文档未发现空白错误;未发现新增凭据或业务报文日志。business.hr.leave_application.submit v1.0.1 在字段写入修复后返回 HTTP 404 + RESOURCE_NOT_FOUND,提示记录不存在或无权限访问;用户确认业务表已有新数据。requestId=4f332b99-9c02-40fe-aa7c-bb0b720f1f2f 的流程动作日志为 FLOW_ACTION/SUBMIT,委托用户 45、当前组织 21,检查点已保存 recordId=19;业务表记录 19 为 tenant_id=1/create_by=45/create_dept=21/document_status=DRAFT。TENANT,记录租户与调用租户一致;本次不是角色或组织数据权限拒绝。REPEATABLE-READ。外层流程动作事务在内层 REQUIRES_NEW 建单前读取了能力来源元数据,形成旧一致性快照;记录 19 在独立事务提交后,外层流程启动查询仍看不到它,因而在 BusinessFlowService.startDocumentFlowInternal 被误报为不可见。READ_COMMITTED,保证后续读取能看到已提交检查点记录;START/APPROVE/REJECT 的现有事务策略保持不变,建单与 recordId 检查点仍在同一 REQUIRES_NEW 事务提交。ExecutionIdentity,外围 USER 委托不再因缺少 Sa-Token 登录态而失去 FOLLOW_SYSTEM 数据权限上下文。git diff --check,目标 Java 与变更文档未发现空白错误或冲突标记。V1.0.82__improve_capability_client_workbench.sql,维护客户端映射模式、调用日志诊断字段、映射模式字典和菜单聚合;内置数据使用 tenant_id=1 并具备防重复保护。git diff --check 未发现空白错误;目标能力模块、前端页面/API 和变更文档未发现行首 Git 冲突标记。git diff --check,目标 Java、XML、Vue 和变更文档未发现空白错误;目标文件未发现行首 Git 冲突标记。