# gov_pipeline_interactive_write_v1.0.ps1 (v1.0.2 clean rewrite) # Preview -> Prompt O/N -> Ecriture reelle (ingest + emit) + post-hook + acceptance # PS 5.1-safe, UTF-8 no BOM, CRLF param( [string]$Root = '\\\\DS-918\\chatgpt\\ChatGPT-Gouvernance-Projets\\_registry', [switch]$Utf8Console, [switch]$NoPrompt ) if($Utf8Console){ try{ [Console]::OutputEncoding = [Text.Encoding]::UTF8 }catch{} } $scripts = Join-Path $Root 'scripts' $inbox = Join-Path $Root 'updates\inbox\kb' $emit = Join-Path $scripts 'kb_emit_bootpack_dual_v1.1.ps1' $ingest = Join-Path $scripts 'kb_quicklog_and_sync_v1.2.1.ps1' $posthk = Join-Path $scripts 'post_bootpack_pointer_refresh_v1.0.2.ps1' $accept = Join-Path $scripts 'kb_acceptance_tests_v1.0.1.ps1' function Exists([string]$p){ return (-not [string]::IsNullOrWhiteSpace($p)) -and (Test-Path -LiteralPath $p) } function Run-Tool([string]$path,[string[]]$argv){ $null = & powershell -NoProfile -ExecutionPolicy Bypass -File $path @argv; return [int]$LASTEXITCODE } function Run-Tool-Write([string]$path,[string[]]$argv){ try{ = & powershell -NoProfile -ExecutionPolicy Bypass -File @( + '-Execute'); return [int]1 }catch{} try{ = & powershell -NoProfile -ExecutionPolicy Bypass -File @( + '-Preview:False'); return [int]1 }catch{} $null = & powershell -NoProfile -ExecutionPolicy Bypass -File $path @argv; return [int]$LASTEXITCODE } function Read-Text-UTF8([string]$p){ if(-not (Test-Path -LiteralPath $p)){ return '' } try{ return Get-Content -LiteralPath $p -Raw -Encoding UTF8 }catch{ return (Get-Content -LiteralPath $p -Raw) } } function Count-EntriesFromJson-Simple([string]$t){ if([string]::IsNullOrWhiteSpace($t)){ return -1 } if($t.Length -gt 0 -and ([int]$t[0] -eq 0xFEFF)){ $t=$t.Substring(1) } try{ $o=$t|ConvertFrom-Json; if($o -and $o.PSObject.Properties.Name -contains 'entries'){ return @($o.entries).Count } }catch{} try{ $m=[regex]::Match($t,'(?ms)"entries"\s*:\s*\[(.*?)\]'); if($m.Success){ return ([regex]::Matches($m.Groups[1].Value,'(?i)"id"\s*:')).Count } }catch{} return -1 } function SelfHeal-Pointer([string]$Root){ \\\DS-918\chatgpt\ChatGPT-Gouvernance-Projets\_registry\bootpack\bootpack.txt = Join-Path \\\DS-918\chatgpt\ChatGPT-Gouvernance-Projets\_registry 'bootpack\\bootpack.txt' \\\DS-918\chatgpt\ChatGPT-Gouvernance-Projets\_registry\bootpack\bootpack_paste.txt= Join-Path \\\DS-918\chatgpt\ChatGPT-Gouvernance-Projets\_registry 'bootpack\\bootpack_paste.txt' if(-not (Test-Path -LiteralPath $boot) -or -not (Test-Path -LiteralPath $paste)){ return 1 } $raw = Read-Text-UTF8 $boot \ = [regex]::IsMatch(\[BOOT-PACK] Name=ChatGPT-Gouvernance-Projets BootPack Version=1.0 Generated=2025-10-22T21:03:15+02:00 [POLICY] GOV_SCRIPT_GATE v1.3 SAFE-WRITE-RULE v1.1 TXT-ONLY SYNC-MEM-ARCHIVE-RULE KB_DUAL_BOOTPACK v1.0 [BUG_KB_JSON_POINTER] Path=\\DS-918\chatgpt\ChatGPT-Gouvernance-Projets\_registry\bootpack\bootpack_paste.txt SHA256=be783a215249bda887c4935b4176d4b5952473a0157c2540359cf4f4eed77c5a Updated=2025-10-22T21:03:15+02:00 Entries=47 SizeBytes=22278 --- DOC-VERSION-FOOTER --- Generated: 2025-10-22T21:03:15+02:00 Policy: TXT-ONLY v1.0; SAFE-WRITE v1.1; GOV_SCRIPT_GATE v1.3; KB_DUAL_BOOTPACK v1.0 Source: KB_EMIT_BOOTPACK_DUAL_v1.1,'(?m)^\[BUG_KB_JSON_POINTER\]\s*$') $okPath = $false if(\){ \$Root='\\DS-918\chatgpt\ChatGPT-Gouvernance-Projets\_registry' =[regex]::Match(\[BOOT-PACK] Name=ChatGPT-Gouvernance-Projets BootPack Version=1.0 Generated=2025-10-22T21:03:15+02:00 [POLICY] GOV_SCRIPT_GATE v1.3 SAFE-WRITE-RULE v1.1 TXT-ONLY SYNC-MEM-ARCHIVE-RULE KB_DUAL_BOOTPACK v1.0 [BUG_KB_JSON_POINTER] Path=\\DS-918\chatgpt\ChatGPT-Gouvernance-Projets\_registry\bootpack\bootpack_paste.txt SHA256=be783a215249bda887c4935b4176d4b5952473a0157c2540359cf4f4eed77c5a Updated=2025-10-22T21:03:15+02:00 Entries=47 SizeBytes=22278 --- DOC-VERSION-FOOTER --- Generated: 2025-10-22T21:03:15+02:00 Policy: TXT-ONLY v1.0; SAFE-WRITE v1.1; GOV_SCRIPT_GATE v1.3; KB_DUAL_BOOTPACK v1.0 Source: KB_EMIT_BOOTPACK_DUAL_v1.1,'(?m)^\s*Path\s*:\s*(.+?)\s*$'); if(\$Root='\\DS-918\chatgpt\ChatGPT-Gouvernance-Projets\_registry' .Success){ \=\$Root='\\DS-918\chatgpt\ChatGPT-Gouvernance-Projets\_registry' .Groups[1].Value.Trim(); \=(Test-Path -LiteralPath \) } } if(-not $has -or -not $okPath){ $sha=(Get-FileHash -Algorithm SHA256 -LiteralPath $paste).Hash.ToUpperInvariant() $size=(Get-Item -LiteralPath $paste).Length $ent=Count-EntriesFromJson-Simple (Read-Text-UTF8 $paste) $blk="[BUG_KB_JSON_POINTER]`r`nPath : $paste`r`nSHA256 : $sha`r`nEntries : $ent`r`nSizeBytes : $size`r`n" \(?ms)^\[BUG_KB_JSON_POINTER\].*?(?=^\[|$\Z)='(?ms)^\[BUG_KB_JSON_POINTER\].*?(?=^\[|$\Z)' if([regex]::IsMatch($raw,$pat)){ $new=[regex]::Replace($raw,$pat,$blk) } else { $sep=if($raw -match '\S'){"`r`n`r`n"}else{""}; $new=$raw+$sep+$blk+"`r`n" } try{ $enc=New-Object System.Text.UTF8Encoding($false); [IO.File]::WriteAllText($boot, ($new -replace "`r?`n","`r`n"), $enc); Write-Host "[SELF-HEAL] Bloc pointer (re)ecrit." } catch{ Write-Host "[SELF-HEAL] Echec ecriture: $($_.Exception.Message)"; return 2 } } return 0 } Write-Host "== GOV PIPELINE :: INTERACTIVE WRITE v1.0 ==" Write-Host ("Root : {0}" -f $Root) $countInbox = 0 if(Exists $inbox){ $countInbox = (Get-ChildItem -LiteralPath $inbox -Filter 'AUTO_*.txt' -ErrorAction SilentlyContinue).Count } Write-Host ("KB inbox : {0} AUTO_*.txt" -f $countInbox) Write-Host "BootPack : PREVIEW plan ->" if(Exists $emit){ $null = Run-Tool $emit @($Root) } else { Write-Host ("[WARN] Emitter introuvable: {0}" -f $emit) } Write-Host "----------------------------------------------------------------" if(-not $NoPrompt){ $resp = Read-Host "Écrire maintenant ? (O/N)"; if($resp -notmatch '^[OoYy]'){ Write-Host "[ABORT] Aucun changement ecrit."; exit 0 } } # -- EXECUTION REELLE --------------------------------------------------- if(($countInbox -gt 0) -and (Exists $ingest)){ Get-ChildItem -LiteralPath \\\DS-918\chatgpt\ChatGPT-Gouvernance-Projets\_registry\updates\inbox\kb -Filter 'AUTO_*.txt' | ForEach-Object { $f = $_.FullName Write-Host ("[INGEST] {0}" -f $f) $rc = Run-Tool $ingest @("-FromFile",$f,"-Execute") if($rc -ne 0){ Write-Host ("[FAIL] ingest rc={0} : {1}" -f $rc,$f); exit $rc } } } else { Write-Host "[INFO] Rien a ingerer (inbox vide ou outil manquant)." } if(Exists $emit){ Write-Host "[EMIT] BootPack (ecriture reelle)..." $rc = Run-Tool-Write $emit @($Root) if($rc -ne 0){ Write-Host ("[FAIL] emit rc={0}" -f $rc); exit $rc } } Write-Host "[POST] Pointer refresh + acceptance..." $null = SelfHeal-Pointer $Root if(Exists $posthk){ $rc = Run-Tool-Write $posthk @("-Root",$Root,"-NoPrompt","-Verify") if($rc -ne 0){ Write-Host ("[WARN] post-hook rc=" + $rc + " -> self-heal + retry...") $null = SelfHeal-Pointer $Root $rc = Run-Tool-Write $posthk @("-Root",$Root,"-NoPrompt","-Verify") if($rc -ne 0){ Write-Host ("[FAIL] post-hook rc={0}" -f $rc); exit $rc } } } else { Write-Host ("[WARN] post-hook introuvable: {0}" -f $posthk) } if(Exists $accept){ Write-Host "[CHECK] Acceptance PTR finale..." $rc = Run-Tool $accept @($Root) if($rc -ne 0){ Write-Host ("[FAIL] acceptance rc={0}" -f $rc); exit $rc } } # -- RESUME ------------------------------------------------------------- $left = 0 if(Exists $inbox){ $left = (Get-ChildItem -LiteralPath $inbox -Filter 'AUTO_*.txt' -ErrorAction SilentlyContinue).Count } Write-Host ("Inbox restant : {0}" -f $left) Get-Item (Join-Path $Root 'bootpack\bootpack_paste.txt'), (Join-Path $Root 'bootpack\bootpack.txt') | Select-Object Name, Length, LastWriteTime | Format-Table -AutoSize Write-Host "[DONE] Interactif : operations appliquees avec succes."