[CLAUDE] Docs: S151 closeout — bootstrap + trio-AUTO đầu tiên + gói 3-máy vá sống + bookend DEEP trả nợ JUMP (tally #53=53, AS-17 promote)
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 5m38s

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
pqhuy1987
2026-07-25 20:13:25 +07:00
parent 398d343403
commit 1b85713bb6
54 changed files with 2422 additions and 95 deletions

View File

@ -98,6 +98,22 @@ function Replace-LineOnce([string]$text, [string]$pattern, [string]$newLine, [st
return $rx.Replace($text, $ev, 1)
}
# Style-preserving field replace (fix S151 format-fork): the S150 signal-write re-serialized
# this file via ConvertTo-Json (BOM + CRLF + two-space after colon), so the fixed-string
# replacer above stopped matching (0 match => exit 7 every session after every bookend).
# This variant's pattern carries TWO capture groups (prefix)(suffix); the matched prefix and
# suffix are kept verbatim, so whichever spacing/EOL shape the file has SURVIVES the write.
# Same exactly-one-match fail-loud as Replace-LineOnce (shape-drift still refuses to write).
function Replace-FieldOnce([string]$text, [string]$pattern, [string]$valueLiteral, [string]$what) {
$rx = New-Object System.Text.RegularExpressions.Regex($pattern, [System.Text.RegularExpressions.RegexOptions]::Multiline)
$n = $rx.Matches($text).Count
if ($n -ne 1) {
Fail-Loud "surgical replace '$what' expected exactly 1 match, found $n - counter-file shape drift; refusing to write." 7
}
$ev = [System.Text.RegularExpressions.MatchEvaluator]({ param($m) $m.Groups[1].Value + $valueLiteral + $m.Groups[2].Value }.GetNewClosure())
return $rx.Replace($text, $ev, 1)
}
function Json-Escape([string]$s) {
# Minimal JSON string escaping. Event text is authored quote/backslash-free, but stay safe.
$s = $s -replace '\\', '\\'
@ -210,25 +226,33 @@ else {
}
$eventJson = Json-Escape $event
# ---- surgical edits on the raw text (preserve formatting / emoji / LF byte-exact) ----
# ---- surgical edits on the raw text (style-preserving: tolerate BOTH the original
# ---- surgical shape (LF / one-space) AND the ConvertTo-Json shape (CRLF / two-space) ----
$new = $rawText
$new = Replace-LineOnce $new '^ "counter": \d+,$' (' "counter": ' + $newCounter + ',') 'counter'
$new = Replace-LineOnce $new '^ "last_ticked_session": "[^"]*",$' (' "last_ticked_session": "' + $Session + '",') 'last_ticked_session'
$new = Replace-LineOnce $new '^ "last_ticked_head": "[^"]*",$' (' "last_ticked_head": "' + $headSha + '",') 'last_ticked_head'
$new = Replace-LineOnce $new '^ "last_ticked_at": "[^"]*",$' (' "last_ticked_at": "' + $tickDate + '",') 'last_ticked_at'
$new = Replace-FieldOnce $new '^(\s{4}"counter":\s+)\d+(,\r?)$' ("$newCounter") 'counter'
$new = Replace-FieldOnce $new '^(\s{4}"last_ticked_session":\s+")[^"]*(",\r?)$' $Session 'last_ticked_session'
$new = Replace-FieldOnce $new '^(\s{4}"last_ticked_head":\s+")[^"]*(",\r?)$' $headSha 'last_ticked_head'
$new = Replace-FieldOnce $new '^(\s{4}"last_ticked_at":\s+")[^"]*(",\r?)$' $tickDate 'last_ticked_at'
# ---- append ONE history entry: insert before the array close (anchored at EOF, exactly once) ----
$entry = " {`n" +
" `"at`": `"$tickDate`",`n" +
" `"session`": `"$Session`",`n" +
" `"event`": `"$eventJson`"`n" +
" }"
$histRx = New-Object System.Text.RegularExpressions.Regex('(\n \})(\n \]\n\}\n?)$', [System.Text.RegularExpressions.RegexOptions]::Singleline)
# ---- append ONE history entry: insert before the array close (anchored at EOF, exactly once).
# Shape-tolerant (fix S151 format-fork): match ANY indent + CRLF-or-LF at EOF; the inserted
# entry reuses the file's own EOL and the LAST entry's own indent, so both shapes stay intact.
$histRx = New-Object System.Text.RegularExpressions.Regex('(\r?\n)([ \t]+)\}([ \t]*)(\r?\n[ \t]*\][ \t]*\r?\n\}[ \t]*\r?\n?)$', [System.Text.RegularExpressions.RegexOptions]::Singleline)
$histN = $histRx.Matches($new).Count
if ($histN -ne 1) {
Fail-Loud "history array-close anchor expected exactly 1 match at EOF, found $histN - counter-file shape drift; refusing to write." 7
}
$histEv = [System.Text.RegularExpressions.MatchEvaluator]({ param($m) $m.Groups[1].Value + ",`n" + $entry + $m.Groups[2].Value }.GetNewClosure())
$histEv = [System.Text.RegularExpressions.MatchEvaluator]({ param($m)
$eol = $m.Groups[1].Value
$ind = $m.Groups[2].Value # indent of the LAST entry's closing brace
$fld = $ind + ' ' # field indent = one level deeper
$entry = $ind + '{' + $eol +
$fld + '"at": "' + $tickDate + '",' + $eol +
$fld + '"session": "' + $Session + '",' + $eol +
$fld + '"event": "' + $eventJson + '"' + $eol +
$ind + '}'
$m.Groups[1].Value + $m.Groups[2].Value + '}' + $m.Groups[3].Value + ',' + $eol + $entry + $m.Groups[4].Value
}.GetNewClosure())
$new = $histRx.Replace($new, $histEv, 1)
# ---- validate the result is still parseable BEFORE we touch disk ----