Files
solution-erp/scripts/nhip-no-probe.ps1
pqhuy1987 36cefcca62
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 5m26s
[CLAUDE] Docs: vá 9 finding audit S143 + mở enum gap-incident-unrecorded
Audit 3 lane (reviewer FAIL 1C/4M/4m/1nit + 2 vai H24 = 6 FLAG), lead tự
re-đo từng finding trước khi vá.

CRITICAL/MAJOR:
- Re-anchor 5 adap-report: sha wal: tiền-closeout (1a0fa59/a458102/96ab2679)
  dangling sau squash -> hub clone không resolve nổi. Đổi sang 2757e41.
  LUẬT: cite outward = commit SẼ SỐNG sau squash, không bao giờ wal:.
- Đính chính claim OK-reachable: phép đo tự huỷ trong cùng phiên (squash lật
  sang squash-benign). Sự thật mạnh hơn: cả 2 nhánh lành đã chạy runtime.
- TRIPLE 17/17/17 chọn enum dễ: README:225 (tự xưng "ĐỦ roster") còn 14 +
  "4 monitor"; README:27 ("Roster THẬT") còn 14. Cả 2 vá -> 17/7.
- TOTAL 46 "== baseline" sai: baseline ghi trong repo là 45. Tách claim-DELTA
  (bền) khỏi claim-TUYỆT-ĐỐI (phải neo commit+thời-điểm).

FLAG view-residual-asym: STATUS:450 + README:190 còn khai "NO Write/Edit" như
cơ-chế chặn -> sửa thành tuyên-bố ý-định (runtime vẫn cấp, 9/9 vai; nhân-chứng
reviewer đã Write+Edit thật).

FLAG gap-carry-dropped: HANDOFF carry 13 -> 14, trả [carry:session-model-adopt].
FLAG gap-decision-sunk: 3 mục "Chờ-anh" chìm 2 nhãn phiên -> lên NEXT anh (10)(11)(12).

Enum flag_classes 10 -> 11: +gap-incident-unrecorded (anh duyệt). Vai
lead-omission từ chối tự chế class và escalate đúng luật CLOSED-enum.

Bài học acceptance: AC4 grep theo SỐ nên 2 site liệt-kê-TÊN lọt lưới.
Lần sau đếm PHẦN TỬ rồi so canonical, đừng so hình-dạng chuỗi.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-22 13:40:49 +07:00

209 lines
10 KiB
PowerShell

<#
.SYNOPSIS
nhip-no-probe.ps1 - Harness-25 "no hien thi" 3-part debt line (B1 section 3.3 floor).
.DESCRIPTION
ONE-LINE, READ-ONLY, ZERO-MUTATION debt probe. Called (never inlined) by the
session command surfaces (/pause, /tiep, session-start, session-end) so a stop
point always PRINTS the standing debt. Contract:
(1) NO-API, NO-MUTATION - only reads JSON + measures file bytes + lists dirs.
(2) exit 0 ALWAYS - a probe MUST NEVER block a stop point. Any exception ->
prints 'probe-loi (khong chan)' and still exit 0.
(3) PowerShell 5.1 compatible, ASCII-only script body (gotcha #30): every
output token is ASCII (NHIP-NO / kiem / light / deep / OVERDUE / over-cap /
run-chua-gom / CONFIG-THIEU / probe-loi) so a BOM-less .ps1 decoded under the
system ANSI codepage never mojibakes.
(4) NO hardcoded cadence/cap - light_every / deep_every / autoinject_cap_bytes are
READ FROM config keys. A MISSING h24_cadence key prints CONFIG-THIEU(h24_cadence)
IN-LINE (no assumed default, not swallowed into the generic probe-loi) - keeps
the no-default signal H24-2 depends on.
Output contract - EXACTLY one line:
NHIP-NO: kiem light a/e deep b/f <ok|OVERDUE:light|deep> | tran-bo-nho x over-cap | run-chua-gom y | pull-cach N ngay
* kiem = audit cadence: a = counter - last_audit.light_at_counter (light debt),
e = h24_cadence.light_every ; b/f = deep pair. OVERDUE when a>=e or b>=f.
* tran-bo-nho = x agent-memory/*/MEMORY.md files whose (Get-Item).Length exceeds
archive_gate.autoinject_cap_bytes (byte-measured FRESH, NOT the stale
'measured' snapshot; Get-Content-count is FORBIDDEN - bay E-010/S130).
* run-chua-gom = y orphan run-folders per the DUAL-ACCEPT rule ported verbatim
from tiep.md:40-53 (flat *-synthesis.md OR C8 harvest/*-synthesis.md,
each non-empty; retired form-3 NOT ported).
* pull-cach = N days since the most recent INBOUND receive-date in
broadcasts/_index.md (col-1 of rows ABOVE the OUTBOUND header).
WHY THIS VE EXISTS (S143): the standing instruction was "watch
broadcasts/inbox" - but inbox only ever holds mail ALREADY pulled,
so it can NEVER surface un-pulled mail. It stayed silent by design
while SE waited on a hub reply that had been sitting in the hub
outbox since 18-07, until the hub had to send a nudge. This ve
measures the thing that was actually blind.
THRESHOLD IS DELIBERATELY ABSENT: prints the raw number only.
If key h24_cadence.pull_warn_days is present it also appends
OVERDUE:pull - but SE does NOT invent that number (owner's call,
same discipline as declining to pick session_ctx_kb).
Unparseable/absent index -> 'pull-cach n-a' (NEVER kills ve 1-3).
.PARAMETER RepoRoot
Repo root. Default = resolved one level up from this script (scripts/ -> repo root).
A non-existent RepoRoot is a probe error -> 'probe-loi (khong chan)' + exit 0.
.EXAMPLE
powershell.exe -ExecutionPolicy Bypass -File scripts/nhip-no-probe.ps1
#>
param(
[string]$RepoRoot = (Resolve-Path (Join-Path $PSScriptRoot '..')).Path
)
$ErrorActionPreference = 'Stop'
# Read a file's byte length via Get-Item (FORBIDDEN: Get-Content line/char count -
# a no-BOM file counted through Get-Content mis-sizes VN text x2-3, bug E-010/S130).
function Get-ByteLen {
param([string]$Path)
return (Get-Item -LiteralPath $Path -ErrorAction Stop).Length
}
try {
if (-not (Test-Path -LiteralPath $RepoRoot)) {
throw "RepoRoot not found: $RepoRoot"
}
# -----------------------------------------------------------------------
# Ve 1 - nhip-kiem (audit cadence debt). Numerators from .session-counter.json,
# denominators from memory-budget.json h24_cadence (READ, never hardcoded).
# -----------------------------------------------------------------------
$counterPath = Join-Path $RepoRoot '.claude\governance\.session-counter.json'
$budgetPath = Join-Path $RepoRoot '.claude\agent-memory\memory-budget.json'
$sc = Get-Content -LiteralPath $counterPath -Raw -Encoding UTF8 | ConvertFrom-Json
$budget = Get-Content -LiteralPath $budgetPath -Raw -Encoding UTF8 | ConvertFrom-Json
$cad = $budget.h24_cadence
if ($null -eq $cad) {
# h24_cadence key ABSENT -> fail-loud IN-LINE (no default, not probe-loi).
$kiemSeg = 'CONFIG-THIEU(h24_cadence)'
}
elseif ($null -eq $cad.light_every) {
$kiemSeg = 'CONFIG-THIEU(h24_cadence.light_every)'
}
elseif ($null -eq $cad.deep_every) {
$kiemSeg = 'CONFIG-THIEU(h24_cadence.deep_every)'
}
else {
$counter = [int]$sc.counter
$lightAt = [int]$sc.last_audit.light_at_counter
$deepAt = [int]$sc.last_audit.deep_at_counter
$lightEvery = [int]$cad.light_every
$deepEvery = [int]$cad.deep_every
$aLight = $counter - $lightAt
$bDeep = $counter - $deepAt
$over = @()
if ($aLight -ge $lightEvery) { $over += 'light' }
if ($bDeep -ge $deepEvery) { $over += 'deep' }
$status = if ($over.Count -gt 0) { 'OVERDUE:' + ($over -join ',') } else { 'ok' }
$kiemSeg = ("light {0}/{1} deep {2}/{3} {4}" -f $aLight, $lightEvery, $bDeep, $deepEvery, $status)
}
# -----------------------------------------------------------------------
# Ve 2 - tran-bo-nho (memory ceiling). Byte-measure agent-memory/*/MEMORY.md
# FRESH vs archive_gate.autoinject_cap_bytes (from key, not hardcoded).
# -----------------------------------------------------------------------
$cap = $budget.archive_gate.autoinject_cap_bytes
if ($null -eq $cap) {
$tranSeg = 'tran-bo-nho CONFIG-THIEU(autoinject_cap_bytes) over-cap'
}
else {
$capN = [int]$cap
$overCap = 0
$memRoot = Join-Path $RepoRoot '.claude\agent-memory'
if (Test-Path $memRoot) {
foreach ($mem in (Get-ChildItem -Path $memRoot -Directory -ErrorAction SilentlyContinue)) {
$mf = Join-Path $mem.FullName 'MEMORY.md'
if (Test-Path $mf) {
if ((Get-ByteLen $mf) -gt $capN) { $overCap++ }
}
}
}
$tranSeg = ("tran-bo-nho {0} over-cap" -f $overCap)
}
# -----------------------------------------------------------------------
# Ve 3 - run-chua-gom (orphan runs). DUAL-ACCEPT ported from tiep.md:40-53:
# form-1 flat <dir>/*-synthesis.md (-s = exists AND non-empty)
# form-2 C8 <dir>/harvest/*-synthesis.md
# form-3 (run.md '## synthesis' heading) = RETIRED @S123, NOT ported.
# -----------------------------------------------------------------------
$orphan = 0
$runsDir = Join-Path $RepoRoot '.claude\workflows\runs'
if (Test-Path $runsDir) {
foreach ($d in (Get-ChildItem -Path $runsDir -Directory -ErrorAction SilentlyContinue)) {
$runMd = Join-Path $d.FullName 'run.md'
if (-not (Test-Path $runMd)) { continue } # no run.md -> not a run -> skip
$found = $false
foreach ($f in (Get-ChildItem -Path $d.FullName -Filter '*-synthesis.md' -File -ErrorAction SilentlyContinue)) {
if ((Get-ByteLen $f.FullName) -gt 0) { $found = $true; break }
}
if (-not $found) {
$harvestDir = Join-Path $d.FullName 'harvest'
if (Test-Path $harvestDir) {
foreach ($f in (Get-ChildItem -Path $harvestDir -Filter '*-synthesis.md' -File -ErrorAction SilentlyContinue)) {
if ((Get-ByteLen $f.FullName) -gt 0) { $found = $true; break }
}
}
}
if (-not $found) { $orphan++ }
}
}
$runSeg = ("run-chua-gom {0}" -f $orphan)
# -----------------------------------------------------------------------
# Ve 4 - pull-cach (broadcast pull lag). Own try/catch ON PURPOSE: a NEW ve
# must never be able to blind the 3 ves that already work. Any failure here
# degrades to 'pull-cach n-a', it does NOT fall through to probe-loi.
# -----------------------------------------------------------------------
$pullSeg = 'pull-cach n-a'
try {
$idxPath = Join-Path $RepoRoot 'broadcasts\_index.md'
if (Test-Path -LiteralPath $idxPath) {
$lines = Get-Content -LiteralPath $idxPath -Encoding UTF8
# Rows ABOVE the OUTBOUND header are INBOUND. Match on the ASCII token
# only - the real heading carries an emoji this script must not contain.
$cut = $lines.Count
for ($i = 0; $i -lt $lines.Count; $i++) {
if ($lines[$i] -match '^#{1,6}.*OUTBOUND') { $cut = $i; break }
}
$newest = $null
for ($i = 0; $i -lt $cut; $i++) {
if ($lines[$i] -match '^\|\s*(\d{4}-\d{2}-\d{2})\s*\|') {
$d = [datetime]::ParseExact($Matches[1], 'yyyy-MM-dd', $null)
if ($null -eq $newest -or $d -gt $newest) { $newest = $d }
}
}
if ($null -ne $newest) {
$days = [int]([datetime]::Now.Date - $newest.Date).TotalDays
$pullSeg = ("pull-cach {0} ngay" -f $days)
# Threshold is OPTIONAL and owner-owned. Absent key = stay INFORM,
# do NOT assume a default (that would be inventing owner's number).
$warn = $null
if ($null -ne $cad) { $warn = $cad.pull_warn_days }
if ($null -ne $warn -and $days -ge [int]$warn) {
$pullSeg = ("pull-cach {0}/{1} ngay OVERDUE:pull" -f $days, [int]$warn)
}
}
}
}
catch {
$pullSeg = 'pull-cach n-a'
}
Write-Host ("NHIP-NO: kiem {0} | {1} | {2} | {3}" -f $kiemSeg, $tranSeg, $runSeg, $pullSeg)
}
catch {
# A probe NEVER blocks a stop point. Any failure prints one generic line.
Write-Host 'probe-loi (khong chan)'
}
exit 0