diff --git a/packages/api/src/api/rest/etapes.ts b/packages/api/src/api/rest/etapes.ts
index 0a23459f7e90893e68886ea33417bff426f944d8..0c1c1d68e99dd688b7923bf2eca5a487067d1e6d 100644
--- a/packages/api/src/api/rest/etapes.ts
+++ b/packages/api/src/api/rest/etapes.ts
@@ -320,7 +320,7 @@ type PerimetreInfos = {
   surface: KM2 | null
 } & Pick<GraphqlEtape, 'geojson4326Forages' | 'geojsonOrigineForages'> &
   Pick<GetGeojsonInformation, 'communes' | 'forets' | 'departements'>
-export const getPerimetreInfosInternal = (
+const getPerimetreInfosInternal = (
   pool: Pool,
   geojson4326Perimetre: GraphqlEtape['geojson4326Perimetre'],
   geojsonOriginePerimetre: GraphqlEtape['geojsonOriginePerimetre'],
diff --git a/packages/api/src/business/processes/titres-etapes-heritage-contenu-update.ts b/packages/api/src/business/processes/titres-etapes-heritage-contenu-update.ts
index 24dca5acc8b8786e579710492916f7f9b65f66b7..71a1d203327c27d452c899216e444bfd04a7442a 100644
--- a/packages/api/src/business/processes/titres-etapes-heritage-contenu-update.ts
+++ b/packages/api/src/business/processes/titres-etapes-heritage-contenu-update.ts
@@ -84,9 +84,6 @@ export const titresEtapesHeritageContenuUpdate = async (pool: Pool, user: UserNo
       if (isNotNullNorUndefinedNorEmpty(titreEtapesPerdantLesSections)) {
         for (const etapePerdantLesSections of titreEtapesPerdantLesSections) {
           console.error(`l'étape https://camino.beta.gouv.fr/etapes/${etapePerdantLesSections.id} de type ${etapePerdantLesSections.typeId} possède un contenu alors qu'elle n'est pas censée en avoir`)
-          // TODO 2025-02-24 : à décommenter et à lancer en prod, puis à supprimer
-          // prettier-ignore
-          // await titreEtapeUpdate(etapePerdantLesSections.id, { contenu: null, heritageContenu: null, }, user, titreDemarche.titreId)
           titresEtapesIdsErrors.push(etapePerdantLesSections.id)
         }
       }
diff --git a/packages/api/src/business/rules-demarches/procedure-specifique/procedure-specifique.machine.test.ts b/packages/api/src/business/rules-demarches/procedure-specifique/procedure-specifique.machine.test.ts
index 531f0457f458ede4883ca0b0f54d8960356014d4..de264500817a1e590db8f739e06248494a922bff 100644
--- a/packages/api/src/business/rules-demarches/procedure-specifique/procedure-specifique.machine.test.ts
+++ b/packages/api/src/business/rules-demarches/procedure-specifique/procedure-specifique.machine.test.ts
@@ -288,6 +288,35 @@ describe('vérifie l’arbre des procédures spécifique', () => {
       ]
     `)
   })
+  test("la démarche devient public dès la création d'une consultation du public à venir", () => {
+    const { tree } = setDateAndOrderAndInterpretMachine(psAxmProMachine, '1999-04-14', [
+      {
+        ...ETES.demande.FAIT,
+        consentement: 'non-applicable',
+        concurrence: { amIFirst: true },
+        paysId: 'FR',
+        surface: hectareToKm2(hectareValidator.parse(10)),
+      },
+      ETES.enregistrementDeLaDemande.FAIT,
+      { ...ETES.recevabiliteDeLaDemande.FAVORABLE, hasTitreFrom: false },
+      ETES.avisDesCollectivites.FAIT,
+      ETES.avisDesServicesEtCommissionsConsultatives.FAIT,
+      ETES.avisDuPrefet.FAVORABLE,
+      ETES.consultationDuPublic.PROGRAMME,
+    ])
+    expect(tree).toMatchInlineSnapshot(`
+      [
+        "RIEN                             (confidentielle, en construction        ) -> [FAIRE_DEMANDE]",
+        "FAIRE_DEMANDE                    (confidentielle, en instruction         ) -> [CLASSER_SANS_SUITE,DEMANDER_INFORMATION,DESISTER_PAR_LE_DEMANDEUR,ENREGISTRER_DEMANDE]",
+        "ENREGISTRER_DEMANDE              (confidentielle, en instruction         ) -> [CLASSER_SANS_SUITE,DEMANDER_INFORMATION,DESISTER_PAR_LE_DEMANDEUR,FAIRE_RECEVABILITE_DEFAVORABLE,FAIRE_RECEVABILITE_FAVORABLE]",
+        "FAIRE_RECEVABILITE_FAVORABLE     (confidentielle, en instruction         ) -> [CLASSER_SANS_SUITE,DEMANDER_INFORMATION,DESISTER_PAR_LE_DEMANDEUR,OUVRIR_CONSULTATION_DU_PUBLIC,OUVRIR_ENQUETE_PUBLIQUE,RENDRE_AVIS_COLLECTIVITES,RENDRE_AVIS_SERVICES_COMMISSIONS]",
+        "RENDRE_AVIS_COLLECTIVITES        (confidentielle, en instruction         ) -> [CLASSER_SANS_SUITE,DEMANDER_INFORMATION,DESISTER_PAR_LE_DEMANDEUR,OUVRIR_CONSULTATION_DU_PUBLIC,OUVRIR_ENQUETE_PUBLIQUE,RENDRE_AVIS_SERVICES_COMMISSIONS]",
+        "RENDRE_AVIS_SERVICES_COMMISSIONS (confidentielle, en instruction         ) -> [CLASSER_SANS_SUITE,DEMANDER_INFORMATION,DESISTER_PAR_LE_DEMANDEUR,OUVRIR_CONSULTATION_DU_PUBLIC,OUVRIR_ENQUETE_PUBLIQUE,RENDRE_AVIS_PREFET]",
+        "RENDRE_AVIS_PREFET               (confidentielle, en instruction         ) -> [CLASSER_SANS_SUITE,DEMANDER_INFORMATION,DESISTER_PAR_LE_DEMANDEUR,OUVRIR_CONSULTATION_DU_PUBLIC,OUVRIR_ENQUETE_PUBLIQUE]",
+        "OUVRIR_CONSULTATION_DU_PUBLIC    (publique      , en instruction         ) -> [CLASSER_SANS_SUITE,DEMANDER_INFORMATION,DESISTER_PAR_LE_DEMANDEUR]",
+      ]
+    `)
+  })
   test("ne peut pas rendre la décision de l'administration si la consultation du public n'est pas terminée", () => {
     const { tree } = setDateAndOrderAndInterpretMachine(psAxmProMachine, '1999-04-14', [
       {
diff --git a/packages/api/src/business/rules-demarches/procedure-specifique/procedure-specifique.machine.ts b/packages/api/src/business/rules-demarches/procedure-specifique/procedure-specifique.machine.ts
index 8d85d97ccc011abe93d1fa66a3600ea58dc6dab0..f3509b6bdbcd0265323f09c048a183bd848be70e 100644
--- a/packages/api/src/business/rules-demarches/procedure-specifique/procedure-specifique.machine.ts
+++ b/packages/api/src/business/rules-demarches/procedure-specifique/procedure-specifique.machine.ts
@@ -586,13 +586,9 @@ const procedureSpecifiqueMachine = (titreTypeId: TitreTypeId, demarcheTypeId: De
                     },
                     {
                       target: 'enAttente',
-                      guard: and([or(['isEnquetePubliqueRequired', 'isEnquetePubliquePossible']), ({ event }) => event.status === ETAPES_STATUTS.EN_COURS]),
+                      guard: and([or(['isEnquetePubliqueRequired', 'isEnquetePubliquePossible']), ({ event }) => [ETAPES_STATUTS.EN_COURS, ETAPES_STATUTS.PROGRAMME].includes(event.status)]),
                       actions: assign({ visibilite: 'publique' }),
                     },
-                    {
-                      target: 'enAttente',
-                      guard: and([or(['isEnquetePubliqueRequired', 'isEnquetePubliquePossible']), ({ event }) => event.status === ETAPES_STATUTS.PROGRAMME]),
-                    },
                   ],
                   OUVRIR_CONSULTATION_DU_PUBLIC: [
                     {
@@ -602,14 +598,9 @@ const procedureSpecifiqueMachine = (titreTypeId: TitreTypeId, demarcheTypeId: De
                     },
                     {
                       target: 'enAttente',
-                      guard: and([not('isEnquetePubliqueRequired'), ({ event }) => event.status === ETAPES_STATUTS.EN_COURS]),
+                      guard: and([not('isEnquetePubliqueRequired'), ({ event }) => [ETAPES_STATUTS.PROGRAMME, ETAPES_STATUTS.EN_COURS].includes(event.status)]),
                       actions: assign({ visibilite: 'publique', consultationDuPublicFaite: true }),
                     },
-                    {
-                      target: 'enAttente',
-                      guard: and([not('isEnquetePubliqueRequired'), ({ event }) => event.status === ETAPES_STATUTS.PROGRAMME]),
-                      actions: assign({ consultationDuPublicFaite: true }),
-                    },
                   ],
                 },
               },
diff --git a/packages/api/src/business/rules-demarches/procedure-specifique/procedure-specifique.pdf b/packages/api/src/business/rules-demarches/procedure-specifique/procedure-specifique.pdf
index c6f07dfb77cc8d9ae70badaecd0995170ab5980a..e2da5ed1b5a015c3338f14b3ce437d097704eae5 100644
Binary files a/packages/api/src/business/rules-demarches/procedure-specifique/procedure-specifique.pdf and b/packages/api/src/business/rules-demarches/procedure-specifique/procedure-specifique.pdf differ
diff --git a/packages/api/src/scripts/check-perimetres.ts b/packages/api/src/scripts/check-perimetres.ts
deleted file mode 100644
index 7e55e22b31962acdac5a9c8906380a4694b62546..0000000000000000000000000000000000000000
--- a/packages/api/src/scripts/check-perimetres.ts
+++ /dev/null
@@ -1,222 +0,0 @@
-import '../init'
-import pg from 'pg'
-import { config } from '../config/index'
-import { Effect } from 'effect'
-import { knex } from '../knex'
-import { EtapeBrouillon, EtapeId } from 'camino-common/src/etape'
-import { CaminoError } from 'camino-common/src/zod-tools'
-import { getPerimetreInfosInternal } from '../api/rest/etapes'
-import { TitreTypeId } from 'camino-common/src/static/titresTypes'
-import { FeatureCollectionForages, FeatureCollectionPoints, FeatureMultiPolygon, MultiPolygon } from 'camino-common/src/perimetre'
-import { GeoSystemeId } from 'camino-common/src/static/geoSystemes'
-import { titreEtapeUpsert } from '../database/queries/titres-etapes'
-import { userSuper } from '../database/user-super'
-import { DemarcheId } from 'camino-common/src/demarche'
-import { CaminoDate } from 'camino-common/src/date'
-import { EtapeTypeId } from 'camino-common/src/static/etapesTypes'
-import { EtapeStatutId } from 'camino-common/src/static/etapesStatuts'
-import { TitreId } from 'camino-common/src/validators/titres'
-import { callAndExit } from '../tools/fp-tools'
-
-// Le pool ne doit être qu'aux entrypoints : le daily, le monthly, et l'application.
-const pool = new pg.Pool({
-  host: config().PGHOST,
-  user: config().PGUSER,
-  password: config().PGPASSWORD,
-  database: config().PGDATABASE,
-})
-
-type QueryError = "Échec de récupération des ids d'étapes en BDD"
-type EtapeError = 'Des étapes ont des périmètres invalides'
-type PerimetreValidationError = "Échec de validation d'un périmètre"
-type EtapeUploadError = "Échec du réupload d'un périmètre"
-type PipelineError = CaminoError<QueryError | EtapeError | PerimetreValidationError | EtapeUploadError>
-
-type Perimetre = {
-  titreId: TitreId
-  titreTypeId: TitreTypeId
-  etapeId: EtapeId
-  demarcheId: DemarcheId
-  isBrouillon: EtapeBrouillon
-  date: CaminoDate
-  etapeTypeId: EtapeTypeId
-  etapeStatutId: EtapeStatutId
-  geojson4326Perimetre: MultiPolygon
-  geojsonOriginePerimetre: FeatureMultiPolygon | null
-  geojsonOriginePoints: FeatureCollectionPoints | null
-  geojsonOrigineGeoSystemeId: GeoSystemeId | null
-  geojsonOrigineForages: FeatureCollectionForages | null
-}
-function getAllPerimetres(): Effect.Effect<Perimetre[], CaminoError<QueryError>, never> {
-  return Effect.gen(function* () {
-    const { rows } = yield* Effect.tryPromise({
-      try: () =>
-        knex.raw<{ rows: Perimetre[] }>(`
-        SELECT
-          "titreId",
-          "titreTypeId",
-          "etapeId",
-          "demarcheId",
-          "isBrouillon",
-          "date",
-          "etapeTypeId",
-          "etapeStatutId",
-          ST_AsGeoJSON("geojson4326_perimetre", 40)::json AS "geojson4326Perimetre",
-          "geojsonOriginePerimetre",
-          "geojsonOriginePoints",
-          "geojsonOrigineGeoSystemeId",
-          "geojsonOrigineForages"
-        FROM (
-          SELECT DISTINCT
-            t.id AS "titreId",
-            t.type_id AS "titreTypeId",
-            te.id AS "etapeId",
-            td.id AS "demarcheId",
-            te.is_brouillon AS "isBrouillon",
-            te.date,
-            te.type_id AS "etapeTypeId",
-            te.statut_id AS "etapeStatutId",
-            te.geojson4326_perimetre,
-            te.geojson_origine_perimetre AS "geojsonOriginePerimetre",
-            te.geojson_origine_points AS "geojsonOriginePoints",
-            te.geojson_origine_geo_systeme_id AS "geojsonOrigineGeoSystemeId",
-            te.geojson_origine_forages AS "geojsonOrigineForages"
-          FROM titres_etapes te
-          JOIN titres_demarches td ON td.id = te.titre_demarche_id
-          JOIN titres t ON t.id = td.titre_id
-          WHERE geojson4326_perimetre IS NOT NULL AND te.archive IS FALSE
-          ORDER BY te.date DESC
-        ) t
-      `),
-      catch: error => ({
-        message: "Échec de récupération des ids d'étapes en BDD" as const,
-        extra: { error },
-      }),
-    })
-
-    return rows
-  })
-}
-
-function updatePerimetre(perimetre: Perimetre): Effect.Effect<void, CaminoError<EtapeUploadError>, never> {
-  return Effect.tryPromise({
-    try: async () => {
-      if (perimetre.geojsonOrigineGeoSystemeId !== '4326') {
-        throw new Error('Geosysteme invalide')
-      }
-
-      await titreEtapeUpsert(
-        {
-          id: perimetre.etapeId,
-          typeId: perimetre.etapeTypeId,
-          statutId: perimetre.etapeStatutId,
-          date: perimetre.date,
-          isBrouillon: perimetre.isBrouillon,
-          titreDemarcheId: perimetre.demarcheId,
-          geojson4326Perimetre: {
-            type: 'Feature',
-            geometry: perimetre.geojson4326Perimetre,
-            properties: {},
-          },
-          geojsonOriginePerimetre: {
-            type: 'Feature',
-            geometry: perimetre.geojson4326Perimetre,
-            properties: {},
-          },
-          geojsonOriginePoints: perimetre.geojsonOriginePoints,
-          geojsonOrigineGeoSystemeId: perimetre.geojsonOrigineGeoSystemeId,
-          geojsonOrigineForages: perimetre.geojsonOrigineForages,
-        },
-        userSuper,
-        perimetre.titreId
-      )
-    },
-    catch: error => ({
-      message: "Échec du réupload d'un périmètre" as const,
-      extra: {
-        etapeId: perimetre.etapeId,
-        error,
-      },
-    }),
-  })
-}
-
-type InvalidEtape = { id: EtapeId; errors: string[] }
-function getInvalidEtapes(rows: Perimetre[]): Effect.Effect<InvalidEtape[], CaminoError<PerimetreValidationError | EtapeUploadError>, never> {
-  return Effect.gen(function* () {
-    const invalidEtapes: InvalidEtape[] = []
-
-    for (let i = 0; i < rows.length; i += 1) {
-      const errors = yield* getPerimetreErrors(rows[i])
-      if (errors.length > 0) {
-        invalidEtapes.push({ id: rows[i].etapeId, errors })
-        console.error(`(${Math.round((i / rows.length) * 10000) / 100}%) ${rows[i].etapeId} : ${errors.join(', ')}\n`)
-
-        yield* updatePerimetre(rows[i])
-      }
-    }
-
-    return invalidEtapes
-  })
-}
-
-function getPerimetreErrors(perimetre: Perimetre): Effect.Effect<string[], CaminoError<PerimetreValidationError>, never> {
-  return Effect.tryPromise({
-    try: async () => {
-      try {
-        await callAndExit(
-          getPerimetreInfosInternal(
-            pool,
-            { type: 'Feature', geometry: perimetre.geojson4326Perimetre, properties: {} },
-            perimetre.geojsonOriginePerimetre,
-            perimetre.geojsonOriginePoints,
-            perimetre.titreTypeId,
-            perimetre.geojsonOrigineGeoSystemeId,
-            perimetre.geojsonOrigineForages
-          )
-        )
-      } catch (error) {
-        if (error instanceof Error) {
-          return [error.message]
-        } else if (typeof error === 'string') {
-          return [error]
-        } else {
-          return ['Périmètre invalide (raison inconnue)']
-        }
-      }
-
-      return []
-    },
-    catch: error => ({
-      message: "Échec de validation d'un périmètre" as const,
-      extra: {
-        etapeId: perimetre.etapeId,
-        error: error instanceof Error ? error.message : error,
-      },
-    }),
-  })
-}
-
-const pipeline: Effect.Effect<void, PipelineError, never> = Effect.gen(function* () {
-  console.time('PIPELINE')
-  const perimetres = yield* getAllPerimetres()
-  const invalidEtapes = yield* getInvalidEtapes(perimetres)
-  console.timeEnd('PIPELINE')
-
-  if (invalidEtapes.length > 0) {
-    // eslint-disable-next-line no-console
-    console.log(`${invalidEtapes.length} ont des périmètres invalides : ${invalidEtapes.map(({ id }) => id).join(',')}`)
-    yield* Effect.fail({
-      message: `Des étapes ont des périmètres invalides` as const,
-      extra: invalidEtapes.map(({ id, errors }) => `${id} : ${errors.join(', ')}`).join('\n'),
-    })
-  }
-})
-
-try {
-  await Effect.runPromise(pipeline)
-  console.info('Script terminé : aucune erreur détectée')
-  process.exit()
-} catch (error) {
-  process.exit(1)
-}