L’Invariante
Ogni regola valutata dalla piattaforma è una funzione pura di (payload, contesto, stato db). Il linguaggio delle espressioni è deterministico per costruzione — la grammatica non ha chiamate a funzione, quindi un manifest non può esprimere now(), random() o uuid(). Lo stesso evento ri-eseguito sullo stesso stato produce sempre lo stesso verdetto.
Il Contratto
Tre motori condividono lo stesso valutatore di espressioni:
- formula_engine — valori calcolati con nome (
weight_delta_pct,tempo_std) riferiti dalle altre regole come$formula.*. - constraint_engine —
pre_commit_ruleslegate ai trigger; un verdettofalserifiuta l’azione. - data_link_engine —
SELECT/INSERT/UPDATEdichiarativi sulle tabellebiz_*, eseguiti dentro la transazione dell’azione.
Prefissi di scope: $payload (input del chiamante), $context (sessione: operatorId, tenant), $db (lookup), $formula (valori calcolati). Qualsiasi scope diverso viene rifiutato al caricamento del manifest.
Il Flusso
- L’action engine lega
$payloaddalla richiesta e$contextdalla sessione. - Le formule riferite dai constraint del trigger vengono valutate per prime.
- Ogni
pre_commit_ruledel trigger viene valutata; qualsiasifalse→CONSTRAINT_VIOLATED, rollback. - In caso di successo viene eseguita la query data-link del trigger — l’SQL è generato dal mapping del manifest, mai interpolato dall’input grezzo.
- I risultati finiscono nello stesso commit della transizione FSM e della riga di audit.
Esempio di Payload
// frammento di manifests/LayoutManifest.production-line.example.json
{
"formula_engine": {
"weight_delta_pct": "(($payload.peso_misurato - $payload.peso_dichiarato) / $payload.peso_dichiarato) * 100"
},
"constraint_engine": {
"pre_commit_rules": [{
"id": "peso_coerente",
"expression": "$formula.weight_delta_pct <= 0.5 && $formula.weight_delta_pct >= -0.5",
"error_message": "Peso misurato fuori tolleranza rispetto al dichiarato",
"triggers": ["ACCEPT_LOT"]
}]
},
"data_link_engine": {
"queries": {
"ACCEPT_LOT": {
"type": "INSERT", "table": "biz_lotti",
"mapping": { "lotto": "$payload.lot_id",
"peso_misurato": "$payload.peso_misurato",
"operator_id": "$context.operatorId" }
}
}
}
}
I Fallimenti Noti
| Sintomo | Causa |
|---|---|
| Manifest rifiutato al load | Espressione fuori grammatica (chiamata a funzione, scope sconosciuto) — riscrivere su $payload/$context/$db/$formula |
CONSTRAINT_VIOLATED su dati apparentemente validi |
Una formula a monte ha prodotto un valore fuori inviluppo — valutarla sullo stesso payload |
Errore su tabella non biz_ |
Le scritture data-link sono ristrette alla superficie biz_ dalla SQL guard |
| Regola scattata sul trigger sbagliato | Lista triggers: [...] troppo ampia — i constraint sono opt-in per trigger |