[CLAUDE] Docs: closeout OUTWARD wave adap đợt-9/10 + vá drift skill-matrix H24
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 5m43s
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 5m43s
Closeout 4 mục OUTWARD của wave S141-S142 (anh gật @S143): - adap-report 7/7 thư, đủ 5 trường REPORT-FORMAT LOCK, evidence đo thật - email hub báo-nấc (sha 6c94873f72e0, selftest_verify exit 0, log _index cùng lượt) - STAGE-2: 7 thư -> inbox/ai_infra/, _index 0 pending, cross-check 7/7 - squash K=8 wal: -> commit chốt Ngoài wave: agents/README skill-matrix thiếu 2 row H24 (drift S121) -> 15/17 thành 17/17. Nấc cao nhất khai được = executed-file/verified-pending-restart (trio CHƯA spawn). 2 phát hiện khai thẳng theo G-015 (chi tiết trong report + email): - whitelist `tools:` KHÔNG chặn ghi ở runtime: 6 vai read-only bị append Write+Edit - pull-lag do "watch broadcasts/inbox" canh nhầm chỗ TICK H24: counter 16->17 (S143), 3-điều-kiện OK-reachable, không fail-loud. Detector TOTAL 46 == baseline 46, 0 flag mới. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@ -1356,6 +1356,164 @@ else {
|
||||
Write-Host (" H24-4 pending-flip flags = {0} [INFORM-only, LOW, NOT folded; 0 = designed first-run]" -f $h244Flags) -ForegroundColor DarkGray
|
||||
}
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# H24-5 - counter-ancestor-classify (INFORM-only, NEW; count SEPARATE, NOT in TOTAL)
|
||||
#
|
||||
# WHAT: a static, read-only replay of the .session-counter.json contract v2 clause
|
||||
# "fail_loud_on_regress" (adopted S141, hub template 58e28bae C-1). The RUNTIME owner of
|
||||
# that clause is the /session-start 2.1.8(b) ritual -- this detector does NOT replace it
|
||||
# and could not: the ritual is the half with teeth (it FAIL-LOUDs to the owner mid-run).
|
||||
# What a detector adds is a between-sessions eye that can be pointed at ANY tree.
|
||||
#
|
||||
# THE CLASSIFICATION (contract order, verbatim shape):
|
||||
# 1. last_ticked_head reachable from HEAD (git merge-base --is-ancestor, exit 0)
|
||||
# -> OK-reachable. No flag.
|
||||
# 2. NOT reachable BUT the object still EXISTS (git cat-file -t = 'commit')
|
||||
# -> SQUASH-BENIGN: a trace line, ZERO flags. This is the expected steady state --
|
||||
# every closeout squashes the session's wal: commits, so the head captured at the
|
||||
# previous tick routinely drops out of history. The 3 historical FAIL-LOUDs recorded
|
||||
# in history[] (S127/S133/S139) all reclassify here; that IS contract v2's purpose.
|
||||
# 3. object MISSING (cat-file fails) -> flag object-missing. The anti-tamper half: a
|
||||
# head that no longer exists AT ALL was not squashed out, it was rewritten away.
|
||||
# [M1] counter-regress, an INDEPENDENT axis and DEFAULT-ON: the stored counter must
|
||||
# never sit BELOW a counter at which an audit already ran (last_audit.light_at_counter
|
||||
# / deep_at_counter). Below = the file was rolled back or hand-edited, and a silent
|
||||
# reset would hide the cadence gap -- the exact thing H24 exists to catch.
|
||||
#
|
||||
# [M2] DAY-ONE = INFORM-SINK. Every H24-5 hit goes through Write-InformFlag: its own
|
||||
# [DETECTOR] line, counted in $script:InformCount, NEVER folded into TOTAL. Same
|
||||
# reasoning as C6/H24-4 (see the Write-InformFlag banner): a brand-new net must not move
|
||||
# the audited baseline on day one, in EITHER direction. No teeth are lost by this --
|
||||
# 2.1.8(b) still FAIL-LOUDs at runtime, independently of this script. Fold + severity
|
||||
# raise is a post-triage, owner-gated call.
|
||||
#
|
||||
# git-based => honours -RepoRoot, so fault-injection on a temp tree isolates completely
|
||||
# (mirror of H25-closeout). Every probe is exit-code checked and never throws: a RepoRoot
|
||||
# that is not a work-tree, or a file that was never ticked, SKIPs WITH A REASON and the
|
||||
# section summary says MEASURED NOTHING -- a 0 printed after a skip is not a green.
|
||||
#
|
||||
# READ-ENCODING (bug E-010/S130): the JSON is read via ReadAllBytes + UTF8.GetString and
|
||||
# NOT Get-Content without -Encoding. A BOM-less UTF-8 file decoded through the ANSI
|
||||
# codepage yields a DIFFERENT document than the one on disk, and a classifier that reads
|
||||
# a different document is worse than no classifier.
|
||||
# ---------------------------------------------------------------------------
|
||||
Write-Section 'H24-5 - counter-ancestor-classify (INFORM-only)'
|
||||
|
||||
$h245Flags = 0
|
||||
$h245Measured = $false
|
||||
$counterP = Join-Path $RepoRoot '.claude\governance\.session-counter.json'
|
||||
if (-not (Test-Path $counterP)) {
|
||||
Write-Host ' [skip] no .claude/governance/.session-counter.json - no tick state to classify' -ForegroundColor DarkGray
|
||||
}
|
||||
elseif (-not (Test-Path (Join-Path $RepoRoot '.git'))) {
|
||||
Write-Host ' [skip] RepoRoot is not a git work-tree - cannot classify head reachability' -ForegroundColor DarkGray
|
||||
}
|
||||
else {
|
||||
# BOM-STRIP (measured S142, NOT theoretical): the file on disk starts EF BB BF -- it is
|
||||
# written by PS 5.1 ConvertTo-Json + Out-File -Encoding utf8, which always emits a BOM.
|
||||
# [Text.Encoding]::UTF8.GetString does NOT consume that BOM (unlike Get-Content or a
|
||||
# StreamReader with detectEncodingFromByteOrderMarks), so the string begins with a
|
||||
# literal U+FEFF and ConvertFrom-Json dies with "Invalid JSON primitive: .".
|
||||
# First run of this detector on the REAL repo raised counter-unparseable on a file that
|
||||
# parses fine -- i.e. the encoding-safe read prescribed to dodge bug E-010 opened a
|
||||
# SECOND failure mode of its own. Both must be handled: read bytes as UTF-8 (never let
|
||||
# the ANSI codepage decode it) AND drop a leading BOM. Written as a code point so this
|
||||
# .ps1 stays ASCII-only (gotcha #30).
|
||||
$ctr = $null
|
||||
try {
|
||||
$ctrJson = [Text.Encoding]::UTF8.GetString([IO.File]::ReadAllBytes($counterP))
|
||||
$ctrJson = $ctrJson.TrimStart([char]0xFEFF)
|
||||
$ctr = ($ctrJson | ConvertFrom-Json)
|
||||
}
|
||||
catch { $ctr = $null }
|
||||
|
||||
if ($null -eq $ctr) {
|
||||
Write-InformFlag (Rel $counterP) `
|
||||
'counter-unparseable: .session-counter.json is not valid JSON - tick state UNREADABLE, classifying NOTHING' `
|
||||
'fix the JSON syntax (the tick contract cannot be replayed against an unparseable file)'
|
||||
$h245Flags++
|
||||
$h245Measured = $true
|
||||
}
|
||||
else {
|
||||
# ---- axis 1: reachability of last_ticked_head ----
|
||||
$head = [string]$ctr.last_ticked_head
|
||||
if ([string]::IsNullOrWhiteSpace($head)) {
|
||||
Write-Host ' [skip-axis1] last_ticked_head is null - never ticked (seed-honesty state), nothing to classify' -ForegroundColor DarkGray
|
||||
}
|
||||
else {
|
||||
$h245Measured = $true
|
||||
$shortHead = $head.Substring(0, [Math]::Min(8, $head.Length))
|
||||
$reachable = $false
|
||||
try {
|
||||
$null = & git -C $RepoRoot merge-base --is-ancestor $head HEAD 2>$null
|
||||
$reachable = ($LASTEXITCODE -eq 0)
|
||||
}
|
||||
catch { $reachable = $false }
|
||||
|
||||
if ($reachable) {
|
||||
Write-Host (" [OK] OK-reachable: last_ticked_head {0} (session {1}) is an ancestor of HEAD" -f `
|
||||
$shortHead, $ctr.last_ticked_session) -ForegroundColor Green
|
||||
}
|
||||
else {
|
||||
$objType = ''
|
||||
$catOk = $false
|
||||
try {
|
||||
$objType = & git -C $RepoRoot cat-file -t $head 2>$null
|
||||
$catOk = ($LASTEXITCODE -eq 0)
|
||||
}
|
||||
catch { $catOk = $false }
|
||||
|
||||
if ($catOk -and (("$objType").Trim() -eq 'commit')) {
|
||||
Write-Host (" [trace] SQUASH-BENIGN: last_ticked_head {0} (session {1}) is NOT reachable from HEAD but the object EXISTS (cat-file -t = commit) - expected closeout-squash drift, 0 flag (contract v2)" -f `
|
||||
$shortHead, $ctr.last_ticked_session) -ForegroundColor DarkGray
|
||||
}
|
||||
else {
|
||||
Write-InformFlag (Rel $counterP) `
|
||||
("object-missing: last_ticked_head {0} (session {1}) is neither reachable from HEAD nor present as an object (cat-file -t failed) - NOT the benign squash class" -f `
|
||||
$head, $ctr.last_ticked_session) `
|
||||
'confirm history was not rewritten; re-tick from a real HEAD or record why the object vanished (contract: object-missing => FAIL-LOUD at runtime)'
|
||||
$h245Flags++
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# ---- axis 2 [M1]: counter-regress vs the already-audited floor (DEFAULT-ON) ----
|
||||
$curCounter = $null
|
||||
if ($null -ne $ctr.counter) { $curCounter = [int]$ctr.counter }
|
||||
$audit = $ctr.last_audit
|
||||
if ($null -eq $curCounter) {
|
||||
Write-InformFlag (Rel $counterP) `
|
||||
'counter-key-missing: no "counter" key - cadence state unreadable, regress-check measuring NOTHING' `
|
||||
'restore the counter key (H24 tick state lives in this file only)'
|
||||
$h245Flags++
|
||||
$h245Measured = $true
|
||||
}
|
||||
elseif ($null -eq $audit) {
|
||||
Write-Host ' [note] no last_audit block - regress-check has no audited floor to compare against' -ForegroundColor DarkGray
|
||||
}
|
||||
else {
|
||||
foreach ($floorKey in @('light_at_counter', 'deep_at_counter')) {
|
||||
$floorVal = $audit.$floorKey
|
||||
if ($null -eq $floorVal) { continue }
|
||||
$h245Measured = $true
|
||||
$floorN = [int]$floorVal
|
||||
if ($curCounter -lt $floorN) {
|
||||
Write-InformFlag (Rel $counterP) `
|
||||
("counter-regress: counter={0} sits BELOW last_audit.{1}={2} - an audit already ran at a HIGHER counter, so this file was rolled back or hand-edited" -f `
|
||||
$curCounter, $floorKey, $floorN) `
|
||||
'restore the counter to its true value; never silently reset (contract: regress => FAIL-LOUD at runtime, cadence gap must stay visible)'
|
||||
$h245Flags++
|
||||
}
|
||||
else {
|
||||
Write-Host (" [ok] counter={0} >= last_audit.{1}={2}" -f $curCounter, $floorKey, $floorN) -ForegroundColor DarkGray
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
$h245Note = if ($h245Measured) { '' } else { ' -- MEASURED NOTHING (skipped above); a 0 after a skip is not a green' }
|
||||
Write-Host (" H24-5 counter-ancestor flags = {0} [INFORM-only, LOW, NOT folded into TOTAL baseline]{1}" -f $h245Flags, $h245Note) -ForegroundColor DarkGray
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Summary + C4 self-exclusion audit (RUNTIME proof)
|
||||
# ---------------------------------------------------------------------------
|
||||
@ -1379,7 +1537,7 @@ if ($selfInScan -eq 0 -and $leaked -eq 0) {
|
||||
|
||||
Write-Host ''
|
||||
Write-Host ("TOTAL FLAGS: {0}" -f $script:FlagCount) -ForegroundColor Cyan
|
||||
Write-Host ("INFORM-ONLY (new nets C6 cite-2-tier + H24-4 pending-flip): {0} - counted SEPARATELY, NOT in TOTAL above (anti-Goodhart, owner-set; fold+sev-raise is post-triage)" -f $script:InformCount) -ForegroundColor DarkGray
|
||||
Write-Host ("INFORM-ONLY (new nets C6 cite-2-tier + H24-4 pending-flip + H24-5 counter-ancestor-classify): {0} - counted SEPARATELY, NOT in TOTAL above (anti-Goodhart, owner-set; fold+sev-raise is post-triage)" -f $script:InformCount) -ForegroundColor DarkGray
|
||||
Write-Host 'NOTE: DETECT-only lowering net. Exit 0 always (never fails build). FLAGs are advisory.' -ForegroundColor DarkGray
|
||||
|
||||
exit 0
|
||||
|
||||
Reference in New Issue
Block a user