[CLAUDE] Infra: W1 - 2 detector H24 + 3 script governance (eol-hygiene / wal-recovery 4-ca / spawn-model-audit)

Wave adap-6-broadcast W1 - 4 lane disjoint qua /hmw RUN-TRACE (wf_de36dea9-265, 4/4 lane 0-error).
Lead TU CHAY LAI ca 4 + tu fault-inject, KHONG tin return (gotcha #53 fire 2/2 @W0.6).

(1) governance-detectors.ps1 455->715
    - GAP-3 +2 token canonical: menu=54 (STATUS.md:19); policy = row CHUA co (W2 land)
      -> FAIL-LOUD + SKIP, khong im lang gia vo xanh.
    - Detector H24-1 title-freshness: anchor_patterns[] = MANG 2 dang (fix C2). Bat buoc co dang
      '**Status (post Session N <em-dash> YYYY-MM-DD):**' vi permission-matrix/SKILL.md
      (positive-control SONG) dung dang do va KHONG co 'Last updated'. Neu 1 regex => detector
      loai thang chinh positive-control cua no => W4 bat-kha-thi.
      NEO-PHAM-VI load-bearing: STATUS.md:6 chua 2026-08-01 / 1987-03-07 / 2026-20-42 (cat tu
      mark-id). Regex-ngay-bat-ky lay max => 2026-20-42 = ngay KHONG ton tai => moc-phai rac
      => trai<phai khong bao gio dung => 0 flag VINH VIEN ma van xanh.
    - Detector H24-2 carry-age INFORM-only: M doc tu agent-memory/memory-budget.json
      h24_cadence.light_every; thieu key => FAIL-LOUD, 0 so nhip hardcode.
    - Bug lane tu bat: PS ten bien CASE-INSENSITIVE => $M (cadence) == $m (loop match) => ghi de
      cadence => vo nhanh fail-loud. exit 0 CHE bug nay; chi stderr moi lo.
    - M3 scope giu: 4 hang so owner-da-ky KHONG dung (walLineCount 40 / ratio / maxGotcha / liveVariants).

(2) agent-frontmatter-eol-check.ps1 (NEW) - HYGIENE-only
    W0.6 spawn-probe @S121 do duoc CRLF-TOLERANT (agent CRLF 276 byte CR spawn an du 4 tang;
    token 45248 LF vs 45240 CRLF, lech 8 = chenh chu trong prompt) => gia thuyet 'CRLF giet
    registry' BI BAC => script ha cap xuong hygiene, khai that ca o header lan thong diep FLAG
    runtime. Scope-chat 37 file (agents/commands/skills), KHONG repo-wide (188 = duong-gia
    factory). Tu in GREEN-BUT-VACUOUS thay vi nhan cong.

(3) wal-recovery-test.ps1 (NEW) - 4/4 ca, 30 assert
    FIX #3-bis: bien re nhanh = DAY RANGE, KHONG phai NONWAL. Counterfactual chay luat cu =>
    tai hien DEADLOCK that voi rebase-exit=0 (hong ma bao thanh cong). Assert
    sut-has-no-NONWAL-param bang Get-Command reflection, KHONG grep => ne tu-tham-chieu (W0.4#1).

(4) spawn-model-audit.ps1 (NEW) - PA-2b
    FAIL-LOUD khi thieu TIER2_EXPECTED_FULL_ID (W2 chua land). Muc E liet 6 dieu no KHONG chung,
    gom precedence spawn-param vs frontmatter (CHUA TEST, defer phien lead=Fable) + fix#8a chua thu.

VERIFY LEAD TU DO (khong phai so sub khai):
  TOTAL FLAGS 42->49 (>=46) . permission-matrix/SKILL.md FIRE 3 dong (W4 kha thi; KHONG lane nao
  cham file do) . exit 0 + stderr 0 x4 . non-ASCII 0/4 . teeth 2/2: inject 276 CR -> FLAG, go -> 0;
  inject claude-opus-9-9 -> FLAG mismatch, sua -> het. Containment sach.

LOI LEAD @S121 (di vao adap-report, khong im):
  (a) San-1 lech: marker wf: dang ky SAU khi phong (luat = TRUOC).
  (b) Khang dinh fact-tren-dia ma KHONG do dia: lead phan 'backfill [carry:*] = orphan chua ai lam'
      -> SAI, da co 7 khoa tu 4727d16 (S119, da push). Co che: ra BANG WAVE thay khong ai duoc
      giao => suy ra chua lam. 'Khong wave nao so huu' != 'chua co tren dia'. Brief lead co 4 tien
      de sai (config path / acceptance ngay 07-14 vs that 07-15 / carry / do-dai); lane (1) do dia va va het.

GAP THAT thay claim sai (lane 1 tim, lead verify dia): carry-age vacuous vi CAU TRUC - 45
logic-segment nhung carry-lines=1 => streak==1 => 0 fire vinh vien ke ca sau W2. Lo = thieu nghi
thuc RE-STAMP moi phien => giao W3 session-end.md, KHONG phai W2.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
pqhuy1987
2026-07-15 12:47:55 +07:00
parent 38bbcad416
commit d07bbb98c5
4 changed files with 1608 additions and 7 deletions

View File

@ -0,0 +1,335 @@
<#
.SYNOPSIS
agent-frontmatter-eol-check.ps1 - HYGIENE-only EOL check for agent/command/skill frontmatter.
NOT a fatal-defect guard. The "CRLF kills the agent registry" claim was REFUTED by experiment
(S121 W0.6) and this script must not be read, cited, or gated on as if it enforced that claim.
.DESCRIPTION
WHAT IT DOES
Enforces the .gitattributes policy line '* text=auto eol=lf' (repo root) on the frontmatter
of the rule-set files:
.claude/agents/*.md
.claude/commands/*.md
.claude/skills/**/SKILL.md
It reads RAW BYTES and counts CR (0x0D) inside the YAML frontmatter block.
WHAT IT IS NOT - the honest grade of this check (read before trusting it)
The S121 W0.6 spawn-probe MEASURED the opposite of the assumption that motivated this
script. A fully CRLF-ised agent file (276 CR bytes) spawned CORRECTLY through all four
stages: discovery / parse / spawn / execute. Token accounting was 45248 (LF) vs 45240
(CRLF); that 8-token delta is explained by wording differences in the prompt, not by EOL.
Verdict: CRLF-TOLERANT. The "LF-only frontmatter reader" hypothesis was REFUTED.
=> This is therefore HYGIENE, not defect-prevention. No CR finding produced here is known
to break anything. Do not describe it as fatal. Do not gate a build on it.
WHY IT STILL EXISTS - the scope limit of that refutation
The W0.6 measurement covers: BEHAVIOUR level only / .claude/agents/ only / ONE win32 build.
NOT covered: .claude/commands/, .claude/skills/, hook .ps1 readers, any other build or
platform. LF hygiene on those surfaces remains unverified-by-experiment, and the
.gitattributes eol=lf policy applies to them regardless of whether any reader currently
chokes. That residual - plus keeping the worktree consistent with the committed blob -
is the entire value proposition. It is a small one. It is stated at its real size on purpose.
SEVERITY LADDER (a deliberate consequence of the refutation)
HIGH - reserved for SELF-BROKEN only: the synthetic control below failed, so the scan
result is meaningless. Never used for a CR finding - none is known to break anything.
MED - CR inside the frontmatter block: the surface a parser would read, and the surface
W0.6 probed on agents/ only.
LOW - CR in the body only: same eol=lf policy, further from any reader hot-path.
Exit code is ALWAYS 0. Inform/hygiene net, never a hard gate.
POSITIVE CONTROL - SYNTHETIC, and declared as such (spec v2 (4)(a))
The scoped set measured 0 CR at S121, so a green run is the expected outcome. A green run
therefore proves NOTHING by itself: a detector that is merely broken is also green. Every
run self-tests the byte-reader against two IN-MEMORY buffers BEFORE touching disk:
(+) CRLF synthetic agent file -> reader MUST report frontmatter CR > 0
(-) LF synthetic agent file -> reader MUST report frontmatter CR = 0
These controls are synthetic BY NECESSITY, not by preference: because W0.6 refuted
CRLF-fatality, no real "file killed by CRLF" exists to serve as a natural positive control.
Note the limit of what a synthetic control buys: it proves the READER works. It does NOT
prove that CRLF harms anything - the experiment says it does not.
If either control fails, a HIGH self-broken FLAG is raised and the scan is reported
UNTRUSTWORTHY.
DESIGN NOTES
- Byte-reader, not text-reader: Get-Content (default and -Raw) drops or normalises CR, so a
text-level check could never fail on a CRLF file - it would be vacuous BY CONSTRUCTION.
[System.IO.File]::ReadAllBytes is used instead. Side effect: no text decoding happens at
all, so target-file encoding is irrelevant and gotcha #30 (ANSI-vs-UTF8 mojibake) cannot
reach the measurement. This script body is still ASCII-only per gotcha #30 / #37.
- No self-reference hazard (W0.4 lesson): the test is STRUCTURAL - count 0x0D inside a
byte-delimited region - not a string-grep, so it cannot match a quoted claim written
about itself. It also lives in scripts/ and scans only .claude/{agents,commands,skills},
so it is path-disjoint from its own scan set as well.
- Counts come from globs, never hardcoded (spec v3 fix #9h). Every PASS/FAIL/GREEN word
printed below is COMPUTED from a measured number (W0.4 meta-count lesson: never print a
verdict label next to a number that says otherwise).
- agents/README.md is intentionally IN scope. R2-C1 excludes README from the ROSTER count
(it is not an agent); EOL policy is per-file, so README is governed like any other file.
The two rules differ on purpose - do not "fix" one by copying the other.
- Scope is deliberately NOT repo-wide. A repo-wide 'i/lf w/crlf' scan matches 188 files
(131 of them EF Migrations); an acceptance of "count == 0" over that set would be a
false-price factory, and mass rm+checkout is forbidden this session (spec v2 W0.2).
The 188 stay INFORM-only and are not this script's business.
.PARAMETER RepoRoot
Repo root. Default = resolved 1 level up from this script (scripts/ -> repo root).
Every path is derived from it, so the script can be pointed at a temp tree for fault-injection.
.EXAMPLE
powershell.exe -ExecutionPolicy Bypass -File scripts/agent-frontmatter-eol-check.ps1
.EXAMPLE
powershell.exe -ExecutionPolicy Bypass -File scripts/agent-frontmatter-eol-check.ps1 -RepoRoot C:\Temp\eol-faultinject
#>
param(
[string]$RepoRoot = (Resolve-Path (Join-Path $PSScriptRoot '..')).Path
)
$ErrorActionPreference = 'Continue'
# ---------------------------------------------------------------------------
# Helpers - shape mirrors scripts/governance-detectors.ps1:43-67 so FLAG output
# from the two nets reads the same way.
# ---------------------------------------------------------------------------
$script:FlagCount = 0
function Write-Flag {
param(
[ValidateSet('HIGH', 'MED', 'LOW')] [string]$Severity,
[string]$Where, # file:line, or file
[string]$Desc,
[string]$Resolve
)
$color = switch ($Severity) { 'HIGH' { 'Red' } 'MED' { 'Yellow' } default { 'Gray' } }
Write-Host ("[EOL] {0,-4} | {1} | {2} | resolve: {3}" -f $Severity, $Where, $Desc, $Resolve) -ForegroundColor $color
$script:FlagCount++
}
function Write-Section($title) {
Write-Host ''
Write-Host ("===== $title =====") -ForegroundColor Cyan
}
# Make a path repo-relative for readable FLAG output (forward slashes).
function Rel($full) {
$r = $full
if ($full.StartsWith($RepoRoot, [StringComparison]::OrdinalIgnoreCase)) {
$r = $full.Substring($RepoRoot.Length).TrimStart('\', '/')
}
return ($r -replace '\\', '/')
}
# ---------------------------------------------------------------------------
# Byte-level frontmatter reader (the whole point - see DESIGN NOTES).
#
# Splits on 0x0A only, then strips one optional trailing 0x0D per line, so the
# frontmatter delimiters are located identically in LF and CRLF files. The
# returned offsets are BYTE offsets, which is what lets us attribute every single
# CR to either the frontmatter block or the body.
# ---------------------------------------------------------------------------
function Measure-EolBytes {
param([byte[]]$Bytes)
if ($null -eq $Bytes) { $Bytes = New-Object byte[] 0 }
$len = $Bytes.Length
# Skip a UTF-8 BOM so a BOM'd file does not silently read as "no frontmatter".
$start = 0
$hasBom = $false
if ($len -ge 3 -and $Bytes[0] -eq 0xEF -and $Bytes[1] -eq 0xBB -and $Bytes[2] -eq 0xBF) {
$hasBom = $true
$start = 3
}
# Locate the frontmatter block: line 0 must be exactly '---'; the block ends at
# the next line that is exactly '---'. $fmEnd = byte offset one past that line.
$fmEnd = -1
$lineStart = $start
$lineIdx = 0
for ($i = $start; $i -le $len; $i++) {
$atEof = ($i -eq $len)
if (-not $atEof -and $Bytes[$i] -ne 0x0A) { continue }
$endExcl = $i
if ($endExcl -gt $lineStart -and $Bytes[$endExcl - 1] -eq 0x0D) { $endExcl-- }
# Byte -> char is Latin-1 here; harmless because the only comparison is the
# ASCII delimiter '---'. Multi-byte UTF-8 in frontmatter cannot false-match it.
$sb = New-Object System.Text.StringBuilder
for ($k = $lineStart; $k -lt $endExcl; $k++) { [void]$sb.Append([char]$Bytes[$k]) }
$content = $sb.ToString().TrimEnd()
if ($lineIdx -eq 0) {
if ($content -ne '---') { break } # no frontmatter block at all
}
elseif ($content -eq '---') {
$fmEnd = if ($atEof) { $len } else { $i + 1 }
break
}
if ($atEof) { break } # opening '---' but never closed
$lineIdx++
$lineStart = $i + 1
}
# Attribute every CR byte. With no frontmatter block, the whole file counts as body.
$split = if ($fmEnd -ge 0) { $fmEnd } else { $start }
$fmCr = 0
$bodyCr = 0
for ($i = $start; $i -lt $len; $i++) {
if ($Bytes[$i] -eq 0x0D) {
if ($i -lt $split) { $fmCr++ } else { $bodyCr++ }
}
}
return [pscustomobject]@{
HasFrontmatter = ($fmEnd -ge 0)
HasBom = $hasBom
FmCr = $fmCr
BodyCr = $bodyCr
TotalCr = ($fmCr + $bodyCr)
Bytes = $len
}
}
function Measure-EolFile {
param([string]$Path)
try {
$bytes = [System.IO.File]::ReadAllBytes($Path)
}
catch {
Write-Host (" [warn] cannot read bytes: {0} - {1}" -f (Rel $Path), $_.Exception.Message) -ForegroundColor DarkGray
return $null
}
return (Measure-EolBytes $bytes)
}
# ---------------------------------------------------------------------------
# SYNTHETIC CONTROL - runs BEFORE the disk scan.
# Declared synthetic on purpose: W0.6 refuted CRLF-fatality, so there is no real
# dead file to use as a natural positive control (spec v2 (4)(a)).
# ---------------------------------------------------------------------------
Write-Section 'Synthetic control (DECLARED SYNTHETIC) - does the byte-reader have teeth?'
$ctrlCrlf = "---`r`nname: _synthetic-control`r`ndescription: synthetic positive control`r`n---`r`nbody line`r`n"
$ctrlLf = "---`nname: _synthetic-control`ndescription: synthetic negative control`n---`nbody line`n"
$ctrlPos = Measure-EolBytes ([System.Text.Encoding]::ASCII.GetBytes($ctrlCrlf))
$ctrlNeg = Measure-EolBytes ([System.Text.Encoding]::ASCII.GetBytes($ctrlLf))
$posOk = ($ctrlPos.HasFrontmatter -and $ctrlPos.FmCr -gt 0)
$negOk = ($ctrlNeg.HasFrontmatter -and $ctrlNeg.FmCr -eq 0 -and $ctrlNeg.BodyCr -eq 0)
$controlOk = ($posOk -and $negOk)
$posLabel = if ($posOk) { 'PASS' } else { 'FAIL' }
$negLabel = if ($negOk) { 'PASS' } else { 'FAIL' }
Write-Host (" (+) CRLF synthetic : fm={0} FmCr={1} BodyCr={2} expect fm=True,FmCr>0 -> {3}" -f `
$ctrlPos.HasFrontmatter, $ctrlPos.FmCr, $ctrlPos.BodyCr, $posLabel)
Write-Host (" (-) LF synthetic : fm={0} FmCr={1} BodyCr={2} expect fm=True,FmCr=0 -> {3}" -f `
$ctrlNeg.HasFrontmatter, $ctrlNeg.FmCr, $ctrlNeg.BodyCr, $negLabel)
if (-not $controlOk) {
Write-Flag 'HIGH' 'scripts/agent-frontmatter-eol-check.ps1 (self)' `
'self-broken: synthetic control FAILED - the byte-reader does not detect CR, or false-positives on LF. Every scan result below is MEANINGLESS.' `
'fix Measure-EolBytes; do NOT trust a green scan until both controls PASS'
}
else {
Write-Host ' [OK] reader detects CRLF and stays silent on LF - a green scan below is at least meaningful' -ForegroundColor Green
}
Write-Host ' (reminder: the control proves the READER works. It does NOT prove CRLF harms anything - S121 W0.6 measured that it does not.)' -ForegroundColor DarkGray
# ---------------------------------------------------------------------------
# Scoped scan - .gitattributes 'eol=lf' hygiene over the rule-set files.
# Scope per spec v2 W0.2 + R2. NOT repo-wide (see DESIGN NOTES).
# ---------------------------------------------------------------------------
Write-Section 'Scoped scan - .gitattributes eol=lf hygiene (.claude/{agents,commands,skills})'
$scopeSpecs = @(
[pscustomobject]@{ Name = '.claude/agents'; Dir = (Join-Path $RepoRoot '.claude\agents'); Filter = '*.md'; Recurse = $false },
[pscustomobject]@{ Name = '.claude/commands'; Dir = (Join-Path $RepoRoot '.claude\commands'); Filter = '*.md'; Recurse = $false },
[pscustomobject]@{ Name = '.claude/skills'; Dir = (Join-Path $RepoRoot '.claude\skills'); Filter = 'SKILL.md'; Recurse = $true }
)
$totalFiles = 0
$totalFmCrFiles = 0
$totalBodyCrFiles = 0
$totalNoFm = 0
$totalCrBytes = 0
foreach ($spec in $scopeSpecs) {
if (-not (Test-Path $spec.Dir)) {
Write-Host (" [skip] {0,-18} not present under RepoRoot" -f $spec.Name) -ForegroundColor DarkGray
continue
}
$files = @(Get-ChildItem -Path $spec.Dir -Filter $spec.Filter -File -Recurse:$spec.Recurse -ErrorAction SilentlyContinue)
$scopeScanned = 0
$scopeFmCr = 0
$scopeBodyCr = 0
$scopeCrBytes = 0
foreach ($f in $files) {
$m = Measure-EolFile $f.FullName
if ($null -eq $m) { continue }
$scopeScanned++
$totalFiles++
$scopeCrBytes += $m.TotalCr
$totalCrBytes += $m.TotalCr
if (-not $m.HasFrontmatter) { $totalNoFm++ }
if ($m.FmCr -gt 0) {
$scopeFmCr++
$totalFmCrFiles++
Write-Flag 'MED' (Rel $f.FullName) `
("eol-frontmatter-cr: {0} CR (0x0D) byte(s) inside the frontmatter block, {1} more in body - violates .gitattributes '* text=auto eol=lf'. HYGIENE only: S121 W0.6 measured a fully-CRLF agent file spawning correctly, so this is NOT a known breakage." -f $m.FmCr, $m.BodyCr) `
'rewrite the file with LF endings (git rm --cached <f> + git checkout -- <f>, or re-save as LF)'
}
elseif ($m.BodyCr -gt 0) {
$scopeBodyCr++
$totalBodyCrFiles++
Write-Flag 'LOW' (Rel $f.FullName) `
("eol-body-cr: frontmatter is clean but the body carries {0} CR (0x0D) byte(s) - same '* text=auto eol=lf' policy, further from any reader hot-path." -f $m.BodyCr) `
'rewrite the file with LF endings (hygiene / worktree-vs-blob consistency)'
}
}
Write-Host (" {0,-18} scanned={1,-3} frontmatter-CR-files={2,-3} body-only-CR-files={3,-3} CR-bytes={4}" -f `
$spec.Name, $scopeScanned, $scopeFmCr, $scopeBodyCr, $scopeCrBytes)
}
# ---------------------------------------------------------------------------
# Summary. Every label below is computed from a measured number (W0.4 lesson).
# ---------------------------------------------------------------------------
Write-Section 'Summary'
Write-Host ("scoped set (counted by glob, never hardcoded): {0} file(s)" -f $totalFiles)
Write-Host (" files with CR in frontmatter : {0}" -f $totalFmCrFiles)
Write-Host (" files with CR in body only : {0}" -f $totalBodyCrFiles)
Write-Host (" total CR (0x0D) bytes in set : {0}" -f $totalCrBytes)
Write-Host (" files with no parseable frontmatter block: {0} (not a flag - body CR still counted)" -f $totalNoFm)
Write-Host ''
Write-Host ("TOTAL FLAGS: {0} (scoped files={1}, CR bytes measured={2})" -f $script:FlagCount, $totalFiles, $totalCrBytes) -ForegroundColor Cyan
if (-not $controlOk) {
Write-Host 'RESULT: UNTRUSTWORTHY - the synthetic control FAILED, so the scan above proves nothing.' -ForegroundColor Red
}
elseif ($script:FlagCount -gt 0) {
Write-Host ("RESULT: {0} hygiene FLAG(s) above. Advisory only - exit code stays 0, nothing is known to be broken." -f $script:FlagCount) -ForegroundColor Yellow
}
elseif ($totalCrBytes -eq 0) {
Write-Host 'RESULT: GREEN-BUT-VACUOUS - 0 CR bytes existed in the scoped set, so this run had nothing to catch.' -ForegroundColor Yellow
Write-Host ' Do NOT bank this as an achievement: the scoped gate was ALREADY green with 0 work to do' -ForegroundColor DarkGray
Write-Host ' (spec v2 W0.2 / R2-C4). The only thing a green run demonstrates is that the reader itself' -ForegroundColor DarkGray
Write-Host ' works (synthetic control PASSED above). Its forward value is regression-catching, not this run.' -ForegroundColor DarkGray
}
else {
Write-Host 'RESULT: GREEN - CR bytes are present in the set but none in a flagged position.' -ForegroundColor Green
}
Write-Host 'NOTE: HYGIENE/INFORM net. Exit 0 always. CRLF-fatality was REFUTED by the S121 W0.6 spawn-probe (a fully-CRLF agent spawned OK through all 4 stages); this check enforces the .gitattributes eol=lf policy and nothing stronger.' -ForegroundColor DarkGray
exit 0