# Analisi tecnica definitiva per estensione generica dello skill `mcp-coldfusion-developer`

## 1. Sintesi esecutiva

Questo documento definisce l'analisi tecnica definitiva per sviluppare un'estensione generica dello skill `mcp-coldfusion-developer` dedicata a migrazioni cross-version tramite directory neutrale.

L'obiettivo è standardizzare un workflow in cui due agenti, o due sessioni dello stesso agente, operano con ruoli distinti:

- **Provider**: analizza il progetto sorgente, estrae funzionalità, frammenti o file e produce artefatti nella directory neutrale.
- **Consumer**: legge gli artefatti prodotti nella directory neutrale, li integra nel progetto target e aggiorna lo stato del tracking.

La soluzione deve rimanere generica. Non deve contenere riferimenti hardcoded a prodotti, clienti, versioni, repository o cartelle applicative specifiche.

La scelta architetturale definitiva è:

- estendere lo skill esistente `mcp-coldfusion-developer`;
- aggiornare il trigger YAML dello skill;
- aggiornare la tabella `Quick Routing` dello skill;
- aggiungere reference Markdown dedicate al workflow;
- aggiungere uno script Node.js di validazione del workspace neutrale;
- aggiungere test automatici minimi per lo script;
- non sviluppare un nuovo MCP server.

---

## 2. Fatti accertati

1. Il workflow richiede due personalità operative distinte: Provider e Consumer.
2. La directory neutrale è il punto di scambio controllato tra sorgente e destinazione.
3. `conventions.md` è il contratto operativo comune.
4. `touched-files.md` è il tracking condiviso e deve rimanere minimale.
5. Gli stati ammessi sono soltanto `TO ADD`, `TO MERGE`, `ADDED`, `MERGED`.
6. Il Provider può creare nuove iterazioni e produrre artefatti pendenti.
7. Il Consumer non deve creare nuove iterazioni, ma solo integrare elementi pendenti e aggiornarli come completati.
8. La struttura target non deve essere dedotta dall'AI: deve essere fornita dall'utente.
9. Il caso concreto citato in conversazione è solo un esempio e non deve essere codificato nello skill.
10. Il nuovo MCP server è escluso dallo scope.
11. Lo script di controllo deve essere scritto in Node.js e incluso nello skill.
12. La modifica deve preservare la struttura reale dello skill esistente, in particolare `SKILL.md`, `references/` e `scripts/`, senza introdurre metadata UI non presenti nello standard locale del repository.

---

## 3. Decisioni tecniche definitive

| ID | Decisione | Motivazione |
|---|---|---|
| DT-01 | Estendere `mcp-coldfusion-developer`, non creare nuovo skill separato. | Il workflow è una modalità operativa del dominio ColdFusion/CFML già esistente. |
| DT-02 | Non creare nuovo MCP server. | Il problema è di coordinamento agentico e validazione file, non di capability runtime. |
| DT-03 | Usare `Cross-Version Migration Mode` come nome della modalità. | Nome esplicito e riusabile anche per branch, varianti e ambienti diversi. |
| DT-04 | Aggiornare la `description` YAML di `SKILL.md`. | La discovery dello skill deve attivarsi anche per richieste di migrazione cross-version. |
| DT-04B | Aggiornare la tabella `Quick Routing` di `SKILL.md`. | Lo skill target usa quella tabella come punto di ingresso operativo per le reference. |
| DT-05 | Dividere le istruzioni dettagliate in reference Markdown. | Mantiene `SKILL.md` compatto e riduce carico di contesto. |
| DT-06 | Ripristinare il tracking compatto iniziale basato su righe `path → STATUS`. | È il formato richiesto: minimale, leggibile e coerente con il template iniziale. |
| DT-07 | Il Consumer aggiorna lo stato inline della riga esistente. | Evita sezioni separate, checkbox e campi aggiuntivi non previsti dal template iniziale. |
| DT-08 | Il validatore resta formale, non semantico. | Non deve fare merge automatici o valutare correttezza CFML. |
| DT-09 | Aggiungere flag `--strict` per controllare esistenza dei file tracciati nella directory neutrale. | Utile in CI o prima di handoff, senza rendere rigida la validazione base. |
| DT-10 | Aggiungere test automatici con moduli built-in Node.js. | Riduce regressioni senza introdurre dipendenze. |
| DT-11 | Non introdurre `agents/openai.yaml` in questa modifica. | Lo skill target osservato non lo contiene e il repository locale non lo richiede per questa estensione. |
| DT-12 | Consentire creazione di `touched-files.md` solo in inizializzazione esplicita. | Evita che il Provider mascheri workspace incompleti durante una migrazione ordinaria. |
| DT-13 | Validare heading iterazione e path ambigui. | Riduce falsi positivi nel validatore e review successive su edge case prevedibili. |
| DT-14 | Rendere la CLI fail-fast su argomenti extra. | Evita esecuzioni ambigue del validatore in CI o handoff. |
| DT-15 | In `--strict`, verificare l'esistenza fisica solo dopo aver validato il path come sicuro. | Evita lookup filesystem fuori workspace quando il tracking contiene path già invalidi. |
| DT-16 | Non normalizzare silenziosamente i path tracciati. | Spazi iniziali/finali nei path sono errore, perché rendono ambiguo il tracking e possono rompere `--strict`. |
| DT-17 | Scrivere le nuove istruzioni Markdown operative in italiano. | Allinea l'estensione allo stile locale dello skill `mcp-coldfusion-developer` e riduce review cosmetiche post sviluppo. |
| DT-18 | Usare fence esterne a quattro backtick quando si documentano file Markdown che contengono altri blocchi fenced. | Evita troncamenti del contenuto nel rendering Markdown e riduce errori di copia da parte di Codex. |
| DT-19 | Non usare campi `neutral:`, `target:`, `reason:` nel tracking. | Non fanno parte del template iniziale e appesantiscono il file di stato. |
| DT-20 | Non usare checkbox nel tracking. | Lo stato è già espresso dal valore dopo la freccia. |
| DT-21 | Non usare sezioni per stato come `### TO ADD`. | Il formato richiesto usa solo blocchi iterazione e righe compatte. |
| DT-22 | Dopo ogni modifica ai trigger o al `SKILL.md`, rigenerare il routing catalog con `node scripts/build-routing-catalog.mjs`. | Il catalogo `scripts/hooks/routing-catalog.json` è generato dal contenuto delle skill e consumato dagli hook Codex; non va aggiornato manualmente. |
| DT-23 | Gli heading iterazione devono avere forma esatta `# Iteration N`, con `N >= 1`. | È il formato iniziale e permette parsing deterministico. |
| DT-24 | Ogni riga tracciata deve avere forma esatta `- relative/path → STATUS`. | Evita interpretazioni divergenti tra Provider, Consumer e validatore. |
| DT-25 | Gli stati ammessi restano `TO ADD`, `TO MERGE`, `ADDED`, `MERGED`. | Preserva il contratto operativo già definito. |

## 4. Requisiti funzionali

### RF-01 - Modalità Cross-Version Migration

Lo skill `mcp-coldfusion-developer` deve includere una modalità chiamata **Cross-Version Migration Mode**.

La modalità si applica quando l'utente chiede di portare funzionalità, file, fix o moduli tra versioni, branch, varianti o ambienti dello stesso prodotto usando una directory neutrale.

### RF-02 - Trigger nello `SKILL.md`

La `description` YAML di `SKILL.md` deve essere aggiornata includendo esplicitamente questi trigger:

- migrazioni cross-version;
- porting tra branch o varianti di prodotto;
- uso di directory neutrale;
- ruoli Provider e Consumer;
- tracking con `conventions.md` e `touched-files.md`.

Non deve essere riscritto completamente `SKILL.md` se non necessario. La modifica deve essere conservativa e compatibile con il contenuto esistente.

La tabella `Quick Routing` esistente deve essere aggiornata con una riga dedicata alla nuova modalità.

Dopo la modifica di `SKILL.md`, Codex deve eseguire:

```bash
node scripts/build-routing-catalog.mjs
```

Se `scripts/hooks/routing-catalog.json` cambia, il diff generato deve essere incluso nella stessa patch. Il file generato non deve essere modificato manualmente.

### RF-03 - Directory neutrale

Il workflow deve richiedere una directory neutrale isolata da sorgente e destinazione.

La directory deve contenere:

- `conventions.md`;
- `touched-files.md`.

`touched-files.md` deve esistere prima di eseguire una normale iterazione Provider o Consumer. Il Provider può crearlo solo quando l'utente chiede esplicitamente di inizializzare un nuovo workspace neutrale.

Può contenere:

- `target-structures.md`, opzionale e raccomandato quando il layout target è diverso dal sorgente;
- artefatti generati dal Provider;
- frammenti da fondere;
- file da aggiungere;
- note del Provider;
- note del Consumer.

### RF-04 - Persona Provider

Quando opera come Provider, l'agente deve:

1. leggere `conventions.md`;
2. leggere `target-structures.md` se presente;
3. leggere `touched-files.md`; se manca, fermarsi e chiedere inizializzazione workspace oppure crearlo solo se l'utente lo ha chiesto esplicitamente;
4. analizzare la sorgente indicata;
5. identificare il minimo set di file o frammenti necessari;
6. produrre artefatti nella directory neutrale;
7. classificare ogni path come `TO ADD` o `TO MERGE`;
8. appendere una nuova iterazione a `touched-files.md` usando il formato compatto;
9. eseguire il validatore Node.js quando disponibile.

Il Provider non deve:

- aggiornare item a `ADDED` o `MERGED`;
- modificare il progetto target;
- inventare path target;
- fare refactoring non richiesto;
- mescolare più funzionalità non correlate nella stessa iterazione.

### RF-05 - Persona Consumer

Quando opera come Consumer, l'agente deve:

1. leggere `conventions.md`;
2. leggere `target-structures.md` se presente;
3. leggere `touched-files.md`;
4. individuare righe con stato `TO ADD` e `TO MERGE`;
5. integrare gli artefatti nel target;
6. aggiornare lo stato inline della stessa riga:
   - `TO ADD` -> `ADDED`;
   - `TO MERGE` -> `MERGED`;
7. eseguire il validatore Node.js quando disponibile.

Il Consumer non deve:

- creare nuove iterazioni;
- aggiungere nuovi item `TO ADD` o `TO MERGE`;
- inventare logica mancante;
- ampliare lo scope;
- marcare completato lavoro non realmente integrato.

### RF-06 - Tracking minimale canonico

`touched-files.md` deve rimanere un file di stato, non un log verboso.

Il formato canonico deve tornare al template iniziale:

```md
# Iteration 9
- client/update/i18n/labels.it.properties → MERGED
- client/update/i18n/labels.en.properties → MERGED
- client/update/i18n/labels.fr.properties → MERGED
```

Regole:

- ogni iterazione usa heading `# Iteration N`, con `N >= 1`;
- ogni riga tracciata usa la forma `- relative/path → STATUS`;
- gli stati ammessi sono solo `TO ADD`, `TO MERGE`, `ADDED`, `MERGED`;
- il Provider aggiunge solo righe `TO ADD` o `TO MERGE`;
- il Consumer aggiorna solo lo stato inline della riga esistente;
- non usare sezioni `### TO ADD`, `### TO MERGE`, `### ADDED`, `### MERGED`;
- non usare checkbox;
- non usare campi `neutral:`, `target:`, `reason:`;
- i path devono essere relativi;
- i path non devono contenere whitespace iniziale o finale;
- i path non devono contenere segmenti `..`;
- i path non devono usare path assoluti POSIX, Windows o UNC;
- evitare backslash nei path del tracking: usare `/` per compatibilità cross-platform.

### RF-07 - Validazione workspace

Lo skill deve includere:

```text
scripts/validate-migration-workspace.js
```

Uso base:

```bash
node scripts/validate-migration-workspace.js <neutral-directory>
```

Uso strict:

```bash
node scripts/validate-migration-workspace.js --strict <neutral-directory>
```

Lo script deve validare almeno:

- directory neutrale esistente;
- presenza di `conventions.md`;
- presenza di `touched-files.md`;
- formato heading iterazione `# Iteration N`;
- numero iterazione positivo obbligatorio (`N >= 1`);
- iterazioni duplicate;
- formato righe `- relative/path → STATUS`;
- status non ammessi;
- righe tracciate fuori da un blocco `# Iteration N`;
- righe non riconosciute dentro `touched-files.md`;
- path assoluti POSIX vietati;
- path assoluti Windows vietati;
- path drive-relative Windows vietati;
- UNC path vietati;
- backslash vietati nei path del tracking;
- segmenti `..` vietati nei path;
- segmenti `.` vietati nei path;
- segmenti vuoti vietati nei path, per esempio `client//file.cfm`;
- shortcut shell `~` vietato;
- whitespace iniziale o finale vietato nei path;
- campi strutturati non ammessi, per esempio `neutral:`, `target:`, `reason:`;
- in modalità `--strict`, presenza fisica dei file referenziati dal path tracciato;
- in modalità `--strict`, nessun controllo di esistenza fisica deve essere eseguito se il path non ha già superato la validazione di sicurezza.

### RF-08 - Test automatici validatore

Lo skill deve includere:

```text
scripts/validate-migration-workspace.test.js
```

I test devono coprire almeno:

- workspace valido con formato compatto iniziale;
- status non ammesso;
- heading iterazione malformato;
- heading iterazione con numero non positivo;
- iterazione duplicata;
- item fuori iterazione;
- item con freccia mancante;
- item con campi `neutral:`, `target:`, `reason:` non ammessi;
- path assoluto POSIX;
- path assoluto Windows;
- path drive-relative Windows;
- UNC path;
- backslash nei path;
- path con `..`;
- path con segmento `.`;
- path con segmento vuoto;
- path con whitespace iniziale/finale;
- shortcut shell `~`;
- argomenti CLI extra;
- modalità `--strict` con file tracciato mancante;
- modalità `--strict` con path invalido: deve fallire per path invalido senza aggiungere errore di artefatto mancante.

Esecuzione prevista:

```bash
node --test scripts/validate-migration-workspace.test.js
```

### RF-09 - Template convenzioni

Lo skill deve fornire un template generico per `conventions.md`, senza riferimenti a casi specifici.

### RF-10 - Separazione tra istruzioni e automazione

Le reference Markdown devono istruire l'agente.

Lo script Node.js deve limitarsi a validare il workspace. Non deve:

- eseguire merge automatici;
- modificare sorgente o target;
- manipolare automaticamente `touched-files.md`;
- valutare semanticamente il codice migrato.

## 5. Requisiti non funzionali

| ID | Requisito | Dettaglio |
|---|---|---|
| RNF-01 | Genericità | Nessun file dell'estensione deve includere nomi hardcoded di clienti, prodotti, versioni o moduli applicativi specifici. |
| RNF-02 | Bassa invasività | La modifica deve essere locale allo skill `mcp-coldfusion-developer`. |
| RNF-03 | Determinismo | La validazione deve essere ripetibile e basata su regole semplici. |
| RNF-04 | Zero dipendenze esterne | Script e test devono usare solo moduli built-in Node.js. |
| RNF-05 | Compatibilità agentica | Il workflow deve funzionare anche con sessioni separate di agenti. |
| RNF-06 | Sicurezza path | Bloccare path assoluti, UNC, backslash e segmenti `..`. |
| RNF-07 | Manutenibilità | Dettagli in reference Markdown brevi, evitando uno `SKILL.md` eccessivamente lungo. |
| RNF-08 | Compatibilità skill | Preservare struttura, frontmatter e convenzioni locali dello skill esistente. |
| RNF-09 | Idempotenza operativa | Il validatore non deve modificare file. |
| RNF-10 | Reviewability | Il piano operativo deve permettere review file-by-file. |

---

## 6. Scope

### Incluso

- Estensione dello skill `mcp-coldfusion-developer`.
- Aggiornamento conservativo di `SKILL.md`.
- Aggiornamento della `description` YAML.
- Nuova modalità `Cross-Version Migration Mode`.
- Reference Markdown dedicate.
- Template generico per `conventions.md`.
- Formato compatto iniziale per `touched-files.md`.
- Script Node.js di validazione.
- Test automatici Node.js per il validatore.
- Esempi generici di tracking.

### Escluso

- Nuovo MCP server.
- Merge automatico del codice.
- Risoluzione automatica dei conflitti.
- Deduzione automatica della struttura target.
- Hardcoding di casi specifici.
- Integrazione con database o UI runtime.
- Creazione di ZIP delta Git.
- Validazione semantica del codice migrato.
- Refactor ampi dello skill esistente.

---

## 7. Struttura file proposta

```text
skills/mcp-coldfusion-developer/
  SKILL.md
  references/
    cross-version-migration.md
    migration-provider.md
    migration-consumer.md
    migration-tracking-format.md
    migration-conventions-template.md
  scripts/
    validate-migration-workspace.js
    validate-migration-workspace.test.js
```

Nota per Codex:

- non introdurre `agents/openai.yaml` in questa modifica se non è già parte dello standard effettivo dello skill target;
- mantenere la struttura locale esistente: `SKILL.md`, `references/`, `scripts/`;
- non introdurre campi o directory non usati dal repository.

---

## 8. Modifica richiesta a `SKILL.md`

### 8.1 Frontmatter

Aggiornare in modo conservativo la `description` YAML esistente includendo i trigger della modalità.

Esempio di contenuto da integrare nella description, adattando al testo esistente:

```yaml
description: Develop and debug CFML safely with linting, bridge inspection, log analysis, post-fix validation handoffs, and controlled cross-version migration workflows through neutral directories with Provider/Consumer personas and touched-files.md tracking.
```

Regole:

- mantenere `name` invariato;
- mantenere frontmatter valido;
- non aggiungere campi YAML non previsti;
- evitare descrizione troppo lunga o specifica di un caso reale;
- non introdurre trigger generici non necessari come `refactoring` o `implementation` se non già giustificati dallo skill target.

### 8.2 Quick Routing

Aggiornare la tabella `Quick Routing` esistente aggiungendo una riga dedicata alla nuova modalità.

Esempio:

```md
| Migrazione cross-version tramite directory neutrale | [references/cross-version-migration.md](references/cross-version-migration.md) |
```

La riga deve essere posizionata vicino agli scenari di migrazione o porting già presenti, senza riordinare inutilmente la tabella.

### 8.3 Body

Aggiungere una sezione sintetica, in italiano e coerente con lo stile locale dello skill:

````md
## Cross-Version Migration Mode

Usa questa modalità quando devi portare funzionalità, file, fix o moduli tra versioni, varianti, branch o ambienti dello stesso prodotto tramite una directory neutrale.

La directory neutrale deve contenere:

- `conventions.md`
- `touched-files.md`

File opzionale ma raccomandato quando il layout target differisce dal layout sorgente:

- `target-structures.md`

Prima di operare, determina la persona assegnata:

- Provider: estrae dal progetto sorgente e scrive artefatti pronti per la migrazione nella directory neutrale.
- Consumer: integra gli artefatti neutri nel progetto target e aggiorna gli stati del tracking.

Non mescolare responsabilità Provider e Consumer nella stessa operazione.

Non assumere path, versioni, moduli, nomi prodotto o strutture target specifiche. Usa solo strutture fornite esplicitamente dall'utente.

Per le istruzioni complete, leggi:

- `references/cross-version-migration.md`
- `references/migration-provider.md` quando operi come Provider
- `references/migration-consumer.md` quando operi come Consumer
- `references/migration-tracking-format.md` prima di modificare `touched-files.md`
- `references/migration-conventions-template.md` quando crei o spieghi `conventions.md`

Quando possibile, esegui:

```bash
node scripts/validate-migration-workspace.js <neutral-directory>
```

Prima dell'handoff finale, quando tutti gli artefatti neutral dovrebbero esistere, usa la validazione strict:

```bash
node scripts/validate-migration-workspace.js --strict <neutral-directory>
```
````

---

## 9. Reference `references/cross-version-migration.md`

````md
# Cross-Version Migration

Workflow per migrare in modo controllato funzionalità tra versioni, varianti, branch o ambienti dello stesso prodotto usando una directory neutrale.

## Ambito

Usa questa modalità per:

- migrare funzionalità applicative tra versioni prodotto;
- estrarre logica dalla versione sorgente in artefatti neutri;
- integrare artefatti neutri in una versione target;
- spostare funzionalità tra repository layout differenti;
- coordinare due ruoli AI-assisted senza scansioni pesanti ripetute.

Il workflow deve restare product-agnostic.

Non hardcodare nomi prodotto, versioni, moduli, path o layout repository.

## Contratto della directory neutrale

La directory neutrale è isolata sia dal repository sorgente sia dal repository target.

Deve contenere:

- `conventions.md`
- `touched-files.md`

Può contenere:

- `target-structures.md`
- frammenti derivati dalla sorgente;
- file da aggiungere;
- file da fondere;
- note Provider;
- note Consumer;
- riferimenti alla struttura target forniti dall'utente.

## Responsabilità umana

L'utente umano deve fornire le strutture target esatte.

Non indovinare, inventare, normalizzare o estrapolare path target.

Se la struttura target manca, fermati e chiedi la struttura mancante prima di assegnare path target.

## Persone operative

### Provider

Il Provider legge il repository sorgente e scrive artefatti pronti per la migrazione nella directory neutrale.

Il Provider può:

- creare nuovi blocchi iterazione;
- aggiungere righe `TO ADD`;
- aggiungere righe `TO MERGE`;
- produrre frammenti minimi da fondere;
- rispecchiare strutture target fornite dall'utente per nuovi file.

Il Provider non deve:

- aggiornare righe a `ADDED` o `MERGED`;
- modificare il progetto target;
- inventare path target;
- includere refactor non correlati.

### Consumer

Il Consumer legge gli item pendenti dalla directory neutrale e li integra nel repository target.

Il Consumer può:

- processare righe `TO ADD`;
- processare righe `TO MERGE`;
- aggiornare lo stato inline a `ADDED` o `MERGED`.

Il Consumer non deve:

- creare nuove iterazioni;
- aggiungere nuovi item `TO ADD` o `TO MERGE`;
- inventare logica sorgente mancante;
- ampliare lo scope della migrazione.

## Stati

Stati ammessi:

- `TO ADD`
- `TO MERGE`
- `ADDED`
- `MERGED`

Nessun altro stato è ammesso.

## Disciplina iterativa

Ogni passata Provider appende un nuovo blocco iterazione a `touched-files.md`.

Ogni passata Consumer aggiorna solo righe pendenti esistenti.

Mantieni il tracking minimale. Non trasformarlo in un log verboso di attività.
````

## 10. Reference `references/migration-provider.md`

````md
# Migration Provider Persona

Opera come Provider quando devi estrarre funzionalità dalla versione sorgente verso la directory neutrale di migrazione.

## Input

Richiedi:

- path del progetto sorgente;
- path della directory neutrale;
- funzionalità, fix, modulo o comportamento da portare;
- struttura target fornita dall'utente;
- `conventions.md`;
- `touched-files.md`, obbligatorio salvo richiesta esplicita di inizializzazione del workspace neutrale.

Leggi `target-structures.md` quando presente.

## Inizializzazione esplicita

Solo quando l'utente chiede esplicitamente di inizializzare un workspace neutrale, il Provider può creare:

- `conventions.md` dal template convenzioni;
- `touched-files.md` vuoto o senza item tracciati.

Un `touched-files.md` appena inizializzato può non contenere blocchi iterazione. Il validatore può emettere warning, ma non deve fallire solo per assenza di iterazioni.

## Procedura

1. Leggi `conventions.md`.
2. Leggi `target-structures.md` se presente.
3. Leggi `touched-files.md`; se manca, fermati salvo richiesta esplicita di inizializzazione workspace.
4. Identifica il set minimo di file sorgente necessario per la funzionalità richiesta.
5. Decidi per ogni path:
   - `TO ADD` quando il file è nuovo per la versione target;
   - `TO MERGE` quando la logica deve essere fusa in un file target esistente.
6. Preserva la struttura target fornita dall'utente.
7. Per `TO MERGE`, produci solo la logica minima necessaria.
8. Appendi un nuovo blocco iterazione a `touched-files.md`.
9. Esegui il validatore del workspace quando disponibile.

## Regole di output

Non produrre refactor ampi.

Non includere modifiche di formattazione non correlate.

Non inferire path target.

Non marcare nulla come `ADDED` o `MERGED`.

## Blocco iterazione consigliato

```md
# Iteration N
- module/path/new-file.ext → TO ADD
- module/path/existing-file.ext → TO MERGE
```
````

## 11. Reference `references/migration-consumer.md`

````md
# Migration Consumer Persona

Opera come Consumer quando devi integrare artefatti pendenti dalla directory neutrale nella versione target.

## Input

Richiedi:

- path del progetto target;
- path della directory neutrale;
- `conventions.md`;
- `touched-files.md`;
- righe pendenti `TO ADD` o `TO MERGE`.

Leggi `target-structures.md` quando presente.

## Procedura

1. Leggi `conventions.md`.
2. Leggi `target-structures.md` se presente.
3. Leggi `touched-files.md`.
4. Individua righe pendenti `TO ADD` e `TO MERGE`.
5. Per `TO ADD`, crea il file target usando l'artefatto neutrale.
6. Per `TO MERGE`, fondi solo la logica richiesta nel file target esistente.
7. Preserva le convenzioni della versione target salvo richiesta esplicita della migrazione.
8. Aggiorna lo stato inline da `TO ADD` a `ADDED` solo dopo integrazione reale.
9. Aggiorna lo stato inline da `TO MERGE` a `MERGED` solo dopo merge reale.
10. Esegui il validatore del workspace quando disponibile.

## Restrizioni

Non creare nuove iterazioni.

Non aggiungere nuovi item pendenti.

Non inventare file mancanti.

Non cambiare stato a lavoro non realmente completato.

Non eseguire cleanup o refactor non correlati.
````

## 12. Reference `references/migration-tracking-format.md`

````md
# Migration Tracking Format

Il file di tracking è `touched-files.md`.

Deve restare minimale.

## Stati ammessi

- `TO ADD`
- `TO MERGE`
- `ADDED`
- `MERGED`

## Forma canonica

Usa blocchi iterazione compatti:

```md
# Iteration 9
- client/update/i18n/labels.it.properties → MERGED
- client/update/i18n/labels.en.properties → MERGED
- client/update/i18n/labels.fr.properties → MERGED
```

Per una nuova iterazione Provider:

```md
# Iteration N
- module/path/new-file.ext → TO ADD
- module/path/existing-file.ext → TO MERGE
```

Dopo il processing del Consumer, aggiornare solo lo stato inline:

```md
# Iteration N
- module/path/new-file.ext → ADDED
- module/path/existing-file.ext → MERGED
```

## Regole

Il Provider appende iterazioni.

Il Consumer aggiorna stati esistenti dentro iterazioni esistenti.

Non aggiungere log verbosi.

Non aggiungere stati non supportati.

Non usare sezioni per stato.

Non usare checkbox.

Non usare campi `neutral:`, `target:`, `reason:`.

Usa `/` come separatore path.

Non usare path assoluti.

Non usare segmenti `..`.

Non usare segmenti `.`.

Non usare segmenti vuoti come `client//file.cfm`.

Non usare whitespace iniziale o finale nei path.
````

## 13. Reference `references/migration-conventions-template.md`

````md
# Migration Conventions

Questa directory media trasferimenti file cross-version, cross-branch o cross-environment.

Due persone AI operano qui:

- Provider
- Consumer

## Responsabilità umana

L'utente umano fornisce le strutture target esatte.

Le AI non devono indovinare, inventare, normalizzare o estrapolare strutture target.

Quando il layout target differisce dal layout sorgente, fornirlo in `target-structures.md` o direttamente nel prompt utente.

## File di tracking

Il file di tracking è:

```text
touched-files.md
```

Deve restare minimale.

L'avanzamento viene tracciato in blocchi iterazione compatti.

Esempio:

```md
# Iteration 9
- client/update/i18n/labels.it.properties → MERGED
- client/update/i18n/labels.en.properties → MERGED
- client/update/i18n/labels.fr.properties → MERGED
```

## Stati ammessi

- `TO ADD`: il Provider marca un nuovo file che deve essere copiato o creato nel progetto target.
- `TO MERGE`: il Provider marca logica che deve essere fusa in un file target esistente.
- `ADDED`: il Consumer marca un file creato con successo nel progetto target.
- `MERGED`: il Consumer marca logica fusa con successo nel progetto target.

## Regole Provider

Il Provider può appendere nuove iterazioni al file di tracking.

Il Provider assegna solo stati `TO ADD` o `TO MERGE`.

I path devono rispecchiare la struttura target fornita dall'utente.

Per `TO MERGE`, file o frammenti devono contenere solo la logica minima richiesta dalla funzionalità.

## Regole Consumer

Il Consumer non deve creare iterazioni.

Il Consumer legge item pendenti, li integra nel progetto target e aggiorna gli stati inline a `ADDED` o `MERGED`.

Il Consumer non deve eseguire refactor non correlati.

## Regole path

Usa solo path relativi.

Usa `/` come separatore.

Non usare path assoluti.

Non usare segmenti `..`.

Non usare path Windows con drive o path UNC.

Non usare segmenti `.` o segmenti vuoti.

Non usare whitespace iniziale o finale nei path.
````

## 14. Script `scripts/validate-migration-workspace.js`

```js
#!/usr/bin/env node

const fs = require("node:fs");
const path = require("node:path");

const ALLOWED_STATUSES = new Set(["TO ADD", "TO MERGE", "ADDED", "MERGED"]);

function createReporter() {
  return {
    errors: [],
    warnings: [],
    ok: [],
    fail(message) {
      this.errors.push(message);
    },
    warn(message) {
      this.warnings.push(message);
    },
    pass(message) {
      this.ok.push(message);
    },
  };
}

function fileExists(filePath) {
  return fs.existsSync(filePath) && fs.statSync(filePath).isFile();
}

function readText(filePath) {
  return fs.readFileSync(filePath, "utf8");
}

function validateRelativeSafePath(label, value, reporter) {
  let valid = true;

  if (value.trim() !== value) {
    reporter.fail(`${label} path must not contain leading or trailing whitespace: ${JSON.stringify(value)}`);
    valid = false;
  }

  if (value.length === 0) {
    reporter.fail(`${label} path must not be empty.`);
    valid = false;
  }

  if (value.startsWith("~")) {
    reporter.fail(`${label} path must not use shell home shortcut '~': ${value}`);
    valid = false;
  }

  if (value.includes("`")) {
    reporter.fail(`${label} path must not contain backticks: ${value}`);
    valid = false;
  }

  if (value.includes("\\")) {
    reporter.fail(`${label} path must use '/' and must not contain backslashes: ${value}`);
    valid = false;
  }

  if (/^\/+/.test(value)) {
    reporter.fail(`${label} path must be relative, not absolute or UNC-like: ${value}`);
    valid = false;
  }

  if (/^[A-Za-z]:[\\/]/.test(value)) {
    reporter.fail(`${label} path must be relative, not Windows absolute: ${value}`);
    valid = false;
  }

  if (/^[A-Za-z]:(?:$|[^\\/])/.test(value)) {
    reporter.fail(`${label} path must not be Windows drive-relative: ${value}`);
    valid = false;
  }

  const segments = value.split("/");

  if (segments.includes("")) {
    reporter.fail(`${label} path must not contain empty segments: ${value}`);
    valid = false;
  }

  if (segments.includes(".")) {
    reporter.fail(`${label} path must not contain '.' segments: ${value}`);
    valid = false;
  }

  if (segments.includes("..")) {
    reporter.fail(`${label} path must not contain '..' segments: ${value}`);
    valid = false;
  }

  return valid;
}

function parseTouchedFiles(markdown, reporter) {
  const lines = markdown.split(/\r?\n/);
  const iterations = [];
  const items = [];
  let currentIteration = null;

  for (let index = 0; index < lines.length; index += 1) {
    const line = lines[index];
    const lineNumber = index + 1;

    if (line.trim() === "") {
      continue;
    }

    const validIteration = line.match(/^# Iteration ([1-9]\d*)\s*$/);
    if (validIteration) {
      currentIteration = Number(validIteration[1]);
      iterations.push(currentIteration);
      continue;
    }

    if (/^#{1,6}\s*Iteration\b/i.test(line) || /^#\s*Iteration\b/i.test(line)) {
      reporter.fail(`Malformed iteration heading at line ${lineNumber}. Expected: # Iteration N with N >= 1.`);
      currentIteration = null;
      continue;
    }

    if (/^#{1,6}\s*/.test(line)) {
      reporter.fail(`Unsupported heading at line ${lineNumber}. Only # Iteration N headings are allowed.`);
      currentIteration = null;
      continue;
    }

    if (/^\s*-\s+/.test(line)) {
      if (!currentIteration) {
        reporter.fail(`Tracked item at line ${lineNumber} is outside an iteration block.`);
      }

      const arrowIndex = line.indexOf("→");
      if (arrowIndex === -1) {
        reporter.fail(`Malformed tracked item at line ${lineNumber}. Expected: - relative/path → STATUS`);
        continue;
      }

      const leftSide = line.slice(0, arrowIndex);
      const rightSide = line.slice(arrowIndex + 1);
      const pathMatch = leftSide.match(/^\s*-\s(.+)$/);
      const status = rightSide.trim();

      if (!pathMatch || status.length === 0) {
        reporter.fail(`Malformed tracked item at line ${lineNumber}. Expected: - relative/path → STATUS`);
        continue;
      }

      const trackedPath = pathMatch[1];

      if (!ALLOWED_STATUSES.has(status)) {
        reporter.fail(`Unsupported status at line ${lineNumber}: ${status}`);
      }

      if (/^(neutral|target|reason):/i.test(trackedPath.trim())) {
        reporter.fail(`Structured tracking field is not allowed at line ${lineNumber}. Use compact format: - relative/path → STATUS`);
      }

      const safePath = validateRelativeSafePath("Tracked", trackedPath, reporter);
      items.push({ iteration: currentIteration, path: trackedPath, status, lineNumber, safePath });
      continue;
    }

    reporter.fail(`Unsupported line at line ${lineNumber}. Expected # Iteration N or - relative/path → STATUS.`);
  }

  const duplicateIterations = iterations.filter((value, index) => iterations.indexOf(value) !== index);
  if (duplicateIterations.length > 0) {
    reporter.fail(`Duplicate iteration number(s): ${[...new Set(duplicateIterations)].join(", ")}`);
  }

  return { iterations, items };
}

function validateWorkspace(neutralDir, options = {}) {
  const reporter = options.reporter || createReporter();
  const strict = Boolean(options.strict);
  const conventionsPath = path.join(neutralDir, "conventions.md");
  const touchedFilesPath = path.join(neutralDir, "touched-files.md");

  if (!fs.existsSync(neutralDir)) {
    reporter.fail(`Neutral directory does not exist: ${neutralDir}`);
    return reporter;
  }

  if (!fs.statSync(neutralDir).isDirectory()) {
    reporter.fail(`Path is not a directory: ${neutralDir}`);
    return reporter;
  }

  if (!fileExists(conventionsPath)) {
    reporter.fail("Missing conventions.md in neutral directory root.");
  } else {
    reporter.pass("Found conventions.md.");
  }

  if (!fileExists(touchedFilesPath)) {
    reporter.fail("Missing touched-files.md in neutral directory root.");
    return reporter;
  }

  reporter.pass("Found touched-files.md.");

  const touched = readText(touchedFilesPath);
  const parsed = parseTouchedFiles(touched, reporter);

  if (parsed.iterations.length === 0) {
    reporter.warn("No iteration blocks found in touched-files.md.");
  } else {
    reporter.pass(`Found ${parsed.iterations.length} iteration block(s).`);
  }

  if (parsed.items.length > 0) {
    reporter.pass(`Validated ${parsed.items.length} tracked item(s).`);
  }

  if (strict) {
    for (const item of parsed.items) {
      if (!item.safePath) {
        continue;
      }

      const artifactPath = path.resolve(neutralDir, item.path);
      const neutralRoot = path.resolve(neutralDir);
      const relative = path.relative(neutralRoot, artifactPath);

      if (relative.startsWith("..") || path.isAbsolute(relative)) {
        reporter.fail(`Tracked path resolves outside neutral directory at line ${item.lineNumber}: ${item.path}`);
        continue;
      }

      if (!fileExists(artifactPath)) {
        reporter.fail(`Missing tracked artifact at line ${item.lineNumber}: ${item.path}`);
      }
    }
  }

  return reporter;
}

function parseArgs(argv) {
  const args = { strict: false, neutralDir: null };
  const positional = [];

  for (const arg of argv) {
    if (arg === "--strict") {
      args.strict = true;
      continue;
    }

    if (arg.startsWith("-")) {
      throw new Error(`Unknown option: ${arg}`);
    }

    positional.push(arg);
  }

  if (positional.length !== 1) {
    throw new Error("Usage: node validate-migration-workspace.js [--strict] <neutral-directory>");
  }

  args.neutralDir = path.resolve(positional[0]);
  return args;
}

function main() {
  let args;
  try {
    args = parseArgs(process.argv.slice(2));
  } catch (error) {
    console.error(error.message);
    process.exit(2);
  }

  const reporter = validateWorkspace(args.neutralDir, { strict: args.strict });

  for (const message of reporter.ok) {
    console.log(`OK: ${message}`);
  }

  for (const message of reporter.warnings) {
    console.warn(`WARN: ${message}`);
  }

  for (const message of reporter.errors) {
    console.error(`ERROR: ${message}`);
  }

  if (reporter.errors.length > 0) {
    console.error("Migration workspace validation failed.");
    process.exit(1);
  }

  console.log("Migration workspace validation passed.");
}

if (require.main === module) {
  main();
}

module.exports = {
  ALLOWED_STATUSES,
  createReporter,
  parseArgs,
  parseTouchedFiles,
  validateRelativeSafePath,
  validateWorkspace,
};
```

## 15. Test `scripts/validate-migration-workspace.test.js`

```js
const assert = require("node:assert/strict");
const fs = require("node:fs");
const os = require("node:os");
const path = require("node:path");
const test = require("node:test");

const { parseArgs, validateWorkspace } = require("./validate-migration-workspace.js");

function makeWorkspace(touchedFilesContent) {
  const dir = fs.mkdtempSync(path.join(os.tmpdir(), "migration-workspace-"));
  fs.writeFileSync(path.join(dir, "conventions.md"), "# Conventions\n", "utf8");
  fs.writeFileSync(path.join(dir, "touched-files.md"), touchedFilesContent, "utf8");
  return dir;
}

function errorsFor(touchedFilesContent, options = {}) {
  const dir = makeWorkspace(touchedFilesContent);
  if (options.files) {
    for (const filePath of options.files) {
      const absolute = path.join(dir, filePath);
      fs.mkdirSync(path.dirname(absolute), { recursive: true });
      fs.writeFileSync(absolute, "", "utf8");
    }
  }
  const reporter = validateWorkspace(dir, { strict: Boolean(options.strict) });
  return reporter.errors;
}

function validTouched(filePath = "client/update/i18n/labels.it.properties", status = "MERGED") {
  return `# Iteration 9\n- ${filePath} → ${status}\n`;
}

test("valid workspace with compact initial format passes", () => {
  const errors = errorsFor(`# Iteration 9
- client/update/i18n/labels.it.properties → MERGED
- client/update/i18n/labels.en.properties → MERGED
- client/update/i18n/labels.fr.properties → MERGED
`);
  assert.deepEqual(errors, []);
});

test("valid pending statuses pass", () => {
  const errors = errorsFor(`# Iteration 1
- module/new-file.cfm → TO ADD
- module/existing-file.cfm → TO MERGE
`);
  assert.deepEqual(errors, []);
});

test("unsupported status fails", () => {
  const errors = errorsFor(validTouched("client/file.cfm", "DONE"));
  assert(errors.some((error) => error.includes("Unsupported status")));
});

test("malformed iteration heading fails", () => {
  const errors = errorsFor(`## Iteration 1\n- client/file.cfm → MERGED\n`);
  assert(errors.some((error) => error.includes("Malformed iteration heading")));
});

test("iteration heading without space fails", () => {
  const errors = errorsFor(`#Iteration 1\n- client/file.cfm → MERGED\n`);
  assert(errors.some((error) => error.includes("Malformed iteration heading")));
});

test("iteration nr heading fails", () => {
  const errors = errorsFor(`# Iteration nr. 1\n- client/file.cfm → MERGED\n`);
  assert(errors.some((error) => error.includes("Malformed iteration heading")));
});

test("iteration zero fails", () => {
  const errors = errorsFor(`# Iteration 0\n- client/file.cfm → MERGED\n`);
  assert(errors.some((error) => error.includes("Malformed iteration heading")));
});

test("duplicate iteration fails", () => {
  const errors = errorsFor(`# Iteration 1
- client/a.cfm → MERGED
# Iteration 1
- client/b.cfm → MERGED
`);
  assert(errors.some((error) => error.includes("Duplicate iteration")));
});

test("item outside iteration fails", () => {
  const errors = errorsFor(`- client/file.cfm → MERGED\n`);
  assert(errors.some((error) => error.includes("outside an iteration")));
});

test("missing arrow fails", () => {
  const errors = errorsFor(`# Iteration 1\n- client/file.cfm MERGED\n`);
  assert(errors.some((error) => error.includes("Malformed tracked item")));
});

test("neutral structured field fails", () => {
  const errors = errorsFor(`# Iteration 1\n- neutral: \`artifacts/file.cfm\` → TO ADD\n`);
  assert(errors.some((error) => error.includes("Structured tracking field")));
});

test("target structured field fails", () => {
  const errors = errorsFor(`# Iteration 1\n- target: \`client/file.cfm\` → TO ADD\n`);
  assert(errors.some((error) => error.includes("Structured tracking field")));
});

test("reason structured field fails", () => {
  const errors = errorsFor(`# Iteration 1\n- reason: short reason → TO ADD\n`);
  assert(errors.some((error) => error.includes("Structured tracking field")));
});

test("absolute POSIX path fails", () => {
  const errors = errorsFor(validTouched("/client/file.cfm"));
  assert(errors.some((error) => error.includes("absolute or UNC-like")));
});

test("absolute Windows path fails", () => {
  const errors = errorsFor(validTouched("C:/client/file.cfm"));
  assert(errors.some((error) => error.includes("Windows absolute")));
});

test("drive-relative Windows path fails", () => {
  const errors = errorsFor(validTouched("C:client/file.cfm"));
  assert(errors.some((error) => error.includes("drive-relative")));
});

test("UNC-like path fails", () => {
  const errors = errorsFor(validTouched("//server/share/file.cfm"));
  assert(errors.some((error) => error.includes("absolute or UNC-like")));
});

test("backslash path fails", () => {
  const errors = errorsFor(validTouched("client\\file.cfm"));
  assert(errors.some((error) => error.includes("backslashes")));
});

test("dot-dot segment fails", () => {
  const errors = errorsFor(validTouched("client/../file.cfm"));
  assert(errors.some((error) => error.includes("'..'")));
});

test("dot segment fails", () => {
  const errors = errorsFor(validTouched("client/./file.cfm"));
  assert(errors.some((error) => error.includes("'.'")));
});

test("empty segment fails", () => {
  const errors = errorsFor(validTouched("client//file.cfm"));
  assert(errors.some((error) => error.includes("empty segments")));
});

test("path with leading whitespace fails", () => {
  const errors = errorsFor(`# Iteration 1\n-  client/file.cfm → MERGED\n`);
  assert(errors.some((error) => error.includes("leading or trailing whitespace")));
});

test("path with trailing whitespace fails", () => {
  const errors = errorsFor(`# Iteration 1\n- client/file.cfm  → MERGED\n`);
  assert(errors.some((error) => error.includes("leading or trailing whitespace")));
});

test("home shortcut fails", () => {
  const errors = errorsFor(validTouched("~/client/file.cfm"));
  assert(errors.some((error) => error.includes("shell home shortcut")));
});

test("unsupported heading fails", () => {
  const errors = errorsFor(`# Notes\n- client/file.cfm → MERGED\n`);
  assert(errors.some((error) => error.includes("Unsupported heading")));
});

test("unsupported free text line fails", () => {
  const errors = errorsFor(`# Iteration 1\nmanual note\n- client/file.cfm → MERGED\n`);
  assert(errors.some((error) => error.includes("Unsupported line")));
});

test("strict mode passes when tracked file exists", () => {
  const errors = errorsFor(validTouched("client/file.cfm"), { strict: true, files: ["client/file.cfm"] });
  assert.deepEqual(errors, []);
});

test("strict mode fails when tracked file is missing", () => {
  const errors = errorsFor(validTouched("client/file.cfm"), { strict: true });
  assert(errors.some((error) => error.includes("Missing tracked artifact")));
});

test("strict mode does not check filesystem for invalid path", () => {
  const errors = errorsFor(validTouched("../outside/file.cfm"), { strict: true });
  assert(errors.some((error) => error.includes("'..'")));
  assert(!errors.some((error) => error.includes("Missing tracked artifact")));
});

test("parseArgs supports strict", () => {
  const args = parseArgs(["--strict", "/tmp/workspace"]);
  assert.equal(args.strict, true);
  assert(args.neutralDir.endsWith(path.normalize("/tmp/workspace")));
});

test("parseArgs fails on extra positional arguments", () => {
  assert.throws(() => parseArgs(["/tmp/one", "/tmp/two"]), /Usage/);
});

test("parseArgs fails on unknown options", () => {
  assert.throws(() => parseArgs(["--bad", "/tmp/workspace"]), /Unknown option/);
});
```

## 16. Piano operativo per Codex

### Step 1 - Creare branch

```bash
git checkout -b feat/coldfusion-cross-version-migration-skill
```

### Step 2 - Ispezionare struttura skill esistente

```bash
find skills/mcp-coldfusion-developer -maxdepth 3 -type f | sort
```

Verificare presenza di:

```text
skills/mcp-coldfusion-developer/SKILL.md
skills/mcp-coldfusion-developer/references/
```

Non creare `agents/openai.yaml` come parte di questa modifica se non risulta già uno standard effettivo del repository.

### Step 3 - Aggiornare `SKILL.md`

Applicare le modifiche definite nella sezione 8, inclusa la riga nella tabella `Quick Routing`.

Vincoli:

- modifica conservativa;
- nessun refactor non richiesto;
- nessun riferimento a casi reali;
- frontmatter YAML valido;
- tabella `Quick Routing` aggiornata senza riordino non necessario;
- routing catalog rigenerato con `node scripts/build-routing-catalog.mjs` e diff verificato;
- reference Markdown operative in italiano, coerenti con lo stile locale dello skill;
- blocchi di codice Markdown annidati renderizzati correttamente con fence esterne a quattro backtick.

### Step 3B - Rigenerare routing catalog

Dopo la modifica di `SKILL.md`, eseguire dalla root del repository:

```bash
node scripts/build-routing-catalog.mjs
```

Verificare il diff generato:

```bash
git diff -- scripts/hooks/routing-catalog.json
```

Vincoli:

- non modificare `scripts/hooks/routing-catalog.json` a mano;
- includere il file generato nel commit se cambia;
- se lo script non produce modifiche, annotarlo nella review pre-commit.

### Step 4 - Aggiungere reference

Creare:

```text
skills/mcp-coldfusion-developer/references/cross-version-migration.md
skills/mcp-coldfusion-developer/references/migration-provider.md
skills/mcp-coldfusion-developer/references/migration-consumer.md
skills/mcp-coldfusion-developer/references/migration-tracking-format.md
skills/mcp-coldfusion-developer/references/migration-conventions-template.md
```

Usare i contenuti delle sezioni 9-13.

### Step 5 - Aggiungere script e test

Creare:

```text
skills/mcp-coldfusion-developer/scripts/validate-migration-workspace.js
skills/mcp-coldfusion-developer/scripts/validate-migration-workspace.test.js
```

Usare i contenuti delle sezioni 14-15.

Rendere eseguibile lo script se il repository usa permessi Unix versionati:

```bash
chmod +x skills/mcp-coldfusion-developer/scripts/validate-migration-workspace.js
```

### Step 6 - Eseguire test

```bash
cd skills/mcp-coldfusion-developer
node --test scripts/validate-migration-workspace.test.js
```

### Step 7 - Test manuale validatore

```bash
tmpdir="$(mktemp -d)"
cat > "$tmpdir/conventions.md" <<'MD'
# Conventions
MD
cat > "$tmpdir/touched-files.md" <<'MD'
# Iteration 9
- client/update/i18n/labels.it.properties → MERGED
- client/update/i18n/labels.en.properties → MERGED
- client/update/i18n/labels.fr.properties → MERGED
MD
mkdir -p "$tmpdir/client/update/i18n"
touch "$tmpdir/client/update/i18n/labels.it.properties"
touch "$tmpdir/client/update/i18n/labels.en.properties"
touch "$tmpdir/client/update/i18n/labels.fr.properties"
node scripts/validate-migration-workspace.js "$tmpdir"
node scripts/validate-migration-workspace.js --strict "$tmpdir"
```

Risultato atteso per entrambi:

```text
Migration workspace validation passed.
```

### Step 8 - Review pre-commit

```bash
git diff -- skills/mcp-coldfusion-developer
```

Controllare:

- nessun riferimento hardcoded a casi specifici;
- nessun nuovo MCP server;
- nessuna dipendenza Node esterna;
- istruzioni Provider/Consumer coerenti;
- tracking minimale nel formato `# Iteration N` + `- path → STATUS`;
- nessun uso di sezioni stato, checkbox, `neutral:`, `target:`, `reason:`;
- test automatici verdi;
- test automatici aggiornati per heading iterazione, path ambigui e CLI;
- frontmatter YAML valido;
- tabella `Quick Routing` aggiornata senza riordino non necessario;
- routing catalog rigenerato con `node scripts/build-routing-catalog.mjs` e diff verificato.

### Step 9 - Commit

```bash
git add skills/mcp-coldfusion-developer
git commit -m "feat(skill): add generic cross-version migration workflow"
```

## 17. Criteri di accettazione

La modifica è accettabile se:

- `mcp-coldfusion-developer` documenta chiaramente la modalità Cross-Version Migration;
- la `description` YAML dello skill include trigger coerenti con la nuova modalità;
- la tabella `Quick Routing` include la riga Cross-Version Migration;
- `scripts/hooks/routing-catalog.json` è stato rigenerato con `node scripts/build-routing-catalog.mjs` o verificato senza modifiche;
- le responsabilità Provider e Consumer sono separate;
- il workflow è generico e non contiene riferimenti hardcoded a casi reali;
- `conventions.md` e `touched-files.md` sono descritti come contratto minimo;
- `target-structures.md` è documentato come opzionale raccomandato;
- il formato canonico di `touched-files.md` è quello iniziale compatto: `# Iteration N` e `- relative/path → STATUS`;
- il Consumer aggiorna lo stato inline della riga esistente, senza spostare item tra sezioni;
- il tracking non usa sezioni stato, checkbox, `neutral:`, `target:`, `reason:`;
- lo script Node.js valida correttamente un workspace neutrale;
- lo script blocca path POSIX assoluti, Windows assoluti, Windows drive-relative, UNC, backslash, segmenti `..`, segmenti `.`, segmenti vuoti, shortcut `~` e whitespace iniziale/finale nei path;
- lo script supporta `--strict` per verificare esistenza fisica dei file tracciati;
- in `--strict`, lo script verifica l'esistenza degli artefatti solo dopo path validation positiva;
- lo script non normalizza silenziosamente path con whitespace ai bordi;
- i test automatici del validatore passano;
- il validatore intercetta righe malformate, item fuori iterazione e heading iterazione malformati;
- lo script non richiede dipendenze esterne;
- non viene introdotto alcun nuovo MCP server;
- il documento di tracking resta minimale;
- le reference operative seguono lo stile italiano già usato dallo skill;
- i contenuti file con fence annidate usano delimiter esterni a quattro backtick;
- la struttura target rimane responsabilità dell'utente.

## 18. Checklist review finale

### Analisi tecnica

- [x] Evidenze, inferenze e decisioni sono separate.
- [x] Le decisioni non banali non sono lasciate a Codex.
- [x] Lo scope è chiaro.
- [x] I rischi principali sono mitigati.
- [x] La soluzione resta generica.

### Implementabilità Codex

- [x] File da creare indicati con path precisi.
- [x] Nessuna directory metadata UI non standard viene introdotta nello scope.
- [x] Contenuti principali forniti.
- [x] Comandi di test inclusi.
- [x] Criteri di accettazione verificabili.
- [x] Ambiguità ridotte su tracking e validatore.
- [x] Routing catalog/hook Codex coperto da passaggio generativo esplicito.

### Code review preventiva

- [x] Formato iniziale di `touched-files.md` ripristinato: `# Iteration N` + `- path → STATUS`.
- [x] Nessun uso di sezioni stato, checkbox, `neutral:`, `target:`, `reason:`.
- [x] Path validation cross-platform esplicitata.
- [x] Item fuori iterazione e item malformati coperti.
- [x] Test automatici inclusi.
- [x] Strict mode definita.
- [x] Strict mode non esegue lookup filesystem per path già invalidi.
- [x] Whitespace iniziale/finale nei path tracciati coperto.
- [x] Nessuna automazione di merge fuori scope.
- [x] `scripts/hooks/routing-catalog.json` non viene modificato manualmente ma solo tramite script generativo.

## 19. Rischi residui

| Rischio | Impatto | Mitigazione |
|---|---:|---|
| Il layout reale dello skill esistente differisce dalla struttura prevista. | Medio | Codex deve ispezionare prima la directory e applicare modifiche conservative. |
| Il parser Markdown del validatore è minimale. | Medio | Formato compatto ristretto, heading iterazione validati e test automatici sugli edge case principali. |
| Migrazioni grandi generano tracking complesso. | Medio | Iterazioni piccole per feature o sotto-feature. |
| Merge semantico errato nel target. | Alto | Non automatizzare merge; usare test applicativi del progetto target. |

---

## 20. Conclusione

L'analisi definisce un handoff tecnico completo per implementare una modalità generica di migrazione cross-version nello skill `mcp-coldfusion-developer`.

La soluzione resta limitata a workflow, reference Markdown, script di validazione e test automatici, senza introdurre un nuovo MCP server o automazioni di merge fuori scope.

Codex può procedere con una patch incrementale e reviewable seguendo il piano operativo, i criteri di accettazione e i vincoli definiti in questo documento.
