---
suivi: 1345
date: 2026-08-14
sujet: siwi_hors_perimetre_poste
chantier: marches_reprise
type: fix
statut: poussé
hash: 38005f71
fichiers:
  - app/Services/SiwiImportService.php
  - app/Console/Commands/SiwiImportCommand.php
  - tools/diag/diag_siwi_hors_perimetre_poste_1345.php
  - database/data/journal_mises_a_jour_post_2026_06_12.php
  - docs/suivi/SUIVI_1345_siwi_hors_perimetre_poste.md
---

## PROMPT ENVOYÉ

SUIVI #1345 — `hors_perimetre_poste` = 0 au lieu de 16 sur le staging
SIWI (1 405 marchés). Confirmer la cause (hypothèse : `poste_propose_code`
NULL, `poste_methode` peuplé sur les 16 C03 AVOCAT), corriger la détection
sur un critère peuplé, ne pas modifier les données staging ni
`applicable_marche` / création marché.

## SYNTHÈSE

### Fiches lues
- `#1328` LEÇON : motif via code nomenclature HECTARE `applicable_marche=0`,
  jamais test chaîne « AVOCAT ». Le code mapping était le critère — **vide
  en prod**.
- `#1335` LEÇON : `applicable_marche` n’est pas un garde-fou de création ;
  ne pas le réintroduire. Motif = recommandation.
- `#1338` / `#1340` : `SiwiImportController` / disque PDF — **non touchés**.
- `#1341` : commune — **non touchée**.

### Cause (CSV prod = source du staging, 1 405 / 646)

`poste_propose_code` vide ; `methode` = `HORS PERIMETRE — C03 AVOCAT existe mais applicable_marche=0`.
`resolvePosteNonApplicableMarche('')` retournait null. `poste_siwi` = « Avocat HT »
(pas « C03 AVOCAT ») : le 1er jeton n’est pas un `code_interne`.

4 lignes mapping, 16 marchés. Compteur peuplé : `preuve_peuplee_methode_C03_marches=16`.

### Fix
Scanner tous les jetons alphanumériques de `poste_propose_code` puis de
`poste_methode` contre la nomenclature HECTARE `applicable_marche=0`.
Compteur import `hors_perimetre_poste_via_methode` (code vide + motif posé).

Pas de migration. Pas d’UPDATE staging. Réimport SOURCE pour basculer.

### Compteurs AVANT → APRÈS (CSV 1405, C03 injecté = token methode)

| Compteur | Avant | Après |
|---|---|---|
| hors_perimetre_lettre | 277 | 277 |
| hors_perimetre_poste | 0 | 16 |
| remboursement_negatif | 12 | 12 |
| multi_lots | 20 | 20 |
| marche_non_valorise | 268 | 255 |
| depassement | 79 | 78 |
| rg_blocage | 6 | 6 |
| poste_fiable | 653 | 653 |
| synonymes | 909 | 909 |
| créables | 1128 (C 527 + G 601) | 1128 |
| hors_perimetre_poste_via_methode | 0 | 16 |

255 / 78 : les 13 + 1 alertes quittées **sont** le sous-ensemble des 16
(`horsArbitrage` #1328). Aucun marché hors des 16 en `hors_perimetre_poste`.

### 16 refs

C794 C1925 C2957 C2954 C2472 C2337 C1307 C2166 C253 C2535 C2149 C2082 C2291 C438 C2281 C1810

## DÉPLOIEMENT-TEST

```bash
git pull origin main
php artisan optimize:clear && php artisan view:clear
php artisan journal:sync
php artisan siwi:import --path=/home/hectare-envol/siwi-import --apply
# pointer hors_perimetre_poste=16 et hors_perimetre_poste_via_methode=16
```

Pas de migrate.

## LEÇON

Un mapping peut identifier un poste HECTARE **dans `methode`** tout en
laissant `poste_propose_code` vide. Un filtre qui ne lit que le code
semble correct et ne protège rien (même famille que index vide).
Exiger un compteur sur le critère **effectivement peuplé** (`via_methode`).
Le 1er jeton de `poste_siwi` (« Avocat HT ») n’est pas un `code_interne`.
