Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
92 changes: 92 additions & 0 deletions docs/artifacts/CORE_ARTIFACT_SCHEMAS.es.md
Original file line number Diff line number Diff line change
@@ -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.
90 changes: 90 additions & 0 deletions docs/artifacts/CORE_ARTIFACT_SCHEMAS.md
Original file line number Diff line number Diff line change
@@ -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.
7 changes: 6 additions & 1 deletion docs/audit/tracker-gaps-opportunities-tracking.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 <c>ArtifactFieldSchema</c> keyed by the
/// artifact kind) and — for optional artifacts — their applicability.
///
/// <para>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
/// <c>docs/artifacts/CORE_ARTIFACT_SCHEMAS.md</c>. 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.</para>
/// </summary>
public static class PhaseArtifactCatalog
{
Expand Down
Loading