# Analisi tecnica — Compatibilità CFLint/CFParser e roadmap del linter CFML

Data: 2026-07-27
Repository target: `D:\mcp-servers`
Codice applicativo di riferimento: `D:\cfprojects\vcs\platform\monorepo`
Ambito: `linter-node`, CFLint, CFParser, configurazione Platform
Stato: workaround MCP implementato, evolutive sul JAR da pianificare
Metodo: skill `mcp-technical-analyst`, analisi multi-sorgente con distinzione tra evidenze, inferenze e punti aperti

---

## 1. Sintesi esecutiva

Il problema principale è confermato nel parser incorporato nel JAR usato dal
linter: gli operatori CFML/Lucee `===` e `!==` non sono riconosciuti da
CFParser 2.11.0 e causano un errore di parsing prima che CFLint possa applicare
regole, configurazioni o direttive `ignore`.

La soluzione immediata raccomandata è un workaround nel server MCP:

1. leggere il file originale senza modificarlo;
2. creare, solo quando necessario, una copia temporanea per CFLint;
3. sostituire `===` con `== ` e `!==` con `!= ` mantenendo invariati lunghezza,
   righe e offset;
4. eseguire CFLint sulla copia;
5. restituire le diagnostiche riferite al percorso originale;
6. eliminare sempre la copia temporanea;
7. permettere il confronto con il parser nativo tramite
   `CFLINT_PARSER_COMPAT_MODE=off`.

La correzione strutturale ideale resta una nuova versione del JAR, ma viene
deliberatamente rimandata a un'evolutiva. Dovrà essere prodotta tramite fork
versionati di `cfparser/cfparser` e, se necessario, `cflint/CFLint`, con build
riproducibile del JAR completo `-all.jar`, test di regressione e successiva
rimozione controllata del workaround MCP.

Non è invece corretto copiare alla cieca i parametri della `.cflintrc`
Platform nel default MCP. Le verifiche sul JAR e sul sorgente CFLint mostrano
che diverse chiavi presenti in Platform non sono implementate e vengono
ignorate silenziosamente:

- `ArgDefChecker.excludedTypes`;
- `QueryParamChecker.excludedVariables`;
- `VarScoper.customScopes`;
- `SelectStarChecker.excludeQoQ`.

Sono supportati i parametri di lunghezza di funzione e componente, ma
rappresentano una scelta di policy Platform e non una correzione del parser.
La lunga lista `excludes` Platform è efficace, ma importarla globalmente
disattiverebbe controlli utili per tutti i progetti non Platform.

---

## 2. Obiettivi e non-obiettivi

### 2.1 Obiettivi

- Evitare falsi `PARSE_ERROR`/`MISSING_SEMI` dovuti a `===` e `!==`.
- Conservare l'integrità del sorgente CFML e l'allineamento delle diagnostiche.
- Rendere il percorso del JAR configurabile tramite `CFLINT_JAR`.
- Documentare come recuperare, verificare e provare un JAR alternativo.
- Distinguere le mitigazioni attuabili nel wrapper da quelle che richiedono
  modifiche a CFLint o CFParser.
- Predisporre un backlog verificabile per una futura distribuzione interna del
  JAR corretto.
- Usare casi reali del monorepo Platform come corpus di regressione, senza
  modificarlo in questa attività.

### 2.2 Non-obiettivi di questa attività

- Modificare o sostituire il JAR ufficiale.
- Creare subito fork remoti o pubblicare release GitHub.
- Importare globalmente tutte le esclusioni della `.cflintrc` Platform.
- Sopprimere genericamente tutte le segnalazioni controverse.
- Riscrivere i sorgenti applicativi per adattarli ai limiti di CFLint.

---

## 3. Baseline tecnica osservata

### 3.1 Runtime effettivo

| Elemento | Valore osservato | Stato |
|---|---|---|
| JAR | `C:\tesisquare\cflint\CFLint-1.5.0-all.jar` | disponibile |
| Versione dichiarata dal JAR | `1.5.0-SNAPSHOT` | evidenza runtime |
| CFParser incorporato | `2.11.0` | evidenza dal contenuto del JAR |
| Java MCP | `D:\programmi\ColdFusion2023\jre\bin\java.exe` | disponibile |
| Java osservato | `17.0.6` | evidenza runtime |
| Configurazione Platform | `D:\cfprojects\vcs\platform\monorepo\.cflintrc` | disponibile |

Il nome esterno `CFLint-1.5.0-all.jar` e la versione interna
`1.5.0-SNAPSHOT` non coincidono perfettamente. Qualunque futura release
interna dovrà esporre versione, commit e checksum non ambigui.

### 3.2 Fonti analizzate

| Fonte | Evidenza ricavata |
|---|---|
| `linter-node/src/config.ts` | risoluzione di `CFLINT_JAR`, `JAVA_BIN`, `CFLINT_CONFIG` dal progetto target |
| `linter-node/src/linters/cflint.ts` | invocazione CLI CFLint e precedenza della `.cflintrc` trovata dal file |
| JAR corrente, `cflint.definition.json` | regole globali abilitate e parametri predefiniti |
| `.cflintrc` Platform | esclusioni e parametri desiderati dal progetto |
| `CFLint/RULES.md` | soli parametri ufficialmente documentati per le regole interessate |
| `ArgDefChecker.java` | nessuna implementazione di `excludedTypes` |
| `QueryParamChecker.java` | nessuna implementazione di `excludedVariables` |
| `VarScoper.java` | scope globali hard-coded, nessun `customScopes` |
| `SelectStarChecker.java` | nessuna gestione `excludeQoQ` |
| issue `cfparser/cfparser#128` | richiesta aperta di supporto agli operatori Lucee |
| grammatica CFParser corrente | assenza di token per `===` e `!==` |
| build CFLint corrente | dipendenza ancora fissata a CFParser 2.11.0 |
| monorepo Platform | esempi reali per operatori, modifier, query, tag e false positive |

### 3.3 Inventario lessicale del monorepo

Sono stati inventariati 7.763 file CFML, escludendo `cfserver/**`,
`3rdparty`, `testbox` e `vendor`. I numeri seguenti misurano l'esposizione ai
costrutti, non il numero di diagnostiche emesse:

| Costrutto | Occorrenze | File | Campione |
|---|---:|---:|---|
| `===` | 158 | 76 | `framework/cflib/gr_cfc/managers/mobileappmanager.cfc:411` |
| `!==` | 129 | 51 | `framework/cflib/gr_cfc/managers/mvc.cfc:1352` |
| totale operatori stretti | 287 | 112 | include CFScript e JavaScript incorporato/generato |
| `static function` | 21 | 3 | `framework/cflib/application/staticutils.cfc:10` |
| `final function` | 4 | 2 | `framework/cflib/gr_cfc/gr_user.cfc:800` |
| `abstract` | 2 | 1 | `framework/cflib/automation/entityeventmanager/base.cfc:5` |
| `cfcookie` tag/script | 7 | 4 | `framework/cflib/application/utils.cfc:1164` |
| `cfcontent` tag/script | 52 | 32 | `framework/cflib/gr_cfc/generic/file_mgmt.cfc:238` |
| `cfsavecontent`/`savecontent` | 5.228 | 2.243 | `framework/cflib/viewer/mercury/sections/widget.cfc:68` |
| `cfloop` | 6.476 | 1.325 | `framework/cflib/application/utils.cfc:286` |
| `queryExecute` | 3.730 | 558 | `framework/util/clear_old_updates.cfm:31` |
| query-of-query | 2.205 | 682 | `dbtype="query"` o equivalente |
| `cflock` tag/script | 108 | 67 | `framework/cflib/application/utils.cfc:250` |

Le direttive CFLint sono 2.340 in 1.208 file, distribuite su 20 codici. Le
principali sono:

- `UNUSED_LOCAL_VARIABLE`: 1.443;
- `CFQUERYPARAM_REQ`: 634;
- `MISSING_VAR`: 109;
- `SQL_SELECT_STAR`: 62;
- `ARG_DEFAULT_MISSING`: 46.

Un campione significativo è
`framework/cflib/automation/automationstoremgr.cfc:45`: `local.q_search`
possiede un ignore `UNUSED_LOCAL_VARIABLE`, ma viene consumata nella stringa
SQL QoQ come `[local].q_search` e passata a `queryExecute`. È un forte
candidato a limite del data-flow del checker. Non dimostra però che tutte le
1.443 direttive siano ancora necessarie: possono coesistere workaround
storici, limiti ancora presenti e veri positivi.

### 3.4 Fonti upstream

- CFLint: <https://github.com/cflint/CFLint>
- CFParser: <https://github.com/cfparser/cfparser>
- Issue operatori Lucee: <https://github.com/cfparser/cfparser/issues/128>
- Regole CFLint: <https://github.com/cflint/CFLint/blob/master/RULES.md>
- `ArgDefChecker`: <https://github.com/cflint/CFLint/blob/master/src/main/java/com/cflint/plugins/core/ArgDefChecker.java>
- `QueryParamChecker`: <https://github.com/cflint/CFLint/blob/master/src/main/java/com/cflint/plugins/core/QueryParamChecker.java>
- `VarScoper`: <https://github.com/cflint/CFLint/blob/master/src/main/java/com/cflint/plugins/core/VarScoper.java>
- `SelectStarChecker`: <https://github.com/cflint/CFLint/blob/master/src/main/java/com/cflint/plugins/core/SelectStarChecker.java>
- fix riferimenti locali in tag/loop: <https://github.com/cflint/CFLint/issues/339>
- fix `cfcookie name`: <https://github.com/cflint/CFLint/issues/518>
- fix variabili in `lock {}`: <https://github.com/cflint/CFLint/issues/488>
- fix colonne nei query loop: <https://github.com/cflint/CFLint/issues/284>
- supporto `queryExecute`: <https://github.com/cflint/CFLint/issues/554>
- falso positivo QoQ con `new Query`: <https://github.com/cflint/CFLint/issues/577>
- supporto CFParser per modifier: <https://github.com/cfparser/cfparser/commit/0de02d6d58d20469f627541208f151a062ace47a>

---

## 4. Evidenze sperimentali

### 4.1 Operatori stretti

Il frammento seguente fallisce con il parser incorporato:

```cfml
if (
    arguments.args.btpag === "inoltra"
    and local.inChargeTo !== arguments.session_info.UserClasseAnag
) {
    local.check.isError = true;
}
```

Una copia di lint con sostituzioni della stessa lunghezza:

```text
===  -> ==·
!==  -> !=·
```

dove `·` rappresenta uno spazio, viene analizzata correttamente dal JAR. La
lunghezza di ogni riga e gli offset successivi restano invariati.

### 4.2 Caso `writeDump(1 == 2);`

Il caso minimo, inserito in un contesto CFScript valido, non ha riprodotto
`MISSING_SEMI` con il runtime corrente. Il problema resta classificato come
non riprodotto, non come risolto. Per riaprirlo servono:

- file completo;
- riga e colonna;
- output JSON integrale;
- configurazione effettiva;
- versione JAR/Java;
- eventuale contesto tag/script circostante.

### 4.3 Parametri Platform ignorati

È stata eseguita una prova A/B su un argomento opzionale di tipo `date`:

1. esecuzione senza configurazione;
2. esecuzione con configurazione contenente
   `ArgDefChecker.excludedTypes=date,any`.

Entrambe hanno prodotto `ARG_DEFAULT_MISSING`. Il sorgente upstream di
`ArgDefChecker` conferma che il parametro non viene letto. Lo stesso controllo
statico sui checker mostra l'assenza delle altre tre chiavi Platform citate.

Conclusione: la presenza di una chiave in `.cflintrc` non dimostra che la
versione di CFLint la applichi.

### 4.4 Attivazione delle regole

Le regole non vengono “attivate” dalla `.cflintrc` Platform. Le implementazioni
sono già elencate nel `ruleImpl` della configurazione globale inclusa nel JAR.
La configurazione di progetto può:

- includere o escludere messaggi;
- impostare parametri che il relativo checker implementa davvero;
- ereditare o non ereditare selezioni di regole.

Una chiave parametro sconosciuta non crea funzionalità nuova. Una esclusione
funziona soltanto dopo che il parser è riuscito a costruire l'AST; non può
risolvere un errore sintattico su `===`, `!==`, `final` o `static`.

### 4.5 Stato upstream dei modifier

CFParser `master` è identificato come `2.13.0-SNAPSHOT` e nel 2024 ha ricevuto
supporto per `static`, `final`, `abstract`, blocchi statici e `::`. CFLint
`master`, tuttavia, continua a dipendere da CFParser 2.11.0: ricostruire
semplicemente CFLint `master` non porta questi miglioramenti nel JAR.

La grammatica CFParser corrente continua invece a non definire token per
`===` e `!==`. Un primo esperimento con CFParser 2.13 può quindi risolvere i 27
costrutti modifier inventariati, ma non sostituisce ancora il workaround per
gli operatori stretti.

---

## 5. Decisioni architetturali

### 5.1 Workaround MCP immediato

Stato: implementato, da mantenere finché il JAR configurato non supera il
medesimo corpus senza adattamenti.

Comportamento:

- modalità predefinita `auto`;
- modalità diagnostica `off`;
- nessuna modifica del file sorgente;
- copia in directory temporanea di sistema;
- sostituzioni solo nel contenuto passato a CFLint;
- righe, colonne e offset preservati;
- warning esplicito nella risposta MCP;
- cleanup nel blocco `finally`;
- `.cflintrc` vuota e non ereditabile nella directory temporanea, usata solo
  per fermare il traversal difettoso di CFLint sugli antenati `%TEMP%`;
- `.cflintrc` cercata a partire dal percorso originale, non dalla directory
  temporanea.

File coinvolti:

- `linter-node/src/linters/cflint-compat.ts`;
- `linter-node/src/linters/cflint.ts`;
- `linter-node/src/config.ts`;
- `linter-node/.env.example`;
- `tests/smoke/linter-node-cfml-compat.smoke.mjs`.

### 5.2 Regole default

Decisione: non aggiungere in questa fase un secondo set di regole CFLint.

Motivi:

- il repository non contiene attualmente una `.cflintrc` globale versionata;
- il default effettivo è `cflint.definition.json` nel JAR;
- la `.cflintrc` Platform non definisce plugin aggiuntivi;
- quattro parametri apparentemente mitigativi sono inattivi;
- copiare gli `excludes` Platform come default ridurrebbe la copertura negli
  ambienti non Platform;
- i progetti Platform continuano a usare la propria `.cflintrc`, che ha
  precedenza.

Decisione futura possibile: introdurre un profilo MCP comune soltanto dopo una
matrice A/B che dimostri, regola per regola, comportamento e assenza di
regressioni.

### 5.3 JAR futuro

Decisione: trattare la modifica del JAR come evolutiva separata.

Il risultato atteso non è una patch manuale di un binario, ma una supply chain
versionata:

```text
fork CFParser
  -> test grammatica/AST
  -> artifact parser versionato
  -> fork CFLint
  -> dipendenza sul parser corretto
  -> test regole/configurazione
  -> shaded JAR -all
  -> checksum + provenienza
  -> test A/B nel linter MCP
  -> rollout tramite CFLINT_JAR
```

---

## 6. Classificazione delle casistiche note

| Casistica | Causa probabile | Intervento raccomandato | Fase |
|---|---|---|---|
| `===`, `!==` | grammatica CFParser | workaround MCP; poi fork CFParser | adesso / E1 |
| `final`, `static`, `abstract` | versione parser incorporata obsoleta | provare parser corrente; poi aggiornare dipendenza | E1 |
| `writeDump(1 == 2)` / `MISSING_SEMI` | contesto non noto | fixture completa e riproduzione | E0 |
| variabili in `cfcookie`/tag | visitor `UnusedLocalVarChecker` incompleto | test + correzione checker | E2 |
| variabili in `cfloop` | tracking assegnazioni/usi incompleto | test di data-flow per iterazioni | E2 |
| `cfsavecontent`, `cfcontent` | attributi tag non riconosciuti come uso | estendere attributi osservati | E2 |
| incremento `+=` nel `for` | AST/data-flow incompleto | test e fix checker/parser | E2 |
| interpolazione `cfquery` | visita delle espressioni incompleta | fix checker con test SQL | E2 |
| `queryExecute` | euristica regex troppo ampia | distinguere valori da identificatori SQL | E3 |
| query-of-query e `[local].kpi` | risoluzione nomi incompleta | corpus QoQ e fix semantico | E2 |
| backup attraverso `cflock` | scope/data-flow interblocco | analisi conservativa o annotazione | E3 |
| `arguments.viaggi` in `cfloop` | classificazione errata come SQL | fixture minima prima del fix | E0 |
| argomento opzionale `date` | `ArgDefChecker` opinionato; parametro inesistente | implementare parametro nel fork | E2 |
| ignore `UNUSED_LOCAL_VARIABLES` | identificatore errato al plurale | usare/testare `UNUSED_LOCAL_VARIABLE` | adesso |
| ignore SQL | differenza tra `CFQUERYPARAM_REQ` e `QUERYPARAM_REQ` | documentazione e test per contesto | adesso / E0 |
| concatenazioni `&` come booleani | AST o checker booleano | fixture + correzione mirata | E2 |
| risultato DML assegnato | policy “unused” vs requisito debug | decisione di coding standard | aperto |
| nomi tabella/colonna dinamici | sicurezza e correttezza non parametrizzabili | regola dedicata/allowlist, non soppressione globale | E3 |

Legenda:

- `E0`: consolidamento evidenze e corpus;
- `E1`: parser e operatori/modifier;
- `E2`: checker CFLint e configurazioni;
- `E3`: SQL dinamico e analisi semantica avanzata.

---

## 7. Roadmap evolutiva

### E0 — Corpus di regressione e baseline

Obiettivo: trasformare le segnalazioni storiche in test deterministici.

Attività:

1. creare fixture minime indipendenti dal monorepo;
2. mantenere un mapping dalla fixture al file reale di origine;
3. registrare output atteso con modalità `auto` e `off`;
4. registrare JAR, Java, configurazione e comando;
5. classificare ogni caso come:
   - vero positivo;
   - falso positivo;
   - errore parser;
   - policy da decidere;
   - non riprodotto;
6. aggiungere test per le direttive:
   - `//cflint ignore:UNUSED_LOCAL_VARIABLE`;
   - `//cflint ignore:QUERYPARAM_REQ`;
   - commento CFML `@CFLintIgnore CFQUERYPARAM_REQ`.

Criterio di uscita: ogni voce prioritaria ha fixture, output corrente e output
atteso approvato.

### E1 — Fork CFParser

Obiettivo: supportare la sintassi CFML adottata senza pre-processing.

Attività:

1. creare fork organizzativo di `cfparser/cfparser`;
2. aggiungere token distinti per `===` e `!==`;
3. definire nodi AST o operatori che preservino la semantica stretta;
4. coprire precedenza, negazione, parentesi, ternari e catene booleane;
5. coprire operatori dentro interpolazioni CFML;
6. verificare `final`, `static` e `abstract` sulla grammatica più recente;
7. mantenere compatibilità con `==`, `!=`, `eq`, `neq`, `is` e `is not`;
8. pubblicare artifact snapshot interno identificato dal commit.

Criterio di uscita: il corpus parser passa senza trasformazioni MCP.

### E2 — Fork CFLint e correzione checker

Obiettivo: integrare il parser corretto e rendere effettive le mitigazioni
configurabili.

Attività:

1. creare fork organizzativo di `cflint/CFLint`;
2. aggiornare la dipendenza CFParser;
3. implementare e documentare:
   - `ArgDefChecker.excludedTypes`;
   - `QueryParamChecker.excludedVariables`, se ancora desiderato;
   - `VarScoper.customScopes`;
   - `SelectStarChecker.excludeQoQ`;
4. correggere `UnusedLocalVarChecker` per tag, loop, query, QoQ,
   `cfsavecontent`, `cfcontent` e `cflock`;
5. aggiungere test per nomi con notazione a parentesi;
6. verificare scope e cardinalità delle direttive ignore;
7. evitare filtri basati soltanto su testo o numero di riga.

Criterio di uscita: i parametri documentati hanno test positivo e negativo e
le chiavi sconosciute producono almeno un warning di configurazione.

### E3 — SQL dinamico

Obiettivo: ridurre falsi positivi senza indebolire controlli di sicurezza.

Attività:

1. distinguere valori SQL parametrizzabili da identificatori
   tabella/colonna/ordinamento;
2. introdurre allowlist configurabili per identificatori;
3. riconoscere placeholder e parameter struct di `queryExecute`;
4. modellare query-of-query separatamente dalle query DB;
5. distinguere DML, DDL e SELECT;
6. decidere il pattern ammesso per query DML assegnate per debug;
7. aggiungere messaggi specifici, evitando un unico `QUERYPARAM_REQ`
   indistinto.

Criterio di uscita: nessuna soppressione globale di interpolazioni SQL e test
negativi per injection mantenuti.

### E4 — Packaging e distribuzione

Obiettivo: produrre un JAR interno verificabile e sostituibile via ambiente.

Attività:

1. definire versione, ad esempio `1.5.0-tesisquare.1`;
2. automatizzare build Gradle del JAR completo `-all.jar`;
3. registrare commit CFLint e CFParser nel manifest di release;
4. produrre SHA-256 e, se disponibile, SBOM;
5. pubblicare in release repository interno o GitHub Release aziendale;
6. aggiornare README con URL stabile e procedura di verifica;
7. configurare il linter tramite `CFLINT_JAR`, senza hard-code aggiuntivi;
8. eseguire smoke su Windows e almeno un ambiente non Windows;
9. documentare rollback al JAR precedente.

Criterio di uscita: un ambiente pulito può scaricare, verificare e usare il
JAR seguendo solo il README.

### E5 — Rimozione del workaround MCP

Obiettivo: evitare doppie trasformazioni dopo l'adozione del parser corretto.

Attività:

1. eseguire A/B con `CFLINT_PARSER_COMPAT_MODE=auto` e `off`;
2. verificare parità delle diagnostiche sul corpus;
3. cambiare il default a `off` soltanto dopo rollout del nuovo JAR;
4. mantenere temporaneamente `auto` come rollback;
5. rimuovere codice e variabile in una release successiva.

Criterio di uscita: nessun JAR supportato richiede più la riscrittura.

---

## 8. Strategia di test

### 8.1 Test unitari MCP

- sostituzione di entrambi gli operatori;
- conservazione della lunghezza;
- conservazione del numero di righe;
- nessuna modifica quando gli operatori non sono presenti;
- nessuna sostituzione nel testo non eseguibile già coperto;
- normalizzazione `auto`/`off`;
- test futuri per interpolazioni e costrutti tag.

### 8.2 Smoke di integrazione

- avvio reale di `linter-node`;
- risoluzione runtime con `get_lint_config`;
- lint di un file BOM con `===` e `!==`;
- assenza di `PARSE_ERROR` e `MISSING_SEMI`;
- warning di compatibilità presente;
- sorgente invariato byte per byte;
- directory temporanea rimossa.

### 8.3 Test futuri del JAR

Ogni fixture deve essere eseguita almeno con:

| Profilo | Scopo |
|---|---|
| JAR corrente + `auto` | baseline operativa MCP |
| JAR corrente + `off` | riproduzione limite parser |
| JAR candidato + `off` | prova della correzione strutturale |
| JAR candidato + `.cflintrc` Platform | compatibilità applicativa |
| JAR candidato senza `.cflintrc` | copertura non Platform |

---

## 9. Rischi e mitigazioni

| Rischio | Impatto | Mitigazione |
|---|---|---|
| sostituzione dentro contesti CFML non modellati | diagnostica incompleta | ampliare corpus, mantenere `off`, migrare al parser corretto |
| offset disallineati | segnalazioni sulla colonna errata | sostituzioni isometriche e test su lunghezza |
| file temporanei residui | privacy/spazio disco | directory isolata e cleanup `finally` |
| import globale degli excludes Platform | perdita di copertura | lasciare le esclusioni nel progetto |
| parametri ignorati silenziosamente | falsa percezione di protezione | test A/B e documentazione per versione |
| fork non mantenuto | debito di supply chain | patch minime, commit upstream tracciati, build automatica |
| divergenza semantica `===`/`==` nel lint | regole basate sull'operatore non accurate | workaround solo parser; JAR futuro con AST distinto |
| SQL dinamico soppresso troppo ampiamente | vulnerabilità non segnalate | allowlist e regole specifiche |

---

## 10. Punti aperti

1. Quale organizzazione ospiterà i fork e gli artifact interni?
2. Il nuovo JAR dovrà restare compatibile con Java 8 oppure il baseline può
   essere elevato?
3. Le soglie Platform 500/5000 devono diventare uno standard comune o restare
   policy di progetto?
4. Gli argomenti opzionali `date`/`any` senza default sono uno standard
   aziendale da codificare o solo una tolleranza legacy?
5. Quali variabili SQL dinamiche possono essere considerate identificatori
   sicuri e con quale allowlist?
6. L'assegnazione del risultato DML a una variabile è un requisito di debug
   formalizzato?
7. Quali versioni Adobe ColdFusion e Lucee devono entrare nella matrice di
   compatibilità?
8. Il caso `writeDump(1 == 2);` è ancora riproducibile nel flusso effettivo?

---

## 11. Definition of Done dell'evolutiva JAR

L'evolutiva potrà considerarsi completata quando:

- i fork e i commit sorgente sono identificati;
- `===`, `!==`, `final`, `static` e `abstract` hanno fixture approvate;
- i checker modificati hanno test positivi e negativi;
- la configurazione rifiuta o segnala parametri ignoti;
- il JAR `-all` è costruito automaticamente;
- versione e checksum sono pubblicati;
- il README indica recupero, verifica, configurazione e rollback;
- il corpus Platform passa con la propria `.cflintrc`;
- il corpus non Platform conserva la copertura delle regole globali;
- lo smoke MCP passa con `CFLINT_PARSER_COMPAT_MODE=off`;
- è documentata la strategia di dismissione del workaround.

---

## 12. Conclusione

La separazione corretta è:

- **ora**: workaround MCP limitato agli operatori stretti, configurabile,
  reversibile e verificato;
- **nel progetto**: `.cflintrc` Platform per le esclusioni realmente volute;
- **non ora**: duplicazione di parametri che il JAR ignora;
- **evolutiva TODO**: fork CFParser/CFLint, correzione del parser e dei checker,
  nuovo JAR completo, rollout tramite `CFLINT_JAR` e rimozione progressiva del
  workaround.

Questa impostazione risolve il blocco operativo più frequente senza alterare il
binario legacy e mantiene una via chiara verso la soluzione strutturale.
