[CLAUDE] Docs: S149-S150 closeout — bookend lượt đầu end-to-end (hình B) + 2 arc đóng + tally #53 chốt 45
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 5m48s
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 5m48s
- Arc-1 hội-tụ-bookend (rename 5 vai + 4 máy PS1 + C9-C12) + arc-2 adap-backlog 23/23 + probe Opus-5 khép (S149)
- Bookend @close S150: wave 6 vai (4 đo + 2 KIỂM) → 20 FLAG disposition từng-dòng; ring1 31/34-ĐẠT, ring2 10/10 + M-1 view-stale-role-desc
- Khoá _frozen_until_owner CẮM trước h24-signal-write (frozen-held in thật); 9 class FIRE; JUMP dải {5,4,4,3}+asym{1,4} chờ anh #21
- STATUS bump CURRENT S149-S150 + 2 khối Recently Done; HANDOFF segment mới + re-stamp đủ-slug + (17)(18)(19) lật + (14) viết lại + 6 slot #21-#26
- K2 posture-A @engine PHẦN K + K5 luật TÁCH vòng-đo-mới @session-end (O-2/O-3 OWNER-DELEGATED execute)
- sleep-doc derive-monitor-set (bỏ hardcode 4-tên); spawn-model-audit desc/comment fix; h24-signal-write param-default fix (first-live bug)
- M9 on-behalf ×3 (tooling + inv-cb F3 + reviewer F4); ring1/ring4 nhà seed; ring2 3 cite-dead vá
- Sổ garble #53 derive-from-body chốt 45 + sub-class ngược-#53/skeleton-ruột-rỗng (ghi-đĩa CẦN-KHÔNG-ĐỦ)
- Session-log S149-S150 (Sàn-5 đăng-ký 6 run=) + closeout-synthesis dạng-1
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
158
scripts/session-scaffold.ps1
Normal file
158
scripts/session-scaffold.ps1
Normal file
@ -0,0 +1,158 @@
|
||||
# session-scaffold.ps1 -- scaffold 1 logic-session folder + _context skeleton (M1, S149).
|
||||
# TAILOR tu hub AI_INFRA/scripts/session_scaffold.py (169 dong) -> SE PowerShell, 2-mode split @S146.
|
||||
#
|
||||
# MODE (exactly one):
|
||||
# -New : allocate a NEW logic-session = max+1 (session-start ONLY). Optional -N pins an
|
||||
# explicit id; if that id already exists (folder OR _context) -> COLLISION
|
||||
# (exit 4, writes NOTHING).
|
||||
# -Ensure : idempotent heal of the CURRENT session (pause/tiep). _context missing -> create;
|
||||
# _context present -> exit 0 NO-OP (mtime preserved). Optional -N pins the id;
|
||||
# default = max existing session.
|
||||
#
|
||||
# INVARIANTS:
|
||||
# - ts-moc = `git log -1 --format=%cI` of RepoRoot HEAD (git-committer). NO wall-clock: git
|
||||
# unavailable -> exit 3 (refuse Get-Date). Deliberate DEVIATION from hub tagged-FALLBACK --
|
||||
# spec M1 line 33 "khong wall-clock"; ts feeds C10 LATENESS measurement, must be deterministic.
|
||||
# - NEVER overwrite an existing _context (ANY mode) -- hard guard in Write-Context (exit 5).
|
||||
# - Pure-ASCII source (gotcha #30/#37 = PS 5.1 diacritics parser-fail). Vietnamese lives ONLY
|
||||
# in the external template .md, never in this .ps1.
|
||||
#
|
||||
# -RepoRoot = fault-inject seam: point at a scratch tree to prove teeth, not just happy-path.
|
||||
# Exit codes: 0 ok/no-op | 2 usage | 3 git-unavailable | 4 collision | 5 defensive-overwrite-block.
|
||||
|
||||
param(
|
||||
[switch]$New,
|
||||
[switch]$Ensure,
|
||||
[int]$N,
|
||||
[string]$RepoRoot = "$PSScriptRoot\.."
|
||||
)
|
||||
|
||||
$ErrorActionPreference = 'Stop'
|
||||
|
||||
# --- helpers ---
|
||||
function Fail {
|
||||
param([string]$Msg, [int]$Code)
|
||||
Write-Output "session-scaffold: ERROR: $Msg"
|
||||
exit $Code
|
||||
}
|
||||
|
||||
function Invoke-Git {
|
||||
# Run git with stderr discarded; return @{ Out; Code }. EAP=Continue so a non-repo tree
|
||||
# (git exit 128) does NOT throw under the script-wide Stop preference.
|
||||
param([string[]]$GitArgs)
|
||||
$old = $ErrorActionPreference
|
||||
$ErrorActionPreference = 'Continue'
|
||||
try {
|
||||
$out = & git @GitArgs 2>$null
|
||||
return @{ Out = (($out | Out-String)).Trim(); Code = $LASTEXITCODE }
|
||||
} finally {
|
||||
$ErrorActionPreference = $old
|
||||
}
|
||||
}
|
||||
|
||||
function Rel {
|
||||
param([string]$Path, [string]$Root)
|
||||
if ($Path.StartsWith($Root, [StringComparison]::OrdinalIgnoreCase)) {
|
||||
return $Path.Substring($Root.Length).TrimStart('\', '/')
|
||||
}
|
||||
return $Path
|
||||
}
|
||||
|
||||
function Write-Context {
|
||||
# Render template -> _context, UTF-8 no-BOM + LF. HARD guard: never overwrite an existing
|
||||
# _context (any mode) -- this is the durable owner-evidence file.
|
||||
param([string]$TemplatePath, [string]$OutPath, [int]$SessionN, [string]$Ts, [string]$Head)
|
||||
if (Test-Path -LiteralPath $OutPath) {
|
||||
Fail "REFUSE-OVERWRITE: $OutPath exists (never overwrite _context)" 5
|
||||
}
|
||||
$tpl = [System.IO.File]::ReadAllText($TemplatePath, [System.Text.Encoding]::UTF8)
|
||||
$rendered = $tpl.Replace('{{N}}', "$SessionN").Replace('{{TS}}', $Ts).Replace('{{HEAD}}', $Head)
|
||||
$rendered = $rendered -replace "`r`n", "`n"
|
||||
$outDir = Split-Path -Parent $OutPath
|
||||
if (-not (Test-Path -LiteralPath $outDir)) {
|
||||
New-Item -ItemType Directory -Path $outDir -Force | Out-Null
|
||||
}
|
||||
$enc = New-Object System.Text.UTF8Encoding($false) # $false = emit NO byte-order-mark
|
||||
[System.IO.File]::WriteAllText($OutPath, $rendered, $enc)
|
||||
}
|
||||
|
||||
# --- validate mode (exactly one) ---
|
||||
if ($New -and $Ensure) { Fail "specify exactly one of -New / -Ensure (both given)" 2 }
|
||||
if (-not $New -and -not $Ensure) { Fail "specify exactly one of -New / -Ensure (none given)" 2 }
|
||||
|
||||
$explicitN = $PSBoundParameters.ContainsKey('N')
|
||||
if ($explicitN -and $N -lt 0) { Fail "-N must be a non-negative integer (got $N)" 2 }
|
||||
|
||||
# --- resolve root + template ---
|
||||
if (-not (Test-Path -LiteralPath $RepoRoot)) { Fail "RepoRoot not found: $RepoRoot" 2 }
|
||||
$root = (Resolve-Path -LiteralPath $RepoRoot).Path
|
||||
$templatePath = Join-Path $root '.claude\templates\session-context-template.md'
|
||||
if (-not (Test-Path -LiteralPath $templatePath)) { Fail "template not found: $templatePath" 2 }
|
||||
$sessionsRoot = Join-Path $root '.claude\sessions'
|
||||
|
||||
# --- compute max existing session-<N> ---
|
||||
$maxN = 0
|
||||
if (Test-Path -LiteralPath $sessionsRoot) {
|
||||
Get-ChildItem -LiteralPath $sessionsRoot -Directory -ErrorAction SilentlyContinue | ForEach-Object {
|
||||
if ($_.Name -match '^session-(\d+)$') {
|
||||
$k = [int]$Matches[1]
|
||||
if ($k -gt $maxN) { $maxN = $k }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# --- resolve target N per mode ---
|
||||
if ($New) {
|
||||
if ($explicitN) { $targetN = $N } else { $targetN = $maxN + 1 }
|
||||
} else {
|
||||
if ($explicitN) {
|
||||
$targetN = $N
|
||||
} else {
|
||||
if ($maxN -lt 1) { Fail "-Ensure: no existing session to heal (run -New first)" 2 }
|
||||
$targetN = $maxN
|
||||
}
|
||||
}
|
||||
|
||||
$sessionDir = Join-Path $sessionsRoot "session-$targetN"
|
||||
$contextPath = Join-Path $sessionDir "_context-s-$targetN.md"
|
||||
$folderExists = Test-Path -LiteralPath $sessionDir
|
||||
$contextExists = Test-Path -LiteralPath $contextPath
|
||||
|
||||
# --- ts-moc from git HEAD (NO wall-clock; refuse if git down) ---
|
||||
$r1 = Invoke-Git @('-C', $root, 'log', '-1', '--format=%cI')
|
||||
$r2 = Invoke-Git @('-C', $root, 'log', '-1', '--format=%h')
|
||||
if ($r1.Code -ne 0 -or $r2.Code -ne 0) {
|
||||
Fail "git HEAD unavailable at $root -- refusing wall-clock fallback (spec M1: no wall-clock)" 3
|
||||
}
|
||||
$ts = $r1.Out
|
||||
$head = $r2.Out
|
||||
if ([string]::IsNullOrWhiteSpace($ts)) {
|
||||
Fail "git returned empty committer-ts -- refusing wall-clock fallback" 3
|
||||
}
|
||||
|
||||
# --- mode: New (allocate; collision => write NOTHING) ---
|
||||
if ($New) {
|
||||
if ($folderExists -or $contextExists) {
|
||||
$why = if ($contextExists) { "_context exists" } else { "session folder exists" }
|
||||
Write-Output "session-scaffold: COLLISION session-$targetN ($why) -- writing NOTHING (exit 4)."
|
||||
exit 4
|
||||
}
|
||||
Write-Context -TemplatePath $templatePath -OutPath $contextPath -SessionN $targetN -Ts $ts -Head $head
|
||||
Write-Output "session-scaffold: [New] created session-$targetN (max was $maxN)"
|
||||
Write-Output " folder = $(Rel $sessionDir $root)"
|
||||
Write-Output " context = $(Rel $contextPath $root)"
|
||||
Write-Output " ts-moc = $ts (HEAD $head)"
|
||||
exit 0
|
||||
}
|
||||
|
||||
# --- mode: Ensure (idempotent heal) ---
|
||||
if ($contextExists) {
|
||||
Write-Output "session-scaffold: [Ensure] session-$targetN _context present -- NO-OP (exit 0, mtime preserved)."
|
||||
exit 0
|
||||
}
|
||||
Write-Context -TemplatePath $templatePath -OutPath $contextPath -SessionN $targetN -Ts $ts -Head $head
|
||||
$note = if ($folderExists) { "healed (folder existed, _context missing)" } else { "created (folder was missing)" }
|
||||
Write-Output "session-scaffold: [Ensure] session-$targetN $note"
|
||||
Write-Output " context = $(Rel $contextPath $root)"
|
||||
Write-Output " ts-moc = $ts (HEAD $head)"
|
||||
exit 0
|
||||
Reference in New Issue
Block a user