Files
solution-erp/scripts/spawn-model-audit.ps1
pqhuy1987 398d343403
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 5m48s
[CLAUDE] Docs: S149-S150 closeout — bookend lượt đầu end-to-end (hình B) + 2 arc đóng + tally #53 chốt 45
- 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>
2026-07-25 12:17:05 +07:00

522 lines
29 KiB
PowerShell

<#
.SYNOPSIS
spawn-model-audit.ps1 - H23 PA-2b: spawn-model audit, resolved-vs-expected. INFORMATIONAL.
.DESCRIPTION
Owner-decision S119 PA-2 (runs/2026-07-15-S119-adap-6-broadcast/owner-decisions-15-07-2026.md:59-60)
splits "anchor the model version" in two, because anchoring AT SPAWN is NOT possible at SE
(the spawn param takes an enum alias only; SE has 0 full-id in any definition file - H8 all-inherit):
PA-2a .claude/workflows/hmw.js declares TIER2_EXPECTED_FULL_ID (value lives ONLY there -
single-source, do NOT copy it here; stale copy 'claude-opus-4-8' fixed S150).
PA-2b THIS script compares the model actually RESOLVED at spawn against that constant.
Drift => print FLAG => owner decides re-pin. NO enforcement (H23 section 2(4)).
Design rules (mirror scripts/governance-detectors.ps1):
(1) NO-API - reads files only. NEVER calls a model/API.
(2) FLAG-only - prints FLAGs, NEVER edits files.
(3) PowerShell 5.1, offline. ASCII-only script body (gotcha #30); target files read -Encoding UTF8.
(4) DETECT-only. Exit code ALWAYS 0 (audit/inform, never a build gate).
---------------------------------------------------------------------------
MEASURABLE vs NOT-MEASURABLE - read before trusting any line of this report
---------------------------------------------------------------------------
MEASURED (this script really reads it, offline, from disk):
* expected = the TIER2_EXPECTED_FULL_ID constant in hmw.js [section A]
* resolved = "message":{"model":"..."} in the per-lane spawn transcripts
<TranscriptRoot>/<slug>/<session>/subagents/workflows/wf_*/agent-*.jsonl
Verified present S119: 9 lanes 'claude-opus-4-8' + 2 lanes 'claude-fable-5'. [section B]
NOT MEASURABLE HERE - declared, never silently passed:
(i) FORWARD drift. This audit is RETROSPECTIVE: it reads what ALREADY resolved in recorded
runs. It cannot pre-verify what the NEXT spawn will resolve to. A clean report does NOT
promise the next spawn stays on the expected version. This is exactly why H23 section 2(4)
makes it informational, not enforcement.
(ii) PRECEDENCE vs a frontmatter HARD-PIN - MEASURED at SE 2026-07-16 (S126), after S124
re-pinned all 14 agents THEN-EXISTING to 'model: opus' (ALIAS pin; roster is 17 as of
S141 - this measurement was taken when N was 14 and was NOT re-run for the 3 new ones):
spawn param 'fable' on agentType
reviewer (pin 'opus') RESOLVED claude-fable-5 (run wf_f960dae2-fa0, 3 records); a
control lane with NO override resolved claude-opus-4-8 under lead=Fable => the pin
itself works at runtime AND the spawn param BEATS it. Caveats: alias-pin only (the
hub form pins FULL-ID 'claude-opus-4-8' 17/17 - NOT covered by this measurement);
retrospective - says nothing about future spawns. Older 'inherit' evidence: below.
(iii)Whether the spawn param REJECTS a full-id (fix #8a). Per harness docs the param is an enum
alias (sonnet|opus|haiku|fable); passing a full-id has NEVER been tried. Not tried here.
(iv) Documentation coverage. This measures EXPLICITNESS IN TRANSCRIPTS only. A clean report must
NOT be read as "the floor is fully applied" (owner-decisions:65, honesty declaration 3).
PRECEDENCE - spawn-param vs frontmatter 'inherit': MEASURED 2026-07-15, no longer "never tested".
Spec v2:271 recorded this as CHUA TUNG DUOC TEST, reasoning that a discriminating experiment
needs lead=Fable. That reasoning only covered the tier:'opus' direction. The discriminating
condition is simply spawn-param family != lead family - and the tier:'fable' direction
satisfies it under lead=Opus. It ALREADY RAN, unplanned, in run wf_cb964f83-331:
lead model = claude-opus-4-8 (290/290 records, session 3d9bec56, zero Fable)
agentType = reviewer (.claude/agents/reviewer.md:5 = 'model: inherit')
spawn param = fable (/fable-real escape-hatch, hmw.js:44 returns the alias)
RESOLVED = claude-fable-5 (2/2 lanes, 39 + 42 assistant records)
If frontmatter 'inherit' had won, resolved would be the lead's claude-opus-4-8. It was not.
=> the spawn param TAKES EFFECT on a frontmatter-'inherit' agent => the GAP#6 fix is NOT a no-op.
HONEST LIMIT: this does not prove 'inherit' LOSES a precedence contest. 'inherit' may simply mean
"defer to the caller", in which case there is no contest at all. Both readings give the same
operative answer (the param takes effect); this data cannot separate them, and does not try.
UPDATE 2026-07-16 (S126): the hard-pin contest HAS now been measured - see NOT-MEASURABLE (ii)
above, which flipped to MEASURED. Param 'fable' beat frontmatter 'model: opus' on a real lane.
.PARAMETER RepoRoot
Repo root. Default = 2 levels up from this script (scripts/ -> repo root).
Every path derives from this, so -RepoRoot <temp tree> makes fault-injection possible.
.PARAMETER TranscriptRoot
Root of the CLI project transcripts. Default derives from $env:USERPROFILE (NOT a hardcoded
absolute path). The per-project folder name is derived from $RepoRoot, so a fault-inject tree
resolves to a slug with no transcripts and section B reports NO-SCOPE instead of faking a number.
.PARAMETER SessionId
Audit one specific session folder. Default = most recent session that HAS spawn transcripts.
Default-to-current is deliberate: scanning old history surfaces pre-convention runs, which is
noise, not a bug storm (owner-decisions:64, honesty declaration 2).
.EXAMPLE
powershell.exe -ExecutionPolicy Bypass -File scripts/spawn-model-audit.ps1
#>
param(
[string]$RepoRoot = (Resolve-Path (Join-Path $PSScriptRoot '..')).Path,
[string]$TranscriptRoot = (Join-Path $env:USERPROFILE '.claude\projects'),
[string]$SessionId = ''
)
$ErrorActionPreference = 'Continue'
# ---------------------------------------------------------------------------
# Owner-ratified expectation (S119 PA-2a, owner-decisions-15-07-2026.md:59).
# Deliberate 2-key design: the expected version is declared TWICE - once in hmw.js (PA-2a) and
# once here - so that a unilateral edit of ONE of them is FLAGGED instead of passing silently.
# Cost, stated plainly: an owner re-pin must touch BOTH files. That cost IS the check.
# NOT a fallback: if hmw.js has no constant, section A fails loud - it never borrows this value.
# ---------------------------------------------------------------------------
# 🔄 VALUE-update 2026-07-25 (broadcast model-default-opus-5-max sha 59ce1d0f + SE-owner "dam Opus 5 MAX"):
# 'claude-opus-4-8' -> 'claude-opus-5'. Khoan 1.4: records cu mang 'claude-opus-4-8*' = LEGACY bucket
# trong giai doan chuyen tiep — dem rieng, KHONG co drift (tranh bao canh bao gia tren ban ghi cu).
# 2-key: doi DONG THOI voi TIER2_EXPECTED_FULL_ID trong .claude/workflows/hmw.js (cung commit).
$OWNER_RATIFIED_TIER2_FULL_ID = 'claude-opus-5'
$TIER2_LEGACY_FULL_ID = 'claude-opus-4-8'
# Family that the 'opus' alias maps to. Alias locks the FAMILY, not the version (H23 section 2(2)):
# same family + different version = the drift this audit exists to catch.
$TIER2_FAMILY_PREFIX = 'claude-opus-'
# ---------------------------------------------------------------------------
# Helpers (shape mirrors scripts/governance-detectors.ps1:43-67)
# ---------------------------------------------------------------------------
$script:FlagCount = 0
function Write-Flag {
param(
[ValidateSet('HIGH', 'MED', 'LOW')] [string]$Severity,
[string]$Where,
[string]$Desc,
[string]$Resolve
)
$color = switch ($Severity) { 'HIGH' { 'Red' } 'MED' { 'Yellow' } default { 'Gray' } }
Write-Host ("[SPAWN-AUDIT] {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
}
function Rel($full) {
$r = $full
if ($full.StartsWith($RepoRoot, [StringComparison]::OrdinalIgnoreCase)) {
$r = $full.Substring($RepoRoot.Length).TrimStart('\', '/')
}
return ($r -replace '\\', '/')
}
Write-Host ''
Write-Host '########## spawn-model-audit.ps1 - H23 PA-2b (INFORMATIONAL, exit 0 always) ##########' -ForegroundColor Cyan
Write-Host ("RepoRoot: {0}" -f $RepoRoot) -ForegroundColor DarkGray
# ===========================================================================
# SECTION A - PA-2a: the EXPECTED constant in hmw.js (STATIC, measurable)
# ===========================================================================
Write-Section 'A - expected constant (PA-2a, hmw.js)'
$hmwPath = Join-Path $RepoRoot '.claude\workflows\hmw.js'
$expected = $null
if (-not (Test-Path $hmwPath)) {
Write-Flag 'HIGH' (Rel $hmwPath) 'hmw.js not found - cannot resolve the expected model version' `
'run from a repo root that contains .claude/workflows/hmw.js'
}
else {
# STRUCTURAL anchor, NOT a loose string grep (W0.4 lesson 1 - self-reference).
# Capture the VALUE of the assignment. A bare grep for the version string is NOT acceptable
# evidence here: hmw.js also carries the expected literal inside COMMENT text (measured S150:
# naive grep = 2 hits, both comments), so a naive grep returns >=1 hit and passes VACUOUSLY
# even when the constant is absent or holds a wrong value. (Old line-pinned example
# 'hmw.js:36 demote-pin' died in an edit - keep this description line-number-free, S150.)
# The naive count is printed below as a counter-example only - it is never used as evidence.
$RX_CONST = 'TIER2_EXPECTED_FULL_ID\s*=\s*[''"]([^''"]+)[''"]'
$constHits = @(Select-String -Path $hmwPath -Pattern $RX_CONST -Encoding UTF8 -AllMatches)
$naiveHits = @(Select-String -Path $hmwPath -Pattern ([regex]::Escape($OWNER_RATIFIED_TIER2_FULL_ID)) -Encoding UTF8)
Write-Host (" anti-vacuous note: naive grep '{0}' in hmw.js = {1} hit(s) [comment text] -> NOT used as evidence" -f `
$OWNER_RATIFIED_TIER2_FULL_ID, $naiveHits.Count) -ForegroundColor DarkGray
if ($constHits.Count -eq 0) {
# FAIL-LOUD. No hardcoded default is substituted: an audit that invents the value it is
# meant to verify would report a PASS about itself.
Write-Flag 'HIGH' (Rel $hmwPath) `
'expected constant missing (W2 chua land): TIER2_EXPECTED_FULL_ID not declared in hmw.js' `
("land PA-2a: add TIER2_EXPECTED_FULL_ID = '{0}' next to resolveModel() in hmw.js" -f $OWNER_RATIFIED_TIER2_FULL_ID)
Write-Host ' -> section B comparison will report SKIPPED (no expected value to compare against)' -ForegroundColor DarkGray
}
else {
$values = @()
foreach ($h in $constHits) {
foreach ($m in $h.Matches) { $values += $m.Groups[1].Value }
}
$distinctValues = @($values | Sort-Object -Unique)
Write-Host (" found {0} definition(s) of TIER2_EXPECTED_FULL_ID; distinct value(s): {1}" -f `
$values.Count, ($distinctValues -join ', '))
foreach ($h in $constHits) {
Write-Host (" {0}:{1}" -f (Rel $hmwPath), $h.LineNumber) -ForegroundColor DarkGray
}
if ($distinctValues.Count -gt 1) {
Write-Flag 'HIGH' (Rel $hmwPath) `
("conflicting definitions: TIER2_EXPECTED_FULL_ID declared with {0} different values [{1}]" -f `
$distinctValues.Count, ($distinctValues -join ' vs ')) `
'keep exactly ONE authoritative definition of TIER2_EXPECTED_FULL_ID'
}
$expected = $distinctValues[0]
# PASS/FAIL is COMPUTED from the measured value (W0.4 lesson 2 - never a label pasted
# next to a number that says otherwise).
if ($expected -cne $OWNER_RATIFIED_TIER2_FULL_ID) {
Write-Flag 'HIGH' (Rel $hmwPath) `
("mismatch vs owner-ratified expectation: hmw.js declares '{0}' but S119 PA-2a ratified '{1}'" -f `
$expected, $OWNER_RATIFIED_TIER2_FULL_ID) `
("set TIER2_EXPECTED_FULL_ID = '{0}', or have the owner re-ratify and update this script" -f $OWNER_RATIFIED_TIER2_FULL_ID)
}
else {
Write-Host (" [OK] hmw.js expected = '{0}' = owner-ratified (S119 PA-2a)" -f $expected) -ForegroundColor Green
}
if ($expected -match '\[1m\]') {
Write-Flag 'MED' (Rel $hmwPath) `
("expected value carries a '[1m]' context-window suffix: '{0}'" -f $expected) `
'drop the [1m] suffix - it is not part of the model id (gotcha #37)'
}
}
}
# ===========================================================================
# SECTION B - PA-2b: the RESOLVED model, from spawn transcripts (MEASURED)
# ===========================================================================
Write-Section 'B - resolved model (PA-2b, spawn transcripts)'
# Project folder name derives from $RepoRoot (path separators -> '-'), so a fault-inject tree
# resolves to a slug with no transcripts -> NO-SCOPE, never a faked measurement.
$slug = $RepoRoot -replace '[:\\/_]', '-'
$projDir = Join-Path $TranscriptRoot $slug
$dispatch = 0 # spawn lanes found (one agent-*.jsonl = one lane)
$explicit = 0 # lanes where a resolved model is actually recorded
$mismatch = 0 # lanes resolved to the tier-2 FAMILY but NOT the expected version = alias drift
$otherFam = 0 # lanes resolved outside the tier-2 family (escape-hatch / inherited lead)
$legacy = 0 # lanes resolved the PRE-FLIP default (transition bucket, Khoan 1.4 - counted, not flagged)
$modelTally = @{}
Write-Host (" transcript root: {0}" -f $TranscriptRoot) -ForegroundColor DarkGray
Write-Host (" project slug : {0} (derived from RepoRoot)" -f $slug) -ForegroundColor DarkGray
if (-not (Test-Path $projDir)) {
Write-Host ' [NO-SCOPE] no transcript folder for this repo - nothing to measure, nothing claimed.' -ForegroundColor DarkGray
Write-Host ' (expected when running against a fault-inject / temp tree)' -ForegroundColor DarkGray
}
else {
$sessionDir = $null
if ($SessionId -ne '') {
$cand = Join-Path $projDir $SessionId
if (Test-Path $cand) { $sessionDir = Get-Item $cand }
else { Write-Flag 'MED' (Rel $cand) 'requested -SessionId not found' 'pass an existing session id, or omit to use the most recent' }
}
else {
$sessionDir = Get-ChildItem -Path $projDir -Directory -ErrorAction SilentlyContinue |
Where-Object { Test-Path (Join-Path $_.FullName 'subagents\workflows') } |
Sort-Object LastWriteTime -Descending | Select-Object -First 1
}
if ($null -eq $sessionDir) {
Write-Host ' [NO-SCOPE] no session with spawn transcripts under this project - nothing measured.' -ForegroundColor DarkGray
}
else {
Write-Host (" session scope : {0} (last write {1:yyyy-MM-dd HH:mm})" -f $sessionDir.Name, $sessionDir.LastWriteTime)
Write-Host ' scope = CURRENT session only, by design (old runs predate the convention; owner-decisions:64)' -ForegroundColor DarkGray
# STRUCTURAL anchor: the model key of an assistant record sits immediately inside
# "message":{ ... . Anchoring on the record shape (not a bare "model": grep) keeps quoted
# JSON inside message CONTENT - agents routinely paste transcript snippets - from being
# counted as if it were a real dispatch.
$RX_MODEL = '"message"\s*:\s*\{\s*"model"\s*:\s*"([^"]+)"'
$wfRoot = Join-Path $sessionDir.FullName 'subagents\workflows'
$laneFiles = @(Get-ChildItem -Path $wfRoot -Recurse -Filter 'agent-*.jsonl' -File -ErrorAction SilentlyContinue)
foreach ($lane in $laneFiles) {
$dispatch++
$hits = @(Select-String -Path $lane.FullName -Pattern $RX_MODEL -Encoding UTF8 -AllMatches)
$models = @()
foreach ($h in $hits) {
foreach ($m in $h.Matches) { $models += $m.Groups[1].Value }
}
$distinct = @($models | Sort-Object -Unique)
$wfName = Split-Path (Split-Path $lane.FullName -Parent) -Leaf
$agentType = '?'
$metaPath = ($lane.FullName -replace '\.jsonl$', '.meta.json')
if (Test-Path $metaPath) {
$metaTxt = Get-Content -Path $metaPath -Raw -Encoding UTF8
$mm = [regex]::Match($metaTxt, '"agentType"\s*:\s*"([^"]+)"')
if ($mm.Success) { $agentType = $mm.Groups[1].Value }
}
if ($distinct.Count -eq 0) {
Write-Host (" {0}/{1} [{2}] -> no model recorded (lane produced no assistant record)" -f `
$wfName, $lane.Name, $agentType) -ForegroundColor DarkGray
continue
}
$explicit++
foreach ($d in $distinct) {
if ($modelTally.ContainsKey($d)) { $modelTally[$d] = $modelTally[$d] + 1 }
else { $modelTally[$d] = 1 }
}
$verdict = 'other-family'
$inFamily = @($distinct | Where-Object { $_.StartsWith($TIER2_FAMILY_PREFIX) })
if ($null -eq $expected) {
$verdict = 'SKIPPED (no expected constant)'
}
elseif ($inFamily.Count -eq 0) {
$verdict = 'other-family (escape-hatch / inherited lead - not a drift signal)'
$otherFam++
}
else {
$bad = @($inFamily | Where-Object { $_ -cne $expected })
# Khoan 1.4 broadcast model-default-opus-5-max (2026-07-25): records that resolved the
# PREVIOUS default are a LEGACY bucket during the transition, counted separately,
# NOT flagged as drift (a value-update flips the expected mid-history; old records
# predate the flip - flagging them is a false alarm storm, exactly what 1.4 forbids).
# A record that is neither expected NOR legacy is still a REAL mismatch.
$legacyOnly = @($bad | Where-Object { $_ -cne $TIER2_LEGACY_FULL_ID })
if ($bad.Count -gt 0 -and $legacyOnly.Count -eq 0) {
$legacy++
$verdict = ("legacy ({0} = pre-flip default; transition bucket Khoan 1.4, not drift)" -f ($bad -join ', '))
}
elseif ($legacyOnly.Count -gt 0) {
$mismatch++
$verdict = 'MISMATCH'
Write-Flag 'HIGH' ("{0}/{1}" -f $wfName, $lane.Name) `
("alias-drift: resolved '{0}' is in the tier-2 family but expected '{1}' (and not the legacy bucket)" -f ($legacyOnly -join ', '), $expected) `
'owner decides re-pin (H23 section 2(2)); update TIER2_EXPECTED_FULL_ID once ratified'
}
else {
$verdict = 'match'
}
}
Write-Host (" {0}/{1} [{2}] -> {3} ({4} record(s)) : {5}" -f `
$wfName, $lane.Name, $agentType, ($distinct -join ', '), $models.Count, $verdict)
}
Write-Host ''
Write-Host (" COUNTS: {0} dispatch | {1} explicit | {2} mismatch" -f $dispatch, $explicit, $mismatch)
Write-Host ' (dispatch = lanes found | explicit = lanes with a model actually recorded | mismatch = tier-2-family lanes off the expected version)' -ForegroundColor DarkGray
if ($modelTally.Count -gt 0) {
Write-Host ' resolved model tally (lanes per model):'
foreach ($k in ($modelTally.Keys | Sort-Object)) {
Write-Host (" {0,-24} {1} lane(s)" -f $k, $modelTally[$k])
}
}
if ($null -eq $expected) {
Write-Host ' [SKIPPED] resolved-vs-expected NOT evaluated: section A found no expected constant.' -ForegroundColor Yellow
Write-Host ' This is NOT a pass. The lanes above are reported raw, uncompared.' -ForegroundColor Yellow
}
elseif ($dispatch -eq 0) {
Write-Host ' [NO-SCOPE] 0 lanes in scope - a 0-mismatch count here would be VACUOUS, not a pass.' -ForegroundColor Yellow
}
elseif ($mismatch -eq 0) {
Write-Host (" [OK] 0/{0} lane(s) drifted off expected '{1}' (retrospective only - says nothing about the NEXT spawn)" -f `
$explicit, $expected) -ForegroundColor Green
}
}
}
# ===========================================================================
# SECTION C - canonical cross-check: docs/STATUS.md, the Sub-agents row
# ===========================================================================
Write-Section 'C - canonical cross-check (STATUS.md Sub-agents row)'
# Row label read from the file, not guessed: docs/STATUS.md:24 = "| Sub-agents | **12** | ...".
# That row is the single-owner flip-chain canonical; hmw.js:34 and agents/README point at it.
$SUBAGENT_ROW_LABEL = 'Sub-agents'
$FLIPCHAIN_MARKER = 'CANONICAL single-owner flip-chain'
$statusPath = Join-Path $RepoRoot 'docs\STATUS.md'
if (-not (Test-Path $statusPath)) {
Write-Flag 'MED' (Rel $statusPath) 'docs/STATUS.md not found - cannot cross-check the roster canonical' `
'run against a repo root that contains docs/STATUS.md'
}
else {
$rowPat = '^\|\s*' + [regex]::Escape($SUBAGENT_ROW_LABEL) + '\s*\|\s*\*\*(\d+)'
$rowHit = Select-String -Path $statusPath -Pattern $rowPat -Encoding UTF8 | Select-Object -First 1
if ($null -eq $rowHit) {
Write-Flag 'MED' (Rel $statusPath) `
("canonical row '| {0} | **N** |' not found in STATUS.md CURRENT STATE table" -f $SUBAGENT_ROW_LABEL) `
'restore the Sub-agents row, or update this script if the canonical owner moved'
}
else {
$canonSub = [int]$rowHit.Matches[0].Groups[1].Value
Write-Host (" STATUS.md:{0} canonical {1} = {2}" -f $rowHit.LineNumber, $SUBAGENT_ROW_LABEL, $canonSub)
if ($rowHit.Line -notmatch [regex]::Escape($FLIPCHAIN_MARKER)) {
Write-Flag 'LOW' ("{0}:{1}" -f (Rel $statusPath), $rowHit.LineNumber) `
("the {0} row no longer carries the '{1}' marker" -f $SUBAGENT_ROW_LABEL, $FLIPCHAIN_MARKER) `
'restore the marker, or re-point this cross-check at the new canonical owner'
}
else {
Write-Host (" [OK] row carries the flip-chain canonical marker") -ForegroundColor Green
}
# disk cross-check: the canonical count must not itself be stale.
$agentDir = Join-Path $RepoRoot '.claude\agents'
if (Test-Path $agentDir) {
$diskAgents = @(Get-ChildItem -Path $agentDir -Filter *.md -File -ErrorAction SilentlyContinue |
Where-Object { $_.Name -ne 'README.md' })
Write-Host (" disk cross-check: .claude/agents/*.md minus README = {0}" -f $diskAgents.Count)
if ($diskAgents.Count -ne $canonSub) {
Write-Flag 'MED' (Rel $statusPath) `
("canonical-itself-stale: STATUS {0}=**{1}** but disk has {2} agent .md" -f `
$SUBAGENT_ROW_LABEL, $canonSub, $diskAgents.Count) `
("re-ground the STATUS.md {0} row to {1}" -f $SUBAGENT_ROW_LABEL, $diskAgents.Count)
}
else {
Write-Host (" [OK] canonical {0} matches disk ({1})" -f $canonSub, $diskAgents.Count) -ForegroundColor Green
}
}
}
}
# ===========================================================================
# SECTION D - S124 worker-tier-pin: agent frontmatter (model: opus + effort: max)
# (was: H8 all-inherit - superseded by owner-decision S124 2026-07-15, adap erratum-h8)
# ===========================================================================
Write-Section 'D - frontmatter worker-tier-pin (S124)'
# GLOB, never a hardcoded roster size: the roster moves 12 -> 14 at W2, and a hardcoded count
# would self-age into a false FAIL the moment it lands (fix #9(h) / R2-M3).
$agentDir = Join-Path $RepoRoot '.claude\agents'
if (-not (Test-Path $agentDir)) {
Write-Flag 'MED' (Rel $agentDir) '.claude/agents not found - cannot check frontmatter' `
'run against a repo root that contains .claude/agents'
}
else {
$agentFiles = @(Get-ChildItem -Path $agentDir -Filter *.md -File -ErrorAction SilentlyContinue |
Where-Object { $_.Name -ne 'README.md' })
$pinCount = 0
$effortOkCount = 0
foreach ($a in $agentFiles) {
$lines = @(Get-Content -Path $a.FullName -Encoding UTF8)
# frontmatter = the block between the first '---' and the next '---'
$modelVal = $null
$modelLine = 0
$effortVal = $null
$effortLine = 0
$inFm = $false
for ($i = 0; $i -lt $lines.Count; $i++) {
$t = $lines[$i].Trim()
if ($t -eq '---') {
if (-not $inFm) { $inFm = $true; continue }
break
}
if ($inFm -and $t -match '^model\s*:\s*(.+?)\s*$') {
$modelVal = $Matches[1].Trim()
$modelLine = $i + 1
}
if ($inFm -and $t -match '^effort\s*:\s*(.+?)\s*$') {
$effortVal = $Matches[1].Trim()
$effortLine = $i + 1
}
}
if ($null -eq $modelVal) {
Write-Flag 'MED' (Rel $a.FullName) `
'no "model:" key in frontmatter - the lane falls back to a harness default, NOT the worker-tier pin' `
'add "model: opus" to the agent frontmatter (S124 worker-tier-pin)'
}
elseif ($modelVal -cne 'opus') {
Write-Flag 'MED' ("{0}:{1}" -f (Rel $a.FullName), $modelLine) `
("frontmatter has 'model: {0}' - S124 worker-tier-pin expects every agent pinned 'model: opus'" -f $modelVal) `
'set "model: opus", or have the owner ratify the change and record it in STATUS.md Sub-agents'
}
else {
$pinCount++
}
if ($null -eq $effortVal) {
Write-Flag 'MED' (Rel $a.FullName) `
'no "effort:" key in frontmatter - S124 worker-tier-pin expects "effort: max" alongside the model pin' `
'add "effort: max" to the agent frontmatter (S124 worker-tier-pin)'
}
elseif ($effortVal -cne 'max') {
Write-Flag 'MED' ("{0}:{1}" -f (Rel $a.FullName), $effortLine) `
("frontmatter has 'effort: {0}' - S124 worker-tier-pin expects 'effort: max'" -f $effortVal) `
'set "effort: max", or have the owner ratify the change and record it in STATUS.md Sub-agents'
}
else {
$effortOkCount++
}
}
# verdict COMPUTED from the counts, never a pasted label (W0.4 lesson 2)
Write-Host (" frontmatter: {0}/{1} agent .md carry 'model: opus' and {2}/{1} carry 'effort: max' (S124 worker-tier-pin)" -f `
$pinCount, $agentFiles.Count, $effortOkCount)
if ($agentFiles.Count -eq 0) {
Write-Host ' [NO-SCOPE] 0 agent .md found - a clean result here would be VACUOUS.' -ForegroundColor Yellow
}
elseif (($pinCount -eq $agentFiles.Count) -and ($effortOkCount -eq $agentFiles.Count)) {
Write-Host (" [OK] worker-tier-pin holds ({0}/{0} model + {0}/{0} effort)" -f $agentFiles.Count) -ForegroundColor Green
}
}
# ===========================================================================
# SECTION E - declared limits (printed EVERY run, so no report can over-read)
# ===========================================================================
Write-Section 'E - what this report does NOT say'
Write-Host ' 1. SPOT-CHECK BY CONVENTION, NOT ENFORCEMENT. Nothing here blocks a spawn (H23 section 2(4)).'
Write-Host ' 2. CURRENT SESSION ONLY. Older runs predate the convention; scanning them yields noise, not a bug storm.'
Write-Host ' 3. NOT "the floor is applied". This measures explicitness in transcripts, never documentation coverage.'
Write-Host ' 4. RETROSPECTIVE ONLY. It reads models that ALREADY resolved; it cannot pre-verify the NEXT spawn.'
Write-Host ' 5. TESTED 2026-07-16 (S126) - spawn param vs frontmatter HARD-PIN: the param WON (reviewer pinned opus +'
Write-Host ' spawn fable -> claude-fable-5; no-override control -> claude-opus-4-8 under lead=Fable). ALIAS-pin only;'
Write-Host ' the full-id-pin form (hub) is still untested here. Inherit-case evidence: header, wf_cb964f83-331.'
Write-Host ' 6. NOT TRIED - whether the spawn param rejects a full-id (fix #8a). Docs say enum alias; never attempted.'
# ---------------------------------------------------------------------------
# Summary
# ---------------------------------------------------------------------------
Write-Section 'Summary'
Write-Host ("TOTAL FLAGS: {0}" -f $script:FlagCount) -ForegroundColor Cyan
Write-Host 'NOTE: informational audit. Exit 0 always (never fails a build). FLAGs are advisory - owner decides re-pin.' -ForegroundColor DarkGray
exit 0