feat(plan-01): Phase 1 — relocate harness code to packages/casan-harness (symlink facade)
Physically move the pure-code subtrees out of .specify into the package, leaving compat symlinks at the old .specify/<dir> paths so every existing reference (internal CASAN_HARNESS_ROOT + external CI/docker/mjs) keeps resolving. Runtime state stays put. Moved (git mv): scripts/ tests/ security/ templates/ config/ governance/ memory/ .specify/<dir> -> packages/casan-harness/<dir> (+ .specify/<dir> symlink) Stays in .specify (state/governance/domain, handled later): logs/ agentops/ level5/ init-options.json traceability-map.json Python `.resolve()` self-location followed the compat symlink into packages and lost the app root; generate-casan-demo-context.py, generate-agentops-dashboard.py and dashboard-server.py now walk UP for the `.specify` state marker instead of a fixed parent depth (fixes "missing trace files" in run-casan4). Full gate: PASS=64 FAIL=0 SKIP=3 (CASAN_CI_STEP_TIMEOUT_SEC=1200 — track-a ~450s runs close to the 600s default and can tip over under load; this is timing variance, not a regression — it passed cleanly with headroom). Runtime log/audit artifacts kept unstaged. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
2c765c9a45
commit
664bd1f00c
@@ -0,0 +1,89 @@
|
||||
#!/usr/bin/env pwsh
|
||||
# CASAN L5 Rollback Manager - PowerShell port of rollback-manager.sh
|
||||
# Usage:
|
||||
# rollback-manager.ps1 record <action> <rollback-command>
|
||||
# rollback-manager.ps1 execute <transaction-id>
|
||||
# rollback-manager.ps1 list
|
||||
#
|
||||
# Exit codes: 0=success, 1=error, 64=usage error
|
||||
|
||||
param(
|
||||
[Parameter(Mandatory=$true, Position=0)][ValidateSet("record","execute","list")][string]$Mode,
|
||||
[Parameter(Position=1)][string]$Arg1 = "",
|
||||
[Parameter(Position=2)][string]$Arg2 = ""
|
||||
)
|
||||
|
||||
$ErrorActionPreference = "Stop"
|
||||
|
||||
$scriptDir = Split-Path $MyInvocation.MyCommand.Path -Parent
|
||||
$projectRoot = (Resolve-Path (Join-Path $scriptDir "../../..")).Path
|
||||
$logDir = Join-Path $projectRoot ".specify/logs/level5"
|
||||
$txLog = Join-Path $logDir "rollback-transactions.jsonl"
|
||||
|
||||
if (!(Test-Path $logDir)) { New-Item -ItemType Directory -Force -Path $logDir | Out-Null }
|
||||
|
||||
function New-TraceId {
|
||||
try { return [System.Guid]::NewGuid().ToString("D") } catch { return "tx-$(Get-Date -Format 'yyyyMMddHHmmss')-$PID" }
|
||||
}
|
||||
|
||||
switch ($Mode) {
|
||||
"record" {
|
||||
$action = $Arg1
|
||||
$rollbackCommand = $Arg2
|
||||
if (!$action -or !$rollbackCommand) {
|
||||
Write-Error "Usage: rollback-manager.ps1 record <action> <rollback-command>"
|
||||
exit 64
|
||||
}
|
||||
$txId = New-TraceId
|
||||
$timestamp = (Get-Date).ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ssZ")
|
||||
$gitRef = ""
|
||||
try { $gitRef = (git rev-parse HEAD 2>$null).Trim() } catch {}
|
||||
|
||||
$line = "{`"timestamp`":`"$timestamp`",`"transaction_id`":`"$txId`",`"action`":`"$action`",`"rollback_command`":`"$(($rollbackCommand -replace '"','\"'))`",`"git_ref`":`"$gitRef`",`"status`":`"recorded`"}"
|
||||
Add-Content -Path $txLog -Value $line -Encoding UTF8
|
||||
Write-Output "ROLLBACK_RECORDED transaction_id=$txId"
|
||||
exit 0
|
||||
}
|
||||
|
||||
"execute" {
|
||||
$txId = $Arg1
|
||||
if (!$txId) { Write-Error "Usage: rollback-manager.ps1 execute <transaction-id>"; exit 64 }
|
||||
if (!(Test-Path $txLog)) { Write-Error "ROLLBACK_NOT_FOUND: transaction log missing"; exit 1 }
|
||||
|
||||
$found = $false
|
||||
$cmd = ""
|
||||
foreach ($line in (Get-Content $txLog)) {
|
||||
try {
|
||||
$rec = $line | ConvertFrom-Json
|
||||
if ($rec.transaction_id -eq $txId) {
|
||||
$cmd = $rec.rollback_command
|
||||
$found = $true
|
||||
break
|
||||
}
|
||||
} catch {}
|
||||
}
|
||||
|
||||
if (!$found -or !$cmd) {
|
||||
Write-Error "ROLLBACK_NOT_FOUND transaction_id=$txId"
|
||||
exit 1
|
||||
}
|
||||
|
||||
Write-Output "Executing rollback: $cmd"
|
||||
Invoke-Expression $cmd
|
||||
$execExit = $LASTEXITCODE
|
||||
|
||||
$timestamp = (Get-Date).ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ssZ")
|
||||
Add-Content -Path $txLog -Value "{`"timestamp`":`"$timestamp`",`"transaction_id`":`"$txId`",`"status`":`"rolled_back`",`"exit_code`":$execExit}" -Encoding UTF8
|
||||
Write-Output "ROLLBACK_EXECUTED transaction_id=$txId exit_code=$execExit"
|
||||
exit $execExit
|
||||
}
|
||||
|
||||
"list" {
|
||||
if (!(Test-Path $txLog)) { Write-Output "No rollback transactions recorded."; exit 0 }
|
||||
$records = Get-Content $txLog | ForEach-Object {
|
||||
try { $_ | ConvertFrom-Json } catch { $null }
|
||||
} | Where-Object { $_ }
|
||||
$records | Format-Table transaction_id, action, status, timestamp -AutoSize
|
||||
exit 0
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user