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

314 lines
32 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 写链路签名验收门禁
采购与请假写命令不再接受数据库中几个布尔字段作为充分证据。启用命令必须同时满足:
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=true``openBlockerCount=0`;已真实完成并复核的阻断项状态改为 `resolved`,同时写入严格 `resolution` 对象:`evidenceArtifact`、对应最终字段映射或写集成文件的原始字节 `evidenceSha256``approvedBy` 和 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`
```powershell
.\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` 完全一致;三者已经进入解析凭证和 `inputFingerprint``sourceDocumentWritePayloadBound=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_AUTHORIZATION``LSERP_WORKFLOW_UAT_AUTHORIZATION_SHA256` 注入 ERP,再重启 ERP。UAT 模式会隐藏通用写能力,只接受授权中固定的工作流、命令和用例。令牌库只供现场采集器读取,严禁放进商用 ZIP、总验收目录、日志、聊天机器人或模型上下文;授权文件、绑定最终包内受限运行时 CLI 身份及精确 ERP PID/数据库作用域/用户/账套/子系统并逐模块验证载荷与原生执行关系的 1.5 只读会话预检,以及绑定该预检 SHA-256 和同一运行时 CLI 的 1.1 现场报告,都必须作为独立原始制品进入总包。
示例(授权与令牌库都必须是尚不存在的新文件):
```powershell
.\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` 指向同名且哈希完全一致的副本。
```powershell
.\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 原始响应。令牌库必须继续留在活动目录之外的受控路径。
每次开始或中断后恢复前先运行只读检查器:
```powershell
.\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 路由,也不解密令牌。它从已经存在且通过严格语义验证的脱敏证据推导断点,输出唯一 `nextCase``inputReady` 以及该项唯一的 `operatorGuide`,其中只包含当前项的角色、准备、操作、只读核对和清理说明,绝不展开整份目录或自动运行采集器。若目录哈希、提交证据与同次派生的审计证据、目录文件集、令牌库位置、授权/双 CLI 身份/ERP PID 或依赖关系不成立,恢复会失败关闭。完整工作流会额外离线复验 13/19 项覆盖率、运行 CLI 一致性和跨用例关系。
### 从 CLI 响应生成脱敏用例
客户 Windows 验收机优先使用随包提供的 `Invoke-WorkflowWriteCaseCapture.ps1`,不要手工把多层 CLI JSON 复制进观察清单。该脚本必须由提升权限的 Windows PowerShell 5.1`powershell.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_blocked``leave_stale_flow_type_blocked``leave_runtime_recheck_blocked` 必须在生成可执行计划后由已授权 DBA/配置人员改变来源或配置,再验证执行阶段确实失败关闭。运行这三项时必须同时传入 `-Execute -PauseAfterPlanForOperatorStaging`,采集器会在计划后暂停,要求输入精确的 `STAGED:<caseCode>`,随后再次复核 CLI、授权文件和令牌库哈希才允许继续执行。该模式禁止 `-NonInteractive`,也不能用于其他场景。采集器不会替 DBA 修改配置或数据。
执行完成后脚本会要求验收人员输入 DBA 只读查询/现场确认得到的业务变更数、原生确认观察、命令审计数、来源 payload 绑定和来源审计数。`-NonInteractive` 模式不会猜测这些值,缺少任一观察参数即失败。成功创建场景可传 `-CorrelatedAuditOutputPath`,用同一次计划/执行响应额外生成 `purchase_audit_correlated``leave_audit_correlated`,其业务变更数固定为零,因此不会为了取得审计证据再次写业务数据。派生审计证据必须绑定授权中自己的唯一审计用例令牌哈希,同时保留实际执行用例码;投影器只允许“采购提交→采购审计”与“请假草稿创建→请假审计”两组固定映射,不能借其他用例响应派生。
示例(观察值省略时,脚本会在执行后逐项提示):
```powershell
$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 身份不合法。
仅在排查旧验收材料时,才手工创建内嵌式原始观察清单。除授权三重哈希和唯一用例令牌哈希外,其字段固定为:`runtimeCliVersion``runtimeCliSha256``runtimeCliSignerThumbprint``caseCode``commandName`、原始 `commandInput`、可空的 `planCliResponse`、可空的 `executeCliResponse`、可空的原始 `idempotencyKey``businessMutationCount``nativeConfirmationObserved``auditEventCount``sourceDocumentWritePayloadBound``sourceDocumentAuditCount``observedAtUtc`。计数和两个来源布尔值同样必须来自 DBA 查询/现场确认,不能由模型猜测。
运行:
```powershell
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` 电子 PDF`resolutionProof` 符合完整 `rp1` 结构,业务结果明确 `success=true`,且计划的 `sourceDocumentCount/sourceDocumentSetSha256` 与命令输入中去重排序后的附件集合一致;仅填写成功码不能通过。离线投影不能取得 ERP 进程内 HMAC 密钥,因此只校验凭证结构;凭证签名、时效和会话/草稿绑定由同一受信任 ERP 进程在计划与执行时实际复核。`planFingerprintSha256` 固定为“小写 `planId` 的 UTF-8 无 BOM 字节 SHA-256”;业务 ID 和幂等键分别独立哈希。采购来源集合按上一段算法生成。原始观察清单不得进入最终 ZIP,也不得发送给模型或聊天机器人。
若原始响应已经分别保存在同一受限目录,也可直接运行:
```powershell
lserp-cli adapters project-write-observation-files `
--input .\restricted\purchase-commit.file-index.json `
--output .\cases\purchase_unique_match_commit.json
```
全部单用例完成后,在同一目录创建不含路径的索引,例如:
```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 基本名,禁止绝对路径、目录穿越、链接和重复项。运行:
```powershell
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
```powershell
.\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 签发机执行:
```powershell
$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` 签发,不会覆盖已有清单。输出的 `evidenceSha256``validatedAtUtc` 必须原样写入 V2 就绪行。签发后只要 `business-adapters.json` 或客户画像任一字节变化(包括工作流开关、字段、金额模式、容差、路径、阻断状态或格式),启动注册门禁都会拒绝旧清单,必须重新复核并签发。运行时每次就绪检查还会重新打开 `LSERP_BUSINESS_ADAPTER_CONFIG` 指向的普通文件并计算实际 SHA-256;配置修改或替换返回 `runtime_configuration_changed`,文件丢失、权限异常、超限或链接属性返回 `runtime_configuration_unavailable`,两者都会在进入固定数据库写过程前阻断写入。
## 4. 离线验证
把公钥证书安装到验收机 `TrustedPeople` 后执行:
```text
lserp-cli adapters verify-acceptance-evidence --input purchase.signed-evidence.json
```
该命令不连接 ERP 或数据库,只验证严格 JSON、内容哈希、证书信任、RSA 签名和有效期,并输出清单绑定的 `runtimeConfigurationSha256``customerProfileSha256` 供部署复核。输出的 `registrationReady=false` 是刻意设计:只有清单通过并与 ERP 启动时实际读取的配置及画像原始字节哈希、当前 V3 就绪结果及其 V2 验收证据行、在线系统目录、低代码字段及运行时过程健康检查全部一致,ERP 进程才会注册写命令。
## 5. 写入 V2 验收证据并启用 V3 就绪核对
部署 `SqlServer/002_workflow_adapter_contract.sql``003_record_workflow_acceptance.sql` 和只读的 `006_workflow_readiness_v3.sql` 后,通过客户变更单调用参数化过程 `p_lserp_agent_record_workflow_acceptance_v2`。必须使用签发脚本输出的精确范围、`evidence_id``evidence_sha256``validated_by``validated_at_utc`;六项验证字段全部来自已签名清单。不要把记录过程授权给 ERP 日常运行账号,只允许客户 DBA 或发布流水线调用。ERP 日常账号只调用 V3 就绪查询;该查询会按数据库兼容级别选定实际读写过程,核对完整有序参数签名,并在过程修改时间晚于验收时间时返回零行。
`p_agent_workflow_adapter_evidence` 和旧 readiness 过程不会自动迁移,也不能启用当前客户端。V2 主键包含工作流、模块、账套和子系统,禁止复制其他账套的证据行。
## 6. 启用配置
`business-adapters.json` 对相应工作流设置:
```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.status``capabilities.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 清单、版本、签名完全一致。