build-edges.ps1 3.2 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495
  1. # Edge builder and validator for cockpit-real-data-wayfinding
  2. param(
  3. [string]$EffortDir = ""
  4. )
  5. if (-not $EffortDir) {
  6. $EffortDir = Split-Path $PSScriptRoot -Parent
  7. }
  8. $TicketsDir = Join-Path $EffortDir "issues"
  9. $MapPath = Join-Path $EffortDir "map.md"
  10. $ExpectedTickets = @{
  11. "01-backend-slice-ticket-boundary.md" = "None"
  12. "02-map-status-filter-and-unassociated-devices.md" = "01"
  13. "03-monitoring-created-at-contract.md" = "01"
  14. "04-real-lifecycle-contract.md" = "None"
  15. "05-integration-baseline-and-evidence.md" = "01, 04"
  16. "06-cross-mode-business-semantics.md" = "None"
  17. "07-map-status-filter-spec.md" = "02"
  18. "08-monitoring-created-at-spec.md" = "03"
  19. "09-real-lifecycle-spec.md" = "04"
  20. "10-business-semantics-spec.md" = "06"
  21. "11-backend-work-order-rate.md" = "01, 06"
  22. "12-backend-read-model-district.md" = "11"
  23. "13-backend-realtime-sync.md" = "12"
  24. "14-frontend-real-scope-filter.md" = "02, 04"
  25. "15-frontend-time-dimension-panel.md" = "03, 06"
  26. "16-frontend-alarm-order-consumption.md" = "01, 06"
  27. "17-postdeploy-live-verification.md" = "11"
  28. "18-frontend-real-integration-gate.md" = "14, 15, 16, 17"
  29. }
  30. $ExpectedCount = 18
  31. $Success = $true
  32. function Set-Edge {
  33. param([string]$TicketPath, [string]$ExpectedEdge)
  34. $Content = Get-Content $TicketPath -Raw
  35. $Line = "Blocked by: $ExpectedEdge"
  36. if ($Content -match "(?m)^Blocked by: .*$") {
  37. $Content = $Content -replace "(?m)^Blocked by: .*$", $Line
  38. } else {
  39. $Content = $Line + "`n`n" + $Content
  40. }
  41. Set-Content -Path $TicketPath -Value $Content -Encoding UTF8 -NoNewline
  42. }
  43. $TicketFiles = @(Get-ChildItem $TicketsDir -Filter "*.md")
  44. if ($TicketFiles.Count -ne $ExpectedCount) {
  45. Write-Host "Ticket count mismatch: expected $ExpectedCount, actual $($TicketFiles.Count)"
  46. $Success = $false
  47. }
  48. foreach ($Ticket in $TicketFiles) {
  49. if (-not $ExpectedTickets.ContainsKey($Ticket.Name)) {
  50. Write-Host "Unexpected ticket: $($Ticket.Name)"
  51. $Success = $false
  52. continue
  53. }
  54. Set-Edge $Ticket.FullName $ExpectedTickets[$Ticket.Name]
  55. }
  56. $MapContent = Get-Content $MapPath -Raw
  57. if ($MapContent -notmatch "(?m)^## Destination$") {
  58. Write-Host "Map is missing ## Destination"
  59. $Success = $false
  60. }
  61. $TaskLines = @([regex]::Matches($MapContent, '(?m)^- \[.\] \[\d{2}: .*?\]\(issues/.*?\.md\)$'))
  62. if ($TaskLines.Count -ne $ExpectedCount) {
  63. Write-Host "Map task count mismatch: expected $ExpectedCount, actual $($TaskLines.Count)"
  64. $Success = $false
  65. }
  66. foreach ($Ticket in @(Get-ChildItem $TicketsDir -Filter "*.md")) {
  67. $Content = Get-Content $Ticket.FullName -Raw
  68. if ($Content -notmatch "(?m)^Blocked by: (.*?)$") {
  69. Write-Host "Missing Blocked by in $($Ticket.Name)"
  70. $Success = $false
  71. continue
  72. }
  73. $Refs = $Matches[1] -split "," | ForEach-Object { $_.Trim() }
  74. foreach ($Ref in $Refs) {
  75. if ($Ref -ne "None" -and -not @(Get-ChildItem $TicketsDir -Filter "$Ref*.md")) {
  76. Write-Host "Invalid dependency in $($Ticket.Name): $Ref"
  77. $Success = $false
  78. }
  79. }
  80. }
  81. if (-not $Success) {
  82. Write-Host "Validation failed."
  83. exit 1
  84. }
  85. Write-Host "Edges and map validated: $ExpectedCount tickets, $($TaskLines.Count) map entries."