diff --git a/docs/general/specs/13. Conformance Test Specification.md b/docs/general/specs/13. Conformance Test Specification.md index 6910c004..fae47833 100644 --- a/docs/general/specs/13. Conformance Test Specification.md +++ b/docs/general/specs/13. Conformance Test Specification.md @@ -105,6 +105,7 @@ For PBS quality claims at this stage: - a language may be considered `frontend-ready` only with Gate U passing, - a language may be considered `integration-ready` only with Gate U and Gate I passing where Gate I applies, - and a published support claim must map to executable evidence from these gates. +- conformance-relevant FE/BE changes in executable backend paths MUST update `22. Backend Spec-to-Test Conformance Matrix.md` and pass matrix hard-gate policy checks. The exact publication vocabulary is owned by `17. Compatibility and Evolution Policy.md`. diff --git a/docs/general/specs/22. Backend Spec-to-Test Conformance Matrix.md b/docs/general/specs/22. Backend Spec-to-Test Conformance Matrix.md index 27cffd0c..8f695673 100644 --- a/docs/general/specs/22. Backend Spec-to-Test Conformance Matrix.md +++ b/docs/general/specs/22. Backend Spec-to-Test Conformance Matrix.md @@ -96,10 +96,18 @@ to concrete positive/negative test evidence and current status. 1. Any backend PR that changes conformance-relevant behavior in FE/BE pipeline MUST update this matrix. 2. If requirement coverage changes, update: mapped tests, status, and `Last Updated` date. 3. New normative MUSTs in specs `19/20/21` or PBS `13` addendum MUST add a new matrix row before merge. +4. Conformance-relevant FE/BE code paths for hard-gate are: + - `prometeu-compiler/prometeu-build-pipeline/` + - `prometeu-compiler/frontends/prometeu-frontend-pbs/` + - `prometeu-compiler/prometeu-frontend-api/` + - `prometeu-compiler/prometeu-compiler-core/` ## 6. Review/Lint Gate Matrix integrity is enforced by automated document lint: - `BackendConformanceMatrixSpecTest` validates file presence, required requirement IDs, and row status integrity. +- `BackendConformanceMatrixSpecTest` enforces hard-gate policy: + - if `PROMETEU_MATRIX_HARD_GATE=true` and `PROMETEU_CHANGED_FILES` contains a path under conformance-relevant FE/BE prefixes, + - then this matrix file MUST be present in `PROMETEU_CHANGED_FILES`, otherwise the gate fails. - CI policy uses strict Gate I mode via `PROMETEU_GATE_I_STRICT=true` (or `CI=true`) and requires `PROMETEU_RUNTIME_CHECK_CMD` for runtime-backed evidence. diff --git a/docs/pbs/specs/2. Governance and Versioning.md b/docs/pbs/specs/2. Governance and Versioning.md index 9de6ee40..d9427c9c 100644 --- a/docs/pbs/specs/2. Governance and Versioning.md +++ b/docs/pbs/specs/2. Governance and Versioning.md @@ -136,6 +136,7 @@ Every accepted change MUST update, when relevant: - diagnostics documentation, - conformance tests, - compatibility matrix/changelog. +- For executable FE/BE conformance-relevant code changes, the backend conformance matrix (`docs/general/specs/22. Backend Spec-to-Test Conformance Matrix.md`) MUST be updated and pass hard-gate policy checks. ## 12. Conflict Resolution diff --git a/prometeu-compiler/prometeu-build-pipeline/src/test/java/p/studio/compiler/specs/BackendConformanceMatrixSpecTest.java b/prometeu-compiler/prometeu-build-pipeline/src/test/java/p/studio/compiler/specs/BackendConformanceMatrixSpecTest.java index 61431a52..2d4a1525 100644 --- a/prometeu-compiler/prometeu-build-pipeline/src/test/java/p/studio/compiler/specs/BackendConformanceMatrixSpecTest.java +++ b/prometeu-compiler/prometeu-build-pipeline/src/test/java/p/studio/compiler/specs/BackendConformanceMatrixSpecTest.java @@ -5,15 +5,24 @@ import org.junit.jupiter.api.Test; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; +import java.util.Arrays; import java.util.List; import java.util.Optional; import java.util.regex.Pattern; +import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertTrue; import static org.junit.jupiter.api.Assertions.fail; class BackendConformanceMatrixSpecTest { private static final String MATRIX_RELATIVE_PATH = "docs/general/specs/22. Backend Spec-to-Test Conformance Matrix.md"; + private static final String MATRIX_HARD_GATE_ENV = "PROMETEU_MATRIX_HARD_GATE"; + private static final String CHANGED_FILES_ENV = "PROMETEU_CHANGED_FILES"; + private static final List HARD_GATE_PATH_PREFIXES = List.of( + "prometeu-compiler/prometeu-build-pipeline/", + "prometeu-compiler/frontends/prometeu-frontend-pbs/", + "prometeu-compiler/prometeu-frontend-api/", + "prometeu-compiler/prometeu-compiler-core/"); private static final Pattern LAST_UPDATED_PATTERN = Pattern.compile("Last Updated: \\d{4}-\\d{2}-\\d{2}"); private static final List REQUIRED_IDS = List.of( "G19-5.1.1", @@ -99,6 +108,46 @@ class BackendConformanceMatrixSpecTest { } } + @Test + void hardGatePolicyMustFailWhenConformanceRelevantPathsChangeWithoutMatrixUpdate() { + final var changedFiles = List.of( + "prometeu-compiler/prometeu-build-pipeline/src/main/java/p/studio/compiler/backend/irvm/OptimizeIRVMService.java", + "prometeu-compiler/frontends/prometeu-frontend-pbs/src/main/java/p/studio/compiler/pbs/PbsFrontendCompiler.java"); + + assertTrue(requiresMatrixUpdate(changedFiles)); + } + + @Test + void hardGatePolicyMustPassWhenConformanceRelevantPathsChangeAndMatrixIsUpdated() { + final var changedFiles = List.of( + "prometeu-compiler/prometeu-build-pipeline/src/main/java/p/studio/compiler/backend/irvm/OptimizeIRVMService.java", + MATRIX_RELATIVE_PATH); + + assertFalse(requiresMatrixUpdate(changedFiles)); + } + + @Test + void hardGatePolicyMustIgnoreNonConformanceChangesWithoutMatrixUpdate() { + final var changedFiles = List.of( + "README.md", + "docs/pbs/agendas/18.0. Backend VM Pipeline - Orchestration Agenda.md"); + + assertFalse(requiresMatrixUpdate(changedFiles)); + } + + @Test + void matrixHardGateEnvironmentCheckMustRejectRelevantChangesWithoutMatrixUpdate() { + if (!isTruthy(System.getenv(MATRIX_HARD_GATE_ENV))) { + return; + } + final var changedFiles = parseChangedFiles(System.getenv(CHANGED_FILES_ENV)); + assertTrue(!changedFiles.isEmpty(), + CHANGED_FILES_ENV + " must be provided when " + MATRIX_HARD_GATE_ENV + " is enabled"); + assertFalse( + requiresMatrixUpdate(changedFiles), + "conformance-relevant FE/BE changes require matrix update: " + MATRIX_RELATIVE_PATH); + } + private Optional findRequirementRow( final List lines, final String requirementId) { @@ -119,4 +168,43 @@ class BackendConformanceMatrixSpecTest { fail("could not locate repository root from working directory"); throw new IllegalStateException("unreachable"); } + + private boolean requiresMatrixUpdate(final List changedFiles) { + final var normalized = changedFiles.stream() + .filter(path -> path != null && !path.isBlank()) + .map(path -> path.replace('\\', '/')) + .toList(); + final var relevantTouched = normalized.stream().anyMatch(this::isConformanceRelevantPath); + final var matrixTouched = normalized.stream().anyMatch(path -> path.equals(MATRIX_RELATIVE_PATH)); + return relevantTouched && !matrixTouched; + } + + private boolean isConformanceRelevantPath(final String path) { + for (final var prefix : HARD_GATE_PATH_PREFIXES) { + if (path.startsWith(prefix)) { + return true; + } + } + return false; + } + + private List parseChangedFiles(final String raw) { + if (raw == null || raw.isBlank()) { + return List.of(); + } + return Arrays.stream(raw.split("[,\\n]")) + .map(String::trim) + .filter(path -> !path.isBlank()) + .toList(); + } + + private boolean isTruthy(final String value) { + if (value == null) { + return false; + } + return switch (value.trim().toLowerCase()) { + case "1", "true", "yes", "on" -> true; + default -> false; + }; + } }