[CLAUDE] Skill: YC-021 tron — ring5-audit verified-runtime + day-wake 4-floor (/day + day-probe fault-inject 4/4) + bang-tham-quyen-DRAFT + thu hub re-stamp; REVIEW 8-MAJ va het truoc commit
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
95
scripts/day-probe.ps1
Normal file
95
scripts/day-probe.ps1
Normal file
@ -0,0 +1,95 @@
|
||||
#Requires -Version 5.1
|
||||
<#
|
||||
.SYNOPSIS
|
||||
day-probe (W-1 day-wake, adopt hub 2026-07-28 "probe-first-resume"; owner YC-021 @S185).
|
||||
READ-ONLY probe deciding CHEAP-WAKE vs FULL-RESUME. Prints EXACTLY one DAY-PROBE line.
|
||||
ALWAYS exit 0 (INFORM layer - the /day command reads the verdict word, nothing blocks).
|
||||
|
||||
.DESCRIPTION
|
||||
Floor F1: pick the LAST session marker by the ts WRITTEN INSIDE the file (never mtime -
|
||||
Dropbox resync touches mtime). Then check 4 delta signals:
|
||||
(a) commits after the anchor (git rev-list count)
|
||||
(b) tracked/untracked dirty files (git status --porcelain, no allowlist - lean DELTA)
|
||||
(c) is covered by (a)+(b): run-folders/artifacts land as commits or dirty files
|
||||
(d) closing: sentinel in .claude/WAL.md (San-2)
|
||||
Floor F3: anchor = the commit that ADDED the marker file (the stop-seal commit), NOT the
|
||||
head-sha inside the marker (trap-one: head-sha predates the seal commit => false DELTA
|
||||
100% of the time). Fallback = head-sha field. Anchor must EXIST (cat-file -e) AND be an
|
||||
ANCESTOR of HEAD (merge-base --is-ancestor); orphaned (post-squash) => verdict ANCHOR-LOST
|
||||
printed LOUDLY (trap-two: fail-safe must have a voice, not die silent).
|
||||
Verdict precedence: ANCHOR-LOST > DELTA > CLEAN. Leaning rule: any probe error => DELTA.
|
||||
Floor F4 lives in /day (the _day-<i>.md marker); this script only measures.
|
||||
|
||||
.PARAMETER RepoRoot
|
||||
Repo root; a temp tree here isolates fault-injection (mirror governance-detectors.ps1).
|
||||
#>
|
||||
[CmdletBinding()]
|
||||
param([string]$RepoRoot = (Get-Location).Path)
|
||||
|
||||
$sw = [System.Diagnostics.Stopwatch]::StartNew()
|
||||
$ErrorActionPreference = 'SilentlyContinue'
|
||||
|
||||
function Out-Line([string]$verdict, [string]$detail) {
|
||||
$script:sw.Stop()
|
||||
Write-Host ("DAY-PROBE: {0} | {1} | {2}ms" -f $verdict, $detail, $script:sw.ElapsedMilliseconds)
|
||||
exit 0
|
||||
}
|
||||
|
||||
try {
|
||||
$sessRoot = Join-Path $RepoRoot '.claude\sessions'
|
||||
if (-not (Test-Path $sessRoot)) { Out-Line 'DELTA' 'probe-loi: no sessions dir (lean DELTA)' }
|
||||
|
||||
# newest logic-session = highest N with a _context file
|
||||
$sess = Get-ChildItem -Path $sessRoot -Directory -Filter 'session-*' |
|
||||
Where-Object { Test-Path (Join-Path $_.FullName ("_context-s-" + ($_.Name -replace '^session-','') + ".md")) } |
|
||||
Sort-Object { [int]($_.Name -replace '^session-','') } -Descending | Select-Object -First 1
|
||||
if ($null -eq $sess) { Out-Line 'DELTA' 'probe-loi: no logic-session found (lean DELTA)' }
|
||||
|
||||
# last marker by ts INSIDE file (F1). _day markers count too (repeat wakes).
|
||||
$markers = @()
|
||||
foreach ($f in (Get-ChildItem -Path $sess.FullName -File | Where-Object { $_.Name -match '^_(pause|tiep|snapshot|day)-\d+\.md$' })) {
|
||||
$ts = $null; $sha = $null
|
||||
foreach ($ln in (Get-Content -Path $f.FullName -TotalCount 8 -Encoding UTF8)) {
|
||||
if ($ln -match '^ts:\s*(\S+)') { $ts = $Matches[1] }
|
||||
if ($ln -match '^head-sha:\s*([0-9a-f]{7,40})') { $sha = $Matches[1] }
|
||||
}
|
||||
if ($null -ne $ts) { $markers += [pscustomobject]@{ File = $f.FullName; Name = $f.Name; Ts = $ts; Sha = $sha } }
|
||||
}
|
||||
if ($markers.Count -eq 0) { Out-Line 'DELTA' ('no marker with in-file ts under ' + $sess.Name + ' (lean DELTA)') }
|
||||
$last = $markers | Sort-Object Ts -Descending | Select-Object -First 1
|
||||
|
||||
# F3 anchor: the commit that ADDED the marker (stop-seal), fallback in-file head-sha
|
||||
Push-Location $RepoRoot
|
||||
try {
|
||||
$rel = (Resolve-Path -Relative $last.File) -replace '^\.\\', '' -replace '\\', '/'
|
||||
$anchor = (& git log --diff-filter=A --format=%H -1 -- $rel 2>$null | Select-Object -First 1)
|
||||
$src = 'seal-commit'
|
||||
if ([string]::IsNullOrWhiteSpace($anchor)) { $anchor = $last.Sha; $src = 'in-file-sha' }
|
||||
if ([string]::IsNullOrWhiteSpace($anchor)) { Out-Line 'DELTA' ('marker ' + $last.Name + ' has no resolvable anchor (lean DELTA)') }
|
||||
|
||||
& git cat-file -e ($anchor + '^{commit}') 2>$null
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
Out-Line 'ANCHOR-LOST' ('anchor=' + $anchor.Substring(0,[Math]::Min(8,$anchor.Length)) + ' (' + $src + ') MISSING from object store - marker=' + $last.Name + ' - route: FULL /tiep (loud fail-safe, F3 trap-two)')
|
||||
}
|
||||
& git merge-base --is-ancestor $anchor HEAD 2>$null
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
Out-Line 'ANCHOR-LOST' ('anchor=' + $anchor.Substring(0,8) + ' (' + $src + ') exists but NOT ancestor of HEAD (post-squash orphan) - marker=' + $last.Name + ' - route: FULL /tiep')
|
||||
}
|
||||
|
||||
# signals
|
||||
$nCommits = [int](& git rev-list --count ($anchor + '..HEAD') 2>$null)
|
||||
$dirty = @(& git status --porcelain 2>$null | Where-Object { $_ -and $_.Trim().Length -gt 0 })
|
||||
$nDirty = $dirty.Count
|
||||
$walP = Join-Path $RepoRoot '.claude\WAL.md'
|
||||
$nClosing = 0
|
||||
if (Test-Path $walP) { $nClosing = @(Select-String -Path $walP -Pattern '^closing:' -Encoding UTF8).Count }
|
||||
|
||||
$detail = ('anchor=' + $anchor.Substring(0,8) + '(' + $src + ') alive+ancestor | commits-sau=' + $nCommits + ' | dirty=' + $nDirty + ' | closing=' + $nClosing + ' | marker=' + $last.Name + ' ts=' + $last.Ts)
|
||||
if ($nCommits -eq 0 -and $nDirty -eq 0 -and $nClosing -eq 0) { Out-Line 'CLEAN' $detail }
|
||||
Out-Line 'DELTA' $detail
|
||||
}
|
||||
finally { Pop-Location }
|
||||
}
|
||||
catch {
|
||||
Out-Line 'DELTA' ('probe-loi: ' + $_.Exception.Message.Substring(0, [Math]::Min(80, $_.Exception.Message.Length)) + ' (lean DELTA)')
|
||||
}
|
||||
@ -46,7 +46,8 @@ $RepoRoot = (Resolve-Path -LiteralPath $RepoRoot).Path
|
||||
$RX_KEBAB = '^[a-z0-9]+(-[a-z0-9]+)*$'
|
||||
$RX_SNAKE = '^[a-z0-9]+(_[a-z0-9]+)*$'
|
||||
$RX_ONEOFF = '^(s[0-9]+-|plan-)'
|
||||
$RX_SESSFAM = '^_(tiep|pause|snapshot|context-s|mind-s|end)'
|
||||
$RX_SESSFAM = '^_(tiep|pause|snapshot|day|context-s|mind-s|end)'
|
||||
# ^ +day @S185 (W-1 day-wake marker _day-<i>.md — reviewer F-6: thieu thi moi marker day = 1 FLAG LECH oan)
|
||||
$RX_SESSDIR = '^session-[0-9]+$'
|
||||
|
||||
# ---------- so ke ----------
|
||||
|
||||
Reference in New Issue
Block a user