param([switch]$Execute) # kb_intake_batch_auto_v1.1.ps1 // batch KB intake (PS 5.1 safe) # Mode: default PREVIEW, -Execute to publish via wrappers $ErrorActionPreference="Stop" function NowIso{(Get-Date).ToString("s")} $Root="\\DS-918\chatgpt\ChatGPT-Gouvernance-Projets\_registry" $PreviewCmd="C:\Temp_Gouvernance\gov_preview.cmd" $ExecuteCmd="C:\Temp_Gouvernance\gov_execute.cmd" $Gate="kb_bug_intake_gate_v1.6.ps1" $ModeCmd= if($Execute){ $ExecuteCmd } else { $PreviewCmd } $SessionTag="session:guard-20251019" Write-Host ("== BUG INTAKE BATCH :: {0} : MODE={1} ==" -f $(NowIso), ($(if($Execute){"EXECUTE"}else{"PREVIEW"}))) $items = @( @{ Title="NowIso parsing: function NowIso vs -f formatting"; Note ="Symptoms: ExpectedExpression/UnexpectedToken quand $(NowIso)/(NowIso()) est mele au -f. Fix: function NowIso { (Get-Date).ToString('s') } + usage propre (precompute var ou -f correct)."; Tags ="powershell,parsing,formatting,ps51,$SessionTag"; Blocking=$true }, @{ Title="Arg passing: concat -Preview-Root et Root:-Root"; Note ="Symptoms: -Preview-Root, Root:-Root, chemins vides. Cause: concatenation/sequencage d'args. Fix: tableau d'arguments propre; ne passer -Root qu'aux steps qui le prennent."; Tags ="powershell,args,binding,$SessionTag"; Blocking=$true }, @{ Title="Runner switches injection: -Execute/-Preview forces -> param errors"; Note ="Erreur quand le runner force -Execute/-Preview sur des scripts sans ces switches. Fix: detecter switches supportes et n'ajouter que si pertinent; -Root seulement si requis."; Tags ="wrapper,runner,params,preview,execute,$SessionTag"; Blocking=$true }, @{ Title="CMD BOM header: EF BB BF -> ???@echo off"; Note ="Cause: wrappers .cmd en UTF-8 BOM. Fix: enregistrer wrappers .cmd en ASCII/UTF-8 sans BOM (texte pur)."; Tags ="encoding,cmd,utf8,bom,$SessionTag"; Blocking=$false }, @{ Title="Wrapper recursion -> stack overflow"; Note ="Symptome: recursion involontaire du wrapper (re-entree). Fix: appel PS direct sur cache, trace entree, garde anti-reentree."; Tags ="wrappers,controlflow,stack,$SessionTag"; Blocking=$true }, @{ Title="Root Null/Empty -> Join-Path/Test-Path errors"; Note ="Symptome: ParameterArgumentValidationErrorEmpty/NullNotAllowed. Cause: binding casse. Fix: valider -Root avant Join-Path/Test-Path; passer -Root uniquement aux steps qui le prennent."; Tags ="paths,validation,$SessionTag"; Blocking=$true }, @{ Title="Regex refactor fragile (-ireplace) -> BadReplaceArgument"; Note ="Lecon: eviter regex intelligents pour refactor; preferer reecriture atomique/sure."; Tags ="regex,refactor,risk,$SessionTag"; Blocking=$false }, @{ Title="Acceptance pointer null -> InvokeMethodOnNull"; Note ="Symptome: .ToLower() sur null. Fix: null-guards avant comparaisons; PASS ensuite."; Tags ="null-guards,acceptance,$SessionTag"; Blocking=$false }, @{ Title="Manifest (emit_resume_manifest) -> erreurs de bloc/parentheses"; Note ="Symptomes: Expression manquante apres , ; bloc non ferme. Cause: saisie manuelle. Statut: non bloquant."; Tags ="manifest,syntax,$SessionTag"; Blocking=$false }, @{ Title="Cache local: script not found"; Note ="Fix: robocopy du NAS vers cache + verif existence avant execution; comparer SHA NAS vs cache."; Tags ="cache,robocopy,$SessionTag"; Blocking=$false }, @{ Title="CLI Tags: tokens orphelins mal routes (PS5.1)"; Note ="Tokens residuels non quotes glissaient vers Workaround/Fix. Fix: capture remainder en Tags + normalisation CSV/guillemets/espaces."; Tags ="powershell,parser,ps51,tags,normalize,$SessionTag"; Blocking=$true }, @{ Title="ExecutionPolicy AllSigned: UNC bloque .ps1"; Note ="AllSigned interdit l'execution directe depuis UNC. Solution: wrappers .cmd ASCII, copie en cache local, powershell.exe -ExecutionPolicy Bypass."; Tags ="powershell,AllSigned,UNC,wrapper,Bypass,$SessionTag"; Blocking=$true }, @{ Title="Join-Path avec tableau -> chemins invalides (PS5.1)"; Note ="Join-Path appele avec un tableau multi-segments genere des chemins errones. Fix: composer segment par segment (boucle)."; Tags ="powershell,join-path,ps51,io,$SessionTag"; Blocking=$true }, @{ Title="Select-String -Recurse indisponible (PS5.1)"; Note ="PS5.1 ne supporte pas -Recurse sur Select-String. Fix: boucler explicitement sur les fichiers (Get-ChildItem) puis Select-String."; Tags ="powershell,ps51,select-string,compat,$SessionTag"; Blocking=$true }, @{ Title="Wrapper .cmd: bug %* / SHIFT (args positionnels)"; Note ="Le batch utilisait %* (non impacte par SHIFT) => doublons/erreurs. Fix: reconstruire ARGS en boucle, %~f1, PowerShell -ExecutionPolicy Bypass."; Tags ="cmd,batch,wrapper,executionpolicy,args,$SessionTag"; Blocking=$true }, @{ Title="kb_bug_intake_gate v1.2: ecriture temporaire -> DirectoryNotFoundException"; Note ="WriteAllText echouait car chemin temporaire derive du dossier du script. Fix: StageRoot dedie (C:\Temp_Gouvernance\stage_io), Ensure-Parent/Ensure-Dir, ecriture atomique (.tmp -> Move-Item), UTF-8 BOM."; Tags ="powershell,io,safe-write,staging,ps51,$SessionTag"; Blocking=$true } ) $fail=$false foreach($it in $items){ \$args=@\(\$Gate,"-Title",\$it\.Title,"-Note",\$it\.Note,"-Tags",\$it\.Tags\) \ \ if\(\$Execute\)\{\ \$args\ \+=\ "-Execute"\ } if($it.Blocking){ $args+="-Blocking" } Write-Host ("[RUN] {0} {1}" -f $ModeCmd, ($args -join " ")) & $ModeCmd @args $ec = $LASTEXITCODE if($ec -ne 0){ Write-Warning ("Intake FAILED (ExitCode={0}) :: {1}" -f $ec,$it.Title); $fail=$true } else{ Write-Host ("[OK] Intake {0}" -f $it.Title) } } if($fail){ Write-Warning "Au moins une intake a echoue. Voir logs/preview." } else{ Write-Host "[OK] Batch intake termine sans erreur." ; if(-not $Execute){ Write-Host "Tip: relancer avec -Execute pour publier." } } Write-Host ("DOC-VERSION-FOOTER kb_intake_batch_auto_v1.1 :: {0}" -f $(NowIso))