Files
baiyue-firstleg/scripts/agents-index-contract.ps1
2026-08-26 17:50:56 +08:00

562 lines
39 KiB
PowerShell
Raw Permalink 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
$engineeringConstraints = Read-RequiredText (Join-Path $workspaceRoot 'docs/AI工程执行与协作约束.md')
# 当前未上线阶段的无兼容原则必须覆盖全部实现与运行状态,不能再次缩窄为文件或数据库专项规则。
Assert-Contains $rootAgents '源码结构、接口与 DTO、字段、状态机、权限、配置键、数据库结构与初始化 SQL、事件、路由、页面、Mock/Fixture、测试和脚本' '根无兼容收敛范围'
Assert-Contains $rootAgents '数据库记录、上传文件、缓存、会话、消息、搜索索引和其他运行状态均视为可丢弃' '根开发运行状态范围'
Assert-Contains $engineeringConstraints '禁止为旧代码、旧调用或开发环境存量保留旧接口/旧字段别名' '工程无兼容执行规则'
Assert-Contains $engineeringConstraints '不授权自动重置数据库、删除数据/文件、执行 SQL、部署或修改环境' '无兼容安全边界'
Assert-Contains $clientAgents '不得继续扩展 `LEGACY_MANUAL`、旧系统入仓码、C02 不可用回退旧 API' 'Client 头程无兼容边界'
# 部署单元必须能从根索引进入。
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 拆柜收货开关'
foreach ($disabledOperation in @(
'库存盘点', '商品移库', '托盘管理',
'换标收货', '换标执行', '换标复核',
'库存查询', '库位查询', '托盘查询'
)) {
$disabledPattern = "(?s)name:\s*'$([regex]::Escape($disabledOperation))'.{0,300}?available:\s*false"
Assert-Matches $overseasWorkbench $disabledPattern "Overseas PDA 禁用入口 $disabledOperation"
}
# 文档声明为正式开放的 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 订舱列表无详情扇出合同'
# 已注册但超出当前四期边界的海外出库及派生运营页只能作为范围漂移事实存在,不得进入根正式业务路由。
$adminOverseasRoutes = Read-RequiredText (Join-Path $workspaceRoot 'apps/admin-web/src/modules/overseas-warehouse/routes.ts')
foreach ($outOfScopeOverseasRoute in @(
'overseas-warehouse/outbounds',
'overseas-warehouse/delivery-orders',
'overseas-warehouse/exception-orders',
'overseas-warehouse/customer-visits'
)) {
Assert-Contains $adminOverseasRoutes "path: '$outOfScopeOverseasRoute'" "Admin 范围外现存路由 $outOfScopeOverseasRoute"
}
Assert-Contains $adminAgents '海外出库、派送、异常与回访(范围外现存代码)' 'Admin 海外范围漂移警示'
foreach ($outOfScopeRootEntry in @(
'OutboundsView.vue', 'DeliveryOrdersView.vue', 'ExceptionOrdersView.vue', 'CustomerVisitsView.vue'
)) {
Assert-NotContains $rootAgents $outOfScopeRootEntry '根正式四期业务路由'
}
# 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 || '/api'" '国内 PDA H5 同源 API'
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 $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 货柜详情确认离仓'
# 平台商品图片和海外 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 签收照片缓存边界'
# 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/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/api/platformContainerLoading.ts',
'apps/admin-web/src/modules/ocean-bookings/api/platformOceanBookings.ts',
'apps/admin-web/src/modules/ocean-bookings/pages/OceanBookingsView.vue',
'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/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/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/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/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/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/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/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/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/财务管理/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 路由、四期范围漂移、仓库主档唯一权威、订舱候选与柜量语义、整柜出仓与船节点单调性、Gateway 覆盖、PDA 页面/运行配置/独立更新/语言预留/能力开关、人工分段验收链、Maven 模块、Lastleg 海外安全投影、同步 Trace、关键入口和排除目录。" -ForegroundColor Green
exit 0