• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

inclusion-numerique / coop-mediation-numerique / 14ba6690-9c33-4ca2-ab73-fa1fd8aa6215

21 May 2026 08:58AM UTC coverage: 9.992% (+3.0%) from 7.009%
14ba6690-9c33-4ca2-ab73-fa1fd8aa6215

Pull #497

circleci

marc-gavanier
feat: improve structure fusion scoring and review export

Significantly reduces the manual review burden by detecting more
true duplicates automatically and avoiding false positives.

Scoring improvements (detect-duplicate-structures, generate-structures-action-plan):
- Treat clusters of type 'mixte' like 'doublon_certain' with per-pair
  scoring (instead of bulk verification_manuelle), uncovering hundreds
  of auto/probable fusions previously hidden in mixed clusters.
- Boost address score to 1.0 when one normalized address is contained
  in the other (e.g. "Lupino" vs "LUPINO PARVIS NOTRE DAME VICTOIRE").
- Add address abbreviations: VC (voie communale), RT (route), ZA, ZI, CH.
- Redistribute geo weight when coords are unavailable, OR when address
  strongly indicates the same place (>=0.85): prevents penalizing
  structures with missing or erroneous coords.
- Normalize "commune de/du", "mairie de/du", "ville de/du" to a single
  "ville" canonical token so variants match.
- Detect "service keywords" (EPN, médiathèque, CCAS, France services,
  MJC, etc.): when one name has such a keyword and the other does not,
  they are distinct entities even with shared SIRET/address. Disables
  the address-contained heuristic and keeps geo in the score.

Sync resilience (findOrCreateStructure):
- After strict siret+codeInsee miss, fall back to siret-only with
  normalized contained-name match. This catches Dataspace structures
  whose codeInsee diverges from the coop's, without merging an EPN
  with its parent town hall (asymmetric-service-keyword guard).

Review output:
- generate-structures-action-plan: structures-fusion-review.csv now
  uses cluster-grouped format (CIBLE + sources + empty line between
  clusters, sorted by ascending score), matching the existing format
  Tim uses for his manual reviews.
- export-duplicate-sirets: cluster-grouped CSV (empty line between
  SIRETs) and exclude empty-string siret. Enrich each row with
  nom_api, adresse_api, corre... (continued)
Pull Request #497: feat: improve structure fusion scoring and review export

688 of 10876 branches covered (6.33%)

Branch coverage included in aggregate %.

26 of 150 new or added lines in 4 files covered. (17.33%)

911 existing lines in 95 files now uncovered.

2111 of 17137 relevant lines covered (12.32%)

1.94 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

77.78
/apps/web/src/features/structures/formationLabel.ts
1
import { labelsToOptions } from '@app/ui/components/Form/utils/options'
1✔
2
import { FormationLabel } from '@gouvfr-anct/lieux-de-mediation-numerique'
1✔
3
import type { FormationLabel as PrismaFormationLabel } from '@prisma/client'
4

UNCOV
5
export const formationLabelLabels: Record<
×
6
  PrismaFormationLabel,
7
  FormationLabel
8
> = {
1✔
9
  FormeAMonEspaceSante: FormationLabel.FormeAMonEspaceSante,
10
  FormeADuplex: FormationLabel.FormeADuplex,
11
  ArniaMednum: FormationLabel.ArniaMednum,
12
  CollectifRessourcesEtActeursReemploi:
13
    FormationLabel.CollectifRessourcesEtActeursReemploi,
14
  FabriquesDeTerritoire: FormationLabel.FabriquesDeTerritoire,
15
  LesEclaireurs: FormationLabel.LesEclaireurs,
16
  MesPapiers: FormationLabel.MesPapiers,
17
  Ordi3: FormationLabel.Ordi3,
18
  SudLabs: FormationLabel.SudLabs,
19
}
20

UNCOV
21
export const formationLabelKeys: Record<FormationLabel, PrismaFormationLabel> =
×
22
  Object.fromEntries(
1✔
23
    Object.entries(formationLabelLabels).map(([key, value]) => [value, key]),
9✔
24
  ) as Record<FormationLabel, PrismaFormationLabel>
25

26
export type FormationLabelLabel = keyof typeof formationLabelLabels
27

28
export const formationLabelValues = Object.keys(formationLabelLabels) as [
1✔
29
  FormationLabelLabel,
30
  ...FormationLabelLabel[],
31
]
32

33
export const formationLabelOptions = labelsToOptions(formationLabelLabels)
1✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc