Il Libro Mastro dell'Ingegneria
"Un tool che funziona per ragioni misteriose non è un tool — è un rituale. Zenzic funziona per ragioni documentate. Questa pagina è la prova."
Questa pagina è il manifesto tecnico dietro ogni decisione che rende Zenzic v0.7.0 abbastanza affidabile da essere chiamato un Safe Harbor. Appartiene al quadrante Developer perché l'utente non ha bisogno di conoscerla per essere protetto — ma il contributor deve comprenderla per estendere il sistema senza rompere il contratto.
Pilastro 1 — Zero Assunzioni: Analizza la Sorgente, Non la Build
Il beneficio per l'utente: Zenzic intercetta link rotti, credenziali esposte ed errori strutturali prima che la build della documentazione inizi — eliminando un'intera classe di fallimenti CI che emergono solo dopo 3 minuti di attesa.
Il principio ingegneristico: L'analisi viene eseguita esclusivamente sui file Markdown
sorgente grezzi e sulle loro configurazioni statiche (es. mkdocs.yml, docusaurus.config.ts,
zenzic.toml). Nessun output HTML viene analizzato. Nessun server web viene avviato.
Nessun motore di build viene invocato.
Perché questo conta tecnicamente: L'output della build è una trasformazione della sorgente. Validare l'output significa fidarsi che la trasformazione sia corretta — il che non è, per definizione, quando la sorgente ha errori strutturali. Zenzic valida le invarianti della sorgente affinché la build possa essere considerata affidabile nel produrre un output corretto.
Implementazione: La Virtual Site Map (VSM) è la prova. core/vsm.py costruisce
una proiezione completa in memoria del sito finale a partire dai soli file sorgente,
usando la conoscenza specifica dell'adattatore su come ogni motore mappa i file agli URL.
Le Ghost Route (fallback i18n, slug versionati) sono modellate senza eseguire la build
che le produrrebbe.
Invariante: core/ non chiama mai subprocess.run. Nessun file in src/zenzic/
lancia un processo esterno. Questo è verificato dalla suite test_cli_e2e.py, che fa
il monkey-patch di subprocess e asserisce che non viene mai raggiunto.
Pilastro 2 — Senza Sottoprocessi: 100% Python Puro
Il beneficio per l'utente: Zenzic gira identicamente su Ubuntu, Windows e macOS —
in un container Docker, in un GitHub Actions runner, o sul laptop dello sviluppatore —
senza dipendenze di sistema nascoste. uvx zenzic check all . funziona allo stesso modo
ovunque.
Il principio ingegneristico: Ogni funzione di analisi è una funzione Python pura. L'unico
I/O permesso è la lettura di file (sorgenti) e la scrittura (report, snapshot). Nessun
comando shell, nessun os.system, nessun subprocess.run, nessuna esecuzione Node.js,
nessun binario esterno.
Perché questo conta tecnicamente: I sottoprocessi introducono comportamento
platform-specific, sensibilità al PATH e timing non deterministico. Un gate CI che si
comporta diversamente sul laptop dello sviluppatore e in produzione non è un gate — è
rumore. Zero sottoprocessi significa che zenzic check all sul tuo laptop produce lo
stesso exit code di zenzic check all in CI.
Implementazione: La matrice CI 3×3 (OS: [ubuntu, windows, macos] × Python:
[3.11, 3.12, 3.13]) è la prova continua. 1.260+ test passano su tutte e nove le
combinazioni dalla versione v0.7.0. I test property-based (Hypothesis, profilo ci:
500 esempi) stress-testano le funzioni core sull'intero spazio di input per individuare
edge case platform-specific.
Invariante (RULE R08): Codificato in copilot-instructions.md come permanente
non negoziabile. Qualsiasi PR che introduce una chiamata a sottoprocesso fallisce
immediatamente il gate di review.
Pilastro 3 — Grafo Deterministico: Pure Functions First
Il beneficio per l'utente: Eseguire zenzic check all due volte sulla stessa sorgente
produce lo stesso report, lo stesso exit code e lo stesso punteggio. Non ci sono race
condition, sorprese da cache invalidation, o fallimenti CI intermittenti causati da Zenzic stesso.
Il principio ingegneristico: La logica di analisi è pura e deterministica. L'I/O è isolato ai margini (Discovery legge i file; Reporting scrive i risultati). I cicli del percorso critico — validazione dei link, scansione delle credenziali, rilevamento degli orfani — non contengono chiamate al file system, stato casuale, né stato mutabile condiviso.
Perché questo conta tecnicamente: I tool di analisi non deterministici creano un pattern di fallimento particolarmente dannoso: insegnano agli ingegneri a ri-eseguire la CI invece di correggere la causa radice. Un tool che a volte passa sullo stesso input allena il team ad ignorarlo. Il determinismo è il fondamento della fiducia.
Implementazione:
# core/scorer.py — D092 Quartz Penalty Scorer
def compute_score(findings_counts: dict[str, int]) -> ScoreReport:
"""
Nessun I/O. Nessun effetto collaterale. Stessi input → stesso output,
su ogni OS, in ogni versione Python, a qualsiasi ora del giorno.
findings_counts: dizionario di codici Zxxx (es. "Z101", "Z402").
"""
...
L'AdaptiveRuleEngine in core/rules.py seleziona automaticamente tra esecuzione
sequenziale e parallela alla soglia dei 50 file — ma entrambe le modalità producono
i medesimi finding. Il parallelismo è un'ottimizzazione delle prestazioni; non altera
il risultato dell'analisi.
Invariante (RULE R01, RULE R03): Nessun Path.exists() o open() nei cicli di
validazione di link/file. Ogni oggetto Finding porta un codice Zxxx da codes.py.
La funzione _to_findings() in cli/_check.py è l'unico punto di conversione autorizzato.
Il Contratto degli Exit Code
I tre pilastri convergono nel contratto degli exit code — la prova più visibile che Zenzic è uno strumento fondato su principi, non uno scanner euristico:
| Exit | Significato | Sopprimibile? |
|---|---|---|
0 | Tutti i controlli passati — documentazione pulita | — |
1 | Finding di qualità (link rotti, orfani, placeholder, ecc.) | ✅ --exit-zero |
2 | Shield — credenziale rilevata (Z201) | ❌ Mai |
3 | Blood Sentinel — path traversal / fatale (Z202/Z203) | ❌ Mai |
Gli exit code 2 e 3 sono verificati al layer CLI (cli/_check.py) prima che qualsiasi
flag --exit-zero venga consultato. Il controllo non è condizionale — è strutturalmente
anteriore. Nessuna configurazione, flag o variabile d'ambiente può sopprimere un exit
di sicurezza.
Questa non è una decisione di policy. È una prova di correttezza: un gate CI che può essere silenziato su una fuga di credenziali non è un gate di sicurezza. È una casella da spuntare.
Ulteriori Risorse
- ADR — Architectural Decision Records — il log completo delle decisioni
- Architecture — gap aperti e roadmap v0.8.0
- Riferimento ai Codici di Finding — il catalogo completo
Zxxx - Safe Harbor — la filosofia dietro l'ingegneria