Architecture Drift Score: la tua documentazione dice la verità? - Archyl Blog

L'Architecture Drift Score è un numero da 0 a 100 che indica quanta parte della tua architettura documentata esiste ancora nella tua codebase. Questo è il meccanismo: la formula, cosa entra nel denominatore, cosa viene escluso deliberatamente, cosa il controllo non riesce a vedere e come imporlo nella CI.

Architecture Drift Score: la tua documentazione dice la verità?

Una metrica che nessuno può verificare è una metrica su cui nessuno dovrebbe agire. Quindi questo post è l'aritmetica: come viene prodotto l'Architecture Drift Score, cosa finisce nel denominatore, cosa lasciamo fuori deliberatamente e le quattro cose che il controllo non può vedere.

Il punteggio risponde a una sola domanda. Quale percentuale della tua architettura documentata esiste ancora nella tua codebase? È un numero da 0 a 100, calcolato da una singola richiesta al tuo provider Git, senza IA nel percorso e senza leggere il contenuto dei file.

Se cerchi il problema invece dell'aritmetica, la guida alla deriva architetturale spiega cos'è la deriva, perché accade e gli altri modi per rilevarla. Parti da lì e poi torna qui. Questa pagina dà per scontato che tu voglia già un numero e voglia sapere se crederci.

Leggere il numero

Apri un progetto qualsiasi in Archyl, clicca sull'icona del battito cardiaco nell'intestazione e premi "Compute Drift Score". In pochi secondi ottieni un numero:

  • 90-100% — Eccellente. La tua documentazione corrisponde fedelmente alla codebase.
  • 70-89% — Buono. Per lo più accurata, alcuni divari da colmare.
  • 50-69% — Discreto. Deriva significativa rilevata. È ora di aggiornare.
  • Sotto il 50% — La tua documentazione è finzione.

Quelle fasce sono il nostro giudizio su cosa valga la pena affrontare, non la misurazione di qualcosa. Il numero che sta sotto è esatto.

Come viene calcolato il numero

Ogni elemento del tuo modello viene smistato in un bucket, e il punteggio è la quota che è sopravvissuta:

score = floor( (matched + 0.5 × partial) / total × 100 )

total = matched + partial + missing_in_code + new_in_code
  • matched — il modello dice che esiste, il repository conferma.
  • missing_in_code — documentato e non trovato. Un container la cui directory è sparita, un elemento di codice il cui file è stato eliminato.
  • new_in_code — trovato nel repository, assente dal modello. Non documentato, il che è deriva nella direzione opposta e pesa contro di te esattamente allo stesso modo.

partial vale mezzo credito ed è riservato agli elementi che corrispondono ma con differenze. I controlli attuali non lo producono: ogni elemento finisce in una delle altre tre categorie, quindi in pratica il punteggio è la frazione di matched. Te lo diciamo perché una formula con un termine che non scatta mai è il genere di cosa che dovresti sentirti dire da noi anziché scoprirla.

Due dettagli che contano quando confronti due esecuzioni. Il risultato viene troncato, non arrotondato, quindi 89,9 viene riportato come 89. E gli elementi non documentati ingrandiscono il denominatore: è per questo che aggiungere tre nuovi servizi senza documentarli abbassa il tuo punteggio anche se nulla di ciò che avevi scritto è diventato falso.

Cosa viene realmente verificato

L'analisi della deriva è leggera per design: una singola richiesta ricorsiva dell'albero al tuo provider Git, nessuna IA, nessun contenuto di file recuperato. Valida la tua architettura su cinque dimensioni:

Systems — Il nome del tuo repository corrisponde al sistema documentato? Usiamo la stessa convenzione di denominazione PascalCase della pipeline di discovery IA, con corrispondenza fuzzy in modo che EkoAuthz corrisponda a un repository chiamato authz.

Containers — Le directory di primo livello nel tuo repository corrispondono ai container documentati? frontend/ corrisponde a FrontendWebApp. backend/ corrisponde a BackendApiServer. I container di infrastruttura (database, code, monitoraggio) che non hanno directory sorgente sono esclusi, perché sono documentazione valida di servizi esterni e non deriva. La sezione successiva spiega quanto costa questa esclusione.

Components — I componenti sotto ogni container sono ancora validi? Se la directory del container padre esiste, i suoi componenti sono presunti validi. Se la directory del container è scomparsa, tutti i suoi componenti vengono segnalati.

Code Elements — Questo è il controllo più preciso. Ogni elemento di codice nel tuo modello C4 ha un filePath. Verifichiamo che ogni file esista ancora nel repository. File rinominato? Classe eliminata? Modulo spostato? Il drift score lo rileva istantaneamente.

Relationships — Una relazione è valida se sia l'elemento sorgente sia quello di destinazione hanno superato la validazione. Se uno dei due endpoint ha subito deriva, la relazione viene segnalata.

Il risultato è una scomposizione per elemento che mostra esattamente cosa corrisponde, cosa manca e cosa è nuovo — non un punteggio opaco, ma un rapporto azionabile.

Cosa viene escluso dal denominatore

Un punteggio è onesto solo quanto le cose che si rifiuta di contare. Tre esclusioni, tutte deliberate:

Sistemi esterni e persone. Tutto ciò che è tipizzato come sistema esterno o come persona viene scartato prima del confronto, da entrambi i lati. Stripe, il tuo identity provider e "Cliente" appartengono a un diagramma di System Context e nessuno di essi comparirà mai nel tuo repository. Contarli come mancanti ti punirebbe per aver disegnato un diagramma corretto.

Container di infrastruttura senza directory sorgente. Un container documentato che non corrisponde ad alcuna directory viene rimosso dal conteggio dei container anziché essere contato come deriva. La tua istanza PostgreSQL, il tuo cluster Kafka e il tuo account Datadog sono container legittimi e nessuno di essi è una cartella.

Quella regola ha un costo e dovresti conoscerlo: anche una vera directory di servizio che hai eliminato viene esclusa dal conteggio dei container, perché il controllo non sa distinguere "database" da "servizio che abbiamo rimosso lo sprint scorso". I suoi componenti non sono esclusi. Continuano a risolversi come mancanti, perché il loro container padre non ha trovato corrispondenza, quindi un servizio rimosso compare eccome nel punteggio, un livello più in basso di dove ti aspetteresti di trovarlo.

Elementi di codice senza percorso file registrato. Se un elemento di codice nel tuo modello non ha un filePath, non c'è nulla da verificare, quindi viene saltato anziché tirato a indovinare. Non conta né a tuo favore né contro di te. I percorsi generati e vendorizzati (vendor/, node_modules/, dist/, target/, __pycache__/ e il resto della lista consueta) vengono filtrati dall'albero dei file prima che tutto questo venga eseguito.

Perché la leggerezza conta

Abbiamo deliberatamente scelto di non eseguire la pipeline completa di discovery IA per il rilevamento della deriva. Ecco perché:

Velocità. L'analisi IA richiede minuti per repository grandi. Il calcolo del drift score richiede secondi. Puoi eseguirlo a ogni push senza rallentare la tua pipeline.

Determinismo. L'IA può produrre risultati diversi sulla stessa codebase a seconda della temperatura del modello, delle variazioni dei prompt e dei limiti di token. L'esistenza di un percorso file è binaria — o il file c'è o non c'è. Il tuo punteggio è riproducibile.

Costo. Nessun token IA consumato. Nessun limite di frequenza API raggiunto. Eseguilo cento volte al giorno se vuoi.

Semplicità. L'algoritmo è auditabile. Verificare percorsi file, abbinare nomi di directory, validare relazioni. Nessuna scatola nera.

Cosa il punteggio non può vedere

Ognuna di queste proprietà è pagata con lo stesso scambio: il controllo legge la struttura, non il codice. Quattro conseguenze, e nessuna di esse è un bug che intendiamo nascondere.

La deriva comportamentale è invisibile. Se due servizi mantengono i loro nomi e le loro directory mentre la chiamata HTTP sincrona tra di essi diventa un messaggio su coda, il punteggio non si muove. Nulla di strutturale è cambiato. Questo è il punto cieco più grande e non esiste una soluzione economica: rilevarlo significa leggere il codice o rivedere il modello con delle persone.

Uno spostamento è identico a una cancellazione. Gli elementi di codice vengono validati tramite percorso file esatto e sensibile alle maiuscole. Sposta internal/auth/token.go in internal/identity/token.go senza toccarne una riga e l'elemento viene segnalato come mancante. È tecnicamente corretto, dato che il percorso documentato è sbagliato, e significa che un refactoring che rinomina le directory abbassa il tuo punteggio in un modo che sembra allarmante e si risolve con una modifica di una riga per elemento.

L'accuratezza a livello di componente è ereditata, non verificata. Se la directory di un container esiste, ogni componente sotto di essa è presunto valido. Il controllo non guarda mai al suo interno. Quindi un container che esiste ancora ma è stato svuotato e riscritto risulta pulito a livello di componente, e il numero è più sicuro del tuo diagramma di Livello 3 di quanto le prove giustifichino.

La corrispondenza dei nomi è generosa. Systems e container vengono abbinati per nome in tre passaggi: esatto senza distinzione tra maiuscole e minuscole, poi contenimento di sottostringa in entrambe le direzioni, poi token sovrapposti dopo aver diviso PascalCase e kebab-case. EkoAuthz corrisponde a un repository chiamato authz; BackendApiServer corrisponde a una directory chiamata backend. È questo che impedisce a differenze banali di denominazione di essere segnalate come deriva, e tende a concedere al tuo modello il beneficio del dubbio. Se vuoi una lettura rigorosa, usa la scomposizione per elemento anziché il numero in copertina.

Nel complesso, il punteggio è una buona misura di quanto il tuo modello descriva ancora lo stesso sistema, e una misura debole di quanto lo descriva correttamente. Tratta un punteggio alto come "nessuna sorpresa strutturale", non come "la documentazione è giusta".

Traccia le tendenze, non solo le istantanee

Un punteggio singolo è utile. Una tendenza è potente.

Ogni calcolo della deriva viene archiviato con la sua scomposizione completa. La tab Overview mostra un grafico a barre del tuo punteggio nel tempo. Clicca su una barra qualsiasi per caricare quel report storico e vedere esattamente cosa è cambiato.

Questo trasforma il drift scoring da audit una tantum a metrica di salute continua. Puoi vedere:

  • Il refactoring della settimana scorsa ha migliorato o peggiorato l'accuratezza della documentazione?
  • La deriva sta peggiorando nel tempo, e qualcosa che hai cambiato nel workflow l'ha rallentata?
  • Quale sprint ha introdotto più modifiche non documentate?

Imponilo nella CI

Una metrica che non imponi è una metrica che ignorerai. Ecco perché abbiamo costruito una GitHub Action.

on:
  push:
    branches: [main]

jobs:
  drift:
    runs-on: ubuntu-latest
    steps:
      - uses: archyl-com/actions/drift-score@v1
        with:
          api-key: ${{ secrets.ARCHYL_API_KEY }}
          organization-id: ${{ secrets.ARCHYL_ORG_ID }}
          project-id: 'your-project-uuid'
          threshold: '70'

Imposta threshold: '70' e l'action fallisce se l'accuratezza della documentazione della tua architettura scende sotto il 70%. Il riepilogo del job mostra una tabella formattata con la scomposizione completa — visibile direttamente nei check della tua PR.

Puoi anche pubblicare il punteggio come commento della PR:

- uses: archyl-com/actions/drift-score@v1
  id: drift
  with:
    api-key: ${{ secrets.ARCHYL_API_KEY }}
    organization-id: ${{ secrets.ARCHYL_ORG_ID }}
    project-id: 'your-project-uuid'

- uses: actions/github-script@v7
  if: github.event_name == 'pull_request'
  with:
    script: |
      github.rest.issues.createComment({
        issue_number: context.issue.number,
        owner: context.repo.owner,
        repo: context.repo.repo,
        body: '## Architecture Drift: ' +
              '${{ steps.drift.outputs.score }}%\n' +
              'Matched: ${{ steps.drift.outputs.matched-count }}' +
              ' / ${{ steps.drift.outputs.total-elements }}'
      })

Ogni sviluppatore vede l'impatto delle proprie modifiche sulla deriva prima del merge. La documentazione dell'architettura diventa un cittadino di prima classe nella tua pipeline CI — accanto ai test, al linting e alle scansioni di sicurezza.

MCP: agenti IA che conoscono la propria accuratezza

Se usi Claude Code, Cursor o qualsiasi agente IA compatibile con MCP insieme al server MCP di Archyl, il drift scoring è disponibile come tool:

compute_drift_score({ projectId: "..." })
get_drift_score({ projectId: "..." })
get_drift_history({ projectId: "..." })
get_drift_details({ scoreId: "..." })

Questo significa che un agente IA può verificare l'accuratezza della documentazione prima di iniziare a lavorare. Il tool get_agent_context fornisce già il modello C4 completo, gli ADR e le regole di conformance. Ora può anche verificare quanto sia affidabile quella documentazione.

Un agente che vede un drift score del 45% sa di dover essere prudente con il contesto architetturale che ha ricevuto. Un agente che vede 95% può fare affidamento con fiducia sulla struttura documentata. Questa è la base per agenti IA consapevoli di sé che adattano il proprio comportamento alla qualità della documentazione.

Avvisi via webhook: sapere quando avviene la deriva

Due nuovi eventi webhook ti permettono di restare informato senza controllare le dashboard:

  • drift.score_computed — Si attiva ogni volta che un drift score termina il calcolo. Invialo a un canale Slack per avere visibilità.
  • drift.score_degraded — Si attiva quando il punteggio scende di 10 punti o più rispetto al calcolo precedente. Questo è il tuo sistema di allerta precoce — l'architettura sta derivando in fretta.

Configurali nelle impostazioni webhook di Archyl. Funzionano con Slack, Microsoft Teams, Discord e qualsiasi endpoint HTTP generico.

L'API REST

Per i team che vogliono il pieno controllo programmatico:

# Avviare il calcolo
curl -X POST https://api.archyl.com/api/v1/drift/compute \
  -H "X-API-Key: $API_KEY" \
  -H "X-Organization-ID: $ORG_ID" \
  -H "Content-Type: application/json" \
  -d '{"projectId": "your-project-uuid"}'

# Ottenere l'ultimo punteggio
curl https://api.archyl.com/api/v1/drift/latest?projectId=...

# Ottenere lo storico dei punteggi
curl https://api.archyl.com/api/v1/drift/history?projectId=...&limit=20

Il calcolo è asincrono — il POST restituisce immediatamente un ID del punteggio, e tu fai polling finché status non diventa completed. La GitHub Action lo gestisce automaticamente.

Dove si colloca nel ciclo

Un punteggio è un passaggio di un ciclo: agenti e persone leggono il modello, il codice cambia, il punteggio misura il divario, la CI tiene una soglia, il team riconcilia. Senza il passaggio della misurazione il ciclo non ha feedback e la documentazione deriva senza che nessuno la contesti. Quell'argomentazione, e il resto delle ragioni per rilevare la deriva, sono nella guida.

Ciò di cui questo post è responsabile è che il passaggio della misurazione sia affidabile. Da qui la formula, le esclusioni e le quattro cose che non riesce a vedere.

Per iniziare

  1. Apri un progetto qualsiasi in Archyl
  2. Clicca sull'icona del battito cardiaco nella barra degli strumenti dell'intestazione
  3. Clicca su "Compute Drift Score"
  4. Configura la GitHub Action per un monitoraggio continuo
  5. Configura un webhook Slack per gli avvisi drift.score_degraded

La documentazione della tua architettura rispecchia la realtà oppure no. Ora hai un numero che ti dice quale delle due, e abbastanza della sua aritmetica per discuterne.


Il resto del cluster: rilevamento della deriva architetturale per il problema e gli altri metodi di rilevamento, documentazione dell'architettura vivente per le pratiche che impediscono a un punteggio di scivolare di nuovo indietro. Definizioni: deriva architetturale. Pagina di prodotto: drift detection.