@antoneeo/agentic-sdlc-skill 1.5.0 → 1.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,30 +1,52 @@
1
1
  # Changelog - Agentic SDLC Skill
2
2
 
3
- Tutte le modifiche significative a questa skill saranno documentate in questo file.
4
-
5
- ## [1.5.0] - 2026-06-13
6
- ### Added
7
- - Introdotta la Regola Zero di triage (`L1`, `L2`, `L3`, `Spike`) per rendere il processo proporzionale al rischio.
8
- - Aggiunta simbiosi esplicita con devPNT: in Hybrid la `M-VISION` guida la milestone, il Master Plan resta roadmap strategica e l'Action Plan governa l'esecuzione tattica.
9
- - Aggiunti support file dentro la skill runtime: `templates.md`, `ENFORCEMENT.md`, `scripts/sdlc_check.py`.
10
- - `agentic-sdlc-install-skill` ora installa la skill nativa anche in `~/.gemini/skills/agentic-sdlc/`.
11
- - Aggiunto validatore meccanico opzionale per frontmatter ANALYSIS, Vision state, indice feature e audit stale.
12
-
13
- ### Changed
14
- - Il nome pubblico resta `agentic-sdlc`; la proposta v2 e' stata integrata come evoluzione, non come skill parallela.
15
- - Aggiornati `agentic-sdlc-init`, template, protocolli generati, README e metadata.
16
- - La modalita Standalone resta completa; devPNT e' un livello di governance superiore, non un prerequisito.
17
-
18
- ## [1.4.0] - 2026-06-07
19
- ### Added
20
- - Introdotta la governance della **Vision** con nuova struttura `ai_docs/vision/` (`project_vision.md`, `roadmap.md`, `principles.md`, `features/`).
21
- - Aggiunto il **Vision Gate** nel workflow operativo: ogni feature significativa deve essere verificata rispetto a obiettivi, non-obiettivi, benefici attesi e segnali di successo prima dell'analisi tecnica.
22
- - Aggiunti template Vision in `references/` e sezione `Allineamento alla Vision` nel template di analisi.
23
- - `agentic-sdlc-init` ora crea i documenti Vision boilerplate nei nuovi progetti.
24
-
25
- ## [1.3.1] - 2026-05-14
26
- ### Fixed
27
- - Correzione documentazione (README + CHANGELOG) della sintassi per invocare il bin `agentic-sdlc-install-skill`. La forma `npx @antoneeo/agentic-sdlc-skill agentic-sdlc-install-skill` documentata in 1.3.0 **non funziona** perché npx non riesce a disambiguare il bin quando il pacchetto ne espone più di uno (errore: `could not determine executable to run`). Sintassi corretta: lanciare `agentic-sdlc-install-skill` direttamente dopo `npm install -g`, oppure usare `npx -p @antoneeo/agentic-sdlc-skill agentic-sdlc-install-skill` con `-p` esplicito.
3
+ Tutte le modifiche significative a questa skill saranno documentate in questo file.
4
+
5
+ ## [1.6.0] - 2026-06-15
6
+ ### Added
7
+ - **Manifest generato dei documenti canonici** (`ai_docs/INDEX.md`): `sdlc_check.py index` ora produce, oltre a `features_history.md`, un indice completo di tutti i doc in `vision/`, `reference/`, `architecture/`, `functional/`, `strategic/`, con descrizione e stato letti dall'header. Si rigenera, quindi non drifta.
8
+ - **Lifecycle dei documenti canonici**: convenzione header `status: CURRENT|SUPERSEDED|DRAFT|DEPRECATED` + `supersedes:`. `validate` avvisa se `status` manca/è invalido o se un doc superseduto è ancora `CURRENT`. Stop ai grep che riportano a guide obsolete.
9
+ - **Modello a due indici** documentato nella sezione "Documenti ai_docs" di `SKILL.md`: `README.md` curato (must-read, a mano) vs `INDEX.md` generato (completo, meccanico) — ruoli separati, prima confusi in un unico README che driftava.
10
+
11
+ ### Changed
12
+ - §1 Audit: leggere `README.md` + `INDEX.md` all'avvio per sapere cosa esiste prima di esplorare il codice.
13
+ - §3 Analisi: cercare con glob/grep un'ANALYSIS esistente prima di crearne una nuova (anti-duplicazione).
14
+ - §5 Chiusura: gate "Indici allineati" — rigenerare `INDEX.md`, aggiornare il `README.md` curato per i must-read, marcare lo `status`; doc canonico non indicizzato o senza `status` = chiusura sporca.
15
+ - `templates.md`: aggiunto il template dell'header dei documenti canonici.
16
+
17
+ ### Fixed
18
+ - `sdlc_check.py` legge ora i file con `utf-8-sig`: un BOM iniziale (file autorati su Windows) non impedisce più il riconoscimento del frontmatter `---`.
19
+ - L'estrattore dell'header riconosce sia il frontmatter `status:` sia la riga in corpo `**Status:**`/`Stato:`, e gli stati di tutte le convenzioni in uso (canonici `CURRENT/SUPERSEDED/DRAFT/DEPRECATED`, vision `DRAFT/APPROVED`, ADR `Accepted/Proposed/Rejected`) — niente più falsi avvisi "status non riconosciuto" su `APPROVED`/`Accepted`.
20
+ - La descrizione del manifest salta righe di metadati (`Date`, `Created`, `Task ref`, ...) e i commenti HTML, così non finiscono come descrizione del documento.
21
+ - `index` non genera più un `INDEX.md` vuoto su progetti senza documenti canonici (solo `solutions/`+`audit/`).
22
+
23
+ ### Migrazione (da 1.5.x)
24
+ - Al primo `sdlc_check.py check`/`validate` dopo l'upgrade, un progetto con documenti canonici darà **un errore** `ai_docs/INDEX.md mancante`: è atteso — esegui **una volta** `sdlc_check.py index` per generarlo. Da lì in poi resta allineato.
25
+ - I documenti canonici preesistenti senza `status:` produrranno **avvisi** (non errori): aggiungi l'header `description:`/`status:` per silenziarli. I nuovi progetti nascono già compatibili (template aggiornati).
26
+
27
+ ## [1.5.0] - 2026-06-13
28
+ ### Added
29
+ - Introdotta la Regola Zero di triage (`L1`, `L2`, `L3`, `Spike`) per rendere il processo proporzionale al rischio.
30
+ - Aggiunta simbiosi esplicita con devPNT: in Hybrid la `M-VISION` guida la milestone, il Master Plan resta roadmap strategica e l'Action Plan governa l'esecuzione tattica.
31
+ - Aggiunti support file dentro la skill runtime: `templates.md`, `ENFORCEMENT.md`, `scripts/sdlc_check.py`.
32
+ - `agentic-sdlc-install-skill` ora installa la skill nativa anche in `~/.gemini/skills/agentic-sdlc/`.
33
+ - Aggiunto validatore meccanico opzionale per frontmatter ANALYSIS, Vision state, indice feature e audit stale.
34
+
35
+ ### Changed
36
+ - Il nome pubblico resta `agentic-sdlc`; la proposta v2 e' stata integrata come evoluzione, non come skill parallela.
37
+ - Aggiornati `agentic-sdlc-init`, template, protocolli generati, README e metadata.
38
+ - La modalita Standalone resta completa; devPNT e' un livello di governance superiore, non un prerequisito.
39
+
40
+ ## [1.4.0] - 2026-06-07
41
+ ### Added
42
+ - Introdotta la governance della **Vision** con nuova struttura `ai_docs/vision/` (`project_vision.md`, `roadmap.md`, `principles.md`, `features/`).
43
+ - Aggiunto il **Vision Gate** nel workflow operativo: ogni feature significativa deve essere verificata rispetto a obiettivi, non-obiettivi, benefici attesi e segnali di successo prima dell'analisi tecnica.
44
+ - Aggiunti template Vision in `references/` e sezione `Allineamento alla Vision` nel template di analisi.
45
+ - `agentic-sdlc-init` ora crea i documenti Vision boilerplate nei nuovi progetti.
46
+
47
+ ## [1.3.1] - 2026-05-14
48
+ ### Fixed
49
+ - Correzione documentazione (README + CHANGELOG) della sintassi per invocare il bin `agentic-sdlc-install-skill`. La forma `npx @antoneeo/agentic-sdlc-skill agentic-sdlc-install-skill` documentata in 1.3.0 **non funziona** perché npx non riesce a disambiguare il bin quando il pacchetto ne espone più di uno (errore: `could not determine executable to run`). Sintassi corretta: lanciare `agentic-sdlc-install-skill` direttamente dopo `npm install -g`, oppure usare `npx -p @antoneeo/agentic-sdlc-skill agentic-sdlc-install-skill` con `-p` esplicito.
28
50
  - Nessuna modifica al codice della skill: il bin di 1.3.0 funziona correttamente, era solo la doc a indicare la sintassi sbagliata.
29
51
 
30
52
  ## [1.3.0] - 2026-05-14
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agentic-sdlc-skill",
3
- "version": "1.5.0",
4
- "description": "Protocollo SDLC Documentation-First con triage, Vision governance e integrazione opzionale devPNT.",
3
+ "version": "1.6.0",
4
+ "description": "Protocollo SDLC Documentation-First con triage, Vision governance e integrazione opzionale devPNT.",
5
5
  "author": "Antonio Pinto (https://github.com/Antoneeo)"
6
6
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@antoneeo/agentic-sdlc-skill",
3
- "version": "1.5.0",
4
- "description": "Protocollo SDLC Documentation-First per Claude Code, Gemini CLI e Codex con triage, Vision governance, support file installati e integrazione opzionale devPNT.",
3
+ "version": "1.6.0",
4
+ "description": "Protocollo SDLC Documentation-First per Claude Code, Gemini CLI e Codex con triage, Vision governance, support file installati e integrazione opzionale devPNT.",
5
5
  "keywords": [
6
6
  "claude-code",
7
7
  "claude-skill",
@@ -25,10 +25,10 @@
25
25
  "preuninstall": "node scripts/preuninstall.js"
26
26
  },
27
27
  "files": [
28
- "skills/agentic-sdlc-skill/SKILL.md",
29
- "skills/agentic-sdlc-skill/templates.md",
30
- "skills/agentic-sdlc-skill/ENFORCEMENT.md",
31
- "skills/agentic-sdlc-skill/scripts/sdlc_check.py",
28
+ "skills/agentic-sdlc-skill/SKILL.md",
29
+ "skills/agentic-sdlc-skill/templates.md",
30
+ "skills/agentic-sdlc-skill/ENFORCEMENT.md",
31
+ "skills/agentic-sdlc-skill/scripts/sdlc_check.py",
32
32
  "gemini-extension.json",
33
33
  "references",
34
34
  "README.md",
@@ -1,3 +1,7 @@
1
+ ---
2
+ description: Stack, struttura directory e pattern architetturali del progetto.
3
+ status: CURRENT
4
+ ---
1
5
  # Architettura del Progetto
2
6
 
3
7
  ## Stack Tecnologico
@@ -6,13 +10,13 @@
6
10
  - **Database:** [es. PostgreSQL]
7
11
  - **Strumenti di Test:** [es. Jest, Vitest]
8
12
 
9
- ## Struttura delle Directory
10
- - `src/`: Codice sorgente.
11
- - `ai_docs/vision/`: Vision di progetto, roadmap, principi e mini-vision delle feature.
12
- - `ai_docs/strategic/`: Architettura, feature esistenti e storico feature.
13
- - `ai_docs/solutions/`: Analisi e piani delle singole feature.
14
- - `ai_docs/audit/`: Piano di audit e handoff di sessione.
15
- - `tests/`: Test automatici.
13
+ ## Struttura delle Directory
14
+ - `src/`: Codice sorgente.
15
+ - `ai_docs/vision/`: Vision di progetto, roadmap, principi e mini-vision delle feature.
16
+ - `ai_docs/strategic/`: Architettura, feature esistenti e storico feature.
17
+ - `ai_docs/solutions/`: Analisi e piani delle singole feature.
18
+ - `ai_docs/audit/`: Piano di audit e handoff di sessione.
19
+ - `tests/`: Test automatici.
16
20
 
17
21
  ## Pattern Architetturali
18
22
  - [es. MVC, Clean Architecture, Layered Architecture]
@@ -1,3 +1,7 @@
1
+ ---
2
+ description: Catalogo sintetico delle funzionalità esistenti del progetto.
3
+ status: CURRENT
4
+ ---
1
5
  # Funzionalità Esistenti
2
6
 
3
7
  - [ID] **Nome Feature**: Descrizione sintetica della funzionalità.
@@ -83,6 +83,7 @@ Regole Hybrid:
83
83
  ### 1. Audit e Allineamento
84
84
 
85
85
  - Leggi `ai_docs/audit/handoff.md` se esiste; se ha Data/Branch non coerenti, trattalo come storico.
86
+ - Leggi `ai_docs/README.md` (must-read curati) e `ai_docs/INDEX.md` (manifest generato di tutti i doc canonici) per sapere cosa esiste prima di esplorare il codice. `solutions/` e `audit/` non sono indicizzate per file: cercale con glob/grep.
86
87
  - Se `ai_docs/` manca o e' incompleta, crea struttura e documenti minimi analizzando il progetto a lotti.
87
88
  - In Standalone usa `ai_docs/audit/audit_plan.md` per mappatura e stato.
88
89
  - In Hybrid preferisci la mappatura devPNT/KL quando disponibile; non duplicare la governance dei piani.
@@ -104,6 +105,7 @@ Hybrid:
104
105
  ### 3. Analisi della Richiesta
105
106
 
106
107
  Standalone L3:
108
+ - Prima di creare un nuovo `ANALYSIS_[feature].md`, cerca con glob/grep in `ai_docs/solutions/` un'analisi gia' esistente sullo stesso tema: se c'e', aggiornala invece di duplicarla.
107
109
  - Crea o aggiorna `ai_docs/solutions/ANALYSIS_[feature].md`.
108
110
  - Sezioni minime: Obiettivo, Vision della Feature o Allineamento alla Vision, Impatto, Sicurezza e Threat Model, Piano d'Azione, Strategia di Test, Diario/Stato Corrente.
109
111
  - Per feature che attraversano piu milestone o piu analisi, crea anche `ai_docs/vision/features/VISION_[feature].md`.
@@ -127,10 +129,39 @@ Hybrid L3:
127
129
  - Esegui test/lint/smoke check pertinenti.
128
130
  - Verifica allineamento con Vision locale o M-VISION devPNT.
129
131
  - Aggiorna solo i documenti effettivamente impattati.
132
+ - **Indici allineati (Poka-Yoke)**: se hai creato, spostato o rimosso documenti canonici (`vision/`, `reference/`, `architecture/`, `functional/`, `strategic/`):
133
+ - rigenera il manifest con `sdlc_check.py index` (scrive `ai_docs/INDEX.md`) — non scriverlo a mano;
134
+ - se il documento e' must-read, aggiungi/aggiorna la sua riga nel `README.md` curato;
135
+ - se il documento ne sostituisce un altro, marca il vecchio `status: SUPERSEDED` e dichiara `supersedes:` nel nuovo;
136
+ - se hai creato una nuova sottodirectory canonica, dalle uno scopo nel `README.md`.
137
+ Doc canonico non indicizzato o senza `status` = chiusura sporca (`sdlc_check.py check` fallisce/avvisa). Non dichiarare DONE finche' non e' pulito. Dettagli: sezione "Documenti ai_docs".
130
138
  - In Hybrid proponi ADR/KL quando ci sono decisioni architetturali.
131
139
  - In Standalone, se il progetto adotta `sdlc_check.py`, esegui `python <skill_dir>/scripts/sdlc_check.py check --root <project_root>` o la copia locale equivalente.
132
140
  - I documenti aggiornati devono viaggiare nello stesso commit/PR del codice che descrivono.
133
141
 
142
+ ## Documenti ai_docs: due indici + lifecycle
143
+
144
+ I documenti in `ai_docs/` hanno due ruoli serviti da due indici distinti — non confonderli:
145
+
146
+ - **`ai_docs/README.md` (curato, a mano):** la priorita' di lettura. Poche righe, solo must-read canonici, cambia di rado. Giudizio umano su "cosa leggere prima".
147
+ - **`ai_docs/INDEX.md` (generato, `sdlc_check.py index`):** il manifest completo di ogni doc canonico (`vision/`, `reference/`, `architecture/`, `functional/`, `strategic/`) con descrizione e stato. Mai a mano: si rigenera, cosi' non drifta.
148
+ - **`strategic/features_history.md` (generato):** lo storico delle ANALYSIS, dai loro frontmatter.
149
+ - `audit/` e `solutions/` sono discovery-by-grep: non entrano nel manifest.
150
+
151
+ **Header dei documenti canonici (lifecycle).** Ogni doc in quelle directory dovrebbe aprirsi con un frontmatter minimo, cosi' il manifest si genera da solo e un agente sa subito se fidarsi:
152
+
153
+ ```markdown
154
+ ---
155
+ description: Una riga — cos'e' e quando leggerlo.
156
+ status: CURRENT # CURRENT | SUPERSEDED | DRAFT | DEPRECATED
157
+ supersedes: vecchio_doc.md # solo se rimpiazza un altro doc
158
+ ---
159
+ ```
160
+
161
+ In fallback (nessun frontmatter) il manifest deduce il titolo dal primo `# H1` e la descrizione dalla prima riga di prosa o blockquote; ma senza `status` un doc non porta segnale di freschezza. `status` mancante, valore non valido, o doc superseduto ancora `CURRENT` = avviso in `validate`. Un doc `SUPERSEDED` resta sul filesystem come storico, ma il suo stato lo dichiara morto: niente piu' grep che riportano a guide obsolete.
162
+
163
+ Senza Python/hook (ambienti minimali) gli indici e gli header restano una disciplina di prosa: aggiorna `README.md` e marca lo `status` a mano; il validatore e' solo il backstop dove e' adottato.
164
+
134
165
  ## Enforcement Meccanico
135
166
 
136
167
  Il prompt non e' enforcement. Quando il progetto richiede garanzie ripetibili:
@@ -5,7 +5,8 @@
5
5
  Comandi:
6
6
  check gate unico di chiusura: validate + stale in un solo comando (exit 1 se uno dei due fallisce)
7
7
  validate verifica la coerenza strutturale di ai_docs/ (exit 1 se errori)
8
- index rigenera ai_docs/strategic/features_history.md dai frontmatter delle ANALYSIS_*.md
8
+ index rigenera gli indici generati: strategic/features_history.md (dai frontmatter
9
+ delle ANALYSIS_*.md) e ai_docs/INDEX.md (manifest dei documenti canonici)
9
10
  stale elenca le aree modificate dopo l'ultima analisi registrata in audit_plan.md (exit 1 se presenti)
10
11
  mark registra percorsi come ANALYZED con riferimento corrente (hash git, altrimenti timestamp UTC)
11
12
  gate hook PreToolUse: blocca scritture su percorsi protetti senza ANALYSIS IN_PROGRESS (exit 2)
@@ -28,6 +29,16 @@ SKIP_DIRS = {".git", ".hg", ".svn", "node_modules", "__pycache__", ".venv", "ven
28
29
  "dist", "build", ".idea", ".vs", "ai_docs"}
29
30
  INDEX_HEADER = ("<!-- GENERATO da sdlc_check.py index - non modificare a mano. "
30
31
  "Fonte di verita': frontmatter dei file ANALYSIS_*.md -->")
32
+ MANIFEST_HEADER = ("<!-- GENERATO da sdlc_check.py index - non modificare a mano. "
33
+ "Fonte di verita': gli header dei documenti canonici in ai_docs/. -->")
34
+ # Directory i cui .md sono documenti canonici durevoli: vengono manifestati in INDEX.md.
35
+ # audit/ e solutions/ restano discovery-by-grep (sessione / process artifact), non manifestati.
36
+ MANIFEST_DIRS = ("vision", "reference", "architecture", "functional", "strategic")
37
+ # Stati riconosciuti: doc canonici (CURRENT/SUPERSEDED/...), vision (DRAFT/APPROVED),
38
+ # ADR (Accepted/Proposed/Rejected). Unione, per non dare falsi avvisi su convenzioni gia' in uso.
39
+ CANONICAL_STATES = {"CURRENT", "SUPERSEDED", "DRAFT", "DEPRECATED",
40
+ "APPROVED", "ACCEPTED", "PROPOSED", "REJECTED"}
41
+ GENERATED_DOCS = {"features_history.md", "INDEX.md"} # generati: mai entrate del manifest
31
42
  MTIME_GRACE = timedelta(seconds=2)
32
43
 
33
44
  try:
@@ -52,7 +63,9 @@ def find_project_root(start=None):
52
63
 
53
64
 
54
65
  def read_text(path):
55
- return path.read_text(encoding="utf-8", errors="replace")
66
+ # utf-8-sig: scarta un eventuale BOM iniziale (file autorati su Windows) cosi'
67
+ # il frontmatter '---' a riga 0 resta riconoscibile; legge utf-8 normale altrimenti.
68
+ return path.read_text(encoding="utf-8-sig", errors="replace")
56
69
 
57
70
 
58
71
  def parse_iso(value):
@@ -181,11 +194,122 @@ def build_index(root):
181
194
  return "\n".join(lines) + "\n"
182
195
 
183
196
 
197
+ # riga "Status:"/"Stato:" nel corpo (con o senza ** **), prefisso che precede la descrizione
198
+ _STATUS_LINE = re.compile(r"^\**\s*(?:status|stato)\s*\**\s*:\s*\**\s*([A-Za-z][\w-]*)", re.I)
199
+ # righe puramente di metadati da saltare quando si sceglie la descrizione di fallback
200
+ _META_LINE = re.compile(r"^\**\s*(date|data|task ref|version|versione|owner|autore|branch|agente|created|creato|updated|aggiornato)\b", re.I)
201
+
202
+
203
+ def extract_doc_meta(path):
204
+ """(title, description, status, supersedes) di un doc canonico.
205
+
206
+ Riconosce DUE convenzioni di header: il frontmatter YAML-lite
207
+ (description/status/supersedes/title) e la riga in corpo `**Status:** X`
208
+ (usata da ADR e doc legacy). In fallback deduce il titolo dal primo '# H1'
209
+ e la descrizione dalla prima riga di prosa, saltando le righe di metadati.
210
+ """
211
+ text = read_text(path)
212
+ lines = text.splitlines()
213
+ meta = load_frontmatter(lines)
214
+ body = lines
215
+ if lines and lines[0].strip() == "---":
216
+ for i in range(1, min(len(lines), 60)):
217
+ if lines[i].strip() == "---":
218
+ body = lines[i + 1:]
219
+ break
220
+
221
+ title = meta.get("title", "")
222
+ if not title:
223
+ for line in body:
224
+ m = re.match(r"^#\s+(.*)$", line)
225
+ if m:
226
+ title = m.group(1).strip()
227
+ break
228
+ title = title or path.stem
229
+
230
+ status = meta.get("status", "").upper()
231
+ if not status:
232
+ for line in body[:25]:
233
+ m = _STATUS_LINE.match(line.strip())
234
+ if m:
235
+ status = m.group(1).upper()
236
+ break
237
+
238
+ desc = meta.get("description", "")
239
+ if not desc:
240
+ for line in body:
241
+ s = line.strip()
242
+ if not s or s.startswith("#") or s.startswith("<!--") or _META_LINE.match(s):
243
+ continue
244
+ if s.startswith(">"):
245
+ s = s.lstrip(">").strip()
246
+ m = _STATUS_LINE.match(s)
247
+ if m:
248
+ # "Status: X — descrizione": tieni la parte dopo lo status; se vuota, salta
249
+ rest = s[m.end():].strip(" *—–-:.")
250
+ if not rest:
251
+ continue
252
+ s = rest
253
+ if s:
254
+ desc = s
255
+ break
256
+ desc = re.sub(r"\s+", " ", desc).strip()
257
+ if len(desc) > 160:
258
+ desc = desc[:157].rstrip() + "..."
259
+ return title, desc, status, meta.get("supersedes", "").strip()
260
+
261
+
262
+ def list_canonical_docs(root):
263
+ """[(rel_to_ai_docs, path, (title, desc, status, supersedes))] per i doc canonici."""
264
+ ai = root / "ai_docs"
265
+ out = []
266
+ for d in MANIFEST_DIRS:
267
+ base = ai / d
268
+ if not base.is_dir():
269
+ continue
270
+ for p in sorted(base.rglob("*.md")):
271
+ if p.name in GENERATED_DOCS or p.name == "README.md":
272
+ continue
273
+ out.append((p.relative_to(ai).as_posix(), p, extract_doc_meta(p)))
274
+ return out
275
+
276
+
277
+ def build_manifest(root):
278
+ docs = list_canonical_docs(root)
279
+ lines = [MANIFEST_HEADER,
280
+ "# Indice documenti `ai_docs/` (generato)",
281
+ "",
282
+ "Manifest completo dei documenti canonici. Per la priorita' di lettura (must-read)",
283
+ "vedi il `README.md` curato a mano. Lo storico delle ANALYSIS e' in",
284
+ "`strategic/features_history.md`. `audit/` e `solutions/` sono discovery-by-grep,",
285
+ "non manifestate qui."]
286
+ by_dir = {}
287
+ for rel, _, meta in docs:
288
+ by_dir.setdefault(rel.split("/", 1)[0], []).append((rel, meta))
289
+ for top in MANIFEST_DIRS:
290
+ rows = by_dir.get(top)
291
+ if not rows:
292
+ continue
293
+ lines += ["", f"## {top}/", "",
294
+ "| Documento | Stato | Descrizione |", "|---|---|---|"]
295
+ for rel, (title, desc, status, _sup) in rows:
296
+ d = (desc or title).replace("|", "\\|")
297
+ lines.append(f"| `{rel}` | {status or '-'} | {d} |")
298
+ return "\n".join(lines).rstrip() + "\n"
299
+
300
+
184
301
  def cmd_index(root):
185
- target = root / "ai_docs" / "strategic" / "features_history.md"
186
- target.parent.mkdir(parents=True, exist_ok=True)
187
- target.write_text(build_index(root), encoding="utf-8")
188
- print(f"[ok] indice rigenerato: {target}")
302
+ hist = root / "ai_docs" / "strategic" / "features_history.md"
303
+ hist.parent.mkdir(parents=True, exist_ok=True)
304
+ hist.write_text(build_index(root), encoding="utf-8")
305
+ print(f"[ok] indice ANALYSIS rigenerato: {hist}")
306
+ # INDEX.md solo se esistono doc canonici: niente manifest vuoto su progetti minimali
307
+ if list_canonical_docs(root):
308
+ manifest = root / "ai_docs" / "INDEX.md"
309
+ manifest.write_text(build_manifest(root), encoding="utf-8")
310
+ print(f"[ok] manifest documenti rigenerato: {manifest}")
311
+ else:
312
+ print("[info] nessun documento canonico: INDEX.md non generato")
189
313
  return 0
190
314
 
191
315
 
@@ -250,6 +374,29 @@ def cmd_validate(root):
250
374
  elif norm_text(read_text(hist)) != norm_text(build_index(root)):
251
375
  errors.append("strategic/features_history.md non allineato alle ANALYSIS: esegui 'sdlc_check.py index'")
252
376
 
377
+ # Manifest dei documenti canonici allineato (Poka-Yoke: file non indicizzato = chiusura sporca)
378
+ docs = list_canonical_docs(root)
379
+ manifest = ai / "INDEX.md"
380
+ if docs:
381
+ if not manifest.is_file():
382
+ errors.append("ai_docs/INDEX.md mancante: esegui 'sdlc_check.py index'")
383
+ elif norm_text(read_text(manifest)) != norm_text(build_manifest(root)):
384
+ errors.append("ai_docs/INDEX.md non allineato ai documenti canonici: esegui 'sdlc_check.py index'")
385
+
386
+ # Lifecycle dei documenti canonici: status dichiarato + coerenza supersedes
387
+ canon_status = {rel: meta[2] for rel, _, meta in docs}
388
+ for rel, _, (title, desc, status, supersedes) in docs:
389
+ if not status:
390
+ warnings.append(f"{rel}: manca 'status:' nell'header (CURRENT/SUPERSEDED/DRAFT/DEPRECATED)")
391
+ elif status not in CANONICAL_STATES:
392
+ warnings.append(f"{rel}: status '{status}' non riconosciuto ({'/'.join(sorted(CANONICAL_STATES))})")
393
+ if supersedes:
394
+ base = os.path.basename(supersedes)
395
+ for other, ost in canon_status.items():
396
+ if (other == supersedes or other.endswith("/" + supersedes)
397
+ or os.path.basename(other) == base) and ost == "CURRENT":
398
+ warnings.append(f"{other}: ancora CURRENT ma superseduto da {rel} (impostare status: SUPERSEDED)")
399
+
253
400
  # Handoff: intestazione e freschezza
254
401
  hand = ai / "audit" / "handoff.md"
255
402
  if hand.is_file():
@@ -443,7 +590,7 @@ def main(argv=None):
443
590
  sub = ap.add_subparsers(dest="cmd", required=True)
444
591
  sub.add_parser("check", parents=[common], help="gate di chiusura: validate + stale in un solo comando")
445
592
  sub.add_parser("validate", parents=[common], help="verifica coerenza di ai_docs/")
446
- sub.add_parser("index", parents=[common], help="rigenera features_history.md")
593
+ sub.add_parser("index", parents=[common], help="rigenera features_history.md + ai_docs/INDEX.md")
447
594
  sub.add_parser("stale", parents=[common], help="aree modificate dopo l'ultima analisi")
448
595
  mp = sub.add_parser("mark", parents=[common], help="registra percorsi come ANALYZED")
449
596
  mp.add_argument("paths", nargs="+", help="percorsi relativi alla radice del progetto")
@@ -5,6 +5,21 @@ Regole generali:
5
5
  - La conformità al template non è l'obiettivo: se una sezione non ha contenuto reale, scrivi esplicitamente perché non si applica. Mai testo riempitivo.
6
6
  - Date sempre assolute, in UTC dove indicato.
7
7
 
8
+ ## Header dei documenti canonici (vision/ reference/ architecture/ functional/ strategic/)
9
+
10
+ Ogni documento canonico durevole apre con questo frontmatter: alimenta il manifest generato `ai_docs/INDEX.md` e dà a un agente il segnale di freschezza prima che si fidi del contenuto.
11
+
12
+ ```markdown
13
+ ---
14
+ description: Una riga — cos'è il documento e quando leggerlo.
15
+ status: CURRENT # CURRENT | SUPERSEDED | DRAFT | DEPRECATED
16
+ supersedes: vecchio_doc.md # solo se rimpiazza un altro doc canonico
17
+ ---
18
+ # Titolo del Documento
19
+ ```
20
+
21
+ Quando un doc ne sostituisce un altro: il nuovo dichiara `supersedes:`, il vecchio passa a `status: SUPERSEDED` (resta come storico, non si cancella). `sdlc_check.py validate` avvisa se `status` manca o se un doc superseduto è ancora `CURRENT`.
22
+
8
23
  ## ai_docs/vision/project_vision.md
9
24
 
10
25
  ```markdown
@@ -152,9 +167,13 @@ Agente: Claude
152
167
 
153
168
  ## ai_docs/strategic/architecture.md e existing_features.md
154
169
 
155
- Invariati rispetto alla v1:
170
+ Doc canonici: aprono con l'header (`description:`/`status:`) cosi' entrano puliti nel manifest `INDEX.md`.
156
171
 
157
172
  ```markdown
173
+ ---
174
+ description: Stack, struttura directory e pattern architetturali del progetto.
175
+ status: CURRENT
176
+ ---
158
177
  # Architettura del Progetto
159
178
  ## Stack Tecnologico
160
179
  ## Struttura delle Directory
@@ -162,8 +181,12 @@ Invariati rispetto alla v1:
162
181
  ```
163
182
 
164
183
  ```markdown
184
+ ---
185
+ description: Catalogo sintetico delle funzionalità esistenti del progetto.
186
+ status: CURRENT
187
+ ---
165
188
  # Funzionalità Esistenti
166
189
  - [ID] **Nome Feature**: Descrizione
167
190
  ```
168
191
 
169
- `ai_docs/strategic/features_history.md` NON ha template: è generato da `sdlc_check.py index`.
192
+ `ai_docs/strategic/features_history.md` e `ai_docs/INDEX.md` NON hanno template: sono generati da `sdlc_check.py index`.