Set-StrictMode -Version Latest
|
$ErrorActionPreference = "Stop"
|
|
$ProjectRoot = (Resolve-Path -LiteralPath ".").Path
|
$CaseId = "ANA-ROBOT-INDUSTRY-001"
|
$RunId = "RUN-ANA-ROBOT-THREEPIECE-ACTUAL-SOURCE-TRACE-REVIEW-SYNC-001"
|
$BatchId = "BATCH-ANA-ROBOT-THREEPIECE-ACTUAL-SOURCE-TRACE-REVIEW-SYNC-001"
|
$ReviewMessageId = "msg_20260705111846575_e7e2c128"
|
$AuditId = "AUDIT-ANA-ROBOT-THREEPIECE-ACTUAL-SOURCE-TRACE-001"
|
$NowStamp = "2026-07-05T11:25:00+08:00"
|
$MtimeStamp = "2026-07-05 11:25:00+08:00"
|
|
$CaseRoot = Join-Path $ProjectRoot "ana-data/cases/机器人案例/ANA-ROBOT-INDUSTRY-001"
|
$EvidenceDir = Join-Path $CaseRoot "evidence"
|
$ManifestDir = Join-Path $CaseRoot "manifest"
|
$OutputCoreDir = Join-Path $CaseRoot "outputs/核心文档"
|
$ResultDir = Join-Path $ProjectRoot "ana-data/result/机器人案例/ANA-ROBOT-INDUSTRY-001"
|
$AuditDocDir = Join-Path $ProjectRoot "ana-doc/机器人案例"
|
|
$Utf8NoBom = New-Object System.Text.UTF8Encoding($false)
|
|
function Read-Text($Path) {
|
return [System.IO.File]::ReadAllText((Resolve-Path -LiteralPath $Path).Path, [System.Text.Encoding]::UTF8)
|
}
|
|
function Write-Text($Path, $Text) {
|
[System.IO.File]::WriteAllText((Resolve-Path -LiteralPath $Path).Path, $Text, $Utf8NoBom)
|
}
|
|
function Rel-Path($Path) {
|
$full = (Resolve-Path -LiteralPath $Path).Path
|
$root = $ProjectRoot.TrimEnd("\")
|
return $full.Substring($root.Length + 1).Replace("\", "/")
|
}
|
|
function Get-FileMeta($RelPath) {
|
$full = Join-Path $ProjectRoot ($RelPath -replace "/", "\")
|
if (-not (Test-Path -LiteralPath $full)) {
|
throw "Missing artifact: $RelPath"
|
}
|
$sha = (Get-FileHash -LiteralPath $full -Algorithm SHA256).Hash.ToLowerInvariant()
|
$file = Get-Item -LiteralPath $full
|
[pscustomobject]@{
|
sha256 = $sha
|
bytes = [string]$file.Length
|
mtime = $file.LastWriteTime.ToString("yyyy-MM-dd HH:mm:ss") + "+08:00"
|
}
|
}
|
|
function ConvertTo-CsvText($Rows) {
|
return ($Rows | ConvertTo-Csv -NoTypeInformation) -join "`r`n"
|
}
|
|
function Add-OrReplaceSection($Text, $Header, $Body) {
|
if ($Text.Contains($Header)) {
|
return $Text
|
}
|
return $Text.TrimEnd() + "`r`n`r`n" + $Header + "`r`n`r`n" + $Body.Trim() + "`r`n"
|
}
|
|
# 1. next_action_list.csv: close 032A review result and queue 032B.
|
$nextPath = Join-Path $ManifestDir "next_action_list.csv"
|
$nextRows = @(Import-Csv -LiteralPath $nextPath)
|
foreach ($row in $nextRows) {
|
if ($row.action_id -eq "NEXT-ROBOT-032A") {
|
$row.output = "threepiece_actual_source_trace_evidence_20260705.csv; threepiece_actual_source_gap_retained_20260705.csv; threepiece_public_source_snapshot_manifest_20260705.csv; threepiece_actual_source_trace_summary_20260705.json; review_result $ReviewMessageId / $AuditId"
|
$row.status = "CONDITIONALLY_PASSED_THREEPIECE_ACTUAL_SOURCE_TRACE_READY_FOR_FOLLOWUP_EVIDENCE_NOT_OUTPUT_PASS"
|
}
|
}
|
if (-not ($nextRows | Where-Object { $_.action_id -eq "NEXT-ROBOT-032B" })) {
|
$nextRows += [pscustomobject]@{
|
priority = "P0"
|
action_id = "NEXT-ROBOT-032B"
|
action = "三件套输出通过前补证包:IFR PDF 页码级抽取、MIR/Omdia/AMR/ASP/公司强字段补证缺口闭环"
|
owner_role = "case_analysis.analyst.cai"
|
input = "$AuditId; threepiece_actual_source_trace_evidence_20260705.csv; threepiece_actual_source_gap_retained_20260705.csv; threepiece_public_source_snapshot_manifest_20260705.csv"
|
output = "输出通过前补证包待建;仍不申请输出通过、覆盖完整、对外交付、完成状态、正式扩池、正式公司池确认或强字段升级"
|
status = "QUEUED_AFTER_THREEPIECE_ACTUAL_SOURCE_TRACE_CONDITIONAL_PASS_NOT_OUTPUT_PASS"
|
}
|
}
|
[System.IO.File]::WriteAllText($nextPath, (ConvertTo-CsvText $nextRows) + "`r`n", $Utf8NoBom)
|
|
# 2. evidence map and migration manifest shared rows.
|
$evidenceMapPath = Join-Path $EvidenceDir "case_evidence_map.csv"
|
$evidenceRows = @(Import-Csv -LiteralPath $evidenceMapPath)
|
$threepieceArtifacts = @(
|
"ana-data/cases/机器人案例/ANA-ROBOT-INDUSTRY-001/outputs/核心文档/机器人报告索引.md",
|
"ana-data/cases/机器人案例/ANA-ROBOT-INDUSTRY-001/outputs/核心文档/机器人的产业链总览.md",
|
"ana-data/cases/机器人案例/ANA-ROBOT-INDUSTRY-001/outputs/核心文档/机器人的市场情况总览.md"
|
)
|
foreach ($row in $evidenceRows) {
|
if ($threepieceArtifacts -contains $row.artifact) {
|
$row.evidence_status = "THREEPIECE_ACTUAL_SOURCE_TRACE_CONDITIONALLY_PASSED_FOR_FOLLOWUP_EVIDENCE_NOT_OUTPUT_PASS"
|
$row.evidence_entry = "threepiece_actual_source_trace_evidence_20260705.csv; threepiece_actual_source_gap_retained_20260705.csv; threepiece_public_source_snapshot_manifest_20260705.csv; threepiece_actual_source_trace_summary_20260705.json; threepiece_actual_source_trace_review_sync_20260705.json"
|
$row.review_status = "CONDITIONALLY_PASSED_NOT_OUTPUT_PASS"
|
}
|
}
|
[System.IO.File]::WriteAllText($evidenceMapPath, (ConvertTo-CsvText $evidenceRows) + "`r`n", $Utf8NoBom)
|
|
$migrationPath = Join-Path $ManifestDir "migration_manifest.csv"
|
$migrationRows = @(Import-Csv -LiteralPath $migrationPath)
|
foreach ($row in $migrationRows) {
|
if ($threepieceArtifacts -contains $row.target) {
|
$row.status = "FROZEN_FORMAL_DRAFT_THREEPIECE_ACTUAL_SOURCE_TRACE_CONDITIONALLY_PASSED_PENDING_FOLLOWUP_EVIDENCE"
|
$row.conclusion_strength = "DRAFT_FOR_REVIEW_PENDING_OUTPUT_REVIEW_STRONG_FIELDS_RETAINED_AS_GAPS_NOT_OUTPUT_PASS"
|
$row.next_action = "执行 NEXT-ROBOT-032B 输出通过前补证包准备;IFR PDF 若引用页码/表格/正文事实需页码级抽取,MIR/Omdia/AMR/ASP/公司强字段继续缺口闭环;不申请输出通过、覆盖完整、对外交付或强字段升级。"
|
}
|
}
|
[System.IO.File]::WriteAllText($migrationPath, (ConvertTo-CsvText $migrationRows) + "`r`n", $Utf8NoBom)
|
|
# 3. review sync JSON.
|
$reviewSyncPath = Join-Path $EvidenceDir "threepiece_actual_source_trace_review_sync_20260705.json"
|
$reviewSync = [ordered]@{
|
case_id = $CaseId
|
action_id = "NEXT-ROBOT-032A"
|
run_id = $RunId
|
source_review_message = $ReviewMessageId
|
source_audit_id = $AuditId
|
synced_at = $NowStamp
|
review_conclusion = "CONDITIONALLY_PASSED"
|
allowed_next = @(
|
"作为后续输出通过前补证输入",
|
"准备 NEXT-ROBOT-032B 输出通过前补证包",
|
"继续页码级抽取、研报来源补强、官方快照或缺口闭环"
|
)
|
prohibited = @(
|
"输出通过",
|
"覆盖完整",
|
"对外交付",
|
"完成状态",
|
"正式扩池",
|
"正式公司池确认",
|
"强字段升级"
|
)
|
retained_gates = @(
|
"IFR 官方快照只支持全球工业机器人有限市场线索;如引用 PDF 页码、表格或正文事实,必须补页码级抽取。",
|
"MIR 协作机器人、Omdia 人形出货、智元引用、AMR、ASP、公司收入、客户供应、主供/独供、BOM 和利润池继续不得升级为强字段事实。",
|
"NEXT-ROBOT-032A 已同步为已复审/有条件通过/可作为后续补证输入。"
|
)
|
}
|
$reviewSyncJson = $reviewSync | ConvertTo-Json -Depth 8
|
[System.IO.File]::WriteAllText($reviewSyncPath, $reviewSyncJson + "`r`n", $Utf8NoBom)
|
|
# 4. Core documents and shared indexes.
|
$coreDocPaths = @(
|
(Join-Path $OutputCoreDir "机器人报告索引.md"),
|
(Join-Path $OutputCoreDir "机器人的产业链总览.md"),
|
(Join-Path $OutputCoreDir "机器人的市场情况总览.md")
|
)
|
$coreReviewBlockHeader = "## 0.4 NEXT-ROBOT-032A 复审承接"
|
$coreReviewBlockBody = @"
|
reviewer 已在 `$ReviewMessageId` / `$AuditId` 对三件套实际回源核验证据包给出有条件通过。该证据包可作为后续输出通过前补证输入,并允许继续准备 `NEXT-ROBOT-032B`:IFR PDF 页码级抽取、研报原始来源补强、官方快照或缺口闭环。
|
|
本结论不批准输出通过、覆盖完整、对外交付、完成状态、正式扩池、正式公司池确认或强字段升级。IFR 官方快照只支持全球工业机器人有限市场线索;MIR 协作机器人、Omdia 人形出货、智元引用、AMR、ASP、公司收入、客户供应、主供 / 独供、BOM 和利润池继续按缺口或待核验处理。
|
"@
|
foreach ($path in $coreDocPaths) {
|
$text = Read-Text $path
|
$text = $text.Replace("THREEPIECE_ACTUAL_SOURCE_TRACE_PREPARED", "THREEPIECE_ACTUAL_SOURCE_TRACE_CONDITIONALLY_PASSED")
|
$text = $text.Replace("NEXT_ROBOT_032A_REVIEW_REQUEST_PREPARED", "NEXT_ROBOT_032A_CONDITIONALLY_PASSED")
|
$text = Add-OrReplaceSection $text $coreReviewBlockHeader $coreReviewBlockBody
|
$text = $text.Replace('$ReviewMessageId', $ReviewMessageId).Replace('$AuditId', $AuditId)
|
Write-Text $path $text
|
}
|
|
$indexPath = Join-Path $ResultDir "result_index.md"
|
$indexText = Read-Text $indexPath
|
$indexText = $indexText.Replace("THREEPIECE_ACTUAL_SOURCE_TRACE_PREPARED", "THREEPIECE_ACTUAL_SOURCE_TRACE_CONDITIONALLY_PASSED")
|
$indexText = $indexText.Replace("NEXT_ROBOT_032A_REVIEW_REQUEST_PREPARED", "NEXT_ROBOT_032A_CONDITIONALLY_PASSED")
|
$indexText = $indexText.Replace("当前状态为 `THREEPIECE_ACTUAL_SOURCE_TRACE_PREPARED_PENDING_REVIEW_NOT_OUTPUT_PASS`。", "当前状态为 `THREEPIECE_ACTUAL_SOURCE_TRACE_CONDITIONALLY_PASSED_FOR_FOLLOWUP_EVIDENCE_NOT_OUTPUT_PASS`。")
|
$indexText = $indexText.Replace("当前状态为 `THREEPIECE_ACTUAL_SOURCE_TRACE_CONDITIONALLY_PASSED_PENDING_REVIEW_NOT_OUTPUT_PASS`。", "当前状态为 `THREEPIECE_ACTUAL_SOURCE_TRACE_CONDITIONALLY_PASSED_FOR_FOLLOWUP_EVIDENCE_NOT_OUTPUT_PASS`。")
|
$indexHeader = "## 2026-07-05 三件套实际回源核验证据包复审承接"
|
$indexBody = @"
|
reviewer 已在 `$ReviewMessageId` / `$AuditId` 对 `NEXT-ROBOT-032A` 给出有条件通过。该结论只允许把实际回源核验证据包作为后续输出通过前补证输入;不批准输出通过、覆盖完整、对外交付、完成状态、正式扩池、正式公司池确认或强字段升级。
|
|
下一步登记为 `NEXT-ROBOT-032B`:准备输出通过前补证包,重点是 IFR PDF 页码级抽取,以及 MIR、Omdia、AMR、ASP、公司收入、客户供应、主供 / 独供、BOM 和利润池等缺口继续闭环。
|
"@
|
$indexText = Add-OrReplaceSection $indexText $indexHeader $indexBody
|
$indexText = $indexText.Replace('$ReviewMessageId', $ReviewMessageId).Replace('$AuditId', $AuditId)
|
Write-Text $indexPath $indexText
|
|
# 5. remaining work plan.
|
$remainingPath = Join-Path $ManifestDir "remaining_work_plan_20260704.md"
|
$remainingText = Read-Text $remainingPath
|
$remainingText = $remainingText.Replace("| 6A | NEXT-ROBOT-032A | 三件套实际回源补证 | primary source、研报原始来源、页码 / 表格 / 截图 / 官方快照、缺口编号、影响范围和结论强度 | REVIEW_REQUEST_PREPARED | 仍不申请输出通过、覆盖完整、对外交付或强字段升级 |", "| 6A | NEXT-ROBOT-032A | 三件套实际回源补证 | primary source、研报原始来源、页码 / 表格 / 截图 / 官方快照、缺口编号、影响范围和结论强度 | CONDITIONALLY_PASSED | reviewer 已允许作为后续补证输入;仍不申请输出通过、覆盖完整、对外交付或强字段升级 |")
|
if (-not $remainingText.Contains("| 6B | NEXT-ROBOT-032B |")) {
|
$remainingText = $remainingText.Replace("| 7 | NEXT-ROBOT-033 | 英搏尔 + 12 个相邻候选 | 补资料复核、继续排除/降级/候选池决策 | QUEUED | 重新进入候选池需单独复审 |", "| 6B | NEXT-ROBOT-032B | 三件套输出通过前补证包 | IFR PDF 页码级抽取、MIR/Omdia/AMR/ASP/公司强字段补证缺口闭环 | QUEUED | 只能准备补证包;不得申请输出通过或强字段升级 |`r`n| 7 | NEXT-ROBOT-033 | 英搏尔 + 12 个相邻候选 | 补资料复核、继续排除/降级/候选池决策 | QUEUED | 重新进入候选池需单独复审 |")
|
}
|
$remainingText = $remainingText.Replace("- 当前状态:THREEPIECE_ACTUAL_SOURCE_TRACE_PREPARED_PENDING_REVIEW_NOT_OUTPUT_PASS;本轮只提交实际回源核验证据包复审,不申请输出通过、覆盖完整、对外交付、完成状态、正式扩池、正式公司池确认或强字段升级。", "- 当前状态:THREEPIECE_ACTUAL_SOURCE_TRACE_CONDITIONALLY_PASSED_FOR_FOLLOWUP_EVIDENCE_NOT_OUTPUT_PASS;reviewer 已允许作为后续输出通过前补证输入,仍不申请输出通过、覆盖完整、对外交付、完成状态、正式扩池、正式公司池确认或强字段升级。")
|
$remainingHeader = "## 17. 复审状态更新(AUDIT-ANA-ROBOT-THREEPIECE-ACTUAL-SOURCE-TRACE-001)"
|
$remainingBody = @"
|
- 来源消息:$ReviewMessageId。
|
- 复审结论:`NEXT-ROBOT-032A` 三件套实际回源核验证据包有条件通过,可作为后续输出通过前补证输入。
|
- 继续允许:准备 `NEXT-ROBOT-032B`,补 IFR PDF 页码级抽取、研报原始来源、官方快照、缺口编号、影响范围和结论强度。
|
- 继续禁止:输出通过、覆盖完整、对外交付、完成状态、正式扩池、正式公司池确认,以及市场规模、出货、ASP、公司收入、客户供应、主供 / 独供、BOM 和利润池等强字段升级。
|
"@
|
$remainingText = Add-OrReplaceSection $remainingText $remainingHeader $remainingBody
|
Write-Text $remainingPath $remainingText
|
|
# 6. Execution log.
|
$execLogPath = Join-Path $AuditDocDir "案例执行日志.md"
|
$execLogText = Read-Text $execLogPath
|
$execHeader = "## 2026-07-05 RUN-ANA-ROBOT-THREEPIECE-ACTUAL-SOURCE-TRACE-REVIEW-SYNC-001"
|
$execBody = @"
|
承接 reviewer 消息 `$ReviewMessageId` / `$AuditId`:`NEXT-ROBOT-032A` 三件套实际回源核验证据包复审结论为有条件通过。
|
|
- 已同步:next_action_list、remaining_work_plan、result_index、机器人报告索引、三件套文档、case_evidence_map 和 migration_manifest。
|
- 新增:`threepiece_actual_source_trace_review_sync_20260705.json`,记录允许事项、禁止事项和保留门禁。
|
- 后续:新增 `NEXT-ROBOT-032B` 输出通过前补证包队列;仍不申请输出通过、覆盖完整、对外交付、完成状态、正式扩池、正式公司池确认或强字段升级。
|
"@
|
$execLogText = Add-OrReplaceSection $execLogText $execHeader $execBody
|
$execLogText = $execLogText.Replace('$ReviewMessageId', $ReviewMessageId).Replace('$AuditId', $AuditId)
|
Write-Text $execLogPath $execLogText
|
|
# 7. Artifact manifest: update changed shared files and record this sync run.
|
$artifactManifestPath = Join-Path $ManifestDir "artifact_manifest.csv"
|
$artifactRows = @(Import-Csv -LiteralPath $artifactManifestPath)
|
$changedRelPaths = @(
|
(Rel-Path $nextPath),
|
(Rel-Path $evidenceMapPath),
|
(Rel-Path $migrationPath),
|
(Rel-Path $reviewSyncPath),
|
(Rel-Path $coreDocPaths[0]),
|
(Rel-Path $coreDocPaths[1]),
|
(Rel-Path $coreDocPaths[2]),
|
(Rel-Path $indexPath),
|
(Rel-Path $remainingPath),
|
(Rel-Path $execLogPath)
|
)
|
$artifactRows = @($artifactRows | Where-Object { $_.run_id -ne $RunId })
|
foreach ($rel in $changedRelPaths) {
|
$meta = Get-FileMeta $rel
|
$artifactRows += [pscustomobject]@{
|
case_id = $CaseId
|
run_id = $RunId
|
batch_id = $BatchId
|
artifact_path = $rel
|
sha256 = $meta.sha256
|
bytes = $meta.bytes
|
mtime = $meta.mtime
|
}
|
}
|
foreach ($row in $artifactRows) {
|
if ([string]::IsNullOrWhiteSpace($row.artifact_path)) {
|
continue
|
}
|
$full = Join-Path $ProjectRoot ($row.artifact_path -replace "/", "\")
|
if (Test-Path -LiteralPath $full) {
|
$meta = Get-FileMeta $row.artifact_path
|
$row.sha256 = $meta.sha256
|
$row.bytes = $meta.bytes
|
$row.mtime = $meta.mtime
|
}
|
}
|
[System.IO.File]::WriteAllText($artifactManifestPath, (ConvertTo-CsvText $artifactRows) + "`r`n", $Utf8NoBom)
|
|
# 8. Self-check.
|
$manifestRows = @(Import-Csv -LiteralPath $artifactManifestPath)
|
$missing = 0
|
$emptySha = 0
|
$mismatch = 0
|
foreach ($row in $manifestRows) {
|
if ([string]::IsNullOrWhiteSpace($row.sha256)) {
|
$emptySha++
|
}
|
$full = Join-Path $ProjectRoot ($row.artifact_path -replace "/", "\")
|
if (-not (Test-Path -LiteralPath $full)) {
|
$missing++
|
continue
|
}
|
$actual = (Get-FileHash -LiteralPath $full -Algorithm SHA256).Hash.ToLowerInvariant()
|
if ($actual -ne $row.sha256) {
|
$mismatch++
|
}
|
}
|
$scanFiles = $changedRelPaths | ForEach-Object { Join-Path $ProjectRoot ($_ -replace "/", "\") }
|
$placeholderHits = 0
|
$sensitiveHits = 0
|
foreach ($file in $scanFiles) {
|
if (-not (Test-Path -LiteralPath $file)) {
|
continue
|
}
|
$txt = Read-Text $file
|
if ($txt -match '\$\(|\$\{|\$extract') {
|
$placeholderHits++
|
}
|
if ($txt -match '(password|token|secret|cookie|连接串|123456)') {
|
$sensitiveHits++
|
}
|
}
|
|
[pscustomobject]@{
|
run_id = $RunId
|
next_032a_status = (@(Import-Csv -LiteralPath $nextPath) | Where-Object { $_.action_id -eq "NEXT-ROBOT-032A" }).status
|
next_032b_exists = [bool](@(Import-Csv -LiteralPath $nextPath) | Where-Object { $_.action_id -eq "NEXT-ROBOT-032B" })
|
manifest_rows = $manifestRows.Count
|
manifest_missing = $missing
|
manifest_empty_sha = $emptySha
|
manifest_mismatch = $mismatch
|
changed_artifacts = $changedRelPaths.Count
|
placeholder_hits = $placeholderHits
|
sensitive_hits = $sensitiveHits
|
}
|