From 3871f954ab8b485a9476349718af661fdc65ae9c Mon Sep 17 00:00:00 2001 From: Yernat Yestekov <2068106+doublewhy@users.noreply.github.com> Date: Thu, 8 Oct 2026 22:31:02 -0700 Subject: [PATCH 1/6] ci(policy): require every published contract to trace to a governing requirement Add tools/check_contract_requirement_tracing.py as the "policy / published contract requirement tracing" stage. A published schema is traced when an ACTIVE or DRAFT requirement record carries an IMPLEMENTS -> SPEC link to its exact path; CODE_FILE links, other link types, and DEPRECATED or ARCHIVED owners never count, and an unreadable record fails closed. Backfill the 72 published contracts that had no such link across 35 requirement records, and document the rule in docs/explain/reference/published-contract-requirement-tracing.md. Closes #712 --- docs/explain/reference/README.md | 3 + .../published-contract-requirement-tracing.md | 91 ++++++ docs/requirements/ACT-605/requirement.md | 2 + docs/requirements/ACT-610/requirement.md | 2 +- docs/requirements/ACT-611/requirement.md | 2 + docs/requirements/ACT-614/requirement.md | 1 + docs/requirements/API-402/requirement.md | 8 + docs/requirements/API-403/requirement.md | 1 + docs/requirements/API-406/requirement.md | 2 + docs/requirements/API-408/requirement.md | 2 + docs/requirements/API-411/requirement.md | 1 + docs/requirements/API-412/requirement.md | 1 + docs/requirements/API-417/requirement.md | 5 + docs/requirements/API-418/requirement.md | 7 + docs/requirements/API-421/requirement.md | 3 + docs/requirements/API-423/requirement.md | 1 + docs/requirements/ASR-501/requirement.md | 1 + docs/requirements/ASR-511/requirement.md | 2 +- docs/requirements/ASR-515/requirement.md | 1 + docs/requirements/ASR-516/requirement.md | 5 +- docs/requirements/ASR-530/requirement.md | 1 + docs/requirements/ASR-535/requirement.md | 6 +- docs/requirements/DSL-114/requirement.md | 3 + docs/requirements/EXP-707/requirement.md | 2 + docs/requirements/EXP-709/requirement.md | 1 + docs/requirements/EXP-719/requirement.md | 4 + docs/requirements/EXP-733/requirement.md | 1 + docs/requirements/GOV-903/requirement.md | 2 + docs/requirements/GOV-913/requirement.md | 1 + docs/requirements/GOV-918/requirement.md | 1 + docs/requirements/GOV-920/requirement.md | 5 + docs/requirements/GOV-942/requirement.md | 3 + docs/requirements/RUN-301/requirement.md | 1 + docs/requirements/RUN-303/requirement.md | 3 + docs/requirements/SEM-207/requirement.md | 1 + docs/requirements/SEM-218/requirement.md | 4 +- docs/requirements/SEM-220/requirement.md | 1 + ..._issue_712_contract_requirement_tracing.py | 259 ++++++++++++++++++ tools/check_contract_requirement_tracing.py | 180 ++++++++++++ tools/nox_support/policy_lanes.py | 1 + 40 files changed, 615 insertions(+), 6 deletions(-) create mode 100644 docs/explain/reference/published-contract-requirement-tracing.md create mode 100644 implementations/python/tests/test_issue_712_contract_requirement_tracing.py create mode 100644 tools/check_contract_requirement_tracing.py diff --git a/docs/explain/reference/README.md b/docs/explain/reference/README.md index d58f0793a..ec834192d 100644 --- a/docs/explain/reference/README.md +++ b/docs/explain/reference/README.md @@ -24,6 +24,9 @@ themselves normative specifications or ADRs. - [published-schema-coverage.md](published-schema-coverage.md) - The `ASR-501` rule requiring every published schema to carry corpus, formal, or declared coverage evidence +- [published-contract-requirement-tracing.md](published-contract-requirement-tracing.md) + - The rule requiring every published schema to trace to a live governing + requirement through an `IMPLEMENTS → SPEC` link - [assessment-semantics.md](assessment-semantics.md) - Architecture guardrails for `SEM-206` assessment semantics work - [objective-semantics.md](objective-semantics.md) diff --git a/docs/explain/reference/published-contract-requirement-tracing.md b/docs/explain/reference/published-contract-requirement-tracing.md new file mode 100644 index 000000000..3000e93f4 --- /dev/null +++ b/docs/explain/reference/published-contract-requirement-tracing.md @@ -0,0 +1,91 @@ +# Published-contract requirement tracing + +Every schema under `contracts/schemas/` is a normative published contract +(`ADR-009` §7). `tools/check_schema_publication.py` proves the inventory and +`tools/check_schema_coverage.py` proves that something exercises each contract. +Neither names the requirement that governs a contract, so a schema could be +published with no owner. `experiment-authoring-input-v1` was linked to `EXP-736` +only after review (issue #675, PR #711). + +`tools/check_contract_requirement_tracing.py` closes that gap. It runs as the +`policy / published contract requirement tracing` stage of `nox -s policy` and +reads the whole published inventory on every run, not the changed-file set. + +## The rule + +A published contract is **traced** when at least one requirement record under +`docs/requirements//requirement.md` whose status is `ACTIVE` or `DRAFT` +carries this link to the contract's exact schema path: + +```markdown +- IMPLEMENTS → SPEC `contracts/schemas//.json` ( published schema) +``` + +- **Only `IMPLEMENTS → SPEC` counts.** `CONSTRAINS`, `DOCUMENTS`, `TESTS`, and + `VERIFIES` links record a relation other than ownership. An `IMPLEMENTS` link + to a schema path typed as `CONFIG`, `SCHEMA`, or `DOCUMENTATION` is a + classification error; correct its artifact type to `SPEC`. +- **`CODE_FILE` links never count.** A module link cannot say which contract a + requirement governs. `raes_contracts/contracts/bundle.py` generates every + published contract and several requirements link it as a `CODE_FILE`, so + accepting module links would mark every contract traced. +- **The path must match exactly.** A link to a document beside the schema, + such as the catalog `contracts/concept-authority/behavioral-relations-v1.json`, + does not trace `contracts/schemas/concept-authority/behavioral-relations-v1.json`. +- **`DRAFT` owners qualify.** Requirement governance admits a `DRAFT` + requirement for implementation work, and the owning requirements of several + contract families, such as the time and participant-budget contracts, are + still `DRAFT`. Requiring an `ACTIVE` owner would force a link to a less + precise requirement. +- **`DEPRECATED` and `ARCHIVED` owners never count.** These are the statuses + `tools/policy/requirement_governance.py` rejects for implementation work. A + contract whose only owner is retired is untraced until a live requirement + owns it. +- **One live owner is enough.** A contract may have several. + +The gate reads requirement records offline through +`RepositoryRequirementClient`, the parser behind the repository requirement +source that `tools/policy/requirement_order.yaml` selects. It makes no Ground +Control request, so it runs on every CI policy run. A record that the parser +rejects, including a malformed traceability line, a symlinked record, or a +directory that is not a canonical requirement UID, fails closed as +`[contract-requirement-record-unreadable]` and owns nothing. + +## The inventory + +The denominator is every `contracts/schemas/**/*.json` file. The contracts lane +already fails when that tree disagrees with `schema_bundle()` +(`tools/check_generated_schemas.py`) or with the publication manifest +(`tools/check_schema_publication.py`), so the gate reads the tree rather than +regenerating the bundle. `test_issue_712_contract_requirement_tracing.py` pins +the three inventories to one set. A removed schema leaves the tree, so its +tombstone needs no owner. + +## Repairing a finding + +`[contract-requirement-trace-missing]` names the schema path that has no live +owner. Add the `IMPLEMENTS → SPEC` line to the Traceability section of the +requirement that governs the contract, in the same pull request that publishes +a new schema. Choose the owner by evidence, strongest first: + +1. A live requirement already records the exact schema path under another link + or artifact type, or links the contract's own catalog or publication record. +2. The pull request that published the schema, or its issue, declared the + requirement. +3. The requirement's statement names the contract's subject. Prefer a + requirement that also links the contract's defining module, tests, or + governing ADR. + +Do not link a requirement only to turn the gate green. Do not waive a finding +through `tools/policy/exceptions.yaml` because a repair is inconvenient. The +waiver mechanism exists for a finding that is factually wrong. + +## Reporting + +```console +$ uv run --project implementations/python --frozen \ + python tools/check_contract_requirement_tracing.py --report +``` + +The report lists every published contract with its live owners, marks a +contract without one as `UNTRACED`, and never gates. diff --git a/docs/requirements/ACT-605/requirement.md b/docs/requirements/ACT-605/requirement.md index 8b81ee05a..b446cc229 100644 --- a/docs/requirements/ACT-605/requirement.md +++ b/docs/requirements/ACT-605/requirement.md @@ -34,3 +34,5 @@ Requirement inventory expansion. Realistic scenarios require first-class specifi - TESTS → TEST `implementations/python/tests/test_dsl_437_snapshot_durability_conformance.py` (Autonomous participant durability and conformance coverage) - IMPLEMENTS → CODE_FILE `implementations/python/packages/raes_processor/compiler/participant_autonomous_execution.py` (Autonomous participant runtime compilation) - IMPLEMENTS → CODE_FILE `implementations/python/packages/raes/semantics/participant_behavior/__init__.py` (Autonomous participant semantic validation) +- IMPLEMENTS → SPEC `contracts/schemas/participant-runtime/participant-execution-control-v1.json` (participant-execution-control-v1 published schema) +- IMPLEMENTS → SPEC `contracts/schemas/participant-runtime/participant-execution-service-state-v1.json` (participant-execution-service-state-v1 published schema) diff --git a/docs/requirements/ACT-610/requirement.md b/docs/requirements/ACT-610/requirement.md index 13ffb51eb..7ee134e03 100644 --- a/docs/requirements/ACT-610/requirement.md +++ b/docs/requirements/ACT-610/requirement.md @@ -23,7 +23,7 @@ Requirement inventory expansion. Defensive behavior needs its own expressible vo - IMPLEMENTS → GITHUB_ISSUE `210` (Defensive Behavior Vocabularies (ACT-610)) - IMPLEMENTS → CONFIG `contracts/concept-authority/controlled-vocabularies-v1.json` (Governed participant defensive behavior vocabulary) -- IMPLEMENTS → CONFIG `contracts/schemas/concept-authority/nist-csf-defensive-categories-source-v1.json` (NIST CSF defensive category source schema) +- IMPLEMENTS → SPEC `contracts/schemas/concept-authority/nist-csf-defensive-categories-source-v1.json` (NIST CSF defensive category source schema) - IMPLEMENTS → CONFIG `contracts/concept-authority/nist-csf-defensive-categories-source-v1.json` (Pinned NIST CSF 2.0 defensive category source) - IMPLEMENTS → SPEC `contracts/schemas/concept-authority/external-concept-bindings-v1.json` (Generic authored defensive behavior classification contract) - IMPLEMENTS → CODE_FILE `implementations/python/packages/raes_contracts/external_concept_bindings.py` (Neutral NIST CSF source snapshot adapter) diff --git a/docs/requirements/ACT-611/requirement.md b/docs/requirements/ACT-611/requirement.md index 355e123f4..241b51bfb 100644 --- a/docs/requirements/ACT-611/requirement.md +++ b/docs/requirements/ACT-611/requirement.md @@ -30,3 +30,5 @@ Requirement inventory expansion. Scenarios need to describe autonomous system be - IMPLEMENTS → GITHUB_ISSUE `211` (Autonomous Service And Agent Behavior Vocabularies (ACT-611)) - TESTS → TEST `implementations/python/tests/test_external_concept_bindings.py` (External concept binding production-path tests) - TESTS → TEST `tools/check_autonomous_behavior_vocabularies.py` (Autonomous behavior vocabulary source integrity checker) +- IMPLEMENTS → SPEC `contracts/schemas/concept-authority/fipa-communicative-acts-source-v1.json` (fipa-communicative-acts-source-v1 published schema) +- IMPLEMENTS → SPEC `contracts/schemas/concept-authority/w3c-activitystreams-activity-types-source-v1.json` (w3c-activitystreams-activity-types-source-v1 published schema) diff --git a/docs/requirements/ACT-614/requirement.md b/docs/requirements/ACT-614/requirement.md index 8efbfade4..7ff66c469 100644 --- a/docs/requirements/ACT-614/requirement.md +++ b/docs/requirements/ACT-614/requirement.md @@ -91,3 +91,4 @@ Requirement inventory expansion. Participant behavior over time is a first-class - TESTS → TEST `implementations/python/tests/test_issue_898_participant_execution_control.py` (Execution-control regression) - TESTS → TEST `implementations/python/tests/test_issue_1181_unified_control_plane_mutations.py` (Control-plane mutation regression) - TESTS → TEST `implementations/python/tests/test_participant_concurrent_batch_reservations.py` (Concurrent reservation regression) +- IMPLEMENTS → SPEC `contracts/schemas/participant-runtime/participant-execution-binding-v1.json` (participant-execution-binding-v1 published schema) diff --git a/docs/requirements/API-402/requirement.md b/docs/requirements/API-402/requirement.md index d443056e7..e0d244b82 100644 --- a/docs/requirements/API-402/requirement.md +++ b/docs/requirements/API-402/requirement.md @@ -57,3 +57,11 @@ Current state: implemented. Portable live-execution contracts are required so in - IMPLEMENTS → CODE_FILE `implementations/python/packages/raes_contracts/contracts/_backend_operation_exports.py` (Public operation contract facade exports) - IMPLEMENTS → CODE_FILE `implementations/python/packages/raes_backend_stubs/manifest.py` (Keep operation supervision opt-in; legacy stub does not advertise an unimplemented provider) - IMPLEMENTS → CODE_FILE `implementations/python/packages/raes_reference_backend/manifest.py` (Keep operation supervision opt-in for reference emulation) +- IMPLEMENTS → SPEC `contracts/schemas/control-plane/backend-operation-capabilities-v1.json` (backend-operation-capabilities-v1 published schema) +- IMPLEMENTS → SPEC `contracts/schemas/control-plane/backend-operation-control-v1.json` (backend-operation-control-v1 published schema) +- IMPLEMENTS → SPEC `contracts/schemas/control-plane/backend-operation-request-v1.json` (backend-operation-request-v1 published schema) +- IMPLEMENTS → SPEC `contracts/schemas/control-plane/backend-operation-response-v1.json` (backend-operation-response-v1 published schema) +- IMPLEMENTS → SPEC `contracts/schemas/control-plane/evaluation-history-event-stream-v1.json` (evaluation-history-event-stream-v1 published schema) +- IMPLEMENTS → SPEC `contracts/schemas/control-plane/evaluation-result-envelope-v1.json` (evaluation-result-envelope-v1 published schema) +- IMPLEMENTS → SPEC `contracts/schemas/control-plane/workflow-history-event-stream-v1.json` (workflow-history-event-stream-v1 published schema) +- IMPLEMENTS → SPEC `contracts/schemas/control-plane/workflow-result-envelope-v1.json` (workflow-result-envelope-v1 published schema) diff --git a/docs/requirements/API-403/requirement.md b/docs/requirements/API-403/requirement.md index 3a588a328..ee387dcfa 100644 --- a/docs/requirements/API-403/requirement.md +++ b/docs/requirements/API-403/requirement.md @@ -29,3 +29,4 @@ Current state: implemented. A per-target control-plane contract is required so r - CONSTRAINS → SPEC `contracts/schemas/control-plane/workflow-cancellation-request-v1.json` (Workflow Cancellation Request Schema) - TESTS → TEST `implementations/python/tests/test_runtime_control_plane.py` (Runtime Control Plane Tests) - TESTS → TEST `implementations/python/tests/test_runtime_control_plane_api.py` (Runtime Control Plane API Tests) +- IMPLEMENTS → SPEC `contracts/schemas/control-plane/workflow-cancellation-request-v1.json` (workflow-cancellation-request-v1 published schema) diff --git a/docs/requirements/API-406/requirement.md b/docs/requirements/API-406/requirement.md index 66a4bc99a..a8b2944fb 100644 --- a/docs/requirements/API-406/requirement.md +++ b/docs/requirements/API-406/requirement.md @@ -29,3 +29,5 @@ Requirement inventory expansion. Participant behavior requires portable external - TESTS → TEST `implementations/python/tests/test_participant_backend_contracts.py` (Participant backend-contract carrier fixture and schema tests) - IMPLEMENTS → CONFIG `contracts/profiles/backend/full-remote-control-plane.json` (Full remote control-plane backend profile API-406 carrier requirements) - TESTS → TEST `implementations/python/tests/test_runtime_conformance.py` (API-406 carrier profile and fixture-suite conformance tests) +- IMPLEMENTS → SPEC `contracts/schemas/participant-runtime/participant-lifecycle-event-v1.json` (participant-lifecycle-event-v1 published schema) +- IMPLEMENTS → SPEC `contracts/schemas/participant-runtime/participant-observation-envelope-v1.json` (participant-observation-envelope-v1 published schema) diff --git a/docs/requirements/API-408/requirement.md b/docs/requirements/API-408/requirement.md index 7263a2358..c11fe3bc6 100644 --- a/docs/requirements/API-408/requirement.md +++ b/docs/requirements/API-408/requirement.md @@ -30,3 +30,5 @@ Requirement inventory expansion. Participant execution must be observable throug - TESTS → TEST `implementations/python/tests/test_runtime_control_plane.py` (Runtime participant retrieval projection tests) - TESTS → TEST `implementations/python/tests/test_runtime_control_plane_api.py` (HTTP participant retrieval route tests) - TESTS → TEST `implementations/python/tests/test_act_614_temporal_durability.py` (Temporal assessments through history retrieval and durable readback) +- IMPLEMENTS → SPEC `contracts/schemas/control-plane/participant-history-view-v1.json` (participant-history-view-v1 published schema) +- IMPLEMENTS → SPEC `contracts/schemas/control-plane/participant-status-view-v1.json` (participant-status-view-v1 published schema) diff --git a/docs/requirements/API-411/requirement.md b/docs/requirements/API-411/requirement.md index 84e5d3f84..f81841e34 100644 --- a/docs/requirements/API-411/requirement.md +++ b/docs/requirements/API-411/requirement.md @@ -25,3 +25,4 @@ Requirement inventory expansion. Participant-local outcomes need portable extern - DOCUMENTS → SPEC `specs/formal/runtime-contracts/participant-backend-contracts.md` (Participant backend-facing contracts formal design (API-411 outcome reports)) - DOCUMENTS → SPEC `contracts/schemas/participant-runtime/participant-outcome-report-v1.json` (Generated participant outcome report schema) - TESTS → TEST `implementations/python/tests/test_participant_backend_contracts.py` (Participant outcome-report fixture and schema tests) +- IMPLEMENTS → SPEC `contracts/schemas/participant-runtime/participant-outcome-report-v1.json` (participant-outcome-report-v1 published schema) diff --git a/docs/requirements/API-412/requirement.md b/docs/requirements/API-412/requirement.md index 4f497e618..966d47117 100644 --- a/docs/requirements/API-412/requirement.md +++ b/docs/requirements/API-412/requirement.md @@ -27,3 +27,4 @@ Current state: implemented. Processor manifests now publish a processor-specific - DOCUMENTS → DOCUMENTATION `contracts/schemas/README.md` (Published Contract Schemas Overview) - DOCUMENTS → DOCUMENTATION `docs/explain/sdl/runtime-architecture.md` (SDL Runtime Architecture) - CONSTRAINS → SPEC `contracts/schemas/processor-manifest/processor-manifest-v2.json` (Processor Manifest Schema v2) +- IMPLEMENTS → SPEC `contracts/schemas/processor-manifest/processor-manifest-v2.json` (processor-manifest-v2 published schema) diff --git a/docs/requirements/API-417/requirement.md b/docs/requirements/API-417/requirement.md index 86f4c2ecc..5d5721547 100644 --- a/docs/requirements/API-417/requirement.md +++ b/docs/requirements/API-417/requirement.md @@ -17,3 +17,8 @@ The ecosystem shall define plain-data contracts for participant episode initiali ## Rationale Primary-source refresh shows that episode lifecycle handling needs portable external contracts rather than backend-local conventions. + +## Traceability + +- IMPLEMENTS → SPEC `contracts/schemas/control-plane/participant-episode-history-event-stream-v1.json` (participant-episode-history-event-stream-v1 published schema) +- IMPLEMENTS → SPEC `contracts/schemas/control-plane/participant-episode-state-envelope-v1.json` (participant-episode-state-envelope-v1 published schema) diff --git a/docs/requirements/API-418/requirement.md b/docs/requirements/API-418/requirement.md index 6b981d89b..8232e9505 100644 --- a/docs/requirements/API-418/requirement.md +++ b/docs/requirements/API-418/requirement.md @@ -17,3 +17,10 @@ The ecosystem shall define plain-data contracts for participant budgets, quotas, ## Rationale Primary-source refresh shows that participant budgets and quota consumption need portable reporting surfaces if runs and benchmarks are to remain comparable. + +## Traceability + +- IMPLEMENTS → SPEC `contracts/schemas/participant-runtime/participant-resource-budget-event-v1.json` (participant-resource-budget-event-v1 published schema) +- IMPLEMENTS → SPEC `contracts/schemas/participant-runtime/participant-resource-budget-policy-v1.json` (participant-resource-budget-policy-v1 published schema) +- IMPLEMENTS → SPEC `contracts/schemas/participant-runtime/participant-resource-budget-state-v1.json` (participant-resource-budget-state-v1 published schema) +- IMPLEMENTS → SPEC `contracts/schemas/participant-runtime/participant-resource-pool-capacity-v1.json` (participant-resource-pool-capacity-v1 published schema) diff --git a/docs/requirements/API-421/requirement.md b/docs/requirements/API-421/requirement.md index be8d63092..2a067bc8e 100644 --- a/docs/requirements/API-421/requirement.md +++ b/docs/requirements/API-421/requirement.md @@ -21,3 +21,6 @@ Independent processors and backends need explicit external declarations for how ## Traceability - DOCUMENTS → SPEC `https://fmi-standard.org/docs/3.0.2/` (FMI 3.0.2 Specification) +- IMPLEMENTS → SPEC `contracts/schemas/time/realized-time-model-v1.json` (realized-time-model-v1 published schema) +- IMPLEMENTS → SPEC `contracts/schemas/time/time-model-v1.json` (time-model-v1 published schema) +- IMPLEMENTS → SPEC `contracts/schemas/time/time-runtime-state-v1.json` (time-runtime-state-v1 published schema) diff --git a/docs/requirements/API-423/requirement.md b/docs/requirements/API-423/requirement.md index c7f242d84..f47108471 100644 --- a/docs/requirements/API-423/requirement.md +++ b/docs/requirements/API-423/requirement.md @@ -67,3 +67,4 @@ API-406 and API-409 provide adjacent carriers, but no common contract records th - IMPLEMENTS → DOCUMENTATION `docs/migration/participant-information-flow-control.md` (Participant information-flow control migration guide) - TESTS → TEST `implementations/python/tests/test_public_docs_policy.py` (Executable participant-control public guide claim example) - DOCUMENTS → DOCUMENTATION `docs/public/participant-control.md` (Participant input and output control guide) +- IMPLEMENTS → SPEC `contracts/schemas/profiles/participant-boundary-flow-policy-v1.json` (participant-boundary-flow-policy-v1 published schema) diff --git a/docs/requirements/ASR-501/requirement.md b/docs/requirements/ASR-501/requirement.md index 2c13c2839..f6e533ac4 100644 --- a/docs/requirements/ASR-501/requirement.md +++ b/docs/requirements/ASR-501/requirement.md @@ -51,3 +51,4 @@ Current state: partially implemented. Checked-in normative schemas exist under c - IMPLEMENTS → CODE_FILE `tools/schema_coverage/_classify.py` (Published inventory to covering-leg join) - TESTS → TEST `implementations/python/tests/test_issue_1330_schema_coverage.py` (Published-schema coverage gate and backfilled contract corpora tests) - IMPLEMENTS → GITHUB_ISSUE `1330` (Issue #1330 detect missing fixture or formal coverage for published schemas) +- IMPLEMENTS → SPEC `contracts/schemas/profiles/raes-semantic-invariants-v1.json` (raes-semantic-invariants-v1 published schema) diff --git a/docs/requirements/ASR-511/requirement.md b/docs/requirements/ASR-511/requirement.md index 165614d30..3c6d18a07 100644 --- a/docs/requirements/ASR-511/requirement.md +++ b/docs/requirements/ASR-511/requirement.md @@ -24,7 +24,7 @@ Requirement inventory expansion. Mature ecosystems need explicit validation-stre - IMPLEMENTS → ADR `docs/decisions/adrs/adr-072-validation-and-admission-profiles.md` (ADR-072 validation and admission profiles) - IMPLEMENTS → SPEC `specs/formal/validation-admission-profiles/README.md` (Validation and admission profiles formal specification) - IMPLEMENTS → CONFIG `contracts/profiles/validation/validation-profile-catalog-v1.json` (Validation profile catalog v1) -- IMPLEMENTS → CONFIG `contracts/schemas/profiles/validation-profile-catalog-v1.json` (Published validation profile catalog schema v1) +- IMPLEMENTS → SPEC `contracts/schemas/profiles/validation-profile-catalog-v1.json` (Published validation profile catalog schema v1) - TESTS → TEST `implementations/python/tests/test_validation_profiles.py` (Validation profile catalog tests) - DOCUMENTS → DOCUMENTATION `docs/decisions/issue-258-asr-511-layered-validation-profiles-preflight.md` (ASR-511 layered validation profiles design boundary) - DOCUMENTS → DOCUMENTATION `contracts/README.md` (Validation profile catalog contract documentation) diff --git a/docs/requirements/ASR-515/requirement.md b/docs/requirements/ASR-515/requirement.md index 7bd272fdd..d77911d4b 100644 --- a/docs/requirements/ASR-515/requirement.md +++ b/docs/requirements/ASR-515/requirement.md @@ -24,3 +24,4 @@ Requirement inventory expansion. Consumers need explicit disclosure of what vali - IMPLEMENTS → ADR `docs/decisions/adrs/adr-072-validation-and-admission-profiles.md` (ADR-072 validation and admission profiles) - IMPLEMENTS → SPEC `specs/formal/validation-admission-profiles/README.md` (Validation and admission profiles formal specification) - IMPLEMENTS → SPEC `specs/formal/assurance-fulfillment.yaml` (Assurance fulfillment mapping for validation-admission profiles) +- IMPLEMENTS → SPEC `contracts/schemas/profiles/validation-basis-disclosure-v1.json` (validation-basis-disclosure-v1 published schema) diff --git a/docs/requirements/ASR-516/requirement.md b/docs/requirements/ASR-516/requirement.md index 65215fcf4..55a7eee71 100644 --- a/docs/requirements/ASR-516/requirement.md +++ b/docs/requirements/ASR-516/requirement.md @@ -30,8 +30,8 @@ Retains the RAES conformance responsibility while HUB-6 owns cross-product task - IMPLEMENTS → CODE_FILE `implementations/python/packages/raes_conformance/_authoring_observations.py` (Production output admission and incumbent evidence projection) - IMPLEMENTS → CODE_FILE `implementations/python/packages/raes_conformance/conformance/validators.py` (Authoring conformance model registration) - IMPLEMENTS → CONFIG `tools/policy/requirement_order.yaml` (Bounded conformance delivery ownership with retained prerequisites) -- IMPLEMENTS → DOCUMENTATION `contracts/schemas/authoring-adapters/authoring-adapter-vector-v1.json` (Portable vector contract) -- IMPLEMENTS → DOCUMENTATION `contracts/schemas/authoring-adapters/authoring-adapter-comparison-v1.json` (Portable independent-axis comparison contract) +- IMPLEMENTS → SPEC `contracts/schemas/authoring-adapters/authoring-adapter-vector-v1.json` (Portable vector contract) +- IMPLEMENTS → SPEC `contracts/schemas/authoring-adapters/authoring-adapter-comparison-v1.json` (Portable independent-axis comparison contract) - DOCUMENTS → DOCUMENTATION `docs/explain/reference/authoring-adapter-conformance.md` (Consumer API and finite-evidence boundaries) - TESTS → TEST `implementations/python/tests/test_authoring_adapters.py` (Published positive and negative vectors, evidence mutation, bounds and admission regressions) - TESTS → TEST `implementations/python/tests/test_corpus_packaging.py` (Authoring-vector execution from an installed wheel) @@ -39,3 +39,4 @@ Retains the RAES conformance responsibility while HUB-6 owns cross-product task - TESTS → TEST `implementations/python/tests/test_specification_coverage.py` (Source-bound evidence replay after authoring conformance changes) - TESTS → TEST `implementations/python/tests/test_formal_semantic_validation.py` (Current formal replay with immutable historical captures) - TESTS → TEST `implementations/python/tests/test_issue_989_versioned_evidence.py` (Evidence release selection, historical isolation and source integrity) +- IMPLEMENTS → SPEC `contracts/schemas/authoring-adapters/authoring-adapter-profile-v1.json` (authoring-adapter-profile-v1 published schema) diff --git a/docs/requirements/ASR-530/requirement.md b/docs/requirements/ASR-530/requirement.md index 0def1cca1..ece70bd66 100644 --- a/docs/requirements/ASR-530/requirement.md +++ b/docs/requirements/ASR-530/requirement.md @@ -95,3 +95,4 @@ Agent-assisted development can produce internally coherent code and documentatio - IMPLEMENTS → PROOF `docs/research/specification-coverage/bundles/raes-standardized-specification-coverage-issue-1208-v9.json` (Atomic coverage release 9.0.0 for typed selections) - IMPLEMENTS → PROOF `docs/research/formal-semantic-validation/bundles/retest-v15.json` (Current formal replay with historical revisions retained) - IMPLEMENTS → PROOF `docs/research/specification-coverage/bundles/raes-standardized-specification-coverage-issue-1210-v14.json` (Current source-bound coverage replay) +- IMPLEMENTS → SPEC `contracts/schemas/exploit-path-analysis/exploit-path-analysis-evidence-v1.json` (exploit-path-analysis-evidence-v1 published schema) diff --git a/docs/requirements/ASR-535/requirement.md b/docs/requirements/ASR-535/requirement.md index e5148af3c..fb30d01eb 100644 --- a/docs/requirements/ASR-535/requirement.md +++ b/docs/requirements/ASR-535/requirement.md @@ -45,7 +45,7 @@ ADR-081 governs relation discipline and current tests provide bounded evidence, - TESTS → TEST `implementations/python/tests/test_issue_961_participant_opacity.py` (Bounded participant-opacity assurance integration tests) - IMPLEMENTS → GITHUB_ISSUE `961` (Implement bounded participant-opacity profiles and falsification) - IMPLEMENTS → CODE_FILE `implementations/python/packages/raes_processor/participant_opacity/_model_check.py` (Explicit-state participant-opacity model checker) -- IMPLEMENTS → CONFIG `contracts/schemas/formal-analysis/participant-opacity-model-check-evidence-v1.json` (Participant-opacity model-check evidence contract) +- IMPLEMENTS → SPEC `contracts/schemas/formal-analysis/participant-opacity-model-check-evidence-v1.json` (Participant-opacity model-check evidence contract) - TESTS → TEST `implementations/python/tests/test_issue_962_participant_opacity_model_check.py` (Finite participant-opacity model-check tests) - IMPLEMENTS → GITHUB_ISSUE `962` (Issue #962 finite participant-opacity model checking) - IMPLEMENTS → GITHUB_ISSUE `963` (Prove participant-opacity relation theorems under declared assumptions) @@ -54,3 +54,7 @@ ADR-081 governs relation discipline and current tests provide bounded evidence, - VERIFIES → PROOF `specs/formal/participant-semantics/participant-opacity-proof-evidence.json` (Participant-opacity proof evidence record) - IMPLEMENTS → GITHUB_ISSUE `1109` (Make the offline Isabelle sandbox portable on Ubuntu) - DOCUMENTS → DOCUMENTATION `docs/decisions/issue-1109-asr-535-isabelle-sandbox-portability.md` (Pinned proof-runtime allowlist decision) +- IMPLEMENTS → SPEC `contracts/schemas/formal-analysis/participant-opacity-analysis-evidence-v1.json` (participant-opacity-analysis-evidence-v1 published schema) +- IMPLEMENTS → SPEC `contracts/schemas/formal-analysis/participant-opacity-analysis-input-v1.json` (participant-opacity-analysis-input-v1 published schema) +- IMPLEMENTS → SPEC `contracts/schemas/formal-analysis/participant-opacity-model-check-input-v1.json` (participant-opacity-model-check-input-v1 published schema) +- IMPLEMENTS → SPEC `contracts/schemas/profiles/behavioral-relation-profile-v1.json` (behavioral-relation-profile-v1 published schema) diff --git a/docs/requirements/DSL-114/requirement.md b/docs/requirements/DSL-114/requirement.md index 277a23daf..74d1dc66e 100644 --- a/docs/requirements/DSL-114/requirement.md +++ b/docs/requirements/DSL-114/requirement.md @@ -34,3 +34,6 @@ Requirement inventory expansion. The author-facing language needs an explicit su - IMPLEMENTS → CODE_FILE `implementations/python/packages/raes_contracts/contracts/external_concept_bindings.py` (Portable external concept binding contract) - IMPLEMENTS → SPEC `contracts/schemas/concept-authority/external-concept-bindings-v1.json` (Published external concept bindings schema) - DOCUMENTS → GITHUB_ISSUE `OpenRAE/rae#104` (External knowledge reference surface (DSL-114)) +- IMPLEMENTS → SPEC `contracts/schemas/candidate-synthesis/sdl-candidate-synthesis-input-v1.json` (sdl-candidate-synthesis-input-v1 published schema) +- IMPLEMENTS → SPEC `contracts/schemas/candidate-synthesis/sdl-candidate-synthesis-profile-v1.json` (sdl-candidate-synthesis-profile-v1 published schema) +- IMPLEMENTS → SPEC `contracts/schemas/candidate-synthesis/sdl-candidate-synthesis-record-v1.json` (sdl-candidate-synthesis-record-v1 published schema) diff --git a/docs/requirements/EXP-707/requirement.md b/docs/requirements/EXP-707/requirement.md index 650c00e6b..1edb0c3ef 100644 --- a/docs/requirements/EXP-707/requirement.md +++ b/docs/requirements/EXP-707/requirement.md @@ -29,3 +29,5 @@ Requirement inventory expansion. Experiment data capture requirements are distin - IMPLEMENTS → CODE_FILE `implementations/python/packages/raes_processor/trial_compiler/inputs.py` (Digest-bound capture specification admission) - TESTS → TEST `implementations/python/tests/test_sce_002_trial_compiler.py` (Capture specification identity and backend admission tests) - TESTS → TEST `implementations/python/tests/test_issue_1401_media_type_coherence.py` (Required media declarations reject unprovable encodings and accept content-provable JSON encodings) +- IMPLEMENTS → SPEC `contracts/schemas/control-plane/observation-demand-v1.json` (observation-demand-v1 published schema) +- IMPLEMENTS → SPEC `contracts/schemas/experiment-core/experiment-capture-spec-v1.json` (experiment-capture-spec-v1 published schema) diff --git a/docs/requirements/EXP-709/requirement.md b/docs/requirements/EXP-709/requirement.md index 3de46f74f..da33bcf7b 100644 --- a/docs/requirements/EXP-709/requirement.md +++ b/docs/requirements/EXP-709/requirement.md @@ -25,3 +25,4 @@ Requirement inventory expansion. Derived evaluations must stay distinct from the - DOCUMENTS → SPEC `specs/formal/experiment-core/README.md` (Experiment Core Formal Specification) - TESTS → TEST `implementations/python/tests/test_runtime_contracts.py` (Experiment derived measure conformance and rejection tests) - IMPLEMENTS → GITHUB_ISSUE `88` (Experiment evidence & measures (EXP-707, EXP-708, EXP-709, EXP-715)) +- IMPLEMENTS → SPEC `contracts/schemas/experiment-core/experiment-derived-measure-v1.json` (experiment-derived-measure-v1 published schema) diff --git a/docs/requirements/EXP-719/requirement.md b/docs/requirements/EXP-719/requirement.md index e92838467..c646b1013 100644 --- a/docs/requirements/EXP-719/requirement.md +++ b/docs/requirements/EXP-719/requirement.md @@ -18,3 +18,7 @@ The ecosystem shall support first-class treatment, factor, condition, and contro ## Rationale Requirement inventory expansion. Designed variation is a distinct experiment concern and should not be left implicit inside ad hoc run metadata. + +## Traceability + +- IMPLEMENTS → SPEC `contracts/schemas/experiment-core/experiment-binding-descriptors-v1.json` (experiment-binding-descriptors-v1 published schema) diff --git a/docs/requirements/EXP-733/requirement.md b/docs/requirements/EXP-733/requirement.md index 9c4245e32..919159ee6 100644 --- a/docs/requirements/EXP-733/requirement.md +++ b/docs/requirements/EXP-733/requirement.md @@ -24,3 +24,4 @@ Current state: identified gap. If the same scenario can be driven by different p - TESTS → TEST `implementations/python/tests/test_runtime_contracts.py` (Participant provenance schema bundle tests) - DOCUMENTS → ADR `ADR-041` (Participant Implementation Manifest and Provenance Surface) - IMPLEMENTS → SPEC `contracts/schemas/participant-implementation-provenance/participant-implementation-provenance-v1.json` (Participant implementation provenance v1 JSON Schema) +- IMPLEMENTS → SPEC `contracts/schemas/participant-implementation-configuration/participant-configuration-result-v1.json` (participant-configuration-result-v1 published schema) diff --git a/docs/requirements/GOV-903/requirement.md b/docs/requirements/GOV-903/requirement.md index 3589f7bf9..ac4120f19 100644 --- a/docs/requirements/GOV-903/requirement.md +++ b/docs/requirements/GOV-903/requirement.md @@ -104,3 +104,5 @@ Requirement inventory expansion. Evolution requires explicit migration and upgra - IMPLEMENTS → ADR `docs/decisions/adrs/adr-095-participant-decision-epoch-state-cut-and-delivery-semantics.md` (Amended current lineage authority for issue #1210) - TESTS → TEST `implementations/python/tests/test_issue_1076_compute_realization.py` (Current snapshot identity and legacy VM spelling join integrity) +- IMPLEMENTS → SPEC `contracts/schemas/provenance/sdl-lineage-ledger-v1.json` (sdl-lineage-ledger-v1 published schema) +- IMPLEMENTS → SPEC `contracts/schemas/sdl/sdl-semantic-migration-context-v1.json` (sdl-semantic-migration-context-v1 published schema) diff --git a/docs/requirements/GOV-913/requirement.md b/docs/requirements/GOV-913/requirement.md index cd34e104a..1ba175bdd 100644 --- a/docs/requirements/GOV-913/requirement.md +++ b/docs/requirements/GOV-913/requirement.md @@ -189,3 +189,4 @@ Requirement inventory expansion. Reusable ecosystem assets need explicit trust a - TESTS → TEST `implementations/python/tests/test_issue_1205_repository_governance.py` (Retained contract ownership checks without the retired tooling-inventory exception) - IMPLEMENTS → SPEC `specs/formal/participant-semantics/participant-opacity-proof-evidence.json` (Replayed proof evidence bound to the current selected-input and private installer sources) +- IMPLEMENTS → SPEC `contracts/schemas/associated-artifacts/associated-artifact-manifest-v1.json` (associated-artifact-manifest-v1 published schema) diff --git a/docs/requirements/GOV-918/requirement.md b/docs/requirements/GOV-918/requirement.md index f07477679..7e362e487 100644 --- a/docs/requirements/GOV-918/requirement.md +++ b/docs/requirements/GOV-918/requirement.md @@ -59,3 +59,4 @@ Portability breaks down when SDL, processor manifests, backend manifests, and re - TESTS → TEST `implementations/python/tests/test_concept_authority_governance.py` (Concept-authority governance gate tests (failure modes, boundaries, catalog error paths)) - DOCUMENTS → ADR `docs/decisions/adrs/adr-062-concept-authority-catalog-governance-gate.md` (ADR-062: Concept-Authority Catalog Governance Gate) - IMPLEMENTS → GITHUB_ISSUE `496` (Issue #496: Concept authority governance gate — new family requires ADR linkage (review CA-6)) +- IMPLEMENTS → SPEC `contracts/schemas/concept-authority/semantic-projection-report-v1.json` (semantic-projection-report-v1 published schema) diff --git a/docs/requirements/GOV-920/requirement.md b/docs/requirements/GOV-920/requirement.md index 63368f8a5..b3e501357 100644 --- a/docs/requirements/GOV-920/requirement.md +++ b/docs/requirements/GOV-920/requirement.md @@ -27,3 +27,8 @@ Interoperability requires more than nominal support for a schema. Shared semanti - TESTS → TEST `implementations/python/tests/test_runtime_contracts.py` (Semantic profile schema publication tests) - DOCUMENTS → SPEC `specs/concept-authority/semantic-profiles.md` (Shared semantic profiles specification) - DOCUMENTS → DOCUMENTATION `docs/explain/reference/shared-concept-model.md` (Shared semantic profile design guidance) +- IMPLEMENTS → SPEC `contracts/schemas/profiles/domain-profile-admission-policy-v1.json` (domain-profile-admission-policy-v1 published schema) +- IMPLEMENTS → SPEC `contracts/schemas/profiles/domain-profile-binding-v1.json` (domain-profile-binding-v1 published schema) +- IMPLEMENTS → SPEC `contracts/schemas/profiles/domain-profile-definition-v1.json` (domain-profile-definition-v1 published schema) +- IMPLEMENTS → SPEC `contracts/schemas/profiles/domain-profile-resolution-context-v1.json` (domain-profile-resolution-context-v1 published schema) +- IMPLEMENTS → SPEC `contracts/schemas/profiles/domain-profile-support-declaration-v1.json` (domain-profile-support-declaration-v1 published schema) diff --git a/docs/requirements/GOV-942/requirement.md b/docs/requirements/GOV-942/requirement.md index 32b8c1cdf..b0b13c4f6 100644 --- a/docs/requirements/GOV-942/requirement.md +++ b/docs/requirements/GOV-942/requirement.md @@ -35,3 +35,6 @@ Academic review and range integration require a reproducible, machine-checkable - TESTS → TEST `implementations/python/tests/test_behavioral_relations.py` (Behavioral-relation catalog, binding, and counterexample tests) - TESTS → TEST `implementations/python/tests/test_behavioral_relation_claims.py` (Behavioral-relation claim policy tests) - IMPLEMENTS → GITHUB_ISSUE `747` (Define behavioral-relation taxonomy and prevent conformance/equivalence conflation) +- IMPLEMENTS → SPEC `contracts/schemas/concept-authority/behavioral-relations-v1.json` (behavioral-relations-v1 published schema) +- IMPLEMENTS → SPEC `contracts/schemas/profiles/scientific-completeness-assessment-v1.json` (scientific-completeness-assessment-v1 published schema) +- IMPLEMENTS → SPEC `contracts/schemas/profiles/scientific-completeness-taxonomy-v1.json` (scientific-completeness-taxonomy-v1 published schema) diff --git a/docs/requirements/RUN-301/requirement.md b/docs/requirements/RUN-301/requirement.md index 30d24c81e..d76d1669e 100644 --- a/docs/requirements/RUN-301/requirement.md +++ b/docs/requirements/RUN-301/requirement.md @@ -25,3 +25,4 @@ Current state: implemented. A concrete instantiated scenario is needed so later - CONSTRAINS → SPEC `contracts/schemas/sdl/scenario-instantiation-request-v1.json` (Scenario Instantiation Request Schema) - CONSTRAINS → SPEC `contracts/schemas/sdl/instantiated-scenario-v1.json` (Instantiated Scenario Schema) - TESTS → TEST `implementations/python/tests/test_runtime_planner.py` (Runtime Planner Tests) +- IMPLEMENTS → SPEC `contracts/schemas/sdl/scenario-instantiation-request-v1.json` (scenario-instantiation-request-v1 published schema) diff --git a/docs/requirements/RUN-303/requirement.md b/docs/requirements/RUN-303/requirement.md index 9b057f58f..ec6ebe349 100644 --- a/docs/requirements/RUN-303/requirement.md +++ b/docs/requirements/RUN-303/requirement.md @@ -34,3 +34,6 @@ Current state: implemented. Planning needs normative semantics so lifecycle deci - DOCUMENTS → DOCUMENTATION `docs/decisions/issue-1103-bounded-dependency-cycle-detection-preflight.md` (Iterative graph-traversal decision and compatibility boundary) - IMPLEMENTS → CODE_FILE `implementations/python/packages/raes_processor/semantics/planner.py` (Iterative strongly-connected dependency analysis) - TESTS → TEST `implementations/python/tests/test_semantics_planner.py` (Cycle-oracle, long-chain, and deterministic-order regressions) +- IMPLEMENTS → SPEC `contracts/schemas/plans/evaluation-plan-v1.json` (evaluation-plan-v1 published schema) +- IMPLEMENTS → SPEC `contracts/schemas/plans/orchestration-plan-v1.json` (orchestration-plan-v1 published schema) +- IMPLEMENTS → SPEC `contracts/schemas/plans/provisioning-plan-v1.json` (provisioning-plan-v1 published schema) diff --git a/docs/requirements/SEM-207/requirement.md b/docs/requirements/SEM-207/requirement.md index b1d7a9d43..f5f05e366 100644 --- a/docs/requirements/SEM-207/requirement.md +++ b/docs/requirements/SEM-207/requirement.md @@ -34,3 +34,4 @@ Requirement inventory phase. Status audit deferred until the full canonical grap - TESTS → TEST `implementations/python/tests/test_semantics_objectives.py` (Objective semantics analyzer + dependency-partition unit tests (TestObjectiveSemantics, TestObjectiveDependencyPartition)) - TESTS → TEST `implementations/python/tests/test_fm2_semantics.py` (Cross-stage objective-semantics agreement (TestObjectiveSemanticAgreement)) - TESTS → TEST `implementations/python/tests/test_sdl_validator.py` (SDL validator objective-binding tests (TestVerifyObjectives)) +- IMPLEMENTS → SPEC `contracts/schemas/control-plane/proposition-truth-result-v1.json` (proposition-truth-result-v1 published schema) diff --git a/docs/requirements/SEM-218/requirement.md b/docs/requirements/SEM-218/requirement.md index 8a56f81bf..b51280409 100644 --- a/docs/requirements/SEM-218/requirement.md +++ b/docs/requirements/SEM-218/requirement.md @@ -116,7 +116,7 @@ Current state: identified gap. Honest portability requires normative semantics f - IMPLEMENTS → CODE_FILE `implementations/python/packages/raes_contracts/realization_structure/_compatibility_downgrade_helpers.py` (Lossless recursive-to-legacy projection helpers) - IMPLEMENTS → CODE_FILE `implementations/python/packages/raes_contracts/bounded_domains.py` (Nullable scalar-domain support for recursive realization constraints) - IMPLEMENTS → SPEC `specs/sdl/recursive-realization-constraints.md` (Normative recursive authority, collection, reference, limit, and provenance semantics) -- IMPLEMENTS → SCHEMA `contracts/schemas/realization-constraints/recursive-realization-constraint-v1.json` (Published recursive realization constraint contract) +- IMPLEMENTS → SPEC `contracts/schemas/realization-constraints/recursive-realization-constraint-v1.json` (Published recursive realization constraint contract) - TESTS → TEST `implementations/python/tests/test_issue_1203_recursive_normal_form.py` (Nested authority, presence, collections, references, limits, refinement, and abstract-model acceptance coverage) - IMPLEMENTS → CODE_FILE `implementations/python/packages/raes_processor/compiler/realization_structure.py` (Authored leaf and scoped collection lowering for mixed runtime constraints) - IMPLEMENTS → CODE_FILE `implementations/python/packages/raes_processor/compiler/realization_concern_explicitness.py` (Concern-owned leaf selection with non-authoritative aggregate support summaries) @@ -330,3 +330,5 @@ Current state: identified gap. Honest portability requires normative semantics f - TESTS → TEST `implementations/python/tests/test_issue_1208_profile_boundaries.py` - TESTS → TEST `implementations/python/tests/test_issue_1208_self_review.py` - TESTS → TEST `implementations/python/tests/test_issue_1208_overcap.py` +- IMPLEMENTS → SPEC `contracts/schemas/plans/backend-realization-preparation-v1.json` (backend-realization-preparation-v1 published schema) +- IMPLEMENTS → SPEC `contracts/schemas/plans/plan-realization-profiles-v1.json` (plan-realization-profiles-v1 published schema) diff --git a/docs/requirements/SEM-220/requirement.md b/docs/requirements/SEM-220/requirement.md index 51fae6a4b..309069ca6 100644 --- a/docs/requirements/SEM-220/requirement.md +++ b/docs/requirements/SEM-220/requirement.md @@ -30,3 +30,4 @@ Primary-source refresh shows that participant decision surfaces vary materially - TESTS → TEST `implementations/python/tests/test_sem_220_participant_decision_surface.py` (SEM-220 participant decision-surface verification suite) - DOCUMENTS → DOCUMENTATION `docs/explain/sdl/lineage.md` (SEM-220 participant decision-surface lineage and nonclaims) - IMPLEMENTS → GITHUB_ISSUE `295` (Participant Decision-Surface Semantics (SEM-220)) +- IMPLEMENTS → SPEC `contracts/schemas/control-plane/participant-decision-surface-v2.json` (participant-decision-surface-v2 published schema) diff --git a/implementations/python/tests/test_issue_712_contract_requirement_tracing.py b/implementations/python/tests/test_issue_712_contract_requirement_tracing.py new file mode 100644 index 000000000..32c7ef6c5 --- /dev/null +++ b/implementations/python/tests/test_issue_712_contract_requirement_tracing.py @@ -0,0 +1,259 @@ +"""Published-contract requirement tracing gate (issue #712). + +Every published schema must trace to a live governing requirement: an +``IMPLEMENTS → SPEC`` link to its exact path from a requirement record whose +status is ACTIVE or DRAFT. These tests drive the rule through temporary +repositories, then assert that the live tree satisfies it and that the +inventory the gate reads agrees with ``schema_bundle()`` and the publication +catalog. +""" + +from __future__ import annotations + +import importlib +import json +import sys +from pathlib import Path +from types import ModuleType, SimpleNamespace + +import pytest +from raes_contracts.contracts import schema_bundle + +REPO_ROOT = Path(__file__).resolve().parents[3] +if str(REPO_ROOT) not in sys.path: + sys.path.insert(0, str(REPO_ROOT)) + +from tools.check_contract_requirement_tracing import ( # noqa: E402 + MISSING_RULE_ID, + UNREADABLE_RULE_ID, + evaluate_contract_tracing, + main, + published_schema_paths, +) +from tools.check_schema_publication import load_schema_publication_catalog # noqa: E402 + +_STAGE = "policy / published contract requirement tracing" +_SCRIPT = "tools/check_contract_requirement_tracing.py" +_SCHEMA = "contracts/schemas/control-plane/operation-status-v1.json" +_RECORD = "docs/requirements/API-403/requirement.md" + + +def _publish(repo_root: Path, schema_path: str = _SCHEMA) -> str: + target = repo_root / schema_path + target.parent.mkdir(parents=True, exist_ok=True) + target.write_text("{}\n", encoding="utf-8") + return schema_path + + +def _link(identifier: str, link_type: str = "IMPLEMENTS", artifact_type: str = "SPEC") -> str: + return f"- {link_type} → {artifact_type} `{identifier}` (fixture link)" + + +def _requirement(repo_root: Path, uid: str, *links: str, status: str = "ACTIVE") -> Path: + record = repo_root / "docs" / "requirements" / uid / "requirement.md" + record.parent.mkdir(parents=True, exist_ok=True) + lines = ["---", f"id: {uid}", f"status: {status}", "---", "", f"# {uid}", "", "## Traceability", "", *links] + record.write_text("\n".join(lines) + "\n", encoding="utf-8") + return record + + +def _paths(failures: list, rule_id: str) -> set[str | None]: + return {failure.path for failure in failures if failure.rule_id == rule_id} + + +# --- the rule ---------------------------------------------------------------- + + +@pytest.mark.parametrize("status", ["ACTIVE", "DRAFT"]) +def test_a_live_implements_spec_link_traces_the_contract(tmp_path: Path, status: str) -> None: + _publish(tmp_path) + _requirement(tmp_path, "API-403", _link(_SCHEMA), status=status) + + assert evaluate_contract_tracing(tmp_path) == [] + + +@pytest.mark.parametrize("status", ["DEPRECATED", "ARCHIVED"]) +def test_a_retired_owner_never_traces_the_contract(tmp_path: Path, status: str) -> None: + _publish(tmp_path) + _requirement(tmp_path, "API-403", _link(_SCHEMA), status=status) + + assert _paths(evaluate_contract_tracing(tmp_path), MISSING_RULE_ID) == {_SCHEMA} + + +def test_one_live_owner_is_enough_beside_a_retired_one(tmp_path: Path) -> None: + _publish(tmp_path) + _requirement(tmp_path, "API-402", _link(_SCHEMA), status="DEPRECATED") + _requirement(tmp_path, "API-403", _link(_SCHEMA)) + + assert evaluate_contract_tracing(tmp_path) == [] + + +@pytest.mark.parametrize( + "link", + [ + pytest.param(_link(_SCHEMA, artifact_type="CODE_FILE"), id="implements-typed-as-code-file"), + pytest.param(_link(_SCHEMA, artifact_type="CONFIG"), id="implements-typed-as-config"), + pytest.param(_link(_SCHEMA, link_type="CONSTRAINS"), id="constrains-spec"), + pytest.param(_link(_SCHEMA, link_type="DOCUMENTS"), id="documents-spec"), + pytest.param(_link(_SCHEMA, link_type="VERIFIES"), id="verifies-spec"), + pytest.param( + _link("contracts/control-plane/operation-status-v1.json"), + id="implements-spec-on-a-sibling-document", + ), + ], +) +def test_only_an_exact_implements_spec_link_traces_the_contract(tmp_path: Path, link: str) -> None: + _publish(tmp_path) + _requirement(tmp_path, "API-403", link) + + assert _paths(evaluate_contract_tracing(tmp_path), MISSING_RULE_ID) == {_SCHEMA} + + +def test_an_untraced_contract_is_reported_by_id_at_its_exact_path(tmp_path: Path) -> None: + _publish(tmp_path) + + [failure] = evaluate_contract_tracing(tmp_path) + + assert (failure.rule_id, failure.path) == (MISSING_RULE_ID, _SCHEMA) + assert "operation-status-v1" in failure.message + + +def _malformed_link(repo_root: Path) -> str: + _requirement(repo_root, "API-403", f"- IMPLEMENTS → SPEC {_SCHEMA}") + return _RECORD + + +def _symlinked_record(repo_root: Path) -> str: + real = _requirement(repo_root / "elsewhere", "API-403", _link(_SCHEMA)) + record = repo_root / _RECORD + record.parent.mkdir(parents=True) + record.symlink_to(real) + return _RECORD + + +def _non_canonical_directory(repo_root: Path) -> str: + _requirement(repo_root, "notes", _link(_SCHEMA)) + return "docs/requirements/notes/requirement.md" + + +@pytest.mark.parametrize("make_record", [_malformed_link, _symlinked_record, _non_canonical_directory]) +def test_an_unreadable_requirement_record_fails_closed_and_owns_nothing(tmp_path: Path, make_record) -> None: + _publish(tmp_path) + record = make_record(tmp_path) + + failures = evaluate_contract_tracing(tmp_path) + + assert _paths(failures, UNREADABLE_RULE_ID) == {record} + assert _paths(failures, MISSING_RULE_ID) == {_SCHEMA} + + +# --- CLI and reporting ------------------------------------------------------- + + +def test_cli_emits_json_naming_each_untraced_contract(tmp_path: Path, capsys: pytest.CaptureFixture[str]) -> None: + _publish(tmp_path) + + assert main(["--repo-root", str(tmp_path), "--json"]) == 1 + payload = json.loads(capsys.readouterr().out) + assert [(item["rule_id"], item["path"]) for item in payload] == [(MISSING_RULE_ID, _SCHEMA)] + + +def test_cli_text_mode_reports_on_stderr_and_passes_a_traced_tree( + tmp_path: Path, capsys: pytest.CaptureFixture[str] +) -> None: + _publish(tmp_path) + + assert main(["--repo-root", str(tmp_path)]) == 1 + assert f"[{MISSING_RULE_ID}] {_SCHEMA}:" in capsys.readouterr().err + + _requirement(tmp_path, "API-403", _link(_SCHEMA)) + assert main(["--repo-root", str(tmp_path)]) == 0 + + +def test_a_shared_policy_waiver_suppresses_only_the_named_finding(tmp_path: Path) -> None: + _publish(tmp_path) + other = _publish(tmp_path, "contracts/schemas/control-plane/operation-receipt-v1.json") + waivers = tmp_path / "tools" / "policy" / "exceptions.yaml" + waivers.parent.mkdir(parents=True) + waivers.write_text(f"exceptions:\n - rule_id: {MISSING_RULE_ID}\n paths: [{_SCHEMA}]\n", encoding="utf-8") + + assert main(["--repo-root", str(tmp_path)]) == 1 + _requirement(tmp_path, "API-403", _link(other)) + assert main(["--repo-root", str(tmp_path)]) == 0 + + +def test_report_names_owners_untraced_contracts_and_unreadable_records_without_gating( + tmp_path: Path, capsys: pytest.CaptureFixture[str] +) -> None: + traced = _publish(tmp_path) + untraced = _publish(tmp_path, "contracts/schemas/control-plane/operation-receipt-v1.json") + _requirement(tmp_path, "API-403", _link(traced)) + _requirement(tmp_path, "API-404", _link(traced), status="DRAFT") + _requirement(tmp_path, "API-402", "- not a link record") + + assert main(["--repo-root", str(tmp_path), "--report"]) == 0 + report = capsys.readouterr().out + assert f"{traced}: API-403, API-404" in report + assert f"{untraced}: UNTRACED" in report + assert f"[{UNREADABLE_RULE_ID}] docs/requirements/API-402/requirement.md" in report + + +# --- policy-lane wiring ------------------------------------------------------ + + +class _Reporter: + def __init__(self) -> None: + self.runs: list[str] = [] + self.skips: list[str] = [] + + def run(self, name: str, func: object, *, detail: str = "") -> None: + del detail + self.runs.append(name) + assert callable(func) + func() + + def skip(self, name: str, reason: str) -> None: + del reason + self.skips.append(name) + + +@pytest.fixture +def policy_lanes(monkeypatch: pytest.MonkeyPatch) -> ModuleType: + """Import the lane module against a stand-in ``nox``; the project env has none.""" + + monkeypatch.setitem(sys.modules, "nox", SimpleNamespace(Session=object)) + for name in [name for name in sys.modules if name.startswith("tools.nox_support")]: + monkeypatch.delitem(sys.modules, name) + return importlib.import_module("tools.nox_support.policy_lanes") + + +def test_policy_lane_runs_the_gate_on_the_working_tree_and_skips_it_when_staged( + monkeypatch: pytest.MonkeyPatch, policy_lanes: ModuleType +) -> None: + scripts: list[str] = [] + monkeypatch.setattr(policy_lanes, "_run_project_python", lambda _session, script, *_args: scripts.append(script)) + + working_tree = _Reporter() + policy_lanes._run_working_tree_policies(SimpleNamespace(), working_tree, staged=False, adr_pin_args=[]) + staged = _Reporter() + policy_lanes._run_working_tree_policies(SimpleNamespace(), staged, staged=True, adr_pin_args=[]) + + assert _STAGE in working_tree.runs + assert _SCRIPT in scripts + assert _STAGE in staged.skips + assert _STAGE not in staged.runs + + +# --- the live tree ----------------------------------------------------------- + + +def test_checked_in_repository_traces_every_published_contract() -> None: + assert evaluate_contract_tracing(REPO_ROOT) == [] + + +def test_the_gate_inventory_agrees_with_schema_bundle_and_the_publication_catalog() -> None: + inventory = published_schema_paths(REPO_ROOT) + catalog = sorted(entry["schema_path"] for entry in load_schema_publication_catalog(REPO_ROOT)["schemas"]) + + assert inventory == catalog + assert sorted(Path(schema_path).stem for schema_path in inventory) == sorted(schema_bundle()) diff --git a/tools/check_contract_requirement_tracing.py b/tools/check_contract_requirement_tracing.py new file mode 100644 index 000000000..b01adc2be --- /dev/null +++ b/tools/check_contract_requirement_tracing.py @@ -0,0 +1,180 @@ +#!/usr/bin/env python3 +# ruff: noqa: E402, I001 +"""Structural gate: every published contract traces to a live governing requirement. + +``ADR-009`` §7 makes ``contracts/schemas/`` the normative contract authority, and +``check_schema_publication.py`` and ``check_schema_coverage.py`` prove that each +published schema is inventoried and exercised. Neither asks which requirement +governs it, so a schema could be published, and stay published, with no +requirement owning it (issue #712). This gate asks that question over the whole +published inventory on every run, not over the changed-file set. + +A published contract is **traced** when at least one requirement record under +``docs/requirements//requirement.md`` whose status is ACTIVE or DRAFT +carries an ``IMPLEMENTS → SPEC`` link to the contract's exact schema path. + +- ``CODE_FILE`` links never count. A module such as + ``raes_contracts/contracts/bundle.py`` generates every contract, so a module + link cannot say which contract a requirement governs. +- Other link types never count. ``CONSTRAINS``, ``DOCUMENTS``, ``TESTS``, and + ``VERIFIES`` record a relation other than ownership, and an ``IMPLEMENTS`` + link typed as anything but ``SPEC`` is a classification error to correct. +- DRAFT owners qualify and DEPRECATED or ARCHIVED owners never do. That is the + status rule ``requirement_governance.py`` applies to implementation work. + +The inventory is every ``contracts/schemas/**/*.json`` file. The contracts lane +already fails when that tree disagrees with ``schema_bundle()`` +(``check_generated_schemas.py``) or with the publication manifest +(``check_schema_publication.py``), so this gate reads the tree and does not +regenerate the bundle. Requirement records are read offline through +``RepositoryRequirementClient``, the authority ``requirement_order.yaml`` +selects. An unreadable record fails closed rather than counting as untraced. + +``--report`` prints the owners of each published contract and never gates. +Failures use ``tools.policy.common.PolicyFailure``. The CLI honours ``--json`` +and the shared ``tools/policy/exceptions.yaml`` waiver mechanism, like the other +``policy`` nox-stage entry points. +""" + +from __future__ import annotations + +import argparse +import sys +from collections import defaultdict +from pathlib import Path + +REPO_ROOT = Path(__file__).resolve().parents[1] +if str(REPO_ROOT) not in sys.path: + sys.path.insert(0, str(REPO_ROOT)) + +from tools.policy.common import PolicyFailure, apply_exceptions, failures_to_json, load_exceptions +from tools.policy.repository_requirements import RepositoryRequirementClient, RepositoryRequirementError + +__all__ = [ + "GOVERNING_LINK", + "MISSING_RULE_ID", + "RETIRED_STATUSES", + "UNREADABLE_RULE_ID", + "build_tracing_report", + "evaluate_contract_tracing", + "governing_owners", + "main", + "published_schema_paths", +] + +SCHEMAS_ROOT = "contracts/schemas" +REQUIREMENTS_ROOT = "docs/requirements" +GOVERNING_LINK = ("IMPLEMENTS", "SPEC") +RETIRED_STATUSES = frozenset({"ARCHIVED", "DEPRECATED"}) +MISSING_RULE_ID = "contract-requirement-trace-missing" +UNREADABLE_RULE_ID = "contract-requirement-record-unreadable" + + +def published_schema_paths(repo_root: Path = REPO_ROOT) -> list[str]: + """Return every published schema as a sorted repository-relative path.""" + + schemas_root = repo_root / SCHEMAS_ROOT + return sorted(path.relative_to(repo_root).as_posix() for path in schemas_root.rglob("*.json")) + + +def _requirement_uids(repo_root: Path) -> list[str]: + requirements_root = repo_root / REQUIREMENTS_ROOT + if not requirements_root.is_dir(): + return [] + return sorted(path.name for path in requirements_root.iterdir() if path.is_dir()) + + +def _governing_identifiers(client: RepositoryRequirementClient, uid: str) -> list[str]: + """Return the ``IMPLEMENTS → SPEC`` identifiers one requirement can own.""" + + if client.get_requirement("", uid)["status"] in RETIRED_STATUSES: + return [] + return [ + link["artifact_identifier"] + for link in client.get_traceability(uid) + if (link["link_type"], link["artifact_type"]) == GOVERNING_LINK + ] + + +def governing_owners(repo_root: Path = REPO_ROOT) -> tuple[dict[str, set[str]], list[PolicyFailure]]: + """Map each governed artifact to its live owners, failing closed on unreadable records.""" + + client = RepositoryRequirementClient(repo_root) + owners: dict[str, set[str]] = defaultdict(set) + failures: list[PolicyFailure] = [] + for uid in _requirement_uids(repo_root): + try: + identifiers = _governing_identifiers(client, uid) + except RepositoryRequirementError as exc: + failures.append(PolicyFailure(UNREADABLE_RULE_ID, str(exc), f"{REQUIREMENTS_ROOT}/{uid}/requirement.md")) + continue + for identifier in identifiers: + owners[identifier].add(uid) + return dict(owners), failures + + +def evaluate_contract_tracing(repo_root: Path = REPO_ROOT) -> list[PolicyFailure]: + """Return every published contract with no live ``IMPLEMENTS → SPEC`` owner.""" + + owners, failures = governing_owners(repo_root) + failures.extend( + PolicyFailure( + MISSING_RULE_ID, + f"published contract {Path(schema_path).stem} has no IMPLEMENTS → SPEC link " + "from an ACTIVE or DRAFT requirement", + schema_path, + ) + for schema_path in published_schema_paths(repo_root) + if schema_path not in owners + ) + return failures + + +def build_tracing_report(repo_root: Path = REPO_ROOT) -> str: + """Render the owners of every published contract. Never gates.""" + + owners, failures = governing_owners(repo_root) + lines = ["Published-contract requirement tracing report (issue #712)", ""] + for schema_path in published_schema_paths(repo_root): + lines.append(f" - {schema_path}: {', '.join(sorted(owners.get(schema_path, ()))) or 'UNTRACED'}") + lines.extend(f" - {failure.render()}" for failure in failures) + return "\n".join(lines) + "\n" + + +def _active_waivers(repo_root: Path) -> list[dict]: + exceptions_file = repo_root / "tools" / "policy" / "exceptions.yaml" + return load_exceptions(repo_root) if exceptions_file.is_file() else [] + + +def _print_failures(failures: list[PolicyFailure], *, as_json: bool) -> None: + if as_json: + print(failures_to_json(failures)) + return + for failure in failures: + print(failure.render(), file=sys.stderr) + + +def parse_args(argv: list[str] | None) -> argparse.Namespace: + parser = argparse.ArgumentParser( + description="Require every published contract to trace to a live governing requirement (issue #712)." + ) + parser.add_argument("--repo-root", type=Path, default=REPO_ROOT, help="Repository root to check.") + parser.add_argument("--json", action="store_true", help="Emit failures as JSON on stdout.") + parser.add_argument("--report", action="store_true", help="Print each contract's owners and exit 0.") + return parser.parse_args(argv) + + +def main(argv: list[str] | None = None) -> int: + args = parse_args(argv) + if args.report: + print(build_tracing_report(args.repo_root), end="") + return 0 + failures = apply_exceptions(evaluate_contract_tracing(args.repo_root), _active_waivers(args.repo_root)) + if failures: + _print_failures(failures, as_json=args.json) + return 1 + return 0 + + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/tools/nox_support/policy_lanes.py b/tools/nox_support/policy_lanes.py index 19be0307b..58007f200 100644 --- a/tools/nox_support/policy_lanes.py +++ b/tools/nox_support/policy_lanes.py @@ -39,6 +39,7 @@ ("policy / agent guidance profile", "tools/check_agent_guidance.py"), ("policy / example library catalog", "tools/check_example_library.py"), ("policy / published schema coverage", "tools/check_schema_coverage.py"), + ("policy / published contract requirement tracing", "tools/check_contract_requirement_tracing.py"), ("policy / project positioning", "tools/check_project_positioning.py"), ("policy / identity cutover", "tools/check_identity_cutover.py"), ) From 8b1cf134c3c689acee7e8e80bc7270e9f8c240ec Mon Sep 17 00:00:00 2001 From: Yernat Yestekov <2068106+doublewhy@users.noreply.github.com> Date: Thu, 8 Oct 2026 23:20:24 -0700 Subject: [PATCH 2/6] ci(policy): give the waiver and failure annotations their type arguments --- .../tests/test_issue_712_contract_requirement_tracing.py | 3 ++- tools/check_contract_requirement_tracing.py | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/implementations/python/tests/test_issue_712_contract_requirement_tracing.py b/implementations/python/tests/test_issue_712_contract_requirement_tracing.py index 32c7ef6c5..7bba87e8f 100644 --- a/implementations/python/tests/test_issue_712_contract_requirement_tracing.py +++ b/implementations/python/tests/test_issue_712_contract_requirement_tracing.py @@ -31,6 +31,7 @@ published_schema_paths, ) from tools.check_schema_publication import load_schema_publication_catalog # noqa: E402 +from tools.policy.common import PolicyFailure # noqa: E402 _STAGE = "policy / published contract requirement tracing" _SCRIPT = "tools/check_contract_requirement_tracing.py" @@ -57,7 +58,7 @@ def _requirement(repo_root: Path, uid: str, *links: str, status: str = "ACTIVE") return record -def _paths(failures: list, rule_id: str) -> set[str | None]: +def _paths(failures: list[PolicyFailure], rule_id: str) -> set[str | None]: return {failure.path for failure in failures if failure.rule_id == rule_id} diff --git a/tools/check_contract_requirement_tracing.py b/tools/check_contract_requirement_tracing.py index b01adc2be..b5eeed4cf 100644 --- a/tools/check_contract_requirement_tracing.py +++ b/tools/check_contract_requirement_tracing.py @@ -141,7 +141,7 @@ def build_tracing_report(repo_root: Path = REPO_ROOT) -> str: return "\n".join(lines) + "\n" -def _active_waivers(repo_root: Path) -> list[dict]: +def _active_waivers(repo_root: Path) -> list[dict[str, object]]: exceptions_file = repo_root / "tools" / "policy" / "exceptions.yaml" return load_exceptions(repo_root) if exceptions_file.is_file() else [] From 9bdae90a16a2a44f7da5a65483db950602577b07 Mon Sep 17 00:00:00 2001 From: Yernat Yestekov <2068106+doublewhy@users.noreply.github.com> Date: Fri, 9 Oct 2026 03:44:30 -0700 Subject: [PATCH 3/6] ci(policy): narrow the IMPLEMENTS retyping rule and add RUN-311 as episode owner An IMPLEMENTS link to a schema path typed CONFIG, SCHEMA, or DOCUMENTATION does not count as ownership and is retyped to SPEC only where it records ownership. The reference page and the checker docstring no longer call every such link a classification error: the 19 that remain record a narrower relation on contracts that already have a SPEC owner, and stay as they are. RUN-311 gains IMPLEMENTS -> SPEC links to the two participant-episode schemas, which commit 9dbbb87f published for RUN-311. The reference page now says that a requirement-governed branch must keep the edited record inside the ownership roots of its governing requirement's phase, and counts the publishing commit as declaring evidence. The negative tests add TESTS links and IMPLEMENTS links typed SCHEMA or DOCUMENTATION, and assert that each record was read. --- .../published-contract-requirement-tracing.md | 18 ++++++++++++++---- docs/requirements/RUN-311/requirement.md | 2 ++ ...t_issue_712_contract_requirement_tracing.py | 8 +++++++- tools/check_contract_requirement_tracing.py | 5 +++-- 4 files changed, 26 insertions(+), 7 deletions(-) diff --git a/docs/explain/reference/published-contract-requirement-tracing.md b/docs/explain/reference/published-contract-requirement-tracing.md index 3000e93f4..c6de04041 100644 --- a/docs/explain/reference/published-contract-requirement-tracing.md +++ b/docs/explain/reference/published-contract-requirement-tracing.md @@ -23,8 +23,11 @@ carries this link to the contract's exact schema path: - **Only `IMPLEMENTS → SPEC` counts.** `CONSTRAINS`, `DOCUMENTS`, `TESTS`, and `VERIFIES` links record a relation other than ownership. An `IMPLEMENTS` link - to a schema path typed as `CONFIG`, `SCHEMA`, or `DOCUMENTATION` is a - classification error; correct its artifact type to `SPEC`. + to a schema path typed as `CONFIG`, `SCHEMA`, or `DOCUMENTATION` does not + count as ownership either. Retype it to `SPEC` only where it records that the + requirement owns the contract. Some such links record a narrower relation, + such as the vocabulary or temporal rules one requirement adds to a shared SDL + schema; leave those as they are. - **`CODE_FILE` links never count.** A module link cannot say which contract a requirement governs. `raes_contracts/contracts/bundle.py` generates every published contract and several requirements link it as a `CODE_FILE`, so @@ -70,12 +73,19 @@ a new schema. Choose the owner by evidence, strongest first: 1. A live requirement already records the exact schema path under another link or artifact type, or links the contract's own catalog or publication record. -2. The pull request that published the schema, or its issue, declared the - requirement. +2. The pull request or commit that published the schema, or its issue, + declared the requirement. 3. The requirement's statement names the contract's subject. Prefer a requirement that also links the contract's defining module, tests, or governing ADR. +On a branch that requirement governance checks, the edited record is a changed +file like any other. Where `tools/policy/requirement_order.yaml` maps ownership +roots to the phase of a requirement governing the branch, including one a scope +file binds the record to, the record must fall inside them. Otherwise +governance reports `requirement-ownership-mismatch`. Some phases, such as +`runtime-core`, own schema paths but not their own requirement records. + Do not link a requirement only to turn the gate green. Do not waive a finding through `tools/policy/exceptions.yaml` because a repair is inconvenient. The waiver mechanism exists for a finding that is factually wrong. diff --git a/docs/requirements/RUN-311/requirement.md b/docs/requirements/RUN-311/requirement.md index 136cd2be8..ef9de2920 100644 --- a/docs/requirements/RUN-311/requirement.md +++ b/docs/requirements/RUN-311/requirement.md @@ -29,3 +29,5 @@ Primary-source refresh shows that participant-supporting runtimes commonly depen - TESTS → TEST `implementations/python/tests/test_runtime_registry.py` (Registry shape validation for participant_runtime field) - IMPLEMENTS → GITHUB_ISSUE `599` (Issue 599 participant implementation action admission binding) - IMPLEMENTS → PULL_REQUEST `617` (PR 617 participant implementation action admission binding) +- IMPLEMENTS → SPEC `contracts/schemas/control-plane/participant-episode-history-event-stream-v1.json` (participant-episode-history-event-stream-v1 published schema) +- IMPLEMENTS → SPEC `contracts/schemas/control-plane/participant-episode-state-envelope-v1.json` (participant-episode-state-envelope-v1 published schema) diff --git a/implementations/python/tests/test_issue_712_contract_requirement_tracing.py b/implementations/python/tests/test_issue_712_contract_requirement_tracing.py index 7bba87e8f..bb48e56cb 100644 --- a/implementations/python/tests/test_issue_712_contract_requirement_tracing.py +++ b/implementations/python/tests/test_issue_712_contract_requirement_tracing.py @@ -94,8 +94,11 @@ def test_one_live_owner_is_enough_beside_a_retired_one(tmp_path: Path) -> None: [ pytest.param(_link(_SCHEMA, artifact_type="CODE_FILE"), id="implements-typed-as-code-file"), pytest.param(_link(_SCHEMA, artifact_type="CONFIG"), id="implements-typed-as-config"), + pytest.param(_link(_SCHEMA, artifact_type="SCHEMA"), id="implements-typed-as-schema"), + pytest.param(_link(_SCHEMA, artifact_type="DOCUMENTATION"), id="implements-typed-as-documentation"), pytest.param(_link(_SCHEMA, link_type="CONSTRAINS"), id="constrains-spec"), pytest.param(_link(_SCHEMA, link_type="DOCUMENTS"), id="documents-spec"), + pytest.param(_link(_SCHEMA, link_type="TESTS"), id="tests-spec"), pytest.param(_link(_SCHEMA, link_type="VERIFIES"), id="verifies-spec"), pytest.param( _link("contracts/control-plane/operation-status-v1.json"), @@ -107,7 +110,10 @@ def test_only_an_exact_implements_spec_link_traces_the_contract(tmp_path: Path, _publish(tmp_path) _requirement(tmp_path, "API-403", link) - assert _paths(evaluate_contract_tracing(tmp_path), MISSING_RULE_ID) == {_SCHEMA} + failures = evaluate_contract_tracing(tmp_path) + + assert _paths(failures, UNREADABLE_RULE_ID) == set() + assert _paths(failures, MISSING_RULE_ID) == {_SCHEMA} def test_an_untraced_contract_is_reported_by_id_at_its_exact_path(tmp_path: Path) -> None: diff --git a/tools/check_contract_requirement_tracing.py b/tools/check_contract_requirement_tracing.py index b5eeed4cf..6a6f978fa 100644 --- a/tools/check_contract_requirement_tracing.py +++ b/tools/check_contract_requirement_tracing.py @@ -17,8 +17,9 @@ ``raes_contracts/contracts/bundle.py`` generates every contract, so a module link cannot say which contract a requirement governs. - Other link types never count. ``CONSTRAINS``, ``DOCUMENTS``, ``TESTS``, and - ``VERIFIES`` record a relation other than ownership, and an ``IMPLEMENTS`` - link typed as anything but ``SPEC`` is a classification error to correct. + ``VERIFIES`` record a relation other than ownership. An ``IMPLEMENTS`` link + to a schema path typed ``CONFIG``, ``SCHEMA``, or ``DOCUMENTATION`` does not + count either; retype it to ``SPEC`` only where it records ownership. - DRAFT owners qualify and DEPRECATED or ARCHIVED owners never do. That is the status rule ``requirement_governance.py`` applies to implementation work. From f9980e09f150584b848c8de0a96fee123ae2c8c9 Mon Sep 17 00:00:00 2001 From: Yernat Yestekov <2068106+doublewhy@users.noreply.github.com> Date: Sun, 11 Oct 2026 18:43:37 -0700 Subject: [PATCH 4/6] ci(policy): trace the mixed-backend contracts from #1442 to API-407 PR #1442 published mixed-backend-execution-binding-v1 and mixed-backend-stage-report-v1 after this branch was cut, so the tracing gate reported both as untraced once the branch was rebased onto dev. API-407 owns both. Issue #1371, which #1442 implements, asks to "Update API-407 contracts" for these carriers, and #1442 states the rules for both contracts under the API-407 section of specs/formal/runtime-contracts/participant-backend-contracts.md. The API-407 statement requires the installed mapping, bridge, time-coordination and readback services that the binding pins and the stage reports evidence to be checked in context, and API-407 already owns mixed-participant-composition-profile-v1 and links the issue #1355 runtime modules whose carriers #1442 published. --- docs/requirements/API-407/requirement.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/requirements/API-407/requirement.md b/docs/requirements/API-407/requirement.md index a3a695f91..309551236 100644 --- a/docs/requirements/API-407/requirement.md +++ b/docs/requirements/API-407/requirement.md @@ -79,3 +79,5 @@ Requirement inventory expansion. Participant-feature boundaries need to be expli - IMPLEMENTS → CODE_FILE `implementations/python/packages/raes_runtime/mixed_runtime_handoff_execution.py` (Effective native transfer and time-service readback enforcement) - IMPLEMENTS → CODE_FILE `implementations/python/packages/raes_runtime/mixed_runtime_result.py` (Evidence-bounded outcome settlement) - TESTS → TEST `implementations/python/tests/test_issue_1355_mixed_mapping_time.py` (Missing support, stale time, mapped execution, and evidenced stage witnesses) +- IMPLEMENTS → SPEC `contracts/schemas/control-plane/mixed-backend-execution-binding-v1.json` (mixed-backend-execution-binding-v1 published schema) +- IMPLEMENTS → SPEC `contracts/schemas/control-plane/mixed-backend-stage-report-v1.json` (mixed-backend-stage-report-v1 published schema) From 4001d9c33598dcdfca6408d41f84d934abeb481b Mon Sep 17 00:00:00 2001 From: Yernat Yestekov <2068106+doublewhy@users.noreply.github.com> Date: Mon, 12 Oct 2026 19:12:02 +0000 Subject: [PATCH 5/6] ci(policy): trace the inject contracts from #1449 to DSL-111 and DSL-142 PR #1449 published inject-trigger-request-v1, inject-occurrence-v1, inject-occurrence-outcome-v1 and inject-occurrence-correlation-v1 after this branch was cut, so the tracing gate reported all four as untraced once the branch was rebased onto dev. Neither #1449 nor issue #1366 declared a requirement, so each owner follows from its statement and the governing specification. #1449's reference page names ADR-112 and EI-01 to EI-06 in specs/sdl/external-injects.md as the contracts' authority, and EI-06 says that DSL-111 owns authored narrative identity and the occurrence relation and DSL-142 owns optional participant binding. DSL-111 owns the request, occurrence and outcome contracts. Its statement requires authorized external requests to instantiate authored injects as independently identified occurrences, prevents duplicate logical execution through retry keys, occurrence identities and scheduled slots, and keeps admission, refusal, application, partial and indeterminate outcomes distinct. It already links ADR-112 and the EI specification. DSL-142 owns the correlation contract. Its statement requires a participant delivery composed with an externally triggered world effect to join that effect's exact occurrence and produced result, which is the identity set the correlation carries for participant consumers. --- docs/requirements/DSL-111/requirement.md | 3 +++ docs/requirements/DSL-142/requirement.md | 1 + 2 files changed, 4 insertions(+) diff --git a/docs/requirements/DSL-111/requirement.md b/docs/requirements/DSL-111/requirement.md index 96ef35f8c..a7dc699f5 100644 --- a/docs/requirements/DSL-111/requirement.md +++ b/docs/requirements/DSL-111/requirement.md @@ -66,3 +66,6 @@ by the [compatibility contract](../../explain/sdl/external-inject-compatibility. - TESTS → TEST `implementations/python/tests/test_runtime_models.py` (Runtime model tests for inject bindings and orchestration window resolution) - TESTS → TEST `implementations/python/tests/test_runtime_planner.py` (Planner tests for inject, event, script, and story scheduling behavior) - TESTS → TEST `implementations/python/tests/test_sdl_realworld.py` (Real-world scenarios exercising nested entities and timeline orchestration together) +- IMPLEMENTS → SPEC `contracts/schemas/control-plane/inject-trigger-request-v1.json` (inject-trigger-request-v1 published schema) +- IMPLEMENTS → SPEC `contracts/schemas/control-plane/inject-occurrence-v1.json` (inject-occurrence-v1 published schema) +- IMPLEMENTS → SPEC `contracts/schemas/control-plane/inject-occurrence-outcome-v1.json` (inject-occurrence-outcome-v1 published schema) diff --git a/docs/requirements/DSL-142/requirement.md b/docs/requirements/DSL-142/requirement.md index 66fd24c32..e63eb3745 100644 --- a/docs/requirements/DSL-142/requirement.md +++ b/docs/requirements/DSL-142/requirement.md @@ -94,3 +94,4 @@ backend execution, delivery or observation. - TESTS → TEST `implementations/python/tests/test_dsl_142_participant_inject_delivery.py` (DSL-142 participant inject delivery tests) - IMPLEMENTS → SPEC `contracts/schemas/sdl/instantiated-scenario-v1.json` (DSL-142 governed instantiated scenario schema) - TESTS → TEST `implementations/python/tests/test_sdl_catalog_parity.py` (DSL-142 SDL catalog parity tests) +- IMPLEMENTS → SPEC `contracts/schemas/control-plane/inject-occurrence-correlation-v1.json` (inject-occurrence-correlation-v1 published schema) From efc217de9d5913ef56f9e318435fa306a29bcb27 Mon Sep 17 00:00:00 2001 From: Brad Edwards Date: Wed, 14 Oct 2026 07:48:53 +0200 Subject: [PATCH 6/6] fix(policy): allow contract owners to maintain their requirement records --- .../published-contract-requirement-tracing.md | 18 ++- ..._issue_712_contract_requirement_tracing.py | 152 ++++++++++++++++++ tools/policy/requirement_governance.py | 15 +- 3 files changed, 176 insertions(+), 9 deletions(-) diff --git a/docs/explain/reference/published-contract-requirement-tracing.md b/docs/explain/reference/published-contract-requirement-tracing.md index c6de04041..4cfaa5bbc 100644 --- a/docs/explain/reference/published-contract-requirement-tracing.md +++ b/docs/explain/reference/published-contract-requirement-tracing.md @@ -79,12 +79,18 @@ a new schema. Choose the owner by evidence, strongest first: requirement that also links the contract's defining module, tests, or governing ADR. -On a branch that requirement governance checks, the edited record is a changed -file like any other. Where `tools/policy/requirement_order.yaml` maps ownership -roots to the phase of a requirement governing the branch, including one a scope -file binds the record to, the record must fall inside them. Otherwise -governance reports `requirement-ownership-mismatch`. Some phases, such as -`runtime-core`, own schema paths but not their own requirement records. +Requirement governance admits the evaluated requirement's exact canonical +record, `docs/requirements//requirement.md`, alongside its phase's mapped +ownership roots. A contract owner can therefore add its traceability link in +the publishing change even when its phase, such as `runtime-core`, does not +list that record. Other requirement records and files still need the phase's +existing ownership permissions. Requirement status, prerequisite order, and +code/test traceability checks still apply. + +When an issue-bound scope file assigns the edited record, bind it to its own +requirement UID. Each assigned owner is checked independently. The self-record +permission applies only to that owner's exact record; other assignments must +satisfy the phase's existing mapped ownership roots. Do not link a requirement only to turn the gate green. Do not waive a finding through `tools/policy/exceptions.yaml` because a repair is inconvenient. The diff --git a/implementations/python/tests/test_issue_712_contract_requirement_tracing.py b/implementations/python/tests/test_issue_712_contract_requirement_tracing.py index bb48e56cb..fe75dbe0e 100644 --- a/implementations/python/tests/test_issue_712_contract_requirement_tracing.py +++ b/implementations/python/tests/test_issue_712_contract_requirement_tracing.py @@ -12,6 +12,7 @@ import importlib import json +import shutil import sys from pathlib import Path from types import ModuleType, SimpleNamespace @@ -32,6 +33,9 @@ ) from tools.check_schema_publication import load_schema_publication_catalog # noqa: E402 from tools.policy.common import PolicyFailure # noqa: E402 +from tools.policy.repository_requirements import RepositoryRequirementClient # noqa: E402 +from tools.policy.requirement_governance import evaluate_requirement_governance # noqa: E402 +from tools.policy.requirement_scope import evaluate_requirement_scope, parse_requirement_scope # noqa: E402 _STAGE = "policy / published contract requirement tracing" _SCRIPT = "tools/check_contract_requirement_tracing.py" @@ -251,6 +255,154 @@ def test_policy_lane_runs_the_gate_on_the_working_tree_and_skips_it_when_staged( assert _STAGE not in staged.runs +# --- owner-record governance ------------------------------------------------- + + +@pytest.fixture +def governed_repo(tmp_path: Path) -> Path: + policy_dir = tmp_path / "tools" / "policy" + policy_dir.mkdir(parents=True) + shutil.copyfile(REPO_ROOT / "tools/policy/requirement_order.yaml", policy_dir / "requirement_order.yaml") + (policy_dir / "exceptions.yaml").write_text("exceptions: []\n", encoding="utf-8") + for uid in ( + "GOV-917", + "GOV-918", + "GOV-919", + "GOV-920", + "GOV-921", + "GOV-922", + "API-412", + "API-413", + "RUN-300", + "RUN-311", + "RUN-313", + "RUN-314", + "RUN-315", + ): + _requirement(tmp_path, uid) + return tmp_path + + +@pytest.mark.parametrize( + ("uid", "schema_path"), + [ + ("RUN-300", _SCHEMA), + ("RUN-311", _SCHEMA), + ("API-412", "contracts/schemas/processor-manifest/processor-manifest-v2.json"), + ("GOV-918", "contracts/schemas/concept-authority/semantic-projection-report-v1.json"), + ("DSL-105", "contracts/schemas/sdl/sdl-authoring-input-v1.json"), + ("SEM-209", "contracts/schemas/sdl/sdl-authoring-input-v1.json"), + ("EXP-701", "contracts/schemas/experiment-core/experiment-run-v1.json"), + ], +) +def test_a_new_contract_and_its_owner_record_pass_both_gates(governed_repo: Path, uid: str, schema_path: str) -> None: + _publish(governed_repo, schema_path) + assert _paths(evaluate_contract_tracing(governed_repo), MISSING_RULE_ID) == {schema_path} + record = _requirement(governed_repo, uid, _link(schema_path)).relative_to(governed_repo).as_posix() + + assert evaluate_contract_tracing(governed_repo) == [] + assert ( + evaluate_requirement_governance( + governed_repo, + [schema_path, record], + client=RepositoryRequirementClient(governed_repo), + requirement_uid=uid, + ) + == [] + ) + + +@pytest.mark.parametrize( + "path", + [ + "docs/requirements/RUN-300/requirement.md", + "docs/requirements/RUN-311/notes.md", + "docs/requirements/RUN-311/requirement.md/extra.md", + "contracts/schemas/experiment-core/experiment-run-v1.json", + ], +) +def test_owner_record_permission_does_not_admit_other_records_or_files(governed_repo: Path, path: str) -> None: + failures = evaluate_requirement_governance( + governed_repo, + [path], + client=RepositoryRequirementClient(governed_repo), + requirement_uid="RUN-311", + ) + + assert [(failure.rule_id, failure.path) for failure in failures] == [("requirement-ownership-mismatch", path)] + + +@pytest.mark.parametrize("assigned_uid", ["RUN-311", "RUN-300"]) +def test_scoped_owner_record_edits_require_the_correct_owner(governed_repo: Path, assigned_uid: str) -> None: + record = "docs/requirements/RUN-311/requirement.md" + scope = parse_requirement_scope( + { + "schema_version": "requirement-scope/v1", + "issue_number": 712, + "primary_requirement_uid": "RUN-311", + "requirement_uids": ["RUN-311", "RUN-300"], + "bindings": {record: [assigned_uid]}, + }, + issue_number=712, + ) + + failures = evaluate_requirement_scope( + governed_repo, + [record], + client=RepositoryRequirementClient(governed_repo), + scope=scope, + ) + + assert [(failure.rule_id, failure.path) for failure in failures] == ( + [] if assigned_uid == "RUN-311" else [("requirement-ownership-mismatch", record)] + ) + + +@pytest.mark.parametrize("status", ["DEPRECATED", "ARCHIVED"]) +def test_owner_record_edits_do_not_admit_retired_requirements(governed_repo: Path, status: str) -> None: + record = _requirement(governed_repo, "RUN-311", status=status).relative_to(governed_repo).as_posix() + + failures = evaluate_requirement_governance( + governed_repo, + [record], + client=RepositoryRequirementClient(governed_repo), + requirement_uid="RUN-311", + ) + + assert [failure.rule_id for failure in failures] == ["requirement-invalid-status"] + + +@pytest.mark.parametrize( + ("path", "rule_id"), + [ + ("implementations/python/packages/raes_contracts/new_contract.py", "traceability-missing-implements"), + ("implementations/python/tests/test_new_contract.py", "traceability-missing-tests"), + ], +) +def test_owner_record_edits_still_require_code_and_test_links(governed_repo: Path, path: str, rule_id: str) -> None: + failures = evaluate_requirement_governance( + governed_repo, + ["docs/requirements/RUN-311/requirement.md", path], + client=RepositoryRequirementClient(governed_repo), + requirement_uid="RUN-311", + ) + + assert [(failure.rule_id, failure.path) for failure in failures] == [(rule_id, path)] + + +def test_owner_record_edits_still_require_completed_prerequisites(governed_repo: Path) -> None: + _requirement(governed_repo, "API-412", status="DRAFT") + + failures = evaluate_requirement_governance( + governed_repo, + ["docs/requirements/RUN-311/requirement.md"], + client=RepositoryRequirementClient(governed_repo), + requirement_uid="RUN-311", + ) + + assert [failure.rule_id for failure in failures] == ["requirement-order-blocked"] + + # --- the live tree ----------------------------------------------------------- diff --git a/tools/policy/requirement_governance.py b/tools/policy/requirement_governance.py index 03ea196c4..1d7da7493 100644 --- a/tools/policy/requirement_governance.py +++ b/tools/policy/requirement_governance.py @@ -210,7 +210,7 @@ def evaluate_requirement_governance( ] failures.extend(_check_phase_predecessors(policy, client, phase_match)) - failures.extend(_check_path_ownership(policy, phase_match, changed)) + failures.extend(_check_path_ownership(policy, phase_match, changed, requirement_uid=requirement_uid)) failures.extend(_check_traceability(client, requirement, policy, changed)) return failures @@ -260,14 +260,23 @@ def _check_phase_predecessors( return failures -def _check_path_ownership(policy: dict[str, object], match: PhaseMatch, changed: list[str]) -> list[PolicyFailure]: +def _check_path_ownership( + policy: dict[str, object], + match: PhaseMatch, + changed: list[str], + *, + requirement_uid: str | None = None, +) -> list[PolicyFailure]: allowed = policy.get("ownership", {}).get(match.phase_id, []) if not allowed: return [] + # Contract owners must maintain their traceability in the same change; + # this grants only the evaluated owner's exact record, never a directory. + owner_record = f"docs/requirements/{requirement_uid}/requirement.md" if requirement_uid else None failures: list[PolicyFailure] = [] relevant = [path for path in changed if path.startswith(("implementations/", "contracts/", "specs/", "docs/"))] for path in relevant: - if not path_matches_any(path, allowed): + if path != owner_record and not path_matches_any(path, allowed): failures.append( PolicyFailure( "requirement-ownership-mismatch",