Files
baiyue-firstleg/scripts/agents-index-contract.ps1
T

1095 lines
95 KiB
PowerShell
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.
[CmdletBinding()]
param()
$ErrorActionPreference = 'Stop'
$backendRoot = Split-Path -Parent $PSScriptRoot
$workspaceRoot = Split-Path -Parent $backendRoot
$failures = [System.Collections.Generic.List[string]]::new()
$checked = 0
function Add-Failure([string]$message) {
$script:failures.Add($message)
}
function Read-RequiredText([string]$path) {
$script:checked++
if (-not (Test-Path -LiteralPath $path -PathType Leaf)) {
Add-Failure "缺少索引文件: $path"
return ''
}
return Get-Content -LiteralPath $path -Raw
}
function Assert-Contains([string]$text, [string]$needle, [string]$scope) {
$script:checked++
if (-not $text.Contains($needle)) {
Add-Failure "$scope 未索引: $needle"
}
}
function Assert-NotContains([string]$text, [string]$needle, [string]$scope) {
$script:checked++
if ($text.Contains($needle)) {
Add-Failure "$scope 仍残留: $needle"
}
}
function Assert-Matches([string]$text, [string]$pattern, [string]$scope) {
$script:checked++
if ($text -notmatch $pattern) {
Add-Failure "$scope 未匹配合同: $pattern"
}
}
function Assert-Path([string]$relativePath) {
$script:checked++
$absolutePath = Join-Path $workspaceRoot $relativePath
if (-not (Test-Path -LiteralPath $absolutePath)) {
Add-Failure "索引入口不存在: $relativePath"
}
}
function Assert-PathMissing([string]$relativePath) {
$script:checked++
$absolutePath = Join-Path $workspaceRoot $relativePath
if (Test-Path -LiteralPath $absolutePath) {
Add-Failure "已移除入口仍然存在: $relativePath"
}
}
function Assert-MarkdownTableUnique([string]$path, [string]$heading, [int]$keyColumn, [string]$scope) {
$script:checked++
$lines = Get-Content -LiteralPath $path
$inside = $false
$keys = [System.Collections.Generic.List[string]]::new()
foreach ($line in $lines) {
if ($line -eq $heading) {
$inside = $true
continue
}
if ($inside -and $line.StartsWith('## ')) { break }
if (-not $inside -or -not $line.StartsWith('|')) { continue }
$cells = @($line.Trim('|').Split('|') | ForEach-Object { $_.Trim() })
if ($keyColumn -ge $cells.Count -or $cells[$keyColumn] -match '^:?-{3,}:?$') { continue }
$keys.Add($cells[$keyColumn])
}
$keys | Group-Object | Where-Object Count -gt 1 | ForEach-Object {
Add-Failure "$scope 存在重复索引键: $($_.Name)($($_.Count) 次)"
}
}
$rootAgentsPath = Join-Path $workspaceRoot 'AGENTS.md'
$adminAgentsPath = Join-Path $workspaceRoot 'apps/admin-web/AGENTS.md'
$clientAgentsPath = Join-Path $workspaceRoot 'apps/client-web/AGENTS.md'
$pdaAgentsPath = Join-Path $workspaceRoot 'apps/pda-uniapp/AGENTS.md'
$overseasPdaAgentsPath = Join-Path $workspaceRoot 'apps/pda-overseas-uniapp/AGENTS.md'
$backendAgentsPath = Join-Path $backendRoot 'AGENTS.md'
$rootAgents = Read-RequiredText $rootAgentsPath
$adminAgents = Read-RequiredText $adminAgentsPath
$clientAgents = Read-RequiredText $clientAgentsPath
$pdaAgents = Read-RequiredText $pdaAgentsPath
$overseasPdaAgents = Read-RequiredText $overseasPdaAgentsPath
$backendAgents = Read-RequiredText $backendAgentsPath
$scriptsAgents = Read-RequiredText (Join-Path $backendRoot 'scripts/AGENTS.md')
$engineeringConstraints = Read-RequiredText (Join-Path $workspaceRoot 'docs/AI工程执行与协作约束.md')
$docsIndex = Read-RequiredText (Join-Path $workspaceRoot 'docs/README.md')
$testTaskRegistry = Read-RequiredText (Join-Path $workspaceRoot 'docs/独立任务协作登记.md')
$devTaskRegistry = Read-RequiredText (Join-Path $workspaceRoot 'docs/开发环境独立任务协作登记.md')
$mapperScanContract = Read-RequiredText (Join-Path $backendRoot 'scripts/mapper-scan-contract.mjs')
# 当前未上线阶段的无兼容原则必须覆盖全部实现与运行状态,不能再次缩窄为文件或数据库专项规则。
Assert-Contains $rootAgents '源码结构、接口与 DTO、字段、状态机、权限、配置键、数据库结构与初始化 SQL、事件、路由、页面、Mock/Fixture、测试和脚本' '根无兼容收敛范围'
Assert-Contains $rootAgents '数据库记录、上传文件、缓存、会话、消息、搜索索引和其他运行状态均视为可丢弃' '根开发运行状态范围'
Assert-Contains $rootAgents '后端 MyBatis Mapper 新增、移动或扫描遗漏' '根 Mapper 快速入口'
Assert-Contains $rootAgents 'node scripts/mapper-scan-contract.mjs' '根 Mapper 静态门禁'
Assert-Contains $rootAgents '脚本管理、全量验证与测试造数' '根脚本管理快速入口'
Assert-Contains $rootAgents 'baiyue-firstleg/scripts/AGENTS.md' '根脚本最近指引'
Assert-Contains $engineeringConstraints '禁止为旧代码、旧调用或开发环境存量保留旧接口/旧字段别名' '工程无兼容执行规则'
Assert-Contains $engineeringConstraints '不授权自动重置数据库、删除数据/文件、执行 SQL、部署或修改环境' '无兼容安全边界'
Assert-Contains $clientAgents '不得继续扩展 `LEGACY_MANUAL`、旧系统入仓码、C02 不可用回退旧 API' 'Client 头程无兼容边界'
Assert-Contains $backendAgents '所有生产 MyBatis Mapper 接口必须显式标记 `@Mapper`' '后端 Mapper 注册规则'
Assert-Contains $backendAgents 'Mapper 新增、移动、Bean 缺失与扫描遗漏' '后端 Mapper 快速路由'
Assert-Contains $backendAgents '脚本管理、全量验证、测试造数与诊断' '后端脚本管理快速路由'
Assert-Contains $backendAgents 'scripts/it-test-wait-split-bulk.mjs' '后端批量待分柜造数入口'
Assert-Contains $backendAgents 'scripts/create-pending-review-orders.mjs' '后端待审核订单造数入口'
Assert-Contains $backendAgents 'scripts/client-quick-order-test-env-acceptance.mjs' '后端 Client 快速下单入口'
Assert-Contains $backendAgents 'service-center-flow' '后端服务中心验收模块'
Assert-Contains $scriptsAgents 'admin-test-env-acceptance.mjs' '脚本指引 Admin 全量入口'
Assert-Contains $scriptsAgents 'client-test-env-acceptance.mjs' '脚本指引 Client 全量入口'
# 开发与测试独立任务必须按保存项目、cwd 和登记表完全隔离,task_id 不得跨表复用。
Assert-Contains $rootAgents 'docs/开发环境独立任务协作登记.md' '根开发协作登记入口'
Assert-Contains $rootAgents 'docs/独立任务协作登记.md' '根测试协作登记入口'
Assert-Contains $engineeringConstraints '不得同时加载两表后混合选取任务' '工程协作登记选择门禁'
Assert-Contains $docsIndex '[测试环境独立任务协作登记](独立任务协作登记.md)' '文档测试登记入口'
Assert-Contains $docsIndex '[开发环境独立任务协作登记](开发环境独立任务协作登记.md)' '文档开发登记入口'
Assert-Contains $testTaskRegistry 'projectId `c64729ff-6710-43c6-8ef2-d84e9666cc1e`' '测试登记保存项目'
Assert-Contains $testTaskRegistry 'C:\Users\BY-OY\Desktop\code\chongchong-global`' '测试登记工作目录'
Assert-Contains $testTaskRegistry '已重新启用测试环境总控调度' '测试登记启用状态'
Assert-Contains $testTaskRegistry '`01a05b10-a5fc-7d51-8203-c671f3a823ad`' '测试环境全流程总控'
Assert-Contains $testTaskRegistry '`01a046ea-cfc4-73a1-85f0-c69c714bff22`' '测试环境海外接柜仓总控'
Assert-Contains $testTaskRegistry '| 海外接柜后端 |' '测试环境海外接柜后端专项'
Assert-Contains $testTaskRegistry '| 海外接柜Admin前端 |' '测试环境海外接柜 Admin 专项'
Assert-Contains $testTaskRegistry '| 海外接柜Client前端 |' '测试环境海外接柜 Client 专项'
Assert-Contains $testTaskRegistry '| 海外接柜PDA前端 |' '测试环境海外接柜 PDA 专项'
Assert-NotContains $testTaskRegistry '01a0194a-259c-7171-8967-074731a27618' '测试登记历史总控'
Assert-NotContains $testTaskRegistry '01a06c0b-0515-7c60-b329-77342b54e666' '测试登记当前开发总控'
Assert-NotContains $testTaskRegistry '6f874ec3-d3b2-49bd-8625-327f4d685f98' '测试登记开发 projectId'
Assert-Contains $devTaskRegistry 'projectId `6f874ec3-d3b2-49bd-8625-327f4d685f98`' '开发登记保存项目'
Assert-Contains $devTaskRegistry 'C:\Users\BY-OY\Desktop\code\chongchong-global-dev`' '开发登记工作目录'
Assert-Contains $devTaskRegistry '`01a06c0b-0515-7c60-b329-77342b54e666`' '开发环境全流程总控'
Assert-NotContains $devTaskRegistry '01a0194a-259c-7171-8967-074731a27618' '开发登记测试总控'
Assert-NotContains $devTaskRegistry 'c64729ff-6710-43c6-8ef2-d84e9666cc1e' '开发登记测试 projectId'
# 业务文档已由开发批次目录收敛为稳定业务域,根快速路由不得继续引用已删除阶段目录。
foreach ($businessDocsEntry in @(
'docs/订单与客户/README.md',
'docs/入库测量与计费/README.md',
'docs/国内货柜履约/README.md',
'docs/海外仓业务/README.md'
)) {
Assert-Contains $rootAgents $businessDocsEntry "根业务域入口 $businessDocsEntry"
}
foreach ($removedPhaseDocsEntry in @('docs/一期/', 'docs/二期/', 'docs/三期/', 'docs/四期/')) {
Assert-NotContains $rootAgents $removedPhaseDocsEntry "根已删除阶段目录 $removedPhaseDocsEntry"
}
Assert-NotContains $rootAgents '不含出库和派送' '根海外仓全流程范围'
# 新增稳定业务能力必须从根表和目标部署单元直接命中。
Assert-Contains $rootAgents '入库扣货、解除与凭证' '根入库扣货路由'
Assert-Contains $adminAgents '入库扣货、解除与凭证历史' 'Admin 入库扣货路由'
Assert-Contains $backendAgents '入库扣货、解除、履约门禁与凭证' '后端入库扣货路由'
Assert-Contains $rootAgents '客户资金账户、充值、授信与业务扣费' '根客户资金账户路由'
Assert-Contains $adminAgents '客户资金账户与柜级公共费用分摊' 'Admin 客户资金账户路由'
Assert-Contains $clientAgents '客户资金账户、授信与充值申请' 'Client 客户资金账户路由'
Assert-Contains $backendAgents '客户资金账户、充值、授信、冻结与结算' '后端客户资金账户路由'
Assert-Contains $rootAgents '顶层授权快照' '根海外顶层授权快照'
Assert-Contains $backendAgents '顶层授权快照' '后端海外顶层授权快照'
Assert-Contains $rootAgents '目的港码头拖车与还空预警' '根目的港码头拖车路由'
Assert-Contains $rootAgents '与订舱级拖车预约是不同生命周期' '根两类拖车边界'
Assert-Contains $rootAgents '尾程订单控制与柜级入仓计划转换' '根尾程订单控制路由'
Assert-Contains $adminAgents '目的港码头拖车与还空预警' 'Admin 目的港码头拖车路由'
Assert-Contains $adminAgents '尾程订单控制与柜级入仓计划转换' 'Admin 尾程订单控制路由'
Assert-Contains $backendAgents '目的港码头拖车与还空预警' '后端目的港码头拖车路由'
Assert-Contains $backendAgents '尾程订单控制与柜级入仓计划转换' '后端尾程订单控制路由'
$testTaskIds = @([regex]::Matches($testTaskRegistry, '(?m)^\|\s*`([0-9a-f-]{36})`\s*\|') | ForEach-Object { $_.Groups[1].Value })
$devTaskIds = @([regex]::Matches($devTaskRegistry, '(?m)^\|\s*`([0-9a-f-]{36})`\s*\|') | ForEach-Object { $_.Groups[1].Value })
foreach ($sharedTaskId in @($testTaskIds | Where-Object { $devTaskIds -contains $_ } | Select-Object -Unique)) {
$script:checked++
Add-Failure "开发/测试登记复用了 task_id: $sharedTaskId"
}
Assert-Contains $scriptsAgents 'client-quick-order-test-env-acceptance.mjs' '脚本指引 Client 快速下单入口'
Assert-Contains $scriptsAgents 'admin-test-env-modules/service-center-flow.mjs' '脚本指引服务中心验收模块'
Assert-Contains $scriptsAgents 'admin-test-env-modules/phase4-tail-order-controls.mjs' '脚本指引尾程单控制模块'
Assert-Contains $scriptsAgents 'admin-test-env-modules/phase5-terminal-drayage.mjs' '脚本指引目的港码头拖车模块'
Assert-Contains $scriptsAgents 'script-documentation-contract.test.mjs' '脚本说明防漏门禁'
Assert-Contains $scriptsAgents '不得散落到 `src/test/scripts/`' '服务局部脚本目录边界'
Assert-Path 'baiyue-firstleg/scripts/AGENTS.md'
Assert-Path 'baiyue-firstleg/scripts/README.md'
Assert-Path 'baiyue-firstleg/scripts/script-documentation-contract.test.mjs'
Assert-Contains $mapperScanContract 'annotationClass = Mapper.class' 'Mapper 根包注解过滤合同'
Assert-Contains $mapperScanContract '禁止分散维护 MapperScan' 'Mapper 单一扫描入口合同'
$firstlegAgents = Read-RequiredText (Join-Path $backendRoot 'firstleg/AGENTS.md')
$lastlegAgents = Read-RequiredText (Join-Path $backendRoot 'lastleg-service/AGENTS.md')
$warehouseAgents = Read-RequiredText (Join-Path $backendRoot 'warehouse/AGENTS.md')
$coloadOpenApi = Read-RequiredText (Join-Path $backendRoot 'firstleg/src/main/resources/openapi/coload-groups-v1.yaml')
Assert-Contains $rootAgents 'modules/unified-orders/api/coLoadGroups.ts' '根同柜不可拆组入口'
Assert-Contains $adminAgents '成员数是入仓片段数,不等于订单票数' 'Admin 同柜成员语义'
Assert-Contains $backendAgents 'loading/coload/controller/PlatformColoadGroupController.java' '后端同柜不可拆组入口'
Assert-Contains $firstlegAgents '服务端冻结每票全部 `WAIT_SPLIT` 可用入仓片段与满箱数' 'Firstleg 同柜建组边界'
Assert-Contains $warehouseAgents 'scripts/warehouse-public-master-data-contract.test.mjs' 'Warehouse 局部脚本入口'
Assert-Contains $coloadOpenApi '允许跨客户及不同目的仓港成组,仅要求国内仓和渠道一致' '同柜资格 OpenAPI'
Assert-Contains $coloadOpenApi '服务端解析每个订单全部 WAIT_SPLIT' '同柜订单展开 OpenAPI'
Assert-Contains $rootAgents '用户可见页面、提示和错误不得展示或以内部数据库 ID 作为业务编号回退' '根业务编号展示边界'
Assert-Contains $adminAgents '/loading-plans/{planId}/lifecycle' 'Admin 装柜清单生命周期入口'
Assert-Contains $adminAgents '合柜报关 / 同柜不可拆组' 'Admin 合柜报关别名入口'
Assert-Contains $clientAgents 'api/inboundCodeAssociations.ts' 'Client 入仓码业务关系入口'
Assert-Contains $pdaAgents 'tests/page-contract.test.mjs' '国内 PDA 页面合同入口'
Assert-Contains $overseasPdaAgents 'tests/business-identifiers-ui.test.mjs' '海外 PDA 内部 ID 隔离合同'
$orderAgents = Read-RequiredText (Join-Path $backendRoot 'order/AGENTS.md')
Assert-Contains $orderAgents '`channelCode` 直接来自 Order/Firstleg 权威快照' 'Order 稳定渠道编码'
Assert-Contains $orderAgents 'InboundCodeAssociationService.java' 'Order 入仓码业务关系入口'
Assert-Contains $firstlegAgents '/loading-plans/{planId}/lifecycle' 'Firstleg 装柜生命周期入口'
Assert-Contains $lastlegAgents 'LastlegOrderCommandService.java' 'Lastleg 尾程订单命令入口'
Assert-Contains $lastlegAgents '固定八行完整快照' 'Lastleg 人工节点快照边界'
Assert-Contains $lastlegAgents '/api/platform/v1/last-leg/inbound-plans/convert-container' 'Lastleg 整柜转换正式入口'
# 本轮新增的批量下单、测量计费、智能装柜、账单联查与导出重试必须从最近指引直达。
$fileAgents = Read-RequiredText (Join-Path $backendRoot 'file/AGENTS.md')
$financeAgents = Read-RequiredText (Join-Path $backendRoot 'finance/AGENTS.md')
Assert-Contains $rootAgents '客户头程订单批量导入' '根批量下单快速路由'
Assert-Contains $orderAgents 'MerchantBatchImportService.java' 'Order 批量导入入口'
Assert-Contains $orderAgents '仓库目录必须翻页读取全部候选' 'Order 批量模板全量仓库约束'
Assert-Contains $clientAgents '中文批量导入' 'Client 批量导入入口'
Assert-Contains $firstlegAgents '客户四档箱规与默认算法' 'Firstleg 客户箱规入口'
Assert-Contains $firstlegAgents '`ADD/MULTIPLY`' 'Firstleg 箱规算法约束'
Assert-Contains $adminAgents '客户箱规策略与计价主数据' 'Admin 箱规计费入口'
Assert-Contains $backendAgents '全局智能装柜候选、柜次、占位与移除' '后端全局智能装柜路由'
Assert-Contains $firstlegAgents '必须成员完整、满箱并作为单个分页与分配单元' 'Firstleg 智能装柜组分页边界'
Assert-Contains $adminAgents 'GlobalSmartLoadingView.vue' 'Admin 全局智能装柜入口'
Assert-Contains $financeAgents 'StatementLine.inboundCode' 'Finance 账单入仓码字段'
Assert-Contains $clientAgents '账单行只显示服务端 `inboundCode`' 'Client 账单入仓码联查边界'
Assert-Contains $fileAgents '`PENDING` 且已有失败尝试' 'File 导出退避重试边界'
Assert-Contains $adminAgents 'attemptCount/maxAttempts/nextRetryAt' 'Admin 导出重试状态入口'
Assert-Path 'baiyue-firstleg/order/src/main/java/com/baiyue/order/service/MerchantBatchImportService.java'
Assert-Path 'baiyue-firstleg/firstleg/src/main/java/com/baiyue/firstleg/service/CustomerDimensionWeightingService.java'
Assert-Path 'apps/admin-web/src/modules/container-loading/pages/GlobalSmartLoadingView.vue'
Assert-Path 'apps/client-web/src/modules/finance/views/FinanceBillsView.vue'
# 平台修改客户原始申报必须能从各层索引直达,并锁住 Order -> Firstleg 的版本化同步与渠道门禁。
$orderOpenApi = Read-RequiredText (Join-Path $backendRoot 'order/src/main/resources/openapi/order-v1.yaml')
$firstlegOpenApi = Read-RequiredText (Join-Path $backendRoot 'firstleg/src/main/resources/openapi/firstleg-v1.yaml')
$orderDeclarationService = Read-RequiredText (Join-Path $backendRoot 'order/src/main/java/com/baiyue/order/service/OrderDeclarationUpdateService.java')
$unifiedOrderQueryService = Read-RequiredText (Join-Path $backendRoot 'order/src/main/java/com/baiyue/order/service/UnifiedOrderQueryService.java')
$firstlegDeclarationService = Read-RequiredText (Join-Path $backendRoot 'firstleg/src/main/java/com/baiyue/firstleg/service/OrderDeclarationSyncService.java')
$adminDeclarationEditor = Read-RequiredText (Join-Path $workspaceRoot 'apps/admin-web/src/modules/unified-orders/components/OrderDeclarationEditorDialog.vue')
Assert-Contains $rootAgents '平台修改客户原始申报与履约渠道' '根订单申报快速路由'
Assert-Contains $adminAgents '客户原始申报资料编辑与渠道变更' 'Admin 订单申报快速路由'
Assert-Contains $backendAgents '平台修改客户原始申报、履约渠道变更与跨服务同步' '后端订单申报快速路由'
Assert-Contains $orderAgents '平台版本化修改客户原始申报' 'Order 申报编辑入口'
Assert-Contains $firstlegAgents 'Order 申报同步与渠道变更履约门禁' 'Firstleg 申报同步入口'
Assert-Contains $orderOpenApi '/api/platform/v1/orders/{orderId}/declaration:' 'Order 申报编辑 OpenAPI'
Assert-Contains $orderOpenApi '不覆盖实测、箱码或已确认费用' 'Order 申报与履约事实边界'
Assert-Contains $firstlegOpenApi '/internal/firstleg/v1/inbounds/order-declaration-updated:' 'Firstleg 申报同步 OpenAPI'
Assert-Contains $orderDeclarationService 'OrderStatus.DRAFT, OrderStatus.REJECTED, OrderStatus.SUBMITTED, OrderStatus.APPROVED' 'Order 申报可编辑状态'
Assert-Contains $orderDeclarationService 'ORDER_DECLARATION_UPDATED_V1' 'Order 申报版本事件'
Assert-Contains $firstlegDeclarationService 'mapper.byEvent(event.tenantId(), event.eventId())' 'Firstleg 申报 eventId 幂等'
Assert-Contains $firstlegDeclarationService 'event.version() < current.orderVersion()' 'Firstleg 申报版本单调性'
Assert-Contains $adminDeclarationEditor '仓库/PDA 实测数据不会被覆盖' 'Admin 申报事实边界提示'
Assert-Contains $rootAgents '统一列表仍固定显示 `PENDING_REVIEW` 并提供审核动作' '根待审核订单优先状态'
Assert-Contains $orderAgents '统一主状态/下一动作仍固定为 `PENDING_REVIEW/APPROVE_ORDER`' 'Order 待审核优先状态'
Assert-Contains $unifiedOrderQueryService 'order.getStatus() == OrderStatus.SUBMITTED' 'Order 待审核状态判断'
Assert-Contains $unifiedOrderQueryService 'pendingReview ? "PENDING_REVIEW" : summary.mainStatus()' 'Order 待审核主状态优先'
Assert-Contains $unifiedOrderQueryService 'pendingReview ? "APPROVE_ORDER" : summary.nextAction()' 'Order 待审核动作优先'
# 智能装柜已扩展到四态候选、Order 待审核补齐、提前占位与未拣整批移除;费用确认和会话恢复也必须可定向命中。
$pendingReviewOrderService = Read-RequiredText (Join-Path $backendRoot 'order/src/main/java/com/baiyue/order/service/PendingReviewOrderQueryService.java')
$merchantInboundBillingService = Read-RequiredText (Join-Path $backendRoot 'firstleg/src/main/java/com/baiyue/firstleg/service/MerchantInboundBillingService.java')
$clientSession = Read-RequiredText (Join-Path $workspaceRoot 'apps/client-web/src/api/session.ts')
$clientHttp = Read-RequiredText (Join-Path $workspaceRoot 'apps/client-web/src/api/http.ts')
Assert-Contains $rootAgents '`PENDING_REVIEW/WAIT_MEASURE/WAIT_SPLIT/LOADING`' '根智能装柜四态候选'
Assert-Contains $rootAgents '能否加入以服务端 `canAssign` 为准' '根智能装柜资格边界'
Assert-Contains $rootAgents '人工加入允许跨渠道,智能推荐仍按柜次渠道' '根智能装柜渠道边界'
Assert-Contains $backendAgents '/pending-review-assignments' '后端待审核装柜占位入口'
Assert-Contains $backendAgents '/unpicked-items' '后端未拣整批移除入口'
Assert-Contains $firstlegAgents '任一成员已拣则整组保留' 'Firstleg 同柜组整批移除边界'
Assert-Contains $orderAgents 'PendingReviewOrderQueryService.java' 'Order 待审核装柜候选入口'
Assert-Contains $adminAgents '按钮资格以服务端 `canAssign` 为准' 'Admin 智能装柜资格边界'
Assert-Contains $firstlegOpenApi '未传或空数组表示 PENDING_REVIEW、WAIT_MEASURE、WAIT_SPLIT、' '智能装柜四态 OpenAPI'
Assert-Contains $firstlegOpenApi '/api/platform/v1/first-leg/smart-loading/plans/{planId}/pending-review-assignments:' '待审核占位 OpenAPI'
Assert-Contains $firstlegOpenApi '/api/platform/v1/first-leg/smart-loading/plans/{planId}/unpicked-items:' '未拣整批移除 OpenAPI'
Assert-Contains $pendingReviewOrderService 'orders.pendingReviewPage' 'Order 待审核候选权威查询'
Assert-Contains $pendingReviewOrderService '"PENDING_REVIEW"' 'Order 待审核候选状态映射'
Assert-Contains $rootAgents '客户入库结果与头程费用确认' '根客户入库费用确认入口'
Assert-Contains $firstlegAgents 'expectedFeeVersion' 'Firstleg 客户费用版本确认'
Assert-Contains $clientAgents 'components/InboundBillingPanel.vue' 'Client 入库费用确认入口'
Assert-Contains $firstlegOpenApi '/api/merchant/v1/first-leg/orders/{orderId}/inbound-billing/confirm:' '客户费用确认 OpenAPI'
Assert-Contains $merchantInboundBillingService 'pricing.confirmByCustomer' 'Firstleg 客户费用确认服务'
Assert-Contains $clientAgents '“记住账号”只记登录标识' 'Client 记住账号边界'
Assert-Contains $clientSession 'localStorage.setItem(REFRESH_TOKEN_KEY, tokens.refreshToken)' 'Client 刷新令牌持久化'
Assert-Contains $clientHttp "'/auth/refresh'" 'Client 公开刷新入口'
Assert-Path 'baiyue-firstleg/order/src/main/java/com/baiyue/order/controller/InternalPendingReviewOrderController.java'
Assert-Path 'baiyue-firstleg/firstleg/src/main/java/com/baiyue/firstleg/controller/MerchantInboundBillingController.java'
Assert-Path 'apps/client-web/src/modules/first-leg/components/InboundBillingPanel.vue'
# 称重确认后的整票库位块和智能装柜暂估数量已成为跨端权威事实,索引必须直达并锁住回退顺序。
$measurementLocationOccupationService = Read-RequiredText (Join-Path $backendRoot 'firstleg/src/main/java/com/baiyue/firstleg/service/MeasurementLocationOccupationService.java')
$inboundMeasurementService = Read-RequiredText (Join-Path $backendRoot 'firstleg/src/main/java/com/baiyue/firstleg/service/InboundMeasurementService.java')
$measurementSubmissionService = Read-RequiredText (Join-Path $backendRoot 'firstleg/src/main/java/com/baiyue/firstleg/service/MeasurementSubmissionService.java')
$smartLoadingService = Read-RequiredText (Join-Path $backendRoot 'firstleg/src/main/java/com/baiyue/firstleg/service/SmartLoadingService.java')
$inboundSchema = Read-RequiredText (Join-Path $backendRoot 'firstleg/src/main/resources/db/phase2-inbound-schema.sql')
$adminWeightPanel = Read-RequiredText (Join-Path $workspaceRoot 'apps/admin-web/src/modules/inbounds/weight/components/WeightOcrPanel.vue')
$clientOrdersView = Read-RequiredText (Join-Path $workspaceRoot 'apps/client-web/src/modules/first-leg/views/FirstLegOrdersView.vue')
Assert-Contains $rootAgents '称重确认、整票库位块与部分拣货资源结算' '根称重库位块路由'
Assert-Contains $backendAgents '称重确认、整票库位块与 PDA 资源结算' '后端称重库位块路由'
Assert-Contains $firstlegAgents 'MeasurementLocationOccupationService.java' 'Firstleg 称重库位块入口'
Assert-Contains $firstlegAgents '最新测量批次的正数 `totalVolumeCbm/originalVolumeCbm` 取较大值' 'Firstleg 库位块测量批次体积选择'
Assert-Contains $firstlegAgents '再无有效值才查询 Order 最新客户申报体积' 'Firstleg 库位块体积回退顺序'
Assert-Contains $firstlegAgents '库位指引失败只记录警告,不阻断称重确认' 'Firstleg 称重库位非阻断语义'
Assert-Contains $firstlegAgents '`ensureForSubmission` 再次补齐和校验' 'Firstleg 提交库位补偿入口'
Assert-Contains $firstlegAgents '槽位与称重唯一键必须包含 `inbound_id`' 'Firstleg 部分拣货快照身份'
Assert-Contains $adminAgents '`locationCode/slotStatus/sharedOverflow`' 'Admin 权威称重库位状态'
Assert-Contains $measurementLocationOccupationService 'orderCargo.measurementDeclaration' 'Firstleg Order 申报体积回退'
Assert-Contains $measurementLocationOccupationService 'measuredVolume.max(declaredVolume)' 'Firstleg 测量批次体积取较大值'
Assert-Contains $measurementLocationOccupationService 'ensureForSubmission' 'Firstleg 提交库位补齐实现'
Assert-Contains $inboundMeasurementService 'ensureLocationWithoutBlocking' 'Firstleg 称重库位非阻断实现'
Assert-Contains $measurementSubmissionService 'locations.ensureForSubmission' 'Firstleg 提交库位补齐调用'
Assert-Contains $firstlegOpenApi '测量批次冻结的申报体积、Order 最新客户申报体积' '称重确认体积回退 OpenAPI'
Assert-Contains $inboundSchema 'UNIQUE KEY uk_pallet_allocation_slot (tenant_id, inbound_id, block_id, slot_no)' '部分拣货块槽快照唯一键'
Assert-Contains $inboundSchema 'UNIQUE KEY uk_pallet_allocation_weight (tenant_id, inbound_id, weight_result_id)' '部分拣货称重快照唯一键'
Assert-Contains $adminWeightPanel 'row.locationCode' 'Admin 称重卡片库位消费'
Assert-Contains $adminWeightPanel 'putawayStatusLabel(row.slotStatus)' 'Admin 称重卡片槽位状态'
Assert-NotContains $adminWeightPanel 'class="putaway-guide"' 'Admin 已移除整票预留引导区'
Assert-Contains $rootAgents '`totalPackageCount/remainingPackageCount`' '根智能装柜暂估数量'
Assert-Contains $firstlegAgents '`totalPackageCount/remainingPackageCount`' 'Firstleg 智能装柜暂估数量'
Assert-Contains $adminAgents '`totalPackageCount/remainingPackageCount`' 'Admin 智能装柜暂估数量'
Assert-Contains $firstlegOpenApi 'required: [id, packageCount, totalPackageCount, remainingPackageCount' '智能装柜计划数量 OpenAPI'
Assert-Contains $smartLoadingService 'repository.measuredPackageCount' '智能装柜已审核测量数量'
Assert-NotContains $firstlegAgents '| 客户费用查询 |' 'Firstleg 重复客户费用入口'
Assert-Contains $clientAgents '所有订单行均可进入计费重弹框' 'Client 独立计费重入口'
Assert-Contains $clientOrdersView 'dialog-only' 'Client 独立计费重弹框实现'
Assert-Path 'baiyue-firstleg/warehouse/src/main/java/com/baiyue/warehouse/service/LocationBlockService.java'
# 企业联系信息与账号登录标识已经解耦,资质审核不得重新把法人身份证设为必填。
$authAgents = Read-RequiredText (Join-Path $backendRoot 'auth/AGENTS.md')
$iamAgents = Read-RequiredText (Join-Path $backendRoot 'iam/AGENTS.md')
$iamOpenApi = Read-RequiredText (Join-Path $backendRoot 'iam/src/main/resources/openapi/iam-v1.yaml')
$authAccountService = Read-RequiredText (Join-Path $backendRoot 'auth/src/main/java/com/baiyue/auth/service/AccountManagementService.java')
$iamMemberService = Read-RequiredText (Join-Path $backendRoot 'iam/src/main/java/com/baiyue/iam/service/MemberService.java')
$adminCustomersView = Read-RequiredText (Join-Path $workspaceRoot 'apps/admin-web/src/modules/customers/pages/CustomersView.vue')
$clientCompanyProfile = Read-RequiredText (Join-Path $workspaceRoot 'apps/client-web/src/modules/tenant-management/views/CompanyProfileView.vue')
$clientMembersView = Read-RequiredText (Join-Path $workspaceRoot 'apps/client-web/src/modules/tenant-management/views/MembersView.vue')
Assert-Contains $rootAgents '公司联系电话/邮箱是企业资料,不作为成员登录标识' '根企业联系人边界'
Assert-Contains $adminAgents '公司联系电话只作企业联系信息,不修改管理员/成员登录手机号' 'Admin 企业联系人边界'
Assert-Contains $clientAgents '成员登录手机号可选,修改时同步 Auth、撤销该账号会话并审计' 'Client 成员登录手机号边界'
Assert-Contains $authAgents '登录标识与企业联系人解耦' 'Auth 登录标识入口'
Assert-Contains $iamAgents '公司联系电话/邮箱属于企业资料,不作为登录标识且不要求跨企业唯一' 'IAM 企业联系人边界'
Assert-Contains $iamAgents '审核必填资质仅营业执照与统一社会信用代码,法人身份证选填' 'IAM 必填资质边界'
Assert-Contains $iamOpenApi '公司联系电话,不作为登录标识且不要求跨企业唯一' 'IAM 公司联系电话 OpenAPI'
Assert-Contains $authAccountService 'tokenSessionStore.revokeAll(account.getId())' 'Auth 登录标识变更会话撤销'
Assert-Contains $iamMemberService 'authClient.revokeSessions' 'IAM 成员变更会话撤销'
Assert-Contains $adminCustomersView '不会修改企业管理员登录手机号' 'Admin 公司联系电话提示'
Assert-Contains $clientCompanyProfile '不会修改任何成员的登录手机号' 'Client 公司联系电话提示'
Assert-Contains $clientMembersView '用于该成员手机号登录;修改后会同步认证账号并退出该成员现有会话' 'Client 成员登录手机号提示'
$fileAgents = Read-RequiredText (Join-Path $backendRoot 'file/AGENTS.md')
$qualificationOpenApi = Read-RequiredText (Join-Path $backendRoot 'file/src/main/resources/openapi/qualification-required-package-v1.yaml')
Assert-Contains $rootAgents '法人身份证选填,可在已有营业执照后单独补传或替换' '根法人身份证单独上传语义'
Assert-Contains $fileAgents '法人身份证选填,客户可在已有营业执照后通过 `/api/merchant/v1/files/qualifications` 单独新增或替换' 'File 法人身份证单独上传入口'
Assert-Contains $qualificationOpenApi '/api/merchant/v1/files/qualifications:' '客户单文件资质 OpenAPI'
Assert-Contains $qualificationOpenApi 'LEGAL_PERSON_ID 可在已有营业执照后单独新增或替换' '客户法人身份证单独上传契约'
Assert-Contains $qualificationOpenApi 'BUSINESS_LICENSE 不允许走此入口' '营业执照整包上传边界'
Assert-Contains $clientCompanyProfile '法人身份证已保存,尚未提交审核' 'Client 法人身份证单独上传反馈'
Assert-NotContains $clientCompanyProfile '当前文件服务尚未开放法人身份证单独上传或替换' 'Client 已移除法人身份证旧阻断'
$truckOpenApi = Read-RequiredText (Join-Path $backendRoot 'firstleg/src/main/resources/openapi/truck-appointments-v1.yaml')
$terminalDrayageOpenApi = Read-RequiredText (Join-Path $backendRoot 'firstleg/src/main/resources/openapi/terminal-drayage-v1.yaml')
$terminalDrayageService = Read-RequiredText (Join-Path $backendRoot 'firstleg/src/main/java/com/baiyue/firstleg/terminaldrayage/service/TerminalDrayageService.java')
$lastlegOrderCommandService = Read-RequiredText (Join-Path $backendRoot 'lastleg-service/src/main/java/com/baiyue/lastleg/service/LastlegOrderCommandService.java')
$adminTerminalDrayages = Read-RequiredText (Join-Path $workspaceRoot 'apps/admin-web/src/modules/container-loading/api/terminalDrayages.ts')
$adminLastMileOrders = Read-RequiredText (Join-Path $workspaceRoot 'apps/admin-web/src/modules/overseas-warehouse/api/lastMileOrders.ts')
$loadingListsOpenApi = Read-RequiredText (Join-Path $backendRoot 'firstleg/src/main/resources/openapi/loading-lists-v1.yaml')
$pdaLoadingApi = Read-RequiredText (Join-Path $workspaceRoot 'apps/pda-uniapp/api/pda-loading.js')
$cabinetEvidenceService = Read-RequiredText (Join-Path $backendRoot 'firstleg/src/main/java/com/baiyue/firstleg/loading/service/CabinetLoadingEvidenceService.java')
Assert-Contains $rootAgents '拖车预约由 `RELEASED` 订舱拥有,不按客户、柜次、装柜计划或真实柜号归属' '根订舱级拖车语义'
Assert-Contains $rootAgents '证据以 `taskId + warehouseId` 进入任务专用 API' '根柜级证据入口'
Assert-Contains $adminAgents '订舱级拖车预约' 'Admin 拖车快速入口'
Assert-Contains $adminAgents '不选择或提交客户、柜次、装柜计划或真实集装箱号' 'Admin 拖车订舱级边界'
Assert-Contains $backendAgents '订舱级拖车' '后端拖车快速入口'
Assert-Contains $firstlegAgents '请求、实体、查询、响应和附件不得恢复 `customerId/customerName`' 'Firstleg 拖车无客户边界'
Assert-Contains $firstlegAgents '公开 DTO 也不得出现 `containerBookingId/loadingPlanId/cabinetNo/containerNo`' 'Firstleg 拖车无柜次边界'
Assert-Contains $firstlegAgents '每订舱通过查询锁与唯一约束最多一张非终态预约' 'Firstleg 拖车唯一有效预约'
Assert-Contains $fileAgents '`businessType=TRUCK_APPOINTMENT_ATTACHMENT`' 'File 拖车平台附件入口'
Assert-Contains $truckOpenApi 'required: [oceanBookingId, carrierId, plannedLoadingAt, expectedVersion]' '拖车订舱级请求字段'
Assert-NotContains $truckOpenApi 'customerId:' '拖车 OpenAPI 客户字段'
Assert-NotContains $truckOpenApi 'containerBookingId:' '拖车 OpenAPI 柜次字段'
Assert-NotContains $truckOpenApi 'loadingPlanId:' '拖车 OpenAPI 装柜计划字段'
Assert-Contains $truckOpenApi 'Each booking may have at most one non-terminal appointment' '拖车订舱级唯一性'
Assert-Contains $truckOpenApi 'PDA loading completion does not change a booking-level truck appointment' '拖车与 PDA 生命周期解耦'
Assert-Contains $truckOpenApi 'excluding bookings that already have a non-terminal truck appointment' '拖车创建候选过滤'
Assert-Contains $firstlegAgents '目的港码头拖车与还空预警' 'Firstleg 目的港码头拖车入口'
Assert-Contains $firstlegAgents '按卸柜完成时间加 72 小时' 'Firstleg 还空预警口径'
Assert-Contains $terminalDrayageOpenApi '/api/platform/v1/terminal-drayages/{containerBookingId}/fleet:' '码头拖车车队命令 OpenAPI'
Assert-Contains $terminalDrayageOpenApi '/api/platform/v1/terminal-drayages/{containerBookingId}/empty-return:' '码头拖车还柜命令 OpenAPI'
Assert-Contains $terminalDrayageService 'EMPTY_RETURN_WARNING_HOURS = 72' '码头拖车 72 小时预警实现'
Assert-Contains $terminalDrayageService 'context.unloadingCompletedAt().plusHours(EMPTY_RETURN_WARNING_HOURS)' '码头拖车权威截止时间实现'
Assert-Contains $adminTerminalDrayages 'allowedActions' 'Admin 码头拖车服务端动作消费'
Assert-Contains $lastlegOrderCommandService '必须提交完整8行人工时间快照' '尾程人工节点完整快照实现'
Assert-Contains $lastlegOrderCommandService '尾程订单已进入出库流程,不能新增暂扣' '尾程暂扣出库门禁实现'
Assert-Contains $adminLastMileOrders '/platform/v1/last-leg/orders/${encodeURIComponent(orderId)}/hold' 'Admin 尾程暂扣入口'
Assert-Contains $adminLastMileOrders '/platform/v1/last-leg/orders/${encodeURIComponent(orderId)}/manual-nodes' 'Admin 尾程人工节点入口'
Assert-Contains $adminAgents '入仓码只读展示并提交订单冻结值' 'Admin 尾程计划冻结入仓码边界'
Assert-Contains $lastlegAgents '接柜仓编码/名称以该 ID 当前目录快照为准' 'Lastleg 稳定接柜仓身份边界'
Assert-Contains $lastlegOrderCommandService '同一幂等键不能用于不同请求' '尾程命令请求哈希重放边界'
Assert-Contains $loadingListsOpenApi '真实集装箱号可在PDA确认装柜完成前补录' '预装真实柜号晚录门禁'
Assert-Contains $loadingListsOpenApi '可在 EDITING 或 LOADING 阶段首次补录真实集装箱号' '预装真实柜号首次补录阶段'
Assert-Contains $adminAgents '创建柜次时自动生成唯一预装计划' 'Admin 自动预装计划流程'
Assert-Contains $loadingListsOpenApi '不依赖真实集装箱号,task 已创建后仍为 true' 'PDA task 不依赖真实柜号'
Assert-Contains $adminAgents 'PDA 最终完成前必须补齐' 'Admin 真实柜号最终门禁'
Assert-Contains $pdaAgents '当前 `taskId + warehouseId` 走任务专用 API' '国内 PDA 柜级证据入口'
Assert-Contains $pdaLoadingApi '/first-leg/pda-loading/tasks/${encodeURIComponent(taskId)}/evidence?warehouseId=' '国内 PDA 证据查询 API'
Assert-NotContains $pdaLoadingApi '/inbounds/${encodeURIComponent(inboundId)}/loading/evidence' '国内 PDA 旧入仓证据 API'
Assert-Contains $rootAgents '上传以幂等键绑定包含文件内容的请求哈希' '根装柜证据上传重放边界'
Assert-Contains $firstlegAgents '完全重放返回当前视图且不得再次上传 File' 'Firstleg 装柜证据重放边界'
Assert-Contains $cabinetEvidenceService 'uploadHash(warehouseId, expectedVersion, evidenceType, sealNo, remark, multipart)' '装柜证据上传请求哈希'
Assert-Contains $cabinetEvidenceService 'digest.update(multipart.getBytes())' '装柜证据文件内容哈希'
Assert-Matches $cabinetEvidenceService '(?s)mapper\.byOperation\(taskId, key\).{0,500}?return view\(scope\);.{0,500}?files\.upload' '装柜证据上传先查重放再调用 File'
$mapperModuleAgents = @(
@{ Module = 'audit-service'; Application = 'BaiyueAuditApplication.java' },
@{ Module = 'auth'; Application = 'BaiyueAuthApplication.java' },
@{ Module = 'event-bridge-service'; Application = 'EventBridgeApplication.java' },
@{ Module = 'file'; Application = 'FileServiceApplication.java' },
@{ Module = 'firstleg'; Application = 'BaiyueFirstlegApplication.java' },
@{ Module = 'iam'; Application = 'BaiyueIamApplication.java' },
@{ Module = 'lastleg-service'; Application = 'BaiyueLastlegApplication.java' },
@{ Module = 'order'; Application = 'BaiyueOrderApplication.java' },
@{ Module = 'warehouse'; Application = 'BaiyueWarehouseApplication.java' },
@{ Module = 'warehouse-overseas-service'; Application = 'BaiyueWarehouseOverseasApplication.java' }
)
foreach ($entry in $mapperModuleAgents) {
$moduleAgents = Read-RequiredText (Join-Path $backendRoot "$($entry.Module)/AGENTS.md")
Assert-Contains $moduleAgents $entry.Application "$($entry.Module) Mapper 启动入口"
Assert-Contains $moduleAgents 'scripts/mapper-scan-contract.mjs' "$($entry.Module) Mapper 静态门禁"
}
# 部署单元必须能从根索引进入。
Get-ChildItem -LiteralPath (Join-Path $workspaceRoot 'apps') -Directory |
Sort-Object Name |
ForEach-Object { Assert-Contains $rootAgents "apps/$($_.Name)/" '根 AGENTS.md' }
Assert-Contains $rootAgents 'baiyue-firstleg/' '根 AGENTS.md'
Assert-MarkdownTableUnique $rootAgentsPath '## 项目快速入口' 0 '根项目表'
Assert-MarkdownTableUnique $rootAgentsPath '## 项目快速入口' 1 '根项目目录'
Assert-MarkdownTableUnique $rootAgentsPath '## 业务快速路由表' 0 '根业务路由表'
Assert-MarkdownTableUnique $rootAgentsPath '## 原型入口索引' 0 '根原型表'
# 前端当前全部业务模块必须能从应用级索引命中。
$applications = @(
@{ Root = 'apps/admin-web/src/modules'; Text = $adminAgents; Scope = 'Admin AGENTS.md' },
@{ Root = 'apps/client-web/src/modules'; Text = $clientAgents; Scope = 'Client AGENTS.md' }
)
foreach ($application in $applications) {
foreach ($moduleDirectory in (Get-ChildItem -LiteralPath (Join-Path $workspaceRoot $application.Root) -Directory | Sort-Object Name)) {
Assert-Contains $application.Text "modules/$($moduleDirectory.Name)/" $application.Scope
}
}
# 国内/海外 PDA 只检查 pages.json 正式注册页面,不把空目录或未注册原型纳入索引。
$pdaApplications = @(
@{ Pages = 'apps/pda-uniapp/pages.json'; Text = $pdaAgents; Scope = 'PDA AGENTS.md'; Prefix = '' },
@{ Pages = 'apps/pda-overseas-uniapp/src/pages.json'; Text = $overseasPdaAgents; Scope = 'Overseas PDA AGENTS.md'; Prefix = 'src/' }
)
foreach ($pdaApplication in $pdaApplications) {
$pagesJsonPath = Join-Path $workspaceRoot $pdaApplication.Pages
$pagesJson = Get-Content -LiteralPath $pagesJsonPath -Raw | ConvertFrom-Json
$registeredPageRoots = $pagesJson.pages.path |
ForEach-Object { $parts = $_ -split '/'; "$($pdaApplication.Prefix)$($parts[0])/$($parts[1])/" } |
Sort-Object -Unique
foreach ($pageRoot in $registeredPageRoots) {
Assert-Contains $pdaApplication.Text $pageRoot $pdaApplication.Scope
}
}
# 海外 PDA 已开放拆柜收货、库内、换标和现场查询真实作业。
$overseasWorkbenchPath = Join-Path $workspaceRoot 'apps/pda-overseas-uniapp/src/data/overseas-workbench.js'
$overseasWorkbench = Read-RequiredText $overseasWorkbenchPath
Assert-Matches $overseasWorkbench "(?s)name:\s*'拆柜收货'.{0,300}?available:\s*true" 'Overseas PDA 拆柜收货开关'
Assert-Matches $overseasWorkbench "(?s)name:\s*'托盘管理'.{0,300}?available:\s*true.{0,200}?route:\s*'/pages/pallet/pallet'" 'Overseas PDA 托盘管理开关'
foreach ($enabledOperation in @(
@{ Name = '库存盘点'; Route = '/pages/stocktake/stocktake' },
@{ Name = '商品移库'; Route = '/pages/move/move' },
@{ Name = '换标收货'; Route = '/pages/relabel/relabel\?op=relabelReceive' },
@{ Name = '换标执行'; Route = '/pages/relabel/relabel\?op=relabelExecute' },
@{ Name = '换标复核'; Route = '/pages/relabel/relabel\?op=relabelReview' },
@{ Name = '库存查询'; Route = '/pages/query/query\?op=inventoryQuery' },
@{ Name = '库位查询'; Route = '/pages/query/query\?op=locationQuery' },
@{ Name = '托盘查询'; Route = '/pages/query/query\?op=palletQuery' }
)) {
$enabledPattern = "(?s)name:\s*'$([regex]::Escape($enabledOperation.Name))'.{0,300}?available:\s*true.{0,200}?route:\s*'$($enabledOperation.Route)'"
Assert-Matches $overseasWorkbench $enabledPattern "Overseas PDA 开放入口 $($enabledOperation.Name)"
}
# 文档声明为正式开放的 Client 海外仓页面必须仍是 active 路由。
$clientOverseasRoutesPath = Join-Path $workspaceRoot 'apps/client-web/src/modules/overseas-warehouse/routes.ts'
$clientOverseasRoutes = Read-RequiredText $clientOverseasRoutesPath
foreach ($route in @(
'overseas-warehouse/labeling',
'overseas-warehouse/storage-transfer',
'overseas-warehouse/cargo-disposal',
'overseas-warehouse/return-relabel'
)) {
$routePattern = "(?s)path:\s*'$([regex]::Escape($route))'.{0,500}?release:\s*'active'"
Assert-Matches $clientOverseasRoutes $routePattern "Client 正式路由 $route"
}
# 根索引中的海外浏览器 API 必须被海外 Gateway 显式覆盖。
$overseasGatewayConfigPath = Join-Path $backendRoot 'gateway-overseas/src/main/resources/application-overseas.yml'
$overseasGatewayConfig = Read-RequiredText $overseasGatewayConfigPath
foreach ($gatewayPath in @(
'/api/merchant/v1/last-leg/**',
'/api/platform/v1/last-leg/**',
'/api/pda/v1/last-leg/**',
'/api/merchant/v1/warehouses/**',
'/api/platform/v1/warehouse-admin/**'
)) {
Assert-Contains $overseasGatewayConfig $gatewayPath 'Overseas Gateway 路由'
}
Assert-Contains $overseasGatewayConfig 'uri: lb://lastleg-service' 'Overseas Gateway Lastleg 路由'
Assert-Contains $overseasGatewayConfig 'uri: lb://warehouse-overseas-service' 'Overseas Gateway Warehouse 路由'
# 海外安全投影已并入 Lastleg,Gateway 校验和 Event Bridge 消费均指向同一海外服务。
$serviceMap = Read-RequiredText (Join-Path $backendRoot 'deploy/service-map.yml')
$overseasCompose = Read-RequiredText (Join-Path $backendRoot 'deploy/docker-compose.overseas.yml')
$serviceJenkinsfile = Read-RequiredText (Join-Path $backendRoot 'Jenkinsfile.service')
Assert-Contains $serviceMap 'lastleg-service:' 'Lastleg 服务部署映射'
Assert-Contains $overseasCompose '/internal/lastleg/security/v1/events' 'Lastleg 安全事件消费地址'
Assert-Contains $overseasCompose 'LASTLEG_SECURITY_SERVICE_URL' 'Lastleg 安全校验地址'
Assert-NotContains $serviceJenkinsfile "'overseas-security-service'" '独立海外安全服务构建入口'
# 高变化语义必须在最近指引与服务契约中保持一致。
Assert-Contains $adminAgents '海外模块内部快速索引(海外仓全流程)' 'Admin 海外仓全流程范围'
Assert-Contains $pdaAgents 'VITE_H5_API_BASE_URL' '国内 PDA H5 运行配置'
Assert-Contains $overseasPdaAgents 'tests/app-icons.test.mjs' '海外 PDA 图标合同'
Assert-Contains $backendAgents 'RestClientTraceInterceptor.java' '后端同步 Trace 入口'
$oceanBookingOpenApi = Read-RequiredText (Join-Path $backendRoot 'firstleg/src/main/resources/openapi/ocean-bookings-v1.yaml')
Assert-Contains $oceanBookingOpenApi 'never represents linked or ACTIVE containers' '订舱柜量语义'
Assert-Contains $oceanBookingOpenApi '/api/platform/v1/ocean-bookings/link-candidates:' '订舱关联候选契约'
Assert-Contains $oceanBookingOpenApi 'exact warehouseId, channelCode and containerType' '订舱关联候选筛选语义'
$adminOceanBookingApi = Read-RequiredText (Join-Path $workspaceRoot 'apps/admin-web/src/modules/ocean-bookings/api/platformOceanBookings.ts')
$adminOceanBookingView = Read-RequiredText (Join-Path $workspaceRoot 'apps/admin-web/src/modules/ocean-bookings/pages/OceanBookingsView.vue')
$adminOceanBookingViewTest = Read-RequiredText (Join-Path $workspaceRoot 'apps/admin-web/src/modules/ocean-bookings/pages/OceanBookingsView.test.ts')
Assert-Contains $adminOceanBookingApi '/link-candidates' 'Admin 订舱关联候选调用'
Assert-Contains $adminOceanBookingView "label: '订舱柜量'" 'Admin 订舱柜量文案'
Assert-Contains $adminOceanBookingViewTest 'without detail N+1' 'Admin 订舱列表无详情扇出合同'
# 海外出库、派送、异常和回访必须从根路由贯通到 Admin 与 Lastleg;PDA 后端存在不等于设备端已挂载。
$adminOverseasRoutes = Read-RequiredText (Join-Path $workspaceRoot 'apps/admin-web/src/modules/overseas-warehouse/routes.ts')
$lastlegAgents = Read-RequiredText (Join-Path $backendRoot 'lastleg-service/AGENTS.md')
foreach ($overseasFulfillmentRoute in @(
'overseas-warehouse/outbounds',
'overseas-warehouse/delivery-orders',
'overseas-warehouse/exception-orders',
'overseas-warehouse/customer-visits'
)) {
Assert-Contains $adminOverseasRoutes "path: '$overseasFulfillmentRoute'" "Admin 海外履约正式路由 $overseasFulfillmentRoute"
}
foreach ($overseasFulfillmentRootEntry in @(
'OutboundsView.vue', 'DeliveryOrdersView.vue', 'ExceptionOrdersView.vue', 'CustomerVisitsView.vue'
)) {
Assert-Contains $rootAgents $overseasFulfillmentRootEntry '根海外履约正式业务路由'
}
Assert-Contains $adminAgents '海外排车、出库与派送' 'Admin 海外出库派送入口'
Assert-Contains $adminAgents '海外异常退回与客户回访' 'Admin 海外异常回访入口'
Assert-Contains $backendAgents '海外排车执行、PDA 出库、派送与一件代发' '后端海外出库派送入口'
Assert-Contains $backendAgents '一件代发 SKU/箱唛与暂扣跨区协同' '后端一件代发跨区协同入口'
Assert-Contains $lastlegAgents '海外仓全流程连续覆盖' 'Lastleg 海外仓全流程范围'
Assert-Contains $overseasPdaAgents '排车拣货与发车' '海外 PDA 排车入口'
Assert-Contains $overseasPdaAgents '普通/一件代发出库' '海外 PDA 出库入口'
# Admin 仅对静态资源过期做一次受控恢复,不能吞掉普通路由错误或覆盖未保存编辑。
$navigationRecovery = Read-RequiredText (Join-Path $workspaceRoot 'apps/admin-web/src/core/routing/navigationRecovery.ts')
Assert-Contains $navigationRecovery 'const RECOVERY_WINDOW_MS = 30_000' 'Admin 路由恢复窗口'
Assert-Contains $navigationRecovery 'if (dependencies.hasUnsavedWork() && !await dependencies.confirmDiscard()) return true' 'Admin 未保存编辑保护'
Assert-Contains $navigationRecovery 'if (!isStaleRouteAssetError(error))' 'Admin 普通路由错误边界'
# 国内 PDA 的 H5 地址必须来自当前构建和同源代理,不能被历史登录缓存覆盖。
$domesticPdaRuntime = Read-RequiredText (Join-Path $workspaceRoot 'apps/pda-uniapp/config/runtime.js')
$domesticPdaVite = Read-RequiredText (Join-Path $workspaceRoot 'apps/pda-uniapp/vite.config.js')
$domesticPdaSession = Read-RequiredText (Join-Path $workspaceRoot 'apps/pda-uniapp/stores/session.js')
Assert-Contains $domesticPdaRuntime "VITE_H5_API_BASE_URL || '/gateway-api'" '国内 PDA H5 同源 API'
Assert-Contains $domesticPdaVite "'/gateway-api'" '国内 PDA H5 独立代理前缀'
Assert-Contains $domesticPdaVite 'path.replace(/^\/gateway-api/, ''/api'')' '国内 PDA H5 Gateway 重写'
Assert-Contains $domesticPdaVite 'API_PROXY_TARGET' '国内 PDA H5 代理上游'
Assert-Contains $domesticPdaSession 'session.apiBase = PLATFORM_API_ROOT' '国内 PDA 当前构建 API'
Assert-NotContains $domesticPdaSession 'apiBase: session.apiBase' '国内 PDA 会话持久化'
# 国内和海外 PDA 使用相同协议但完全独立的 APK/WGT 更新通道。
$domesticPdaUpdater = Read-RequiredText (Join-Path $workspaceRoot 'apps/pda-uniapp/utils/app-update.js')
$domesticPdaApp = Read-RequiredText (Join-Path $workspaceRoot 'apps/pda-uniapp/App.vue')
$overseasPdaUpdater = Read-RequiredText (Join-Path $workspaceRoot 'apps/pda-overseas-uniapp/src/utils/app-update.js')
$overseasPdaApp = Read-RequiredText (Join-Path $workspaceRoot 'apps/pda-overseas-uniapp/src/App.vue')
foreach ($pdaUpdate in @(
@{ Source = $domesticPdaUpdater; Scope = '国内 PDA 在线更新' },
@{ Source = $overseasPdaUpdater; Scope = '海外 PDA 在线更新' }
)) {
Assert-Contains $pdaUpdate.Source 'VITE_PDA_UPDATE_URL' $pdaUpdate.Scope
Assert-Contains $pdaUpdate.Source "['apk', 'wgt'].includes(packageType)" $pdaUpdate.Scope
Assert-Contains $pdaUpdate.Source '更新包必须使用 HTTPS 地址' $pdaUpdate.Scope
Assert-Contains $pdaUpdate.Source 'plus.runtime.install' $pdaUpdate.Scope
}
Assert-Contains $domesticPdaApp '#ifdef APP-PLUS' '国内 PDA App 更新平台边界'
Assert-Contains $overseasPdaApp '#ifdef APP-PLUS' '海外 PDA App 更新平台边界'
Assert-Contains $pdaAgents '不得复用海外 PDA' '国内 PDA 独立更新通道'
Assert-Contains $overseasPdaAgents '不得与国内 PDA 混用' '海外 PDA 独立更新通道'
# 人工分柜到 LOADED 只允许使用已登记的可选 fixture/verify 链,不进入默认全量。
$adminAcceptanceEntry = Read-RequiredText (Join-Path $backendRoot 'scripts/admin-test-env-acceptance.mjs')
$adminAcceptanceModuleIndex = Read-RequiredText (Join-Path $backendRoot 'scripts/admin-test-env-modules/README.md')
$scriptsIndex = Read-RequiredText (Join-Path $backendRoot 'scripts/README.md')
Assert-Contains $adminAcceptanceEntry "const OPTIONAL_MODULES = ['manual-order-splitting-fixture'" '人工验收可选模块注册'
Assert-Contains $adminAcceptanceModuleIndex '人工分柜通过后可继续执行 `manual-preload-push-fixture.mjs`' '人工分柜到预装链路'
Assert-Contains $adminAcceptanceModuleIndex 'PDA 待复核通过后,`manual-loading-complete-fixture.mjs`' '人工 PDA 到 LOADED 链路'
Assert-Contains $scriptsIndex 'manual-*-fixture/verify' '人工分段验收根索引'
# 同步 RestClient Trace 必须注册为公共自动配置,不能只有孤立拦截器源码。
$commonWebAutoConfigurations = Read-RequiredText (Join-Path $backendRoot 'common-web/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports')
Assert-Contains $commonWebAutoConfigurations 'com.baiyue.common.web.RestClientTracePropagationAutoConfiguration' 'RestClient Trace 自动配置注册'
# 全部仓库主档统一归国内 Warehouse;海外服务只保存 warehouseId 引用和物理资源。
$warehouseAgents = Read-RequiredText (Join-Path $backendRoot 'warehouse/AGENTS.md')
$overseasWarehouseAgents = Read-RequiredText (Join-Path $backendRoot 'warehouse-overseas-service/AGENTS.md')
$domesticWarehouseService = Read-RequiredText (Join-Path $backendRoot 'warehouse/src/main/java/com/baiyue/warehouse/service/WarehouseApplicationService.java')
$domesticWarehouseController = Read-RequiredText (Join-Path $backendRoot 'warehouse/src/main/java/com/baiyue/warehouse/controller/InternalWarehouseController.java')
$overseasWarehouseSql = Read-RequiredText (Join-Path $backendRoot 'warehouse-overseas-service/src/main/resources/db/warehouse.sql')
$adminIamApi = Read-RequiredText (Join-Path $workspaceRoot 'apps/admin-web/src/modules/iam/api/platformIam.ts')
Assert-Contains $backendAgents '全部仓库 ID、类型、状态、地址和能力主档归国内 `warehouse`' '后端仓库主档权威'
Assert-Contains $warehouseAgents '/internal/warehouses/shared-overseas' '国内 Warehouse 共享海外目录'
Assert-Contains $warehouseAgents '/internal/warehouses/0/{warehouseId}/active' '国内 Warehouse FBA 内部校验入口'
Assert-Contains $overseasWarehouseAgents '只保存国内仓库 ID 引用' '海外 Warehouse 引用边界'
Assert-Contains $domesticWarehouseController '@GetMapping("/shared-overseas")' '共享海外仓列表入口'
Assert-Contains $domesticWarehouseService 'hasReceivingCapability' '共享海外收货能力筛选'
Assert-Contains $adminIamApi "capabilityCode: 'RECEIVING'" 'Admin 海外收货仓候选'
Assert-NotContains $overseasWarehouseSql 'CREATE TABLE IF NOT EXISTS wh_warehouse' '海外仓库主档表'
Assert-NotContains $overseasWarehouseSql 'CREATE TABLE IF NOT EXISTS wh_warehouse_address' '海外仓库地址表'
# 国内出仓按真实货柜原子确认,船节点实际进度只允许严格向后推进。
$outboundDispatchOpenApi = Read-RequiredText (Join-Path $backendRoot 'firstleg/src/main/resources/openapi/phase3-outbound-dispatch-v1.yaml')
$carrierScheduleOpenApi = Read-RequiredText (Join-Path $backendRoot 'firstleg/src/main/resources/openapi/carrier-schedule-query-v1.yaml')
$adminContainerDetail = Read-RequiredText (Join-Path $workspaceRoot 'apps/admin-web/src/modules/container-loading/pages/ContainerDetailView.vue')
Assert-Contains $outboundDispatchOpenApi 'No partial success is possible.' '整柜出仓原子性'
Assert-Contains $outboundDispatchOpenApi 'truckAppointmentStatus: {type: string, nullable: true, description: Reference-only status' '拖车状态非门禁语义'
Assert-Contains $carrierScheduleOpenApi 'strictly greater standard-node sequence than latestActualNode' '手工实际节点单调推进'
Assert-Contains $carrierScheduleOpenApi 'estimated facts never advance actual progress' '预计节点不推进实际进度'
Assert-Contains $adminContainerDetail 'confirmDeparture' 'Admin 货柜详情确认离仓'
# 装柜完成后的整柜报关必须保持客户退税资料、平台冻结/完成与 File 二进制边界一致。
$firstlegAgents = Read-RequiredText (Join-Path $backendRoot 'firstleg/AGENTS.md')
$containerCustomsOpenApi = Read-RequiredText (Join-Path $backendRoot 'firstleg/src/main/resources/openapi/customs-v1.yaml')
$adminContainerCustomsApi = Read-RequiredText (Join-Path $workspaceRoot 'apps/admin-web/src/modules/container-loading/api/platformContainerCustoms.ts')
$clientContainerCustomsApi = Read-RequiredText (Join-Path $workspaceRoot 'apps/client-web/src/modules/first-leg/api/customs.ts')
$customsFileOpenApi = Read-RequiredText (Join-Path $backendRoot 'file/src/main/resources/openapi/customs-file-and-export-v1.yaml')
Assert-Contains $rootAgents 'ContainerCustomsPanel.vue' '根整柜报关 Admin 入口'
Assert-Contains $rootAgents 'CustomsDocumentsDialog.vue' '根整柜报关 Client 入口'
Assert-Contains $adminAgents 'components/ContainerCustomsPanel.vue' 'Admin 整柜报关入口'
Assert-Contains $adminAgents 'complete-all-buy' 'Admin 全买单柜入口'
Assert-Contains $clientAgents 'components/CustomsDocumentsDialog.vue' 'Client 退税报关资料入口'
Assert-Contains $clientAgents '开始后只读冻结资料' 'Client 报关冻结边界'
Assert-Contains $firstlegAgents 'customs/container/controller/PlatformContainerCustomsController.java' 'Firstleg 平台整柜报关入口'
Assert-Contains $firstlegAgents 'customs/container/controller/MerchantContainerCustomsController.java' 'Firstleg 客户整柜报关入口'
Assert-Contains $containerCustomsOpenApi '/api/merchant/v1/customs/loading-plans/{planId}/documents/upload:' '客户退税资料上传契约'
Assert-Contains $containerCustomsOpenApi '/api/merchant/v1/customs/documents/{documentId}/inbounds:' '客户资料入仓码范围契约'
Assert-Contains $containerCustomsOpenApi '/api/platform/v1/customs/loading-plans/{planId}/start:' '平台开始报关冻结契约'
Assert-Contains $containerCustomsOpenApi '/api/platform/v1/customs/loading-plans/documents/{documentId}/completion/upload:' '平台完成文件契约'
Assert-Contains $containerCustomsOpenApi '/api/platform/v1/customs/loading-plans/{planId}/complete-all-buy:' '全买单柜完成契约'
Assert-Contains $containerCustomsOpenApi 'enum: [TAX_REFUND, BUY_DECLARATION]' '整柜报关税务模式'
Assert-Contains $adminContainerCustomsApi "const basePath = '/platform/v1/customs/loading-plans'" 'Admin 整柜报关真实调用'
Assert-Contains $clientContainerCustomsApi '/merchant/v1/customs/orders/' 'Client 订单报关真实调用'
Assert-Contains $clientContainerCustomsApi 'Idempotency-Key' 'Client 报关写入幂等'
Assert-Contains $customsFileOpenApi 'LOADING_LIST_CUSTOMS_SOURCE' 'File 报关源文件类别'
Assert-Contains $customsFileOpenApi 'LOADING_LIST_CUSTOMS_RESULT' 'File 报关完成文件类别'
# 平台商品图片和海外 PDA 签收照片都必须走鉴权下载,不暴露内部存储路径。
$productImageController = Read-RequiredText (Join-Path $backendRoot 'file/src/main/java/com/baiyue/file/controller/PlatformProductImageController.java')
$receivingController = Read-RequiredText (Join-Path $backendRoot 'lastleg-service/src/main/java/com/baiyue/lastleg/inboundplan/pda/controller/ReceivingContainerController.java')
Assert-Contains $productImageController '/api/platform/v1/files/product-images' '平台商品图片入口'
Assert-Contains $productImageController "hasAuthority('platform:order:list')" '平台商品图片权限'
Assert-Contains $receivingController '/current/unload-photos/files/{fileId}/download' '海外 PDA 签收照片预览'
Assert-Contains $receivingController 'CacheControl.noStore()' '海外 PDA 签收照片缓存边界'
# 尾程订单按来源柜展示服务端计划进度,整柜转换每票独立计划且整批原子。
$lastlegBusinessOpenApi = Read-RequiredText (Join-Path $backendRoot 'lastleg-service/src/main/resources/openapi/overseas-business-v1.yaml')
$lastlegAgents = Read-RequiredText (Join-Path $backendRoot 'lastleg-service/AGENTS.md')
$adminLastMileApi = Read-RequiredText (Join-Path $workspaceRoot 'apps/admin-web/src/modules/overseas-warehouse/api/lastMileOrders.ts')
Assert-Contains $lastlegBusinessOpenApi '/api/platform/v1/last-leg/orders/container-summaries:' 'Lastleg 柜级摘要契约'
Assert-Contains $lastlegBusinessOpenApi '/api/platform/v1/last-leg/inbound-plans/convert-container:' 'Lastleg 整柜计划转换契约'
Assert-Contains $lastlegBusinessOpenApi 'sourceContainerBookingId' 'Lastleg 稳定来源柜身份'
Assert-Contains $adminAgents '/orders/container-summaries' 'Admin 柜级摘要目标入口'
Assert-Contains $rootAgents '尾程订单控制与柜级入仓计划转换' '根柜级计划入口'
Assert-Contains $backendAgents '分页前排除全部入仓码均已生成有效独立计划的柜' '后端柜级计划待处理筛选'
Assert-Contains $adminAgents '返回仍有待生成计划入仓码的柜' 'Admin 柜级计划待处理筛选'
Assert-Contains $lastlegAgents '分页前排除全部入仓码均已生成有效独立计划的柜' 'Lastleg 柜级计划待处理筛选'
Assert-Contains $lastlegBusinessOpenApi '仅返回仍有入仓码待生成有效独立计划的柜' 'Lastleg 柜级计划待处理 OpenAPI'
Assert-Contains $adminAgents 'ACTIVE + FBA' 'Admin FBA 权威仓候选'
Assert-Contains $adminAgents '/inbound-plans/convert-container' 'Admin 整柜转换目标入口'
Assert-Contains $adminLastMileApi '/orders/container-summaries' 'Admin 柜级摘要真实调用'
Assert-NotContains $adminLastMileApi '/orders/pending-containers' 'Admin 旧柜级摘要调用'
Assert-Contains $lastlegBusinessOpenApi 'ContainerPlanProgressSummary' 'Lastleg 柜级计划进度摘要模型'
Assert-Contains $lastlegBusinessOpenApi 'ContainerPlanProgressDetail' 'Lastleg 柜级计划进度详情模型'
Assert-Contains $lastlegBusinessOpenApi 'allPlansReady' 'Lastleg 全柜计划就绪事实'
Assert-Contains $lastlegBusinessOpenApi 'plannedArrivalAt' 'Lastleg 计划到仓冻结事实'
Assert-Contains $lastlegAgents 'service/FbaWarehouseValidator.java' 'Lastleg FBA 权威仓校验入口'
# 国内 PDA 当前以页面、API 和作业状态合同覆盖部分拣货及库位不足反馈。
Assert-Contains $pdaAgents 'tests/page-contract.test.mjs' '国内 PDA 页面合同'
Assert-Contains $pdaAgents 'tests/pda-loading-api.test.mjs' '国内 PDA API 合同'
# 国内柜费分摊与海外费用跨区入池必须能从根索引直达,并锁住归属、金额、版本与直接已付隔离。
$financeAgents = Read-RequiredText (Join-Path $backendRoot 'finance/AGENTS.md')
$eventBridgeAgents = Read-RequiredText (Join-Path $backendRoot 'event-bridge-service/AGENTS.md')
$commonEventAgents = Read-RequiredText (Join-Path $backendRoot 'common-event-contract/AGENTS.md')
$adminFinanceAgents = Read-RequiredText (Join-Path $workspaceRoot 'apps/admin-web/src/modules/finance/AGENTS.md')
$containerFeeOpenApi = Read-RequiredText (Join-Path $backendRoot 'firstleg/src/main/resources/openapi/container-fees-v1.yaml')
$containerFeeController = Read-RequiredText (Join-Path $backendRoot 'firstleg/src/main/java/com/baiyue/firstleg/controller/PlatformContainerFeeDetailController.java')
$containerFeeService = Read-RequiredText (Join-Path $backendRoot 'firstleg/src/main/java/com/baiyue/firstleg/service/ContainerFeeDetailService.java')
$overseasFinanceOpenApi = Read-RequiredText (Join-Path $backendRoot 'lastleg-service/src/main/resources/openapi/overseas-finance-fees-v1.yaml')
$businessFeeEvent = Read-RequiredText (Join-Path $backendRoot 'common-event-contract/src/main/java/com/baiyue/common/event/BusinessFeeSourceChangedV1.java')
$eventTypes = Read-RequiredText (Join-Path $backendRoot 'common-event-contract/src/main/java/com/baiyue/common/event/EventTypes.java')
$overseasDispatcher = Read-RequiredText (Join-Path $backendRoot 'event-bridge-service/src/main/java/com/baiyue/eventbridge/service/OverseasEventDispatcher.java')
$financeEventConsumer = Read-RequiredText (Join-Path $backendRoot 'finance/src/main/java/com/baiyue/finance/service/BusinessFeeSourceEventService.java')
$financePhase1Service = Read-RequiredText (Join-Path $backendRoot 'finance/src/main/java/com/baiyue/finance/service/FinancePhase1OperationService.java')
Assert-Contains $rootAgents '财务管理与柜级公共费用分摊' '根柜费分摊快速路由'
Assert-Contains $rootAgents '海外业务费用来源与客户财务' '根海外费用快速路由'
Assert-Contains $adminAgents '财务、客户资金账户与柜级公共费用分摊' 'Admin 柜费分摊快速路由'
Assert-Contains $backendAgents '柜级公共费用跨客户分摊' '后端柜费分摊快速路由'
Assert-Contains $backendAgents '海外业务费用来源跨区入池' '后端海外费用快速路由'
Assert-Contains $firstlegAgents '单行入口拒绝分摊组' 'Firstleg 分摊组原子边界'
Assert-Contains $adminFinanceAgents '`allocationGroupId` 整组审核、驳回、调整或作废' 'Admin 分摊组操作边界'
Assert-Contains $containerFeeOpenApi '/fee-details/allocation-groups:' '柜费分摊组创建 OpenAPI'
Assert-Contains $containerFeeOpenApi '各分摊金额必须大于0且合计等于费用总额' '柜费分摊金额守恒'
Assert-Contains $containerFeeOpenApi '单行接口拒绝处理分摊组' '柜费分摊整组操作契约'
Assert-Contains $containerFeeController '@PostMapping("/allocation-groups/{groupId}/approve")' '柜费分摊整组审核入口'
Assert-Contains $containerFeeController '@PostMapping("/allocation-groups/{groupId}/adjust")' '柜费分摊整组调整入口'
Assert-Contains $containerFeeService '分摊客户、订单及入仓信息与柜内真实归属不一致' '柜费分摊真实归属校验'
Assert-Contains $containerFeeService '调整必须包含分摊组全部费用行' '柜费分摊完整调整校验'
Assert-Contains $lastlegAgents '海外入仓、采购、美国卡车、本土散板和海外仓服务费必须匹配当前客户的真实业务' 'Lastleg 五类海外费用归属'
Assert-Contains $overseasFinanceOpenApi 'OVERSEAS_INBOUND, OVERSEAS_PROCUREMENT, US_TRUCK, LOCAL_LOOSEBOARD, WAREHOUSE_SERVICE' '海外五类费用 OpenAPI'
Assert-Contains $overseasFinanceOpenApi '审核通过与作废均事务性写入Outbox' '海外费用可靠发布契约'
Assert-Contains $commonEventAgents '海外业务费用来源变更 V1' '公共海外费用事件入口'
Assert-Contains $eventTypes 'BUSINESS_FEE_SOURCE_CHANGED = "BusinessFeeSourceChanged"' '海外费用事件类型'
Assert-Contains $businessFeeEvent 'int sourceVersion' '海外费用事件来源版本'
Assert-Contains $businessFeeEvent 'List<String> paymentVoucherFileIds' '海外费用事件付款证据快照'
Assert-Contains $businessFeeEvent 'String sourceHash' '海外费用事件来源哈希'
Assert-Contains $eventBridgeAgents '`BUSINESS_FEE_SOURCE_CHANGED` 与 `WALLET_COMMAND_REQUESTED` 定向投 Finance' 'Event Bridge Finance 定向路由'
Assert-Contains $eventBridgeAgents '/internal/finance/v1/business-fee-source-events' 'Event Bridge Finance 内部入口'
Assert-Contains $overseasDispatcher 'EventTypes.BUSINESS_FEE_SOURCE_CHANGED' 'Event Bridge 海外费用事件 Finance 路由集合'
Assert-Contains $overseasDispatcher 'EventTypes.WALLET_COMMAND_REQUESTED' 'Event Bridge 海外资金指令 Finance 路由集合'
Assert-Matches $overseasDispatcher '(?s)FINANCE_EVENT_TYPES\.contains\(eventType\).{0,150}?financeEventClient\.deliver\(event\)' 'Event Bridge Finance 事件定向投递'
Assert-Contains $financeAgents '`eventId + payloadHash` 防重放冲突' 'Finance 海外事件幂等边界'
Assert-Contains $financeAgents '`PAYABLE + DIRECT_PAID` 审核版本必须生成 `BUSINESS_DIRECT_PAID`' 'Finance 直接已付隔离边界'
Assert-Contains $rootAgents '入库单扣货、解除与履约门禁' '根入库扣货快速路由'
Assert-Contains $adminAgents '入库单扣货、解除、凭证与历史' 'Admin 入库扣货快速路由'
Assert-Contains $backendAgents '入库单扣货、解除、凭证与履约门禁' '后端入库扣货快速路由'
Assert-Contains $firstlegAgents '入库单扣货、履约门禁与凭证' 'Firstleg 入库扣货入口'
Assert-Contains $rootAgents '客户资金账户、充值与海外业务资金指令' '根客户钱包快速路由'
Assert-Contains $backendAgents '客户资金账户、充值、授信与跨区资金指令' '后端客户钱包快速路由'
Assert-Contains $lastlegAgents '海外业务资金指令与结果' 'Lastleg 跨区钱包入口'
Assert-Contains $lastlegAgents '拆柜打托成本与客户应收分摊' 'Lastleg 拆柜打托费用入口'
Assert-Contains $clientAgents '换标申请必须提交正数 CNY `chargeAmount`' 'Client 换标钱包金额边界'
Assert-Contains $rootAgents '海外 Token 只携带稳定身份、客户/仓库范围和版本声明,不携带角色或权限集' '根海外小 Token 边界'
Assert-Contains $backendAgents '海外 Token 只携带稳定身份、客户/仓库范围和版本声明,不携带角色或权限集' '后端海外小 Token 边界'
Assert-Contains $financeEventConsumer 'envelope.payloadHash().equals(row.get("payload_hash"))' 'Finance 海外事件 Payload 哈希幂等'
Assert-Contains $financeEventConsumer "cost_origin='BUSINESS_DIRECT_PAID'" 'Finance 海外直接已付成本投影'
Assert-Contains $financePhase1Service "f.settlement_mode='ON_ACCOUNT'" 'Finance AP 只纳入账期应付'
Assert-Contains $financePhase1Service "'FIRSTLEG_DIRECT_PAID','BUSINESS_DIRECT_PAID'" 'Finance 已付成本汇总'
Assert-Contains $scriptsAgents 'Finance 扩展 HTTP 模块' '脚本指引 Finance 扩展模块'
foreach ($financeModule in @('firstleg-container-fee-allocation', 'finance-direct-paid-isolation', 'phase4-overseas-finance-cross-region')) {
Assert-Contains $adminAcceptanceEntry "'$financeModule'" "Admin 总入口 $financeModule 注册"
Assert-Contains $adminAcceptanceModuleIndex "$financeModule.mjs" "Admin 模块索引 $financeModule"
}
# 国内 PDA 部分拣货必须展示真实可用库位事实,并在无库位时保持页面整洁。
Assert-Contains $pdaAgents 'tests/partial-layout.test.mjs' '国内 PDA 部分拣货布局合同'
Assert-Contains $pdaAgents 'tests/picking-location-display.test.mjs' '国内 PDA 库位展示合同'
# Maven 聚合声明的全部历史/当前模块必须在后端根指引中可定位。
[xml]$pom = Get-Content -LiteralPath (Join-Path $backendRoot 'pom.xml') -Raw
foreach ($module in $pom.project.modules.module) {
Assert-Contains $backendAgents "$module/" '后端 AGENTS.md'
}
# 对本轮高变化链路做精确文件门禁,防止改名或删除后留下悬空索引。
$criticalPaths = @(
'apps/admin-web/src/modules/overseas-warehouse/api/inboundOrders.ts',
'apps/admin-web/src/modules/overseas-warehouse/api/lastMileOrders.ts',
'apps/pda-overseas-uniapp/src/api/pallet.js',
'apps/pda-overseas-uniapp/src/pages/pallet/pallet.vue',
'apps/pda-overseas-uniapp/tests/pallet-operations.test.mjs',
'apps/admin-web/src/modules/overseas-warehouse/pages/LastMileOrdersView.vue',
'apps/admin-web/src/modules/overseas-warehouse/api/inboundPlans.ts',
'apps/admin-web/src/modules/overseas-warehouse/api/inventory.ts',
'apps/admin-web/src/modules/overseas-warehouse/api/pallets.ts',
'apps/admin-web/src/modules/overseas-warehouse/api/dispatches.ts',
'apps/admin-web/src/modules/overseas-warehouse/pages/DispatchesView.vue',
'apps/admin-web/src/modules/overseas-warehouse/pages/DispatchDetailView.vue',
'apps/admin-web/src/modules/overseas-warehouse/components/SmartDispatchDialog.vue',
'apps/admin-web/src/modules/container-loading/pages/SmartLoadingWorkbenchView.vue',
'apps/admin-web/src/modules/container-loading/pages/ContainerDetailView.vue',
'apps/admin-web/src/modules/container-loading/components/ContainerOverviewPanel.vue',
'apps/admin-web/src/modules/container-loading/components/ContainerCustomsPanel.vue',
'apps/admin-web/src/modules/container-loading/api/platformContainerCustoms.ts',
'apps/admin-web/src/modules/container-loading/api/platformContainerCustoms.test.ts',
'apps/admin-web/src/modules/container-loading/api/platformContainerLoading.ts',
'apps/admin-web/src/modules/loading-lists/pages/PreloadPlanDetailView.lifecycle.test.ts',
'apps/admin-web/src/modules/unified-orders/api/coLoadGroups.ts',
'apps/admin-web/src/modules/unified-orders/pages/UnifiedOrdersView.vue',
'apps/admin-web/src/modules/ocean-bookings/api/platformOceanBookings.ts',
'apps/admin-web/src/modules/ocean-bookings/pages/OceanBookingsView.vue',
'apps/admin-web/src/modules/ocean-bookings/components/OceanBookingDocumentsPanel.vue',
'apps/admin-web/src/modules/ocean-bookings/components/OceanBookingPrintDialog.vue',
'apps/admin-web/src/modules/trucking/components/TruckAppointmentForm.vue',
'apps/admin-web/src/modules/trucking/api/platformTrucking.ts',
'apps/admin-web/src/core/routing/navigationRecovery.ts',
'apps/admin-web/src/core/routing/navigationRecovery.test.ts',
'apps/admin-web/src/modules/overseas-warehouse/api/outbounds.ts',
'apps/admin-web/src/modules/overseas-warehouse/pages/OutboundsView.vue',
'apps/admin-web/src/modules/overseas-warehouse/api/deliveryOrders.ts',
'apps/admin-web/src/modules/overseas-warehouse/pages/DeliveryOrdersView.vue',
'apps/admin-web/src/modules/overseas-warehouse/pages/DeliveryOrderDetailView.vue',
'apps/admin-web/src/modules/overseas-warehouse/api/exceptionOrders.ts',
'apps/admin-web/src/modules/overseas-warehouse/pages/ExceptionOrdersView.vue',
'apps/admin-web/src/modules/overseas-warehouse/api/customerVisits.ts',
'apps/admin-web/src/modules/overseas-warehouse/pages/CustomerVisitsView.vue',
'apps/admin-web/src/modules/iam/pages/InternalUsersView.vue',
'apps/admin-web/src/modules/iam/api/platformIam.ts',
'apps/admin-web/src/modules/unified-orders/api/unifiedOrders.ts',
'apps/client-web/src/api/overseasHttp.ts',
'apps/client-web/src/modules/overseas-warehouse/routes.ts',
'apps/client-web/src/modules/overseas-warehouse/api/warehouseServices.ts',
'apps/client-web/src/modules/overseas-warehouse/views/WarehouseServiceView.vue',
'apps/client-web/src/modules/first-leg/components/CustomsDocumentsDialog.vue',
'apps/client-web/src/modules/first-leg/api/customs.ts',
'apps/client-web/src/modules/first-leg/api/customs.test.mjs',
'apps/client-web/src/modules/first-leg/api/inboundCodeAssociations.ts',
'apps/client-web/src/modules/first-leg/components/InboundCodeAssociationDialog.vue',
'apps/admin-web/src/modules/overseas-business/api/platformOverseasBusiness.ts',
'apps/admin-web/src/modules/overseas-master-data/api/overseasMasterData.ts',
'apps/pda-uniapp/pages/tasks/tasks.vue',
'apps/pda-uniapp/config/runtime.js',
'apps/pda-uniapp/.env.example',
'apps/pda-uniapp/vite.config.js',
'apps/pda-uniapp/utils/app-update.js',
'apps/pda-uniapp/tests/app-update.test.mjs',
'apps/pda-uniapp/tests/page-contract.test.mjs',
'apps/pda-uniapp/tests/pda-loading-api.test.mjs',
'apps/pda-uniapp/utils/evidence-upload-queue.js',
'apps/pda-overseas-uniapp/package.json',
'apps/pda-overseas-uniapp/src/pages.json',
'apps/pda-overseas-uniapp/src/data/overseas-workbench.js',
'apps/pda-overseas-uniapp/src/pages/operation/operation.vue',
'apps/pda-overseas-uniapp/src/pages/dispatch/dispatch.vue',
'apps/pda-overseas-uniapp/src/pages/outbound/outbound.vue',
'apps/pda-overseas-uniapp/src/api/fulfillment.js',
'apps/pda-overseas-uniapp/src/stores/fulfillment.js',
'apps/pda-overseas-uniapp/tests/fulfillment-workflows.test.mjs',
'apps/pda-overseas-uniapp/src/stores/receiving.js',
'apps/pda-overseas-uniapp/tests/receiving-photo-ui-contract.test.mjs',
'apps/pda-overseas-uniapp/src/config/runtime.js',
'apps/pda-overseas-uniapp/src/api/auth.js',
'apps/pda-overseas-uniapp/src/api/inbound.js',
'apps/pda-overseas-uniapp/src/api/receiving-adapter.js',
'apps/pda-overseas-uniapp/src/api/overseas.js',
'apps/pda-overseas-uniapp/src/utils/scan-broadcast.js',
'apps/pda-overseas-uniapp/src/manifest.json',
'apps/pda-overseas-uniapp/tests/app-icons.test.mjs',
'apps/pda-overseas-uniapp/src/utils/app-update.js',
'apps/pda-overseas-uniapp/tests/app-update.test.mjs',
'apps/pda-overseas-uniapp/tests/business-identifiers-ui.test.mjs',
'apps/pda-overseas-uniapp/src/i18n/index.js',
'apps/pda-overseas-uniapp/src/i18n/locales/zh-CN.js',
'apps/pda-overseas-uniapp/src/i18n/locales/en.js',
'apps/pda-overseas-uniapp/src/i18n/locales/es.js',
'baiyue-firstleg/firstleg/src/main/java/com/baiyue/firstleg/service/FeePaymentSnapshotValidator.java',
'baiyue-firstleg/scripts/mapper-scan-contract.mjs',
'baiyue-firstleg/scripts/mapper-scan-contract.test.mjs',
'baiyue-firstleg/firstleg/src/test/java/com/baiyue/firstleg/MapperRegistrationArchitectureTest.java',
'baiyue-firstleg/lastleg-service/src/test/java/com/baiyue/lastleg/MapperRegistrationArchitectureTest.java',
'baiyue-firstleg/firstleg/src/main/java/com/baiyue/firstleg/client/FeePaymentVoucherFileClient.java',
'baiyue-firstleg/lastleg-service/src/main/java/com/baiyue/lastleg/inboundplan/mapper/InboundPlanQueryMapper.java',
'baiyue-firstleg/lastleg-service/src/main/java/com/baiyue/lastleg/inboundplan/service/InboundFbaAppointmentService.java',
'baiyue-firstleg/lastleg-service/src/main/java/com/baiyue/lastleg/inboundplan/pda/gateway/UnloadPhotoFileGateway.java',
'baiyue-firstleg/lastleg-service/src/main/java/com/baiyue/lastleg/dispatch/controller/DispatchQueryController.java',
'baiyue-firstleg/lastleg-service/src/main/java/com/baiyue/lastleg/dispatch/controller/SmartDispatchController.java',
'baiyue-firstleg/lastleg-service/src/main/java/com/baiyue/lastleg/dispatch/controller/DispatchController.java',
'baiyue-firstleg/lastleg-service/src/main/java/com/baiyue/lastleg/dispatch/pda/controller/DispatchPdaController.java',
'baiyue-firstleg/lastleg-service/src/main/java/com/baiyue/lastleg/delivery/controller/DeliveryTransferController.java',
'baiyue-firstleg/lastleg-service/src/main/java/com/baiyue/lastleg/delivery/controller/OutboundPdaController.java',
'baiyue-firstleg/lastleg-service/src/main/java/com/baiyue/lastleg/delivery/controller/MerchantDeliveryController.java',
'baiyue-firstleg/lastleg-service/src/main/java/com/baiyue/lastleg/exceptionorder/controller/ExceptionOrderController.java',
'baiyue-firstleg/lastleg-service/src/main/java/com/baiyue/lastleg/customervisit/controller/CustomerVisitController.java',
'baiyue-firstleg/lastleg-service/src/main/java/com/baiyue/lastleg/dropship/service/DropshipOrderService.java',
'baiyue-firstleg/lastleg-service/src/main/java/com/baiyue/lastleg/service/InboundOrderDetainedOutboxService.java',
'baiyue-firstleg/common-event-contract/src/main/java/com/baiyue/common/event/OverseasInboundOrderDetainedChangedV1.java',
'baiyue-firstleg/firstleg/src/main/java/com/baiyue/firstleg/service/DropshipPalletizationService.java',
'baiyue-firstleg/firstleg/src/main/java/com/baiyue/firstleg/service/OverseasInboundOrderDetainedConsumer.java',
'baiyue-firstleg/order/src/main/java/com/baiyue/order/controller/InternalOrderCargoController.java',
'baiyue-firstleg/lastleg-service/src/main/java/com/baiyue/lastleg/dispatch/entity/DispatchDraftContainer.java',
'baiyue-firstleg/lastleg-service/src/main/java/com/baiyue/lastleg/dispatch/mapper/DispatchDraftContainerMapper.java',
'baiyue-firstleg/firstleg/src/main/java/com/baiyue/firstleg/controller/PlatformSmartLoadingController.java',
'baiyue-firstleg/firstleg/src/main/java/com/baiyue/firstleg/service/SmartLoadingService.java',
'baiyue-firstleg/firstleg/src/main/java/com/baiyue/firstleg/controller/PlatformContainerController.java',
'baiyue-firstleg/firstleg/src/main/java/com/baiyue/firstleg/mapper/ContainerOverviewMapper.java',
'baiyue-firstleg/firstleg/src/main/java/com/baiyue/firstleg/customs/container/controller/PlatformContainerCustomsController.java',
'baiyue-firstleg/firstleg/src/main/java/com/baiyue/firstleg/customs/container/controller/MerchantContainerCustomsController.java',
'baiyue-firstleg/firstleg/src/main/java/com/baiyue/firstleg/customs/container/service/ContainerCustomsService.java',
'baiyue-firstleg/firstleg/src/main/resources/openapi/customs-v1.yaml',
'baiyue-firstleg/firstleg/src/main/resources/openapi/coload-groups-v1.yaml',
'baiyue-firstleg/firstleg/src/main/resources/openapi/loading-lists-v1.yaml',
'baiyue-firstleg/firstleg/src/main/java/com/baiyue/firstleg/loading/coload/controller/PlatformColoadGroupController.java',
'baiyue-firstleg/firstleg/src/main/java/com/baiyue/firstleg/loading/coload/service/ColoadGroupService.java',
'baiyue-firstleg/firstleg/src/main/java/com/baiyue/firstleg/oceanbooking/service/OceanBookingDocumentService.java',
'baiyue-firstleg/firstleg/src/main/java/com/baiyue/firstleg/oceanbooking/service/OceanBookingPrintService.java',
'baiyue-firstleg/firstleg/src/main/java/com/baiyue/firstleg/service/TruckAppointmentService.java',
'baiyue-firstleg/firstleg/src/main/resources/openapi/truck-appointments-v1.yaml',
'baiyue-firstleg/file/src/main/resources/openapi/customs-file-and-export-v1.yaml',
'baiyue-firstleg/order/src/main/java/com/baiyue/order/service/InboundCodeAssociationService.java',
'baiyue-firstleg/order/src/main/java/com/baiyue/order/service/UnifiedOrderQueryService.java',
'baiyue-firstleg/order/src/main/resources/openapi/order-v1.yaml',
'baiyue-firstleg/firstleg/src/main/java/com/baiyue/firstleg/outbound/dispatch/controller/PlatformOutboundDispatchController.java',
'baiyue-firstleg/firstleg/src/main/resources/openapi/phase3-container-overview-v1.yaml',
'baiyue-firstleg/firstleg/src/main/resources/openapi/phase3-outbound-dispatch-v1.yaml',
'baiyue-firstleg/firstleg/src/main/resources/openapi/carrier-schedule-query-v1.yaml',
'baiyue-firstleg/firstleg/src/main/java/com/baiyue/firstleg/oceanbooking/controller/PlatformOceanBookingController.java',
'baiyue-firstleg/firstleg/src/main/java/com/baiyue/firstleg/oceanbooking/mapper/OceanBookingMapper.java',
'baiyue-firstleg/firstleg/src/main/resources/openapi/ocean-bookings-v1.yaml',
'baiyue-firstleg/firstleg/src/main/java/com/baiyue/firstleg/pricebookquery/application/port/in/PriceBookQueryUseCase.java',
'baiyue-firstleg/firstleg/src/main/java/com/baiyue/firstleg/pricebookquery/application/PriceBookQueryService.java',
'baiyue-firstleg/firstleg/src/main/java/com/baiyue/firstleg/pricebookquery/application/port/out/PriceBookQueryReader.java',
'baiyue-firstleg/firstleg/src/main/java/com/baiyue/firstleg/pricebookquery/adapter/out/persistence/PriceBookQueryMapper.java',
'baiyue-firstleg/firstleg/docs/firstleg-internal-modularization-baseline.md',
'baiyue-firstleg/firstleg/scripts/analyze-firstleg-dependencies.mjs',
'baiyue-firstleg/firstleg/scripts/analyze-firstleg-dependencies.test.mjs',
'baiyue-firstleg/firstleg/src/test/resources/architecture/firstleg-slice-dependencies.json',
'baiyue-firstleg/auth/src/main/java/com/baiyue/auth/service/OverseasTokenService.java',
'baiyue-firstleg/auth/src/main/java/com/baiyue/auth/service/OverseasSessionValidationService.java',
'baiyue-firstleg/iam/src/main/java/com/baiyue/iam/service/PlatformUserManagementService.java',
'baiyue-firstleg/iam/src/main/java/com/baiyue/iam/service/SecurityEventOutboxService.java',
'baiyue-firstleg/iam/src/main/java/com/baiyue/iam/service/SecurityEventOutboxRelay.java',
'baiyue-firstleg/iam/src/main/java/com/baiyue/iam/entity/IamMembership.java',
'baiyue-firstleg/iam/src/main/java/com/baiyue/iam/service/CustomerDimensionRuleInitializationService.java',
'baiyue-firstleg/iam/src/main/java/com/baiyue/iam/service/CustomerDimensionInitializationRelay.java',
'baiyue-firstleg/iam/src/main/java/com/baiyue/iam/repository/CustomerDimensionInitializationRepository.java',
'baiyue-firstleg/iam/src/main/java/com/baiyue/iam/client/CustomerDimensionRuleClient.java',
'baiyue-firstleg/iam/src/main/resources/db/customer-dimension-initialization-task.sql',
'baiyue-firstleg/common-security/src/main/java/com/baiyue/common/security/AuthenticatedUser.java',
'baiyue-firstleg/common-security/src/main/java/com/baiyue/common/security/JwtClaimsMapper.java',
'baiyue-firstleg/common-openapi/src/test/java/com/baiyue/common/openapi/PdaOpenApiGroupContractTest.java',
'baiyue-firstleg/common-web/src/main/java/com/baiyue/common/web/RestClientTraceInterceptor.java',
'baiyue-firstleg/common-web/src/main/java/com/baiyue/common/web/RestClientTracePropagationAutoConfiguration.java',
'baiyue-firstleg/common-web/src/test/java/com/baiyue/common/web/RestClientTraceInterceptorTest.java',
'baiyue-firstleg/gateway-overseas/src/main/java/com/baiyue/gateway/filter/PdaSessionValidationFilter.java',
'baiyue-firstleg/gateway-overseas/src/main/java/com/baiyue/gateway/filter/HttpPdaSessionValidationClient.java',
'baiyue-firstleg/lastleg-service/src/main/java/com/baiyue/lastleg/security/controller/LastlegSecurityController.java',
'baiyue-firstleg/lastleg-service/src/main/java/com/baiyue/lastleg/security/service/LastlegSecurityProjectionService.java',
'baiyue-firstleg/lastleg-service/src/main/java/com/baiyue/lastleg/security/service/LastlegSecurityValidationService.java',
'baiyue-firstleg/lastleg-service/src/main/java/com/baiyue/lastleg/inboundplan/pda/controller/ReceivingContainerController.java',
'baiyue-firstleg/lastleg-service/src/main/java/com/baiyue/lastleg/dto/ContainerPlanProgressSummary.java',
'baiyue-firstleg/lastleg-service/src/main/java/com/baiyue/lastleg/dto/ContainerPlanProgressDetail.java',
'baiyue-firstleg/lastleg-service/src/test/java/com/baiyue/lastleg/service/ContainerPlanProgressContractTest.java',
'baiyue-firstleg/lastleg-service/src/main/resources/openapi/overseas-business-v1.yaml',
'baiyue-firstleg/lastleg-service/src/main/java/com/baiyue/lastleg/inboundplan/pda/service/ReceivingContainerService.java',
'baiyue-firstleg/lastleg-service/src/main/java/com/baiyue/lastleg/inboundplan/pda/gateway/UnloadPhotoFileGateway.java',
'baiyue-firstleg/lastleg-service/src/main/java/com/baiyue/lastleg/pda/stocktake/controller/PdaStocktakeController.java',
'baiyue-firstleg/lastleg-service/src/main/java/com/baiyue/lastleg/pda/stocktake/service/PdaStocktakeService.java',
'baiyue-firstleg/lastleg-service/src/main/java/com/baiyue/lastleg/pda/move/controller/PdaInventoryMoveController.java',
'baiyue-firstleg/lastleg-service/src/main/java/com/baiyue/lastleg/pda/move/service/PdaInventoryMoveService.java',
'baiyue-firstleg/lastleg-service/src/main/java/com/baiyue/lastleg/palletops/controller/PdaPalletOperationController.java',
'baiyue-firstleg/lastleg-service/src/main/java/com/baiyue/lastleg/palletops/service/PdaPalletOperationService.java',
'baiyue-firstleg/lastleg-service/src/main/java/com/baiyue/lastleg/relabel/pda/controller/PdaRelabelController.java',
'baiyue-firstleg/lastleg-service/src/main/java/com/baiyue/lastleg/relabel/pda/service/PdaRelabelService.java',
'baiyue-firstleg/lastleg-service/src/main/java/com/baiyue/lastleg/pda/warehouse/controller/PdaWarehouseController.java',
'baiyue-firstleg/lastleg-service/src/main/java/com/baiyue/lastleg/pda/warehouse/service/PdaWarehouseService.java',
'baiyue-firstleg/lastleg-service/src/main/resources/openapi/overseas-pda-operations-v1.yaml',
'baiyue-firstleg/warehouse-overseas-service/src/main/java/com/baiyue/warehouse/controller/InternalPdaPalletTransitionController.java',
'baiyue-firstleg/warehouse-overseas-service/src/main/java/com/baiyue/warehouse/service/WarehousePalletTransitionService.java',
'baiyue-firstleg/warehouse-overseas-service/src/main/java/com/baiyue/warehouse/entity/WarehousePalletOperationEntity.java',
'baiyue-firstleg/warehouse-overseas-service/src/main/java/com/baiyue/warehouse/client/DomesticWarehouseDirectoryClient.java',
'baiyue-firstleg/warehouse-overseas-service/src/main/java/com/baiyue/warehouse/service/DomesticWarehouseDirectory.java',
'baiyue-firstleg/warehouse/src/main/java/com/baiyue/warehouse/controller/InternalWarehouseController.java',
'baiyue-firstleg/warehouse/src/main/java/com/baiyue/warehouse/dto/SharedOverseasWarehouseResponse.java',
'baiyue-firstleg/file/src/main/java/com/baiyue/file/controller/PlatformProductImageController.java',
'baiyue-firstleg/lastleg-service/docs/lastleg-internal-modularization-baseline.md',
'baiyue-firstleg/lastleg-service/scripts/analyze-lastleg-dependencies.mjs',
'baiyue-firstleg/lastleg-service/scripts/analyze-lastleg-dependencies.test.mjs',
'baiyue-firstleg/lastleg-service/src/test/resources/architecture/lastleg-slice-dependencies.json',
'baiyue-firstleg/lastleg-service/src/main/java/com/baiyue/lastleg/masterdata/vehicle/adapter/in/web/PlatformVehicleController.java',
'baiyue-firstleg/lastleg-service/src/main/java/com/baiyue/lastleg/masterdata/vehicle/application/VehicleApplicationService.java',
'baiyue-firstleg/lastleg-service/src/main/java/com/baiyue/lastleg/masterdata/vehicle/application/port/out/VehicleRepository.java',
'baiyue-firstleg/lastleg-service/src/main/java/com/baiyue/lastleg/masterdata/vehicle/adapter/out/persistence/VehiclePersistenceAdapter.java',
'baiyue-firstleg/lastleg-service/src/main/java/com/baiyue/lastleg/config/LastlegRestClientFactory.java',
'baiyue-firstleg/lastleg-service/src/main/java/com/baiyue/lastleg/controller/MerchantLastlegOrderController.java',
'baiyue-firstleg/lastleg-service/src/main/java/com/baiyue/lastleg/model/LastlegOrderType.java',
'baiyue-firstleg/lastleg-service/src/main/java/com/baiyue/lastleg/model/LastlegOrderStatus.java',
'baiyue-firstleg/firstleg/src/main/java/com/baiyue/firstleg/portschedule/service/CarrierScheduleQuerySlots.java',
'baiyue-firstleg/firstleg/src/main/java/com/baiyue/firstleg/portschedule/entity/CarrierScheduleExceptionFactEntity.java',
'baiyue-firstleg/integration-service/src/main/java/com/baiyue/integration/domain/CarrierScheduleStandardNode.java',
'baiyue-firstleg/integration-service/src/main/java/com/baiyue/integration/domain/CarrierScheduleExceptionCode.java',
'baiyue-firstleg/gateway-overseas/src/test/java/com/baiyue/gateway/config/OverseasLastlegRouteContractTest.java',
'baiyue-firstleg/event-bridge-service/src/main/java/com/baiyue/eventbridge/service/FirstlegEventClient.java',
'baiyue-firstleg/common-event-contract/src/main/java/com/baiyue/common/event/FirstLegLoadingPlanCompletedV2.java',
'baiyue-firstleg/common-event-contract/src/main/java/com/baiyue/common/event/FirstLegContainerShippingNodeRecordedV1.java',
'baiyue-firstleg/firstleg/src/main/java/com/baiyue/firstleg/portschedule/service/CarrierScheduleNodeOutboxService.java',
'baiyue-firstleg/lastleg-service/src/main/java/com/baiyue/lastleg/shipping/service/ContainerShippingNodeConsumer.java',
'baiyue-firstleg/lastleg-service/src/main/java/com/baiyue/lastleg/shipping/entity/ContainerShippingGate.java',
'baiyue-firstleg/firstleg/src/test/java/com/baiyue/firstleg/service/TaillegRealProducerAcceptanceTest.java',
'baiyue-firstleg/lastleg-service/src/main/java/com/baiyue/lastleg/entity/LastlegInboundOrder.java',
'baiyue-firstleg/lastleg-service/src/main/java/com/baiyue/lastleg/mapper/LastlegInboundOrderMapper.java',
'baiyue-firstleg/lastleg-service/src/test/java/com/baiyue/lastleg/service/TaillegRealConsumerAcceptanceTest.java',
'baiyue-firstleg/deploy/scripts/deploy-built-service.sh',
'baiyue-firstleg/scripts/deploy-built-service-rollback.test.mjs',
'baiyue-firstleg/scripts/java-quality-summary.mjs',
'baiyue-firstleg/scripts/java-quality-summary.test.mjs',
'baiyue-firstleg/scripts/admin-test-env-modules/manual-order-splitting-contract.test.mjs',
'baiyue-firstleg/scripts/admin-test-env-modules/manual-preload-push-contract.test.mjs',
'baiyue-firstleg/scripts/admin-test-env-modules/manual-pda-ready-contract.test.mjs',
'baiyue-firstleg/scripts/admin-test-env-modules/manual-pda-batch-contract.test.mjs',
'baiyue-firstleg/scripts/admin-test-env-modules/manual-loading-complete-contract.test.mjs',
'docs/海外仓业务/船节点标准化契约.md',
'docs/订单与客户/订单与客户头程订单闭环设计.md',
'docs/入库测量与计费/入库测量与计费需求优化版-v2-测量计费入库主流程.md',
'docs/墨家设备测量上传接口说明-V3.md',
'docs/国内货柜履约/国内货柜履约需求确认表.md',
'docs/统一订单主状态与操作契约.md',
'docs/开发环境独立任务协作登记.md',
'docs/独立任务协作登记.md',
'docs/财务管理/财务管理产品确认表.md',
'docs/财务管理/Firstleg-Finance跨服务契约.md'
)
$criticalPaths | ForEach-Object { Assert-Path $_ }
foreach ($removedOverseasWarehouseMasterPath in @(
'baiyue-firstleg/warehouse-overseas-service/src/main/java/com/baiyue/warehouse/controller/PlatformWarehouseController.java',
'baiyue-firstleg/warehouse-overseas-service/src/main/java/com/baiyue/warehouse/controller/MerchantWarehouseController.java',
'baiyue-firstleg/warehouse-overseas-service/src/main/java/com/baiyue/warehouse/entity/WarehouseEntity.java',
'baiyue-firstleg/warehouse-overseas-service/src/main/java/com/baiyue/warehouse/entity/WarehouseAddressEntity.java',
'baiyue-firstleg/warehouse-overseas-service/src/main/java/com/baiyue/warehouse/entity/ServiceCapabilityEntity.java'
)) {
Assert-PathMissing $removedOverseasWarehouseMasterPath
}
# 只检查明确维护的快速索引表,避免把排除规则正文中的目录名误判为业务入口。
$indexedAgentFiles = @(
$rootAgentsPath,
$adminAgentsPath,
$clientAgentsPath,
$pdaAgentsPath,
$overseasPdaAgentsPath,
$backendAgentsPath,
(Join-Path $backendRoot 'firstleg/AGENTS.md'),
(Join-Path $backendRoot 'finance/AGENTS.md'),
(Join-Path $backendRoot 'lastleg-service/AGENTS.md'),
(Join-Path $backendRoot 'iam/AGENTS.md'),
(Join-Path $backendRoot 'common-security/AGENTS.md'),
(Join-Path $backendRoot 'common-web/AGENTS.md'),
(Join-Path $backendRoot 'common-openapi/AGENTS.md'),
(Join-Path $backendRoot 'warehouse-overseas-service/AGENTS.md'),
(Join-Path $backendRoot 'warehouse/AGENTS.md'),
(Join-Path $backendRoot 'event-bridge-service/AGENTS.md'),
(Join-Path $backendRoot 'file/AGENTS.md'),
(Join-Path $backendRoot 'common-event-contract/AGENTS.md')
)
$excludedTargetPattern = '(?i)`(?:[^`]*/)?(node_modules(?:\.[^/`]*)?|dist|target|reports|output|outputs|uni_modules|\.git|\.codex[^/`]*|\.runtime[^/`]*)(?:/|`)'
$excludedPatternSamples = @(
'| 错误入口 | `node_modules/pkg/` |',
'| 错误入口 | `node_modules.corrupt/.bin/vite` |',
'| 错误入口 | `src/target/classes/` |',
'| 错误入口 | `.codex-temp/task/` |',
'| 错误入口 | `.runtime-tailleg/DbQuery.java` |'
)
foreach ($sample in $excludedPatternSamples) {
$script:checked++
if ($sample -notmatch $excludedTargetPattern) {
Add-Failure "排除目录检测器自检失败: $sample"
}
}
foreach ($agentFile in $indexedAgentFiles) {
$script:checked++
if (-not (Test-Path -LiteralPath $agentFile -PathType Leaf)) {
Add-Failure "缺少受检索引文件: $agentFile"
continue
}
$lineNumber = 0
foreach ($line in Get-Content -LiteralPath $agentFile) {
$lineNumber++
if ($line.StartsWith('|') -and $line -match $excludedTargetPattern) {
Add-Failure "快速索引引用了排除目录: $agentFile`:$lineNumber"
}
}
}
if ($failures.Count -gt 0) {
Write-Host "AGENTS 索引合同失败,共 $($failures.Count) 项:" -ForegroundColor Red
$failures | ForEach-Object { Write-Host "- $_" -ForegroundColor Red }
exit 1
}
Write-Host "AGENTS 索引合同通过:$checked 项检查,覆盖快速表唯一性、部署单元、开发/测试任务登记隔离、前端模块、Client active 路由、客户中文批量下单、箱规算法与测量计费、称重整票库位块与暂估箱数校准、入库扣货履约门禁、全局智能装柜组分页、客户账单入仓码联查、客户钱包与跨区资金指令、导出退避任务重试、脚本目录治理、Finance 扩展 HTTP 模块、柜费跨客户原子分摊、海外费用跨区入池与直接已付隔离、企业联系信息与登录标识解耦、选填法人身份证独立上传、待审核订单状态优先、订单申报版本同步与渠道门禁、装柜证据内容哈希重放、业务编号与内部 ID 隔离、装柜清单生命周期与真实柜号后补、订舱级拖车与柜级证据、海外仓全流程范围、柜级待处理计划筛选与范围漂移、仓库主档唯一权威、订舱候选与柜量语义、整柜出仓与船节点单调性、海外小 Token 与安全投影、Gateway 覆盖、PDA 页面/运行配置/独立更新/语言预留/能力开关、人工分段验收链、Maven 模块、同步 Trace、关键入口和排除目录。" -ForegroundColor Green
exit 0