diff --git a/docs/artifacts/CORE_ARTIFACT_SCHEMAS.es.md b/docs/artifacts/CORE_ARTIFACT_SCHEMAS.es.md new file mode 100644 index 00000000..212eb420 --- /dev/null +++ b/docs/artifacts/CORE_ARTIFACT_SCHEMAS.es.md @@ -0,0 +1,92 @@ +# Esquemas canónicos de artefacto que publica Evolith Core + +> **Navegación bilingüe:** [English](./CORE_ARTIFACT_SCHEMAS.md) · Español (este documento) + +`PhaseArtifactCatalog` le dice a un tenant que un `prd` es **obligatorio** en discovery. Hasta ahora +no le decía a nadie **qué debe contener un PRD**, porque el catálogo lleva solo `ArtifactKind`, +`Label` y `Required` — ninguna referencia a la forma canónica. Este documento es ese enlace que +faltaba (`GAP-020`). + +## Qué es esto, y qué no es + +**Es** un puntero a la forma que el Core publica para un artefacto, para que quien vaya a rellenar +uno pueda ver los campos canónicos. + +**No es** una restricción sobre lo que un tenant puede registrar. Según +[`T-056`](../adrs/T-056-three-layer-separation.es.md), la validación de contenido es configuración +del tenant y no código del motor: los campos propios que un tenant añade con `ArtifactFieldSchema` +siguen siendo suyos, y los tipos de evidencia que declara (`ci-result`, `regression`, +`release-notes`) no salen de ninguna lista cerrada de aguas arriba. + +## Por qué el enlace es una URL y no una ruta + +Las definiciones de gate del Core llevan `requiredArtifacts[].schemaRef` como ruta relativa al +repositorio. Esas rutas estaban **rotas** hasta `evolith_arch32#378`: escritas +`../schema/prd.schema.json`, resolvían desde el directorio de gates a +`reference/governance/sdlc/schema/`, un directorio que no existe, mientras los ficheros están en +`src/rulesets/schema/`. Nadie podía dereferenciarlas, aguas arriba incluido. + +Ya son correctas, y aun así este documento enlaza por **`$id`** y no por ruta — a propósito. Una ruta +es un hecho sobre dónde está un fichero en un repositorio en un momento; el `$id` es la identidad +publicada del esquema y sobrevive a que el fichero se mueva. Un satélite que enlazara por ruta se +rompería la próxima vez que el Core reorganice su árbol. + +## Los artefactos que tienen esquema canónico + +**Catorce** de los veinticuatro artefactos obligatorios del Core publican uno. Se da la clase del Tracker +porque los nombres **no** coinciden mecánicamente — la correspondencia es una decisión, escrita aquí +en vez de derivada de un slug. + +| Fase | Clase en el Tracker | Artefacto del Core | Esquema canónico | +|---|---|---|---| +| discovery | `prd` | PRD | [`prd.schema.json`](https://evolith.dev/schema/prd.schema.json) | +| discovery | *(sin clase en el catálogo)* | Discovery Canvas | [`discovery-canvas.schema.json`](https://evolith.dev/schema/discovery-canvas.schema.json) | +| discovery | `technical-feasibility-canvas` | Technical Feasibility Canvas | [`technical-feasibility.schema.json`](https://evolith.dev/schema/technical-feasibility.schema.json) | +| discovery | *(sin clase en el catálogo)* | Ballpark Estimation | [`ballpark-estimation.schema.json`](https://evolith.dev/schema/ballpark-estimation.schema.json) | +| discovery | `build-versus-compose-analysis` | Build-versus-Compose Analysis | [`build-vs-compose.schema.json`](https://evolith.dev/schema/build-vs-compose.schema.json) | +| design | `bounded-context-map` | Bounded Context Map | [`bounded-context-map.schema.json`](https://evolith.dev/schema/bounded-context-map.schema.json) | +| construction | `definition-of-done-checklist` | Definition of Done Checklist | [`definition-of-done-checklist.schema.json`](https://evolith.dev/schema/definition-of-done-checklist.schema.json) | +| qa | `test-summary-report` | Test Summary Report | [`test-summary-report.schema.json`](https://evolith.dev/schema/test-summary-report.schema.json) | +| qa | `security-scan-result` | Security Scan **Report** | [`security-scan-report.schema.json`](https://evolith.dev/schema/security-scan-report.schema.json) | +| qa | *(sin clase en el catálogo)* | Integration Evidence | [`integration-evidence.schema.json`](https://evolith.dev/schema/integration-evidence.schema.json) | +| release | `release-notes` | Release Notes | [`release-notes.schema.json`](https://evolith.dev/schema/release-notes.schema.json) | +| release | `observability-readiness` | Observability **Validation** | [`observability-validation.schema.json`](https://evolith.dev/schema/observability-validation.schema.json) | +| release | `rollback-plan` | Rollback **Procedure** | [`rollback-rehearsal.schema.json`](https://evolith.dev/schema/rollback-rehearsal.schema.json) | +| release | *(sin clase en el catálogo)* | On-Call Handoff | [`on-call-handoff.schema.json`](https://evolith.dev/schema/on-call-handoff.schema.json) | + +Tres filas merecen atención en vez de un mapeo silencioso: + +- **`security-scan-result` ⇄ Security Scan Report**, **`rollback-plan` ⇄ Rollback Procedure** y + **`observability-readiness` ⇄ Observability Validation** son el mismo artefacto con nombres + distintos. Una herramienta que emparejara por slug fallaría en los tres. +- **Integration Evidence** y **On-Call Handoff** tienen esquema aguas arriba y **ninguna clase en el + catálogo del Tracker**. Se listan igualmente, porque quien los busque debe enterarse de que + existen en vez de concluir que no. + +## Los artefactos que no tienen esquema, y por qué + +Diez de los veinticuatro no están cubiertos, y se dividen en dos grupos que piden respuestas +distintas. + +**Tres son salida de herramienta, y a propósito no llevan esquema de Evolith** — declaran +`producedBy` en su lugar: + +| Artefacto | Lo emite | +|---|---| +| CI Pipeline | el registro nativo de ejecución del proveedor de CI | +| Coverage Report | `cobertura` / `lcov` / `jacoco` | +| Pyramid Distribution | derivado del reporter de tests | + +Inventarles una forma canónica sería repetir lo que la herramienta ya publica, forzar una traducción +con pérdida, y quedar obsoleto el día que la herramienta cambie. + +**Siete no tienen esquema todavía:** MoSCoW Prioritization Matrix, ADR Registry, Reference Blueprint +Alignment, Simplicity Checklist Phase 1, Documentation Delta, Acceptance Validation y Deployment +Evidence. + +`adr.schema.json` **no** se cablea a *ADR Registry* aunque los nombres lo inviten: un registro es una +*lista* de ADRs y no un ADR, así que la correspondencia daría una validación que falla contra el +artefacto real — cobertura en el papel, falso negativo en la práctica. + +Donde no hay esquema, la forma es la que diga el `ArtifactFieldSchema` del tenant, y nada de aguas +arriba la contradice. \ No newline at end of file diff --git a/docs/artifacts/CORE_ARTIFACT_SCHEMAS.md b/docs/artifacts/CORE_ARTIFACT_SCHEMAS.md new file mode 100644 index 00000000..bd18c873 --- /dev/null +++ b/docs/artifacts/CORE_ARTIFACT_SCHEMAS.md @@ -0,0 +1,90 @@ +# Canonical artifact schemas published by Evolith Core + +> **Bilingual Navigation:** English (this document) · [Versión en Español](./CORE_ARTIFACT_SCHEMAS.es.md) + +`PhaseArtifactCatalog` tells a tenant that a `prd` is **required** in discovery. Until now it did +not tell anybody **what a PRD is supposed to contain**, because the catalog carries only +`ArtifactKind`, `Label` and `Required` — no reference to the canonical shape. This document is that +missing link (`GAP-020`). + +## What this is, and what it is not + +It **is** a pointer to the shape the Core publishes for an artifact, so that someone filling one in +can see the canonical fields. + +It is **not** a constraint on what a tenant may record. Per [`T-056`](../adrs/T-056-three-layer-separation.md), +content validation is the tenant's configuration and not engine code: the custom fields a tenant +adds through `ArtifactFieldSchema` remain theirs, and the evidence item types they declare +(`ci-result`, `regression`, `release-notes`) are not drawn from any closed upstream list. + +## Why the link is a URL and not a path + +The Core's gate definitions carry `requiredArtifacts[].schemaRef` as a repo-relative path. Those +paths were **broken** until `evolith_arch32#378`: written `../schema/prd.schema.json`, they resolved +from the gates directory to `reference/governance/sdlc/schema/`, a directory that does not exist, +while the files live in `src/rulesets/schema/`. Nobody could dereference them, upstream included. + +They are correct now, and this document still links by **`$id`** rather than by path — deliberately. +A path is a fact about where a file sits in one repository at one moment; the `$id` is the schema's +own published identity and survives the file being moved. A satellite that linked by path would break +the next time the Core reorganised its tree. + +## The artifacts that have a canonical schema + +**Fourteen** of the Core's twenty-four required artifacts publish one. The Tracker kind is given because the +names do **not** match mechanically — the correspondence is a decision, written down here rather +than derived from a slug. + +| Phase | Tracker kind | Core artifact | Canonical schema | +|---|---|---|---| +| discovery | `prd` | PRD | [`prd.schema.json`](https://evolith.dev/schema/prd.schema.json) | +| discovery | *(no catalog kind)* | Discovery Canvas | [`discovery-canvas.schema.json`](https://evolith.dev/schema/discovery-canvas.schema.json) | +| discovery | `technical-feasibility-canvas` | Technical Feasibility Canvas | [`technical-feasibility.schema.json`](https://evolith.dev/schema/technical-feasibility.schema.json) | +| discovery | *(no catalog kind)* | Ballpark Estimation | [`ballpark-estimation.schema.json`](https://evolith.dev/schema/ballpark-estimation.schema.json) | +| discovery | `build-versus-compose-analysis` | Build-versus-Compose Analysis | [`build-vs-compose.schema.json`](https://evolith.dev/schema/build-vs-compose.schema.json) | +| design | `bounded-context-map` | Bounded Context Map | [`bounded-context-map.schema.json`](https://evolith.dev/schema/bounded-context-map.schema.json) | +| construction | `definition-of-done-checklist` | Definition of Done Checklist | [`definition-of-done-checklist.schema.json`](https://evolith.dev/schema/definition-of-done-checklist.schema.json) | +| qa | `test-summary-report` | Test Summary Report | [`test-summary-report.schema.json`](https://evolith.dev/schema/test-summary-report.schema.json) | +| qa | `security-scan-result` | Security Scan **Report** | [`security-scan-report.schema.json`](https://evolith.dev/schema/security-scan-report.schema.json) | +| qa | *(no catalog kind)* | Integration Evidence | [`integration-evidence.schema.json`](https://evolith.dev/schema/integration-evidence.schema.json) | +| release | `release-notes` | Release Notes | [`release-notes.schema.json`](https://evolith.dev/schema/release-notes.schema.json) | +| release | `observability-readiness` | Observability **Validation** | [`observability-validation.schema.json`](https://evolith.dev/schema/observability-validation.schema.json) | +| release | `rollback-plan` | Rollback **Procedure** | [`rollback-rehearsal.schema.json`](https://evolith.dev/schema/rollback-rehearsal.schema.json) | +| release | *(no catalog kind)* | On-Call Handoff | [`on-call-handoff.schema.json`](https://evolith.dev/schema/on-call-handoff.schema.json) | + +Three rows deserve attention rather than a silent mapping: + +- **`security-scan-result` ⇄ Security Scan Report**, **`rollback-plan` ⇄ Rollback Procedure** and + **`observability-readiness` ⇄ Observability Validation** are the same artifact under different + names. A tool that matched by slug would miss all three. +- **Integration Evidence** and **On-Call Handoff** have an upstream schema and **no kind in the + Tracker's catalog**. They are listed anyway, because a reader looking for them should find out + they exist rather than conclude they do not. + +## The artifacts that have no schema, and why + +Ten of the twenty-four are not covered, and they split into two groups that call for different +answers. + +**Three are tool output, and deliberately have no Evolith schema** — they declare `producedBy` +instead: + +| Artifact | Emitted by | +|---|---| +| CI Pipeline | the CI provider's native run record | +| Coverage Report | `cobertura` / `lcov` / `jacoco` | +| Pyramid Distribution | derived from the test reporter | + +Inventing a canonical shape for these would restate what the tool already publishes, force a lossy +translation, and rot the day the tool changes. + +**Seven have no schema yet:** MoSCoW Prioritization Matrix, ADR Registry, Reference Blueprint +Alignment, Simplicity Checklist Phase 1, Documentation Delta, Acceptance Validation and Deployment +Evidence. + +`adr.schema.json` is **not** wired to *ADR Registry* even though the names invite it: a registry is a +*list* of ADRs and not an ADR, so the mapping would produce a validation that fails against the real +artifact — coverage on paper, a false negative in practice. + +Where there is no schema, the shape is whatever the tenant's `ArtifactFieldSchema` says, and nothing +upstream contradicts it. \ No newline at end of file diff --git a/docs/audit/tracker-gaps-opportunities-tracking.md b/docs/audit/tracker-gaps-opportunities-tracking.md index fe9e3727..75db4800 100644 --- a/docs/audit/tracker-gaps-opportunities-tracking.md +++ b/docs/audit/tracker-gaps-opportunities-tracking.md @@ -420,7 +420,12 @@ This document is the only operational gap register in this repository. The maste - **Criticality:** 🟡 MEDIUM - **Complexity:** 🟡 MEDIUM - **Description:** Artifact Schema URLs from Core Missing -- **Next Step:** Define owner and remediation action before execution. +- **Scope, established 2026-08-01 (the row had none — its next step said "define owner and remediation action before execution", and nobody ever had):** `PhaseArtifactCatalog` carries `ArtifactKind`, `Label` and `Required`, and **no schema reference at all**. So a consumer of `PhaseArtifactProfileDto` learns that a `prd` is required in discovery and has no way to find out what a PRD is supposed to contain. +- **What the Core actually publishes:** its gate definitions (`reference/governance/sdlc/gates/gate-f*.json`) declared `requiredArtifacts[].schemaRef` for **10 of 24** required artifacts when this row was scoped; `evolith_arch32#378` took that to **14**, declared 3 more as tool output (`producedBy`) and left 7 uncovered — `PRD`, `Technical Feasibility Canvas`, `Build-versus-Compose Analysis`, `Test Summary Report`, `Security Scan Report`, `Integration Evidence`, `Release Notes`, `Observability Validation`, `Rollback Procedure` and `On-Call Handoff`. The other 14 have no schema upstream, so there is nothing to link and this row must not pretend otherwise. +- **Upstream defect found while scoping this (belongs to the Core, not here):** those `schemaRef` values are **broken relative paths**. `../schema/prd.schema.json` resolves from the gates directory to `reference/governance/sdlc/schema/`, which does not exist; the files actually live in `src/rulesets/schema/`. So the refs cannot be dereferenced as paths by anybody. What IS stable and usable is each schema's public `$id` — `https://evolith.dev/schema/prd.schema.json` and peers — and that is what this satellite links to. +- **Naming does not match, and mapping by string would be wrong:** the Tracker's kinds and the Core's artifact names agree for some (`prd`, `release-notes`, `test-summary-report`) and diverge for others (`security-scan-result` vs `Security Scan Report`, `rollback-plan` vs `Rollback Procedure`, `observability-readiness` vs `Observability Validation`). The correspondence is a decision, not a transformation, so it is written down explicitly rather than derived from a slug. +- **Deliberately NOT in scope: coupling the vocabularies.** Forcing the Tracker's artifact kinds — or the tenant-declared evidence item types (`ci-result`, `regression`, `release-notes`) — into a closed Core-published list is precisely what `T-056` refuses: content validation is the tenant's configuration, not engine code. This row links to the canonical shape; it does not make the Core the authority over what a tenant may record. +- **Next Step:** DONE — `docs/artifacts/CORE_ARTIFACT_SCHEMAS.md` links the 14 artifacts that have an upstream schema to its published `$id`, lists the 3 that are tool output, and names the 7 that have none. The broken paths were fixed upstream in the same wave. [Back to master register](#master-register) diff --git a/src/apps/tracker-api/Tracker.Application/Governance/ArtifactFieldSchema/PhaseArtifactCatalog.cs b/src/apps/tracker-api/Tracker.Application/Governance/ArtifactFieldSchema/PhaseArtifactCatalog.cs index ce838004..88d3fd43 100644 --- a/src/apps/tracker-api/Tracker.Application/Governance/ArtifactFieldSchema/PhaseArtifactCatalog.cs +++ b/src/apps/tracker-api/Tracker.Application/Governance/ArtifactFieldSchema/PhaseArtifactCatalog.cs @@ -6,6 +6,14 @@ namespace Tracker.Application.Governance.ArtifactFieldSchema; /// Registry in Design, …). This is READ-ONLY for a tenant: required artifacts cannot be removed; /// the tenant configures custom fields per artifact (via ArtifactFieldSchema keyed by the /// artifact kind) and — for optional artifacts — their applicability. +/// +/// GAP-020 — este catálogo dice que un `prd` es obligatorio y NO dice qué debe contener. La +/// forma canónica, para los 10 de 24 artefactos que la tienen aguas arriba, está enlazada en +/// docs/artifacts/CORE_ARTIFACT_SCHEMAS.md. No se enlaza desde aquí como dato porque los +/// nombres no coinciden mecánicamente (`security-scan-result` ⇄ Security Scan Report, +/// `rollback-plan` ⇄ Rollback Procedure) y la correspondencia es una decisión escrita, no una +/// transformación de cadena — y porque el `schemaRef` que publican los gates del Core es una ruta +/// relativa ROTA: resuelve a un directorio que no existe. /// public static class PhaseArtifactCatalog {