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

1561 lines
135 KiB
PowerShell
Raw Normal View History

[CmdletBinding()]
2026-08-20 19:55:21 +08:00
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"
}
}
2026-08-25 16:40:48 +08:00
function Assert-NotContains([string]$text, [string]$needle, [string]$scope) {
$script:checked++
if ($text.Contains($needle)) {
Add-Failure "$scope 仍残留: $needle"
}
}
2026-08-24 09:29:26 +08:00
function Assert-Matches([string]$text, [string]$pattern, [string]$scope) {
$script:checked++
if ($text -notmatch $pattern) {
Add-Failure "$scope 未匹配合同: $pattern"
}
}
2026-08-20 19:55:21 +08:00
function Assert-Path([string]$relativePath) {
$script:checked++
$absolutePath = Join-Path $workspaceRoot $relativePath
if (-not (Test-Path -LiteralPath $absolutePath)) {
Add-Failure "索引入口不存在: $relativePath"
}
}
2026-08-26 15:58:54 +08:00
function Assert-PathMissing([string]$relativePath) {
$script:checked++
$absolutePath = Join-Path $workspaceRoot $relativePath
if (Test-Path -LiteralPath $absolutePath) {
Add-Failure "已移除入口仍然存在: $relativePath"
}
}
2026-08-21 17:19:49 +08:00
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])
}
if (-not $inside) {
Add-Failure "$scope 缺少章节: $heading"
return
}
if ($keys.Count -lt 2) {
Add-Failure "$scope 缺少表头或入口行: $heading"
}
2026-08-21 17:19:49 +08:00
$keys | Group-Object | Where-Object Count -gt 1 | ForEach-Object {
Add-Failure "$scope 存在重复索引键: $($_.Name)($($_.Count) 次)"
}
}
# 只检查指定文档的本地 Markdown 链接与标题锚点,不递归读取目录或把代码片段当路径。
function Assert-MarkdownLinks([string]$path, [string]$text, [string]$scope) {
foreach ($link in [regex]::Matches($text, '(?<!!)\[[^\]\r\n]+\]\((?<target><[^>\r\n]+>|[^\s)]+)\)')) {
$target = $link.Groups['target'].Value.Trim([char[]]'<>')
if ($target -match '^[a-zA-Z][a-zA-Z0-9+.-]*:') { continue }
$parts = $target -split '#', 2
$linkedPath = if ($parts[0]) { Join-Path (Split-Path -Parent $path) ([Uri]::UnescapeDataString($parts[0])) } else { $path }
$script:checked++
if (-not (Test-Path -LiteralPath $linkedPath -PathType Leaf)) {
Add-Failure "$scope 链接目标不存在: $target"
continue
}
if ($parts.Count -lt 2 -or -not $parts[1] -or [IO.Path]::GetExtension($linkedPath) -ne '.md') { continue }
$script:checked++
$linkedText = if ($linkedPath -eq $path) { $text } else { Get-Content -LiteralPath $linkedPath -Raw }
$headingIds = [System.Collections.Generic.HashSet[string]]::new([StringComparer]::Ordinal)
foreach ($heading in [regex]::Matches($linkedText, '(?m)^#{1,6}[ \t]+(.+?)\r?$')) {
$title = $heading.Groups[1].Value -replace '[ \t]+#+[ \t]*$', ''
$slug = [regex]::Replace($title.Trim().ToLowerInvariant(), '[^\p{L}\p{M}\p{N}_\s-]', '') -replace '\s+', '-'
$headingId = $slug
$suffix = 0
while ($headingIds.Contains($headingId)) { $suffix++; $headingId = "$slug-$suffix" }
[void]$headingIds.Add($headingId)
}
if (-not $headingIds.Contains([Uri]::UnescapeDataString($parts[1]))) {
Add-Failure "$scope 标题锚点不存在: $target"
}
}
}
# 路由表只放定位,不放规则;单行过宽意味着业务规则又回流到表格。
function Assert-TableRowWidth([string]$path, [string]$heading, [int]$maxLength, [string]$scope) {
$script:checked++
$inside = $false
foreach ($line in Get-Content -LiteralPath $path) {
if ($line -eq $heading) { $inside = $true; continue }
if ($inside -and $line.StartsWith('## ')) { break }
if (-not $inside -or -not $line.StartsWith('|')) { continue }
if ($line -match '^\|[\s\-:|]+\|$') { continue }
if ($line.Length -gt $maxLength) {
Add-Failure "$scope 路由行过宽($($line.Length) > $maxLength):$($line.Substring(0, 40))…"
}
}
}
2026-08-20 19:55:21 +08:00
$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'
2026-08-20 20:54:30 +08:00
$overseasPdaAgentsPath = Join-Path $workspaceRoot 'apps/pda-overseas-uniapp/AGENTS.md'
2026-08-20 19:55:21 +08:00
$backendAgentsPath = Join-Path $backendRoot 'AGENTS.md'
$rootAgents = Read-RequiredText $rootAgentsPath
2026-09-10 19:27:09 +08:00
$businessIndexPath = Join-Path $workspaceRoot 'docs/业务快速索引.md'
$businessIndex = Read-RequiredText $businessIndexPath
2026-10-21 16:40:18 +08:00
$businessRulesPath = Join-Path $workspaceRoot 'docs/业务实现边界.md'
$businessRules = Read-RequiredText $businessRulesPath
# 业务断言检查实际正文,不再要求导航表复制规则;路由校验仍使用短索引。
$businessFacts = $businessIndex + "`n" + $businessRules
2026-09-10 19:27:09 +08:00
Assert-Contains $rootAgents 'docs/业务快速索引.md' '根按需业务索引入口'
Assert-MarkdownLinks $rootAgentsPath $rootAgents '根导航与文档链接'
2026-09-10 19:27:09 +08:00
Assert-MarkdownTableUnique $businessIndexPath '## 业务快速路由表' 0 '详细业务路由表'
Assert-MarkdownTableUnique $businessIndexPath '## 常用说法与歧义分流' 0 '业务歧义分流表'
Assert-Contains $businessIndex '## 业务快速路由表' '详细业务表存在'
Assert-Contains $businessIndex '## 常用说法与歧义分流' '业务歧义分流存在'
2026-10-19 17:56:36 +08:00
$adminEntry = Read-RequiredText $adminAgentsPath
$adminIndexPath = Join-Path $workspaceRoot 'apps/admin-web/docs/business-index.md'
$adminIndex = Read-RequiredText $adminIndexPath
$adminAgents = $adminEntry + "`n" + $adminIndex
2026-09-12 18:34:23 +08:00
$adminOverseasAgentsPath = Join-Path $workspaceRoot 'apps/admin-web/src/modules/overseas-warehouse/AGENTS.md'
$adminOverseasAgents = Read-RequiredText $adminOverseasAgentsPath
2026-10-21 17:22:19 +08:00
# 页面细则归入既有业务正文;只读取对应子节,保留原有字段和状态断言。
$adminInboundPageRules = [regex]::Match($businessRules, '(?ms)^### Admin 入仓计划页面约束\r?\n(?<body>.*?)(?=^#{1,3} |\z)').Groups['body'].Value
$checked++
if (-not $adminInboundPageRules) { Add-Failure '缺少 Admin 入仓计划页面约束正文' }
2026-09-12 18:34:23 +08:00
Assert-Contains $adminAgents 'src/modules/overseas-warehouse/AGENTS.md' 'Admin 海外仓按需指引入口'
Assert-MarkdownTableUnique $adminOverseasAgentsPath '## 页面与业务快速索引' 0 'Admin 海外仓模块表'
2026-10-19 17:56:36 +08:00
$clientEntry = Read-RequiredText $clientAgentsPath
$clientIndexPath = Join-Path $workspaceRoot 'apps/client-web/docs/business-index.md'
$clientIndex = Read-RequiredText $clientIndexPath
$clientAgents = $clientEntry + "`n" + $clientIndex
2026-08-20 19:55:21 +08:00
$pdaAgents = Read-RequiredText $pdaAgentsPath
2026-10-19 17:56:36 +08:00
$overseasPdaEntry = Read-RequiredText $overseasPdaAgentsPath
$overseasPdaIndexPath = Join-Path $workspaceRoot 'apps/pda-overseas-uniapp/docs/business-index.md'
$overseasPdaIndex = Read-RequiredText $overseasPdaIndexPath
$overseasPdaAgents = $overseasPdaEntry + "`n" + $overseasPdaIndex
2026-08-20 19:55:21 +08:00
$backendAgents = Read-RequiredText $backendAgentsPath
2026-09-18 18:02:27 +08:00
$backendIndexPath = Join-Path $backendRoot 'docs/backend-business-index.md'
$lastlegIndexPath = Join-Path $backendRoot 'lastleg-service/docs/business-index.md'
$backendIndex = Read-RequiredText $backendIndexPath
$lastlegIndex = Read-RequiredText $lastlegIndexPath
Assert-Contains $backendAgents 'docs/backend-business-index.md' '后端按需索引入口'
$lastlegEntry = Read-RequiredText (Join-Path $backendRoot 'lastleg-service/AGENTS.md')
Assert-Contains $lastlegEntry 'docs/business-index.md' 'Lastleg 按需索引入口'
2026-10-19 17:56:36 +08:00
$firstlegEntryPath = Join-Path $backendRoot 'firstleg/AGENTS.md'
$firstlegIndexPath = Join-Path $backendRoot 'firstleg/docs/business-index.md'
$firstlegEntry = Read-RequiredText $firstlegEntryPath
$firstlegIndex = Read-RequiredText $firstlegIndexPath
Assert-Contains $firstlegEntry 'docs/business-index.md' 'Firstleg 按需索引入口'
Assert-Contains $firstlegEntry '修改前必须核对该索引对应入口' 'Firstleg 业务变更细则读取边界'
Assert-Contains $firstlegIndex '以 `firstleg/` 服务目录起算' 'Firstleg 详细索引路径起点'
Assert-Contains $adminEntry 'docs/business-index.md' 'Admin 按需索引入口'
Assert-Contains $clientEntry 'docs/business-index.md' 'Client 按需索引入口'
Assert-Contains $overseasPdaEntry 'docs/business-index.md' '海外 PDA 按需索引入口'
foreach ($applicationDetailIndex in @(
@{ Name = 'Admin'; Text = $adminIndex; Base = 'apps/admin-web' },
@{ Name = 'Client'; Text = $clientIndex; Base = 'apps/client-web' },
@{ Name = '海外 PDA'; Text = $overseasPdaIndex; Base = 'apps/pda-overseas-uniapp' }
)) {
Assert-Matches $applicationDetailIndex.Text '\[[^\]]+\]\(\.\./AGENTS\.md\)' "$($applicationDetailIndex.Name) 详细索引链接应用主指引"
Assert-Path "$($applicationDetailIndex.Base)/docs/../AGENTS.md"
}
Assert-MarkdownTableUnique $adminAgentsPath '## 模块快速路由' 0 'Admin 短入口表'
Assert-TableRowWidth $rootAgentsPath '## 业务快速路由表' 260 '根业务快速路由表'
Assert-TableRowWidth $rootAgentsPath '## 项目快速入口' 260 '根项目快速入口'
Assert-TableRowWidth $rootAgentsPath '## 专项约束按需入口' 200 '根专项约束表'
Assert-TableRowWidth $adminAgentsPath '## 模块快速路由' 200 'Admin 短入口表'
Assert-TableRowWidth $clientAgentsPath '## 模块快速查询' 160 'Client 短入口表'
Assert-TableRowWidth $backendAgentsPath '## 服务路由(按关键词定位)' 160 '后端根服务路由表'
Assert-TableRowWidth $overseasPdaAgentsPath '## 页面与能力快速索引' 200 '海外 PDA 入口表'
2026-10-19 17:56:36 +08:00
Assert-MarkdownTableUnique $adminIndexPath '## 模块快速路由' 0 'Admin 详细索引表'
Assert-MarkdownTableUnique $clientAgentsPath '## 模块快速查询' 0 'Client 短入口表'
Assert-MarkdownTableUnique $clientIndexPath '## 模块快速查询' 0 'Client 详细索引表'
Assert-MarkdownTableUnique $overseasPdaAgentsPath '## 页面与能力快速索引' 0 '海外 PDA 短入口表'
Assert-MarkdownTableUnique $overseasPdaIndexPath '## 页面与能力快速索引' 0 '海外 PDA 详细索引表'
foreach ($readingBoundary in @($adminEntry, $clientEntry, $overseasPdaEntry)) {
Assert-Contains $readingBoundary '涉及业务行为变更时必须核对对应细则' '终端业务细则读取边界'
}
2026-09-18 18:02:27 +08:00
foreach ($budget in @(
@{ Name = '后端根'; Text = $backendAgents; Limit = 13000 },
2026-10-19 17:56:36 +08:00
@{ Name = 'Firstleg'; Text = $firstlegEntry; Limit = 8000 },
@{ Name = 'Lastleg'; Text = $lastlegEntry; Limit = 9000 },
@{ Name = 'Admin'; Text = $adminEntry; Limit = 8000 },
@{ Name = 'Client'; Text = $clientEntry; Limit = 8000 },
@{ Name = '海外 PDA'; Text = $overseasPdaEntry; Limit = 8000 }
2026-09-18 18:02:27 +08:00
)) {
$script:checked++
2026-10-19 17:56:36 +08:00
$normalizedLength = ($budget.Text -replace "`r`n", "`n").Length
if ($normalizedLength -gt $budget.Limit) { Add-Failure "$($budget.Name) 指引超出字符预算 $($budget.Limit),请将细节按需下沉" }
2026-09-18 18:02:27 +08:00
}
Assert-MarkdownTableUnique $backendIndexPath '## 服务路由(按关键词定位)' 0 '后端详细索引'
Assert-MarkdownTableUnique $lastlegIndexPath '## 快速索引' 0 'Lastleg 详细索引'
2026-10-19 17:56:36 +08:00
Assert-MarkdownTableUnique $firstlegEntryPath '## 模块入口' 0 'Firstleg 首个代码入口'
Assert-MarkdownTableUnique $firstlegIndexPath '## 模块入口' 0 'Firstleg 详细索引'
2026-09-18 18:02:27 +08:00
# 保留全部业务语义断言,只将事实读取范围扩展到明确链接的按需文档。
$backendAgents += "`n" + $backendIndex
2026-09-12 18:34:23 +08:00
# 固定样本只检查目标索引行和真实文件,不递归搜索;字符数是读取量指标,不是耗时或 Token 实测。
$lookupSamples = @(
2026-10-19 17:56:36 +08:00
@{ Key = '客户专属价格簿'; Text = $adminEntry; Entry = 'modules/fba-pricing/carrier-rates/pages/CarrierRateDetailView.vue'; Base = 'apps/admin-web/src' },
@{ Key = '入库扣货、解除与凭证历史'; Text = $adminEntry; Entry = 'modules/unified-orders/pages/UnifiedOrdersView.vue'; Base = 'apps/admin-web/src' },
@{ Key = '国内/海外 PDA 独立人员'; Text = $adminEntry; Entry = 'modules/iam/pages/InternalUsersView.vue'; Base = 'apps/admin-web/src' },
2026-09-12 18:34:23 +08:00
@{ Key = '尾程订单控制'; Text = $adminOverseasAgents; Entry = 'pages/LastMileOrdersView.vue'; Base = 'apps/admin-web/src/modules/overseas-warehouse' },
@{ Key = '排车查询'; Text = $adminOverseasAgents; Entry = 'pages/DispatchesView.vue'; Base = 'apps/admin-web/src/modules/overseas-warehouse' },
@{ Key = '海外出库与派送'; Text = $adminOverseasAgents; Entry = 'pages/OutboundsView.vue'; Base = 'apps/admin-web/src/modules/overseas-warehouse' },
@{ Key = '异常退回与客户回访'; Text = $adminOverseasAgents; Entry = 'pages/ExceptionOrdersView.vue'; Base = 'apps/admin-web/src/modules/overseas-warehouse' },
@{ Key = '库存余额'; Text = $adminOverseasAgents; Entry = 'pages/InventoryView.vue'; Base = 'apps/admin-web/src/modules/overseas-warehouse' },
2026-10-19 17:56:36 +08:00
@{ Key = '退货入库签收与合箱'; Text = $overseasPdaEntry; Entry = 'src/pages/return-receipt/return-receipt.vue'; Base = 'apps/pda-overseas-uniapp' },
@{ Key = '退货入库签收与合箱'; Text = $overseasPdaEntry; Entry = 'src/pages/return-packing/return-packing.vue'; Base = 'apps/pda-overseas-uniapp' }
2026-09-12 18:34:23 +08:00
)
$lookupCharacters = 0
2026-09-18 18:02:27 +08:00
foreach ($alias in @(
@{ Term = '转运打托'; Entry = 'apps/pda-overseas-uniapp/src/pages/warehouse-transfer/warehouse-transfer.vue' },
2026-10-21 17:22:19 +08:00
@{ Term = '转运通过'; Entry = 'apps/admin-web/src/modules/overseas-warehouse/components/WarehouseTransferReviewDialog.vue' },
@{ Term = '转运驳回'; Entry = 'apps/admin-web/src/modules/overseas-warehouse/api/warehouseTransfers.ts' },
2026-09-23 18:26:04 +08:00
@{ Term = '退税资料'; Entry = 'apps/client-web/src/modules/first-leg/components/CustomsDocumentsDialog.vue' },
@{ Term = '订单审核'; Entry = 'apps/admin-web/src/modules/unified-orders/' },
@{ Term = 'PDA 出库'; Entry = 'apps/pda-overseas-uniapp/src/pages/dispatch/dispatch.vue' },
@{ Term = '客户账单'; Entry = 'apps/client-web/src/modules/finance/views/FinanceBillsView.vue' }
2026-09-18 18:02:27 +08:00
)) {
$aliasSection = (($businessIndex -split '## 常用说法与歧义分流', 2)[1] -split '\r?\n## ', 2)[0]
2026-09-23 18:26:04 +08:00
$allHits = @($aliasSection -split '\r?\n' | Where-Object { $_.Contains($alias.Term) })
$rowHits = @($allHits | Where-Object { $_.TrimStart().StartsWith('|') })
$hits = @($rowHits)
if ($hits.Count -eq 0) { $hits = @($allHits) }
2026-09-18 18:02:27 +08:00
$script:checked++
if ($hits.Count -ne 1) { Add-Failure "口语入口必须唯一命中: $($alias.Term)"; continue }
Assert-Contains $hits[0] $alias.Entry "口语入口 $($alias.Term)"
Assert-Path $alias.Entry
}
2026-09-12 18:34:23 +08:00
foreach ($sample in $lookupSamples) {
$hits = @($sample.Text -split '\r?\n' | Where-Object { $_.StartsWith('| ' + $sample.Key) })
$script:checked++
if ($hits.Count -ne 1) {
Add-Failure "检索样本必须唯一命中: $($sample.Key),实际 $($hits.Count) 行"
continue
}
Assert-Contains $hits[0] $sample.Entry "检索样本 $($sample.Key)"
Assert-Path ($sample.Base + '/' + $sample.Entry)
$lookupCharacters += $hits[0].Length
}
Write-Host "定向检索样本:$($lookupSamples.Count) 项,命中行共 $lookupCharacters 字符(不含上层指引读取量,非端到端性能测量)。"
2026-09-01 11:02:10 +08:00
$scriptsAgents = Read-RequiredText (Join-Path $backendRoot 'scripts/AGENTS.md')
2026-08-26 14:08:41 +08:00
$engineeringConstraints = Read-RequiredText (Join-Path $workspaceRoot 'docs/AI工程执行与协作约束.md')
2026-09-01 14:46:44 +08:00
$docsIndex = Read-RequiredText (Join-Path $workspaceRoot 'docs/README.md')
2026-10-21 16:40:18 +08:00
# 只检查明确列出的当前入口和迁移正文,不递归扫描历史资料。
$overseasDocEntryPath = Join-Path $workspaceRoot 'docs/海外仓业务/README.md'
$overseasDocEntry = Read-RequiredText $overseasDocEntryPath
$overseasDocRulesPath = Join-Path $workspaceRoot 'docs/海外仓业务/业务规则.md'
$overseasDocRules = Read-RequiredText $overseasDocRulesPath
$financeDocEntryPath = Join-Path $workspaceRoot 'docs/财务管理/README.md'
$financeDocEntry = Read-RequiredText $financeDocEntryPath
$financeP1Path = Join-Path $workspaceRoot 'docs/财务管理/财务对账结算P1闭环.md'
$financeP1 = Read-RequiredText $financeP1Path
foreach ($document in @(
@{ Name = '业务导航'; Path = $businessIndexPath; Text = $businessIndex; Limit = 12500 },
@{ Name = '文档总入口'; Path = (Join-Path $workspaceRoot 'docs/README.md'); Text = $docsIndex; Limit = 3500 },
@{ Name = '海外仓文档入口'; Path = $overseasDocEntryPath; Text = $overseasDocEntry; Limit = 2000 },
2026-10-21 17:22:19 +08:00
@{ Name = '财务文档入口'; Path = $financeDocEntryPath; Text = $financeDocEntry; Limit = 1800 },
@{ Name = 'Admin 海外仓指引'; Path = $adminOverseasAgentsPath; Text = $adminOverseasAgents; Limit = 8000 }
2026-10-21 16:40:18 +08:00
)) {
Assert-MarkdownLinks $document.Path $document.Text $document.Name
$checked++
if (($document.Text -replace "`r`n", "`n").Length -gt $document.Limit) {
Add-Failure "$($document.Name) 超出入口预算 $($document.Limit),请将正文归回主题主文档"
}
}
foreach ($document in @(
@{ Name = '跨端实现边界'; Path = $businessRulesPath; Text = $businessRules },
@{ Name = '海外仓业务正文'; Path = $overseasDocRulesPath; Text = $overseasDocRules },
@{ Name = '财务当前闭环'; Path = $financeP1Path; Text = $financeP1 }
)) { Assert-MarkdownLinks $document.Path $document.Text $document.Name }
Assert-TableRowWidth $businessIndexPath '## 业务快速路由表' 260 '详细业务导航表'
$businessRouteSection = (($businessIndex -split '(?m)^## 业务快速路由表\r?$', 2)[1] -split '(?m)^## ', 2)[0]
2026-10-21 16:58:30 +08:00
# 同一规则可供多个终端入口复用;校验实际正文链接,不要求路由名称复制正文标题。
$businessRuleSections = [regex]::Matches($businessRules, '(?ms)^## (?<name>[^\r\n]+)\r?\n(?<body>.*?)(?=^## |\z)')
foreach ($topic in $businessRuleSections) {
$name = $topic.Groups['name'].Value
$slug = [regex]::Replace($name.Trim().ToLowerInvariant(), '[^\p{L}\p{M}\p{N}_\s-]', '') -replace '\s+', '-'
$target = '业务实现边界.md#' + $slug
$hasRoute = $businessRouteSection.Contains('](' + $target + ')')
if (-not $hasRoute) {
# 已有正式正文时允许索引直接跳转,避免为覆盖率强加一层摘要。
$sourceLine = [regex]::Match($topic.Groups['body'].Value, '(?m)^范围依据:[^\r\n]+')
$sourceLink = [regex]::Match($sourceLine.Value, '\[[^\]]+\]\((?<target>[^)]+)\)')
$hasRoute = $sourceLink.Success -and $businessRouteSection.Contains('](' + $sourceLink.Groups['target'].Value + ')')
}
2026-10-21 16:40:18 +08:00
$checked++
2026-10-21 16:58:30 +08:00
if (-not $hasRoute) { Add-Failure "业务正文或其正式依据缺少导航入口:$name" }
2026-10-21 16:40:18 +08:00
}
Assert-Contains $rootAgents '备选导航' '索引不是串行读取清单'
Assert-Contains $rootAgents '命中正文即停止扩展' '正文命中后的读取停止条件'
Assert-Contains $financeDocEntry '财务对账结算P1闭环.md#客户资金账户' '当前资金账户正文入口'
Assert-NotContains $financeDocEntry '钱包不做' '财务入口不混入历史排除范围'
Assert-Contains $financeP1 '首批固定为 CNY' '资金账户币种规则迁入现行正文'
Assert-Contains $financeP1 '充值先归还已用授信或负余额' '资金账户充值规则迁入现行正文'
Assert-Contains $financeP1 '新账户默认授信为 `0.00`' '资金账户默认授信规则迁入现行正文'
2026-10-21 17:22:19 +08:00
# 入口存在不足以证明动作存在:核对弹框实际调用与 API 结论,避免将接口能力当成按钮。
$transferReviewUi = Read-RequiredText (Join-Path $workspaceRoot 'apps/admin-web/src/modules/overseas-warehouse/components/WarehouseTransferReviewDialog.vue')
$transferReviewApi = Read-RequiredText (Join-Path $workspaceRoot 'apps/admin-web/src/modules/overseas-warehouse/api/warehouseTransfers.ts')
$transferUiRow = @($adminOverseasAgents -split '\r?\n' | Where-Object { $_.StartsWith('| 仓储转运审核、审核通过 |') })
$transferApiRow = @($adminOverseasAgents -split '\r?\n' | Where-Object { $_.StartsWith('| 转运驳回、REJECT 接口能力 |') })
$checked++
if ($transferUiRow.Count -ne 1 -or $transferApiRow.Count -ne 1) {
Add-Failure '转运审核的界面入口与 API 能力必须分别定位'
} else {
Assert-Contains $transferUiRow[0] 'components/WarehouseTransferReviewDialog.vue' '转运通过界面入口'
Assert-Contains $transferUiRow[0] 'APPROVE' '转运通过界面结论'
Assert-Contains $transferApiRow[0] 'api/warehouseTransfers.ts' '转运驳回 API 入口'
Assert-Contains $transferApiRow[0] 'REJECT' '转运 API 驳回结论'
Assert-Matches $transferReviewUi 'reviewWarehouseTransfer\([^)]*,\s*[''"]APPROVE[''"](?:\s*,[^)]*)?\s*\)' '转运通过真实调用'
Assert-Matches $transferReviewApi 'decision\s*:\s*[''"]APPROVE[''"]\s*\|\s*[''"]REJECT[''"]' '转运 API 允许的结论'
if ($transferReviewUi -match 'reviewWarehouseTransfer\([^)]*,\s*[''"]REJECT[''"]') {
Assert-NotContains $transferUiRow[0] '无驳回按钮' '转运界面能力变化后更新指引'
Assert-Contains $transferUiRow[0] 'REJECT' '转运界面新增驳回后更新指引'
} else {
Assert-Contains $transferUiRow[0] '无驳回按钮' '转运界面不能虚构驳回动作'
Assert-NotContains $transferUiRow[0] 'REJECT' '转运界面与 API 能力分开'
}
}
Assert-Contains $adminOverseasAgents 'baiyue-firstleg/print/AGENTS.md' '托盘模板指向 Print 权威入口'
Assert-NotContains $adminOverseasAgents 'INBOUND_MARK_V1' 'Admin 不复制箱唛模板为托盘模板'
$adminOverseasVerification = [regex]::Match($adminOverseasAgents, '(?ms)^## 验证\r?\n(?<body>.*?)(?=^## |\z)').Groups['body'].Value
$checked++
if (-not $adminOverseasVerification -or ($adminOverseasVerification -replace '\r', '').Length -gt 800) {
Add-Failure 'Admin 海外仓验证节须存在且不超过800字符,业务正文应归回按需条款'
}
2026-10-21 16:40:18 +08:00
$docLookupCharacters = 0
2026-10-21 16:58:30 +08:00
$walletRuleTarget = '财务管理/财务对账结算P1闭环.md#客户资金账户'
2026-10-21 16:40:18 +08:00
$docLookupSamples = @(
2026-10-21 16:58:30 +08:00
@{ Key = '客户头程订单批量导入'; Text = $businessIndex; Column = 1; Entry = 'apps/client-web/src/modules/first-leg/AGENTS.md' },
2026-10-21 17:22:19 +08:00
@{ Key = '仓储转运审核、转运通过'; Text = $businessIndex; Column = 2; Entry = 'apps/admin-web/src/modules/overseas-warehouse/components/WarehouseTransferReviewDialog.vue' },
@{ Key = '转运驳回、REJECT'; Text = $businessIndex; Column = 2; Entry = 'apps/admin-web/src/modules/overseas-warehouse/api/warehouseTransfers.ts' },
2026-10-21 16:58:30 +08:00
@{ Key = '平台资金账户、充值审核、手工充扣与授信'; Text = $businessIndex; Column = 1; Entry = 'apps/admin-web/src/modules/finance/AGENTS.md'; Rules = $walletRuleTarget },
@{ Key = '客户资金账户、余额、授信与充值申请'; Text = $businessIndex; Column = 1; Entry = 'apps/client-web/src/modules/finance/AGENTS.md'; Rules = $walletRuleTarget },
@{ Key = '服务端资金账户、授信、冻结、结算与业务扣费'; Text = $businessIndex; Column = 1; Entry = 'baiyue-firstleg/finance/AGENTS.md'; Rules = $walletRuleTarget },
@{ Key = '海外仓库主档、名称、地址与能力'; Text = $businessIndex; Column = 1; Entry = 'apps/admin-web/src/modules/warehouses/AGENTS.md'; Rules = '业务实现边界.md#海外仓库与通用资料' },
@{ Key = '海外仓库主档、名称、地址与能力'; Text = $businessIndex; Column = 1; Entry = 'baiyue-firstleg/warehouse/AGENTS.md'; Rules = '业务实现边界.md#海外仓库与通用资料' },
@{ Key = '海外库位、托盘与资源锁'; Text = $businessIndex; Column = 1; Entry = 'baiyue-firstleg/warehouse-overseas-service/AGENTS.md'; Rules = '业务实现边界.md#海外仓库与通用资料' },
@{ Key = '客户统计与运营指标'; Text = $businessIndex; Column = 1; Entry = 'apps/admin-web/src/modules/customers/AGENTS.md' },
@{ Key = '平台日志、操作日志、审计日志与操作人缺失'; Text = $businessIndex; Column = 1; Entry = 'apps/admin-web/src/modules/audit/AGENTS.md' },
@{ Key = '客户账单、客户对账单、账单确认'; Text = $businessIndex; Column = 2; Entry = 'apps/client-web/src/modules/finance/views/FinanceBillsView.vue' },
@{ Key = '客户资金账户、充值、授信、冻结与业务扣费'; Text = $financeDocEntry; Column = 1; Entry = '财务对账结算P1闭环.md#客户资金账户' },
@{ Key = '海外排车、出库与派送改造'; Text = $overseasDocEntry; Column = 1; Entry = '排车列表统一作业改造契约.md' },
@{ Key = '本土卡车与散板表单'; Text = $overseasDocEntry; Column = 1; Entry = '业务规则.md#本土散板简化下单' }
2026-10-21 16:40:18 +08:00
)
foreach ($sample in $docLookupSamples) {
$hits = @($sample.Text -split '\r?\n' | Where-Object { $_.StartsWith('| ' + $sample.Key + ' |') })
$checked++
if ($hits.Count -ne 1) { Add-Failure "文档路由样本必须唯一命中:$($sample.Key)"; continue }
2026-10-21 16:58:30 +08:00
# 代码入口与规则正文分别核对,不能靠其他列碰巧包含目标路径通过。
$cells = @($hits[0].Trim('|').Split('|') | ForEach-Object { $_.Trim() })
if ($sample.Column -ge $cells.Count) { Add-Failure "文档路由样本缺少目标列:$($sample.Key)"; continue }
Assert-Contains $cells[$sample.Column] $sample.Entry "文档路由样本 $($sample.Key)"
if ($sample.Rules) {
if ($cells.Count -lt 3) { Add-Failure "文档路由样本缺少规则正文:$($sample.Key)"; continue }
Assert-Contains $cells[2] $sample.Rules "文档正文样本 $($sample.Key)"
}
2026-10-21 16:40:18 +08:00
$docLookupCharacters += $hits[0].Length
}
Write-Host "文档路由样本:$($docLookupSamples.Count) 项,命中行共 $docLookupCharacters 字符(不含上层指引或按需正文,不代表端到端耗时)。"
2026-09-01 14:46:44 +08:00
$testTaskRegistry = Read-RequiredText (Join-Path $workspaceRoot 'docs/独立任务协作登记.md')
$devTaskRegistry = Read-RequiredText (Join-Path $workspaceRoot 'docs/开发环境独立任务协作登记.md')
2026-08-28 23:01:52 +08:00
$mapperScanContract = Read-RequiredText (Join-Path $backendRoot 'scripts/mapper-scan-contract.mjs')
2026-08-26 14:08:41 +08:00
# 当前未上线阶段的无兼容原则必须覆盖全部实现与运行状态,不能再次缩窄为文件或数据库专项规则。
Assert-Contains $rootAgents '源码结构、接口与 DTO、字段、状态机、权限、配置键、数据库结构与初始化 SQL、事件、路由、页面、Mock/Fixture、测试和脚本' '根无兼容收敛范围'
Assert-Contains $rootAgents '数据库记录、上传文件、缓存、会话、消息、搜索索引和其他运行状态均视为可丢弃' '根开发运行状态范围'
2026-08-28 23:01:52 +08:00
Assert-Contains $rootAgents '后端 MyBatis Mapper 新增、移动或扫描遗漏' '根 Mapper 快速入口'
Assert-Contains $rootAgents 'node scripts/mapper-scan-contract.mjs' '根 Mapper 静态门禁'
2026-10-21 16:40:18 +08:00
Assert-Contains $businessFacts '脚本管理、全量验证与测试造数' '根脚本管理快速入口'
2026-09-01 11:02:10 +08:00
Assert-Contains $rootAgents 'baiyue-firstleg/scripts/AGENTS.md' '根脚本最近指引'
2026-08-26 14:08:41 +08:00
Assert-Contains $engineeringConstraints '禁止为旧代码、旧调用或开发环境存量保留旧接口/旧字段别名' '工程无兼容执行规则'
Assert-Contains $engineeringConstraints '不授权自动重置数据库、删除数据/文件、执行 SQL、部署或修改环境' '无兼容安全边界'
2026-08-26 15:58:54 +08:00
Assert-Contains $clientAgents '不得继续扩展 `LEGACY_MANUAL`、旧系统入仓码、C02 不可用回退旧 API' 'Client 头程无兼容边界'
2026-08-28 23:01:52 +08:00
Assert-Contains $backendAgents '所有生产 MyBatis Mapper 接口必须显式标记 `@Mapper`' '后端 Mapper 注册规则'
Assert-Contains $backendAgents 'Mapper 新增、移动、Bean 缺失与扫描遗漏' '后端 Mapper 快速路由'
2026-09-01 11:02:10 +08:00
Assert-Contains $backendAgents '脚本管理、全量验证、测试造数与诊断' '后端脚本管理快速路由'
Assert-Contains $backendAgents 'scripts/it-test-wait-split-bulk.mjs' '后端批量待分柜造数入口'
Assert-Contains $backendAgents 'scripts/create-pending-review-orders.mjs' '后端待审核订单造数入口'
2026-09-04 15:55:43 +08:00
Assert-Contains $backendAgents 'scripts/client-quick-order-test-env-acceptance.mjs' '后端 Client 快速下单入口'
Assert-Contains $backendAgents 'service-center-flow' '后端服务中心验收模块'
2026-09-01 11:02:10 +08:00
Assert-Contains $scriptsAgents 'admin-test-env-acceptance.mjs' '脚本指引 Admin 全量入口'
Assert-Contains $scriptsAgents 'client-test-env-acceptance.mjs' '脚本指引 Client 全量入口'
2026-09-01 14:46:44 +08:00
# 开发与测试独立任务必须按保存项目、cwd 和登记表完全隔离,task_id 不得跨表复用。
Assert-Contains $rootAgents 'docs/开发环境独立任务协作登记.md' '根开发协作登记入口'
Assert-Contains $rootAgents 'docs/独立任务协作登记.md' '根测试协作登记入口'
Assert-Contains $engineeringConstraints '不得同时加载两表后混合选取任务' '工程协作登记选择门禁'
Assert-Contains $docsIndex '[测试环境独立任务协作登记](独立任务协作登记.md)' '文档测试登记入口'
Assert-Contains $docsIndex '[开发环境独立任务协作登记](开发环境独立任务协作登记.md)' '文档开发登记入口'
# BEGIN CURRENT TEST REGISTRY CONTRACT
function Assert-TestTaskRegistry([string]$registry) {
2026-10-14 00:07:12 +08:00
# Count this authorized group only; newer independently authorized groups must not be mixed into it.
$current = [regex]::Match($registry, '(?ms)^## 2026-10-04 用户确认的三个独立执行对话(当前派工)\r?\n.*?(?=^## |\z)').Value
Assert-Contains $current '## 2026-10-04 用户确认的三个独立执行对话(当前派工)' '当前全流程协作入口'
Assert-Contains $current '用户明确选择“按这 3 个独立对话创建”' '测试任务精确数量授权'
Assert-Contains $current '所属唯一总控仍为 `退税报关` / `01a0d0da-130f-7d43-97b5-9c76abc1b5f1`' '测试所属总控'
Assert-Contains $current '`c64729ff-6710-43c6-8ef2-d84e9666cc1e`' '测试保存项目'
Assert-Contains $current '`C:/Users/BY-OY/Desktop/code/chongchong-global`' '测试工作目录'
Assert-Contains $current 'host `local` 与 cwd' '测试授权环境边界'
Assert-Contains $current '旧对话保持原状态,不恢复或唤醒' '测试任务禁止历史恢复'
$expectedIds = @('01a10686-c55c-75a3-9639-655b50cbce6c','01a10686-cae9-7943-b976-27e78ad92723','01a10686-cfdd-7f50-8500-7704e6fbc768')
$actualIds = @([regex]::Matches($current, '(?m)^\|\s*`([0-9a-f-]{36})`\s*\|') | ForEach-Object { $_.Groups[1].Value })
$script:checked++
if ($actualIds.Count -ne 3 -or @($actualIds | Select-Object -Unique).Count -ne 3 -or
@($expectedIds | Where-Object { $actualIds -notcontains $_ }).Count -gt 0) {
Add-Failure '测试当前登记必须恰为三个已授权独立任务,归属于唯一全流程总控'
}
Assert-NotContains $registry '当前无登记任务' '测试登记不得混入过期清空状态'
Assert-NotContains $registry '01a0194a-259c-7171-8967-074731a27618' '测试登记历史总控'
Assert-NotContains $registry '01a06c0b-0515-7c60-b329-77342b54e666' '测试登记开发总控'
Assert-NotContains $registry '6f874ec3-d3b2-49bd-8625-327f4d685f98' '测试登记开发项目'
}
# END CURRENT TEST REGISTRY CONTRACT
Assert-TestTaskRegistry $testTaskRegistry
2026-09-01 14:46:44 +08:00
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`' '开发环境全流程总控'
2026-09-01 14:46:44 +08:00
Assert-NotContains $devTaskRegistry '01a0194a-259c-7171-8967-074731a27618' '开发登记测试总控'
Assert-NotContains $devTaskRegistry 'c64729ff-6710-43c6-8ef2-d84e9666cc1e' '开发登记测试 projectId'
2026-09-07 15:07:34 +08:00
# 业务文档已由开发批次目录收敛为稳定业务域,根快速路由不得继续引用已删除阶段目录。
foreach ($businessDocsEntry in @(
'docs/订单与客户/README.md',
'docs/入库测量与计费/README.md',
'docs/国内货柜履约/README.md',
'docs/海外仓业务/README.md'
)) {
2026-10-21 16:40:18 +08:00
Assert-Contains $businessFacts $businessDocsEntry "根业务域入口 $businessDocsEntry"
2026-09-07 15:07:34 +08:00
}
foreach ($removedPhaseDocsEntry in @('docs/一期/', 'docs/二期/', 'docs/三期/', 'docs/四期/')) {
Assert-NotContains $rootAgents $removedPhaseDocsEntry "根已删除阶段目录 $removedPhaseDocsEntry"
}
Assert-NotContains $rootAgents '不含出库和派送' '根海外仓全流程范围'
# 新增稳定业务能力必须从根表和目标部署单元直接命中。
2026-10-21 16:40:18 +08:00
Assert-Contains $businessFacts '入库扣货、解除与凭证' '根入库扣货路由'
2026-09-07 15:07:34 +08:00
Assert-Contains $adminAgents '入库扣货、解除与凭证历史' 'Admin 入库扣货路由'
Assert-Contains $backendAgents '入库单扣货、解除、凭证与履约门禁' '后端入库扣货路由'
2026-10-21 16:40:18 +08:00
Assert-Contains $businessFacts '客户资金账户、充值、授信与业务扣费' '根客户资金账户路由'
2026-09-07 15:07:34 +08:00
Assert-Contains $adminAgents '客户资金账户与柜级公共费用分摊' 'Admin 客户资金账户路由'
Assert-Contains $clientAgents '客户资金账户、授信与充值申请' 'Client 客户资金账户路由'
Assert-Contains $backendAgents '客户资金账户、充值、授信、冻结、结算与跨区资金指令' '后端客户资金账户路由'
2026-10-21 16:40:18 +08:00
Assert-Contains $businessFacts '顶层授权快照' '根海外顶层授权快照'
2026-09-07 15:07:34 +08:00
Assert-Contains $backendAgents '顶层授权快照' '后端海外顶层授权快照'
2026-10-21 16:40:18 +08:00
Assert-Contains $businessFacts '目的港码头拖车与还空预警' '根目的港码头拖车路由'
Assert-Contains $businessFacts '与订舱级拖车预约是不同生命周期' '根两类拖车边界'
Assert-Contains $businessFacts '尾程订单控制与柜级入仓计划转换' '根尾程订单控制路由'
2026-09-08 14:07:31 +08:00
Assert-Contains $adminAgents '目的港码头拖车与还空预警' 'Admin 目的港码头拖车路由'
Assert-Contains $adminAgents '尾程订单控制与柜级入仓计划转换' 'Admin 尾程订单控制路由'
Assert-Contains $backendAgents '目的港码头拖车与还空预警' '后端目的港码头拖车路由'
2026-09-09 09:52:46 +08:00
Assert-Contains $backendAgents '尾程订单控制、柜级预览与入仓计划转换' '后端尾程订单控制路由'
2026-09-01 14:46:44 +08:00
$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"
}
2026-09-04 15:55:43 +08:00
Assert-Contains $scriptsAgents 'client-quick-order-test-env-acceptance.mjs' '脚本指引 Client 快速下单入口'
Assert-Contains $scriptsAgents 'admin-test-env-modules/service-center-flow.mjs' '脚本指引服务中心验收模块'
2026-09-08 14:07:31 +08:00
Assert-Contains $scriptsAgents 'admin-test-env-modules/phase4-tail-order-controls.mjs' '脚本指引尾程单控制模块'
Assert-Contains $scriptsAgents 'admin-test-env-modules/phase5-terminal-drayage.mjs' '脚本指引目的港码头拖车模块'
2026-09-01 11:02:10 +08:00
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'
2026-08-28 23:01:52 +08:00
Assert-Contains $mapperScanContract 'annotationClass = Mapper.class' 'Mapper 根包注解过滤合同'
Assert-Contains $mapperScanContract '禁止分散维护 MapperScan' 'Mapper 单一扫描入口合同'
2026-10-19 17:56:36 +08:00
$firstlegAgents = $firstlegEntry + "`n" + $firstlegIndex
2026-09-18 18:02:27 +08:00
$lastlegAgents = $lastlegEntry + "`n" + $lastlegIndex
2026-09-01 11:02:10 +08:00
$warehouseAgents = Read-RequiredText (Join-Path $backendRoot 'warehouse/AGENTS.md')
2026-08-30 17:02:19 +08:00
$coloadOpenApi = Read-RequiredText (Join-Path $backendRoot 'firstleg/src/main/resources/openapi/coload-groups-v1.yaml')
2026-10-21 16:40:18 +08:00
Assert-Contains $businessFacts 'modules/unified-orders/api/coLoadGroups.ts' '根同柜不可拆组入口'
2026-08-30 17:02:19 +08:00
Assert-Contains $adminAgents '成员数是入仓片段数,不等于订单票数' 'Admin 同柜成员语义'
Assert-Contains $backendAgents 'loading/coload/controller/PlatformColoadGroupController.java' '后端同柜不可拆组入口'
2026-09-20 14:43:26 +08:00
Assert-Contains $firstlegAgents '服务端允许待审核、待测量/测量中、待分柜及装柜中订单' 'Firstleg 同柜建组边界'
2026-09-01 11:02:10 +08:00
Assert-Contains $warehouseAgents 'scripts/warehouse-public-master-data-contract.test.mjs' 'Warehouse 局部脚本入口'
2026-08-30 17:02:19 +08:00
Assert-Contains $coloadOpenApi '允许跨客户及不同目的仓港成组,仅要求国内仓和渠道一致' '同柜资格 OpenAPI'
2026-09-20 14:43:26 +08:00
Assert-Contains $coloadOpenApi '待分柜或装柜中的全部有效入仓片段' '同柜订单展开 OpenAPI'
2026-08-31 18:55:03 +08:00
Assert-Contains $rootAgents '用户可见页面、提示和错误不得展示或以内部数据库 ID 作为业务编号回退' '根业务编号展示边界'
Assert-Contains $adminAgents '/loading-plans/{planId}/lifecycle' 'Admin 装柜清单生命周期入口'
Assert-Contains $adminAgents '合柜报关 / 同柜不可拆组' 'Admin 合柜报关别名入口'
Assert-Contains $clientAgents 'api/inboundCodeAssociations.ts' 'Client 入仓码业务关系入口'
2026-09-01 14:27:16 +08:00
Assert-Contains $pdaAgents 'tests/page-contract.test.mjs' '国内 PDA 页面合同入口'
2026-08-31 18:55:03 +08:00
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 装柜生命周期入口'
2026-09-08 14:07:31 +08:00
Assert-Contains $lastlegAgents 'LastlegOrderCommandService.java' 'Lastleg 尾程订单命令入口'
Assert-Contains $lastlegAgents '固定八行完整快照' 'Lastleg 人工节点快照边界'
Assert-Contains $lastlegAgents '/api/platform/v1/last-leg/inbound-plans/convert-container' 'Lastleg 整柜转换正式入口'
2026-09-02 11:59:54 +08:00
2026-09-03 18:05:34 +08:00
# 本轮新增的批量下单、测量计费、智能装柜、账单联查与导出重试必须从最近指引直达。
$fileAgents = Read-RequiredText (Join-Path $backendRoot 'file/AGENTS.md')
$financeAgents = Read-RequiredText (Join-Path $backendRoot 'finance/AGENTS.md')
2026-10-21 16:40:18 +08:00
Assert-Contains $businessFacts '客户头程订单批量导入' '根批量下单快速路由'
2026-09-03 18:05:34 +08:00
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 箱规计费入口'
2026-09-04 10:51:25 +08:00
Assert-Contains $backendAgents '全局智能装柜候选、柜次、占位与移除' '后端全局智能装柜路由'
Assert-Contains $firstlegAgents '必须成员完整、满箱并作为单个分页与分配单元' 'Firstleg 智能装柜组分页边界'
2026-09-03 18:05:34 +08:00
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'
2026-09-02 11:59:54 +08:00
# 平台修改客户原始申报必须能从各层索引直达,并锁住 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')
2026-09-02 15:15:41 +08:00
$unifiedOrderQueryService = Read-RequiredText (Join-Path $backendRoot 'order/src/main/java/com/baiyue/order/service/UnifiedOrderQueryService.java')
2026-09-02 11:59:54 +08:00
$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')
2026-10-21 16:40:18 +08:00
Assert-Contains $businessFacts '平台修改客户原始申报与履约渠道' '根订单申报快速路由'
2026-09-02 11:59:54 +08:00
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 申报事实边界提示'
2026-10-21 16:40:18 +08:00
Assert-Contains $businessFacts '统一列表仍固定显示 `PENDING_REVIEW` 并提供审核动作' '根待审核订单优先状态'
2026-09-02 15:15:41 +08:00
Assert-Contains $orderAgents '统一主状态/下一动作仍固定为 `PENDING_REVIEW/APPROVE_ORDER`' 'Order 待审核优先状态'
Assert-Contains $unifiedOrderQueryService 'order.getStatus() == OrderStatus.SUBMITTED' 'Order 待审核状态判断'
2026-09-15 16:10:55 +08:00
Assert-Contains $unifiedOrderQueryService 'pendingReview ? "PENDING_REVIEW" : completed ? "COMPLETED" : summary.mainStatus()' 'Order 待审核主状态优先于完成态与履约投影'
Assert-Contains $unifiedOrderQueryService 'pendingReview ? "APPROVE_ORDER" : completed ? null : summary.nextAction()' 'Order 待审核动作优先且完成态无下一动作'
2026-09-02 11:59:54 +08:00
2026-09-09 09:52:46 +08:00
# 批量审核、客户专属价格簿和柜级阶梯计价已经成为稳定跨端能力,必须从根表直达且锁住服务端权威规则。
$batchReviewPreviewService = Read-RequiredText (Join-Path $backendRoot 'order/src/main/java/com/baiyue/order/service/BatchOrderReviewPreviewService.java')
$fbaPricingOpenApi = Read-RequiredText (Join-Path $backendRoot 'firstleg/src/main/resources/openapi/fba-pricing-v1.yaml')
$fbaPricingService = Read-RequiredText (Join-Path $backendRoot 'firstleg/src/main/java/com/baiyue/firstleg/service/FbaPricingService.java')
$inboundFeeDetailService = Read-RequiredText (Join-Path $backendRoot 'firstleg/src/main/java/com/baiyue/firstleg/service/InboundFeeDetailService.java')
$adminUnifiedOrdersApi = Read-RequiredText (Join-Path $workspaceRoot 'apps/admin-web/src/modules/unified-orders/api/unifiedOrders.ts')
$adminCarrierRatesView = Read-RequiredText (Join-Path $workspaceRoot 'apps/admin-web/src/modules/fba-pricing/carrier-rates/pages/CarrierRatesView.vue')
2026-10-21 16:40:18 +08:00
Assert-Contains $businessFacts '头程订单、批量审核预览与入仓码关系' '根批量审核预览路由'
2026-09-09 09:52:46 +08:00
Assert-Contains $adminAgents '订单列表、批量审核预览、详情、商品图片与入库费用' 'Admin 批量审核预览路由'
Assert-Contains $backendAgents '平台订单批量审核预览' '后端批量审核预览路由'
Assert-Contains $orderAgents '平台批量审核预览' 'Order 批量审核预览入口'
Assert-Contains $orderOpenApi '/api/platform/v1/orders/first-leg/batch-review-preview:' 'Order 批量审核预览 OpenAPI'
Assert-Contains $batchReviewPreviewService '固定两次批量查询生成审核弹窗快照' 'Order 批量审核禁止逐票查询'
Assert-Contains $adminUnifiedOrdersApi '/platform/v1/orders/first-leg/batch-review-preview' 'Admin 批量审核预览 API'
2026-10-21 16:40:18 +08:00
Assert-Contains $businessFacts '客户专属报价、柜级阶梯运费与费用调整' '根客户专属报价路由'
2026-09-09 09:52:46 +08:00
Assert-Contains $adminAgents '客户专属价格簿、柜级阶梯运费与受控调价' 'Admin 客户专属报价路由'
Assert-Contains $backendAgents '客户专属价格簿、柜级阶梯运费与受控调价' '后端客户专属报价路由'
Assert-Contains $firstlegAgents '客户专属价格簿、柜级阶梯运费与调价边界' 'Firstleg 客户专属报价入口'
Assert-Contains $fbaPricingOpenApi '计价时优先使用客户专属 ACTIVE 版本,不存在时回退公共 ACTIVE 版本' '价格簿作用域优先级'
Assert-Contains $fbaPricingOpenApi '计费量只能在系统原计费量上下10%范围内(含边界)' '计费量调整边界'
Assert-Contains $fbaPricingService 'recalculateUnlockedContainerCustomerFees' '柜级阶梯费用重算入口'
Assert-Contains $firstlegAgents '一件代发 `WAIT_PALLETIZE` 可在预装确认前试算' 'Firstleg 一件代发预装前计价边界'
Assert-Contains $fbaPricingService '"WAIT_PALLETIZE"' '一件代发托盘化状态可计价'
Assert-Contains $fbaPricingService 'preserveProcessStatusDuringPricing' '计价保留履约状态入口'
Assert-Contains $inboundFeeDetailService 'PRIVATE_LAST_MILE_DELIVERY_FEE_CODE' '私人仓尾程派送费稳定代码'
Assert-Contains $adminCarrierRatesView 'customerId' 'Admin 价格簿客户作用域'
Assert-Path 'baiyue-firstleg/firstleg/src/main/java/com/baiyue/firstleg/pricing/ContainerTierAmountAllocator.java'
# 海外异常处理必须贯通证据、原出库来源和库存恢复,不能退化为仅修改派送状态。
$exceptionOrderService = Read-RequiredText (Join-Path $backendRoot 'lastleg-service/src/main/java/com/baiyue/lastleg/exceptionorder/service/ExceptionOrderService.java')
$inventoryCommandService = Read-RequiredText (Join-Path $backendRoot 'lastleg-service/src/main/java/com/baiyue/lastleg/inventory/command/service/InventoryCommandService.java')
2026-10-21 16:40:18 +08:00
Assert-Contains $businessFacts '海外出库、排车、派送、异常与回访' '根海外异常库存恢复路由'
Assert-Contains $businessFacts 'exceptionorder/' '根海外异常服务入口'
2026-10-19 17:56:36 +08:00
Assert-Contains $lastlegIndex '退回海外仓须把实收按原出库来源恢复到服务端校验的真实托盘/库位' 'Lastleg 海外异常库存恢复规则'
2026-09-12 18:34:23 +08:00
Assert-Contains $adminOverseasAgents '库存恢复、异常完成与派送 `RETURNED` 由服务端原子推进' 'Admin 海外异常原子边界'
2026-09-09 09:52:46 +08:00
Assert-Contains $backendAgents '海外异常退回、库存恢复与客户回访' '后端海外异常库存恢复路由'
Assert-Contains $lastlegAgents 'ExceptionEvidenceFileGateway.java' 'Lastleg 异常证据入口'
Assert-Contains $lastlegAgents '`RETURN_STOCK_IN` 流水' 'Lastleg 退回库存流水边界'
Assert-Contains $fileAgents 'businessType=OVERSEAS_EXCEPTION_EVIDENCE' 'File 海外异常证据归属'
Assert-Contains $exceptionOrderService 'restoreReturnedInventory' '海外异常退回库存恢复调用'
Assert-Contains $exceptionOrderService 'delivery.setStatus("RETURNED")' '海外异常完成派送状态'
Assert-Contains $inventoryCommandService 'ReturnedInventoryRestoreRequest' '海外退回库存命令入口'
Assert-Path 'baiyue-firstleg/lastleg-service/src/main/java/com/baiyue/lastleg/exceptionorder/gateway/ExceptionEvidenceFileGateway.java'
2026-09-04 10:51:25 +08:00
# 智能装柜已扩展到四态候选、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')
2026-10-21 16:40:18 +08:00
Assert-Contains $businessFacts '`PENDING_REVIEW/WAIT_MEASURE/WAIT_SPLIT/LOADING`' '根智能装柜四态候选'
Assert-Contains $businessFacts '能否加入以服务端 `canAssign` 为准' '根智能装柜资格边界'
Assert-Contains $businessFacts '人工加入允许跨渠道,智能推荐仍按柜次渠道' '根智能装柜渠道边界'
2026-09-04 10:51:25 +08:00
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'
2026-09-04 11:35:19 +08:00
Assert-Contains $pendingReviewOrderService 'orders.pendingReviewPage' 'Order 待审核候选权威查询'
Assert-Contains $pendingReviewOrderService '"PENDING_REVIEW"' 'Order 待审核候选状态映射'
2026-10-21 16:40:18 +08:00
Assert-Contains $businessFacts '客户入库结果与头程费用确认' '根客户入库费用确认入口'
2026-09-04 10:51:25 +08:00
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'
2026-09-04 14:41:23 +08:00
# 称重确认后的整票库位块和智能装柜暂估数量已成为跨端权威事实,索引必须直达并锁住回退顺序。
$measurementLocationOccupationService = Read-RequiredText (Join-Path $backendRoot 'firstleg/src/main/java/com/baiyue/firstleg/service/MeasurementLocationOccupationService.java')
2026-09-04 15:19:45 +08:00
$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')
2026-09-04 14:41:23 +08:00
$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')
2026-10-21 16:40:18 +08:00
Assert-Contains $businessFacts '称重确认、整票库位块与部分拣货资源结算' '根称重库位块路由'
2026-09-04 14:41:23 +08:00
Assert-Contains $backendAgents '称重确认、整票库位块与 PDA 资源结算' '后端称重库位块路由'
Assert-Contains $firstlegAgents 'MeasurementLocationOccupationService.java' 'Firstleg 称重库位块入口'
2026-09-04 15:19:45 +08:00
Assert-Contains $firstlegAgents '最新测量批次的正数 `totalVolumeCbm/originalVolumeCbm` 取较大值' 'Firstleg 库位块测量批次体积选择'
Assert-Contains $firstlegAgents '再无有效值才查询 Order 最新客户申报体积' 'Firstleg 库位块体积回退顺序'
Assert-Contains $firstlegAgents '库位指引失败只记录警告,不阻断称重确认' 'Firstleg 称重库位非阻断语义'
Assert-Contains $firstlegAgents '`ensureForSubmission` 再次补齐和校验' 'Firstleg 提交库位补偿入口'
2026-09-04 14:41:23 +08:00
Assert-Contains $firstlegAgents '槽位与称重唯一键必须包含 `inbound_id`' 'Firstleg 部分拣货快照身份'
Assert-Contains $adminAgents '`locationCode/slotStatus/sharedOverflow`' 'Admin 权威称重库位状态'
Assert-Contains $measurementLocationOccupationService 'orderCargo.measurementDeclaration' 'Firstleg Order 申报体积回退'
2026-09-04 15:19:45 +08:00
Assert-Contains $measurementLocationOccupationService 'measuredVolume.max(declaredVolume)' 'Firstleg 测量批次体积取较大值'
Assert-Contains $measurementLocationOccupationService 'ensureForSubmission' 'Firstleg 提交库位补齐实现'
Assert-Contains $inboundMeasurementService 'ensureLocationWithoutBlocking' 'Firstleg 称重库位非阻断实现'
Assert-Contains $measurementSubmissionService 'locations.ensureForSubmission' 'Firstleg 提交库位补齐调用'
2026-09-04 14:41:23 +08:00
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 已移除整票预留引导区'
2026-10-21 16:40:18 +08:00
Assert-Contains $businessFacts '`totalPackageCount/remainingPackageCount`' '根智能装柜暂估数量'
2026-09-04 14:41:23 +08:00
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 重复客户费用入口'
2026-10-20 18:44:23 +08:00
Assert-Contains $clientAgents 'customerFeeConfirmationRequired=true' 'Client 费用待确认入口'
2026-10-20 18:16:29 +08:00
Assert-Contains $clientOrdersView 'dialog-only' 'Client 费用确认弹框实现'
2026-09-04 14:41:23 +08:00
Assert-Path 'baiyue-firstleg/warehouse/src/main/java/com/baiyue/warehouse/service/LocationBlockService.java'
2026-09-02 11:59:54 +08:00
# 企业联系信息与账号登录标识已经解耦,资质审核不得重新把法人身份证设为必填。
$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')
2026-10-21 16:40:18 +08:00
Assert-Contains $businessFacts '公司联系电话/邮箱是企业资料,不作为成员登录标识' '根企业联系人边界'
2026-09-02 11:59:54 +08:00
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 成员登录手机号提示'
2026-09-01 10:29:14 +08:00
$fileAgents = Read-RequiredText (Join-Path $backendRoot 'file/AGENTS.md')
2026-09-02 15:15:41 +08:00
$qualificationOpenApi = Read-RequiredText (Join-Path $backendRoot 'file/src/main/resources/openapi/qualification-required-package-v1.yaml')
2026-10-21 16:40:18 +08:00
Assert-Contains $businessFacts '法人身份证选填,可在已有营业执照后单独补传或替换' '根法人身份证单独上传语义'
2026-09-02 15:15:41 +08:00
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 已移除法人身份证旧阻断'
2026-09-01 10:29:14 +08:00
$truckOpenApi = Read-RequiredText (Join-Path $backendRoot 'firstleg/src/main/resources/openapi/truck-appointments-v1.yaml')
2026-09-08 14:07:31 +08:00
$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')
2026-09-01 10:29:14 +08:00
$pdaLoadingApi = Read-RequiredText (Join-Path $workspaceRoot 'apps/pda-uniapp/api/pda-loading.js')
2026-09-02 15:15:41 +08:00
$cabinetEvidenceService = Read-RequiredText (Join-Path $backendRoot 'firstleg/src/main/java/com/baiyue/firstleg/loading/service/CabinetLoadingEvidenceService.java')
2026-10-21 16:40:18 +08:00
Assert-Contains $businessFacts '拖车预约由 `RELEASED` 订舱拥有,不按客户、柜次、装柜计划或真实柜号归属' '根订舱级拖车语义'
Assert-Contains $businessFacts '证据以 `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 拖车唯一有效预约'
2026-09-01 10:29:14 +08:00
Assert-Contains $fileAgents '`businessType=TRUCK_APPOINTMENT_ATTACHMENT`' 'File 拖车平台附件入口'
Assert-Contains $truckOpenApi 'required: [oceanBookingId, carrierId, plannedLoadingAt, expectedVersion]' '拖车订舱级请求字段'
2026-09-01 10:29:14 +08:00
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' '拖车订舱级唯一性'
2026-09-14 20:03:22 +08:00
Assert-Contains $truckOpenApi 'PDA loading completion alone does not complete the appointment' '拖车与 PDA 生命周期解耦'
Assert-Contains $truckOpenApi 'excluding bookings that already have an active or completed truck appointment' '拖车创建候选过滤'
2026-09-08 14:07:31 +08:00
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 'value.setEstimatedEmptyReturnAt(returnDeadline(context))' '码头拖车权威截止时间实现'
Assert-Contains $terminalDrayageService 'context.directCompletion().instant().plus(Duration.ofHours(EMPTY_RETURN_WARNING_HOURS))' '直送目的仓按绝对时长计算还空预警'
Assert-Contains $terminalDrayageService 'completedUnloading(context).plusHours(EMPTY_RETURN_WARNING_HOURS)' '原海外仓卸柜截止时间实现'
2026-09-08 14:07:31 +08:00
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 尾程人工节点入口'
2026-10-21 17:22:19 +08:00
Assert-Contains $adminInboundPageRules '入仓码只读展示并提交订单冻结值' 'Admin 尾程计划冻结入仓码边界'
2026-09-08 14:07:31 +08:00
Assert-Contains $lastlegAgents '接柜仓编码/名称以该 ID 当前目录快照为准' 'Lastleg 稳定接柜仓身份边界'
Assert-Contains $lastlegOrderCommandService '同一幂等键不能用于不同请求' '尾程命令请求哈希重放边界'
2026-09-16 19:32:52 +08:00
Assert-Contains $loadingListsOpenApi '且真实集装箱号已经补录' '确认预装真实柜号门禁'
2026-09-01 20:07:38 +08:00
Assert-Contains $loadingListsOpenApi '可在 EDITING 或 LOADING 阶段首次补录真实集装箱号' '预装真实柜号首次补录阶段'
Assert-Contains $adminAgents '创建柜次时自动生成唯一预装计划' 'Admin 自动预装计划流程'
2026-09-16 19:32:52 +08:00
Assert-Contains $loadingListsOpenApi 'PDA 创建前置条件是否全部满足,包含真实集装箱号已录入' 'PDA task 真实柜号门禁'
Assert-Contains $adminAgents '确认预装和创建 PDA 任务前必须补齐' 'Admin 真实柜号确认门禁'
2026-09-01 10:29:14 +08:00
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'
2026-10-21 16:40:18 +08:00
Assert-Contains $businessFacts '上传以幂等键绑定包含文件内容的请求哈希' '根装柜证据上传重放边界'
2026-09-02 15:15:41 +08:00
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'
2026-08-28 23:01:52 +08:00
$mapperModuleAgents = @(
@{ Module = 'audit-service'; Application = 'BaiyueAuditApplication.java' },
@{ Module = 'auth'; Application = 'BaiyueAuthApplication.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 静态门禁"
}
2026-08-20 19:55:21 +08:00
# 部署单元必须能从根索引进入。
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'
2026-08-21 17:19:49 +08:00
Assert-MarkdownTableUnique $rootAgentsPath '## 项目快速入口' 0 '根项目表'
Assert-MarkdownTableUnique $rootAgentsPath '## 项目快速入口' 1 '根项目目录'
Assert-MarkdownTableUnique $rootAgentsPath '## 业务快速路由表' 0 '根业务路由表'
Assert-Contains $rootAgents 'docs/业务快速索引.md#原型入口索引' '根按需原型入口'
Assert-MarkdownTableUnique $businessIndexPath '## 原型入口索引' 0 '按需原型入口表'
$prototypeRoutes = (($businessIndex -split '(?m)^## 原型入口索引\r?$', 2)[1] -split '(?m)^## ', 2)[0]
$prototypeFiles = [regex]::Matches($prototypeRoutes, '`([^`]+\.(?:md|html|json|js|vue))`') |
ForEach-Object { $_.Groups[1].Value } | Sort-Object -Unique
foreach ($prototypeFile in $prototypeFiles) { Assert-Path $prototypeFile }
2026-08-20 19:55:21 +08:00
# 前端当前全部业务模块必须能从应用级索引命中。
$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
}
}
2026-08-20 20:54:30 +08:00
# 国内/海外 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
}
2026-08-20 19:55:21 +08:00
}
2026-09-11 16:17:16 +08:00
# 海外 PDA 已开放拆柜收货、移库、托盘、换标和现场查询真实作业;库存盘点仅保留底层实现。
2026-08-25 11:52:25 +08:00
$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 拆柜收货开关'
2026-08-28 13:54:32 +08:00
Assert-Matches $overseasWorkbench "(?s)name:\s*'托盘管理'.{0,300}?available:\s*true.{0,200}?route:\s*'/pages/pallet/pallet'" 'Overseas PDA 托盘管理开关'
2026-09-11 16:17:16 +08:00
Assert-NotContains $overseasWorkbench "key: 'stocktake'" 'Overseas PDA 隐藏库存盘点入口'
foreach ($enabledOperation in @(
@{ Name = '商品移库'; Route = '/pages/move/move' },
2026-09-15 16:10:55 +08:00
@{ 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' }
2026-08-25 11:52:25 +08:00
)) {
$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)"
2026-08-25 11:52:25 +08:00
}
2026-08-24 09:29:26 +08:00
# 文档声明为正式开放的 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"
}
# 四端统一 Gateway;Compose默认TEST,生产只走Jenkins固定环境及部署白名单。
2026-09-29 18:47:37 +08:00
$unifiedGateway = Read-RequiredText (Join-Path $backendRoot 'gateway/src/main/resources/application.yml')
foreach ($gatewayPath in @('/api/merchant/v1/last-leg/**', '/api/platform/v1/last-leg/**', '/api/pda/v1/last-leg/**', '/api/platform/v1/warehouse-admin/**', '/api/platform/v1/overseas-warehouse-resources/**')) {
Assert-Contains $unifiedGateway $gatewayPath '统一 Gateway 路由'
2026-08-24 09:29:26 +08:00
}
2026-09-29 18:47:37 +08:00
Assert-Contains $unifiedGateway 'uri: lb://lastleg-service' 'Lastleg 服务路由'
Assert-Contains $unifiedGateway 'uri: lb://warehouse-overseas-service' '海外仓资源路由'
2026-08-25 15:08:34 +08:00
$serviceMap = Read-RequiredText (Join-Path $backendRoot 'deploy/service-map.yml')
2026-09-29 18:47:37 +08:00
$testCompose = Read-RequiredText (Join-Path $backendRoot 'deploy/docker-compose.yml')
2026-08-25 15:08:34 +08:00
$serviceJenkinsfile = Read-RequiredText (Join-Path $backendRoot 'Jenkinsfile.service')
$dispatchJenkinsfile = Read-RequiredText (Join-Path $backendRoot 'Jenkinsfile')
$builtServiceDeploy = Read-RequiredText (Join-Path $backendRoot 'deploy/scripts/deploy-built-service.sh')
$batchServiceDeploy = Read-RequiredText (Join-Path $backendRoot 'deploy/scripts/deploy-services.sh')
2026-09-29 18:47:37 +08:00
Assert-Contains $testCompose 'AUTH_SESSION_VALIDATION_URL: http://auth:9100/internal/auth/accounts/sessions/validate' '统一权威会话校验'
Assert-Contains $testCompose 'REDIS_TOKEN_KEY_PREFIX' '统一会话前缀'
Assert-Matches $testCompose '(?m)^ SPRING_PROFILES_ACTIVE: \$\{DEPLOY_ENV:-test\}\r?$' 'Compose业务profile默认TEST'
Assert-Matches $testCompose '(?m)^ SPRING_PROFILES_ACTIVE: \$\{DEPLOY_ENV:-test\},cn\r?$' '统一Gateway默认TEST及cn路由profile'
Assert-Contains $testCompose 'name: firstleg-${DEPLOY_ENV:-test}' 'Compose项目默认TEST并按环境隔离'
Assert-Contains $builtServiceDeploy 'case "$DEPLOY_ENV" in test|production) ;; *)' '单服务部署环境白名单'
Assert-Contains $builtServiceDeploy 'Only test and production are supported' '非法部署环境拒绝'
Assert-Contains $batchServiceDeploy '[ "$1" = "test" ] || exit 2' '批量部署入口仍限TEST'
Assert-Matches $dispatchJenkinsfile '(?s)case ''backend-java'':\s*return ''test''.*?case ''backend-java-prod'':\s*return ''production''' '总控Job固定TEST及生产映射'
Assert-Contains $dispatchJenkinsfile 'if (!resolvedEnvironment || !resolvedJobPrefix)' '未知总控Job拒绝'
Assert-Contains $dispatchJenkinsfile 'params.ENVIRONMENT != resolvedEnvironment' '总控参数不得切换固定环境'
Assert-Contains $dispatchJenkinsfile "return [fixedEnvironmentForJob(jobBaseName) ?: 'test']" '总控环境选项默认TEST'
Assert-Contains $serviceJenkinsfile "if (jobBaseName?.startsWith('baiyue-firstleg-prod-')) return 'production'" '生产单服务Job固定映射'
Assert-Contains $serviceJenkinsfile "!jobBaseName.startsWith('baiyue-firstleg-dev-')" '单服务Job不接受开发环境前缀'
Assert-Contains $serviceJenkinsfile 'if (!resolvedEnvironment)' '未知单服务Job拒绝'
Assert-Contains $serviceJenkinsfile 'params.ENVIRONMENT != resolvedEnvironment' '单服务参数不得切换固定环境'
Assert-Contains $serviceJenkinsfile "return [fixedEnvironmentForServiceJob(jobBaseName) ?: 'test']" '单服务环境选项默认TEST'
foreach ($mapping in @(
@{ Text = $dispatchJenkinsfile; Function = 'fixedEnvironmentForJob'; Scope = '总控环境映射' },
@{ Text = $serviceJenkinsfile; Function = 'fixedEnvironmentForServiceJob'; Scope = '单服务环境映射' }
)) {
$bodyMatch = [regex]::Match($mapping.Text, '(?ms)^def ' + $mapping.Function + '\([^\r\n]*\)\s*\{(.*?)^\}')
Assert-Matches $bodyMatch.Value 'return ''test''' ($mapping.Scope + '默认TEST能力')
Assert-Matches $bodyMatch.Value 'return null' ($mapping.Scope + '未知Job无环境')
foreach ($returned in [regex]::Matches($bodyMatch.Value, 'return ''([^'']+)''')) {
Assert-Matches $returned.Groups[1].Value '^(test|production)$' ($mapping.Scope + '仅允许TEST及生产')
}
}
2026-09-29 18:47:37 +08:00
foreach ($retired in @('gateway-overseas:', 'event-bridge-service:')) {
Assert-NotContains $serviceMap $retired '部署映射'
Assert-NotContains $testCompose $retired 'TEST Compose'
}
Assert-Contains $backendAgents 'config/nacos/test/' '唯一 Nacos 配置入口'
2026-08-25 15:08:34 +08:00
2026-08-26 11:10:42 +08:00
# 高变化语义必须在最近指引与服务契约中保持一致。
Assert-Contains $adminAgents '海外模块内部快速索引(海外仓全流程)' 'Admin 海外仓全流程范围'
2026-08-26 11:10:42 +08:00
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 'booking channel belonging to channelGroupCode' '订舱关联候选筛选语义'
2026-08-26 11:10:42 +08:00
$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 后端存在不等于设备端已挂载。
2026-08-26 11:10:42 +08:00
$adminOverseasRoutes = Read-RequiredText (Join-Path $workspaceRoot 'apps/admin-web/src/modules/overseas-warehouse/routes.ts')
2026-09-18 18:02:27 +08:00
$lastlegAgents = $lastlegEntry + "`n" + $lastlegIndex
foreach ($overseasFulfillmentRoute in @(
2026-08-26 17:31:09 +08:00
'overseas-warehouse/outbounds',
'overseas-warehouse/delivery-orders',
'overseas-warehouse/exception-orders',
'overseas-warehouse/customer-visits'
)) {
Assert-Contains $adminOverseasRoutes "path: '$overseasFulfillmentRoute'" "Admin 海外履约正式路由 $overseasFulfillmentRoute"
2026-08-26 17:31:09 +08:00
}
foreach ($overseasFulfillmentRootEntry in @(
2026-08-26 17:31:09 +08:00
'OutboundsView.vue', 'DeliveryOrdersView.vue', 'ExceptionOrdersView.vue', 'CustomerVisitsView.vue'
)) {
2026-10-21 16:40:18 +08:00
Assert-Contains $businessFacts $overseasFulfillmentRootEntry '根海外履约正式业务路由'
2026-08-26 17:31:09 +08:00
}
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 出库入口'
2026-08-26 11:10:42 +08:00
2026-10-19 17:56:36 +08:00
# 排车新主流程按单号、公开版本和动作资格定位,不再指向独立车次发车请求。
2026-10-21 14:30:41 +08:00
Assert-Contains $overseasPdaEntry 'completeDispatchLoading' '海外 PDA 装车直接派送调用入口'
Assert-Contains $overseasPdaIndex 'actions.PICK/LOADING_COMPLETE' '海外 PDA 服务端动作资格'
2026-10-19 17:56:36 +08:00
Assert-Contains $overseasPdaIndex 'recordVersion' '海外 PDA 排车公开版本'
Assert-Contains $lastlegIndex 'docs/海外仓业务/排车列表统一作业改造契约.md' 'Lastleg 当前排车主契约'
Assert-NotContains $overseasPdaAgents 'tripDepartureRequest' '海外 PDA 旧车次发车入口退出'
Assert-NotContains $overseasPdaAgents 'tripRecordVersion' '海外 PDA 旧车次版本退出'
Assert-Contains $lastlegEntry 'dispatch/controller/DispatchAggregateController.java' 'Lastleg 主指引平台整车入口'
Assert-Contains $lastlegEntry 'dispatch/pda/controller/DispatchPdaController.java' 'Lastleg 主指引 PDA 整车入口'
2026-10-21 14:30:41 +08:00
Assert-Contains $lastlegEntry 'DispatchLoadingDepartureService.java' 'Lastleg 主指引装车直接发运服务'
2026-10-19 17:56:36 +08:00
foreach ($lastlegDispatchGuide in @(
@{ Name = 'Lastleg 主指引'; Text = $lastlegEntry },
@{ Name = 'Lastleg 详细索引'; Text = $lastlegIndex }
)) {
Assert-Contains $lastlegDispatchGuide.Text 'recordVersion' "$($lastlegDispatchGuide.Name) 排车公开版本"
foreach ($obsoleteDispatchRule in @('提交车次版本', 'tripRecordVersion', 'READY_TO_DEPART')) {
Assert-NotContains $lastlegDispatchGuide.Text $obsoleteDispatchRule "$($lastlegDispatchGuide.Name) 旧排车规则退出"
}
}
$lastlegPdaPublicController = Read-RequiredText (Join-Path $backendRoot 'lastleg-service/src/main/java/com/baiyue/lastleg/dispatch/pda/controller/DispatchPdaController.java')
2026-10-21 14:30:41 +08:00
Assert-Contains $lastlegPdaPublicController 'DispatchLoadingDepartureService' 'Lastleg PDA 真实入口使用装车发运服务'
Assert-Contains $lastlegPdaPublicController 'DispatchCommands.LoadingComplete' 'Lastleg PDA 真实入口使用装车完成命令'
Assert-NotContains $lastlegPdaPublicController '@PostMapping("/{dispatchNo}/depart")' 'Lastleg PDA 独立发车入口退出'
Assert-Path 'baiyue-firstleg/lastleg-service/src/main/java/com/baiyue/lastleg/dispatch/service/DispatchLoadingDepartureService.java'
2026-10-19 17:56:36 +08:00
2026-08-26 11:10:42 +08:00
# 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')
2026-08-27 17:16:33 +08:00
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 重写'
2026-08-26 11:10:42 +08:00
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 会话持久化'
2026-08-26 17:31:09 +08:00
# 国内和海外 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')
2026-09-16 11:43:02 +08:00
Assert-Matches $adminAcceptanceEntry "(?s)const\s+OPTIONAL_MODULES\s*=\s*\[[^\]]*'manual-order-splitting-fixture'[^\]]*\]" '人工验收可选模块注册(不依赖数组顺序)'
2026-08-26 17:31:09 +08:00
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' '人工分段验收根索引'
2026-08-26 11:10:42 +08:00
# 同步 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 自动配置注册'
2026-08-26 15:58:54 +08:00
# 全部仓库主档统一归国内 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 共享海外目录'
2026-08-28 13:54:32 +08:00
Assert-Contains $warehouseAgents '/internal/warehouses/0/{warehouseId}/active' '国内 Warehouse FBA 内部校验入口'
2026-08-26 15:58:54 +08:00
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 货柜详情确认离仓'
2026-08-28 17:10:12 +08:00
# 装柜完成后的整柜报关必须保持客户退税资料、平台冻结/完成与 File 二进制边界一致。
2026-10-19 17:56:36 +08:00
$firstlegAgents = $firstlegEntry + "`n" + $firstlegIndex
2026-08-28 17:10:12 +08:00
$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')
2026-10-21 16:40:18 +08:00
Assert-Contains $businessFacts 'ContainerCustomsPanel.vue' '根整柜报关 Admin 入口'
Assert-Contains $businessFacts 'CustomsDocumentsDialog.vue' '根整柜报关 Client 入口'
2026-08-28 17:10:12 +08:00
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}/receipt/upload:' '平台报关行回执契约'
Assert-Contains $containerCustomsOpenApi '/api/platform/v1/customs/loading-plans/documents/{documentId}/final/upload:' '平台完成文件契约'
2026-08-28 17:10:12 +08:00
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_RECEIPT' 'File 报关行回执类别'
2026-08-28 17:10:12 +08:00
Assert-Contains $customsFileOpenApi 'LOADING_LIST_CUSTOMS_RESULT' 'File 报关完成文件类别'
2026-08-26 15:58:54 +08:00
# 平台商品图片和海外 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 签收照片缓存边界'
2026-09-09 09:52:46 +08:00
# 尾程订单按来源柜展示服务端计划进度;整柜确认必须绑定预览快照并编排真实托盘批次。
2026-08-27 17:16:33 +08:00
$lastlegBusinessOpenApi = Read-RequiredText (Join-Path $backendRoot 'lastleg-service/src/main/resources/openapi/overseas-business-v1.yaml')
2026-09-18 18:02:27 +08:00
$lastlegAgents = $lastlegEntry + "`n" + $lastlegIndex
2026-08-27 17:16:33 +08:00
$adminLastMileApi = Read-RequiredText (Join-Path $workspaceRoot 'apps/admin-web/src/modules/overseas-warehouse/api/lastMileOrders.ts')
2026-09-09 09:52:46 +08:00
$containerConversionCoordinator = Read-RequiredText (Join-Path $backendRoot 'lastleg-service/src/main/java/com/baiyue/lastleg/inboundplan/service/ContainerInboundPlanConversionCoordinator.java')
$warehousePalletBatchService = Read-RequiredText (Join-Path $backendRoot 'warehouse-overseas-service/src/main/java/com/baiyue/warehouse/service/WarehousePalletBatchService.java')
$overseasWarehouseAgents = Read-RequiredText (Join-Path $backendRoot 'warehouse-overseas-service/AGENTS.md')
$overseasPdaReceivingAdapter = Read-RequiredText (Join-Path $workspaceRoot 'apps/pda-overseas-uniapp/src/api/receiving-adapter.js')
2026-08-27 17:16:33 +08:00
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 整柜计划转换契约'
2026-09-09 09:52:46 +08:00
Assert-Contains $lastlegBusinessOpenApi '/api/platform/v1/last-leg/inbound-plans/container-preview:' 'Lastleg 整柜计划预览契约'
Assert-Contains $lastlegBusinessOpenApi 'snapshotVersion' 'Lastleg 整柜计划快照版本'
Assert-Contains $lastlegBusinessOpenApi 'snapshotHash' 'Lastleg 整柜计划快照哈希'
2026-08-27 17:16:33 +08:00
Assert-Contains $lastlegBusinessOpenApi 'sourceContainerBookingId' 'Lastleg 稳定来源柜身份'
2026-10-21 17:22:19 +08:00
Assert-Contains $adminInboundPageRules '/orders/container-summaries' 'Admin 柜级摘要目标入口'
2026-10-21 16:40:18 +08:00
Assert-Contains $businessFacts '尾程订单控制与柜级入仓计划转换' '根柜级计划入口'
2026-09-09 09:52:46 +08:00
Assert-Contains $backendAgents '分页返回全部稳定来源柜' '后端全柜工作台范围'
2026-10-21 17:22:19 +08:00
Assert-Contains $adminInboundPageRules '服务端分页返回全部稳定来源柜' 'Admin 全柜工作台范围'
2026-09-09 09:52:46 +08:00
Assert-Contains $lastlegAgents '分页返回全部稳定来源柜' 'Lastleg 全柜工作台范围'
Assert-Contains $lastlegBusinessOpenApi '返回全部稳定来源柜' 'Lastleg 全柜工作台 OpenAPI'
2026-10-21 17:22:19 +08:00
Assert-Contains $adminInboundPageRules 'ACTIVE + FBA' 'Admin FBA 权威仓候选'
Assert-Contains $adminInboundPageRules '/inbound-plans/convert-container' 'Admin 整柜转换目标入口'
Assert-Contains $adminInboundPageRules '/inbound-plans/container-preview' 'Admin 整柜预览目标入口'
Assert-Contains $adminInboundPageRules '同一 `snapshotVersion/snapshotHash` 原样提交' 'Admin 整柜快照确认边界'
2026-08-27 17:16:33 +08:00
Assert-Contains $adminLastMileApi '/orders/container-summaries' 'Admin 柜级摘要真实调用'
2026-09-09 09:52:46 +08:00
Assert-Contains $adminLastMileApi '/platform/v1/last-leg/inbound-plans/container-preview' 'Admin 柜级预览真实调用'
2026-08-27 17:16:33 +08:00
Assert-NotContains $adminLastMileApi '/orders/pending-containers' 'Admin 旧柜级摘要调用'
2026-08-28 13:54:32 +08:00
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 权威仓校验入口'
2026-09-09 09:52:46 +08:00
Assert-Contains $lastlegAgents 'ContainerInboundPlanConversionCoordinator.java' 'Lastleg 柜级计划 Saga 入口'
Assert-Contains $containerConversionCoordinator 'warehouse.ensurePalletBatch' 'Lastleg 托盘批次预留'
Assert-Contains $containerConversionCoordinator 'warehouse.confirmPalletBatch' 'Lastleg 托盘批次确认'
Assert-Contains $containerConversionCoordinator 'warehouse.compensatePalletBatch' 'Lastleg 托盘批次补偿'
Assert-Contains $warehousePalletBatchService 'Only a RESERVED pallet batch can be confirmed' '海外资源批次确认状态门禁'
Assert-Contains $overseasWarehouseAgents '同柜重放不得产生第二批资源' '海外资源批次幂等边界'
Assert-Contains $overseasPdaAgents 'assigned/mergeAllowed/urgent/mergeHint' '海外 PDA 计划标志索引'
Assert-Contains $overseasPdaAgents '不在设备端重新分配' '海外 PDA 预留托盘边界'
Assert-Contains $overseasPdaReceivingAdapter 'mergeAllowed: value.mergeAllowed === true' '海外 PDA 合托可选事实适配'
2026-08-27 17:16:33 +08:00
2026-09-01 14:27:16 +08:00
# 国内 PDA 当前以页面、API 和作业状态合同覆盖部分拣货及库位不足反馈。
Assert-Contains $pdaAgents 'tests/page-contract.test.mjs' '国内 PDA 页面合同'
Assert-Contains $pdaAgents 'tests/pda-loading-api.test.mjs' '国内 PDA API 合同'
2026-09-02 19:53:07 +08:00
# 国内柜费分摊与海外费用跨区入池必须能从根索引直达,并锁住归属、金额、版本与直接已付隔离。
$financeAgents = Read-RequiredText (Join-Path $backendRoot 'finance/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')
2026-09-29 18:47:37 +08:00
$directEventClient = Read-RequiredText (Join-Path $backendRoot 'lastleg-service/src/main/java/com/baiyue/lastleg/client/DirectEventClient.java')
$financeBusinessClient = Read-RequiredText (Join-Path $backendRoot 'lastleg-service/src/main/java/com/baiyue/lastleg/client/FinanceBusinessEventClient.java')
2026-09-02 19:53:07 +08:00
$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')
2026-09-23 17:47:50 +08:00
$overseasFinancePhase0ContractPath = Join-Path $workspaceRoot 'docs/财务管理/海外仓费用统一接入阶段0技术契约.md'
$overseasFinancePhase0Contract = Read-RequiredText $overseasFinancePhase0ContractPath
2026-10-21 16:40:18 +08:00
Assert-Contains $businessFacts '财务管理与柜级公共费用分摊' '根柜费分摊快速路由'
Assert-Contains $businessFacts '海外业务费用来源与客户财务' '根海外费用快速路由'
2026-09-07 15:07:34 +08:00
Assert-Contains $adminAgents '财务、客户资金账户与柜级公共费用分摊' 'Admin 柜费分摊快速路由'
2026-09-02 19:53:07 +08:00
Assert-Contains $backendAgents '柜级公共费用跨客户分摊' '后端柜费分摊快速路由'
Assert-Contains $backendAgents '海外业务费用来源跨区入池' '后端海外费用快速路由'
2026-10-21 16:40:18 +08:00
Assert-Contains $businessFacts '海外仓费用统一接入阶段0技术契约.md' '根海外费用阶段 0 按需入口'
2026-09-23 17:47:50 +08:00
Assert-Contains $financeAgents '海外仓费用统一接入阶段0技术契约.md' 'Finance 海外费用阶段 0 按需入口'
Assert-Contains $lastlegAgents '海外仓费用统一接入阶段0技术契约.md' 'Lastleg 海外费用阶段 0 按需入口'
Assert-Contains $lastlegAgents '不能因文档存在宣称已实现' '阶段 0 设计与代码事实边界'
2026-09-02 19:53:07 +08:00
Assert-Contains $firstlegAgents '单行入口拒绝分摊组' 'Firstleg 分摊组原子边界'
Assert-Contains $adminFinanceAgents '`allocationGroupId` 整组审核、驳回、调整或作废' 'Admin 分摊组操作边界'
Assert-Contains $containerFeeOpenApi '/fee-details/allocation-groups:' '柜费分摊组创建 OpenAPI'
2026-09-10 12:18:33 +08:00
Assert-Matches $containerFeeOpenApi '各行按\s+HALF_UP\s+保留两位后必须大于零,\s*落库金额合计必须等于两位小数的总额' '柜费舍入后正数与金额守恒'
Assert-Contains $containerFeeOpenApi '分摊组不可经单行入口修改' '柜费分摊整组操作契约'
2026-09-02 19:53:07 +08:00
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 五类海外费用归属'
2026-09-10 12:18:33 +08:00
# 在 BusinessType 枚举内逐项核对,新增类型或调整顺序不应使原有覆盖误报。
$businessTypeEnumMatch = [regex]::Match($overseasFinanceOpenApi, '(?s)BusinessType:\s*\{\s*type:\s*string,\s*enum:\s*\[([^\]]*)\]')
Assert-Matches $overseasFinanceOpenApi 'BusinessType:\s*\{\s*type:\s*string,\s*enum:' '海外业务类型枚举定义'
$businessTypeValues = @($businessTypeEnumMatch.Groups[1].Value.Split(',') | ForEach-Object { $_.Trim() })
foreach ($businessType in @('OVERSEAS_INBOUND', 'OVERSEAS_PROCUREMENT', 'PROCUREMENT_FEE', 'US_TRUCK', 'LOCAL_LOOSEBOARD', 'WAREHOUSE_SERVICE', 'OVERSEAS_CONTAINER', 'LASTLEG_ORDER', 'DELIVERY_ORDER', 'RELABEL_ORDER')) {
$checked++
if ($businessType -notin $businessTypeValues) { Add-Failure "海外 BusinessType 枚举缺少: $businessType" }
}
2026-09-02 19:53:07 +08:00
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' '海外费用事件来源哈希'
2026-09-29 18:47:37 +08:00
Assert-Contains $directEventClient 'EventTypes.BUSINESS_FEE_SOURCE_CHANGED -> checkedFinance(finance.fee(token, event))' '费用事件定向 Finance'
Assert-Contains $directEventClient 'EventTypes.WALLET_COMMAND_REQUESTED -> checkedFinance(finance.wallet(token, event))' '资金指令定向 Finance'
Assert-Contains $financeBusinessClient '/internal/finance/v1/business-fee-source-events' 'Finance 费用内部入口'
Assert-Contains $financeBusinessClient '/internal/finance/v1/wallet-command-events' 'Finance 资金内部入口'
2026-09-02 19:53:07 +08:00
Assert-Contains $financeAgents '`eventId + payloadHash` 防重放冲突' 'Finance 海外事件幂等边界'
Assert-Contains $financeAgents '`PAYABLE + DIRECT_PAID` 审核版本必须生成 `BUSINESS_DIRECT_PAID`' 'Finance 直接已付隔离边界'
2026-10-21 16:40:18 +08:00
Assert-Contains $businessFacts '入库扣货、解除与凭证' '根入库扣货快速路由'
2026-09-10 19:27:09 +08:00
Assert-Contains $adminAgents '入库扣货、解除与凭证历史' 'Admin 入库扣货快速路由'
2026-09-07 15:34:36 +08:00
Assert-Contains $backendAgents '入库单扣货、解除、凭证与履约门禁' '后端入库扣货快速路由'
Assert-Contains $firstlegAgents '入库单扣货、履约门禁与凭证' 'Firstleg 入库扣货入口'
2026-10-21 16:40:18 +08:00
Assert-Contains $businessFacts '客户资金账户、充值、授信与业务扣费' '根客户钱包快速路由'
Assert-Contains $backendAgents '客户资金账户、充值、授信、冻结、结算与跨区资金指令' '后端客户钱包快速路由'
2026-09-07 15:34:36 +08:00
Assert-Contains $lastlegAgents '海外业务资金指令与结果' 'Lastleg 跨区钱包入口'
Assert-Contains $lastlegAgents '拆柜打托成本与客户应收分摊' 'Lastleg 拆柜打托费用入口'
Assert-Contains $clientAgents '换标申请必须提交正数 CNY `chargeAmount`' 'Client 换标钱包金额边界'
2026-10-21 16:40:18 +08:00
Assert-Contains $businessFacts '统一认证与服务通信契约.md' '根统一认证契约入口'
2026-09-29 17:55:54 +08:00
Assert-Contains $backendAgents '各端共用 Gateway 和 Redis 会话' '后端统一认证目标'
$unifiedCommunication = Read-RequiredText (Join-Path $workspaceRoot 'docs/统一认证与服务通信契约.md')
Assert-Contains $unifiedCommunication 'JWT 不携带角色或权限集合' '统一 JWT 最小身份边界'
Assert-Contains $unifiedCommunication '平台/客户/PDA' '统一认证访问域隔离'
2026-09-30 17:13:11 +08:00
Assert-Matches $unifiedCommunication '整体迁移(尚未完成|验收尚未关闭)' '认证目标与落地状态分离'
2026-09-02 19:53:07 +08:00
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"
}
2026-08-27 17:16:33 +08:00
# 国内 PDA 部分拣货必须展示真实可用库位事实,并在无库位时保持页面整洁。
Assert-Contains $pdaAgents 'tests/partial-layout.test.mjs' '国内 PDA 部分拣货布局合同'
Assert-Contains $pdaAgents 'tests/picking-location-display.test.mjs' '国内 PDA 库位展示合同'
2026-08-20 19:55:21 +08:00
# Maven 聚合声明的全部历史/当前模块必须在后端根指引中可定位。
[xml]$pom = Get-Content -LiteralPath (Join-Path $backendRoot 'pom.xml') -Raw
2026-09-29 18:47:37 +08:00
if (@($pom.project.modules.module).Count -ne 20) { Add-Failure '当前聚合必须为20模块(7公共/依赖+13服务)' }
if ([regex]::Matches($serviceMap, '(?m)^ [a-z][a-z-]+:').Count -ne 13) { Add-Failure '当前发布映射必须为13服务' }
2026-08-20 19:55:21 +08:00
foreach ($module in $pom.project.modules.module) {
Assert-Contains $backendAgents "$module/" '后端 AGENTS.md'
}
# 对本轮高变化链路做精确文件门禁,防止改名或删除后留下悬空索引。
$criticalPaths = @(
'apps/admin-web/src/modules/overseas-warehouse/api/inboundOrders.ts',
2026-09-23 17:47:50 +08:00
'docs/财务管理/海外仓费用统一接入阶段0技术契约.md',
2026-08-27 17:16:33 +08:00
'apps/admin-web/src/modules/overseas-warehouse/api/lastMileOrders.ts',
2026-08-28 13:54:32 +08:00
'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',
2026-08-27 17:16:33 +08:00
'apps/admin-web/src/modules/overseas-warehouse/pages/LastMileOrdersView.vue',
2026-08-20 19:55:21 +08:00
'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',
2026-08-21 17:19:49 +08:00
'apps/admin-web/src/modules/overseas-warehouse/api/dispatches.ts',
'apps/admin-web/src/modules/overseas-warehouse/pages/DispatchesView.vue',
2026-08-22 09:56:26 +08:00
'apps/admin-web/src/modules/overseas-warehouse/pages/DispatchDetailView.vue',
2026-08-21 17:19:49 +08:00
'apps/admin-web/src/modules/overseas-warehouse/components/SmartDispatchDialog.vue',
2026-08-22 09:56:26 +08:00
'apps/admin-web/src/modules/container-loading/pages/SmartLoadingWorkbenchView.vue',
2026-08-26 11:10:42 +08:00
'apps/admin-web/src/modules/container-loading/pages/ContainerDetailView.vue',
'apps/admin-web/src/modules/container-loading/components/ContainerOverviewPanel.vue',
2026-08-28 17:10:12 +08:00
'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',
2026-08-22 09:56:26 +08:00
'apps/admin-web/src/modules/container-loading/api/platformContainerLoading.ts',
2026-08-31 18:55:03 +08:00
'apps/admin-web/src/modules/loading-lists/pages/PreloadPlanDetailView.lifecycle.test.ts',
2026-08-30 17:02:19 +08:00
'apps/admin-web/src/modules/unified-orders/api/coLoadGroups.ts',
'apps/admin-web/src/modules/unified-orders/pages/UnifiedOrdersView.vue',
2026-08-26 11:10:42 +08:00
'apps/admin-web/src/modules/ocean-bookings/api/platformOceanBookings.ts',
'apps/admin-web/src/modules/ocean-bookings/pages/OceanBookingsView.vue',
2026-09-01 10:29:14 +08:00
'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',
2026-08-26 11:10:42 +08:00
'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',
2026-08-26 17:31:09 +08:00
'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',
2026-08-25 15:08:34 +08:00
'apps/admin-web/src/modules/iam/pages/InternalUsersView.vue',
'apps/admin-web/src/modules/iam/api/platformIam.ts',
2026-08-26 15:58:54 +08:00
'apps/admin-web/src/modules/unified-orders/api/unifiedOrders.ts',
2026-09-29 17:55:54 +08:00
'apps/client-web/src/api/http.ts',
2026-08-22 09:56:26 +08:00
'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',
2026-08-28 17:10:12 +08:00
'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',
2026-08-31 18:55:03 +08:00
'apps/client-web/src/modules/first-leg/api/inboundCodeAssociations.ts',
'apps/client-web/src/modules/first-leg/components/InboundCodeAssociationDialog.vue',
2026-08-20 19:55:21 +08:00
'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',
2026-08-26 11:10:42 +08:00
'apps/pda-uniapp/config/runtime.js',
'apps/pda-uniapp/.env.example',
'apps/pda-uniapp/vite.config.js',
2026-08-26 17:31:09 +08:00
'apps/pda-uniapp/utils/app-update.js',
'apps/pda-uniapp/tests/app-update.test.mjs',
2026-09-01 14:27:16 +08:00
'apps/pda-uniapp/tests/page-contract.test.mjs',
'apps/pda-uniapp/tests/pda-loading-api.test.mjs',
'apps/pda-uniapp/tests/picking-failure-recovery.test.mjs',
2026-08-20 20:54:30 +08:00
'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',
2026-09-01 14:47:45 +08:00
'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',
2026-08-26 15:58:54 +08:00
'apps/pda-overseas-uniapp/src/stores/receiving.js',
'apps/pda-overseas-uniapp/tests/receiving-photo-ui-contract.test.mjs',
2026-08-20 20:54:30 +08:00
'apps/pda-overseas-uniapp/src/config/runtime.js',
'apps/pda-overseas-uniapp/src/api/auth.js',
2026-08-25 11:52:25 +08:00
'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',
2026-08-20 20:54:30 +08:00
'apps/pda-overseas-uniapp/src/utils/scan-broadcast.js',
2026-08-26 11:10:42 +08:00
'apps/pda-overseas-uniapp/src/manifest.json',
'apps/pda-overseas-uniapp/tests/app-icons.test.mjs',
2026-08-26 17:31:09 +08:00
'apps/pda-overseas-uniapp/src/utils/app-update.js',
'apps/pda-overseas-uniapp/tests/app-update.test.mjs',
2026-08-31 18:55:03 +08:00
'apps/pda-overseas-uniapp/tests/business-identifiers-ui.test.mjs',
2026-08-26 17:31:09 +08:00
'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',
2026-08-20 19:55:21 +08:00
'baiyue-firstleg/firstleg/src/main/java/com/baiyue/firstleg/service/FeePaymentSnapshotValidator.java',
2026-08-28 23:01:52 +08:00
'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',
2026-08-20 19:55:21 +08:00
'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',
2026-08-21 17:19:49 +08:00
'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',
2026-09-01 14:27:16 +08:00
'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',
2026-09-01 14:27:16 +08:00
'baiyue-firstleg/firstleg/src/main/java/com/baiyue/firstleg/service/OverseasInboundOrderDetainedConsumer.java',
'baiyue-firstleg/order/src/main/java/com/baiyue/order/controller/InternalOrderCargoController.java',
2026-08-22 09:56:26 +08:00
'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',
2026-08-26 15:58:54 +08:00
'baiyue-firstleg/firstleg/src/main/java/com/baiyue/firstleg/controller/PlatformContainerController.java',
'baiyue-firstleg/firstleg/src/main/java/com/baiyue/firstleg/mapper/ContainerOverviewMapper.java',
2026-08-28 17:10:12 +08:00
'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',
2026-08-30 17:02:19 +08:00
'baiyue-firstleg/firstleg/src/main/resources/openapi/coload-groups-v1.yaml',
2026-08-31 18:55:03 +08:00
'baiyue-firstleg/firstleg/src/main/resources/openapi/loading-lists-v1.yaml',
2026-08-30 17:02:19 +08:00
'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',
2026-09-01 10:29:14 +08:00
'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',
2026-08-28 17:10:12 +08:00
'baiyue-firstleg/file/src/main/resources/openapi/customs-file-and-export-v1.yaml',
2026-08-31 18:55:03 +08:00
'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',
2026-08-26 15:58:54 +08:00
'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',
2026-08-26 11:10:42 +08:00
'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',
2026-08-25 15:08:34 +08:00
'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',
2026-09-29 17:55:54 +08:00
'baiyue-firstleg/auth/src/main/java/com/baiyue/auth/config/UnifiedJwtConfiguration.java',
2026-09-29 18:47:37 +08:00
'baiyue-firstleg/auth/src/main/java/com/baiyue/auth/service/SessionStateService.java',
2026-08-25 15:08:34 +08:00
'baiyue-firstleg/iam/src/main/java/com/baiyue/iam/service/PlatformUserManagementService.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',
2026-09-29 18:47:37 +08:00
'baiyue-firstleg/common-security/src/main/java/com/baiyue/common/security/HttpSessionStateVerifier.java',
'baiyue-firstleg/gateway/src/main/java/com/baiyue/gateway/config/RedisTokenSessionWebFilter.java',
'baiyue-firstleg/lastleg-service/src/main/java/com/baiyue/lastleg/client/DirectEventClient.java',
2026-08-25 15:08:34 +08:00
'baiyue-firstleg/common-openapi/src/test/java/com/baiyue/common/openapi/PdaOpenApiGroupContractTest.java',
2026-08-26 11:10:42 +08:00
'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',
2026-08-25 11:52:25 +08:00
'baiyue-firstleg/lastleg-service/src/main/java/com/baiyue/lastleg/inboundplan/pda/controller/ReceivingContainerController.java',
2026-08-28 13:54:32 +08:00
'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',
2026-08-27 17:16:33 +08:00
'baiyue-firstleg/lastleg-service/src/main/resources/openapi/overseas-business-v1.yaml',
2026-08-25 11:52:25 +08:00
'baiyue-firstleg/lastleg-service/src/main/java/com/baiyue/lastleg/inboundplan/pda/service/ReceivingContainerService.java',
2026-08-26 15:58:54 +08:00
'baiyue-firstleg/lastleg-service/src/main/java/com/baiyue/lastleg/inboundplan/pda/gateway/UnloadPhotoFileGateway.java',
2026-08-25 11:52:25 +08:00
'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',
2026-08-25 15:08:34 +08:00
'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',
2026-08-26 15:58:54 +08:00
'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',
2026-08-25 15:08:34 +08:00
'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',
2026-08-21 17:19:49 +08:00
'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/common-event-contract/src/main/java/com/baiyue/common/event/FirstLegLoadingPlanCompletedV2.java',
2026-09-15 13:36:58 +08:00
'baiyue-firstleg/common-event-contract/src/main/java/com/baiyue/common/event/FirstLegLoadingPlanCompletedV3.java',
2026-08-25 11:52:25 +08:00
'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',
2026-08-24 09:29:26 +08:00
'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',
2026-08-25 15:08:34 +08:00
'baiyue-firstleg/scripts/java-quality-summary.mjs',
'baiyue-firstleg/scripts/java-quality-summary.test.mjs',
2026-08-26 17:31:09 +08:00
'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',
2026-08-26 17:50:56 +08:00
'docs/墨家设备测量上传接口说明-V3.md',
'docs/国内货柜履约/国内货柜履约需求确认表.md',
2026-08-26 17:50:56 +08:00
'docs/统一订单主状态与操作契约.md',
2026-09-01 14:46:44 +08:00
'docs/开发环境独立任务协作登记.md',
'docs/独立任务协作登记.md',
2026-08-26 17:50:56 +08:00
'docs/财务管理/财务管理产品确认表.md',
'docs/财务管理/Firstleg-Finance跨服务契约.md'
2026-08-20 19:55:21 +08:00
)
$criticalPaths | ForEach-Object { Assert-Path $_ }
2026-09-29 18:47:37 +08:00
# phase4前端定向合同是本地测试入口;不代表真实页面或环境验收通过。
foreach ($frontendTestPath in @('apps/admin-web/vitest.phase4-test.config.ts', 'apps/admin-web/scripts/phase4-test-frontend.acceptance.ts', 'apps/admin-web/scripts/phase4-test-frontend-acceptance.mjs', 'apps/admin-web/scripts/phase4-test-frontend-contract.test.mjs')) {
Assert-Path $frontendTestPath
}
$adminPackage = Read-RequiredText (Join-Path $workspaceRoot 'apps/admin-web/package.json')
Assert-Contains $adminPackage '"test:phase4:test": "node scripts/phase4-test-frontend-acceptance.mjs"' 'Admin phase4 TEST入口'
2026-08-20 19:55:21 +08:00
2026-08-26 15:58:54 +08:00
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',
2026-09-17 18:25:05 +08:00
'baiyue-firstleg/warehouse-overseas-service/src/main/java/com/baiyue/warehouse/controller/MerchantWarehouseResourceController.java',
2026-08-26 15:58:54 +08:00
'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
}
2026-08-20 19:55:21 +08:00
# 只检查明确维护的快速索引表,避免把排除规则正文中的目录名误判为业务入口。
$indexedAgentFiles = @(
$rootAgentsPath,
$adminAgentsPath,
2026-09-12 18:34:23 +08:00
$adminOverseasAgentsPath,
2026-08-20 19:55:21 +08:00
$clientAgentsPath,
$pdaAgentsPath,
2026-08-20 20:54:30 +08:00
$overseasPdaAgentsPath,
2026-08-20 19:55:21 +08:00
$backendAgentsPath,
2026-09-18 18:02:27 +08:00
$backendIndexPath,
$lastlegIndexPath,
2026-10-19 17:56:36 +08:00
$firstlegIndexPath,
$adminIndexPath,
$clientIndexPath,
$overseasPdaIndexPath,
2026-08-20 19:55:21 +08:00
(Join-Path $backendRoot 'firstleg/AGENTS.md'),
(Join-Path $backendRoot 'finance/AGENTS.md'),
(Join-Path $backendRoot 'lastleg-service/AGENTS.md'),
2026-08-25 15:08:34 +08:00
(Join-Path $backendRoot 'iam/AGENTS.md'),
(Join-Path $backendRoot 'common-security/AGENTS.md'),
2026-08-26 11:10:42 +08:00
(Join-Path $backendRoot 'common-web/AGENTS.md'),
2026-08-25 15:08:34 +08:00
(Join-Path $backendRoot 'common-openapi/AGENTS.md'),
(Join-Path $backendRoot 'warehouse-overseas-service/AGENTS.md'),
2026-08-26 15:58:54 +08:00
(Join-Path $backendRoot 'warehouse/AGENTS.md'),
2026-08-20 19:55:21 +08:00
(Join-Path $backendRoot 'file/AGENTS.md'),
(Join-Path $backendRoot 'common-event-contract/AGENTS.md')
)
2026-08-25 15:08:34 +08:00
$excludedTargetPattern = '(?i)`(?:[^`]*/)?(node_modules(?:\.[^/`]*)?|dist|target|reports|output|outputs|uni_modules|\.git|\.codex[^/`]*|\.runtime[^/`]*)(?:/|`)'
2026-08-20 19:55:21 +08:00
$excludedPatternSamples = @(
'| 错误入口 | `node_modules/pkg/` |',
2026-08-25 15:08:34 +08:00
'| 错误入口 | `node_modules.corrupt/.bin/vite` |',
2026-08-20 19:55:21 +08:00
'| 错误入口 | `src/target/classes/` |',
2026-08-24 09:29:26 +08:00
'| 错误入口 | `.codex-temp/task/` |',
'| 错误入口 | `.runtime-tailleg/DbQuery.java` |'
2026-08-20 19:55:21 +08:00
)
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
}
2026-09-29 18:47:37 +08:00
Write-Host "AGENTS 索引合同通过:$checked 项检查,覆盖快速表唯一性、部署单元、开发/测试任务登记隔离、前端模块、Client active 路由、客户中文批量下单、箱规算法与测量计费、一件代发预装前计价、称重整票库位块与暂估箱数校准、入库扣货履约门禁、全局智能装柜组分页、客户账单入仓码联查、客户钱包与跨区资金指令、导出退避任务重试、脚本目录治理、Finance 扩展 HTTP 模块、柜费跨客户原子分摊、海外费用跨区入池与直接已付隔离、企业联系信息与登录标识解耦、选填法人身份证独立上传、待审核订单状态优先、订单申报版本同步与渠道门禁、装柜证据内容哈希重放、业务编号与内部 ID 隔离、装柜清单生命周期与真实柜号后补、订舱级拖车与柜级证据、海外仓全流程范围、柜级待处理计划筛选与范围漂移、柜级全柜工作台、计划快照与托盘 Saga、海外 PDA 多计划标志、仓库主档唯一权威、订舱候选与柜量语义、整柜出仓与船节点单调性、统一 Token 与权威会话、Gateway 覆盖、PDA 页面/运行配置/独立更新/语言预留/能力开关、人工分段验收链、Maven 模块、同步 Trace、关键入口和排除目录。" -ForegroundColor Green
2026-08-20 19:55:21 +08:00
exit 0