Files
lserp_cs_6.0/插件库/Lskj.AgentBridge/Deployment/WRITE_ACCEPTANCE.md
T
2026-08-14 14:28:28 +08:00

32 KiB
Raw Blame History

写链路签名验收门禁

采购与请假写命令不再接受数据库中几个布尔字段作为充分证据。启用命令必须同时满足:

  1. 当前 ERP 账套、子系统和模块通过 V3 运行时就绪查询,并匹配唯一的 V2 验收证据行。
  2. evidence_sha256 与本地签名验收清单的 contentSha256 完全一致。
  3. 清单绑定相同的工作流、模块、账套、子系统、适配器 ID/版本、证据 ID、验证人和验证时间。
  4. 清单绑定实际部署的 business-adapters.json、客户只读画像、字段映射、只读契约证据和 Windows 写集成证据五个文件的 SHA-256。
  5. 清单由 Windows TrustedPeople 中精确 thumbprint 匹配、当前有效的 RSA CSP 证书使用 RSA-SHA256 签名。
  6. 清单未过期,最长生命周期为 366 天;包括“关键目录运行时复核”在内的七项商用要求必须明确为 true

门禁在启动注册、生成计划和确认后执行前都会重新读取数据库与清单、验证签名,并用固定只读查询把签名画像与当前 SQL Server 系统目录重新比较。任一文件被替换、证书失效、子系统切换、数据库行变化、关键列/过程参数漂移或目录查询不可用,写命令保持禁用或在写过程调用前停止。

1. 证书准备

  • 使用客户验收/发布专用 RSA CSP 代码签名证书。
  • 私钥只保留在受控签发机,不安装到普通 ERP 客户端。
  • 把不含私钥的公钥证书安装到 ERP Windows 用户或本机的 TrustedPeople
  • 客户端验证按 40 位 SHA-1 certificate thumbprint 精确查找证书,再用证书内 RSA 公钥验证 SHA-256 签名。thumbprint 只用于定位,内容签名算法仍是 RSA-SHA256。
  • CNG-only 私钥不适用于当前 .NET Framework 4.0 签发脚本;应使用可暴露 RSACryptoServiceProvider 的证书。

2. 准备运行时配置、客户画像和三份验收输入

  • 已完成所有工作流开关、字段映射、金额/税额模式、容差、customerProfilePath 和验收清单路径设置的最终 schemaVersion=1.1 business-adapters.json。先生成该配置,再签发清单;配置中的清单路径可以尚不存在。
  • 经内置管理员在当前 ERP 连接执行 lserp-cli adapters revalidate-profile --input <画像> 后,criticalCatalogContractMatches=true,且不存在数据库身份、兼容级别或关键目录漂移的 1.2 客户只读画像。本次签发工作流必须显示 workflowActivation.<purchase|leave>.approved=trueopenBlockerCount=0;已真实完成并复核的阻断项状态改为 resolved,同时写入严格 resolution 对象:evidenceArtifact、对应最终字段映射或写集成文件的原始字节 evidenceSha256approvedBy 和 UTC approvedAtUtc。仍开放的项必须是 resolution=null;不得删除、替换或新增固定阻断码。采购还必须把目标选择改为 selected_and_activation_approved/activationAllowed=true。另一工作流可以仍保持 open。部署 Agent 支撑对象导致的表/视图/过程/触发器总数变化,以及画像原先为 agentWorkflowObjectsPresent=false 后变为已部署,是签发脚本唯一允许的非关键漂移;其他漂移全部拒绝。脚本会再次调用最终 CLI 在线复核并逐项确认解决哈希与清单即将签名的精确制品哈希一致;只保存一份旧命令输出不能代替该步骤。
  • 禁止手工编辑上述 resolved/resolution。三份证据齐备后,在同一客户 ERP 管理员会话运行 lserp-cli adapters prepare-profile-activation <purchase|leave> --input <开放画像> --field-mapping <最终映射> --read-evidence <只读证据> --write-evidence <写集成证据> --runtime-sha256 <最终配置哈希> --source-commit <提交> --package-sha256 <商用包哈希> --output <新画像>。该命令会重新验证当前低代码字段、证据范围和在线关键目录,并只新建一份 registrationReady=false 的未签名候选;随后把这份新画像传给本签发流程。
  • 已人工复核的最终字段映射 JSON(不是 export-review 生成的复核包)。签发脚本会以同一 ERP 账号、账套和子系统再次执行 adapters validate-fields,只有 fieldMapReady=true、零问题且模块完全一致才接受,并绑定该输入文件原始字节 SHA-256。
  • adapters verify-contract 生成且已离线复核的只读契约证据。
  • 客户 Windows 验收库中事务回滚、数据库持久幂等、权限复核、原 ERP 保存链、业务审计及重试测试报告。该报告不能再是任意文本:必须使用下述用例模板和严格证据生成器,并绑定当前源码提交、商用 ZIP、账套、子系统和最终运行时配置。

输入文件不得包含业务隐私、密码、连接串、API Key、原始发票或员工请假原因。

先生成不会通过验收的用例模板,逐项填入脱敏后的实际观察值;passed 在独立复核前必须保持 false

.\New-WorkflowWriteCasesTemplate.ps1 `
  -Workflow purchase `
  -OutputPath .\purchase.write-cases.json

模板会预填每个场景允许的 resultCode 和必要的 issueCode,这些是验收期望,不代表测试已通过;必须用实际 CLI/桥响应逐项核对,禁止为了通过验证而改写观察结果。

当前写集成报告使用严格 schemaVersion=1.6。每个用例必须绑定同一份 schemaVersion=1.2 签名短时 UAT 授权的原始文件/内容/授权 ID 哈希、固定用例唯一令牌哈希,以及实际执行桥调用的 lserp-agent-cli.exe 版本、SHA-256 和签发者;跨用例复用令牌、运行 CLI 漂移或用管理员 CLI 冒充运行 CLI都会被拒绝。报告还必须绑定同一 ERP PID 返回的上下文、计划/执行共用关联 ID、账套/子系统/用户编号哈希/用户名哈希/数据库作用域/管理员状态,以及实际命令名、版本、模块、风险和调度器固定十分钟计划有效期;汇总器再把全部用例反向绑定到报告声明的模块、账套、子系统、精确 ERP 登录身份和 UAT 授权中的运行 CLI。采购固定 13 项:唯一匹配提交、歧义阻断、累计超额阻断、命令权限阻断、数据库权限复核阻断、目标币种字段未配置、币种换算未审批、组织/部门/采购员精确范围未授权、确认后来源变化、事务回滚、幂等重放、幂等冲突和审计关联。请假固定 19 项:单日自然语言唯一解析、多日区间员工日历解析、解析凭证绕过阻断、歧义假别、歧义流程类别、缺少上午/下午/全天、带 Z/偏移的本地时间拒绝、越权员工、命令权限阻断、数据库权限复核阻断、草稿创建、第二次独立提交确认、时间冲突、预览后流程类别失效、其他运行时变化(含日历工时快照改变)、事务回滚、幂等重放、幂等冲突和审计关联。

每项 resultCode 必须等于真实 CLI/数据库稳定码;计划阶段阻断取桥响应中的 plan.outcomeCode,执行阶段取 result.code,不能填用例名或任意合法字符串。采购歧义/超额固定为 purchase_match_invalid;请假解析阻断固定为 leave_resolution_invalid,重叠阻断固定为 leave_request_invalid。四类自然语言解析/越权阻断还必须填写精确 issueCode。所有确认后阻断、幂等重放和幂等冲突都必须带计划指纹、幂等键哈希和 nativeConfirmationObserved=true;确认前阻断不得伪称已确认。

验证器还会做跨用例关联:提交与幂等重放必须指向相同规范化业务输入、记录、事务、审计和幂等键,但桥在提交成功后会消费原计划,因此重放必须由新的计划发起并使用不同计划指纹;幂等冲突必须复用同一键但使用不同业务输入/计划。采购和请假 create 的输入指纹只排除顶层精确 resolutionProof,允许新的 resolve 凭证重放同一业务;其他字段、其他命令和嵌套同名字段不排除,新计划仍必须携带有效凭证。重放和冲突都必须至少包含“新计划 + 执行结果/失败”两条命令审计事件。审计关联必须指向原提交及原计划;请假的独立提交必须沿用草稿记录但使用不同计划、事务、审计和幂等键。采购成功、重放和审计关联三项还必须用同一个 sourceDocumentSetSha256 和同一有序 sourceDocumentPreprocessContracts 证明附件集合与处理实现同时进入命令输入指纹、写过程 payload 和同一业务审计链;该数组必须精确包含 pdfium_minimax_pages_v1。报告中不得保存原始发票内容。所有业务记录号、附件集合指纹、事务证据 ID、审计 ID 和幂等键只写 SHA-256,不写原值。

sourceDocumentSetSha256 的复核算法固定为:取本次受信任附件回执与 p_agent_business_source_document 中的每个小写 source_sha256,去重后按 Ordinal 升序排列,以单个 \n 连接(末尾不加换行),再对 UTF-8 无 BOM 字节计算小写 SHA-256。sourceDocumentAuditCount 等于同一 businessAuditId 下参与该集合的去重审计行数。每一行还必须有 64 位小写 extraction_sha256 和非空 preprocess_contract,并与命令输入中同一 source_sha256 对应的 extractionSha256/preprocessContract 完全一致;三者已经进入解析凭证和 inputFingerprintsourceDocumentWritePayloadBound=true 只有在 DBA 观察到两种摘要和处理契约均进入固定 XML v3 payload 与同一业务审计事务时才能填写。这样验收人员可以证明文件集合、Agent 实际看到的提取版本和具体受信任处理链均未被替换,而无需把文件名、路径或原始发票内容写进报告。

签发一次性客户 UAT 授权

写命令在生产配置中始终默认关闭。只有客户可恢复、明确非生产的 UAT 库可以由提升权限的 Windows PowerShell 5.1 运行 New-WorkflowUatAuthorization.ps1,将客户、环境、ERP 用户、运行配置、客户画像、发布策略、最终 ZIP、签名 ERP/CLI 及固定用例绑定到最长 24 小时的 RSA-SHA256 授权。命令必须显式传入 -DatabaseBackupVerified-RestoreProcedureVerified-NonProductionEnvironmentVerified-NativeConfirmationVerified-TransactionAuditVerified;任一安全事实未验证都不得签发。生成器同时创建仅当前提升用户与 LocalSystem 可访问、带高完整性标签并由 DPAPI CurrentUser 加密的令牌库。

将授权文件路径及其原始字节 SHA-256 通过 LSERP_WORKFLOW_UAT_AUTHORIZATIONLSERP_WORKFLOW_UAT_AUTHORIZATION_SHA256 注入 ERP,再重启 ERP。UAT 模式会隐藏通用写能力,只接受授权中固定的工作流、命令和用例。令牌库只供现场采集器读取,严禁放进商用 ZIP、总验收目录、日志、聊天机器人或模型上下文;授权文件、绑定最终包内受限运行时 CLI 身份及精确 ERP PID/数据库作用域/用户/账套/子系统并逐模块验证载荷与原生执行关系的 1.5 只读会话预检,以及绑定该预检 SHA-256 和同一运行时 CLI 的 1.1 现场报告,都必须作为独立原始制品进入总包。

示例(授权与令牌库都必须是尚不存在的新文件):

.\New-WorkflowUatAuthorization.ps1 `
  -Workflow both `
  -PurchaseModuleCode PURCHASE -PurchaseAdapterId lserp.purchase.customer-a -PurchaseAdapterVersion 1.0.0 `
  -LeaveModuleCode LEAVE -LeaveAdapterId lserp.leave.customer-a -LeaveAdapterVersion 1.0.0 `
  -AuthorizationId CUSTOMER-A-UAT-20260813-01 `
  -CustomerId CUSTOMER-A -EnvironmentId CUSTOMER-A-UAT-01 `
  -AccountBook ACCOUNT-1 -SubSystemId SUB-1 `
  -ErpUserId 1 -ErpUserName 管理员 `
  -DatabaseScopeFingerprint <当前ERP返回的64位数据库作用域指纹> `
  -RuntimeConfigurationFile .\business-adapters.json `
  -CustomerProfileFile .\lserp-ai.readonly-map.json `
  -RolloutPolicyFile .\command-rollout.json `
  -CommercialPackageFile .\Lserp-AgentPet-win-x64.zip `
  -SourceCommit <40位提交号> -ExpectedPackageSha256 <最终ZIP的64位哈希> `
  -ErpExecutablePath D:\Acceptance\legacy-erp-build\Runtime\Ls_ERP.exe `
  -RuntimeCliPath D:\Acceptance\agent-pet\Host\lserp-agent-cli.exe `
  -ExpectedRuntimeCliVersion @LSERP_PACKAGE_VERSION@ `
  -VerifierCliPath D:\Acceptance\legacy-erp-build\Runtime\lserp-cli.exe `
  -ExpectedErpSignerThumbprint <ERP的40位签发者指纹> `
  -ExpectedCliSignerThumbprint <CLI的40位签发者指纹> `
  -ExpectedRuntimeCliSignerThumbprint <运行CLI的40位签发者指纹> `
  -ApprovedBy QA-APPROVER-1 `
  -DatabaseBackupVerified -RestoreProcedureVerified `
  -NonProductionEnvironmentVerified -NativeConfirmationVerified `
  -TransactionAuditVerified `
  -CertificateThumbprint <UAT授权签名证书指纹> `
  -OutputPath .\workflow-uat-authorization.json `
  -TokenVaultPath C:\ProgramData\Langsu\Acceptance\workflow-uat-token-vault.json `
  -ValidHours 8

建立可断点续跑的现场 UAT 活动

授权签发、ERP 重启并加载同一授权后,不要编写“循环执行 32 个用例”的批量脚本。使用 New-WorkflowWriteUatCampaign.ps1 从已签名授权生成固定活动清单。脚本只创建当前提升用户与 LocalSystem 可访问、带高完整性标签的受限目录,固化授权/CLI 身份、13+19 项顺序、命令、计划或执行模式、依赖、幂等关系和 DBA 人工阶段;不会连接桥、读取令牌明文或写数据库,也不会创建业务输入、幂等键或令牌文件。活动目录不是最终验收制品,不能放进客户总验收目录。

商用包中的 workflow-write-uat-case-catalog.v1.json 是这 32 项的版本化现场目录,给每项固定角色、夹具类别、前置条件、操作步骤、DBA 只读核对、清理、重试策略及预期结果。它不含凭据、业务标识、SQL 或可执行指令。生成器和检查器都内置并复核其精确 SHA-256,活动清单还会再次记录该哈希;不要编辑、另存或“按客户习惯”改写此文件。默认读取脚本同目录的文件,如需从受控制品目录显式指定,只能通过 -CaseCatalogFile 指向同名且哈希完全一致的副本。

.\New-WorkflowWriteUatCampaign.ps1 `
  -CampaignId CUSTOMER-A-UAT-20260813-01 `
  -UatAuthorizationFile .\workflow-uat-authorization.json `
  -VerifierCliPath D:\Acceptance\legacy-erp-build\Runtime\lserp-cli.exe `
  -RuntimeCliPath D:\Acceptance\agent-pet\Host\lserp-agent-cli.exe `
  -ExpectedUatAuthorizationSha256 <授权文件的64位原始字节哈希> `
  -ExpectedVerifierCliSha256 <LEGACY-BUILD-EVIDENCE中的64位CLI哈希> `
  -ExpectedRuntimeCliVersion @LSERP_PACKAGE_VERSION@ `
  -ExpectedRuntimeCliSha256 <最终ZIP清单中的运行CLI哈希> `
  -ExpectedVerifierSignerThumbprint <管理员CLI的40位签发者指纹> `
  -ExpectedRuntimeSignerThumbprint <运行CLI的40位签发者指纹> `
  -OutputRoot C:\ProgramData\Langsu\Acceptance\Campaigns

生成器不会替换已有活动目录。把每个场景经客户脱敏、单独复核的输入放到清单指定的 private-input/<caseCode>.json;不要在活动目录保存原始发票、请假原因、令牌库、明文幂等键或 CLI 原始响应。令牌库必须继续留在活动目录之外的受控路径。

每次开始或中断后恢复前先运行只读检查器:

.\Test-WorkflowWriteUatCampaign.ps1 `
  -CampaignFile C:\ProgramData\Langsu\Acceptance\Campaigns\CUSTOMER-A-UAT-20260813-01\campaign.json `
  -UatAuthorizationFile .\workflow-uat-authorization.json `
  -UatTokenVaultPath C:\ProgramData\Langsu\Acceptance\workflow-uat-token-vault.json `
  -VerifierCliPath D:\Acceptance\legacy-erp-build\Runtime\lserp-cli.exe `
  -RuntimeCliPath D:\Acceptance\agent-pet\Host\lserp-agent-cli.exe `
  -ExpectedUatAuthorizationSha256 <授权文件哈希> `
  -ExpectedVerifierCliSha256 <管理员CLI哈希> `
  -ExpectedRuntimeCliVersion @LSERP_PACKAGE_VERSION@ `
  -ExpectedRuntimeCliSha256 <运行CLI哈希> `
  -ExpectedVerifierSignerThumbprint <管理员CLI签发者指纹> `
  -ExpectedRuntimeSignerThumbprint <运行CLI签发者指纹> `
  -ErpProcessId 1234

检查器用管理员 lserp-cli.exe 验证签名授权和脱敏证据,只用受限 lserp-agent-cli.exe 执行 version 与桥 health;没有 execute 路由,也不解密令牌。它从已经存在且通过严格语义验证的脱敏证据推导断点,输出唯一 nextCaseinputReady 以及该项唯一的 operatorGuide,其中只包含当前项的角色、准备、操作、只读核对和清理说明,绝不展开整份目录或自动运行采集器。若目录哈希、提交证据与同次派生的审计证据、目录文件集、令牌库位置、授权/双 CLI 身份/ERP PID 或依赖关系不成立,恢复会失败关闭。完整工作流会额外离线复验 13/19 项覆盖率、运行 CLI 一致性和跨用例关系。

从 CLI 响应生成脱敏用例

客户 Windows 验收机优先使用随包提供的 Invoke-WorkflowWriteCaseCapture.ps1,不要手工把多层 CLI JSON 复制进观察清单。该脚本必须由提升权限的 Windows PowerShell 5.1powershell.exe)运行,以使用受控 NTFS ACL、DPAPI、高完整性标签和 Authenticode;不会在 PowerShell 7、macOS 或 Linux 上降级执行。脚本锁定并离线验证签名 UAT 授权、受限令牌库和最终 CLI,复核它们的预期 SHA-256/签发者以及 ERP 已加载的同一授权。它从签名授权中取得并验证原始 ERP PID,以及数据库作用域指纹、用户编号、用户名、账套、子系统和管理员布尔值六项预期范围,然后把 PID 和六项范围作为每次受限 CLI health/context/plan/execute 的显式参数;CLI 自身仍会在目标命令前后复核实际 ERP 上下文。UAT 令牌只通过关闭的标准输入传给 --uat-token-stdin,幂等键只通过同一次关闭的标准输入传给 --idempotency-key-stdin,两者都不进入命令行或输出。对采购/请假创建场景,脚本会在受限临时目录自动执行 resolve -> create,只把服务器返回的短期 resolutionProof 用于后续计划,不要求人工准备或导出该凭证。它绑定同一关联 ID,分别保存源输入、实际创建输入、上下文、准备计划、目标计划和可选执行响应,再离线投影;成功或失败后都会清理受限原始目录,清理失败时已发布输出也会撤回。

purchase_runtime_recheck_blockedleave_stale_flow_type_blockedleave_runtime_recheck_blocked 必须在生成可执行计划后由已授权 DBA/配置人员改变来源或配置,再验证执行阶段确实失败关闭。运行这三项时必须同时传入 -Execute -PauseAfterPlanForOperatorStaging,采集器会在计划后暂停,要求输入精确的 STAGED:<caseCode>,随后再次复核 CLI、授权文件和令牌库哈希才允许继续执行。该模式禁止 -NonInteractive,也不能用于其他场景。采集器不会替 DBA 修改配置或数据。

执行完成后脚本会要求验收人员输入 DBA 只读查询/现场确认得到的业务变更数、原生确认观察、命令审计数、来源 payload 绑定和来源审计数。-NonInteractive 模式不会猜测这些值,缺少任一观察参数即失败。成功创建场景可传 -CorrelatedAuditOutputPath,用同一次计划/执行响应额外生成 purchase_audit_correlatedleave_audit_correlated,其业务变更数固定为零,因此不会为了取得审计证据再次写业务数据。派生审计证据必须绑定授权中自己的唯一审计用例令牌哈希,同时保留实际执行用例码;投影器只允许“采购提交→采购审计”与“请假草稿创建→请假审计”两组固定映射,不能借其他用例响应派生。

示例(观察值省略时,脚本会在执行后逐项提示):

$key = Read-Host '本次稳定业务幂等键' -AsSecureString
.\Invoke-WorkflowWriteCaseCapture.ps1 `
  -CaseCode purchase_unique_match_commit `
  -CommandName purchase.invoice.create `
  -CommandInputFile .\restricted-input\purchase-create.json `
  -OutputPath .\cases\purchase_unique_match_commit.json `
  -CorrelatedAuditOutputPath .\cases\purchase_audit_correlated.json `
  -VerifierCliPath D:\Acceptance\legacy-erp-build\Runtime\lserp-cli.exe `
  -RuntimeCliPath D:\Acceptance\agent-pet\Host\lserp-agent-cli.exe `
  -UatAuthorizationFile .\workflow-uat-authorization.json `
  -UatTokenVaultPath C:\ProgramData\Langsu\Acceptance\workflow-uat-token-vault.json `
  -ExpectedUatAuthorizationSha256 <授权文件的64位原始字节哈希> `
  -ExpectedVerifierCliSha256 <LEGACY-BUILD-EVIDENCE中的64位哈希> `
  -ExpectedRuntimeCliVersion @LSERP_PACKAGE_VERSION@ `
  -ExpectedRuntimeCliSha256 <最终ZIP清单中的运行CLI哈希> `
  -ExpectedVerifierSignerThumbprint <管理员CLI的40位证书指纹> `
  -ExpectedRuntimeSignerThumbprint <运行CLI的40位证书指纹> `
  -ErpProcessId 1234 `
  -Execute `
  -IdempotencyKey $key

计划阶段阻断用例省略 -Execute 和幂等键。无人值守调用可改用只允许一行的受限 -IdempotencyKeyFile,并显式传入 -BusinessMutationCount-NativeConfirmationObserved-AuditEventCount-SourceDocumentWritePayloadBound-SourceDocumentAuditCount-NonInteractive;调用者提供的幂等键文件不由脚本删除,验收流程必须自行安全销毁。

底层文件索引使用严格 schemaVersion=1.3,除命令、上下文、计划/执行和 DBA 观察字段外,还固定包含 UAT 授权原始文件/内容/授权 ID 哈希、授权签发/失效时间、实际执行用例码、该用例令牌哈希及运行 CLI 的版本/SHA-256/签发者。文件引用只允许同目录、不重复的安全 ASCII .json 基本名;绝对路径、目录穿越和链接均被拒绝。上下文响应必须成功;至少要有一份计划/执行 CLI 响应;有执行响应时必须同时带成功且可执行的计划响应,而且上下文、准备计划、目标计划与执行必须显式使用同一个安全 --correlation-id。投影器还会拒绝观察时间不在授权窗口、执行用例与索引不一致、授权哈希漂移或运行 CLI 身份不合法。

仅在排查旧验收材料时,才手工创建内嵌式原始观察清单。除授权三重哈希和唯一用例令牌哈希外,其字段固定为:runtimeCliVersionruntimeCliSha256runtimeCliSignerThumbprintcaseCodecommandName、原始 commandInput、可空的 planCliResponse、可空的 executeCliResponse、可空的原始 idempotencyKeybusinessMutationCountnativeConfirmationObservedauditEventCountsourceDocumentWritePayloadBoundsourceDocumentAuditCountobservedAtUtc。计数和两个来源布尔值同样必须来自 DBA 查询/现场确认,不能由模型猜测。

运行:

lserp-cli adapters project-write-observation `
  --input .\restricted\purchase-commit.raw.json `
  --output .\cases\purchase_unique_match_commit.json

投影器会严格拒绝未知/重复 JSON 字段、注释、链接文件、错配的命令输入指纹、错误的固定结果码、缺失的精确 issueCode、不成立的确认/事务/幂等/审计语义以及已有输出文件。采购提交、幂等重放和审计关联三项还必须精确调用 purchase.invoice.create 1.4,输入通过完整创建 Schema(发票日期、头金额、至少一条完整明细和来源附件均不可省略),至少包含一份 pdfium_minimax_pages_v1 电子 PDFresolutionProof 符合完整 rp1 结构,业务结果明确 success=true,且计划的 sourceDocumentCount/sourceDocumentSetSha256 与命令输入中去重排序后的附件集合一致;仅填写成功码不能通过。离线投影不能取得 ERP 进程内 HMAC 密钥,因此只校验凭证结构;凭证签名、时效和会话/草稿绑定由同一受信任 ERP 进程在计划与执行时实际复核。planFingerprintSha256 固定为“小写 planId 的 UTF-8 无 BOM 字节 SHA-256”;业务 ID 和幂等键分别独立哈希。采购来源集合按上一段算法生成。原始观察清单不得进入最终 ZIP,也不得发送给模型或聊天机器人。

若原始响应已经分别保存在同一受限目录,也可直接运行:

lserp-cli adapters project-write-observation-files `
  --input .\restricted\purchase-commit.file-index.json `
  --output .\cases\purchase_unique_match_commit.json

全部单用例完成后,在同一目录创建不含路径的索引,例如:

{
  "schemaVersion": "1.0",
  "workflow": "purchase",
  "caseFiles": [
    "purchase_unique_match_commit.json",
    "purchase_ambiguous_match_blocked.json",
    "purchase_overallocation_blocked.json",
    "purchase_permission_denied.json",
    "purchase_database_permission_recheck_denied.json",
    "purchase_currency_field_missing_blocked.json",
    "purchase_currency_crosswalk_unapproved_blocked.json",
    "purchase_row_scope_denied.json",
    "purchase_runtime_recheck_blocked.json",
    "purchase_transaction_rollback.json",
    "purchase_idempotency_replay.json",
    "purchase_idempotency_conflict.json",
    "purchase_audit_correlated.json"
  ]
}

索引必须完整列出采购 13 个或请假 19 个文件。文件名只允许安全 ASCII 基本名,禁止绝对路径、目录穿越、链接和重复项。运行:

lserp-cli adapters assemble-write-observations `
  --input .\cases\purchase-index.json `
  --output .\cases\purchase-cases.json

汇总器会按固定用例顺序输出数组,并在发布前再次检查完整覆盖以及提交、重放、冲突、审计、来源附件和请假独立提交之间的哈希关系。把该数组作为 New-WorkflowWriteIntegrationEvidence.ps1 -CasesFile 的输入,不再手工复制 JSON。

复核用例后生成自哈希报告。这里的 CLI 必须是最终 Windows 旧 ERP 构建目录中已签名且受 LEGACY-BUILD-EVIDENCE.json 保护的 CLI

.\New-WorkflowWriteIntegrationEvidence.ps1 `
  -Workflow purchase `
  -ModuleCode PURCHASE `
  -AccountBook ACCOUNT-1 `
  -SubSystemId SUB-1 `
  -SourceCommit <40位提交号> `
  -PackageSha256 <商用ZIP的SHA-256> `
  -RuntimeConfigurationFile .\business-adapters.json `
  -RolloutCustomerId CUSTOMER-A `
  -EnvironmentId CUSTOMER-A-UAT-01 `
  -TestedBy QA-ADMIN-1 `
  -CasesFile .\purchase.write-cases.json `
  -UatAuthorizationFile .\workflow-uat-authorization.json `
  -VerifierCliPath D:\Acceptance\legacy-erp-build\Runtime\lserp-cli.exe `
  -OutputPath .\purchase-windows-test-report.json

生成器先写临时文件,再调用 CLI 严格验证;遗漏、重复、未知、失败、结果码或问题码不匹配、来源附件未贯通、跨提交、跨包、跨账套或证据字段不足时不会发布最终报告。

3. 签发清单

在持有证书私钥的受控 Windows 签发机执行:

$erpPassword = Read-Host 'ERP password' -AsSecureString
.\New-WorkflowAcceptanceEvidence.ps1 `
  -Workflow purchase `
  -ModuleCode PURCHASE `
  -AccountBook ACCOUNT-1 `
  -SubSystemId SUB-1 `
  -AdapterId lserp.purchase.customer-a `
  -AdapterVersion 1.0.0 `
  -EvidenceId acc-purchase-20260811 `
  -RuntimeConfigurationFile .\business-adapters.json `
  -CustomerProfileFile .\lserp-ai.readonly-map.json `
  -FieldMappingEvidence .\purchase-mapping.json `
  -ReadContractEvidence .\purchase-read-evidence.json `
  -WriteIntegrationEvidence .\purchase-windows-test-report.json `
  -VerifierCliPath D:\Acceptance\legacy-erp-build\Runtime\lserp-cli.exe `
  -ErpUser 1 `
  -ErpPassword $erpPassword `
  -ExpectedSourceCommit <40位提交号> `
  -ExpectedPackageSha256 <商用ZIP的SHA-256> `
  -ValidatedBy QA-ADMIN-1 `
  -CertificateThumbprint 00112233445566778899AABBCCDDEEFF00112233 `
  -OutputPath .\purchase.signed-evidence.json

脚本先以只读共享锁锁定最终 CLI、运行配置、画像、字段映射及两份集成证据;六个输入和输出必须是互不重复的普通文件,验证与签名期间不能被写入、删除或同名替换。随后用最终 CLI 和同一 ERP 身份在线复核客户画像,并拒绝本次工作流任何未关闭阻断项;画像为采购/请假声明的模块编号还必须与 -ModuleCode 逐字一致。再实时验证最终字段映射,离线验证只读契约证据的 verified=true 及工作流/模块/账套/子系统,最后验证写集成报告的完整用例、运行时配置、源码提交和商用包哈希。三个业务证据输入在验证前后还会重新计算 SHA-256,变化时不签;ERP 密码只以 SecureString 接收并通过 stdin 交给 CLI,不进入命令行、环境变量、签名内容或日志。最后使用 CreateNew 签发,不会覆盖已有清单。输出的 evidenceSha256validatedAtUtc 必须原样写入 V2 就绪行。签发后只要 business-adapters.json 或客户画像任一字节变化(包括工作流开关、字段、金额模式、容差、路径、阻断状态或格式),启动注册门禁都会拒绝旧清单,必须重新复核并签发。运行时每次就绪检查还会重新打开 LSERP_BUSINESS_ADAPTER_CONFIG 指向的普通文件并计算实际 SHA-256;配置修改或替换返回 runtime_configuration_changed,文件丢失、权限异常、超限或链接属性返回 runtime_configuration_unavailable,两者都会在进入固定数据库写过程前阻断写入。

4. 离线验证

把公钥证书安装到验收机 TrustedPeople 后执行:

lserp-cli adapters verify-acceptance-evidence --input purchase.signed-evidence.json

该命令不连接 ERP 或数据库,只验证严格 JSON、内容哈希、证书信任、RSA 签名和有效期,并输出清单绑定的 runtimeConfigurationSha256customerProfileSha256 供部署复核。输出的 registrationReady=false 是刻意设计:只有清单通过并与 ERP 启动时实际读取的配置及画像原始字节哈希、当前 V3 就绪结果及其 V2 验收证据行、在线系统目录、低代码字段及运行时过程健康检查全部一致,ERP 进程才会注册写命令。

5. 写入 V2 验收证据并启用 V3 就绪核对

部署 SqlServer/002_workflow_adapter_contract.sql003_record_workflow_acceptance.sql 和只读的 006_workflow_readiness_v3.sql 后,通过客户变更单调用参数化过程 p_lserp_agent_record_workflow_acceptance_v2。必须使用签发脚本输出的精确范围、evidence_idevidence_sha256validated_byvalidated_at_utc;六项验证字段全部来自已签名清单。不要把记录过程授权给 ERP 日常运行账号,只允许客户 DBA 或发布流水线调用。ERP 日常账号只调用 V3 就绪查询;该查询会按数据库兼容级别选定实际读写过程,核对完整有序参数签名,并在过程修改时间晚于验收时间时返回零行。

p_agent_workflow_adapter_evidence 和旧 readiness 过程不会自动迁移,也不能启用当前客户端。V2 主键包含工作流、模块、账套和子系统,禁止复制其他账套的证据行。

6. 启用配置

business-adapters.json 对相应工作流设置:

{
  "schemaVersion": "1.1",
  "customerProfilePath": "customer-profiles/lserp-ai.readonly-map.json",
  "purchase": {
  "enabled": true,
  "acceptanceEvidencePath": "acceptance/purchase.signed-evidence.json"
  }
}

相对路径按适配器配置文件所在目录解析。清单必须是 256 KB 内的普通 UTF-8 文件,链接文件、重复属性、JSON 注释、多根值、未知字段、错误哈希或过期证据都会失败关闭。

启动 ERP 后,以管理员身份查看 adapters.statuscapabilities.list。只有全部门禁通过时才应出现 purchase.invoice.create 或请假三个命令。

采购和请假都签发完成后,不要把两份清单孤立交付。按 CUSTOMER_ACCEPTANCE.md 收集 23 个原始文件:采购与请假各用一份只授权自身工作流的 UAT 文件、各自子系统的 1.5 只读预检和 1.1 现场交接,诊断另用管理员子系统预检与交接。向 New-CustomerAcceptanceBundle.ps1 分别传三组会话文件与子系统、两份 UAT 文件、管理员 -VerifierCliPath、最终 ZIP 中的受限 -RuntimeCliPath-ExpectedRuntimeCliVersion,生成 schemaVersion=1.8 客户总签章。最终验证器会拒绝运行时/管理员 CLI 角色混用、跨子系统交换、合并授权或角色混用;令牌库绝不能进入目录。管理员验证 CLI 必须与旧 ERP 构建证据一致,受限运行时 CLI 必须与最终 ZIP 清单、版本、签名完全一致。