From 5870fada27623f9fe58a5981ea138263611fd363 Mon Sep 17 00:00:00 2001 From: aarroyo Date: Sat, 1 Aug 2026 22:51:41 -0500 Subject: [PATCH] =?UTF-8?q?docs(discovery):=20cover=20Create/Read/Supersed?= =?UTF-8?q?e=20in=20Gherkin=20=E2=80=94=20close=20COH-012,=20GAP-016?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit COH-012 asked for the two missing CRUD operations. Nine scenarios added across three Features: Create (type derivation for 0/1/2/7 products against InitiativeScope.Derive, the Initiative.TenantRequired guard, ConsolidateFrom lineage), Read (own-tenant hit; other-tenant read returning exactly what a non-existent id returns) and withdrawal. The row's premise is corrected, not obeyed. There is no Delete in this aggregate and there must not be: an initiative is superseded into another (Supersede -> consolidated, BR-DIS-005) because its lineage is governance evidence. A Scenario: Delete would have satisfied the row, satisfied the probe that was watching for exactly that string, and described a system that does not exist. The COH-012 entry is withdrawn from falsifiable-claims.json with that reason recorded in the file rather than deleted silently — a probe inherits whatever its row assumed, and a row can assume something false. Constants in the scenarios were read from the code, not guessed: TENANT_WIDE, SINGLE_PRODUCT, CROSS_PRODUCT, consolidated, Initiative.TenantRequired, Initiative.NotConsolidatable. GAP-016 was stale. The roadmap has carried Document Status: SUPERSEDED since it was corrected, and the marker cites this row by id. Note on coverage: with COH-012 withdrawn and GAP-022 resolved, the falsifiable-claim guard now probes ZERO claims and says so on every run. That is the guard working as designed, not a pass. --- docs/audit/falsifiable-claims.json | 28 ++----- .../tracker-gaps-opportunities-tracking.md | 14 ++-- docs/design/discovery-functional-specs.md | 77 +++++++++++++++++++ 3 files changed, 91 insertions(+), 28 deletions(-) diff --git a/docs/audit/falsifiable-claims.json b/docs/audit/falsifiable-claims.json index ba491e41..8433662a 100644 --- a/docs/audit/falsifiable-claims.json +++ b/docs/audit/falsifiable-claims.json @@ -6,27 +6,6 @@ "notProse": "Probes are DATA, never regular expressions over the row's prose. `50-validate-gap-claim` in the Core repository read prose to infer intent, produced nine false attributions in one day, and taught authors to delete true sentences to appease it. That failure is not repeated here: a claim is checked only when someone writes down, explicitly, the symbol and the paths that would refute it." }, "claims": [ - { - "id": "COH-012", - "claim": "Gherkin covers only Create and Update; Delete and Read are entirely missing.", - "probe": { - "kind": "symbol-absent", - "symbols": [ - "Scenario: Delete", - "Scenario: Read", - "Escenario: Eliminar" - ], - "paths": [ - "docs", - "reference" - ], - "extensions": [ - ".feature", - ".md" - ] - }, - "note": "Refuted the day a Delete or Read scenario appears anywhere in the specs. The row is about spec coverage, so the probe reads specs and not code." - }, { "id": "GAP-022", "claim": "SPACE metrics are not defined anywhere.", @@ -46,5 +25,12 @@ }, "note": "The row claims absence of a definition. Any document that defines the framework refutes it." } + ], + "withdrawn": [ + { + "id": "COH-012", + "probeWas": "symbol-absent on 'Scenario: Delete' / 'Scenario: Read' / 'Escenario: Eliminar'", + "why": "The probe encoded a WRONG PREMISE and would have stayed green forever while rewarding the wrong fix. It asked for a Delete scenario; the Discovery aggregate has no Delete and must not have one — an initiative is superseded into another (Supersede, status consolidated, BR-DIS-005) because its lineage is governance evidence. Adding 'Scenario: Delete' would have turned the probe green by describing a system that does not exist. Recorded rather than quietly removed: the lesson is that a falsifiable probe inherits whatever the row assumed, and a row can assume something false." + } ] } diff --git a/docs/audit/tracker-gaps-opportunities-tracking.md b/docs/audit/tracker-gaps-opportunities-tracking.md index 58e3e50d..2d3d2592 100644 --- a/docs/audit/tracker-gaps-opportunities-tracking.md +++ b/docs/audit/tracker-gaps-opportunities-tracking.md @@ -25,11 +25,11 @@ This document is the only operational gap register in this repository. The maste | # | Status | ID | Type | Category | Component | Module | Story(ies) | Description | Resolution / Next Step | Criticality | Complexity | |---:|---|---|---|---|---|---|---|---|---|:---:|:---:| -| 1 | 🟡 OPEN | [GAP-016](#detail-gap-016) | Docs | Documentation gap | Docs | Docs | N/A | Roadmap Has No Calendar Dates | Pending owner/action definition in this register. | 🟡 MEDIUM | 🟡 MEDIUM | -| 2 | 🟡 OPEN | [GAP-023](#detail-gap-023) | Docs | Documentation gap | Docs | Docs | N/A | Re-Do Flow Not Fully Designed | Pending owner/action definition in this register. | 🟡 MEDIUM | 🟡 MEDIUM | -| 3 | 🟡 OPEN | [GAP-025](#detail-gap-025) | Docs | Documentation gap | Docs | Docs | N/A | Portal DDD incomplete — NARROWED 2026-08-01: the strategic-map half is DONE (`reference/specs/architecture/bounded-context-map.md` calls itself «the single, authoritative strategic map» of the 9 contexts, with integration patterns and cross-context events). What remains is the four support contexts. | Only the remaining half is open. Withdrawn from `falsifiable-claims.json`: «four support contexts» needs judgement about WHICH four, and a probe that pretended to check it would refute the row on any document mentioning a context. | 🟡 MEDIUM | 🟡 MEDIUM | -| 4 | 🟡 OPEN | [COH-012](#detail-coh-012) | GAP | Missing capability / corrective gap | Backend | Discovery | US-DIS-006 | Gherkin covers only 2 of 4 CRUD operations (Create, Update). Delete and Read entirely missing. Zero edge cases. | Pending owner/action definition in this register. | 🟢 | 🟢 | -| 5 | 🟡⏳ DEFERRED | [OPP-002](#detail-opp-002) | OPP | Improvement opportunity | Backend | N/A | N/A | Extraer AuditTrail como Shared Kernel — 5+ contextos implementan historiales inmutables | Pending owner/action definition in this register. | 🟠 HIGH | 🔴 HIGH | +| 1 | 🟡 OPEN | [GAP-023](#detail-gap-023) | Docs | Documentation gap | Docs | Docs | N/A | Re-Do Flow Not Fully Designed | Pending owner/action definition in this register. | 🟡 MEDIUM | 🟡 MEDIUM | +| 2 | 🟡 OPEN | [GAP-025](#detail-gap-025) | Docs | Documentation gap | Docs | Docs | N/A | Portal DDD incomplete — NARROWED 2026-08-01: the strategic-map half is DONE (`reference/specs/architecture/bounded-context-map.md` calls itself «the single, authoritative strategic map» of the 9 contexts, with integration patterns and cross-context events). What remains is the four support contexts. | Only the remaining half is open. Withdrawn from `falsifiable-claims.json`: «four support contexts» needs judgement about WHICH four, and a probe that pretended to check it would refute the row on any document mentioning a context. | 🟡 MEDIUM | 🟡 MEDIUM | +| 3 | 🟡⏳ DEFERRED | [OPP-002](#detail-opp-002) | OPP | Improvement opportunity | Backend | N/A | N/A | Extraer AuditTrail como Shared Kernel — 5+ contextos implementan historiales inmutables | Pending owner/action definition in this register. | 🟠 HIGH | 🔴 HIGH | +| 4 | 🟢 RESOLVED | [GAP-016](#detail-gap-016) | Docs | Documentation gap | Docs | Docs | N/A | Roadmap Has No Calendar Dates | RESOLVED — stale row. `reference/specs/design/tracker-implementation-roadmap.md` has carried `Document Status: SUPERSEDED — historical NestJS-era draft` since it was corrected, and the marker cites **this row by id**: «SUPERSEDED (GAP-016)». The roadmap planned a NestJS build that was executed in .NET, so «no calendar dates» is moot on a document that describes a plan already carried out under a different stack. The other board, `tracker-gap-tracking.md`, recorded this correctly; this register did not. | 🟡 MEDIUM | 🟡 MEDIUM | +| 5 | 🟢 RESOLVED | [COH-012](#detail-coh-012) | GAP | Missing capability / corrective gap | Backend | Discovery | US-DIS-006 | Gherkin covers only 2 of 4 CRUD operations (Create, Update). Delete and Read entirely missing. Zero edge cases. | RESOLVED — 9 scenarios added to `docs/design/discovery-functional-specs.md`, covering Create (type derivation for 0/1/2/7 products against `InitiativeScope.Derive`, the `Initiative.TenantRequired` guard, and `ConsolidateFrom` lineage), Read (own-tenant hit, and other-tenant read returning exactly what a non-existent id returns — the shape that stops the id being confirmed), and withdrawal. **The row's premise was partly wrong and is corrected rather than obeyed:** there is no Delete in this aggregate and there must not be. An initiative is superseded into another (`Supersede` → `consolidated`, BR-DIS-005) because its lineage is governance evidence. Writing a Delete scenario would have satisfied the row and described a system that does not exist. The COH-012 probe in `falsifiable-claims.json` is therefore withdrawn, with the reason recorded in that file: it had inherited the same false premise. | 🟢 | 🟢 | | 6 | 🟢 RESOLVED | [GAP-011](#detail-gap-011) | Docs | Documentation gap | Docs | Docs | N/A | C4 Topology No English version | RESOLVED — the row was TRUE and had been mismeasured. `c4-macro-topology-phase1.md` existed, was labelled «English (this document)» and passed `check-bilingual-parity`, but 86 of its 87 non-empty lines were byte-identical to the Spanish file: only the navigation banner had been translated. It is now genuinely in English — prose, diagram descriptions and relationship labels — and its entry was removed from `untranslated-allowlist.json`, which drops from 9 declared to 7. Note for the record: the other board, `tracker-gap-tracking.md`, marked this DONE while the file was still Spanish. | 🟡 MEDIUM | 🟡 MEDIUM | | 7 | 🟢 RESOLVED | [GAP-017](#detail-gap-017) | Docs | Documentation gap | Docs | Docs | N/A | Discovery Canvas Has No ES Version | RESOLVED — same defect and same correction as GAP-011. `DISCOVERY_CANVAS.md` was 23 of 24 non-empty lines identical to `DISCOVERY_CANVAS.es.md`; the English label was the only English in it. Now translated in full and removed from `untranslated-allowlist.json`. Both boards had this backwards on direction — one said the ES version was missing, the other said the EN one was — and what was actually missing was English content behind an English filename. | 🟡 MEDIUM | 🟡 MEDIUM | | 8 | 🟢 RESOLVED | [COH-009](#detail-coh-009) | INCO | Source incoherence | Backend | Release | All REL | BR-003 conflated: product-brief = "no deploy without QA gate", but 5+ stories invoke as "human authorization required." Two rules sharing one ID. | RESOLVED — and the repository says so in the row's own words. The business-rule table in `evolith-tracker-crosscutting-diagram.md` now carries a `BR-010` row, *CFR Quality Threshold*, whose own description reads «escindida de BR-003 por COH-009; BR-003 es sólo la firma humana». The split this row asked for was made, credited to this row, and the row was never moved. Verified across the repository: every `BR-003` occurrence outside the audit tree means Human Sign-Off and nothing else, and the QA-gate half lives as `BR-010` — cited by `reference/specs/qa/` («no deployment is authorized without an approved QA verdict and CFR < 2%»), by the test strategy against `PhaseGateEvaluator`, and by the Re-Do flow design. Two rules, two ids. | 🟢 | 🟢 | @@ -380,7 +380,7 @@ This document is the only operational gap register in this repository. The maste ### Detail GAP-016 -- **Status:** 🟡 OPEN +- **Status:** 🟢 RESOLVED - **Type:** Docs (Documentation gap) - **Component:** Docs - **Module:** Docs @@ -497,7 +497,7 @@ This document is the only operational gap register in this repository. The maste ### Detail COH-012 -- **Status:** 🟡 OPEN +- **Status:** 🟢 RESOLVED - **Type:** GAP (Missing capability / corrective gap) - **Component:** Backend - **Module:** Discovery diff --git a/docs/design/discovery-functional-specs.md b/docs/design/discovery-functional-specs.md index 82b96d28..f2949942 100644 --- a/docs/design/discovery-functional-specs.md +++ b/docs/design/discovery-functional-specs.md @@ -44,6 +44,83 @@ La compuerta de aprobación de Discovery es dinámica y se basa en el tipo de in A continuación, se detallan los escenarios base que guían el QA y aseguran la coherencia entre el requerimiento y el modelo de dominio. +> [!NOTE] +> **Sobre "las cuatro operaciones CRUD" (COH-012).** El hallazgo original pedía cubrir Create, Read, Update y Delete. Tres de las cuatro existen en el agregado; **`Delete` no existe y no debe existir**: una iniciativa nunca se borra, se *supersede* (`Supersede` → estado `consolidated`, BR-DIS-005), porque su linaje es evidencia de gobierno y borrarlo rompería la trazabilidad. Escribir un escenario `Delete` habría satisfecho la ficha y descrito un sistema que no es éste. Lo que sigue cubre Create, Read y la operación de retiro que el dominio sí tiene. + +```gherkin +Feature: Initiative Creation & Type Derivation + + Scenario Outline: Type is derived from the size of the product scope + Given a tenant "acme" + When an Initiative is created with Product(s) in its ProductScope + Then its InitiativeType is "" + And a Facet stub exists for each product in the scope + And the Initiative is in "draft" state with TypeFrozen false + + Examples: + | count | type | + | 0 | TENANT_WIDE | + | 1 | SINGLE_PRODUCT | + | 2 | CROSS_PRODUCT | + | 7 | CROSS_PRODUCT | + + Scenario: Creation without a tenant is refused + Given no tenant context + When an Initiative is created with an empty tenant identifier + Then the operation is rejected with error "Initiative.TenantRequired" + And no Initiative is persisted + + Scenario: A consolidating Initiative records the lineage of what it groups + Given three source inputs from Intake + When an Initiative is created via ConsolidateFrom with those three as constituents + Then the Initiative is in "draft" state + And its Constituents list the three sources + And its type is derived from the supplied scope, not from the constituents + +``` + +```gherkin +Feature: Reading an Initiative + + Scenario: An Initiative is readable by its own tenant + Given an Initiative belonging to tenant "acme" + When tenant "acme" requests it by id + Then the Initiative is returned with its scope, facets and approval state + + Scenario: An Initiative of another tenant is indistinguishable from one that does not exist + Given an Initiative belonging to tenant "acme" + When tenant "globex" requests it by the same id + Then nothing is returned + And the response is identical to requesting an id that was never created + + # The two outcomes MUST stay identical. A distinct "forbidden" answer would confirm to + # tenant "globex" that the id exists — which is the leak the null-for-both shape prevents. + +``` + +```gherkin +Feature: Withdrawing an Initiative (Supersede — the domain has no Delete) + + Scenario: A draft Initiative is superseded by a larger one + Given an Initiative in "draft" state + When it is superseded into initiative "INI-042" with reason "grouped into the platform epic" + Then the Initiative transitions to "consolidated" + And its SupersededByInitiativeId is "INI-042" + And the reason is retained in its metadata + And the Initiative is still readable — nothing is deleted + + Scenario: An already-consolidated Initiative cannot be superseded again + Given an Initiative in "consolidated" state + When it is superseded into another initiative + Then the operation is rejected with error "Initiative.NotConsolidatable" + + Scenario: A rejected Initiative cannot be superseded + Given an Initiative in "rejected" state + When it is superseded into another initiative + Then the operation is rejected with error "Initiative.NotConsolidatable" + +``` + ```gherkin Feature: Initiative State Machine & Scope Freezing