---
suivi: 1289
date: 2026-08-12
sujet: perimetre_dossier_materialise
chantier: module-foncier
type: feature
statut: poussé
hash: 6cf83bd4
fichiers:
  - database/migrations/2026_08_12_150000_add_origine_dossier_foncier_parcelle_1289.php
  - database/migrations/2026_08_12_150100_backfill_dossier_foncier_parcelle_from_detentions_1289.php
  - app/Services/Foncier/DossierFoncierPerimetreService.php
  - app/Models/DossierFoncier.php
  - app/Http/Controllers/Foncier/DossierFoncierController.php
  - app/Http/Controllers/Foncier/OffreFonciereController.php
  - app/Http/Controllers/Foncier/ScenarioFaisabiliteController.php
  - routes/web.php
  - resources/js/Components/Foncier/DossierFoncierTab.vue
  - tools/diag/verif_perimetre_dossier_1289.php
  - database/data/journal_mises_a_jour_post_2026_06_12.php
---

## PROMPT ENVOYÉ

Matérialisation du périmètre dossier (`dossier_foncier_parcelle` = source de vérité), reprise depuis détentions, retrait unitaire avec refus si engagements. Suite clause d’arrêt #1286. Avant #1288 dans le plan — #1288 déjà poussé : ce lot s’appuie dessus.

## SYNTHÈSE

### Pourquoi la table existait sans être lue
Créée #1075 comme pivot, puis dépréciée #1111 (miroir `sync()`). L’UI lisait les détentions (`parcellesCandidats`). #1286 a bloqué le retrait unitaire faute de SoT.

### Colonne `origine`
Le schéma repo (#1075) **n’avait pas** `origine`. Le prompt #1289 l’annonçait en prod. Migration `150000` l’ajoute de façon idempotente (`hasColumn`). Valeurs : `detention` | `manuel`.

### Reprise
Migration `150100` : insert idempotent des dérivées absentes (`origine=detention`). Conserve les lignes existantes ; orphelines hors dérivation → `manuel`.

### Distinction périmètre / détention
Retrait = DELETE liaison + FieldAudit `perimetre_parcelle` + commentaire fil. Détention `parcelle_proprietaire` intacte. Plus de `sync()` destructif : `synchroniserDepuisDetentions` ajoute detention manquantes et retire seulement `origine=detention` orphelines.

### `origine` à l’ajout
- attach / store parcelles sous propriétaire / attach propriétaire → sync → `detention`
- lignes hors dérivation conservées → `manuel`

### Engagements bloquants (refus serveur nommé)
offre_parcelle, promesse (+ avenants + CS), acte_parcelle, scenario_parcelle, charges_portage (parcelle).

### Trace
FieldAuditService::recordChange + EntiteCommentaire `[Périmètre]…` sur le dossier.

### #1288
R1c « dossier qui porte la parcelle » s’appuie désormais sur une notion matérialisée et synchronisée.

## DÉPLOIEMENT-TEST

```bash
git pull origin main
php artisan migrate --force
php artisan optimize:clear
php artisan view:clear
php artisan journal:sync
php -d display_errors=1 tools/diag/verif_perimetre_dossier_1289.php
```

Contrôle Pending **seul** : `php artisan migrate:status | grep -c Pending`

## LEÇON

Ne jamais faire d’un miroir `sync()` la SoT d’un périmètre qu’on veut retirer unitairement. Matérialiser d’abord, remplacer sync par attach/detach ciblés, puis exposer le bouton. La colonne d’audit d’intention ne survit pas à un sync.
