# Edge builder and validator for cockpit-real-data-wayfinding param( [string]$EffortDir = "" ) if (-not $EffortDir) { $EffortDir = Split-Path $PSScriptRoot -Parent } $TicketsDir = Join-Path $EffortDir "issues" $MapPath = Join-Path $EffortDir "map.md" $ExpectedTickets = @{ "01-backend-slice-ticket-boundary.md" = "None" "02-map-status-filter-and-unassociated-devices.md" = "01" "03-monitoring-created-at-contract.md" = "01" "04-real-lifecycle-contract.md" = "None" "05-integration-baseline-and-evidence.md" = "01, 04" "06-cross-mode-business-semantics.md" = "None" "07-map-status-filter-spec.md" = "02" "08-monitoring-created-at-spec.md" = "03" "09-real-lifecycle-spec.md" = "04" "10-business-semantics-spec.md" = "06" "11-backend-work-order-rate.md" = "01, 06" "12-backend-read-model-district.md" = "11" "13-backend-realtime-sync.md" = "12" "14-frontend-real-scope-filter.md" = "02, 04" "15-frontend-time-dimension-panel.md" = "03, 06" "16-frontend-alarm-order-consumption.md" = "01, 06" "17-postdeploy-live-verification.md" = "11" "18-frontend-real-integration-gate.md" = "14, 15, 16, 17" } $ExpectedCount = 18 $Success = $true function Set-Edge { param([string]$TicketPath, [string]$ExpectedEdge) $Content = Get-Content $TicketPath -Raw $Line = "Blocked by: $ExpectedEdge" if ($Content -match "(?m)^Blocked by: .*$") { $Content = $Content -replace "(?m)^Blocked by: .*$", $Line } else { $Content = $Line + "`n`n" + $Content } Set-Content -Path $TicketPath -Value $Content -Encoding UTF8 -NoNewline } $TicketFiles = @(Get-ChildItem $TicketsDir -Filter "*.md") if ($TicketFiles.Count -ne $ExpectedCount) { Write-Host "Ticket count mismatch: expected $ExpectedCount, actual $($TicketFiles.Count)" $Success = $false } foreach ($Ticket in $TicketFiles) { if (-not $ExpectedTickets.ContainsKey($Ticket.Name)) { Write-Host "Unexpected ticket: $($Ticket.Name)" $Success = $false continue } Set-Edge $Ticket.FullName $ExpectedTickets[$Ticket.Name] } $MapContent = Get-Content $MapPath -Raw if ($MapContent -notmatch "(?m)^## Destination$") { Write-Host "Map is missing ## Destination" $Success = $false } $TaskLines = @([regex]::Matches($MapContent, '(?m)^- \[.\] \[\d{2}: .*?\]\(issues/.*?\.md\)$')) if ($TaskLines.Count -ne $ExpectedCount) { Write-Host "Map task count mismatch: expected $ExpectedCount, actual $($TaskLines.Count)" $Success = $false } foreach ($Ticket in @(Get-ChildItem $TicketsDir -Filter "*.md")) { $Content = Get-Content $Ticket.FullName -Raw if ($Content -notmatch "(?m)^Blocked by: (.*?)$") { Write-Host "Missing Blocked by in $($Ticket.Name)" $Success = $false continue } $Refs = $Matches[1] -split "," | ForEach-Object { $_.Trim() } foreach ($Ref in $Refs) { if ($Ref -ne "None" -and -not @(Get-ChildItem $TicketsDir -Filter "$Ref*.md")) { Write-Host "Invalid dependency in $($Ticket.Name): $Ref" $Success = $false } } } if (-not $Success) { Write-Host "Validation failed." exit 1 } Write-Host "Edges and map validated: $ExpectedCount tickets, $($TaskLines.Count) map entries."