Files
CM95/scripts/cm95_japan_continue_from_step8.ps1

393 lines
12 KiB
PowerShell

param(
[string]$ProjectRoot = "D:\React\cm93-mysql-importer-starter",
[string]$SourceRoot = "D:\Ship\CM93V2\CM93JAPAN",
[int]$DatasetId = 1,
[int]$ExpectedCells = 1492,
[int]$Workers = 4
)
Set-StrictMode -Version Latest
$ErrorActionPreference = "Stop"
function Step([string]$Text) {
Write-Host ""
Write-Host "======================================================================"
Write-Host $Text
Write-Host "======================================================================"
}
function Run([string]$Label, [scriptblock]$Action) {
Step $Label
& $Action
$Code = $LASTEXITCODE
if ($null -ne $Code -and $Code -ne 0) {
throw "$Label FAILED (exit=$Code)"
}
}
function StateCount($States, [string]$Name) {
if ($null -eq $States) { return 0 }
$P = $States.PSObject.Properties[$Name]
if ($null -eq $P) { return 0 }
return [int]$P.Value
}
Set-Location $ProjectRoot
$Python = ".\.venv\Scripts\python.exe"
$Cm95Pbf = ".\.venv\Scripts\cm95pbf.exe"
$Mapping = ".\config\mappings\cm95_to_navsea_v1.yaml"
$Disposition = ".\config\mappings\cm95_gap_disposition_japan_dataset_1_v1.yaml"
$Policy = ".\config\pbf\cm95_tile_policy_japan_full_detail_v1.yaml"
$GapAudit = ".\build\production\cm95_global_mapping_gap_audit_dataset_1.json"
$Closure = ".\build\production\cm95_global_mapping_gap_closure_dataset_1_after_review.json"
$MappingContract = ".\build\production\cm95_mapping_contract_check_japan_dataset_1.json"
$Manifest = ".\build\cm95_fid_manifest_japan_dataset_1_v1.sqlite"
$Plan = ".\build\production\cm95_production_plan_japan_full_detail_v1.json"
$PlanAudit = ".\build\production\cm95_production_plan_audit_japan_full_detail_v1.json"
foreach ($Path in @($Python,$Cm95Pbf,$Mapping,$Disposition,$Policy)) {
if (-not (Test-Path $Path)) {
throw "Missing required file: $Path"
}
}
# ----------------------------------------------------------------------
# 0. Verify v1.4.5 runtime
# ----------------------------------------------------------------------
Run "STEP 0 - CM95 v1.4.5 preflight" {
& $Python ".\tools\cm95_v1_4_5_preflight.py"
}
# ----------------------------------------------------------------------
# 1. Verify fresh Japan Dataset in MySQL, no reimport
# ----------------------------------------------------------------------
Step "STEP 1 - Verify existing fresh Japan Dataset"
$Tmp = Join-Path $env:TEMP ("cm95_japan_continue_" + $PID)
Remove-Item $Tmp -Recurse -Force -ErrorAction SilentlyContinue
New-Item -ItemType Directory -Path $Tmp | Out-Null
try {
$Helper = Join-Path $Tmp "verify_dataset.py"
@'
from pathlib import Path
from dotenv import load_dotenv
import os, sys, json, pymysql
project_root = Path(sys.argv[1]).resolve()
dataset_id = int(sys.argv[2])
expected_root = str(Path(sys.argv[3]).resolve())
load_dotenv(dotenv_path=project_root / ".env")
conn = pymysql.connect(
host=os.getenv("CM93_DB_HOST", "127.0.0.1"),
port=int(os.getenv("CM93_DB_PORT", "3306")),
user=os.getenv("CM93_DB_USER", "root"),
password=os.getenv("CM93_DB_PASSWORD", ""),
database=os.getenv("CM93_DB_NAME", "cm93_chart"),
charset=os.getenv("CM93_DB_CHARSET", "utf8mb4"),
cursorclass=pymysql.cursors.DictCursor,
)
try:
with conn.cursor() as cur:
cur.execute(
"""
SELECT d.id,d.name,d.source_root,
COUNT(c.id) cells,
SUM(c.import_status='DONE') done_cells,
SUM(c.import_status='FAILED') failed_cells
FROM chart_dataset d
LEFT JOIN chart_cell c ON c.dataset_id=d.id
WHERE d.id=%s
GROUP BY d.id,d.name,d.source_root
""",
(dataset_id,),
)
row = cur.fetchone()
if not row:
raise RuntimeError(f"dataset {dataset_id} not found")
actual_root = str(Path(row["source_root"]).resolve())
result = {
"id": int(row["id"]),
"name": row["name"],
"source_root": actual_root,
"cells": int(row["cells"] or 0),
"done_cells": int(row["done_cells"] or 0),
"failed_cells": int(row["failed_cells"] or 0),
}
if actual_root.lower() != expected_root.lower():
raise RuntimeError(
f"source_root mismatch: {actual_root} != {expected_root}"
)
print(json.dumps(result, ensure_ascii=False))
finally:
conn.close()
'@ | Set-Content $Helper -Encoding UTF8
$DatasetText = (
& $Python $Helper $ProjectRoot $DatasetId $SourceRoot |
Out-String
).Trim()
if ($LASTEXITCODE -ne 0) {
throw "Dataset verification failed"
}
$Dataset = $DatasetText | ConvertFrom-Json
if ([int]$Dataset.cells -ne $ExpectedCells -or
[int]$Dataset.done_cells -ne $ExpectedCells -or
[int]$Dataset.failed_cells -ne 0) {
throw "Dataset state mismatch: $DatasetText"
}
Write-Host $DatasetText
}
finally {
Remove-Item $Tmp -Recurse -Force -ErrorAction SilentlyContinue
}
# ----------------------------------------------------------------------
# 2. Re-run gap audit and closure with the new dataset-specific disposition
# ----------------------------------------------------------------------
Run "STEP 2A - Re-run global mapping gap audit" {
& $Python ".\tools\cm95_global_mapping_gap_audit_v1.py" `
--dataset-id $DatasetId `
--mapping $Mapping `
--output $GapAudit
}
Run "STEP 2B - Close 25 new Japan gap variants" {
& $Python ".\tools\cm95_global_mapping_gap_closure_audit_v2.py" `
--gap-audit $GapAudit `
--mapping $Mapping `
--disposition $Disposition `
--output $Closure
}
$C = Get-Content $Closure -Raw | ConvertFrom-Json
if ([string]$C.overall -ne "PASS") {
throw "Mapping gap closure is not PASS"
}
if (@($C.unclassified_variants).Count -ne 0) {
throw "Unclassified variants remain"
}
if ([int]$C.observed_gap_variants -ne 165) {
throw "Unexpected gap variant count: $($C.observed_gap_variants)"
}
if (@($C.pending_semantic_review).Count -ne 137) {
throw "Unexpected pending variant count: $(@($C.pending_semantic_review).Count)"
}
if ([int]$C.pending_semantic_review_feature_rows -ne 90009) {
throw "Unexpected pending rows: $($C.pending_semantic_review_feature_rows)"
}
Write-Host ""
Write-Host "Expected closure confirmed:"
Write-Host " observed = 165"
Write-Host " unclassified = 0"
Write-Host " pending = 137"
Write-Host " pending rows = 90009"
Write-Host " overall = PASS"
# ----------------------------------------------------------------------
# 3. Static mapping/style/sprite contract
# ----------------------------------------------------------------------
Run "STEP 3 - Mapping / Style / Sprite static contract" {
& $Python ".\tools\cm95_mapping_contract_check_v1.py" `
--mapping $Mapping `
--style ".\config\style\style.navsea-delivery-full-semantic-unified-20260808-cm95-v1.json" `
--sprite-json ".\config\sprite\semantic-sprite-20260808.json" `
--output $MappingContract
}
$MC = Get-Content $MappingContract -Raw | ConvertFrom-Json
if ([string]$MC.overall -ne "PASS") {
throw "Mapping/style/sprite contract failed"
}
# ----------------------------------------------------------------------
# 4. Full-detail policy hard gate: G=7500 must be in z12
# ----------------------------------------------------------------------
Step "STEP 4 - Japan full-detail policy check"
$PolicyObj = Get-Content $Policy -Raw |
& $Python -c "import sys,yaml,json; print(json.dumps(yaml.safe_load(sys.stdin.read())))" |
ConvertFrom-Json
# No multi-line Python is passed here; only a fixed one-line expression.
$Enum12 = @($PolicyObj.enumeration_scales.'12')
$Ladder12 = @($PolicyObj.scale_ladders.'12')
if (7500 -notin $Enum12 -or
$Ladder12.Count -eq 0 -or
[int]$Ladder12[0] -ne 7500) {
throw "Japan full-detail policy does not prioritize G=7500 at z12"
}
Write-Host "z12 enumeration : $($Enum12 -join ', ')"
Write-Host "z12 ladder : $($Ladder12 -join ', ')"
Write-Host "G=7500 gate : PASS"
# ----------------------------------------------------------------------
# 5. Reset PBF-side outputs only. MySQL remains untouched.
# ----------------------------------------------------------------------
Step "STEP 5 - Reset PBF-side outputs only"
Remove-Item ".\build\releases" -Recurse -Force -ErrorAction SilentlyContinue
Remove-Item $Manifest -Force -ErrorAction SilentlyContinue
Remove-Item $Plan -Force -ErrorAction SilentlyContinue
Remove-Item $PlanAudit -Force -ErrorAction SilentlyContinue
New-Item -ItemType Directory -Force -Path ".\build\releases" | Out-Null
# ----------------------------------------------------------------------
# 6. Fresh deterministic FID manifest
# ----------------------------------------------------------------------
Run "STEP 6 - Build fresh FID manifest" {
& $Cm95Pbf build-fid-manifest `
--dataset-id $DatasetId `
--manifest $Manifest `
--rebuild-fid-manifest
}
# ----------------------------------------------------------------------
# 7. Fresh production plan using G=7500-aware z12 policy
# ----------------------------------------------------------------------
Run "STEP 7A - plan-production z0-z12 Japan full detail" {
& $Cm95Pbf plan-production `
--dataset-id $DatasetId `
--zooms 0-12 `
--profile delivery `
--mapping $Mapping `
--policy $Policy `
--manifest $Manifest `
--output $Plan
}
Run "STEP 7B - production plan audit" {
& $Python ".\tools\cm95_production_plan_audit_v1.py" `
--plan $Plan `
--expected-zooms 0-12 `
--output $PlanAudit
}
$PA = Get-Content $PlanAudit -Raw | ConvertFrom-Json
if ([string]$PA.overall -ne "PASS") {
throw "Production plan audit failed"
}
$PlanObj = Get-Content $Plan -Raw | ConvertFrom-Json
$ReleaseId = [string]$PlanObj.release_id
Write-Host ""
Write-Host "Plan ID : $($PlanObj.plan_id)"
Write-Host "Release ID : $ReleaseId"
Write-Host "Jobs : $($PlanObj.job_count)"
# ----------------------------------------------------------------------
# 8. Full production build
# ----------------------------------------------------------------------
Run "STEP 8 - Full PBF production build" {
& $Cm95Pbf build-production `
--plan $Plan `
--release-root ".\build\releases" `
--workers $Workers `
--max-attempts 3
}
# ----------------------------------------------------------------------
# 9. Status
# ----------------------------------------------------------------------
Step "STEP 9 - Production status"
$StatusText = (
& $Cm95Pbf status-production `
--plan $Plan `
--release-root ".\build\releases" |
Out-String
).Trim()
if ($LASTEXITCODE -ne 0) {
throw "status-production failed"
}
Write-Host $StatusText
$S = $StatusText | ConvertFrom-Json
$Pass = StateCount $S.states "PASS"
$Fail = StateCount $S.states "FAILED"
$Pending = StateCount $S.states "PENDING"
$Running = StateCount $S.states "RUNNING"
if ($Pass -ne [int]$S.jobs -or
$Fail -ne 0 -or
$Pending -ne 0 -or
$Running -ne 0) {
throw "Production state gate failed"
}
# ----------------------------------------------------------------------
# 10. Final release gate
# ----------------------------------------------------------------------
Run "STEP 10 - Finalize production release" {
& $Cm95Pbf finalize-production `
--plan $Plan `
--release-root ".\build\releases" `
--style ".\config\style\style.navsea-delivery-full-semantic-unified-20260808-cm95-v1.json" `
--sprite-json ".\config\sprite\semantic-sprite-20260808.json" `
--gap-disposition $Disposition
}
$ReleaseManifest = ".\build\releases\$ReleaseId\release_manifest_v1.json"
if (-not (Test-Path $ReleaseManifest)) {
throw "Release manifest missing: $ReleaseManifest"
}
$Final = Get-Content $ReleaseManifest -Raw | ConvertFrom-Json
if ([string]$Final.status -ne "PASS") {
throw "Final release status is not PASS"
}
Step "JAPAN CONTINUATION COMPLETE / PASS"
Write-Host "Dataset ID : $DatasetId"
Write-Host "Release ID : $ReleaseId"
Write-Host "Jobs : $($S.jobs)"
Write-Host "PBF files : $($S.pbf_files)"
Write-Host "Output features : $($S.output_features)"
Write-Host "Semantic status : $($Final.semantic_completeness)"
Write-Host "Pending variants : 137"
Write-Host "Pending rows : 90009"
Write-Host ""
Write-Host "Web test:"
Write-Host " cd `"$ProjectRoot`""
Write-Host " & `".\.venv\Scripts\python.exe`" .\web\cm95_web.py --release-id `"$ReleaseId`""