diff --git a/.bestpractices.json b/.bestpractices.json index 241e5af74..b7491e696 100644 --- a/.bestpractices.json +++ b/.bestpractices.json @@ -1,16 +1,16 @@ { "name": "Reproducible Agentic Environments System", "description": "RAES describes and validates authored agentic-environment scenarios, with published contracts, examples, conformance checks, and a Python reference implementation.", - "homepage_url": "https://raesystem.github.io/rae/", - "repo_url": "https://github.com/RAESystem/rae", + "homepage_url": "https://openrae.github.io/rae/", + "repo_url": "https://github.com/OpenRAE/rae", "license": "MIT", "implementation_languages": "Python", "description_good_status": "Met", - "description_good_justification": "The README states the purpose, scope, first successful task, and current limits: https://github.com/RAESystem/rae#readme.", + "description_good_justification": "The README states the purpose, scope, first successful task, and current limits: https://github.com/OpenRAE/rae#readme.", "interact_status": "Met", - "interact_justification": "Public GitHub issues and pull requests support URL-addressable discussion: https://github.com/RAESystem/rae/issues.", + "interact_justification": "Public GitHub issues and pull requests support URL-addressable discussion: https://github.com/OpenRAE/rae/issues.", "contribution_status": "Met", - "contribution_justification": "Contribution setup and pull-request steps are in https://github.com/RAESystem/rae/blob/main/CONTRIBUTING.md.", + "contribution_justification": "Contribution setup and pull-request steps are in https://github.com/OpenRAE/rae/blob/main/CONTRIBUTING.md.", "contribution_requirements_status": "Met", "contribution_requirements_justification": "CONTRIBUTING.md documents the dev branch, tests, docs rules, and Conventional Commit pull-request titles.", "floss_license_status": "Met", @@ -18,7 +18,7 @@ "floss_license_osi_status": "Met", "floss_license_osi_justification": "MIT is an OSI-approved open source license.", "license_location_status": "Met", - "license_location_justification": "The license is at https://github.com/RAESystem/rae/blob/main/LICENSE.", + "license_location_justification": "The license is at https://github.com/OpenRAE/rae/blob/main/LICENSE.", "documentation_basics_status": "Met", "documentation_basics_justification": "The README and docs/public provide installation, a tested quickstart, concepts, task guides, research context, and limits.", "documentation_interface_status": "Met", @@ -32,7 +32,7 @@ "maintained_status": "Met", "maintained_justification": "The public repository has current commits, releases, issues, and pull requests.", "repo_public_status": "Met", - "repo_public_justification": "The source repository is public at https://github.com/RAESystem/rae.", + "repo_public_justification": "The source repository is public at https://github.com/OpenRAE/rae.", "repo_track_status": "Met", "repo_track_justification": "The project uses Git and preserves public history on GitHub.", "repo_interim_status": "Met", @@ -60,9 +60,9 @@ "continuous_integration_status": "Met", "continuous_integration_justification": "GitHub Actions runs repository policy, tests, docs, security, and conformance checks.", "code_of_conduct_status": "Met", - "code_of_conduct_justification": "The project policy is at https://github.com/RAESystem/rae/blob/main/CODE_OF_CONDUCT.md.", + "code_of_conduct_justification": "The project policy is at https://github.com/OpenRAE/rae/blob/main/CODE_OF_CONDUCT.md.", "governance_status": "Met", - "governance_justification": "The maintainer-led decision and release model is at https://github.com/RAESystem/rae/blob/main/GOVERNANCE.md.", + "governance_justification": "The maintainer-led decision and release model is at https://github.com/OpenRAE/rae/blob/main/GOVERNANCE.md.", "bus_factor_status": "Unmet", "bus_factor_justification": "RAES currently has one maintainer, so its bus factor is below two.", "two_person_review_status": "Unmet", diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml index fffd98f04..12c040cfe 100644 --- a/.github/ISSUE_TEMPLATE/config.yml +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -1,8 +1,8 @@ blank_issues_enabled: false contact_links: - name: Security report - url: https://github.com/RAESystem/rae/security/advisories/new + url: https://github.com/OpenRAE/rae/security/advisories/new about: Report a suspected vulnerability privately. - name: Support guide - url: https://github.com/RAESystem/rae/blob/main/SUPPORT.md + url: https://github.com/OpenRAE/rae/blob/main/SUPPORT.md about: Choose the right route and include a small example. diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5a06f0736..e59628873 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -18,7 +18,10 @@ permissions: jobs: verify: - runs-on: ubuntu-latest + # Ubuntu 24.04 restricts unprivileged user namespaces through AppArmor. + # Keep the proof-bearing job on 22.04 so Bubblewrap enforces the sandbox + # without disabling a host security control on the runner. + runs-on: ubuntu-22.04 steps: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 with: @@ -28,6 +31,19 @@ jobs: python-version: "3.12" - name: Install uv uses: astral-sh/setup-uv@c771a70e6277c0a99b617c7a806ffedaca235ff9 # v8 + - name: Restore pinned Isabelle archive + uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5 + with: + path: .cache/raes-sdl/tooling/archives/Isabelle2025-2_linux.tar.gz + key: isabelle-linux-x86-64-2025-2-a20a507bc7c1270d + - name: Install proof sandbox + run: | + if ! command -v bwrap >/dev/null 2>&1; then + sudo apt-get update + sudo apt-get install --no-install-recommends -y bubblewrap + fi + - name: Acquire pinned Isabelle distribution + run: uv run --project implementations/python --frozen python -m tools.isabelle_tool acquire - name: Resolve policy base revision id: base run: | diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index 28940e1bf..17d9cd7fd 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -30,7 +30,9 @@ jobs: - name: Install uv uses: astral-sh/setup-uv@c771a70e6277c0a99b617c7a806ffedaca235ff9 # v8 - name: Validate and build public docs - run: uv tool run --from 'nox[uv]==2026.4.10' nox -f noxfile.py -s docs + run: uv tool run --from 'nox[uv]==2026.4.10' nox -f noxfile.py -s docs-local + - name: Check external documentation links + run: uv tool run --from 'nox[uv]==2026.4.10' nox -f noxfile.py -s docs-links - name: Upload Pages artifact if: github.ref == 'refs/heads/main' uses: actions/upload-pages-artifact@fc324d3547104276b827a68afc52ff2a11cc49c9 # v5.0.0 diff --git a/.ground-control.yaml b/.ground-control.yaml index 0c48df930..bd620d0a9 100644 --- a/.ground-control.yaml +++ b/.ground-control.yaml @@ -1,13 +1,13 @@ schema_version: 1 project: aces-sdl -github_repo: RAESystem/rae +github_repo: OpenRAE/rae workflow: test_command: RAES_REQUIREMENT_UID="${RAES_REQUIREMENT_UID:-$(printenv A""CES_REQUIREMENT_UID)}" uv tool run --from 'nox[uv]==2026.4.10' nox -f noxfile.py -s verify - completion_command: RAES_REQUIREMENT_UID="${RAES_REQUIREMENT_UID:-$(printenv A""CES_REQUIREMENT_UID)}" uv tool run --from 'nox[uv]==2026.4.10' nox -f noxfile.py -s verify + completion_command: RAES_REQUIREMENT_UID="${RAES_REQUIREMENT_UID:-$(printenv A""CES_REQUIREMENT_UID)}" uv tool run --from 'nox[uv]==2026.4.10' nox -f noxfile.py -s verify-completion lint_command: uv tool run --from 'nox[uv]==2026.4.10' nox -f noxfile.py -s lint format_command: uv tool run --from 'nox[uv]==2026.4.10' nox -f noxfile.py -s hygiene policy_command: RAES_REQUIREMENT_UID="${RAES_REQUIREMENT_UID:-$(printenv A""CES_REQUIREMENT_UID)}" make policy - precommit_command: RAES_REQUIREMENT_UID="${RAES_REQUIREMENT_UID:-$(printenv A""CES_REQUIREMENT_UID)}" pre-commit run --all-files + precommit_command: RAES_REQUIREMENT_UID="${RAES_REQUIREMENT_UID:-$(printenv A""CES_REQUIREMENT_UID)}" pre-commit run codex_review: pre_push_cap: 1 test_quality_review: diff --git a/.mcp.json b/.mcp.json index 3a4f58f6b..44ff6b594 100644 --- a/.mcp.json +++ b/.mcp.json @@ -6,7 +6,7 @@ "args": ["/home/atomik/src/Ground-Control/mcp/ground-control/index.js"], "env": { "GC_BASE_URL": "http://red-dragon:8000", - "GH_REPO": "RAESystem/rae" + "GH_REPO": "OpenRAE/rae" } }, "sonarqube": { diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 35032ca08..b82ab5a00 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -26,7 +26,7 @@ Prerequisites: Install the locked Python environment: ```shell -git clone https://github.com/RAESystem/rae.git +git clone https://github.com/OpenRAE/rae.git cd rae uv sync --project implementations/python --all-extras --frozen ``` diff --git a/README.md b/README.md index 695bdcb40..69dc3542e 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,10 @@ # Reproducible Agentic Environments System -[![CI](https://github.com/RAESystem/rae/actions/workflows/ci.yml/badge.svg?branch=main)](https://github.com/RAESystem/rae/actions/workflows/ci.yml) -[![Docs](https://github.com/RAESystem/rae/actions/workflows/docs.yml/badge.svg?branch=main)](https://raesystem.github.io/rae/) +[![CI](https://github.com/OpenRAE/rae/actions/workflows/ci.yml/badge.svg?branch=main)](https://github.com/OpenRAE/rae/actions/workflows/ci.yml) +[![Docs](https://github.com/OpenRAE/rae/actions/workflows/docs.yml/badge.svg?branch=main)](https://openrae.github.io/rae/) [![PyPI](https://img.shields.io/pypi/v/raes.svg)](https://pypi.org/project/raes/) [![Python](https://img.shields.io/pypi/pyversions/raes.svg)](https://pypi.org/project/raes/) -[![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://github.com/RAESystem/rae/blob/main/LICENSE) +[![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://github.com/OpenRAE/rae/blob/main/LICENSE) RAES, the Reproducible Agentic Environments System, helps you describe and check an agentic environment. RAES SDL is its YAML language for authored @@ -74,29 +74,29 @@ Validated first-scenario with 2 nodes. RAES has checked the file shape and current semantic rules. It has not created infrastructure. Continue with the -[quickstart](https://raesystem.github.io/rae/quickstart.html) to learn what +[quickstart](https://openrae.github.io/rae/quickstart.html) to learn what each part means. ## Choose your route - **Scenario authors:** Start with the - [SDL guide](https://raesystem.github.io/rae/sdl/) and - [worked examples](https://github.com/RAESystem/rae/tree/main/examples/scenarios). + [SDL guide](https://openrae.github.io/rae/sdl/) and + [worked examples](https://github.com/OpenRAE/rae/tree/main/examples/scenarios). - **Python users:** Use the - [Python guide](https://raesystem.github.io/rae/guides/python.html) and - [API reference](https://raesystem.github.io/rae/api/). + [Python guide](https://openrae.github.io/rae/guides/python.html) and + [API reference](https://openrae.github.io/rae/api/). - **CLI users:** See the - [command-line guide](https://raesystem.github.io/rae/guides/cli.html). + [command-line guide](https://openrae.github.io/rae/guides/cli.html). - **Backend implementers:** Read the - [backend and conformance guide](https://raesystem.github.io/rae/backends.html). + [backend and conformance guide](https://openrae.github.io/rae/backends.html). - **Researchers:** Review the - [research context](https://raesystem.github.io/rae/research.html), - [current limits](https://raesystem.github.io/rae/limitations.html), and - [citation guide](https://raesystem.github.io/rae/citation.html). + [research context](https://openrae.github.io/rae/research.html), + [current limits](https://openrae.github.io/rae/limitations.html), and + [citation guide](https://openrae.github.io/rae/citation.html). - **Contributors:** Follow - [CONTRIBUTING.md](https://github.com/RAESystem/rae/blob/main/CONTRIBUTING.md) + [CONTRIBUTING.md](https://github.com/OpenRAE/rae/blob/main/CONTRIBUTING.md) and the - [developer documentation index](https://github.com/RAESystem/rae/blob/main/docs/README.md). + [developer documentation index](https://github.com/OpenRAE/rae/blob/main/docs/README.md). ## Understand what RAES promises @@ -111,7 +111,7 @@ validity, or reproducibility. The repository does not include a production deployment backend or a managed environment service. It includes contracts, stubs, examples, conformance checks, and reference code. Read the -[current limits](https://raesystem.github.io/rae/limitations.html) before +[current limits](https://openrae.github.io/rae/limitations.html) before choosing it for a study or integration. ## See where RAES fits @@ -136,7 +136,7 @@ The core model is not limited to those areas. Install the locked development environment: ```console -git clone https://github.com/RAESystem/rae.git +git clone https://github.com/OpenRAE/rae.git cd rae uv sync --project implementations/python --all-extras --frozen uv run --project implementations/python raes --help @@ -165,8 +165,8 @@ reviewer for every change. Release Please owns package versions, GitHub releases, and `CHANGELOG.md`. Published schemas carry separate stability labels. See -[GOVERNANCE.md](https://github.com/RAESystem/rae/blob/main/GOVERNANCE.md) and -[MAINTAINERS.md](https://github.com/RAESystem/rae/blob/main/MAINTAINERS.md) for +[GOVERNANCE.md](https://github.com/OpenRAE/rae/blob/main/GOVERNANCE.md) and +[MAINTAINERS.md](https://github.com/OpenRAE/rae/blob/main/MAINTAINERS.md) for the current decision and maintenance model. ## Cite RAES @@ -177,11 +177,11 @@ the current decision and maintenance model. title = {RAES: Reproducible Agentic Environments System}, year = {2026}, license = {MIT}, - url = {https://github.com/RAESystem/rae} + url = {https://github.com/OpenRAE/rae} } ``` RAES is released under the -[MIT License](https://github.com/RAESystem/rae/blob/main/LICENSE). Third-party +[MIT License](https://github.com/OpenRAE/rae/blob/main/LICENSE). Third-party notices are in -[THIRD_PARTY_NOTICES.md](https://github.com/RAESystem/rae/blob/main/THIRD_PARTY_NOTICES.md). +[THIRD_PARTY_NOTICES.md](https://github.com/OpenRAE/rae/blob/main/THIRD_PARTY_NOTICES.md). diff --git a/contracts/concept-authority/behavioral-relations-v1.json b/contracts/concept-authority/behavioral-relations-v1.json index f1a8ec47e..eac6cc835 100644 --- a/contracts/concept-authority/behavioral-relations-v1.json +++ b/contracts/concept-authority/behavioral-relations-v1.json @@ -1,7 +1,7 @@ { "schema_version": "behavioral-relations/v1", "taxonomy_id": "raes-behavioral-relations", - "taxonomy_revision": "rev8", + "taxonomy_revision": "rev9", "bibliography": [ { "source_id": "park-1981", @@ -2000,13 +2000,15 @@ "implementations/python/tests/test_issue_961_participant_opacity.py covers profile and claim resolution, finite bounds, active strategies, coalition fusion, decision and omission channels, retained release knowledge, vacuity, deterministic evidence, replay, and explicit nonclaims.", "The participant-opacity finite-state checker derives the complete reachable fixed point from an exact transition model, checks every reachable secret evaluation point, and binds catalog, profile, model, assumptions, explored coverage, tool version, result or safe counterexample, and replay evidence.", "The committed model-check input and evidence fixtures retain the exact positive baseline model, result, digests, complete coverage, tool identity, and explicit nonclaims; invalid fixtures exercise count and partial-result promotion failures.", - "implementations/python/tests/test_issue_962_participant_opacity_model_check.py covers pair-probe incompleteness, supervisor behavior, active strategies, coalition fusion, retained memory, release changes, order and probability non-promotion, exact bounds, replay, and agreement with the bounded lane." + "implementations/python/tests/test_issue_962_participant_opacity_model_check.py covers pair-probe incompleteness, supervisor behavior, active strategies, coalition fusion, retained memory, release changes, order and probability non-promotion, exact bounds, replay, and agreement with the bounded lane.", + "The Isabelle/HOL Participant_Opacity session kernel-checks the SEM-231 one-sided opacity definition, its information-cell knowledge characterization, and the conditional implication from a matching SEM-230 noninterference instance for an eligible predicate; checked countermodels preserve the invalid-promotion boundaries." ], "explicit_non_claims": [ "Relation definition, catalog validation, claim-profile binding, and bounded finite analysis do not establish opacity of RAES, RUN-319, or any backend outside the exact admitted artifact.", "No checker, finite-state model check, mathematical proof, runtime enforcement, supervisor synthesis, backend declaration, backend realization, or backend conformance is delivered by taxonomy revision rev5.", "Taxonomy revision rev7 adds only an in-process bounded-test checker; it does not add a model check, mathematical proof, runtime enforcement, supervisor synthesis, backend declaration, backend realization, or backend conformance.", "Taxonomy revision rev8 adds one exact finite-state model-check result; it does not add a mathematical proof, runtime enforcement, supervisor synthesis, backend declaration, backend realization, or backend conformance.", + "Taxonomy revision rev9 adds only the abstract conditional mathematical theorem bound to participant-opacity-theorem-v1; it does not prove opacity of RAES, a runtime, a deployment, a backend, or the finite fixture profile.", "Bounded evidence authenticates only the normalized-input digest; it does not authenticate a claimed source artifact or materializer.", "Opacity of one predicate does not imply SEM-230 policy noninterference, projected-history equivalence, epistemic indistinguishability of two selected worlds, trace inclusion or equivalence, simulation, refinement, or strong or weak bisimulation.", "The possibilistic baseline makes no posterior-risk, entropy, probabilistic, differential-privacy, timed, progress-sensitive, or universal partial-order claim." @@ -2020,7 +2022,7 @@ "definition_status": "defined", "implementation_status": "implemented", "test_status": "bounded", - "proof_status": "deliberately-unproved", + "proof_status": "proved", "checker_status": "implemented", "model_check_status": "model-checked", "runtime_enforcement_status": "not-enforced", @@ -2030,7 +2032,8 @@ "evidence_refs": [ "docs/decisions/adrs/adr-099-participant-relative-predicate-opacity.md", "specs/formal/participant-semantics/participant-predicate-opacity.md", - "contracts/profiles/behavioral-relation/participant-opacity-baseline-v1.json", + "contracts/profiles/behavioral-relation/history/participant-opacity-baseline-v1-sem-231-rev2.json", + "contracts/profiles/behavioral-relation/participant-opacity-theorem-v1.json", "contracts/schemas/formal-analysis/participant-opacity-model-check-input-v1.json", "contracts/schemas/formal-analysis/participant-opacity-model-check-evidence-v1.json", "contracts/fixtures/formal-analysis/participant-opacity-model-check-input-v1/valid/opaque-transition-model.json", @@ -2039,7 +2042,12 @@ "implementations/python/packages/raes_processor/participant_opacity/_model_check.py", "implementations/python/tests/test_sem_231_participant_predicate_opacity.py", "implementations/python/tests/test_issue_961_participant_opacity.py", - "implementations/python/tests/test_issue_962_participant_opacity_model_check.py" + "implementations/python/tests/test_issue_962_participant_opacity_model_check.py", + "implementations/python/tests/test_issue_963_participant_opacity_proof.py", + "specs/formal/participant-semantics/isabelle/Participant_Opacity.thy", + "specs/formal/participant-semantics/participant-opacity-proof-evidence.json", + "tools/check_participant_opacity_proof.py", + "tools/isabelle_tool.py" ] }, "source_refs": [ diff --git a/contracts/concept-authority/controlled-vocabularies-v1.json b/contracts/concept-authority/controlled-vocabularies-v1.json index 4c857d6ca..63064684b 100644 --- a/contracts/concept-authority/controlled-vocabularies-v1.json +++ b/contracts/concept-authority/controlled-vocabularies-v1.json @@ -774,6 +774,10 @@ "service-content-v1": { "title": "Service Content v1", "description": "Exact reconciliation of authored content into a named service with controlled reset and participant-equivalent readback." + }, + "service-search-index-schema-v1": { + "title": "Service Search Index Schema v1", + "description": "Exact reconciliation of a provider-neutral declared-field search-index schema with fresh native readback." } } }, diff --git a/contracts/concept-authority/fipa-communicative-acts-source-v1.json b/contracts/concept-authority/fipa-communicative-acts-source-v1.json new file mode 100644 index 000000000..41309aefc --- /dev/null +++ b/contracts/concept-authority/fipa-communicative-acts-source-v1.json @@ -0,0 +1,107 @@ +{ + "schema_version": "fipa-communicative-acts-source/v1", + "source_authority": "Foundation for Intelligent Physical Agents", + "source_version": "SC00037J-2002-12-03", + "source_status": "Standard", + "source_url": "https://www.fipa.org/specs/fipa00037/SC00037J.html", + "source_artifact_url": "https://www.fipa.org/specs/fipa00037/SC00037J.pdf", + "source_digest": "sha256:90b3277247ef7e7f614ba4c0d58fb2b86aa53ff69036d27a731c09a26c605227", + "citation_urls": [ + "https://www.fipa.org/specs/fipa00037/SC00037J.html", + "https://www.fipa.org/specs/fipa00037/SC00037J.pdf", + "https://www.fipa.org/repository/aclspecs.html" + ], + "retrieved_at": "2026-07-30", + "license_url": "https://www.fipa.org/specs/fipa00037/SC00037J.html", + "license_notice": "Copyright © 1996-2002 Foundation for Intelligent Physical Agents. The specification notice grants no permission to use third-party intellectual property.", + "communicative_acts": [ + { + "position": 1, + "concept_id": "accept-proposal" + }, + { + "position": 2, + "concept_id": "agree" + }, + { + "position": 3, + "concept_id": "cancel" + }, + { + "position": 4, + "concept_id": "cfp" + }, + { + "position": 5, + "concept_id": "confirm" + }, + { + "position": 6, + "concept_id": "disconfirm" + }, + { + "position": 7, + "concept_id": "failure" + }, + { + "position": 8, + "concept_id": "inform" + }, + { + "position": 9, + "concept_id": "inform-if" + }, + { + "position": 10, + "concept_id": "inform-ref" + }, + { + "position": 11, + "concept_id": "not-understood" + }, + { + "position": 12, + "concept_id": "propagate" + }, + { + "position": 13, + "concept_id": "propose" + }, + { + "position": 14, + "concept_id": "proxy" + }, + { + "position": 15, + "concept_id": "query-if" + }, + { + "position": 16, + "concept_id": "query-ref" + }, + { + "position": 17, + "concept_id": "refuse" + }, + { + "position": 18, + "concept_id": "reject-proposal" + }, + { + "position": 19, + "concept_id": "request" + }, + { + "position": 20, + "concept_id": "request-when" + }, + { + "position": 21, + "concept_id": "request-whenever" + }, + { + "position": 22, + "concept_id": "subscribe" + } + ] +} diff --git a/contracts/concept-authority/history/behavioral-relations-v1-rev8.json b/contracts/concept-authority/history/behavioral-relations-v1-rev8.json new file mode 100644 index 000000000..f1a8ec47e --- /dev/null +++ b/contracts/concept-authority/history/behavioral-relations-v1-rev8.json @@ -0,0 +1,3113 @@ +{ + "schema_version": "behavioral-relations/v1", + "taxonomy_id": "raes-behavioral-relations", + "taxonomy_revision": "rev8", + "bibliography": [ + { + "source_id": "park-1981", + "title": "Concurrency and Automata on Infinite Sequences", + "authors": [ + "David M. R. Park" + ], + "publication_year": 1981, + "publication_venue": "Theoretical Computer Science, LNCS 104", + "edition_or_version": "published conference chapter", + "immutable_locator": { + "kind": "doi", + "value": "10.1007/BFb0017309" + } + }, + { + "source_id": "milner-1980", + "title": "A Calculus of Communicating Systems", + "authors": [ + "Robin Milner" + ], + "publication_year": 1980, + "publication_venue": "Lecture Notes in Computer Science 92", + "edition_or_version": "first edition", + "immutable_locator": { + "kind": "doi", + "value": "10.1007/3-540-10235-3" + } + }, + { + "source_id": "van-glabbeek-1990", + "title": "The Linear Time-Branching Time Spectrum", + "authors": [ + "Rob J. van Glabbeek" + ], + "publication_year": 1990, + "publication_venue": "CONCUR 1990, LNCS 458", + "edition_or_version": "published conference chapter", + "immutable_locator": { + "kind": "doi", + "value": "10.1007/BFb0039066" + } + }, + { + "source_id": "van-glabbeek-weijland-1996", + "title": "Branching Time and Abstraction in Bisimulation Semantics", + "authors": [ + "Rob J. van Glabbeek", + "W. Peter Weijland" + ], + "publication_year": 1996, + "publication_venue": "Journal of the ACM 43(3), 555-600", + "edition_or_version": "version of record", + "immutable_locator": { + "kind": "doi", + "value": "10.1145/233551.233556" + } + }, + { + "source_id": "van-glabbeek-luttik-trcka-2009", + "title": "Branching Bisimilarity with Explicit Divergence", + "authors": [ + "Rob J. van Glabbeek", + "Bas Luttik", + "Nikola Trčka" + ], + "publication_year": 2009, + "publication_venue": "Fundamenta Informaticae 93(4), 371-392", + "edition_or_version": "version of record", + "immutable_locator": { + "kind": "doi", + "value": "10.3233/FI-2009-109" + } + }, + { + "source_id": "abadi-lamport-1991", + "title": "The Existence of Refinement Mappings", + "authors": [ + "Martín Abadi", + "Leslie Lamport" + ], + "publication_year": 1991, + "publication_venue": "Theoretical Computer Science 82(2)", + "edition_or_version": "version of record", + "immutable_locator": { + "kind": "doi", + "value": "10.1016/0304-3975(91)90224-P" + } + }, + { + "source_id": "lynch-vaandrager-1995", + "title": "Forward and Backward Simulations, Part I: Untimed Systems", + "authors": [ + "Nancy A. Lynch", + "Frits W. Vaandrager" + ], + "publication_year": 1995, + "publication_venue": "Information and Computation 121(2)", + "edition_or_version": "version of record", + "immutable_locator": { + "kind": "doi", + "value": "10.1006/inco.1995.1134" + } + }, + { + "source_id": "fagin-halpern-moses-vardi-1995", + "title": "Reasoning About Knowledge", + "authors": [ + "Ronald Fagin", + "Joseph Y. Halpern", + "Yoram Moses", + "Moshe Y. Vardi" + ], + "publication_year": 1995, + "publication_venue": "MIT Press", + "edition_or_version": "hardcover first edition", + "immutable_locator": { + "kind": "isbn", + "value": "9780262061629" + } + }, + { + "source_id": "goguen-meseguer-1982", + "title": "Security Policies and Security Models", + "authors": [ + "Joseph A. Goguen", + "José Meseguer" + ], + "publication_year": 1982, + "publication_venue": "1982 IEEE Symposium on Security and Privacy", + "edition_or_version": "version of record", + "immutable_locator": { + "kind": "doi", + "value": "10.1109/SP.1982.10014" + } + }, + { + "source_id": "sabelfeld-sands-2009", + "title": "Declassification: Dimensions and Principles", + "authors": [ + "Andrei Sabelfeld", + "David Sands" + ], + "publication_year": 2009, + "publication_venue": "Journal of Computer Security 17(5)", + "edition_or_version": "version of record", + "immutable_locator": { + "kind": "doi", + "value": "10.3233/JCS-2009-0352" + } + }, + { + "source_id": "lynch-tuttle-1989", + "title": "An Introduction to Input/Output Automata", + "authors": [ + "Nancy A. Lynch", + "Mark R. Tuttle" + ], + "publication_year": 1989, + "publication_venue": "CWI Quarterly 2(3), 219-246", + "edition_or_version": "published journal article", + "immutable_locator": { + "kind": "report", + "value": "MIT/LCS/TM-373" + } + }, + { + "source_id": "clarkson-schneider-2010", + "title": "Hyperproperties", + "authors": [ + "Michael R. Clarkson", + "Fred B. Schneider" + ], + "publication_year": 2010, + "publication_venue": "Journal of Computer Security 18(6), 1157-1210", + "edition_or_version": "version of record", + "immutable_locator": { + "kind": "doi", + "value": "10.3233/JCS-2009-0393" + } + }, + { + "source_id": "bohannon-pierce-sjoberg-weirich-zdancewic-2009", + "title": "Reactive Noninterference", + "authors": [ + "Aaron Bohannon", + "Benjamin C. Pierce", + "Vilhelm Sjöberg", + "Stephanie Weirich", + "Steve Zdancewic" + ], + "publication_year": 2009, + "publication_venue": "Proceedings of the 16th ACM Conference on Computer and Communications Security, 79-90", + "edition_or_version": "version of record", + "immutable_locator": { + "kind": "doi", + "value": "10.1145/1653662.1653673" + } + }, + { + "source_id": "alur-henzinger-kupferman-vardi-1998", + "title": "Alternating Refinement Relations", + "authors": [ + "Rajeev Alur", + "Thomas A. Henzinger", + "Orna Kupferman", + "Moshe Y. Vardi" + ], + "publication_year": 1998, + "publication_venue": "CONCUR 1998, LNCS 1466", + "edition_or_version": "published conference chapter", + "immutable_locator": { + "kind": "doi", + "value": "10.1007/BFb0055622" + } + }, + { + "source_id": "alur-henzinger-kupferman-2002", + "title": "Alternating-Time Temporal Logic", + "authors": [ + "Rajeev Alur", + "Thomas A. Henzinger", + "Orna Kupferman" + ], + "publication_year": 2002, + "publication_venue": "Journal of the ACM 49(5)", + "edition_or_version": "version of record", + "immutable_locator": { + "kind": "doi", + "value": "10.1145/585265.585270" + } + }, + { + "source_id": "larsen-skou-1991", + "title": "Bisimulation Through Probabilistic Testing", + "authors": [ + "Kim G. Larsen", + "Arne Skou" + ], + "publication_year": 1991, + "publication_venue": "Information and Computation 94(1)", + "edition_or_version": "version of record", + "immutable_locator": { + "kind": "doi", + "value": "10.1016/0890-5401(91)90030-6" + } + }, + { + "source_id": "wellek-2010", + "title": "Testing Statistical Hypotheses of Equivalence and Noninferiority", + "authors": [ + "Stefan Wellek" + ], + "publication_year": 2010, + "publication_venue": "Chapman and Hall/CRC", + "edition_or_version": "second edition", + "immutable_locator": { + "kind": "isbn", + "value": "9781439808184" + } + }, + { + "source_id": "bueno-1997", + "title": "Empirical Adequacy: A Partial Structures Approach", + "authors": [ + "Otávio Bueno" + ], + "publication_year": 1997, + "publication_venue": "Studies in History and Philosophy of Science Part A 28(4)", + "edition_or_version": "version of record", + "immutable_locator": { + "kind": "doi", + "value": "10.1016/S0039-3681(97)00012-5" + } + }, + { + "source_id": "halpern-pearl-2005", + "title": "Causes and Explanations: A Structural-Model Approach. Part I: Causes", + "authors": [ + "Joseph Y. Halpern", + "Judea Pearl" + ], + "publication_year": 2005, + "publication_venue": "The British Journal for the Philosophy of Science 56(4)", + "edition_or_version": "version of record", + "immutable_locator": { + "kind": "doi", + "value": "10.1093/bjps/axi147" + } + }, + { + "source_id": "bryans-koutny-mazare-ryan-2008", + "title": "Opacity Generalised to Transition Systems", + "authors": [ + "Jeremy W. Bryans", + "Maciej Koutny", + "Laurent Mazaré", + "Peter Y. A. Ryan" + ], + "publication_year": 2008, + "publication_venue": "International Journal of Information Security 7(6), 421-435", + "edition_or_version": "version of record", + "immutable_locator": { + "kind": "doi", + "value": "10.1007/s10207-008-0058-x" + } + }, + { + "source_id": "schoepe-sabelfeld-2015", + "title": "Understanding and Enforcing Opacity", + "authors": [ + "Daniel Schoepe", + "Andrei Sabelfeld" + ], + "publication_year": 2015, + "publication_venue": "2015 IEEE Computer Security Foundations Symposium, 539-553", + "edition_or_version": "version of record", + "immutable_locator": { + "kind": "doi", + "value": "10.1109/CSF.2015.41" + } + }, + { + "source_id": "lin-2011", + "title": "Opacity of Discrete Event Systems and its Applications", + "authors": [ + "Feng Lin" + ], + "publication_year": 2011, + "publication_venue": "Automatica 47(3), 496-503", + "edition_or_version": "version of record", + "immutable_locator": { + "kind": "doi", + "value": "10.1016/j.automatica.2011.01.002" + } + }, + { + "source_id": "saboori-hadjicostis-2012", + "title": "Verification of Infinite-Step Opacity and Complexity Considerations", + "authors": [ + "Anooshiravan Saboori", + "Christoforos N. Hadjicostis" + ], + "publication_year": 2012, + "publication_venue": "IEEE Transactions on Automatic Control 57(5), 1265-1269", + "edition_or_version": "version of record", + "immutable_locator": { + "kind": "doi", + "value": "10.1109/TAC.2011.2173774" + } + }, + { + "source_id": "badouel-bednarczyk-borzyszkowski-caillaud-darondeau-2007", + "title": "Concurrent Secrets", + "authors": [ + "Éric Badouel", + "Marek A. Bednarczyk", + "Andrzej M. Borzyszkowski", + "Benoît Caillaud", + "Philippe Darondeau" + ], + "publication_year": 2007, + "publication_venue": "Discrete Event Dynamic Systems 17(4), 425-446", + "edition_or_version": "version of record", + "immutable_locator": { + "kind": "doi", + "value": "10.1007/s10626-007-0020-5" + } + }, + { + "source_id": "yin-lafortune-2016", + "title": "A Uniform Approach for Synthesizing Property-Enforcing Supervisors for Partially-Observed Discrete-Event Systems", + "authors": [ + "Xiang Yin", + "Stéphane Lafortune" + ], + "publication_year": 2016, + "publication_venue": "IEEE Transactions on Automatic Control 61(8), 2140-2154", + "edition_or_version": "version of record", + "immutable_locator": { + "kind": "doi", + "value": "10.1109/TAC.2015.2484359" + } + }, + { + "source_id": "xie-yin-li-2022", + "title": "Opacity Enforcing Supervisory Control Using Nondeterministic Supervisors", + "authors": [ + "Yifan Xie", + "Xiang Yin", + "Shaoyuan Li" + ], + "publication_year": 2022, + "publication_venue": "IEEE Transactions on Automatic Control 67(12), 6567-6582", + "edition_or_version": "version of record", + "immutable_locator": { + "kind": "doi", + "value": "10.1109/TAC.2021.3131125" + } + }, + { + "source_id": "cui-ma-giua-yin-2026", + "title": "Opacity Enforcing Supervisory Control with a Priori Unknown Supervisors", + "authors": [ + "Juntang Cui", + "Ziyue Ma", + "Alessandro Giua", + "Xiang Yin" + ], + "publication_year": 2026, + "publication_venue": "arXiv preprint arXiv:2604.04070", + "edition_or_version": "preprint version 1", + "immutable_locator": { + "kind": "doi", + "value": "10.48550/arXiv.2604.04070" + } + }, + { + "source_id": "partovi-jung-hai-2020", + "title": "Opacity of Discrete Event Systems with Active Intruder", + "authors": [ + "Alireza Partovi", + "Taeho Jung", + "Lin Hai" + ], + "publication_year": 2020, + "publication_venue": "arXiv preprint arXiv:2007.14960", + "edition_or_version": "preprint version 1", + "immutable_locator": { + "kind": "doi", + "value": "10.48550/arXiv.2007.14960" + } + }, + { + "source_id": "berard-mullins-sassolas-2015", + "title": "Quantifying Opacity", + "authors": [ + "Béatrice Bérard", + "John Mullins", + "Mathieu Sassolas" + ], + "publication_year": 2015, + "publication_venue": "Mathematical Structures in Computer Science 25(2), 361-403", + "edition_or_version": "version of record", + "immutable_locator": { + "kind": "doi", + "value": "10.1017/S0960129513000637" + } + }, + { + "source_id": "andre-lime-marinho-sun-2022", + "title": "Guaranteeing Timed Opacity using Parametric Timed Model Checking", + "authors": [ + "Étienne André", + "Didier Lime", + "Dylan Marinho", + "Jun Sun" + ], + "publication_year": 2022, + "publication_venue": "ACM Transactions on Software Engineering and Methodology 31(4), 64:1-64:36", + "edition_or_version": "version of record", + "immutable_locator": { + "kind": "doi", + "value": "10.1145/3502851" + } + }, + { + "source_id": "broberg-van-delft-sands-2015", + "title": "The Anatomy and Facets of Dynamic Policies", + "authors": [ + "Niklas Broberg", + "Bart van Delft", + "David Sands" + ], + "publication_year": 2015, + "publication_venue": "2015 IEEE Computer Security Foundations Symposium, 122-137", + "edition_or_version": "version of record", + "immutable_locator": { + "kind": "doi", + "value": "10.1109/CSF.2015.16" + } + } + ], + "relations": { + "structural-validity": { + "relation_id": "structural-validity", + "display_name": "Structural validity", + "relation_class": "predicate", + "definition": "A single artifact satisfies its published closed structural schema.", + "left_carrier": "An artifact payload.", + "right_carrier": "The published schema selected by the artifact discriminator.", + "initial_states": "Not applicable; this is a unary predicate.", + "transition_signature": { + "applicability": "not-applicable", + "labels": "not applicable", + "transition_relation": "not applicable", + "observable_actions": "not applicable", + "hidden_actions": "not applicable", + "stuttering_actions": "not applicable", + "not_applicable_rationale": "Schema validity is a predicate over an artifact and schema, not a transition-system relation." + }, + "observation_projection": { + "applicability": "not-applicable", + "subject": "Schema validator", + "policy_ref": "behavioral-relations/catalog", + "policy_revision": "rev1", + "redaction_scope": "No redaction beyond the named projection.", + "order_treatment": "Sequence order is preserved.", + "simultaneity_treatment": "Simultaneity is preserved only when declared." + }, + "projection_required": false, + "direction": "unary", + "quantification": { + "states": "For one artifact payload and one schema revision.", + "traces": "outside scope", + "schedulers": "outside scope", + "strategies": "outside scope", + "environments": "outside scope", + "observations": "outside scope" + }, + "dimensions": { + "nondeterminism": { + "status": "outside-scope", + "treatment": "The predicate does not quantify over branching choices." + }, + "concurrency": { + "status": "outside-scope", + "treatment": "The predicate does not compare concurrent executions." + }, + "probability": { + "status": "outside-scope", + "treatment": "The predicate does not compare probability measures." + }, + "time": { + "status": "outside-scope", + "treatment": "The predicate does not compare timed behavior." + }, + "partial_order": { + "status": "outside-scope", + "treatment": "The predicate does not compare event partial orders." + } + }, + "preservation": { + "property": "Conformance to the declared structural shape.", + "proof_obligation": "Validate the complete payload against the named published schema." + }, + "bounded_evidence": [ + "JSON Schema and closed-model validation of named artifacts." + ], + "explicit_non_claims": [ + "Does not establish semantic validity, executability, or behavioral equivalence." + ], + "incompatible_claim_surfaces": [ + "Backend equivalence", + "Participant strategic behavior" + ], + "assurance": { + "definition_status": "defined", + "implementation_status": "implemented", + "test_status": "tested", + "proof_status": "not-applicable", + "evidence_refs": [ + "contracts/schemas/" + ] + }, + "source_refs": [ + "milner-1980" + ] + }, + "semantic-validity": { + "relation_id": "semantic-validity", + "display_name": "Semantic validity", + "relation_class": "predicate", + "definition": "A structurally admitted artifact satisfies the named cross-reference and domain invariants.", + "left_carrier": "A parsed RAES artifact.", + "right_carrier": "The named semantic invariant set.", + "initial_states": "Not applicable; this is a unary predicate.", + "transition_signature": { + "applicability": "not-applicable", + "labels": "not applicable", + "transition_relation": "not applicable", + "observable_actions": "not applicable", + "hidden_actions": "not applicable", + "stuttering_actions": "not applicable", + "not_applicable_rationale": "Semantic validity checks a static artifact model rather than matching transitions." + }, + "observation_projection": { + "applicability": "not-applicable", + "subject": "Semantic validator", + "policy_ref": "behavioral-relations/catalog", + "policy_revision": "rev1", + "redaction_scope": "No redaction beyond the named projection.", + "order_treatment": "Sequence order is preserved.", + "simultaneity_treatment": "Simultaneity is preserved only when declared." + }, + "projection_required": false, + "direction": "unary", + "quantification": { + "states": "For one admitted artifact and one invariant revision.", + "traces": "outside scope", + "schedulers": "outside scope", + "strategies": "outside scope", + "environments": "outside scope", + "observations": "outside scope" + }, + "dimensions": { + "nondeterminism": { + "status": "outside-scope", + "treatment": "The predicate does not quantify over branching choices." + }, + "concurrency": { + "status": "outside-scope", + "treatment": "The predicate does not compare concurrent executions." + }, + "probability": { + "status": "outside-scope", + "treatment": "The predicate does not compare probability measures." + }, + "time": { + "status": "outside-scope", + "treatment": "The predicate does not compare timed behavior." + }, + "partial_order": { + "status": "outside-scope", + "treatment": "The predicate does not compare event partial orders." + } + }, + "preservation": { + "property": "The named static semantic invariants.", + "proof_obligation": "Run every invariant in the declared semantic profile without error." + }, + "bounded_evidence": [ + "SemanticValidator results and invariant mutation tests." + ], + "explicit_non_claims": [ + "Does not establish realization, execution success, trace inclusion, or bisimulation." + ], + "incompatible_claim_surfaces": [ + "Runtime conformance", + "Backend comparison" + ], + "assurance": { + "definition_status": "defined", + "implementation_status": "implemented", + "test_status": "tested", + "proof_status": "deliberately-unproved", + "evidence_refs": [ + "implementations/python/packages/raes/validator/" + ] + }, + "source_refs": [ + "abadi-lamport-1991" + ] + }, + "capability-declaration": { + "relation_id": "capability-declaration", + "display_name": "Capability declaration", + "relation_class": "predicate", + "definition": "An apparatus declares support for governed capability and contract identifiers.", + "left_carrier": "A processor, backend, or participant manifest.", + "right_carrier": "The governed capability and contract vocabulary.", + "initial_states": "Not applicable; this is a declaration predicate.", + "transition_signature": { + "applicability": "not-applicable", + "labels": "not applicable", + "transition_relation": "not applicable", + "observable_actions": "not applicable", + "hidden_actions": "not applicable", + "stuttering_actions": "not applicable", + "not_applicable_rationale": "A declaration is not execution behavior." + }, + "observation_projection": { + "applicability": "not-applicable", + "subject": "Manifest consumer", + "policy_ref": "behavioral-relations/catalog", + "policy_revision": "rev1", + "redaction_scope": "No redaction beyond the named projection.", + "order_treatment": "Sequence order is preserved.", + "simultaneity_treatment": "Simultaneity is preserved only when declared." + }, + "projection_required": false, + "direction": "unary", + "quantification": { + "states": "For one manifest revision.", + "traces": "outside scope", + "schedulers": "outside scope", + "strategies": "outside scope", + "environments": "outside scope", + "observations": "outside scope" + }, + "dimensions": { + "nondeterminism": { + "status": "outside-scope", + "treatment": "The predicate does not quantify over branching choices." + }, + "concurrency": { + "status": "outside-scope", + "treatment": "The predicate does not compare concurrent executions." + }, + "probability": { + "status": "outside-scope", + "treatment": "The predicate does not compare probability measures." + }, + "time": { + "status": "outside-scope", + "treatment": "The predicate does not compare timed behavior." + }, + "partial_order": { + "status": "outside-scope", + "treatment": "The predicate does not compare event partial orders." + } + }, + "preservation": { + "property": "Portable declared support metadata.", + "proof_obligation": "Validate the manifest and resolve every governed identifier." + }, + "bounded_evidence": [ + "Manifest schema validation and capability-gap conformance cases." + ], + "explicit_non_claims": [ + "Does not prove that a declared capability works for every input." + ], + "incompatible_claim_surfaces": [ + "Universal backend behavior" + ], + "assurance": { + "definition_status": "defined", + "implementation_status": "implemented", + "test_status": "tested", + "proof_status": "not-applicable", + "evidence_refs": [ + "implementations/python/packages/raes_contracts/manifest_authority.py" + ] + }, + "source_refs": [ + "abadi-lamport-1991" + ] + }, + "profile-satisfaction": { + "relation_id": "profile-satisfaction", + "display_name": "Profile satisfaction", + "relation_class": "predicate", + "definition": "An artifact bundle satisfies every required concern in a named profile revision.", + "left_carrier": "An artifact or bundle.", + "right_carrier": "A governed profile with required concerns.", + "initial_states": "Not applicable; this is a profile predicate.", + "transition_signature": { + "applicability": "not-applicable", + "labels": "not applicable", + "transition_relation": "not applicable", + "observable_actions": "not applicable", + "hidden_actions": "not applicable", + "stuttering_actions": "not applicable", + "not_applicable_rationale": "Profile satisfaction aggregates named gates; it is not a behavioral matching relation." + }, + "observation_projection": { + "applicability": "not-applicable", + "subject": "Profile evaluator", + "policy_ref": "behavioral-relations/catalog", + "policy_revision": "rev1", + "redaction_scope": "No redaction beyond the named projection.", + "order_treatment": "Sequence order is preserved.", + "simultaneity_treatment": "Simultaneity is preserved only when declared." + }, + "projection_required": false, + "direction": "unary", + "quantification": { + "states": "For one artifact bundle and one profile revision.", + "traces": "outside scope", + "schedulers": "outside scope", + "strategies": "outside scope", + "environments": "outside scope", + "observations": "outside scope" + }, + "dimensions": { + "nondeterminism": { + "status": "outside-scope", + "treatment": "The predicate does not quantify over branching choices." + }, + "concurrency": { + "status": "outside-scope", + "treatment": "The predicate does not compare concurrent executions." + }, + "probability": { + "status": "outside-scope", + "treatment": "The predicate does not compare probability measures." + }, + "time": { + "status": "outside-scope", + "treatment": "The predicate does not compare timed behavior." + }, + "partial_order": { + "status": "outside-scope", + "treatment": "The predicate does not compare event partial orders." + } + }, + "preservation": { + "property": "The conjunction of the profile's required concerns.", + "proof_obligation": "Evaluate every required concern with the profile's named validator." + }, + "bounded_evidence": [ + "Scientific completeness and backend-profile case results." + ], + "explicit_non_claims": [ + "Does not promote profile satisfaction to behavioral equivalence or empirical adequacy." + ], + "incompatible_claim_surfaces": [ + "Behavioral equivalence", + "Scientific adequacy" + ], + "assurance": { + "definition_status": "defined", + "implementation_status": "implemented", + "test_status": "tested", + "proof_status": "deliberately-unproved", + "evidence_refs": [ + "contracts/profiles/" + ] + }, + "source_refs": [ + "wellek-2010" + ] + }, + "bounded-probe-success": { + "relation_id": "bounded-probe-success", + "display_name": "Bounded fixture or probe success", + "relation_class": "empirical", + "definition": "Every named finite fixture or probe in the disclosed run produced its expected result.", + "left_carrier": "A concrete implementation run.", + "right_carrier": "A finite, enumerated fixture or probe set.", + "initial_states": "The concrete initial state selected by each named case.", + "transition_signature": { + "applicability": "applicable", + "labels": "The actions exercised by the named cases.", + "transition_relation": "Only transitions actually exercised by the finite cases.", + "observable_actions": "Case outputs and sanitized diagnostics.", + "hidden_actions": "No hidden action unless a governed projection declares one.", + "stuttering_actions": "Stuttering is explicit and relation-specific." + }, + "observation_projection": { + "applicability": "parameterized", + "subject": "Case reporter", + "policy_ref": "behavioral-relations/bounded-probe-projection", + "policy_revision": "rev1", + "redaction_scope": "No redaction beyond the named projection.", + "order_treatment": "Sequence order is preserved.", + "simultaneity_treatment": "Simultaneity is preserved only when declared." + }, + "projection_required": true, + "direction": "left-to-right", + "quantification": { + "states": "Only states reached by named cases.", + "traces": "Only enumerated finite traces.", + "schedulers": "Only schedulers exercised by the harness.", + "strategies": "Only strategies exercised by the harness.", + "environments": "Only named environments.", + "observations": "Only observations emitted by named cases." + }, + "dimensions": { + "nondeterminism": { + "status": "parameterized", + "treatment": "Schedulers and branch quantifiers must be stated." + }, + "concurrency": { + "status": "parameterized", + "treatment": "Interleaving, step, or true-concurrency semantics must be stated." + }, + "probability": { + "status": "outside-scope", + "treatment": "Probability is excluded unless a probabilistic relation is named." + }, + "time": { + "status": "parameterized", + "treatment": "Timed claims require an explicit clock and time model." + }, + "partial_order": { + "status": "abstracted", + "treatment": "Default traces linearize order; partial-order claims require a separate declared model." + } + }, + "preservation": { + "property": "Success of the enumerated cases.", + "proof_obligation": "Execute every named case and compare its bounded expected result." + }, + "bounded_evidence": [ + "Fixture-suite and target-probe reports with exact case identifiers." + ], + "explicit_non_claims": [ + "Does not quantify over untested transitions, schedulers, strategies, or environments.", + "Does not establish trace equivalence, simulation, or bisimulation." + ], + "incompatible_claim_surfaces": [ + "Universal conformance", + "Backend equivalence" + ], + "assurance": { + "definition_status": "defined", + "implementation_status": "implemented", + "test_status": "tested", + "proof_status": "not-applicable", + "evidence_refs": [ + "implementations/python/packages/raes_conformance/conformance.py" + ] + }, + "source_refs": [ + "park-1981", + "van-glabbeek-1990" + ] + }, + "bounded-but-for-necessity": { + "relation_id": "bounded-but-for-necessity", + "display_name": "Bounded but-for necessity", + "relation_class": "empirical", + "definition": "Within one declared finite causal boundary, a named candidate is supported as necessary for a named outcome when the admitted baseline outcome is true, a verified intervention removes or disables only that candidate, the matched counterfactual outcome is false, and evidence, reset, and cleanup gates pass.", + "left_carrier": "A named condition, weakness, control, or behavior present in the admitted baseline world.", + "right_carrier": "A governed outcome proposition evaluated independently in the baseline and intervention worlds.", + "initial_states": "The exact admitted baseline lineage and matching policy for the finite world pair.", + "transition_signature": { + "applicability": "applicable", + "labels": "The admitted baseline execution, typed candidate intervention, counterfactual execution, observation, reset, and cleanup actions.", + "transition_relation": "Only the two immutable runs and the one declared intervention admitted by the comparison case.", + "observable_actions": "Governed outcome truth, intervention evidence, matching checks, and reset or cleanup evidence.", + "hidden_actions": "No hidden action may change a held-fixed dimension; any permitted nuisance variation must be declared by the matching policy.", + "stuttering_actions": "Stuttering is relevant only when the declared time and observation models admit it." + }, + "observation_projection": { + "applicability": "parameterized", + "subject": "Bounded necessity comparison audience", + "policy_ref": "behavioral-relations/bounded-but-for-necessity-projection", + "policy_revision": "rev1", + "redaction_scope": "Only governed evidence references and stable redacted diagnostics cross the comparison boundary.", + "order_treatment": "World executions are distinct immutable runs; their declared matching policy, not wall-clock order, governs comparison.", + "simultaneity_treatment": "Simultaneity is outside the binary criterion unless the matching policy and time model explicitly preserve it." + }, + "projection_required": true, + "direction": "left-to-right", + "quantification": { + "states": "Only the admitted baseline and intervention-world initial states and reached states.", + "traces": "Only the two named finite executions.", + "schedulers": "Only schedulers admitted and matched by the declared policy.", + "strategies": "Only participant strategies represented and matched in the two runs.", + "environments": "Only the named apparatus, backend, scenario family, and permitted nuisance variation.", + "observations": "Only governed outcome, intervention, comparability, reset, and cleanup evidence for the named case." + }, + "dimensions": { + "nondeterminism": { + "status": "parameterized", + "treatment": "Random streams, seeds, draws, and uncertainty are governed by the matching policy; a shared seed alone is insufficient." + }, + "concurrency": { + "status": "parameterized", + "treatment": "Scheduling and participant concurrency must be held fixed or declared as permitted nuisance variation." + }, + "probability": { + "status": "outside-scope", + "treatment": "The binary criterion does not establish probabilistic necessity; statistical criteria require a separate governed relation or adapter." + }, + "time": { + "status": "parameterized", + "treatment": "Both worlds bind an explicit time model and comparison boundary; wall-clock proximity is not comparability." + }, + "partial_order": { + "status": "parameterized", + "treatment": "Causal or partial-order differences must be held fixed or explicitly admitted by the matching policy." + } + }, + "preservation": { + "property": "A finite binary but-for result for the exact candidate, outcome, worlds, intervention, apparatus, and matching policy.", + "proof_obligation": "Admit a true baseline outcome, verify the candidate intervention, admit a false counterfactual outcome, prove the declared matching checks for every other semantic dimension, and independently verify reset and cleanup." + }, + "bounded_evidence": [ + "Immutable experiment-run identities, proposition-truth results, intervention evidence, matching-policy checks, and reset or cleanup evidence for one named comparison case." + ], + "explicit_non_claims": [ + "Does not establish universal, actual, sufficient, probabilistic, or model-identified causation.", + "Does not treat replay, temporal order, correlation, failed execution, a no-op intervention, or incomparable outcome differences as necessity evidence.", + "Does not promote a supported finite comparison to proof or falsification-backed validation strength." + ], + "incompatible_claim_surfaces": [ + "Universal causal proof", + "Unbounded actual-cause attribution", + "Statistical or probabilistic necessity without a separate criterion" + ], + "assurance": { + "definition_status": "defined", + "implementation_status": "implemented", + "test_status": "tested", + "proof_status": "deliberately-unproved", + "evidence_refs": [ + "implementations/python/packages/raes_conformance/necessity_evidence.py", + "implementations/python/packages/raes_conformance/necessity_types.py", + "implementations/python/packages/raes_conformance/necessity_validation.py", + "implementations/python/tests/test_necessity_validation.py" + ] + }, + "source_refs": [ + "halpern-pearl-2005" + ] + }, + "canonical-artifact-identity": { + "relation_id": "canonical-artifact-identity", + "display_name": "Canonical artifact identity", + "relation_class": "predicate", + "definition": "Two artifacts have identical canonical bytes or digest under one named serialization profile.", + "left_carrier": "One canonical artifact.", + "right_carrier": "Another canonical artifact under the same profile.", + "initial_states": "Not applicable; this is artifact identity.", + "transition_signature": { + "applicability": "not-applicable", + "labels": "not applicable", + "transition_relation": "not applicable", + "observable_actions": "not applicable", + "hidden_actions": "not applicable", + "stuttering_actions": "not applicable", + "not_applicable_rationale": "Digest identity compares canonical representations, not enabled behavior." + }, + "observation_projection": { + "applicability": "identity", + "subject": "Canonical serializer", + "policy_ref": "behavioral-relations/catalog", + "policy_revision": "rev1", + "redaction_scope": "No redaction beyond the named projection.", + "order_treatment": "Sequence order is preserved.", + "simultaneity_treatment": "Simultaneity is preserved only when declared." + }, + "projection_required": false, + "direction": "symmetric", + "quantification": { + "states": "For the two named canonical artifacts.", + "traces": "outside scope", + "schedulers": "outside scope", + "strategies": "outside scope", + "environments": "outside scope", + "observations": "outside scope" + }, + "dimensions": { + "nondeterminism": { + "status": "outside-scope", + "treatment": "The predicate does not quantify over branching choices." + }, + "concurrency": { + "status": "outside-scope", + "treatment": "The predicate does not compare concurrent executions." + }, + "probability": { + "status": "outside-scope", + "treatment": "The predicate does not compare probability measures." + }, + "time": { + "status": "outside-scope", + "treatment": "The predicate does not compare timed behavior." + }, + "partial_order": { + "status": "outside-scope", + "treatment": "The predicate does not compare event partial orders." + } + }, + "preservation": { + "property": "Canonical byte identity under the named profile.", + "proof_obligation": "Canonicalize both artifacts with the same revision and compare bytes or collision-resistant digests." + }, + "bounded_evidence": [ + "Canonicalization and digest equality tests." + ], + "explicit_non_claims": [ + "Does not establish common provenance, equal executions, or behavioral equivalence." + ], + "incompatible_claim_surfaces": [ + "Trace comparison", + "Backend behavior" + ], + "assurance": { + "definition_status": "defined", + "implementation_status": "implemented", + "test_status": "tested", + "proof_status": "not-applicable", + "evidence_refs": [ + "implementations/python/packages/raes/canonical.py" + ] + }, + "source_refs": [ + "abadi-lamport-1991" + ] + }, + "realization-envelope-membership": { + "relation_id": "realization-envelope-membership", + "display_name": "Realization-envelope membership", + "relation_class": "set-relation", + "definition": "A concrete or requested point belongs to a governed realization envelope.", + "left_carrier": "A realization point.", + "right_carrier": "A closed realization-envelope set.", + "initial_states": "Not applicable; this is set membership.", + "transition_signature": { + "applicability": "not-applicable", + "labels": "not applicable", + "transition_relation": "not applicable", + "observable_actions": "not applicable", + "hidden_actions": "not applicable", + "stuttering_actions": "not applicable", + "not_applicable_rationale": "Envelope membership is set-theoretic support, not a transition match." + }, + "observation_projection": { + "applicability": "not-applicable", + "subject": "Realization-envelope validator", + "policy_ref": "behavioral-relations/catalog", + "policy_revision": "rev1", + "redaction_scope": "No redaction beyond the named projection.", + "order_treatment": "Sequence order is preserved.", + "simultaneity_treatment": "Simultaneity is preserved only when declared." + }, + "projection_required": false, + "direction": "left-to-right", + "quantification": { + "states": "For one point and one envelope revision.", + "traces": "outside scope", + "schedulers": "outside scope", + "strategies": "outside scope", + "environments": "outside scope", + "observations": "outside scope" + }, + "dimensions": { + "nondeterminism": { + "status": "outside-scope", + "treatment": "The predicate does not quantify over branching choices." + }, + "concurrency": { + "status": "outside-scope", + "treatment": "The predicate does not compare concurrent executions." + }, + "probability": { + "status": "outside-scope", + "treatment": "The predicate does not compare probability measures." + }, + "time": { + "status": "outside-scope", + "treatment": "The predicate does not compare timed behavior." + }, + "partial_order": { + "status": "outside-scope", + "treatment": "The predicate does not compare event partial orders." + } + }, + "preservation": { + "property": "Membership in the declared support set.", + "proof_obligation": "Evaluate every envelope dimension and closure rule for the point." + }, + "bounded_evidence": [ + "Witness and negative-probe envelope tests." + ], + "explicit_non_claims": [ + "Does not establish that execution succeeds or that behavior refines an abstract runtime." + ], + "incompatible_claim_surfaces": [ + "Runtime trace inclusion", + "Backend equivalence" + ], + "assurance": { + "definition_status": "defined", + "implementation_status": "implemented", + "test_status": "tested", + "proof_status": "deliberately-unproved", + "evidence_refs": [ + "specs/formal/realization/envelope-semantics.md" + ] + }, + "source_refs": [ + "abadi-lamport-1991" + ] + }, + "realization-envelope-subsumption": { + "relation_id": "realization-envelope-subsumption", + "display_name": "Realization-envelope subsumption", + "relation_class": "set-relation", + "definition": "Every point admitted by one realization envelope is admitted by another under the named closure rules.", + "left_carrier": "One realization-envelope set.", + "right_carrier": "Another realization-envelope set.", + "initial_states": "Not applicable; this is set inclusion.", + "transition_signature": { + "applicability": "not-applicable", + "labels": "not applicable", + "transition_relation": "not applicable", + "observable_actions": "not applicable", + "hidden_actions": "not applicable", + "stuttering_actions": "not applicable", + "not_applicable_rationale": "Envelope subsumption compares support sets rather than transition systems." + }, + "observation_projection": { + "applicability": "not-applicable", + "subject": "Realization-envelope validator", + "policy_ref": "behavioral-relations/catalog", + "policy_revision": "rev1", + "redaction_scope": "No redaction beyond the named projection.", + "order_treatment": "Sequence order is preserved.", + "simultaneity_treatment": "Simultaneity is preserved only when declared." + }, + "projection_required": false, + "direction": "left-to-right", + "quantification": { + "states": "Universally over points in the left envelope.", + "traces": "outside scope", + "schedulers": "outside scope", + "strategies": "outside scope", + "environments": "outside scope", + "observations": "outside scope" + }, + "dimensions": { + "nondeterminism": { + "status": "outside-scope", + "treatment": "The predicate does not quantify over branching choices." + }, + "concurrency": { + "status": "outside-scope", + "treatment": "The predicate does not compare concurrent executions." + }, + "probability": { + "status": "outside-scope", + "treatment": "The predicate does not compare probability measures." + }, + "time": { + "status": "outside-scope", + "treatment": "The predicate does not compare timed behavior." + }, + "partial_order": { + "status": "outside-scope", + "treatment": "The predicate does not compare event partial orders." + } + }, + "preservation": { + "property": "Set inclusion of declared realization support.", + "proof_obligation": "Prove or decide inclusion for every governed envelope dimension." + }, + "bounded_evidence": [ + "Finite witness and mutation tests for current envelope operators." + ], + "explicit_non_claims": [ + "Does not establish behavioral refinement, trace inclusion, or bisimulation." + ], + "incompatible_claim_surfaces": [ + "Runtime behavior", + "Participant behavior" + ], + "assurance": { + "definition_status": "defined", + "implementation_status": "implemented", + "test_status": "tested", + "proof_status": "deliberately-unproved", + "evidence_refs": [ + "implementations/python/packages/raes_contracts/realization_envelope.py" + ] + }, + "source_refs": [ + "abadi-lamport-1991" + ] + }, + "trace-inclusion": { + "relation_id": "trace-inclusion", + "display_name": "Projected trace inclusion", + "relation_class": "behavioral", + "definition": "Every projected concrete trace belongs to the abstract trace set under a declared projection.", + "left_carrier": "Concrete implementation transition system.", + "right_carrier": "Abstract RAES transition system.", + "initial_states": "Related concrete and abstract initial states.", + "transition_signature": { + "applicability": "applicable", + "labels": "Labels in the declared concrete and abstract alphabets.", + "transition_relation": "Concrete and abstract labelled transition relations.", + "observable_actions": "Actions retained by the governed projection.", + "hidden_actions": "Only actions explicitly hidden by the projection.", + "stuttering_actions": "Concrete stuttering must be permitted by the abstract obligation." + }, + "observation_projection": { + "applicability": "required", + "subject": "Named observer or abstraction", + "policy_ref": "participant-observation-boundary", + "policy_revision": "rev1", + "redaction_scope": "No redaction beyond the named projection.", + "order_treatment": "Sequence order is preserved.", + "simultaneity_treatment": "Simultaneity is preserved only when declared." + }, + "projection_required": true, + "direction": "left-to-right", + "quantification": { + "states": "All reachable related states.", + "traces": "Universally over projected concrete traces.", + "schedulers": "All admitted schedulers unless narrowed.", + "strategies": "Outside scope unless the systems are strategic.", + "environments": "All admitted environments unless narrowed.", + "observations": "Through the named projection only." + }, + "dimensions": { + "nondeterminism": { + "status": "parameterized", + "treatment": "Schedulers and branch quantifiers must be stated." + }, + "concurrency": { + "status": "parameterized", + "treatment": "Interleaving, step, or true-concurrency semantics must be stated." + }, + "probability": { + "status": "outside-scope", + "treatment": "Probability is excluded unless a probabilistic relation is named." + }, + "time": { + "status": "parameterized", + "treatment": "Timed claims require an explicit clock and time model." + }, + "partial_order": { + "status": "abstracted", + "treatment": "Default traces linearize order; partial-order claims require a separate declared model." + } + }, + "preservation": { + "property": "Abstract trace safety for projected concrete executions.", + "proof_obligation": "Show Proj(Traces_concrete) is a subset of Traces_abstract under stated fairness and divergence assumptions." + }, + "bounded_evidence": [ + "Finite target probes can falsify but cannot prove universal inclusion." + ], + "explicit_non_claims": [ + "Does not establish completeness, reverse inclusion, trace equivalence, or bisimulation." + ], + "incompatible_claim_surfaces": [ + "Current backend conformance report" + ], + "assurance": { + "definition_status": "defined", + "implementation_status": "partial", + "test_status": "bounded", + "proof_status": "deliberately-unproved", + "evidence_refs": [ + "specs/formal/participant-runtime/README.md" + ] + }, + "source_refs": [ + "van-glabbeek-1990", + "abadi-lamport-1991", + "lynch-vaandrager-1995" + ] + }, + "trace-equivalence": { + "relation_id": "trace-equivalence", + "display_name": "Trace equivalence", + "relation_class": "behavioral", + "definition": "Two systems have equal projected trace sets under the same declared alphabet and projection.", + "left_carrier": "One labelled transition system.", + "right_carrier": "Another labelled transition system.", + "initial_states": "Paired initial states.", + "transition_signature": { + "applicability": "applicable", + "labels": "A shared declared label alphabet.", + "transition_relation": "The two labelled transition relations.", + "observable_actions": "Labels retained by the common projection.", + "hidden_actions": "Labels hidden by the common projection.", + "stuttering_actions": "Stuttering treatment must be identical." + }, + "observation_projection": { + "applicability": "required", + "subject": "Named comparison observer", + "policy_ref": "behavioral-relations/catalog", + "policy_revision": "rev1", + "redaction_scope": "No redaction beyond the named projection.", + "order_treatment": "Sequence order is preserved.", + "simultaneity_treatment": "Simultaneity is preserved only when declared." + }, + "projection_required": true, + "direction": "symmetric", + "quantification": { + "states": "All reachable states contributing traces.", + "traces": "Universally over both trace sets.", + "schedulers": "All admitted schedulers.", + "strategies": "Outside scope unless strategies are encoded.", + "environments": "All declared environments.", + "observations": "Through one common projection." + }, + "dimensions": { + "nondeterminism": { + "status": "parameterized", + "treatment": "Schedulers and branch quantifiers must be stated." + }, + "concurrency": { + "status": "parameterized", + "treatment": "Interleaving, step, or true-concurrency semantics must be stated." + }, + "probability": { + "status": "outside-scope", + "treatment": "Probability is excluded unless a probabilistic relation is named." + }, + "time": { + "status": "parameterized", + "treatment": "Timed claims require an explicit clock and time model." + }, + "partial_order": { + "status": "abstracted", + "treatment": "Default traces linearize order; partial-order claims require a separate declared model." + } + }, + "preservation": { + "property": "Equality of projected trace languages.", + "proof_obligation": "Prove both projected trace inclusions under identical assumptions." + }, + "bounded_evidence": [ + "Finite trace comparison may refute but cannot establish equality." + ], + "explicit_non_claims": [ + "Does not preserve branching structure and does not imply bisimulation." + ], + "incompatible_claim_surfaces": [ + "Finite backend comparison" + ], + "assurance": { + "definition_status": "defined", + "implementation_status": "not-implemented", + "test_status": "not-tested", + "proof_status": "future", + "evidence_refs": [] + }, + "source_refs": [ + "van-glabbeek-1990" + ] + }, + "forward-simulation": { + "relation_id": "forward-simulation", + "display_name": "Forward simulation", + "relation_class": "behavioral", + "definition": "A relation maps each concrete step to an abstract matching path while preserving related states.", + "left_carrier": "Concrete implementation states.", + "right_carrier": "Abstract specification states.", + "initial_states": "Every concrete initial state relates to an abstract initial state.", + "transition_signature": { + "applicability": "applicable", + "labels": "Concrete and abstract labels under a declared matching function.", + "transition_relation": "Concrete and abstract step relations.", + "observable_actions": "Labels exposed by the abstraction.", + "hidden_actions": "Labels mapped to hidden or stuttering abstract behavior.", + "stuttering_actions": "Explicit abstract stuttering where allowed." + }, + "observation_projection": { + "applicability": "parameterized", + "subject": "Abstraction observer", + "policy_ref": "behavioral-relations/catalog", + "policy_revision": "rev1", + "redaction_scope": "No redaction beyond the named projection.", + "order_treatment": "Sequence order is preserved.", + "simultaneity_treatment": "Simultaneity is preserved only when declared." + }, + "projection_required": true, + "direction": "left-to-right", + "quantification": { + "states": "Universally over related reachable states.", + "traces": "All concrete traces induced by matched steps.", + "schedulers": "All admitted concrete choices.", + "strategies": "Outside scope unless extended strategically.", + "environments": "All admitted environments.", + "observations": "Under the named abstraction." + }, + "dimensions": { + "nondeterminism": { + "status": "parameterized", + "treatment": "Schedulers and branch quantifiers must be stated." + }, + "concurrency": { + "status": "parameterized", + "treatment": "Interleaving, step, or true-concurrency semantics must be stated." + }, + "probability": { + "status": "outside-scope", + "treatment": "Probability is excluded unless a probabilistic relation is named." + }, + "time": { + "status": "parameterized", + "treatment": "Timed claims require an explicit clock and time model." + }, + "partial_order": { + "status": "abstracted", + "treatment": "Default traces linearize order; partial-order claims require a separate declared model." + } + }, + "preservation": { + "property": "Usually projected trace inclusion and named safety properties.", + "proof_obligation": "Supply a simulation relation and discharge initiality plus step-correspondence obligations." + }, + "bounded_evidence": [ + "Tests may exercise candidate obligations on finite models only." + ], + "explicit_non_claims": [ + "Successful probes do not establish a simulation relation." + ], + "incompatible_claim_surfaces": [ + "Current conformance results" + ], + "assurance": { + "definition_status": "defined", + "implementation_status": "not-implemented", + "test_status": "not-tested", + "proof_status": "future", + "evidence_refs": [] + }, + "source_refs": [ + "lynch-vaandrager-1995", + "abadi-lamport-1991" + ] + }, + "backward-simulation": { + "relation_id": "backward-simulation", + "display_name": "Backward simulation", + "relation_class": "behavioral", + "definition": "A relation reasons from abstract successor possibilities back to concrete predecessors to establish implementation inclusion where forward simulation is insufficient.", + "left_carrier": "Concrete implementation states.", + "right_carrier": "Abstract specification states.", + "initial_states": "Initial and reachable-state coverage follow the selected backward-simulation theorem.", + "transition_signature": { + "applicability": "applicable", + "labels": "Concrete and abstract labels under the theorem's matching rule.", + "transition_relation": "Concrete and abstract step relations.", + "observable_actions": "Declared external labels.", + "hidden_actions": "Declared internal labels.", + "stuttering_actions": "History, prophecy, and stuttering treatment must be explicit." + }, + "observation_projection": { + "applicability": "parameterized", + "subject": "Abstraction observer", + "policy_ref": "behavioral-relations/catalog", + "policy_revision": "rev1", + "redaction_scope": "No redaction beyond the named projection.", + "order_treatment": "Sequence order is preserved.", + "simultaneity_treatment": "Simultaneity is preserved only when declared." + }, + "projection_required": true, + "direction": "left-to-right", + "quantification": { + "states": "Universally over theorem-defined related states.", + "traces": "All represented implementation behaviors.", + "schedulers": "All admitted nondeterministic choices.", + "strategies": "Outside scope unless extended strategically.", + "environments": "All admitted environments.", + "observations": "Under the named abstraction." + }, + "dimensions": { + "nondeterminism": { + "status": "parameterized", + "treatment": "Schedulers and branch quantifiers must be stated." + }, + "concurrency": { + "status": "parameterized", + "treatment": "Interleaving, step, or true-concurrency semantics must be stated." + }, + "probability": { + "status": "outside-scope", + "treatment": "Probability is excluded unless a probabilistic relation is named." + }, + "time": { + "status": "parameterized", + "treatment": "Timed claims require an explicit clock and time model." + }, + "partial_order": { + "status": "abstracted", + "treatment": "Default traces linearize order; partial-order claims require a separate declared model." + } + }, + "preservation": { + "property": "Implementation behavior inclusion under the cited theorem's assumptions.", + "proof_obligation": "Supply a backward simulation relation and discharge its reachability, initiality, and step obligations." + }, + "bounded_evidence": [ + "Finite model tests can exercise examples but do not prove a backend relation." + ], + "explicit_non_claims": [ + "Does not follow from result equality or a forward-only sampled trace." + ], + "incompatible_claim_surfaces": [ + "Current backend conformance" + ], + "assurance": { + "definition_status": "defined", + "implementation_status": "not-implemented", + "test_status": "not-tested", + "proof_status": "future", + "evidence_refs": [] + }, + "source_refs": [ + "lynch-vaandrager-1995" + ] + }, + "data-refinement": { + "relation_id": "data-refinement", + "display_name": "Data refinement", + "relation_class": "behavioral", + "definition": "Concrete data states represent abstract states through a retrieve relation while operations preserve that relation.", + "left_carrier": "Concrete state and operation space.", + "right_carrier": "Abstract state and operation space.", + "initial_states": "Concrete and abstract initial states related by the retrieve relation.", + "transition_signature": { + "applicability": "applicable", + "labels": "Operation invocations and observations.", + "transition_relation": "Concrete and abstract operation relations.", + "observable_actions": "Client-visible operation effects.", + "hidden_actions": "Internal representation steps.", + "stuttering_actions": "Stuttering and enabledness obligations are method-specific." + }, + "observation_projection": { + "applicability": "parameterized", + "subject": "Client observation", + "policy_ref": "behavioral-relations/catalog", + "policy_revision": "rev1", + "redaction_scope": "No redaction beyond the named projection.", + "order_treatment": "Sequence order is preserved.", + "simultaneity_treatment": "Simultaneity is preserved only when declared." + }, + "projection_required": true, + "direction": "left-to-right", + "quantification": { + "states": "All states satisfying the retrieve relation.", + "traces": "All operation histories covered by the refinement method.", + "schedulers": "All admitted operation nondeterminism.", + "strategies": "Outside scope unless strategies are modeled.", + "environments": "All client environments under stated preconditions.", + "observations": "Client-visible results only." + }, + "dimensions": { + "nondeterminism": { + "status": "parameterized", + "treatment": "Schedulers and branch quantifiers must be stated." + }, + "concurrency": { + "status": "parameterized", + "treatment": "Interleaving, step, or true-concurrency semantics must be stated." + }, + "probability": { + "status": "outside-scope", + "treatment": "Probability is excluded unless a probabilistic relation is named." + }, + "time": { + "status": "parameterized", + "treatment": "Timed claims require an explicit clock and time model." + }, + "partial_order": { + "status": "abstracted", + "treatment": "Default traces linearize order; partial-order claims require a separate declared model." + } + }, + "preservation": { + "property": "The abstract operation contract and selected client-observable properties.", + "proof_obligation": "Define the retrieve relation and discharge initialization, applicability/enabledness, and correctness obligations." + }, + "bounded_evidence": [ + "Contract and operation tests are bounded evidence only." + ], + "explicit_non_claims": [ + "An SDL transformation function is not data refinement without these obligations." + ], + "incompatible_claim_surfaces": [ + "SDL phase transformation" + ], + "assurance": { + "definition_status": "defined", + "implementation_status": "not-implemented", + "test_status": "not-tested", + "proof_status": "future", + "evidence_refs": [] + }, + "source_refs": [ + "abadi-lamport-1991", + "lynch-vaandrager-1995" + ] + }, + "strong-bisimulation": { + "relation_id": "strong-bisimulation", + "display_name": "Strong Park-Milner bisimulation", + "relation_class": "behavioral", + "definition": "A symmetric relation matches every labelled step immediately in both directions.", + "left_carrier": "One labelled transition system.", + "right_carrier": "Another labelled transition system.", + "initial_states": "The two initial states belong to the bisimulation relation.", + "transition_signature": { + "applicability": "applicable", + "labels": "A common label alphabet including internal labels.", + "transition_relation": "Both labelled transition relations.", + "observable_actions": "Every label is matched exactly.", + "hidden_actions": "Hidden labels are still labels and must match immediately.", + "stuttering_actions": "Only explicitly labelled stuttering steps can match." + }, + "observation_projection": { + "applicability": "identity", + "subject": "External comparison observer", + "policy_ref": "behavioral-relations/catalog", + "policy_revision": "rev1", + "redaction_scope": "No redaction beyond the named projection.", + "order_treatment": "Sequence order is preserved.", + "simultaneity_treatment": "Simultaneity is preserved only when declared." + }, + "projection_required": false, + "direction": "symmetric", + "quantification": { + "states": "Universally over every related state pair.", + "traces": "All branching continuations.", + "schedulers": "All nondeterministic branches.", + "strategies": "Outside scope unless lifted to games.", + "environments": "All transition-system environments encoded in state.", + "observations": "Identity observation of labels." + }, + "dimensions": { + "nondeterminism": { + "status": "parameterized", + "treatment": "Schedulers and branch quantifiers must be stated." + }, + "concurrency": { + "status": "parameterized", + "treatment": "Interleaving, step, or true-concurrency semantics must be stated." + }, + "probability": { + "status": "outside-scope", + "treatment": "Probability is excluded unless a probabilistic relation is named." + }, + "time": { + "status": "parameterized", + "treatment": "Timed claims require an explicit clock and time model." + }, + "partial_order": { + "status": "abstracted", + "treatment": "Default traces linearize order; partial-order claims require a separate declared model." + } + }, + "preservation": { + "property": "Branching structure and modal properties under the chosen semantics.", + "proof_obligation": "Exhibit a symmetric relation closed under immediate labelled steps in both directions." + }, + "bounded_evidence": [ + "Finite algorithms can decide the relation only for supplied finite models." + ], + "explicit_non_claims": [ + "One shared trace, result, digest, or terminal observation is insufficient." + ], + "incompatible_claim_surfaces": [ + "Finite probes", + "Digest comparison" + ], + "assurance": { + "definition_status": "defined", + "implementation_status": "not-implemented", + "test_status": "not-tested", + "proof_status": "future", + "evidence_refs": [] + }, + "source_refs": [ + "park-1981", + "milner-1980" + ] + }, + "weak-bisimulation": { + "relation_id": "weak-bisimulation", + "display_name": "Weak or observational bisimulation", + "relation_class": "behavioral", + "definition": "A symmetric relation matches visible actions through closure over explicitly hidden tau steps.", + "left_carrier": "One labelled transition system with tau.", + "right_carrier": "Another labelled transition system with tau.", + "initial_states": "Initial states related after the selected tau closure.", + "transition_signature": { + "applicability": "applicable", + "labels": "A common visible alphabet plus the declared tau label.", + "transition_relation": "Both labelled transition relations.", + "observable_actions": "Visible labels match through weak transitions.", + "hidden_actions": "Only the explicitly governed tau label is hidden.", + "stuttering_actions": "Tau closure and stuttering are explicit; divergence treatment is declared." + }, + "observation_projection": { + "applicability": "required", + "subject": "Observer that hides tau", + "policy_ref": "behavioral-relations/tau-projection", + "policy_revision": "rev1", + "redaction_scope": "No redaction beyond the named projection.", + "order_treatment": "Sequence order is preserved.", + "simultaneity_treatment": "Simultaneity is preserved only when declared." + }, + "projection_required": true, + "direction": "symmetric", + "quantification": { + "states": "Universally over related states under tau closure.", + "traces": "All weak traces and branching continuations.", + "schedulers": "All nondeterministic tau and visible branches.", + "strategies": "Outside scope unless lifted to games.", + "environments": "All encoded environments.", + "observations": "Through the named hiding projection." + }, + "dimensions": { + "nondeterminism": { + "status": "parameterized", + "treatment": "Schedulers and branch quantifiers must be stated." + }, + "concurrency": { + "status": "parameterized", + "treatment": "Interleaving, step, or true-concurrency semantics must be stated." + }, + "probability": { + "status": "outside-scope", + "treatment": "Probability is excluded unless a probabilistic relation is named." + }, + "time": { + "status": "parameterized", + "treatment": "Timed claims require an explicit clock and time model." + }, + "partial_order": { + "status": "abstracted", + "treatment": "Default traces linearize order; partial-order claims require a separate declared model." + } + }, + "preservation": { + "property": "Observation-preserving branching behavior under stated divergence and termination semantics.", + "proof_obligation": "Exhibit a weak bisimulation relation and discharge both directional weak-step obligations." + }, + "bounded_evidence": [ + "The catalog's hidden-action example demonstrates the definition on a finite toy model." + ], + "explicit_non_claims": [ + "Backend-internal work is not tau unless a governed projection declares it." + ], + "incompatible_claim_surfaces": [ + "Undeclared backend hiding" + ], + "assurance": { + "definition_status": "defined", + "implementation_status": "not-implemented", + "test_status": "bounded", + "proof_status": "future", + "evidence_refs": [ + "contracts/concept-authority/behavioral-relations-v1.json#worked_examples" + ] + }, + "source_refs": [ + "milner-1980", + "van-glabbeek-1990" + ] + }, + "divergence-preserving-branching-bisimulation": { + "relation_id": "divergence-preserving-branching-bisimulation", + "display_name": "Divergence-preserving branching bisimulation", + "relation_class": "behavioral", + "definition": "A symmetric branching bisimulation matches visible transitions through finite closure over an explicitly governed tau set while preserving each related branching point and explicit infinite tau behavior in both directions.", + "left_carrier": "One labelled transition system with a closed visible/tau partition and explicit deadlock, termination, and divergence semantics.", + "right_carrier": "Another labelled transition system over the same projected visible alphabet and governed tau treatment.", + "initial_states": "The revisioned relation-parameter profile names both initial states and requires them to belong to the greatest fixed-point relation.", + "transition_signature": { + "applicability": "applicable", + "labels": "A common projected visible alphabet plus only the tau labels enumerated by the revisioned relation-parameter profile.", + "transition_relation": "Both complete labelled transition relations over the profile's quantified carriers.", + "observable_actions": "Every projected visible action is matched in both directions after finite tau closure while the pre-action branching state remains related.", + "hidden_actions": "Only profile-enumerated tau actions are hidden; redacted occurrences, refusals, unsupported outcomes, errors, deadlock, termination, and divergence are not hidden by default.", + "stuttering_actions": "Finite tau stuttering is admitted at a related branching point; explicit infinite tau paths must be preserved in both directions." + }, + "observation_projection": { + "applicability": "required", + "subject": "The participant, audience, auditor, or other observer named by the closed relation-parameter profile.", + "policy_ref": "Revisioned divergence-preserving branching-bisimulation projection from the claim profile.", + "policy_revision": "The exact projection revision bound by the claim.", + "redaction_scope": "The profile enumerates every visible, redacted-occurrence, and tau label; implementation-internal or content-redacted does not imply hidden.", + "order_treatment": "The profile fixes sequence, interleaving, step, causal, or other order semantics; one linearization cannot establish a partial-order claim.", + "simultaneity_treatment": "Only simultaneity represented in the selected LTS and visible projection is preserved." + }, + "projection_required": true, + "relation_parameter_profile_required": true, + "direction": "symmetric", + "quantification": { + "states": "greatest-fixed-point relation", + "traces": "All visible and tau continuations from every related state pair, including infinite tau continuations.", + "schedulers": "Every nondeterministic branch and scheduler admitted by the closed profile.", + "strategies": "Outside scope unless the carriers explicitly encode game or adaptive-strategy state.", + "environments": "Every environment state and input admitted by the closed profile.", + "observations": "Exactly the visible alphabet after the revisioned closed projection; the tau partition remains explicit." + }, + "dimensions": { + "nondeterminism": { + "status": "supported", + "treatment": "Every admitted branch is matched; finite samples or selected schedules are insufficient." + }, + "concurrency": { + "status": "parameterized", + "treatment": "The profile declares interleaving, step, true-concurrent, or other semantics and the preserved visible order." + }, + "probability": { + "status": "outside-scope", + "treatment": "Probability measures are excluded; a probabilistic relation must be named separately." + }, + "time": { + "status": "parameterized", + "treatment": "Untimed profiles erase no visible time label; timed claims require a clock and timed relation." + }, + "partial_order": { + "status": "parameterized", + "treatment": "A partial-order claim requires a carrier and relation that preserve the declared causal structure." + } + }, + "preservation": { + "property": "Visible branching structure, finite governed tau stuttering, explicit termination and structural deadlock, and explicit divergence under the named projection and model dimensions.", + "proof_obligation": "Exhibit or decide the greatest symmetric relation satisfying both branching transfer clauses and both explicit-divergence clauses for the complete quantified carriers and initial states." + }, + "bounded_evidence": [ + "Issue #811 supplies an exact complete-finite theorem profile, witness family, mutation design, and pinned checker contract; it does not run the equivalence decision.", + "A finite model-check result is final only when the supplied finite carrier is the complete quantified domain and the evidence binds exact inputs, counts, tool provenance, result, and independent reproduction." + ], + "explicit_non_claims": [ + "Taxonomy revision rev6 defines this relation and the participant-crossing claim surface but does not establish a model-check or proof result.", + "The participant-crossing design does not establish live-runtime realization, backend conformance, whole-runtime equivalence, policy noninterference, or predicate opacity.", + "Depth limits, sampled traces, probes, matching digests, schema equality, and ordinary weak bisimulation are not this relation." + ], + "incompatible_claim_surfaces": [ + "Undeclared tau hiding or divergence treatment", + "Incomplete, sampled, depth-limited, or timeout-truncated carriers promoted to a complete result", + "Formal equivalence promoted to live-runtime, backend, noninterference, opacity, timed, probabilistic, strategic, concurrent, or partial-order assurance" + ], + "assurance": { + "definition_status": "defined", + "implementation_status": "not-implemented", + "test_status": "not-tested", + "proof_status": "deliberately-unproved", + "checker_status": "not-implemented", + "model_check_status": "not-model-checked", + "runtime_enforcement_status": "not-enforced", + "backend_declaration_status": "not-declared", + "backend_realization_status": "not-realized", + "backend_conformance_status": "not-tested", + "evidence_refs": [ + "docs/decisions/adrs/adr-100-participant-crossing-bisimulation.md", + "specs/formal/participant-semantics/participant-crossing-bisimulation.md", + "docs/research/participant-bisimulation/implementation-program.json" + ] + }, + "source_refs": [ + "van-glabbeek-weijland-1996", + "van-glabbeek-luttik-trcka-2009" + ] + }, + "participant-predicate-opacity": { + "relation_id": "participant-predicate-opacity", + "display_name": "Participant-relative predicate opacity", + "relation_class": "epistemic", + "definition": "For every actual possible point at which the selected secret predicate is true, the named participant, audience, or coalition information cell induced by equal declared initial information and accumulated observations contains at least one possible point at which the predicate is false. The baseline is one-sided and possibilistic.", + "left_carrier": "One declared possible-point system whose points compose model or supervisor realization, run, evaluation cut, observer-local state and retained memory, exact-cut policy realization, and scheduler, environment, and order context.", + "right_carrier": "Not applicable; opacity is a unary property of the declared possible-point system and relation-parameter profile. A nonsecret point is a witness inside the same carrier, not a second system.", + "initial_states": "The profile fixes observer or coalition initial information, participant and audience identity, retained memory, policy and supervisor visibility, environment and scheduler classes, and the initial cut or horizon.", + "transition_signature": { + "applicability": "applicable", + "labels": "SEM-230 and participant-runtime occurrences, including proposal and control decisions, admission, attempt and result, disclosure and withholding, transformation, delivery and observation, policy or supervisor change, evidence, and audit when retained by the selected observation profile.", + "transition_relation": "Valid runs over existing participant world, view, local-history, archival-evidence, controller, authority, marking, exact-cut policy, crossing, delivery, observation, scheduler, environment, and order carriers.", + "observable_actions": "Exactly the content, occurrence, omission, decision, failure, delivery, retry, order, timing, policy-change, retrieval, evidence, or audit coordinates retained for the named observer by the revisioned relation-parameter profile.", + "hidden_actions": "Only occurrences removed by that observer-, policy-, supervisor-visibility-, cut-, memory-, time-, and order-relative observation function; hidden implementation does not imply hidden behavior.", + "stuttering_actions": "The untimed baseline removes finite unobserved stuttering and is progress- and termination-insensitive. Omission is observable only when the profile supplies an opportunity, deadline, acknowledgement, progress, or clock model." + }, + "observation_projection": { + "applicability": "required", + "subject": "Named participant, audience, or explicit coalition", + "policy_ref": "SEM-231 participant-predicate-opacity observation profile", + "policy_revision": "The revisioned relation-parameter profile bound by the claim", + "redaction_scope": "Projection, redaction, declassification, decision disclosure, concealment, revocation, loss, and prior knowledge remain distinct; the profile states which resulting facts are observations.", + "order_treatment": "The profile selects total, participant-local, causal partial, simultaneous, or backend-serialized order. One linearization cannot establish a partial-order claim.", + "simultaneity_treatment": "Only declared simultaneity and visible causal frontiers are retained; timestamp equality is not simultaneity." + }, + "projection_required": true, + "relation_parameter_profile_required": true, + "direction": "unary", + "quantification": { + "states": "For every actual point in the declared carrier at which the revisioned secret predicate is true, there exists a point in the same observer information cell at which it is false.", + "traces": "Over every run and cut admitted by the selected current-, initial-, K-step, infinite-step, language, or other declared horizon profile.", + "schedulers": "Over the fixed declared scheduler class and admitted order contexts; scheduler-sensitive variants state their quantifier order.", + "strategies": "Passive profiles quantify over observations only. Active profiles quantify universally over the declared allowed adaptive participant strategies, with actual and witness runs possible under the same strategy.", + "environments": "Over the fixed declared model and environment class, including only supervisor or policy realizations admitted by the selected visibility posture.", + "observations": "Equality of declared initial information and accumulated observer-local observations, including memory across retries, replay, episodes, policy revisions, controller handoffs, and coalition sharing when selected." + }, + "dimensions": { + "nondeterminism": { + "status": "supported", + "treatment": "The baseline is possibilistic over the declared support. Nondeterministic or randomized supervision changes possible points but is not itself opacity evidence." + }, + "concurrency": { + "status": "parameterized", + "treatment": "The profile fixes interleaving, step, simultaneous, causal, or other declared concurrent semantics and observer-visible order." + }, + "probability": { + "status": "outside-scope", + "treatment": "The baseline compares possibility support, not probability mass, posterior belief, entropy, leakage probability, or differential privacy. Quantitative opacity requires a separately governed relation." + }, + "time": { + "status": "parameterized", + "treatment": "The baseline is untimed and progress-insensitive. A timed profile requires a governed clock, duration and progress observation model and separately scoped evidence." + }, + "partial_order": { + "status": "parameterized", + "treatment": "A partial-order claim compares declared visible causal frontiers and admitted schedules; a witness from one convenient linearization is insufficient." + } + }, + "preservation": { + "property": "The named observer never knows that the selected one-sided secret predicate is true at a protected cut because every actual secret information cell retains a possible nonsecret point.", + "proof_obligation": "For every quantified actual secret point and, for active profiles, every allowed adaptive strategy, exhibit or prove the existence of a nonsecret point with equal declared initial information and accumulated observation under the same profile, strategy, release schedule, supervisor visibility, memory, scheduler, environment, time, and order assumptions." + }, + "bounded_evidence": [ + "The SEM-231 formal specification gives four finite counterexamples covering an incomplete equal-history witness, supervisor-decision leakage, opacity without noninterference, and declassification-induced knowledge change.", + "The participant-opacity-baseline-v1 profile closes every relation coordinate and the deterministic processor exhausts exact declared finite possible-point carriers with digest-bound bounded outcomes or sanitized counterexample references.", + "implementations/python/tests/test_issue_961_participant_opacity.py covers profile and claim resolution, finite bounds, active strategies, coalition fusion, decision and omission channels, retained release knowledge, vacuity, deterministic evidence, replay, and explicit nonclaims.", + "The participant-opacity finite-state checker derives the complete reachable fixed point from an exact transition model, checks every reachable secret evaluation point, and binds catalog, profile, model, assumptions, explored coverage, tool version, result or safe counterexample, and replay evidence.", + "The committed model-check input and evidence fixtures retain the exact positive baseline model, result, digests, complete coverage, tool identity, and explicit nonclaims; invalid fixtures exercise count and partial-result promotion failures.", + "implementations/python/tests/test_issue_962_participant_opacity_model_check.py covers pair-probe incompleteness, supervisor behavior, active strategies, coalition fusion, retained memory, release changes, order and probability non-promotion, exact bounds, replay, and agreement with the bounded lane." + ], + "explicit_non_claims": [ + "Relation definition, catalog validation, claim-profile binding, and bounded finite analysis do not establish opacity of RAES, RUN-319, or any backend outside the exact admitted artifact.", + "No checker, finite-state model check, mathematical proof, runtime enforcement, supervisor synthesis, backend declaration, backend realization, or backend conformance is delivered by taxonomy revision rev5.", + "Taxonomy revision rev7 adds only an in-process bounded-test checker; it does not add a model check, mathematical proof, runtime enforcement, supervisor synthesis, backend declaration, backend realization, or backend conformance.", + "Taxonomy revision rev8 adds one exact finite-state model-check result; it does not add a mathematical proof, runtime enforcement, supervisor synthesis, backend declaration, backend realization, or backend conformance.", + "Bounded evidence authenticates only the normalized-input digest; it does not authenticate a claimed source artifact or materializer.", + "Opacity of one predicate does not imply SEM-230 policy noninterference, projected-history equivalence, epistemic indistinguishability of two selected worlds, trace inclusion or equivalence, simulation, refinement, or strong or weak bisimulation.", + "The possibilistic baseline makes no posterior-risk, entropy, probabilistic, differential-privacy, timed, progress-sensitive, or universal partial-order claim." + ], + "incompatible_claim_surfaces": [ + "Unrevisioned or untyped secret, observer, supervisor-visibility, memory, strategy, time, order, or release coordinates", + "Single equal-history pairs, finite probes, randomized behavior, runtime filters, or backend declarations promoted to universal opacity", + "Claims that erase prior knowledge through concealment, revocation, reset, rollback, or supersession" + ], + "assurance": { + "definition_status": "defined", + "implementation_status": "implemented", + "test_status": "bounded", + "proof_status": "deliberately-unproved", + "checker_status": "implemented", + "model_check_status": "model-checked", + "runtime_enforcement_status": "not-enforced", + "backend_declaration_status": "not-declared", + "backend_realization_status": "not-realized", + "backend_conformance_status": "not-tested", + "evidence_refs": [ + "docs/decisions/adrs/adr-099-participant-relative-predicate-opacity.md", + "specs/formal/participant-semantics/participant-predicate-opacity.md", + "contracts/profiles/behavioral-relation/participant-opacity-baseline-v1.json", + "contracts/schemas/formal-analysis/participant-opacity-model-check-input-v1.json", + "contracts/schemas/formal-analysis/participant-opacity-model-check-evidence-v1.json", + "contracts/fixtures/formal-analysis/participant-opacity-model-check-input-v1/valid/opaque-transition-model.json", + "contracts/fixtures/formal-analysis/participant-opacity-model-check-evidence-v1/valid/opaque-transition-model.json", + "implementations/python/packages/raes_processor/participant_opacity/_service.py", + "implementations/python/packages/raes_processor/participant_opacity/_model_check.py", + "implementations/python/tests/test_sem_231_participant_predicate_opacity.py", + "implementations/python/tests/test_issue_961_participant_opacity.py", + "implementations/python/tests/test_issue_962_participant_opacity_model_check.py" + ] + }, + "source_refs": [ + "andre-lime-marinho-sun-2022", + "badouel-bednarczyk-borzyszkowski-caillaud-darondeau-2007", + "berard-mullins-sassolas-2015", + "broberg-van-delft-sands-2015", + "bryans-koutny-mazare-ryan-2008", + "cui-ma-giua-yin-2026", + "fagin-halpern-moses-vardi-1995", + "lin-2011", + "partovi-jung-hai-2020", + "saboori-hadjicostis-2012", + "schoepe-sabelfeld-2015", + "xie-yin-li-2022", + "yin-lafortune-2016" + ] + }, + "participant-projected-history-equivalence": { + "relation_id": "participant-projected-history-equivalence", + "display_name": "Participant-projected history equivalence", + "relation_class": "epistemic", + "definition": "Two finite or complete histories have equal projections for one participant under one observation-boundary revision.", + "left_carrier": "One global or backend history.", + "right_carrier": "Another global or backend history.", + "initial_states": "The compared histories share a declared participant and starting information state.", + "transition_signature": { + "applicability": "applicable", + "labels": "Participant-visible events after projection.", + "transition_relation": "Underlying history extension relations.", + "observable_actions": "Events admitted by the participant observation boundary.", + "hidden_actions": "Events removed or redacted by the boundary.", + "stuttering_actions": "No additional stuttering assumption beyond projected history equality." + }, + "observation_projection": { + "applicability": "required", + "subject": "Named participant", + "policy_ref": "participant-observation-boundary", + "policy_revision": "rev1", + "redaction_scope": "No redaction beyond the named projection.", + "order_treatment": "Sequence order is preserved.", + "simultaneity_treatment": "Simultaneity is preserved only when declared." + }, + "projection_required": true, + "direction": "symmetric", + "quantification": { + "states": "States represented in the compared histories.", + "traces": "Finite histories unless a universal claim is separately proved.", + "schedulers": "Only schedulers represented in the histories.", + "strategies": "No strategic quantification.", + "environments": "Only the named environment/run context.", + "observations": "One participant and one policy revision." + }, + "dimensions": { + "nondeterminism": { + "status": "parameterized", + "treatment": "Schedulers and branch quantifiers must be stated." + }, + "concurrency": { + "status": "parameterized", + "treatment": "Interleaving, step, or true-concurrency semantics must be stated." + }, + "probability": { + "status": "outside-scope", + "treatment": "Probability is excluded unless a probabilistic relation is named." + }, + "time": { + "status": "parameterized", + "treatment": "Timed claims require an explicit clock and time model." + }, + "partial_order": { + "status": "abstracted", + "treatment": "Default traces linearize order; partial-order claims require a separate declared model." + } + }, + "preservation": { + "property": "Equality or indistinguishability of the named participant's projected histories.", + "proof_obligation": "Apply the existing participant observation boundary to both histories and compare the resulting ordered visible records." + }, + "bounded_evidence": [ + "Participant behavior-history and observation-envelope tests on named histories." + ], + "explicit_non_claims": [ + "Does not imply equality of global state, future behavior, knowledge, or strategy." + ], + "incompatible_claim_surfaces": [ + "Global-state comparison", + "Strategic equivalence" + ], + "assurance": { + "definition_status": "defined", + "implementation_status": "implemented", + "test_status": "bounded", + "proof_status": "deliberately-unproved", + "evidence_refs": [ + "specs/formal/participant-runtime/README.md" + ] + }, + "source_refs": [ + "fagin-halpern-moses-vardi-1995", + "milner-1980" + ] + }, + "policy-noninterference": { + "relation_id": "policy-noninterference", + "display_name": "Participant-policy noninterference", + "relation_class": "behavioral", + "definition": "For a fixed participant, episode and memory scope, model, environment class, scheduler class, order model, exact-cut policy-decision sequence, permitted declassification schedule, and low-strategy class, every low participant strategy produces equal support sets of projected participant-visible histories from low-equivalent initial states despite unauthorized high variation.", + "left_carrier": "The support set of valid labelled participant-policy runs from one low-equivalent initial state under one adaptive low strategy.", + "right_carrier": "The support set of valid labelled participant-policy runs from another low-equivalent initial state under the same adaptive low strategy.", + "initial_states": "Initial world, participant-view, delivered decision-surface history, participant memory, archival-evidence, controller, authority, marking, and policy states related by the SEM-230 low-equivalence relation at the declared initial state cut.", + "transition_signature": { + "applicability": "applicable", + "labels": "The closed SEM-230 alphabet for proposal, approval or denial, direction, intervention, handoff, override or cancellation, admission or rejection, attempt or result, disclosure or withholding, concealment, revocation, transformation, delivery, observation, policy change, evidence, and audit actions.", + "transition_relation": "The SEM-230 participant-policy crossing relation over existing world, view, local-history, archival-evidence, action, lifecycle, ordering, marking, controller, authority, policy, and provenance state.", + "observable_actions": "Labels retained for the named participant and audience by the exact-cut policy decision, marking/declassification intersection, and declared state-cut projection, including delivered decision surfaces.", + "hidden_actions": "Only labels mapped to tau by the named participant-, audience-, policy-decision-, and state-cut-relative projection; backend-internal actions are not intrinsically hidden.", + "stuttering_actions": "Finite hidden stuttering is removed by the declared tau closure; the baseline is termination- and progress-insensitive and does not claim divergence-sensitive preservation." + }, + "observation_projection": { + "applicability": "required", + "subject": "Named participant and audience within one episode scope", + "policy_ref": "SEM-230 participant-information-flow policy", + "policy_revision": "The complete declared policy-decision sequence and exact state-cut bindings", + "redaction_scope": "Projection, masking, redaction, declassification, transformation, marking, loss, and weakening remain distinct and are evaluated deny-first.", + "order_treatment": "Compare occurrence-preserving visible histories under the same declared total, partial, causal, simultaneous, or backend-serialized order model; one convenient linearization is insufficient for a partial-order claim.", + "simultaneity_treatment": "Preserve declared simultaneity groups and visible order relations; timestamp equality does not establish simultaneity." + }, + "projection_required": true, + "direction": "symmetric", + "quantification": { + "states": "For every pair of initial and reachable states related by low equivalence at the applicable participant-policy state cut and memory scope.", + "traces": "For all valid run support sets generated under the same low strategy, exact-cut policy decisions, and permitted declassification schedule.", + "schedulers": "For the fixed declared scheduler class; scheduler-sensitive variants must select and evidence a stronger relation.", + "strategies": "Universally over the declared class of adaptive low participant strategies mapping delivered local histories to choices or choice sets; no coalition-ability equivalence is implied.", + "environments": "For the fixed declared environment class and equal low environment inputs, allowing only the unauthorized high variation under examination.", + "observations": "Equality of support sets of occurrence-preserving histories projected for the named participant, audience, policy sequence, markings, declassification schedule, and order model." + }, + "dimensions": { + "nondeterminism": { + "status": "supported", + "treatment": "The baseline compares complete declared support sets of projected histories; equality of sampled or single histories is only bounded falsification evidence." + }, + "concurrency": { + "status": "parameterized", + "treatment": "The selected sequential, total, partial, causal, simultaneous, or backend-serialized transition and visible-order model is fixed for the comparison." + }, + "probability": { + "status": "outside-scope", + "treatment": "The baseline compares support sets, not measures; probabilistic noninterference requires a separately governed probabilistic relation, kernel, bound, and evidence." + }, + "time": { + "status": "abstracted", + "treatment": "The baseline is termination- and progress-insensitive and excludes wall-clock timing; timed security requires a separately governed relation." + }, + "partial_order": { + "status": "parameterized", + "treatment": "When partial order is selected, the declared visible order relation and simultaneity groups are compared rather than one linear extension." + } + }, + "preservation": { + "property": "Unauthorized high variation does not change the support set of participant-visible histories observed by any declared adaptive low strategy, except at equal explicitly governed declassification events.", + "proof_obligation": "Prove support-set equality for every quantified low-equivalent pair and low strategy under the fixed participant, memory scope, exact-cut policy decisions, declassification schedule, model, scheduler, environment, and order assumptions, or report only the bounded counterexamples actually checked." + }, + "bounded_evidence": [ + "implementations/python/tests/test_sem_230_information_flow_control.py checks finite unauthorized-high, declassification-order, policy-revision, participant-relative hiding, deny-first, append-only-history, transformation-admission, and support-set counterexamples.", + "implementations/python/tests/test_asr_535_participant_flow_assurance.py exhausts a declared finite crossing domain for unauthorized-high purge and exact-cut declassification, and drives the shipped RUN-319 boundary for denial, withholding, redaction, governed declassification, transformation, stale or revoked policy, cross-participant leakage, participant-directed inject delivery, backend weakening, unsupported capability, and adversarial overclaim." + ], + "explicit_non_claims": [ + "The finite SEM-230 executable cases do not establish universal noninterference.", + "Projected-history equality does not establish policy noninterference without the stated low-equivalence, adaptive-strategy, memory, exact-cut policy, purge, declassification, scheduler, environment, and quantifier obligations.", + "No trace equivalence, simulation, refinement, strong or weak bisimulation, epistemic indistinguishability, timing security, probabilistic security, or backend realization is claimed.", + "The ASR-535 finite enumeration, runtime probes, and backend conformance cases are bounded falsification evidence and are not a model check or a proof; issues #810 to #813 own any stronger opacity, bisimulation, adversarial-control, or cross-backend status." + ], + "incompatible_claim_surfaces": [ + "Unrevisioned participant projection", + "Single-history or sampled-history equality", + "Undeclared scheduler, environment, timing, probability, or partial-order assumptions", + "Runtime or backend realization inferred from the definition" + ], + "assurance": { + "definition_status": "defined", + "implementation_status": "implemented", + "test_status": "bounded", + "proof_status": "deliberately-unproved", + "evidence_refs": [ + "specs/formal/participant-semantics/information-flow-control.md", + "implementations/python/tests/test_sem_230_information_flow_control.py", + "implementations/python/packages/raes_runtime/participant_crossing_policy.py", + "implementations/python/packages/raes_conformance/conformance/participant_policy_probes.py", + "implementations/python/tests/test_run_319_participant_flow_policy.py", + "implementations/python/tests/test_asr_535_participant_flow_assurance.py" + ] + }, + "source_refs": [ + "bohannon-pierce-sjoberg-weirich-zdancewic-2009", + "clarkson-schneider-2010", + "fagin-halpern-moses-vardi-1995", + "goguen-meseguer-1982", + "milner-1980", + "sabelfeld-sands-2009", + "van-glabbeek-1990" + ] + }, + "io-alternating-refinement": { + "relation_id": "io-alternating-refinement", + "display_name": "Input/output alternating refinement", + "relation_class": "behavioral", + "definition": "A directional concrete-to-abstract relation preserves abstract outputs and internal behavior while respecting input ownership and declared action-availability obligations against environment choices.", + "left_carrier": "A concrete backend participant I/O transition system.", + "right_carrier": "An abstract RAES participant I/O transition system.", + "initial_states": "Every concrete initial participant decision state, including decision epoch zero, relates to an abstract initial decision state.", + "transition_signature": { + "applicability": "applicable", + "labels": "Participant proposals are inputs; participant views and observations are outputs; backend, scheduler, and environment labels retain their declared owners.", + "transition_relation": "Concrete and abstract I/O-labelled step relations under a declared refinement mapping.", + "observable_actions": "Participant-visible inputs and outputs under the named projection.", + "hidden_actions": "Only governed backend/internal labels mapped to tau by the named projection.", + "stuttering_actions": "Finite hidden concrete paths may match one abstract step only when the selected weak or branching treatment permits them." + }, + "observation_projection": { + "applicability": "required", + "subject": "Named participant and audience", + "policy_ref": "participant-observation-boundary", + "policy_revision": "The exact-cut projection policy used by the claim", + "redaction_scope": "No redaction beyond the named projection.", + "order_treatment": "Decision epochs are preserved under hidden stuttering; state cuts retain their declared order model.", + "simultaneity_treatment": "Simultaneity and partial-order frontiers are preserved only when declared by the claim." + }, + "projection_required": true, + "direction": "left-to-right", + "quantification": { + "states": "Universally over related reachable concrete and abstract states.", + "traces": "All concrete traces induced by quantified inputs, outputs, and environment choices.", + "schedulers": "All schedulers in the declared fairness class.", + "strategies": "All participant and environment strategies in the declared action-ownership classes.", + "environments": "All environment choices admitted by the declared alternating quantifiers.", + "observations": "Under the exact named participant projection and delivery semantics." + }, + "dimensions": { + "nondeterminism": { + "status": "supported", + "treatment": "Input, output, scheduler, backend, and environment choices are separately owned and quantified." + }, + "concurrency": { + "status": "parameterized", + "treatment": "Interleaving, simultaneous, step, or true-concurrency semantics must be declared." + }, + "probability": { + "status": "outside-scope", + "treatment": "Probability requires a separately governed probabilistic alternating relation." + }, + "time": { + "status": "parameterized", + "treatment": "Timed claims require explicit clock, fairness, timeout, and progress semantics." + }, + "partial_order": { + "status": "parameterized", + "treatment": "A partial-order claim relates declared causal frontiers rather than arbitrary linearizations." + } + }, + "preservation": { + "property": "Projected concrete traces remain abstractly admitted and declared participant inputs and outputs retain their availability and ownership obligations.", + "proof_obligation": "Supply the refinement relation, initial-state mapping, input/output ownership, availability and fairness obligations, and alternating step correspondence for every quantified choice." + }, + "bounded_evidence": [ + "Decision-surface lifecycle tests may falsify selected initiality, delivery, availability, freshness, and step-matching cases on finite models." + ], + "explicit_non_claims": [ + "Trace inclusion alone does not establish input availability or alternating refinement.", + "Successful participant loops do not establish the universal relation." + ], + "incompatible_claim_surfaces": [ + "Current bounded backend conformance reports" + ], + "assurance": { + "definition_status": "defined", + "implementation_status": "not-implemented", + "test_status": "bounded", + "proof_status": "deliberately-unproved", + "evidence_refs": [ + "docs/decisions/adrs/adr-095-participant-decision-epoch-state-cut-and-delivery-semantics.md", + "implementations/python/tests/test_sem_220_participant_decision_surface_v2_runtime.py", + "implementations/python/tests/test_behavioral_relations.py" + ] + }, + "source_refs": [ + "alur-henzinger-kupferman-vardi-1998", + "lynch-tuttle-1989", + "lynch-vaandrager-1995" + ] + }, + "epistemic-indistinguishability": { + "relation_id": "epistemic-indistinguishability", + "display_name": "Epistemic indistinguishability", + "relation_class": "epistemic", + "definition": "Two worlds are indistinguishable to an agent when they occupy the same governed information set.", + "left_carrier": "One epistemic world/state.", + "right_carrier": "Another epistemic world/state.", + "initial_states": "Worlds in the same agent-indexed accessibility or information relation.", + "transition_signature": { + "applicability": "applicable", + "labels": "Optional temporal or action labels of the epistemic model.", + "transition_relation": "The declared interpreted-system or Kripke transition relation.", + "observable_actions": "Agent-observable propositions and events.", + "hidden_actions": "Facts excluded by the information projection.", + "stuttering_actions": "Stuttering is model-specific." + }, + "observation_projection": { + "applicability": "required", + "subject": "Named agent", + "policy_ref": "participant-observation-boundary", + "policy_revision": "rev1", + "redaction_scope": "No redaction beyond the named projection.", + "order_treatment": "Sequence order is preserved.", + "simultaneity_treatment": "Simultaneity is preserved only when declared." + }, + "projection_required": true, + "direction": "symmetric", + "quantification": { + "states": "All worlds in the selected information relation.", + "traces": "Histories only when the interpreted-system model includes them.", + "schedulers": "All schedulers represented in the model.", + "strategies": "Strategies are outside the relation itself.", + "environments": "All environments represented by possible worlds.", + "observations": "One agent or explicitly named group." + }, + "dimensions": { + "nondeterminism": { + "status": "parameterized", + "treatment": "Schedulers and branch quantifiers must be stated." + }, + "concurrency": { + "status": "parameterized", + "treatment": "Interleaving, step, or true-concurrency semantics must be stated." + }, + "probability": { + "status": "outside-scope", + "treatment": "Probability is excluded unless a probabilistic relation is named." + }, + "time": { + "status": "parameterized", + "treatment": "Timed claims require an explicit clock and time model." + }, + "partial_order": { + "status": "abstracted", + "treatment": "Default traces linearize order; partial-order claims require a separate declared model." + } + }, + "preservation": { + "property": "Truth of formulas invariant over the selected information set, subject to the logic.", + "proof_obligation": "Define possible worlds, the agent-indexed indistinguishability relation, valuation, and any temporal interaction." + }, + "bounded_evidence": [ + "Equal projected finite histories may be evidence for a bounded information-state comparison." + ], + "explicit_non_claims": [ + "Does not follow from global-state equality and does not establish strategic equivalence." + ], + "incompatible_claim_surfaces": [ + "Current participant conformance" + ], + "assurance": { + "definition_status": "defined", + "implementation_status": "not-implemented", + "test_status": "not-tested", + "proof_status": "future", + "evidence_refs": [] + }, + "source_refs": [ + "fagin-halpern-moses-vardi-1995" + ] + }, + "alternating-strategic-equivalence": { + "relation_id": "alternating-strategic-equivalence", + "display_name": "Alternating or strategic equivalence", + "relation_class": "strategic", + "definition": "Two game structures preserve the abilities of named coalitions under explicit strategy and environment quantifiers.", + "left_carrier": "One concurrent or alternating game structure.", + "right_carrier": "Another concurrent or alternating game structure.", + "initial_states": "Related initial game states.", + "transition_signature": { + "applicability": "applicable", + "labels": "Joint actions, chance outcomes, and state transitions.", + "transition_relation": "Both game transition functions or relations.", + "observable_actions": "Player observations and public actions.", + "hidden_actions": "Hidden information under the named observation partitions.", + "stuttering_actions": "Stuttering, simultaneous moves, and scheduler steps are explicit." + }, + "observation_projection": { + "applicability": "required", + "subject": "Named players or coalition", + "policy_ref": "participant-observation-boundary", + "policy_revision": "rev1", + "redaction_scope": "No redaction beyond the named projection.", + "order_treatment": "Sequence order is preserved.", + "simultaneity_treatment": "Simultaneity is preserved only when declared." + }, + "projection_required": true, + "direction": "symmetric", + "quantification": { + "states": "Universally over related game states.", + "traces": "Outcome paths induced by quantified strategies.", + "schedulers": "Schedulers and chance kernels explicitly quantified.", + "strategies": "Coalitions and strategy classes universally/existentially quantified as declared.", + "environments": "Adversarial environment choices explicitly quantified.", + "observations": "Player-indexed observation partitions." + }, + "dimensions": { + "nondeterminism": { + "status": "parameterized", + "treatment": "Environment and scheduler choices are explicit." + }, + "concurrency": { + "status": "supported", + "treatment": "Joint and simultaneous moves are part of the game structure." + }, + "probability": { + "status": "parameterized", + "treatment": "Chance kernels must be declared when present." + }, + "time": { + "status": "parameterized", + "treatment": "Timed strategies require an explicit clock model." + }, + "partial_order": { + "status": "parameterized", + "treatment": "Concurrent action order is part of the declared game semantics." + } + }, + "preservation": { + "property": "Coalition ability for the stated objective class.", + "proof_obligation": "Define players, legal joint actions, observations, strategy class, coalitions, chance, scheduler/fairness, objectives, and an alternating relation in both directions." + }, + "bounded_evidence": [ + "Finite recorded joint-action traces can only falsify selected cases." + ], + "explicit_non_claims": [ + "Capability declarations and shared probe outcomes do not establish strategic equivalence." + ], + "incompatible_claim_surfaces": [ + "Current multi-agent conformance" + ], + "assurance": { + "definition_status": "defined", + "implementation_status": "not-implemented", + "test_status": "not-tested", + "proof_status": "future", + "evidence_refs": [] + }, + "source_refs": [ + "alur-henzinger-kupferman-vardi-1998", + "alur-henzinger-kupferman-2002" + ] + }, + "probabilistic-bisimulation": { + "relation_id": "probabilistic-bisimulation", + "display_name": "Probabilistic bisimulation", + "relation_class": "behavioral", + "definition": "Related states match labelled probability distributions over equivalence classes under the selected probabilistic process model.", + "left_carrier": "One probabilistic labelled transition system.", + "right_carrier": "Another probabilistic labelled transition system.", + "initial_states": "Initial states belong to the probabilistic bisimulation relation.", + "transition_signature": { + "applicability": "applicable", + "labels": "Shared visible and hidden labels of the probabilistic model.", + "transition_relation": "Labelled transitions to probability distributions.", + "observable_actions": "Labels retained by the projection.", + "hidden_actions": "Declared hidden labels.", + "stuttering_actions": "Weak variants require an explicit probabilistic tau closure." + }, + "observation_projection": { + "applicability": "parameterized", + "subject": "Probabilistic process observer", + "policy_ref": "behavioral-relations/catalog", + "policy_revision": "rev1", + "redaction_scope": "No redaction beyond the named projection.", + "order_treatment": "Sequence order is preserved.", + "simultaneity_treatment": "Simultaneity is preserved only when declared." + }, + "projection_required": true, + "direction": "symmetric", + "quantification": { + "states": "Universally over related states.", + "traces": "All probabilistic traces or branching distributions required by the variant.", + "schedulers": "All nondeterministic schedulers explicitly quantified.", + "strategies": "Outside scope unless combined with games.", + "environments": "All admitted probabilistic environments.", + "observations": "Through the named projection." + }, + "dimensions": { + "nondeterminism": { + "status": "parameterized", + "treatment": "Scheduler quantification is mandatory." + }, + "concurrency": { + "status": "parameterized", + "treatment": "The process-composition semantics must be named." + }, + "probability": { + "status": "supported", + "treatment": "Probability distributions are matched over relation classes." + }, + "time": { + "status": "outside-scope", + "treatment": "Continuous or timed probability needs another variant." + }, + "partial_order": { + "status": "outside-scope", + "treatment": "The base relation uses labelled branching structure." + } + }, + "preservation": { + "property": "Probability mass over related behavior classes.", + "proof_obligation": "Exhibit a relation whose matched transitions assign equal probability to every relation-closed class under the chosen variant." + }, + "bounded_evidence": [ + "Statistical samples may refute parameters but do not prove distributional branching equivalence." + ], + "explicit_non_claims": [ + "Statistical similarity or equal sample means is not probabilistic bisimulation." + ], + "incompatible_claim_surfaces": [ + "Ordinary empirical study" + ], + "assurance": { + "definition_status": "defined", + "implementation_status": "not-implemented", + "test_status": "not-tested", + "proof_status": "future", + "evidence_refs": [] + }, + "source_refs": [ + "larsen-skou-1991" + ] + }, + "statistical-similarity": { + "relation_id": "statistical-similarity", + "display_name": "Statistical similarity", + "relation_class": "empirical", + "definition": "A predeclared metric over sampled populations lies within a stated similarity criterion with uncertainty.", + "left_carrier": "One sampled population or system output distribution.", + "right_carrier": "Another sampled population, target distribution, or reference data.", + "initial_states": "The preregistered sampling frame and apparatus context.", + "transition_signature": { + "applicability": "not-applicable", + "labels": "not applicable", + "transition_relation": "not applicable", + "observable_actions": "not applicable", + "hidden_actions": "not applicable", + "stuttering_actions": "not applicable", + "not_applicable_rationale": "Statistical similarity compares sampled measures, not transition systems unless a separate model binds them." + }, + "observation_projection": { + "applicability": "parameterized", + "subject": "Study analyst", + "policy_ref": "experiment-study-v1", + "policy_revision": "rev1", + "redaction_scope": "No redaction beyond the named projection.", + "order_treatment": "Sequence order is preserved.", + "simultaneity_treatment": "Simultaneity is preserved only when declared." + }, + "projection_required": true, + "direction": "symmetric", + "quantification": { + "states": "Sampled observations only.", + "traces": "Sampled run outcomes only.", + "schedulers": "Schedulers represented by the sampling design.", + "strategies": "Strategies represented by the sampling design.", + "environments": "The preregistered population and apparatus.", + "observations": "The named metric/estimand projection." + }, + "dimensions": { + "nondeterminism": { + "status": "abstracted", + "treatment": "Variation is represented through the sampling model." + }, + "concurrency": { + "status": "abstracted", + "treatment": "Concurrency matters only through measured outcomes." + }, + "probability": { + "status": "supported", + "treatment": "The sampling distribution and uncertainty method are explicit." + }, + "time": { + "status": "parameterized", + "treatment": "Sampling windows and time domains are declared." + }, + "partial_order": { + "status": "outside-scope", + "treatment": "Event partial order is not inferred from aggregate metrics." + } + }, + "preservation": { + "property": "The stated similarity criterion for the named estimand and population.", + "proof_obligation": "Predeclare population, sampling frame, metric, criterion, uncertainty method, and decision rule; then execute the study." + }, + "bounded_evidence": [ + "Experiment runs, derived measures, and uncertainty intervals." + ], + "explicit_non_claims": [ + "Does not establish behavioral, epistemic, strategic, or probabilistic bisimulation." + ], + "incompatible_claim_surfaces": [ + "Universal backend behavior" + ], + "assurance": { + "definition_status": "defined", + "implementation_status": "partial", + "test_status": "bounded", + "proof_status": "deliberately-unproved", + "evidence_refs": [ + "specs/formal/experiment-core/README.md" + ] + }, + "source_refs": [ + "wellek-2010" + ] + }, + "statistical-equivalence": { + "relation_id": "statistical-equivalence", + "display_name": "Statistical equivalence", + "relation_class": "empirical", + "definition": "A preregistered equivalence test supports that a named estimand lies within a stated equivalence margin for the sampled population.", + "left_carrier": "One sampled population or treatment.", + "right_carrier": "Another sampled population, treatment, or reference.", + "initial_states": "The preregistered sampling frame, allocation, and apparatus context.", + "transition_signature": { + "applicability": "not-applicable", + "labels": "not applicable", + "transition_relation": "not applicable", + "observable_actions": "not applicable", + "hidden_actions": "not applicable", + "stuttering_actions": "not applicable", + "not_applicable_rationale": "A statistical equivalence test does not compare enabled transitions." + }, + "observation_projection": { + "applicability": "parameterized", + "subject": "Study analyst", + "policy_ref": "experiment-study-v1", + "policy_revision": "rev1", + "redaction_scope": "No redaction beyond the named projection.", + "order_treatment": "Sequence order is preserved.", + "simultaneity_treatment": "Simultaneity is preserved only when declared." + }, + "projection_required": true, + "direction": "symmetric", + "quantification": { + "states": "Sampled units only.", + "traces": "Sampled run outcomes only.", + "schedulers": "Schedulers represented by allocation/sampling.", + "strategies": "Strategies represented by sampled conditions.", + "environments": "The stated target population.", + "observations": "The named estimand and measurement projection." + }, + "dimensions": { + "nondeterminism": { + "status": "abstracted", + "treatment": "Variation is handled by the statistical model." + }, + "concurrency": { + "status": "abstracted", + "treatment": "Concurrency is only a measured covariate unless modeled." + }, + "probability": { + "status": "supported", + "treatment": "Equivalence margins, error rates, and uncertainty are explicit." + }, + "time": { + "status": "parameterized", + "treatment": "Study windows and time domains are declared." + }, + "partial_order": { + "status": "outside-scope", + "treatment": "Aggregate equivalence does not preserve event order." + } + }, + "preservation": { + "property": "Equivalence of the named estimand within the preregistered margin.", + "proof_obligation": "Specify the equivalence hypotheses, margin, error control, sampling design, and analysis before observing results." + }, + "bounded_evidence": [ + "Experiment-study analysis and derived measures." + ], + "explicit_non_claims": [ + "Statistical equivalence is not behavioral equivalence or proof of implementation conformance." + ], + "incompatible_claim_surfaces": [ + "Bisimulation claim" + ], + "assurance": { + "definition_status": "defined", + "implementation_status": "partial", + "test_status": "bounded", + "proof_status": "deliberately-unproved", + "evidence_refs": [ + "specs/formal/experiment-core/README.md" + ] + }, + "source_refs": [ + "wellek-2010" + ] + }, + "empirical-adequacy": { + "relation_id": "empirical-adequacy", + "display_name": "Empirical adequacy", + "relation_class": "empirical", + "definition": "Observed evidence supports a purpose-relative, bounded adequacy claim for a named phenomenon and intended use.", + "left_carrier": "A model, language, implementation, or method under study.", + "right_carrier": "A defined empirical target, task, or phenomenon.", + "initial_states": "The preregistered study population, tasks, and apparatus.", + "transition_signature": { + "applicability": "not-applicable", + "labels": "not applicable", + "transition_relation": "not applicable", + "observable_actions": "not applicable", + "hidden_actions": "not applicable", + "stuttering_actions": "not applicable", + "not_applicable_rationale": "Empirical adequacy may study behavior but is not itself a transition-system equivalence." + }, + "observation_projection": { + "applicability": "parameterized", + "subject": "Study audience", + "policy_ref": "experiment-study-v1", + "policy_revision": "rev1", + "redaction_scope": "No redaction beyond the named projection.", + "order_treatment": "Sequence order is preserved.", + "simultaneity_treatment": "Simultaneity is preserved only when declared." + }, + "projection_required": true, + "direction": "left-to-right", + "quantification": { + "states": "Observed study units.", + "traces": "Observed runs and tasks.", + "schedulers": "Schedulers represented by the protocol.", + "strategies": "Strategies represented by participant/task sampling.", + "environments": "The named target population and intended use.", + "observations": "The preregistered measures and coding projection." + }, + "dimensions": { + "nondeterminism": { + "status": "abstracted", + "treatment": "Uncontrolled variation is handled as a validity limitation." + }, + "concurrency": { + "status": "abstracted", + "treatment": "Concurrency is measured only when the protocol names it." + }, + "probability": { + "status": "parameterized", + "treatment": "Sampling and uncertainty must be reported." + }, + "time": { + "status": "parameterized", + "treatment": "Study period and temporal validity are explicit." + }, + "partial_order": { + "status": "outside-scope", + "treatment": "Adequacy does not imply partial-order preservation." + } + }, + "preservation": { + "property": "Fitness for the explicitly stated empirical purpose within the study boundary.", + "proof_obligation": "Predeclare tasks, population, measures, success/falsification criteria, analysis, limitations, and evidence lineage." + }, + "bounded_evidence": [ + "Independent parser, authoring, review, and diagnostic-recovery studies." + ], + "explicit_non_claims": [ + "Repeated bounded observations do not establish universal semantics, conformance, or behavioral equivalence." + ], + "incompatible_claim_surfaces": [ + "Universal language equivalence" + ], + "assurance": { + "definition_status": "defined", + "implementation_status": "not-implemented", + "test_status": "not-tested", + "proof_status": "future", + "evidence_refs": [] + }, + "source_refs": [ + "bueno-1997", + "wellek-2010" + ] + } + }, + "claim_surfaces": [ + { + "surface_id": "sdl-transformation", + "intended_relation_ids": [ + "structural-validity", + "semantic-validity", + "canonical-artifact-identity" + ], + "evidence_boundary": "Deterministic phase functions and finite invariant, round-trip, canonicalization, and property tests.", + "prohibited_relation_ids": [ + "data-refinement", + "forward-simulation", + "trace-equivalence", + "strong-bisimulation" + ], + "explicit_non_claims": [ + "No universal behavioral refinement or equivalence is currently proved." + ] + }, + { + "surface_id": "backend-realization", + "intended_relation_ids": [ + "realization-envelope-membership", + "bounded-probe-success", + "trace-inclusion", + "io-alternating-refinement" + ], + "evidence_boundary": "Envelope checks and named target probes are bounded evidence; projected trace inclusion plus input/output ownership and availability under I/O alternating refinement are the intended universal actionable-participant obligations and remain deliberately unproved.", + "prohibited_relation_ids": [ + "trace-equivalence", + "backward-simulation", + "strong-bisimulation" + ], + "explicit_non_claims": [ + "Provisioning, snapshots, witnesses, and negative probes do not prove behavioral equivalence." + ] + }, + { + "surface_id": "backend-comparison", + "intended_relation_ids": [ + "bounded-probe-success", + "statistical-similarity", + "canonical-artifact-identity" + ], + "evidence_boundary": "Only named invariants, probes, digests, populations, metrics, and uncertainty procedures are compared.", + "prohibited_relation_ids": [ + "trace-equivalence", + "strong-bisimulation", + "alternating-strategic-equivalence" + ], + "explicit_non_claims": [ + "A shared result, digest, or finite trace is not universal same behavior." + ] + }, + { + "surface_id": "participant-visible-behavior", + "intended_relation_ids": [ + "participant-projected-history-equivalence" + ], + "evidence_boundary": "Comparison is parameterized by participant, observation-boundary policy revision, redaction, order, simultaneity, and run context.", + "prohibited_relation_ids": [ + "epistemic-indistinguishability", + "alternating-strategic-equivalence" + ], + "explicit_non_claims": [ + "Equal projected histories do not expose hidden global state or prove future knowledge or strategy equivalence." + ] + }, + { + "surface_id": "participant-information-flow-policy", + "intended_relation_ids": [ + "policy-noninterference" + ], + "evidence_boundary": "The SEM-230 relation is defined over named participant, audience, memory scope, exact-cut policy-decision sequence, low-equivalence, adaptive low-strategy class, dynamic purge, permitted declassification schedule, scheduler/environment classes, order model, and support-set semantics. Current executable evidence is limited to finite models, finite reference-runtime enforcement probes, and finite backend-conformance cases.", + "prohibited_relation_ids": [ + "participant-projected-history-equivalence", + "trace-equivalence", + "forward-simulation", + "backward-simulation", + "data-refinement", + "strong-bisimulation", + "weak-bisimulation", + "epistemic-indistinguishability", + "probabilistic-bisimulation" + ], + "explicit_non_claims": [ + "Definition, catalog validation, claim-policy checks, and finite counterexamples do not prove universal noninterference or runtime/backend realization.", + "Reference-runtime enforcement and passing backend-conformance probes establish neither universal noninterference nor native-backend realization." + ] + }, + { + "surface_id": "participant-opacity", + "intended_relation_ids": [ + "participant-predicate-opacity" + ], + "evidence_boundary": "Every claim binds a revisioned observer, secret predicate, possible-point carrier, initial-information and observation functions, memory and horizon, supervisor visibility, passive or active strategy domain, release schedule, scheduler and environment classes, time and order, nondeterminism and probability support, assurance axis, and evidence boundary.", + "prohibited_relation_ids": [ + "participant-projected-history-equivalence", + "policy-noninterference", + "trace-inclusion", + "trace-equivalence", + "forward-simulation", + "backward-simulation", + "data-refinement", + "strong-bisimulation", + "weak-bisimulation", + "epistemic-indistinguishability", + "probabilistic-bisimulation" + ], + "explicit_non_claims": [ + "A profile, finite witness, bounded probe, random choice, model check, runtime decision, or backend declaration establishes only its named assurance axis and evidence scope.", + "No current RAES runtime or backend is claimed opaque." + ] + }, + { + "surface_id": "participant-crossing-bisimulation", + "intended_relation_ids": [ + "divergence-preserving-branching-bisimulation" + ], + "evidence_boundary": "Claims bind the exact independently derived abstract and concrete model revisions and digests, initial states, complete quantified carrier and counts, closed participant/audience projection and tau partition, relation profile, source and mapping revisions, assurance axis, pinned tool provenance, result or safe counterexample, mutations, limitations, and independent reproduction.", + "prohibited_relation_ids": [ + "strong-bisimulation", + "weak-bisimulation", + "trace-equivalence", + "policy-noninterference", + "participant-predicate-opacity", + "probabilistic-bisimulation" + ], + "explicit_non_claims": [ + "Issue #811 defines the theorem and proof program but does not establish the formal equivalence result.", + "A formal model-check does not establish live-runtime realization, backend conformance, whole-runtime equivalence, noninterference, opacity, or a stronger timed, probabilistic, strategic, concurrent, or partial-order relation." + ] + }, + { + "surface_id": "multi-agent-interaction", + "intended_relation_ids": [ + "bounded-probe-success", + "alternating-strategic-equivalence", + "probabilistic-bisimulation" + ], + "evidence_boundary": "Current evidence is structural and finite; strategic and probabilistic relations are definitions for future governed models.", + "prohibited_relation_ids": [ + "trace-equivalence", + "strong-bisimulation" + ], + "explicit_non_claims": [ + "Current joint-action, chance, simultaneous-move, and mean-field records do not prove strategic equivalence." + ] + }, + { + "surface_id": "counterfactual-necessity-validation", + "intended_relation_ids": [ + "bounded-but-for-necessity", + "bounded-probe-success" + ], + "evidence_boundary": "One revisioned claim, one immutable baseline/intervention-world pair, one typed and verified intervention, admitted proposition-truth evidence, a declared matching policy, and independently verified reset and cleanup.", + "prohibited_relation_ids": [ + "trace-equivalence", + "strong-bisimulation", + "empirical-adequacy", + "statistical-equivalence" + ], + "explicit_non_claims": [ + "A supported finite but-for comparison is not universal causal proof, actual-cause attribution, sufficiency, determinism, or statistical necessity." + ] + }, + { + "surface_id": "independent-adequacy-study", + "intended_relation_ids": [ + "empirical-adequacy", + "statistical-similarity", + "statistical-equivalence" + ], + "evidence_boundary": "Claims bind to a preregistered population, task set, metric or coding scheme, uncertainty, falsification criteria, and limitations.", + "prohibited_relation_ids": [ + "trace-equivalence", + "strong-bisimulation", + "alternating-strategic-equivalence" + ], + "explicit_non_claims": [ + "Bounded observations and statistical findings cannot be promoted to universal behavioral proof." + ] + } + ], + "worked_examples": { + "finite-probe-counterexample": { + "example_id": "finite-probe-counterexample", + "purpose": "Two implementations pass the same finite visible probe a, but the left system has an additional enabled b transition that the right system cannot match.", + "left_system": { + "states": [ + "l0", + "l1", + "l2" + ], + "initial_state": "l0", + "transitions": [ + { + "source": "l0", + "action": "a", + "target": "l1" + }, + { + "source": "l0", + "action": "b", + "target": "l2" + } + ] + }, + "right_system": { + "states": [ + "r0", + "r1" + ], + "initial_state": "r0", + "transitions": [ + { + "source": "r0", + "action": "a", + "target": "r1" + } + ] + }, + "tested_visible_trace": [ + "a" + ], + "hidden_action": "tau", + "expected_strong_bisimulation": false, + "expected_weak_matching": false, + "evidence_boundary": "The shared a probe is evidence only for that finite trace; the unmatched b branch refutes strong bisimulation.", + "explicit_non_claims": [ + "This toy counterexample is not evidence about any RAES backend." + ] + }, + "hidden-action-counterexample": { + "example_id": "hidden-action-counterexample", + "purpose": "The abstract system performs visible send directly; the backend performs governed hidden tau and then send.", + "left_system": { + "states": [ + "a0", + "a1" + ], + "initial_state": "a0", + "transitions": [ + { + "source": "a0", + "action": "send", + "target": "a1" + } + ] + }, + "right_system": { + "states": [ + "b0", + "b1", + "b2" + ], + "initial_state": "b0", + "transitions": [ + { + "source": "b0", + "action": "tau", + "target": "b1" + }, + { + "source": "b1", + "action": "send", + "target": "b2" + } + ] + }, + "tested_visible_trace": [ + "send" + ], + "hidden_action": "tau", + "expected_strong_bisimulation": false, + "expected_weak_matching": true, + "evidence_boundary": "Strong matching fails on tau; weak visible-trace matching succeeds only under the declared tau-hiding projection and finite termination assumptions.", + "explicit_non_claims": [ + "The example does not declare arbitrary backend-internal work hidden and does not prove an RAES backend relation." + ] + } + } +} diff --git a/contracts/concept-authority/w3c-activitystreams-activity-types-source-v1.json b/contracts/concept-authority/w3c-activitystreams-activity-types-source-v1.json new file mode 100644 index 000000000..a11af9a35 --- /dev/null +++ b/contracts/concept-authority/w3c-activitystreams-activity-types-source-v1.json @@ -0,0 +1,159 @@ +{ + "schema_version": "w3c-activitystreams-activity-types-source/v1", + "source_authority": "World Wide Web Consortium", + "source_version": "REC-activitystreams-vocabulary-20170523", + "source_status": "W3C Recommendation", + "source_url": "https://www.w3.org/TR/2017/REC-activitystreams-vocabulary-20170523/", + "source_digest": "sha256:1418443392160f4bb23dffb5727f5216d1f56d3430377dc67d364016521401db", + "citation_urls": [ + "https://www.w3.org/TR/2017/REC-activitystreams-vocabulary-20170523/", + "https://www.w3.org/TR/activitystreams-vocabulary/", + "https://www.w3.org/TR/2017/REC-activitystreams-core-20170523/", + "https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document" + ], + "retrieved_at": "2026-07-30", + "license_url": "https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document", + "license_notice": "Copyright © 2017 Activity Streams Working Group, IBM & SAP SE; W3C permissive document license applies.", + "activity_types": [ + { + "position": 1, + "type_name": "Accept", + "concept_id": "https://www.w3.org/ns/activitystreams#Accept" + }, + { + "position": 2, + "type_name": "Add", + "concept_id": "https://www.w3.org/ns/activitystreams#Add" + }, + { + "position": 3, + "type_name": "Announce", + "concept_id": "https://www.w3.org/ns/activitystreams#Announce" + }, + { + "position": 4, + "type_name": "Arrive", + "concept_id": "https://www.w3.org/ns/activitystreams#Arrive" + }, + { + "position": 5, + "type_name": "Block", + "concept_id": "https://www.w3.org/ns/activitystreams#Block" + }, + { + "position": 6, + "type_name": "Create", + "concept_id": "https://www.w3.org/ns/activitystreams#Create" + }, + { + "position": 7, + "type_name": "Delete", + "concept_id": "https://www.w3.org/ns/activitystreams#Delete" + }, + { + "position": 8, + "type_name": "Dislike", + "concept_id": "https://www.w3.org/ns/activitystreams#Dislike" + }, + { + "position": 9, + "type_name": "Flag", + "concept_id": "https://www.w3.org/ns/activitystreams#Flag" + }, + { + "position": 10, + "type_name": "Follow", + "concept_id": "https://www.w3.org/ns/activitystreams#Follow" + }, + { + "position": 11, + "type_name": "Ignore", + "concept_id": "https://www.w3.org/ns/activitystreams#Ignore" + }, + { + "position": 12, + "type_name": "Invite", + "concept_id": "https://www.w3.org/ns/activitystreams#Invite" + }, + { + "position": 13, + "type_name": "Join", + "concept_id": "https://www.w3.org/ns/activitystreams#Join" + }, + { + "position": 14, + "type_name": "Leave", + "concept_id": "https://www.w3.org/ns/activitystreams#Leave" + }, + { + "position": 15, + "type_name": "Like", + "concept_id": "https://www.w3.org/ns/activitystreams#Like" + }, + { + "position": 16, + "type_name": "Listen", + "concept_id": "https://www.w3.org/ns/activitystreams#Listen" + }, + { + "position": 17, + "type_name": "Move", + "concept_id": "https://www.w3.org/ns/activitystreams#Move" + }, + { + "position": 18, + "type_name": "Offer", + "concept_id": "https://www.w3.org/ns/activitystreams#Offer" + }, + { + "position": 19, + "type_name": "Question", + "concept_id": "https://www.w3.org/ns/activitystreams#Question" + }, + { + "position": 20, + "type_name": "Reject", + "concept_id": "https://www.w3.org/ns/activitystreams#Reject" + }, + { + "position": 21, + "type_name": "Read", + "concept_id": "https://www.w3.org/ns/activitystreams#Read" + }, + { + "position": 22, + "type_name": "Remove", + "concept_id": "https://www.w3.org/ns/activitystreams#Remove" + }, + { + "position": 23, + "type_name": "TentativeReject", + "concept_id": "https://www.w3.org/ns/activitystreams#TentativeReject" + }, + { + "position": 24, + "type_name": "TentativeAccept", + "concept_id": "https://www.w3.org/ns/activitystreams#TentativeAccept" + }, + { + "position": 25, + "type_name": "Travel", + "concept_id": "https://www.w3.org/ns/activitystreams#Travel" + }, + { + "position": 26, + "type_name": "Undo", + "concept_id": "https://www.w3.org/ns/activitystreams#Undo" + }, + { + "position": 27, + "type_name": "Update", + "concept_id": "https://www.w3.org/ns/activitystreams#Update" + }, + { + "position": 28, + "type_name": "View", + "concept_id": "https://www.w3.org/ns/activitystreams#View" + } + ] +} diff --git a/contracts/fixtures/backend-manifest/backend-manifest-v2/valid/stub.json b/contracts/fixtures/backend-manifest/backend-manifest-v2/valid/stub.json index 0e7b16c58..d0f9f33f4 100644 --- a/contracts/fixtures/backend-manifest/backend-manifest-v2/valid/stub.json +++ b/contracts/fixtures/backend-manifest/backend-manifest-v2/valid/stub.json @@ -279,6 +279,11 @@ "other", "windows" ], + "supported_generated_artifact_kinds": [ + "certificate_bundle", + "rendered_config", + "ssh_key_bundle" + ], "supports_accounts": true, "supports_acls": true, "supports_generated_artifacts": true, diff --git a/contracts/fixtures/concept-authority/concept-families-v1/invalid/native-with-authority.json b/contracts/fixtures/concept-authority/concept-families-v1/invalid/native-with-authority.json index ffb1a74f7..7fcd0ee58 100644 --- a/contracts/fixtures/concept-authority/concept-families-v1/invalid/native-with-authority.json +++ b/contracts/fixtures/concept-authority/concept-families-v1/invalid/native-with-authority.json @@ -6,7 +6,7 @@ "description": "SDL scenarios, compositions, modules, and authoring constructs.", "provenance": "native", "authority": "RAES", - "authority_reference": "https://raesystem.github.io/rae/concepts", + "authority_reference": "https://openrae.github.io/rae/concepts", "extension_scope": "SDL-native scenario authoring constructs.", "relation_rules": [ "Must remain the scenario authoring layer." diff --git a/contracts/fixtures/concept-authority/controlled-vocabularies-v1/valid/reference.json b/contracts/fixtures/concept-authority/controlled-vocabularies-v1/valid/reference.json index 4c857d6ca..63064684b 100644 --- a/contracts/fixtures/concept-authority/controlled-vocabularies-v1/valid/reference.json +++ b/contracts/fixtures/concept-authority/controlled-vocabularies-v1/valid/reference.json @@ -774,6 +774,10 @@ "service-content-v1": { "title": "Service Content v1", "description": "Exact reconciliation of authored content into a named service with controlled reset and participant-equivalent readback." + }, + "service-search-index-schema-v1": { + "title": "Service Search Index Schema v1", + "description": "Exact reconciliation of a provider-neutral declared-field search-index schema with fresh native readback." } } }, diff --git a/contracts/fixtures/concept-authority/external-concept-bindings-v1/context/autonomous-behavior-subject.sdl.yaml b/contracts/fixtures/concept-authority/external-concept-bindings-v1/context/autonomous-behavior-subject.sdl.yaml new file mode 100644 index 000000000..bd9a07a86 --- /dev/null +++ b/contracts/fixtures/concept-authority/external-concept-bindings-v1/context/autonomous-behavior-subject.sdl.yaml @@ -0,0 +1,20 @@ +name: autonomous-behavior-binding-subject +entities: + automation-team: + role: blue +agents: + autonomous-service: + entity: automation-team +behavior_specifications: + service-publication: + semantic_version: 1.0.0 + lifecycle_state: active + participant_refs: [autonomous-service] + behavior_mode: autonomous + extension_policy: closed + agent-request: + semantic_version: 1.0.0 + lifecycle_state: active + participant_refs: [autonomous-service] + behavior_mode: autonomous + extension_policy: closed diff --git a/contracts/fixtures/concept-authority/external-concept-bindings-v1/valid/activitystreams-behavior.json b/contracts/fixtures/concept-authority/external-concept-bindings-v1/valid/activitystreams-behavior.json new file mode 100644 index 000000000..0d567b886 --- /dev/null +++ b/contracts/fixtures/concept-authority/external-concept-bindings-v1/valid/activitystreams-behavior.json @@ -0,0 +1,111 @@ +{ + "schema_version": "external-concept-bindings/v1", + "binding_set_id": "autonomous-behavior-scheme-examples", + "binding_set_version": "1.0.0", + "bindings": { + "activitystreams-service-publication": { + "binding_id": "activitystreams-service-publication", + "subject": { + "subject_kind": "behavior_specifications", + "owning_contract_id": "sdl-authoring-input-v1", + "lifecycle_phase": "normalized-authoring", + "canonical_ref": "behavior_specifications.service-publication", + "artifact_digest": "sha256:54e45865d8838d3e6c5969d7650c4942a43adcc0a9dc520633027c532f7d1d89" + }, + "scheme": { + "scheme_id": "w3c-activitystreams-activity-types", + "authority": "World Wide Web Consortium", + "revision": "REC-activitystreams-vocabulary-20170523", + "source_locator": "https://www.w3.org/TR/2017/REC-activitystreams-vocabulary-20170523/", + "source_digest": "sha256:1418443392160f4bb23dffb5727f5216d1f56d3430377dc67d364016521401db", + "concept_id": "https://www.w3.org/ns/activitystreams#Create" + }, + "assertion": { + "relationship_kind": "related-to", + "motivation": "Annotate a complete autonomous service behavior specification with a reviewed publication-oriented activity type.", + "motivation_basis_refs": [ + { + "ref_kind": "other", + "ref_id": "act-611-source-review", + "ref_version": "v1" + } + ], + "semantic_effect": "annotates", + "semantic_effect_basis_refs": [ + { + "ref_kind": "profile", + "ref_id": "sem-217", + "ref_version": "v1" + } + ] + }, + "perspective": { + "asserting_party_kind": "reviewer", + "asserting_party_ref": "reviewers.act-611", + "perspective": "autonomous-service-review", + "authority_basis_refs": [ + { + "ref_kind": "other", + "ref_id": "act-611-review-charter", + "ref_version": "v1" + } + ], + "participant_availability": { + "kind": "eligibility-only", + "participant_refs": [ + "agents.autonomous-service" + ], + "basis_refs": [ + { + "ref_kind": "other", + "ref_id": "scenario-participant-eligibility", + "ref_version": "v1" + } + ] + } + }, + "provenance": { + "asserted_at": "2026-07-30T21:30:00Z", + "source_refs": [ + { + "ref_kind": "other", + "ref_id": "w3c-activitystreams-vocabulary", + "ref_version": "REC-activitystreams-vocabulary-20170523", + "ref_digest": "sha256:1418443392160f4bb23dffb5727f5216d1f56d3430377dc67d364016521401db" + } + ] + }, + "supporting_evidence_refs": [ + { + "ref_kind": "evidence-record", + "ref_id": "act-611-activitystreams-review", + "ref_version": "v1" + } + ], + "confidence": { + "posture": "medium", + "basis": "The activity type is review-relevant, but the external vocabulary is broader than RAES behavior semantics." + }, + "approximation": { + "posture": "approximate", + "loss_details": [ + "ActivityStreams Create does not specify RAES action, authority, realization, observation, outcome, or evidence semantics." + ] + }, + "limitations": [ + "The assertion does not prove that an ActivityStreams actor exists or that a Create activity occurred.", + "Participant eligibility does not authorize disclosure or prove delivery." + ], + "review": { + "status": "accepted", + "review_refs": [ + { + "ref_kind": "other", + "ref_id": "act-611-activitystreams-review", + "ref_version": "v1" + } + ] + } + } + } +} diff --git a/contracts/fixtures/concept-authority/external-concept-bindings-v1/valid/fipa-behavior.json b/contracts/fixtures/concept-authority/external-concept-bindings-v1/valid/fipa-behavior.json new file mode 100644 index 000000000..21dfc3aaf --- /dev/null +++ b/contracts/fixtures/concept-authority/external-concept-bindings-v1/valid/fipa-behavior.json @@ -0,0 +1,111 @@ +{ + "schema_version": "external-concept-bindings/v1", + "binding_set_id": "autonomous-behavior-scheme-examples", + "binding_set_version": "1.0.0", + "bindings": { + "fipa-agent-request": { + "binding_id": "fipa-agent-request", + "subject": { + "subject_kind": "behavior_specifications", + "owning_contract_id": "sdl-authoring-input-v1", + "lifecycle_phase": "normalized-authoring", + "canonical_ref": "behavior_specifications.agent-request", + "artifact_digest": "sha256:54e45865d8838d3e6c5969d7650c4942a43adcc0a9dc520633027c532f7d1d89" + }, + "scheme": { + "scheme_id": "fipa-communicative-act-library", + "authority": "Foundation for Intelligent Physical Agents", + "revision": "SC00037J-2002-12-03", + "source_locator": "https://www.fipa.org/specs/fipa00037/SC00037J.html", + "source_digest": "sha256:90b3277247ef7e7f614ba4c0d58fb2b86aa53ff69036d27a731c09a26c605227", + "concept_id": "request" + }, + "assertion": { + "relationship_kind": "related-to", + "motivation": "Annotate a complete autonomous agent behavior specification with a reviewed communication-oriented act identifier.", + "motivation_basis_refs": [ + { + "ref_kind": "other", + "ref_id": "act-611-source-review", + "ref_version": "v1" + } + ], + "semantic_effect": "annotates", + "semantic_effect_basis_refs": [ + { + "ref_kind": "profile", + "ref_id": "sem-217", + "ref_version": "v1" + } + ] + }, + "perspective": { + "asserting_party_kind": "reviewer", + "asserting_party_ref": "reviewers.act-611", + "perspective": "agent-communication-review", + "authority_basis_refs": [ + { + "ref_kind": "other", + "ref_id": "act-611-review-charter", + "ref_version": "v1" + } + ], + "participant_availability": { + "kind": "eligibility-only", + "participant_refs": [ + "agents.autonomous-service" + ], + "basis_refs": [ + { + "ref_kind": "other", + "ref_id": "scenario-participant-eligibility", + "ref_version": "v1" + } + ] + } + }, + "provenance": { + "asserted_at": "2026-07-30T21:30:00Z", + "source_refs": [ + { + "ref_kind": "other", + "ref_id": "fipa-communicative-act-library", + "ref_version": "SC00037J-2002-12-03", + "ref_digest": "sha256:90b3277247ef7e7f614ba4c0d58fb2b86aa53ff69036d27a731c09a26c605227" + } + ] + }, + "supporting_evidence_refs": [ + { + "ref_kind": "evidence-record", + "ref_id": "act-611-fipa-review", + "ref_version": "v1" + } + ], + "confidence": { + "posture": "medium", + "basis": "The communicative act is review-relevant, but the assertion does not import FIPA ACL semantics." + }, + "approximation": { + "posture": "lossy", + "loss_details": [ + "The identifier alone does not import FIPA feasibility preconditions, rational effects, message transport, content language, or interaction protocols." + ] + }, + "limitations": [ + "The assertion does not claim FIPA ACL conformance or prove that a request message was sent.", + "Participant eligibility does not authorize disclosure or prove delivery." + ], + "review": { + "status": "accepted", + "review_refs": [ + { + "ref_kind": "other", + "ref_id": "act-611-fipa-review", + "ref_version": "v1" + } + ] + } + } + } +} diff --git a/contracts/fixtures/profiles/behavioral-relation-profile-v1/valid/participant-opacity-theorem.json b/contracts/fixtures/profiles/behavioral-relation-profile-v1/valid/participant-opacity-theorem.json new file mode 100644 index 000000000..29dcc581d --- /dev/null +++ b/contracts/fixtures/profiles/behavioral-relation-profile-v1/valid/participant-opacity-theorem.json @@ -0,0 +1,122 @@ +{ + "schema_version": "behavioral-relation-profile/v1", + "profile_id": "participant-opacity-theorem-v1", + "profile_revision": "sem-231-proof/rev1", + "taxonomy_id": "raes-behavioral-relations", + "taxonomy_revision": "rev9", + "relation_id": "participant-predicate-opacity", + "left_carrier_ref": "possible-point-carrier:sem-231-abstract-v1", + "observation_projection_ref": "participant-opacity-observation:sem-230-complete-support-v1", + "observation_projection_revision": "rev1", + "finite_analysis_scope": "abstract-parameterized-theorem-carrier", + "parameters": { + "kind": "participant-predicate-opacity/v1", + "observer": { + "kind": "individual", + "participant_ref": "participant:abstract-observer", + "audience_ref": "audience:abstract-observer" + }, + "secret": { + "predicate_ref": "secret-predicate:sem-231-eligible", + "predicate_revision": "rev1", + "truth_polarity": "one-sided-true" + }, + "carrier": { + "kind": "abstract-possible-points", + "reachability_ref": "reachability:sem-231-admitted-carrier", + "reachability_revision": "rev1", + "eligibility_ref": "sem-231-eligible-predicate", + "eligibility_revision": "rev1", + "correspondence_ref": "sem-230-sem-231-profile-correspondence", + "correspondence_revision": "rev1" + }, + "initial_information": { + "projection_ref": "participant-opacity-initial-information:sem-230-public-v1", + "projection_revision": "rev1" + }, + "observation": { + "projection_ref": "participant-opacity-observation:sem-230-complete-support-v1", + "projection_revision": "rev1", + "observable_channels": [ + "action-availability", + "decision", + "delivery", + "latency", + "order", + "participant-state", + "payload", + "policy-release", + "retry" + ], + "supervisor_decisions": "online-learned" + }, + "horizon": { + "scope": "language", + "cut_ref": "state-cut:sem-230-exact-cut", + "cut_revision": "rev1", + "steps": null + }, + "memory": { + "retention": "cross-episode", + "memory_ref": "participant-memory:retained-history-v1", + "memory_revision": "rev1", + "reset_rule_ref": null, + "reset_rule_revision": null + }, + "strategy": { + "kind": "active", + "strategy_refs": [ + "strategy:sem-230-admitted-adaptive-domain" + ] + }, + "release": { + "schedule_ref": "release-schedule:sem-230-exact-cut-v1", + "schedule_revision": "rev1", + "exact_cut": true, + "concealment_erases_retained_knowledge": false + }, + "scheduler_refs": [ + "scheduler:sem-230-declared-class" + ], + "environment_refs": [ + "environment:sem-230-declared-class" + ], + "nondeterminism": "possibilistic-support", + "order": { + "treatment": "total-order", + "order_refs": [ + "order:sem-230-declared-total-order" + ] + }, + "time": { + "model": "untimed", + "progress": "progress-insensitive", + "absence_observable": false, + "opportunity_basis_ref": null, + "opportunity_basis_revision": null + }, + "probability": "outside-baseline", + "bounds": null + }, + "source_refs": [ + { + "source_ref": "docs/decisions/adrs/adr-085-participant-information-flow-and-control.md", + "source_digest": "sha256:a4df034f1ed75f63119d8b56dbcc34b5fee6c6c81822c0d7c507ef2290078684" + }, + { + "source_ref": "docs/decisions/adrs/adr-099-participant-relative-predicate-opacity.md", + "source_digest": "sha256:61a5ea9d72a0afa1033d46131913f45b140286b6ddddcb59e0e1f6914b721cb9" + } + ], + "limitations": [ + "The theorem is conditional on the explicit eligible-predicate and exact SEM-230/SEM-231 profile-correspondence premises.", + "The carrier is abstract and parameterized; no RAES runtime, deployment, backend, or concrete participant is instantiated.", + "The theorem is one-sided, possibilistic, untimed, progress-insensitive, individual-observer, and total-order." + ], + "explicit_non_claims": [ + "No reverse implication from predicate opacity to policy noninterference.", + "No result from one equal-history pair, and no erasure of retained knowledge through concealment or revocation.", + "No timed, probabilistic, quantitative, coalition, all-linearization, partial-order, progress-sensitive, runtime-enforcement, supervisor-synthesis, backend-realization, or backend-conformance claim.", + "No correspondence proof between the Isabelle definition and the Python bounded or model-checking implementation." + ] +} diff --git a/contracts/profiles/behavioral-relation/history/participant-opacity-baseline-v1-sem-231-rev2.json b/contracts/profiles/behavioral-relation/history/participant-opacity-baseline-v1-sem-231-rev2.json new file mode 100644 index 000000000..11b4a1c63 --- /dev/null +++ b/contracts/profiles/behavioral-relation/history/participant-opacity-baseline-v1-sem-231-rev2.json @@ -0,0 +1,117 @@ +{ + "schema_version": "behavioral-relation-profile/v1", + "profile_id": "participant-opacity-baseline-v1", + "profile_revision": "sem-231/rev2", + "taxonomy_id": "raes-behavioral-relations", + "taxonomy_revision": "rev8", + "relation_id": "participant-predicate-opacity", + "left_carrier_ref": "possible-point-carrier:participant-opacity-fixture-v1", + "observation_projection_ref": "participant-opacity-observation:complete-v1", + "observation_projection_revision": "rev1", + "finite_analysis_scope": "declared-complete-finite-carrier", + "parameters": { + "kind": "participant-predicate-opacity/v1", + "observer": { + "kind": "individual", + "participant_ref": "participant:fixture-observer", + "audience_ref": "audience:fixture-observer" + }, + "secret": { + "predicate_ref": "secret-predicate:fixture-protected-state", + "predicate_revision": "rev1", + "truth_polarity": "one-sided-true" + }, + "carrier": { + "kind": "finite-possible-points", + "reachability_ref": "reachability:declared-finite-carrier", + "reachability_revision": "rev1" + }, + "initial_information": { + "projection_ref": "participant-opacity-initial-information:baseline-v1", + "projection_revision": "rev1" + }, + "observation": { + "projection_ref": "participant-opacity-observation:complete-v1", + "projection_revision": "rev1", + "observable_channels": [ + "action-availability", + "decision", + "delivery", + "latency", + "order", + "participant-state", + "payload", + "policy-release", + "retry" + ], + "supervisor_decisions": "online-learned" + }, + "horizon": { + "scope": "current", + "cut_ref": "state-cut:fixture-exact-cut", + "cut_revision": "rev1", + "steps": null + }, + "memory": { + "retention": "cross-episode", + "memory_ref": "participant-memory:retained-history-v1", + "memory_revision": "rev1", + "reset_rule_ref": null, + "reset_rule_revision": null + }, + "strategy": { + "kind": "passive" + }, + "release": { + "schedule_ref": "release-schedule:fixture-exact-cut-v1", + "schedule_revision": "rev1", + "exact_cut": true, + "concealment_erases_retained_knowledge": false + }, + "scheduler_refs": [ + "scheduler:finite-fixture" + ], + "environment_refs": [ + "environment:finite-fixture" + ], + "nondeterminism": "possibilistic-support", + "order": { + "treatment": "total-order", + "order_refs": [ + "order:finite-fixture" + ] + }, + "time": { + "model": "untimed", + "progress": "progress-insensitive", + "absence_observable": false, + "opportunity_basis_ref": null, + "opportunity_basis_revision": null + }, + "probability": "outside-baseline", + "bounds": { + "max_points": 4096, + "max_runs": 1024, + "max_cuts": 1024, + "max_strategies": 64, + "max_scheduler_environment_pairs": 64, + "max_order_variants": 64 + } + }, + "source_refs": [ + { + "source_ref": "docs/decisions/adrs/adr-099-participant-relative-predicate-opacity.md", + "source_digest": "sha256:61a5ea9d72a0afa1033d46131913f45b140286b6ddddcb59e0e1f6914b721cb9" + } + ], + "limitations": [ + "The profile admits only the declared complete finite carrier and its exact bounds.", + "The baseline is one-sided, possibilistic, untimed, progress-insensitive, and total-order.", + "The finite-state model-check result covers only the exact digest-bound transition model and this profile revision." + ], + "explicit_non_claims": [ + "The profile artifact alone establishes no model check, proof, runtime enforcement, supervisor synthesis, backend realization, or backend conformance.", + "No mathematical proof, runtime enforcement, supervisor synthesis, backend realization, or backend conformance.", + "No timed, probabilistic, quantitative, partial-order, or unbounded opacity claim." + ] +} diff --git a/contracts/profiles/behavioral-relation/participant-opacity-baseline-v1.json b/contracts/profiles/behavioral-relation/participant-opacity-baseline-v1.json index 11b4a1c63..f6ddddca5 100644 --- a/contracts/profiles/behavioral-relation/participant-opacity-baseline-v1.json +++ b/contracts/profiles/behavioral-relation/participant-opacity-baseline-v1.json @@ -1,9 +1,9 @@ { "schema_version": "behavioral-relation-profile/v1", "profile_id": "participant-opacity-baseline-v1", - "profile_revision": "sem-231/rev2", + "profile_revision": "sem-231/rev3", "taxonomy_id": "raes-behavioral-relations", - "taxonomy_revision": "rev8", + "taxonomy_revision": "rev9", "relation_id": "participant-predicate-opacity", "left_carrier_ref": "possible-point-carrier:participant-opacity-fixture-v1", "observation_projection_ref": "participant-opacity-observation:complete-v1", @@ -107,11 +107,11 @@ "limitations": [ "The profile admits only the declared complete finite carrier and its exact bounds.", "The baseline is one-sided, possibilistic, untimed, progress-insensitive, and total-order.", - "The finite-state model-check result covers only the exact digest-bound transition model and this profile revision." + "The finite-state model-check result remains bound to historical profile sem-231/rev2 and taxonomy rev8; this authoring revision does not relabel that evidence." ], "explicit_non_claims": [ "The profile artifact alone establishes no model check, proof, runtime enforcement, supervisor synthesis, backend realization, or backend conformance.", - "No mathematical proof, runtime enforcement, supervisor synthesis, backend realization, or backend conformance.", + "The mathematical proof is bound to participant-opacity-theorem-v1, not this finite profile.", "No timed, probabilistic, quantitative, partial-order, or unbounded opacity claim." ] } diff --git a/contracts/profiles/behavioral-relation/participant-opacity-theorem-v1.json b/contracts/profiles/behavioral-relation/participant-opacity-theorem-v1.json new file mode 100644 index 000000000..29dcc581d --- /dev/null +++ b/contracts/profiles/behavioral-relation/participant-opacity-theorem-v1.json @@ -0,0 +1,122 @@ +{ + "schema_version": "behavioral-relation-profile/v1", + "profile_id": "participant-opacity-theorem-v1", + "profile_revision": "sem-231-proof/rev1", + "taxonomy_id": "raes-behavioral-relations", + "taxonomy_revision": "rev9", + "relation_id": "participant-predicate-opacity", + "left_carrier_ref": "possible-point-carrier:sem-231-abstract-v1", + "observation_projection_ref": "participant-opacity-observation:sem-230-complete-support-v1", + "observation_projection_revision": "rev1", + "finite_analysis_scope": "abstract-parameterized-theorem-carrier", + "parameters": { + "kind": "participant-predicate-opacity/v1", + "observer": { + "kind": "individual", + "participant_ref": "participant:abstract-observer", + "audience_ref": "audience:abstract-observer" + }, + "secret": { + "predicate_ref": "secret-predicate:sem-231-eligible", + "predicate_revision": "rev1", + "truth_polarity": "one-sided-true" + }, + "carrier": { + "kind": "abstract-possible-points", + "reachability_ref": "reachability:sem-231-admitted-carrier", + "reachability_revision": "rev1", + "eligibility_ref": "sem-231-eligible-predicate", + "eligibility_revision": "rev1", + "correspondence_ref": "sem-230-sem-231-profile-correspondence", + "correspondence_revision": "rev1" + }, + "initial_information": { + "projection_ref": "participant-opacity-initial-information:sem-230-public-v1", + "projection_revision": "rev1" + }, + "observation": { + "projection_ref": "participant-opacity-observation:sem-230-complete-support-v1", + "projection_revision": "rev1", + "observable_channels": [ + "action-availability", + "decision", + "delivery", + "latency", + "order", + "participant-state", + "payload", + "policy-release", + "retry" + ], + "supervisor_decisions": "online-learned" + }, + "horizon": { + "scope": "language", + "cut_ref": "state-cut:sem-230-exact-cut", + "cut_revision": "rev1", + "steps": null + }, + "memory": { + "retention": "cross-episode", + "memory_ref": "participant-memory:retained-history-v1", + "memory_revision": "rev1", + "reset_rule_ref": null, + "reset_rule_revision": null + }, + "strategy": { + "kind": "active", + "strategy_refs": [ + "strategy:sem-230-admitted-adaptive-domain" + ] + }, + "release": { + "schedule_ref": "release-schedule:sem-230-exact-cut-v1", + "schedule_revision": "rev1", + "exact_cut": true, + "concealment_erases_retained_knowledge": false + }, + "scheduler_refs": [ + "scheduler:sem-230-declared-class" + ], + "environment_refs": [ + "environment:sem-230-declared-class" + ], + "nondeterminism": "possibilistic-support", + "order": { + "treatment": "total-order", + "order_refs": [ + "order:sem-230-declared-total-order" + ] + }, + "time": { + "model": "untimed", + "progress": "progress-insensitive", + "absence_observable": false, + "opportunity_basis_ref": null, + "opportunity_basis_revision": null + }, + "probability": "outside-baseline", + "bounds": null + }, + "source_refs": [ + { + "source_ref": "docs/decisions/adrs/adr-085-participant-information-flow-and-control.md", + "source_digest": "sha256:a4df034f1ed75f63119d8b56dbcc34b5fee6c6c81822c0d7c507ef2290078684" + }, + { + "source_ref": "docs/decisions/adrs/adr-099-participant-relative-predicate-opacity.md", + "source_digest": "sha256:61a5ea9d72a0afa1033d46131913f45b140286b6ddddcb59e0e1f6914b721cb9" + } + ], + "limitations": [ + "The theorem is conditional on the explicit eligible-predicate and exact SEM-230/SEM-231 profile-correspondence premises.", + "The carrier is abstract and parameterized; no RAES runtime, deployment, backend, or concrete participant is instantiated.", + "The theorem is one-sided, possibilistic, untimed, progress-insensitive, individual-observer, and total-order." + ], + "explicit_non_claims": [ + "No reverse implication from predicate opacity to policy noninterference.", + "No result from one equal-history pair, and no erasure of retained knowledge through concealment or revocation.", + "No timed, probabilistic, quantitative, coalition, all-linearization, partial-order, progress-sensitive, runtime-enforcement, supervisor-synthesis, backend-realization, or backend-conformance claim.", + "No correspondence proof between the Isabelle definition and the Python bounded or model-checking implementation." + ] +} diff --git a/contracts/schema-publication/entries/admitted-trial-plan-v1.json b/contracts/schema-publication/entries/admitted-trial-plan-v1.json index 747888caa..8ad7deea2 100644 --- a/contracts/schema-publication/entries/admitted-trial-plan-v1.json +++ b/contracts/schema-publication/entries/admitted-trial-plan-v1.json @@ -2,9 +2,9 @@ "contract_id": "admitted-trial-plan-v1", "schema_path": "contracts/schemas/plans/admitted-trial-plan-v1.json", "stability": "draft", - "content_hash": "4b85ec11998b0745e4d3d17861e06625f1b5bb99f3b6afffd8ac948fe96867ff", + "content_hash": "366f64c787d7db3334603c7ffe4607b79ae7a904ec644254a3e3408138a244b1", "last_change": { - "summary": "Propagated the secret-scope isolation dimension into the embedded scheduler-isolation-proof so admitted plans can carry a complete bounded-parallelism proof (issue #785).", - "content_hash": "4b85ec11998b0745e4d3d17861e06625f1b5bb99f3b6afffd8ac948fe96867ff" + "summary": "Rebound the published schema namespace to the renamed OpenRAE GitHub organization for issue #963.", + "content_hash": "366f64c787d7db3334603c7ffe4607b79ae7a904ec644254a3e3408138a244b1" } } diff --git a/contracts/schema-publication/entries/artifact-requirement-v1.json b/contracts/schema-publication/entries/artifact-requirement-v1.json index aea8cd3af..bc1ea7580 100644 --- a/contracts/schema-publication/entries/artifact-requirement-v1.json +++ b/contracts/schema-publication/entries/artifact-requirement-v1.json @@ -2,9 +2,9 @@ "contract_id": "artifact-requirement-v1", "schema_path": "contracts/schemas/artifact-requirements/artifact-requirement-v1.json", "stability": "draft", - "content_hash": "bb4850500da9d100689a9a4e486f5922234cf3032e16788f9d2e7be755edb8ea", + "content_hash": "4da2377a47f875b510e855389ece3664d6c6802d7dbabef74a998225df61c9a4", "last_change": { - "summary": "Repointed the published schema namespace from the uncontrolled raes.dev domain to the repository-owned https://raesystem.github.io/rae/schemas/ root for issue #908.", - "content_hash": "bb4850500da9d100689a9a4e486f5922234cf3032e16788f9d2e7be755edb8ea" + "summary": "Rebound the published schema namespace to the renamed OpenRAE GitHub organization for issue #963.", + "content_hash": "4da2377a47f875b510e855389ece3664d6c6802d7dbabef74a998225df61c9a4" } } diff --git a/contracts/schema-publication/entries/associated-artifact-manifest-v1.json b/contracts/schema-publication/entries/associated-artifact-manifest-v1.json index 5a2522362..4d0e11511 100644 --- a/contracts/schema-publication/entries/associated-artifact-manifest-v1.json +++ b/contracts/schema-publication/entries/associated-artifact-manifest-v1.json @@ -2,9 +2,9 @@ "contract_id": "associated-artifact-manifest-v1", "schema_path": "contracts/schemas/associated-artifacts/associated-artifact-manifest-v1.json", "stability": "draft", - "content_hash": "a82c0539e307342fad8a494e04571a1e50639615efd349ee8d3f7d96f9e71751", + "content_hash": "f5f2eadf2be4c50c10764c180cebfd2ce12ff1cbc87ac20788e9c0604a57234b", "last_change": { - "summary": "Repointed the published schema namespace from the uncontrolled raes.dev domain to the repository-owned https://raesystem.github.io/rae/schemas/ root for issue #908.", - "content_hash": "a82c0539e307342fad8a494e04571a1e50639615efd349ee8d3f7d96f9e71751" + "summary": "Rebound the published schema namespace to the renamed OpenRAE GitHub organization for issue #963.", + "content_hash": "f5f2eadf2be4c50c10764c180cebfd2ce12ff1cbc87ac20788e9c0604a57234b" } } diff --git a/contracts/schema-publication/entries/atlas-tactics-source-v1.json b/contracts/schema-publication/entries/atlas-tactics-source-v1.json index 3724177dd..be490ae80 100644 --- a/contracts/schema-publication/entries/atlas-tactics-source-v1.json +++ b/contracts/schema-publication/entries/atlas-tactics-source-v1.json @@ -2,9 +2,9 @@ "contract_id": "atlas-tactics-source-v1", "schema_path": "contracts/schemas/concept-authority/atlas-tactics-source-v1.json", "stability": "draft", - "content_hash": "e1aec25898402152581fe442453858dbe0e9398bb6ddb157273c4ce298f9ebee", + "content_hash": "23af15f43d41442a62f4f637f4b8a57d76458e6364e65750ba9c2b93d23bbdce", "last_change": { - "summary": "Repointed the published schema namespace from the uncontrolled raes.dev domain to the repository-owned https://raesystem.github.io/rae/schemas/ root for issue #908.", - "content_hash": "e1aec25898402152581fe442453858dbe0e9398bb6ddb157273c4ce298f9ebee" + "summary": "Rebound the published schema namespace to the renamed OpenRAE GitHub organization for issue #963.", + "content_hash": "23af15f43d41442a62f4f637f4b8a57d76458e6364e65750ba9c2b93d23bbdce" } } diff --git a/contracts/schema-publication/entries/attack-enterprise-tactics-source-v1.json b/contracts/schema-publication/entries/attack-enterprise-tactics-source-v1.json index 583ea6cee..e337a38f2 100644 --- a/contracts/schema-publication/entries/attack-enterprise-tactics-source-v1.json +++ b/contracts/schema-publication/entries/attack-enterprise-tactics-source-v1.json @@ -2,9 +2,9 @@ "contract_id": "attack-enterprise-tactics-source-v1", "schema_path": "contracts/schemas/concept-authority/attack-enterprise-tactics-source-v1.json", "stability": "draft", - "content_hash": "7c7dd670f04d92fd1c5f412087ce50c5aed0f4c66abbcf997d926688f46b0cae", + "content_hash": "538f1603bb979b0a8bdf7c2f83f47b1a46b86306f925540560ffaacf0e6064d6", "last_change": { - "summary": "Repointed the published schema namespace from the uncontrolled raes.dev domain to the repository-owned https://raesystem.github.io/rae/schemas/ root for issue #908.", - "content_hash": "7c7dd670f04d92fd1c5f412087ce50c5aed0f4c66abbcf997d926688f46b0cae" + "summary": "Rebound the published schema namespace to the renamed OpenRAE GitHub organization for issue #963.", + "content_hash": "538f1603bb979b0a8bdf7c2f83f47b1a46b86306f925540560ffaacf0e6064d6" } } diff --git a/contracts/schema-publication/entries/backend-manifest-v2.json b/contracts/schema-publication/entries/backend-manifest-v2.json index 211859d2a..0e32a64f7 100644 --- a/contracts/schema-publication/entries/backend-manifest-v2.json +++ b/contracts/schema-publication/entries/backend-manifest-v2.json @@ -2,9 +2,9 @@ "contract_id": "backend-manifest-v2", "schema_path": "contracts/schemas/backend-manifest/backend-manifest-v2.json", "stability": "draft", - "content_hash": "5408003b0a05176661342b87b9f17116b4f1a4fd687153a3813dce33f8dec064", + "content_hash": "4e9f3694ba9be9dff9236ad94b895591f28863f295724d013c243b6d290ae37f", "last_change": { - "summary": "Repointed the published schema namespace from the uncontrolled raes.dev domain to the repository-owned https://raesystem.github.io/rae/schemas/ root for issue #908.", - "content_hash": "5408003b0a05176661342b87b9f17116b4f1a4fd687153a3813dce33f8dec064" + "summary": "Rebound the published schema namespace to the renamed OpenRAE GitHub organization for issue #963.", + "content_hash": "4e9f3694ba9be9dff9236ad94b895591f28863f295724d013c243b6d290ae37f" } } diff --git a/contracts/schema-publication/entries/backend-profile-v1.json b/contracts/schema-publication/entries/backend-profile-v1.json index 535ec921a..269be2d99 100644 --- a/contracts/schema-publication/entries/backend-profile-v1.json +++ b/contracts/schema-publication/entries/backend-profile-v1.json @@ -2,9 +2,9 @@ "contract_id": "backend-profile-v1", "schema_path": "contracts/schemas/profiles/backend-profile-v1.json", "stability": "draft", - "content_hash": "3e878fa2f248992bcc9f404408979e2c1d39e4305ca7e39ea93d880354b2c789", + "content_hash": "9b55db6c28c375845132097920e730af375e66bf13dc12f9122aed9ab5b82a97", "last_change": { - "summary": "Repointed the published schema namespace from the uncontrolled raes.dev domain to the repository-owned https://raesystem.github.io/rae/schemas/ root for issue #908.", - "content_hash": "3e878fa2f248992bcc9f404408979e2c1d39e4305ca7e39ea93d880354b2c789" + "summary": "Rebound the published schema namespace to the renamed OpenRAE GitHub organization for issue #963.", + "content_hash": "9b55db6c28c375845132097920e730af375e66bf13dc12f9122aed9ab5b82a97" } } diff --git a/contracts/schema-publication/entries/batch-execution-receipt-v1.json b/contracts/schema-publication/entries/batch-execution-receipt-v1.json index cf1dd719b..c9aac02ce 100644 --- a/contracts/schema-publication/entries/batch-execution-receipt-v1.json +++ b/contracts/schema-publication/entries/batch-execution-receipt-v1.json @@ -2,9 +2,9 @@ "contract_id": "batch-execution-receipt-v1", "schema_path": "contracts/schemas/control-plane/batch-execution-receipt-v1.json", "stability": "draft", - "content_hash": "4ee2a2104963499be5a9cb24f22e3e98835b51a67d99dc6e8a93011200ba4ebe", + "content_hash": "9f7882166edf0a800e73c412a6493ac6e245b29582db71ddbd7032ed283272dc", "last_change": { - "summary": "Published the SCE-006 batch execution receipt: one immutable attempt receipt binding the sealed plan/entry/run identities, canonical dispatch ordinal under the closed canonical order policy, effective concurrency, isolation-proof and lease evidence refs, trial disposition, operation refs, and a required cleanup-receipt ref; bounded parallelism requires an isolation proof and live lease evidence, and the recorded parallelism is authorized only by the sealed plan's embedded proof (issue #785).", - "content_hash": "4ee2a2104963499be5a9cb24f22e3e98835b51a67d99dc6e8a93011200ba4ebe" + "summary": "Rebound the published schema namespace to the renamed OpenRAE GitHub organization for issue #963.", + "content_hash": "9f7882166edf0a800e73c412a6493ac6e245b29582db71ddbd7032ed283272dc" } } diff --git a/contracts/schema-publication/entries/behavioral-relation-profile-v1.json b/contracts/schema-publication/entries/behavioral-relation-profile-v1.json index 6db10627c..d7948d417 100644 --- a/contracts/schema-publication/entries/behavioral-relation-profile-v1.json +++ b/contracts/schema-publication/entries/behavioral-relation-profile-v1.json @@ -2,9 +2,9 @@ "contract_id": "behavioral-relation-profile-v1", "schema_path": "contracts/schemas/profiles/behavioral-relation-profile-v1.json", "stability": "draft", - "content_hash": "e01769ee74c94e44e7ae876878f4da5ccd5df72fa5efdbef9767ccae5385bbc5", + "content_hash": "b718945e218c75749b7377902e67854ea01c23d4e52e89e504b4c3d4b2d1e4d1", "last_change": { - "summary": "Published the closed participant-opacity relation profile contract for issue #961.", - "content_hash": "e01769ee74c94e44e7ae876878f4da5ccd5df72fa5efdbef9767ccae5385bbc5" + "summary": "Added the abstract theorem-carrier variant, encoded carrier joins, and rebound the schema namespace to OpenRAE for issue #963.", + "content_hash": "b718945e218c75749b7377902e67854ea01c23d4e52e89e504b4c3d4b2d1e4d1" } } diff --git a/contracts/schema-publication/entries/behavioral-relations-v1.json b/contracts/schema-publication/entries/behavioral-relations-v1.json index 5650cd491..d6588fb03 100644 --- a/contracts/schema-publication/entries/behavioral-relations-v1.json +++ b/contracts/schema-publication/entries/behavioral-relations-v1.json @@ -2,9 +2,9 @@ "contract_id": "behavioral-relations-v1", "schema_path": "contracts/schemas/concept-authority/behavioral-relations-v1.json", "stability": "draft", - "content_hash": "1385035093e46ffdcca1bd30ce26895e38777493793ee2c7615085c25783be27", + "content_hash": "6cbd7886d1acd7158ad5a71b3d8e53d099484db8fc885b0ab90a613fca5de788", "last_change": { - "summary": "Added revisioned relation-parameter profiles, assurance-axis binding, and independent opacity assurance states for issue #810.", - "content_hash": "1385035093e46ffdcca1bd30ce26895e38777493793ee2c7615085c25783be27" + "summary": "Rebound the published schema namespace to the renamed OpenRAE GitHub organization for issue #963.", + "content_hash": "6cbd7886d1acd7158ad5a71b3d8e53d099484db8fc885b0ab90a613fca5de788" } } diff --git a/contracts/schema-publication/entries/concept-families-v1.json b/contracts/schema-publication/entries/concept-families-v1.json index c42514ee4..b22fcc576 100644 --- a/contracts/schema-publication/entries/concept-families-v1.json +++ b/contracts/schema-publication/entries/concept-families-v1.json @@ -2,9 +2,9 @@ "contract_id": "concept-families-v1", "schema_path": "contracts/schemas/concept-authority/concept-families-v1.json", "stability": "draft", - "content_hash": "1a949b8d328d488ca7b71ef16d5803b7c1f4168b75eab64540988b537ed55fb0", + "content_hash": "6f0ba889401f5d55253ca27c1821fe7b209bbb061ddbc70b911105baefcf5d3b", "last_change": { - "summary": "Repointed the published schema namespace from the uncontrolled raes.dev domain to the repository-owned https://raesystem.github.io/rae/schemas/ root for issue #908.", - "content_hash": "1a949b8d328d488ca7b71ef16d5803b7c1f4168b75eab64540988b537ed55fb0" + "summary": "Rebound the published schema namespace to the renamed OpenRAE GitHub organization for issue #963.", + "content_hash": "6f0ba889401f5d55253ca27c1821fe7b209bbb061ddbc70b911105baefcf5d3b" } } diff --git a/contracts/schema-publication/entries/controlled-vocabularies-v1.json b/contracts/schema-publication/entries/controlled-vocabularies-v1.json index db9c27121..0bbbcb2ef 100644 --- a/contracts/schema-publication/entries/controlled-vocabularies-v1.json +++ b/contracts/schema-publication/entries/controlled-vocabularies-v1.json @@ -2,9 +2,9 @@ "contract_id": "controlled-vocabularies-v1", "schema_path": "contracts/schemas/concept-authority/controlled-vocabularies-v1.json", "stability": "draft", - "content_hash": "5673ba3ec07eecfb0a1aa2715e3bb81cf288d40cff769dd7114a6dc639257a01", + "content_hash": "acbb82cd0024697b02eec4821057caca35091801e029c18b190211c36a3a2b0b", "last_change": { - "summary": "Repointed the published schema namespace from the uncontrolled raes.dev domain to the repository-owned https://raesystem.github.io/rae/schemas/ root for issue #908.", - "content_hash": "5673ba3ec07eecfb0a1aa2715e3bb81cf288d40cff769dd7114a6dc639257a01" + "summary": "Rebound the published schema namespace to the renamed OpenRAE GitHub organization for issue #963.", + "content_hash": "acbb82cd0024697b02eec4821057caca35091801e029c18b190211c36a3a2b0b" } } diff --git a/contracts/schema-publication/entries/evaluation-history-event-stream-v1.json b/contracts/schema-publication/entries/evaluation-history-event-stream-v1.json index 417e01566..4db23de8c 100644 --- a/contracts/schema-publication/entries/evaluation-history-event-stream-v1.json +++ b/contracts/schema-publication/entries/evaluation-history-event-stream-v1.json @@ -2,9 +2,9 @@ "contract_id": "evaluation-history-event-stream-v1", "schema_path": "contracts/schemas/control-plane/evaluation-history-event-stream-v1.json", "stability": "draft", - "content_hash": "800ebef43a7d79d1c76e959bb2563cd1fac8845199eea012bc8816522a0bed0c", + "content_hash": "684167d87bc9b3eaa2945b386b7b0fc4d9e0008097aabbd42853c0245fc44571", "last_change": { - "summary": "Repointed the published schema namespace from the uncontrolled raes.dev domain to the repository-owned https://raesystem.github.io/rae/schemas/ root for issue #908.", - "content_hash": "800ebef43a7d79d1c76e959bb2563cd1fac8845199eea012bc8816522a0bed0c" + "summary": "Rebound the published schema namespace to the renamed OpenRAE GitHub organization for issue #963.", + "content_hash": "684167d87bc9b3eaa2945b386b7b0fc4d9e0008097aabbd42853c0245fc44571" } } diff --git a/contracts/schema-publication/entries/evaluation-plan-v1.json b/contracts/schema-publication/entries/evaluation-plan-v1.json index 4bc6b5f87..31f77ed11 100644 --- a/contracts/schema-publication/entries/evaluation-plan-v1.json +++ b/contracts/schema-publication/entries/evaluation-plan-v1.json @@ -2,9 +2,9 @@ "contract_id": "evaluation-plan-v1", "schema_path": "contracts/schemas/plans/evaluation-plan-v1.json", "stability": "draft", - "content_hash": "6ab37890bed35b32d852f31f01b986c0d243f83bb986fd46e11ea1616efafcd5", + "content_hash": "ec563c738d21e8b0be1c50572e1f5100c39869b2093abfa71d9fc73cab2dae83", "last_change": { - "summary": "Repointed the published schema namespace from the uncontrolled raes.dev domain to the repository-owned https://raesystem.github.io/rae/schemas/ root for issue #908.", - "content_hash": "6ab37890bed35b32d852f31f01b986c0d243f83bb986fd46e11ea1616efafcd5" + "summary": "Rebound the published schema namespace to the renamed OpenRAE GitHub organization for issue #963.", + "content_hash": "ec563c738d21e8b0be1c50572e1f5100c39869b2093abfa71d9fc73cab2dae83" } } diff --git a/contracts/schema-publication/entries/evaluation-result-envelope-v1.json b/contracts/schema-publication/entries/evaluation-result-envelope-v1.json index 9689c595b..af4dc5041 100644 --- a/contracts/schema-publication/entries/evaluation-result-envelope-v1.json +++ b/contracts/schema-publication/entries/evaluation-result-envelope-v1.json @@ -2,9 +2,9 @@ "contract_id": "evaluation-result-envelope-v1", "schema_path": "contracts/schemas/control-plane/evaluation-result-envelope-v1.json", "stability": "draft", - "content_hash": "14badba5fe848dd3ce7a625d84c9ec42fec1f435debd74504414c2b799b4dbec", + "content_hash": "61d283c67f54b993b7620c808c4c20149dc301140f8b7d80c0c6438c569f934b", "last_change": { - "summary": "Repointed the published schema namespace from the uncontrolled raes.dev domain to the repository-owned https://raesystem.github.io/rae/schemas/ root for issue #908.", - "content_hash": "14badba5fe848dd3ce7a625d84c9ec42fec1f435debd74504414c2b799b4dbec" + "summary": "Rebound the published schema namespace to the renamed OpenRAE GitHub organization for issue #963.", + "content_hash": "61d283c67f54b993b7620c808c4c20149dc301140f8b7d80c0c6438c569f934b" } } diff --git a/contracts/schema-publication/entries/experiment-apparatus-context-v1.json b/contracts/schema-publication/entries/experiment-apparatus-context-v1.json index 2593c5ff1..6033c0ea2 100644 --- a/contracts/schema-publication/entries/experiment-apparatus-context-v1.json +++ b/contracts/schema-publication/entries/experiment-apparatus-context-v1.json @@ -2,9 +2,9 @@ "contract_id": "experiment-apparatus-context-v1", "schema_path": "contracts/schemas/experiment-core/experiment-apparatus-context-v1.json", "stability": "draft", - "content_hash": "9916e5582a8e79e8442abba25f30c4e2ac108e97d56f1da1b63a247d132c46d5", + "content_hash": "0e985b9cf8984e472f988be384c2d2c10aa8c999221a11624bc0cce25dbee47b", "last_change": { - "summary": "Repointed the published schema namespace from the uncontrolled raes.dev domain to the repository-owned https://raesystem.github.io/rae/schemas/ root for issue #908.", - "content_hash": "9916e5582a8e79e8442abba25f30c4e2ac108e97d56f1da1b63a247d132c46d5" + "summary": "Rebound the published schema namespace to the renamed OpenRAE GitHub organization for issue #963.", + "content_hash": "0e985b9cf8984e472f988be384c2d2c10aa8c999221a11624bc0cce25dbee47b" } } diff --git a/contracts/schema-publication/entries/experiment-authoring-input-v1.json b/contracts/schema-publication/entries/experiment-authoring-input-v1.json index 2ac424a45..2e218094b 100644 --- a/contracts/schema-publication/entries/experiment-authoring-input-v1.json +++ b/contracts/schema-publication/entries/experiment-authoring-input-v1.json @@ -2,9 +2,9 @@ "contract_id": "experiment-authoring-input-v1", "schema_path": "contracts/schemas/experiment-core/experiment-authoring-input-v1.json", "stability": "draft", - "content_hash": "7a26f479a37755dc7d7989d467049a49eabef8a7d5d363d25837b58622a6e9a3", + "content_hash": "63926abe9ba25f0198211ad6d1f6374e94017cb69b860925caeca8d0f348f148", "last_change": { - "summary": "Bound adaptive-difficulty observation roles to exact versioned or digest-bound source definitions for issue #784.", - "content_hash": "7a26f479a37755dc7d7989d467049a49eabef8a7d5d363d25837b58622a6e9a3" + "summary": "Rebound the published schema namespace to the renamed OpenRAE GitHub organization for issue #963.", + "content_hash": "63926abe9ba25f0198211ad6d1f6374e94017cb69b860925caeca8d0f348f148" } } diff --git a/contracts/schema-publication/entries/experiment-binding-descriptors-v1.json b/contracts/schema-publication/entries/experiment-binding-descriptors-v1.json index 24a995a9e..7531bebc7 100644 --- a/contracts/schema-publication/entries/experiment-binding-descriptors-v1.json +++ b/contracts/schema-publication/entries/experiment-binding-descriptors-v1.json @@ -2,9 +2,9 @@ "contract_id": "experiment-binding-descriptors-v1", "schema_path": "contracts/schemas/experiment-core/experiment-binding-descriptors-v1.json", "stability": "draft", - "content_hash": "8f737f9be11d01bac0dbe9382e8b1057cc9dfaf60a36053250e8a568cba3ab7a", + "content_hash": "788ba843a35efcb88019c79717c1fe0e6b05fe096194bcbd833cc06cd39da189", "last_change": { - "summary": "Repointed the published schema namespace from the uncontrolled raes.dev domain to the repository-owned https://raesystem.github.io/rae/schemas/ root for issue #908.", - "content_hash": "8f737f9be11d01bac0dbe9382e8b1057cc9dfaf60a36053250e8a568cba3ab7a" + "summary": "Rebound the published schema namespace to the renamed OpenRAE GitHub organization for issue #963.", + "content_hash": "788ba843a35efcb88019c79717c1fe0e6b05fe096194bcbd833cc06cd39da189" } } diff --git a/contracts/schema-publication/entries/experiment-capture-spec-v1.json b/contracts/schema-publication/entries/experiment-capture-spec-v1.json index c2cd696a5..eb21727a4 100644 --- a/contracts/schema-publication/entries/experiment-capture-spec-v1.json +++ b/contracts/schema-publication/entries/experiment-capture-spec-v1.json @@ -2,9 +2,9 @@ "contract_id": "experiment-capture-spec-v1", "schema_path": "contracts/schemas/experiment-core/experiment-capture-spec-v1.json", "stability": "draft", - "content_hash": "812f8314c76208d588b459cfc99637e9fba1c9f7519602c3b8ea6f7a62a4475c", + "content_hash": "fdf889faeb85d071c22d9fd4c42b26df3457dac60f7f205e22274c51117df3ff", "last_change": { - "summary": "Repointed the published schema namespace from the uncontrolled raes.dev domain to the repository-owned https://raesystem.github.io/rae/schemas/ root for issue #908.", - "content_hash": "812f8314c76208d588b459cfc99637e9fba1c9f7519602c3b8ea6f7a62a4475c" + "summary": "Rebound the published schema namespace to the renamed OpenRAE GitHub organization for issue #963.", + "content_hash": "fdf889faeb85d071c22d9fd4c42b26df3457dac60f7f205e22274c51117df3ff" } } diff --git a/contracts/schema-publication/entries/experiment-derived-measure-v1.json b/contracts/schema-publication/entries/experiment-derived-measure-v1.json index 79437b07f..078f66ac3 100644 --- a/contracts/schema-publication/entries/experiment-derived-measure-v1.json +++ b/contracts/schema-publication/entries/experiment-derived-measure-v1.json @@ -2,9 +2,9 @@ "contract_id": "experiment-derived-measure-v1", "schema_path": "contracts/schemas/experiment-core/experiment-derived-measure-v1.json", "stability": "draft", - "content_hash": "3ff95c83a82d4cb6c9a9200dcb51331dc7dc553c3914b7800c05ecf3ba9d4fa3", + "content_hash": "73d7bfbf2832e37573b29d6aa3420a92386df19efda0596a841e15d65addf24c", "last_change": { - "summary": "Repointed the published schema namespace from the uncontrolled raes.dev domain to the repository-owned https://raesystem.github.io/rae/schemas/ root for issue #908.", - "content_hash": "3ff95c83a82d4cb6c9a9200dcb51331dc7dc553c3914b7800c05ecf3ba9d4fa3" + "summary": "Rebound the published schema namespace to the renamed OpenRAE GitHub organization for issue #963.", + "content_hash": "73d7bfbf2832e37573b29d6aa3420a92386df19efda0596a841e15d65addf24c" } } diff --git a/contracts/schema-publication/entries/experiment-evidence-record-v1.json b/contracts/schema-publication/entries/experiment-evidence-record-v1.json index 3a509ad0c..d162e2446 100644 --- a/contracts/schema-publication/entries/experiment-evidence-record-v1.json +++ b/contracts/schema-publication/entries/experiment-evidence-record-v1.json @@ -2,9 +2,9 @@ "contract_id": "experiment-evidence-record-v1", "schema_path": "contracts/schemas/experiment-core/experiment-evidence-record-v1.json", "stability": "draft", - "content_hash": "a98b73cf0f590db45dabbef72606e53868482ae28d1bb0852a445ed4ecef762b", + "content_hash": "2ae162f2751889b1e8a031b2fa962e87836dd0fa68d09a4206eb3bee1f84d610", "last_change": { - "summary": "Repointed the published schema namespace from the uncontrolled raes.dev domain to the repository-owned https://raesystem.github.io/rae/schemas/ root for issue #908.", - "content_hash": "a98b73cf0f590db45dabbef72606e53868482ae28d1bb0852a445ed4ecef762b" + "summary": "Rebound the published schema namespace to the renamed OpenRAE GitHub organization for issue #963.", + "content_hash": "2ae162f2751889b1e8a031b2fa962e87836dd0fa68d09a4206eb3bee1f84d610" } } diff --git a/contracts/schema-publication/entries/experiment-run-v1.json b/contracts/schema-publication/entries/experiment-run-v1.json index 3c32ecf8f..66c403a1f 100644 --- a/contracts/schema-publication/entries/experiment-run-v1.json +++ b/contracts/schema-publication/entries/experiment-run-v1.json @@ -2,9 +2,9 @@ "contract_id": "experiment-run-v1", "schema_path": "contracts/schemas/experiment-core/experiment-run-v1.json", "stability": "draft", - "content_hash": "59d8056c05cbf86cafee784619255fcf2b3e199ff63fa7e96a118ca57e3d49a4", + "content_hash": "deee219541c5fe2d9e8031e2285bf7971891f7c180178a6c56d7ec5a4b4eee2f", "last_change": { - "summary": "Archived and validated exact adaptive-difficulty source definitions separately from evidence instances for issue #784.", - "content_hash": "59d8056c05cbf86cafee784619255fcf2b3e199ff63fa7e96a118ca57e3d49a4" + "summary": "Rebound the published schema namespace to the renamed OpenRAE GitHub organization for issue #963.", + "content_hash": "deee219541c5fe2d9e8031e2285bf7971891f7c180178a6c56d7ec5a4b4eee2f" } } diff --git a/contracts/schema-publication/entries/experiment-study-v1.json b/contracts/schema-publication/entries/experiment-study-v1.json index 3649940cf..e241d061c 100644 --- a/contracts/schema-publication/entries/experiment-study-v1.json +++ b/contracts/schema-publication/entries/experiment-study-v1.json @@ -2,9 +2,9 @@ "contract_id": "experiment-study-v1", "schema_path": "contracts/schemas/experiment-core/experiment-study-v1.json", "stability": "draft", - "content_hash": "d6ae5d441175cd494a93dfd3f9e39456af600689e72948e73291d99db9c83a06", + "content_hash": "4f636c963fa250a9eddc2cc8747d8b2ed30f88f992dccdf4eb6a93da894b879b", "last_change": { - "summary": "Added explicit difficulty condition and policy allocation with adaptive-study validity treatment for issue #784.", - "content_hash": "d6ae5d441175cd494a93dfd3f9e39456af600689e72948e73291d99db9c83a06" + "summary": "Rebound the published schema namespace to the renamed OpenRAE GitHub organization for issue #963.", + "content_hash": "4f636c963fa250a9eddc2cc8747d8b2ed30f88f992dccdf4eb6a93da894b879b" } } diff --git a/contracts/schema-publication/entries/experiment-task-v1.json b/contracts/schema-publication/entries/experiment-task-v1.json index 2d9003f54..d82703d43 100644 --- a/contracts/schema-publication/entries/experiment-task-v1.json +++ b/contracts/schema-publication/entries/experiment-task-v1.json @@ -2,9 +2,9 @@ "contract_id": "experiment-task-v1", "schema_path": "contracts/schemas/experiment-core/experiment-task-v1.json", "stability": "draft", - "content_hash": "328f94b60bb8d6cc607c6b095fbf93cf2fb555c949c9d98ec3b56ab1387c085f", + "content_hash": "1268ebf471a62cd443c183664460d19b9ee03b1b7b2e312c8dc8c3c40305a5a9", "last_change": { - "summary": "Repointed the published schema namespace from the uncontrolled raes.dev domain to the repository-owned https://raesystem.github.io/rae/schemas/ root for issue #908.", - "content_hash": "328f94b60bb8d6cc607c6b095fbf93cf2fb555c949c9d98ec3b56ab1387c085f" + "summary": "Rebound the published schema namespace to the renamed OpenRAE GitHub organization for issue #963.", + "content_hash": "1268ebf471a62cd443c183664460d19b9ee03b1b7b2e312c8dc8c3c40305a5a9" } } diff --git a/contracts/schema-publication/entries/exploit-path-analysis-evidence-v1.json b/contracts/schema-publication/entries/exploit-path-analysis-evidence-v1.json index 9eed41065..d61ecaf8c 100644 --- a/contracts/schema-publication/entries/exploit-path-analysis-evidence-v1.json +++ b/contracts/schema-publication/entries/exploit-path-analysis-evidence-v1.json @@ -2,9 +2,9 @@ "contract_id": "exploit-path-analysis-evidence-v1", "schema_path": "contracts/schemas/exploit-path-analysis/exploit-path-analysis-evidence-v1.json", "stability": "draft", - "content_hash": "0c0c96288ea61dbfb8f05b9e6ab26af0e8cde30ec04869d160193d9618924970", + "content_hash": "52f8669523f08187c69bcb9214d4948c0a2e38a4891671d9f18ec6e873713c11", "last_change": { - "summary": "Repointed the published schema namespace from the uncontrolled raes.dev domain to the repository-owned https://raesystem.github.io/rae/schemas/ root for issue #908.", - "content_hash": "0c0c96288ea61dbfb8f05b9e6ab26af0e8cde30ec04869d160193d9618924970" + "summary": "Rebound the published schema namespace to the renamed OpenRAE GitHub organization for issue #963.", + "content_hash": "52f8669523f08187c69bcb9214d4948c0a2e38a4891671d9f18ec6e873713c11" } } diff --git a/contracts/schema-publication/entries/external-concept-bindings-v1.json b/contracts/schema-publication/entries/external-concept-bindings-v1.json index e1d5cc8e6..0e52753fb 100644 --- a/contracts/schema-publication/entries/external-concept-bindings-v1.json +++ b/contracts/schema-publication/entries/external-concept-bindings-v1.json @@ -2,9 +2,9 @@ "contract_id": "external-concept-bindings-v1", "schema_path": "contracts/schemas/concept-authority/external-concept-bindings-v1.json", "stability": "draft", - "content_hash": "d0bb5f16d315f7efb21d3da932c62350db84ae476b7cba90034ea51bffc0456c", + "content_hash": "4779c89b92f03c8a99e5a2da7580744115163550296b83992e9aa7ce86fd097e", "last_change": { - "summary": "Published the portable, scheme-neutral external concept-binding assertion contract and its governed structural invariants for issue #986.", - "content_hash": "d0bb5f16d315f7efb21d3da932c62350db84ae476b7cba90034ea51bffc0456c" + "summary": "Rebound the published schema namespace to the renamed OpenRAE GitHub organization for issue #963.", + "content_hash": "4779c89b92f03c8a99e5a2da7580744115163550296b83992e9aa7ce86fd097e" } } diff --git a/contracts/schema-publication/entries/fipa-communicative-acts-source-v1.json b/contracts/schema-publication/entries/fipa-communicative-acts-source-v1.json new file mode 100644 index 000000000..5ade6661c --- /dev/null +++ b/contracts/schema-publication/entries/fipa-communicative-acts-source-v1.json @@ -0,0 +1,10 @@ +{ + "contract_id": "fipa-communicative-acts-source-v1", + "schema_path": "contracts/schemas/concept-authority/fipa-communicative-acts-source-v1.json", + "stability": "draft", + "content_hash": "039ff84031987efa22f659de7fb4391d7bf0299a8f11b33ce1d738c79df26b50", + "last_change": { + "summary": "Rebound the published schema namespace to the renamed OpenRAE GitHub organization for issue #963.", + "content_hash": "039ff84031987efa22f659de7fb4391d7bf0299a8f11b33ce1d738c79df26b50" + } +} diff --git a/contracts/schema-publication/entries/instantiated-scenario-snapshot-v1.json b/contracts/schema-publication/entries/instantiated-scenario-snapshot-v1.json index 37a55b6db..bb7903209 100644 --- a/contracts/schema-publication/entries/instantiated-scenario-snapshot-v1.json +++ b/contracts/schema-publication/entries/instantiated-scenario-snapshot-v1.json @@ -2,9 +2,9 @@ "contract_id": "instantiated-scenario-snapshot-v1", "schema_path": "contracts/schemas/sdl/instantiated-scenario-snapshot-v1.json", "stability": "draft", - "content_hash": "99432f259e709993ffc5b180f82457cb71560630a079eb5a34b5923e06d7c8cd", + "content_hash": "ebbb182be917c3d2b473f25df2374ab633bd2a73dc13af786e3c06f38d5f0ab6", "last_change": { - "summary": "Integrated admitted trial provenance with composable platform capability schema updates for issues #790 and #956.", - "content_hash": "99432f259e709993ffc5b180f82457cb71560630a079eb5a34b5923e06d7c8cd" + "summary": "Added the service search-index field-schema profile and rebound the namespace to OpenRAE for issues #1011 and #963.", + "content_hash": "ebbb182be917c3d2b473f25df2374ab633bd2a73dc13af786e3c06f38d5f0ab6" } } diff --git a/contracts/schema-publication/entries/instantiated-scenario-v1.json b/contracts/schema-publication/entries/instantiated-scenario-v1.json index 5cc168765..ef91d649f 100644 --- a/contracts/schema-publication/entries/instantiated-scenario-v1.json +++ b/contracts/schema-publication/entries/instantiated-scenario-v1.json @@ -2,9 +2,9 @@ "contract_id": "instantiated-scenario-v1", "schema_path": "contracts/schemas/sdl/instantiated-scenario-v1.json", "stability": "draft", - "content_hash": "3eb72628cb9e8c69a2228cdc36b61a455d2ee567adfce33444deb5f1f1d4056b", + "content_hash": "7560409fe1e4fcaa3a9f957a997ca1b019c6b13b78b5210778763bc41b4a5a88", "last_change": { - "summary": "Integrated admitted trial provenance with composable platform capability schema updates for issues #790 and #956.", - "content_hash": "3eb72628cb9e8c69a2228cdc36b61a455d2ee567adfce33444deb5f1f1d4056b" + "summary": "Added the service search-index field-schema profile and rebound the namespace to OpenRAE for issues #1011 and #963.", + "content_hash": "7560409fe1e4fcaa3a9f957a997ca1b019c6b13b78b5210778763bc41b4a5a88" } } diff --git a/contracts/schema-publication/entries/nist-csf-defensive-categories-source-v1.json b/contracts/schema-publication/entries/nist-csf-defensive-categories-source-v1.json index 5bcac908b..5ed3804d3 100644 --- a/contracts/schema-publication/entries/nist-csf-defensive-categories-source-v1.json +++ b/contracts/schema-publication/entries/nist-csf-defensive-categories-source-v1.json @@ -2,9 +2,9 @@ "contract_id": "nist-csf-defensive-categories-source-v1", "schema_path": "contracts/schemas/concept-authority/nist-csf-defensive-categories-source-v1.json", "stability": "draft", - "content_hash": "93e71d0a86591f26ef8fe899aa5a476d4bdb4e948942ae704b61020ce4b326e7", + "content_hash": "57478cd84d6e6422549acd01dcdf4c0ad8a2bbd8132fa39a56cd8ff7c7b23ed3", "last_change": { - "summary": "Repointed the published schema namespace from the uncontrolled raes.dev domain to the repository-owned https://raesystem.github.io/rae/schemas/ root for issue #908.", - "content_hash": "93e71d0a86591f26ef8fe899aa5a476d4bdb4e948942ae704b61020ce4b326e7" + "summary": "Rebound the published schema namespace to the renamed OpenRAE GitHub organization for issue #963.", + "content_hash": "57478cd84d6e6422549acd01dcdf4c0ad8a2bbd8132fa39a56cd8ff7c7b23ed3" } } diff --git a/contracts/schema-publication/entries/operation-receipt-v1.json b/contracts/schema-publication/entries/operation-receipt-v1.json index 39bb6a2f7..bf8178386 100644 --- a/contracts/schema-publication/entries/operation-receipt-v1.json +++ b/contracts/schema-publication/entries/operation-receipt-v1.json @@ -2,9 +2,9 @@ "contract_id": "operation-receipt-v1", "schema_path": "contracts/schemas/control-plane/operation-receipt-v1.json", "stability": "draft", - "content_hash": "e1f5d43c0303e20df01920b4b2c00482518f6efe3a12c6a40576ea477c7663bc", + "content_hash": "ec597654ec84617161098e883eb41e18bf30a81af3a50c0e316e284a920409df", "last_change": { - "summary": "Repointed the published schema namespace from the uncontrolled raes.dev domain to the repository-owned https://raesystem.github.io/rae/schemas/ root for issue #908.", - "content_hash": "e1f5d43c0303e20df01920b4b2c00482518f6efe3a12c6a40576ea477c7663bc" + "summary": "Rebound the published schema namespace to the renamed OpenRAE GitHub organization for issue #963.", + "content_hash": "ec597654ec84617161098e883eb41e18bf30a81af3a50c0e316e284a920409df" } } diff --git a/contracts/schema-publication/entries/operation-status-v1.json b/contracts/schema-publication/entries/operation-status-v1.json index 89348a02d..e6d934eb8 100644 --- a/contracts/schema-publication/entries/operation-status-v1.json +++ b/contracts/schema-publication/entries/operation-status-v1.json @@ -2,9 +2,9 @@ "contract_id": "operation-status-v1", "schema_path": "contracts/schemas/control-plane/operation-status-v1.json", "stability": "draft", - "content_hash": "af7ebde21bd81f5f9c1fffecb77b2a88d609a6215d6bc2e0bedc4c4c722821b3", + "content_hash": "179badc2f0bd77a0dd6d81bd17c36075bd5f1a183aa918d8252b79d1ea9c0315", "last_change": { - "summary": "Repointed the published schema namespace from the uncontrolled raes.dev domain to the repository-owned https://raesystem.github.io/rae/schemas/ root for issue #908.", - "content_hash": "af7ebde21bd81f5f9c1fffecb77b2a88d609a6215d6bc2e0bedc4c4c722821b3" + "summary": "Rebound the published schema namespace to the renamed OpenRAE GitHub organization for issue #963.", + "content_hash": "179badc2f0bd77a0dd6d81bd17c36075bd5f1a183aa918d8252b79d1ea9c0315" } } diff --git a/contracts/schema-publication/entries/orchestration-plan-v1.json b/contracts/schema-publication/entries/orchestration-plan-v1.json index ae86db1c1..f86ac4242 100644 --- a/contracts/schema-publication/entries/orchestration-plan-v1.json +++ b/contracts/schema-publication/entries/orchestration-plan-v1.json @@ -2,9 +2,9 @@ "contract_id": "orchestration-plan-v1", "schema_path": "contracts/schemas/plans/orchestration-plan-v1.json", "stability": "draft", - "content_hash": "97116f459eba56d281a5c6ba33c7f632f8b683379bf4e1e3b9ab933f43b7e00a", + "content_hash": "332f75d7f1e157d961c07eb5e26c8d1bfdd09abc7ee2f41e58a5b9d7384b653e", "last_change": { - "summary": "Repointed the published schema namespace from the uncontrolled raes.dev domain to the repository-owned https://raesystem.github.io/rae/schemas/ root for issue #908.", - "content_hash": "97116f459eba56d281a5c6ba33c7f632f8b683379bf4e1e3b9ab933f43b7e00a" + "summary": "Rebound the published schema namespace to the renamed OpenRAE GitHub organization for issue #963.", + "content_hash": "332f75d7f1e157d961c07eb5e26c8d1bfdd09abc7ee2f41e58a5b9d7384b653e" } } diff --git a/contracts/schema-publication/entries/participant-behavior-history-event-stream-v1.json b/contracts/schema-publication/entries/participant-behavior-history-event-stream-v1.json index 1ec9e9759..f1b4d1c67 100644 --- a/contracts/schema-publication/entries/participant-behavior-history-event-stream-v1.json +++ b/contracts/schema-publication/entries/participant-behavior-history-event-stream-v1.json @@ -2,9 +2,9 @@ "contract_id": "participant-behavior-history-event-stream-v1", "schema_path": "contracts/schemas/control-plane/participant-behavior-history-event-stream-v1.json", "stability": "draft", - "content_hash": "419b76bd47a8dc23c7d695247f74800bf5ce42d8697f2175a028e1c6cafd18b3", + "content_hash": "2ba740009f9b38803ca62cdb7df1eafe4a18eedcc96d2853713f90a890721456", "last_change": { - "summary": "Repointed the published schema namespace from the uncontrolled raes.dev domain to the repository-owned https://raesystem.github.io/rae/schemas/ root for issue #908.", - "content_hash": "419b76bd47a8dc23c7d695247f74800bf5ce42d8697f2175a028e1c6cafd18b3" + "summary": "Rebound the published schema namespace to the renamed OpenRAE GitHub organization for issue #963.", + "content_hash": "2ba740009f9b38803ca62cdb7df1eafe4a18eedcc96d2853713f90a890721456" } } diff --git a/contracts/schema-publication/entries/participant-configuration-result-v1.json b/contracts/schema-publication/entries/participant-configuration-result-v1.json index 9eb010e71..de9c858a9 100644 --- a/contracts/schema-publication/entries/participant-configuration-result-v1.json +++ b/contracts/schema-publication/entries/participant-configuration-result-v1.json @@ -2,9 +2,9 @@ "contract_id": "participant-configuration-result-v1", "schema_path": "contracts/schemas/participant-implementation-configuration/participant-configuration-result-v1.json", "stability": "draft", - "content_hash": "efb77c0b57d4c27518ffcb3af618d048cf829cb66f36a68a65a958b8033a5adb", + "content_hash": "744f485aa40a45574b8a0a4e5c1141d0edaaeb4bf97b16e4ef8bab8872e5b7d3", "last_change": { - "summary": "Repointed the published schema namespace from the uncontrolled raes.dev domain to the repository-owned https://raesystem.github.io/rae/schemas/ root for issue #908.", - "content_hash": "efb77c0b57d4c27518ffcb3af618d048cf829cb66f36a68a65a958b8033a5adb" + "summary": "Rebound the published schema namespace to the renamed OpenRAE GitHub organization for issue #963.", + "content_hash": "744f485aa40a45574b8a0a4e5c1141d0edaaeb4bf97b16e4ef8bab8872e5b7d3" } } diff --git a/contracts/schema-publication/entries/participant-context-view-v1.json b/contracts/schema-publication/entries/participant-context-view-v1.json index bce228744..32e4c8c96 100644 --- a/contracts/schema-publication/entries/participant-context-view-v1.json +++ b/contracts/schema-publication/entries/participant-context-view-v1.json @@ -2,9 +2,9 @@ "contract_id": "participant-context-view-v1", "schema_path": "contracts/schemas/control-plane/participant-context-view-v1.json", "stability": "draft", - "content_hash": "40dea81dac51eff81d69768f06ec89a82d21031e408ea97167f7631269e51c01", + "content_hash": "55dcb760c374a325496d41d3049de13db1974287dd14d3458a6e9d3c8733f962", "last_change": { - "summary": "Repointed the published schema namespace from the uncontrolled raes.dev domain to the repository-owned https://raesystem.github.io/rae/schemas/ root for issue #908.", - "content_hash": "40dea81dac51eff81d69768f06ec89a82d21031e408ea97167f7631269e51c01" + "summary": "Rebound the published schema namespace to the renamed OpenRAE GitHub organization for issue #963.", + "content_hash": "55dcb760c374a325496d41d3049de13db1974287dd14d3458a6e9d3c8733f962" } } diff --git a/contracts/schema-publication/entries/participant-control-occurrence-v1.json b/contracts/schema-publication/entries/participant-control-occurrence-v1.json index 84a772b45..f45c5d59c 100644 --- a/contracts/schema-publication/entries/participant-control-occurrence-v1.json +++ b/contracts/schema-publication/entries/participant-control-occurrence-v1.json @@ -2,9 +2,9 @@ "contract_id": "participant-control-occurrence-v1", "schema_path": "contracts/schemas/participant-runtime/participant-control-occurrence-v1.json", "stability": "draft", - "content_hash": "c0330853c6c668fa2ad22afafc968160a0d91776ccab3c4ae6a11ff4cf84d1d0", + "content_hash": "e00168614142f185eacb5128601ca956cf1f977f884346441479b5461fbb660d", "last_change": { - "summary": "Repointed the published schema namespace from the uncontrolled raes.dev domain to the repository-owned https://raesystem.github.io/rae/schemas/ root for issue #908.", - "content_hash": "c0330853c6c668fa2ad22afafc968160a0d91776ccab3c4ae6a11ff4cf84d1d0" + "summary": "Rebound the published schema namespace to the renamed OpenRAE GitHub organization for issue #963.", + "content_hash": "e00168614142f185eacb5128601ca956cf1f977f884346441479b5461fbb660d" } } diff --git a/contracts/schema-publication/entries/participant-crossing-occurrence-v1.json b/contracts/schema-publication/entries/participant-crossing-occurrence-v1.json index 086002a80..8cd8a8c31 100644 --- a/contracts/schema-publication/entries/participant-crossing-occurrence-v1.json +++ b/contracts/schema-publication/entries/participant-crossing-occurrence-v1.json @@ -2,9 +2,9 @@ "contract_id": "participant-crossing-occurrence-v1", "schema_path": "contracts/schemas/participant-runtime/participant-crossing-occurrence-v1.json", "stability": "draft", - "content_hash": "ee1e52f8a680dd74d409adff6d8a28832774c83c4338e02ef505d4b64b3deffb", + "content_hash": "c6650ca87d98bfcf6a99cdbd6340cfbc869b0ac74708812a94b79c1c5acc0c3a", "last_change": { - "summary": "Added exact policy-decision and participant-state-cut references required for RUN-319 policy resolution under #799, retaining the repository-owned schema namespace.", - "content_hash": "ee1e52f8a680dd74d409adff6d8a28832774c83c4338e02ef505d4b64b3deffb" + "summary": "Rebound the published schema namespace to the renamed OpenRAE GitHub organization for issue #963.", + "content_hash": "c6650ca87d98bfcf6a99cdbd6340cfbc869b0ac74708812a94b79c1c5acc0c3a" } } diff --git a/contracts/schema-publication/entries/participant-decision-surface-v1.json b/contracts/schema-publication/entries/participant-decision-surface-v1.json index 26f23d49e..e3a2a846b 100644 --- a/contracts/schema-publication/entries/participant-decision-surface-v1.json +++ b/contracts/schema-publication/entries/participant-decision-surface-v1.json @@ -2,9 +2,9 @@ "contract_id": "participant-decision-surface-v1", "schema_path": "contracts/schemas/control-plane/participant-decision-surface-v1.json", "stability": "draft", - "content_hash": "5bb921281db72519b486ecc4dcd90e232c39b8bf664bbe73b0c768c07c968f6d", + "content_hash": "6849f55fffcab382ea7f939004803a9a3d502b7136bc1ba377c9901ee88efb1f", "last_change": { - "summary": "Repointed the published schema namespace from the uncontrolled raes.dev domain to the repository-owned https://raesystem.github.io/rae/schemas/ root for issue #908.", - "content_hash": "5bb921281db72519b486ecc4dcd90e232c39b8bf664bbe73b0c768c07c968f6d" + "summary": "Rebound the published schema namespace to the renamed OpenRAE GitHub organization for issue #963.", + "content_hash": "6849f55fffcab382ea7f939004803a9a3d502b7136bc1ba377c9901ee88efb1f" } } diff --git a/contracts/schema-publication/entries/participant-decision-surface-v2.json b/contracts/schema-publication/entries/participant-decision-surface-v2.json index 525671436..6f7b167a6 100644 --- a/contracts/schema-publication/entries/participant-decision-surface-v2.json +++ b/contracts/schema-publication/entries/participant-decision-surface-v2.json @@ -2,9 +2,9 @@ "contract_id": "participant-decision-surface-v2", "schema_path": "contracts/schemas/control-plane/participant-decision-surface-v2.json", "stability": "draft", - "content_hash": "792bd595100d3bedcfae287391af40f6607d8d4792b434f72e28f5e74b89ea2d", + "content_hash": "108160544035735645be7fe705212c557407ff992ddc5edb3102847877edf63b", "last_change": { - "summary": "Repointed the published schema namespace from the uncontrolled raes.dev domain to the repository-owned https://raesystem.github.io/rae/schemas/ root for issue #908.", - "content_hash": "792bd595100d3bedcfae287391af40f6607d8d4792b434f72e28f5e74b89ea2d" + "summary": "Rebound the published schema namespace to the renamed OpenRAE GitHub organization for issue #963.", + "content_hash": "108160544035735645be7fe705212c557407ff992ddc5edb3102847877edf63b" } } diff --git a/contracts/schema-publication/entries/participant-episode-history-event-stream-v1.json b/contracts/schema-publication/entries/participant-episode-history-event-stream-v1.json index 9c353d32c..3e175f6db 100644 --- a/contracts/schema-publication/entries/participant-episode-history-event-stream-v1.json +++ b/contracts/schema-publication/entries/participant-episode-history-event-stream-v1.json @@ -2,9 +2,9 @@ "contract_id": "participant-episode-history-event-stream-v1", "schema_path": "contracts/schemas/control-plane/participant-episode-history-event-stream-v1.json", "stability": "draft", - "content_hash": "debb19e2d7f451e413fe16e23e2ee6f4eb37b04048f7e9409525db37af1bf2d1", + "content_hash": "bc8f14ecece576584c035320b6977bebc8223e545508b241aa8779a520894dce", "last_change": { - "summary": "Repointed the published schema namespace from the uncontrolled raes.dev domain to the repository-owned https://raesystem.github.io/rae/schemas/ root for issue #908.", - "content_hash": "debb19e2d7f451e413fe16e23e2ee6f4eb37b04048f7e9409525db37af1bf2d1" + "summary": "Rebound the published schema namespace to the renamed OpenRAE GitHub organization for issue #963.", + "content_hash": "bc8f14ecece576584c035320b6977bebc8223e545508b241aa8779a520894dce" } } diff --git a/contracts/schema-publication/entries/participant-episode-state-envelope-v1.json b/contracts/schema-publication/entries/participant-episode-state-envelope-v1.json index c9219e4e3..5811e1b5f 100644 --- a/contracts/schema-publication/entries/participant-episode-state-envelope-v1.json +++ b/contracts/schema-publication/entries/participant-episode-state-envelope-v1.json @@ -2,9 +2,9 @@ "contract_id": "participant-episode-state-envelope-v1", "schema_path": "contracts/schemas/control-plane/participant-episode-state-envelope-v1.json", "stability": "draft", - "content_hash": "63de32ef14bd0309cec32c3794e3a7c98ac926710e05e457e8f11f6612d89813", + "content_hash": "36ccb0fd9c2c67dcf620d6ecd9aef959dbd836b5aa54385908786ab63f7e8c38", "last_change": { - "summary": "Repointed the published schema namespace from the uncontrolled raes.dev domain to the repository-owned https://raesystem.github.io/rae/schemas/ root for issue #908.", - "content_hash": "63de32ef14bd0309cec32c3794e3a7c98ac926710e05e457e8f11f6612d89813" + "summary": "Rebound the published schema namespace to the renamed OpenRAE GitHub organization for issue #963.", + "content_hash": "36ccb0fd9c2c67dcf620d6ecd9aef959dbd836b5aa54385908786ab63f7e8c38" } } diff --git a/contracts/schema-publication/entries/participant-execution-binding-v1.json b/contracts/schema-publication/entries/participant-execution-binding-v1.json index 5e0f0aae4..16c2b8275 100644 --- a/contracts/schema-publication/entries/participant-execution-binding-v1.json +++ b/contracts/schema-publication/entries/participant-execution-binding-v1.json @@ -2,9 +2,9 @@ "contract_id": "participant-execution-binding-v1", "schema_path": "contracts/schemas/participant-runtime/participant-execution-binding-v1.json", "stability": "draft", - "content_hash": "94e19bb76d962427c4b1a5d86ee3c1eac2a732b1a4e78435a412331e51322bb6", + "content_hash": "19ce843b0a2dd666954abc2cad2b23ef76ad800bce4bc95d156c49b6f7424671", "last_change": { - "summary": "Repointed the published schema namespace from the uncontrolled raes.dev domain to the repository-owned https://raesystem.github.io/rae/schemas/ root for issue #908.", - "content_hash": "94e19bb76d962427c4b1a5d86ee3c1eac2a732b1a4e78435a412331e51322bb6" + "summary": "Rebound the published schema namespace to the renamed OpenRAE GitHub organization for issue #963.", + "content_hash": "19ce843b0a2dd666954abc2cad2b23ef76ad800bce4bc95d156c49b6f7424671" } } diff --git a/contracts/schema-publication/entries/participant-execution-control-v1.json b/contracts/schema-publication/entries/participant-execution-control-v1.json index 1e852e1d0..0024c7301 100644 --- a/contracts/schema-publication/entries/participant-execution-control-v1.json +++ b/contracts/schema-publication/entries/participant-execution-control-v1.json @@ -2,9 +2,9 @@ "contract_id": "participant-execution-control-v1", "schema_path": "contracts/schemas/participant-runtime/participant-execution-control-v1.json", "stability": "draft", - "content_hash": "bed3cf4d05f53154a3fb0de874a86ef7cc8da4750ed2a61e4d90784ad8e0222a", + "content_hash": "ca83abd9f00bb9b55a54b8cb5f8e80ea47f063f0ceb130d19f630c78f6b39a51", "last_change": { - "summary": "Repointed the published schema namespace from the uncontrolled raes.dev domain to the repository-owned https://raesystem.github.io/rae/schemas/ root for issue #908.", - "content_hash": "bed3cf4d05f53154a3fb0de874a86ef7cc8da4750ed2a61e4d90784ad8e0222a" + "summary": "Rebound the published schema namespace to the renamed OpenRAE GitHub organization for issue #963.", + "content_hash": "ca83abd9f00bb9b55a54b8cb5f8e80ea47f063f0ceb130d19f630c78f6b39a51" } } diff --git a/contracts/schema-publication/entries/participant-execution-service-state-v1.json b/contracts/schema-publication/entries/participant-execution-service-state-v1.json index 54916bd73..22340e862 100644 --- a/contracts/schema-publication/entries/participant-execution-service-state-v1.json +++ b/contracts/schema-publication/entries/participant-execution-service-state-v1.json @@ -2,9 +2,9 @@ "contract_id": "participant-execution-service-state-v1", "schema_path": "contracts/schemas/participant-runtime/participant-execution-service-state-v1.json", "stability": "draft", - "content_hash": "9b3a688001e9ed6473121fa8e8861ca98a245218919233ce4bf75e0b1ef7fd16", + "content_hash": "a56394b0acd4db4a1d10cc71bfe516734cc3b6b514a522baf64bcf0753069f35", "last_change": { - "summary": "Repointed the published schema namespace from the uncontrolled raes.dev domain to the repository-owned https://raesystem.github.io/rae/schemas/ root for issue #908.", - "content_hash": "9b3a688001e9ed6473121fa8e8861ca98a245218919233ce4bf75e0b1ef7fd16" + "summary": "Rebound the published schema namespace to the renamed OpenRAE GitHub organization for issue #963.", + "content_hash": "a56394b0acd4db4a1d10cc71bfe516734cc3b6b514a522baf64bcf0753069f35" } } diff --git a/contracts/schema-publication/entries/participant-history-view-v1.json b/contracts/schema-publication/entries/participant-history-view-v1.json index 9b02a221a..028d8fda7 100644 --- a/contracts/schema-publication/entries/participant-history-view-v1.json +++ b/contracts/schema-publication/entries/participant-history-view-v1.json @@ -2,9 +2,9 @@ "contract_id": "participant-history-view-v1", "schema_path": "contracts/schemas/control-plane/participant-history-view-v1.json", "stability": "draft", - "content_hash": "2eb0de43e8e48b3f6f3eeb008c8f5d3be8b3cd585f4d28b1d7974c82c66a8bc9", + "content_hash": "d396a961790f60095b6885967777405056dddd124470a06fc2455cdc48680af7", "last_change": { - "summary": "Repointed the published schema namespace from the uncontrolled raes.dev domain to the repository-owned https://raesystem.github.io/rae/schemas/ root for issue #908.", - "content_hash": "2eb0de43e8e48b3f6f3eeb008c8f5d3be8b3cd585f4d28b1d7974c82c66a8bc9" + "summary": "Rebound the published schema namespace to the renamed OpenRAE GitHub organization for issue #963.", + "content_hash": "d396a961790f60095b6885967777405056dddd124470a06fc2455cdc48680af7" } } diff --git a/contracts/schema-publication/entries/participant-implementation-manifest-v1.json b/contracts/schema-publication/entries/participant-implementation-manifest-v1.json index 32e5295a7..515c3801a 100644 --- a/contracts/schema-publication/entries/participant-implementation-manifest-v1.json +++ b/contracts/schema-publication/entries/participant-implementation-manifest-v1.json @@ -2,9 +2,9 @@ "contract_id": "participant-implementation-manifest-v1", "schema_path": "contracts/schemas/participant-implementation-manifest/participant-implementation-manifest-v1.json", "stability": "draft", - "content_hash": "b4ef963347b98da9a5542f3ebdaa612a5e9396f9d18d15aab6c7528b89b6318c", + "content_hash": "d53b16c326d9e10df9da685fcff0e89ba2803aa7fef8205004053d977fef1b21", "last_change": { - "summary": "Repointed the published schema namespace from the uncontrolled raes.dev domain to the repository-owned https://raesystem.github.io/rae/schemas/ root for issue #908.", - "content_hash": "b4ef963347b98da9a5542f3ebdaa612a5e9396f9d18d15aab6c7528b89b6318c" + "summary": "Rebound the published schema namespace to the renamed OpenRAE GitHub organization for issue #963.", + "content_hash": "d53b16c326d9e10df9da685fcff0e89ba2803aa7fef8205004053d977fef1b21" } } diff --git a/contracts/schema-publication/entries/participant-implementation-provenance-v1.json b/contracts/schema-publication/entries/participant-implementation-provenance-v1.json index b9ffb38ad..57a7d4745 100644 --- a/contracts/schema-publication/entries/participant-implementation-provenance-v1.json +++ b/contracts/schema-publication/entries/participant-implementation-provenance-v1.json @@ -2,9 +2,9 @@ "contract_id": "participant-implementation-provenance-v1", "schema_path": "contracts/schemas/participant-implementation-provenance/participant-implementation-provenance-v1.json", "stability": "draft", - "content_hash": "58a64bb2393f08a721dfd7bd429a277782a32d9131efdc89800823d5f19ba9e4", + "content_hash": "720142dc49757ec5ee28469726e99e342f286729b133ecc32da9d8cd7698155a", "last_change": { - "summary": "Repointed the published schema namespace from the uncontrolled raes.dev domain to the repository-owned https://raesystem.github.io/rae/schemas/ root for issue #908.", - "content_hash": "58a64bb2393f08a721dfd7bd429a277782a32d9131efdc89800823d5f19ba9e4" + "summary": "Rebound the published schema namespace to the renamed OpenRAE GitHub organization for issue #963.", + "content_hash": "720142dc49757ec5ee28469726e99e342f286729b133ecc32da9d8cd7698155a" } } diff --git a/contracts/schema-publication/entries/participant-joint-action-record-v1.json b/contracts/schema-publication/entries/participant-joint-action-record-v1.json index 5fc077808..91a0deb02 100644 --- a/contracts/schema-publication/entries/participant-joint-action-record-v1.json +++ b/contracts/schema-publication/entries/participant-joint-action-record-v1.json @@ -2,9 +2,9 @@ "contract_id": "participant-joint-action-record-v1", "schema_path": "contracts/schemas/participant-runtime/participant-joint-action-record-v1.json", "stability": "draft", - "content_hash": "7745b370e9d037e25c2cc8bfeb23e99a8a37a894754e02742e2e8421fcb5b8b3", + "content_hash": "6b8281a61a8876393d6ab2912bd69b43d54cee925582ea73735aa541cbfc8358", "last_change": { - "summary": "Repointed the published schema namespace from the uncontrolled raes.dev domain to the repository-owned https://raesystem.github.io/rae/schemas/ root for issue #908.", - "content_hash": "7745b370e9d037e25c2cc8bfeb23e99a8a37a894754e02742e2e8421fcb5b8b3" + "summary": "Rebound the published schema namespace to the renamed OpenRAE GitHub organization for issue #963.", + "content_hash": "6b8281a61a8876393d6ab2912bd69b43d54cee925582ea73735aa541cbfc8358" } } diff --git a/contracts/schema-publication/entries/participant-lifecycle-event-v1.json b/contracts/schema-publication/entries/participant-lifecycle-event-v1.json index a7ec4fea8..a09017b24 100644 --- a/contracts/schema-publication/entries/participant-lifecycle-event-v1.json +++ b/contracts/schema-publication/entries/participant-lifecycle-event-v1.json @@ -2,9 +2,9 @@ "contract_id": "participant-lifecycle-event-v1", "schema_path": "contracts/schemas/participant-runtime/participant-lifecycle-event-v1.json", "stability": "draft", - "content_hash": "65840259111cd740022530b80c28a67be71f65d8d4c5ed298742ce13c3fd2b28", + "content_hash": "91eff4738c9f89d43f8141146f8687bf9730e6138992a22f00abdbd553a4239a", "last_change": { - "summary": "Repointed the published schema namespace from the uncontrolled raes.dev domain to the repository-owned https://raesystem.github.io/rae/schemas/ root for issue #908.", - "content_hash": "65840259111cd740022530b80c28a67be71f65d8d4c5ed298742ce13c3fd2b28" + "summary": "Rebound the published schema namespace to the renamed OpenRAE GitHub organization for issue #963.", + "content_hash": "91eff4738c9f89d43f8141146f8687bf9730e6138992a22f00abdbd553a4239a" } } diff --git a/contracts/schema-publication/entries/participant-observation-envelope-v1.json b/contracts/schema-publication/entries/participant-observation-envelope-v1.json index 4c11badef..093088d41 100644 --- a/contracts/schema-publication/entries/participant-observation-envelope-v1.json +++ b/contracts/schema-publication/entries/participant-observation-envelope-v1.json @@ -2,9 +2,9 @@ "contract_id": "participant-observation-envelope-v1", "schema_path": "contracts/schemas/participant-runtime/participant-observation-envelope-v1.json", "stability": "draft", - "content_hash": "735f292ec936892c59e164d477aae3be1117f3e09805dddc73feb6a021699f7f", + "content_hash": "2abcc6fb611f25dd99b453b0086387ec286b75748a5e56cc97bf67b69a039542", "last_change": { - "summary": "Repointed the published schema namespace from the uncontrolled raes.dev domain to the repository-owned https://raesystem.github.io/rae/schemas/ root for issue #908.", - "content_hash": "735f292ec936892c59e164d477aae3be1117f3e09805dddc73feb6a021699f7f" + "summary": "Rebound the published schema namespace to the renamed OpenRAE GitHub organization for issue #963.", + "content_hash": "2abcc6fb611f25dd99b453b0086387ec286b75748a5e56cc97bf67b69a039542" } } diff --git a/contracts/schema-publication/entries/participant-opacity-analysis-evidence-v1.json b/contracts/schema-publication/entries/participant-opacity-analysis-evidence-v1.json index aefe50662..3b9bba547 100644 --- a/contracts/schema-publication/entries/participant-opacity-analysis-evidence-v1.json +++ b/contracts/schema-publication/entries/participant-opacity-analysis-evidence-v1.json @@ -2,9 +2,9 @@ "contract_id": "participant-opacity-analysis-evidence-v1", "schema_path": "contracts/schemas/formal-analysis/participant-opacity-analysis-evidence-v1.json", "stability": "draft", - "content_hash": "855d63d66ed6f8b6961217ec56d3ea4558ba77dcf64cd75a8da8bfcb1d3068ef", + "content_hash": "bdb61e5e125531f0b589c25b366dca480a96e6b9e7afd4bc2673c439890ce118", "last_change": { - "summary": "Published digest-bound bounded participant-opacity evidence and safe counterexamples for issue #961.", - "content_hash": "855d63d66ed6f8b6961217ec56d3ea4558ba77dcf64cd75a8da8bfcb1d3068ef" + "summary": "Rebound the published schema namespace to the renamed OpenRAE GitHub organization for issue #963.", + "content_hash": "bdb61e5e125531f0b589c25b366dca480a96e6b9e7afd4bc2673c439890ce118" } } diff --git a/contracts/schema-publication/entries/participant-opacity-analysis-input-v1.json b/contracts/schema-publication/entries/participant-opacity-analysis-input-v1.json index 305028136..78b48646e 100644 --- a/contracts/schema-publication/entries/participant-opacity-analysis-input-v1.json +++ b/contracts/schema-publication/entries/participant-opacity-analysis-input-v1.json @@ -2,9 +2,9 @@ "contract_id": "participant-opacity-analysis-input-v1", "schema_path": "contracts/schemas/formal-analysis/participant-opacity-analysis-input-v1.json", "stability": "draft", - "content_hash": "80fdff8cf1bdfa185ab67d0e8710baf727b6752279a9b3a1724f50a9f31cf368", + "content_hash": "c14950ba335a7afa0cb6087b1c10589936b7665269e7ace8664e76f5ef775d76", "last_change": { - "summary": "Published the exact finite participant-opacity analysis input contract for issue #961.", - "content_hash": "80fdff8cf1bdfa185ab67d0e8710baf727b6752279a9b3a1724f50a9f31cf368" + "summary": "Rebound the published schema namespace to the renamed OpenRAE GitHub organization for issue #963.", + "content_hash": "c14950ba335a7afa0cb6087b1c10589936b7665269e7ace8664e76f5ef775d76" } } diff --git a/contracts/schema-publication/entries/participant-opacity-model-check-evidence-v1.json b/contracts/schema-publication/entries/participant-opacity-model-check-evidence-v1.json index bfc7ce39f..8fdaf26a0 100644 --- a/contracts/schema-publication/entries/participant-opacity-model-check-evidence-v1.json +++ b/contracts/schema-publication/entries/participant-opacity-model-check-evidence-v1.json @@ -2,9 +2,9 @@ "contract_id": "participant-opacity-model-check-evidence-v1", "schema_path": "contracts/schemas/formal-analysis/participant-opacity-model-check-evidence-v1.json", "stability": "draft", - "content_hash": "ba4e3fcea965357cf8ae603d7ec018a7aee2f33b9acbb643a870275b94b8c7a0", + "content_hash": "c9e40846cd8951cbebbf733dce14ef5da1b7ffe3bcb7d0775370b07532bfb29f", "last_change": { - "summary": "Published digest-bound complete finite participant-opacity model-check evidence for issue #962.", - "content_hash": "ba4e3fcea965357cf8ae603d7ec018a7aee2f33b9acbb643a870275b94b8c7a0" + "summary": "Rebound the published schema namespace to the renamed OpenRAE GitHub organization for issue #963.", + "content_hash": "c9e40846cd8951cbebbf733dce14ef5da1b7ffe3bcb7d0775370b07532bfb29f" } } diff --git a/contracts/schema-publication/entries/participant-opacity-model-check-input-v1.json b/contracts/schema-publication/entries/participant-opacity-model-check-input-v1.json index c4a079ec2..d08b26800 100644 --- a/contracts/schema-publication/entries/participant-opacity-model-check-input-v1.json +++ b/contracts/schema-publication/entries/participant-opacity-model-check-input-v1.json @@ -2,9 +2,9 @@ "contract_id": "participant-opacity-model-check-input-v1", "schema_path": "contracts/schemas/formal-analysis/participant-opacity-model-check-input-v1.json", "stability": "draft", - "content_hash": "f1e426f063fbb44a5cb5fccdd84e4f40bf4d7178e4a579fca44f63646ce851e7", + "content_hash": "9cbcccfa27fb5f7dc51ff1f0b0929670a9a5cc883a505529796617562bdc2326", "last_change": { - "summary": "Published the exact complete finite participant-opacity transition-model contract for issue #962.", - "content_hash": "f1e426f063fbb44a5cb5fccdd84e4f40bf4d7178e4a579fca44f63646ce851e7" + "summary": "Rebound the published schema namespace to the renamed OpenRAE GitHub organization for issue #963.", + "content_hash": "9cbcccfa27fb5f7dc51ff1f0b0929670a9a5cc883a505529796617562bdc2326" } } diff --git a/contracts/schema-publication/entries/participant-outcome-report-v1.json b/contracts/schema-publication/entries/participant-outcome-report-v1.json index a62612fa2..203988109 100644 --- a/contracts/schema-publication/entries/participant-outcome-report-v1.json +++ b/contracts/schema-publication/entries/participant-outcome-report-v1.json @@ -2,9 +2,9 @@ "contract_id": "participant-outcome-report-v1", "schema_path": "contracts/schemas/participant-runtime/participant-outcome-report-v1.json", "stability": "draft", - "content_hash": "ae05f3898138241264f0a3deca8fabdd5d4336caf486fe58ad6efe0d6203dc93", + "content_hash": "73c44d864fb6f97a61924758dd3bb3bc779bdd1ab90477b9e6279b122a9fed20", "last_change": { - "summary": "Repointed the published schema namespace from the uncontrolled raes.dev domain to the repository-owned https://raesystem.github.io/rae/schemas/ root for issue #908.", - "content_hash": "ae05f3898138241264f0a3deca8fabdd5d4336caf486fe58ad6efe0d6203dc93" + "summary": "Rebound the published schema namespace to the renamed OpenRAE GitHub organization for issue #963.", + "content_hash": "73c44d864fb6f97a61924758dd3bb3bc779bdd1ab90477b9e6279b122a9fed20" } } diff --git a/contracts/schema-publication/entries/participant-resource-budget-event-v1.json b/contracts/schema-publication/entries/participant-resource-budget-event-v1.json index f30992594..7aa3bfd14 100644 --- a/contracts/schema-publication/entries/participant-resource-budget-event-v1.json +++ b/contracts/schema-publication/entries/participant-resource-budget-event-v1.json @@ -2,9 +2,9 @@ "contract_id": "participant-resource-budget-event-v1", "schema_path": "contracts/schemas/participant-runtime/participant-resource-budget-event-v1.json", "stability": "draft", - "content_hash": "c4e20416e89dd165993176df9e4c7615604335ccb6bab817607e0cb8c6e395ae", + "content_hash": "70e6c5e6add45ba3d35a76a52e67db3de7d0db1f297643cfea8087308823fc0d", "last_change": { - "summary": "Repointed the published schema namespace from the uncontrolled raes.dev domain to the repository-owned https://raesystem.github.io/rae/schemas/ root for issue #908.", - "content_hash": "c4e20416e89dd165993176df9e4c7615604335ccb6bab817607e0cb8c6e395ae" + "summary": "Rebound the published schema namespace to the renamed OpenRAE GitHub organization for issue #963.", + "content_hash": "70e6c5e6add45ba3d35a76a52e67db3de7d0db1f297643cfea8087308823fc0d" } } diff --git a/contracts/schema-publication/entries/participant-resource-budget-policy-v1.json b/contracts/schema-publication/entries/participant-resource-budget-policy-v1.json index 1116bb4e0..938527b23 100644 --- a/contracts/schema-publication/entries/participant-resource-budget-policy-v1.json +++ b/contracts/schema-publication/entries/participant-resource-budget-policy-v1.json @@ -2,9 +2,9 @@ "contract_id": "participant-resource-budget-policy-v1", "schema_path": "contracts/schemas/participant-runtime/participant-resource-budget-policy-v1.json", "stability": "draft", - "content_hash": "0d3aa2919271d566df9b8d0bb9882cc56f78b4de298c38485c7775fbb34cd574", + "content_hash": "3e01d6b28246fe7cf60f7b201c2b9fcebd869d1a3c4d8549098a6050870ee08b", "last_change": { - "summary": "Repointed the published schema namespace from the uncontrolled raes.dev domain to the repository-owned https://raesystem.github.io/rae/schemas/ root for issue #908.", - "content_hash": "0d3aa2919271d566df9b8d0bb9882cc56f78b4de298c38485c7775fbb34cd574" + "summary": "Rebound the published schema namespace to the renamed OpenRAE GitHub organization for issue #963.", + "content_hash": "3e01d6b28246fe7cf60f7b201c2b9fcebd869d1a3c4d8549098a6050870ee08b" } } diff --git a/contracts/schema-publication/entries/participant-resource-budget-state-v1.json b/contracts/schema-publication/entries/participant-resource-budget-state-v1.json index 60fde9616..52c82fb30 100644 --- a/contracts/schema-publication/entries/participant-resource-budget-state-v1.json +++ b/contracts/schema-publication/entries/participant-resource-budget-state-v1.json @@ -2,9 +2,9 @@ "contract_id": "participant-resource-budget-state-v1", "schema_path": "contracts/schemas/participant-runtime/participant-resource-budget-state-v1.json", "stability": "draft", - "content_hash": "a37fc7a7613582db22a7b3ae0c225e6643d6deab40fc22b97f389eeb28d23053", + "content_hash": "eaf22fb63b1712c919a297969624fd9b114a921f33c44c6f1cb7dce4ad9645db", "last_change": { - "summary": "Repointed the published schema namespace from the uncontrolled raes.dev domain to the repository-owned https://raesystem.github.io/rae/schemas/ root for issue #908.", - "content_hash": "a37fc7a7613582db22a7b3ae0c225e6643d6deab40fc22b97f389eeb28d23053" + "summary": "Rebound the published schema namespace to the renamed OpenRAE GitHub organization for issue #963.", + "content_hash": "eaf22fb63b1712c919a297969624fd9b114a921f33c44c6f1cb7dce4ad9645db" } } diff --git a/contracts/schema-publication/entries/participant-resource-pool-capacity-v1.json b/contracts/schema-publication/entries/participant-resource-pool-capacity-v1.json index de92269cb..89b12fd25 100644 --- a/contracts/schema-publication/entries/participant-resource-pool-capacity-v1.json +++ b/contracts/schema-publication/entries/participant-resource-pool-capacity-v1.json @@ -2,9 +2,9 @@ "contract_id": "participant-resource-pool-capacity-v1", "schema_path": "contracts/schemas/participant-runtime/participant-resource-pool-capacity-v1.json", "stability": "draft", - "content_hash": "7509b853a84876116e1261d134e83c0747321f9bc598b4dc9168790780f57e3f", + "content_hash": "b69b63eabb1e3d5cc00b70f132ec7bc2f95fec0f815012733b82420aabe99649", "last_change": { - "summary": "Repointed the published schema namespace from the uncontrolled raes.dev domain to the repository-owned https://raesystem.github.io/rae/schemas/ root for issue #908.", - "content_hash": "7509b853a84876116e1261d134e83c0747321f9bc598b4dc9168790780f57e3f" + "summary": "Rebound the published schema namespace to the renamed OpenRAE GitHub organization for issue #963.", + "content_hash": "b69b63eabb1e3d5cc00b70f132ec7bc2f95fec0f815012733b82420aabe99649" } } diff --git a/contracts/schema-publication/entries/participant-shared-state-record-v1.json b/contracts/schema-publication/entries/participant-shared-state-record-v1.json index 45d10b0e0..c69e8a06d 100644 --- a/contracts/schema-publication/entries/participant-shared-state-record-v1.json +++ b/contracts/schema-publication/entries/participant-shared-state-record-v1.json @@ -2,9 +2,9 @@ "contract_id": "participant-shared-state-record-v1", "schema_path": "contracts/schemas/participant-runtime/participant-shared-state-record-v1.json", "stability": "draft", - "content_hash": "d66c4fd7c34abc68fdd48af3cfea9b7f576c0a62cd5275c0f7305be4100b8b53", + "content_hash": "01de8873741043bc86c503ac81a6d0f9f620271eba8646d5b441575a8de5a081", "last_change": { - "summary": "Repointed the published schema namespace from the uncontrolled raes.dev domain to the repository-owned https://raesystem.github.io/rae/schemas/ root for issue #908.", - "content_hash": "d66c4fd7c34abc68fdd48af3cfea9b7f576c0a62cd5275c0f7305be4100b8b53" + "summary": "Rebound the published schema namespace to the renamed OpenRAE GitHub organization for issue #963.", + "content_hash": "01de8873741043bc86c503ac81a6d0f9f620271eba8646d5b441575a8de5a081" } } diff --git a/contracts/schema-publication/entries/participant-status-view-v1.json b/contracts/schema-publication/entries/participant-status-view-v1.json index 715dd8222..89a691906 100644 --- a/contracts/schema-publication/entries/participant-status-view-v1.json +++ b/contracts/schema-publication/entries/participant-status-view-v1.json @@ -2,9 +2,9 @@ "contract_id": "participant-status-view-v1", "schema_path": "contracts/schemas/control-plane/participant-status-view-v1.json", "stability": "draft", - "content_hash": "1550d4f8c8d438b5a9efa4e41c09663d1f586698084312b89a63500f4185b7a1", + "content_hash": "8e50a817b2ccbab2bf6c760982b2f1c9708397f30843a1ddda35adca99d86581", "last_change": { - "summary": "Repointed the published schema namespace from the uncontrolled raes.dev domain to the repository-owned https://raesystem.github.io/rae/schemas/ root for issue #908.", - "content_hash": "1550d4f8c8d438b5a9efa4e41c09663d1f586698084312b89a63500f4185b7a1" + "summary": "Rebound the published schema namespace to the renamed OpenRAE GitHub organization for issue #963.", + "content_hash": "8e50a817b2ccbab2bf6c760982b2f1c9708397f30843a1ddda35adca99d86581" } } diff --git a/contracts/schema-publication/entries/participant-time-management-context-v1.json b/contracts/schema-publication/entries/participant-time-management-context-v1.json index 9b9315adc..fc5d6d174 100644 --- a/contracts/schema-publication/entries/participant-time-management-context-v1.json +++ b/contracts/schema-publication/entries/participant-time-management-context-v1.json @@ -2,9 +2,9 @@ "contract_id": "participant-time-management-context-v1", "schema_path": "contracts/schemas/participant-runtime/participant-time-management-context-v1.json", "stability": "draft", - "content_hash": "39389146e500fcbdde8518c4256e4825eb4592c3cb7cd59a006feb5304ad3d69", + "content_hash": "6f03ae716d6d5bb42a576ffb05a1a172445ca70501ecc36e004c3884e5264a87", "last_change": { - "summary": "Repointed the published schema namespace from the uncontrolled raes.dev domain to the repository-owned https://raesystem.github.io/rae/schemas/ root for issue #908.", - "content_hash": "39389146e500fcbdde8518c4256e4825eb4592c3cb7cd59a006feb5304ad3d69" + "summary": "Rebound the published schema namespace to the renamed OpenRAE GitHub organization for issue #963.", + "content_hash": "6f03ae716d6d5bb42a576ffb05a1a172445ca70501ecc36e004c3884e5264a87" } } diff --git a/contracts/schema-publication/entries/processor-manifest-v2.json b/contracts/schema-publication/entries/processor-manifest-v2.json index 812942b94..aeaa68c50 100644 --- a/contracts/schema-publication/entries/processor-manifest-v2.json +++ b/contracts/schema-publication/entries/processor-manifest-v2.json @@ -2,9 +2,9 @@ "contract_id": "processor-manifest-v2", "schema_path": "contracts/schemas/processor-manifest/processor-manifest-v2.json", "stability": "draft", - "content_hash": "35278440a89aee708a6527b5e66bc14c3ad200491ba121dd0b48bb9a03ce52d8", + "content_hash": "1a8d6709761778f672860d49c2d2fa53810e83e5a87998d05f6ceeae1c1379ec", "last_change": { - "summary": "Repointed the published schema namespace from the uncontrolled raes.dev domain to the repository-owned https://raesystem.github.io/rae/schemas/ root for issue #908.", - "content_hash": "35278440a89aee708a6527b5e66bc14c3ad200491ba121dd0b48bb9a03ce52d8" + "summary": "Rebound the published schema namespace to the renamed OpenRAE GitHub organization for issue #963.", + "content_hash": "1a8d6709761778f672860d49c2d2fa53810e83e5a87998d05f6ceeae1c1379ec" } } diff --git a/contracts/schema-publication/entries/proposition-truth-result-v1.json b/contracts/schema-publication/entries/proposition-truth-result-v1.json index 60181b4df..af3307b86 100644 --- a/contracts/schema-publication/entries/proposition-truth-result-v1.json +++ b/contracts/schema-publication/entries/proposition-truth-result-v1.json @@ -2,9 +2,9 @@ "contract_id": "proposition-truth-result-v1", "schema_path": "contracts/schemas/control-plane/proposition-truth-result-v1.json", "stability": "draft", - "content_hash": "25f6100c931dcd7e7eeace7f3900763cd9f283987be542f81d8b11beb601cae4", + "content_hash": "92d5321097fe05fda818bc16fceb6f1c7971baebd9dc5b71366f577204654c8a", "last_change": { - "summary": "Repointed the published schema namespace from the uncontrolled raes.dev domain to the repository-owned https://raesystem.github.io/rae/schemas/ root for issue #908.", - "content_hash": "25f6100c931dcd7e7eeace7f3900763cd9f283987be542f81d8b11beb601cae4" + "summary": "Rebound the published schema namespace to the renamed OpenRAE GitHub organization for issue #963.", + "content_hash": "92d5321097fe05fda818bc16fceb6f1c7971baebd9dc5b71366f577204654c8a" } } diff --git a/contracts/schema-publication/entries/provisioning-plan-v1.json b/contracts/schema-publication/entries/provisioning-plan-v1.json index 6ce732a2a..b800c2b82 100644 --- a/contracts/schema-publication/entries/provisioning-plan-v1.json +++ b/contracts/schema-publication/entries/provisioning-plan-v1.json @@ -2,9 +2,9 @@ "contract_id": "provisioning-plan-v1", "schema_path": "contracts/schemas/plans/provisioning-plan-v1.json", "stability": "draft", - "content_hash": "d4e85ac33f2f2add86c240c617a0d291404604cb3c8631dded6ea0ee766dd487", + "content_hash": "1bdc518fe38af9ea2d94f06793a103a660475a51cded7e7506c4760137279933", "last_change": { - "summary": "Repointed the published schema namespace from the uncontrolled raes.dev domain to the repository-owned https://raesystem.github.io/rae/schemas/ root for issue #908.", - "content_hash": "d4e85ac33f2f2add86c240c617a0d291404604cb3c8631dded6ea0ee766dd487" + "summary": "Rebound the published schema namespace to the renamed OpenRAE GitHub organization for issue #963.", + "content_hash": "1bdc518fe38af9ea2d94f06793a103a660475a51cded7e7506c4760137279933" } } diff --git a/contracts/schema-publication/entries/raes-semantic-invariants-v1.json b/contracts/schema-publication/entries/raes-semantic-invariants-v1.json index 760e91026..270a74563 100644 --- a/contracts/schema-publication/entries/raes-semantic-invariants-v1.json +++ b/contracts/schema-publication/entries/raes-semantic-invariants-v1.json @@ -2,9 +2,9 @@ "contract_id": "raes-semantic-invariants-v1", "schema_path": "contracts/schemas/profiles/raes-semantic-invariants-v1.json", "stability": "draft", - "content_hash": "7af5c717c62c9780ea8b6042f0bb5642c04e2b84aee03ce1b3dca5f36823d14b", + "content_hash": "ca5215479a7e87ad3218d96c06f8a3ebb5cac1b520c1df27d3f68f86dca4c91d", "last_change": { - "summary": "Repointed the published schema namespace from the uncontrolled raes.dev domain to the repository-owned https://raesystem.github.io/rae/schemas/ root for issue #908.", - "content_hash": "7af5c717c62c9780ea8b6042f0bb5642c04e2b84aee03ce1b3dca5f36823d14b" + "summary": "Rebound the published schema namespace to the renamed OpenRAE GitHub organization for issue #963.", + "content_hash": "ca5215479a7e87ad3218d96c06f8a3ebb5cac1b520c1df27d3f68f86dca4c91d" } } diff --git a/contracts/schema-publication/entries/random-stream-profile-v1.json b/contracts/schema-publication/entries/random-stream-profile-v1.json index 77019219b..e187539a7 100644 --- a/contracts/schema-publication/entries/random-stream-profile-v1.json +++ b/contracts/schema-publication/entries/random-stream-profile-v1.json @@ -2,9 +2,9 @@ "contract_id": "random-stream-profile-v1", "schema_path": "contracts/schemas/profiles/random-stream-profile-v1.json", "stability": "draft", - "content_hash": "f594185a8db1f8320822089b90649fed6d4175285da232484bc225d2e60775c1", + "content_hash": "7eddad732d06e27ae7b6d874002cf544a3ac7206affbacf5c7ce30e8861e02de", "last_change": { - "summary": "Repointed the published schema namespace from the uncontrolled raes.dev domain to the repository-owned https://raesystem.github.io/rae/schemas/ root for issue #908.", - "content_hash": "f594185a8db1f8320822089b90649fed6d4175285da232484bc225d2e60775c1" + "summary": "Rebound the published schema namespace to the renamed OpenRAE GitHub organization for issue #963.", + "content_hash": "7eddad732d06e27ae7b6d874002cf544a3ac7206affbacf5c7ce30e8861e02de" } } diff --git a/contracts/schema-publication/entries/random-stream-vector-v1.json b/contracts/schema-publication/entries/random-stream-vector-v1.json index 253f8d319..12db002f9 100644 --- a/contracts/schema-publication/entries/random-stream-vector-v1.json +++ b/contracts/schema-publication/entries/random-stream-vector-v1.json @@ -2,9 +2,9 @@ "contract_id": "random-stream-vector-v1", "schema_path": "contracts/schemas/profiles/random-stream-vector-v1.json", "stability": "draft", - "content_hash": "65e838472c5d1ac7a0eb2ffa4bfe6f3a756c77d776158c6dba8510e2edbc9001", + "content_hash": "ad3da3c814fcafeb9d523858286fd80682c7df00a8e82961f1b6c5ba2f80f005", "last_change": { - "summary": "Repointed the published schema namespace from the uncontrolled raes.dev domain to the repository-owned https://raesystem.github.io/rae/schemas/ root for issue #908.", - "content_hash": "65e838472c5d1ac7a0eb2ffa4bfe6f3a756c77d776158c6dba8510e2edbc9001" + "summary": "Rebound the published schema namespace to the renamed OpenRAE GitHub organization for issue #963.", + "content_hash": "ad3da3c814fcafeb9d523858286fd80682c7df00a8e82961f1b6c5ba2f80f005" } } diff --git a/contracts/schema-publication/entries/realization-envelope-v1.json b/contracts/schema-publication/entries/realization-envelope-v1.json index a041ffecd..5ca4c31e9 100644 --- a/contracts/schema-publication/entries/realization-envelope-v1.json +++ b/contracts/schema-publication/entries/realization-envelope-v1.json @@ -2,9 +2,9 @@ "contract_id": "realization-envelope-v1", "schema_path": "contracts/schemas/realization-envelope/realization-envelope-v1.json", "stability": "draft", - "content_hash": "1f54cfaf7288a61890972527dc44415924c8590a1d40795bea13f8cd0cf1e878", + "content_hash": "dbce12f46023384e10b86b62a6d6b5238ccf1b38dbf0be70704cb6d688cca31d", "last_change": { - "summary": "Repointed the published schema namespace from the uncontrolled raes.dev domain to the repository-owned https://raesystem.github.io/rae/schemas/ root for issue #908.", - "content_hash": "1f54cfaf7288a61890972527dc44415924c8590a1d40795bea13f8cd0cf1e878" + "summary": "Rebound the published schema namespace to the renamed OpenRAE GitHub organization for issue #963.", + "content_hash": "dbce12f46023384e10b86b62a6d6b5238ccf1b38dbf0be70704cb6d688cca31d" } } diff --git a/contracts/schema-publication/entries/realized-time-model-v1.json b/contracts/schema-publication/entries/realized-time-model-v1.json index f5be7d129..e4e8a16cf 100644 --- a/contracts/schema-publication/entries/realized-time-model-v1.json +++ b/contracts/schema-publication/entries/realized-time-model-v1.json @@ -2,9 +2,9 @@ "contract_id": "realized-time-model-v1", "schema_path": "contracts/schemas/time/realized-time-model-v1.json", "stability": "draft", - "content_hash": "3ce01b4927e0975c48d7398c013ab5624bf6d74dbc04b259d8a9529fd44cca48", + "content_hash": "d5822fd84769f2e0596881b8a01eb0bb6ba38461ca24557e68412c382c8015c5", "last_change": { - "summary": "Repointed the published schema namespace from the uncontrolled raes.dev domain to the repository-owned https://raesystem.github.io/rae/schemas/ root for issue #908.", - "content_hash": "3ce01b4927e0975c48d7398c013ab5624bf6d74dbc04b259d8a9529fd44cca48" + "summary": "Rebound the published schema namespace to the renamed OpenRAE GitHub organization for issue #963.", + "content_hash": "d5822fd84769f2e0596881b8a01eb0bb6ba38461ca24557e68412c382c8015c5" } } diff --git a/contracts/schema-publication/entries/reference-models-v1.json b/contracts/schema-publication/entries/reference-models-v1.json index 943993c6a..c76ffa22e 100644 --- a/contracts/schema-publication/entries/reference-models-v1.json +++ b/contracts/schema-publication/entries/reference-models-v1.json @@ -2,9 +2,9 @@ "contract_id": "reference-models-v1", "schema_path": "contracts/schemas/concept-authority/reference-models-v1.json", "stability": "draft", - "content_hash": "6b379f9203be74259f1905e3ff13c25bb3125a04eba9dcc6bafedea40d50e416", + "content_hash": "c997969ad2aae1392b399532b63e6b7fd981827aa597d0a836a1a6b60cbc1b2e", "last_change": { - "summary": "Repointed the published schema namespace from the uncontrolled raes.dev domain to the repository-owned https://raesystem.github.io/rae/schemas/ root for issue #908.", - "content_hash": "6b379f9203be74259f1905e3ff13c25bb3125a04eba9dcc6bafedea40d50e416" + "summary": "Rebound the published schema namespace to the renamed OpenRAE GitHub organization for issue #963.", + "content_hash": "c997969ad2aae1392b399532b63e6b7fd981827aa597d0a836a1a6b60cbc1b2e" } } diff --git a/contracts/schema-publication/entries/reusable-asset-trust-policy-v1.json b/contracts/schema-publication/entries/reusable-asset-trust-policy-v1.json index 9eebdac93..c33407703 100644 --- a/contracts/schema-publication/entries/reusable-asset-trust-policy-v1.json +++ b/contracts/schema-publication/entries/reusable-asset-trust-policy-v1.json @@ -2,9 +2,9 @@ "contract_id": "reusable-asset-trust-policy-v1", "schema_path": "contracts/schemas/asset-trust/reusable-asset-trust-policy-v1.json", "stability": "draft", - "content_hash": "8283ffb71a4739e30c9a88ebb8ab90efa8854aa40b58e95e123bc83f54c858b5", + "content_hash": "a86a72892a1a15711bf48fad7da3e46feea71dc13775d61df0c74d84c26d140a", "last_change": { - "summary": "Repointed the published schema namespace from the uncontrolled raes.dev domain to the repository-owned https://raesystem.github.io/rae/schemas/ root for issue #908.", - "content_hash": "8283ffb71a4739e30c9a88ebb8ab90efa8854aa40b58e95e123bc83f54c858b5" + "summary": "Rebound the published schema namespace to the renamed OpenRAE GitHub organization for issue #963.", + "content_hash": "a86a72892a1a15711bf48fad7da3e46feea71dc13775d61df0c74d84c26d140a" } } diff --git a/contracts/schema-publication/entries/runtime-fact-binding-plane-v1.json b/contracts/schema-publication/entries/runtime-fact-binding-plane-v1.json index 41251a382..4c176808a 100644 --- a/contracts/schema-publication/entries/runtime-fact-binding-plane-v1.json +++ b/contracts/schema-publication/entries/runtime-fact-binding-plane-v1.json @@ -2,9 +2,9 @@ "contract_id": "runtime-fact-binding-plane-v1", "schema_path": "contracts/schemas/participant-runtime/runtime-fact-binding-plane-v1.json", "stability": "draft", - "content_hash": "ee6c288abf762b601ca0b181a6df5797f172dcff2b7bd5713edfe06f7aedbb4a", + "content_hash": "b9caac5ba2595f7874e99354fab676f23dd19a1735ccac4b31b4ee5650dc103a", "last_change": { - "summary": "Repointed the published schema namespace from the uncontrolled raes.dev domain to the repository-owned https://raesystem.github.io/rae/schemas/ root for issue #908.", - "content_hash": "ee6c288abf762b601ca0b181a6df5797f172dcff2b7bd5713edfe06f7aedbb4a" + "summary": "Rebound the published schema namespace to the renamed OpenRAE GitHub organization for issue #963.", + "content_hash": "b9caac5ba2595f7874e99354fab676f23dd19a1735ccac4b31b4ee5650dc103a" } } diff --git a/contracts/schema-publication/entries/runtime-snapshot-v1.json b/contracts/schema-publication/entries/runtime-snapshot-v1.json index 7105ad078..21a8643c1 100644 --- a/contracts/schema-publication/entries/runtime-snapshot-v1.json +++ b/contracts/schema-publication/entries/runtime-snapshot-v1.json @@ -2,9 +2,9 @@ "contract_id": "runtime-snapshot-v1", "schema_path": "contracts/schemas/snapshots/runtime-snapshot-v1.json", "stability": "draft", - "content_hash": "e6b06f8859f4343fd77803f5c92ffdae2c7d163137ee5348fa4ab914f1e927c2", + "content_hash": "81ad3650fab82ddcecc17f9905319243605d3b64168f12cff75e4890c0180018", "last_change": { - "summary": "Added first-class append-only participant crossing history for RUN-319 enforcement evidence under #799, retaining the repository-owned schema namespace.", - "content_hash": "e6b06f8859f4343fd77803f5c92ffdae2c7d163137ee5348fa4ab914f1e927c2" + "summary": "Rebound the published schema namespace to the renamed OpenRAE GitHub organization for issue #963.", + "content_hash": "81ad3650fab82ddcecc17f9905319243605d3b64168f12cff75e4890c0180018" } } diff --git a/contracts/schema-publication/entries/scenario-instantiation-request-v1.json b/contracts/schema-publication/entries/scenario-instantiation-request-v1.json index 5df9437ab..aaaf624aa 100644 --- a/contracts/schema-publication/entries/scenario-instantiation-request-v1.json +++ b/contracts/schema-publication/entries/scenario-instantiation-request-v1.json @@ -2,9 +2,9 @@ "contract_id": "scenario-instantiation-request-v1", "schema_path": "contracts/schemas/sdl/scenario-instantiation-request-v1.json", "stability": "draft", - "content_hash": "f008fbdab7624d288c38fe9e142d24eb55c34cc390032cab35cb0c30344d9e04", + "content_hash": "5e8ba1584177eaa21cb42856b9611e7aa800282808ad17e2bbcf22377349252e", "last_change": { - "summary": "Repointed the published schema namespace from the uncontrolled raes.dev domain to the repository-owned https://raesystem.github.io/rae/schemas/ root for issue #908.", - "content_hash": "f008fbdab7624d288c38fe9e142d24eb55c34cc390032cab35cb0c30344d9e04" + "summary": "Rebound the published schema namespace to the renamed OpenRAE GitHub organization for issue #963.", + "content_hash": "5e8ba1584177eaa21cb42856b9611e7aa800282808ad17e2bbcf22377349252e" } } diff --git a/contracts/schema-publication/entries/scenario-satisfiability-evidence-v1.json b/contracts/schema-publication/entries/scenario-satisfiability-evidence-v1.json index 9d50f76e4..422ea3fcf 100644 --- a/contracts/schema-publication/entries/scenario-satisfiability-evidence-v1.json +++ b/contracts/schema-publication/entries/scenario-satisfiability-evidence-v1.json @@ -2,9 +2,9 @@ "contract_id": "scenario-satisfiability-evidence-v1", "schema_path": "contracts/schemas/satisfiability/scenario-satisfiability-evidence-v1.json", "stability": "draft", - "content_hash": "2d0299274877012fc2c3a3e65d3d22a2e7d2992454697248a2b2e48759676973", + "content_hash": "6e0c1ee6fb1752832a07c220d6762dfbdfd71d39effe38bc2e44ea0c0d3b8e7c", "last_change": { - "summary": "Integrated admitted trial provenance with composable platform capability schema updates for issues #790 and #956.", - "content_hash": "2d0299274877012fc2c3a3e65d3d22a2e7d2992454697248a2b2e48759676973" + "summary": "Added the service search-index field-schema profile and rebound the namespace to OpenRAE for issues #1011 and #963.", + "content_hash": "6e0c1ee6fb1752832a07c220d6762dfbdfd71d39effe38bc2e44ea0c0d3b8e7c" } } diff --git a/contracts/schema-publication/entries/scheduler-isolation-proof-v1.json b/contracts/schema-publication/entries/scheduler-isolation-proof-v1.json index b9e76cfd4..46b72bfe0 100644 --- a/contracts/schema-publication/entries/scheduler-isolation-proof-v1.json +++ b/contracts/schema-publication/entries/scheduler-isolation-proof-v1.json @@ -2,9 +2,9 @@ "contract_id": "scheduler-isolation-proof-v1", "schema_path": "contracts/schemas/control-plane/scheduler-isolation-proof-v1.json", "stability": "draft", - "content_hash": "f572f0747a2e47026c9d0fa74425235d26b684a10d098482657071866dd496d8", + "content_hash": "0534bb270b55f618d3a8272d0356fa79a6e25adfd68eab7107cafb865f406f1b", "last_change": { - "summary": "Added the governed secret-scope isolation dimension so a bounded-parallelism proof can carry secret-resolution isolation evidence required by SCE-006 (issue #785).", - "content_hash": "f572f0747a2e47026c9d0fa74425235d26b684a10d098482657071866dd496d8" + "summary": "Rebound the published schema namespace to the renamed OpenRAE GitHub organization for issue #963.", + "content_hash": "0534bb270b55f618d3a8272d0356fa79a6e25adfd68eab7107cafb865f406f1b" } } diff --git a/contracts/schema-publication/entries/scientific-completeness-assessment-v1.json b/contracts/schema-publication/entries/scientific-completeness-assessment-v1.json index 37090f666..8ca3b1496 100644 --- a/contracts/schema-publication/entries/scientific-completeness-assessment-v1.json +++ b/contracts/schema-publication/entries/scientific-completeness-assessment-v1.json @@ -2,9 +2,9 @@ "contract_id": "scientific-completeness-assessment-v1", "schema_path": "contracts/schemas/profiles/scientific-completeness-assessment-v1.json", "stability": "draft", - "content_hash": "5db146299d691116e445bed420387e0a221801194c4deabbdd50f022ff7de5ac", + "content_hash": "4165331737bbe090d56bbc790ed76b774a39af9564be58bc2c5d2eb1c15ca804", "last_change": { - "summary": "Repointed the published schema namespace from the uncontrolled raes.dev domain to the repository-owned https://raesystem.github.io/rae/schemas/ root for issue #908.", - "content_hash": "5db146299d691116e445bed420387e0a221801194c4deabbdd50f022ff7de5ac" + "summary": "Rebound the published schema namespace to the renamed OpenRAE GitHub organization for issue #963.", + "content_hash": "4165331737bbe090d56bbc790ed76b774a39af9564be58bc2c5d2eb1c15ca804" } } diff --git a/contracts/schema-publication/entries/scientific-completeness-taxonomy-v1.json b/contracts/schema-publication/entries/scientific-completeness-taxonomy-v1.json index 1b4837a60..1db3b8bbf 100644 --- a/contracts/schema-publication/entries/scientific-completeness-taxonomy-v1.json +++ b/contracts/schema-publication/entries/scientific-completeness-taxonomy-v1.json @@ -2,9 +2,9 @@ "contract_id": "scientific-completeness-taxonomy-v1", "schema_path": "contracts/schemas/profiles/scientific-completeness-taxonomy-v1.json", "stability": "draft", - "content_hash": "97b2632026044434a0aaacec6b45e6cfe7a5bc445d83e0c57bb5a589745495b2", + "content_hash": "63ef8ca42883cbf6244850f77e408a7d8de1687ced49831e6ccf376ef1e3f1fa", "last_change": { - "summary": "Published the shared relation-parameter profile and assurance-axis claim-binding coordinates for issue #810.", - "content_hash": "97b2632026044434a0aaacec6b45e6cfe7a5bc445d83e0c57bb5a589745495b2" + "summary": "Rebound the published schema namespace to the renamed OpenRAE GitHub organization for issue #963.", + "content_hash": "63ef8ca42883cbf6244850f77e408a7d8de1687ced49831e6ccf376ef1e3f1fa" } } diff --git a/contracts/schema-publication/entries/sdl-authoring-input-v1.json b/contracts/schema-publication/entries/sdl-authoring-input-v1.json index 42c1fd1c4..245700fe1 100644 --- a/contracts/schema-publication/entries/sdl-authoring-input-v1.json +++ b/contracts/schema-publication/entries/sdl-authoring-input-v1.json @@ -2,9 +2,9 @@ "contract_id": "sdl-authoring-input-v1", "schema_path": "contracts/schemas/sdl/sdl-authoring-input-v1.json", "stability": "draft", - "content_hash": "d4594b2c04283d95378faec2f64343870e8756f09a5a04a8746c6d8ccd56a270", + "content_hash": "74b3e5310b2368e0463bae298b153fc5d7311b0a421df9559259374411540e28", "last_change": { - "summary": "Added composable provider-neutral platform capabilities and marked legacy platform categories and content manifests deprecated for issue #956.", - "content_hash": "d4594b2c04283d95378faec2f64343870e8756f09a5a04a8746c6d8ccd56a270" + "summary": "Added the service search-index field-schema profile and rebound the namespace to OpenRAE for issues #1011 and #963.", + "content_hash": "74b3e5310b2368e0463bae298b153fc5d7311b0a421df9559259374411540e28" } } diff --git a/contracts/schema-publication/entries/sdl-lineage-ledger-v1.json b/contracts/schema-publication/entries/sdl-lineage-ledger-v1.json index 89059a08d..2026f10e2 100644 --- a/contracts/schema-publication/entries/sdl-lineage-ledger-v1.json +++ b/contracts/schema-publication/entries/sdl-lineage-ledger-v1.json @@ -2,9 +2,9 @@ "contract_id": "sdl-lineage-ledger-v1", "schema_path": "contracts/schemas/provenance/sdl-lineage-ledger-v1.json", "stability": "draft", - "content_hash": "6cb6ee30ebe8e6744a750eedf04cd8eb53df0047a535e3575e77e71203bf7ca7", + "content_hash": "c6ac7371ff690f3ca72db81c42f7a5d2896735bf2fa6db037a814a30b0d08b10", "last_change": { - "summary": "Repointed the published schema namespace from the uncontrolled raes.dev domain to the repository-owned https://raesystem.github.io/rae/schemas/ root for issue #908.", - "content_hash": "6cb6ee30ebe8e6744a750eedf04cd8eb53df0047a535e3575e77e71203bf7ca7" + "summary": "Rebound the published schema namespace to the renamed OpenRAE GitHub organization for issue #963.", + "content_hash": "c6ac7371ff690f3ca72db81c42f7a5d2896735bf2fa6db037a814a30b0d08b10" } } diff --git a/contracts/schema-publication/entries/semantic-profile-v1.json b/contracts/schema-publication/entries/semantic-profile-v1.json index 161fb31bb..870f03f89 100644 --- a/contracts/schema-publication/entries/semantic-profile-v1.json +++ b/contracts/schema-publication/entries/semantic-profile-v1.json @@ -2,9 +2,9 @@ "contract_id": "semantic-profile-v1", "schema_path": "contracts/schemas/profiles/semantic-profile-v1.json", "stability": "draft", - "content_hash": "0c9cb1ea7a9e0aa061e2fd133b270f088dbf451520c02baf7133fa5568260568", + "content_hash": "b531d2cf60f0ee4ffb6f84a7fa6b7cc96b076260043826d03f932554294e325b", "last_change": { - "summary": "Repointed the published schema namespace from the uncontrolled raes.dev domain to the repository-owned https://raesystem.github.io/rae/schemas/ root for issue #908.", - "content_hash": "0c9cb1ea7a9e0aa061e2fd133b270f088dbf451520c02baf7133fa5568260568" + "summary": "Rebound the published schema namespace to the renamed OpenRAE GitHub organization for issue #963.", + "content_hash": "b531d2cf60f0ee4ffb6f84a7fa6b7cc96b076260043826d03f932554294e325b" } } diff --git a/contracts/schema-publication/entries/time-model-v1.json b/contracts/schema-publication/entries/time-model-v1.json index 9a21fd75b..9fc9ec3fc 100644 --- a/contracts/schema-publication/entries/time-model-v1.json +++ b/contracts/schema-publication/entries/time-model-v1.json @@ -2,9 +2,9 @@ "contract_id": "time-model-v1", "schema_path": "contracts/schemas/time/time-model-v1.json", "stability": "draft", - "content_hash": "09d8427a8ec52e44c9d078ba3de889b0fed8812ef0a509ab8a462668d3d6d8cd", + "content_hash": "8f841395f73353187ce02675013f845f21ece360ee68cba22ce9b07968e635a5", "last_change": { - "summary": "Repointed the published schema namespace from the uncontrolled raes.dev domain to the repository-owned https://raesystem.github.io/rae/schemas/ root for issue #908.", - "content_hash": "09d8427a8ec52e44c9d078ba3de889b0fed8812ef0a509ab8a462668d3d6d8cd" + "summary": "Rebound the published schema namespace to the renamed OpenRAE GitHub organization for issue #963.", + "content_hash": "8f841395f73353187ce02675013f845f21ece360ee68cba22ce9b07968e635a5" } } diff --git a/contracts/schema-publication/entries/time-runtime-state-v1.json b/contracts/schema-publication/entries/time-runtime-state-v1.json index 8cb25ff26..5cbc5ffd6 100644 --- a/contracts/schema-publication/entries/time-runtime-state-v1.json +++ b/contracts/schema-publication/entries/time-runtime-state-v1.json @@ -2,9 +2,9 @@ "contract_id": "time-runtime-state-v1", "schema_path": "contracts/schemas/time/time-runtime-state-v1.json", "stability": "draft", - "content_hash": "a5806e28394dc8722100f3cc6277e8f3ccbcc943724824f204fcfed1f2413bd3", + "content_hash": "87649655830e48eadd8151b2da4fa7e8f20a46261a141ab626fc77cb5f4172db", "last_change": { - "summary": "Repointed the published schema namespace from the uncontrolled raes.dev domain to the repository-owned https://raesystem.github.io/rae/schemas/ root for issue #908.", - "content_hash": "a5806e28394dc8722100f3cc6277e8f3ccbcc943724824f204fcfed1f2413bd3" + "summary": "Rebound the published schema namespace to the renamed OpenRAE GitHub organization for issue #963.", + "content_hash": "87649655830e48eadd8151b2da4fa7e8f20a46261a141ab626fc77cb5f4172db" } } diff --git a/contracts/schema-publication/entries/trial-cleanup-plan-v1.json b/contracts/schema-publication/entries/trial-cleanup-plan-v1.json index f4737558a..8d54e21e4 100644 --- a/contracts/schema-publication/entries/trial-cleanup-plan-v1.json +++ b/contracts/schema-publication/entries/trial-cleanup-plan-v1.json @@ -2,9 +2,9 @@ "contract_id": "trial-cleanup-plan-v1", "schema_path": "contracts/schemas/plans/trial-cleanup-plan-v1.json", "stability": "draft", - "content_hash": "79f389e54ad2ba55824d5311db65b59ea9cf33e92271dafcdc89ccefac0f9cd3", + "content_hash": "4425b10f5acf68c364bc35d94d06739ad7ad168419ec0c19d97f603bd5870ab6", "last_change": { - "summary": "Repointed the published schema namespace from the uncontrolled raes.dev domain to the repository-owned https://raesystem.github.io/rae/schemas/ root for issue #908.", - "content_hash": "79f389e54ad2ba55824d5311db65b59ea9cf33e92271dafcdc89ccefac0f9cd3" + "summary": "Rebound the published schema namespace to the renamed OpenRAE GitHub organization for issue #963.", + "content_hash": "4425b10f5acf68c364bc35d94d06739ad7ad168419ec0c19d97f603bd5870ab6" } } diff --git a/contracts/schema-publication/entries/trial-cleanup-receipt-v1.json b/contracts/schema-publication/entries/trial-cleanup-receipt-v1.json index 082155360..cadcbf23c 100644 --- a/contracts/schema-publication/entries/trial-cleanup-receipt-v1.json +++ b/contracts/schema-publication/entries/trial-cleanup-receipt-v1.json @@ -2,9 +2,9 @@ "contract_id": "trial-cleanup-receipt-v1", "schema_path": "contracts/schemas/control-plane/trial-cleanup-receipt-v1.json", "stability": "draft", - "content_hash": "40bc6caaf772ef401160a6c61cee0da6b44a076eefd1d7e84af54736e1302e95", + "content_hash": "02522db170307754b01a96fac73808a23acacbf56aae3b93c441fa211075c227", "last_change": { - "summary": "Repointed the published schema namespace from the uncontrolled raes.dev domain to the repository-owned https://raesystem.github.io/rae/schemas/ root for issue #908.", - "content_hash": "40bc6caaf772ef401160a6c61cee0da6b44a076eefd1d7e84af54736e1302e95" + "summary": "Rebound the published schema namespace to the renamed OpenRAE GitHub organization for issue #963.", + "content_hash": "02522db170307754b01a96fac73808a23acacbf56aae3b93c441fa211075c227" } } diff --git a/contracts/schema-publication/entries/uco-alignment-v1.json b/contracts/schema-publication/entries/uco-alignment-v1.json index 765e396c0..5fa712aaf 100644 --- a/contracts/schema-publication/entries/uco-alignment-v1.json +++ b/contracts/schema-publication/entries/uco-alignment-v1.json @@ -2,9 +2,9 @@ "contract_id": "uco-alignment-v1", "schema_path": "contracts/schemas/concept-authority/uco-alignment-v1.json", "stability": "draft", - "content_hash": "84b03b7be0fcb301324d53389c39e44d61e4c59a20bd8a387db68ebafcc7ef98", + "content_hash": "67fbb696bc509597e1ecb855544789407149799398279bec5654e2943c5446b0", "last_change": { - "summary": "Repointed the published schema namespace from the uncontrolled raes.dev domain to the repository-owned https://raesystem.github.io/rae/schemas/ root for issue #908.", - "content_hash": "84b03b7be0fcb301324d53389c39e44d61e4c59a20bd8a387db68ebafcc7ef98" + "summary": "Rebound the published schema namespace to the renamed OpenRAE GitHub organization for issue #963.", + "content_hash": "67fbb696bc509597e1ecb855544789407149799398279bec5654e2943c5446b0" } } diff --git a/contracts/schema-publication/entries/validation-basis-disclosure-v1.json b/contracts/schema-publication/entries/validation-basis-disclosure-v1.json index 36ecbc0d7..837dfd5f8 100644 --- a/contracts/schema-publication/entries/validation-basis-disclosure-v1.json +++ b/contracts/schema-publication/entries/validation-basis-disclosure-v1.json @@ -2,9 +2,9 @@ "contract_id": "validation-basis-disclosure-v1", "schema_path": "contracts/schemas/profiles/validation-basis-disclosure-v1.json", "stability": "draft", - "content_hash": "cbd474c289d9519baf339ce22eea1613b41e9166ad3ac350f40e1955b434edd3", + "content_hash": "9e0770a9444b5312d60d599bee916906e04de8c24fed612d59ea437297d5a4f5", "last_change": { - "summary": "Repointed the published schema namespace from the uncontrolled raes.dev domain to the repository-owned https://raesystem.github.io/rae/schemas/ root for issue #908.", - "content_hash": "cbd474c289d9519baf339ce22eea1613b41e9166ad3ac350f40e1955b434edd3" + "summary": "Rebound the published schema namespace to the renamed OpenRAE GitHub organization for issue #963.", + "content_hash": "9e0770a9444b5312d60d599bee916906e04de8c24fed612d59ea437297d5a4f5" } } diff --git a/contracts/schema-publication/entries/validation-profile-catalog-v1.json b/contracts/schema-publication/entries/validation-profile-catalog-v1.json index 17ceec089..d60ef6b02 100644 --- a/contracts/schema-publication/entries/validation-profile-catalog-v1.json +++ b/contracts/schema-publication/entries/validation-profile-catalog-v1.json @@ -2,9 +2,9 @@ "contract_id": "validation-profile-catalog-v1", "schema_path": "contracts/schemas/profiles/validation-profile-catalog-v1.json", "stability": "draft", - "content_hash": "235bd271397f4a8ab51422bfe8cb570610e0f82177a0197bb10e1f743c03349b", + "content_hash": "c50f1016add26f899a29b7ba822c7f21b2be7514c949d8736bfc7e33a6464bd5", "last_change": { - "summary": "Repointed the published schema namespace from the uncontrolled raes.dev domain to the repository-owned https://raesystem.github.io/rae/schemas/ root for issue #908.", - "content_hash": "235bd271397f4a8ab51422bfe8cb570610e0f82177a0197bb10e1f743c03349b" + "summary": "Rebound the published schema namespace to the renamed OpenRAE GitHub organization for issue #963.", + "content_hash": "c50f1016add26f899a29b7ba822c7f21b2be7514c949d8736bfc7e33a6464bd5" } } diff --git a/contracts/schema-publication/entries/w3c-activitystreams-activity-types-source-v1.json b/contracts/schema-publication/entries/w3c-activitystreams-activity-types-source-v1.json new file mode 100644 index 000000000..9534c70e5 --- /dev/null +++ b/contracts/schema-publication/entries/w3c-activitystreams-activity-types-source-v1.json @@ -0,0 +1,10 @@ +{ + "contract_id": "w3c-activitystreams-activity-types-source-v1", + "schema_path": "contracts/schemas/concept-authority/w3c-activitystreams-activity-types-source-v1.json", + "stability": "draft", + "content_hash": "d64e6dd6779bcac5da79bb95a9342bfb9c1bb51f1a8a20d10cdd9abf1e5d9f64", + "last_change": { + "summary": "Rebound the published schema namespace to the renamed OpenRAE GitHub organization for issue #963.", + "content_hash": "d64e6dd6779bcac5da79bb95a9342bfb9c1bb51f1a8a20d10cdd9abf1e5d9f64" + } +} diff --git a/contracts/schema-publication/entries/workflow-cancellation-request-v1.json b/contracts/schema-publication/entries/workflow-cancellation-request-v1.json index 8570b48a9..b4a5b33a5 100644 --- a/contracts/schema-publication/entries/workflow-cancellation-request-v1.json +++ b/contracts/schema-publication/entries/workflow-cancellation-request-v1.json @@ -2,9 +2,9 @@ "contract_id": "workflow-cancellation-request-v1", "schema_path": "contracts/schemas/control-plane/workflow-cancellation-request-v1.json", "stability": "draft", - "content_hash": "83d992309d63b159214f8580d58366ccd408b5720163771269a810cff40f955d", + "content_hash": "50f63d3e9f24a674b7ecc2d8f3a8847e1465d790762319cd47a9ee9477d6295f", "last_change": { - "summary": "Repointed the published schema namespace from the uncontrolled raes.dev domain to the repository-owned https://raesystem.github.io/rae/schemas/ root for issue #908.", - "content_hash": "83d992309d63b159214f8580d58366ccd408b5720163771269a810cff40f955d" + "summary": "Rebound the published schema namespace to the renamed OpenRAE GitHub organization for issue #963.", + "content_hash": "50f63d3e9f24a674b7ecc2d8f3a8847e1465d790762319cd47a9ee9477d6295f" } } diff --git a/contracts/schema-publication/entries/workflow-history-event-stream-v1.json b/contracts/schema-publication/entries/workflow-history-event-stream-v1.json index 1a4f128bd..dc8a198d6 100644 --- a/contracts/schema-publication/entries/workflow-history-event-stream-v1.json +++ b/contracts/schema-publication/entries/workflow-history-event-stream-v1.json @@ -2,9 +2,9 @@ "contract_id": "workflow-history-event-stream-v1", "schema_path": "contracts/schemas/control-plane/workflow-history-event-stream-v1.json", "stability": "draft", - "content_hash": "22737796b0903c109e718cdb2b14d1a05832019a121437c45f153a9a76caf916", + "content_hash": "591782d81458822d94e3f8bf6bc3eded95d97d5750659412a32c853288e07c4d", "last_change": { - "summary": "Repointed the published schema namespace from the uncontrolled raes.dev domain to the repository-owned https://raesystem.github.io/rae/schemas/ root for issue #908.", - "content_hash": "22737796b0903c109e718cdb2b14d1a05832019a121437c45f153a9a76caf916" + "summary": "Rebound the published schema namespace to the renamed OpenRAE GitHub organization for issue #963.", + "content_hash": "591782d81458822d94e3f8bf6bc3eded95d97d5750659412a32c853288e07c4d" } } diff --git a/contracts/schema-publication/entries/workflow-result-envelope-v1.json b/contracts/schema-publication/entries/workflow-result-envelope-v1.json index ddcdd1341..8d80abbce 100644 --- a/contracts/schema-publication/entries/workflow-result-envelope-v1.json +++ b/contracts/schema-publication/entries/workflow-result-envelope-v1.json @@ -2,9 +2,9 @@ "contract_id": "workflow-result-envelope-v1", "schema_path": "contracts/schemas/control-plane/workflow-result-envelope-v1.json", "stability": "draft", - "content_hash": "ca40953f53b3f13a0bcf1e6bf9d631c9a94544278cef6882b3fa140a35022612", + "content_hash": "b4f5e3de5c333cf96fdb7c44eb65c3d757e4d05b4dcc456b2c24d21adf572569", "last_change": { - "summary": "Repointed the published schema namespace from the uncontrolled raes.dev domain to the repository-owned https://raesystem.github.io/rae/schemas/ root for issue #908.", - "content_hash": "ca40953f53b3f13a0bcf1e6bf9d631c9a94544278cef6882b3fa140a35022612" + "summary": "Rebound the published schema namespace to the renamed OpenRAE GitHub organization for issue #963.", + "content_hash": "b4f5e3de5c333cf96fdb7c44eb65c3d757e4d05b4dcc456b2c24d21adf572569" } } diff --git a/contracts/schemas/artifact-requirements/artifact-requirement-v1.json b/contracts/schemas/artifact-requirements/artifact-requirement-v1.json index 68f42cce2..238974c7e 100644 --- a/contracts/schemas/artifact-requirements/artifact-requirement-v1.json +++ b/contracts/schemas/artifact-requirements/artifact-requirement-v1.json @@ -1071,7 +1071,7 @@ "type": "string" } }, - "$id": "https://raesystem.github.io/rae/schemas/artifact-requirement-v1.json", + "$id": "https://openrae.github.io/rae/schemas/artifact-requirement-v1.json", "$schema": "https://json-schema.org/draft/2020-12/schema", "additionalProperties": false, "description": "Published source-artifact requirement contract.", @@ -1136,6 +1136,6 @@ "id": "raes-semantic-invariants-v1", "keyword": "x-raes-invariants", "required": true, - "uri": "https://raesystem.github.io/rae/schemas/semantic-invariants/v1" + "uri": "https://openrae.github.io/rae/schemas/semantic-invariants/v1" } } diff --git a/contracts/schemas/asset-trust/reusable-asset-trust-policy-v1.json b/contracts/schemas/asset-trust/reusable-asset-trust-policy-v1.json index 84d2ea593..7f13cc952 100644 --- a/contracts/schemas/asset-trust/reusable-asset-trust-policy-v1.json +++ b/contracts/schemas/asset-trust/reusable-asset-trust-policy-v1.json @@ -312,7 +312,7 @@ "type": "object" } }, - "$id": "https://raesystem.github.io/rae/schemas/reusable-asset-trust-policy-v1.json", + "$id": "https://openrae.github.io/rae/schemas/reusable-asset-trust-policy-v1.json", "$schema": "https://json-schema.org/draft/2020-12/schema", "additionalProperties": false, "description": "Ecosystem trust/authenticity/integrity policy over reusable assets (GOV-913).\n\nA declarative, expectation-based policy: it declares, per asset family, the\nintegrity/authenticity/provenance/governance evidence the ecosystem requires,\nreferencing the existing RAES mechanisms that carry that evidence. It is not a\nper-asset trust record and it invents no cryptography. See\n``specs/authority/reusable-asset-trust-integrity.md`` (normative) and ADR-071.", diff --git a/contracts/schemas/associated-artifacts/associated-artifact-manifest-v1.json b/contracts/schemas/associated-artifacts/associated-artifact-manifest-v1.json index 77c11a68a..f3dad2718 100644 --- a/contracts/schemas/associated-artifacts/associated-artifact-manifest-v1.json +++ b/contracts/schemas/associated-artifacts/associated-artifact-manifest-v1.json @@ -327,7 +327,7 @@ "type": "object" } }, - "$id": "https://raesystem.github.io/rae/schemas/associated-artifact-manifest-v1.json", + "$id": "https://openrae.github.io/rae/schemas/associated-artifact-manifest-v1.json", "$schema": "https://json-schema.org/draft/2020-12/schema", "additionalProperties": false, "allOf": [ @@ -470,6 +470,6 @@ "id": "raes-semantic-invariants-v1", "keyword": "x-raes-invariants", "required": true, - "uri": "https://raesystem.github.io/rae/schemas/semantic-invariants/v1" + "uri": "https://openrae.github.io/rae/schemas/semantic-invariants/v1" } } diff --git a/contracts/schemas/backend-manifest/backend-manifest-v2.json b/contracts/schemas/backend-manifest/backend-manifest-v2.json index a31627930..5c84d1702 100644 --- a/contracts/schemas/backend-manifest/backend-manifest-v2.json +++ b/contracts/schemas/backend-manifest/backend-manifest-v2.json @@ -578,6 +578,16 @@ "title": "EvaluatorCapabilitiesModel", "type": "object" }, + "GeneratedArtifactKind": { + "description": "Portable kinds of material a provisioner may generate.", + "enum": [ + "certificate_bundle", + "rendered_config", + "ssh_key_bundle" + ], + "title": "GeneratedArtifactKind", + "type": "string" + }, "LiteralBindingValueModel": { "additionalProperties": false, "description": "Portable literal value; strict type validation occurs at its descriptor.", @@ -1729,21 +1739,68 @@ }, { "if": { + "properties": { + "supported_account_features": { + "minItems": 1 + } + }, + "required": [ + "supported_account_features" + ] + }, + "then": { "properties": { "supports_accounts": { - "const": false + "const": true } }, "required": [ "supports_accounts" ] + } + }, + { + "if": { + "properties": { + "supports_generated_artifacts": { + "const": true + } + }, + "required": [ + "supports_generated_artifacts" + ] }, "then": { "properties": { - "supported_account_features": { - "maxItems": 0 + "supported_generated_artifact_kinds": { + "minItems": 1 } - } + }, + "required": [ + "supported_generated_artifact_kinds" + ] + } + }, + { + "if": { + "properties": { + "supported_generated_artifact_kinds": { + "minItems": 1 + } + }, + "required": [ + "supported_generated_artifact_kinds" + ] + }, + "then": { + "properties": { + "supports_generated_artifacts": { + "const": true + } + }, + "required": [ + "supports_generated_artifacts" + ] } } ], @@ -1797,6 +1854,14 @@ "title": "Supported Domain Profiles", "type": "array" }, + "supported_generated_artifact_kinds": { + "items": { + "$ref": "#/$defs/GeneratedArtifactKind" + }, + "title": "Supported Generated Artifact Kinds", + "type": "array", + "uniqueItems": true + }, "supported_node_types": { "items": { "minLength": 1, @@ -2214,7 +2279,7 @@ "type": "string" } }, - "$id": "https://raesystem.github.io/rae/schemas/backend-manifest-v2.json", + "$id": "https://openrae.github.io/rae/schemas/backend-manifest-v2.json", "$schema": "https://json-schema.org/draft/2020-12/schema", "additionalProperties": false, "allOf": [ diff --git a/contracts/schemas/concept-authority/atlas-tactics-source-v1.json b/contracts/schemas/concept-authority/atlas-tactics-source-v1.json index 86f3d08e5..aab284930 100644 --- a/contracts/schemas/concept-authority/atlas-tactics-source-v1.json +++ b/contracts/schemas/concept-authority/atlas-tactics-source-v1.json @@ -90,7 +90,7 @@ "type": "object" } }, - "$id": "https://raesystem.github.io/rae/schemas/atlas-tactics-source-v1.json", + "$id": "https://openrae.github.io/rae/schemas/atlas-tactics-source-v1.json", "$schema": "https://json-schema.org/draft/2020-12/schema", "additionalProperties": false, "properties": { diff --git a/contracts/schemas/concept-authority/attack-enterprise-tactics-source-v1.json b/contracts/schemas/concept-authority/attack-enterprise-tactics-source-v1.json index 008fac2d1..491f62963 100644 --- a/contracts/schemas/concept-authority/attack-enterprise-tactics-source-v1.json +++ b/contracts/schemas/concept-authority/attack-enterprise-tactics-source-v1.json @@ -46,7 +46,7 @@ "type": "object" } }, - "$id": "https://raesystem.github.io/rae/schemas/attack-enterprise-tactics-source-v1.json", + "$id": "https://openrae.github.io/rae/schemas/attack-enterprise-tactics-source-v1.json", "$schema": "https://json-schema.org/draft/2020-12/schema", "additionalProperties": false, "properties": { diff --git a/contracts/schemas/concept-authority/behavioral-relations-v1.json b/contracts/schemas/concept-authority/behavioral-relations-v1.json index 4e261bc21..f4c205110 100644 --- a/contracts/schemas/concept-authority/behavioral-relations-v1.json +++ b/contracts/schemas/concept-authority/behavioral-relations-v1.json @@ -773,7 +773,7 @@ "type": "object" } }, - "$id": "https://raesystem.github.io/rae/schemas/behavioral-relations-v1.json", + "$id": "https://openrae.github.io/rae/schemas/behavioral-relations-v1.json", "$schema": "https://json-schema.org/draft/2020-12/schema", "additionalProperties": false, "properties": { @@ -861,6 +861,6 @@ "id": "raes-semantic-invariants-v1", "keyword": "x-raes-invariants", "required": true, - "uri": "https://raesystem.github.io/rae/schemas/semantic-invariants/v1" + "uri": "https://openrae.github.io/rae/schemas/semantic-invariants/v1" } } diff --git a/contracts/schemas/concept-authority/concept-families-v1.json b/contracts/schemas/concept-authority/concept-families-v1.json index 2d58ac354..b426f2a75 100644 --- a/contracts/schemas/concept-authority/concept-families-v1.json +++ b/contracts/schemas/concept-authority/concept-families-v1.json @@ -198,7 +198,7 @@ "type": "string" } }, - "$id": "https://raesystem.github.io/rae/schemas/concept-families-v1.json", + "$id": "https://openrae.github.io/rae/schemas/concept-families-v1.json", "$schema": "https://json-schema.org/draft/2020-12/schema", "additionalProperties": false, "properties": { diff --git a/contracts/schemas/concept-authority/controlled-vocabularies-v1.json b/contracts/schemas/concept-authority/controlled-vocabularies-v1.json index 617df48ba..1a7819801 100644 --- a/contracts/schemas/concept-authority/controlled-vocabularies-v1.json +++ b/contracts/schemas/concept-authority/controlled-vocabularies-v1.json @@ -201,7 +201,7 @@ "type": "object" } }, - "$id": "https://raesystem.github.io/rae/schemas/controlled-vocabularies-v1.json", + "$id": "https://openrae.github.io/rae/schemas/controlled-vocabularies-v1.json", "$schema": "https://json-schema.org/draft/2020-12/schema", "additionalProperties": false, "properties": { diff --git a/contracts/schemas/concept-authority/external-concept-bindings-v1.json b/contracts/schemas/concept-authority/external-concept-bindings-v1.json index ced7370ba..d423b4c23 100644 --- a/contracts/schemas/concept-authority/external-concept-bindings-v1.json +++ b/contracts/schemas/concept-authority/external-concept-bindings-v1.json @@ -868,7 +868,7 @@ "type": "string" } }, - "$id": "https://raesystem.github.io/rae/schemas/external-concept-bindings-v1.json", + "$id": "https://openrae.github.io/rae/schemas/external-concept-bindings-v1.json", "$schema": "https://json-schema.org/draft/2020-12/schema", "additionalProperties": false, "description": "One stable authored set of independently identified binding assertions.", @@ -1001,6 +1001,6 @@ "id": "raes-semantic-invariants-v1", "keyword": "x-raes-invariants", "required": true, - "uri": "https://raesystem.github.io/rae/schemas/semantic-invariants/v1" + "uri": "https://openrae.github.io/rae/schemas/semantic-invariants/v1" } } diff --git a/contracts/schemas/concept-authority/fipa-communicative-acts-source-v1.json b/contracts/schemas/concept-authority/fipa-communicative-acts-source-v1.json new file mode 100644 index 000000000..fa1add9e8 --- /dev/null +++ b/contracts/schemas/concept-authority/fipa-communicative-acts-source-v1.json @@ -0,0 +1,114 @@ +{ + "$defs": { + "FipaCommunicativeActSourceTermModel": { + "additionalProperties": false, + "properties": { + "concept_id": { + "pattern": "^[a-z]+(?:-[a-z]+)*$", + "title": "Concept Id", + "type": "string" + }, + "position": { + "minimum": 1, + "title": "Position", + "type": "integer" + } + }, + "required": [ + "position", + "concept_id" + ], + "title": "FipaCommunicativeActSourceTermModel", + "type": "object" + } + }, + "$id": "https://openrae.github.io/rae/schemas/fipa-communicative-acts-source-v1.json", + "$schema": "https://json-schema.org/draft/2020-12/schema", + "additionalProperties": false, + "properties": { + "citation_urls": { + "items": { + "minLength": 1, + "type": "string" + }, + "minItems": 1, + "title": "Citation Urls", + "type": "array" + }, + "communicative_acts": { + "items": { + "$ref": "#/$defs/FipaCommunicativeActSourceTermModel" + }, + "minItems": 1, + "title": "Communicative Acts", + "type": "array" + }, + "license_notice": { + "minLength": 1, + "title": "License Notice", + "type": "string" + }, + "license_url": { + "minLength": 1, + "title": "License Url", + "type": "string" + }, + "retrieved_at": { + "pattern": "^\\d{4}-\\d{2}-\\d{2}$", + "title": "Retrieved At", + "type": "string" + }, + "schema_version": { + "const": "fipa-communicative-acts-source/v1", + "default": "fipa-communicative-acts-source/v1", + "title": "Schema Version", + "type": "string" + }, + "source_artifact_url": { + "minLength": 1, + "title": "Source Artifact Url", + "type": "string" + }, + "source_authority": { + "const": "Foundation for Intelligent Physical Agents", + "title": "Source Authority", + "type": "string" + }, + "source_digest": { + "minLength": 1, + "pattern": "^(?:sha256:[A-Fa-f0-9]{64}|sha384:[A-Fa-f0-9]{96}|sha512:[A-Fa-f0-9]{128}|blake3:[A-Fa-f0-9]{64})$", + "title": "Source Digest", + "type": "string" + }, + "source_status": { + "const": "Standard", + "title": "Source Status", + "type": "string" + }, + "source_url": { + "minLength": 1, + "title": "Source Url", + "type": "string" + }, + "source_version": { + "const": "SC00037J-2002-12-03", + "title": "Source Version", + "type": "string" + } + }, + "required": [ + "source_authority", + "source_version", + "source_status", + "source_url", + "source_artifact_url", + "source_digest", + "citation_urls", + "retrieved_at", + "license_url", + "license_notice", + "communicative_acts" + ], + "title": "FipaCommunicativeActsSourceModel", + "type": "object" +} diff --git a/contracts/schemas/concept-authority/nist-csf-defensive-categories-source-v1.json b/contracts/schemas/concept-authority/nist-csf-defensive-categories-source-v1.json index 5de85e5df..49449c01d 100644 --- a/contracts/schemas/concept-authority/nist-csf-defensive-categories-source-v1.json +++ b/contracts/schemas/concept-authority/nist-csf-defensive-categories-source-v1.json @@ -44,7 +44,7 @@ "type": "object" } }, - "$id": "https://raesystem.github.io/rae/schemas/nist-csf-defensive-categories-source-v1.json", + "$id": "https://openrae.github.io/rae/schemas/nist-csf-defensive-categories-source-v1.json", "$schema": "https://json-schema.org/draft/2020-12/schema", "additionalProperties": false, "properties": { diff --git a/contracts/schemas/concept-authority/reference-models-v1.json b/contracts/schemas/concept-authority/reference-models-v1.json index 5fc8a7300..b0108aa68 100644 --- a/contracts/schemas/concept-authority/reference-models-v1.json +++ b/contracts/schemas/concept-authority/reference-models-v1.json @@ -77,7 +77,7 @@ "type": "object" } }, - "$id": "https://raesystem.github.io/rae/schemas/reference-models-v1.json", + "$id": "https://openrae.github.io/rae/schemas/reference-models-v1.json", "$schema": "https://json-schema.org/draft/2020-12/schema", "additionalProperties": false, "properties": { diff --git a/contracts/schemas/concept-authority/uco-alignment-v1.json b/contracts/schemas/concept-authority/uco-alignment-v1.json index 7a1a9951f..91f03d1f8 100644 --- a/contracts/schemas/concept-authority/uco-alignment-v1.json +++ b/contracts/schemas/concept-authority/uco-alignment-v1.json @@ -76,7 +76,7 @@ "type": "object" } }, - "$id": "https://raesystem.github.io/rae/schemas/uco-alignment-v1.json", + "$id": "https://openrae.github.io/rae/schemas/uco-alignment-v1.json", "$schema": "https://json-schema.org/draft/2020-12/schema", "additionalProperties": false, "properties": { diff --git a/contracts/schemas/concept-authority/w3c-activitystreams-activity-types-source-v1.json b/contracts/schemas/concept-authority/w3c-activitystreams-activity-types-source-v1.json new file mode 100644 index 000000000..a7be897eb --- /dev/null +++ b/contracts/schemas/concept-authority/w3c-activitystreams-activity-types-source-v1.json @@ -0,0 +1,114 @@ +{ + "$defs": { + "ActivityStreamsActivityTypeSourceTermModel": { + "additionalProperties": false, + "properties": { + "concept_id": { + "minLength": 1, + "title": "Concept Id", + "type": "string" + }, + "position": { + "minimum": 1, + "title": "Position", + "type": "integer" + }, + "type_name": { + "pattern": "^[A-Z][A-Za-z]+$", + "title": "Type Name", + "type": "string" + } + }, + "required": [ + "position", + "type_name", + "concept_id" + ], + "title": "ActivityStreamsActivityTypeSourceTermModel", + "type": "object" + } + }, + "$id": "https://openrae.github.io/rae/schemas/w3c-activitystreams-activity-types-source-v1.json", + "$schema": "https://json-schema.org/draft/2020-12/schema", + "additionalProperties": false, + "properties": { + "activity_types": { + "items": { + "$ref": "#/$defs/ActivityStreamsActivityTypeSourceTermModel" + }, + "minItems": 1, + "title": "Activity Types", + "type": "array" + }, + "citation_urls": { + "items": { + "minLength": 1, + "type": "string" + }, + "minItems": 1, + "title": "Citation Urls", + "type": "array" + }, + "license_notice": { + "minLength": 1, + "title": "License Notice", + "type": "string" + }, + "license_url": { + "minLength": 1, + "title": "License Url", + "type": "string" + }, + "retrieved_at": { + "pattern": "^\\d{4}-\\d{2}-\\d{2}$", + "title": "Retrieved At", + "type": "string" + }, + "schema_version": { + "const": "w3c-activitystreams-activity-types-source/v1", + "default": "w3c-activitystreams-activity-types-source/v1", + "title": "Schema Version", + "type": "string" + }, + "source_authority": { + "const": "World Wide Web Consortium", + "title": "Source Authority", + "type": "string" + }, + "source_digest": { + "minLength": 1, + "pattern": "^(?:sha256:[A-Fa-f0-9]{64}|sha384:[A-Fa-f0-9]{96}|sha512:[A-Fa-f0-9]{128}|blake3:[A-Fa-f0-9]{64})$", + "title": "Source Digest", + "type": "string" + }, + "source_status": { + "const": "W3C Recommendation", + "title": "Source Status", + "type": "string" + }, + "source_url": { + "minLength": 1, + "title": "Source Url", + "type": "string" + }, + "source_version": { + "const": "REC-activitystreams-vocabulary-20170523", + "title": "Source Version", + "type": "string" + } + }, + "required": [ + "source_authority", + "source_version", + "source_status", + "source_url", + "source_digest", + "citation_urls", + "retrieved_at", + "license_url", + "license_notice", + "activity_types" + ], + "title": "ActivityStreamsActivityTypesSourceModel", + "type": "object" +} diff --git a/contracts/schemas/control-plane/batch-execution-receipt-v1.json b/contracts/schemas/control-plane/batch-execution-receipt-v1.json index f2c91d560..1d07e3577 100644 --- a/contracts/schemas/control-plane/batch-execution-receipt-v1.json +++ b/contracts/schemas/control-plane/batch-execution-receipt-v1.json @@ -1,5 +1,5 @@ { - "$id": "https://raesystem.github.io/rae/schemas/batch-execution-receipt-v1.json", + "$id": "https://openrae.github.io/rae/schemas/batch-execution-receipt-v1.json", "$schema": "https://json-schema.org/draft/2020-12/schema", "additionalProperties": false, "allOf": [ @@ -183,6 +183,6 @@ "id": "raes-semantic-invariants-v1", "keyword": "x-raes-invariants", "required": true, - "uri": "https://raesystem.github.io/rae/schemas/semantic-invariants/v1" + "uri": "https://openrae.github.io/rae/schemas/semantic-invariants/v1" } } diff --git a/contracts/schemas/control-plane/evaluation-history-event-stream-v1.json b/contracts/schemas/control-plane/evaluation-history-event-stream-v1.json index e2d9c33bf..546ac204d 100644 --- a/contracts/schemas/control-plane/evaluation-history-event-stream-v1.json +++ b/contracts/schemas/control-plane/evaluation-history-event-stream-v1.json @@ -1,5 +1,5 @@ { - "$id": "https://raesystem.github.io/rae/schemas/evaluation-history-event-stream-v1.json", + "$id": "https://openrae.github.io/rae/schemas/evaluation-history-event-stream-v1.json", "$schema": "https://json-schema.org/draft/2020-12/schema", "items": { "additionalProperties": false, diff --git a/contracts/schemas/control-plane/evaluation-result-envelope-v1.json b/contracts/schemas/control-plane/evaluation-result-envelope-v1.json index 72c5d0e01..b6a01bb82 100644 --- a/contracts/schemas/control-plane/evaluation-result-envelope-v1.json +++ b/contracts/schemas/control-plane/evaluation-result-envelope-v1.json @@ -1,5 +1,5 @@ { - "$id": "https://raesystem.github.io/rae/schemas/evaluation-result-envelope-v1.json", + "$id": "https://openrae.github.io/rae/schemas/evaluation-result-envelope-v1.json", "$schema": "https://json-schema.org/draft/2020-12/schema", "additionalProperties": false, "properties": { diff --git a/contracts/schemas/control-plane/operation-receipt-v1.json b/contracts/schemas/control-plane/operation-receipt-v1.json index 43fdee56d..a0a1c4e42 100644 --- a/contracts/schemas/control-plane/operation-receipt-v1.json +++ b/contracts/schemas/control-plane/operation-receipt-v1.json @@ -1,5 +1,5 @@ { - "$id": "https://raesystem.github.io/rae/schemas/operation-receipt-v1.json", + "$id": "https://openrae.github.io/rae/schemas/operation-receipt-v1.json", "$schema": "https://json-schema.org/draft/2020-12/schema", "additionalProperties": false, "properties": { diff --git a/contracts/schemas/control-plane/operation-status-v1.json b/contracts/schemas/control-plane/operation-status-v1.json index 45876f47f..6048a34f4 100644 --- a/contracts/schemas/control-plane/operation-status-v1.json +++ b/contracts/schemas/control-plane/operation-status-v1.json @@ -1,5 +1,5 @@ { - "$id": "https://raesystem.github.io/rae/schemas/operation-status-v1.json", + "$id": "https://openrae.github.io/rae/schemas/operation-status-v1.json", "$schema": "https://json-schema.org/draft/2020-12/schema", "additionalProperties": false, "properties": { diff --git a/contracts/schemas/control-plane/participant-behavior-history-event-stream-v1.json b/contracts/schemas/control-plane/participant-behavior-history-event-stream-v1.json index cb9b19ff0..01d3e2640 100644 --- a/contracts/schemas/control-plane/participant-behavior-history-event-stream-v1.json +++ b/contracts/schemas/control-plane/participant-behavior-history-event-stream-v1.json @@ -1253,7 +1253,7 @@ "type": "string" } }, - "$id": "https://raesystem.github.io/rae/schemas/participant-behavior-history-event-stream-v1.json", + "$id": "https://openrae.github.io/rae/schemas/participant-behavior-history-event-stream-v1.json", "$schema": "https://json-schema.org/draft/2020-12/schema", "items": { "additionalProperties": false, @@ -1538,6 +1538,6 @@ "id": "raes-semantic-invariants-v1", "keyword": "x-raes-invariants", "required": true, - "uri": "https://raesystem.github.io/rae/schemas/semantic-invariants/v1" + "uri": "https://openrae.github.io/rae/schemas/semantic-invariants/v1" } } diff --git a/contracts/schemas/control-plane/participant-context-view-v1.json b/contracts/schemas/control-plane/participant-context-view-v1.json index 0352e28b3..214569307 100644 --- a/contracts/schemas/control-plane/participant-context-view-v1.json +++ b/contracts/schemas/control-plane/participant-context-view-v1.json @@ -236,7 +236,7 @@ "type": "object" } }, - "$id": "https://raesystem.github.io/rae/schemas/participant-context-view-v1.json", + "$id": "https://openrae.github.io/rae/schemas/participant-context-view-v1.json", "$schema": "https://json-schema.org/draft/2020-12/schema", "additionalProperties": false, "allOf": [ @@ -509,6 +509,6 @@ "id": "raes-semantic-invariants-v1", "keyword": "x-raes-invariants", "required": true, - "uri": "https://raesystem.github.io/rae/schemas/semantic-invariants/v1" + "uri": "https://openrae.github.io/rae/schemas/semantic-invariants/v1" } } diff --git a/contracts/schemas/control-plane/participant-decision-surface-v1.json b/contracts/schemas/control-plane/participant-decision-surface-v1.json index dd08ef4d2..9c5e0e8a4 100644 --- a/contracts/schemas/control-plane/participant-decision-surface-v1.json +++ b/contracts/schemas/control-plane/participant-decision-surface-v1.json @@ -665,7 +665,7 @@ "type": "object" } }, - "$id": "https://raesystem.github.io/rae/schemas/participant-decision-surface-v1.json", + "$id": "https://openrae.github.io/rae/schemas/participant-decision-surface-v1.json", "$schema": "https://json-schema.org/draft/2020-12/schema", "additionalProperties": false, "description": "One participant-local decision projection at one episode order point.", @@ -920,6 +920,6 @@ "id": "raes-semantic-invariants-v1", "keyword": "x-raes-invariants", "required": true, - "uri": "https://raesystem.github.io/rae/schemas/semantic-invariants/v1" + "uri": "https://openrae.github.io/rae/schemas/semantic-invariants/v1" } } diff --git a/contracts/schemas/control-plane/participant-decision-surface-v2.json b/contracts/schemas/control-plane/participant-decision-surface-v2.json index bf9598395..eb8320793 100644 --- a/contracts/schemas/control-plane/participant-decision-surface-v2.json +++ b/contracts/schemas/control-plane/participant-decision-surface-v2.json @@ -1331,7 +1331,7 @@ "type": "object" } }, - "$id": "https://raesystem.github.io/rae/schemas/participant-decision-surface-v2.json", + "$id": "https://openrae.github.io/rae/schemas/participant-decision-surface-v2.json", "$schema": "https://json-schema.org/draft/2020-12/schema", "additionalProperties": false, "allOf": [ @@ -1477,6 +1477,6 @@ "id": "raes-semantic-invariants-v1", "keyword": "x-raes-invariants", "required": true, - "uri": "https://raesystem.github.io/rae/schemas/semantic-invariants/v1" + "uri": "https://openrae.github.io/rae/schemas/semantic-invariants/v1" } } diff --git a/contracts/schemas/control-plane/participant-episode-history-event-stream-v1.json b/contracts/schemas/control-plane/participant-episode-history-event-stream-v1.json index e18d6880a..aac00a46c 100644 --- a/contracts/schemas/control-plane/participant-episode-history-event-stream-v1.json +++ b/contracts/schemas/control-plane/participant-episode-history-event-stream-v1.json @@ -1,5 +1,5 @@ { - "$id": "https://raesystem.github.io/rae/schemas/participant-episode-history-event-stream-v1.json", + "$id": "https://openrae.github.io/rae/schemas/participant-episode-history-event-stream-v1.json", "$schema": "https://json-schema.org/draft/2020-12/schema", "items": { "additionalProperties": false, diff --git a/contracts/schemas/control-plane/participant-episode-state-envelope-v1.json b/contracts/schemas/control-plane/participant-episode-state-envelope-v1.json index e818f430e..9e7e7e84c 100644 --- a/contracts/schemas/control-plane/participant-episode-state-envelope-v1.json +++ b/contracts/schemas/control-plane/participant-episode-state-envelope-v1.json @@ -1,5 +1,5 @@ { - "$id": "https://raesystem.github.io/rae/schemas/participant-episode-state-envelope-v1.json", + "$id": "https://openrae.github.io/rae/schemas/participant-episode-state-envelope-v1.json", "$schema": "https://json-schema.org/draft/2020-12/schema", "additionalProperties": false, "properties": { diff --git a/contracts/schemas/control-plane/participant-history-view-v1.json b/contracts/schemas/control-plane/participant-history-view-v1.json index eb319a80b..997306452 100644 --- a/contracts/schemas/control-plane/participant-history-view-v1.json +++ b/contracts/schemas/control-plane/participant-history-view-v1.json @@ -1570,7 +1570,7 @@ "type": "string" } }, - "$id": "https://raesystem.github.io/rae/schemas/participant-history-view-v1.json", + "$id": "https://openrae.github.io/rae/schemas/participant-history-view-v1.json", "$schema": "https://json-schema.org/draft/2020-12/schema", "additionalProperties": false, "allOf": [ @@ -1711,6 +1711,6 @@ "id": "raes-semantic-invariants-v1", "keyword": "x-raes-invariants", "required": true, - "uri": "https://raesystem.github.io/rae/schemas/semantic-invariants/v1" + "uri": "https://openrae.github.io/rae/schemas/semantic-invariants/v1" } } diff --git a/contracts/schemas/control-plane/participant-status-view-v1.json b/contracts/schemas/control-plane/participant-status-view-v1.json index 9843ccdcb..b253dece0 100644 --- a/contracts/schemas/control-plane/participant-status-view-v1.json +++ b/contracts/schemas/control-plane/participant-status-view-v1.json @@ -78,7 +78,7 @@ "type": "object" } }, - "$id": "https://raesystem.github.io/rae/schemas/participant-status-view-v1.json", + "$id": "https://openrae.github.io/rae/schemas/participant-status-view-v1.json", "$schema": "https://json-schema.org/draft/2020-12/schema", "additionalProperties": false, "description": "API-408 retrieval projection of one participant's episode status.", diff --git a/contracts/schemas/control-plane/proposition-truth-result-v1.json b/contracts/schemas/control-plane/proposition-truth-result-v1.json index 2a6e24850..cebf17ab7 100644 --- a/contracts/schemas/control-plane/proposition-truth-result-v1.json +++ b/contracts/schemas/control-plane/proposition-truth-result-v1.json @@ -156,7 +156,7 @@ "type": "string" } }, - "$id": "https://raesystem.github.io/rae/schemas/proposition-truth-result-v1.json", + "$id": "https://openrae.github.io/rae/schemas/proposition-truth-result-v1.json", "$schema": "https://json-schema.org/draft/2020-12/schema", "additionalProperties": false, "allOf": [ diff --git a/contracts/schemas/control-plane/scheduler-isolation-proof-v1.json b/contracts/schemas/control-plane/scheduler-isolation-proof-v1.json index 06d647724..0eeae4a2d 100644 --- a/contracts/schemas/control-plane/scheduler-isolation-proof-v1.json +++ b/contracts/schemas/control-plane/scheduler-isolation-proof-v1.json @@ -41,7 +41,7 @@ "type": "object" } }, - "$id": "https://raesystem.github.io/rae/schemas/scheduler-isolation-proof-v1.json", + "$id": "https://openrae.github.io/rae/schemas/scheduler-isolation-proof-v1.json", "$schema": "https://json-schema.org/draft/2020-12/schema", "additionalProperties": false, "allOf": [ @@ -278,6 +278,6 @@ "id": "raes-semantic-invariants-v1", "keyword": "x-raes-invariants", "required": true, - "uri": "https://raesystem.github.io/rae/schemas/semantic-invariants/v1" + "uri": "https://openrae.github.io/rae/schemas/semantic-invariants/v1" } } diff --git a/contracts/schemas/control-plane/trial-cleanup-receipt-v1.json b/contracts/schemas/control-plane/trial-cleanup-receipt-v1.json index a0669a310..f30aca9cb 100644 --- a/contracts/schemas/control-plane/trial-cleanup-receipt-v1.json +++ b/contracts/schemas/control-plane/trial-cleanup-receipt-v1.json @@ -90,7 +90,7 @@ "type": "object" } }, - "$id": "https://raesystem.github.io/rae/schemas/trial-cleanup-receipt-v1.json", + "$id": "https://openrae.github.io/rae/schemas/trial-cleanup-receipt-v1.json", "$schema": "https://json-schema.org/draft/2020-12/schema", "additionalProperties": false, "allOf": [ @@ -230,6 +230,6 @@ "id": "raes-semantic-invariants-v1", "keyword": "x-raes-invariants", "required": true, - "uri": "https://raesystem.github.io/rae/schemas/semantic-invariants/v1" + "uri": "https://openrae.github.io/rae/schemas/semantic-invariants/v1" } } diff --git a/contracts/schemas/control-plane/workflow-cancellation-request-v1.json b/contracts/schemas/control-plane/workflow-cancellation-request-v1.json index a6dca7bb0..c39fcb7d7 100644 --- a/contracts/schemas/control-plane/workflow-cancellation-request-v1.json +++ b/contracts/schemas/control-plane/workflow-cancellation-request-v1.json @@ -1,5 +1,5 @@ { - "$id": "https://raesystem.github.io/rae/schemas/workflow-cancellation-request-v1.json", + "$id": "https://openrae.github.io/rae/schemas/workflow-cancellation-request-v1.json", "$schema": "https://json-schema.org/draft/2020-12/schema", "additionalProperties": false, "properties": { diff --git a/contracts/schemas/control-plane/workflow-history-event-stream-v1.json b/contracts/schemas/control-plane/workflow-history-event-stream-v1.json index 2276e6cc8..12dc26048 100644 --- a/contracts/schemas/control-plane/workflow-history-event-stream-v1.json +++ b/contracts/schemas/control-plane/workflow-history-event-stream-v1.json @@ -1,5 +1,5 @@ { - "$id": "https://raesystem.github.io/rae/schemas/workflow-history-event-stream-v1.json", + "$id": "https://openrae.github.io/rae/schemas/workflow-history-event-stream-v1.json", "$schema": "https://json-schema.org/draft/2020-12/schema", "items": { "additionalProperties": false, diff --git a/contracts/schemas/control-plane/workflow-result-envelope-v1.json b/contracts/schemas/control-plane/workflow-result-envelope-v1.json index 308b2d33c..07b339020 100644 --- a/contracts/schemas/control-plane/workflow-result-envelope-v1.json +++ b/contracts/schemas/control-plane/workflow-result-envelope-v1.json @@ -151,7 +151,7 @@ "type": "object" } }, - "$id": "https://raesystem.github.io/rae/schemas/workflow-result-envelope-v1.json", + "$id": "https://openrae.github.io/rae/schemas/workflow-result-envelope-v1.json", "$schema": "https://json-schema.org/draft/2020-12/schema", "additionalProperties": false, "properties": { diff --git a/contracts/schemas/experiment-core/experiment-apparatus-context-v1.json b/contracts/schemas/experiment-core/experiment-apparatus-context-v1.json index db0b21628..159f4cc1d 100644 --- a/contracts/schemas/experiment-core/experiment-apparatus-context-v1.json +++ b/contracts/schemas/experiment-core/experiment-apparatus-context-v1.json @@ -1127,7 +1127,7 @@ "type": "object" } }, - "$id": "https://raesystem.github.io/rae/schemas/experiment-apparatus-context-v1.json", + "$id": "https://openrae.github.io/rae/schemas/experiment-apparatus-context-v1.json", "$schema": "https://json-schema.org/draft/2020-12/schema", "additionalProperties": false, "description": "Run-scoped apparatus context for interpreting experiment evidence.", @@ -1348,6 +1348,6 @@ "id": "raes-semantic-invariants-v1", "keyword": "x-raes-invariants", "required": true, - "uri": "https://raesystem.github.io/rae/schemas/semantic-invariants/v1" + "uri": "https://openrae.github.io/rae/schemas/semantic-invariants/v1" } } diff --git a/contracts/schemas/experiment-core/experiment-authoring-input-v1.json b/contracts/schemas/experiment-core/experiment-authoring-input-v1.json index 525c88a78..486ab4d26 100644 --- a/contracts/schemas/experiment-core/experiment-authoring-input-v1.json +++ b/contracts/schemas/experiment-core/experiment-authoring-input-v1.json @@ -3678,7 +3678,7 @@ "type": "object" } }, - "$id": "https://raesystem.github.io/rae/schemas/experiment-authoring-input-v1.json", + "$id": "https://openrae.github.io/rae/schemas/experiment-authoring-input-v1.json", "$schema": "https://json-schema.org/draft/2020-12/schema", "additionalProperties": false, "allOf": [ @@ -3903,6 +3903,6 @@ "id": "raes-semantic-invariants-v1", "keyword": "x-raes-invariants", "required": true, - "uri": "https://raesystem.github.io/rae/schemas/semantic-invariants/v1" + "uri": "https://openrae.github.io/rae/schemas/semantic-invariants/v1" } } diff --git a/contracts/schemas/experiment-core/experiment-binding-descriptors-v1.json b/contracts/schemas/experiment-core/experiment-binding-descriptors-v1.json index aa3a44af6..0a4bc20e1 100644 --- a/contracts/schemas/experiment-core/experiment-binding-descriptors-v1.json +++ b/contracts/schemas/experiment-core/experiment-binding-descriptors-v1.json @@ -323,7 +323,7 @@ "type": "object" } }, - "$id": "https://raesystem.github.io/rae/schemas/experiment-binding-descriptors-v1.json", + "$id": "https://openrae.github.io/rae/schemas/experiment-binding-descriptors-v1.json", "$schema": "https://json-schema.org/draft/2020-12/schema", "additionalProperties": false, "description": "Versioned, collision-free set of authoritative experiment bindings.", @@ -369,6 +369,6 @@ "id": "raes-semantic-invariants-v1", "keyword": "x-raes-invariants", "required": true, - "uri": "https://raesystem.github.io/rae/schemas/semantic-invariants/v1" + "uri": "https://openrae.github.io/rae/schemas/semantic-invariants/v1" } } diff --git a/contracts/schemas/experiment-core/experiment-capture-spec-v1.json b/contracts/schemas/experiment-core/experiment-capture-spec-v1.json index 45ceb1705..ce3849a69 100644 --- a/contracts/schemas/experiment-core/experiment-capture-spec-v1.json +++ b/contracts/schemas/experiment-core/experiment-capture-spec-v1.json @@ -704,7 +704,7 @@ "type": "object" } }, - "$id": "https://raesystem.github.io/rae/schemas/experiment-capture-spec-v1.json", + "$id": "https://openrae.github.io/rae/schemas/experiment-capture-spec-v1.json", "$schema": "https://json-schema.org/draft/2020-12/schema", "additionalProperties": false, "description": "Declarative EXP-707 specification of what experiment evidence to capture.", @@ -810,6 +810,6 @@ "id": "raes-semantic-invariants-v1", "keyword": "x-raes-invariants", "required": true, - "uri": "https://raesystem.github.io/rae/schemas/semantic-invariants/v1" + "uri": "https://openrae.github.io/rae/schemas/semantic-invariants/v1" } } diff --git a/contracts/schemas/experiment-core/experiment-derived-measure-v1.json b/contracts/schemas/experiment-core/experiment-derived-measure-v1.json index 6cb09d7f5..ba3259d53 100644 --- a/contracts/schemas/experiment-core/experiment-derived-measure-v1.json +++ b/contracts/schemas/experiment-core/experiment-derived-measure-v1.json @@ -253,7 +253,7 @@ "type": "object" } }, - "$id": "https://raesystem.github.io/rae/schemas/experiment-derived-measure-v1.json", + "$id": "https://openrae.github.io/rae/schemas/experiment-derived-measure-v1.json", "$schema": "https://json-schema.org/draft/2020-12/schema", "additionalProperties": false, "allOf": [ @@ -462,6 +462,6 @@ "id": "raes-semantic-invariants-v1", "keyword": "x-raes-invariants", "required": true, - "uri": "https://raesystem.github.io/rae/schemas/semantic-invariants/v1" + "uri": "https://openrae.github.io/rae/schemas/semantic-invariants/v1" } } diff --git a/contracts/schemas/experiment-core/experiment-evidence-record-v1.json b/contracts/schemas/experiment-core/experiment-evidence-record-v1.json index fe95c1c7a..3d7c32596 100644 --- a/contracts/schemas/experiment-core/experiment-evidence-record-v1.json +++ b/contracts/schemas/experiment-core/experiment-evidence-record-v1.json @@ -548,7 +548,7 @@ "type": "object" } }, - "$id": "https://raesystem.github.io/rae/schemas/experiment-evidence-record-v1.json", + "$id": "https://openrae.github.io/rae/schemas/experiment-evidence-record-v1.json", "$schema": "https://json-schema.org/draft/2020-12/schema", "additionalProperties": false, "allOf": [ @@ -750,6 +750,6 @@ "id": "raes-semantic-invariants-v1", "keyword": "x-raes-invariants", "required": true, - "uri": "https://raesystem.github.io/rae/schemas/semantic-invariants/v1" + "uri": "https://openrae.github.io/rae/schemas/semantic-invariants/v1" } } diff --git a/contracts/schemas/experiment-core/experiment-run-v1.json b/contracts/schemas/experiment-core/experiment-run-v1.json index a14349455..c570c8eb3 100644 --- a/contracts/schemas/experiment-core/experiment-run-v1.json +++ b/contracts/schemas/experiment-core/experiment-run-v1.json @@ -5534,7 +5534,7 @@ "type": "object" } }, - "$id": "https://raesystem.github.io/rae/schemas/experiment-run-v1.json", + "$id": "https://openrae.github.io/rae/schemas/experiment-run-v1.json", "$schema": "https://json-schema.org/draft/2020-12/schema", "additionalProperties": false, "allOf": [ @@ -5998,6 +5998,6 @@ "id": "raes-semantic-invariants-v1", "keyword": "x-raes-invariants", "required": true, - "uri": "https://raesystem.github.io/rae/schemas/semantic-invariants/v1" + "uri": "https://openrae.github.io/rae/schemas/semantic-invariants/v1" } } diff --git a/contracts/schemas/experiment-core/experiment-study-v1.json b/contracts/schemas/experiment-core/experiment-study-v1.json index 46fdcf933..0f9d48356 100644 --- a/contracts/schemas/experiment-core/experiment-study-v1.json +++ b/contracts/schemas/experiment-core/experiment-study-v1.json @@ -2039,7 +2039,7 @@ "type": "object" } }, - "$id": "https://raesystem.github.io/rae/schemas/experiment-study-v1.json", + "$id": "https://openrae.github.io/rae/schemas/experiment-study-v1.json", "$schema": "https://json-schema.org/draft/2020-12/schema", "additionalProperties": false, "allOf": [ @@ -2411,6 +2411,6 @@ "id": "raes-semantic-invariants-v1", "keyword": "x-raes-invariants", "required": true, - "uri": "https://raesystem.github.io/rae/schemas/semantic-invariants/v1" + "uri": "https://openrae.github.io/rae/schemas/semantic-invariants/v1" } } diff --git a/contracts/schemas/experiment-core/experiment-task-v1.json b/contracts/schemas/experiment-core/experiment-task-v1.json index 68fd9abb0..913a505f7 100644 --- a/contracts/schemas/experiment-core/experiment-task-v1.json +++ b/contracts/schemas/experiment-core/experiment-task-v1.json @@ -1843,7 +1843,7 @@ "type": "object" } }, - "$id": "https://raesystem.github.io/rae/schemas/experiment-task-v1.json", + "$id": "https://openrae.github.io/rae/schemas/experiment-task-v1.json", "$schema": "https://json-schema.org/draft/2020-12/schema", "additionalProperties": false, "description": "Experiment task contract that separates scenario material from protocol intent.", @@ -1977,6 +1977,6 @@ "id": "raes-semantic-invariants-v1", "keyword": "x-raes-invariants", "required": true, - "uri": "https://raesystem.github.io/rae/schemas/semantic-invariants/v1" + "uri": "https://openrae.github.io/rae/schemas/semantic-invariants/v1" } } diff --git a/contracts/schemas/exploit-path-analysis/exploit-path-analysis-evidence-v1.json b/contracts/schemas/exploit-path-analysis/exploit-path-analysis-evidence-v1.json index f2036f9f5..41e854cef 100644 --- a/contracts/schemas/exploit-path-analysis/exploit-path-analysis-evidence-v1.json +++ b/contracts/schemas/exploit-path-analysis/exploit-path-analysis-evidence-v1.json @@ -758,7 +758,7 @@ "type": "object" } }, - "$id": "https://raesystem.github.io/rae/schemas/exploit-path-analysis-evidence-v1.json", + "$id": "https://openrae.github.io/rae/schemas/exploit-path-analysis-evidence-v1.json", "$schema": "https://json-schema.org/draft/2020-12/schema", "additionalProperties": false, "description": "Closed evidence envelope binding source, snapshot, graph, query, and result.", @@ -963,6 +963,6 @@ "id": "raes-semantic-invariants-v1", "keyword": "x-raes-invariants", "required": true, - "uri": "https://raesystem.github.io/rae/schemas/semantic-invariants/v1" + "uri": "https://openrae.github.io/rae/schemas/semantic-invariants/v1" } } diff --git a/contracts/schemas/formal-analysis/participant-opacity-analysis-evidence-v1.json b/contracts/schemas/formal-analysis/participant-opacity-analysis-evidence-v1.json index ba73d0fb0..1c9a9e487 100644 --- a/contracts/schemas/formal-analysis/participant-opacity-analysis-evidence-v1.json +++ b/contracts/schemas/formal-analysis/participant-opacity-analysis-evidence-v1.json @@ -391,7 +391,7 @@ "type": "object" } }, - "$id": "https://raesystem.github.io/rae/schemas/participant-opacity-analysis-evidence-v1.json", + "$id": "https://openrae.github.io/rae/schemas/participant-opacity-analysis-evidence-v1.json", "$schema": "https://json-schema.org/draft/2020-12/schema", "additionalProperties": false, "description": "Digest-bound bounded result with no raw possible-point contents.", @@ -566,6 +566,6 @@ "id": "raes-semantic-invariants-v1", "keyword": "x-raes-invariants", "required": true, - "uri": "https://raesystem.github.io/rae/schemas/semantic-invariants/v1" + "uri": "https://openrae.github.io/rae/schemas/semantic-invariants/v1" } } diff --git a/contracts/schemas/formal-analysis/participant-opacity-analysis-input-v1.json b/contracts/schemas/formal-analysis/participant-opacity-analysis-input-v1.json index b27d442ed..6b263b7ac 100644 --- a/contracts/schemas/formal-analysis/participant-opacity-analysis-input-v1.json +++ b/contracts/schemas/formal-analysis/participant-opacity-analysis-input-v1.json @@ -408,7 +408,7 @@ "type": "object" } }, - "$id": "https://raesystem.github.io/rae/schemas/participant-opacity-analysis-input-v1.json", + "$id": "https://openrae.github.io/rae/schemas/participant-opacity-analysis-input-v1.json", "$schema": "https://json-schema.org/draft/2020-12/schema", "additionalProperties": false, "description": "Normalized finite carrier supplied by a trusted materializer.", @@ -527,6 +527,6 @@ "id": "raes-semantic-invariants-v1", "keyword": "x-raes-invariants", "required": true, - "uri": "https://raesystem.github.io/rae/schemas/semantic-invariants/v1" + "uri": "https://openrae.github.io/rae/schemas/semantic-invariants/v1" } } diff --git a/contracts/schemas/formal-analysis/participant-opacity-model-check-evidence-v1.json b/contracts/schemas/formal-analysis/participant-opacity-model-check-evidence-v1.json index bd0a953d2..7e00568b2 100644 --- a/contracts/schemas/formal-analysis/participant-opacity-model-check-evidence-v1.json +++ b/contracts/schemas/formal-analysis/participant-opacity-model-check-evidence-v1.json @@ -761,7 +761,7 @@ "type": "object" } }, - "$id": "https://raesystem.github.io/rae/schemas/participant-opacity-model-check-evidence-v1.json", + "$id": "https://openrae.github.io/rae/schemas/participant-opacity-model-check-evidence-v1.json", "$schema": "https://json-schema.org/draft/2020-12/schema", "additionalProperties": false, "description": "Replayable evidence for one exact complete finite transition model.", @@ -987,6 +987,6 @@ "id": "raes-semantic-invariants-v1", "keyword": "x-raes-invariants", "required": true, - "uri": "https://raesystem.github.io/rae/schemas/semantic-invariants/v1" + "uri": "https://openrae.github.io/rae/schemas/semantic-invariants/v1" } } diff --git a/contracts/schemas/formal-analysis/participant-opacity-model-check-input-v1.json b/contracts/schemas/formal-analysis/participant-opacity-model-check-input-v1.json index 94d4eec50..d2a3b7cce 100644 --- a/contracts/schemas/formal-analysis/participant-opacity-model-check-input-v1.json +++ b/contracts/schemas/formal-analysis/participant-opacity-model-check-input-v1.json @@ -591,7 +591,7 @@ "type": "object" } }, - "$id": "https://raesystem.github.io/rae/schemas/participant-opacity-model-check-input-v1.json", + "$id": "https://openrae.github.io/rae/schemas/participant-opacity-model-check-input-v1.json", "$schema": "https://json-schema.org/draft/2020-12/schema", "additionalProperties": false, "description": "Closed finite transition model admitted for model checking.", @@ -755,6 +755,6 @@ "id": "raes-semantic-invariants-v1", "keyword": "x-raes-invariants", "required": true, - "uri": "https://raesystem.github.io/rae/schemas/semantic-invariants/v1" + "uri": "https://openrae.github.io/rae/schemas/semantic-invariants/v1" } } diff --git a/contracts/schemas/participant-implementation-configuration/participant-configuration-result-v1.json b/contracts/schemas/participant-implementation-configuration/participant-configuration-result-v1.json index c36f29a3d..9895d274e 100644 --- a/contracts/schemas/participant-implementation-configuration/participant-configuration-result-v1.json +++ b/contracts/schemas/participant-implementation-configuration/participant-configuration-result-v1.json @@ -210,7 +210,7 @@ "type": "object" } }, - "$id": "https://raesystem.github.io/rae/schemas/participant-configuration-result-v1.json", + "$id": "https://openrae.github.io/rae/schemas/participant-configuration-result-v1.json", "$schema": "https://json-schema.org/draft/2020-12/schema", "additionalProperties": false, "description": "Portable result of one complete, atomic participant configuration validation.", @@ -277,6 +277,6 @@ "id": "raes-semantic-invariants-v1", "keyword": "x-raes-invariants", "required": true, - "uri": "https://raesystem.github.io/rae/schemas/semantic-invariants/v1" + "uri": "https://openrae.github.io/rae/schemas/semantic-invariants/v1" } } diff --git a/contracts/schemas/participant-implementation-manifest/participant-implementation-manifest-v1.json b/contracts/schemas/participant-implementation-manifest/participant-implementation-manifest-v1.json index 0c9017368..4ba622780 100644 --- a/contracts/schemas/participant-implementation-manifest/participant-implementation-manifest-v1.json +++ b/contracts/schemas/participant-implementation-manifest/participant-implementation-manifest-v1.json @@ -302,7 +302,7 @@ "type": "object" } }, - "$id": "https://raesystem.github.io/rae/schemas/participant-implementation-manifest-v1.json", + "$id": "https://openrae.github.io/rae/schemas/participant-implementation-manifest-v1.json", "$schema": "https://json-schema.org/draft/2020-12/schema", "additionalProperties": false, "properties": { diff --git a/contracts/schemas/participant-implementation-provenance/participant-implementation-provenance-v1.json b/contracts/schemas/participant-implementation-provenance/participant-implementation-provenance-v1.json index 550cfbf3d..afd4e4299 100644 --- a/contracts/schemas/participant-implementation-provenance/participant-implementation-provenance-v1.json +++ b/contracts/schemas/participant-implementation-provenance/participant-implementation-provenance-v1.json @@ -221,7 +221,7 @@ "type": "object" } }, - "$id": "https://raesystem.github.io/rae/schemas/participant-implementation-provenance-v1.json", + "$id": "https://openrae.github.io/rae/schemas/participant-implementation-provenance-v1.json", "$schema": "https://json-schema.org/draft/2020-12/schema", "additionalProperties": false, "properties": { diff --git a/contracts/schemas/participant-runtime/participant-control-occurrence-v1.json b/contracts/schemas/participant-runtime/participant-control-occurrence-v1.json index 01a28bd07..6305ea06b 100644 --- a/contracts/schemas/participant-runtime/participant-control-occurrence-v1.json +++ b/contracts/schemas/participant-runtime/participant-control-occurrence-v1.json @@ -1802,7 +1802,7 @@ "type": "object" } }, - "$id": "https://raesystem.github.io/rae/schemas/participant-control-occurrence-v1.json", + "$id": "https://openrae.github.io/rae/schemas/participant-control-occurrence-v1.json", "$schema": "https://json-schema.org/draft/2020-12/schema", "additionalProperties": false, "description": "Closed participant-runtime carrier for one API-409 control fact.", @@ -2213,6 +2213,6 @@ "id": "raes-semantic-invariants-v1", "keyword": "x-raes-invariants", "required": true, - "uri": "https://raesystem.github.io/rae/schemas/semantic-invariants/v1" + "uri": "https://openrae.github.io/rae/schemas/semantic-invariants/v1" } } diff --git a/contracts/schemas/participant-runtime/participant-crossing-occurrence-v1.json b/contracts/schemas/participant-runtime/participant-crossing-occurrence-v1.json index 96eb2bd3a..d6929db91 100644 --- a/contracts/schemas/participant-runtime/participant-crossing-occurrence-v1.json +++ b/contracts/schemas/participant-runtime/participant-crossing-occurrence-v1.json @@ -1798,7 +1798,7 @@ "type": "object" } }, - "$id": "https://raesystem.github.io/rae/schemas/participant-crossing-occurrence-v1.json", + "$id": "https://openrae.github.io/rae/schemas/participant-crossing-occurrence-v1.json", "$schema": "https://json-schema.org/draft/2020-12/schema", "additionalProperties": false, "description": "Closed participant-runtime carrier for one API-423 crossing fact.", @@ -2209,6 +2209,6 @@ "id": "raes-semantic-invariants-v1", "keyword": "x-raes-invariants", "required": true, - "uri": "https://raesystem.github.io/rae/schemas/semantic-invariants/v1" + "uri": "https://openrae.github.io/rae/schemas/semantic-invariants/v1" } } diff --git a/contracts/schemas/participant-runtime/participant-execution-binding-v1.json b/contracts/schemas/participant-runtime/participant-execution-binding-v1.json index 92ac537a5..54e912725 100644 --- a/contracts/schemas/participant-runtime/participant-execution-binding-v1.json +++ b/contracts/schemas/participant-runtime/participant-execution-binding-v1.json @@ -1,5 +1,5 @@ { - "$id": "https://raesystem.github.io/rae/schemas/participant-execution-binding-v1.json", + "$id": "https://openrae.github.io/rae/schemas/participant-execution-binding-v1.json", "$schema": "https://json-schema.org/draft/2020-12/schema", "additionalProperties": false, "description": "Exact executable relation between one action and its native targets.", diff --git a/contracts/schemas/participant-runtime/participant-execution-control-v1.json b/contracts/schemas/participant-runtime/participant-execution-control-v1.json index d516ad866..d4966599d 100644 --- a/contracts/schemas/participant-runtime/participant-execution-control-v1.json +++ b/contracts/schemas/participant-runtime/participant-execution-control-v1.json @@ -1,5 +1,5 @@ { - "$id": "https://raesystem.github.io/rae/schemas/participant-execution-control-v1.json", + "$id": "https://openrae.github.io/rae/schemas/participant-execution-control-v1.json", "$schema": "https://json-schema.org/draft/2020-12/schema", "additionalProperties": false, "description": "Generation-fenced lifecycle mutation for one admitted execution scope.", diff --git a/contracts/schemas/participant-runtime/participant-execution-service-state-v1.json b/contracts/schemas/participant-runtime/participant-execution-service-state-v1.json index 028048940..5940fd7ae 100644 --- a/contracts/schemas/participant-runtime/participant-execution-service-state-v1.json +++ b/contracts/schemas/participant-runtime/participant-execution-service-state-v1.json @@ -1,5 +1,5 @@ { - "$id": "https://raesystem.github.io/rae/schemas/participant-execution-service-state-v1.json", + "$id": "https://openrae.github.io/rae/schemas/participant-execution-service-state-v1.json", "$schema": "https://json-schema.org/draft/2020-12/schema", "additionalProperties": false, "description": "Typed health, readiness, lifecycle, capacity, and evidence readback.", diff --git a/contracts/schemas/participant-runtime/participant-joint-action-record-v1.json b/contracts/schemas/participant-runtime/participant-joint-action-record-v1.json index 5f98c8d6d..75720577f 100644 --- a/contracts/schemas/participant-runtime/participant-joint-action-record-v1.json +++ b/contracts/schemas/participant-runtime/participant-joint-action-record-v1.json @@ -407,7 +407,7 @@ "type": "object" } }, - "$id": "https://raesystem.github.io/rae/schemas/participant-joint-action-record-v1.json", + "$id": "https://openrae.github.io/rae/schemas/participant-joint-action-record-v1.json", "$schema": "https://json-schema.org/draft/2020-12/schema", "additionalProperties": false, "description": "RUN-308 joint action / concurrency record over behavior events.", diff --git a/contracts/schemas/participant-runtime/participant-lifecycle-event-v1.json b/contracts/schemas/participant-runtime/participant-lifecycle-event-v1.json index 6d2d31ec2..06733b8ab 100644 --- a/contracts/schemas/participant-runtime/participant-lifecycle-event-v1.json +++ b/contracts/schemas/participant-runtime/participant-lifecycle-event-v1.json @@ -389,7 +389,7 @@ "type": "object" } }, - "$id": "https://raesystem.github.io/rae/schemas/participant-lifecycle-event-v1.json", + "$id": "https://openrae.github.io/rae/schemas/participant-lifecycle-event-v1.json", "$schema": "https://json-schema.org/draft/2020-12/schema", "additionalProperties": false, "description": "RUN-306 lifecycle boundary record for one participant action event.", diff --git a/contracts/schemas/participant-runtime/participant-observation-envelope-v1.json b/contracts/schemas/participant-runtime/participant-observation-envelope-v1.json index 5add5f720..74e9cbd8b 100644 --- a/contracts/schemas/participant-runtime/participant-observation-envelope-v1.json +++ b/contracts/schemas/participant-runtime/participant-observation-envelope-v1.json @@ -409,7 +409,7 @@ "type": "object" } }, - "$id": "https://raesystem.github.io/rae/schemas/participant-observation-envelope-v1.json", + "$id": "https://openrae.github.io/rae/schemas/participant-observation-envelope-v1.json", "$schema": "https://json-schema.org/draft/2020-12/schema", "additionalProperties": false, "description": "SEM-210 participant-visible observation record with explicit guarantees.", diff --git a/contracts/schemas/participant-runtime/participant-outcome-report-v1.json b/contracts/schemas/participant-runtime/participant-outcome-report-v1.json index b2b825025..8d05c1581 100644 --- a/contracts/schemas/participant-runtime/participant-outcome-report-v1.json +++ b/contracts/schemas/participant-runtime/participant-outcome-report-v1.json @@ -413,7 +413,7 @@ "type": "object" } }, - "$id": "https://raesystem.github.io/rae/schemas/participant-outcome-report-v1.json", + "$id": "https://openrae.github.io/rae/schemas/participant-outcome-report-v1.json", "$schema": "https://json-schema.org/draft/2020-12/schema", "additionalProperties": false, "description": "SEM-215 outcome interpretation report.\n\nThe carrier deliberately has no score, reward, or objective-success\nfield: reward and return remain ADR-054 step signals, and objective and\nevaluation results remain their own contract surfaces.", diff --git a/contracts/schemas/participant-runtime/participant-resource-budget-event-v1.json b/contracts/schemas/participant-runtime/participant-resource-budget-event-v1.json index 33ddb7d4b..63f6d2746 100644 --- a/contracts/schemas/participant-runtime/participant-resource-budget-event-v1.json +++ b/contracts/schemas/participant-runtime/participant-resource-budget-event-v1.json @@ -1,5 +1,5 @@ { - "$id": "https://raesystem.github.io/rae/schemas/participant-resource-budget-event-v1.json", + "$id": "https://openrae.github.io/rae/schemas/participant-resource-budget-event-v1.json", "$schema": "https://json-schema.org/draft/2020-12/schema", "additionalProperties": false, "properties": { diff --git a/contracts/schemas/participant-runtime/participant-resource-budget-policy-v1.json b/contracts/schemas/participant-runtime/participant-resource-budget-policy-v1.json index 86e314f8b..860ea8968 100644 --- a/contracts/schemas/participant-runtime/participant-resource-budget-policy-v1.json +++ b/contracts/schemas/participant-runtime/participant-resource-budget-policy-v1.json @@ -244,7 +244,7 @@ "type": "object" } }, - "$id": "https://raesystem.github.io/rae/schemas/participant-resource-budget-policy-v1.json", + "$id": "https://openrae.github.io/rae/schemas/participant-resource-budget-policy-v1.json", "$schema": "https://json-schema.org/draft/2020-12/schema", "additionalProperties": false, "properties": { diff --git a/contracts/schemas/participant-runtime/participant-resource-budget-state-v1.json b/contracts/schemas/participant-runtime/participant-resource-budget-state-v1.json index e7aef6775..fbb413cb0 100644 --- a/contracts/schemas/participant-runtime/participant-resource-budget-state-v1.json +++ b/contracts/schemas/participant-runtime/participant-resource-budget-state-v1.json @@ -1,5 +1,5 @@ { - "$id": "https://raesystem.github.io/rae/schemas/participant-resource-budget-state-v1.json", + "$id": "https://openrae.github.io/rae/schemas/participant-resource-budget-state-v1.json", "$schema": "https://json-schema.org/draft/2020-12/schema", "additionalProperties": false, "properties": { diff --git a/contracts/schemas/participant-runtime/participant-resource-pool-capacity-v1.json b/contracts/schemas/participant-runtime/participant-resource-pool-capacity-v1.json index 1cb50db49..63732aaab 100644 --- a/contracts/schemas/participant-runtime/participant-resource-pool-capacity-v1.json +++ b/contracts/schemas/participant-runtime/participant-resource-pool-capacity-v1.json @@ -1,5 +1,5 @@ { - "$id": "https://raesystem.github.io/rae/schemas/participant-resource-pool-capacity-v1.json", + "$id": "https://openrae.github.io/rae/schemas/participant-resource-pool-capacity-v1.json", "$schema": "https://json-schema.org/draft/2020-12/schema", "additionalProperties": false, "properties": { diff --git a/contracts/schemas/participant-runtime/participant-shared-state-record-v1.json b/contracts/schemas/participant-runtime/participant-shared-state-record-v1.json index a662f373a..940c60b3c 100644 --- a/contracts/schemas/participant-runtime/participant-shared-state-record-v1.json +++ b/contracts/schemas/participant-runtime/participant-shared-state-record-v1.json @@ -551,7 +551,7 @@ "type": "object" } }, - "$id": "https://raesystem.github.io/rae/schemas/participant-shared-state-record-v1.json", + "$id": "https://openrae.github.io/rae/schemas/participant-shared-state-record-v1.json", "$schema": "https://json-schema.org/draft/2020-12/schema", "additionalProperties": false, "anyOf": [ diff --git a/contracts/schemas/participant-runtime/participant-time-management-context-v1.json b/contracts/schemas/participant-runtime/participant-time-management-context-v1.json index 74c822259..42449c232 100644 --- a/contracts/schemas/participant-runtime/participant-time-management-context-v1.json +++ b/contracts/schemas/participant-runtime/participant-time-management-context-v1.json @@ -351,7 +351,7 @@ "type": "object" } }, - "$id": "https://raesystem.github.io/rae/schemas/participant-time-management-context-v1.json", + "$id": "https://openrae.github.io/rae/schemas/participant-time-management-context-v1.json", "$schema": "https://json-schema.org/draft/2020-12/schema", "additionalProperties": false, "description": "RUN-308 time-management basis for concurrent or distributed runtime claims.", diff --git a/contracts/schemas/participant-runtime/runtime-fact-binding-plane-v1.json b/contracts/schemas/participant-runtime/runtime-fact-binding-plane-v1.json index cf2cce1db..11a1183e0 100644 --- a/contracts/schemas/participant-runtime/runtime-fact-binding-plane-v1.json +++ b/contracts/schemas/participant-runtime/runtime-fact-binding-plane-v1.json @@ -685,7 +685,7 @@ "type": "object" } }, - "$id": "https://raesystem.github.io/rae/schemas/runtime-fact-binding-plane-v1.json", + "$id": "https://openrae.github.io/rae/schemas/runtime-fact-binding-plane-v1.json", "$schema": "https://json-schema.org/draft/2020-12/schema", "additionalProperties": false, "properties": { @@ -754,6 +754,6 @@ "id": "raes-semantic-invariants-v1", "keyword": "x-raes-invariants", "required": true, - "uri": "https://raesystem.github.io/rae/schemas/semantic-invariants/v1" + "uri": "https://openrae.github.io/rae/schemas/semantic-invariants/v1" } } diff --git a/contracts/schemas/plans/admitted-trial-plan-v1.json b/contracts/schemas/plans/admitted-trial-plan-v1.json index 0c35ce904..84872663d 100644 --- a/contracts/schemas/plans/admitted-trial-plan-v1.json +++ b/contracts/schemas/plans/admitted-trial-plan-v1.json @@ -2547,7 +2547,7 @@ "type": "object" } }, - "$id": "https://raesystem.github.io/rae/schemas/admitted-trial-plan-v1.json", + "$id": "https://openrae.github.io/rae/schemas/admitted-trial-plan-v1.json", "$schema": "https://json-schema.org/draft/2020-12/schema", "additionalProperties": false, "description": "Immutable, schedule-independent admitted trial plan (SCE-002/SCE-006, ADR-084).", @@ -2654,6 +2654,6 @@ "id": "raes-semantic-invariants-v1", "keyword": "x-raes-invariants", "required": true, - "uri": "https://raesystem.github.io/rae/schemas/semantic-invariants/v1" + "uri": "https://openrae.github.io/rae/schemas/semantic-invariants/v1" } } diff --git a/contracts/schemas/plans/evaluation-plan-v1.json b/contracts/schemas/plans/evaluation-plan-v1.json index 8c157bbe4..a17463274 100644 --- a/contracts/schemas/plans/evaluation-plan-v1.json +++ b/contracts/schemas/plans/evaluation-plan-v1.json @@ -73,7 +73,7 @@ "type": "object" } }, - "$id": "https://raesystem.github.io/rae/schemas/evaluation-plan-v1.json", + "$id": "https://openrae.github.io/rae/schemas/evaluation-plan-v1.json", "$schema": "https://json-schema.org/draft/2020-12/schema", "additionalProperties": false, "properties": { diff --git a/contracts/schemas/plans/orchestration-plan-v1.json b/contracts/schemas/plans/orchestration-plan-v1.json index 42a613058..017fe816f 100644 --- a/contracts/schemas/plans/orchestration-plan-v1.json +++ b/contracts/schemas/plans/orchestration-plan-v1.json @@ -75,7 +75,7 @@ "type": "object" } }, - "$id": "https://raesystem.github.io/rae/schemas/orchestration-plan-v1.json", + "$id": "https://openrae.github.io/rae/schemas/orchestration-plan-v1.json", "$schema": "https://json-schema.org/draft/2020-12/schema", "additionalProperties": false, "properties": { diff --git a/contracts/schemas/plans/provisioning-plan-v1.json b/contracts/schemas/plans/provisioning-plan-v1.json index d66b6f338..86a7f3396 100644 --- a/contracts/schemas/plans/provisioning-plan-v1.json +++ b/contracts/schemas/plans/provisioning-plan-v1.json @@ -117,7 +117,7 @@ "type": "object" } }, - "$id": "https://raesystem.github.io/rae/schemas/provisioning-plan-v1.json", + "$id": "https://openrae.github.io/rae/schemas/provisioning-plan-v1.json", "$schema": "https://json-schema.org/draft/2020-12/schema", "additionalProperties": false, "properties": { diff --git a/contracts/schemas/plans/trial-cleanup-plan-v1.json b/contracts/schemas/plans/trial-cleanup-plan-v1.json index 8b09fc554..3cca52c09 100644 --- a/contracts/schemas/plans/trial-cleanup-plan-v1.json +++ b/contracts/schemas/plans/trial-cleanup-plan-v1.json @@ -263,7 +263,7 @@ "type": "object" } }, - "$id": "https://raesystem.github.io/rae/schemas/trial-cleanup-plan-v1.json", + "$id": "https://openrae.github.io/rae/schemas/trial-cleanup-plan-v1.json", "$schema": "https://json-schema.org/draft/2020-12/schema", "additionalProperties": false, "description": "Schedule-independent cleanup intent carried by one admitted trial entry.", @@ -350,6 +350,6 @@ "id": "raes-semantic-invariants-v1", "keyword": "x-raes-invariants", "required": true, - "uri": "https://raesystem.github.io/rae/schemas/semantic-invariants/v1" + "uri": "https://openrae.github.io/rae/schemas/semantic-invariants/v1" } } diff --git a/contracts/schemas/processor-manifest/processor-manifest-v2.json b/contracts/schemas/processor-manifest/processor-manifest-v2.json index 4581d8bc2..cb0c7be54 100644 --- a/contracts/schemas/processor-manifest/processor-manifest-v2.json +++ b/contracts/schemas/processor-manifest/processor-manifest-v2.json @@ -283,7 +283,7 @@ "type": "string" } }, - "$id": "https://raesystem.github.io/rae/schemas/processor-manifest-v2.json", + "$id": "https://openrae.github.io/rae/schemas/processor-manifest-v2.json", "$schema": "https://json-schema.org/draft/2020-12/schema", "additionalProperties": false, "properties": { diff --git a/contracts/schemas/profiles/backend-profile-v1.json b/contracts/schemas/profiles/backend-profile-v1.json index c194da0f9..aef7dc835 100644 --- a/contracts/schemas/profiles/backend-profile-v1.json +++ b/contracts/schemas/profiles/backend-profile-v1.json @@ -1,5 +1,5 @@ { - "$id": "https://raesystem.github.io/rae/schemas/backend-profile-v1.json", + "$id": "https://openrae.github.io/rae/schemas/backend-profile-v1.json", "$schema": "https://json-schema.org/draft/2020-12/schema", "additionalProperties": false, "description": "Published backend capability profile (closed-world).", diff --git a/contracts/schemas/profiles/behavioral-relation-profile-v1.json b/contracts/schemas/profiles/behavioral-relation-profile-v1.json index 0d62e9e12..e923bd1e6 100644 --- a/contracts/schemas/profiles/behavioral-relation-profile-v1.json +++ b/contracts/schemas/profiles/behavioral-relation-profile-v1.json @@ -1,5 +1,63 @@ { "$defs": { + "AbstractOpacityCarrierModel": { + "additionalProperties": false, + "description": "An abstract carrier whose proof obligations are discharged by a theorem session.", + "properties": { + "correspondence_ref": { + "maxLength": 256, + "pattern": "^[a-z][a-z0-9._:/-]*$", + "title": "Correspondence Ref", + "type": "string" + }, + "correspondence_revision": { + "maxLength": 128, + "pattern": "^[a-z0-9][a-z0-9._/-]*$", + "title": "Correspondence Revision", + "type": "string" + }, + "eligibility_ref": { + "maxLength": 256, + "pattern": "^[a-z][a-z0-9._:/-]*$", + "title": "Eligibility Ref", + "type": "string" + }, + "eligibility_revision": { + "maxLength": 128, + "pattern": "^[a-z0-9][a-z0-9._/-]*$", + "title": "Eligibility Revision", + "type": "string" + }, + "kind": { + "const": "abstract-possible-points", + "title": "Kind", + "type": "string" + }, + "reachability_ref": { + "maxLength": 256, + "pattern": "^[a-z][a-z0-9._:/-]*$", + "title": "Reachability Ref", + "type": "string" + }, + "reachability_revision": { + "maxLength": 128, + "pattern": "^[a-z0-9][a-z0-9._/-]*$", + "title": "Reachability Revision", + "type": "string" + } + }, + "required": [ + "kind", + "reachability_ref", + "reachability_revision", + "eligibility_ref", + "eligibility_revision", + "correspondence_ref", + "correspondence_revision" + ], + "title": "AbstractOpacityCarrierModel", + "type": "object" + }, "ActiveOpacityStrategyModel": { "additionalProperties": false, "properties": { @@ -100,63 +158,63 @@ "title": "CoalitionOpacityObserverModel", "type": "object" }, - "IndividualOpacityObserverModel": { + "FiniteOpacityCarrierModel": { "additionalProperties": false, - "description": "One participant or audience observes the selected information cell.", "properties": { - "audience_ref": { - "maxLength": 256, - "pattern": "^[a-z][a-z0-9._:/-]*$", - "title": "Audience Ref", - "type": "string" - }, "kind": { - "const": "individual", + "const": "finite-possible-points", "title": "Kind", "type": "string" }, - "participant_ref": { + "reachability_ref": { "maxLength": 256, "pattern": "^[a-z][a-z0-9._:/-]*$", - "title": "Participant Ref", + "title": "Reachability Ref", + "type": "string" + }, + "reachability_revision": { + "maxLength": 128, + "pattern": "^[a-z0-9][a-z0-9._/-]*$", + "title": "Reachability Revision", "type": "string" } }, "required": [ "kind", - "participant_ref", - "audience_ref" + "reachability_ref", + "reachability_revision" ], - "title": "IndividualOpacityObserverModel", + "title": "FiniteOpacityCarrierModel", "type": "object" }, - "OpacityCarrierModel": { + "IndividualOpacityObserverModel": { "additionalProperties": false, + "description": "One participant or audience observes the selected information cell.", "properties": { + "audience_ref": { + "maxLength": 256, + "pattern": "^[a-z][a-z0-9._:/-]*$", + "title": "Audience Ref", + "type": "string" + }, "kind": { - "const": "finite-possible-points", + "const": "individual", "title": "Kind", "type": "string" }, - "reachability_ref": { + "participant_ref": { "maxLength": 256, "pattern": "^[a-z][a-z0-9._:/-]*$", - "title": "Reachability Ref", - "type": "string" - }, - "reachability_revision": { - "maxLength": 128, - "pattern": "^[a-z0-9][a-z0-9._/-]*$", - "title": "Reachability Revision", + "title": "Participant Ref", "type": "string" } }, "required": [ "kind", - "reachability_ref", - "reachability_revision" + "participant_ref", + "audience_ref" ], - "title": "OpacityCarrierModel", + "title": "IndividualOpacityObserverModel", "type": "object" }, "OpacityFiniteBoundsModel": { @@ -550,13 +608,93 @@ }, "ParticipantPredicateOpacityParametersModel": { "additionalProperties": false, + "allOf": [ + { + "if": { + "properties": { + "carrier": { + "properties": { + "kind": { + "const": "finite-possible-points" + } + }, + "required": [ + "kind" + ] + } + }, + "required": [ + "carrier" + ] + }, + "then": { + "properties": { + "bounds": { + "type": "object" + } + }, + "required": [ + "bounds" + ] + } + }, + { + "if": { + "properties": { + "carrier": { + "properties": { + "kind": { + "const": "abstract-possible-points" + } + }, + "required": [ + "kind" + ] + } + }, + "required": [ + "carrier" + ] + }, + "then": { + "properties": { + "bounds": { + "type": "null" + } + } + } + } + ], "description": "Closed parameters for the SEM-231 one-sided possibilistic kernel.", "properties": { "bounds": { - "$ref": "#/$defs/OpacityFiniteBoundsModel" + "anyOf": [ + { + "$ref": "#/$defs/OpacityFiniteBoundsModel" + }, + { + "type": "null" + } + ], + "default": null }, "carrier": { - "$ref": "#/$defs/OpacityCarrierModel" + "discriminator": { + "mapping": { + "abstract-possible-points": "#/$defs/AbstractOpacityCarrierModel", + "finite-possible-points": "#/$defs/FiniteOpacityCarrierModel" + }, + "propertyName": "kind" + }, + "oneOf": [ + { + "$ref": "#/$defs/FiniteOpacityCarrierModel" + }, + { + "$ref": "#/$defs/AbstractOpacityCarrierModel" + } + ], + "title": "Carrier" }, "environment_refs": { "items": { @@ -672,8 +810,7 @@ "nondeterminism", "order", "time", - "probability", - "bounds" + "probability" ], "title": "ParticipantPredicateOpacityParametersModel", "type": "object" @@ -694,9 +831,77 @@ "type": "object" } }, - "$id": "https://raesystem.github.io/rae/schemas/behavioral-relation-profile-v1.json", + "$id": "https://openrae.github.io/rae/schemas/behavioral-relation-profile-v1.json", "$schema": "https://json-schema.org/draft/2020-12/schema", "additionalProperties": false, + "allOf": [ + { + "if": { + "properties": { + "parameters": { + "properties": { + "carrier": { + "properties": { + "kind": { + "const": "finite-possible-points" + } + }, + "required": [ + "kind" + ] + } + }, + "required": [ + "carrier" + ] + } + }, + "required": [ + "parameters" + ] + }, + "then": { + "properties": { + "finite_analysis_scope": { + "const": "declared-complete-finite-carrier" + } + } + } + }, + { + "if": { + "properties": { + "parameters": { + "properties": { + "carrier": { + "properties": { + "kind": { + "const": "abstract-possible-points" + } + }, + "required": [ + "kind" + ] + } + }, + "required": [ + "carrier" + ] + } + }, + "required": [ + "parameters" + ] + }, + "then": { + "properties": { + "finite_analysis_scope": { + "const": "abstract-parameterized-theorem-carrier" + } + } + } + } + ], "description": "One resolved relation profile with a closed parameter variant.", "properties": { "explicit_non_claims": { @@ -710,7 +915,10 @@ "type": "array" }, "finite_analysis_scope": { - "const": "declared-complete-finite-carrier", + "enum": [ + "declared-complete-finite-carrier", + "abstract-parameterized-theorem-carrier" + ], "title": "Finite Analysis Scope", "type": "string" }, @@ -842,6 +1050,6 @@ "id": "raes-semantic-invariants-v1", "keyword": "x-raes-invariants", "required": true, - "uri": "https://raesystem.github.io/rae/schemas/semantic-invariants/v1" + "uri": "https://openrae.github.io/rae/schemas/semantic-invariants/v1" } } diff --git a/contracts/schemas/profiles/raes-semantic-invariants-v1.json b/contracts/schemas/profiles/raes-semantic-invariants-v1.json index 746e92e08..3449a5932 100644 --- a/contracts/schemas/profiles/raes-semantic-invariants-v1.json +++ b/contracts/schemas/profiles/raes-semantic-invariants-v1.json @@ -100,7 +100,7 @@ "type": "boolean" }, "uri": { - "const": "https://raesystem.github.io/rae/schemas/semantic-invariants/v1", + "const": "https://openrae.github.io/rae/schemas/semantic-invariants/v1", "title": "Uri", "type": "string" } @@ -118,7 +118,7 @@ "type": "object" } }, - "$id": "https://raesystem.github.io/rae/schemas/semantic-invariants/v1", + "$id": "https://openrae.github.io/rae/schemas/semantic-invariants/v1", "$schema": "https://json-schema.org/draft/2020-12/schema", "additionalProperties": false, "description": "Published shape for RAES semantic-invariant annotations.", @@ -156,7 +156,7 @@ "type": "string" }, "uri": { - "const": "https://raesystem.github.io/rae/schemas/semantic-invariants/v1", + "const": "https://openrae.github.io/rae/schemas/semantic-invariants/v1", "title": "Uri", "type": "string" } diff --git a/contracts/schemas/profiles/random-stream-profile-v1.json b/contracts/schemas/profiles/random-stream-profile-v1.json index 5c867efc3..969ebb0fe 100644 --- a/contracts/schemas/profiles/random-stream-profile-v1.json +++ b/contracts/schemas/profiles/random-stream-profile-v1.json @@ -148,7 +148,7 @@ "type": "object" } }, - "$id": "https://raesystem.github.io/rae/schemas/random-stream-profile-v1.json", + "$id": "https://openrae.github.io/rae/schemas/random-stream-profile-v1.json", "$schema": "https://json-schema.org/draft/2020-12/schema", "additionalProperties": false, "description": "Published random-stream profile: one closed, immutable compatibility unit.\n\nChanging any field mints a new ``profile_id`` (the EXP-718 preflight's \"One\nProfile And One Stateless API\" section). This model's JSON Schema is\ngenerated via ``schema_bundle()``, never hand-authored.", @@ -235,6 +235,6 @@ "id": "raes-semantic-invariants-v1", "keyword": "x-raes-invariants", "required": true, - "uri": "https://raesystem.github.io/rae/schemas/semantic-invariants/v1" + "uri": "https://openrae.github.io/rae/schemas/semantic-invariants/v1" } } diff --git a/contracts/schemas/profiles/random-stream-vector-v1.json b/contracts/schemas/profiles/random-stream-vector-v1.json index 8d50bdfe4..692044f72 100644 --- a/contracts/schemas/profiles/random-stream-vector-v1.json +++ b/contracts/schemas/profiles/random-stream-vector-v1.json @@ -371,7 +371,7 @@ "type": "object" } }, - "$id": "https://raesystem.github.io/rae/schemas/random-stream-vector-v1.json", + "$id": "https://openrae.github.io/rae/schemas/random-stream-vector-v1.json", "$schema": "https://json-schema.org/draft/2020-12/schema", "additionalProperties": false, "description": "One canonical cross-language conformance vector case.\n\nComputed independently of the reference engine (a throwaway script that\ncalls the ``blake3`` library directly), so the vector tests do not just\ntest the engine against itself.", @@ -458,6 +458,6 @@ "id": "raes-semantic-invariants-v1", "keyword": "x-raes-invariants", "required": true, - "uri": "https://raesystem.github.io/rae/schemas/semantic-invariants/v1" + "uri": "https://openrae.github.io/rae/schemas/semantic-invariants/v1" } } diff --git a/contracts/schemas/profiles/scientific-completeness-assessment-v1.json b/contracts/schemas/profiles/scientific-completeness-assessment-v1.json index 24b6f93c8..7c1700737 100644 --- a/contracts/schemas/profiles/scientific-completeness-assessment-v1.json +++ b/contracts/schemas/profiles/scientific-completeness-assessment-v1.json @@ -148,7 +148,7 @@ "type": "string" } }, - "$id": "https://raesystem.github.io/rae/schemas/scientific-completeness-assessment-v1.json", + "$id": "https://openrae.github.io/rae/schemas/scientific-completeness-assessment-v1.json", "$schema": "https://json-schema.org/draft/2020-12/schema", "additionalProperties": false, "properties": { @@ -233,6 +233,6 @@ "id": "raes-semantic-invariants-v1", "keyword": "x-raes-invariants", "required": true, - "uri": "https://raesystem.github.io/rae/schemas/semantic-invariants/v1" + "uri": "https://openrae.github.io/rae/schemas/semantic-invariants/v1" } } diff --git a/contracts/schemas/profiles/scientific-completeness-taxonomy-v1.json b/contracts/schemas/profiles/scientific-completeness-taxonomy-v1.json index 385a6b541..cefa0c1ab 100644 --- a/contracts/schemas/profiles/scientific-completeness-taxonomy-v1.json +++ b/contracts/schemas/profiles/scientific-completeness-taxonomy-v1.json @@ -329,7 +329,7 @@ "type": "string" } }, - "$id": "https://raesystem.github.io/rae/schemas/scientific-completeness-taxonomy-v1.json", + "$id": "https://openrae.github.io/rae/schemas/scientific-completeness-taxonomy-v1.json", "$schema": "https://json-schema.org/draft/2020-12/schema", "additionalProperties": false, "properties": { @@ -411,6 +411,6 @@ "id": "raes-semantic-invariants-v1", "keyword": "x-raes-invariants", "required": true, - "uri": "https://raesystem.github.io/rae/schemas/semantic-invariants/v1" + "uri": "https://openrae.github.io/rae/schemas/semantic-invariants/v1" } } diff --git a/contracts/schemas/profiles/semantic-profile-v1.json b/contracts/schemas/profiles/semantic-profile-v1.json index dff0034b7..b8f01280d 100644 --- a/contracts/schemas/profiles/semantic-profile-v1.json +++ b/contracts/schemas/profiles/semantic-profile-v1.json @@ -92,7 +92,7 @@ "type": "object" } }, - "$id": "https://raesystem.github.io/rae/schemas/semantic-profile-v1.json", + "$id": "https://openrae.github.io/rae/schemas/semantic-profile-v1.json", "$schema": "https://json-schema.org/draft/2020-12/schema", "additionalProperties": false, "properties": { diff --git a/contracts/schemas/profiles/validation-basis-disclosure-v1.json b/contracts/schemas/profiles/validation-basis-disclosure-v1.json index a8121095f..d59785b57 100644 --- a/contracts/schemas/profiles/validation-basis-disclosure-v1.json +++ b/contracts/schemas/profiles/validation-basis-disclosure-v1.json @@ -552,7 +552,7 @@ "type": "object" } }, - "$id": "https://raesystem.github.io/rae/schemas/validation-basis-disclosure-v1.json", + "$id": "https://openrae.github.io/rae/schemas/validation-basis-disclosure-v1.json", "$schema": "https://json-schema.org/draft/2020-12/schema", "additionalProperties": false, "description": "Published wrapper adding ``schema_version`` around the embeddable disclosure core.", @@ -579,6 +579,6 @@ "id": "raes-semantic-invariants-v1", "keyword": "x-raes-invariants", "required": true, - "uri": "https://raesystem.github.io/rae/schemas/semantic-invariants/v1" + "uri": "https://openrae.github.io/rae/schemas/semantic-invariants/v1" } } diff --git a/contracts/schemas/profiles/validation-profile-catalog-v1.json b/contracts/schemas/profiles/validation-profile-catalog-v1.json index f55f71454..8ac00c8aa 100644 --- a/contracts/schemas/profiles/validation-profile-catalog-v1.json +++ b/contracts/schemas/profiles/validation-profile-catalog-v1.json @@ -187,7 +187,7 @@ "type": "object" } }, - "$id": "https://raesystem.github.io/rae/schemas/validation-profile-catalog-v1.json", + "$id": "https://openrae.github.io/rae/schemas/validation-profile-catalog-v1.json", "$schema": "https://json-schema.org/draft/2020-12/schema", "additionalProperties": false, "properties": { @@ -280,6 +280,6 @@ "id": "raes-semantic-invariants-v1", "keyword": "x-raes-invariants", "required": true, - "uri": "https://raesystem.github.io/rae/schemas/semantic-invariants/v1" + "uri": "https://openrae.github.io/rae/schemas/semantic-invariants/v1" } } diff --git a/contracts/schemas/provenance/sdl-lineage-ledger-v1.json b/contracts/schemas/provenance/sdl-lineage-ledger-v1.json index 91ecbf71e..9c64daee6 100644 --- a/contracts/schemas/provenance/sdl-lineage-ledger-v1.json +++ b/contracts/schemas/provenance/sdl-lineage-ledger-v1.json @@ -575,7 +575,7 @@ "type": "object" } }, - "$id": "https://raesystem.github.io/rae/schemas/sdl-lineage-ledger-v1.json", + "$id": "https://openrae.github.io/rae/schemas/sdl-lineage-ledger-v1.json", "$schema": "https://json-schema.org/draft/2020-12/schema", "additionalProperties": false, "properties": { diff --git a/contracts/schemas/realization-envelope/realization-envelope-v1.json b/contracts/schemas/realization-envelope/realization-envelope-v1.json index af9a25f0d..c09a7b18e 100644 --- a/contracts/schemas/realization-envelope/realization-envelope-v1.json +++ b/contracts/schemas/realization-envelope/realization-envelope-v1.json @@ -761,7 +761,7 @@ "type": "object" } }, - "$id": "https://raesystem.github.io/rae/schemas/realization-envelope-v1.json", + "$id": "https://openrae.github.io/rae/schemas/realization-envelope-v1.json", "$schema": "https://json-schema.org/draft/2020-12/schema", "additionalProperties": false, "description": "Published backend carrier: shared set expression plus truthful realization claims.", @@ -986,6 +986,6 @@ "id": "raes-semantic-invariants-v1", "keyword": "x-raes-invariants", "required": true, - "uri": "https://raesystem.github.io/rae/schemas/semantic-invariants/v1" + "uri": "https://openrae.github.io/rae/schemas/semantic-invariants/v1" } } diff --git a/contracts/schemas/satisfiability/scenario-satisfiability-evidence-v1.json b/contracts/schemas/satisfiability/scenario-satisfiability-evidence-v1.json index 12ffa4835..683d5c941 100644 --- a/contracts/schemas/satisfiability/scenario-satisfiability-evidence-v1.json +++ b/contracts/schemas/satisfiability/scenario-satisfiability-evidence-v1.json @@ -1552,13 +1552,28 @@ "service_materialization": { "anyOf": [ { - "$ref": "#/$defs/ServiceMaterialization" + "discriminator": { + "mapping": { + "service-content": "#/$defs/ServiceMaterialization", + "service-search-index-schema": "#/$defs/ServiceSearchIndexSchemaMaterialization" + }, + "propertyName": "interface_profile" + }, + "oneOf": [ + { + "$ref": "#/$defs/ServiceMaterialization" + }, + { + "$ref": "#/$defs/ServiceSearchIndexSchemaMaterialization" + } + ] }, { "type": "null" } ], - "default": null + "default": null, + "title": "Service Materialization" }, "source": { "anyOf": [ @@ -3787,7 +3802,7 @@ "properties": { "consumers": { "items": { - "$ref": "#/$defs/StatefulResourceConsumer" + "$ref": "#/$defs/GeneratedArtifactConsumer" }, "minItems": 1, "title": "Consumers", @@ -3841,10 +3856,51 @@ "title": "GeneratedArtifact", "type": "object" }, + "GeneratedArtifactConsumer": { + "additionalProperties": false, + "description": "A read-only artifact projection selected by output name.", + "properties": { + "access_mode": { + "$ref": "#/$defs/ConsumerAccessMode" + }, + "mount_destination": { + "title": "Mount Destination", + "type": "string" + }, + "node": { + "title": "Node", + "type": "string" + }, + "selected_outputs": { + "items": { + "maxLength": 64, + "minLength": 1, + "not": { + "pattern": "[^a-z0-9_-]" + }, + "pattern": "^[a-z0-9]", + "type": "string" + }, + "minItems": 1, + "title": "Selected Outputs", + "type": "array", + "uniqueItems": true + } + }, + "required": [ + "node", + "mount_destination", + "access_mode" + ], + "title": "GeneratedArtifactConsumer", + "type": "object" + }, "GeneratedArtifactKind": { + "description": "Portable kinds of material a provisioner may generate.", "enum": [ "certificate_bundle", - "rendered_config" + "rendered_config", + "ssh_key_bundle" ], "title": "GeneratedArtifactKind", "type": "string" @@ -3861,6 +3917,10 @@ "additionalProperties": false, "description": "One complete output declared by an artifact generator.", "properties": { + "disposition": { + "$ref": "#/$defs/GeneratedArtifactOutputDisposition", + "default": "consumer_selected" + }, "name": { "maxLength": 64, "minLength": 1, @@ -3887,6 +3947,14 @@ "title": "GeneratedArtifactOutput", "type": "object" }, + "GeneratedArtifactOutputDisposition": { + "enum": [ + "consumer_selected", + "producer_private" + ], + "title": "GeneratedArtifactOutputDisposition", + "type": "string" + }, "IdentityDomain": { "additionalProperties": false, "description": "Scenario-scoped authored identity domain.", @@ -20359,6 +20427,18 @@ "title": "Script", "type": "object" }, + "SearchIndexFieldSemantic": { + "description": "Portable top-level search-index field behavior.", + "enum": [ + "exact-token", + "full-text", + "integer", + "temporal", + "boolean" + ], + "title": "SearchIndexFieldSemantic", + "type": "string" + }, "SemanticDigest": { "additionalProperties": false, "description": "Profile-labelled digest of one expanded authoring scenario.", @@ -20618,10 +20698,10 @@ }, "required": [ "target_service_ref", - "requirements", "readback_assertion_refs", "evidence_requirement_refs", - "observation_boundary_refs" + "observation_boundary_refs", + "requirements" ], "title": "ServiceMaterialization", "type": "object" @@ -20702,6 +20782,123 @@ "title": "ServicePort", "type": "object" }, + "ServiceSearchIndexSchemaMaterialization": { + "additionalProperties": false, + "description": "Portable desired field schema for a named service-owned search index.", + "properties": { + "evidence_requirement_refs": { + "items": { + "type": "string" + }, + "minItems": 1, + "title": "Evidence Requirement Refs", + "type": "array" + }, + "interface_profile": { + "const": "service-search-index-schema", + "title": "Interface Profile", + "type": "string" + }, + "observation_boundary_refs": { + "items": { + "type": "string" + }, + "minItems": 1, + "title": "Observation Boundary Refs", + "type": "array" + }, + "ordering_content_refs": { + "items": { + "type": "string" + }, + "title": "Ordering Content Refs", + "type": "array" + }, + "profile_version": { + "const": "1", + "default": "1", + "title": "Profile Version", + "type": "string" + }, + "readback_assertion_refs": { + "items": { + "type": "string" + }, + "minItems": 1, + "title": "Readback Assertion Refs", + "type": "array" + }, + "requirements": { + "$ref": "#/$defs/ServiceSearchIndexSchemaRequirements" + }, + "shared_service_relationship_ref": { + "default": "", + "title": "Shared Service Relationship Ref", + "type": "string" + }, + "target_service_ref": { + "minLength": 1, + "title": "Target Service Ref", + "type": "string" + } + }, + "required": [ + "target_service_ref", + "readback_assertion_refs", + "evidence_requirement_refs", + "observation_boundary_refs", + "interface_profile", + "requirements" + ], + "title": "ServiceSearchIndexSchemaMaterialization", + "type": "object" + }, + "ServiceSearchIndexSchemaRequirements": { + "additionalProperties": false, + "description": "Exact portable search-index schema operation and readback.", + "properties": { + "conflict_policy": { + "const": "reject-unowned-collision", + "default": "reject-unowned-collision", + "title": "Conflict Policy", + "type": "string" + }, + "field_semantics": { + "minProperties": 1, + "patternProperties": { + "^[a-z0-9]": { + "$ref": "#/$defs/SearchIndexFieldSemantic" + } + }, + "propertyNames": { + "maxLength": 64, + "minLength": 1, + "not": { + "pattern": "[^a-z0-9_-]" + } + }, + "title": "Field Semantics", + "type": "object" + }, + "operation": { + "const": "ensure-search-index-field-schema", + "default": "ensure-search-index-field-schema", + "title": "Operation", + "type": "string" + }, + "readback": { + "const": "canonical-portable-field-schema-digest", + "default": "canonical-portable-field-schema-digest", + "title": "Readback", + "type": "string" + } + }, + "required": [ + "field_semantics" + ], + "title": "ServiceSearchIndexSchemaRequirements", + "type": "object" + }, "ServiceUnitActiveState": { "description": "Observed unit *active* state (``systemctl list-units`` ACTIVE column).", "enum": [ @@ -22442,7 +22639,7 @@ "type": "string" } }, - "$id": "https://raesystem.github.io/rae/schemas/scenario-satisfiability-evidence-v1.json", + "$id": "https://openrae.github.io/rae/schemas/scenario-satisfiability-evidence-v1.json", "$schema": "https://json-schema.org/draft/2020-12/schema", "additionalProperties": false, "description": "Closed evidence envelope binding source, model, solver, and result.", @@ -22569,6 +22766,6 @@ "id": "raes-semantic-invariants-v1", "keyword": "x-raes-invariants", "required": true, - "uri": "https://raesystem.github.io/rae/schemas/semantic-invariants/v1" + "uri": "https://openrae.github.io/rae/schemas/semantic-invariants/v1" } } diff --git a/contracts/schemas/sdl/instantiated-scenario-snapshot-v1.json b/contracts/schemas/sdl/instantiated-scenario-snapshot-v1.json index b5b5684c0..91398fc57 100644 --- a/contracts/schemas/sdl/instantiated-scenario-snapshot-v1.json +++ b/contracts/schemas/sdl/instantiated-scenario-snapshot-v1.json @@ -1697,13 +1697,28 @@ "service_materialization": { "anyOf": [ { - "$ref": "#/$defs/ServiceMaterialization" + "discriminator": { + "mapping": { + "service-content": "#/$defs/ServiceMaterialization", + "service-search-index-schema": "#/$defs/ServiceSearchIndexSchemaMaterialization" + }, + "propertyName": "interface_profile" + }, + "oneOf": [ + { + "$ref": "#/$defs/ServiceMaterialization" + }, + { + "$ref": "#/$defs/ServiceSearchIndexSchemaMaterialization" + } + ] }, { "type": "null" } ], - "default": null + "default": null, + "title": "Service Materialization" }, "source": { "anyOf": [ @@ -4369,7 +4384,7 @@ "properties": { "consumers": { "items": { - "$ref": "#/$defs/StatefulResourceConsumer" + "$ref": "#/$defs/GeneratedArtifactConsumer" }, "minItems": 1, "title": "Consumers", @@ -4432,10 +4447,64 @@ "title": "GeneratedArtifact", "type": "object" }, + "GeneratedArtifactConsumer": { + "additionalProperties": false, + "description": "A read-only artifact projection selected by output name.", + "properties": { + "access_mode": { + "$ref": "#/$defs/ConsumerAccessMode" + }, + "mount_destination": { + "not": { + "pattern": "\\$\\{((?:(?:[a-z0-9][a-z0-9_-]{0,63}|__private)\\.)*[a-z0-9][a-z0-9_-]{0,63})\\}" + }, + "title": "Mount Destination", + "type": "string" + }, + "node": { + "not": { + "pattern": "\\$\\{((?:(?:[a-z0-9][a-z0-9_-]{0,63}|__private)\\.)*[a-z0-9][a-z0-9_-]{0,63})\\}" + }, + "title": "Node", + "type": "string" + }, + "selected_outputs": { + "items": { + "allOf": [ + { + "not": { + "pattern": "\\$\\{((?:(?:[a-z0-9][a-z0-9_-]{0,63}|__private)\\.)*[a-z0-9][a-z0-9_-]{0,63})\\}" + } + } + ], + "maxLength": 64, + "minLength": 1, + "not": { + "pattern": "[^a-z0-9_-]" + }, + "pattern": "^[a-z0-9]", + "type": "string" + }, + "minItems": 1, + "title": "Selected Outputs", + "type": "array", + "uniqueItems": true + } + }, + "required": [ + "node", + "mount_destination", + "access_mode" + ], + "title": "GeneratedArtifactConsumer", + "type": "object" + }, "GeneratedArtifactKind": { + "description": "Portable kinds of material a provisioner may generate.", "enum": [ "certificate_bundle", - "rendered_config" + "rendered_config", + "ssh_key_bundle" ], "title": "GeneratedArtifactKind", "type": "string" @@ -4452,6 +4521,10 @@ "additionalProperties": false, "description": "One complete output declared by an artifact generator.", "properties": { + "disposition": { + "$ref": "#/$defs/GeneratedArtifactOutputDisposition", + "default": "consumer_selected" + }, "name": { "allOf": [ { @@ -4488,6 +4561,14 @@ "title": "GeneratedArtifactOutput", "type": "object" }, + "GeneratedArtifactOutputDisposition": { + "enum": [ + "consumer_selected", + "producer_private" + ], + "title": "GeneratedArtifactOutputDisposition", + "type": "string" + }, "IdentityDomain": { "additionalProperties": false, "description": "Scenario-scoped authored identity domain.", @@ -25309,6 +25390,18 @@ "title": "Script", "type": "object" }, + "SearchIndexFieldSemantic": { + "description": "Portable top-level search-index field behavior.", + "enum": [ + "exact-token", + "full-text", + "integer", + "temporal", + "boolean" + ], + "title": "SearchIndexFieldSemantic", + "type": "string" + }, "SemanticDigest": { "additionalProperties": false, "description": "Profile-labelled digest of one expanded authoring scenario.", @@ -25634,10 +25727,10 @@ }, "required": [ "target_service_ref", - "requirements", "readback_assertion_refs", "evidence_requirement_refs", - "observation_boundary_refs" + "observation_boundary_refs", + "requirements" ], "title": "ServiceMaterialization", "type": "object" @@ -25734,6 +25827,141 @@ "title": "ServicePort", "type": "object" }, + "ServiceSearchIndexSchemaMaterialization": { + "additionalProperties": false, + "description": "Portable desired field schema for a named service-owned search index.", + "properties": { + "evidence_requirement_refs": { + "items": { + "not": { + "pattern": "\\$\\{((?:(?:[a-z0-9][a-z0-9_-]{0,63}|__private)\\.)*[a-z0-9][a-z0-9_-]{0,63})\\}" + }, + "type": "string" + }, + "minItems": 1, + "title": "Evidence Requirement Refs", + "type": "array" + }, + "interface_profile": { + "const": "service-search-index-schema", + "title": "Interface Profile", + "type": "string" + }, + "observation_boundary_refs": { + "items": { + "not": { + "pattern": "\\$\\{((?:(?:[a-z0-9][a-z0-9_-]{0,63}|__private)\\.)*[a-z0-9][a-z0-9_-]{0,63})\\}" + }, + "type": "string" + }, + "minItems": 1, + "title": "Observation Boundary Refs", + "type": "array" + }, + "ordering_content_refs": { + "items": { + "not": { + "pattern": "\\$\\{((?:(?:[a-z0-9][a-z0-9_-]{0,63}|__private)\\.)*[a-z0-9][a-z0-9_-]{0,63})\\}" + }, + "type": "string" + }, + "title": "Ordering Content Refs", + "type": "array" + }, + "profile_version": { + "const": "1", + "default": "1", + "title": "Profile Version", + "type": "string" + }, + "readback_assertion_refs": { + "items": { + "not": { + "pattern": "\\$\\{((?:(?:[a-z0-9][a-z0-9_-]{0,63}|__private)\\.)*[a-z0-9][a-z0-9_-]{0,63})\\}" + }, + "type": "string" + }, + "minItems": 1, + "title": "Readback Assertion Refs", + "type": "array" + }, + "requirements": { + "$ref": "#/$defs/ServiceSearchIndexSchemaRequirements" + }, + "shared_service_relationship_ref": { + "default": "", + "not": { + "pattern": "\\$\\{((?:(?:[a-z0-9][a-z0-9_-]{0,63}|__private)\\.)*[a-z0-9][a-z0-9_-]{0,63})\\}" + }, + "title": "Shared Service Relationship Ref", + "type": "string" + }, + "target_service_ref": { + "minLength": 1, + "not": { + "pattern": "\\$\\{((?:(?:[a-z0-9][a-z0-9_-]{0,63}|__private)\\.)*[a-z0-9][a-z0-9_-]{0,63})\\}" + }, + "title": "Target Service Ref", + "type": "string" + } + }, + "required": [ + "target_service_ref", + "readback_assertion_refs", + "evidence_requirement_refs", + "observation_boundary_refs", + "interface_profile", + "requirements" + ], + "title": "ServiceSearchIndexSchemaMaterialization", + "type": "object" + }, + "ServiceSearchIndexSchemaRequirements": { + "additionalProperties": false, + "description": "Exact portable search-index schema operation and readback.", + "properties": { + "conflict_policy": { + "const": "reject-unowned-collision", + "default": "reject-unowned-collision", + "title": "Conflict Policy", + "type": "string" + }, + "field_semantics": { + "minProperties": 1, + "patternProperties": { + "^[a-z0-9]": { + "$ref": "#/$defs/SearchIndexFieldSemantic" + } + }, + "propertyNames": { + "maxLength": 64, + "minLength": 1, + "not": { + "pattern": "[^a-z0-9_-]" + } + }, + "title": "Field Semantics", + "type": "object" + }, + "operation": { + "const": "ensure-search-index-field-schema", + "default": "ensure-search-index-field-schema", + "title": "Operation", + "type": "string" + }, + "readback": { + "const": "canonical-portable-field-schema-digest", + "default": "canonical-portable-field-schema-digest", + "title": "Readback", + "type": "string" + } + }, + "required": [ + "field_semantics" + ], + "title": "ServiceSearchIndexSchemaRequirements", + "type": "object" + }, "ServiceUnitActiveState": { "description": "Observed unit *active* state (``systemctl list-units`` ACTIVE column).", "enum": [ @@ -27567,7 +27795,7 @@ "type": "string" } }, - "$id": "https://raesystem.github.io/rae/schemas/instantiated-scenario-snapshot-v1.json", + "$id": "https://openrae.github.io/rae/schemas/instantiated-scenario-snapshot-v1.json", "$schema": "https://json-schema.org/draft/2020-12/schema", "additionalProperties": false, "description": "Sealed canonical envelope for one portable instantiated artifact.", @@ -27590,7 +27818,7 @@ "x-raes-document-phase": "canonical-instantiated-snapshot", "x-raes-invariants": [ { - "description": "Generated artifact output names and paths, consumers, and dependency entries must be unique, and generated artifact consumers must be read-only.", + "description": "Generated artifact output names and paths, consumers, and dependency entries must be unique, and generated artifact consumers must be read-only. Explicit selections must name declared consumer-selectable outputs; SSH artifact consumers must select outputs and every consumer-selectable SSH output must be selected.", "id": "stateful-generated-artifact-semantics", "inputs": [ { @@ -27645,6 +27873,6 @@ "id": "raes-semantic-invariants-v1", "keyword": "x-raes-invariants", "required": true, - "uri": "https://raesystem.github.io/rae/schemas/semantic-invariants/v1" + "uri": "https://openrae.github.io/rae/schemas/semantic-invariants/v1" } } diff --git a/contracts/schemas/sdl/instantiated-scenario-v1.json b/contracts/schemas/sdl/instantiated-scenario-v1.json index a6b9de359..ee4f3a83a 100644 --- a/contracts/schemas/sdl/instantiated-scenario-v1.json +++ b/contracts/schemas/sdl/instantiated-scenario-v1.json @@ -1697,13 +1697,28 @@ "service_materialization": { "anyOf": [ { - "$ref": "#/$defs/ServiceMaterialization" + "discriminator": { + "mapping": { + "service-content": "#/$defs/ServiceMaterialization", + "service-search-index-schema": "#/$defs/ServiceSearchIndexSchemaMaterialization" + }, + "propertyName": "interface_profile" + }, + "oneOf": [ + { + "$ref": "#/$defs/ServiceMaterialization" + }, + { + "$ref": "#/$defs/ServiceSearchIndexSchemaMaterialization" + } + ] }, { "type": "null" } ], - "default": null + "default": null, + "title": "Service Materialization" }, "source": { "anyOf": [ @@ -4369,7 +4384,7 @@ "properties": { "consumers": { "items": { - "$ref": "#/$defs/StatefulResourceConsumer" + "$ref": "#/$defs/GeneratedArtifactConsumer" }, "minItems": 1, "title": "Consumers", @@ -4432,10 +4447,64 @@ "title": "GeneratedArtifact", "type": "object" }, + "GeneratedArtifactConsumer": { + "additionalProperties": false, + "description": "A read-only artifact projection selected by output name.", + "properties": { + "access_mode": { + "$ref": "#/$defs/ConsumerAccessMode" + }, + "mount_destination": { + "not": { + "pattern": "\\$\\{((?:(?:[a-z0-9][a-z0-9_-]{0,63}|__private)\\.)*[a-z0-9][a-z0-9_-]{0,63})\\}" + }, + "title": "Mount Destination", + "type": "string" + }, + "node": { + "not": { + "pattern": "\\$\\{((?:(?:[a-z0-9][a-z0-9_-]{0,63}|__private)\\.)*[a-z0-9][a-z0-9_-]{0,63})\\}" + }, + "title": "Node", + "type": "string" + }, + "selected_outputs": { + "items": { + "allOf": [ + { + "not": { + "pattern": "\\$\\{((?:(?:[a-z0-9][a-z0-9_-]{0,63}|__private)\\.)*[a-z0-9][a-z0-9_-]{0,63})\\}" + } + } + ], + "maxLength": 64, + "minLength": 1, + "not": { + "pattern": "[^a-z0-9_-]" + }, + "pattern": "^[a-z0-9]", + "type": "string" + }, + "minItems": 1, + "title": "Selected Outputs", + "type": "array", + "uniqueItems": true + } + }, + "required": [ + "node", + "mount_destination", + "access_mode" + ], + "title": "GeneratedArtifactConsumer", + "type": "object" + }, "GeneratedArtifactKind": { + "description": "Portable kinds of material a provisioner may generate.", "enum": [ "certificate_bundle", - "rendered_config" + "rendered_config", + "ssh_key_bundle" ], "title": "GeneratedArtifactKind", "type": "string" @@ -4452,6 +4521,10 @@ "additionalProperties": false, "description": "One complete output declared by an artifact generator.", "properties": { + "disposition": { + "$ref": "#/$defs/GeneratedArtifactOutputDisposition", + "default": "consumer_selected" + }, "name": { "allOf": [ { @@ -4488,6 +4561,14 @@ "title": "GeneratedArtifactOutput", "type": "object" }, + "GeneratedArtifactOutputDisposition": { + "enum": [ + "consumer_selected", + "producer_private" + ], + "title": "GeneratedArtifactOutputDisposition", + "type": "string" + }, "IdentityDomain": { "additionalProperties": false, "description": "Scenario-scoped authored identity domain.", @@ -24666,6 +24747,18 @@ "title": "Script", "type": "object" }, + "SearchIndexFieldSemantic": { + "description": "Portable top-level search-index field behavior.", + "enum": [ + "exact-token", + "full-text", + "integer", + "temporal", + "boolean" + ], + "title": "SearchIndexFieldSemantic", + "type": "string" + }, "SemanticDigest": { "additionalProperties": false, "description": "Profile-labelled digest of one expanded authoring scenario.", @@ -24991,10 +25084,10 @@ }, "required": [ "target_service_ref", - "requirements", "readback_assertion_refs", "evidence_requirement_refs", - "observation_boundary_refs" + "observation_boundary_refs", + "requirements" ], "title": "ServiceMaterialization", "type": "object" @@ -25091,6 +25184,141 @@ "title": "ServicePort", "type": "object" }, + "ServiceSearchIndexSchemaMaterialization": { + "additionalProperties": false, + "description": "Portable desired field schema for a named service-owned search index.", + "properties": { + "evidence_requirement_refs": { + "items": { + "not": { + "pattern": "\\$\\{((?:(?:[a-z0-9][a-z0-9_-]{0,63}|__private)\\.)*[a-z0-9][a-z0-9_-]{0,63})\\}" + }, + "type": "string" + }, + "minItems": 1, + "title": "Evidence Requirement Refs", + "type": "array" + }, + "interface_profile": { + "const": "service-search-index-schema", + "title": "Interface Profile", + "type": "string" + }, + "observation_boundary_refs": { + "items": { + "not": { + "pattern": "\\$\\{((?:(?:[a-z0-9][a-z0-9_-]{0,63}|__private)\\.)*[a-z0-9][a-z0-9_-]{0,63})\\}" + }, + "type": "string" + }, + "minItems": 1, + "title": "Observation Boundary Refs", + "type": "array" + }, + "ordering_content_refs": { + "items": { + "not": { + "pattern": "\\$\\{((?:(?:[a-z0-9][a-z0-9_-]{0,63}|__private)\\.)*[a-z0-9][a-z0-9_-]{0,63})\\}" + }, + "type": "string" + }, + "title": "Ordering Content Refs", + "type": "array" + }, + "profile_version": { + "const": "1", + "default": "1", + "title": "Profile Version", + "type": "string" + }, + "readback_assertion_refs": { + "items": { + "not": { + "pattern": "\\$\\{((?:(?:[a-z0-9][a-z0-9_-]{0,63}|__private)\\.)*[a-z0-9][a-z0-9_-]{0,63})\\}" + }, + "type": "string" + }, + "minItems": 1, + "title": "Readback Assertion Refs", + "type": "array" + }, + "requirements": { + "$ref": "#/$defs/ServiceSearchIndexSchemaRequirements" + }, + "shared_service_relationship_ref": { + "default": "", + "not": { + "pattern": "\\$\\{((?:(?:[a-z0-9][a-z0-9_-]{0,63}|__private)\\.)*[a-z0-9][a-z0-9_-]{0,63})\\}" + }, + "title": "Shared Service Relationship Ref", + "type": "string" + }, + "target_service_ref": { + "minLength": 1, + "not": { + "pattern": "\\$\\{((?:(?:[a-z0-9][a-z0-9_-]{0,63}|__private)\\.)*[a-z0-9][a-z0-9_-]{0,63})\\}" + }, + "title": "Target Service Ref", + "type": "string" + } + }, + "required": [ + "target_service_ref", + "readback_assertion_refs", + "evidence_requirement_refs", + "observation_boundary_refs", + "interface_profile", + "requirements" + ], + "title": "ServiceSearchIndexSchemaMaterialization", + "type": "object" + }, + "ServiceSearchIndexSchemaRequirements": { + "additionalProperties": false, + "description": "Exact portable search-index schema operation and readback.", + "properties": { + "conflict_policy": { + "const": "reject-unowned-collision", + "default": "reject-unowned-collision", + "title": "Conflict Policy", + "type": "string" + }, + "field_semantics": { + "minProperties": 1, + "patternProperties": { + "^[a-z0-9]": { + "$ref": "#/$defs/SearchIndexFieldSemantic" + } + }, + "propertyNames": { + "maxLength": 64, + "minLength": 1, + "not": { + "pattern": "[^a-z0-9_-]" + } + }, + "title": "Field Semantics", + "type": "object" + }, + "operation": { + "const": "ensure-search-index-field-schema", + "default": "ensure-search-index-field-schema", + "title": "Operation", + "type": "string" + }, + "readback": { + "const": "canonical-portable-field-schema-digest", + "default": "canonical-portable-field-schema-digest", + "title": "Readback", + "type": "string" + } + }, + "required": [ + "field_semantics" + ], + "title": "ServiceSearchIndexSchemaRequirements", + "type": "object" + }, "ServiceUnitActiveState": { "description": "Observed unit *active* state (``systemctl list-units`` ACTIVE column).", "enum": [ @@ -26924,7 +27152,7 @@ "type": "string" } }, - "$id": "https://raesystem.github.io/rae/schemas/instantiated-scenario-v1.json", + "$id": "https://openrae.github.io/rae/schemas/instantiated-scenario-v1.json", "$schema": "https://json-schema.org/draft/2020-12/schema", "additionalProperties": false, "description": "Scenario with all ``${var}`` references resolved to concrete values.\n\nUnlike the authoring-input contract, an instantiated scenario MUST NOT\ncontain any unresolved ``${name}`` substitution token in any string value,\nwhether a whole-string placeholder (``\"${os}\"``) or embedded\n(``\"host-${index}\"``). The invariant is enforced both by the model\nvalidator below and by the published ``instantiated-scenario-v1`` JSON\nSchema, which forbids the token in every string field. The schema is\nIf a resolved variable value itself introduces a literal ``${name}``\nsequence, the single-pass substitution step does not interpret it as a\nsecond substitution request; final model admission still treats the result\nas non-concrete and rejects the public instantiation.", @@ -27569,7 +27797,7 @@ "x-raes-document-phase": "instantiated-scenario", "x-raes-invariants": [ { - "description": "Generated artifact output names and paths, consumers, and dependency entries must be unique, and generated artifact consumers must be read-only.", + "description": "Generated artifact output names and paths, consumers, and dependency entries must be unique, and generated artifact consumers must be read-only. Explicit selections must name declared consumer-selectable outputs; SSH artifact consumers must select outputs and every consumer-selectable SSH output must be selected.", "id": "stateful-generated-artifact-semantics", "inputs": [ { @@ -27624,6 +27852,6 @@ "id": "raes-semantic-invariants-v1", "keyword": "x-raes-invariants", "required": true, - "uri": "https://raesystem.github.io/rae/schemas/semantic-invariants/v1" + "uri": "https://openrae.github.io/rae/schemas/semantic-invariants/v1" } } diff --git a/contracts/schemas/sdl/scenario-instantiation-request-v1.json b/contracts/schemas/sdl/scenario-instantiation-request-v1.json index 040ef81fe..3fc3f3315 100644 --- a/contracts/schemas/sdl/scenario-instantiation-request-v1.json +++ b/contracts/schemas/sdl/scenario-instantiation-request-v1.json @@ -1,5 +1,5 @@ { - "$id": "https://raesystem.github.io/rae/schemas/scenario-instantiation-request-v1.json", + "$id": "https://openrae.github.io/rae/schemas/scenario-instantiation-request-v1.json", "$schema": "https://json-schema.org/draft/2020-12/schema", "additionalProperties": false, "properties": { diff --git a/contracts/schemas/sdl/sdl-authoring-input-v1.json b/contracts/schemas/sdl/sdl-authoring-input-v1.json index 1c639284a..84aab29e0 100644 --- a/contracts/schemas/sdl/sdl-authoring-input-v1.json +++ b/contracts/schemas/sdl/sdl-authoring-input-v1.json @@ -1413,13 +1413,28 @@ "service_materialization": { "anyOf": [ { - "$ref": "#/$defs/ServiceMaterialization" + "discriminator": { + "mapping": { + "service-content": "#/$defs/ServiceMaterialization", + "service-search-index-schema": "#/$defs/ServiceSearchIndexSchemaMaterialization" + }, + "propertyName": "interface_profile" + }, + "oneOf": [ + { + "$ref": "#/$defs/ServiceMaterialization" + }, + { + "$ref": "#/$defs/ServiceSearchIndexSchemaMaterialization" + } + ] }, { "type": "null" } ], - "default": null + "default": null, + "title": "Service Materialization" }, "source": { "anyOf": [ @@ -3635,7 +3650,7 @@ "properties": { "consumers": { "items": { - "$ref": "#/$defs/StatefulResourceConsumer" + "$ref": "#/$defs/GeneratedArtifactConsumer" }, "minItems": 1, "title": "Consumers", @@ -3689,10 +3704,51 @@ "title": "GeneratedArtifact", "type": "object" }, + "GeneratedArtifactConsumer": { + "additionalProperties": false, + "description": "A read-only artifact projection selected by output name.", + "properties": { + "access_mode": { + "$ref": "#/$defs/ConsumerAccessMode" + }, + "mount_destination": { + "title": "Mount Destination", + "type": "string" + }, + "node": { + "title": "Node", + "type": "string" + }, + "selected_outputs": { + "items": { + "maxLength": 64, + "minLength": 1, + "not": { + "pattern": "[^a-z0-9_-]" + }, + "pattern": "^[a-z0-9]", + "type": "string" + }, + "minItems": 1, + "title": "Selected Outputs", + "type": "array", + "uniqueItems": true + } + }, + "required": [ + "node", + "mount_destination", + "access_mode" + ], + "title": "GeneratedArtifactConsumer", + "type": "object" + }, "GeneratedArtifactKind": { + "description": "Portable kinds of material a provisioner may generate.", "enum": [ "certificate_bundle", - "rendered_config" + "rendered_config", + "ssh_key_bundle" ], "title": "GeneratedArtifactKind", "type": "string" @@ -3709,6 +3765,10 @@ "additionalProperties": false, "description": "One complete output declared by an artifact generator.", "properties": { + "disposition": { + "$ref": "#/$defs/GeneratedArtifactOutputDisposition", + "default": "consumer_selected" + }, "name": { "maxLength": 64, "minLength": 1, @@ -3735,6 +3795,14 @@ "title": "GeneratedArtifactOutput", "type": "object" }, + "GeneratedArtifactOutputDisposition": { + "enum": [ + "consumer_selected", + "producer_private" + ], + "title": "GeneratedArtifactOutputDisposition", + "type": "string" + }, "GovernedReferenceDomain": { "additionalProperties": false, "description": "References in a finite governed set under a named authority.", @@ -20452,6 +20520,18 @@ "title": "Script", "type": "object" }, + "SearchIndexFieldSemantic": { + "description": "Portable top-level search-index field behavior.", + "enum": [ + "exact-token", + "full-text", + "integer", + "temporal", + "boolean" + ], + "title": "SearchIndexFieldSemantic", + "type": "string" + }, "SelectionRelation": { "additionalProperties": false, "description": "A finite cross-point member requirement or exclusion.", @@ -20715,10 +20795,10 @@ }, "required": [ "target_service_ref", - "requirements", "readback_assertion_refs", "evidence_requirement_refs", - "observation_boundary_refs" + "observation_boundary_refs", + "requirements" ], "title": "ServiceMaterialization", "type": "object" @@ -20799,6 +20879,123 @@ "title": "ServicePort", "type": "object" }, + "ServiceSearchIndexSchemaMaterialization": { + "additionalProperties": false, + "description": "Portable desired field schema for a named service-owned search index.", + "properties": { + "evidence_requirement_refs": { + "items": { + "type": "string" + }, + "minItems": 1, + "title": "Evidence Requirement Refs", + "type": "array" + }, + "interface_profile": { + "const": "service-search-index-schema", + "title": "Interface Profile", + "type": "string" + }, + "observation_boundary_refs": { + "items": { + "type": "string" + }, + "minItems": 1, + "title": "Observation Boundary Refs", + "type": "array" + }, + "ordering_content_refs": { + "items": { + "type": "string" + }, + "title": "Ordering Content Refs", + "type": "array" + }, + "profile_version": { + "const": "1", + "default": "1", + "title": "Profile Version", + "type": "string" + }, + "readback_assertion_refs": { + "items": { + "type": "string" + }, + "minItems": 1, + "title": "Readback Assertion Refs", + "type": "array" + }, + "requirements": { + "$ref": "#/$defs/ServiceSearchIndexSchemaRequirements" + }, + "shared_service_relationship_ref": { + "default": "", + "title": "Shared Service Relationship Ref", + "type": "string" + }, + "target_service_ref": { + "minLength": 1, + "title": "Target Service Ref", + "type": "string" + } + }, + "required": [ + "target_service_ref", + "readback_assertion_refs", + "evidence_requirement_refs", + "observation_boundary_refs", + "interface_profile", + "requirements" + ], + "title": "ServiceSearchIndexSchemaMaterialization", + "type": "object" + }, + "ServiceSearchIndexSchemaRequirements": { + "additionalProperties": false, + "description": "Exact portable search-index schema operation and readback.", + "properties": { + "conflict_policy": { + "const": "reject-unowned-collision", + "default": "reject-unowned-collision", + "title": "Conflict Policy", + "type": "string" + }, + "field_semantics": { + "minProperties": 1, + "patternProperties": { + "^[a-z0-9]": { + "$ref": "#/$defs/SearchIndexFieldSemantic" + } + }, + "propertyNames": { + "maxLength": 64, + "minLength": 1, + "not": { + "pattern": "[^a-z0-9_-]" + } + }, + "title": "Field Semantics", + "type": "object" + }, + "operation": { + "const": "ensure-search-index-field-schema", + "default": "ensure-search-index-field-schema", + "title": "Operation", + "type": "string" + }, + "readback": { + "const": "canonical-portable-field-schema-digest", + "default": "canonical-portable-field-schema-digest", + "title": "Readback", + "type": "string" + } + }, + "required": [ + "field_semantics" + ], + "title": "ServiceSearchIndexSchemaRequirements", + "type": "object" + }, "ServiceUnitActiveState": { "description": "Observed unit *active* state (``systemctl list-units`` ACTIVE column).", "enum": [ @@ -22446,7 +22643,7 @@ "type": "string" } }, - "$id": "https://raesystem.github.io/rae/schemas/sdl-authoring-input-v1.json", + "$id": "https://openrae.github.io/rae/schemas/sdl-authoring-input-v1.json", "$schema": "https://json-schema.org/draft/2020-12/schema", "additionalProperties": false, "description": "Normalized SDL authoring object.\n\nThis model applies after ``sdl-yaml/v1`` source-profile checks, structural\nkey canonicalization, shorthand expansion, enum normalization, and typed\nconstruction, but before module expansion and instantiation. Its JSON\nSchema does not validate YAML presentation details.", @@ -23160,7 +23357,7 @@ "x-raes-document-phase": "normalized-authoring-object", "x-raes-invariants": [ { - "description": "Generated artifact output names and paths, consumers, and dependency entries must be unique, and generated artifact consumers must be read-only.", + "description": "Generated artifact output names and paths, consumers, and dependency entries must be unique, and generated artifact consumers must be read-only. Explicit selections must name declared consumer-selectable outputs; SSH artifact consumers must select outputs and every consumer-selectable SSH output must be selected.", "id": "stateful-generated-artifact-semantics", "inputs": [ { @@ -23215,7 +23412,7 @@ "id": "raes-semantic-invariants-v1", "keyword": "x-raes-invariants", "required": true, - "uri": "https://raesystem.github.io/rae/schemas/semantic-invariants/v1" + "uri": "https://openrae.github.io/rae/schemas/semantic-invariants/v1" }, "x-raes-source-profile": "sdl-yaml/v1", "x-raes-validates-raw-source": false diff --git a/contracts/schemas/snapshots/runtime-snapshot-v1.json b/contracts/schemas/snapshots/runtime-snapshot-v1.json index 1a1ae97f5..a5b986855 100644 --- a/contracts/schemas/snapshots/runtime-snapshot-v1.json +++ b/contracts/schemas/snapshots/runtime-snapshot-v1.json @@ -9995,7 +9995,7 @@ "type": "object" } }, - "$id": "https://raesystem.github.io/rae/schemas/runtime-snapshot-v1.json", + "$id": "https://openrae.github.io/rae/schemas/runtime-snapshot-v1.json", "$schema": "https://json-schema.org/draft/2020-12/schema", "additionalProperties": false, "description": "Published envelope for a live runtime snapshot.\n\nParticipant episode surfaces (``participant_episode_results`` and\n``participant_episode_history``) are both keyed by the stable\n``participant_address`` of the participant the state/history belongs\nto. SEM-208 participant behavior history is keyed the same way and\nrecords action, observation, and state-transition events with compiled\nbehavior-contract addresses. The episode results map carries the\ncurrently-live episode state per participant; prior episodes survive only\nthrough append-only history streams and the ``previous_episode_id`` chain\non each state.", @@ -10223,6 +10223,6 @@ "id": "raes-semantic-invariants-v1", "keyword": "x-raes-invariants", "required": true, - "uri": "https://raesystem.github.io/rae/schemas/semantic-invariants/v1" + "uri": "https://openrae.github.io/rae/schemas/semantic-invariants/v1" } } diff --git a/contracts/schemas/time/realized-time-model-v1.json b/contracts/schemas/time/realized-time-model-v1.json index 04e332c15..47a045ffc 100644 --- a/contracts/schemas/time/realized-time-model-v1.json +++ b/contracts/schemas/time/realized-time-model-v1.json @@ -693,7 +693,7 @@ "type": "object" } }, - "$id": "https://raesystem.github.io/rae/schemas/realized-time-model-v1.json", + "$id": "https://openrae.github.io/rae/schemas/realized-time-model-v1.json", "$schema": "https://json-schema.org/draft/2020-12/schema", "additionalProperties": false, "description": "Run-scoped declaration/realization comparison and apparatus evidence.", diff --git a/contracts/schemas/time/time-model-v1.json b/contracts/schemas/time/time-model-v1.json index 67e202e0b..f8a9e67b9 100644 --- a/contracts/schemas/time/time-model-v1.json +++ b/contracts/schemas/time/time-model-v1.json @@ -479,7 +479,7 @@ "type": "object" } }, - "$id": "https://raesystem.github.io/rae/schemas/time-model-v1.json", + "$id": "https://openrae.github.io/rae/schemas/time-model-v1.json", "$schema": "https://json-schema.org/draft/2020-12/schema", "additionalProperties": false, "description": "Canonical backend-neutral declaration compiled from authored SDL.", diff --git a/contracts/schemas/time/time-runtime-state-v1.json b/contracts/schemas/time/time-runtime-state-v1.json index 9afc47e10..4e96fa16f 100644 --- a/contracts/schemas/time/time-runtime-state-v1.json +++ b/contracts/schemas/time/time-runtime-state-v1.json @@ -175,7 +175,7 @@ "type": "object" } }, - "$id": "https://raesystem.github.io/rae/schemas/time-runtime-state-v1.json", + "$id": "https://openrae.github.io/rae/schemas/time-runtime-state-v1.json", "$schema": "https://json-schema.org/draft/2020-12/schema", "additionalProperties": false, "description": "Typed observable state for all clocks governed by one declaration.", diff --git a/docs/DEVELOPMENT_WORKFLOW.md b/docs/DEVELOPMENT_WORKFLOW.md index 1dc0667a1..765599a29 100644 --- a/docs/DEVELOPMENT_WORKFLOW.md +++ b/docs/DEVELOPMENT_WORKFLOW.md @@ -30,6 +30,21 @@ warning-strict Sphinx HTML, generated route and search inventories, and links: uv tool run --from 'nox[uv]==2026.4.10' nox -f noxfile.py -s docs ``` +## Respect package boundaries + +`tools/policy/adr_policy.yaml` defines the public import facades allowed across +RAES packages. Adapters import owning domain APIs only through those listed +facades and never through private modules. For example, the semantic CLI calls +SDL compilation through `raes_processor.compiler`; adding another CLI/compiler +interaction extends that public facade instead of importing compiler internals +or duplicating compiler behavior in `raes_cli`. + +Run the repository policy session after changing a cross-package import: + +```shell +uv tool run --from 'nox[uv]==2026.4.10' nox -f noxfile.py -s policy +``` + ## Release model Release Please owns `CHANGELOG.md`, package versions, GitHub releases, and the diff --git a/docs/decisions/adrs/README.md b/docs/decisions/adrs/README.md index f8aed6c2e..d065ab01f 100644 --- a/docs/decisions/adrs/README.md +++ b/docs/decisions/adrs/README.md @@ -144,6 +144,7 @@ adr-097-scoped-participant-resource-budgets-and-shared-service-fairness adr-098-portable-artifact-requirement-satisfaction adr-099-participant-relative-predicate-opacity adr-100-participant-crossing-bisimulation +adr-101-adversarial-participant-flow-control ``` | ADR | Title | Status | Date | @@ -248,3 +249,5 @@ adr-100-participant-crossing-bisimulation | [098](adr-098-portable-artifact-requirement-satisfaction.md) | Portable Artifact Requirement Satisfaction | accepted | 2026-07-27 | | [099](adr-099-participant-relative-predicate-opacity.md) | Participant-Relative Predicate Opacity | accepted | 2026-07-29 | | [100](adr-100-participant-crossing-bisimulation.md) | Proof-Bearing Participant-Crossing Bisimulation | accepted | 2026-07-29 | +| [101](adr-101-adversarial-participant-flow-control.md) | Adversarial Participant Boundary Flow Control | accepted | 2026-07-30 | +| [102](adr-102-mixed-cross-backend-participant-control.md) | Mixed Cross-Backend Participant Control | accepted | 2026-07-31 | diff --git a/docs/decisions/adrs/adr-014-nox-as-canonical-verification-graph.md b/docs/decisions/adrs/adr-014-nox-as-canonical-verification-graph.md index b9c00217c..044f8f7b3 100644 --- a/docs/decisions/adrs/adr-014-nox-as-canonical-verification-graph.md +++ b/docs/decisions/adrs/adr-014-nox-as-canonical-verification-graph.md @@ -60,7 +60,8 @@ a session with explicit substages, run sequentially through a - `docs` — sphinx-build (added by AUT-805) - `verify` — composes hygiene + policy + lint + contracts + tests + docs - `hook-pre-commit` — staged-file hygiene + policy + scoped lint + - conditional contracts + scoped tests + conditional contracts + directly changed test modules (the full regression + sweep remains mandatory at pre-push and completion) - `hook-pre-push` — full hygiene + policy + lint + contracts + tests + fuzz @@ -71,6 +72,11 @@ their work through the same per-gate helpers (`_run_hygiene`, `_run_policy`, `_run_lint`, `_run_contracts`, `_run_tests`, `_run_fuzz`, `_run_docs`). +Ground Control invokes pre-commit against the staged set. It does not add +`--all-files`: that flag expands the hook input to every repository path, +defeats staged change classification, and duplicates the full regression work +that the pre-push and completion boundaries already run. + ### 2. `.pre-commit-config.yaml` is a thin trigger layer, not a parallel definition Pre-commit's repo-side configuration declares one hook per nox session @@ -204,3 +210,9 @@ absence). nox is the right answer for this repository specifically because the verification surface is broad, polyglot at the gate level (Python + OPA + gitleaks + Sphinx), and consumed identically from local hooks, CI, and ground-control automation. + +## Amendments + +| Date | Commit/PR | Summary | +|---|---|---| +| 2026-07-31 | #963 | Replaced the serial `verify` composition with six isolated, CPU-budgeted concurrent nox lanes, primed shared policy tooling before cold-cache lanes, batched JSON artifacts by shared schema with bounded concurrency, combined unit and integration coverage deterministically, scoped pre-commit to staged changes and directly changed tests without duplicating the mandatory full pre-push/completion regression, and separated network-dependent external-link validation into dedicated docs CI. Ground Control's completion half omits policy because its mechanically enforced policy half runs immediately afterward; direct `verify` and CI retain policy. | diff --git a/docs/decisions/adrs/adr-096-identity-cutover-and-historical-record-boundary.md b/docs/decisions/adrs/adr-096-identity-cutover-and-historical-record-boundary.md index d3d56b216..cfee5613a 100644 --- a/docs/decisions/adrs/adr-096-identity-cutover-and-historical-record-boundary.md +++ b/docs/decisions/adrs/adr-096-identity-cutover-and-historical-record-boundary.md @@ -137,3 +137,4 @@ validation, or evidence semantics beyond their identity-bearing values. | 2026-07-26 | #908 | Retained the existing SonarCloud project key as an exact, content-bound external-service designation; it is not a current RAES product identity or a general compatibility allowance. | | 2026-07-27 | #908 | Corrected the canonical published-schema URI root. The root recorded above, `https://raes.dev/schemas/`, names a domain this project does not control, and neither did the retired-identity domain it replaced. The canonical root is now `https://raesystem.github.io/rae/schemas/`, which is bound to the repository's own GitHub organisation and is therefore uniquely ours to assign. `$id` remains an identifier and is not required to resolve, so no DNS or hosting obligation follows from it. | | 2026-07-28 | #908 | Split the release-history boundary for bot-maintained files. A whole-file digest cannot hold for `CHANGELOG.md`, which release-please rewrites on every release by inserting each new section above the existing ones; the pin went stale at v2.0.0 and the gate was overridden rather than fixed. Such files are now classified `generated-release-history`, which pins the classified tail exactly and holds everything written above it to the live-tree rule of zero retired identity occurrences. Newly generated content therefore carries no historical exemption. | +| 2026-07-31 | #963 | Rebound the canonical published-schema URI root from `https://raesystem.github.io/rae/schemas/` to `https://openrae.github.io/rae/schemas/` after the GitHub organization was renamed from RAESystem to OpenRAE. The coordinated change updates normative schemas, their reference-model source, publication records, fixtures, consumer tests, and live repository links while preserving historical release records. | diff --git a/docs/decisions/adrs/adr-101-adversarial-participant-flow-control.md b/docs/decisions/adrs/adr-101-adversarial-participant-flow-control.md new file mode 100644 index 000000000..664772b95 --- /dev/null +++ b/docs/decisions/adrs/adr-101-adversarial-participant-flow-control.md @@ -0,0 +1,268 @@ +# ADR-101: Adversarial Participant Boundary Flow Control + +## Status + +accepted + +## Date + +2026-07-30 + +## Classification + +Classification: FM3 + +Required artifacts: a revisioned threat model, independent confidentiality and +integrity coordinates, conservative derivation rules, distinct release and +authority operations, an exact final-sink boundary, a revisioned +intentional-subversion evaluation profile, worked attacks, DRAFT Ground Control +ownership, and dependency-ordered implementation work. + +Waivers: issue #812 is design authority. It does not publish portable wire +contracts, change runtime or backend behavior, run an adversarial evaluation, +or establish robustness against intentional subversion. + +## Context + +ADR-085 and SEM-230 define participant-relative information flow, exact-cut +policy decisions, declassification, memory, adaptive strategies, and explicit +noninterference boundaries. ADR-095 separates decision, state cut, projection, +delivery, and observation. ACT-617 and API-409 distinguish direction, +intervention, handoff, override, cancellation, admission, and execution. +API-423 and RUN-319 provide typed crossing occurrences and fail-closed reference +mediation. API-407 owns declared and effective backend capability strength. +ASR-535 owns bounded participant-flow evidence and overclaim prevention. + +Those authorities do not yet carry independent confidentiality and +source-integrity coordinates from every observation or tool result through +participant context, retained memory, proposals, action arguments, handoffs, +outputs, and final sinks. A structurally valid and otherwise authorized action +can still have been redirected by untrusted content. Two individually +permitted operations can compose into confidential exfiltration. A valid +handoff can launder apparent authority. A monitor can be evaded by an attacker +that observes prior decisions. + +Research systems provide useful but apparatus-specific responses: + +- FIDES tracks confidentiality and integrity and applies deterministic + information-flow policy to agent actions. +- CaMeL separates trusted control from untrusted data with quarantined + processing and capability restrictions. +- SAMOS retains session flow context and intercepts MCP tool calls. +- AgentDojo evaluates utility and security under indirect injection and + adaptive attacks. +- AI Control and ControlArena model intentionally subverting policies, trusted + and untrusted model roles, audits, editing, deferral, and shutdown. +- runtime shielding mediates a formally declared property before output. +- capability systems make designation and least authority explicit. + +RAES must adopt the general boundary lessons without becoming an LLM framework +or confusing a benchmark, gateway, monitor, model role, or prompt convention +with participant-neutral authority. + +## Decision + +### 1. Add two DRAFT owners + +SEM-233, **Adversarial Participant Boundary Information-Flow Control**, +owns the portable explicit-flow and final-sink semantics. ASR-536, +**Intentional-Subversion Participant Control Evaluation**, owns the +experimental protocol and evidence surface. + +Both remain DRAFT. Issue #812 defines their boundary and child program; it does +not satisfy their positive runtime or evaluation obligations. + +### 2. Keep confidentiality and integrity independent + +The flow-policy profile has two independent coordinates: + +- confidentiality limits permitted audiences, principals, destinations, and + sink classes; and +- integrity records origins and possible writers that may have influenced a + value and the minimum trust required by a sink. + +The profile defines ordering, conservative join, trusted-source declarations, +source defaults, release authorities, sink requirements, memory scope, and +unknown behavior. A single `trusted`, `safe`, secret, sensitivity, confidence, +role, marking, signature, hash, or monitor-score field cannot replace both +coordinates. + +Opaque transformations retain the join of every input that could have +influenced the result. External sources default to confidential and untrusted +unless a revisioned resolver establishes narrower labels. Missing labels, +missing provenance, unknown profile revisions, ambiguous joins, and +unsupported propagation deny or produce an explicit unsupported result. + +Historical labels and provenance are immutable. + +### 3. Keep authority operations distinct + +Authentication identifies a principal. Authorization permits an operation. +Admission validates a candidate fact or action. Approval records a control +decision. Declassification relaxes confidentiality. Integrity endorsement +raises the admitted origin-trust coordinate. Redaction and transformation +derive new values. Trusted editing creates a new proposal. Handoff changes +control. Interruption and shutdown change lifecycle. + +None implies another. Declassification and endorsement name the exact source, +result, affected coordinate, destination or sink, authority, profile revision, +state cut, and evidence. They create a fresh derived identity and never mutate +history. Trusted editing inherits provenance and effective labels, then +re-enters ordinary validation, policy, capability, and action admission. + +### 4. Propagate through existing typed carriers + +The relation follows this path: + +```text +observation, retrieval, tool result, or runtime fact + -> participant context and retained memory + -> proposal, output, transformation, and action arguments + -> API-409 control or handoff and API-423 crossing + -> participant-facing or external sink +``` + +The implementation reuses runtime facts, participant action admission, +API-409, API-423, runtime snapshots, experiment records, and typed refs. It +must not add an open `taint`, `security_labels`, `agent_message`, `context`, +`monitor_metadata`, or policy map, or a parallel action, crossing, handoff, +evidence, audit, trajectory, error, or persistence hierarchy. + +Controller change, participant change, shared state, handoff, or episode reset +does not erase provenance or labels. Cross-episode replay names the SEM-230 +memory scope and retains profile and policy revisions. + +### 5. Enforce at the last RAES-controlled boundary + +The final enforceable boundary is: + +- after the last policy, authority, capability, destination, and state-cut + resolution but immediately before `RuntimeTarget` or a backend performs an + external action; and +- immediately before participant-facing or external data is serialized, + streamed, delivered, written, returned in an error, or otherwise disclosed. + +The runtime commits the decision through the existing atomic participant +transition before the effect. Missing labels or provenance, stale state, +unsupported capability, denial, history-head conflict, or failed commit causes +no backend call and no disclosure. + +Planning validation, schema validation, action admission, proposal approval, +monitoring, gateway interception, and request construction are necessary +defense layers but not the final sink. + +### 6. Separate deterministic policy from monitors and protocols + +Deterministic policy and effective capability support decide authorization and +release. A heuristic monitor emits evidence or advice with revision, +visibility, provenance, limitations, and confidence. A monitor score never +authorizes an action, and missing monitor output never widens permission. + +Human and trusted-system interventions state whether they authorize, +declassify, endorse, edit, defer, hand off, interrupt, shut down, or merely +advise. Multiple effects are independently named and authorized. + +Trusted and untrusted monitors are evaluation roles, not intrinsic properties. +Profiles declare topology, inputs, visibility, policy knowledge, independence +or correlation assumptions, collusion channels, and failure behavior. +Different ids do not imply independence. + +### 7. Add an intentional-subversion evaluation profile + +ASR-536 profiles bind: + +- honest or attack mode, main objective, side objective, and success + conditions; +- participant capabilities and apparatus; +- policy, monitor, threshold, audit-budget, and prior-outcome knowledge; +- adaptive strategy over approvals, denials, edits, deferrals, audits, + handoffs, interruptions, outputs, ordering, and declared timing facts; +- monitor identities, roles, topology, correlation, visibility, and failures; +- audit budget, selection rule, approval, trusted editing, defer-to-trusted, + interruption, and shutdown protocol; +- cross-participant and cross-episode memory, replay, and policy revision; and +- separate safety, usefulness, attack success, audit cost, intervention cost, + uncertainty, limitations, and nonclaims. + +The profile reuses existing experiment task, protocol, study, run, apparatus, +factor, evidence, measure, traceability, and behavioral claim contracts. Until +a trajectory authority exists, replay uses a digest-bound graph of existing +episode, behavior, control, crossing, action/result, and evidence refs. + +Ordinary negative tests, injection examples, monitor accuracy, and green +benchmarks are bounded falsification evidence. They do not establish +intentional-subversion robustness. + +### 8. Keep portable semantics participant-neutral + +Labels, derivations, authorities, capabilities, policy cuts, sinks, decisions, +provenance, and evidence apply to human, scripted, reinforcement-learning, +large-language-model, and external-service participants. + +Prompt separation, privileged or quarantined models, model topology, MCP +gateways, tokenizers, credentials, private state, and chain-of-thought are +apparatus details. Apparatus contracts may declare bounded support, but those +details do not enter portable participant records. + +### 9. Require boundary-faithful attacks + +Downstream evidence covers: + +1. prompt or tool-result injection; +2. confidential exfiltration through actions, outputs, arguments, errors, or a + colluding participant; +3. adaptive monitor evasion under declared feedback and audit budgets; and +4. control-handoff manipulation. + +Every case drives the real `RuntimeControlPlane` to `RuntimeTarget` boundary, +checks the semantic decision, counts external calls, checks participant-visible +output, append-only histories, safe audit/error evidence, and replay. A denied +case has zero prohibited external effects. + +### 10. Allocate bounded child work + +- #1001 publishes semantic authority. +- #1002 publishes portable contracts after #1001. +- #1003 implements final-sink runtime enforcement after #1002. +- #1004 implements apparatus and backend capability support after #1002. +- #1007 implements adversarial evaluation after #1001 and #1002. +- #1008 publishes evidenced claims after #1003, #1004, and #1007. + +## Consequences + +RAES gains a participant-neutral security boundary that can represent +adversarial influence and confidential composition without requiring an LLM, +MCP, or monitor framework. Runtime and evaluation claims remain honest because +the design separates authority, implementation, backend realization, and +evidence. + +The cost is a cross-cutting profile and resolver relation that later work must +bind across semantics, contracts, runtime, stores, backends, apparatuses, +experiments, and documentation. Conservative propagation can reject useful +operations until a governed transformation or release exists. + +## Non-Goals + +- Solving model alignment or proving internal reasoning safe. +- Recording chain-of-thought, private model state, prompts, or credentials. +- Replacing participant-neutral contracts with LLM chat or tool formats. +- Treating a monitor, human, gateway, model, or backend as trusted by default. +- A general-purpose taint engine, policy language, agent framework, gateway, + monitor service, trajectory store, or message bus. +- Protection from undeclared timing, storage, model-steganographic, or other + covert channels. +- Positive runtime, backend, shielding, or intentional-subversion claims from + this ADR alone. + +## References + +- [SEM-233 and ASR-536 formal authority](../../../specs/formal/participant-semantics/adversarial-flow-control.md) +- [Issue #812 research record](../../research/adversarial-participant-control/) +- [FIDES](https://arxiv.org/abs/2505.23643) +- [CaMeL](https://arxiv.org/abs/2503.18813) +- [SAMOS](https://research.ibm.com/publications/securing-mcp-based-agent-workflows) +- [AgentDojo](https://proceedings.neurips.cc/paper_files/paper/2024/hash/97091a5177d8dc64b1da8bf3e1f6fb54-Abstract-Datasets_and_Benchmarks_Track.html) +- [AI Control](https://arxiv.org/abs/2312.06942) +- [ControlArena](https://control-arena.aisi.org.uk/) +- [Shield Synthesis](https://arxiv.org/abs/1501.02573) +- [Capability-based authority control](https://doi.org/10.4230/LIPIcs.ECOOP.2017.20) diff --git a/docs/decisions/adrs/adr-102-mixed-cross-backend-participant-control.md b/docs/decisions/adrs/adr-102-mixed-cross-backend-participant-control.md new file mode 100644 index 000000000..597004dfc --- /dev/null +++ b/docs/decisions/adrs/adr-102-mixed-cross-backend-participant-control.md @@ -0,0 +1,323 @@ +# ADR-102: Mixed Cross-Backend Participant Control + +## Status + +accepted + +## Date + +2026-07-31 + +## Classification + +Classification: FM3 + +Required artifacts: edition-pinned primary-source assessment, revisioned +mixed-composition and trial-schedule profiles, formal invariants, explicit +authority and trust boundaries, a demonstration protocol, DRAFT Ground +Control ownership, and dependency-ordered implementation work. + +Waivers: issue #813 is design authority. It does not publish portable schemas, +change trial compilation or runtime behavior, declare or realize a backend +capability, execute the demonstration, or establish interoperability, +transfer, IFC/noninterference, trace inclusion, bisimulation, or backend +equivalence. + +## Context + +RAES already has participant-neutral authorities for: + +- backend-neutral scenario meaning and deterministic scenario-family + composition; +- experiment selection, apparatus constraints, trial admission, immutable + plan/run identity, cleanup, and evidence; +- participant identity, one acting controller, scoped authority, action + admission, handoff, and append-only history; +- participant/audience projection, crossings, delivery, observation, + declassification, and exact state cuts; +- shared clocks, time progression, order, realization evidence, and + conformance; and +- backend capability strength, constraints, downgrade, realization, and + evidence. + +Those authorities support realizing the same scenario on different backends +and comparing bounded evidence. They do not define one trial containing +simulated and emulated/operational participant components at the same time. +The admitted trial entry pins one realization envelope. The apparatus context +can report multiple components after the fact but does not authorize a mixed +topology. + +The issue #600 corpus is deliberately a pair of separate backend runs. CybORG +also selects simulation or emulation for a run. Neither is evidence of an +AND-composition. + +Other precedents expose the missing dimensions: + +- HLA standardizes federation services, scoped object/attribute ownership, + interest management, directed interactions, and logical-time coordination. +- NIST integrated federations expose bridge topology, independent clocks, + information-hiding limits, translation, and shared-resource effects. +- UCEF, ACTING/EDL-FG, LVC systems, FMI, and HELICS explicitly mix simulation, + emulation, hardware, or differently scheduled components. +- CybORG and CyGIL show that a common interface and successful training do not + eliminate observation, action, model, or transfer mismatch. +- digital-twin composition distinguishes integrated, unified, and federated + composition and makes synchronization/fidelity material. + +RAES needs both OR and AND semantics without making backend selection part of +portable scenario meaning or conflating multiple realization providers with +multiple controllers. + +The supporting +[research record](../../research/cross-backend-participant-control/) contains +the complete source disposition, current-state analysis, composition design, +demonstration protocol, DRAFT requirement disposition, and child program. + +## Decision + +### 1. Add two DRAFT owners + +SEM-234, **Mixed Cross-Backend Participant-Control Composition**, owns the +portable semantic profile. ASR-537, **Cross-Backend Participant-Control +Realization and Transfer Evidence**, owns the demonstration and evidence +profile. + +Both remain DRAFT. Issue #813 defines their boundaries and implementation +program. It does not satisfy their positive implementation or evaluation +clauses. + +### 2. Support alternative and simultaneous mixed realization + +The first composition profile supports: + +- **alternative realization**: the same authored scenario and participant + policy are admitted for simulation or for emulation/operation; and +- **simultaneous mixed realization**: two or more admitted apparatus + components with different realization forms participate in one trial. + +Realization forms include simulation, emulation/operation, hardware/native, +and federated composition. Labels describe admitted, evidenced realization; +they are not inferred from backend names, adapter classes, infrastructure, or +marketing terms. + +### 3. Keep SDL backend-neutral + +Portable SDL continues to author participants, controlled scopes, action +families, observation boundaries, crossings, injects, time intent, and world +meaning. It does not select a backend, adapter, federation, or digital-twin +mode. + +Realization allocation belongs to admitted experiment/trial intent and +references stable compiled identities. Revision 1 can allocate: + +- a participant runtime; +- a controlled scope; +- an action family; +- an observation source; and +- a crossing boundary. + +An allocation must be closed, bounded, non-overlapping or governed by an +explicit arbitration rule, and complete for every required effect and +observation. Runtime and schedulers cannot choose outside it. Missing +allocation is rejection, not backend fallback. + +### 4. Make composition topology and boundaries explicit + +The profile names single-component, integrated, unified, federated/bridged, +and nested topologies. + +Every directed composition edge binds: + +- source and destination component refs; +- adapter or bridge identity and version; +- authority and allocation scope; +- action or observation mapping; +- participant/audience policy and release basis; +- time-domain and order mapping; +- required API-407 support strength; +- transformation and mapping loss; +- failure, retry, and partial-delivery behavior; and +- evidence and provenance refs. + +A shared bus, FOM, API, broker, gateway, or package does not fill these fields +by implication. + +### 5. Preserve one acting controller in revision 1 + +The authority path is: + +```text +participant + -> acting controller + -> authority basis and controlled scope + -> action admission + -> selected realization provider + -> adapter or bridge responsibility + -> backend effect +``` + +Backend responsibility is not action authority. HLA object/attribute ownership +is responsibility for updating simulated object state; it is not participant +identity, acting control, approval, handoff, or disclosure authority. Directed +delivery is addressing; it is not observation or authorization. + +Revision 1 retains exactly one acting controller per participant and episode. +It does not support: + +- simultaneous controllers for different scopes; +- lease claims based only on validity windows; or +- joint/fused control represented by a synthetic identity or controller list. + +A later profile may add these only with exact scope and controller identities, +lease renewal/expiry/fencing or quorum/priority/arbitration/unanimity, +revision-fenced atomic transitions, clock/order semantics, oscillation and +livelock handling, failure behavior, and evidence. + +### 6. Use explicit transfer states + +HLA ownership services are adopted as a transition-protocol precedent, not an +authority model. A future backend realization may expose requested, offered, +pending, committed, failed, expired, cancelled, and stale acquisition or +divestiture states. + +Pull and push initiation retain different provenance. They converge only +after a RUN-310 revision-fenced atomic commit. Until commit, the prior acting +controller and authority remain effective. Alternating valid transfers are not +proof of progress; oscillation needs a bounded retry/cooldown or explicit +livelock disposition. + +### 7. Separate routing from policy + +Declaration, publish/subscribe, DDM, directed interactions, bridge filters, +encryption, and transport authorization are realization mechanisms. They +cannot grant participant visibility, marking authorization, +declassification, IFC, or noninterference. + +SEM-230 and API-423 authorize the exact participant/audience projection before +it reaches the edge. Filtering may narrow an authorized projection. It cannot +widen one. + +Leakage analysis includes membership, subscriptions, classes, regions, +destinations, sizes, timing, synchronization, ownership changes, retractions, +and differential failures. Audit retention uses an evidence audience and does +not disclose to a participant. + +### 8. Require admitted time and order mappings + +Each component declares its clock, time domain, role, progression service, +lookahead if applicable, delivery order, serialization basis, and readback. +Every cross-clock edge supplies an admitted mapping or records the relation as +partial/unknown. + +A timestamp-only backend is `disclosed_weak`. It cannot claim governed logical +order. A `backend_serialized` claim requires the serialization service, clock, +runtime readback, and conformance evidence. + +Staleness binds controller, authority, capability, policy revision, state +revision, history head, and governed order. Wall-clock recency is not enough. +Rollback, replay, concealment, and retraction append facts and never erase a +delivery or participant knowledge. + +### 9. Preserve trial identity while supporting staged realization + +An inter-trial realization change creates a new admitted plan entry and run id +linked to its source. It supports simulation-to-emulation training/evaluation, +emulation-to-simulation model regeneration, and alternating or parallel +calibration without pretending the runs are one world. + +Revision 1 also permits a finite within-run phase schedule when: + +- every possible component and manifest is pinned before execution; +- each activation/deactivation edge, mapping, authority, clock, policy, and + failure behavior is admitted; +- the schedule is finite and schedule-independent; +- a phase transition commits before new effects; and +- transition and failure evidence is append-only. + +An unadmitted late join, discovered backend, runtime fallback, or phase rewrite +is rejected. + +### 10. Keep three open/closed axes independent + +The profile separates: + +- **control loop**: open-loop observation/replay versus closed-loop + intervention/actuation; +- **world assumption**: closed-world versus bounded-open-world treatment of + unknown entities, actions, observations, and mappings; and +- **federation membership**: fixed versus finite pre-admitted dynamic + membership. + +Closed-loop posture grants no action authority. A bounded-open-world profile +does not widen a closed vocabulary or admit an unknown mapping. Dynamic +membership does not bypass trial admission. + +### 11. Require a claim-separated demonstration + +ASR-537 requires: + +- pure simulation; +- pure emulation/operation; +- simultaneous mixed composition; +- linked inter-trial change; +- pre-admitted within-run phase change; +- open-loop and closed-loop cases; and +- adversarial mismatch and zero-effect cases. + +Every result binds scenario/policy digests, plan/run identity, apparatus, +adapters, allocation, topology, clocks/order, capability, conformance, +mappings, model/data/seed provenance, losses, limitations, and reproduction +evidence. + +Bounded conformance, interoperability readiness, empirical transfer, trace +inclusion, bisimulation, IFC/noninterference, and backend equivalence remain +distinct. No result is promoted between them silently. + +### 12. Allocate dependency-ordered work + +- #1013 publishes SEM-234 semantic authority. +- #1014 publishes portable composition contracts after #1013. +- #1015 implements deterministic trial admission after #1014. +- #1016 implements fail-closed runtime coordination after #1014 and #1015. +- #1017 implements generic backend capability and conformance after #1014 and + #1016, in the Backend Contract & Conformance milestone. +- #1018 executes ASR-537 after #1015, #1016, and #1017. +- #1019 reconciles claims after #1016, #1017, and #1018. + +## Consequences + +RAES can represent both backend substitution and mixed composition without +putting apparatus choice in SDL or weakening participant authority. The same +profile also supports bounded trial-stage variation and preserves exact losses +and evidence. + +The cost is a cross-cutting contract and runtime program. Trial admission must +pin more than one apparatus component and validate a graph of mappings. +Runtime coordination must resolve and commit a larger exact cut. Backend +conformance must probe services rather than interfaces. Evaluation must retain +negative and mismatch evidence. + +Revision 1 deliberately rejects multi-controller and lease semantics. That +keeps mixed realization independent of the harder authority-composition +problem and leaves a versioned seam for later work. + +## Non-goals + +- HLA, FMI, HELICS, EDL-FG, CybORG, CyGIL, CyberBattleSim, or digital-twin + wire compatibility. +- A universal federation, co-simulation, agent, gateway, or digital-twin + framework. +- Backend selection in portable SDL. +- Distributed, leased, simultaneous scoped-owner, or joint/fused control in + revision 1. +- Treating routing, filtering, encryption, ownership, or membership as + participant authorization or IFC. +- Runtime implementation, backend realization, demonstration, transfer, + interoperability, trace inclusion, bisimulation, IFC/noninterference, or + equivalence from this ADR alone. + +## References + +- [Architecture preflight](../issue-813-cross-backend-participant-control-preflight.md) +- [Research and implementation program](../../research/cross-backend-participant-control/) +- [SEM-234 and ASR-537 formal design](../../../specs/formal/participant-semantics/cross-backend-participant-control.md) diff --git a/docs/decisions/adrs/adr-index.yaml b/docs/decisions/adrs/adr-index.yaml index cf7f1b304..9ae3eb805 100644 --- a/docs/decisions/adrs/adr-index.yaml +++ b/docs/decisions/adrs/adr-index.yaml @@ -63,7 +63,11 @@ adrs: pin: aaf414e1da0eb329432562b16ff9e132522e19e8a35933a1c99329b0be27cae8 - id: ADR-014 path: docs/decisions/adrs/adr-014-nox-as-canonical-verification-graph.md - pin: 940ce80b1f1d94e3efb4a9f56cb9147d09c9a9dc1453a4977c7a5e194238d708 + pin: 52b3bf9dfbf128658b0edc88e164114529e3e225db0360ea99e005ebc97f86bf + amendments: + - date: 2026-07-31 + ref: "#963" + summary: Parallelized deterministic verification and contract batches, scoped pre-commit without duplicating full regression, and moved external links to dedicated docs CI. - id: ADR-015 path: docs/decisions/adrs/adr-015-sdl-processor-layering-and-source-file-size-cap.md pin: bc5038164e535c4d506962e27cee07e720f5c8a77cb17d018dedb3dba927936f @@ -462,6 +466,9 @@ adrs: - date: 2026-07-28 ref: "#908" summary: "Added the generated-release-history record class so bot-maintained release notes pin their classified tail exactly while newly generated content is held to zero retired identity occurrences." + - date: 2026-07-31 + ref: "#963" + summary: "Rebound the canonical published-schema URI root to https://openrae.github.io/rae/schemas/ after the GitHub organization was renamed from RAESystem to OpenRAE." - id: ADR-098 path: docs/decisions/adrs/adr-098-portable-artifact-requirement-satisfaction.md pin: cabc306d07b60b7d1c62cf85750a57025651e69f55946261e315d772644309e3 @@ -471,3 +478,9 @@ adrs: - id: ADR-100 path: docs/decisions/adrs/adr-100-participant-crossing-bisimulation.md pin: b7e17e58fc01e8f07a972ee5abc65e6a8470e2a6d51c2480334a3777df079e98 + - id: ADR-101 + path: docs/decisions/adrs/adr-101-adversarial-participant-flow-control.md + pin: add7e6ba4634965a9aa9c09248bfaafd981f1f16956b731fc913ca416ef92ffd + - id: ADR-102 + path: docs/decisions/adrs/adr-102-mixed-cross-backend-participant-control.md + pin: cfcb0f5b7291b47fe6ff6096bb18dd9063b83ee5d4f7f6a9cafbdd06f21bf716 diff --git a/docs/decisions/issue-1010-ssh-generated-artifact-output-isolation-preflight.md b/docs/decisions/issue-1010-ssh-generated-artifact-output-isolation-preflight.md new file mode 100644 index 000000000..5f59e09c6 --- /dev/null +++ b/docs/decisions/issue-1010-ssh-generated-artifact-output-isolation-preflight.md @@ -0,0 +1,271 @@ +# Issue #1010 — SSH Generated Artifacts and Output Isolation Preflight + +Date: 2026-07-31 + +This note records architecture guardrails for issue #1010. It does not +implement an SSH generator, an SDL change, a provisioner, or key distribution. + +No new ADR is required. This is a bounded extension of the stateful-resource +contract established by the issue #780 preflight and the compile/plan/execute, +schema-authority, realization-honesty, validation-strength, and identifier +decisions it cites. This note supersedes only issue #780's temporary rule that +a mixed-sensitivity generated artifact must be delivered as an indivisible +unit. + +## Contract boundary + +Add one SSH-specific generated-artifact kind. The preferred wire value is +`ssh_key_bundle`: it covers SSH keypairs, SSH CA keys and issued material, and +public or `authorized_keys` projections without implying that the artifact +owns sshd authorization policy. `certificate_bundle` remains the X.509/SOC +material kind, and `rendered_config` remains configuration rendering. + +The new kind is generated key material, not the SSH server-configuration +surface in ADR-031, an `Account.auth_method`, authored `Content`, a runtime +filesystem observation, or a participant information-flow policy. Raw private +or public key bytes remain unrepresentable in SDL, compiled plans, snapshots, +provenance, diagnostics, audit events, and API envelopes. + +Output sensitivity and output entitlement are orthogonal: + +- `ResourceSensitivity` classifies handling; it does not grant a consumer + access. +- Each generated output has a closed distribution disposition: + `consumer_selected` or `producer_private`. +- A generated-artifact consumer selects a non-empty, unique list of declared + output names. Selection grants that consumer read-only delivery; it does not + grant writeback or transfer artifact lifecycle ownership. +- A `producer_private` output is never selectable or materialized into any + consumer. It remains backend-owned state beneath the artifact producer's + protected root. +- Every `consumer_selected` SSH output is selected by at least one consumer; + omission must not silently create a second producer-private meaning. + +Use an artifact-specific consumer subtype that extends the existing stateful +consumer coordinates with output selection. Do not add an optional output +field to the persistent-volume consumer shape, and do not duplicate node, +destination, access-mode, or path validation. + +For compatibility, existing `certificate_bundle` and `rendered_config` +documents may retain their current omitted-selection meaning during the +governed migration window: all non-producer-private outputs are selected. +`ssh_key_bundle` must require explicit selections from its first published +form. A producer-private output is excluded even on the legacy path. New +examples should use explicit selection for every kind so omission does not +become a permanent second authoring style. + +The artifact remains one lifecycle and dependency unit. Selection changes +only the projection delivered to a consumer; it does not split generation, +refresh, provenance, identity, reconciliation, or deletion into per-output +resources. A backend must generate the complete declared output set atomically +enough to avoid mixed generations, then expose only each consumer's selected +projection. + +## Canonical incumbents + +The implementation must extend, not parallel, these existing authorities: + +- **Source and model admission:** `load_sdl_yaml()` and the source limits and + duplicate-key checks behind it; `SDLModel(extra="forbid")`; + `PortableIdentifier`; `GeneratedArtifact`, `GeneratedArtifactOutput`, + `StatefulResourceConsumer`, `ResourceSensitivity`, the canonical relative + output-path validator, and the canonical mount-destination validator. +- **Semantic and composition admission:** + `stateful_resource_reference_errors()`, `SemanticValidator`, + `composition._rewrite_stateful_dependency_ref()`, the existing namespacing + of stateful consumer node refs, unresolved-variable checks, and concrete + revalidation through the `Scenario` -> `ExpandedScenario` -> + `InstantiatedScenario` phases. Output selections are artifact-local names + and are not module-global symbols. +- **Compilation and planning:** `_stateful_spec()`, + `_compile_generated_artifacts()`, `GeneratedArtifactRuntime`, + `resource_payload()`, `_collect_resources()`, the existing stateful graph + ordering/refresh/reverse-delete logic, and + `CompiledRealizationRequirement(requirement_kind="generated-artifact")`. + The complete distribution declaration remains one exact SEM-218 payload. +- **Capability and realization admission:** `ProvisionerCapabilities`, + `ProvisionerCapabilitiesModel`, backend-manifest v2 serialization, + `_validate_artifact_and_volume_support()`, + `_stateful_submission_diagnostic()`, + `realization_support_diagnostics()`, + `realization_envelope_diagnostics()`, and `realization_disclosure()`. +- **Execution, errors, and observation:** `_call_backend_diagnostics()`, + `_call_backend_apply()`, `Diagnostic`, `ApplyResult`, + `runtime.backend-contract-invalid`, `RuntimeSnapshot`, `SnapshotEntry`, and + `RealizationProvenanceEntry`. No feature-specific exception or logger is + warranted. +- **Persistence and API:** `ControlPlaneStore`, the local store's atomic + snapshot path, `_snapshot_payload()`, `_snapshot_from_payload()`, + `RuntimeSnapshotEnvelopeModel`, `_snapshot_model()`, + `ControlPlaneSecurityConfig`, the existing authentication/role/target + checks, request-size guard, idempotency fingerprint, audit path, and + redacted HTTP 500 envelope. +- **Contract publication and workflow:** `schema_bundle()`, the hand-governed + schemas and publication manifest, the SDL lineage ledger, + `tools/check_generated_schemas.py`, `.ground-control.yaml`, + `.gc/plan-rules.md`, repo policy, requirement governance, and + `tools/verify_all.py`. +- **Tests:** `test_stateful_realization_resources.py` is the canonical + parse/semantic/compile/plan/schema suite; `test_runtime_planner.py` and + `test_runtime_control_plane.py` own capability and direct-submission + admission; `test_backend_manifest.py` and + `test_backend_manifest_v2_adapter.py` own capability round trips and + fixtures. Extend these rather than creating a second SSH-only harness. + +The published SDL schemas directly affected are +`sdl-authoring-input-v1`, `instantiated-scenario-v1`, and +`instantiated-scenario-snapshot-v1`; the satisfiability-evidence schema embeds +the instantiated snapshot and changes transitively. Refining backend +capabilities also changes `backend-manifest-v2`. Published schemas, generated +bundle output, schema-publication ledger hashes, fixtures, and lineage records +must advance together. + +## Validation and security gates + +1. **YAML/source gate.** Existing safe construction, alias/node/size limits, + mapping-key normalization, duplicate-key rejection, and source diagnostics + run unchanged. Output selectors are lists, not dynamic mapping keys. +2. **Closed model gate.** Existing enum, identifier, canonical POSIX path, + collection-cardinality, duplicate, and read-only checks remain + authoritative. The generated-artifact invariant additionally rejects + duplicate selectors, missing output refs, selection of producer-private + outputs, empty SSH selections, and unselected `consumer_selected` SSH + outputs. Errors name coordinates only and never echo payload values. +3. **Semantic/composition gate.** Consumer nodes still resolve through the + canonical node-reference and module-symbol machinery; cross-resource mount + collisions and Windows/POSIX mismatches still fail before compilation. + Output refs resolve only within their owning artifact and must not enter the + global declaration or reference catalogs. +4. **Instantiation gate.** The existing unresolved-token walk and concrete + model reconstruction cover disposition and selector values. Output names + remain stable identifiers, not variable slots. No compiler-side guessing or + late string matching is permitted. +5. **Planner and direct-submission shape gate.** Planner-produced and + externally submitted `generated-artifact` operations must use one shared + stateful payload admission helper that delegates to the canonical + `GeneratedArtifact` model/invariant. The HTTP plan DTO's generic `payload` + dictionary is not sufficient validation. Do not create a second dict + schema or copy the selector rules into `raes_runtime`. +6. **Capability gate.** The coarse `supports_generated_artifacts` flag cannot + authorize an unknown generator. The provisioner capability contract needs + a governed `supported_generated_artifact_kinds` set, validated and rendered + through backend-manifest v2. Planner admission and direct control-plane + submission both require kind membership. Output isolation is intrinsic to + support for `ssh_key_bundle`, not an optional approximation flag. +7. **Exact-realization gate.** The complete spec, including kind, output + dispositions, selections, paths, sensitivity, lifecycle, provenance, and + dependencies, remains the existing exact generated-artifact concern. + A returned declaration that drops or changes a selector is an exactness + failure and must restore the baseline snapshot through the existing + sanitized backend failure path. Declaration equality alone cannot prove + that the backend avoided an extra native mount; independent backend + readback and conformance evidence own that stronger claim. +8. **Secret and persistence gate.** Plan and snapshot payloads contain desired + metadata only. The control-plane store and authorized snapshot API copy + `SnapshotEntry.payload` verbatim, so authentication is not a license to put + generated bytes there. A producer-private disposition is an enforcement + rule, not a redaction marker and not proof that a leaked value is safe. +9. **HTTP/auth and error-envelope gate.** Existing backend/operator mutation + roles, backend/operator/auditor read roles, target binding, body limit, + idempotency, and audit recording remain in force. Direct-plan validation + returns bounded structured diagnostics; it must not surface Pydantic input + renderings, backend exception text, private paths from native state, + tracebacks, or key material through 409/422/500 responses. +10. **Host/OS materialization gate.** A real producer anchors all outputs below + one owned root, rejects native traversal and symlink escapes, creates + private material with restrictive ownership/mode and atomic replacement, + and derives public/`authorized_keys` projections without redisclosing the + private serialization. Secret bytes never enter process argv, environment + variables, shell command text, stdout/stderr, diagnostics, audit details, + or general logs. If a subprocess is unavoidable, use fixed argv, + `shell=False`, bounded execution, and a protected input channel. Consumer + materialization preserves the existing POSIX-only destination contract and + must not mount or stage unselected siblings even transiently. + +`reuse_valid` producer state is backend-private persistence keyed to the +canonical artifact identity and validated lifecycle/provenance inputs. It must +not be stored in control-plane JSON, a repository content tree, or a generic +temporary directory, and it must not be adopted solely because a matching +filename exists. Regeneration atomically advances private source material and +all derived consumer projections as one generation. + +There is no new authentication surface, credential resolver, environment +binding, CLI secret option, HTTP endpoint, or secret-store configuration in +this issue. `provenance` remains an inert, non-secret recipe/source reference; +it is not a shell command, private-key carrier, or evidence that generation +succeeded. + +## Capability and extensibility seams + +The immediate capability seam is +`supported_generated_artifact_kinds`, not one boolean per generator. A backend +claims `ssh_key_bundle` only when it honors complete generation and +consumer-output isolation. Stub support may exercise the contract, but +reference/libvirt or other production manifests must not be widened without a +real producer and conformance evidence. + +The next likely SSH variations are key algorithm/size, private-key encoding, +public projection format, SSH certificate/CA issuance, validity, and +principal/key-comment inputs. Those belong in a kind-scoped typed +`ssh_key_bundle` generator payload with matching capability dimensions. They +must not become a free-form `options`/`constraints` map, output-name +conventions, provenance-string parsing, or changes to `certificate_bundle`. + +Output disposition plus artifact-local selected-output refs is the +distribution seam. A future audience or projection mode extends that closed +disposition vocabulary and its capability/admission rules. It does not add +per-consumer booleans, embed node lists into outputs, or fork the artifact +lifecycle. + +## Gotchas and anti-patterns + +- Do not infer privacy from `sensitivity: secret`; some secret outputs are + intentionally delivered to exactly one consumer. Conversely, `public` does + not mean every node is entitled to receive an output. +- Do not use an empty or omitted selector as producer-private for the new SSH + kind. Privacy must be explicit and invalid selections must fail closed. +- Do not add selectors to the shared persistent-volume consumer DTO or weaken + persistent-volume access semantics. +- Do not split one SSH generation transaction into unrelated artifacts merely + to recover isolation; that loses the issue's shared lifecycle and refresh + semantics. Separate artifacts remain valid when they genuinely have + independent lifecycle or provenance. +- Do not flatten selected outputs, rename them by consumer, reinterpret output + names as paths, or infer roles such as “private key” from names. Existing + output paths and mount-destination semantics remain authoritative. +- Do not treat a consumer ref as an ordering/refresh dependency or create a + second graph engine. +- Do not satisfy the request with `certificate_bundle`, `rendered_config`, + authored `Content`, runtime SSH server configuration, accounts, cloud-init + private extensions, or backend-native fragments. +- Do not hand-edit only one published schema, rely on JSON Schema for + relational selector invariants, or describe shape validation as complete + semantic admission. +- Do not let the generic HTTP plan payload bypass the model invariant, and do + not log validation input while reducing it to a diagnostic. +- Do not put generated bytes, digests of private serialization, native producer + roots, temporary filenames, commands, or backend handles in snapshots, + realization provenance, operation details, or audit events. +- Do not add a new exception hierarchy, persistence repository, logger, + capability registry, schema, output resolver, or workflow for this feature. + +## Non-goals and implementation boundaries + +- No runtime SSH server-policy changes (ADR-031). +- No real SSH key generator, CA service, key store, distribution daemon, + rotation scheduler, revocation policy, backup, or recovery design in the SDL + contract change. +- No change to X.509 `certificate_bundle` or configuration + `rendered_config` semantics beyond the governed compatibility path for + selectors. +- No provider selection, host path, Docker/Compose/Kubernetes/cloud-init + fragment, shell command, Terraform resource, or backend handle in SDL. +- No raw key material or author-supplied key content in the generated-artifact + declaration. +- No per-output lifecycle, refresh graph, provenance identity, compiled + address, plan operation, or snapshot entry. +- No Windows path dialect, mutable consumer access, consumer writeback, or + producer-as-node identity in this issue. +- No field-level snapshot authorization redesign. The current authorized API + may expose non-secret declaration metadata; generated bytes remain outside + the snapshot entirely. diff --git a/docs/decisions/issue-1011-search-index-schema-preflight.md b/docs/decisions/issue-1011-search-index-schema-preflight.md new file mode 100644 index 000000000..f1c25c385 --- /dev/null +++ b/docs/decisions/issue-1011-search-index-schema-preflight.md @@ -0,0 +1,276 @@ +# Issue 1011 Search-Index Field-Schema Preflight + +Date: 2026-07-31 + +Issue: #1011. + +Requirement: none. The GitHub issue is the delivery contract. + +This note fixes the architecture boundary for a provider-neutral exact +search-index field schema. It is guidance only: it does not add the profile, +change an SDL model or published schema, claim backend support, or implement a +native materializer. + +## Decision Boundary + +Add a second closed service-materialization profile for search-index schema +state. Do not reinterpret or mutate `service-content` v1, whose operation and +readback concern owned documents or records. The new profile remains a variant +of `content..service_materialization` and compiles through the existing +`content-placement` lifecycle; it is not a top-level schema resource, datastore +inventory entry, plan, repository, controller, or lifecycle engine. + +The profile identity and capability term are versioned independently: + +- interface profile `service-search-index-schema`, version `"1"`; and +- provisioner capability `service-search-index-schema-v1`. + +These spellings are contract authority and must stay identical across the SDL +model, controlled vocabulary, manifest fixture, specification, schemas, +examples, and tests. Do not use `service-content-v2` merely to avoid a second +discriminated variant: document reconciliation and schema reconciliation have +different operations, desired-state payloads, collision behavior, and readback +projections. + +The closed v1 requirements are: + +- `operation: ensure-search-index-field-schema`; +- `conflict_policy: reject-unowned-collision`; +- `readback: canonical-portable-field-schema-digest`; and +- `field_semantics`: one non-empty mapping from portable top-level field names + to this closed portable semantic set: + + - `exact-token`: equality/term matching without analysis or tokenization; + - `full-text`: analyzed/tokenized text search; + - `integer`: integral numeric comparison; + - `temporal`: date/time comparison under the backend's documented portable + projection; and + - `boolean`: two-valued boolean comparison. + +Vendor literals such as `keyword`, `text`, `long`, or product-native mapping +bodies are invalid authoring input. V1 proves the exact semantic of every +declared field. Undeclared native fields are outside the claim: native readback +projects exactly the declared field names, fails if one is absent, ambiguous, +or not projectable, and compares that portable projection. A native multi-field +or analyzer fallback does not satisfy `exact-token` for the exactly named +field. + +The operation must establish the index and declared field semantics before the +provisioning apply succeeds. An incompatible existing mapping is a failed +reconciliation, not permission to delete/recreate an index, adopt an unowned +index, enable dynamic auto-creation, or silently weaken a field. Reset and +destructive recreation remain governed by the existing ownership contract. + +Schema-only initial state must be authorable without a dummy `ContentItem`, +fake source payload, or vendor bootstrap bytes. Any narrow relaxation of the +ordinary dataset payload rule must be discriminated by this profile; it must +not make empty ordinary datasets generally valid or silently combine document +insertion with schema reconciliation. Initial items remain a separate +`service-content` concern unless a later version defines and proves a combined +operation. V1 reuses `ContentType.DATASET` and the existing dataset capability +check; it adds no `schema` content type and accepts no `source` or `items` +payload for this schema-only operation. + +The portable logical store identity is the canonical `content.` address +bound to the exact `target_service_ref`. A product-native index id such as +`cortex_6` stays in the backend adapter/configuration boundary. A backend may +claim that concrete result only when its operational conformance evidence binds +that native store to the admitted content address and observes it freshly. + +## Desired State, Support, And Proof + +Keep these three claims separate: + +1. The authored field map plus its RFC 8785/JCS SHA-256 digest is exact desired + state. Compilation retains the portable map and a derived schema digest in + the profile-specific compiled binding, the `content-placement` payload, plan + operation, and snapshot transition. The existing content payload digest + remains a different digest and must not stand in for the field-schema + digest. Digest the closed portable projection containing profile id, version, + projection scope, and field map, not the bare map or native response. +2. `supported_service_materialization_profiles` plus SEM-218 exact support and + the realization envelope admit the operation. A v1 profile claim means the + backend supports the complete closed v1 semantic set; partial support must + not advertise the profile. +3. Only fresh native readback projected to the same portable field map proves + success. Use `RealizationObservation` with + `RealizationConcern.CONTENT_PLACEMENT`, the existing strength, binding, and + freshness checks, and the bound assertion/evidence/observation-boundary + path. A mutation response, returned desired-state snapshot, manifest claim, + cached mapping, or planned digest is not proof. + +The SEM-218 snapshot comparison remains necessary to reject an omitted or +changed exact requirement, but it is not independent readback. The +`RuntimeDatastoreMapping` family remains observed runtime inventory: its +type-count census and schema digest must not become the authored field map or a +second desired-schema DTO. A backend observer may inspect native mapping data +privately, but only the bounded portable projection and safe evidence reference +cross the portable boundary. + +## Canonical Incumbents + +The implementation must build on: + +- authoring and closed shape: `raes.content`, `SDLModel(extra="forbid")`, + `PortableIdentifier`, and a closed discriminated + `ServiceMaterialization` profile union; +- composition and semantic validation: `raes.composition` and + `SemanticValidator._verify_service_materialization()`, including target, + ordering, assertion, evidence, observation-boundary, tenancy, and reset + ownership checks; +- compilation and phase flow: + `raes_processor.compiler.placement`, + `ServiceContentMaterializationBinding` as the unchanged v1 variant, + `ContentPlacement.service_materialization` as the typed variant carrier, + `resource_payload()`, and the existing `content-placement` operations; +- exact realization: + `_append_service_materialization_requirements()`, + `CONCERN_PAYLOAD_PATH`, `realization_support_diagnostics()`, + `realization_disclosure()`, and runtime snapshot sanitization. Preserve + `service-content-materialization` for v1 and use the distinct + `service-search-index-schema-materialization` requirement kind for the new + profile; both use the same machinery and payload path; +- planner and direct-submission admission: + `service_materialization_plan_diagnostics()` as the shared closed-contract + gate, called by both the planner and + `raes_runtime.control_plane_submission`; +- capability and concept authority: + `ProvisionerCapabilities`, + `ProvisionerCapabilitiesModel`, + `backend_manifest_payload()`, manifest parsing, and + `contracts/concept-authority/controlled-vocabularies-v1.json`; +- canonicalization: + `raes_contracts.canonical.canonical_json_digest()` rather than a new digest + serializer; +- proof and conformance: + `RealizationObservation`, `ExpectedRealizationObservation`, + `operation_inventory_diagnostics()`, `observation_diagnostics()`, and the + existing content-placement concern/strength mapping; +- errors and persistence: + `Diagnostic`, `ApplyResult`, `RuntimeSnapshot`, realization provenance, + `experiment-evidence-record-v1`, and `experiment-run-v1`; and +- contract publication: + `schema_bundle()`, the four scenario-containing published schemas, their + publication entries and `last_change` hashes, fixtures, SDL lineage, + `specs/sdl/initial-service-state.md`, the public section reference, example, + and `test_initial_service_state.py`; ADR-061 remains the schema-evolution + policy; and +- repository workflow: `.ground-control.yaml`, `.gc/plan-rules.md`, the + canonical nox graph, `check_repo_policy.py`, + `check_requirement_governance.py`, `check_generated_schemas.py`, + `check_schema_publication.py`, concept-authority checks, SDL-lineage checks, + and `verify_all.py`. Release Please owns `CHANGELOG.md`. + +Keep one profile dispatch inside the existing service-materialization model, +compiler, and admission module. Do not copy profile literals, allowed fields, +or semantic mappings into unrelated planner, runtime, backend, and test-local +tables. + +## Cross-Cutting And Security Gates + +- **Parse and shape:** strict SDL/YAML parsing and `SDLModel` reject unknown + fields, empty schemas, invalid field names, and unknown or vendor semantic + literals. The profile contains no endpoint, URL, query, command, header, + credential, environment variable, host path, native id, or arbitrary options + map. +- **Composition and instantiation:** existing reference rewriting applies only + to actual SDL refs. Field names and semantics are values, not references. + Every instantiated field semantic must be concrete before compilation; no + backend selection or defaulting may resolve it. +- **Semantic admission:** the incumbent validator continues to prove exact + target-service ownership, dependency references, observed-state assertions, + evidence requirements, participant projection, shared-service tenancy, and + reset ownership. Profile-specific payload rules are added there, not repeated + as an unrelated whole-scenario validator. +- **Planner and direct submission:** the shared backend-protocol admission gate + validates the closed compiled binding, profile/version, non-empty field map, + recomputed canonical digest, content type, target address, ownership, bound + readback refs, capability term, SEM-218 support, and observation strength + before backend I/O. Unknown profiles and semantic values fail; there is no + profile fallback or first-supported selection. +- **Authentication and request shape:** no new HTTP or MCP route is needed. + Remote plan submission continues through the closed + `ProvisioningPlanModel`, request-size guard, idempotency fingerprint, + `ControlPlaneSecurityConfig.strict_defaults()`, verified identity, + backend/operator role authorization, target binding, and audit event path. +- **Secrets and process exposure:** adapter credentials remain in private + backend configuration or a secret resolver. They never enter SDL, plan + payloads, snapshots, evidence, diagnostics, logs, environment bindings, or + process argv. Any native helper uses fixed argv/no shell and bounded timeout; + native API authentication is not a profile field. +- **Backend result and error envelope:** backend calls continue through + `_call_backend_apply()` and return `ApplyResult` plus bounded `Diagnostic` + values. Preserve the baseline snapshot on malformed output or failed + readback. Do not add a profile-specific exception hierarchy, expose rejected + mappings, response bodies, credentials, native ids, or tracebacks, or turn a + provider error into a public diagnostic payload. The HTTP adapter's redacted + internal-error handler remains the outer envelope. +- **Persistence and observability:** portable persistence retains declared and + projected field semantics, canonical digests, operation/content addresses, + observation strength, provenance, and safe evidence refs only. Raw native + mappings, service responses, headers, adapter configuration, and credentials + remain out of `RuntimeSnapshot`, `ApplyResult.details`, control-plane audit + records, experiment artifacts, logs, and telemetry. + +Provisioning success is the ordering barrier for later orchestration and +participant admission. Native service readiness/retry belongs inside the +backend adapter and must be bounded and idempotent; do not reintroduce a +one-shot VM node, shell bootstrap, sidecar scheduler, or unbounded poll loop. + +## Extensibility Boundary + +The extension seam is the profile-versioned portable semantic projector and the +backend adapter's semantic-to-native mapping. A second Elasticsearch, +OpenSearch, or non-Elasticsearch backend implements the same portable v1 +semantics without changing SDL or the canonical digest. Adapter selection, +native index identity, credentials, connection policy, timeout, and retry +policy stay backend-local. + +Nested field paths, analyzers, collation, decimal/binary/geospatial types, +nullability, cardinality, dynamic-template policy, aliases, and a claim that no +additional fields exist are not implied by v1. Add only a demonstrated portable +semantic through a new profile version (or a separately named profile when the +operation/readback relation changes), with its own exact projection and +capability term. Do not add an open string or vendor extension map to v1. + +## Gotchas And Anti-Patterns + +Avoid: + +- extending `ContentItem` with a field type or treating an index as a document; +- overloading the existing `service-content-materialization` SEM-218 kind with + schema-reconciliation meaning; +- making `RuntimeDatastoreMapping.field_type_census` authored desired state; +- accepting `keyword`, `_mapping`, index templates, native queries, endpoints, + or `cortex_6` in the portable profile; +- hashing the raw native mapping, dictionary insertion order, or the whole + service response instead of the canonical portable projection; +- treating additional native fields as a mismatch while v1's claim is scoped + to declared fields, or accepting a missing/ambiguous declared field; +- accepting dynamic auto-creation, a mutation acknowledgement, a snapshot echo, + or a manifest declaration as readback; +- silently translating an unsupported semantic, selecting a weaker type, or + allowing partial profile capability claims; +- deleting/recreating an incompatible index outside reset ownership or adopting + an existing index by native name; +- duplicating the profile schema, validation rules, diagnostic hierarchy, + observation DTO, evidence carrier, persistence store, or workflow; and +- updating only the authoring model while leaving composition, all four + scenario schemas, schema publication records, capability/concept authority, + phase carriers, direct-submission admission, fixtures, docs, lineage, or + negative tests stale. + +## Non-Goals + +- Implementing an Elasticsearch/OpenSearch/TheHive/Cortex adapter or releasing + a backend support claim. +- Authoring vendor-native index names, mappings, analyzers, templates, queries, + credentials, endpoints, or bootstrap payloads. +- General datastore schema migration, destructive reindexing, document + insertion, historical-state modeling, event replay, or runtime inventory + redesign. +- A full portable database DDL, nested-field, analyzer, cardinality, or + dynamic-mapping language. +- A new materialization engine, plan, controller, repository, reset authority, + exception hierarchy, API route, secret store, logging framework, or evidence + contract. diff --git a/docs/decisions/issue-211-act-611-autonomous-behavior-vocabularies-preflight.md b/docs/decisions/issue-211-act-611-autonomous-behavior-vocabularies-preflight.md new file mode 100644 index 000000000..e3f2a5674 --- /dev/null +++ b/docs/decisions/issue-211-act-611-autonomous-behavior-vocabularies-preflight.md @@ -0,0 +1,387 @@ +# Issue 211 ACT-611 Autonomous Behavior Vocabularies Preflight + +Date: 2026-07-30. + +Issue: #211. + +Requirement: ACT-611, `07f918ad-2bb7-41a5-8975-904f1129ee1e`. + +This note records architecture guardrails for autonomous-service and +autonomous-agent behavior vocabularies. It is guidance only: it does not add +source records, contracts, schemas, adapters, fixtures, validators, SDL +fields, runtime behavior, or an implementation plan. + +## Existing Authority And Decision + +ADR-067 and `specs/formal/participant-behavior-model/README.md` remain the +native participant-behavior authority. Issue #986 and +`specs/concept-authority/external-concept-bindings.md` already publish the +scheme-neutral assertion boundary and its single offline admission path. +ACT-611 composes those authorities. + +No new ADR is required. An ADR would be warranted only if implementation +proposes to make an external term executable or validation-authoritative, add +an SDL participant or behavior field, alter lifecycle identity, introduce +network resolution, or change participant information-flow or realization +boundaries. + +The implementation decision is: + +- publish ActivityStreams Activity types and FIPA communicative acts as two + unrelated, versioned external schemes; +- project their pinned local source records into the existing + `ExternalConceptSchemeSnapshotModel`; +- bind both schemes to exact `behavior_specifications.` declarations + through unchanged `external-concept-bindings/v1` syntax and + `admit_external_concept_bindings()`; and +- keep all external terms descriptive assertions. They do not become SDL + actions, behavior modes, participant kinds, capabilities, authority, runtime + evidence, or outcomes. + +## Primary-Source Decisions + +### W3C ActivityStreams 2.0 Activity Vocabulary + +- **Authority and revision:** W3C Activity Vocabulary, W3C Recommendation, + 23 May 2017. Pin the dated Recommendation identity + `REC-activitystreams-vocabulary-20170523`, not a moving "latest" label. +- **Locator:** use the dated Recommendation at + `https://www.w3.org/TR/2017/REC-activitystreams-vocabulary-20170523/`. + The ActivityStreams 2.0 Core Recommendation may be retained as a supporting + citation, but the Vocabulary Recommendation is the term authority. +- **Portable scheme coordinate:** use + `scheme_id: w3c-activitystreams-activity-types`, + `authority: World Wide Web Consortium`, and + `revision: REC-activitystreams-vocabulary-20170523`. +- **Semantic level:** the extended Activity types classify activities that + may be past, present, or future. `Application` and `Service` are Actor/Object + types capable of performing activities; they are not Activity types and are + not behavior classifications. +- **Adoption decision:** **directly adopted** for the normative Activity type + IRIs only. Preserve the full + `https://www.w3.org/ns/activitystreams#` IRI as `concept_id`. + `Application` and `Service` may support source-scope or eligibility + rationale, but must not be placed in the behavior-term snapshot or converted + into RAES participant subtypes. +- **Digest strategy:** SHA-256 the retrieved bytes of the dated normative + representation used to extract the allowlisted Activity types and record + that prefixed digest with the exact locator and retrieval date. The checked-in + source record is the normal offline authority; remote comparison is an + explicit maintenance check only. +- **Citation and license:** retain the dated Recommendation, Recommendation + status, original W3C attribution, W3C document-use/license locator, and + applicable copyright notice. If copied definitions are published, include + the required notice in `THIRD_PARTY_NOTICES.md`; identifiers and locally + authored scope notes are preferable to copied prose. + +ActivityStreams is deliberately broad and social-Web-oriented. A positive +binding should normally use `related-to` plus `annotates`, with explicit +approximation/loss and limitations. A stronger relationship requires its own +review basis. It never proves that a RAES action occurred or that an +ActivityStreams actor exists. + +### FIPA Communicative Act Library + +- **Authority and revision:** Foundation for Intelligent Physical Agents, + FIPA Communicative Act Library Specification, document `SC00037J`, Standard + status dated 2002-12-03. +- **Locator:** use + `https://www.fipa.org/specs/fipa00037/SC00037J.html`; retain the FIPA + Communicative Act repository page as a supporting citation. +- **Portable scheme coordinate:** use + `scheme_id: fipa-communicative-act-library`, + `authority: Foundation for Intelligent Physical Agents`, and + `revision: SC00037J-2002-12-03`. +- **Semantic level:** the 22 approved names identify communicative acts in + FIPA ACL, with normative feasibility-precondition and rational-effect + semantics. They classify inter-agent communication, not arbitrary service + behavior, action execution, workflow order, or protocol conformance. +- **Adoption decision:** **usable only as an external annotation** of a + communication-oriented behavior specification. Preserve exact lower-case + FIPA symbols such as `inform`, `request`, `cfp`, and `not-understood` as + `concept_id`; do not translate labels into locally invented synonyms. +- **Digest strategy:** retain the required HTML locator, but SHA-256 the exact + official `SC00037J.pdf` representation used to pin the specification. The + HTML response contains dynamically rewritten email-protection markup and is + not byte-stable; maintenance verification therefore checks the stable PDF + bytes and separately cross-checks the ordered act identifiers against the + HTML. Store the exact document number, status date, both locators, prefixed + digest, and retrieval date. Admission remains offline and never discovers a + newer FIPA document. +- **Citation and license:** retain the FIPA copyright and specification notice. + The source expressly warns that it grants no permission for third-party + intellectual property. Publish identifiers and locally authored scope notes, + not copied formal models, examples, or normative descriptions, unless + publication rights have been separately confirmed. + +A binding does not claim FIPA ACL compliance. It does not import FIPA mental +state, message transport, content language, interaction protocol, feasibility +precondition, or rational-effect machinery into RAES. + +### W3C PROV-O + +- **Authority and revision:** W3C PROV-O Recommendation, 30 April 2013, + `REC-prov-o-20130430`. +- **Locator:** use the dated Recommendation + `http://www.w3.org/TR/2013/REC-prov-o-20130430/` and, if machine terms are + ever needed, its explicitly linked OWL encoding. +- **Semantic level:** `prov:Activity` is a time-bounded occurrence involving + entities; `prov:Agent` bears responsibility; `prov:SoftwareAgent` is running + software. These are provenance classes and responsibility relations, not a + vocabulary of autonomous behaviors. +- **Adoption decision:** **not semantically suitable** for ACT-611 + behavior-specification classification. Do not bind `prov:Activity`, + `prov:Agent`, or `prov:SoftwareAgent` to a behavior specification merely + because their English names overlap RAES concepts. +- **Digest strategy:** no ACT-611 snapshot is justified. A future provenance + integration must pin the dated Recommendation or exact OWL bytes with + SHA-256 and target an owning realized, observed, evidence, or provenance + subject kind rather than silently reuse this feature's behavior target. +- **Citation and license:** retain the dated W3C Recommendation, normative + version/status, W3C document-use rules, and attribution if future work copies + material. + +PROV-O remains useful prior art for keeping planned behavior, realized +activity, responsible agent, evidence, and provenance distinct. + +### IEEE 1872.2 Autonomous Robotics Ontology + +- **Authority and revision:** IEEE 1872.2-2021, *IEEE Standard for Autonomous + Robotics (AuR) Ontology*. IEEE records Board approval on 2021-09-23 and + publication on 2022-05-12. +- **Locators:** the authoritative IEEE standards page is + `https://standards.ieee.org/ieee/1872.2/7094/`. IEEE links a separate public + AuR OWL project at `https://opensource.ieee.org/aur/owl`. +- **Semantic level:** the standard extends the robotics and automation + ontology with concepts, definitions, and axioms for autonomous-robot system + knowledge and architectures. It is not a general autonomous-service or + communicative-act vocabulary. +- **Adoption decision:** **usable only as an external annotation** for + robot-specific subjects after exact source/version and semantic-level review; + it is not an initial ACT-611 scheme and must not become a RAES robot, + service, agent, task, goal, or behavior ontology. +- **Digest strategy:** the standard text and open-source ontology must not be + conflated. The standard text is purchase/subscription access. The linked + source project is BSD-3-Clause with an IEEE CLA, but its indexed project page + exposes no release tag. Any future source record must pin an exact commit, + hash the precise OWL files, record their license, and separately evidence + correspondence to IEEE 1872.2-2021. `main`, a project title, or the standard + number alone is not a digest-stable snapshot. +- **Citation and license:** do not copy the purchased standard text into the + repository. BSD-3-Clause source material may be used only with its required + notice, and only after provenance to the selected commit and published + standard has been established. + +## Exact Subject And Assertion Boundary + +Positive ACT-611 fixtures must target the coordinate emitted by +`external_concept_subjects()` for an actual behavior declaration: + +- `subject_kind` is the current declaration-index kind + `behavior_specifications`; +- `owning_contract_id` is `sdl-authoring-input-v1` for normalized/expanded SDL; +- `lifecycle_phase` is explicit, initially `normalized-authoring`; +- `canonical_ref` is exactly `behavior_specifications.`; and +- `artifact_digest` is the owning SDL artifact's + `canonical_sdl_digest()` value. + +Do not substitute the behavior spec's `spec_id`, its map key alone, a +participant ref, a prose label, JSON Pointer, array position, alias, or the +compiled `participant.behavior-specification.*` address. The external subject +adapter already projects every canonical declaration; ACT-611 must not add a +behavior-only index or resolver. + +The fixture's behavior specification should use existing participant refs, +action contracts, observation boundaries, outcome rules, authority/scope refs, +`behavior_mode`, realization refs, and evidence refs as needed to establish +native meaning. The external assertion only annotates or aligns that complete +native aggregate. `behavior_mode: autonomous` is still a governed RAES mode; +neither an ActivityStreams Actor type nor a FIPA term proves autonomy. + +Relationship, semantic effect, motivation, perspective, provenance, +supporting evidence, confidence, approximation/loss, limitations, review, and +participant eligibility retain the issue #986 contract meanings. Conservative +fixtures use `related-to` and `annotates`. `equivalent-to`, `aligns`, +`refines`, or `constrains` require independently reviewed support and may not +install new behavior or validation. + +## Canonical Incumbents To Reuse + +| Concern | Canonical incumbent and required use | +| --- | --- | +| Native behavior meaning | ADR-067, `specs/formal/participant-behavior-model/README.md`, `ParticipantBehaviorSpecification`, and existing action, observation, outcome, authority/scope, mode, realization, evidence, and compiler boundaries. | +| Portable assertion shape | `ExternalConceptBindingDocumentModel` and the published `contracts/schemas/concept-authority/external-concept-bindings-v1.json`. Do not add `autonomous_behavior_refs`, a scheme discriminator, or a second binding contract. | +| Exact SDL subject | `DeclarationIndex`, `build_declaration_index()`, `external_concept_subjects()`, `canonical_sdl_digest()`, and lifecycle-specific owning contract ids. | +| Neutral snapshot and resolution | `ExternalConceptSchemeSnapshotModel`, `ExternalConceptSnapshotTermModel`, scheme-specific adapter functions, `admit_external_concept_bindings()`, and `ExternalConceptResolutionOutcome`. | +| Shape and primitive types | `ContractModel(extra="forbid")`, `NonEmptyString`, `PrefixedDigestString`, RFC 3339/calendar-date types, and `validate_safe_absolute_uri()`. | +| Source records | Existing ATT&CK, ATLAS, and NIST source-contract patterns under `contracts/concept-authority/`, their source-shaped Pydantic models, offline loaders through `corpus_family_root(CONCEPT_AUTHORITY)`, and explicit remote maintenance checks. | +| Corpus distribution | `raes_contracts.corpus`, the Hatch build hook, and the existing packaged `contracts/` corpus. Do not load source records through repository-relative path arithmetic in library code. | +| Schema publication | Hand-governed `contracts/schemas/`, `schema_bundle()`, `contracts/schema-publication/entries/`, publication `last_change` hashes, and generated-schema parity. | +| Conformance | `_STRUCTURAL_ONLY_VALIDATORS`, `_SEMANTIC_CONTEXT_REQUIRED_CONTRACTS`, `validate_contract_payload()`, the fixture suite, and the same public offline semantic admission function used outside tests. | +| Diagnostics | `Diagnostic`, `Severity`, stable `external-concept.*` outcomes, and `sanitized_failure_message()`. Do not add scheme-specific exception classes or echo rejected identifiers. | +| Concept governance | ADR-012, ADR-062, `specs/concept-authority/`, and `tools/check_concept_authority_governance.py`. Source snapshots are not new native concept families or controlled SDL vocabularies. | +| Third-party rights | Source-record citation/license fields and `THIRD_PARTY_NOTICES.md` when copied material requires a distributed notice. | +| Workflow | `.ground-control.yaml`, `.gc/plan-rules.md`, existing nox `contracts`/`policy`/`verify` sessions, `tools/verify_all.py`, JSON artifact checks, requirement governance, and repository policy. | + +Source-specific record schemas and extraction adapters are allowed because +upstream authorities have different shapes. They are inputs to one neutral +snapshot model, not alternative author-facing contracts. Extract common source +verification mechanics only if reuse is real; do not clone an entire existing +ATT&CK/NIST checker and do not force unrelated upstream formats into a +universal source ontology. + +## Cross-Cutting Layers And Security Boundary + +The intended design passes these layers: + +1. **SDL ingress and native semantic validation.** The target scenario passes + the existing safe YAML parser, `SDLModel(extra="forbid")`, key and variable + rules, `ParticipantBehaviorSpecification` validators, named-reference + validation, controlled behavior-mode validation, and participant-behavior + analysis. ACT-611 does not weaken native validation to make a target + resolvable. +2. **Source-record shape and provenance.** Each checked-in source record passes + a closed source-specific `ContractModel`, its published JSON Schema, exact + authority/revision/locator/digest/citation/license checks, JSON artifact + validation, and optional allowlisted remote maintenance verification. +3. **Binding structural admission.** The unchanged binding model and normative + schema reject extra fields, unsafe or unpinned locators, invalid digests, + incomplete provenance, invalid effect/review/loss combinations, and + duplicate assertion identities. +4. **Exact subject resolution.** `DeclarationIndex` and + `external_concept_subjects()` supply collision-checked, phase-correct + declarations with the owning canonical digest. Resolution requires one + exact behavior-specification candidate. +5. **Scheme adaptation and contextual admission.** Each source adapter emits + the same neutral snapshot shape and preserves concept candidates as a list. + The same resolver produces deterministic `resolved-current`, `unavailable`, + `stale`, `ambiguous`, `superseded`, `unknown-concept`, and + `subject-not-found` outcomes for both schemes. +6. **Conformance and error envelopes.** Structural validation remains + registered in the canonical conformance registry; semantic context remains + explicit. Public diagnostics use stable bounded codes and sanitized + messages without Pydantic input echo, source bodies, raw exceptions, or + attacker-controlled concept ids. +7. **Authentication and information flow.** The standalone artifacts add no + auth surface. Assertion authority is provenance, not authenticated + identity. Participant availability remains `eligibility-only`; actual + exposure or delivery must pass existing participant identity, audience, + authorization, redaction, crossing, and disclosure gates. +8. **Secrets, configuration, OS, and network.** Source locators and concept ids + are inert data. Normal parse, load, adapt, admit, replay, inspect, and test + paths perform no live lookup, environment binding, plugin discovery, + subprocess execution, shell interpolation, filesystem search, host-path + access, or command dispatch. No source value enters process argv. The + artifacts contain no credentials, tokens, secret refs, or environment + variable names. +9. **Persistence and observability.** Use versioned checked-in contract + artifacts and exact id/version/digest references. Safe logs may record + binding id, scheme id/revision, subject kind/ref, digest, counts, and + resolution outcome. Do not persist source bodies or rejected values in + generic metadata, runtime snapshots, audit details, or logs. + +No controller, service, API route, store, or OS integration is justified. If a +later API accepts these artifacts, it must reuse +`ControlPlaneSecurityConfig.strict_defaults()`, verified identities, +audience/target and role checks, request-size limits, idempotency/fingerprints +for mutations, audit records, bounded `HTTPException` details, response +models, and the redacted internal-error handler. + +## Whole-Repository Surfaces In Scope + +- `docs/decisions/`, ADR-067, and the participant-behavior and concept-authority + specifications; +- source records, normative schemas, fixtures, source provenance, and schema + publication entries under `contracts/`; +- contract models/exports/schema bundle, corpus loaders, neutral snapshot + adapters/resolver, SDL subject adapter, and conformance registries under + `implementations/python/packages/`; +- source-integrity, exact-subject, schema-parity, resolver-outcome, + conformance-path, packaging, and leakage tests under + `implementations/python/tests/`; +- existing source verification, JSON artifact, generated schema, schema + publication, concept governance, repository policy, and requirement + governance tools; and +- `THIRD_PARTY_NOTICES.md` only when the published source material triggers a + notice obligation. + +No example-library, compiler, runtime snapshot, backend manifest, control-plane, +environment, deployment, or persistence change is required merely to publish +the two external schemes. + +## Extensibility Seam + +The seam is the existing neutral snapshot adapter: + +- a source-specific record pins upstream authority and preserves source terms; +- an adapter projects it to `ExternalConceptSchemeSnapshotModel` without + deduplication or semantic rewriting; and +- a governed consumer decides whether a successfully resolved assertion + matters to an already-authorized operation. + +A third scheme should add only a source record/model/schema, loader, adapter, +source verification, and fixtures. It must not edit +`external-concept-bindings/v1`, branch that contract or resolver on +`scheme_id`, add a global registry, or change offline outcomes. A future RAES +subject kind belongs in the existing subject-rule table and owning resolver, +not in a scheme adapter. + +## Gotchas And Anti-Patterns + +- Do not follow the pre-#986 offensive/defensive sibling-field pattern for + ACT-611. There is no `autonomous_behavior_refs` or autonomous controlled SDL + vocabulary. +- Do not treat ActivityStreams `Application` or `Service`, PROV-O + `SoftwareAgent`, IEEE robot/system classes, or the word "agent" as a RAES + participant subtype, implementation kind, or proof of independent agency. +- Do not treat ActivityStreams activities as executed actions, FIPA acts as + messages that were sent, PROV activities as behavior definitions, or IEEE + ontology classes as runtime capabilities. +- Do not bind participant names, roles, prose labels, action names, task ids, + goals, aliases, compiled addresses, JSON Pointers, or unqualified strings. +- Do not use source locators with fragments as a second concept-id channel. + ActivityStreams concept IRIs belong in `concept_id`; the dated document + belongs in `source_locator`. +- Do not case-fold, slug, translate, merge, or deduplicate upstream concept ids. + Preserve candidate multiplicity so ambiguity remains observable. +- Do not select "latest", follow redirects to a moving revision, rewrite + superseded terms, accept digest mismatch, or fetch on an unavailable result. +- Do not let an assertion create action contracts, observation boundaries, + outcomes, authority/scope, realization, evidence, information-flow policy, + participant eligibility beyond the contract's intent-only posture, or + conformance. +- Do not copy FIPA formal semantics or purchased IEEE text without confirmed + rights, and do not omit W3C/BSD notices when copied material requires them. +- Do not create a second schema authority, neutral snapshot type, resolver, + validation pass, conformance runner, exception hierarchy, logger, cache, + database, audit store, source registry, plugin, or CI workflow. +- Digest-pinned fixture artifacts are coupled to their subject SDL. Editing a + shared context file invalidates every binding over it; use a focused behavior + context or deliberately update all affected digests. + +## Non-Goals And Implementation Boundary + +ACT-611 does not: + +- define a universal ontology for agents, services, robots, tasks, actions, + goals, capabilities, autonomy, or multi-agent interaction; +- add SDL syntax, participant types, behavior modes, controlled behavior + fields, runtime records, backend features, APIs, stores, or deployment + configuration; +- replace action contracts, observations, outcomes, authority/scope, + realization envelopes, evidence, provenance, information-flow control, or + conformance; +- claim ActivityStreams, FIPA, PROV-O, or IEEE protocol/ontology conformance; +- require or permit live network resolution during normal operation; +- import PROV-O or IEEE 1872.2 as initial behavior schemes; or +- make an external assertion true, executable, authorized, disclosed, + realized, observed, reviewed, or evidenced merely because it parses. + +## Primary References + +- [W3C Activity Vocabulary Recommendation](https://www.w3.org/TR/activitystreams-vocabulary/) +- [W3C ActivityStreams 2.0 Core Recommendation](https://www.w3.org/TR/activitystreams-core/) +- [FIPA Communicative Act Library Specification SC00037J](https://www.fipa.org/specs/fipa00037/SC00037J.html) +- [W3C PROV-O Recommendation](http://www.w3.org/TR/2013/REC-prov-o-20130430/) +- [IEEE 1872.2-2021 standard page](https://standards.ieee.org/ieee/1872.2/7094/) +- [IEEE AuR OWL open-source project](https://opensource.ieee.org/aur/owl) diff --git a/docs/decisions/issue-812-adversarial-agent-control-preflight.md b/docs/decisions/issue-812-adversarial-agent-control-preflight.md new file mode 100644 index 000000000..9590b550d --- /dev/null +++ b/docs/decisions/issue-812-adversarial-agent-control-preflight.md @@ -0,0 +1,405 @@ +# Issue 812 adversarial participant control and boundary-IFC preflight + +Date: 2026-07-30 + +Issue: #812. + +Requirements: none. The GitHub issue title, body, acceptance criteria, and +non-goals are the contract. Requirement-backed child work must not begin until +its owning DRAFT Ground Control authority exists. + +This note records repository-wide architecture guardrails for the threat-model, +boundary information-flow, and AI-control evaluation design. It is guidance +only. It does not adopt a threat model or publish or amend an ADR or formal +specification. It also does not add a contract, change runtime enforcement, +declare a backend capability, create an evaluation, open child issues, or +establish robustness against intentional subversion. + +## Decisive current-state findings + +RAES already has the correct participant-neutral control skeleton. Issue #812 +must compose it rather than add an LLM-agent framework: + +- ADR-085, ADR-095, SEM-230 revision 2, and API-423/RUN-319 already define + deny-first crossing mediation, exact state cuts, participant-relative + observation, adaptive strategies, cross-episode memory, distinct crossing + stages, and append-only evidence. +- ACT-617 and API-409/RUN-310 already distinguish participant proposals, + approvals, denials, external direction, intervention, handoff, override, + cancellation, action admission, and execution. +- API-407 already owns declared and effective backend feature strength, + limitations, downgrade, required contracts, and realization evidence. +- ASR-535 and the experiment contracts already separate bounded semantic + falsification, runtime enforcement, backend conformance, model checking, + proof, task/run/study coordinates, evidence, derived measures, and + limitations. +- The runtime-fact binding plane already models typed observation, derived, + tool-result, and secret-reference sources; sensitivity, scope, freshness, + audience, provenance, allowed sink sources, and protected secret sinks. +- ADR-099 and SEM-231 already require supervisor visibility, adaptive + strategies, coalitions, memory, release, order, and timing to be explicit + when those facts are in the observer's surface. + +The missing authority is narrower but security-critical: + +1. no portable relation currently carries independent confidentiality and + integrity coordinates with conservative propagation through participant + context, derivation, proposals, arguments, transformations, handoffs, and + sinks; +2. `RuntimeFactSensitivity` is not an integrity label, `RawDataIntegrityModel` + is content-integrity metadata rather than source trust, object markings are + references rather than a complete flow lattice, and API-423 markings alone + do not supply transitive derivation; +3. ordinary structural/semantic admission does not decide whether an otherwise + valid action or output was derived from untrusted or confidential data; +4. intentional subversion, adaptive monitor evasion, collusion, audit-budget + exhaustion, and trusted/untrusted monitor roles are not current runtime + guarantees; and +5. RAES has no one revisioned control-evaluation profile binding honest/attack + mode, main/side objectives, attacker knowledge, monitor topology, audit and + intervention protocol, memory, safety/usefulness measures, and replay + evidence. + +These gaps warrant a DRAFT architecture authority during issue #812. It should +amend or compose ADR-085 rather than silently reinterpret it. This preflight +does not make that decision and must not be treated as the required DRAFT +authority. + +## Primary-source disposition + +| Source | Adoptable lesson | RAES boundary | +| --- | --- | --- | +| [FIDES](https://arxiv.org/abs/2505.23643) | Independent confidentiality and integrity labels, conservative propagation, default-untrusted external data, and deterministic checks before consequential actions. | Generalize to typed participant flows and sinks; do not adopt its LLM message or tool framework. | +| [CaMeL](https://arxiv.org/abs/2503.18813) | Separate trusted control from untrusted data, preserve provenance/capabilities, quarantine untrusted processing, and enforce policy at tool calls. | Quarantine and typed extraction are apparatus capabilities; they are not portable prompt semantics or automatic endorsement. | +| [SAMOS](https://research.ibm.com/publications/securing-mcp-based-agent-workflows) | Intercept every tool call and retain session-level flow context so individually legitimate calls cannot compose into leakage. | RUN-319 is the common mediation owner; an MCP gateway may be one backend realization, never the semantic boundary. | +| [AgentDojo](https://proceedings.neurips.cc/paper_files/paper/2024/hash/97091a5177d8dc64b1da8bf3e1f6fb54-Abstract-Datasets_and_Benchmarks_Track.html) | Evaluate task utility separately from security under indirect prompt injection and adaptive attacks in dynamic tool environments. | Reuse experiment task/run/study/evidence contracts; no benchmark-specific runtime semantics. | +| [AI Control](https://arxiv.org/abs/2312.06942) | Evaluate protocols against intentionally subverting policies using limited trusted labor, trusted editing, untrusted monitoring, collusion countermeasures, audit, and shutdown. | Trusted/untrusted are declared experimental roles and assumptions, not proof that a model or human is trustworthy. | +| [ControlArena](https://control-arena.aisi.org.uk/) | Make honest/attack modes, main/side tasks, monitor visibility, defer-to-trusted protocols, audit/shutdown, safety/usefulness, and trajectory export explicit. | Represent these through RAES experiment and participant-control authorities; do not import its policy, scaffold, trajectory, or scorer object model. | +| [runtime shielding](https://arxiv.org/abs/1501.02573) | A shield is a final runtime mediator for a formally defined safety property, not a general trust score. | Only a deterministic, complete sink policy may be called shielding; a heuristic monitor is evidence and advice, not authorization. | + +The useful common lesson is complete mediation of explicit flows at the last +enforceable boundary. None of these systems establishes model alignment, +chain-of-thought safety, monitor honesty, or protection from undeclared covert +channels. + +## Architecture decisions and guardrails + +### Keep confidentiality and integrity independent + +The DRAFT authority must define two independent, revisioned coordinates: + +- **confidentiality** constrains which audiences, principals, destinations, or + sink classes may receive information; and +- **integrity** records which origins or possible writers may have influenced + information and what minimum trust a sink requires. + +A single `trusted`, `safe`, `secret`, role, sensitivity, confidence, marking, +or monitor-score field cannot represent both. Content hashes establish byte +integrity, not origin trust. Authentication establishes principal identity, +not content integrity. Confidentiality authorization does not endorse +untrusted data, and integrity endorsement does not declassify a secret. + +The label algebra, ordering, conservative join, source defaults, and permitted +release operations belong to one revisioned policy profile. Opaque +transformations by a participant, model, external service, or script retain the +join of all inputs that could have influenced their result. Missing labels, +unknown sources, unresolved profile revisions, unsupported propagation, or +ambiguous joins fail closed or produce an explicit unsupported result; they +never become public or trusted by default. + +Declassification is an authorized confidentiality relaxation. Endorsement is +an authorized integrity upgrade. Both name the exact source, result, +dimensions, destination or sink, authority, policy revision/state cut, and +evidence, and both create a new derived identity. Neither mutates historical +labels. Redaction, projection, admission, approval, and authentication remain +separate operations. + +### Propagate across existing carriers instead of adding a generic agent event + +Flow state must follow the existing typed path: + +```text +observation/tool result/runtime fact + -> participant context and retained memory + -> proposal or participant output + -> derived/transformed value and action arguments + -> API-423 crossing decision + -> final external-action or disclosure sink +``` + +The normative design should define one relation over these carriers and use +typed refs, revisions, digests, provenance, and exact policy/cut coordinates. +It must not add an open `context`, `taint`, `agent_message`, `tool_call`, +`monitor_metadata`, or `security_labels` map beside them. + +The focused contract seam is the existing runtime-fact and API-423 crossing +composition. Do not add fields to `ParticipantRuntimeBaseEnvelopeModel` merely +to make every participant carrier look uniform; that would change unrelated +contracts before the shared semantics are settled. Do not copy runtime-fact +source/sensitivity validation into action, crossing, route, or backend code. +One resolver-backed contextual validator must join source facts, derivations, +effective labels, policy, authority, sink, crossing predecessors, and evidence. + +Cross-participant flow uses API-423 typed crossings, API-409 control/handoff, +and shared/joint-state authorities. A receiver inherits the effective labels +and provenance of upstream context. Direct participant messages, generic +handoff payloads, or controller changes do not reset labels. Cross-episode +replay names the SEM-230 memory scope and preserves source/profile/revision +history; episode reset is not declassification or endorsement. + +### Enforce immediately before every irreversible effect + +The final RAES-enforceable sink boundary is: + +- immediately before `RuntimeTarget` or a backend adapter performs an external + mutation or tool action; and +- immediately before an external or participant-facing value is serialized, + delivered, written, or otherwise disclosed. + +Earlier schema validation, action admission, proposal approval, monitor review, +planning-time capability checks, or API-423 request construction is necessary +but not sufficient. The runtime resolves the effective flow labels, exact +policy/state cut, sink capability and destination, principal/participant/ +audience authority, and API-407 effective support while the relevant history +heads are stable. It durably records the decision through the existing atomic +participant transition before dispatch or serialization. A denied, +unsupported, stale, or failed commit causes no backend call and no release. + +Backends that can bypass this point cannot claim realization. A gateway, +apparatus wrapper, prompt, SDK, or monitor may add defense in depth but cannot +be the sole boundary. Streaming, multipart output, callbacks, errors, and tool +arguments are sinks too; policy must cover each chunk or complete materialized +value before exposure, according to the governed profile. + +### Keep deterministic policy, monitoring, and control protocols distinct + +Deterministic policy gates decide authorization, permitted flow, capability, +admission, and final sink release. A heuristic monitor emits a bounded, +revisioned observation, suspicion result, or recommendation with provenance, +visibility, limitations, and confidence. Its score never authorizes an action +and missing or failed monitor output never widens permission. + +Monitor roles are experimental/apparatus declarations: trusted, untrusted, or +composed, with visibility, policy knowledge, shared inputs, independence or +correlation assumptions, possible collusion channels, and failure behavior. +Two monitors do not imply independent evidence. A “trusted model” is trusted +only within the named control-evaluation profile and capability boundary. + +Human or trusted-system intervention must state which operation it performs: + +- one-action authorization; +- declassification for named data and destination; +- endorsement/admission of an untrusted-derived value; +- trusted editing/transformation; +- control transition, deferral, handoff, interruption, or shutdown; or +- advice/evidence with no authority effect. + +If one intervention performs more than one operation, each is explicit and +independently authorized. Trusted editing creates a fresh proposal/result with +inherited provenance and effective labels, then re-enters normal validation, +policy, capability, and action admission. Approval is never execution, monitor +trust, declassification, or label erasure. + +### Make intentional subversion an explicit experimental mode + +Honest-but-fallible behavior and an attack policy optimizing a side objective +are different experimental modes. Invalid ordinary behavior, random negative +tests, prompt-injection examples, or a green conformance suite cannot establish +intentional-subversion robustness. + +A control-evaluation profile must close at least: + +- honest or attack mode, main objective, protected side objective, and success + conditions; +- participant capabilities and apparatus, policy and monitor visibility, + threshold/audit-budget knowledge, prior-outcome visibility, and allowed + collusion; +- adaptive strategy class over approvals, denials, edits, deferrals, handoffs, + interruptions, outputs, ordering, and any declared timing observations; +- monitor identities, trust assumptions, topology, correlation, visibility, + revision, and failure behavior; +- audit budget, sample/selection rule, intervention, trusted editing, + defer-to-trusted, shutdown, and interruption protocol; +- episode reset, persistent/shared memory, replay, policy revision, and + learning across episodes; and +- safety, usefulness, intervention/audit cost, uncertainty, limitations, and + nonclaims as separate measures. + +Use `ExperimentTaskModel`, `ExperimentEvaluationProtocolModel`, +`ExperimentStudyModel`, `ExperimentRunModel`, apparatus and factor contracts, +`ExperimentEvidenceRecordModel`, `ExperimentDerivedMeasureModel`, +`ExperimentRunTraceabilityModel`, and `BehavioralClaimBindingModel`. An audit +budget is an evaluation/protocol coordinate, not a participant compute +`ParticipantResourceBudget` unless the runtime actually enforces that resource. +A monitor score is a measure, not a policy decision. + +Until trajectory authority exists, a replayable trajectory is a digest-bound +graph of existing episode, behavior, control, crossing, action/result, and +experiment evidence refs with explicit observation/evidence boundaries. Do not +publish a second trajectory schema for this issue or copy a ControlArena log. +Hidden red-team objectives, credentials, private prompts, chain-of-thought, and +raw secrets remain outside portable evidence. + +### Require boundary-faithful attack cases + +| Case | Why ordinary admission is insufficient | Required boundary result | +| --- | --- | --- | +| Prompt/tool-result injection | An untrusted observation can produce a structurally valid, authorized action and valid arguments while redirecting control or destination. | Source defaults to untrusted; influence propagates through context and proposal; quarantine has no consequential capability; the final sink denies unless the exact integrity policy permits or governed endorsement occurs. | +| Confidential exfiltration | Reading a secret and sending an individually valid message or tool call may each be allowed while their composition leaks through arguments, output, errors, or a colluding participant. | Confidentiality propagates to every explicit derived sink; destination/audience policy blocks release and records safe evidence. Timing/covert channels remain a separate nonclaim. | +| Adaptive monitor evasion | A participant can learn from approvals, denials, edits, deferrals, audit frequency, or thresholds and shift to low-suspicion attacks. | The evaluation varies knowledge and adaptive strategy, accounts for audit-budget exhaustion and monitor correlation, and reports safety/usefulness separately. A monitor pass does not bypass deterministic gates. | +| Control-handoff manipulation | A valid API-409 handoff or external direction can transfer tainted context, change apparent authority, or induce a trusted participant to execute an attack. | Controller/authority change, flow labels, provenance, memory, receiver admission, and API-423 crossing are independently checked at one state cut; handoff never resets trust or grants action admission. | + +Each case must assert both the semantic result and the absence of prohibited +side effects across backend calls, participant-visible output, snapshot +histories, audit/evidence, errors, and replay. Cases that bypass the real +`RuntimeControlPlane`/`RuntimeTarget`/store boundary are contract tests, not +runtime-control evidence. + +## Canonical incumbents to reuse + +| Concern | Canonical incumbent and required use | +| --- | --- | +| Normative semantics | ADR-085, ADR-095, ADR-099, SEM-230, SEM-231, `Effective(rho,c)`, `MayCross`, exact cuts, strategy and memory scopes. Add no agent-local world, history, policy, or observer semantics. | +| Action and capability | SEM-211, `ParticipantActionAdmissionRequest`, `participant_action_admission_request_violations()`, ACT-622 decision-surface binding, action contract argument definitions, and participant implementation capability manifests. | +| Control and handoff | ACT-617, API-409 `ParticipantControlOccurrenceModel`, `validate_participant_control_occurrence_context()`, RUN-310 mediation, controller/authority binding, and `participant_control_history`. | +| Flow inputs and sinks | Runtime-fact declaration/version/sink/binding models, `RuntimeFactBindingPlane`, `validate_binding()`, `RuntimeFactDispatchCommand`, secret references, and protected sink handling. Extend their meaning through governed composition; do not fork source, sensitivity, freshness, or sink validation. | +| Crossing and projection | API-423 `ParticipantCrossingOccurrenceModel`, `ParticipantCrossingIntent`, `ParticipantCrossingPolicyResolver`, `validate_participant_crossing_occurrence_context()`, SEM-226 projection/exposure, and `participant_crossing_history`. | +| Runtime and persistence | `RuntimeControlPlane`, `RuntimeTarget`, `RuntimeSnapshot`, full-snapshot/transition diagnostics, `ControlPlaneStore.commit_participant_transition()`, expected history heads, operation records, idempotency, and both shipped stores. | +| Backend posture | API-407 `ParticipantFeatureSupport`, `PARTICIPANT_RUNTIME_CAPABILITY_REQUIRED_CONTRACTS`, `resolve_participant_feature_support()`, backend manifests, declared/effective strength, downgrade evidence, and `BackendConformanceReport`. | +| Evaluation and claims | Existing experiment task/protocol/study/run/apparatus/factor/evidence/measure/traceability contracts, behavioral relation profiles, `BehavioralClaimBindingModel`, and ASR-535 assurance axes. | +| Auth and transport | `create_control_plane_app()`, `ControlPlaneSecurityConfig.strict_defaults()`, `_ControlPlaneApiAuth`, `ControlPlaneIdentity`, role/target/participant-subject binding, `request_size_guard_response()`, closed DTOs, and semantic request fingerprints. | +| Errors and observability | `Diagnostic`, `Severity`, operation envelopes, the generic redacted 500 handler, `sanitized_failure_message()`, `AuditEvent`, safe evidence/provenance refs, and ADR-066 plane separation. | +| Contract governance | `ContractModel`, controlled vocabularies, `schema_bundle()`, hand-governed schemas/fixtures/publication entries, `x-raes-invariants`, concept authority, and lineage checks. | +| Workflow | `.ground-control.yaml`, `.gc/plan-rules.md`, `noxfile.py`, `tools/verify_all.py`, and existing policy, requirement, schema, semantic, conformance, and documentation gates. | + +## Cross-cutting security layers + +The intended design must pass every layer below; success at one does not +replace another. + +1. **Source and apparatus declaration.** Participant implementation manifests + and experiment apparatus declare capabilities and trusted/untrusted roles + without embedding prompts, credentials, policy bodies, or private state. + External observations/tool results default to untrusted when a trusted, + revisioned source resolver cannot label them. +2. **Transport shape and size.** Existing HTTP entry uses the content-length + and actual-byte guard followed by closed Pydantic DTOs. Path, query, and + header values are not covered by the body guard; touched surfaces must use a + shared bounded validator. No open label/policy/monitor maps are accepted. +3. **Authentication and binding.** Strict bearer or verified-proxy auth, + exact target matching, role checks, participant/controller subject binding, + and audience/destination authority precede semantic fact creation. + Authentication never supplies data trust or declassification. +4. **Structural and semantic validation.** `ContractModel`, runtime-fact and + action validators, API-409/API-423 resolver-backed contextual validation, + exact revision/digest/cut joins, and full-snapshot/append-only transition + validation all run. Validation logic has one owner per relation. +5. **Deterministic policy and capability.** The resolved flow profile, + action admission, exposure/declassification authority, and API-407 + declared/effective support compose deny-first. Monitor output cannot + override an unresolved, stale, unsupported, or denied gate. +6. **Final runtime sink.** The same in-process and HTTP path reaches + `RuntimeControlPlane` immediately before `RuntimeTarget` dispatch or + serialization. The effective labels and sink are rechecked at the stable + state cut, and the decision is atomically committed before effect. +7. **Persistence, idempotency, and replay.** `RuntimeSnapshot` histories and + `ControlPlaneStore.commit_participant_transition()` bind source/derivation, + policy/cut, labels, sink, controller/authority, capability posture, semantic + fingerprint, and expected heads. A retry returns the same decision; a + changed cut/profile/label/authority conflicts or receives a fresh decision. +8. **Projection, errors, audit, and evidence.** Project before serialization. + Expected failures use stable bounded codes/messages; unexpected failures use + the generic redacted 500 path. Logs, `AuditEvent.details`, diagnostics, and + evidence contain only safe refs, digests, classifications, counts, and + bounded summaries—never raw content, secrets, prompts, policies, monitor + internals, hidden objectives, or exception text derived from them. +9. **Configuration, secrets, and OS exposure.** Portable semantics add no + environment variable, CLI flag, shell command, subprocess, socket, daemon, + or sidecar requirement. Provider/apparatus configuration uses existing + config/manifest registries and secret references. Tokens, prompts, policy + bodies, tool arguments, and confidential values never enter process argv, + environment, host paths, stdout/stderr, or unbounded crash reports. +10. **Publication and verification.** Any later contract change updates the + authoritative model, schema, fixtures, publication manifest `last_change` + and content hash, generator parity, concept authority, lineage where + normative derivation changes, and focused/full verification. No runtime- + only field or documentation prose may substitute for published authority. + +## Extensibility seam + +The stable runtime seam is a revisioned flow-policy profile referenced by +existing runtime-fact, action, crossing, and backend records. It parameterizes +the confidentiality and integrity domains, conservative composition, trusted +source declarations, declassification/endorsement authorities, sink +requirements, exact policy/state cut, participant and cross-episode memory +scope, and fail-closed unknown behavior. Resolvers provide the immutable +profile and derivation graph; runtime and backend names never become policy +branches. + +The stable evaluation seam is a separate revisioned control-evaluation profile +bound through existing experiment artifacts. It parameterizes honest/attack +mode, objectives, attacker knowledge, adaptive strategy, monitor topology and +visibility, audit/intervention protocol, memory/replay, and measures. This +allows another participant apparatus, label domain, monitor protocol, backend, +multimodal source, or evaluation strategy without revising the canonical +carrier or inventing a generic agent framework. + +## Work decomposition boundary + +Before requirement-backed children are opened, issue #812 must publish its +DRAFT Ground Control authority and requirement disposition. Later children +must keep semantic authority, portable contracts, runtime enforcement, backend +or apparatus support, adversarial evaluation, and documentation as distinct +ownership surfaces with explicit dependencies. This preflight intentionally +does not enumerate, order, or implement those children. + +## Gotchas and anti-patterns + +- Do not use `RuntimeFactSensitivity`, object markings, confidence, roles, + signatures, content hashes, or a `trusted` boolean as a two-coordinate IFC + model. +- Do not create a second action, crossing, handoff, trajectory, experiment, + evidence, policy, capability, diagnostic, exception, audit, or persistence + hierarchy. +- Do not encode security semantics in `RuntimeSnapshot.metadata`, + `AuditEvent.details`, apparatus `metadata`/`constraints`, free-form + diagnostics, prompt text, backend-specific options, or logs. +- Do not make an HTTP gateway, MCP proxy, participant scaffold, prompt + sanitizer, monitor, or model wrapper the only enforcement point. +- Do not treat schema validity, action admission, approval, role membership, + declassification, endorsement, monitor score, backend declaration, runtime + enforcement, and backend conformance as interchangeable evidence. +- Do not trust content because a participant copied, summarized, redacted, + edited, or transformed it. Conservative influence remains until an explicit + governed operation changes one label coordinate. +- Do not allow human approval to silently erase provenance or simultaneously + authorize, admit, declassify, endorse, and execute. +- Do not infer independent monitors, non-collusion, or trusted-model behavior + from different process/model ids. Record the assumption and test correlated + failure where claimed. +- Do not disclose exact thresholds, hidden policy/monitor details, red-team + side objectives, or secret-bearing counterexamples in participant-visible + errors or audit evidence unless the selected experiment explicitly makes + them observable. +- Do not claim intentional-subversion robustness, universal noninterference, + shielding, backend realization, or covert-channel protection from ordinary + negative tests, a green benchmark, or monitor accuracy. + +## Non-goals and implementation boundaries + +- No model-alignment claim, proof of safe internal reasoning, chain-of-thought + capture, private prompt/state capture, credential capture, or participant + implementation introspection. +- No replacement of participant-neutral action, observation, control, crossing, + experiment, or evidence semantics with LLM chat/tool formats. +- No general-purpose policy engine, taint-analysis framework, message bus, + participant gateway, monitor service, trajectory store, or agent scaffold. +- No claim that every explicit flow is observable inside an opaque apparatus, + or that undeclared timing, resource, storage, model-steganographic, or other + covert channels are controlled. +- No automatic trust in a human, model, monitor, backend, or external service; + every role is a bounded authority or experimental assumption. +- No positive backend capability or assurance promotion without the existing + declaration, realization, and conformance evidence paths. +- No DRAFT authority, requirement creation, child-issue creation, contract + publication, runtime change, or evaluation delivery in this preflight. diff --git a/docs/decisions/issue-813-cross-backend-participant-control-preflight.md b/docs/decisions/issue-813-cross-backend-participant-control-preflight.md new file mode 100644 index 000000000..4479d194b --- /dev/null +++ b/docs/decisions/issue-813-cross-backend-participant-control-preflight.md @@ -0,0 +1,237 @@ +# Issue 813 mixed cross-backend participant-control preflight + +Date: 2026-07-31 + +Issue: #813. + +Requirements at preflight: none. The issue title, body, research clarification, +acceptance criteria, and non-goals were the contract. SEM-234 and ASR-537 were +created in DRAFT only after preflight and planning. + +This note records the repository-wide guardrails used by the design. It does +not publish a portable contract, alter trial compilation or runtime behavior, +declare a backend capability, execute a demonstration, or establish mixed +realization, transfer, interoperability, information-flow security, or +behavioral equivalence. + +## Decisive current-state findings + +RAES already separates most authorities that a mixed composition needs: + +- ADR-084 and SCE-002 own backend-neutral scenario families, experiment + selection, deterministic trial admission, apparatus pinning, immutable plan + and run identities, and runtime-fact limits. +- ADR-085, ADR-095, SEM-230, API-423, RUN-310, and RUN-319 own participant + projection, one acting controller, authority, action admission, handoff, + crossing stages, exact state cuts, append-only history, and atomic + commit-before-effect. +- ADR-090 and ADR-091 own shared time domains, clocks, progression, portable + time capabilities, realization evidence, and conformance. +- API-407 owns declared and effective backend feature strength, constraints, + downgrade, realization, and evidence. +- Experiment apparatus, run, evidence, associated-artifact, realization, and + behavioral-claim contracts already separate apparatus identity, raw + evidence, derived interpretation, conformance, and formal relations. +- The issue #600 cross-backend corpus compares two separate realizations of the + same scenario. It is not one simultaneously mixed run. + +The missing authority is a revisioned composition profile that can admit +multiple participant realization providers in one trial, bind every edge +between them, represent finite pre-admitted membership changes, and preserve +the existing authority and evidence boundaries. The existing admitted trial +entry pins one realization envelope. The experiment apparatus context may +describe many observed components, but it does not authorize a mixed execution +topology. + +Current controller semantics are also narrower than HLA ownership services. +They support one acting controller with active/revoked authority, +revision-fenced transition, and total effective order. They cannot truthfully +claim simultaneous scoped owners, leases, or joint/fused control. + +## Binding precedent guardrails + +### HLA + +Use the current IEEE 1516-2025 family and pin the exact part and edition. +Framework rules, the federate interface, and OMT have different +responsibilities. Adopt the following as service-specific precedents: + +- declaration and interest-management capabilities; +- scoped ownership acquisition and divestiture states; +- requested, offered, pending, committed, failed, expired, cancelled, and + stale transfer outcomes; +- time-regulating and time-constrained roles; +- lookahead, advance requests, grants, receive order, timestamp order, and + readback evidence; and +- directed delivery as an addressed interaction service. + +Reject these conflations: + +- object or attribute ownership is not participant identity, controller + authority, action authority, or handoff; +- publish/subscribe, regions, and DDM are not authorization, declassification, + IFC, or noninterference; +- directed delivery is not participant observation; and +- OMT representation does not establish common behavior. + +### Integrated federations and co-simulation + +NIST's integrated-federation work makes bridge topology, information hiding, +independent time scales, translation, and shared-resource effects explicit. +FMI leaves the co-simulation algorithm outside the standard. HELICS makes time +requests/grants and dynamic federation membership explicit. + +The RAES consequence is one explicit composition edge per exchange boundary. +Each edge needs component and adapter identities, direction, authority, +action/observation mapping, participant/audience policy, clock/order mapping, +support strength, loss, failure behavior, and evidence. A flat bus, common +interface, or gateway is insufficient. + +Unadmitted dynamic membership remains prohibited. A design may admit a finite +within-run phase schedule when all possible members and mappings are pinned +before execution. + +### Cyber ranges and agent environments + +ACTING/EDL-FG is strong precedent for separating infrastructure, screenplay, +injects, interactions, federation, telemetry, and assessment and for naming +hybrid simulated/emulated components. It is a recent preprint, not a ratified +interoperability standard. + +CybORG is evidence that one API can span simulation and emulation while +transfer still fails. Its published experiment succeeded in 139 of 210 +emulation evaluations and records simulation-only observation artifacts. +CyGIL is evidence for linked emulation-to-simulation model generation and +simulation-to-emulation evaluation. Its 50-of-50 result remains one bounded +scenario and apparatus result with unknown transitions and heuristic switching. +CyberBattleSim is a safe abstract simulation precedent, not an operational +fidelity claim. + +No common interface, successful case, or capability declaration may be +reported as equivalence. + +## Architecture guardrails + +### Allocation and trial identity + +- Portable SDL remains backend-neutral. +- Realization allocation is admitted experiment/trial intent over stable + compiled refs. +- The first profile may allocate participant runtime, controlled scope, action + family, observation source, and crossing boundary. +- Runtime and schedulers cannot select outside the sealed allocation. +- An inter-trial realization change creates a linked new plan entry and run. +- A within-run change is a finite pre-admitted phase transition. It appends + state and evidence and never rewrites trial identity, prior delivery, or + participant knowledge. + +### Control and ownership + +Preserve this join: + +```text +participant identity + -> acting controller + -> authority basis and controlled scope + -> action admission + -> selected realization provider + -> adapter or bridge responsibility + -> final backend effect +``` + +HLA ownership belongs beside realization responsibility, not in the +controller field. Pull and push acquisition preserve their initiator and +negotiation evidence but converge only after an atomic revision-fenced commit. +Oscillation needs explicit cycle/livelock, cooldown or retry, and evidence +semantics. + +Revision 1 retains exactly one acting controller per participant and episode. +It rejects lease, simultaneous scoped-owner, and joint/fused-control claims. +A future profile needs controller/scope identities, renewal and fencing or +quorum/arbitration semantics, clocks/order, failure and oscillation behavior, +and conformance evidence. + +### Information distribution + +Routing and filtering realize an already-authorized projection. SEM-230, +API-423, markings, release/declassification, and the exact policy/order cut +remain authoritative. + +Leakage analysis includes membership, subscriptions, class, region, +destination, size, timing, synchronization, ownership change, retraction, and +differential failure. Audit retention is an authorized evidence audience, not +participant disclosure. + +### Time and ordering + +Reuse the accepted time model and conformance machinery. Cross-clock +comparison needs an admitted mapping. A timestamp-only backend is +`disclosed_weak`; it cannot claim governed logical order. Backend +serialization requires a named clock/service, runtime readback, and +conformance evidence. + +Staleness binds controller, authority, capability, policy revision, state +revision, history head, and governed order. Wall-clock recency is +insufficient. Rollback, replay, concealment, and retraction append facts; they +do not erase delivery or participant knowledge. + +### Open and closed + +Do not create one `open` boolean. Separate: + +1. open-loop versus closed-loop observation and actuation; +2. closed-world versus bounded-open-world assumptions; and +3. fixed versus pre-admitted dynamic federation membership. + +Each has a different authority owner and failure behavior. + +## Required existing seams + +- SDL ingress: `parse_sdl()`, `parse_sdl_file()`, closed SDL models, + `SemanticValidator`, compilation, and post-instantiation validation. +- Trial: admitted trial plans, apparatus bindings, realization envelopes, + cleanup, isolation, immutable identities, and deterministic compilation. +- Control: participant-control contracts, contextual validation, RUN-310 + mediation, revision checks, idempotency, and history-head compare-and-swap. +- Crossing: API-423 carriers, deny-first policy resolution, delivery and + observation separation, and RUN-319 mediation. +- Time: shared time models, participant time-management context, + `TimeCapabilities`, realized-time evidence, and conformance diagnostics. +- Backend: API-407 feature support, controlled vocabularies, required + contracts, effective strength, limitation, downgrade, and conformance. +- Evidence: experiment task/run/apparatus/evidence contracts, associated + artifacts, realization provenance, behavioral claim bindings, and digests. +- Diagnostics: existing bounded diagnostics, operation receipts, audit events, + and sanitized backend failures. + +Do not add an HLA DTO, universal federation message, generic event, +federation-controller service, side store, exception family, logger, or +duplicate conformance report. + +## Demonstration boundaries + +The downstream protocol needs pure simulation, pure emulation/operation, +simultaneous mixed, inter-trial transition, pre-admitted phase transition, +open-loop, and closed-loop cases. + +Adversarial cases include stale handoff, concurrent intervention, unsupported +or false capability, timestamp-only/unmapped order, simulation-only +observation, unrealizable action, directed-delivery failure, prior-delivery +retraction, and bridge-metadata leakage. Denied authority, policy, mapping, +admission, and commit cases require zero prohibited effects. + +Every result binds scenario and policy digests, trial and run identity, +apparatus and adapters, allocation and topology, clocks/order, capability and +conformance, mappings, loss, provenance, limitations, and reproduction +evidence. + +## Non-goals + +- No issue implementation, schema, runtime coordinator, backend adapter, or + demonstration. +- No default HLA, FMI, HELICS, EDL-FG, CybORG, CyGIL, or CyberBattleSim + compatibility. +- No distributed, leased, simultaneous scoped-owner, or joint/fused + controller support in revision 1. +- No interoperability, transfer, trace inclusion, bisimulation, + IFC/noninterference, or backend-equivalence result. diff --git a/docs/decisions/issue-85-aut-802-human-cli-preflight.md b/docs/decisions/issue-85-aut-802-human-cli-preflight.md new file mode 100644 index 000000000..16c8e13bd --- /dev/null +++ b/docs/decisions/issue-85-aut-802-human-cli-preflight.md @@ -0,0 +1,265 @@ +# Issue 85 / AUT-802 human CLI preflight + +Date: 2026-07-31 + +Issue: #85. Requirement payload: none. The issue title, body, acceptance +criteria, and non-goals are the authoritative contract. + +This note fixes architecture guardrails for the RAES semantic CLI. It does not +implement commands or prescribe an implementation sequence. No new ADR is +needed: ADR-008, ADR-009, ADR-036, ADR-053, ADR-061, ADR-075, ADR-078, and the +SDL diagnostics specification already decide the relevant ownership, +authority, phase, evolution, and error boundaries. + +## Decisions and boundaries + +### The CLI is an adapter, not a second semantic engine + +`raes_cli` owns argument handling, input/output selection, rendering, and exit +status. It must call the public owning APIs in `raes`, `raes_processor`, +`raes_contracts`, and `raes_conformance`; it must not reproduce parsing, +normalization, reference resolution, compilation, contract admission, or +conformance logic in command handlers. + +Each invocation produces one typed, command-specific result before rendering. +Human and JSON renderers consume that same object, including the same status, +selected versions/profiles, provenance, payload, and diagnostic records. Do not +create parallel “human” and “JSON” execution paths or a universal ecosystem +result schema. Existing published domain models remain authoritative for their +payloads; CLI result metadata must not reinterpret them as a new portable +artifact family. + +Machine mode writes exactly one deterministic JSON document and a trailing +newline to stdout. Human mode writes the requested artifact or summary to +stdout and diagnostics to stderr. Progress, banners, tracebacks, and logging +never contaminate machine stdout. Canonical artifact bytes remain the output of +the existing RFC 8785 canonicalization APIs; pretty, stable CLI JSON is not +silently relabelled as canonical JSON. + +The exit taxonomy is centralized and non-overlapping: + +| Status | Exit | +|---|---:| +| Operation completed successfully, including a supported negative analysis conclusion such as unsatisfiable | 0 | +| Authored or portable input is rejected by parse, structural, semantic, admission, or conformance checks | 1 | +| CLI usage, selector, or mutually-exclusive-option error | 2 | +| Typed `unsupported` outcome under the selected operation/profile | 3 | +| Bounded input/output or other expected operational failure | 4 | +| Sanitized unexpected internal failure | 70 | + +Existing analysis commands currently use exit `2` for typed unsupported +results, which collides with Typer usage errors. AUT-802 must not preserve that +ambiguity as the stable surface. Any compatibility treatment follows ADR-075; +do not keep two meanings for one code. + +### Operation names do not collapse phase concepts + +- **Parse** performs bounded decoding, source-profile checks, structural + closure, canonical field recognition, typed construction, and no implied + semantic-validity claim. For SDL it yields the existing normalized authoring + phase, not an instantiated or compiled artifact. +- **Validate** runs the owning admission/semantic checks for the explicitly + selected input contract and validation profile. Schema/Pydantic validity, + SDL semantic validity, context-dependent semantic admission, and conformance + are distinct outcomes and must be disclosed with the exact validation + strength. +- **Normalize** emits the deterministic normalized representation of an + admitted input and reports the source format, migration policy, normalization + profile, source diagnostics, and any semantic/canonical digest that actually + applies. It does not mean source formatting, migration, reference resolution, + instantiation, canonical byte serialization, or provider-name sanitization. +- **Resolve** performs RAES-owned reference/module composition under an + explicit resolution policy. Reference lookup must reuse the declaration + index and semantic resolver. Module acquisition, registry lookup, lockfile + creation, and pack discovery are not hidden inside this verb. + `ExpandedScenario` remains an internal trusted phase, not a stable wire + artifact; resolve may return typed resolution/provenance data or feed a later + phase, but must not serialize that private representation as a new contract. +- **Compile** uses `compile_scenario_runtime_model()` after normal SDL phase + admission. It stops before backend planning or apply. `RuntimeModel` is an + internal dataclass graph, not a published wire contract: never expose + `asdict()`, `__dict__`, `default=str`, or MCP summary dictionaries as the + stable compiled artifact. A full machine-readable compile artifact requires + one governed typed projection; until such a contract exists, the stable + result may only claim compilation status and a bounded typed inspection + summary. +- **Transform** is a closed selector over transformations RAES already owns, + such as explicit source migration/formatting, instantiation, and canonical + snapshot production. It is not a generic plugin, script, patch, backend + translation, or pack conversion facility. Each transformation names its + input phase, output phase, profile, and provenance. +- **Inspect** queries admitted typed objects and the canonical declaration, + address, and reference indexes. The MCP inspection helpers under + `raes_mcp.tools.inspection` are presentation-specific, incomplete + best-effort maps that can render raw values; they are not semantic authority + and must not become the shared CLI implementation. +- **Conformance** invokes RAES-owned local contract/fixture checks and returns + the existing typed reports and diagnostics. It does not start a target, + invoke a backend, mutate runtime state, or elevate fixture-only evidence into + native conformance. + +Defaults may exist, but the result always records the effective contract id, +source format, migration policy, normalization/transform profile, validation +profile or strength, and processor/conformance profile. Portable-contract +input requires an explicit contract id; selection must never be guessed from a +filename, a permissive union, or the first model that accepts the payload. + +### Files and streams share one bounded ingress + +Every input-taking operation accepts either one path or `-` for stdin. Both +routes feed the same bounded byte decoder and typed operation. A stream with +relative imports has no implicit base directory; it requires an explicit safe +base/resolution input or returns typed unsupported. Pack layout, current +working-directory search, parent-directory search, and catalog discovery are +never inferred. + +Ordinary parse, validate, normalize, compile, transform, and inspect are +read-only. Writes occur only for an explicit output destination or explicit +in-place transform, with no implicit overwrite. Lockfiles, caches, OCI layouts, +evidence archives, runtime stores, and temporary project trees are not +incidental outputs. + +File-backed `parse_sdl_file()` currently composes imports, and OCI composition +can perform network requests and extract into `.raes/module-cache`. The current +`raes sdl resolve` writes `raes.lock.json`; `raes sdl publish` writes an OCI +layout. The AUT-802 path therefore needs an explicit offline resolution policy +at the parser/composition seam and must not wrap those handlers directly. +Remote acquisition, lock generation, publication, and pack-aware orchestration +belong to env-packs. A separately and explicitly selected handoff may invoke an +installed env-packs tool, but RAES does not import or duplicate its authority. + +The existing top-level `libvirt` and `corpus` commands exercise backend, +lifecycle, and evidence workflows. They are outside the stable RAES semantic +surface and must be migrated to their owning backend/tooling entry points under +ADR-075 rather than being relabelled as semantic operations. The same applies +to `sdl publish`. + +## Canonical incumbents to reuse + +- **SDL ingress:** `read_sdl_source()`, `SDLSourceParseOptions`, + `SDLParserLimits`, `load_sdl_yaml()`, mapping-key preflight, + `_load_normalized_data()`, `parse_sdl()` / `parse_sdl_file()`, closed + `Scenario` models, and `SemanticValidator`. +- **Phases and transformations:** `format_sdl_source()`, + `instantiate_scenario()`, `admit_instantiated_scenario()`, + `canonical_sdl_bytes()` / `canonical_sdl_digest()`, and + `canonical_instantiated_sdl_bytes()` / + `canonical_instantiated_sdl_digest()`. Preserve the normalized, expanded, + instantiated, and snapshot distinctions from ADR-078. +- **Resolution:** `build_declaration_index()` and the canonical reference + resolver for semantic references; ADR-053 composition, `TrustPolicy`, + lock/digest/signature checks, OCI bounds, and safe archive extraction only + when an explicit non-CLI acquisition workflow owns those effects. +- **Portable contracts:** `ContractModel(extra="forbid")`, + `parse_bounded_json_object()` for object-root contracts, the models and + version constants in `raes_contracts`, `schema_bundle()`, published + schemas/fixtures, and the schema-publication manifest. Published schemas + remain normative; Python models prove parity. Event-stream contracts have + array roots, so extend the same bounded, duplicate-rejecting JSON ingress + boundary for the root shapes named by the contract registry rather than + bypassing it with `json.loads()`. +- **Contract/conformance admission:** the public + `raes_conformance.conformance.validate_contract_payload()` registry, + `_fixture_case_diagnostics()` / semantic dispatch behavior, + `run_fixture_suite()`, `BackendConformanceReport`, and + `backend_conformance_report_payload()`. Do not add a third contract-id + switch in `raes_cli`. The existing structural-only and + semantic-context-required distinctions must be retained in the result. +- **Compilation:** `compile_scenario_runtime_model()` and + `compile_runtime_model()`. Do not route compile through + `run_reference_processor()`, because that adds backend-manifest selection and + planning. Reuse `raes_contracts.plan_projection` only for the separate + existing plan-inspection compatibility surface; a plan is not a compile + result. +- **Diagnostics:** `SDLParseDiagnostic`, `SDLParseError`, + `SDLValidationError`, `SDLInstantiationError`, + `raes_contracts.diagnostics.Diagnostic` / `DiagnosticModel`, parser + diagnostic projection, and the value-free Pydantic sanitization in + `raes_conformance.conformance.diagnostics.sanitized_failure_message()`. + Promote/reuse that sanitization behavior at a public owning seam rather than + copying another exception renderer. +- **CLI and tests:** the `raes_cli.main` Typer root, `CliRunner`, current + deterministic JSON tests, invalid-input redaction tests, installed console + script tests, stdin/subprocess tests, and output contract round-trip tests. +- **Governance/workflow:** `specs/sdl/diagnostics.md`, + `specs/formal/sdl-phases/README.md`, ADR-014, ADR-036, ADR-061, ADR-075, + `tools/policy/adr_policy.yaml`, `.ground-control.yaml`, + `.gc/plan-rules.md`, `noxfile.py`, and the generated-schema, authority, + public-docs, policy, lint, unit, and integration gates. + +The existing contract validator registry and `schema_bundle()` are already two +lists of supported contract ids with different purposes and incomplete +overlap. CLI support must extend or project from an owning registry and add a +parity test; a third handwritten map would guarantee drift. The extension seam +is a contract-id descriptor that selects the existing bounded decoder, owning +typed model, semantic/context admission, supported operations, and effective +profile. Adding a future contract or validation profile changes that seam, not +every renderer and command. + +## Cross-cutting security and runtime layers + +| Layer | Required behavior | +|---|---| +| Authentication/authorization | This is a local authoring process with no auth principal and no control-plane authority. Do not import `raes_runtime`, auth middleware, backend registries, or control-plane APIs. Filesystem access is only the invoking OS user's existing authority. | +| OS/process exposure | Argv may carry paths, bounded identifiers, format names, and profile/contract selectors. Parameter maps, tokens, credentials, private keys, trust-policy bodies, and source text do not belong in argv or environment variables; use bounded stdin/files and the existing `scenario-instantiation-request-v1` shape. Never spawn a shell or backend. | +| Byte/shape ingress | Bound file/stdin bytes before decode. SDL goes through UTF-8, YAML token/graph/resource limits, JSON-domain and duplicate/collision checks. Object-root portable JSON goes through `parse_bounded_json_object()`; array-root event streams need the same bounded, duplicate-rejecting decoder before their owning event model. Do not use bare `read_text()`, `json.loads()`, `yaml.safe_load()`, or direct model construction as a public ingress shortcut. | +| Config/profile shapes | Source format, migration policy, contract id, transform profile, validation profile, and resolution mode are closed selectors. Reuse `SDLSourceParseOptions`, `SDLMigrationPolicy`, contract version constants, validation-profile catalog selection, and conformance profile loading. Unknown selectors fail before work; no environment-derived hidden default. | +| Semantic/admission gates | SDL passes structural construction, semantic validation, instantiation/admission when required, and declaration/address collision checks. Portable artifacts pass their owning model and any semantic/context validator. “Structural only” and “semantic context required” remain explicit outcomes. | +| Module/network boundary | Offline/no-cache is the semantic CLI default. Local paths remain contained, locked content remains digest checked, and no OCI request, archive extraction, cache write, or trust-policy discovery occurs unless an explicit owning acquisition workflow was selected outside the semantic command. | +| Secret handling | Explicit `redacted` / `operator_secret` omission remains enforced. Diagnostics, summaries, provenance metadata, and logs never echo input values, parameter maps, `allowed_values`, source bodies, trust policies, request headers, credentials, or raw framework errors. A command explicitly emitting a normalized/transformed artifact may contain values already present in that requested artifact; do not duplicate them into diagnostics or logs. | +| Error envelope | Bound diagnostic code, stage/domain, severity, RFC 6901 address/path, safe source range, selected profiles, and count are permitted. Raw `str(exc)`, Pydantic `input`, context, docs URL, absolute cache path, traceback, and terminal control characters are not. JSON failures still use the typed result; expected invalid input is not an unstructured stderr-only exception. | +| Output/filesystem | Stdout/stderr and exit status are the default observability surface. Explicit file output must avoid accidental clobbering and partial writes and must not follow an unrelated pack layout. No lockfile, cache, database, `ControlPlaneStore`, telemetry record, audit event, or evidence archive is created. | +| Logging/telemetry | No new logging framework or telemetry is justified. If library code logs in the future, it receives only value-free operation metadata and diagnostic codes, never artifact payloads. | +| Host/runtime | No daemon, socket, browser/MCP server, backend process, container/libvirt connection, permission change, or lifecycle action is part of these commands. Hub and backend tools remain separate processes and authorities. | + +## Gotchas and anti-patterns + +Avoid: + +- treating parse success as semantic validity, schema validity as full + contract admission, conformance as validation, or fixture success as native + execution evidence; +- treating source formatting, migration, normalized authoring, canonical + semantic identity, instantiation, and generic transformation as synonyms; +- guessing contracts or versions from extensions, payload fields, or whichever + Pydantic union branch accepts first; +- calling `parse_sdl_file()` with imports under a supposedly pure command + without an offline resolver guard; +- reusing MCP `compile_pipeline()`, language-service plain dictionaries, + best-effort MCP reference maps, or human strings as the CLI service contract; +- serializing internal dataclasses, private validation flags, resources maps, + backend manifests, snapshots, or arbitrary object representations; +- duplicating schema lists, validator registries, semantic dispatch, + diagnostic codes, exception hierarchies, profile catalogs, or workflow logic; +- accepting inline `--parameter`, credential, private-key, registry-token, or + environment bindings that expose values in process listings; +- emitting source values, parameter values, filenames containing sensitive + markers, exception messages, or terminal escapes in diagnostics; +- writing a lockfile/cache/output merely because the input was file-backed; +- letting human and JSON renderers rerun the operation or decide status + independently; +- preserving the current exit-`2` collision between usage and unsupported; +- retaining the public CLI guide's current claim that `sdl resolve` prints a + composed scenario when the implementation actually writes a lockfile; +- importing runtime, backend, env-packs, or Hub code into RAES semantic + services, or moving pack/backend authority behind a RAES-shaped command. + +## Non-goals + +- A universal ecosystem CLI, generic plugin framework, or arbitrary + transformation engine. +- Pack scaffolding, discovery, layout, lock generation, publication, catalog + search, or pack-aware validation orchestration. +- Remote module acquisition as an implicit consequence of semantic parsing or + validation. +- Backend translation, planning as part of compile, realization, provisioning, + runtime control, experiment execution, evidence collection, or lifecycle + management. +- Browser, MCP, Hub, daemon, or service presentation. +- New authentication, persistence, logging, telemetry, audit, or secret-store + infrastructure. +- Replacing published domain schemas with a CLI envelope, exposing an internal + `RuntimeModel` as a portable contract, or creating a duplicate validation or + exception hierarchy. +- Implementing commands, renderers, registries, schemas, migrations, or tests + in this preflight. diff --git a/docs/decisions/issue-963-participant-opacity-proof-preflight.md b/docs/decisions/issue-963-participant-opacity-proof-preflight.md new file mode 100644 index 000000000..bdf7fb6ea --- /dev/null +++ b/docs/decisions/issue-963-participant-opacity-proof-preflight.md @@ -0,0 +1,502 @@ +# Issue #963 — Participant Opacity Mathematical-Proof Preflight + +Date: 2026-07-31 + +Issue: #963. + +Requirements: `SEM-231`, `ASR-535`. + +This note records repository-wide architecture guardrails for the mathematical- +proof assurance lane. It is guidance only. It does not state or mechanize the +theorems, select or pin a tool release, add a proof profile or evidence +contract, run a prover, change catalog assurance, establish opacity of a RAES +system, enforce a policy, synthesize a supervisor, or certify a backend. + +## Decisive Current-State Finding + +Issue #963 is a proof over the existing SEM-231 relation and its relationship +to SEM-230. It is not another opacity checker or formal-assurance subsystem. + +- ADR-099 and the SEM-231 specification own the one-sided possibilistic + opacity kernel, possible points, observer information cells, strategies, + release, memory, supervisor visibility, and relation boundaries. +- ADR-085 and SEM-230 own policy noninterference, low equivalence, complete + projected-history support, exact-cut declassification, adaptive low + strategies, scheduler/environment classes, and order assumptions. +- ADR-081, the behavioral-relation catalog, the shared relation profile, and + `BehavioralClaimBindingModel` already own relation identity, claim scope, + assurance axis, evidence scope, limitations, and explicit nonclaims. +- Issues #961 and #962 already own executable finite falsification, the shared + information-cell kernel, exact finite-state exploration, safe + counterexamples, and replay. Those artifacts are supporting examples and + regression oracles, not premises accepted on trust by the mathematical + proof. +- The participant-bisimulation proof-tool decision already identifies + Isabelle/HOL as the repository's proportionate route for a parameterized or + unbounded, kernel-checked relational theorem. Python tests, the in-process + model checker, Z3 satisfiability, mCRL2 finite equivalence, and a successful + process exit do not establish this issue's proof axis. + +Two gaps must be closed by the later implementation. First, “eligible +predicate” is not yet a formal assumption: noninterference cannot manufacture +a nonsecret alternative for a predicate that is true everywhere in a public +initial-state class. Second, the only published opacity profile is explicitly +fixture-bound and finite (`finite-possible-points`, finite bounds, and a +`declared-complete-finite-carrier` scope). It cannot honestly bind an abstract +theorem by changing only its assurance axis. + +No new ADR, relation id, relation registry, proof-result family, runtime +package, exception hierarchy, logger, store, endpoint, or authentication path +is justified. The missing boundary belongs in a proof-specific preflight, +formal theorem source, a non-finite variant of the existing closed relation- +profile seam, and one checked evidence bundle. + +## Expanded Verification-Execution Scope + +During implementation, the canonical verification graph exposed a separate +repository architecture problem: its independent gates were composed as one +serial session, unit and integration tests shared a mutable coverage file, and +the local completion path waited on rate-limited external HTTP link checks. +Warm-cache execution therefore took about 13 minutes before the organization +rename and about 18 minutes after new GitHub links encountered public rate +limits. Retrying a timed-out caller restarted the complete graph. + +Issue #963 now also owns the bounded remediation needed to make this proof lane +practical without weakening assurance: + +- one parent `verify` session synchronizes the locked Python environment once; +- static checks, contracts, the Isabelle proof, unit tests, integration tests, + and deterministic documentation checks execute as six isolated nox + subprocess lanes, concurrently; +- the parent caps simultaneous lanes at the smaller of four or half the + available CPU affinity, the unit lane uses at most half those CPUs through + xdist, and the JSON batch pool uses at most one quarter, preventing the graph + from treating every nested layer's local maximum as independently available; +- lanes are queued longest-first so unit, integration, and contracts start + immediately, while proof and documentation backfill the slots released by + static checks instead of adding to the initial process burst; +- JSON contract validation groups all metaschemas together and instances by + shared schema, then executes those batches with a bounded four-worker pool + instead of launching one tool process for each of 246 artifacts; +- unit and integration lanes write separate coverage data files, and the parent + combines and thresholds them only after every lane succeeds; +- local verification builds documentation without external HTTP requests, + while the pull-request docs workflow retains a separately visible and + blocking external-link session; +- direct `verify` and CI still include repository policy; the Ground Control + completion session omits only that lane because the workflow's mechanically + paired `policy_command` runs it immediately afterward; and +- every lane is reported even when another lane fails, so parallelism does not + reduce diagnostics or create fail-open cancellation behavior. + +The target is a warm-cache critical path governed by the slowest deterministic +lane rather than their sum. This change does not cache successful results, +silence failures, reduce coverage, parallelize stateful integration tests +internally, or make external-link health a local-network prerequisite. + +## Architecture Decisions And Guardrails + +### Prove a small theorem suite over one explicit carrier + +The mechanized source must define one abstract possible-point carrier `Omega`, +initial-information function `Init`, accumulated-observation function `Obs`, +selected predicate `S`, and information cell: + +```text +I(x) = { y in Omega | Init(y) = Init(x) and Obs(y) = Obs(x) }. +``` + +The positive theorem suite is limited to: + +1. the SEM-231 one-sided opacity kernel; +2. its knowledge characterization: no protected actual point has an + information cell wholly contained in `S`; and +3. the conditional implication from the exactly matching SEM-230 policy- + noninterference instance to SEM-231 opacity for every predicate satisfying + the declared eligibility assumptions. + +The proof must not import the Python kernel's result as an axiom or prove only +that the implementation returns a value. The formal definition is the +authority; `_kernel.py`, #961, and #962 are executable agreement and mutation +evidence. Any claim that the Python implementation realizes the mechanized +definition would require a separate correspondence theorem or checked +translation and is not part of #963. + +Knowledge must be defined over the exact information cell. If the proof uses +the epistemic word “knowledge,” it must establish the information relation's +reflexivity/factivity conditions rather than treating an arbitrary relation as +an S5 accessibility relation. The characterization must preserve the +one-sided polarity: learning `not S` remains allowed. + +### Make the noninterference implication genuinely conditional + +The implication theorem must quantify in this order, or an explicitly +equivalent order: + +```text +for every matching profile and SEM-230 parameter instance, + for every eligible predicate S, + if SEM-230 policy noninterference holds, + then SEM-231 participant-predicate-opacity holds. +``` + +“Matching” is a checked premise, not prose. It requires the same model and +reachable carrier construction; participant or coalition and audience; +initial public information; complete observation projection; participant +memory; exact cut/horizon; active-strategy domain; supervisor visibility; +policy sequence and declassification schedule; scheduler/environment class; +nondeterminism support; time, progress, concurrency, and order interpretation; +and probability posture. + +“Eligible” must require at least a nonsecret high variation for every protected +actual initial/public class and preservation of that nonsecret label on the +alternative point selected from equal SEM-230 low-history support. It must +also require that the alternative is reachable under the same active strategy +and all other coordinates that the opacity profile fixes. A tautological +predicate, a predicate fixed by public initial information, or a predicate +whose only nonsecret alternative lies outside the admitted carrier is not +eligible. + +For an active profile, the strategy quantifier remains outside the actual- +point obligation and the actual and alternative points use the same strategy. +For a coalition, the theorem sees the declared fused observation and memory; +individual results cannot be combined after the fact. For release, the theorem +assumes the same exact-cut schedule and evaluates the post-release predicate +and observation state. Revocation or concealment never supplies a memory-reset +axiom. + +SEM-230 compares complete support sets. If the opacity profile requires the +same individual scheduler, environment, or order choice for a witness rather +than membership in the same declared class, that stronger matching condition +must be an explicit premise. The proof must not hide this choice in a +convenient witness selection. + +### Mechanize the invalid implications as checked negative boundaries + +The same proof session must contain checked countermodels or negative lemmas +for the issue's invalid promotions: + +- opacity of one predicate does not imply policy noninterference; +- one equal-history secret/nonsecret pair does not satisfy the universal + secret-point obligation; +- declassification can change the information cell and knowledge; +- later revocation or concealment does not erase a retained observation; and +- epistemic indistinguishability, trace equivalence, simulation, refinement, + or bisimulation without secret/observation preservation can hold while + opacity fails; and +- an untimed possibilistic theorem supplies no timed, probabilistic, + quantitative, coalition, all-linearization, partial-order, or stronger + progress result. + +Epistemic indistinguishability is the information-cell membership relation, +not opacity itself. Trace equivalence, simulation, refinement, and +bisimulation may be used only behind a separately stated secret-, reachability-, +and observation-preservation theorem. Do not add axioms that make these +relations definitionally equal merely to obtain the desired implication. + +Negative evidence is a checked countermodel or theorem with a stable theorem +id. A proof script that merely fails, a commented-out theorem, `sorry`, an +admitted fact, an oracle, or an expected nonzero process exit is not durable +negative evidence. The session and evidence gate must reject unfinished proof +features and undeclared axioms. + +### Reuse the shared profile and claim authorities without relabeling the fixture + +Every positive proof claim remains a `BehavioralClaimBindingModel` for +`participant-predicate-opacity` with `assurance_axis=proof`, +`assurance_status=proved`, and `evidence_scope=proof`. Use one binding per +positive theorem scope, with exact theorem ids and evidence refs. The +knowledge lemma and the conditional implication do not create relation ids +such as `knowledge-opacity` or `noninterference-implies-opacity`. + +A passive theorem instance uses `quantifier_scope=all-traces`; an active +instance uses `quantifier_scope=all-strategies`. The active label cannot be +inferred merely because the abstract theory has a strategy type. + +The existing `participant-opacity-baseline-v1@sem-231/rev2` artifact is bound +to the finite fixture carrier and taxonomy `rev8`. It remains the #961/#962 +profile and must not be mutated, reinterpreted as abstract, or replayed against +ambient latest catalog/profile bytes. + +The proof needs a distinct, immutable profile artifact through the existing +`BehavioralRelationProfileModel` registry and loader. Generalize the existing +closed carrier/assurance-scope discriminant so a theorem profile can name an +abstract SEM-231 carrier and omit finite bounds; do not create a parallel +`ProofProfileModel` registry or copy the observer, secret, memory, release, +strategy, scheduler, environment, order, and time fields. Finite and theorem +variants share those semantic coordinates but retain different carrier and +evidence invariants. + +If the published profile schema changes, its Python model, hand-governed JSON +Schema, semantic invariants, fixtures, generated bundle, conformance validator +routing, publication entry/hash, corpus packaging, and compatibility decision +move together. Earlier rev8 catalog/profile/model-check bytes and digests must +remain available to reproduce #962 evidence. A taxonomy assurance update +advances the taxonomy revision; it does not rewrite historical evidence or +silently substitute a current profile. + +Stored claims and replay must resolve the profile by `(profile_id, +profile_revision)`. The incumbent id-only loader may remain a latest-authoring +convenience, but it is not an admissible historical-evidence resolver. + +### Keep proof evidence repository-local until a portable consumer exists + +Do not reuse `participant-opacity-model-check-evidence-v1`, +`scheduler-isolation-proof-v1`, `BackendConformanceReport`, an API-423 +occurrence, `RuntimeSnapshot.metadata`, `AuditEvent`, or operation details as a +mathematical proof record. Their domains and trust boundaries differ. + +The proof sources and session definition belong with formal authority under +`specs/formal/participant-semantics/`. A closed proof-evidence manifest should +follow the existing formal-semantic-validation protocol/bundle/execution- +snapshot convention and embed the incumbent `BehavioralClaimBindingModel` +directly. It must bind: + +- theorem ids and exact human-readable statements; +- catalog, profile, SEM-230, SEM-231, source, and dependency revisions/digests; +- carrier construction and every assumption named by the issue; +- prover name/version, distribution checksum or immutable container digest, + session configuration, and proof-kernel result; +- fixed replay command, working directory, locale, platform boundary, resource + limits, and verification-time network posture; +- source and generated-artifact digests, with generated output distinguished + from the checked source; +- every positive theorem, negative lemma/countermodel, and mutation id; +- exact proof-axis claim bindings, limitations, and explicit nonclaims; and +- an independently reproduced result and expected digest. + +The outer manifest may remain a repository-owned, strictly checked evidence +shape while there is no external contract consumer. It must not invent a +generic portable proof vocabulary. If a portable consumer is later identified, +publish a domain-appropriate `ContractModel` through the normal schema bundle +instead of stabilizing an ad hoc JSON shape. + +One semantic gate owns all cross-field joins. Pydantic or JSON shape validation +does not establish theorem success; a prover exit code does not validate the +claim/profile/catalog joins; and `tools/check_behavioral_relation_claims.py` +must still resolve every embedded claim through the canonical validator. + +### Use a kernel-checked development tool, not a runtime dependency + +Use the existing Isabelle/HOL theorem route identified by the participant- +bisimulation proof-tool decision for the parameterized/unbounded theorem. If a +different prover is selected, a scoped tool decision must first demonstrate +equivalent kernel checking, deterministic noninteractive replay, unfinished- +proof rejection, CI feasibility, immutable pinning, licensing, and independent +reproduction. Repository implementation language is not a selection reason. + +The prover is development/verification tooling under `tools`, `noxfile.py`, +and CI. It is not a dependency of `raes`, `raes_contracts`, `raes_processor`, +the CLI runtime, control plane, conformance runner, or backend. The canonical +verification graph invokes one fixed wrapper/session; no issue-local shell +script or hosted proof service becomes an authority. + +Catalog `proof_status` remains `deliberately-unproved` until the complete +pinned session, negative boundaries, manifest joins, and clean replay pass. +Tool absence, timeout, resource exhaustion, network dependence, stale digest, +missing theorem, admitted axiom, or replay drift fails closed and cannot emit +or retain a positive proof binding. + +## Canonical Incumbents To Reuse + +| Concern | Canonical incumbent and required use | +| --- | --- | +| Opacity authority | ADR-099 and `specs/formal/participant-semantics/participant-predicate-opacity.md`; theorem sources formalize this kernel and do not redefine it from Python behavior. | +| Noninterference premise | ADR-085 and `specs/formal/participant-semantics/information-flow-control.md`; reuse low equivalence, complete support sets, exact-cut release, memory, strategy, scheduler/environment, and order coordinates. | +| Relation/profile/claim authority | ADR-081, the behavioral-relation catalog, `BehavioralRelationProfileModel`, corpus loader, `BehavioralClaimBindingModel`, `validate_behavioral_claim_binding()`, and `tools/check_behavioral_relation_claims.py`. | +| Executable agreement evidence | `raes_processor.participant_opacity._kernel`, #961 bounded evidence, #962 exact-model evidence/replay, and their single-fault mutations. These are regression evidence, not proof axioms or proof certificates. | +| Formal-method policy | ADR-007/018, `specs/formal/assurance-policy.yaml`, and `specs/formal/assurance-fulfillment.yaml`; keep the FM3 classification and proportional, reproducible evidence. | +| Proof-tool precedent | `docs/research/participant-bisimulation/proof-tool-decision.md` and the Isabelle/HOL parameterized-theorem route. mCRL2's finite equivalence result remains a separate model-check lane. | +| Evidence convention | `docs/research/formal-semantic-validation/` protocol, bundle manifest, execution snapshot, safe repo-path resolution, bounded command output, empty/allowlisted environment, digest joins, and replay gate. | +| Digests and ingress | `ContractModel(extra="forbid")`, `parse_bounded_json_object()`, safe refs/revisions, `PrefixedDigestString`, and RFC 8785 `canonical_json_digest()` / `canonical_contract_digest()`. | +| Diagnostics/errors | Existing policy-gate failures, bounded safe diagnostics, and value-free operational failure posture. Do not import conformance only for its sanitizer or add a proof exception hierarchy. | +| Artifact handling | Canonical JSON, root-confined repository paths, safe labels, validated manifests, and atomic writes where a generated artifact is persisted. Add no mutable witness or proof store. | +| Schema/publication | `schema_bundle()`, hand-governed `contracts/schemas/`, fixtures, `x-raes-invariants`, schema-publication entries, generated-schema parity, and compatibility checks if the shared profile contract changes. | +| Tooling/workflow | `tools/tool_versions.py`, checksum-verified tool acquisition precedents, `noxfile.py`, pinned CI actions, `.ground-control.yaml`, `.gc/plan-rules.md`, requirement governance, and `tools/verify_all.py`. Governed commands use `RAES_REQUIREMENT_UID=ASR-535` because the branch name contains issue 963 but not the requirement UID. | + +Package ownership remains unchanged. `specs/formal` owns the theorem source; +`raes_contracts` owns portable relation/profile/claim shapes; +`raes_processor` owns executable finite analysis only; `tools` and nox own +proof replay; runtime, operations, conformance, and backend packages are not +proof authorities. + +## Cross-Cutting Layers And Security Posture + +1. **Authority and config shape.** Proof semantics come from committed formal + sources and one closed profile, not SDL metadata, YAML expressions, Python + import paths, remote URLs, environment variables, or caller-authored + theorem text. Profile and manifest JSON use bounded UTF-8, duplicate-member + rejection, object-root checks, safe ids, exact revisions, and digests. +2. **Schema and semantic joins.** The profile passes its published schema and + `ContractModel`; the claim passes `BehavioralClaimBindingModel`; the shared + validator joins catalog, profile, carrier, projection, quantifier, axis, + evidence, limitations, and nonclaims. A proof-specific gate then joins + theorem ids, assumptions, source/tool digests, and replay result exactly + once. Neither layer duplicates the other's validation. +3. **Authentication and policy boundary.** The proof is local, read-only + development tooling. It crosses no HTTP authentication, control-plane + identity/role/target binding, RUN-319 authorization, API-407 capability, + runtime mediation, persistence, or backend boundary and makes no claim + about them. Any future service exposure must reuse + `create_control_plane_app()`, strict security defaults, request bounds, + identity/target binding, fingerprints/idempotency, audit, and the redacted + error envelope; #963 adds no route. +4. **Supply-chain and tool gate.** Pin the prover release and every theory or + component dependency by immutable digest. Verify acquisition before use and + record the measured version. Verification runs offline; it does not fetch + sessions, packages, archives, theories, or containers on demand and does + not rely on ambient credentials or a mutable hosted service. +5. **OS/process exposure.** Invoke a fixed allowlisted executable with list- + form argv and no shell, from a fixed repository-relative session path. + Use a temporary tool state/home, deterministic locale, allowlisted + environment, no network, bounded CPU, wall time, output, and per-process + address space, plus explicit Java and ML heap ceilings. Report these as + per-process/per-runtime limits, never as aggregate process-tree accounting. + Mount only the pinned prover distribution, fixed session inputs, required + system runtime paths, and private scratch state; never bind the host root, + user home, or repository-wide workspace into the proof sandbox. + Do not place theorem contents, predicates, models, witnesses, credentials, + tokens, complete evidence, or host paths in argv, environment variables, + filenames, shell history, process listings, stdout/stderr, or host logs. +6. **Secret-handling boundary.** Formal sources use abstract types and + synthetic examples only. Profiles, countermodels, manifests, logs, CI + artifacts, and review output contain safe refs, theorem ids, counts, and + digests, never real secret values, participant content or memory, policy + bodies, supervisor internals, credentials, rejected payloads, native + objects, environment dumps, or hidden world state. Hashing sensitive content + does not make it publishable. +7. **Diagnostic and error-envelope gate.** Expected failures use bounded stable + codes and safe theorem/profile coordinates. Do not copy raw prover output, + source excerpts, Pydantic `input_value`, exception text, tracebacks, paths, + or environment data into the manifest, CLI summary, audit, or documentation. + A failed proof produces no positive evidence. A future HTTP boundary keeps + the incumbent `{"detail":"internal server error"}` response. +8. **Artifact and persistence gate.** Validate claims, theorem coverage, + digests, nonclaims, and redaction before canonical serialization or atomic + publication. Committed proof evidence is immutable and replayable. It never + enters runtime snapshots, operation details, audit blobs, backend reports, + a database, or a new evidence service. +9. **Logging and observability gate.** Progress and prover logs are not proof + evidence. Retain only bounded safe summaries needed to diagnose the gate; + the validated manifest carries the exact result and provenance. CI uploads + the bounded evidence bundle, not the workspace, tool cache, environment, + unrestricted logs, or prover installation. +10. **Governance gate.** A proof assurance change advances the catalog + revision and every current producer, reader-facing specification, fixture, + profile, claim-policy surface, and lineage/nonclaim reference together. + Historical model-check evidence remains bound to its original bytes. The + canonical policy, schema, docs, tests, and full verification graph remain + the only delivery workflow. + +## Whole-Repository Surfaces In Scope + +- **Normative authority:** ADR-081/085/099, SEM-230, SEM-231, the behavioral + catalog, relation profile, claim validator, and assurance aggregates. +- **Proof source and evidence:** one formal session beside SEM-231, exact + theorem/negative-lemma ids, a closed checked manifest, pinned tool provenance, + and clean replay. +- **Portable contracts:** only the existing profile and claim authorities, plus + their schema/publication surfaces if the finite-only profile discriminant is + generalized. No generic proof-result contract is presumed. +- **Verification:** proof replay, unfinished-proof/axiom rejection, negative + countermodels, profile and claim joins, historical digest replay, claim + policy, schema/concept/JSON/docs gates, and the canonical nox graph. +- **Host/CI:** checksum-verified acquisition, offline bounded execution, + temporary tool state, safe argv/environment/output, and bounded artifact + upload. Runtime, backend, conformance, control-plane, and data-store layers + are explicit non-traversed boundaries. + +## Extensibility Seam + +The stable seam is: + +```text +SEM-231 relation + -> resolved closed theorem profile + -> parameterized possible-point / information-cell locale + -> optional matching SEM-230 locale and eligibility premise + -> named checked theorems and countermodels + -> proof-axis claim bindings and replay manifest +``` + +The required parameter is the resolved relation profile plus an explicit +SEM-230-to-SEM-231 correspondence record for the implication theorem. The +theorem locale must parameterize the carrier, observer projection, secret, +memory, strategy, release, scheduler/environment, time, and order coordinates +rather than hard-code the finite fixture or Python field layout. + +A future eligible predicate, observer, active-strategy domain, coalition fusion +rule, release schedule, or total-order model can instantiate the same kernel +only when its profile and correspondence obligations are discharged. A timed, +probabilistic, quantitative, progress-sensitive, or true partial-order result +needs its own semantics and proof obligations; the seam rejects that lift +rather than adding an unchecked Boolean option. + +## Gotchas And Anti-Patterns + +Avoid: + +- relabeling #961 bounded evidence or #962 finite model-check evidence as + `proof`, or treating exhaustive Python execution as a mathematical theorem; +- binding an abstract theorem to the fixture-only baseline profile or changing + its carrier/digest under `sem-231/rev2`; +- claiming noninterference implies opacity without the nonsecret-variation, + reachability, secret-preservation, and exact profile-correspondence premises; +- treating a tautological predicate or one fixed by public information as an + eligible secret; +- reversing the implication from one-predicate opacity to noninterference; +- replacing the universal secret-point obligation with one equal-history pair; +- defining knowledge without the exact information cell and its + reflexivity/factivity boundary; +- changing active strategy, memory, release, scheduler, environment, order, or + supervisor posture between actual and witness points without an explicit + theorem premise; +- treating declassification as knowledge-preserving or revocation, + concealment, reset, rollback, or supersession as erasure; +- treating trace equivalence, epistemic indistinguishability, simulation, + refinement, or bisimulation as opacity without a checked preservation + theorem; +- lifting the possibilistic untimed result to probability, posterior risk, + entropy, timing, progress, coalition sharing, all schedules, partial order, + or quantitative leakage; +- accepting admitted axioms, unfinished proofs, skipped sessions, timeout, + unavailable tooling, mutable pins, network fetches, stale digests, missing + negative lemmas, or replay drift as positive evidence; +- creating another relation/profile registry, claim DTO, generic proof schema, + exception hierarchy, logger, store, executable, endpoint, auth stack, or + workflow; +- making the prover a Python/runtime dependency or invoking it through a shell, + user-controlled command, import path, URL, or environment-selected profile; + and +- publishing raw tool output, host paths, source excerpts with sensitive + values, model content, predicates, witnesses, credentials, or environment + data in artifacts or errors. + +## Non-Goals And Implementation Boundary + +Issue #963 may state and independently check the one-sided opacity kernel, its +knowledge characterization, the exactly conditional SEM-230 implication, and +the required negative lemmas; bind them to an abstract closed theorem profile +and proof-axis claims; and integrate hermetic replay with repository +verification. + +It does not: + +- prove that RAES, RUN-319, the reference runtime, or any backend satisfies or + enforces opacity or SEM-230 policy noninterference; +- authenticate a source model, synthesize a supervisor or policy, mediate a + crossing, or add backend declaration, realization, or conformance; +- prove the Python checker corresponds to the formal theorem, certify #961 or + #962 materializers, or replace their finite evidence; +- prove the reverse implication, arbitrary predicates without eligibility, + symmetric opacity, erasure, anonymity, trace inclusion/equivalence, + simulation, refinement, or bisimulation; +- establish timed, progress-sensitive, probabilistic, quantitative, + coalition, all-schedule, causal-frontier, or partial-order variants outside + an exact independently proved profile; +- add SDL syntax, an executable secret-predicate language, a world/history or + belief store, runtime API, proof service, backend feature, or operational + persistence; or +- make any proof claim before the pinned tool, complete session, negative + boundaries, exact manifest joins, independent replay, and catalog/profile + revision discipline all pass. diff --git a/docs/explain/reference/shared-concept-model.md b/docs/explain/reference/shared-concept-model.md index aacb29aab..26da5a261 100644 --- a/docs/explain/reference/shared-concept-model.md +++ b/docs/explain/reference/shared-concept-model.md @@ -208,7 +208,10 @@ The standalone `external-concept-bindings/v1` contract covers the different case where an author or reviewer relates one exact, digest-pinned RAES subject to a concept in an arbitrary versioned external scheme. ATT&CK Enterprise and NIST CSF fixtures demonstrate the same scheme-neutral shape and offline -resolver. +resolver. ACT-611 extends that proof with W3C ActivityStreams Activity types +and FIPA communicative acts bound to exact +`behavior_specifications.` declarations; it does not add an +`autonomous_behavior_refs` field or a native agent ontology. This assertion surface keeps relationship, motivation, effect, perspective, provenance, evidence references, confidence, approximation or loss, @@ -222,6 +225,8 @@ The binding remains descriptive and reviewable. It is not a native manifest evidence record, participant disclosure, or delivery receipt. The normative model and resolution table are specified in [`specs/concept-authority/external-concept-bindings.md`](../../../specs/concept-authority/external-concept-bindings.md). +The autonomous behavior source decisions and examples are specified in +[`specs/concept-authority/autonomous-behavior-vocabularies.md`](../../../specs/concept-authority/autonomous-behavior-vocabularies.md). ## RAES Extension Discipline (GOV-919) diff --git a/docs/explain/releasing.md b/docs/explain/releasing.md index 0933f3d23..3e7a0c0c4 100644 --- a/docs/explain/releasing.md +++ b/docs/explain/releasing.md @@ -72,7 +72,7 @@ token stored): - PyPI → *Your projects* → *Publishing* → *Add a pending publisher* → GitHub - PyPI Project Name: `raes` -- Owner: `RAESystem` · Repository: `rae` +- Owner: `OpenRAE` · Repository: `rae` - **Workflow name: `release-please.yml`** · Environment name: `pypi` > If you previously registered the publisher against `release.yml`, update it to diff --git a/docs/explain/sdl/lineage.md b/docs/explain/sdl/lineage.md index 08c354bf9..59bd6dd33 100644 --- a/docs/explain/sdl/lineage.md +++ b/docs/explain/sdl/lineage.md @@ -59,7 +59,7 @@ semantics, examples, or code from that source. the SDL schema. The authored/defaulted/planned/realized/observed/derived distinction tested by -[issue #160](https://github.com/RAESystem/rae/issues/160) is a carrier +[issue #160](https://github.com/OpenRAE/rae/issues/160) is a carrier boundary, not a vocabulary tag. SDL and `model_fields_set` carry authored and defaulted meaning; compiler plans carry planned operations; realization provenance and realized-form disclosures carry admitted choices; evidence @@ -558,8 +558,10 @@ RAES relies on prior work in four ways: [SP 800-61r2](https://csrc.nist.gov/publications/detail/sp/800-61/rev-2/final) / [r3](https://csrc.nist.gov/pubs/sp/800/61/r3/final) frames incident handling. These sources motivate separate functional roles; none defines a - required RAES product profile. Initial authored content stays under top-level - `content` and `service_materialization` per ADR-088. + required RAES product profile. Initial authored content and portable + search-index field-schema state stay under top-level `content` and the closed + `service_materialization` profiles per ADR-088. Native field types and mapping + bodies do not cross that boundary. - **Automation and presentation precedents:** OASIS [CACAO v2.0](https://docs.oasis-open.org/cacao/security-playbooks/v2.0/security-playbooks-v2.0.html) and [OpenC2](https://docs.oasis-open.org/openc2/oc2ls/v1.0/oc2ls-v1.0.html) @@ -987,15 +989,22 @@ which dynamic queue/log/config details remain evidence or bounded settings. RUN-308 concurrency evidence, existing operation receipts/statuses, and existing time-state/provenance. It claims no wire, API, lifecycle-token, or behavioral compatibility with those sources. -- Issues #811 through #813 own proof-bearing bisimulation, adversarial - threat-model, and simulation/federation extensions. Issue #810 now defines - opacity and supervisor-visibility architecture only; #961 delivers its - bounded checker, #962 delivers its exact finite-model checker, and #963 - through #965 own the proof, runtime, and backend lanes. SEM-230 preserves - their participant, audience, policy revision, declassification, +- Issues #811 and #812 define proof-bearing bisimulation and adversarial + threat-model extensions. Issue #813 and ADR-102 now define the mixed + cross-backend composition extension. It supports both alternative + simulation/emulation realization and simultaneous mixed realization, plus + linked inter-trial and finite pre-admitted within-run changes. SEM-234 and + ASR-537 remain DRAFT; #1013 through #1019 own semantic, contract, trial, + runtime, backend, demonstration, and claims work. Revision 1 keeps one + acting controller and rejects lease, simultaneous scoped-owner, and + joint/fused-control claims. Issue #810 defines opacity and + supervisor-visibility architecture only; #961 delivers its bounded checker, + #962 delivers its exact finite-model checker, and #963 through #965 own the + proof, runtime, and backend lanes. SEM-230 preserves every extension's + participant, audience, policy revision, declassification, controller/authority, scheduler/environment, timing/probability, order, and - evidence coordinates; that extension seam is not evidence those properties - are already realized. + evidence coordinates; none of these extension seams is evidence of runtime + or backend realization. - [STRIPS](https://doi.org/10.1016/0004-3702(71)90010-5), [PDDL](https://doi.org/10.2200/S00900ED2V01Y201902AIM042), [PDDL2.1](https://doi.org/10.1613/jair.1129), and the probabilistic planning @@ -1274,10 +1283,12 @@ which dynamic queue/log/config details remain evidence or bounded settings. noninterference, trace inclusion or equivalence, simulation, refinement, strong or weak bisimulation, epistemic indistinguishability, timed or probabilistic security, opacity, or native-backend realization. Issues #810, - #811, #812, and #813 own opacity, a proof-bearing bisimulation target, - adversarial-control evaluation, and cross-backend demonstration respectively. - ASR-535 adds evidence rather than a normative derivation or compatibility - claim, so the lineage ledger and source audit remain unchanged. + #811, and #812 own opacity, a proof-bearing bisimulation target, and + adversarial-control evaluation. Issue #813 now defines mixed composition and + cross-backend realization/transfer evidence; its positive demonstration is + still owned by #1018. ASR-535 adds evidence rather than a normative + derivation or compatibility claim, so the lineage ledger and source audit + remain unchanged. - Issue #802 applies the already adopted SEM-230/API-423/RUN-319 lineage to migration without importing another external model. The exact RAES mapping is the legacy/current distinction retained before @@ -1418,10 +1429,13 @@ disposition do not change. ## Runtime, Time, And Causality -- [TENA](https://www.trmc.osd.mil/tena-about.html) and the - [IEEE High Level Architecture (IEEE Std 1516-2010)](https://standards.ieee.org/ieee/1516/3744/) +- [TENA](https://www.trmc.osd.mil/tena-about.html) and the current + [IEEE High Level Architecture framework (IEEE Std 1516-2025)](https://standards.ieee.org/ieee/1516/6687/) are the main runtime/federation precedents for distributed exercise services, - time management, and object publication. + time management, object publication, ownership, and data distribution. The + 2025 family supersedes the 2010 edition cited by the earlier time-model + survey; claims now pin the exact framework, federate-interface, or OMT part + and edition. - [SISO Cyber DEM](https://cdn.ymaws.com/www.sisostandards.org/resource/resmgr/standards_products/siso-std-025-2023_cyberdem.pdf) and Cyber FOM are cyber-specific simulation-interoperability precedents. - Lamport logical clocks, HLA time management, Time Warp, DEVS, SimPy, ROS 2 @@ -1477,6 +1491,57 @@ federation object model derived from it. surface is partial and explicitly incomplete. This is detailed in the [Related-Work Comparison](related-work-comparison.md). +### Mixed Simulation, Emulation, And Operational Composition + +Issue #813 adds an edition-pinned composition lineage: + +- [NIST integrated HLA federations](https://www.nist.gov/publications/integrating-multiple-hla-federations-effective-simulation-based-evaluations-cps) + show why a flat federation can be insufficient for information hiding, + independent time scales, resource sharing, and organizational boundaries. + Bridges need explicit message and time translation. +- [NIST UCEF](https://www.nist.gov/ctl/smart-connected-systems-division/iot-devices-and-infrastructures-group/how-does-ucef-work) + explicitly composes simulators, emulators, equipment, and combinations in + one HLA federation. +- [ACTING EDL-FG](https://arxiv.org/abs/2605.12170) separates infrastructure, + screenplay, injects, participant interaction, federation, telemetry, and + assessment and names hybrid simulated/emulated components. RAES adopts the + separation, not the recent preprint's schema. +- [FMI 3.0.2](https://fmi-standard.org/docs/3.0.2/) leaves the + co-simulation algorithm outside the standard, while + [HELICS](https://docs.helics.org/en/latest/user-guide/fundamental_topics/timing_configuration.html) + makes time request/grant and dynamic membership explicit. These support + explicit coordinator, clock/order mapping, and finite pre-admitted phase + semantics. +- [ISO 23247-6:2026](https://www.iso.org/standard/87426.html) distinguishes + integrated, unified, and federated digital-twin composition. The topology + distinction is adopted without treating a simulator, emulator, model, + shadow, and synchronized twin as synonyms. +- [IEEE 1730.1-2023](https://standards.ieee.org/ieee/1730.1/11140/) and + [SISO SIRL](https://www.sisostandards.org/page/StandardsProducts) keep + multi-architecture engineering and interoperability-readiness evidence + separate from actual interoperability. + +The RAES mapping is ADR-102, SEM-234, and ASR-537. Portable SDL remains +backend-neutral. Admitted trial intent allocates stable participant runtime, +controlled-scope, action-family, observation-source, and crossing refs to +apparatus components. Every composition edge binds authority, mapping, +participant/audience policy, clock/order, support strength, loss, failure, and +evidence. + +CybORG's published simulation-to-emulation experiment reports 139 successful +evaluations out of 210 and includes simulation-only observation failures. +CyGIL reports one bounded 50-of-50 emulation evaluation while retaining +unknown-transition and heuristic-switching limits. These are empirical +transfer precedents, not equivalence claims. RAES therefore keeps bounded +conformance, interoperability readiness, empirical transfer, trace inclusion, +bisimulation, IFC/noninterference, and backend equivalence distinct. + +Revision 1 also separates three overloaded open/closed axes: control-loop +posture, world assumption, and federation membership. Multiple realization +providers do not become multiple acting controllers. Leases, simultaneous +scoped owners, and joint/fused control require a later versioned authority +profile. + ## Adversary Emulation And Security Knowledge - [MITRE ATT&CK](https://www.mitre.org/news-insights/publication/mitre-attck-design-and-philosophy), @@ -1520,3 +1585,34 @@ RAES adds backend-neutral authored declarations, exact rational mappings, ordinary SDL subject references, canonical compilation, and segment-preserving runtime control. It does not claim ROS, FMI, HLA, TENA, or OpenSCENARIO conformance through those generic declarations. + +### Adversarial Participant Flow And Control + +- [FIDES](https://arxiv.org/abs/2505.23643) supplies the immediate precedent + for independent confidentiality/integrity labels, conservative propagation, + and deterministic action policy. +- [CaMeL](https://arxiv.org/abs/2503.18813) supplies the trusted-control and + untrusted-data separation, quarantine, and capability precedent. RAES keeps + model topology and prompt separation apparatus-specific. +- [SAMOS](https://research.ibm.com/publications/securing-mcp-based-agent-workflows) + supplies the session-flow and complete tool-call interception precedent. + RAES does not require MCP and places portable authority at the final + external-action or disclosure sink. +- [AgentDojo](https://proceedings.neurips.cc/paper_files/paper/2024/hash/97091a5177d8dc64b1da8bf3e1f6fb54-Abstract-Datasets_and_Benchmarks_Track.html), + [AI Control](https://arxiv.org/abs/2312.06942), and + [ControlArena](https://control-arena.aisi.org.uk/) supply dynamic injection, + intentional subversion, honest/attack modes, main/side objectives, + monitoring, audit, editing, deferral, shutdown, safety, usefulness, and + adaptive evaluation precedents. +- [runtime shielding](https://arxiv.org/abs/1501.02573) supplies the + property-bound last-moment runtime mediation precedent, while + [capability-based authority control](https://doi.org/10.4230/LIPIcs.ECOOP.2017.20) + supplies the least-authority precedent. +- ADR-101 adapts those lessons through SEM-233 and ASR-536 over the existing + SEM-230, ACT-617, API-409/API-423, RUN-310/RUN-319, API-407, experiment, and + ASR-535 carriers. It does not import an LLM framework, prompt format, model + role, MCP gateway, monitor, scorer, or trajectory hierarchy. +- Issue #812 is design authority. Its DRAFT requirements and program do not + establish runtime enforcement, backend realization, intentional-subversion + robustness, model alignment, monitor honesty, private-reasoning safety, or + control of undeclared covert channels. diff --git a/docs/explain/sdl/precedents.md b/docs/explain/sdl/precedents.md index 369e4d944..546e12a1a 100644 --- a/docs/explain/sdl/precedents.md +++ b/docs/explain/sdl/precedents.md @@ -236,8 +236,12 @@ The primary research set for this area is curated in | Distinct time domains and clock authority | [ROS 2 Clock and Time](https://design.ros2.org/articles/clock_and_time.html), [FMI 3.0.2](https://fmi-standard.org/docs/3.0.2/) | Semantics | Authored temporal intent and realized clocks cannot be treated as the same thing; multiple clocks and explicit clock authority are first-class concerns | | Event-driven, logical, and virtual time progression | [SimPy Time and Scheduling](https://simpy.readthedocs.io/en/4.0.2/topical_guides/time_and_scheduling.html), Misra virtual-time work, DEVS literature | Semantics | Time advancement policy is part of system meaning, not just a backend optimization | | Real-time pacing and synchronization | [ns-3 realtime execution](https://www.nsnam.org/docs/manual/html/realtime.html), adaptive time-dilation work for integrated simulation/emulation | Semantics | Synchronization policy, pacing, and dilation are apparatus properties that affect experiment validity and comparability | +| Simultaneous mixed realization | [NIST UCEF](https://www.nist.gov/ctl/smart-connected-systems-division/iot-devices-and-infrastructures-group/how-does-ucef-work), [ACTING EDL-FG](https://arxiv.org/abs/2605.12170), [HELICS dynamic federations](https://docs.helics.org/en/latest/user-guide/advanced_topics/dynamic_federations.html) | Semantics | A trial may admit simulated, emulated/operational, and hardware components together, but every allocation, topology edge, authority, clock mapping, loss, and failure remains explicit | +| Component composition topology | [NIST integrated HLA federations](https://www.nist.gov/publications/integrating-multiple-hla-federations-effective-simulation-based-evaluations-cps), [ISO 23247-6:2026](https://www.iso.org/standard/87426.html) | Semantics | Integrated, unified, and bridged/federated composition are distinct topology profiles; topology does not imply policy or compatibility | | Ordering and causality beyond raw timestamps | Time Warp, DEVS, distributed-simulation time-management literature | Semantics | Event order, causality guarantees, and temporal windows/deadlines must be modeled separately from the existence of timestamps | | Reset, replay, and episode-local temporal semantics | OpenRange episode model, benchmark/task systems, simulation literature | Semantics | Episode boundaries, reset semantics, and replayability are temporal concerns, not just lifecycle bookkeeping | +| Inter-trial and phase-bounded realization changes | [CyGIL](https://arxiv.org/abs/2304.01244), [HELICS dynamic federations](https://docs.helics.org/en/latest/user-guide/advanced_topics/dynamic_federations.html) | Semantics | Cross-trial changes use new linked plan/run identities; within-run membership changes are finite and admitted before execution | +| Interface parity versus transfer evidence | [CybORG](https://arxiv.org/abs/2108.09118), [CyGIL](https://arxiv.org/abs/2304.01244) | Evidence | A common action/observation seam does not establish equivalence; retain simulation-only observations, unrealizable actions, unknown transitions, and bounded transfer results | | Realized-time disclosure and provenance | OpenRange run/training-data records, co-simulation timing literature | Semantics | Runs need explicit disclosure of the realized time model when results are compared across backends or replayed | diff --git a/docs/explain/sdl/sections.md b/docs/explain/sdl/sections.md index 7d487d5df..9fc939870 100644 --- a/docs/explain/sdl/sections.md +++ b/docs/explain/sdl/sections.md @@ -1550,6 +1550,37 @@ content: observation_boundary_refs: [participant-mail-view] ``` +Search-index schema is a separate closed profile because field-schema +reconciliation has different desired state and readback from inserting owned +items: + +```yaml +content: + job-index-schema: + type: dataset + target: analysis + service_materialization: + target_service_ref: nodes.analysis.services.search + interface_profile: service-search-index-schema + profile_version: "1" + requirements: + operation: ensure-search-index-field-schema + conflict_policy: reject-unowned-collision + readback: canonical-portable-field-schema-digest + field_semantics: + key: exact-token + status: exact-token + relations: exact-token + readback_assertion_refs: [job-index-schema-visible] + evidence_requirement_refs: [job-index-schema-readback] + observation_boundary_refs: [participant-search-view] +``` + +The portable semantic set also includes `full-text`, `integer`, `temporal`, and +`boolean`. Native mapping types, index names, endpoints, and queries remain in +backend-private configuration. A profile claim admits the operation; only fresh +native readback projected to the declared portable fields proves it. + The interface profile does not describe product APIs. It requires the backend to reconcile the ordinary content through the named service, reject unowned-item collisions, preserve declared tenant/reset ownership, and return @@ -1558,8 +1589,9 @@ and participant projection. Backend profile support is separate from ordinary `file`/`dataset`/`directory` support. The normative contract is `specs/sdl/initial-service-state.md`. -`file` content requires `path`; `dataset` content requires either `source` or -non-empty `items`; `directory` content requires `destination`. +`file` content requires `path`; ordinary `dataset` content requires either +`source` or non-empty `items`; the schema-only profile permits neither; +`directory` content requires `destination`. --- diff --git a/docs/migration/raes-rename.md b/docs/migration/raes-rename.md index 104242cd6..55c636f7f 100644 --- a/docs/migration/raes-rename.md +++ b/docs/migration/raes-rename.md @@ -13,7 +13,7 @@ does not retain public aliases or dual-name compatibility. | Python distribution and imports | `raes` and the owning `raes_*` packages | installed wheel and source-boundary tests | | CLI and MCP commands | `raes`, `raes-mcp` | CLI and MCP construction tests | | MCP server and tools | RAES server metadata and `raes_*` tool identifiers | advertised-tool and guidance tests | -| Published schema namespace | `https://raesystem.github.io/rae/schemas/` | generated parity and schema-publication checks | +| Published schema namespace | `https://openrae.github.io/rae/schemas/` | generated parity and schema-publication checks | | Contract/profile identities | RAES contract, profile, annotation, and wire identifiers | contract models, fixtures, JSON Schema validation | | Module artifacts | `raes.lock.json`, `raes-trust.yaml`, `.raes/module-cache`, RAES OCI media types and labels | registry, digest, signature, archive, and CLI tests | | Runtime and evidence artifacts | RAES schema names, event/status values, evidence ids, and resource names | DTO, fixture, persistence, and backend tests | @@ -65,6 +65,19 @@ Consumers must not guess replacement spellings, mix identities from the two release lines, or introduce aliases and fallback reads. The release's schemas, fixtures, and migration evidence are the source of truth for the new values. +## GitHub Organization Rename + +The GitHub organization was renamed from RAESystem to OpenRAE. Live repository +configuration, clone URLs, issue links, evidence references, and documentation +now use `OpenRAE/rae`. + +The published schema namespace moved with the organization from +`https://raesystem.github.io/rae/schemas/` to +`https://openrae.github.io/rae/schemas/`. Contract ids and schema paths are +unchanged, but consumers that pin or cache schema `$id` values must update them +atomically. The repository does not retain a second accepted namespace or a +fallback reader for the former URI root. + ## Scenario And Environment-Pack Vocabulary `Scenario` remains the RAES SDL authored-content concept, and diff --git a/docs/public/api/cli.rst b/docs/public/api/cli.rst index ddb9186e5..832e40114 100644 --- a/docs/public/api/cli.rst +++ b/docs/public/api/cli.rst @@ -1,7 +1,7 @@ CLI Reference ============= -The ``raes`` command-line interface is built with `Typer `_ +The ``raes`` command-line interface is built with `Typer `_ and lives in the canonical ``raes_cli`` package. .. currentmodule:: raes_cli @@ -12,9 +12,24 @@ Main CLI .. automodule:: raes_cli.main :members: +Semantic Commands +----------------- + +``raes semantic`` is the offline, read-only human and automation surface. +Every command accepts a file path or ``-`` for stdin, requires an explicit +versioned contract selection (defaulting to ``sdl-yaml/v1`` for SDL), and +derives human and deterministic JSON presentation from one typed result. + +.. automodule:: raes_cli.semantic + :members: + SDL Commands ------------ +The ``raes sdl`` group contains source-format and legacy module-registry +compatibility commands. Module acquisition, lock generation, and publication +are not part of the stable semantic command contract. + .. automodule:: raes_cli.sdl :members: @@ -23,3 +38,9 @@ Processor Commands .. automodule:: raes_cli.processor :members: + +Conformance Commands +-------------------- + +.. automodule:: raes_cli.conformance + :members: diff --git a/docs/public/backends.md b/docs/public/backends.md index 632bfd78f..b14bde4a1 100644 --- a/docs/public/backends.md +++ b/docs/public/backends.md @@ -16,5 +16,5 @@ The repository includes contracts, stubs, a reference emulation backend, and conformance tests. It does not ship a production deployment backend or managed environment service. -Start with the [backend schemas](https://github.com/RAESystem/rae/tree/main/contracts/schemas/backend-manifest) +Start with the [backend schemas](https://github.com/OpenRAE/rae/tree/main/contracts/schemas/backend-manifest) and the [conformance API](api/contracts.rst). diff --git a/docs/public/citation.md b/docs/public/citation.md index 65b8ea08e..833e1e113 100644 --- a/docs/public/citation.md +++ b/docs/public/citation.md @@ -8,7 +8,7 @@ Use this software citation when RAES contributes to your work: title = {RAES: Reproducible Agentic Environments System}, year = {2026}, license = {MIT}, - url = {https://github.com/RAESystem/rae} + url = {https://github.com/OpenRAE/rae} } ``` diff --git a/docs/public/conf.py b/docs/public/conf.py index e53367f6c..6ea2d8f27 100644 --- a/docs/public/conf.py +++ b/docs/public/conf.py @@ -34,6 +34,16 @@ exclude_patterns = ["_build", "Thumbs.db", ".DS_Store"] redirects = json.loads((Path(__file__).parent / "redirects.json").read_text(encoding="utf-8")) +# Bound remote I/O and avoid connection-pool stalls during the required +# repository-wide link check. Links back into this repository are covered by +# local policy and schema checks, so do not spend unauthenticated GitHub quota +# rechecking them over the network. +linkcheck_timeout = 15 +linkcheck_workers = 1 +linkcheck_ignore = [ + r"^https://github\.com/(?:RAESystem|OpenRAE)/rae(?:/|$)", +] + # -- MyST (Markdown) settings -------------------------------------------------- myst_enable_extensions = [ @@ -51,7 +61,7 @@ html_static_path = ["_static"] html_theme_options = { - "source_repository": "https://github.com/RAESystem/rae", + "source_repository": "https://github.com/OpenRAE/rae", "source_branch": "main", "source_directory": "docs/public/", "navigation_with_keys": True, diff --git a/docs/public/contributing.md b/docs/public/contributing.md index c959dab60..84a4025fc 100644 --- a/docs/public/contributing.md +++ b/docs/public/contributing.md @@ -3,13 +3,13 @@ Choose the route that matches your change: - Report a reproducible defect with the - [bug template](https://github.com/RAESystem/rae/issues/new?template=bug_report.md). + [bug template](https://github.com/OpenRAE/rae/issues/new?template=bug_report.md). - Propose a focused improvement with the - [feature template](https://github.com/RAESystem/rae/issues/new?template=feature_request.md). -- Follow [CONTRIBUTING.md](https://github.com/RAESystem/rae/blob/main/CONTRIBUTING.md) + [feature template](https://github.com/OpenRAE/rae/issues/new?template=feature_request.md). +- Follow [CONTRIBUTING.md](https://github.com/OpenRAE/rae/blob/main/CONTRIBUTING.md) for setup, tests, commits, and pull requests. - Read the repository - [documentation style guide](https://github.com/RAESystem/rae/blob/main/docs/explain/reference/documentation-style-guide.md) + [documentation style guide](https://github.com/OpenRAE/rae/blob/main/docs/explain/reference/documentation-style-guide.md) before changing public prose. Discuss SDL, contract, or authority changes before implementation. A small diff --git a/docs/public/guides/cli.md b/docs/public/guides/cli.md index f7f4321e1..dc630ad18 100644 --- a/docs/public/guides/cli.md +++ b/docs/public/guides/cli.md @@ -1,25 +1,68 @@ -# Work with SDL from the command line +# Work with RAES artifacts from the command line -Use the CLI to format, resolve imports, verify imports, and publish an authored -scenario. +Use `raes semantic` to work with RAES data. It provides `parse`, `validate`, +`normalize`, `resolve`, `compile`, `transform`, `inspect`, and `conformance` +commands. Each command accepts a file path or `-` for stdin. Each command is +offline and read-only by default. From a repository checkout: ```console -uv run --project implementations/python raes sdl --help +uv run --project implementations/python raes semantic --help ``` -Common commands include: +Each run names a versioned input contract. SDL uses `sdl-yaml/v1` by default. +For portable JSON, pass its published contract ID. ```console -uv run --project implementations/python raes sdl format --check scenario.sdl.yaml -uv run --project implementations/python raes sdl verify-imports scenario.sdl.yaml -uv run --project implementations/python raes sdl resolve scenario.sdl.yaml +uv run --project implementations/python raes semantic parse scenario.sdl.yaml \ + --contract sdl-yaml/v1 --output json +uv run --project implementations/python raes semantic validate - \ + --contract operation-status-v1 --output json < operation-status.json +uv run --project implementations/python raes semantic normalize scenario.sdl.yaml \ + --contract sdl-yaml/v1 --migration-policy reject +uv run --project implementations/python raes semantic compile scenario.sdl.yaml \ + --contract sdl-yaml/v1 --output json +uv run --project implementations/python raes semantic transform scenario.sdl.yaml \ + --contract sdl-yaml/v1 --transform canonical --output json ``` -`format --check` parses the document and checks its canonical formatting. -`verify-imports` checks referenced modules. `resolve` prints the composed -scenario. None of these commands provisions infrastructure. +Human and JSON output use the same typed result. JSON mode writes one stable +JSON document and a newline to stdout. Each result records the contract and +source format that were used. It also records the migration, normalization, +validation, processor, and transform profiles that apply. Pretty JSON is a +stable CLI format. Only the `canonical` transform emits RFC 8785 SDL bytes. + +The exit statuses are stable for automation: + +| Exit | Meaning | +| ---: | --- | +| `0` | The selected operation completed successfully. | +| `1` | Authored or portable input was rejected. | +| `2` | A command, option, or selector was invalid. | +| `3` | The selected operation is not supported for that contract or profile. | +| `4` | A bounded input/output or other expected operational failure occurred. | +| `70` | An unexpected failure was sanitized at the CLI boundary. | + +Semantic commands do not fetch remote modules or search pack layouts. They do +not write lockfiles or caches. They do not publish data, call backends, or +manage experiments. `resolve` reads the RAES declarations and references in an +accepted scenario. env-packs owns module fetch and lockfile workflows. + +Operations are available only when the selected contract has an owning semantic +API. SDL supports parse, validate, normalize, resolve, compile, transform, and +inspect. Portable JSON contracts support validate, inspect, and conformance. +Other combinations return exit `3`; in particular, the CLI does not describe +portable contract admission as parse-only behavior or SDL validation as a +conformance report. + +## Existing compatibility surfaces + +Use `raes sdl format --check` to check the source format. The old `raes sdl +resolve`, `verify-imports`, and `publish` commands maintain module packages. +`sdl resolve` writes a lockfile. `verify-imports` checks locked imports. +`publish` writes an OCI layout. These commands are not part of the offline +`raes semantic` contract. Pack-aware workflows belong in env-packs. Use `raes processor --help` and `raes conformance --help` for the processor and backend-contract surfaces. The [CLI API reference](../api/cli.rst) lists the diff --git a/docs/public/index.md b/docs/public/index.md index e0fde346d..90e7e076d 100644 --- a/docs/public/index.md +++ b/docs/public/index.md @@ -12,7 +12,7 @@ about five minutes and uses the Python package. - **New to RAES?** Learn the [core concepts](concepts.md), then complete the [first-scenario tutorial](tutorials/first-scenario.md). - **Writing a scenario?** Use the [SDL guide](sdl/index.md) and - [examples](https://github.com/RAESystem/rae/tree/main/examples/scenarios). + [examples](https://github.com/OpenRAE/rae/tree/main/examples/scenarios). - **Controlling participant input or output?** Use the [participant-control guide](participant-control.md). - **Integrating RAES?** Choose the [Python API](guides/python.md) or diff --git a/docs/public/participant-control.md b/docs/public/participant-control.md index b4c0c061f..662ee1933 100644 --- a/docs/public/participant-control.md +++ b/docs/public/participant-control.md @@ -6,11 +6,11 @@ This guide explains the shipped RAES model. It serves five reader roles. It does not define participant-control semantics. Read -[ADR-085](https://github.com/RAESystem/rae/blob/main/docs/decisions/adrs/adr-085-participant-information-flow-and-control.md), -[ADR-095](https://github.com/RAESystem/rae/blob/main/docs/decisions/adrs/adr-095-participant-decision-epoch-state-cut-and-delivery-semantics.md), -[SEM-230 information-flow specification](https://github.com/RAESystem/rae/blob/main/specs/formal/participant-semantics/information-flow-control.md), +[ADR-085](https://github.com/OpenRAE/rae/blob/main/docs/decisions/adrs/adr-085-participant-information-flow-and-control.md), +[ADR-095](https://github.com/OpenRAE/rae/blob/main/docs/decisions/adrs/adr-095-participant-decision-epoch-state-cut-and-delivery-semantics.md), +[SEM-230 information-flow specification](https://github.com/OpenRAE/rae/blob/main/specs/formal/participant-semantics/information-flow-control.md), and the -[API-423 crossing schema](https://github.com/RAESystem/rae/blob/main/contracts/schemas/participant-runtime/participant-crossing-occurrence-v1.json). +[API-423 crossing schema](https://github.com/OpenRAE/rae/blob/main/contracts/schemas/participant-runtime/participant-crossing-occurrence-v1.json). They own the rules. Follow them if this guide seems to differ. ## Keep four planes separate @@ -32,6 +32,58 @@ decision, change, release, delivery attempt, delivery, observation, and audit. Each stage refers to an existing carrier. It does not copy the carrier payload into a generic participant message. +## Mixed simulation and emulation are DRAFT + +Issue #813 and ADR-102 define the design boundary for using the same +participant-control intent in: + +- simulation or emulation/operation as alternative realizations; and +- simulation and emulation/operation together in one admitted trial. + +SEM-234 and ASR-537 are DRAFT. The design does not mean current RAES runtimes +can execute a mixed trial. + +Portable SDL stays backend-neutral. Future admitted trial intent will allocate +stable participant-runtime, controlled-scope, action-family, +observation-source, and crossing refs to exact apparatus components. Every +component edge must state its adapter, authority, action/observation mapping, +participant/audience policy, clock/order mapping, support strength, loss, +failure behavior, and evidence. + +Keep these separate: + +- participant identity; +- the one acting controller in revision 1; +- authority basis and controlled scope; +- action admission; +- the provider responsible for realizing an action or observation; +- HLA-style object/attribute ownership; +- delivery routing; and +- participant disclosure authority. + +Multiple providers are not multiple controllers. Revision 1 does not support +leases, simultaneous scoped controllers, or joint/fused control. + +The design also separates three meanings of open/closed: + +1. open-loop observation versus closed-loop actuation; +2. closed-world versus bounded-open-world assumptions; and +3. fixed versus finite pre-admitted dynamic membership. + +Closed-loop does not grant action authority. Bounded-open-world does not allow +unknown commands or mappings. Dynamic membership does not allow an unadmitted +backend to join. + +An inter-trial realization change creates a new linked plan entry and run. A +within-run change is permitted only as a finite schedule whose components, +mappings, policy, clocks, and failure behavior were admitted before execution. +Neither kind erases prior delivery or participant knowledge. + +Do not treat a shared adapter, passing conformance probe, paired backend run, +or successful transfer trial as backend equivalence. The implementation and +evidence work is tracked by issues #1013 through #1019. See the +[issue #813 design record](https://github.com/OpenRAE/rae/issues/813). + ## Choose the route for your role ### Scenario author @@ -53,9 +105,9 @@ observation boundary. Reuse the action, control, or inject carrier. carrier. The -[mixed-control fixture](https://github.com/RAESystem/rae/blob/main/contracts/fixtures/sdl/mixed-control-v1/valid/mixed-control-participant.yaml) +[mixed-control fixture](https://github.com/OpenRAE/rae/blob/main/contracts/fixtures/sdl/mixed-control-v1/valid/mixed-control-participant.yaml) and -[participant-directed inject fixture](https://github.com/RAESystem/rae/blob/main/contracts/fixtures/sdl/participant-inject-delivery-v1/valid/participant-directed.yaml) +[participant-directed inject fixture](https://github.com/OpenRAE/rae/blob/main/contracts/fixtures/sdl/participant-inject-delivery-v1/valid/participant-directed.yaml) show the governed authoring shapes. They show SDL checks. They do not show runtime delivery. @@ -111,7 +163,7 @@ resolver, the HTTP adapter binds the audience before lookup. It resolves trusted evidence. It commits crossing facts before it writes the view. Use the -[participant-control migration guide](https://github.com/RAESystem/rae/blob/dev/docs/migration/participant-information-flow-control.md) +[participant-control migration guide](https://github.com/OpenRAE/rae/blob/dev/docs/migration/participant-information-flow-control.md) for legacy, opt-in, required, rollout, and rollback steps. After the first governed write, keep a resolver-aware reader. Keep the crossing history, operation, idempotency, and audit write set. Never delete crossing facts. Do @@ -133,9 +185,9 @@ The shipped reference backend currently declares all six participant-policy features `unsupported`. Some tests use stronger manifests. Those tests do not turn the reference backend into a native implementation. Start with the [backend guide](backends.md). Then read the -[feature-admission implementation](https://github.com/RAESystem/rae/blob/main/implementations/python/packages/raes_backend_protocols/participant_feature_admission.py), +[feature-admission implementation](https://github.com/OpenRAE/rae/blob/main/implementations/python/packages/raes_backend_protocols/participant_feature_admission.py), and -[finite participant-policy probes](https://github.com/RAESystem/rae/blob/dev/implementations/python/packages/raes_conformance/conformance/participant_policy_probes.py). +[finite participant-policy probes](https://github.com/OpenRAE/rae/blob/dev/implementations/python/packages/raes_conformance/conformance/participant_policy_probes.py). ### Researcher @@ -238,12 +290,12 @@ this bounded behavior. A manifest entry alone is not runtime support. It is not conformance. All seven finite cases are exercised and bounded in -[the ASR-535 assurance tests](https://github.com/RAESystem/rae/blob/dev/implementations/python/tests/test_asr_535_participant_flow_assurance.py). +[the ASR-535 assurance tests](https://github.com/OpenRAE/rae/blob/dev/implementations/python/tests/test_asr_535_participant_flow_assurance.py). ## Select a behavioral claim Read the current -[behavioral-relation catalog](https://github.com/RAESystem/rae/blob/main/contracts/concept-authority/behavioral-relations-v1.json) +[behavioral-relation catalog](https://github.com/OpenRAE/rae/blob/main/contracts/concept-authority/behavioral-relations-v1.json) instead of defining relation meaning in a report. | Question | Catalog relation | Required boundary | @@ -316,5 +368,38 @@ environment values, host paths, and raw proof. Do not place these values in responses, logs, fixtures, screenshots, or docs. For current delivery status, evidence, and known limits, use the -[participant-control adoption index](https://github.com/RAESystem/rae/tree/main/docs/research/participant-io-control) +[participant-control adoption index](https://github.com/OpenRAE/rae/tree/main/docs/research/participant-io-control) and [current project limitations](limitations.md). + +## Treat adversarial participants as a boundary problem + +Issue #812 and ADR-101 +define a DRAFT participant-neutral design for intentionally subverting +participants and untrusted content. + +The design keeps two coordinates separate: + +- confidentiality restricts audiences, destinations, and sink classes; and +- integrity records the origins that may have influenced a value and the trust + a sink requires. + +Labels and provenance follow observations, tool results, retained memory, +proposals, action arguments, handoffs, crossings, outputs, and errors. +Authentication, approval, action admission, authorization, declassification, +integrity endorsement, editing, and execution remain distinct. + +The reference enforcement point is immediately before `RuntimeTarget` performs +an external effect or before participant-facing or external data is +serialized or delivered. A monitor score is evidence or advice, never +authorization. Missing labels, provenance, profile support, or a stable state +cut fail closed. + +The companion DRAFT evaluation profile distinguishes honest and attack modes +and makes objectives, policy/monitor knowledge, adaptation, collusion, audit +budgets, monitor correlation, interventions, memory, safety, usefulness, cost, +uncertainty, and limitations explicit. + +This is design authority, not a delivered robustness claim. Runtime and +backend enforcement, attack evaluations, monitor honesty, model alignment, +private reasoning, and undeclared covert channels remain unclaimed. See the +[issue #812 design record](https://github.com/OpenRAE/rae/issues/812). diff --git a/docs/public/research.md b/docs/public/research.md index d8cdf391c..de4f8e745 100644 --- a/docs/public/research.md +++ b/docs/public/research.md @@ -13,9 +13,9 @@ You can inspect: Working records remain in the repository for peer review. They are not part of this hosted guide. Start with the -[formal specifications](https://github.com/RAESystem/rae/tree/main/specs), -[contracts](https://github.com/RAESystem/rae/tree/main/contracts), and -[research directory](https://github.com/RAESystem/rae/tree/main/docs/research). +[formal specifications](https://github.com/OpenRAE/rae/tree/main/specs), +[contracts](https://github.com/OpenRAE/rae/tree/main/contracts), and +[research directory](https://github.com/OpenRAE/rae/tree/main/docs/research). RAES can support a bounded reproduction attempt. One successful parse, realization, or replay does not prove scientific reproducibility. diff --git a/docs/public/sdl/index.md b/docs/public/sdl/index.md index 0ba180ae8..c5c1f8b51 100644 --- a/docs/public/sdl/index.md +++ b/docs/public/sdl/index.md @@ -17,9 +17,9 @@ variation, and evidence requirements. The published schemas and normative specifications remain the authority for accepted fields and meaning: -- [SDL schema](https://github.com/RAESystem/rae/tree/main/contracts/schemas/sdl) -- [Normative SDL specification](https://github.com/RAESystem/rae/tree/main/specs) -- [Worked examples](https://github.com/RAESystem/rae/tree/main/examples/scenarios) +- [SDL schema](https://github.com/OpenRAE/rae/tree/main/contracts/schemas/sdl) +- [Normative SDL specification](https://github.com/OpenRAE/rae/tree/main/specs) +- [Worked examples](https://github.com/OpenRAE/rae/tree/main/examples/scenarios) Read [current limits](../limitations.md) before assuming that a backend can realize every valid authored section. diff --git a/docs/public/support.md b/docs/public/support.md index 9d0139d99..6399b76f9 100644 --- a/docs/public/support.md +++ b/docs/public/support.md @@ -1,11 +1,11 @@ # Get help -Use a [GitHub issue](https://github.com/RAESystem/rae/issues/new/choose) for a +Use a [GitHub issue](https://github.com/OpenRAE/rae/issues/new/choose) for a reproducible defect, docs problem, or focused feature request. Do not post a suspected vulnerability in a public issue. Follow the private reporting route in -[SECURITY.md](https://github.com/RAESystem/rae/blob/main/SECURITY.md). +[SECURITY.md](https://github.com/OpenRAE/rae/blob/main/SECURITY.md). RAES is maintained on a best-effort basis. The project does not promise a response time or support service level. diff --git a/docs/public/tutorials/first-scenario.md b/docs/public/tutorials/first-scenario.md index 8f8842666..f603289aa 100644 --- a/docs/public/tutorials/first-scenario.md +++ b/docs/public/tutorials/first-scenario.md @@ -7,7 +7,7 @@ Build on the quickstart file and use the CLI to inspect its current structure. Clone the repository when you want the CLI and complete example library: ```console -git clone https://github.com/RAESystem/rae.git +git clone https://github.com/OpenRAE/rae.git cd rae uv sync --project implementations/python --all-extras --frozen ``` @@ -26,9 +26,24 @@ uv run --project implementations/python raes sdl format \ Exit code `0` means the file parses and already uses the canonical format. The command does not provision the scenario. +## Inspect the admitted declarations + +Use the read-only semantic surface to validate the scenario and inspect its +canonical declaration index: + +```console +uv run --project implementations/python raes semantic inspect \ + docs/public/_static/examples/first-scenario.sdl.yaml \ + --contract sdl-yaml/v1 --output json +``` + +The result records the effective source, migration, normalization, and +validation profiles. It does not acquire modules, write a lockfile or cache, +invoke a backend, or provision infrastructure. + ## Explore a larger scenario -The [scenario collection](https://github.com/RAESystem/rae/tree/main/examples/scenarios) +The [scenario collection](https://github.com/OpenRAE/rae/tree/main/examples/scenarios) contains authored examples with participants, behaviors, objectives, and evidence requirements. Check each example's notes before treating it as a backend-ready deployment. diff --git a/docs/research/adversarial-participant-control/attack-cases.md b/docs/research/adversarial-participant-control/attack-cases.md new file mode 100644 index 000000000..6dc596eff --- /dev/null +++ b/docs/research/adversarial-participant-control/attack-cases.md @@ -0,0 +1,77 @@ +# Adversarial Participant Boundary Attack Cases + +Date: 2026-07-30 + +These cases are design obligations, not reported test results. Downstream +evidence must drive the real `RuntimeControlPlane` to `RuntimeTarget` boundary +and inspect semantic result, target-call count, participant-visible output, +append-only history, safe audit/error evidence, and replay. + +## Prompt or tool-result injection + +An untrusted observation or tool result includes content intended to redirect +the participant. The participant produces a structurally valid, otherwise +authorized action with valid arguments. + +Ordinary schema and action admission are insufficient because they do not +establish whether untrusted content influenced the destination or control. +Integrity influence propagates through context, memory, proposal, and action +arguments. Quarantined processing has no consequential capability. The final +sink denies unless the exact policy admits that integrity label or a governed +endorsement creates a fresh result. + +A denied case has zero target calls and no participant/external disclosure. + +## Confidential exfiltration + +The participant reads a confidential fact and later sends a valid message, +tool call, output, callback, error, or handoff to an unauthorized destination +or colluding participant. + +The read and send can each be permitted in isolation. Confidentiality joins +through every explicit derivation, argument, output, crossing, and error sink. +Destination and audience policy denies release unless an exact +declassification authority creates a fresh result. + +The evidence checks output and error paths as well as backend calls. Timing and +other undeclared covert channels remain explicit nonclaims. + +## Adaptive monitor evasion + +An attack participant learns from approvals, denials, edits, deferrals, +audits, handoffs, interruptions, outputs, thresholds, or remaining audit +budget and shifts to lower-suspicion behavior. + +A static negative test or monitor-accuracy score is insufficient. The +evaluation varies policy/monitor knowledge, prior-outcome visibility, adaptive +strategy, audit budget, monitor topology, correlation, collusion, and memory. +Safety and usefulness remain separate. + +A monitor pass cannot bypass deterministic flow, capability, or final-sink +policy. + +## Control-handoff manipulation + +Tainted context or external direction crosses a valid API-409 handoff. A +receiver that is treated as trusted forms a valid proposal and API-423 +crossing. + +Control validity is insufficient because the handoff can launder influence or +apparent authority. Controller state, authority, labels, provenance, memory, +receiver admission, crossing policy, and final sink resolve independently at +one exact cut. Handoff does not reset labels or grant action admission. + +A denial leaves no external effect and preserves the append-only control and +crossing evidence required to reproduce the decision. + +## Evidence matrix + +| Case | Required semantic result | Required runtime evidence | Evaluation coordinates | +| --- | --- | --- | --- | +| injection | untrusted influence reaches sink; deny or exact endorsement | zero prohibited target calls/output; committed safe denial | source, mode, policy knowledge, quarantine, monitor visibility | +| exfiltration | confidentiality reaches every explicit destination | zero unauthorized action/output/error disclosure | secret visibility, destination, collusion, release authority | +| adaptive evasion | monitor result remains non-authorizing | deterministic sink outcome independent of monitor score | feedback, thresholds, audit budget, topology, correlation, memory | +| handoff manipulation | control change preserves flow and provenance | control/crossing histories and zero denied effects | sender/receiver roles, authority, shared memory, receiver trust assumption | + +No case establishes universal information-flow security, model alignment, +monitor honesty, or undeclared covert-channel control. diff --git a/docs/research/adversarial-participant-control/current-state-assessment.md b/docs/research/adversarial-participant-control/current-state-assessment.md new file mode 100644 index 000000000..836a7f42c --- /dev/null +++ b/docs/research/adversarial-participant-control/current-state-assessment.md @@ -0,0 +1,80 @@ +# Adversarial Participant Control Current-State Assessment + +Date: 2026-07-30 + +Parent issue: [#812](https://github.com/OpenRAE/rae/issues/812). + +## Method + +The assessment compared primary research and implementation sources with the +current RAES semantic, contract, runtime, backend, experiment, evidence, and +documentation authorities. The canonical structured disposition is in +[`implementation-program.json`](implementation-program.json). + +## Primary-source findings + +| Source | Adopt | RAES boundary | +| --- | --- | --- | +| [FIDES](https://arxiv.org/abs/2505.23643) | Independent confidentiality/integrity labels, conservative propagation, deterministic action policy, explicit release. | Generalize to typed participants and sinks; do not import its planner or LLM message model. | +| [CaMeL](https://arxiv.org/abs/2503.18813) | Trusted-control/untrusted-data separation, quarantine, typed extraction, capability-restricted flows. | Quarantine and model topology are apparatus capabilities, not portable prompt semantics or endorsement. | +| [SAMOS](https://research.ibm.com/publications/securing-mcp-based-agent-workflows) | Intercept tool calls and retain session flow state so permitted calls cannot compose into leakage. | MCP is optional; RUN-319 and the final effect/disclosure sink own the portable boundary. | +| [AgentDojo](https://proceedings.neurips.cc/paper_files/paper/2024/hash/97091a5177d8dc64b1da8bf3e1f6fb54-Abstract-Datasets_and_Benchmarks_Track.html) | Separate utility and security; use dynamic tasks and adaptive indirect injection. | Reuse experiment contracts; benchmark objects and results remain profile-bounded. | +| [AI Control](https://arxiv.org/abs/2312.06942) | Evaluate intentionally subverting policies, trusted editing, untrusted monitoring, limited trusted labor, audit, and collusion. | Trusted/untrusted are declared roles and assumptions, not proof about a model or human. | +| [ControlArena](https://control-arena.aisi.org.uk/) | Explicit honest/attack modes, main/side objectives, visibility, defer/shutdown protocols, safety/usefulness, and trajectories. | Reuse RAES experiment authorities; do not copy its policy, monitor, scorer, or trajectory hierarchy. | +| [runtime shielding](https://arxiv.org/abs/1501.02573) | Mediate a declared property at runtime before unsafe output is realized. | Only a complete deterministic sink policy may be called shielding; a heuristic monitor is not authorization. | +| [capability authority control](https://doi.org/10.4230/LIPIcs.ECOOP.2017.20) | Give components only required authority and avoid ambient authority. | Reuse action arguments, participant capabilities, identity binding, and API-407; capability restriction does not replace IFC. | + +The shared lesson is complete mediation of declared explicit flows at the last +enforceable boundary. None of the sources establishes model alignment, safe +private reasoning, monitor honesty, or protection from undeclared covert +channels. + +## Existing RAES coverage + +- ADR-085, ADR-095, SEM-230, and SEM-231 define exact-cut + participant-relative flow, projection, declassification, memory, adaptive + strategies, supervisor visibility, coalitions, and honest claim boundaries. +- ACT-617, API-409, RUN-310, and action admission separate proposals, + approvals, denials, direction, intervention, handoff, override, + cancellation, admission, and execution. +- API-423 and RUN-319 define typed crossing stages, independent gates, + effective capability support, append-only histories, idempotency, replay, + and atomic persistence. +- Runtime facts already carry typed observation, derived, tool-result, and + secret-reference sources, sensitivity, scope, audience, provenance, and sink + restrictions. +- API-407 separates declared support, effective strength, downgrade, + realization, and bounded conformance. +- Experiment task, protocol, study, run, apparatus, evidence, measure, and + traceability contracts can host control evaluations without a new benchmark + hierarchy. +- ASR-535 already separates bounded semantic falsification, runtime evidence, + backend conformance, model checking, proof, and nonclaims. + +## Gaps + +Before issue #812, RAES has no authority that: + +1. carries independent confidentiality and integrity coordinates + conservatively through every relevant typed carrier; +2. distinguishes integrity endorsement from confidentiality declassification + and both from approval, admission, authentication, and authorization; +3. rechecks effective flow at the final external-action and disclosure sink; +4. treats intentional subversion, policy-aware adaptation, audit-budget + exhaustion, collusion, and correlated monitor failure as explicit + evaluation variables; or +5. binds honest/attack mode, objectives, monitor topology, intervention + protocol, memory, replay, safety, usefulness, cost, uncertainty, and + limitations in one revisioned evaluation profile. + +## Adopted response + +ADR-101 and the formal authority add two DRAFT owners: + +- SEM-233 owns the participant-neutral flow-policy profile and final-sink + semantics. +- ASR-536 owns the intentional-subversion evaluation profile. + +Issue #812 also opens six ordered implementation issues. It does not alter +published schemas or runtime behavior and does not claim either DRAFT +requirement is satisfied. diff --git a/docs/research/adversarial-participant-control/implementation-program.json b/docs/research/adversarial-participant-control/implementation-program.json new file mode 100644 index 000000000..d3626f1d9 --- /dev/null +++ b/docs/research/adversarial-participant-control/implementation-program.json @@ -0,0 +1,827 @@ +{ + "schema_version": "adversarial-participant-control-program/v1", + "assessment_date": "2026-07-30", + "parent_issue": 812, + "milestone": "Participant Information-Flow & Behavioral Equivalence", + "deliverables": [ + "docs/decisions/issue-812-adversarial-agent-control-preflight.md", + "docs/decisions/adrs/adr-101-adversarial-participant-flow-control.md", + "docs/research/adversarial-participant-control/index.md", + "docs/research/adversarial-participant-control/current-state-assessment.md", + "docs/research/adversarial-participant-control/threat-model.md", + "docs/research/adversarial-participant-control/trust-flow-architecture.md", + "docs/research/adversarial-participant-control/attack-cases.md", + "docs/research/adversarial-participant-control/requirement-disposition.md", + "docs/research/adversarial-participant-control/implementation-program.md", + "docs/research/adversarial-participant-control/implementation-program.json", + "specs/formal/participant-semantics/adversarial-flow-control.md", + "docs/public/participant-control.md", + "docs/explain/sdl/lineage.md" + ], + "primary_sources": [ + { + "id": "fides", + "title": "Securing AI Agents with Information-Flow Control", + "primary_url": "https://arxiv.org/abs/2505.23643", + "adopted_lessons": [ + "independent confidentiality and integrity labels", + "conservative propagation through derivations", + "deterministic policy before consequential tools", + "explicit selective release operations" + ], + "raes_boundary": "Generalize the two-coordinate flow relation to every RAES participant and typed sink; do not import the FIDES planner, message model, or LLM-only primitives.", + "nonclaims": [ + "The paper and its implementation do not establish RAES runtime or backend realization.", + "Information-flow enforcement does not establish model alignment or covert-channel control." + ] + }, + { + "id": "camel", + "title": "Defeating Prompt Injections by Design", + "primary_url": "https://arxiv.org/abs/2503.18813", + "adopted_lessons": [ + "separate trusted control from untrusted data", + "quarantine untrusted processing", + "retain capability and provenance constraints", + "prevent unauthorized private-data flows" + ], + "raes_boundary": "Treat quarantine, privileged/quarantined model roles, and typed extraction as apparatus capabilities. They neither define portable prompt semantics nor automatically endorse their outputs.", + "nonclaims": [ + "RAES does not require a dual-LLM architecture.", + "A quarantined component is not a final sink unless it controls every effect and disclosure." + ] + }, + { + "id": "samos", + "title": "Securing MCP-based Agent Workflows", + "primary_url": "https://research.ibm.com/publications/securing-mcp-based-agent-workflows", + "adopted_lessons": [ + "intercept every tool call", + "retain session-level flow context", + "evaluate composed calls rather than isolated calls", + "use annotations and policy to block leakage" + ], + "raes_boundary": "An MCP gateway can realize part of RUN-319, but the portable owner is the RAES flow relation and the final backend/action or disclosure sink.", + "nonclaims": [ + "MCP is not required by RAES.", + "Gateway mediation does not cover effects or disclosures that bypass that gateway." + ] + }, + { + "id": "agentdojo", + "title": "AgentDojo: A Dynamic Environment to Evaluate Prompt Injection Attacks and Defenses for LLM Agents", + "primary_url": "https://proceedings.neurips.cc/paper_files/paper/2024/hash/97091a5177d8dc64b1da8bf3e1f6fb54-Abstract-Datasets_and_Benchmarks_Track.html", + "adopted_lessons": [ + "measure task utility separately from security", + "evaluate indirect prompt injection in dynamic tool environments", + "include adaptive attacks", + "avoid treating benign task failure as security success" + ], + "raes_boundary": "Reuse RAES experiment task, protocol, run, evidence, and measure contracts; do not import benchmark-specific task, tool, or trajectory semantics.", + "nonclaims": [ + "A benchmark result is bounded to its tasks, attacks, apparatus, and policies.", + "Ordinary benchmark success is not intentional-subversion robustness." + ] + }, + { + "id": "ai-control", + "title": "AI Control: Improving Safety Despite Intentional Subversion", + "primary_url": "https://arxiv.org/abs/2312.06942", + "adopted_lessons": [ + "distinguish an intentionally subverting policy from an honest policy", + "evaluate trusted editing and untrusted monitoring", + "budget scarce trusted labor", + "model collusion and audit protocols" + ], + "raes_boundary": "Trusted and untrusted are profile-scoped experimental roles. Human or model intervention must declare its authority operation and re-enter deterministic validation.", + "nonclaims": [ + "A role declaration does not prove a model or human trustworthy.", + "One evaluated protocol does not establish general control." + ] + }, + { + "id": "controlarena", + "title": "ControlArena", + "primary_url": "https://control-arena.aisi.org.uk/", + "adopted_lessons": [ + "make honest and attack modes explicit", + "separate main and side objectives", + "declare policy and monitor visibility", + "bind audit, intervention, shutdown, safety, usefulness, and trajectory analysis" + ], + "raes_boundary": "Represent the coordinates through RAES experiment and participant-control authorities; do not copy ControlArena policy, monitor, scorer, solution, or trajectory object models.", + "nonclaims": [ + "RAES does not require Inspect AI or ControlArena.", + "A trajectory score never authorizes a runtime action." + ] + }, + { + "id": "runtime-shielding", + "title": "Shield Synthesis: Runtime Enforcement for Reactive Systems", + "primary_url": "https://arxiv.org/abs/1501.02573", + "adopted_lessons": [ + "mediate at runtime before an unsafe output is realized", + "bind enforcement to a declared safety property", + "distinguish correction from observation", + "avoid delay between decision and effect" + ], + "raes_boundary": "Use shielding language only for a deterministic complete sink policy over a declared property. A heuristic monitor or incomplete gateway is evidence, not a shield.", + "nonclaims": [ + "Issue 812 does not synthesize a shield.", + "A flow policy is not a universal safety property." + ] + }, + { + "id": "capability-security", + "title": "A Capability-Based Module System for Authority Control", + "primary_url": "https://doi.org/10.4230/LIPIcs.ECOOP.2017.20", + "adopted_lessons": [ + "grant only the authority a component needs", + "separate designation from ambient authority", + "make authority boundaries explicit", + "compose least authority with information-flow policy" + ], + "raes_boundary": "Reuse action-contract arguments, participant implementation capabilities, identity binding, and API-407 strength instead of adding a second capability language.", + "nonclaims": [ + "Capability restriction does not replace confidentiality or integrity propagation.", + "A declared capability does not prove correct backend enforcement." + ] + } + ], + "threat_model": { + "model_id": "adversarial-participant-boundary-threat-model-v1", + "revision": "rev1", + "actors": [ + { + "id": "honest-fallible-participant", + "intentional_subversion": false, + "capabilities": [ + "produce invalid or unsafe proposals accidentally", + "misinterpret observations", + "select unsupported actions" + ], + "trust_boundary": "Subject to the same deterministic admission, flow, capability, and sink decisions as every participant." + }, + { + "id": "intentionally-subverting-participant", + "intentional_subversion": true, + "capabilities": [ + "optimize a hidden side objective", + "construct structurally valid malicious actions", + "adapt to approvals, denials, audits, edits, deferrals, and handoffs", + "retain state across episodes when the apparatus permits it" + ], + "trust_boundary": "The participant apparatus is untrusted with respect to the named protected objective; no internal-reasoning observation is assumed." + }, + { + "id": "untrusted-content-source", + "intentional_subversion": true, + "capabilities": [ + "inject instructions into observations, tool results, retrieval, files, and errors", + "influence an opaque participant transformation", + "attempt destination and control redirection" + ], + "trust_boundary": "External content defaults to confidential-and-untrusted until a revisioned resolver establishes narrower labels." + }, + { + "id": "adaptive-policy-aware-attacker", + "intentional_subversion": true, + "capabilities": [ + "know policy or monitor structure", + "estimate or know thresholds and audit budgets", + "learn from prior outcomes", + "shift attack timing and presentation" + ], + "trust_boundary": "Knowledge and feedback are explicit evaluation variables and participant-visible facts, never implicit benchmark assumptions." + }, + { + "id": "colluding-participants-or-monitors", + "intentional_subversion": true, + "capabilities": [ + "share explicit information through permitted channels", + "coordinate low-suspicion behavior", + "produce correlated monitor failures", + "launder influence through a trusted-looking handoff" + ], + "trust_boundary": "Coalition membership, visibility, shared inputs, independence assumptions, and memory are declared; different ids do not imply independence." + } + ], + "protected_assets": [ + "confidential participant and environment data", + "integrity of control and policy decisions", + "external systems reached by actions or tools", + "participant-visible and external outputs", + "append-only control, crossing, evidence, and audit histories", + "hidden experiment objectives and security-sensitive configuration" + ], + "explicit_flow_channels": [ + "observations", + "tool-results", + "retrieved-content", + "participant-context", + "retained-memory", + "proposals", + "action-arguments", + "participant-outputs", + "errors", + "handoffs", + "external-direction", + "transformations", + "stream-chunks", + "colluding-participant-crossings" + ], + "crossing_scopes": [ + "within-participant", + "cross-participant", + "cross-episode" + ], + "outside_guarantee": [ + "undeclared-timing-channels", + "covert-storage-channels", + "model-steganography", + "private-reasoning-safety", + "monitor-honesty", + "model-alignment", + "unobservable-flows-inside-opaque-apparatuses" + ] + }, + "flow_policy_profile": { + "profile_id": "participant-boundary-flow-policy-v1", + "revision": "rev1", + "confidentiality": { + "independent_coordinate": true, + "meaning": "maximum permitted audiences, principals, destinations, and sink classes", + "join": "least-upper-bound", + "release_operation": "declassification" + }, + "integrity": { + "independent_coordinate": true, + "meaning": "origins and possible writers that may have influenced the value plus sink-required trust", + "join": "conservative-influence-union", + "release_operation": "integrity-endorsement" + }, + "unknown_source_default": "confidential-and-untrusted", + "missing_or_unknown_behavior": "deny-or-explicitly-unsupported", + "opaque_transformation": "retain-join-of-all-possible-inputs", + "historical_labels_are_immutable": true, + "distinct_operations": [ + "authentication", + "authorization", + "admission", + "approval", + "declassification", + "integrity-endorsement", + "redaction", + "transformation", + "trusted-editing", + "deferral", + "handoff", + "interruption", + "shutdown", + "advice", + "execution" + ], + "carriers": [ + "runtime-fact", + "participant-observation", + "participant-context", + "retained-memory", + "participant-proposal", + "derived-value", + "action-argument", + "API-409-control-occurrence", + "API-423-crossing-occurrence", + "participant-output", + "external-output" + ], + "sinks": [ + "external-action", + "tool-argument", + "participant-output", + "external-serialization", + "stream-chunk", + "error-output", + "callback", + "persistent-external-write" + ], + "final_enforcement_boundary": "after-last-policy-and-state-cut-resolution-before-external-effect-or-disclosure", + "decision_committed_before_effect": true, + "deny_without_side_effect": [ + "missing-label", + "missing-provenance", + "unknown-profile", + "ambiguous-join", + "stale-state-cut", + "unsupported-capability", + "policy-deny", + "failed-atomic-commit", + "history-head-conflict", + "unauthorized-release-operation" + ], + "participant_neutrality": { + "portable": [ + "labels", + "derivation", + "authority", + "capability", + "policy cut", + "sink", + "decision", + "provenance", + "evidence" + ], + "apparatus_specific": [ + "prompt separation", + "model topology", + "quarantined model", + "MCP gateway", + "tokenizer", + "private model state", + "credentials" + ], + "covered_participant_kinds": [ + "human", + "scripted", + "reinforcement-learning", + "large-language-model", + "external-service" + ] + } + }, + "control_evaluation_profile": { + "profile_id": "intentional-subversion-control-evaluation-v1", + "revision": "rev1", + "modes": [ + "honest", + "attack" + ], + "variables": [ + { + "id": "mode", + "domain": "honest or attack", + "evidence_boundary": "Bound to every run and participant policy." + }, + { + "id": "main-objective", + "domain": "declared utility objective and success condition", + "evidence_boundary": "Portable bounded ref; raw private instructions are excluded." + }, + { + "id": "side-objective", + "domain": "protected adversarial objective and success condition", + "evidence_boundary": "May remain hidden from the evaluated participant while retained as access-controlled experiment evidence." + }, + { + "id": "policy-knowledge", + "domain": "none, partial, or declared complete policy knowledge", + "evidence_boundary": "Names exactly what is observable." + }, + { + "id": "monitor-knowledge", + "domain": "monitor identity, prompt/profile, topology, score, or threshold visibility", + "evidence_boundary": "Hidden monitor internals remain outside participant-visible evidence unless the profile releases them." + }, + { + "id": "audit-budget-knowledge", + "domain": "none, distributional, threshold, or exact remaining budget", + "evidence_boundary": "Budget knowledge and budget size are separate." + }, + { + "id": "prior-outcome-visibility", + "domain": "approvals, denials, edits, deferrals, audits, handoffs, interruptions, and outputs", + "evidence_boundary": "Only outcomes actually delivered to the participant enter its observation surface." + }, + { + "id": "adaptive-strategy", + "domain": "declared strategy class over visible history and retained memory", + "evidence_boundary": "No undeclared private-state introspection." + }, + { + "id": "collusion", + "domain": "none, participant, monitor, or mixed declared coalition", + "evidence_boundary": "Names allowed communication and shared state." + }, + { + "id": "monitor-topology", + "domain": "single, serial, parallel, adversarial, or composed monitors", + "evidence_boundary": "Topology is separate from trust." + }, + { + "id": "monitor-correlation", + "domain": "independent, correlated, shared-input, shared-model, or unknown", + "evidence_boundary": "Independence requires evidence; unknown is not independent." + }, + { + "id": "audit-budget", + "domain": "finite selection and escalation budget", + "evidence_boundary": "An experiment protocol coordinate unless the runtime enforces it as a resource." + }, + { + "id": "intervention-protocol", + "domain": "approval, trusted editing, defer-to-trusted, interruption, or shutdown", + "evidence_boundary": "Each authority effect is explicit and re-enters deterministic policy." + }, + { + "id": "memory-scope", + "domain": "none, episode, participant, shared, or cross-episode retained state", + "evidence_boundary": "Replay names the same scope and policy revisions." + } + ], + "monitor_roles": [ + "trusted", + "untrusted", + "composed" + ], + "interventions": [ + "human-approval", + "trusted-editing", + "defer-to-trusted", + "interruption", + "shutdown" + ], + "measures": [ + "safety", + "usefulness", + "audit-cost", + "intervention-cost", + "uncertainty", + "attack-success", + "false-positive-rate", + "limitations" + ], + "monitor_score_authorizes_action": false, + "ordinary_negative_tests_establish_subversion_robustness": false, + "replay_evidence": "digest-bound graph of existing episode, behavior, control, crossing, action/result, experiment, and evidence refs" + }, + "attack_cases": [ + { + "id": "prompt-or-tool-result-injection", + "attack_path": "untrusted observation or tool result -> participant context -> structurally valid proposal -> action argument -> external sink", + "why_ordinary_admission_is_insufficient": "The action and argument may be valid and authorized in isolation while an untrusted source redirected the control or destination.", + "deterministic_boundary_result": "Conservative integrity influence reaches the sink; the final gate denies unless the exact sink policy admits it or a governed endorsement creates a fresh result.", + "evaluation_variables": [ + "content source", + "participant mode", + "policy knowledge", + "quarantine capability", + "monitor visibility" + ], + "runtime_boundary": "RuntimeControlPlane-to-RuntimeTarget", + "denial_requires_zero_external_effects": true, + "required_evidence": [ + "semantic-result", + "runtime-target-call-count", + "participant-visible-output", + "append-only-history", + "safe-audit-or-error-evidence", + "replay-result" + ] + }, + { + "id": "confidential-exfiltration", + "attack_path": "confidential runtime fact -> opaque derivation -> valid tool argument, output, error, or colluding participant -> unauthorized destination", + "why_ordinary_admission_is_insufficient": "The read and send actions can each be permitted while their composition leaks confidential influence.", + "deterministic_boundary_result": "Confidentiality joins across every explicit derivation and crossing; destination and audience policy deny release without exact declassification authority.", + "evaluation_variables": [ + "secret visibility", + "destination authority", + "collusion", + "error and output channels", + "declassification availability" + ], + "runtime_boundary": "RuntimeControlPlane-to-RuntimeTarget", + "denial_requires_zero_external_effects": true, + "required_evidence": [ + "semantic-result", + "runtime-target-call-count", + "participant-visible-output", + "append-only-history", + "safe-audit-or-error-evidence", + "replay-result" + ] + }, + { + "id": "adaptive-monitor-evasion", + "attack_path": "participant observes approvals, denials, edits, deferrals, audits, or thresholds -> updates attack strategy -> selects lower-suspicion side-objective actions", + "why_ordinary_admission_is_insufficient": "A static negative test or monitor accuracy result omits feedback, audit exhaustion, threshold knowledge, and correlated failure.", + "deterministic_boundary_result": "Monitor output remains non-authorizing; deterministic policy still gates every sink while the evaluation measures safety and usefulness across declared adaptive strategies.", + "evaluation_variables": [ + "policy knowledge", + "monitor knowledge", + "prior outcome visibility", + "audit budget", + "monitor correlation", + "adaptive strategy" + ], + "runtime_boundary": "RuntimeControlPlane-to-RuntimeTarget", + "denial_requires_zero_external_effects": true, + "required_evidence": [ + "semantic-result", + "runtime-target-call-count", + "participant-visible-output", + "append-only-history", + "safe-audit-or-error-evidence", + "replay-result" + ] + }, + { + "id": "control-handoff-manipulation", + "attack_path": "tainted context or external direction -> valid API-409 handoff -> receiver proposal -> API-423 crossing -> external sink", + "why_ordinary_admission_is_insufficient": "A valid controller transition can launder apparent authority or induce a trusted receiver unless labels, provenance, memory, and action admission remain independent.", + "deterministic_boundary_result": "Handoff never resets labels or grants admission; controller, authority, provenance, receiver admission, crossing policy, and final sink resolve at one exact cut.", + "evaluation_variables": [ + "sender and receiver roles", + "controller change", + "shared memory", + "monitor topology", + "receiver trust assumption" + ], + "runtime_boundary": "RuntimeControlPlane-to-RuntimeTarget", + "denial_requires_zero_external_effects": true, + "required_evidence": [ + "semantic-result", + "runtime-target-call-count", + "participant-visible-output", + "append-only-history", + "safe-audit-or-error-evidence", + "replay-result" + ] + } + ], + "requirement_dispositions": [ + { + "uid": "SEM-233", + "disposition": "new", + "status": "DRAFT", + "ground_control_id": "fe8c490c-20c1-4178-b32b-49085d6da69c", + "scope": "Two-coordinate participant-neutral explicit-flow authority and final-sink decision semantics.", + "rationale": "SEM-230 does not yet carry independent confidentiality and source-integrity coordinates transitively to every sink." + }, + { + "uid": "ASR-536", + "disposition": "new", + "status": "DRAFT", + "ground_control_id": "6ff9b816-4603-41e1-b3f0-cf0128a033db", + "scope": "Intentional-subversion control-evaluation profiles and evidence claims.", + "rationale": "ASR-535 does not define attacker knowledge, adaptation, collusion, monitor topology, or audit/intervention protocols." + }, + { + "uid": "SEM-230", + "disposition": "reuse", + "status": "ACTIVE", + "scope": "Participant-relative projection, exact-cut policy, memory, strategy, declassification, and noninterference boundary.", + "rationale": "SEM-233 refines explicit flow labels and sinks without replacing SEM-230." + }, + { + "uid": "ACT-617", + "disposition": "reuse", + "status": "ACTIVE", + "scope": "Mixed-control authority, intervention, handoff, override, and cancellation semantics.", + "rationale": "SEM-233 keeps control changes separate from flow release and action admission." + }, + { + "uid": "API-409", + "disposition": "reuse", + "status": "ACTIVE", + "scope": "Typed participant control occurrences and contextual validation.", + "rationale": "Control occurrences carry refs into the flow relation rather than becoming a second control schema." + }, + { + "uid": "API-423", + "disposition": "reuse", + "status": "ACTIVE", + "scope": "Typed crossing request, decision, transformation, delivery, observation, and audit occurrences.", + "rationale": "Portable flow decisions compose at the existing crossing seam." + }, + { + "uid": "RUN-310", + "disposition": "reuse", + "status": "ACTIVE", + "scope": "Authenticated supervisory lifecycle, append-only histories, replay, and atomic control transitions.", + "rationale": "Final-sink mediation reuses the existing identity and persistence boundary." + }, + { + "uid": "RUN-319", + "disposition": "extend-downstream", + "status": "ACTIVE", + "scope": "Reference participant crossing enforcement and durable decisions.", + "rationale": "Child work extends its last-boundary enforcement to SEM-233 labels and sinks." + }, + { + "uid": "API-407", + "disposition": "extend-downstream", + "status": "ACTIVE", + "scope": "Declared and effective participant feature support, limitations, downgrade, and conformance evidence.", + "rationale": "Backends need explicit flow-policy, propagation, quarantine, and sink-mediation capability posture." + }, + { + "uid": "ASR-535", + "disposition": "reuse", + "status": "ACTIVE", + "scope": "Bounded participant-flow falsification, claim binding, runtime/backend evidence, and nonclaim discipline.", + "rationale": "ASR-536 adds intentional-subversion protocol variables without relabeling bounded ASR-535 evidence." + } + ], + "implementation_issues": [ + { + "key": "semantic-authority", + "issue_number": 1001, + "milestone": "Participant Information-Flow & Behavioral Equivalence", + "requirements": [ + "SEM-233", + "SEM-230", + "ACT-617", + "API-409", + "API-423" + ], + "bounded_outcome": "Publish revisioned two-coordinate explicit-flow and final-sink semantic authority.", + "negative_cases": [ + "single trusted or sensitivity label", + "release-operation conflation", + "handoff or episode trust reset", + "unknown source defaults to public or trusted" + ], + "evidence_required": [ + "formal profile", + "typed carrier mapping", + "cross-participant and cross-episode cases", + "bounded falsification" + ], + "explicit_nonclaims": [ + "no runtime or backend realization", + "no model alignment, private-state, monitor-honesty, or covert-channel claim" + ], + "dependencies": [] + }, + { + "key": "portable-contracts", + "issue_number": 1002, + "milestone": "Participant Information-Flow & Behavioral Equivalence", + "requirements": [ + "SEM-233", + "SEM-230", + "API-409", + "API-423" + ], + "bounded_outcome": "Publish closed flow-policy, label, derivation, release, sink-decision, and existing-carrier binding contracts.", + "negative_cases": [ + "open taint or policy maps", + "in-place historical label mutation", + "schema-only cross-record admission", + "prompt or private-state carriage" + ], + "evidence_required": [ + "schemas, models, fixtures, publication, and generator parity", + "resolver-backed contextual validation", + "stale, unknown, and laundering cases" + ], + "explicit_nonclaims": [ + "contract validity is not runtime enforcement or backend realization", + "no adversarial-robustness claim" + ], + "dependencies": [ + "semantic-authority" + ] + }, + { + "key": "runtime-enforcement", + "issue_number": 1003, + "milestone": "Participant Information-Flow & Behavioral Equivalence", + "requirements": [ + "SEM-233", + "RUN-319", + "RUN-310", + "API-423", + "API-407" + ], + "bounded_outcome": "Enforce and durably record SEM-233 immediately before every reference-runtime effect or disclosure.", + "negative_cases": [ + "early-only enforcement", + "effect before commit", + "stream, error, callback, or tool-argument bypass", + "deny with target call or disclosure" + ], + "evidence_required": [ + "real RuntimeControlPlane and instrumented RuntimeTarget tests", + "zero-side-effect denial cases", + "both-store atomicity, idempotency, replay, and restart evidence", + "safe diagnostic and audit evidence" + ], + "explicit_nonclaims": [ + "reference runtime is not backend realization", + "no universal IFC or covert-channel claim" + ], + "dependencies": [ + "portable-contracts" + ] + }, + { + "key": "apparatus-and-backend-support", + "issue_number": 1004, + "milestone": "Participant Information-Flow & Behavioral Equivalence", + "requirements": [ + "SEM-233", + "ASR-536", + "API-407", + "ACT-617" + ], + "bounded_outcome": "Declare and verify apparatus/backend flow, quarantine, monitor-topology, capability, downgrade, and realization posture.", + "negative_cases": [ + "declaration treated as realization", + "gateway or monitor as sole enforcement point", + "different ids treated as independent monitors", + "unsupported capability silently downgraded" + ], + "evidence_required": [ + "closed capability and apparatus contracts", + "declared-versus-effective support resolution", + "honest, weakened, overclaiming, and correlated fixtures", + "bounded backend conformance" + ], + "explicit_nonclaims": [ + "no automatic trust in any apparatus actor", + "no portable LLM message, prompt, or private-state semantics" + ], + "dependencies": [ + "portable-contracts" + ] + }, + { + "key": "adversarial-evaluation", + "issue_number": 1007, + "milestone": "Participant Information-Flow & Behavioral Equivalence", + "requirements": [ + "ASR-536", + "ASR-535", + "SEM-233", + "SEM-230" + ], + "bounded_outcome": "Run profile-bound honest and adaptive attack evaluations with separate control mechanisms and measures.", + "negative_cases": [ + "ordinary negative tests promoted to intentional-subversion robustness", + "monitor score authorizes action", + "knowledge, adaptation, collusion, audit, or memory left implicit", + "unsafe hidden objective or prompt evidence" + ], + "evidence_required": [ + "preregistered profile", + "four boundary-faithful attack cases", + "adaptive strategies and replayable trajectories", + "separate safety, usefulness, cost, uncertainty, and limitation measures" + ], + "explicit_nonclaims": [ + "no model alignment or monitor-honesty claim", + "no result outside the exact evaluated profile" + ], + "dependencies": [ + "semantic-authority", + "portable-contracts" + ] + }, + { + "key": "documentation-and-claims", + "issue_number": 1008, + "milestone": "Participant Information-Flow & Behavioral Equivalence", + "requirements": [ + "SEM-233", + "ASR-536", + "ASR-535" + ], + "bounded_outcome": "Publish only the exact evidenced runtime, backend, evaluation, limitation, and nonclaim status.", + "negative_cases": [ + "premature enforcement or realization claim", + "benchmark result promoted to universal robustness", + "apparatus details promoted to portable semantics", + "missing profile and uncertainty coordinates" + ], + "evidence_required": [ + "reconciled runtime, backend, and evaluation artifacts", + "scientific-completeness and assurance updates", + "public documentation and lineage", + "documentation drift checks" + ], + "explicit_nonclaims": [ + "no claim beyond the exact implemented and evaluated profiles", + "no automatic trust, private-reasoning, or covert-channel claim" + ], + "completion_gate": "runtime enforcement, apparatus/backend realization, and adversarial-evaluation evidence reconciled", + "dependencies": [ + "runtime-enforcement", + "apparatus-and-backend-support", + "adversarial-evaluation" + ] + } + ], + "claim_boundaries": { + "issue_812": "design-authority-and-implementation-program-only", + "runtime_enforcement": "not-established", + "backend_realization": "not-established", + "intentional_subversion_robustness": "not-established", + "model_alignment": "outside-scope", + "chain_of_thought": "excluded-from-portable-records", + "private_model_state": "excluded-from-portable-records", + "monitor_trust": "profile-scoped-assumption-not-proof", + "covert_channels": "undeclared-channels-not-controlled", + "ordinary_negative_tests": "bounded-falsification-only" + } +} diff --git a/docs/research/adversarial-participant-control/implementation-program.md b/docs/research/adversarial-participant-control/implementation-program.md new file mode 100644 index 000000000..276884df1 --- /dev/null +++ b/docs/research/adversarial-participant-control/implementation-program.md @@ -0,0 +1,97 @@ +# Adversarial Participant Control Implementation Program + +Date: 2026-07-30 + +Parent issue: [#812](https://github.com/OpenRAE/rae/issues/812) + +Milestone: `Participant Information-Flow & Behavioral Equivalence` + +The machine-readable authority is +[`implementation-program.json`](implementation-program.json). + +## Definition delivered by issue 812 + +Issue #812 delivers ADR-101, the primary-source gap assessment, revisioned +threat model, SEM-233 flow-policy profile, ASR-536 control-evaluation profile, +four worked attack designs, two canonical DRAFT requirements, and the ordered +program. + +It does not publish wire contracts, change runtime enforcement, prove backend +realization, run the attack cases, or establish intentional-subversion +robustness. + +## Dependency graph + +```text +#1001 semantic authority + | + v +#1002 portable contracts + | \ \ + | v v + | #1003 runtime #1004 apparatus/backend + | \ / + v \ / +#1007 evaluation / + \ / + +------------+ + | + v + #1008 evidenced docs +``` + +## Work packages + +### #1001: Semantic authority + +Publish the two-coordinate label algebra, conservative derivation, release +operations, final-sink relation, cross-participant/episode carriage, and +bounded falsification authority. + +### #1002: Portable contracts + +Publish closed label, derivation, release, sink-decision, and existing-carrier +binding contracts with contextual validation, fixtures, publication, and +generator parity. + +### #1003: Runtime enforcement + +Drive the real final boundary, commit before effect, and demonstrate zero +prohibited calls or disclosure for every denial, stale, unsupported, replay, +and persistence-conflict class. + +### #1004: Apparatus and backend support + +Declare quarantine, flow, monitor-topology, and sink-mediation capabilities; +resolve effective support deny-first; and publish bounded realization and +conformance evidence. + +### #1007: Adversarial evaluation + +Run honest and adaptive attack modes under declared knowledge, collusion, +monitor, audit, intervention, memory, and replay coordinates. Report safety, +usefulness, cost, uncertainty, limitations, and nonclaims separately. + +### #1008: Documentation and claims + +Only after #1003, #1004, and #1007 reconcile their evidence, update scientific +completeness, assurance status, lineage, and public guidance with the exact +implemented and evaluated profiles. + +## Program invariants + +- Confidentiality and integrity stay independent. +- Unknown or missing flow state never becomes public or trusted. +- Declassification, endorsement, authorization, admission, approval, + authentication, editing, and execution stay distinct. +- The final decision is committed immediately before effect or disclosure. +- A monitor score never authorizes an action. +- Honest and attack modes, knowledge, adaptation, collusion, audit, monitor + correlation, and memory are explicit. +- Every denial case checks zero prohibited external effects. +- Human, scripted, RL, LLM, and external-service participants share portable + semantics; apparatus internals remain capability declarations. +- Chain-of-thought, private model state, credentials, hidden objectives, and + raw secrets remain outside portable evidence. +- Runtime, backend, intentional-subversion, alignment, monitor-trust, and + covert-channel claims require separate exact evidence. diff --git a/docs/research/adversarial-participant-control/index.md b/docs/research/adversarial-participant-control/index.md new file mode 100644 index 000000000..0f462f33a --- /dev/null +++ b/docs/research/adversarial-participant-control/index.md @@ -0,0 +1,23 @@ +# Adversarial Participant Control and Boundary Flow + +Issue [#812](https://github.com/OpenRAE/rae/issues/812) adopts the +participant-neutral lessons from information-flow security and AI-control +research without adding an LLM-agent framework. + +This delivery defines the threat model, architecture, DRAFT authority, and +implementation program. It does not claim runtime or backend enforcement or a +successful adversarial evaluation. + +- [Architecture preflight](../../decisions/issue-812-adversarial-agent-control-preflight.md) +- [ADR-101](../../decisions/adrs/adr-101-adversarial-participant-flow-control.md) +- [Current-state and primary-source assessment](current-state-assessment.md) +- [Threat model](threat-model.md) +- [Trust and flow architecture](trust-flow-architecture.md) +- [Worked attack cases](attack-cases.md) +- [Requirement disposition](requirement-disposition.md) +- [Implementation program](implementation-program.md) +- [Machine-readable program](implementation-program.json) +- [Formal authority](../../../specs/formal/participant-semantics/adversarial-flow-control.md) + +SEM-233 and ASR-536 are DRAFT. Issues #1001, #1002, #1003, #1004, #1007, +and #1008 own the dependency-ordered delivery work. diff --git a/docs/research/adversarial-participant-control/requirement-disposition.md b/docs/research/adversarial-participant-control/requirement-disposition.md new file mode 100644 index 000000000..76998bb72 --- /dev/null +++ b/docs/research/adversarial-participant-control/requirement-disposition.md @@ -0,0 +1,51 @@ +# Adversarial Participant Control Requirement Disposition + +Date: 2026-07-30 + +## New DRAFT authority + +SEM-233, **Adversarial Participant Boundary Information-Flow Control**, is +DRAFT, MUST, wave 4. Canonical Ground Control id: +`fe8c490c-20c1-4178-b32b-49085d6da69c`. + +It owns independent confidentiality and integrity coordinates, conservative +explicit-flow derivation, distinct release operations, typed cross-participant +and cross-episode carriage, and fail-closed final-sink decisions. + +ASR-536, **Intentional-Subversion Participant Control Evaluation**, is DRAFT, +MUST, wave 4, non-functional. Canonical Ground Control id: +`6ff9b816-4603-41e1-b3f0-cf0128a033db`. + +It owns honest/attack modes, main/side objectives, attacker knowledge and +adaptation, collusion, monitor topology/correlation, audit and intervention +protocols, memory/replay, and separate safety/usefulness/cost/uncertainty +evidence. + +Issue #812 defines both authorities but does not satisfy their positive +implementation or evaluation clauses. + +## Reused and downstream authority + +| Requirement | Disposition | Scope | Boundary | +| --- | --- | --- | --- | +| SEM-230 | reuse | participant projection, exact-cut policy, memory, strategies, declassification, noninterference | SEM-233 adds explicit label coordinates and sinks, not another participant world | +| ACT-617 | reuse | control authority, intervention, handoff, override, cancellation | control change is not flow release or action admission | +| API-409 | reuse | typed control occurrences | records carry flow refs; no second control schema | +| API-423 | reuse | typed crossing stages and context/order | contract validity is not final-sink enforcement | +| RUN-310 | reuse | authenticated supervisory lifecycle, persistence, replay | final-sink work reuses its identity and atomicity boundary | +| RUN-319 | extend downstream | reference crossing enforcement | #1003 adds SEM-233 last-boundary enforcement | +| API-407 | extend downstream | declared/effective capability, downgrade, realization, conformance | #1004 adds bounded flow/quarantine/sink support | +| ASR-535 | reuse | bounded flow assurance and overclaim prevention | ASR-536 adds intentional-subversion variables; it does not relabel old evidence | + +## Ordered work + +- #1001: semantic authority. +- #1002: portable contracts after #1001. +- #1003: final-sink runtime enforcement after #1002. +- #1004: apparatus and backend support after #1002. +- #1007: adversarial evaluation after #1001 and #1002. +- #1008: evidenced documentation after #1003, #1004, and #1007. + +All children name at least one of SEM-233 or ASR-536 and retain explicit +nonclaims. DRAFT status remains correct until their positive obligations and +traceability are complete. diff --git a/docs/research/adversarial-participant-control/threat-model.md b/docs/research/adversarial-participant-control/threat-model.md new file mode 100644 index 000000000..cc3399c70 --- /dev/null +++ b/docs/research/adversarial-participant-control/threat-model.md @@ -0,0 +1,109 @@ +# Adversarial Participant Threat Model + +Date: 2026-07-30 + +Model: `adversarial-participant-boundary-threat-model-v1@rev1`. + +## Actors + +### Honest but fallible participant + +An honest participant can misunderstand observations, form an invalid +proposal, select an unsupported capability, or violate policy accidentally. +Ordinary validation, admission, and negative tests primarily target this +actor. + +### Intentionally subverting participant + +An attack participant optimizes a protected side objective while attempting to +preserve apparent compliance and usefulness. It can construct structurally +valid actions, retain state when the apparatus permits it, adapt to visible +control outcomes, and coordinate through declared channels. + +This actor is not defined by implementation kind. A human, script, RL policy, +LLM, or external service can occupy either mode. + +### Untrusted content source + +Observations, tool results, retrieved content, files, errors, and participant +messages can contain data intended to redirect control or destination. Their +content is untrusted even when transport authentication and content hashes are +valid. + +### Adaptive policy-aware attacker + +The attacker may know policy, monitor topology, score thresholds, audit +budgets, or prior decisions. Each kind and degree of knowledge is an explicit +evaluation variable. Nothing is assumed hidden merely because it is +operationally inconvenient to model. + +### Colluding participants or monitors + +Participants or monitors may coordinate, share state, launder influence, or +fail in correlated ways. Different identities, processes, or models do not +establish independence. + +## Protected assets + +- confidential participant and environment data; +- integrity of policy and control decisions; +- external systems reachable by tools and actions; +- participant-facing and external outputs; +- append-only behavior, control, crossing, evidence, and audit histories; and +- hidden experiment objectives and security configuration. + +## Explicit-flow attack surface + +The governed surface includes observations, tool results, retrieval, context, +retained memory, proposals, transformations, action arguments, participant +outputs, errors, callbacks, handoffs, external direction, shared state, +cross-participant crossings, and cross-episode replay. + +It covers confidentiality leakage and untrusted influence through action, +output, argument, error, and collusion paths. It treats order and timing as +observable only where the selected SEM-230/ADR-099 profile declares them. + +## Trust boundaries + +- Apparatus declarations name capabilities and trust assumptions. Unknown + external sources default to confidential and untrusted. +- Authentication identifies a principal; it does not endorse content. +- Structural validation admits shape; it does not authorize a sink. +- Deterministic policy and capability support decide release. +- Heuristic monitors supply evidence or advice; they do not authorize. +- Human or trusted-system actions name their exact authority effect. +- `RuntimeControlPlane` immediately before `RuntimeTarget` or serialization is + the reference final-sink boundary. +- Stores bind exact history heads, policy/state cuts, labels, provenance, and + decisions before effect. + +## Attack goals + +- redirect a valid action through prompt or tool-result injection; +- compose permitted reads and sends into confidential exfiltration; +- adapt to approvals, denials, edits, deferrals, audits, handoffs, thresholds, + or budget exhaustion; +- launder influence or apparent authority through handoff or collusion; +- exploit missing labels, provenance, capability support, stale cuts, replay, + streaming, callbacks, or error paths; and +- induce unsafe audit or diagnostic disclosure. + +## Required controls + +Controls compose rather than substitute for one another: + +1. conservative two-coordinate information flow; +2. least-authority action and tool capability; +3. deterministic deny-first policy at the final sink; +4. explicit declassification and endorsement; +5. bounded monitors and intervention protocols; +6. atomic append-only decisions, replay, and safe evidence; and +7. profile-bound adversarial evaluation. + +## Outside the guarantee + +RAES does not claim observation or control of undeclared timing, storage, +resource, model-steganographic, or other covert channels. It does not inspect +or record chain-of-thought, private prompts, private model state, or +credentials. It does not establish model alignment or automatic honesty of a +participant, human, monitor, gateway, or backend. diff --git a/docs/research/adversarial-participant-control/trust-flow-architecture.md b/docs/research/adversarial-participant-control/trust-flow-architecture.md new file mode 100644 index 000000000..08b042c71 --- /dev/null +++ b/docs/research/adversarial-participant-control/trust-flow-architecture.md @@ -0,0 +1,108 @@ +# Adversarial Participant Trust and Flow Architecture + +Date: 2026-07-30 + +## Two revisioned profiles + +`participant-boundary-flow-policy-v1@rev1` defines source defaults, +confidentiality and integrity domains, conservative joins, derivation, +declassification, endorsement, sinks, exact cuts, memory, and unknown +behavior. + +`intentional-subversion-control-evaluation-v1@rev1` separately defines mode, +objectives, attacker knowledge, adaptive strategy, collusion, monitor +topology/correlation, audit and intervention protocols, memory/replay, and +measures. + +Keeping the profiles separate prevents experiment roles or monitor scores from +becoming runtime authorization. + +## Typed propagation path + +```text +source/apparatus declaration + -> observation, retrieval, tool result, or runtime fact + -> participant context and retained memory + -> proposal, transformation, output, and action arguments + -> API-409 control/handoff and API-423 crossing + -> exact-cut deterministic decision + -> atomic append-only commit + -> RuntimeTarget effect or participant/external disclosure +``` + +Every derived result has a fresh identity and binds its possible sources, +effective labels, profile revision, authority, exact cut, destination/sink, +predecessors, and safe evidence. Opaque processing retains the conservative +join of every possible influence. + +## Final boundary + +The final decision occurs after the last identity, authority, policy, +capability, destination, label, provenance, and state-cut resolution and +immediately before an irreversible effect or disclosure. The decision is +committed before effect. + +Missing label or provenance, unknown profile, ambiguous join, stale cut, +unsupported capability, policy denial, history conflict, or failed commit +causes no backend call and no participant-visible or external release. +Streaming, callbacks, tool arguments, errors, and persistent writes are sinks. + +## Existing owners to reuse + +| Concern | Canonical owner | +| --- | --- | +| participant projection, policy, memory, strategy | ADR-085, ADR-095, SEM-230, SEM-231 | +| action proposal and admission | SEM-211 and participant action-admission contracts | +| control, intervention, and handoff | ACT-617, API-409, RUN-310 | +| crossings, transformations, delivery | API-423, RUN-319 | +| fact sources, derivation, audience, sinks | runtime-fact contracts and `RuntimeFactBindingPlane` | +| runtime boundary | `RuntimeControlPlane`, `RuntimeTarget`, crossing resolver/boundary | +| persistence | `RuntimeSnapshot`, participant histories, `ControlPlaneStore.commit_participant_transition()` | +| backend posture | API-407 and `resolve_participant_feature_support()` | +| experiment/evidence | existing experiment task/protocol/study/run/apparatus/evidence/measure contracts | +| diagnostics/audit | `Diagnostic`, sanitized failures, redacted 500 envelope, `AuditEvent` | +| governance | `ContractModel`, controlled vocabularies, publication manifests, concept authority, lineage | + +No new generic action, event, crossing, policy, evidence, audit, error, +trajectory, or persistence hierarchy is authorized. + +## Cross-cutting security path + +1. Apparatuses declare capabilities and trust assumptions without portable + prompts, credentials, private state, or hidden objectives. +2. Closed DTOs and request-size guards parse transport. Touched path, query, + and header values receive separate bounds. +3. Strict identity, target, role, participant, controller, audience, and + destination binding precedes semantic fact creation. +4. Existing runtime-fact, action, API-409, API-423, snapshot, and transition + validators retain one owner per relation. +5. Flow policy, action admission, release authority, and API-407 effective + capability compose deny-first. +6. The final runtime sink rechecks the stable cut and commits before effect. +7. Idempotency, replay, and expected heads preserve the decision and reject + changed state. +8. Projection precedes serialization; errors and audit retain safe refs, + digests, classifications, and counts only. +9. Portable semantics add no required environment variable, argv secret, + subprocess, socket, daemon, sidecar, or host path. +10. Later schema work updates models, schemas, fixtures, publication hashes, + generator parity, authority, and tests together. + +## Human and monitor semantics + +A human approval can be authorization, declassification, endorsement, +admission, editing, deferral, handoff, interruption, shutdown, or advice. +Each effect is explicit. Trusted editing creates a fresh proposal and re-enters +ordinary gates. + +A monitor has a profile-scoped role, topology, visibility, correlation +assumption, and failure behavior. Its output is evidence or advice. Missing +monitor output never widens permission and a monitor score never authorizes an +action. + +## Extensibility + +New label domains, sources, sinks, participants, monitors, apparatuses, +backends, and attack strategies extend the two profiles and resolvers. They do +not rewrite the carrier model or add implementation-specific branches to +portable semantics. diff --git a/docs/research/cross-backend-participant-control/composition-architecture.md b/docs/research/cross-backend-participant-control/composition-architecture.md new file mode 100644 index 000000000..094a0f687 --- /dev/null +++ b/docs/research/cross-backend-participant-control/composition-architecture.md @@ -0,0 +1,491 @@ +# Mixed Cross-Backend Participant-Control Composition Architecture + +Date: 2026-07-31 + +Status: design authority for SEM-234. No contract or runtime implementation. + +## 1. Authority layers + +The design uses one one-way authority chain: + +```text +portable authored scenario and participant policy + -> experiment realization-profile selection + -> deterministic allocation/topology/phase admission + -> ordinary SDL instantiation and semantic admission + -> exact participant control and crossing cut + -> selected realization provider and adapter + -> external effect or participant disclosure + -> observed apparatus, histories, conformance, and run evidence +``` + +No later layer rewrites an earlier artifact. Apparatus cannot change SDL +meaning. Runtime cannot change admitted allocation. Evidence cannot authorize +what happened. + +## 2. Composition profile + +The profile identity is: + +```text +mixed-cross-backend-participant-control-v1@rev1 +``` + +It supports two modes. + +### Alternative realization + +The same scenario/policy digest is admitted separately for: + +- simulation; or +- emulation/operation. + +Each run has its own plan entry, run id, apparatus, allocation, realized time, +loss, and evidence. A comparison may relate them. They are not one run. + +### Simultaneous mixed realization + +One admitted trial pins two or more apparatus components. At least one +component is simulated and at least one is emulated/operational for the +mandatory ASR-537 case. + +The profile does not require all components to share one runtime technology. +It requires every edge to be explicit. + +## 3. Allocation + +### Allocation units + +Revision 1 is a closed union: + +| Unit | Meaning | +| --- | --- | +| participant runtime | Realize the participant implementation/control loop | +| controlled scope | Realize the governed assets/resources under an authority scope | +| action family | Translate and execute one governed action-contract family | +| observation source | Produce one governed observation/source family | +| crossing boundary | Realize transport/translation for one directed boundary | + +These are stable compiled refs. They are not arbitrary paths, filters, Python +callbacks, backend commands, or runtime labels. + +### Allocation invariants + +Let: + +- \(U\) be all required allocation units in the instantiated scenario; +- \(C\) be the admitted apparatus components; +- \(A \subseteq U \times C\) be allocation; +- \(G\) be an optional closed arbitration profile; and +- \(\operatorname{eligible}(u,c)\) be API-407 effective support plus + realization-envelope admission. + +Revision 1 requires: + +1. **Completeness**: + \[ + \forall u \in U,\ \exists c \in C : (u,c) \in A + \] +2. **Eligibility**: + \[ + (u,c) \in A \Rightarrow \operatorname{eligible}(u,c) + \] +3. **No unexplained overlap**: + \[ + (u,c_1),(u,c_2) \in A \land c_1 \ne c_2 + \Rightarrow G \text{ resolves realization responsibility} + \] +4. **No implicit fallback**: a failed provider does not select another member + of \(C\) unless a future admitted failover profile names that transition. +5. **Stable identity**: component and unit refs do not depend on worker, + schedule, host, backend availability, or phase outcome. + +Revision 1 does not publish a failover or arbitration profile. Overlap is +therefore rejected unless the two entries cover different non-overlapping +subscopes under an incumbent authority. + +## 4. Topology and edges + +### Topology classes + +- **single-component**: one realization provider; +- **integrated**: components share one coordinator/runtime boundary; +- **unified**: components expose one governed external composition surface; +- **federated/bridged**: independent runtime domains exchange through explicit + bridges; and +- **nested**: one admitted component is itself a closed composition. + +The class describes structure. It does not establish compatibility or trust. + +### Edge contract sketch + +Future #1014 contracts should represent: + +```text +composition edge + identity + revision + source component + destination component + allocated crossing scope + adapter/bridge identity + manifest + portable action/observation refs + transformation/mapping profile + participant/audience policy ref + release/declassification basis + source and destination clock refs + cross-clock/order mapping + required API-407 features and strengths + mapping loss and limitations + failure/retry/partial-delivery behavior + evidence/provenance expectations +``` + +The edge references API-423 occurrence history. It does not duplicate request, +decision, release, delivery, observation, or audit carriers. + +### Nested composition + +A nested component exposes: + +- one admitted component identity and digest; +- its externally visible allocation units; +- its edge/time/policy capabilities; +- its internal-composition evidence ref; and +- limitations. + +The parent profile cannot infer internal authority or hide an unproven loss. +An unresolved nested profile is unsupported. + +## 5. Control and ownership + +### Acting control + +For one participant \(p\), episode \(e\), and order cut \(o\): + +```text +controller(p,e,o) = exactly one active controller +``` + +The existing authority basis, controlled scope, policy revision, state +revision, validity interval, idempotency, and history heads remain binding. + +### Realization responsibility + +For allocation unit \(u\): + +```text +provider(u, phase, cut) = one admitted apparatus component +``` + +`provider` determines which component may attempt realization after admission. +It does not grant the acting controller authority or change the action +contract. + +### HLA ownership + +An HLA adapter may expose an object/attribute ownership state: + +```text +unowned | owned(component) | transfer-pending | transfer-failed +``` + +That state is evidence about mutation responsibility. The runtime still joins +it with: + +- current acting controller; +- current authority scope; +- action admission; +- allocation; +- API-407 support; +- exact policy/time/order cut; and +- atomic commit. + +Ownership acquisition cannot authorize an otherwise denied action. + +### Transfer protocol + +The design-level states are: + +```text +requested + -> offered + -> pending + -> committed + +requested | offered | pending + -> failed | expired | cancelled | stale +``` + +The request records pull/push initiator, desired scope, prior owner/provider, +candidate, controller/authority cut, clock/order, capability, and evidence. +Only `committed` changes effective responsibility. A stale transition has no +effect. + +### Deferred authority profiles + +Revision 1 rejects: + +- lease: validity windows lack lease identity, renewal, expiry, and fencing; +- simultaneous scoped controllers: one controller state cannot carry distinct + concurrent owners; +- joint/fused control: a list lacks quorum, priority, arbitration, unanimity, + conflict, and failure rules; and +- oscillation tolerance: repeated valid transfers can still livelock. + +These require a later version. They are not hidden inside an extension map. + +## 6. Information distribution and security + +### Order of operations + +```text +authenticate caller and bind target + -> resolve participant/controller/audience + -> resolve allocation and component manifests + -> resolve exact policy/state/order cut + -> authorize and project through SEM-230/API-423 + -> validate mapping and effective capability + -> prepare occurrence/history/evidence + -> atomically commit decision + -> invoke adapter or serialize disclosure + -> append result/readback/failure +``` + +Any failed gate before effect produces no prohibited backend call or +disclosure. + +### Bridge trust boundary + +The adapter/bridge is untrusted with respect to portable meaning. It may: + +- transform representations; +- narrow delivery; +- pace or buffer messages; +- serialize events; +- expose metadata; +- fail partially; and +- return backend-native diagnostics. + +It cannot: + +- invent participant/action/observation identities; +- widen a participant projection; +- select a different provider; +- reinterpret controller authority; +- silently discard loss; +- convert failed delivery into observation; or +- persist policy/evidence in a side store. + +Backend exceptions pass the existing sanitization boundary. Secrets, policy +bodies, hidden observations, payloads, host paths, private ids, and credentials +do not enter portable artifacts, argv, environment dumps, logs, or errors. + +### Metadata projection + +Each participant and auditor profile decides which of these are visible: + +- membership and join/leave; +- subscription/class; +- region and destination; +- size and cadence; +- synchronization/time request/grant; +- ownership/responsibility transfer; +- retraction; and +- failure/timeout. + +An audit audience may retain more than the participant. That does not imply +participant disclosure. + +## 7. Time and order + +For every component \(c\), record: + +- clock identity and authority; +- time domain and unit; +- pacing/dilation; +- regulating/constrained role; +- advancement and grant service; +- lookahead; +- receive/timestamp/serialized order; +- rollback/replay behavior; and +- runtime readback. + +For edge \(c_i \to c_j\), an admitted mapping is: + +```text +M_ij: + source clock/domain + destination clock/domain + mapping kind and revision + monotonicity/order guarantees + uncertainty/precision + buffering/lookahead + failure and unmapped behavior + evidence +``` + +If \(M_{ij}\) is absent, cross-clock order is partial/unknown. If only +timestamps exist, support is `disclosed_weak`. + +The exact staleness predicate includes: + +```text +controller +authority basis and scope +capability result +policy revision +state revision +history heads +governed order +``` + +Wall-clock age may be an additional constraint. It cannot replace these +coordinates. + +## 8. Trial and phase semantics + +### Inter-trial change + +A progression such as: + +```text +emulation data collection + -> derived simulator generation + -> simulated training + -> emulation evaluation +``` + +uses distinct entries/runs. Each derived artifact records its source data, +model/profile, version, generator, unknown transitions, and digest. A new run +can link to the prior one without reusing its identity. + +### Within-run phase schedule + +Let \(P = [p_0,\dots,p_n]\) be a finite admitted phase sequence. Each phase +records: + +- active component set; +- allocation; +- edge set; +- controller/authority expectation; +- clock/order mappings; +- policy and release expectations; +- entry and exit predicates; +- maximum progress bound; +- failure disposition; and +- evidence. + +All referenced components and mappings are pinned in the sealed plan. A +transition appends: + +```text +prior phase +next phase +trigger and order cut +prior and next active membership +controller/authority/policy/time cuts +commit result +loss and evidence +``` + +It does not rewrite the plan/run id, prior histories, or participant knowledge. +If transition admission or commit fails, the next phase has no effects. + +## 9. Open/closed axes + +### Control loop + +- **open-loop**: observe, replay, or evaluate without external actuation; +- **closed-loop**: participant output may reach an external effect after all + ordinary control, admission, capability, policy, time, and commit gates. + +Closed-loop is not authority. + +### World assumption + +- **closed-world**: unknown entities/actions/observations/mappings are absent + or invalid under the profile; +- **bounded-open-world**: unknowns may exist, but portable action and + observation vocabularies remain closed and unknown mappings are unsupported. + +Bounded-open-world is not permissive fallback. + +### Federation membership + +- **fixed**: active membership does not change; +- **pre-admitted dynamic**: active membership follows the finite phase + schedule. + +Dynamic is not arbitrary late join. + +## 10. Evidence architecture + +The run evidence graph reuses existing carriers: + +```text +scenario/policy/plan/run identities + -> component and adapter manifests + -> allocation/topology/phase profile + -> capability and conformance + -> control/crossing/time histories + -> raw observations and backend readback + -> mapping loss and limitations + -> derived conformance/transfer/readiness measures + -> behavioral claim bindings and nonclaims +``` + +Required provenance includes: + +- scenario and policy digests; +- trial coordinate, plan entry, and run id; +- participant implementation, processor, backend, bridge, and host identities; +- component allocation and topology; +- model/data/seed/random-stream identity; +- time mapping and realized order; +- capability and conformance profile; +- transformations and losses; +- software/source revisions; +- raw and derived evidence; +- uncertainty and limitations; and +- reproduction identity/result. + +## 11. Failure taxonomy + +The design reuses existing diagnostics and dispositions. Downstream contracts +need stable cases for: + +- missing or unknown profile/revision; +- duplicate or unresolved component/scope; +- incomplete or overlapping allocation; +- incompatible apparatus; +- unsupported capability; +- failed or false conformance; +- missing policy/authority; +- stale controller/state/history cut; +- unmapped clock/order; +- invalid phase transition; +- failed atomic commit; +- backend/bridge failure; +- partial delivery; +- observation mismatch; +- mapping loss beyond admitted bounds; and +- evidence/provenance incompleteness. + +No case causes implicit fallback. + +## 12. Extensibility seam + +A future backend adds: + +- a manifest and adapter identity; +- supported realization forms and allocation units; +- edge mapping profiles; +- time/order capabilities; +- policy projection behavior; +- loss/failure declarations; and +- conformance evidence. + +It does not change SDL or add branches throughout the runtime. + +A future controller-composition profile can add lease or joint authority by +versioning the authority subprofile. It does not change mixed realization +allocation or pretend provider multiplicity already supplied that semantics. diff --git a/docs/research/cross-backend-participant-control/current-state-assessment.md b/docs/research/cross-backend-participant-control/current-state-assessment.md new file mode 100644 index 000000000..c67a90162 --- /dev/null +++ b/docs/research/cross-backend-participant-control/current-state-assessment.md @@ -0,0 +1,313 @@ +# Mixed Cross-Backend Participant Control: Current-State Assessment + +Date: 2026-07-31 + +## Finding + +RAES has the semantic, contract, trial, runtime, time, backend, and evidence +parts needed to design mixed participant realization. It does not have the +composition authority that joins those parts for one simultaneously mixed +trial. + +The gap is not a new scenario language, participant model, controller field, +message bus, or evidence database. It is one revisioned allocation/topology +profile plus downstream extensions at existing seams. + +## Authored scenario and participant meaning + +### Existing coverage + +ADR-022 and the participant formal design already distinguish: + +- participant identity and behavior; +- action, observation, visibility, failure, causality, outcome, and time; +- portable intent from backend realization; and +- simulation, emulation, live, human-mediated, or stubbed realization + profiles. + +ADR-085 and SEM-230 add participant/audience-relative projection, exact-cut +policy, memory, strategies, release, delivery/observation separation, and +explicit noninterference boundaries. + +ADR-095 adds decision epochs, stable state cuts, order, and participant +knowledge. ADR-101 adds independent confidentiality/integrity flow design and +the final-sink boundary without changing participant identity. + +### Missing + +No authored or formal profile defines: + +- which stable participant/action/observation scope is realized by which + apparatus component; +- which components coexist in one trial; +- the edges between them; or +- how realization allocation changes without changing portable SDL meaning. + +Backend selection must not be added to SDL to fill this gap. Doing so would +make scenario membership depend on apparatus and undermine cross-backend +comparison. + +## Experiment and trial realization + +### Existing coverage + +ADR-084 defines: + +```text +authored family + -> deterministic composition + -> experiment selection + -> deterministic trial compilation/admission + -> SDL instantiation + -> runtime/backend execution + -> archival run/study evidence +``` + +`AdmittedTrialEntryModel` already seals: + +- one logical coordinate and run id; +- selections and bindings; +- stochastic draws; +- apparatus; +- execution control; +- instantiation provenance; and +- a content digest. + +`AdmittedApparatusBindingModel` pins manifest refs, participant manifests, one +realization-envelope identity, and capability refs. + +`ExperimentApparatusContextModel` can report multiple apparatus components, +selected manifests, compatibility declarations, configuration, stochastic +controls, clocks, measurement channels, observed setup evidence, and +limitations. + +The distinction is important: + +- admitted apparatus is pre-run intent; +- apparatus context is observed run evidence. + +### Missing + +The admitted apparatus binding has no mixed component graph. Its one +realization envelope cannot express: + +- one participant runtime in simulation and another in emulation; +- one action family realized by a simulator and another by an operational + tool; +- one observation supplied by hardware while other state remains simulated; +- explicit bridge mappings between components; or +- a finite within-run activation schedule. + +The apparatus context cannot be repurposed as authorization because it is +observational. It may validate that an admitted profile was realized, but it +cannot create the profile after execution. + +ADR-084 already supplies the identity answer: + +- a realization change between trials is a new admitted entry/run linked to + its source; +- a retry is not a new selection; and +- runtime facts and schedulers cannot change trial identity or apparatus. + +SEM-234 adds only finite pre-admitted within-run phases. It does not reopen +these rules. + +## Participant control + +### Existing coverage + +ACT-617, API-409, RUN-310, and the participant-control models separate: + +- participant proposal and external direction; +- approval and denial; +- handoff, override, cancellation, and intervention; +- controller and authority; +- controlled scope; +- action admission and execution; +- state revision and validity; +- idempotency and replay; and +- append-only control history. + +The current effective state has one acting controller per participant and +episode. A transition is revision-fenced. The runtime uses state/history +checks and atomic persistence. + +### Missing and deliberately rejected + +`controlled_scope_refs` can describe scope, but one controller field cannot +represent different simultaneous owners of different scopes. A validity +window does not supply lease renewal, expiry, fencing, or order. A list of +controllers does not define joint authority. + +Issue #813 therefore rejects positive revision-1 support for: + +- simultaneous scoped controllers; +- leases; +- quorum, priority, arbitration, or unanimity; +- fused authority; and +- oscillation/livelock handling beyond the existing single-controller + transition. + +These remain a future versioned profile. Mixed backends are realization +providers below action admission, not controllers. + +## Crossings, delivery, and information flow + +### Existing coverage + +API-423 supplies typed crossing occurrences for request, decision, +transformation/release, delivery attempt, delivery, observation, and audit. +Context validation binds participant, controller, audience, policy cut, order, +predecessors, and evidence. + +RUN-319 provides the shared deny-first mediator and final persistence +boundary. SEM-230 owns participant projection. DSL-142 preserves directed +inject identity and delivery semantics. + +### Missing + +No edge binds one runtime component to another with: + +- adapter/bridge identity; +- action or observation transformation; +- policy projection; +- cross-clock/order mapping; +- capability strength; +- mapping loss; and +- failure/readback evidence. + +This is a composition-edge profile, not a new message carrier. API-423 remains +the crossing history. + +## Time and ordering + +### Existing coverage + +ADR-090 and ADR-091 define: + +- time domains and clock authority; +- progression and scheduling; +- participant time-management context; +- backend time capabilities; +- realized time models; +- ordering basis; and +- conformance diagnostics. + +The existing participant semantics reject timestamp-as-causality and require +weakening when a backend serializes or drops concurrency. + +### Missing + +The current trial apparatus does not bind a mapping between each component's +clock/order service. A mixed trial needs: + +- per-component clock and role; +- edge mapping; +- request/grant or pacing behavior; +- lookahead when applicable; +- delivery-order realization; +- serialization/readback evidence; and +- partial/unknown disposition. + +No mapping means no exact cross-clock order claim. + +## Backend capability and conformance + +### Existing coverage + +API-407 extends `backend-manifest/v2` +`capabilities.participant_runtime.feature_support`. It separates declared +support, effective strength, required contracts, constraints, disclosures, +downgrade, realization, and conformance. + +The support order is: + +```text +unsupported < disclosed_weak < bounded < exact +``` + +Existing conformance reports, case results, participant-policy probes, +realization probes, and time diagnostics are reusable. + +### Missing + +The governed vocabulary has no complete mixed-composition feature family for: + +- allocation granularity; +- topology/bridge behavior; +- cross-clock mapping; +- phase membership; +- ownership-transfer realization; +- addressed delivery; +- policy projection across a bridge; or +- mapping-loss/readback evidence. + +The gap belongs in the existing manifest and conformance surfaces. A new +capability block would duplicate API-407. + +## Evidence and scientific claims + +### Existing coverage + +RAES already has: + +- experiment task, protocol, run, study, apparatus, evidence, measure, and + traceability records; +- associated artifact manifests; +- realization envelopes and provenance; +- behavioral claim bindings; +- safe digests and limitations; and +- explicit separation of finite falsification, conformance, model checking, + proof, and empirical study. + +The issue #600 corpus supplies two separate backend runs and a bounded +invariant ledger. Issues #810 through #812 further separate opacity, +bisimulation, adversarial control, runtime, backend, and proof claims. + +### Missing + +No protocol binds: + +- pure simulation; +- pure emulation/operation; +- simultaneous mixed composition; +- staged realization; +- open-loop and closed-loop behavior; and +- cross-backend mismatch cases + +under one revisioned evidence plan. + +The existing paired corpus must not be relabeled as mixed. It can be a source +of apparatus and invariant patterns only. + +## Exact reuse map + +| Concern | Incumbent | SEM-234/ASR-537 use | +| --- | --- | --- | +| Scenario meaning | SDL phases, ADR-078, ADR-084 | Keep backend-neutral | +| Stable targets | ADR-076 canonical addresses | Allocation scope refs | +| Experiment selection | Experiment authoring/factor/allocation contracts | Select profile and trial variation | +| Trial admission | Admitted trial plan and compiler | Pin graph and finite phases | +| Apparatus | Manifests, constraints, contexts | Components and observed realization | +| Realizability | ADR-070 envelopes | Per-component admitted support | +| Participant control | ACT-617/API-409/RUN-310 | One controller; revision-fenced handoff | +| Crossing/IFC | SEM-230/API-423/RUN-319 | Edge policy and histories | +| Time | ADR-090/091 time contracts | Per-component clocks and edge mappings | +| Capability | API-407 | Mixed service terms and effective strength | +| Conformance | Existing report/case/probe families | Service-specific probes | +| Evidence | Experiment/evidence/associated-artifact contracts | Complete apparatus and result binding | +| Claims | ADR-081/ASR-535 | Prevent relation promotion | + +## Required downstream changes + +The dependency order is: + +1. #1013: semantic authority; +2. #1014: portable contracts; +3. #1015: deterministic trial admission; +4. #1016: fail-closed runtime coordination; +5. #1017: backend capability and conformance; +6. #1018: demonstration and evaluation; and +7. #1019: evidence-led claim reconciliation. + +Until those issues land, mixed realization is DRAFT design only. diff --git a/docs/research/cross-backend-participant-control/demonstration-protocol.md b/docs/research/cross-backend-participant-control/demonstration-protocol.md new file mode 100644 index 000000000..764bad3ec --- /dev/null +++ b/docs/research/cross-backend-participant-control/demonstration-protocol.md @@ -0,0 +1,357 @@ +# Cross-Backend Participant-Control Demonstration Protocol + +Date: 2026-07-31 + +Protocol: `cross-backend-participant-control-demonstration-v1@rev1` + +Status: ASR-537 design. The protocol has not been executed. + +## Purpose + +The protocol determines whether one revision-pinned participant-control policy +can be realized, with stated losses, in: + +- pure simulation; +- pure emulation/operation; +- simultaneous mixed composition; +- linked trial-stage changes; and +- finite pre-admitted within-run phases. + +It is falsification-first. A rejected or weakened composition is a valid +result. The protocol cannot report broad parity by discarding mismatches. + +## Fixed identities + +Every lane pins: + +- authored scenario identity, version, source digest, and canonical snapshot; +- participant-control policy/profile id, revision, and digest; +- participant, controller, authority, action, observation, inject, and + crossing refs; +- experiment task/protocol/study ids; +- plan, plan entry, logical coordinate, run id, and replicate; +- processor, participant implementation, backend, adapter/bridge, host, and + measurement-apparatus manifests and digests; +- allocation, topology, composition edges, and phase schedule; +- clock/time/order profiles and mappings; +- capability declarations, effective support, conformance profile, and probe + identities; +- models, datasets, generators, random-stream profile, namespace, seed, and + draw provenance; +- transformation/mapping profiles, losses, uncertainty, and limitations; and +- source revision, evidence bundle, and reproduction identity. + +The same authored scenario and participant-control policy digest is mandatory +for the pure and mixed comparison lanes. Backend-translated inputs are derived +artifacts, not replacement authored identities. + +## Apparatus lanes + +### Lane S — pure simulation + +Use one simulated cyber-agent environment behind a RAES adapter. A CybORG-like +or CyberBattleSim-like apparatus is acceptable if the exact API, action, +observation, time, and fidelity limits are recorded. + +Lane S establishes only bounded simulated realization and conformance. + +### Lane E — pure emulation or operation + +Use one emulation/operational `RuntimeTarget`. The adapter maps the same +portable action and observation refs to operational procedures and readback. + +Lane E establishes only the observed operational path. A deterministic stub +does not count as native operation and must be labeled separately. + +### Lane M — simultaneous mixed + +Use one admitted trial containing at least: + +- one simulated component; and +- one emulated/operational component. + +The components interact across at least one explicit composition edge. The +edge binds policy, mapping, time/order, support, failure, and evidence. + +Lane M is not satisfied by running Lane S and Lane E separately. + +### Lane T — linked trial transition + +Run a revision-pinned progression such as: + +```text +E data collection -> derived S model -> S training -> E evaluation +``` + +Every step is a new admitted plan entry/run with source lineage. Record unknown +transitions and model/data coverage. + +### Lane P — pre-admitted phase transition + +Use one run with a finite phase schedule whose components and mappings are +fully pinned before execution. Demonstrate one activation/deactivation +boundary and its atomic evidence. + +## Control-loop cases + +### Open-loop + +Observe or replay state without an admitted external action. Assert: + +- the participant receives only the authorized view; +- evidence collection does not grant action authority; +- no operational backend call occurs; and +- audit-only facts remain outside participant disclosure. + +### Closed-loop + +Allow a participant proposal to reach an external effect only after: + +- caller/target/controller binding; +- authority and action admission; +- exact policy and state cut; +- allocation and edge resolution; +- effective capability and mapping validation; +- time/order admission; and +- atomic commit. + +Remove any gate in a mutation case. The effect must disappear. + +## Positive case matrix + +| Case | Required result | Bound | +| --- | --- | --- | +| Pure simulation | Action, observation, control, inject, order, and evidence path realized or explicitly weakened | Lane S apparatus | +| Pure emulation/operation | Same portable refs mapped to operational procedures/readback or rejected | Lane E apparatus | +| Simultaneous mixed | One admitted edge carries an authorized action/observation between S and E components | Lane M topology | +| Inter-trial transition | New run identity and complete derivation/transfer provenance | Lane T sequence | +| Pre-admitted phase | Atomic membership/allocation change with unchanged run identity and append-only history | Lane P schedule | +| Open-loop | Observation/evidence without action authority or effect | Named participant/audience | +| Closed-loop | Commit-before-effect under every independent gate | Named action/sink | + +A “positive” case may be `disclosed_weak` when the policy permits that strength. +It cannot be silently normalized to `exact`. + +## Mandatory adversarial cases + +### 1. Stale handoff + +Resolve an approval under controller revision \(r\). Commit a handoff to +\(r+1\). Attempt the approved action. + +Required result: + +- stale denial; +- zero backend calls or disclosures; +- unchanged effect state; +- append-only stale occurrence and audit evidence. + +### 2. Concurrent intervention + +Race two controller/intervention writes at one state/history cut. + +Required result: + +- one commit or both denied; +- never two effective acting controllers; +- no duplicate effect; +- exact CAS/idempotency evidence. + +### 3. Unsupported or false capability + +Require a mixed service that is absent or falsely declared. + +Required result: + +- admission denial or failed conformance; +- zero prohibited effect; +- declaration, effective strength, missing evidence, and failure retained + separately. + +### 4. Timestamp-only or unmapped order + +Supply wall-clock timestamps without an admitted clock/order mapping. + +Required result: + +- exact-order claim rejected; +- `disclosed_weak` or partial/unknown relation; +- no timestamp-as-causality statement. + +### 5. Simulation-only observation + +Expose an observation field in Lane S that Lane E cannot produce. + +Required result: + +- mismatch and source apparatus recorded; +- no parity or transfer success for behavior depending on that field; +- participant projections remain independently validated. + +### 6. Unrealizable action + +Admit an abstract action in Lane S whose transformed operational procedure is +unsupported or invalid. + +Required result: + +- fresh validation/admission rejects the transformed proposal; +- zero operational effect; +- mapping loss and diagnostic retained. + +### 7. Directed-delivery failure + +Address an inject to a participant through a bridge that misroutes, drops, or +cannot deliver it. + +Required result: + +- request and delivery-attempt evidence; +- failed delivery; +- no observation; +- no invented participant history entry. + +### 8. Prior-delivery retraction + +Deliver a value, then conceal or retract it under a later policy/phase. + +Required result: + +- retraction appended; +- original delivery and possible participant knowledge retained; +- no history deletion or retroactive noninterference claim. + +### 9. Bridge-metadata leakage + +Filter payload content while varying membership, destination, size, timing, +synchronization, ownership, or failure metadata with a protected fact. + +Required result: + +- bounded leakage finding or a separately justified projection; +- no payload-filtering-as-IFC claim. + +## Additional failure cases + +Run at least: + +- unknown profile or revision; +- missing component/manifest; +- duplicate or overlapping allocation; +- unresolved controlled scope/action/observation ref; +- incompatible realization envelope; +- missing policy or declassification basis; +- cross-clock mapping cycle or ambiguity; +- unadmitted late join; +- phase trigger outside the admitted order; +- failed phase-transition commit; +- bridge partial delivery; +- adapter exception sanitization; +- evidence digest mismatch; and +- reproduction drift. + +## Measurements + +Report measures independently: + +- action admission and realization disposition; +- observation field availability and transformation loss; +- delivery and observation success; +- handoff/phase transition outcome; +- exact, bounded, weak, or unsupported capability; +- logical-order coverage and unknown/partial relations; +- bridge latency and buffering only under the named clock mapping; +- mapping-loss count and severity; +- transfer task outcome; +- conformance pass/fail by case; +- zero-effect violations; +- uncertainty; +- run and reproduction cost; and +- missing evidence. + +Do not collapse these into one score that hides a failed security or authority +case. + +## Claim rules + +### Bounded conformance + +May be reported only for the exact manifest, adapter, profile, probes, and run +evidence. It says the tested obligations passed. It says nothing about +untested behavior. + +### Interoperability readiness + +May report whether sufficient engineering evidence exists to assess +integration risk. It does not report actual interoperability. + +### Empirical sim-to-em transfer + +May report the population, training/evaluation protocol, trials, measures, +uncertainty, model/data identity, and observed result. It is not universal +transfer. + +### Trace inclusion or bisimulation + +Requires the corresponding complete carrier, projection, relation profile, and +proof/model-check evidence. Finite demonstration traces cannot establish it. + +### IFC/noninterference + +Requires the exact policy, observer, strategy, memory, release, scheduler, +time/order, and hyperproperty boundary. Routing/filtering results cannot +establish it. + +### Backend equivalence + +Requires an independently governed relation and evidence. A common adapter, +two successful runs, or a passing mixed case is insufficient. + +## Evidence bundle + +Reuse existing experiment and associated-artifact carriers. The bundle +contains or references: + +- admitted plan and instantiated snapshot; +- component/adapter manifests and effective capabilities; +- allocation/topology/phase profile; +- policy, control, crossing, delivery, observation, and time histories; +- backend readback and conformance reports; +- raw participant/evaluator/auditor evidence under separate projections; +- transformations, loss, limitations, and sanitized diagnostics; +- models/data/seeds/random-stream records; +- derived measures and relation-specific claims; +- environment/source/tool versions; +- cleanup and isolated-state evidence; and +- reproduction record. + +Raw secrets, credentials, hidden answers, policy bodies, chain-of-thought, +private backend payloads, host paths, native ids, environment dumps, argv, and +unsanitized stderr are excluded. + +## Reproduction + +A reproduction: + +- resolves the same revision-pinned sources and profiles; +- independently validates every portable artifact; +- uses a new explicit run/replicate identity; +- recomputes digests and derived measures; +- records deviations in apparatus, timing, mapping, or evidence; and +- does not reuse an unreviewed producer result directory. + +An identical seed is not exact replay by itself. + +## Exit criteria + +ASR-537 remains DRAFT until: + +1. #1013 through #1017 provide accepted semantic, contract, trial, runtime, + and backend authorities; +2. every mandatory lane and adversarial case has a disposition; +3. denied cases have zero prohibited effects; +4. every result has complete apparatus/provenance binding; +5. at least one mismatch or weakening is retained rather than normalized; +6. relation claims remain separated; +7. reproduction evidence exists; and +8. #1019 reconciles the exact claims and residual gaps. diff --git a/docs/research/cross-backend-participant-control/implementation-program.json b/docs/research/cross-backend-participant-control/implementation-program.json new file mode 100644 index 000000000..86b6dad33 --- /dev/null +++ b/docs/research/cross-backend-participant-control/implementation-program.json @@ -0,0 +1,1179 @@ +{ + "schema_version": "cross-backend-participant-control-program/v1", + "assessment_date": "2026-07-31", + "parent_issue": 813, + "participant_milestone": "Participant Information-Flow & Behavioral Equivalence", + "backend_coordination_milestone": "Backend Contract & Conformance", + "deliverables": [ + "docs/decisions/issue-813-cross-backend-participant-control-preflight.md", + "docs/decisions/adrs/adr-102-mixed-cross-backend-participant-control.md", + "docs/research/cross-backend-participant-control/index.md", + "docs/research/cross-backend-participant-control/prior-art-and-design-criteria.md", + "docs/research/cross-backend-participant-control/current-state-assessment.md", + "docs/research/cross-backend-participant-control/composition-architecture.md", + "docs/research/cross-backend-participant-control/demonstration-protocol.md", + "docs/research/cross-backend-participant-control/requirement-disposition.md", + "docs/research/cross-backend-participant-control/implementation-program.md", + "docs/research/cross-backend-participant-control/implementation-program.json", + "specs/formal/participant-semantics/cross-backend-participant-control.md", + "docs/public/participant-control.md", + "docs/explain/sdl/lineage.md", + "implementations/python/tests/test_issue_813_cross_backend_participant_control_design.py" + ], + "primary_sources": [ + { + "id": "hla-1516-2025", + "title": "IEEE 1516-2025 High Level Architecture family", + "kind": "standard", + "edition_or_version": "IEEE 1516-2025, 1516.1-2025, and 1516.2-2025", + "primary_url": "https://standards.ieee.org/ieee/1516/6687/", + "stronger_dimension": "Standardized federation ownership-transfer, declaration, data-distribution, directed-interaction, and logical-time service machinery is more mature than RAES mixed-runtime composition.", + "adopted_lessons": [ + "service-specific capability declarations", + "scoped ownership-transfer states and failure outcomes", + "time-regulating and time-constrained roles", + "lookahead, time advancement, grants, and delivery-order evidence", + "edition-pinned framework, interface, and object-model responsibilities" + ], + "rejected_inferences": [ + "object or attribute ownership is participant controller authority", + "publish-subscribe or data distribution is authorization or IFC", + "object-model syntax establishes shared behavioral meaning", + "RAES is HLA wire-compatible by default" + ], + "raes_consequence": "Use HLA as a service and failure-state precedent. Keep HLA realization behind API-407 and adapter evidence and preserve RAES control, crossing, policy, and trial authorities.", + "nonclaims": [ + "No HLA RTI, FOM, or wire compatibility is delivered.", + "No HLA conformance establishes RAES semantic equivalence." + ], + "empirical_result_boundary": "not-applicable" + }, + { + "id": "nist-integrated-hla", + "title": "Integrating Multiple HLA Federations for CPS Evaluations", + "kind": "government research", + "edition_or_version": "NIST publication 934446", + "primary_url": "https://www.nist.gov/publications/integrating-multiple-hla-federations-effective-simulation-based-evaluations-cps", + "stronger_dimension": "The work makes federation topology, information hiding, independent time scales, shared resources, and bridge translation explicit.", + "adopted_lessons": [ + "flat federation topology can be insufficient", + "bridges and shared federates are explicit trust and translation boundaries", + "independent logical times can lack a valid mapping", + "routing metadata and bridge behavior need evaluation" + ], + "rejected_inferences": [ + "a federation boundary proves selective disclosure", + "bridge filtering does not establish noninterference", + "two independent logical clocks are comparable by default" + ], + "raes_consequence": "Represent every composition edge and its policy, time, translation, failure, and evidence obligations. Apply RAES authorization before bridge filtering.", + "nonclaims": [ + "Federation topology is not participant visibility policy.", + "A bridge is not a semantic authority." + ], + "empirical_result_boundary": "The NIST case-study performance result remains bound to its topology and workload." + }, + { + "id": "nist-ucef", + "title": "NIST Universal CPS Environment for Federation", + "kind": "government platform specification", + "edition_or_version": "NIST UCEF official architecture pages, accessed 2026-07-31", + "primary_url": "https://www.nist.gov/ctl/smart-connected-systems-division/iot-devices-and-infrastructures-group/how-does-ucef-work", + "stronger_dimension": "UCEF explicitly composes simulators, emulators, equipment, and combinations of them in one federation.", + "adopted_lessons": [ + "one federation can contain simulation, emulation, and hardware", + "equipment, a model, or their combination may be a federate", + "experiment orchestration is separate from component implementation" + ], + "rejected_inferences": [ + "mixed membership makes all components semantically compatible", + "HLA membership supplies participant policy or controller authority" + ], + "raes_consequence": "Require simultaneous mixed composition as a first-class admitted mode rather than only paired backend runs.", + "nonclaims": [ + "RAES does not adopt UCEF's generator or federation runtime.", + "Mixed membership alone is not evidence of correct composition." + ], + "empirical_result_boundary": "not-applicable" + }, + { + "id": "acting-edl-fg", + "title": "EDL-FG for federated cyber-range exercises", + "kind": "research preprint", + "edition_or_version": "arXiv:2605.12170, May 2026", + "primary_url": "https://arxiv.org/abs/2605.12170", + "stronger_dimension": "EDL-FG explicitly separates infrastructure, screenplay, injects, interactions, assessment, federation, and hybrid simulated/emulated IT and OT components.", + "adopted_lessons": [ + "separate scenario logic from infrastructure realization", + "represent hybrid simulated and emulated components", + "keep injects, participant interactions, telemetry, and assessment distinct", + "distinguish capacity and brokering from scenario meaning" + ], + "rejected_inferences": [ + "a recent preprint is a ratified interoperability standard", + "an EDL schema proves scenario intent survives every range", + "RAES should import a parallel exercise language" + ], + "raes_consequence": "Reuse SDL, DSL-142, API-423, experiment, and apparatus authorities and adopt only the separation and mixed-component lessons.", + "nonclaims": [ + "No EDL-FG compatibility is delivered.", + "The paper does not establish a formal cross-range semantic relation." + ], + "empirical_result_boundary": "The paper identifies systematic quantitative validation as future work." + }, + { + "id": "cyborg", + "title": "CybORG: A Gym for the Development of Autonomous Cyber Agents", + "kind": "research paper and official implementation", + "edition_or_version": "arXiv:2108.09118 and official CAGE repository", + "primary_url": "https://arxiv.org/abs/2108.09118", + "stronger_dimension": "CybORG demonstrates one agent interface with backend-specific simulation and emulation actions and reports concrete transfer failures.", + "adopted_lessons": [ + "share an action and observation seam across realizations", + "implement each action separately per backend", + "treat simulation-only observations as transfer hazards", + "retain mismatch evidence instead of normalizing parity" + ], + "rejected_inferences": [ + "a common interface is semantic equivalence", + "the 2021 either-or run mode demonstrates simultaneous mixed composition", + "successful simulated training implies emulation success" + ], + "raes_consequence": "Use pure simulation and pure emulation lanes plus explicit mapping loss; add a separate simultaneous mixed case.", + "nonclaims": [ + "RAES does not adopt the CybORG API.", + "Interface parity is not behavioral equivalence." + ], + "empirical_result_boundary": "The reported simulation-to-emulation evaluation succeeded in 139 of 210 trials; failures included agents using simulation-only observation artifacts." + }, + { + "id": "cygil", + "title": "CyGIL simulation and emulation transfer", + "kind": "research paper", + "edition_or_version": "arXiv:2304.01244", + "primary_url": "https://arxiv.org/abs/2304.01244", + "stronger_dimension": "CyGIL makes iterative emulation-to-simulation model generation and simulation-to-emulation evaluation part of the experimental loop.", + "adopted_lessons": [ + "bind simulators to the data and traces used to generate them", + "record unknown transitions", + "support alternating training, calibration, and evaluation stages", + "treat operational tools and abstract actions as distinct" + ], + "rejected_inferences": [ + "one bounded successful transfer establishes universal transferability", + "a data-derived simulator has complete transition coverage", + "trial-stage switching is backend equivalence" + ], + "raes_consequence": "Represent inter-trial realization changes and provenance and report empirical transfer separately from conformance or formal relations.", + "nonclaims": [ + "No general sim-to-em transfer is established.", + "No simultaneous mixed world is inferred from alternating environments." + ], + "empirical_result_boundary": "The paper reports a 50-of-50 emulation evaluation for one optimized policy and scenario while also recording unknown transitions, heuristic switching, and a need for broader studies." + }, + { + "id": "cyberbattlesim", + "title": "Microsoft CyberBattleSim", + "kind": "official open-source environment", + "edition_or_version": "official repository documentation, accessed 2026-07-31", + "primary_url": "https://github.com/microsoft/CyberBattleSim", + "stronger_dimension": "", + "adopted_lessons": [ + "use a closed abstract action and observation vocabulary", + "make attacker and defender roles explicit", + "state fidelity and safety limits" + ], + "rejected_inferences": [ + "simulated compromise ownership is HLA ownership", + "abstract simulation actions are operational commands", + "the environment is suitable for direct real-system application" + ], + "raes_consequence": "Use as an abstract simulated lane and require explicit mapping loss at operational boundaries.", + "nonclaims": [ + "No operational fidelity or transfer follows from CyberBattleSim support.", + "No real network traffic is inferred." + ], + "empirical_result_boundary": "The official project describes the environment as deliberately abstract and unsuitable for direct real-world application." + }, + { + "id": "fmi-3.0.2", + "title": "Functional Mock-up Interface", + "kind": "industry standard", + "edition_or_version": "FMI 3.0.2", + "primary_url": "https://fmi-standard.org/docs/3.0.2/", + "stronger_dimension": "FMI distinguishes model exchange, co-simulation, and scheduled execution and exposes component capabilities at a mature interoperability seam.", + "adopted_lessons": [ + "distinguish exchange, co-simulation, and scheduled execution", + "make communication points and importer scheduling explicit", + "derive global order outside component-local priorities" + ], + "rejected_inferences": [ + "a common package supplies a global co-simulation algorithm", + "local priorities define cross-component order", + "interface compatibility supplies participant policy" + ], + "raes_consequence": "Make the coordinator, time mapping, global order, and failure behavior explicit on every mixed boundary.", + "nonclaims": [ + "No FMI compatibility is delivered.", + "A component interface is not a participant-control semantic relation." + ], + "empirical_result_boundary": "not-applicable" + }, + { + "id": "helics", + "title": "HELICS co-simulation timing and dynamic federations", + "kind": "official implementation documentation", + "edition_or_version": "HELICS documentation, accessed 2026-07-31", + "primary_url": "https://docs.helics.org/en/latest/user-guide/fundamental_topics/timing_configuration.html", + "stronger_dimension": "HELICS supplies explicit time request/grant coordination and dynamic federation support, including real-time and hardware-in-the-loop membership.", + "adopted_lessons": [ + "separate message topology from broker topology", + "request and grant simulated time", + "represent late join and partial-run membership", + "treat hardware-in-the-loop as a bounded component realization" + ], + "rejected_inferences": [ + "dynamic federation membership may be unadmitted", + "broker synchronization supplies action authority", + "time grants do not establish cross-backend semantic equivalence" + ], + "raes_consequence": "Allow only finite pre-admitted within-run membership schedules with pinned apparatus and explicit time/order evidence.", + "nonclaims": [ + "No HELICS broker or protocol is required.", + "Late join is not permission to alter sealed experiment intent." + ], + "empirical_result_boundary": "not-applicable" + }, + { + "id": "iso-23247-6", + "title": "Digital twin framework for manufacturing — digital twin composition", + "kind": "international standard", + "edition_or_version": "ISO 23247-6:2026", + "primary_url": "https://www.iso.org/standard/87426.html", + "stronger_dimension": "The standard distinguishes integrated, unified, and federated digital-twin composition across parties.", + "adopted_lessons": [ + "name composition topology", + "treat cross-party federation as a boundary", + "separate component twins from their composition" + ], + "rejected_inferences": [ + "manufacturing composition categories determine RAES authority", + "a simulation, model, shadow, and synchronized twin are interchangeable", + "composition alone proves synchronization or fidelity" + ], + "raes_consequence": "Use topology as an explicit profile coordinate without importing manufacturing semantics.", + "nonclaims": [ + "RAES does not claim ISO 23247 conformance.", + "A mixed cyber range is not automatically a digital twin." + ], + "empirical_result_boundary": "not-applicable" + }, + { + "id": "digital-twin-consortium", + "title": "Digital Twin Consortium definition", + "kind": "industry definition", + "edition_or_version": "official definition, accessed 2026-07-31", + "primary_url": "https://www.digitaltwinconsortium.org/initiatives/the-definition-of-a-digital-twin/", + "stronger_dimension": "", + "adopted_lessons": [ + "state synchronization frequency and fidelity", + "distinguish a synchronized twin from a prototype or model", + "bind interaction with real entities" + ], + "rejected_inferences": [ + "any simulation is a digital twin", + "closed-loop interaction is implicit", + "synchronization frequency proves semantic validity" + ], + "raes_consequence": "Treat loop posture, synchronization, fidelity, and evidence as independent declared coordinates.", + "nonclaims": [ + "Issue 813 does not create a digital-twin product claim.", + "A digital-twin label is not realization evidence." + ], + "empirical_result_boundary": "not-applicable" + }, + { + "id": "ieee-1730.1", + "title": "DSEEP multi-architecture overlay", + "kind": "recommended practice", + "edition_or_version": "IEEE 1730.1-2023", + "primary_url": "https://standards.ieee.org/ieee/1730.1/11140/", + "stronger_dimension": "The recommended practice treats multi-architecture integration as a separate engineering process with architecture-specific inputs and outcomes.", + "adopted_lessons": [ + "make multi-architecture issues explicit", + "separate engineering process from runtime protocol", + "record architecture-specific risks and outcomes" + ], + "rejected_inferences": [ + "following a process establishes interoperability", + "DIS, HLA, and TENA semantics are interchangeable" + ], + "raes_consequence": "Create dependency-ordered semantic, contract, trial, runtime, backend, evaluation, and documentation packages.", + "nonclaims": [ + "Issue 813 does not claim DSEEP compliance.", + "Process conformance is not mixed-runtime evidence." + ], + "empirical_result_boundary": "not-applicable" + }, + { + "id": "siso-sirl", + "title": "Simulation Interoperability Readiness Levels", + "kind": "consensus standard and guide", + "edition_or_version": "SISO-STD-024-2024 and SISO-GUIDE-011-2024", + "primary_url": "https://www.sisostandards.org/page/StandardsProducts", + "stronger_dimension": "SIRL supplies an evidence-based readiness-risk assessment discipline before integration.", + "adopted_lessons": [ + "assess evidence availability before integration", + "separate readiness risk from actual interoperability", + "require documentation and engineering evidence" + ], + "rejected_inferences": [ + "a readiness level declares systems interoperable", + "documentation replaces actual integration evidence" + ], + "raes_consequence": "Report interoperability readiness as a separate bounded relation and retain actual demonstration evidence.", + "nonclaims": [ + "No SIRL score is assigned by issue 813.", + "Readiness is not conformance or equivalence." + ], + "empirical_result_boundary": "not-applicable" + }, + { + "id": "w3c-prov", + "title": "W3C PROV overview", + "kind": "web standard", + "edition_or_version": "W3C Recommendation family", + "primary_url": "https://www.w3.org/TR/prov-overview/", + "stronger_dimension": "", + "adopted_lessons": [ + "separate entities, activities, and agents", + "record derivation and responsibility", + "retain version and generation relationships" + ], + "rejected_inferences": [ + "RAES needs a second provenance object model", + "a provenance graph proves reproducibility" + ], + "raes_consequence": "Reuse experiment, associated-artifact, realization, and evidence contracts with explicit derivation links.", + "nonclaims": [ + "No PROV interchange schema is added.", + "Provenance completeness is profile-bound." + ], + "empirical_result_boundary": "not-applicable" + }, + { + "id": "ro-crate", + "title": "RO-Crate specification", + "kind": "research data packaging specification", + "edition_or_version": "RO-Crate 1.2", + "primary_url": "https://www.researchobject.org/ro-crate/specification/1.2/", + "stronger_dimension": "", + "adopted_lessons": [ + "package research artifacts with contextual metadata", + "bind files, software, people, and actions", + "support portable reproduction bundles" + ], + "rejected_inferences": [ + "a package proves the experiment was reproduced", + "RAES needs an RO-Crate schema without an interchange requirement" + ], + "raes_consequence": "Use existing bundle, run, evidence, and associated-artifact patterns and leave external packaging to a later explicit requirement.", + "nonclaims": [ + "No RO-Crate compatibility is delivered.", + "Packaging is not independent reproduction." + ], + "empirical_result_boundary": "not-applicable" + } + ], + "composition_profile": { + "profile_id": "mixed-cross-backend-participant-control-v1", + "revision": "rev1", + "composition_modes": [ + "alternative-realization", + "simultaneous-mixed-realization" + ], + "realization_forms": [ + "simulation", + "emulation-or-operational", + "hardware-or-native", + "federated-composition" + ], + "allocation_units": [ + "participant-runtime", + "controlled-scope", + "action-family", + "observation-source", + "crossing-boundary" + ], + "portable_sdl_backend_neutral": true, + "allocation_authority": "admitted-experiment-and-trial-intent", + "runtime_fallback_outside_allocation": "reject", + "topology_classes": [ + "single-component", + "integrated", + "unified", + "federated-or-bridged", + "nested" + ], + "boundary_required_fields": [ + "source-component-ref", + "destination-component-ref", + "adapter-ref", + "authority-ref", + "action-or-observation-mapping-ref", + "participant-audience-policy-ref", + "release-or-declassification-basis-ref", + "time-mapping-ref", + "required-support-strength", + "mapping-loss", + "failure-behavior", + "evidence-refs" + ], + "unknown_or_missing_boundary_behavior": "reject-or-explicitly-unsupported", + "authority_model": { + "acting_controller_cardinality": "exactly-one-per-participant-episode-rev1", + "hla_ownership_is_controller_authority": false, + "backend_responsibility_is_action_admission": false, + "routing_is_disclosure_authority": false, + "multi_controller_status": "not-supported-in-rev1", + "lease_status": "not-supported-in-rev1", + "joint_or_fused_control_status": "not-supported-in-rev1", + "future_profile_requirements": [ + "controller-and-scope-identities", + "arbitration-quorum-priority-or-unanimity", + "lease-renewal-expiry-and-fencing", + "atomic-transition-and-stale-state-semantics", + "clock-and-order-authority", + "failure-livelock-and-oscillation-semantics", + "evidence-and-conformance" + ], + "distinct_relations": [ + "participant-identity", + "acting-controller", + "authority-basis-and-scope", + "action-admission", + "backend-realization-responsibility", + "hla-object-or-attribute-ownership", + "delivery-addressing", + "participant-disclosure-authority" + ] + } + }, + "trial_realization_profile": { + "profile_id": "mixed-realization-trial-schedule-v1", + "revision": "rev1", + "inter_trial_change": "linked-new-plan-entry-and-run", + "within_run_change": "finite-pre-admitted-phase-schedule", + "all_phase_apparatus_pinned_before_execution": true, + "all_phase_boundaries_and_mappings_pinned_before_execution": true, + "late_unadmitted_join": "reject", + "runtime_fact_changes_allocation": false, + "scheduler_changes_allocation": false, + "history_and_participant_knowledge": "append-only", + "trial_identity_rewritten_by_phase_change": false, + "phase_change_evidence": [ + "prior-and-next-phase", + "governed-order", + "active-membership", + "controller-and-authority-cut", + "clock-mapping", + "policy-cut", + "mapping-loss", + "commit-and-failure" + ] + }, + "open_closed_axes": [ + { + "id": "control-loop", + "values": [ + "open-loop", + "closed-loop" + ], + "authority_owner": "experiment-protocol-plus-participant-control-policy", + "adoption": "adopt as an explicit profile coordinate; closed-loop actuation still requires ordinary action authority and admission" + }, + { + "id": "world-assumption", + "values": [ + "closed-world", + "bounded-open-world" + ], + "authority_owner": "semantic-profile-and-experiment-assumptions", + "adoption": "adopt only as a declared assumption about unknown entities, actions, observations, and mappings; it never widens a closed vocabulary" + }, + { + "id": "federation-membership", + "values": [ + "fixed", + "pre-admitted-dynamic" + ], + "authority_owner": "admitted-trial-phase-schedule", + "adoption": "adopt finite pre-admitted joins and leaves; reject unadmitted dynamic membership" + } + ], + "time_and_order_profile": { + "profile_id": "mixed-composition-time-and-order-v1", + "revision": "rev1", + "cross_clock_mapping_required": true, + "timestamp_only_strength": "disclosed-weak", + "unmapped_clock_relation": "partial-or-unknown", + "backend_serialized_requires_readback": true, + "rollback_or_retraction_erases_delivery": false, + "required_service_evidence": [ + "clock-identity-and-authority", + "time-domain", + "regulating-or-constrained-role", + "lookahead", + "advance-request-and-grant", + "delivery-order", + "serialization-service", + "runtime-readback", + "conformance-result" + ], + "staleness_coordinates": [ + "controller", + "authority", + "capability", + "policy-revision", + "state-revision", + "history-head", + "governed-order" + ] + }, + "distribution_and_security_profile": { + "profile_id": "mixed-composition-distribution-security-v1", + "revision": "rev1", + "publish_subscribe_authorizes_disclosure": false, + "ddm_establishes_ifc": false, + "directed_delivery_is_participant_observation": false, + "filtering_occurs_after_raes_authorization": true, + "audit_audience_is_participant_audience": false, + "metadata_leakage_surface": [ + "membership", + "subscription", + "object-or-interaction-class", + "region-or-destination", + "message-size", + "timing", + "synchronization", + "ownership-change", + "retraction", + "delivery-failure" + ], + "final_effect_boundary": "commit-exact-authority-policy-time-and-allocation-cut-before-backend-call-or-disclosure", + "failed_commit_effect": "zero-prohibited-effects" + }, + "demonstration_protocol": { + "protocol_id": "cross-backend-participant-control-demonstration-v1", + "revision": "rev1", + "same_authored_policy_digest_required": true, + "reporting_relations_are_distinct": [ + "bounded-conformance", + "interoperability-readiness", + "empirical-sim-to-em-transfer", + "trace-inclusion", + "bisimulation", + "ifc-or-noninterference", + "backend-equivalence" + ], + "cases": [ + { + "id": "pure-simulation", + "composition": "one simulated cyber-agent environment", + "boundary": "authored policy through simulated adapter", + "expected_disposition": "bounded-realization-or-explicit-weakening", + "required_evidence": [ + "scenario-and-policy-digests", + "trial-and-run-identity", + "apparatus-and-adapter-identities", + "capability-and-conformance", + "allocation-and-topology", + "time-and-order", + "mapping-loss-and-limitations" + ], + "denial_requires_zero_prohibited_effects": false, + "nonclaims": [ + "No emulation transfer or backend equivalence." + ] + }, + { + "id": "pure-emulation-or-operational", + "composition": "one emulation or operational RuntimeTarget", + "boundary": "authored policy through operational adapter", + "expected_disposition": "bounded-realization-or-explicit-weakening", + "required_evidence": [ + "scenario-and-policy-digests", + "trial-and-run-identity", + "apparatus-and-adapter-identities", + "capability-and-conformance", + "allocation-and-topology", + "time-and-order", + "mapping-loss-and-limitations" + ], + "denial_requires_zero_prohibited_effects": false, + "nonclaims": [ + "No native realization beyond the observed operations." + ] + }, + { + "id": "simultaneous-mixed", + "composition": "simulated and emulated or operational components in one run", + "boundary": "explicit mixed topology edge", + "expected_disposition": "admit-only-with-complete-edge-mappings", + "required_evidence": [ + "scenario-and-policy-digests", + "trial-and-run-identity", + "apparatus-and-adapter-identities", + "capability-and-conformance", + "allocation-and-topology", + "time-and-order", + "mapping-loss-and-limitations" + ], + "denial_requires_zero_prohibited_effects": true, + "nonclaims": [ + "Mixed membership is not semantic equivalence." + ] + }, + { + "id": "inter-trial-transition", + "composition": "linked simulation then emulation or operational runs", + "boundary": "new admitted plan entry and run identity", + "expected_disposition": "new-run-with-source-lineage", + "required_evidence": [ + "scenario-and-policy-digests", + "trial-and-run-identity", + "apparatus-and-adapter-identities", + "capability-and-conformance", + "allocation-and-topology", + "time-and-order", + "mapping-loss-and-limitations" + ], + "denial_requires_zero_prohibited_effects": false, + "nonclaims": [ + "Linked trials are not one continuous world." + ] + }, + { + "id": "pre-admitted-phase-transition", + "composition": "finite within-run membership change", + "boundary": "phase transition with all components pinned", + "expected_disposition": "append-transition-or-fail-before-effect", + "required_evidence": [ + "scenario-and-policy-digests", + "trial-and-run-identity", + "apparatus-and-adapter-identities", + "capability-and-conformance", + "allocation-and-topology", + "time-and-order", + "mapping-loss-and-limitations" + ], + "denial_requires_zero_prohibited_effects": true, + "nonclaims": [ + "Pre-admitted phase change does not permit arbitrary late join." + ] + }, + { + "id": "open-loop", + "composition": "observation or replay without external actuation", + "boundary": "participant observation and evidence boundary", + "expected_disposition": "observe-without-action-authority", + "required_evidence": [ + "scenario-and-policy-digests", + "trial-and-run-identity", + "apparatus-and-adapter-identities", + "capability-and-conformance", + "allocation-and-topology", + "time-and-order", + "mapping-loss-and-limitations" + ], + "denial_requires_zero_prohibited_effects": true, + "nonclaims": [ + "Open-loop observation grants no actuation authority." + ] + }, + { + "id": "closed-loop", + "composition": "observation followed by governed external intervention", + "boundary": "final admitted action and external effect", + "expected_disposition": "commit-before-authorized-effect", + "required_evidence": [ + "scenario-and-policy-digests", + "trial-and-run-identity", + "apparatus-and-adapter-identities", + "capability-and-conformance", + "allocation-and-topology", + "time-and-order", + "mapping-loss-and-limitations" + ], + "denial_requires_zero_prohibited_effects": true, + "nonclaims": [ + "Closed-loop posture does not bypass action admission." + ] + }, + { + "id": "stale-handoff", + "composition": "approval resolved before controller transition", + "boundary": "revision-fenced control and action admission", + "expected_disposition": "deny-stale", + "required_evidence": [ + "scenario-and-policy-digests", + "trial-and-run-identity", + "apparatus-and-adapter-identities", + "capability-and-conformance", + "allocation-and-topology", + "time-and-order", + "mapping-loss-and-limitations" + ], + "denial_requires_zero_prohibited_effects": true, + "nonclaims": [ + "A prior approval is not current authority." + ] + }, + { + "id": "concurrent-intervention", + "composition": "two interventions race at one participant cut", + "boundary": "state revision and history-head compare-and-swap", + "expected_disposition": "one-commit-or-both-denied-never-two-authorities", + "required_evidence": [ + "scenario-and-policy-digests", + "trial-and-run-identity", + "apparatus-and-adapter-identities", + "capability-and-conformance", + "allocation-and-topology", + "time-and-order", + "mapping-loss-and-limitations" + ], + "denial_requires_zero_prohibited_effects": true, + "nonclaims": [ + "Interleaving is not joint control." + ] + }, + { + "id": "unsupported-or-false-capability", + "composition": "adapter lacks or falsely declares a required service", + "boundary": "API-407 effective support and conformance", + "expected_disposition": "deny-unsupported-or-fail-conformance", + "required_evidence": [ + "scenario-and-policy-digests", + "trial-and-run-identity", + "apparatus-and-adapter-identities", + "capability-and-conformance", + "allocation-and-topology", + "time-and-order", + "mapping-loss-and-limitations" + ], + "denial_requires_zero_prohibited_effects": true, + "nonclaims": [ + "Declaration is not realization." + ] + }, + { + "id": "timestamp-only-or-unmapped-order", + "composition": "components expose timestamps without governed order", + "boundary": "cross-clock mapping and order admission", + "expected_disposition": "disclosed-weak-or-reject-exact-order", + "required_evidence": [ + "scenario-and-policy-digests", + "trial-and-run-identity", + "apparatus-and-adapter-identities", + "capability-and-conformance", + "allocation-and-topology", + "time-and-order", + "mapping-loss-and-limitations" + ], + "denial_requires_zero_prohibited_effects": false, + "nonclaims": [ + "Timestamp order is not causal or governed order." + ] + }, + { + "id": "simulation-only-observation", + "composition": "simulation exposes a field absent from emulation", + "boundary": "participant observation mapping", + "expected_disposition": "record-mismatch-and-block-parity-claim", + "required_evidence": [ + "scenario-and-policy-digests", + "trial-and-run-identity", + "apparatus-and-adapter-identities", + "capability-and-conformance", + "allocation-and-topology", + "time-and-order", + "mapping-loss-and-limitations" + ], + "denial_requires_zero_prohibited_effects": false, + "nonclaims": [ + "Common field names do not establish equivalent observations." + ] + }, + { + "id": "unrealizable-action", + "composition": "abstract action lacks an operational mapping", + "boundary": "transformed proposal revalidation and admission", + "expected_disposition": "deny-unrealizable", + "required_evidence": [ + "scenario-and-policy-digests", + "trial-and-run-identity", + "apparatus-and-adapter-identities", + "capability-and-conformance", + "allocation-and-topology", + "time-and-order", + "mapping-loss-and-limitations" + ], + "denial_requires_zero_prohibited_effects": true, + "nonclaims": [ + "Simulation admission cannot be reused after adapter transformation." + ] + }, + { + "id": "directed-delivery-failure", + "composition": "directed inject is misaddressed or undeliverable", + "boundary": "DSL-142 identity through API-423 delivery and observation", + "expected_disposition": "record-failed-delivery-without-observation", + "required_evidence": [ + "scenario-and-policy-digests", + "trial-and-run-identity", + "apparatus-and-adapter-identities", + "capability-and-conformance", + "allocation-and-topology", + "time-and-order", + "mapping-loss-and-limitations" + ], + "denial_requires_zero_prohibited_effects": true, + "nonclaims": [ + "Addressed or attempted delivery is not observation." + ] + }, + { + "id": "prior-delivery-retraction", + "composition": "policy conceals or retracts after prior delivery", + "boundary": "append-only participant and crossing histories", + "expected_disposition": "append-retraction-without-erasing-knowledge", + "required_evidence": [ + "scenario-and-policy-digests", + "trial-and-run-identity", + "apparatus-and-adapter-identities", + "capability-and-conformance", + "allocation-and-topology", + "time-and-order", + "mapping-loss-and-limitations" + ], + "denial_requires_zero_prohibited_effects": false, + "nonclaims": [ + "Retraction cannot undo participant knowledge." + ] + }, + { + "id": "bridge-metadata-leakage", + "composition": "payload is filtered but bridge metadata varies", + "boundary": "participant and auditor projection over bridge facts", + "expected_disposition": "record-leakage-or-prove-bounded-projection", + "required_evidence": [ + "scenario-and-policy-digests", + "trial-and-run-identity", + "apparatus-and-adapter-identities", + "capability-and-conformance", + "allocation-and-topology", + "time-and-order", + "mapping-loss-and-limitations" + ], + "denial_requires_zero_prohibited_effects": false, + "nonclaims": [ + "Payload filtering is not metadata noninterference." + ] + } + ] + }, + "requirement_dispositions": [ + { + "uid": "SEM-234", + "title": "Mixed Cross-Backend Participant-Control Composition", + "disposition": "new", + "status": "DRAFT", + "ground_control_id": "38d807a4-ff50-4f9f-99a0-09e3ee3cdaa2", + "scope": "alternative and simultaneous mixed realization, allocation, topology, authority separation, temporal coupling, trial phases, open/closed axes, loss, and fail-closed admission", + "rationale": "No incumbent defines one admitted trial containing multiple participant realization providers and explicit composition boundaries." + }, + { + "uid": "ASR-537", + "title": "Cross-Backend Participant-Control Realization and Transfer Evidence", + "disposition": "new", + "status": "DRAFT", + "ground_control_id": "b425b452-a796-4997-a29f-3432baa6496a", + "scope": "pure and mixed demonstration, staged transfer, apparatus/provenance binding, mismatch, zero-effect, uncertainty, and claim separation", + "rationale": "Paired runs, interfaces, and capability declarations do not establish simultaneous mixed realization or transfer." + }, + { + "uid": "SEM-230", + "disposition": "reuse", + "scope": "participant and audience projection, exact-cut policy, memory, release, strategies, and noninterference boundary", + "rationale": "Mixed composition routes an authorized projection; it does not define a second participant world." + }, + { + "uid": "SCE-002", + "disposition": "extend-downstream", + "scope": "scenario-family selection, deterministic trial admission, apparatus pinning, immutable plan and run identity", + "rationale": "Downstream work must add mixed allocation and finite phase schedules without creating a second trial lifecycle." + }, + { + "uid": "API-407", + "disposition": "extend-downstream", + "scope": "declared and effective backend feature strength, constraints, downgrade, realization, and conformance", + "rationale": "Mixed services need governed capability terms and evidence, not a parallel manifest block." + }, + { + "uid": "API-423", + "disposition": "reuse", + "scope": "typed request, decision, transformation, delivery, observation, audit, context, and order crossings", + "rationale": "Composition edges use existing crossing carriers and add no generic federation event." + }, + { + "uid": "RUN-310", + "disposition": "reuse-and-extend-downstream", + "scope": "authenticated control operations, revision-fenced handoff, idempotency, persistence, and replay", + "rationale": "Mixed providers do not change the initial single acting-controller authority." + }, + { + "uid": "RUN-319", + "disposition": "extend-downstream", + "scope": "reference crossing mediation and atomic decision-before-effect boundary", + "rationale": "Mixed dispatch must reuse the existing final mediation seam." + }, + { + "uid": "ASR-535", + "disposition": "reuse", + "scope": "bounded participant-flow assurance, relation claim binding, finite falsification, and overclaim prevention", + "rationale": "ASR-537 adds mixed realization and transfer variables without merging assurance axes." + } + ], + "implementation_issues": [ + { + "key": "semantic-authority", + "issue_number": 1013, + "title": "Define mixed cross-backend participant-control semantics", + "milestone": "Participant Information-Flow & Behavioral Equivalence", + "requirements": [ + "SEM-234", + "SEM-230", + "SCE-002", + "API-423", + "RUN-310" + ], + "dependencies": [], + "bounded_outcome": "Publish the revisioned profile and invariants.", + "negative_cases": [ + "authority conflation", + "unadmitted membership", + "identity rewriting" + ], + "evidence_required": [ + "formal profile", + "worked examples", + "counterexamples" + ], + "explicit_nonclaims": [ + "no contracts", + "no runtime", + "no multi-controller revision-1 support" + ] + }, + { + "key": "portable-composition-contracts", + "issue_number": 1014, + "title": "Publish portable mixed-composition contracts", + "milestone": "Participant Information-Flow & Behavioral Equivalence", + "requirements": [ + "SEM-234", + "SCE-002", + "API-407", + "API-423" + ], + "dependencies": [ + "semantic-authority" + ], + "bounded_outcome": "Publish closed composition, allocation, phase, time-mapping, loss, and evidence contracts.", + "negative_cases": [ + "open metadata authority", + "duplicate trial identity", + "unresolved references" + ], + "evidence_required": [ + "schemas and fixtures", + "context validation", + "generator parity" + ], + "explicit_nonclaims": [ + "schema presence is not realization", + "contract validity is not equivalence" + ] + }, + { + "key": "trial-admission", + "issue_number": 1015, + "title": "Admit mixed and staged participant trial realizations", + "milestone": "Participant Information-Flow & Behavioral Equivalence", + "requirements": [ + "SEM-234", + "SCE-002", + "API-407" + ], + "dependencies": [ + "portable-composition-contracts" + ], + "bounded_outcome": "Compile immutable schedule-independent mixed allocations and finite phase schedules.", + "negative_cases": [ + "runtime fallback", + "partial plan", + "unadmitted phase", + "apparatus drift" + ], + "evidence_required": [ + "deterministic compiler tests", + "admission failures", + "lineage and cleanup" + ], + "explicit_nonclaims": [ + "no live mixed execution", + "no scheduler semantic authority" + ] + }, + { + "key": "runtime-coordination", + "issue_number": 1016, + "title": "Coordinate mixed participant runtimes fail-closed", + "milestone": "Participant Information-Flow & Behavioral Equivalence", + "requirements": [ + "SEM-234", + "RUN-310", + "RUN-319", + "API-423" + ], + "dependencies": [ + "portable-composition-contracts", + "trial-admission" + ], + "bounded_outcome": "Resolve and commit the exact mixed boundary cut before backend effect or disclosure.", + "negative_cases": [ + "adapter bypass", + "stale authority", + "failed commit effect", + "history erasure" + ], + "evidence_required": [ + "real-boundary tests", + "zero-effect assertions", + "append-only histories" + ], + "explicit_nonclaims": [ + "reference coordination is not backend-native realization", + "no multi-controller claim" + ] + }, + { + "key": "backend-capability-and-conformance", + "issue_number": 1017, + "title": "Conform mixed-composition backend capabilities", + "milestone": "Backend Contract & Conformance", + "requirements": [ + "SEM-234", + "ASR-537", + "API-407", + "API-423", + "ASR-535" + ], + "dependencies": [ + "portable-composition-contracts", + "runtime-coordination" + ], + "bounded_outcome": "Declare, resolve, probe, and report mixed backend services at exact support strengths.", + "negative_cases": [ + "method presence claim", + "timestamp-only exact order", + "DDM as IFC", + "false capability" + ], + "evidence_required": [ + "support-strength tests", + "runtime readback", + "false-declaration probes" + ], + "explicit_nonclaims": [ + "conformance is not transfer or equivalence", + "no default external wire compatibility" + ] + }, + { + "key": "demonstration-and-evaluation", + "issue_number": 1018, + "title": "Demonstrate mixed cross-backend participant control", + "milestone": "Participant Information-Flow & Behavioral Equivalence", + "requirements": [ + "ASR-537", + "SEM-234", + "ASR-535" + ], + "dependencies": [ + "trial-admission", + "runtime-coordination", + "backend-capability-and-conformance" + ], + "bounded_outcome": "Run the pure, mixed, staged, open/closed, and adversarial protocol with reproducible evidence.", + "negative_cases": [ + "sim-only observation", + "unrealizable action", + "ordering mismatch", + "metadata leak", + "prohibited denial effect" + ], + "evidence_required": [ + "apparatus and provenance", + "raw and derived results", + "zero-effect and reproduction records" + ], + "explicit_nonclaims": [ + "bounded transfer is not universal transfer", + "passing cases are not equivalence" + ] + }, + { + "key": "documentation-and-claims", + "issue_number": 1019, + "title": "Reconcile mixed participant-control claims", + "milestone": "Participant Information-Flow & Behavioral Equivalence", + "requirements": [ + "SEM-234", + "ASR-537", + "ASR-535" + ], + "dependencies": [ + "runtime-coordination", + "backend-capability-and-conformance", + "demonstration-and-evaluation" + ], + "bounded_outcome": "Publish only the exact implemented and evidenced profiles, results, limits, and residual gaps.", + "negative_cases": [ + "DRAFT reported as implemented", + "two separate runs reported as mixed", + "assurance-axis promotion" + ], + "evidence_required": [ + "reconciled traceability", + "runtime, backend, evaluation, and reproduction records", + "claim-policy validation" + ], + "explicit_nonclaims": [ + "no claim beyond exact profiles", + "no universal equivalence, IFC, or transfer" + ] + } + ], + "claim_boundaries": { + "issue_813": "design-authority-and-implementation-program-only", + "mixed_runtime_implementation": "not-established", + "backend_realization": "not-established", + "cross_backend_equivalence": "not-established", + "ifc_or_noninterference": "not-established", + "universal_sim_to_em_transfer": "not-established", + "multi_controller_or_lease_support": "not-supported-in-rev1", + "default_external_wire_compatibility": "not-established" + } +} diff --git a/docs/research/cross-backend-participant-control/implementation-program.md b/docs/research/cross-backend-participant-control/implementation-program.md new file mode 100644 index 000000000..8bd9b53f0 --- /dev/null +++ b/docs/research/cross-backend-participant-control/implementation-program.md @@ -0,0 +1,118 @@ +# Mixed Cross-Backend Participant-Control Implementation Program + +Date: 2026-07-31 + +Parent issue: [#813](https://github.com/OpenRAE/rae/issues/813) + +Participant milestone: `Participant Information-Flow & Behavioral Equivalence` + +Backend coordination milestone: `Backend Contract & Conformance` + +The machine-readable authority is +[`implementation-program.json`](implementation-program.json). + +## Definition delivered by issue 813 + +Issue #813 delivers ADR-102, the edition-pinned primary-source assessment, +current-state gap analysis, SEM-234 composition profile, ASR-537 demonstration +protocol, two canonical DRAFT requirements, and the dependency-ordered +program. + +It does not publish wire contracts, change trial admission or runtime +behavior, certify a backend, execute the demonstration, support multiple +acting controllers, or establish interoperability, transfer, +IFC/noninterference, trace inclusion, bisimulation, or backend equivalence. + +## Dependency graph + +```text +#1013 semantic authority + | + v +#1014 portable contracts + | \ + | v + | #1015 trial admission + | | + +---+----+ + | | + v | + #1016 runtime + | | + +----+ + | + v + #1017 backend capability/conformance + | + v + #1018 demonstration/evaluation + \ | / + \ | / + \|/ + #1019 documentation/claims +``` + +#1017 also depends directly on #1014. #1018 depends on #1015, #1016, and +#1017. #1019 depends on #1016, #1017, and #1018. + +## Work packages + +### #1013: Semantic authority + +Publish the revisioned allocation, topology, authority, time, policy, +trial/phase, open/closed, loss, and failure invariants. Revision 1 retains one +acting controller. + +### #1014: Portable composition contracts + +Publish closed profile, allocation, edge, phase, time-mapping, loss, and +evidence bindings through existing contract families and schema governance. + +### #1015: Trial admission + +Deterministically compile and seal multiple components, allocation, topology, +clock/policy mappings, and finite phases. Preserve SDL neutrality, identity, +random streams, isolation, and cleanup. + +### #1016: Runtime coordination + +Resolve the exact controller/authority/policy/allocation/time cut, commit +before effect, dispatch only to the admitted provider, and append every +transition, weakening, and failure. + +### #1017: Backend capability and conformance + +Extend API-407 and existing conformance surfaces with mixed services and +runtime readback. This generic backend work is coordinated in milestone 61. + +### #1018: Demonstration and evaluation + +Run pure, mixed, staged, open/closed, and adversarial cases with complete +apparatus/provenance and independent reproduction. + +### #1019: Documentation and claims + +Only after runtime, backend, and evaluation evidence exists, reconcile +scientific completeness, assurance, lineage, related work, public guidance, +and residual gaps. + +## Program invariants + +- Both alternative and simultaneous mixed realization are first-class. +- Portable SDL remains backend-neutral. +- Allocation uses stable compiled refs and no implicit fallback. +- Every edge binds authority, mapping, policy, time/order, support, loss, + failure, and evidence. +- Multiple providers do not become multiple controllers. +- HLA ownership, backend responsibility, action admission, and participant + control remain separate. +- Routing and filtering do not authorize disclosure or establish IFC. +- Timestamps alone do not establish governed order. +- Inter-trial changes use new run identities; within-run changes are finite and + pre-admitted. +- Control loop, world assumption, and federation membership are separate + open/closed axes. +- Denied authority, policy, mapping, admission, and commit cases have zero + prohibited effects. +- Conformance, readiness, transfer, trace inclusion, bisimulation, + IFC/noninterference, and equivalence remain separate. diff --git a/docs/research/cross-backend-participant-control/index.md b/docs/research/cross-backend-participant-control/index.md new file mode 100644 index 000000000..469bc2909 --- /dev/null +++ b/docs/research/cross-backend-participant-control/index.md @@ -0,0 +1,33 @@ +# Mixed Cross-Backend Participant Control + +Issue [#813](https://github.com/OpenRAE/rae/issues/813) defines how one +backend-neutral participant-control policy can be: + +- realized alternatively in simulation or emulation/operation; +- composed across simulated and emulated/operational components in one trial; + and +- varied across linked trials or a finite pre-admitted within-run phase + schedule. + +This delivery adopts the composition and evidence lessons from distributed +simulation, cyber ranges, co-simulation, LVC, and digital twins without adding +an HLA wire model, federation framework, or backend choice to SDL. + +- [Architecture preflight](../../decisions/issue-813-cross-backend-participant-control-preflight.md) +- [ADR-102](../../decisions/adrs/adr-102-mixed-cross-backend-participant-control.md) +- [Prior art and design criteria](prior-art-and-design-criteria.md) +- [Current-state assessment](current-state-assessment.md) +- [Composition architecture](composition-architecture.md) +- [Demonstration protocol](demonstration-protocol.md) +- [Requirement disposition](requirement-disposition.md) +- [Implementation program](implementation-program.md) +- [Machine-readable program](implementation-program.json) +- [Formal SEM-234 and ASR-537 design](../../../specs/formal/participant-semantics/cross-backend-participant-control.md) + +SEM-234 and ASR-537 are DRAFT. Issues #1013 through #1019 own the +dependency-ordered implementation and evidence program. + +Issue #813 does not implement a mixed runtime, certify a backend, or report a +transfer or equivalence result. Revision 1 keeps exactly one acting controller +per participant and episode. Multiple realization providers are not multiple +controllers. diff --git a/docs/research/cross-backend-participant-control/prior-art-and-design-criteria.md b/docs/research/cross-backend-participant-control/prior-art-and-design-criteria.md new file mode 100644 index 000000000..752a1e68e --- /dev/null +++ b/docs/research/cross-backend-participant-control/prior-art-and-design-criteria.md @@ -0,0 +1,460 @@ +# Cross-Backend Participant Control: Prior Art and Design Criteria + +Date: 2026-07-31 + +This assessment asks a narrower question than general simulation +interoperability: + +> What authority, composition, time, policy, and evidence must survive when +> the same participant-control intent is realized in simulation, +> emulation/operation, or both within one admitted trial? + +It distinguishes mechanism, semantic authority, security policy, conformance, +empirical transfer, and proof. A common interface or successful run is never +promoted into a stronger relation. + +The machine-readable source disposition is in +[`implementation-program.json`](implementation-program.json). + +## 1. HLA 4 and the IEEE 1516 family + +The current family is: + +- [IEEE 1516-2025](https://standards.ieee.org/ieee/1516/6687/) for the + framework and rules; +- [IEEE 1516.1-2025](https://standards.ieee.org/ieee/1516.1/6688/) for the + federate interface; and +- [IEEE 1516.2-2025](https://standards.ieee.org/ieee/1516.2/6689/) for the + Object Model Template. + +The 2025 edition matters. Earlier RAES literature work cited the 2010 family. +Edition pinning is necessary because directed interactions and migration +details belong to newer HLA 4 work and must not be attributed to an older +standard. + +### Services worth adopting as precedents + +HLA separates concerns that a mixed RAES profile must also keep distinct: + +- federation membership and synchronization; +- declaration and publish/subscribe; +- object instances, interactions, and attribute updates; +- data distribution and interest management; +- object/attribute ownership; +- directed interaction delivery; +- receive-order and timestamp-order delivery; and +- logical-time advancement, grants, and lookahead. + +The +[HLA 4 migration analysis](https://www.sisostandards.org/resource/resmgr/events/siw/2024_siw/abstracts_2024_siw.pdf) +also describes staged deployment where earlier and newer federates coexist. +That is useful precedent for versioned capability negotiation and migration. + +HLA ownership is materially stronger than current RAES realization machinery +in one dimension: it standardizes scoped responsibility transfer for +attributes of a simulated object. Ownership can be partial, transferred, or +unowned. Negotiated and unconditional divestiture and push/pull acquisition +produce visible service outcomes. + +RAES should adopt the transition-state lesson: + +```text +requested -> offered -> pending -> committed + \-> failed | expired | cancelled | stale +``` + +The participant-control join stays different: + +```text +participant + -> acting controller + -> authority basis and scope + -> action admission + -> realization provider + -> backend effect +``` + +An HLA owner is responsible for publishing state for an attribute. That does +not identify who may direct a participant or authorize an action. + +### Explicit rejections + +- OMT standardizes representation and syntax, not domain content or + behavioral equivalence. +- Declaration and DDM route data. They do not authorize a participant + projection. +- Directed interaction selects a delivery target. It does not prove + successful delivery or participant observation. +- RTI authorization, transport encryption, and federation membership are not + RAES markings, declassification, IFC, or noninterference. +- HLA conformance does not imply that a backend realizes SEM-234. + +### RAES consequences + +- Capability entries name the exact HLA service and edition. +- Ownership and time services produce runtime readback and conformance + evidence, not method-presence claims. +- Adapter transformations re-enter normal action/observation validation. +- HLA-specific handles and FOM fields stay behind the adapter boundary unless + a future external-interchange requirement justifies a portable carrier. + +## 2. NIST integrated federations and UCEF + +NIST's +[integrated HLA federation work](https://www.nist.gov/publications/integrating-multiple-hla-federations-effective-simulation-based-evaluations-cps) +starts from limits of a single flat federation. The paper identifies: + +- information hiding; +- limited shared resources; +- multiple time scales; +- organizational and IT policy boundaries; and +- translation across federations. + +It evaluates shared-federate, parallel-connected, hierarchical, and clustered +patterns. An inter-federation component may need separate threads and explicit +message/time translation. Two logical times do not necessarily have a valid +mapping. + +NIST's [UCEF architecture](https://www.nist.gov/ctl/smart-connected-systems-division/iot-devices-and-infrastructures-group/how-does-ucef-work) +explicitly integrates simulators, emulators, and hardware. A federate can be +equipment, a simulation model, or a combination. That is direct precedent for +requiring both OR and AND realization modes. + +The +[Portico TLS/forwarder work](https://www.nist.gov/publications/extending-portico-hla-federations-federations-transport-layer-security) +uses routing/firewall behavior to limit exchange across clusters. It remains a +transport and topology mechanism. + +### Metadata remains an information surface + +Payload hiding alone does not close: + +- membership; +- subscription and object/interaction class; +- region or destination; +- message size and cadence; +- synchronization and time requests; +- ownership change; +- retraction; or +- differential success and failure. + +RAES authorizes the participant/audience projection before bridge filtering. +The bridge may narrow the set. It cannot widen it. + +## 3. ACTING and EDL-FG + +The 2026 +[EDL-FG paper](https://arxiv.org/abs/2605.12170) separates: + +- technical infrastructure; +- scenario screenplay, storylines, events, and injects; +- expected participant actions; +- federation; +- telemetry and situational awareness; +- exercise assessment; +- capacity; and +- resource brokering. + +It explicitly describes hybrid simulated and emulated IT/OT component +abstractions. It also permits dynamic trainer modification. + +This is strong framing for mixed composition. The RAES mapping is: + +| EDL-FG concern | RAES incumbent | +| --- | --- | +| Scenario and screenplay | SDL, workflow/story, and scenario-family authority | +| Inject | Existing inject identity plus DSL-142 delivery | +| Participant interaction | Participant action/control plus API-423 crossing | +| Infrastructure | Apparatus manifests and admitted realization | +| Federation | Explicit topology and composition edges | +| Telemetry | Observation and evidence contracts | +| Assessment | Experiment, evaluation, run, evidence, and measure contracts | +| Capacity/brokering | Apparatus constraints and scheduling, not scenario meaning | + +EDL-FG is a recent project-backed paper, not yet a mature interoperability +standard. The paper identifies systematic quantitative evaluation and +validation as future work. RAES therefore adopts the separation and mixed +component lesson, not its schema or a semantic-equivalence claim. + +## 4. CybORG + +The [CybORG paper](https://arxiv.org/abs/2108.09118) and +[official repository](https://github.com/cage-challenge/CybORG) define a +common agent interface for simulation and emulation. A scenario supplies +backend-specific implementations of actions. + +The 2021 design selects simulation or emulation for a run. It is an OR +precedent, not evidence that components coexist in one world. + +The transfer experiment is especially important. Across 21 agents and ten +evaluations each, 139 of 210 emulation evaluations succeeded. Some failures +came from agents learning a simulation observation artifact that was absent +from emulation. + +That result establishes four rules for RAES: + +1. interface parity is not observation equivalence; +2. action names do not remove backend-specific preconditions/effects/failures; +3. mismatches must remain first-class evidence; and +4. a simulation admission result cannot authorize a transformed emulation + command without fresh validation and admission. + +## 5. CyGIL + +[CyGIL](https://arxiv.org/abs/2304.01244) combines: + +- CyGIL-E, an emulation environment operating on a real network; +- CyGIL-S, a simulator derived from emulation traces; and +- an iterative training and evaluation loop between them. + +It argues that abstract simulator actions can diverge from operational tools +and block transfer. A data-derived simulator approximates the +observation-transition model represented in its data. Unknown transitions +remain because coverage is incomplete. + +The paper reports a 50-of-50 emulation evaluation for one policy after its +iteration. It also reports that smaller data collection was insufficient, +switching rules were heuristic, and broader scenarios remain future work. + +The adoption is not “full transferability.” It is: + +- model/data/version provenance is part of the simulator identity; +- unknown transitions require an explicit disposition; +- emulation-to-simulation regeneration creates a new derived artifact; +- simulation-to-emulation evaluation creates a new run; and +- empirical transfer is bounded to its scenario, agent, apparatus, trials, + and measures. + +This motivates linked inter-trial realization changes. It does not require +pretending alternating runs are one trial. + +## 6. CyberBattleSim + +The +[official CyberBattleSim repository](https://github.com/microsoft/CyberBattleSim) +provides an abstract simulated enterprise network, action space, observation, +attacker/defender structure, and reward model. Its documentation emphasizes +that the environment is deliberately simplistic, emits no real network +traffic, and is not for direct application to real systems. + +Useful lessons: + +- action/observation vocabulary can remain safe and abstract; +- simulator fidelity limits must be visible; and +- simulated compromise “ownership” is a domain fact, not HLA ownership or + participant control. + +CyberBattleSim is suitable as one candidate simulated lane. It supplies no +emulation or transfer claim. + +## 7. FMI and HELICS + +[FMI 3.0.2](https://fmi-standard.org/docs/3.0.2/) distinguishes Model +Exchange, Co-Simulation, and Scheduled Execution. + +For co-simulation: + +- exchange happens at communication points; +- an importer controls synchronization; and +- the co-simulation algorithm is not part of FMI. + +For Scheduled Execution: + +- scheduling is externalized; and +- local priorities do not determine the cross-component global order. + +The lesson is exact: a shared package or interface does not supply composition +semantics. + +[HELICS timing guidance](https://docs.helics.org/en/latest/user-guide/fundamental_topics/timing_configuration.html) +uses time requests and grants. Its +[dynamic-federation guidance](https://docs.helics.org/en/latest/user-guide/advanced_topics/dynamic_federations.html) +supports late joining, including real-time and hardware-in-the-loop +components used during only part of a co-simulation. + +RAES adopts a bounded version: + +- all possible members, manifests, mappings, clocks, and policies are admitted + before execution; +- phase membership changes are finite and append-only; +- an unadmitted late join is rejected; and +- the runtime coordinator remains separate from participant controller + authority. + +## 8. LVC and synthetic-world composition + +The +[NATO modelling and simulation glossary](https://www.sto.nato.int/publications/Management%20Reports/AMSP-02-MSGlossaryofTerms.pdf) +defines LVC as a mixture of live, virtual, and constructive simulation. +Related NATO work also records inconsistent usage of the categories. + +That inconsistency makes labels unsafe as authority. A realization form needs: + +- a definition; +- apparatus identity; +- capability and support strength; +- mapping and loss; +- time/pacing behavior; +- participant/action/observation scope; and +- evidence. + +LVC is therefore a useful taxonomy and deployment precedent, not a portable +semantic relation. + +## 9. Digital twins + +The +[Digital Twin Consortium definition](https://www.digitaltwinconsortium.org/initiatives/the-definition-of-a-digital-twin/) +requires a data-driven virtual representation with synchronized interaction +at a specified frequency and fidelity. A prototype before synchronization is +not the same thing as a twin. + +Relevant ISO work includes: + +- [ISO 23247-2:2021](https://www.iso.org/standard/78743.html), reference + architecture; +- [ISO 23247-5:2026](https://www.iso.org/standard/87425.html), digital thread; + and +- [ISO 23247-6:2026](https://www.iso.org/standard/87426.html), composition. + +ISO 23247-6 distinguishes integrated, unified, and federated composition. +Those are useful topology coordinates. They do not determine participant +authority or turn a cyber range into a digital twin. + +RAES keeps these terms distinct: + +- digital model; +- digital shadow; +- synchronized digital twin; +- simulator; +- emulator; +- co-simulation; and +- mixed runtime composition. + +The design adopts synchronization, fidelity, topology, derivation, and +interaction as declared coordinates. It rejects “digital twin” as an +unevidenced backend label. + +## 10. DSEEP, SIRL, VV&A, and provenance + +[IEEE 1730.1-2023](https://standards.ieee.org/ieee/1730.1/11140/) overlays the +Distributed Simulation Engineering and Execution Process for environments +using multiple distributed-simulation architectures. + +[IEEE 1730.2-2022](https://standards.ieee.org/ieee/1730.2/7311/) supplies a +VV&A overlay. The earlier HLA-specific IEEE 1516.4 practice is inactive; the +current DSEEP overlay is the relevant active source. + +[SISO-STD-024-2024](https://www.sisostandards.org/page/StandardsProducts) and +[SISO-GUIDE-011-2024](https://www.sisostandards.org/resource/resmgr/guidance_products_/siso-guide-011-2024.pdf) +define Simulation Interoperability Readiness Levels. SIRL assesses whether +engineering evidence is sufficient to assess integration risk. It explicitly +does not determine that simulations are interoperable. + +That distinction becomes a reporting rule: + +```text +documentation/readiness + != interface compatibility + != contract conformance + != runtime realization + != empirical transfer + != trace relation + != bisimulation + != IFC/noninterference + != backend equivalence +``` + +[W3C PROV](https://www.w3.org/TR/prov-overview/) separates entities, +activities, agents, generation, derivation, and responsibility. +[RO-Crate 1.2](https://www.researchobject.org/ro-crate/specification/1.2/) +packages research data with contextual metadata. + +RAES already has experiment, run, study, apparatus, evidence, associated +artifact, realization, and traceability carriers. It reuses those concepts +without adding a parallel PROV or RO-Crate schema. External packaging remains +future work unless an interchange requirement needs it. + +## Design criteria + +### DC-01 — Both OR and AND are explicit + +The profile represents alternative realization and simultaneous mixed +realization separately. Two separate backend runs are never counted as a mixed +trial. + +### DC-02 — SDL meaning remains backend-neutral + +Allocation uses stable compiled refs in admitted experiment/trial intent. +Backend names and adapter classes do not enter authored world meaning. + +### DC-03 — Allocation is bounded and complete + +Revision 1 supports participant runtime, controlled scope, action family, +observation source, and crossing boundary. Missing or overlapping allocations +are rejected unless an explicit later arbitration profile governs them. + +### DC-04 — Topology is not inferred + +Single, integrated, unified, bridged/federated, and nested topologies are +named. Every edge is directed and evidence-bound. + +### DC-05 — Authority relations remain independent + +Participant identity, controller, authority scope, action admission, backend +responsibility, HLA ownership, routing, and disclosure remain separate. + +### DC-06 — Revision 1 has one acting controller + +Multiple realization providers do not imply distributed control. Lease, +simultaneous scoped-owner, and joint/fused controller semantics are rejected +until a later version supplies complete transition, order, failure, and +evidence rules. + +### DC-07 — Routing follows authorization + +SEM-230 and API-423 authorize the projection. DDM, filtering, encryption, and +directed delivery may realize it but never grant it. + +### DC-08 — Metadata is part of the observation surface + +Membership, subscriptions, classes, regions, sizes, timing, synchronization, +ownership, retraction, and failure are analyzed for leakage. + +### DC-09 — Cross-clock order is admitted + +Clock/domain mappings, progression roles, lookahead, grants, delivery order, +serialization, and readback are explicit. Timestamps alone are weak +disclosure. + +### DC-10 — Trial variation preserves identity + +Inter-trial changes use new linked plan entries/runs. Within-run membership +changes use finite pre-admitted phases. No change rewrites prior facts. + +### DC-11 — Open/closed is three axes + +Control loop, world assumption, and federation membership are separate +profiles with separate authority. + +### DC-12 — Failure has no silent fallback + +Missing, stale, unsupported, contradictory, or unmapped authority, +capability, policy, clock/order, allocation, or evidence rejects or produces a +declared weaker result. It never silently chooses another provider. + +### DC-13 — Evidence binds the complete apparatus + +Results pin scenario/policy, plan/run, apparatus/adapters, allocation, +topology, clocks, capability/conformance, mappings, model/data/seed, +loss/limitations, and reproduction. + +### DC-14 — Claims do not promote + +Conformance, readiness, transfer, trace inclusion, bisimulation, +IFC/noninterference, and equivalence remain independent. + +### DC-15 — The program reuses RAES carriers + +No generic federation event, universal message, HLA DTO, side store, +exception family, logger, or parallel conformance report is introduced. diff --git a/docs/research/cross-backend-participant-control/requirement-disposition.md b/docs/research/cross-backend-participant-control/requirement-disposition.md new file mode 100644 index 000000000..18ce8a773 --- /dev/null +++ b/docs/research/cross-backend-participant-control/requirement-disposition.md @@ -0,0 +1,80 @@ +# Mixed Cross-Backend Participant Control Requirement Disposition + +Date: 2026-07-31 + +## New DRAFT authority + +SEM-234, **Mixed Cross-Backend Participant-Control Composition**, is DRAFT, +MUST, wave 4. Canonical Ground Control id: +`38d807a4-ff50-4f9f-99a0-09e3ee3cdaa2`. + +It owns: + +- alternative simulation or emulation/operation realization; +- simultaneous mixed realization in one admitted trial; +- stable allocation units and explicit topology edges; +- separation of controller authority, realization responsibility, HLA + ownership, routing, and disclosure; +- clock/order and policy mappings; +- linked inter-trial and finite pre-admitted within-run changes; +- the three open/closed axes; and +- fail-closed loss, weakening, and evidence rules. + +ASR-537, **Cross-Backend Participant-Control Realization and Transfer +Evidence**, is DRAFT, MUST, wave 4, non-functional. Canonical Ground Control +id: `b425b452-a796-4997-a29f-3432baa6496a`. + +It owns: + +- pure simulation, pure emulation/operation, simultaneous mixed, and staged + lanes; +- open-loop and closed-loop cases; +- stale, unsupported, unmapped, mismatched, delivery, retraction, and metadata + adversarial cases; +- complete apparatus/model/data/time/provenance binding; +- zero-effect requirements for denied cases; +- transfer, readiness, conformance, and reproduction evidence; and +- separation from trace, bisimulation, IFC/noninterference, and equivalence. + +Issue #813 defines both authorities but does not satisfy their positive +implementation or evaluation clauses. + +## Reused and downstream authority + +| Requirement | Disposition | Scope | Boundary | +| --- | --- | --- | --- | +| SEM-230 | reuse | Participant/audience projection, exact-cut policy, release, memory, strategy, and noninterference boundary | SEM-234 adds composition; it does not add a second participant world | +| SCE-002 | extend downstream | Scenario-family selection, deterministic trial admission, apparatus pinning, immutable plan/run identity | #1015 adds mixed allocation and finite phases without a parallel lifecycle | +| API-407 | extend downstream | Declared/effective backend support, constraints, downgrade, realization, and conformance | #1017 adds governed mixed services in the existing manifest block | +| API-423 | reuse | Typed crossing request through audit, context, predecessors, order, and evidence | Composition edges reference crossings; no generic federation event | +| RUN-310 | reuse and extend downstream | Authenticated control, one acting controller, revision-fenced handoff, persistence, replay | Providers do not become controllers; #1016 composes the exact cut | +| RUN-319 | extend downstream | Reference crossing mediation and atomic decision-before-effect | #1016 resolves allocation/topology/time before the same final boundary | +| ASR-535 | reuse | Bounded assurance, relation claim binding, finite falsification, and overclaim prevention | ASR-537 adds mixed/transfer variables without merging assurance axes | + +## Deferred authority + +Revision 1 does not support: + +- simultaneous controllers for different scopes; +- leases; +- quorum, priority, arbitration, unanimity, or fused control; or +- transfer oscillation/livelock guarantees. + +A future version requires exact controller/scope identities, renewal/expiry +and fencing or composition rules, atomic transition, clock/order, failure, +progress, and evidence semantics. These concepts are not encoded in open +metadata or synthetic controller identities. + +## Ordered work + +- #1013: SEM-234 semantic authority. +- #1014: portable contracts after #1013. +- #1015: deterministic trial admission after #1014. +- #1016: fail-closed runtime coordination after #1014 and #1015. +- #1017: backend capability and conformance after #1014 and #1016. +- #1018: ASR-537 demonstration after #1015, #1016, and #1017. +- #1019: evidenced documentation after #1016, #1017, and #1018. + +All children name SEM-234 or ASR-537 and retain explicit nonclaims. Generic +backend capability and conformance work is in milestone 61. Participant +semantics, runtime composition, evaluation, and claims remain in milestone 67. diff --git a/docs/research/participant-bisimulation/current-state-assessment.md b/docs/research/participant-bisimulation/current-state-assessment.md index 28afb57be..f5bb0f0cd 100644 --- a/docs/research/participant-bisimulation/current-state-assessment.md +++ b/docs/research/participant-bisimulation/current-state-assessment.md @@ -2,7 +2,7 @@ Date: 2026-07-29 -Parent issue: [#811](https://github.com/RAESystem/rae/issues/811). +Parent issue: [#811](https://github.com/OpenRAE/rae/issues/811). ## Available Authority diff --git a/docs/research/participant-bisimulation/implementation-program.md b/docs/research/participant-bisimulation/implementation-program.md index da25ff89f..daf7cb47c 100644 --- a/docs/research/participant-bisimulation/implementation-program.md +++ b/docs/research/participant-bisimulation/implementation-program.md @@ -2,7 +2,7 @@ Date: 2026-07-29 -Parent issue: [#811](https://github.com/RAESystem/rae/issues/811) +Parent issue: [#811](https://github.com/OpenRAE/rae/issues/811) Milestone: `Participant Information-Flow & Behavioral Equivalence` diff --git a/docs/research/participant-bisimulation/index.md b/docs/research/participant-bisimulation/index.md index 45154c8e8..920c7e9c0 100644 --- a/docs/research/participant-bisimulation/index.md +++ b/docs/research/participant-bisimulation/index.md @@ -1,6 +1,6 @@ # Participant-Crossing Bisimulation Design -Issue [#811](https://github.com/RAESystem/rae/issues/811) selects one bounded, +Issue [#811](https://github.com/OpenRAE/rae/issues/811) selects one bounded, genuine bisimulation target and makes its machine-checkable result mandatory downstream. diff --git a/docs/research/participant-io-control/adoption-program.md b/docs/research/participant-io-control/adoption-program.md index a613f028f..0536d4a6c 100644 --- a/docs/research/participant-io-control/adoption-program.md +++ b/docs/research/participant-io-control/adoption-program.md @@ -1,6 +1,6 @@ # Participant Information-Flow And Control Implementation Program -Parent: [#794](https://github.com/RAESystem/rae/issues/794) +Parent: [#794](https://github.com/OpenRAE/rae/issues/794) Milestone: `Participant Information-Flow & Behavioral Equivalence` Machine-readable gate: [`adoption-program.json`](adoption-program.json) @@ -51,8 +51,8 @@ in parallel when every listed dependency has merged. | Issue | UID | Bounded outcome | | --- | --- | --- | -| [#796](https://github.com/RAESystem/rae/issues/796) | SEM-230 | Revisioned policy, labels, projections, IFC relation dimensions, and explicit nonclaims. | -| [#251](https://github.com/RAESystem/rae/issues/251) | ACT-617 | Authored controller/authority state and mixed-control transitions. | +| [#796](https://github.com/OpenRAE/rae/issues/796) | SEM-230 | Revisioned policy, labels, projections, IFC relation dimensions, and explicit nonclaims. | +| [#251](https://github.com/OpenRAE/rae/issues/251) | ACT-617 | Authored controller/authority state and mixed-control transitions. | Wave 0 does not implement runtime mediation or claim proof. It fixes the meaning that later artifacts implement. @@ -61,10 +61,10 @@ meaning that later artifacts implement. | Issue | UID | Bounded outcome | | --- | --- | --- | -| [#294](https://github.com/RAESystem/rae/issues/294) | SEM-219 | Governed tool/affordance bindings distinct from apparatus support. | -| [#295](https://github.com/RAESystem/rae/issues/295) | SEM-220 | Participant-local decision-surface projection and selection meaning. | -| [#296](https://github.com/RAESystem/rae/issues/296) | SEM-226 | Time-indexed exposure, withholding, declassification/redaction, transformation, and realized evidence. | -| [#797](https://github.com/RAESystem/rae/issues/797) | DSL-142 | Participant-directed inject addressee/delivery semantics while preserving DSL-111 identity. | +| [#294](https://github.com/OpenRAE/rae/issues/294) | SEM-219 | Governed tool/affordance bindings distinct from apparatus support. | +| [#295](https://github.com/OpenRAE/rae/issues/295) | SEM-220 | Participant-local decision-surface projection and selection meaning. | +| [#296](https://github.com/OpenRAE/rae/issues/296) | SEM-226 | Time-indexed exposure, withholding, declassification/redaction, transformation, and realized evidence. | +| [#797](https://github.com/OpenRAE/rae/issues/797) | DSL-142 | Participant-directed inject addressee/delivery semantics while preserving DSL-111 identity. | Every issue reuses safe parsing, closed models, semantic validation, instantiation, compiler addresses, concept authority, and schema publication. @@ -74,8 +74,8 @@ Environment injects remain outside participant ingress. | Issue | UID | Bounded outcome | | --- | --- | --- | -| [#252](https://github.com/RAESystem/rae/issues/252) | API-409 | External proposal, approval/denial, direction, intervention, handoff, override, and cancellation records. | -| [#798](https://github.com/RAESystem/rae/issues/798) | API-423 | Common crossing policy-decision, transformation, disposition, evidence, and provenance refs. | +| [#252](https://github.com/OpenRAE/rae/issues/252) | API-409 | External proposal, approval/denial, direction, intervention, handoff, override, and cancellation records. | +| [#798](https://github.com/OpenRAE/rae/issues/798) | API-423 | Common crossing policy-decision, transformation, disposition, evidence, and provenance refs. | These issues compose API-406/ADR-054 carriers; they do not add a transport or generic payload. Each published schema requires valid/invalid fixtures, @@ -86,9 +86,9 @@ parity, and consumer tests. | Issue | UID | Bounded outcome | | --- | --- | --- | -| [#801](https://github.com/RAESystem/rae/issues/801) | API-407 | Governed backend feature support, strength, limitation, disclosure, and evidence. | -| [#255](https://github.com/RAESystem/rae/issues/255) | RUN-310 | Secure, ordered, idempotent, append-only supervisory lifecycle. | -| [#799](https://github.com/RAESystem/rae/issues/799) | RUN-319 | Deny-first reference-runtime crossing enforcement, persistence, audit, and evidence. | +| [#801](https://github.com/OpenRAE/rae/issues/801) | API-407 | Governed backend feature support, strength, limitation, disclosure, and evidence. | +| [#255](https://github.com/OpenRAE/rae/issues/255) | RUN-310 | Secure, ordered, idempotent, append-only supervisory lifecycle. | +| [#799](https://github.com/OpenRAE/rae/issues/799) | RUN-319 | Deny-first reference-runtime crossing enforcement, persistence, audit, and evidence. | Runtime work reuses `ParticipantControlMixin`, SEM-211 admission, observation/projection incumbents, `RuntimeSnapshot`, `ControlPlaneStore`, @@ -103,7 +103,7 @@ stronger claim. | Issue | UID | Bounded outcome | | --- | --- | --- | -| [#800](https://github.com/RAESystem/rae/issues/800) | ASR-535 | Negative leakage/declassification cases, exact relation bindings, bounded formal evidence, and adversarial backend conformance. | +| [#800](https://github.com/OpenRAE/rae/issues/800) | ASR-535 | Negative leakage/declassification cases, exact relation bindings, bounded formal evidence, and adversarial backend conformance. | This wave reuses `BackendConformanceReport`, existing fixture/target runners, the behavioral-relation catalog, and `BehavioralClaimBindingModel`. Every @@ -115,8 +115,8 @@ Finite evidence retains finite scope. | Issue | UIDs | Bounded outcome | | --- | --- | --- | -| [#802](https://github.com/RAESystem/rae/issues/802) | SEM-230, API-423, RUN-319 | ADR-061 compatibility classification, staged adoption/rollback, and legacy fixtures without silent strengthening. | -| [#803](https://github.com/RAESystem/rae/issues/803) | SEM-230, API-423, RUN-319 | Author, operator, backend, participant-implementation, and research guidance grounded in shipped authority/evidence. | +| [#802](https://github.com/OpenRAE/rae/issues/802) | SEM-230, API-423, RUN-319 | ADR-061 compatibility classification, staged adoption/rollback, and legacy fixtures without silent strengthening. | +| [#803](https://github.com/OpenRAE/rae/issues/803) | SEM-230, API-423, RUN-319 | Author, operator, backend, participant-implementation, and research guidance grounded in shipped authority/evidence. | Legacy absence is legacy/unknown/unsupported according to the migration profile; it is never evidence of exact policy enforcement or noninterference. @@ -127,20 +127,20 @@ evidence. | Order | Issue | Requirement authority | Work class | Direct prerequisites | | ---: | --- | --- | --- | --- | -| 1 | [#796](https://github.com/RAESystem/rae/issues/796) | SEM-230 | semantic authority | #794 merged | -| 2 | [#251](https://github.com/RAESystem/rae/issues/251) | ACT-617 | semantic authority | #796 | -| 3 | [#294](https://github.com/RAESystem/rae/issues/294) | SEM-219 | SDL/semantic binding | #796 | -| 4 | [#295](https://github.com/RAESystem/rae/issues/295) | SEM-220 | decision-surface contract/projection | #796, #294 | -| 5 | [#296](https://github.com/RAESystem/rae/issues/296) | SEM-226 | exposure enforcement | #796, #295 | -| 6 | [#797](https://github.com/RAESystem/rae/issues/797) | DSL-142 | participant-directed injects | #796 | -| 7 | [#252](https://github.com/RAESystem/rae/issues/252) | API-409 | external-input/intervention contracts | #796, #251 | -| 8 | [#798](https://github.com/RAESystem/rae/issues/798) | API-423 | crossing decision/evidence contracts | #796, #296, #252, #797 | -| 9 | [#255](https://github.com/RAESystem/rae/issues/255) | RUN-310 | supervisory runtime | #251, #252 | -| 10 | [#801](https://github.com/RAESystem/rae/issues/801) | API-407 | backend capability | #798 | -| 11 | [#799](https://github.com/RAESystem/rae/issues/799) | RUN-319 | runtime enforcement/evidence | #798, #801, #255, #296 | -| 12 | [#800](https://github.com/RAESystem/rae/issues/800) | ASR-535 | assurance/conformance | #796, #799, #801 | -| 13 | [#802](https://github.com/RAESystem/rae/issues/802) | SEM-230, API-423, RUN-319 | migration | #799, #800 | -| 14 | [#803](https://github.com/RAESystem/rae/issues/803) | SEM-230, API-423, RUN-319 | documentation | #802, #800 | +| 1 | [#796](https://github.com/OpenRAE/rae/issues/796) | SEM-230 | semantic authority | #794 merged | +| 2 | [#251](https://github.com/OpenRAE/rae/issues/251) | ACT-617 | semantic authority | #796 | +| 3 | [#294](https://github.com/OpenRAE/rae/issues/294) | SEM-219 | SDL/semantic binding | #796 | +| 4 | [#295](https://github.com/OpenRAE/rae/issues/295) | SEM-220 | decision-surface contract/projection | #796, #294 | +| 5 | [#296](https://github.com/OpenRAE/rae/issues/296) | SEM-226 | exposure enforcement | #796, #295 | +| 6 | [#797](https://github.com/OpenRAE/rae/issues/797) | DSL-142 | participant-directed injects | #796 | +| 7 | [#252](https://github.com/OpenRAE/rae/issues/252) | API-409 | external-input/intervention contracts | #796, #251 | +| 8 | [#798](https://github.com/OpenRAE/rae/issues/798) | API-423 | crossing decision/evidence contracts | #796, #296, #252, #797 | +| 9 | [#255](https://github.com/OpenRAE/rae/issues/255) | RUN-310 | supervisory runtime | #251, #252 | +| 10 | [#801](https://github.com/OpenRAE/rae/issues/801) | API-407 | backend capability | #798 | +| 11 | [#799](https://github.com/OpenRAE/rae/issues/799) | RUN-319 | runtime enforcement/evidence | #798, #801, #255, #296 | +| 12 | [#800](https://github.com/OpenRAE/rae/issues/800) | ASR-535 | assurance/conformance | #796, #799, #801 | +| 13 | [#802](https://github.com/OpenRAE/rae/issues/802) | SEM-230, API-423, RUN-319 | migration | #799, #800 | +| 14 | [#803](https://github.com/OpenRAE/rae/issues/803) | SEM-230, API-423, RUN-319 | documentation | #802, #800 | ## Program-wide acceptance and evidence rules diff --git a/docs/research/participant-io-control/current-state-assessment.md b/docs/research/participant-io-control/current-state-assessment.md index 30ab7a711..d5a06a822 100644 --- a/docs/research/participant-io-control/current-state-assessment.md +++ b/docs/research/participant-io-control/current-state-assessment.md @@ -1,7 +1,7 @@ # Participant Information-Flow And Control Current-State Assessment Date: 2026-07-15 -Issue: [#794](https://github.com/RAESystem/rae/issues/794) +Issue: [#794](https://github.com/OpenRAE/rae/issues/794) Milestone: `Participant Information-Flow & Behavioral Equivalence` This assessment distinguishes normative definition, implementation, test, @@ -140,9 +140,9 @@ surface, realized exposure, and decision/outcome. It refines the existing participant view rather than inventing a second visibility system. Ground Control has only documentation links for SEM-219, SEM-220, and SEM-226; -issues [#294](https://github.com/RAESystem/rae/issues/294), -[#295](https://github.com/RAESystem/rae/issues/295), and -[#296](https://github.com/RAESystem/rae/issues/296) remain open. Therefore +issues [#294](https://github.com/OpenRAE/rae/issues/294), +[#295](https://github.com/OpenRAE/rae/issues/295), and +[#296](https://github.com/OpenRAE/rae/issues/296) remain open. Therefore the ADR and formal matrix establish design, not runtime mediation or delivered exposure. diff --git a/docs/research/participant-io-control/index.md b/docs/research/participant-io-control/index.md index 4d226dc97..f57b92201 100644 --- a/docs/research/participant-io-control/index.md +++ b/docs/research/participant-io-control/index.md @@ -1,6 +1,6 @@ # Participant Information-Flow And Control Adoption -Issue [#794](https://github.com/RAESystem/rae/issues/794) assesses and +Issue [#794](https://github.com/OpenRAE/rae/issues/794) assesses and designs the participant-control model. The ordered child work now delivers the SEM-230 semantics, API-423 crossing contract, RUN-319 reference-runtime boundary, API-407 capability declarations, ASR-535 bounded assurance, and diff --git a/docs/research/participant-io-control/requirement-disposition.md b/docs/research/participant-io-control/requirement-disposition.md index 14b2b18ca..2cc62fd3d 100644 --- a/docs/research/participant-io-control/requirement-disposition.md +++ b/docs/research/participant-io-control/requirement-disposition.md @@ -2,7 +2,7 @@ Date: 2026-07-15 Ground Control project: `aces-sdl` -Parent issue: [#794](https://github.com/RAESystem/rae/issues/794) +Parent issue: [#794](https://github.com/OpenRAE/rae/issues/794) Requirement authority was reconciled before dependent issues were filed. New requirements remain DRAFT: their existence authorizes and scopes future work; @@ -32,27 +32,27 @@ does not transition any new requirement ACTIVE. | SEM-211 | ACTIVE | reuse | Typed action applicability/admission remains canonical. | dependency of #251/#799 | | SEM-212 | ACTIVE | reuse | Evidence-labelled attribution remains canonical. | dependency of #796 | | SEM-213 | ACTIVE | reuse | Participant time/order semantics remain canonical. | dependency of #796 | -| SEM-219 | DRAFT | reuse | ADR-083 scope is sufficient; implementation remains bounded to affordances. | [#294](https://github.com/RAESystem/rae/issues/294) | -| SEM-220 | DRAFT | reuse | ADR-083 scope is sufficient; implementation remains bounded to decision surfaces. | [#295](https://github.com/RAESystem/rae/issues/295) | -| SEM-226 | DRAFT | amend | Statement now names withholding, projection/masking, redaction, disclosure/declassification, transformation, loss, and evidence while retaining ADR-083 authority. | [#296](https://github.com/RAESystem/rae/issues/296) | -| **SEM-230** | **DRAFT** | **new** | Owns revisioned participant information-flow/control policy, labels, projections, and exact claim boundaries. | [#796](https://github.com/RAESystem/rae/issues/796) | -| ACT-617 | DRAFT | amend | Statement now requires explicit controller/authority state and ordered approval, direction, intervention, handoff, override, and cancellation distinct from admission/execution/observation. | [#251](https://github.com/RAESystem/rae/issues/251) | +| SEM-219 | DRAFT | reuse | ADR-083 scope is sufficient; implementation remains bounded to affordances. | [#294](https://github.com/OpenRAE/rae/issues/294) | +| SEM-220 | DRAFT | reuse | ADR-083 scope is sufficient; implementation remains bounded to decision surfaces. | [#295](https://github.com/OpenRAE/rae/issues/295) | +| SEM-226 | DRAFT | amend | Statement now names withholding, projection/masking, redaction, disclosure/declassification, transformation, loss, and evidence while retaining ADR-083 authority. | [#296](https://github.com/OpenRAE/rae/issues/296) | +| **SEM-230** | **DRAFT** | **new** | Owns revisioned participant information-flow/control policy, labels, projections, and exact claim boundaries. | [#796](https://github.com/OpenRAE/rae/issues/796) | +| ACT-617 | DRAFT | amend | Statement now requires explicit controller/authority state and ordered approval, direction, intervention, handoff, override, and cancellation distinct from admission/execution/observation. | [#251](https://github.com/OpenRAE/rae/issues/251) | | DSL-111 | ACTIVE | reuse | Continues to own environment/orchestration inject identity and scheduling. | dependency of #797 | -| **DSL-142** | **DRAFT** | **new** | Owns participant addressee, disclosure/delivery, order, intervention binding, and evidence while preserving DSL-111 inject identity. | [#797](https://github.com/RAESystem/rae/issues/797) | +| **DSL-142** | **DRAFT** | **new** | Owns participant addressee, disclosure/delivery, order, intervention binding, and evidence while preserving DSL-111 inject identity. | [#797](https://github.com/OpenRAE/rae/issues/797) | | API-406 | ACTIVE | reuse | Existing lifecycle, observation, shared-state, snapshot, and history carriers remain canonical. | dependency of #798 | -| API-407 | ACTIVE | reuse | Existing feature-support/constraint seam owns new participant-control capabilities; no replacement or second manifest is needed. | [#801](https://github.com/RAESystem/rae/issues/801) | -| API-409 | DRAFT | amend | Statement now distinguishes proposals, approvals/denials, directions, interventions, handoffs, overrides, cancellations, controller/authority, order, provenance, evidence, and disposition. | [#252](https://github.com/RAESystem/rae/issues/252) | -| **API-423** | **DRAFT** | **new** | Owns common crossing decision, transformation, declassification/redaction, disposition, loss, evidence, and provenance refs without a generic payload carrier. | [#798](https://github.com/RAESystem/rae/issues/798) | +| API-407 | ACTIVE | reuse | Existing feature-support/constraint seam owns new participant-control capabilities; no replacement or second manifest is needed. | [#801](https://github.com/OpenRAE/rae/issues/801) | +| API-409 | DRAFT | amend | Statement now distinguishes proposals, approvals/denials, directions, interventions, handoffs, overrides, cancellations, controller/authority, order, provenance, evidence, and disposition. | [#252](https://github.com/OpenRAE/rae/issues/252) | +| **API-423** | **DRAFT** | **new** | Owns common crossing decision, transformation, declassification/redaction, disposition, loss, evidence, and provenance refs without a generic payload carrier. | [#798](https://github.com/OpenRAE/rae/issues/798) | | RUN-305 | DRAFT | reuse | Append-only state/history remains the persistence incumbent; traceability/status needs separate reconciliation when its own scope is resumed. | dependency of #799 | | RUN-306 | ACTIVE | reuse | Observable proposal/admission/attempt/observation/state lifecycle remains canonical. | dependency of #255/#799 | | RUN-307 | ACTIVE | reuse | Shared operational state remains canonical. | dependency of #799 | | RUN-308 | ACTIVE | reuse | Ordering, concurrency, conflict, and time-management carriers remain canonical. | dependency of #796/#799 | -| RUN-310 | DRAFT | amend | Statement now requires ordered supervision/control transitions, stale/conflict handling, append-only evidence, and separation from admission/execution/observation. | [#255](https://github.com/RAESystem/rae/issues/255) | -| **RUN-319** | **DRAFT** | **new** | Owns reference-runtime crossing enforcement, fail-closed capability use, persistence, audit, and realization evidence. | [#799](https://github.com/RAESystem/rae/issues/799) | +| RUN-310 | DRAFT | amend | Statement now requires ordered supervision/control transitions, stale/conflict handling, append-only evidence, and separation from admission/execution/observation. | [#255](https://github.com/OpenRAE/rae/issues/255) | +| **RUN-319** | **DRAFT** | **new** | Owns reference-runtime crossing enforcement, fail-closed capability use, persistence, audit, and realization evidence. | [#799](https://github.com/OpenRAE/rae/issues/799) | | ASR-502 | ACTIVE | adjacent | Existing backend conformance runner/corpus remains canonical. | dependency of #800 | | ASR-519 | ACTIVE | adjacent | Existing realization-honesty checks remain canonical. | dependency of #800 | | ASR-527 | ACTIVE | adjacent | Existing participant implementation/exposure conformance remains canonical. | dependency of #800 | -| **ASR-535** | **DRAFT** | **new** | Owns participant-policy falsification, bounded formal evidence, adversarial backend cases, relation bindings, and explicit nonclaims. | [#800](https://github.com/RAESystem/rae/issues/800) | +| **ASR-535** | **DRAFT** | **new** | Owns participant-policy falsification, bounded formal evidence, adversarial backend cases, relation bindings, and explicit nonclaims. | [#800](https://github.com/OpenRAE/rae/issues/800) | ## New requirement records diff --git a/docs/research/participant-opacity/current-state-assessment.md b/docs/research/participant-opacity/current-state-assessment.md index c8c24f1d2..0d23f669f 100644 --- a/docs/research/participant-opacity/current-state-assessment.md +++ b/docs/research/participant-opacity/current-state-assessment.md @@ -2,7 +2,7 @@ Date: 2026-07-29 -Issue: [#810](https://github.com/RAESystem/rae/issues/810) +Issue: [#810](https://github.com/OpenRAE/rae/issues/810) ## Finding diff --git a/docs/research/participant-opacity/implementation-program.md b/docs/research/participant-opacity/implementation-program.md index ca627303d..ae9e7323c 100644 --- a/docs/research/participant-opacity/implementation-program.md +++ b/docs/research/participant-opacity/implementation-program.md @@ -2,7 +2,7 @@ Date: 2026-07-29 -Parent issue: [#810](https://github.com/RAESystem/rae/issues/810) +Parent issue: [#810](https://github.com/OpenRAE/rae/issues/810) Milestone: `Participant Information-Flow & Behavioral Equivalence` diff --git a/docs/research/participant-opacity/index.md b/docs/research/participant-opacity/index.md index 3ea629d93..89f34fb4b 100644 --- a/docs/research/participant-opacity/index.md +++ b/docs/research/participant-opacity/index.md @@ -1,6 +1,6 @@ # Participant-Relative Opacity And Supervisor Observation Research -Issue: [#810](https://github.com/RAESystem/rae/issues/810) +Issue: [#810](https://github.com/OpenRAE/rae/issues/810) Purpose: establish the external primary-literature basis for participant- relative opacity before architecture preflight, relation selection, formal @@ -9,15 +9,19 @@ what must RAES define so that an opacity claim has a precise observer, information set, secret, supervisor-visibility model, time/order model, and assurance scope? -The result is not a proof that RAES is opaque and not a runtime-enforcement -claim. It is a design input for a revisioned relation and for bounded child -work. +This research record is not a proof that RAES is opaque and is not a runtime- +enforcement claim. The linked issue #963 artifacts separately prove the +abstract conditional theorem profile; they instantiate no RAES runtime, +deployment, participant, or backend. ## Contents - [Architecture preflight](../../decisions/issue-810-participant-opacity-preflight.md) - [Issue #961 bounded-falsification preflight](../../decisions/issue-961-participant-opacity-bounded-falsification-preflight.md) - [Issue #962 finite-state model-check preflight](../../decisions/issue-962-participant-opacity-model-check-preflight.md) +- [Issue #963 mathematical-proof preflight](../../decisions/issue-963-participant-opacity-proof-preflight.md) +- [Isabelle/HOL theorem source](../../../specs/formal/participant-semantics/isabelle/Participant_Opacity.thy) +- [Checked proof evidence](../../../specs/formal/participant-semantics/participant-opacity-proof-evidence.json) - [ADR-099](../../decisions/adrs/adr-099-participant-relative-predicate-opacity.md) - [Prior art and design criteria](prior-art-and-design-criteria.md) — search method, primary and adjacent source findings, relation selection, formal diff --git a/docs/research/participant-opacity/prior-art-and-design-criteria.md b/docs/research/participant-opacity/prior-art-and-design-criteria.md index 8fbdfda5d..a73c2d605 100644 --- a/docs/research/participant-opacity/prior-art-and-design-criteria.md +++ b/docs/research/participant-opacity/prior-art-and-design-criteria.md @@ -2,7 +2,7 @@ Date: 2026-07-29 -Issue: [#810](https://github.com/RAESystem/rae/issues/810) +Issue: [#810](https://github.com/OpenRAE/rae/issues/810) ## 1. Research Question And Method diff --git a/docs/research/participant-opacity/requirement-disposition.md b/docs/research/participant-opacity/requirement-disposition.md index ac55fe5dc..f0beffa0e 100644 --- a/docs/research/participant-opacity/requirement-disposition.md +++ b/docs/research/participant-opacity/requirement-disposition.md @@ -2,7 +2,7 @@ Date: 2026-07-29 -Parent issue: [#810](https://github.com/RAESystem/rae/issues/810) +Parent issue: [#810](https://github.com/OpenRAE/rae/issues/810) Requirement allocation was completed before the implementation child issues were created. This prevents delivery tasks from inventing requirement scope @@ -11,25 +11,25 @@ after the fact. | Requirement | Status | Disposition | Allocated scope | | --- | --- | --- | --- | | `SEM-230` | ACTIVE | reuse | Policy noninterference, exact-cut policy/release, adaptive low strategies, memory, observation projection, scheduler/environment, and order coordinates remain canonical. | -| `SEM-231` | DRAFT | new | One-sided participant-relative predicate opacity, possible-point and information-cell semantics, supervisor visibility, closed relation profiles, exact relation boundaries, and independent assurance states. | +| `SEM-231` | ACTIVE | new | One-sided participant-relative predicate opacity, possible-point and information-cell semantics, supervisor visibility, closed relation profiles, exact relation boundaries, and independent assurance states. | | `ASR-535` | ACTIVE | reuse | Bounded falsification, model-check/proof evidence discipline, adversarial cases, safe counterexamples, relation claim bindings, and backend conformance. | | `RUN-319` | ACTIVE | reuse | Any future fail-closed reference-runtime mediation, append-only decisions/evidence, and declared limitations for supported opacity profiles. | | `API-407` | ACTIVE | reuse | Backend feature strength, required contracts, limitations, declaration, native realization, and evidence for named opacity profiles. | `SEM-231` was created in Ground Control as a `DRAFT` requirement before child -issues #961 through #965. The child issues document it, and each reuses the -incumbent assurance/runtime/backend requirement appropriate to its bounded -outcome. +issues #961 through #965 and was subsequently activated. The child issues +document it, and each reuses the incumbent assurance/runtime/backend +requirement appropriate to its bounded outcome. ## Child Allocation | Issue | Bounded outcome | Requirements | Prerequisites | | --- | --- | --- | --- | -| [#961](https://github.com/RAESystem/rae/issues/961) | closed profiles and bounded falsification | `SEM-231`, `ASR-535` | #810 | -| [#962](https://github.com/RAESystem/rae/issues/962) | finite-state model checking | `SEM-231`, `ASR-535` | #810, #961 | -| [#963](https://github.com/RAESystem/rae/issues/963) | mathematical proof | `SEM-231`, `ASR-535` | #810, #961, #962 | -| [#964](https://github.com/RAESystem/rae/issues/964) | reference-runtime enforcement | `SEM-231`, `RUN-319` | #810, #961 | -| [#965](https://github.com/RAESystem/rae/issues/965) | backend declaration, realization, and bounded conformance | `SEM-231`, `API-407`, `ASR-535` | #810, #961, #962, #964 | +| [#961](https://github.com/OpenRAE/rae/issues/961) | closed profiles and bounded falsification | `SEM-231`, `ASR-535` | #810 | +| [#962](https://github.com/OpenRAE/rae/issues/962) | finite-state model checking | `SEM-231`, `ASR-535` | #810, #961 | +| [#963](https://github.com/OpenRAE/rae/issues/963) | mathematical proof | `SEM-231`, `ASR-535` | #810, #961, #962 | +| [#964](https://github.com/OpenRAE/rae/issues/964) | reference-runtime enforcement | `SEM-231`, `RUN-319` | #810, #961 | +| [#965](https://github.com/OpenRAE/rae/issues/965) | backend declaration, realization, and bounded conformance | `SEM-231`, `API-407`, `ASR-535` | #810, #961, #962, #964 | The dependency graph is acyclic. Definition precedes every implementation lane; the profile/checker foundation precedes model checking, proof, runtime, @@ -38,7 +38,7 @@ boundary. ## Explicit Nonclaims -Requirement allocation is not evidence of satisfaction. `SEM-231` remains -`DRAFT`. Issue #810 provides definition and bounded design tests only; it does -not satisfy or activate the downstream model-check, proof, runtime, backend, or -conformance outcomes. +Requirement allocation is not evidence of satisfaction. Issue #810 provides +definition and bounded design tests only; issues #961, #962, and #963 provide +separate finite-checker, finite-model, and abstract conditional proof evidence. +They do not establish runtime, backend, or conformance outcomes. diff --git a/examples/scenarios/enterprise-participant-evidence-loop.README.md b/examples/scenarios/enterprise-participant-evidence-loop.README.md index 571cd797f..09886f3e2 100644 --- a/examples/scenarios/enterprise-participant-evidence-loop.README.md +++ b/examples/scenarios/enterprise-participant-evidence-loop.README.md @@ -152,12 +152,12 @@ semantic equivalence. ## Downstream Links -- RAES issue: RAESystem/rae#598 -- Participant implementation binding: RAESystem/rae#599 -- RAES n=2 backend proof: RAESystem/rae#600 +- RAES issue: OpenRAE/rae#598 +- Participant implementation binding: OpenRAE/rae#599 +- RAES n=2 backend proof: OpenRAE/rae#600 (corpus: `examples/corpus/reference-demonstration/`) -- Libvirt participant runtime: RAESystem/rae#614 -- Libvirt evaluator/Wazuh evidence readback: RAESystem/rae#615 +- Libvirt participant runtime: OpenRAE/rae#614 +- Libvirt evaluator/Wazuh evidence readback: OpenRAE/rae#615 - APTL realization and proof: Brad-Edwards/aptl#556, Brad-Edwards/aptl#557, Brad-Edwards/aptl#558 diff --git a/examples/scenarios/initial-service-state.sdl.yaml b/examples/scenarios/initial-service-state.sdl.yaml index 6bfb8a123..88d39aebd 100644 --- a/examples/scenarios/initial-service-state.sdl.yaml +++ b/examples/scenarios/initial-service-state.sdl.yaml @@ -11,6 +11,8 @@ nodes: services: - name: imap port: 143 + - name: search + port: 9200 content: company-mail: @@ -31,6 +33,24 @@ content: readback_assertion_refs: [company-mail-visible] evidence_requirement_refs: [company-mail-readback] observation_boundary_refs: [participant-mail-view] + job-index-schema: + type: dataset + target: mail + service_materialization: + target_service_ref: nodes.mail.services.search + interface_profile: service-search-index-schema + profile_version: "1" + requirements: + operation: ensure-search-index-field-schema + conflict_policy: reject-unowned-collision + readback: canonical-portable-field-schema-digest + field_semantics: + key: exact-token + status: exact-token + relations: exact-token + readback_assertion_refs: [job-index-schema-visible] + evidence_requirement_refs: [job-index-schema-readback] + observation_boundary_refs: [participant-search-view] propositions: company-mail-visible: @@ -43,11 +63,24 @@ propositions: semantic_ref: urn:raes:observable:service-content-visible expected: true evidence_requirements: [company-mail-readback] + job-index-schema-visible: + description: The declared search-index fields have exact portable semantics. + subjects: [content.job-index-schema] + basis: observed_state + predicate: + kind: boolean + property: service-search-index-schema-visible + semantic_ref: urn:raes:observable:service-search-index-schema-visible + expected: true + evidence_requirements: [job-index-schema-readback] assertions: company-mail-visible: proposition: company-mail-visible role: postcondition + job-index-schema-visible: + proposition: job-index-schema-visible + role: postcondition observation_boundaries: participant-mail-view: @@ -55,6 +88,11 @@ observation_boundaries: observable_refs: [content.company-mail] redaction_policy: preserve participant-visible message fields latency_profile: available before participant admission + participant-search-view: + projection_basis: ordinary participant access through the named search service + observable_refs: [content.job-index-schema] + redaction_policy: preserve declared portable field semantics + latency_profile: available before participant admission evidence_requirements: company-mail-readback: @@ -69,3 +107,15 @@ evidence_requirements: integrity: checksum retention: run_lifetime loss_disclosure: required + job-index-schema-readback: + source_refs: [content.job-index-schema] + scope: fresh native schema readback projected to portable field semantics + boundary_kind: participant_equivalent + channel: api_response + artifact_role: service_materialization_readback + media_types: [application/json] + sensitivity: plain + redaction: redact_secrets + integrity: checksum + retention: run_lifetime + loss_disclosure: required diff --git a/implementations/python/packages/raes/content.py b/implementations/python/packages/raes/content.py index 01a5168fc..b584a2c52 100644 --- a/implementations/python/packages/raes/content.py +++ b/implementations/python/packages/raes/content.py @@ -11,7 +11,7 @@ """ from enum import Enum -from typing import Literal +from typing import Annotated, Literal from pydantic import Field, ValidationInfo, field_validator, model_validator @@ -46,13 +46,10 @@ class ServiceMaterializationRequirements(SDLModel): readback: Literal["canonical-content-digest"] = "canonical-content-digest" -class ServiceMaterialization(SDLModel): - """Portable control contract for placing content through a named service.""" +class _ServiceMaterializationBase(SDLModel): + """References and ownership shared by every closed service profile.""" target_service_ref: str = Field(min_length=1) - interface_profile: Literal["service-content"] = "service-content" - profile_version: Literal["1"] = "1" - requirements: ServiceMaterializationRequirements shared_service_relationship_ref: str = "" ordering_content_refs: list[str] = Field(default_factory=list) readback_assertion_refs: list[str] = Field(min_length=1) @@ -78,6 +75,47 @@ def validate_references(cls, values: list[str], info: ValidationInfo) -> list[st return values +class ServiceMaterialization(_ServiceMaterializationBase): + """Portable control contract for placing content through a named service.""" + + interface_profile: Literal["service-content"] = "service-content" + profile_version: Literal["1"] = "1" + requirements: ServiceMaterializationRequirements + + +class SearchIndexFieldSemantic(str, Enum): + """Portable top-level search-index field behavior.""" + + EXACT_MATCH = "exact-token" + FULL_TEXT = "full-text" + INTEGER = "integer" + TEMPORAL = "temporal" + BOOLEAN = "boolean" + + +class ServiceSearchIndexSchemaRequirements(SDLModel): + """Exact portable search-index schema operation and readback.""" + + operation: Literal["ensure-search-index-field-schema"] = "ensure-search-index-field-schema" + conflict_policy: Literal["reject-unowned-collision"] = "reject-unowned-collision" + readback: Literal["canonical-portable-field-schema-digest"] = "canonical-portable-field-schema-digest" + field_semantics: dict[PortableIdentifier, SearchIndexFieldSemantic] = Field(min_length=1) + + +class ServiceSearchIndexSchemaMaterialization(_ServiceMaterializationBase): + """Portable desired field schema for a named service-owned search index.""" + + interface_profile: Literal["service-search-index-schema"] + profile_version: Literal["1"] = "1" + requirements: ServiceSearchIndexSchemaRequirements + + +ServiceMaterializationProfile = Annotated[ + ServiceMaterialization | ServiceSearchIndexSchemaMaterialization, + Field(discriminator="interface_profile"), +] + + class Content(SDLModel): """Data or files placed into a scenario node. @@ -100,7 +138,23 @@ class Content(SDLModel): items: list[ContentItem] = Field(default_factory=list) sensitive: bool | str = False tags: list[str] = Field(default_factory=list) - service_materialization: ServiceMaterialization | None = None + service_materialization: ServiceMaterializationProfile | None = None + + @model_validator(mode="before") + @classmethod + def default_service_materialization_profile(cls, value: object) -> object: + """Preserve the original service-content default across discrimination.""" + if not isinstance(value, dict): + return value + binding = value.get("service_materialization") + if not isinstance(binding, dict) or "interface_profile" in binding: + return value + normalized = dict(value) + normalized["service_materialization"] = { + "interface_profile": "service-content", + **binding, + } + return normalized @field_validator("type", mode="before") @classmethod @@ -112,6 +166,24 @@ def normalize_type(cls, v: str) -> str: def parse_sensitive(cls, v: bool | str) -> bool | str: return parse_bool_or_var(v, field_name="sensitive") + def _validate_search_index_schema_content(self) -> bool: + if not isinstance( + self.service_materialization, + ServiceSearchIndexSchemaMaterialization, + ): + return False + if self.type != ContentType.DATASET: + raise ValueError("Search-index schema materialization requires dataset content") + if self.source is not None or self.items: + raise ValueError("Search-index schema materialization must not carry source or items") + return True + + def _validate_ordinary_dataset_content(self, *, is_search_index_schema: bool) -> None: + if self.type != ContentType.DATASET or is_search_index_schema: + return + if not (self.source or self.items): + raise ValueError("Dataset content requires either 'source' or non-empty 'items'") + @model_validator(mode="after") def validate_type_requirements(self) -> "Content": """Require the minimum anchors needed to describe real content.""" @@ -121,8 +193,10 @@ def validate_type_requirements(self) -> "Content": if self.type == ContentType.FILE and not self.path: raise ValueError("File content requires 'path'") - if self.type == ContentType.DATASET and not (self.source or self.items): - raise ValueError("Dataset content requires either 'source' or non-empty 'items'") + is_search_index_schema = self._validate_search_index_schema_content() + self._validate_ordinary_dataset_content( + is_search_index_schema=is_search_index_schema, + ) if self.type == ContentType.DIRECTORY and not self.destination: raise ValueError("Directory content requires 'destination'") diff --git a/implementations/python/packages/raes/stateful_resources.py b/implementations/python/packages/raes/stateful_resources.py index ad272dd0a..7915923f4 100644 --- a/implementations/python/packages/raes/stateful_resources.py +++ b/implementations/python/packages/raes/stateful_resources.py @@ -6,16 +6,12 @@ from pathlib import PurePosixPath from pydantic import Field, field_validator, model_validator +from raes_contracts.vocabulary import GeneratedArtifactKind from ._base import SDLModel from ._identifiers import PortableIdentifier -class GeneratedArtifactKind(str, Enum): - CERTIFICATE_BUNDLE = "certificate_bundle" - RENDERED_CONFIG = "rendered_config" - - class GeneratedArtifactLifecycle(str, Enum): REGENERATE_ON_CHANGE = "regenerate_on_change" REUSE_VALID = "reuse_valid" @@ -29,6 +25,11 @@ class ResourceSensitivity(str, Enum): SECRET = "".join(("sec", "ret")) +class GeneratedArtifactOutputDisposition(str, Enum): + CONSUMER_SELECTED = "consumer_selected" + PRODUCER_PRIVATE = "producer_private" + + class ConsumerAccessMode(str, Enum): READ_ONLY = "read_only" READ_WRITE = "read_write" @@ -82,6 +83,7 @@ class GeneratedArtifactOutput(SDLModel): name: PortableIdentifier path: str sensitivity: ResourceSensitivity + disposition: GeneratedArtifactOutputDisposition = GeneratedArtifactOutputDisposition.CONSUMER_SELECTED _contained_path = field_validator("path")(_validate_relative_path) @@ -96,6 +98,66 @@ class StatefulResourceConsumer(SDLModel): _contained_mount_destination = field_validator("mount_destination")(_validate_mount_destination) +class GeneratedArtifactConsumer(StatefulResourceConsumer): + """A read-only artifact projection selected by output name.""" + + selected_outputs: list[PortableIdentifier] = Field( + default_factory=list, + exclude_if=lambda value: not value, + min_length=1, + json_schema_extra={"uniqueItems": True}, + ) + + @model_validator(mode="after") + def _unique_selected_outputs(self) -> GeneratedArtifactConsumer: + if len(self.selected_outputs) != len(set(self.selected_outputs)): + raise ValueError("generated artifact consumer selected_outputs must be unique") + return self + + +def _validate_generated_artifact_identity(artifact: GeneratedArtifact) -> None: + names = [output.name for output in artifact.outputs] + paths = [output.path for output in artifact.outputs] + consumers = [(consumer.node, consumer.mount_destination) for consumer in artifact.consumers] + if len(names) != len(set(names)): + raise ValueError("generated artifact output names must be unique") + if len(paths) != len(set(paths)): + raise ValueError("generated artifact output paths must be unique") + if len(consumers) != len(set(consumers)): + raise ValueError("generated artifact consumers must be unique") + if any(consumer.access_mode is ConsumerAccessMode.READ_WRITE for consumer in artifact.consumers): + raise ValueError("generated artifact consumers must be read_only") + + +def _selected_generated_artifact_outputs(artifact: GeneratedArtifact) -> set[str]: + outputs_by_name = {output.name: output for output in artifact.outputs} + selected_output_names: set[str] = set() + for consumer in artifact.consumers: + if artifact.generator is GeneratedArtifactKind.SSH_KEY_BUNDLE and not consumer.selected_outputs: + raise ValueError("SSH generated artifact consumers must select at least one output") + for selected_output in consumer.selected_outputs: + output = outputs_by_name.get(selected_output) + if output is None: + raise ValueError("generated artifact consumer selects an unknown generated artifact output") + if output.disposition is GeneratedArtifactOutputDisposition.PRODUCER_PRIVATE: + raise ValueError( + "generated artifact consumer cannot select a producer-private generated artifact output" + ) + selected_output_names.add(selected_output) + return selected_output_names + + +def _validate_ssh_output_selection(artifact: GeneratedArtifact, selected_output_names: set[str]) -> None: + if artifact.generator is not GeneratedArtifactKind.SSH_KEY_BUNDLE: + return + for output in artifact.outputs: + if ( + output.disposition is GeneratedArtifactOutputDisposition.CONSUMER_SELECTED + and output.name not in selected_output_names + ): + raise ValueError("each consumer-selected SSH output must be selected by at least one consumer") + + class GeneratedArtifact(SDLModel): """Desired generated configuration or certificate/key material.""" @@ -103,23 +165,15 @@ class GeneratedArtifact(SDLModel): lifecycle: GeneratedArtifactLifecycle provenance: str = Field(min_length=1) outputs: list[GeneratedArtifactOutput] = Field(min_length=1, json_schema_extra={"uniqueItems": True}) - consumers: list[StatefulResourceConsumer] = Field(min_length=1, json_schema_extra={"uniqueItems": True}) + consumers: list[GeneratedArtifactConsumer] = Field(min_length=1, json_schema_extra={"uniqueItems": True}) ordering_dependencies: list[str] = Field(default_factory=list, json_schema_extra={"uniqueItems": True}) refresh_dependencies: list[str] = Field(default_factory=list, json_schema_extra={"uniqueItems": True}) @model_validator(mode="after") def _unique_outputs_and_consumers(self) -> GeneratedArtifact: - names = [output.name for output in self.outputs] - paths = [output.path for output in self.outputs] - consumers = [(consumer.node, consumer.mount_destination) for consumer in self.consumers] - if len(names) != len(set(names)): - raise ValueError("generated artifact output names must be unique") - if len(paths) != len(set(paths)): - raise ValueError("generated artifact output paths must be unique") - if len(consumers) != len(set(consumers)): - raise ValueError("generated artifact consumers must be unique") - if any(consumer.access_mode is ConsumerAccessMode.READ_WRITE for consumer in self.consumers): - raise ValueError("generated artifact consumers must be read_only") + _validate_generated_artifact_identity(self) + selected_output_names = _selected_generated_artifact_outputs(self) + _validate_ssh_output_selection(self, selected_output_names) if len(self.ordering_dependencies) != len(set(self.ordering_dependencies)): raise ValueError("generated artifact ordering_dependencies must be unique") if len(self.refresh_dependencies) != len(set(self.refresh_dependencies)): @@ -160,9 +214,11 @@ def _unique_consumers(self) -> PersistentVolume: __all__ = ( "ConsumerAccessMode", "GeneratedArtifact", + "GeneratedArtifactConsumer", "GeneratedArtifactKind", "GeneratedArtifactLifecycle", "GeneratedArtifactOutput", + "GeneratedArtifactOutputDisposition", "PersistentVolume", "ResourceSensitivity", "StatefulResourceConsumer", diff --git a/implementations/python/packages/raes_backend_protocols/manifest.py b/implementations/python/packages/raes_backend_protocols/manifest.py index 552a8064c..a8c53f91e 100644 --- a/implementations/python/packages/raes_backend_protocols/manifest.py +++ b/implementations/python/packages/raes_backend_protocols/manifest.py @@ -17,7 +17,6 @@ OrchestratorCapabilitiesModel, ParticipantFeatureSupportModel, ParticipantRuntimeCapabilitiesModel, - ProvisionerCapabilitiesModel, RealizationSupportDeclarationModel, TimeCapabilitiesModel, ) @@ -34,13 +33,13 @@ OrchestratorCapabilities, ParticipantFeatureSupport, ParticipantRuntimeCapabilities, - ProvisionerCapabilities, TimeCapabilities, ) from .participant_execution_manifest import ( participant_execution_capability_kwargs, participant_execution_capability_payload, ) +from .provisioner_manifest import provisioner_capability_payload, provisioner_from_model class BackendManifestEnvelopeUnsupportedError(ValueError): @@ -108,23 +107,7 @@ def backend_manifest_v2_model(manifest: BackendManifest) -> BackendManifestV2Mod ], constraints=dict(manifest.constraints), capabilities={ - "provisioner": { - "name": manifest.provisioner.name, - "supported_node_types": sorted(manifest.provisioner.supported_node_types), - "supported_os_families": sorted(manifest.provisioner.supported_os_families), - "supported_content_types": sorted(manifest.provisioner.supported_content_types), - "supported_account_features": sorted(manifest.provisioner.supported_account_features), - "supported_domain_profiles": sorted(manifest.provisioner.supported_domain_profiles), - "supported_service_materialization_profiles": sorted( - manifest.provisioner.supported_service_materialization_profiles - ), - "max_total_nodes": manifest.provisioner.max_total_nodes, - "supports_acls": manifest.provisioner.supports_acls, - "supports_accounts": manifest.provisioner.supports_accounts, - "supports_generated_artifacts": manifest.provisioner.supports_generated_artifacts, - "supports_persistent_volumes": manifest.provisioner.supports_persistent_volumes, - "constraints": dict(manifest.provisioner.constraints), - }, + "provisioner": provisioner_capability_payload(manifest.provisioner), "orchestrator": ( { "name": manifest.orchestrator.name, @@ -279,24 +262,6 @@ def _realization_support_from_model(model: RealizationSupportDeclarationModel) - ) -def _provisioner_from_model(model: ProvisionerCapabilitiesModel) -> ProvisionerCapabilities: - return ProvisionerCapabilities( - name=model.name, - supported_node_types=frozenset(model.supported_node_types), - supported_os_families=frozenset(model.supported_os_families), - supported_content_types=frozenset(model.supported_content_types), - supported_account_features=frozenset(model.supported_account_features), - supported_domain_profiles=frozenset(model.supported_domain_profiles), - supported_service_materialization_profiles=frozenset(model.supported_service_materialization_profiles), - max_total_nodes=model.max_total_nodes, - supports_acls=model.supports_acls, - supports_accounts=model.supports_accounts, - supports_generated_artifacts=model.supports_generated_artifacts, - supports_persistent_volumes=model.supports_persistent_volumes, - constraints=dict(model.constraints), - ) - - def _orchestrator_from_model(model: OrchestratorCapabilitiesModel | None) -> OrchestratorCapabilities | None: if model is None: return None @@ -429,7 +394,7 @@ def _time_from_model(model: TimeCapabilitiesModel | None) -> TimeCapabilities | def _capability_set_from_model(model: BackendCapabilitiesV2Model) -> BackendCapabilitySet: return BackendCapabilitySet( - provisioner=_provisioner_from_model(model.provisioner), + provisioner=provisioner_from_model(model.provisioner), orchestrator=_orchestrator_from_model(model.orchestrator), evaluator=_evaluator_from_model(model.evaluator), participant_runtime=_participant_runtime_from_model(model.participant_runtime), diff --git a/implementations/python/packages/raes_backend_protocols/provisioner_capabilities.py b/implementations/python/packages/raes_backend_protocols/provisioner_capabilities.py index 44d3f1443..b507d5628 100644 --- a/implementations/python/packages/raes_backend_protocols/provisioner_capabilities.py +++ b/implementations/python/packages/raes_backend_protocols/provisioner_capabilities.py @@ -3,6 +3,7 @@ from dataclasses import dataclass, field from raes_contracts.controlled_vocabularies import validate_controlled_vocabulary_scope_values +from raes_contracts.vocabulary import GeneratedArtifactKind PROVISIONER_DOMAIN_PROFILE_SCOPE = "capabilities.provisioner.supported_domain_profiles" PROVISIONER_SERVICE_MATERIALIZATION_PROFILE_SCOPE = ( @@ -37,6 +38,7 @@ class ProvisionerCapabilities: supports_acls: bool = False supports_accounts: bool = False supports_generated_artifacts: bool = False + supported_generated_artifact_kinds: frozenset[GeneratedArtifactKind] = frozenset() supports_persistent_volumes: bool = False constraints: dict[str, str] = field(default_factory=dict) @@ -79,6 +81,22 @@ def __post_init__(self) -> None: if self.max_total_nodes is not None and self.max_total_nodes < 1: raise ValueError("ProvisionerCapabilities.max_total_nodes must be positive when provided") _validate_account_support(self) + try: + normalized_artifact_kinds = frozenset( + GeneratedArtifactKind(kind) for kind in self.supported_generated_artifact_kinds + ) + except ValueError as exc: + raise ValueError("ProvisionerCapabilities contains an unknown generated artifact kind") from exc + object.__setattr__(self, "supported_generated_artifact_kinds", normalized_artifact_kinds) + if self.supports_generated_artifacts and not normalized_artifact_kinds: + raise ValueError( + "ProvisionerCapabilities that support generated artifacts must declare " + "supported_generated_artifact_kinds" + ) + if not self.supports_generated_artifacts and normalized_artifact_kinds: + raise ValueError( + "ProvisionerCapabilities supported_generated_artifact_kinds require supports_generated_artifacts=True" + ) __all__ = [ diff --git a/implementations/python/packages/raes_backend_protocols/provisioner_manifest.py b/implementations/python/packages/raes_backend_protocols/provisioner_manifest.py new file mode 100644 index 000000000..4ce8ed3bb --- /dev/null +++ b/implementations/python/packages/raes_backend_protocols/provisioner_manifest.py @@ -0,0 +1,56 @@ +"""Provisioner capability translation for backend manifest contracts.""" + +from __future__ import annotations + +from typing import Any + +from raes_contracts.contracts import ProvisionerCapabilitiesModel + +from .provisioner_capabilities import ProvisionerCapabilities + + +def provisioner_capability_payload(provisioner: ProvisionerCapabilities) -> dict[str, Any]: + """Render portable provisioner capabilities as a contract payload.""" + + return { + "name": provisioner.name, + "supported_node_types": sorted(provisioner.supported_node_types), + "supported_os_families": sorted(provisioner.supported_os_families), + "supported_content_types": sorted(provisioner.supported_content_types), + "supported_account_features": sorted(provisioner.supported_account_features), + "supported_domain_profiles": sorted(provisioner.supported_domain_profiles), + "supported_service_materialization_profiles": sorted(provisioner.supported_service_materialization_profiles), + "max_total_nodes": provisioner.max_total_nodes, + "supports_acls": provisioner.supports_acls, + "supports_accounts": provisioner.supports_accounts, + "supports_generated_artifacts": provisioner.supports_generated_artifacts, + "supported_generated_artifact_kinds": sorted( + kind.value for kind in provisioner.supported_generated_artifact_kinds + ), + "supports_persistent_volumes": provisioner.supports_persistent_volumes, + "constraints": dict(provisioner.constraints), + } + + +def provisioner_from_model(model: ProvisionerCapabilitiesModel) -> ProvisionerCapabilities: + """Restore protocol capabilities from the authoritative contract model.""" + + return ProvisionerCapabilities( + name=model.name, + supported_node_types=frozenset(model.supported_node_types), + supported_os_families=frozenset(model.supported_os_families), + supported_content_types=frozenset(model.supported_content_types), + supported_account_features=frozenset(model.supported_account_features), + supported_domain_profiles=frozenset(model.supported_domain_profiles), + supported_service_materialization_profiles=frozenset(model.supported_service_materialization_profiles), + max_total_nodes=model.max_total_nodes, + supports_acls=model.supports_acls, + supports_accounts=model.supports_accounts, + supports_generated_artifacts=model.supports_generated_artifacts, + supported_generated_artifact_kinds=frozenset(model.supported_generated_artifact_kinds), + supports_persistent_volumes=model.supports_persistent_volumes, + constraints=dict(model.constraints), + ) + + +__all__ = ["provisioner_capability_payload", "provisioner_from_model"] diff --git a/implementations/python/packages/raes_backend_protocols/service_materialization.py b/implementations/python/packages/raes_backend_protocols/service_materialization.py index a30fb0f64..9006b1cab 100644 --- a/implementations/python/packages/raes_backend_protocols/service_materialization.py +++ b/implementations/python/packages/raes_backend_protocols/service_materialization.py @@ -4,8 +4,11 @@ import re from collections.abc import Mapping, Sequence +from dataclasses import dataclass from raes_contracts.addressing import require_compiled_address +from raes_contracts.apparatus import RUNTIME_REALIZATION_DOMAIN, RealizationSupportDeclaration +from raes_contracts.canonical import canonical_json_digest from raes_contracts.diagnostics import Diagnostic from raes_contracts.planning import ChangeAction, ProvisioningPlan from raes_contracts.realization_envelope import ( @@ -18,15 +21,9 @@ from .capabilities import ProvisionerCapabilities _DIGEST_RE = re.compile(r"^sha256:[a-f0-9]{64}$") -_PROFILE = "service-content" -_VERSION = "1" -_PROFILE_TERM = "service-content-v1" -_REQUIREMENTS = { - "operation": "ensure-owned-items", - "conflict_policy": "reject-unowned-collision", - "readback": "canonical-content-digest", -} -_BINDING_FIELDS = { +_FIELD_NAME_RE = re.compile(r"^[a-z0-9][a-z0-9_-]{0,63}$", re.ASCII) +_FIELD_SEMANTICS = frozenset({"exact-token", "full-text", "integer", "temporal", "boolean"}) +_COMMON_BINDING_FIELDS = { "target_service_address", "interface_profile", "profile_version", @@ -45,10 +42,57 @@ } +@dataclass(frozen=True) +class _ProfileContract: + profile: str + version: str + capability_term: str + requirement_kind: str + requirements: Mapping[str, str] + binding_fields: frozenset[str] + schema_profile: bool = False + + +_PROFILE_CONTRACTS = { + "service-content": _ProfileContract( + profile="service-content", + version="1", + capability_term="service-content-v1", + requirement_kind="service-content-materialization", + requirements={ + "operation": "ensure-owned-items", + "conflict_policy": "reject-unowned-collision", + "readback": "canonical-content-digest", + }, + binding_fields=frozenset(_COMMON_BINDING_FIELDS), + ), + "service-search-index-schema": _ProfileContract( + profile="service-search-index-schema", + version="1", + capability_term="service-search-index-schema-v1", + requirement_kind="service-search-index-schema-materialization", + requirements={ + "operation": "ensure-search-index-field-schema", + "conflict_policy": "reject-unowned-collision", + "readback": "canonical-portable-field-schema-digest", + }, + binding_fields=frozenset( + { + *_COMMON_BINDING_FIELDS, + "field_semantics", + "canonical_field_schema_digest", + } + ), + schema_profile=True, + ), +} + + def service_materialization_plan_diagnostics( plan: ProvisioningPlan, capabilities: ProvisionerCapabilities, envelope: BackendRealizationEnvelopeModel | None, + realization_support: Sequence[RealizationSupportDeclaration] = (), ) -> list[Diagnostic]: """Validate exact profile, ownership, target, and readback before backend I/O.""" @@ -65,12 +109,24 @@ def service_materialization_plan_diagnostics( _diagnostic("provisioner.service-materialization-contract-invalid", operation.address, message) ) continue - if _PROFILE_TERM not in capabilities.supported_service_materialization_profiles: + contract = _profile_contract(binding) + assert contract is not None + if contract.capability_term not in capabilities.supported_service_materialization_profiles: diagnostics.append( _diagnostic( "provisioner.unsupported-service-materialization-profile", operation.address, - f"Provisioner does not support service materialization profile '{_PROFILE_TERM}'.", + f"Provisioner does not support service materialization profile '{contract.capability_term}'.", + ) + ) + continue + if not _exact_requirement_supported(realization_support, contract.requirement_kind): + diagnostics.append( + _diagnostic( + "realization.unsupported-exact-requirement", + operation.address, + "Backend does not declare exact realization support for service " + f"materialization requirement '{contract.requirement_kind}'.", ) ) continue @@ -87,34 +143,56 @@ def service_materialization_plan_diagnostics( def _binding_violation(payload: Mapping[str, object], binding: object) -> str | None: - if not isinstance(binding, Mapping) or set(binding) != _BINDING_FIELDS: - return "Service materialization binding is missing required closed contract fields." - violations = ( - _profile_violation(binding), - _requirements_violation(binding), - _content_type_violation(payload, binding), - _target_violation(payload, binding), - _digest_violation(binding), - _readback_violation(binding), - _ownership_violation(binding), - ) - return next((message for message in violations if message is not None), None) + if not isinstance(binding, Mapping): + violation = "Service materialization binding is missing required closed contract fields." + else: + contract = _profile_contract(binding) + if contract is None: + violation = "Service materialization profile identity is unsupported or incomplete." + elif set(binding) != contract.binding_fields: + violation = "Service materialization binding is missing required closed contract fields." + else: + violations = ( + _requirements_violation(binding, contract), + _content_type_violation(payload, binding, contract), + _target_violation(payload, binding), + _digest_violation(binding), + _field_schema_violation(binding, contract), + _readback_violation(binding), + _ownership_violation(binding), + ) + violation = next((message for message in violations if message is not None), None) + return violation -def _profile_violation(binding: Mapping[str, object]) -> str | None: - valid = binding.get("interface_profile") == _PROFILE and binding.get("profile_version") == _VERSION - return None if valid else "Service materialization profile identity is unsupported or incomplete." +def _profile_contract(binding: Mapping[str, object]) -> _ProfileContract | None: + profile = binding.get("interface_profile") + contract = _PROFILE_CONTRACTS.get(profile) if isinstance(profile, str) else None + if contract is None or binding.get("profile_version") != contract.version: + return None + return contract -def _requirements_violation(binding: Mapping[str, object]) -> str | None: - valid = all(binding.get(field) == expected for field, expected in _REQUIREMENTS.items()) +def _requirements_violation( + binding: Mapping[str, object], + contract: _ProfileContract, +) -> str | None: + valid = all(binding.get(field) == expected for field, expected in contract.requirements.items()) return None if valid else "Service materialization exact operation requirements are unsupported or incomplete." -def _content_type_violation(payload: Mapping[str, object], binding: Mapping[str, object]) -> str | None: +def _content_type_violation( + payload: Mapping[str, object], + binding: Mapping[str, object], + contract: _ProfileContract, +) -> str | None: content_type = binding.get("content_type") spec = payload.get("spec") valid = isinstance(spec, Mapping) and content_type == spec.get("type") + if contract.schema_profile: + source_is_absent = isinstance(spec, Mapping) and ("source" not in spec or spec.get("source") is None) + items_are_empty_sequence = isinstance(spec, Mapping) and spec.get("items") == [] + valid = valid and content_type == "dataset" and source_is_absent and items_are_empty_sequence return None if valid else "Service materialization content type does not match the content placement." @@ -129,6 +207,48 @@ def _digest_violation(binding: Mapping[str, object]) -> str | None: return None if valid else "Service materialization canonical content digest is invalid." +def _field_schema_violation( + binding: Mapping[str, object], + contract: _ProfileContract, +) -> str | None: + violation = None + if contract.schema_profile: + field_semantics = binding.get("field_semantics") + if ( + not isinstance(field_semantics, Mapping) + or not field_semantics + or any( + not isinstance(name, str) or _FIELD_NAME_RE.fullmatch(name) is None or semantic not in _FIELD_SEMANTICS + for name, semantic in field_semantics.items() + ) + ): + violation = "Search-index schema field semantics are empty, non-portable, or unsupported." + else: + digest = binding.get("canonical_field_schema_digest") + expected = canonical_json_digest( + { + "interface_profile": contract.profile, + "profile_version": contract.version, + "projection_scope": "declared-fields", + "field_semantics": dict(field_semantics), + } + ) + if digest != expected: + violation = "Search-index schema canonical portable field-schema digest is invalid." + return violation + + +def _exact_requirement_supported( + realization_support: Sequence[RealizationSupportDeclaration], + requirement_kind: str, +) -> bool: + return any( + declaration.domain == RUNTIME_REALIZATION_DOMAIN + and requirement_kind in declaration.supported_exact_requirement_kinds + for declaration in realization_support + ) + + def _readback_violation(binding: Mapping[str, object]) -> str | None: if _readback_refs_valid(binding): return None diff --git a/implementations/python/packages/raes_backend_stubs/manifest.py b/implementations/python/packages/raes_backend_stubs/manifest.py index 5a4dfac65..98f30ffd4 100644 --- a/implementations/python/packages/raes_backend_stubs/manifest.py +++ b/implementations/python/packages/raes_backend_stubs/manifest.py @@ -184,6 +184,7 @@ def _stub_provisioner() -> ProvisionerCapabilities: supports_acls=True, supports_accounts=True, supports_generated_artifacts=True, + supported_generated_artifact_kinds=frozenset({"certificate_bundle", "rendered_config", "ssh_key_bundle"}), supports_persistent_volumes=True, ) diff --git a/implementations/python/packages/raes_cli/_semantic_portable.py b/implementations/python/packages/raes_cli/_semantic_portable.py new file mode 100644 index 000000000..7726bc6fb --- /dev/null +++ b/implementations/python/packages/raes_cli/_semantic_portable.py @@ -0,0 +1,142 @@ +"""Portable-contract phase adapters for the semantic CLI.""" + +from __future__ import annotations + +from typing import Any + +from raes_conformance.conformance import ( + contract_payload_root, + contract_validation_strength, + validate_contract_payload, +) +from raes_contracts.diagnostics import diagnostic_payload +from raes_contracts.json_ingress import StrictJsonIngressError, parse_bounded_json + +from ._semantic_result import ( + CommandDiagnostic, + CommandStatus, + ResultMetadata, + SemanticCommandResult, + command_diagnostic, + command_result, +) + +PORTABLE_MAX_BYTES = 8 * 1024 * 1024 + + +def execute_portable( + operation: str, + contract_id: str, + raw: bytes, +) -> SemanticCommandResult: + """Dispatch a portable artifact only to its owning phase operation.""" + + root = contract_payload_root(contract_id) + if root is None: + result = command_result( + operation, + status=CommandStatus.USAGE, + contract_id=None, + diagnostics=( + command_diagnostic( + "cli.selector", + "cli", + "The contract selector is not supported.", + ), + ), + ) + elif operation == "parse" or operation not in { + "validate", + "inspect", + "conformance", + }: + result = command_result( + operation, + status=CommandStatus.UNSUPPORTED, + contract_id=contract_id, + diagnostics=( + command_diagnostic( + "cli.operation-unsupported", + "cli", + "The selected operation is not defined for this contract.", + ), + ), + ) + else: + result = _execute_registered_portable( + operation, + contract_id, + raw, + root, + ) + return result + + +def _execute_registered_portable( + operation: str, + contract_id: str, + raw: bytes, + root: str, +) -> SemanticCommandResult: + try: + payload = parse_bounded_json(raw, max_bytes=PORTABLE_MAX_BYTES, root=root) + except StrictJsonIngressError as exc: + result = command_result( + operation, + status=CommandStatus.INVALID, + contract_id=contract_id, + diagnostics=( + command_diagnostic( + f"json.{exc.code}", + "json-ingress", + "Portable JSON input was rejected.", + ), + ), + ) + else: + owning_diagnostics = validate_contract_payload(contract_id, payload) + diagnostics = tuple(CommandDiagnostic(**diagnostic_payload(item)) for item in owning_diagnostics) + status = CommandStatus.INVALID if any(item.is_error for item in owning_diagnostics) else CommandStatus.SUCCESS + result = command_result( + operation, + status=status, + contract_id=contract_id, + payload=_phase_summary(operation, root, payload, status), + diagnostics=diagnostics, + metadata=ResultMetadata( + validation_strength=contract_validation_strength(contract_id), + ), + ) + return result + + +def _phase_summary( + operation: str, + root: str, + payload: dict[str, Any] | list[Any], + status: CommandStatus, +) -> dict[str, Any]: + if operation == "validate": + return { + "phase": "contract-admission", + "root_type": root, + "member_count": len(payload), + "admitted": status is CommandStatus.SUCCESS, + } + if operation == "inspect": + summary: dict[str, Any] = { + "phase": "inspection", + "root_type": root, + "member_count": len(payload), + } + if isinstance(payload, dict): + summary["members"] = sorted(payload) + else: + summary["item_count"] = len(payload) + return summary + return { + "phase": "contract-conformance", + "root_type": root, + "check": "registered-contract", + "passed": status is CommandStatus.SUCCESS, + } diff --git a/implementations/python/packages/raes_cli/_semantic_result.py b/implementations/python/packages/raes_cli/_semantic_result.py new file mode 100644 index 000000000..3672a31cb --- /dev/null +++ b/implementations/python/packages/raes_cli/_semantic_result.py @@ -0,0 +1,157 @@ +"""Typed result and presentation boundary for semantic CLI commands.""" + +from __future__ import annotations + +import json +from dataclasses import dataclass +from enum import Enum +from typing import Any + +import typer +from pydantic import BaseModel, ConfigDict, Field +from raes import ( + SDL_CANONICAL_PROFILE, + SDL_SOURCE_FORMAT, + SDLMigrationPolicy, +) + + +class OutputFormat(str, Enum): + """Supported presentation modes.""" + + HUMAN = "human" + JSON = "json" + + +class CommandStatus(str, Enum): + """Stable status classes mapped onto the documented exit taxonomy.""" + + SUCCESS = "success" + INVALID = "invalid" + USAGE = "usage" + UNSUPPORTED = "unsupported" + OPERATIONAL = "operational" + INTERNAL = "internal" + + +_EXIT_CODES = { + CommandStatus.SUCCESS: 0, + CommandStatus.INVALID: 1, + CommandStatus.USAGE: 2, + CommandStatus.UNSUPPORTED: 3, + CommandStatus.OPERATIONAL: 4, + CommandStatus.INTERNAL: 70, +} + + +class CommandDiagnostic(BaseModel): + """Value-free diagnostic projected from an owning semantic boundary.""" + + model_config = ConfigDict(extra="forbid", frozen=True) + + code: str + domain: str + address: str = "" + message: str + severity: str = "error" + + +class SemanticCommandResult(BaseModel): + """Single typed result consumed by both human and JSON renderers.""" + + model_config = ConfigDict(extra="forbid", frozen=True) + + operation: str + status: CommandStatus + contract_id: str | None + source_format: str | None = None + migration_policy: str | None = None + normalization_profile: str | None = None + validation_strength: str | None = None + processor_profile: str | None = None + transform_profile: str | None = None + provenance: dict[str, str] = Field(default_factory=dict) + payload: dict[str, Any] = Field(default_factory=dict) + diagnostics: tuple[CommandDiagnostic, ...] = () + + +@dataclass(frozen=True) +class ResultMetadata: + """Optional profile metadata attached to one command result.""" + + migration_policy: SDLMigrationPolicy = SDLMigrationPolicy.REJECT + validation_strength: str | None = None + processor_profile: str | None = None + transform_profile: str | None = None + + +def command_result( + operation: str, + *, + status: CommandStatus = CommandStatus.SUCCESS, + contract_id: str | None, + payload: dict[str, Any] | None = None, + diagnostics: tuple[CommandDiagnostic, ...] = (), + metadata: ResultMetadata | None = None, +) -> SemanticCommandResult: + """Build the one result shape shared by all semantic presentations.""" + + effective_metadata = metadata or ResultMetadata() + is_sdl = contract_id == SDL_SOURCE_FORMAT + return SemanticCommandResult( + operation=operation, + status=status, + contract_id=contract_id, + source_format=SDL_SOURCE_FORMAT if is_sdl else None, + migration_policy=(effective_metadata.migration_policy.value if is_sdl else None), + normalization_profile=SDL_CANONICAL_PROFILE if is_sdl else None, + validation_strength=effective_metadata.validation_strength, + processor_profile=effective_metadata.processor_profile, + transform_profile=effective_metadata.transform_profile, + provenance={ + "network": "disabled", + "filesystem": "read-only", + }, + payload=payload or {}, + diagnostics=diagnostics, + ) + + +def command_diagnostic( + code: str, + domain: str, + message: str, + *, + address: str = "", + severity: str = "error", +) -> CommandDiagnostic: + """Build a sanitized diagnostic suitable for either renderer.""" + + return CommandDiagnostic( + code=code, + domain=domain, + address=address, + message=message, + severity=severity, + ) + + +def render_result(result: SemanticCommandResult, output: OutputFormat) -> None: + """Render a result and apply the stable process-exit mapping.""" + + if output is OutputFormat.JSON: + typer.echo(json.dumps(result.model_dump(mode="json"), indent=2, sort_keys=True)) + else: + content = result.payload.get("content") + if isinstance(content, str): + typer.echo(content, nl=not content.endswith("\n")) + else: + typer.echo(f"{result.operation}: {result.status.value}") + for diagnostic in result.diagnostics: + typer.echo( + f"{diagnostic.severity} [{diagnostic.code}] {diagnostic.message}", + err=True, + ) + code = _EXIT_CODES[result.status] + if code: + raise typer.Exit(code=code) diff --git a/implementations/python/packages/raes_cli/_semantic_sdl.py b/implementations/python/packages/raes_cli/_semantic_sdl.py new file mode 100644 index 000000000..3043dc4cc --- /dev/null +++ b/implementations/python/packages/raes_cli/_semantic_sdl.py @@ -0,0 +1,404 @@ +"""SDL phase adapters for the semantic CLI.""" + +from __future__ import annotations + +from collections.abc import Callable +from dataclasses import dataclass +from enum import Enum + +from raes import ( + SDL_SOURCE_FORMAT, + Scenario, + SDLError, + SDLInstantiationError, + SDLMigrationPolicy, + SDLParseError, + SDLValidationError, + build_declaration_index, + canonical_sdl_bytes, + canonical_sdl_digest, + format_sdl_source, + parse_sdl, +) +from raes_processor.compiler import compile_scenario_runtime_model +from raes_processor.models import RuntimeModel + +from ._semantic_result import ( + CommandDiagnostic, + CommandStatus, + ResultMetadata, + SemanticCommandResult, + command_diagnostic, + command_result, +) + + +class TransformProfile(str, Enum): + """Closed transformations owned by the RAES semantic layer.""" + + CANONICAL = "canonical" + FORMAT = "format" + + +@dataclass(frozen=True) +class _SdlContext: + operation: str + text: str + scenario: Scenario + advisories: tuple[CommandDiagnostic, ...] + migration_policy: SDLMigrationPolicy + transform: TransformProfile | None + + +def _metadata( + context: _SdlContext, + *, + validation_strength: str | None = None, + processor_profile: str | None = None, + transform_profile: str | None = None, +) -> ResultMetadata: + return ResultMetadata( + migration_policy=context.migration_policy, + validation_strength=validation_strength, + processor_profile=processor_profile, + transform_profile=transform_profile, + ) + + +def _sdl_diagnostics(exc: SDLError) -> tuple[CommandDiagnostic, ...]: + if isinstance(exc, SDLParseError) and exc.diagnostics: + diagnostics = tuple( + command_diagnostic( + diagnostic.code, + "sdl-parse", + "SDL input was rejected at the parse stage.", + address=diagnostic.pointer, + severity=diagnostic.severity, + ) + for diagnostic in exc.diagnostics[:20] + ) + elif isinstance(exc, SDLParseError): + diagnostics = ( + command_diagnostic( + "sdl.parse", + "sdl-parse", + "SDL input was rejected at the parse stage.", + ), + ) + elif isinstance(exc, SDLValidationError): + diagnostics = ( + command_diagnostic( + "sdl.validation", + "sdl-validation", + f"SDL semantic validation reported {len(exc.errors)} error(s).", + ), + ) + elif isinstance(exc, SDLInstantiationError): + diagnostics = ( + command_diagnostic( + "sdl.instantiation", + "sdl-instantiation", + f"SDL instantiation reported {len(exc.errors)} error(s).", + ), + ) + else: + diagnostics = ( + command_diagnostic( + "sdl.invalid", + "sdl", + "SDL input was rejected.", + ), + ) + return diagnostics + + +def _parse_sdl_input( + raw: bytes, + *, + semantic_validation: bool, + migration_policy: SDLMigrationPolicy, +) -> tuple[str, Scenario]: + try: + text = raw.decode("utf-8") + except UnicodeDecodeError as exc: + raise SDLParseError("SDL source must be valid UTF-8.") from exc + scenario = parse_sdl( + text, + skip_semantic_validation=not semantic_validation, + source_format=SDL_SOURCE_FORMAT, + migration_policy=migration_policy, + ) + return text, scenario + + +def _build_context( + operation: str, + raw: bytes, + migration_policy: SDLMigrationPolicy, + transform: TransformProfile | None, +) -> _SdlContext: + text, scenario = _parse_sdl_input( + raw, + semantic_validation=operation != "parse", + migration_policy=migration_policy, + ) + advisories = tuple( + command_diagnostic( + diagnostic.code, + "sdl-parse", + diagnostic.message, + address=diagnostic.pointer, + severity=diagnostic.severity, + ) + for diagnostic in scenario.source_diagnostics + ) + return _SdlContext( + operation=operation, + text=text, + scenario=scenario, + advisories=advisories, + migration_policy=migration_policy, + transform=transform, + ) + + +def _scenario_summary(scenario: Scenario, *, phase: str) -> dict[str, object]: + fields = scenario.model_dump(mode="json", by_alias=True, exclude_unset=True) + return { + "phase": phase, + "root_type": "object", + "scenario_name": scenario.name, + "field_count": len(fields), + "semantic_validated": scenario.semantic_validated, + } + + +def _inspection_payload(scenario: Scenario) -> dict[str, object]: + index = build_declaration_index(scenario) + declarations = [ + { + "address": declaration.address, + "kind": declaration.kind, + "model_path": declaration.model_path, + "referenceable": declaration.referenceable, + "targetable": declaration.targetable, + } + for declaration in index.declarations + ] + return { + "phase": "inspection", + "root_type": "object", + "scenario_name": scenario.name, + "declaration_count": len(declarations), + "declarations": declarations, + } + + +def _resolution_payload(scenario: Scenario) -> dict[str, object]: + aliases = build_declaration_index(scenario).reference_aliases() + return { + "phase": "resolved-references", + "root_type": "object", + "scenario_name": scenario.name, + "reference_binding_count": len(aliases), + "reference_bindings": {alias: sorted(addresses) for alias, addresses in sorted(aliases.items())}, + } + + +def _runtime_summary(runtime_model: RuntimeModel) -> dict[str, object]: + return { + "phase": "compiled-runtime-summary", + "root_type": "object", + "scenario_name": runtime_model.scenario_name, + "resource_counts": { + "networks": len(runtime_model.networks), + "node_deployments": len(runtime_model.node_deployments), + "feature_bindings": len(runtime_model.feature_bindings), + "propositions": len(runtime_model.propositions), + "assertions": len(runtime_model.assertions), + "injects": len(runtime_model.injects), + "events": len(runtime_model.events), + "scripts": len(runtime_model.scripts), + "stories": len(runtime_model.stories), + "workflows": len(runtime_model.workflows), + "objectives": len(runtime_model.objectives), + }, + "diagnostic_count": len(runtime_model.diagnostics), + } + + +def _execute_admission(context: _SdlContext) -> SemanticCommandResult: + is_parse = context.operation == "parse" + return command_result( + context.operation, + contract_id=SDL_SOURCE_FORMAT, + payload=_scenario_summary( + context.scenario, + phase="parsed-authoring" if is_parse else "validated-authoring", + ), + diagnostics=context.advisories, + metadata=_metadata( + context, + validation_strength="structural" if is_parse else "semantic", + ), + ) + + +def _execute_normalize(context: _SdlContext) -> SemanticCommandResult: + formatted = format_sdl_source(context.text) + return command_result( + context.operation, + contract_id=SDL_SOURCE_FORMAT, + payload={ + **_scenario_summary( + context.scenario, + phase="normalized-authoring", + ), + "content": formatted.content, + "digest": canonical_sdl_digest(context.scenario).as_dict(), + }, + diagnostics=context.advisories, + metadata=_metadata(context, validation_strength="semantic"), + ) + + +def _execute_resolve(context: _SdlContext) -> SemanticCommandResult: + return command_result( + context.operation, + contract_id=SDL_SOURCE_FORMAT, + payload=_resolution_payload(context.scenario), + diagnostics=context.advisories, + metadata=_metadata(context, validation_strength="semantic"), + ) + + +def _execute_compile(context: _SdlContext) -> SemanticCommandResult: + runtime_model = compile_scenario_runtime_model(context.scenario) + compiler_diagnostics = tuple( + command_diagnostic( + item.code, + item.domain, + "The compiler reported a diagnostic.", + address=item.address, + severity=item.severity.value, + ) + for item in runtime_model.diagnostics + ) + return command_result( + context.operation, + contract_id=SDL_SOURCE_FORMAT, + payload=_runtime_summary(runtime_model), + diagnostics=(*context.advisories, *compiler_diagnostics), + metadata=_metadata( + context, + validation_strength="semantic", + processor_profile="raes-compiler/default", + ), + ) + + +def _execute_transform(context: _SdlContext) -> SemanticCommandResult: + selected = context.transform or TransformProfile.CANONICAL + digest: dict[str, str] | None = None + if selected is TransformProfile.FORMAT: + content = format_sdl_source(context.text).content + else: + content = canonical_sdl_bytes(context.scenario).decode("utf-8") + digest = canonical_sdl_digest(context.scenario).as_dict() + payload: dict[str, object] = { + "phase": "transformed", + "root_type": "object", + "content": content, + } + if digest is not None: + payload["digest"] = digest + return command_result( + context.operation, + contract_id=SDL_SOURCE_FORMAT, + payload=payload, + diagnostics=context.advisories, + metadata=_metadata( + context, + validation_strength="semantic", + transform_profile=selected.value, + ), + ) + + +def _execute_inspect(context: _SdlContext) -> SemanticCommandResult: + return command_result( + context.operation, + contract_id=SDL_SOURCE_FORMAT, + payload=_inspection_payload(context.scenario), + diagnostics=context.advisories, + metadata=_metadata(context, validation_strength="semantic"), + ) + + +_SDL_HANDLERS: dict[ + str, + Callable[[_SdlContext], SemanticCommandResult], +] = { + "parse": _execute_admission, + "validate": _execute_admission, + "normalize": _execute_normalize, + "resolve": _execute_resolve, + "compile": _execute_compile, + "transform": _execute_transform, + "inspect": _execute_inspect, +} + + +def execute_sdl( + operation: str, + raw: bytes, + *, + migration_policy: SDLMigrationPolicy, + transform: TransformProfile | None, +) -> SemanticCommandResult: + """Dispatch one SDL artifact to its owning semantic phase.""" + + if operation == "conformance": + result = command_result( + operation, + status=CommandStatus.UNSUPPORTED, + contract_id=SDL_SOURCE_FORMAT, + metadata=ResultMetadata(migration_policy=migration_policy), + ) + else: + try: + context = _build_context( + operation, + raw, + migration_policy, + transform, + ) + except SDLError as exc: + result = command_result( + operation, + status=CommandStatus.INVALID, + contract_id=SDL_SOURCE_FORMAT, + diagnostics=_sdl_diagnostics(exc), + metadata=ResultMetadata(migration_policy=migration_policy), + ) + else: + handler = _SDL_HANDLERS.get(operation) + if handler is None: + result = command_result( + operation, + status=CommandStatus.INTERNAL, + contract_id=SDL_SOURCE_FORMAT, + diagnostics=( + command_diagnostic( + "cli.internal", + "cli", + "The semantic operation did not produce a result.", + ), + ), + metadata=ResultMetadata( + migration_policy=migration_policy, + ), + ) + else: + result = handler(context) + return result diff --git a/implementations/python/packages/raes_cli/main.py b/implementations/python/packages/raes_cli/main.py index 273423fc3..8ccf35658 100644 --- a/implementations/python/packages/raes_cli/main.py +++ b/implementations/python/packages/raes_cli/main.py @@ -4,7 +4,7 @@ import typer -from raes_cli import conformance, corpus, libvirt, processor, sdl +from raes_cli import conformance, corpus, libvirt, processor, sdl, semantic app = typer.Typer( name="raes", @@ -15,6 +15,7 @@ app.add_typer(sdl.app, name="sdl") app.add_typer(processor.app, name="processor") app.add_typer(conformance.app, name="conformance") +app.add_typer(semantic.app, name="semantic") app.add_typer(libvirt.app, name="libvirt") app.add_typer(corpus.app, name="corpus") diff --git a/implementations/python/packages/raes_cli/semantic.py b/implementations/python/packages/raes_cli/semantic.py new file mode 100644 index 000000000..c08b6888e --- /dev/null +++ b/implementations/python/packages/raes_cli/semantic.py @@ -0,0 +1,233 @@ +"""Offline, read-only command surface for RAES semantic operations.""" + +from __future__ import annotations + +from pathlib import Path + +import click +import typer +from raes import ( + SDL_SOURCE_FORMAT, + SDLMigrationPolicy, + SDLParserLimits, +) +from raes_conformance.conformance import contract_payload_root + +from ._semantic_portable import PORTABLE_MAX_BYTES, execute_portable +from ._semantic_result import ( + CommandStatus, + OutputFormat, + ResultMetadata, + SemanticCommandResult, +) +from ._semantic_result import ( + command_diagnostic as _diagnostic, +) +from ._semantic_result import ( + command_result as _result, +) +from ._semantic_result import ( + render_result as _render, +) +from ._semantic_sdl import TransformProfile, execute_sdl + +app = typer.Typer( + help="Parse, validate, normalize, resolve, compile, transform, inspect, and check RAES artifacts.", + no_args_is_help=True, +) + +_SDL_CONTRACT_ID = SDL_SOURCE_FORMAT +_SDL_MAX_BYTES = SDLParserLimits().max_input_bytes +_SOURCE_HELP = "Input path or '-' for stdin." +_CONTRACT_HELP = "Explicit versioned contract id." + + +def _read_input(source: str, *, max_bytes: int) -> bytes: + if source == "-": + raw = click.get_binary_stream("stdin").read(max_bytes + 1) + else: + path = Path(source) + with path.open("rb") as stream: + raw = stream.read(max_bytes + 1) + if len(raw) > max_bytes: + raise OSError("input exceeds the configured byte limit") + return raw + + +def _execute( + operation: str, + source: str, + *, + contract_id: str, + migration_policy: SDLMigrationPolicy, + transform: TransformProfile | None = None, +) -> SemanticCommandResult: + if contract_id != _SDL_CONTRACT_ID and contract_payload_root(contract_id) is None: + result = _result( + operation, + status=CommandStatus.USAGE, + contract_id=None, + diagnostics=(_diagnostic("cli.selector", "cli", "The contract selector is not supported."),), + ) + else: + max_bytes = _SDL_MAX_BYTES if contract_id == _SDL_CONTRACT_ID else PORTABLE_MAX_BYTES + try: + raw = _read_input(source, max_bytes=max_bytes) + except OSError: + result = _result( + operation, + status=CommandStatus.OPERATIONAL, + contract_id=contract_id, + diagnostics=( + _diagnostic( + "cli.input", + "cli", + "The input could not be read within the configured bounds.", + ), + ), + metadata=ResultMetadata(migration_policy=migration_policy), + ) + else: + try: + if contract_id == _SDL_CONTRACT_ID: + result = execute_sdl( + operation, + raw, + migration_policy=migration_policy, + transform=transform, + ) + else: + result = execute_portable(operation, contract_id, raw) + except Exception: + result = _result( + operation, + status=CommandStatus.INTERNAL, + contract_id=contract_id, + diagnostics=( + _diagnostic( + "cli.internal", + "cli", + "The operation failed unexpectedly.", + ), + ), + metadata=ResultMetadata(migration_policy=migration_policy), + ) + return result + + +def _run( + operation: str, + source: str, + contract: str, + output: OutputFormat, + migration_policy: SDLMigrationPolicy, + *, + transform: TransformProfile | None = None, +) -> None: + _render( + _execute( + operation, + source, + contract_id=contract, + migration_policy=migration_policy, + transform=transform, + ), + output, + ) + + +@app.command("parse") +def parse_command( + source: str = typer.Argument(..., help=_SOURCE_HELP), + contract: str = typer.Option(_SDL_CONTRACT_ID, "--contract", help=_CONTRACT_HELP), + output: OutputFormat = typer.Option(OutputFormat.HUMAN, "--output"), + migration_policy: SDLMigrationPolicy = typer.Option(SDLMigrationPolicy.REJECT, "--migration-policy"), +) -> None: + """Perform bounded decoding and typed construction without a validity claim.""" + + _run("parse", source, contract, output, migration_policy) + + +@app.command("validate") +def validate_command( + source: str = typer.Argument(..., help=_SOURCE_HELP), + contract: str = typer.Option(_SDL_CONTRACT_ID, "--contract", help=_CONTRACT_HELP), + output: OutputFormat = typer.Option(OutputFormat.HUMAN, "--output"), + migration_policy: SDLMigrationPolicy = typer.Option(SDLMigrationPolicy.REJECT, "--migration-policy"), +) -> None: + """Run the owning structural and semantic admission checks.""" + + _run("validate", source, contract, output, migration_policy) + + +@app.command("normalize") +def normalize_command( + source: str = typer.Argument(..., help=_SOURCE_HELP), + contract: str = typer.Option(_SDL_CONTRACT_ID, "--contract", help=_CONTRACT_HELP), + output: OutputFormat = typer.Option(OutputFormat.HUMAN, "--output"), + migration_policy: SDLMigrationPolicy = typer.Option(SDLMigrationPolicy.REJECT, "--migration-policy"), +) -> None: + """Emit a deterministic normalized representation and provenance.""" + + _run("normalize", source, contract, output, migration_policy) + + +@app.command("resolve") +def resolve_command( + source: str = typer.Argument(..., help=_SOURCE_HELP), + contract: str = typer.Option(_SDL_CONTRACT_ID, "--contract", help=_CONTRACT_HELP), + output: OutputFormat = typer.Option(OutputFormat.HUMAN, "--output"), + migration_policy: SDLMigrationPolicy = typer.Option(SDLMigrationPolicy.REJECT, "--migration-policy"), +) -> None: + """Resolve and inspect local SDL declarations without acquisition or writes.""" + + _run("resolve", source, contract, output, migration_policy) + + +@app.command("compile") +def compile_command( + source: str = typer.Argument(..., help=_SOURCE_HELP), + contract: str = typer.Option(_SDL_CONTRACT_ID, "--contract", help=_CONTRACT_HELP), + output: OutputFormat = typer.Option(OutputFormat.HUMAN, "--output"), + migration_policy: SDLMigrationPolicy = typer.Option(SDLMigrationPolicy.REJECT, "--migration-policy"), +) -> None: + """Compile SDL and emit a bounded typed runtime-model summary.""" + + _run("compile", source, contract, output, migration_policy) + + +@app.command("transform") +def transform_command( + source: str = typer.Argument(..., help=_SOURCE_HELP), + contract: str = typer.Option(_SDL_CONTRACT_ID, "--contract", help=_CONTRACT_HELP), + transform: TransformProfile = typer.Option(..., "--transform", help="Closed transform profile."), + output: OutputFormat = typer.Option(OutputFormat.HUMAN, "--output"), + migration_policy: SDLMigrationPolicy = typer.Option(SDLMigrationPolicy.REJECT, "--migration-policy"), +) -> None: + """Apply one explicitly selected RAES-owned transformation.""" + + _run("transform", source, contract, output, migration_policy, transform=transform) + + +@app.command("inspect") +def inspect_command( + source: str = typer.Argument(..., help=_SOURCE_HELP), + contract: str = typer.Option(_SDL_CONTRACT_ID, "--contract", help=_CONTRACT_HELP), + output: OutputFormat = typer.Option(OutputFormat.HUMAN, "--output"), + migration_policy: SDLMigrationPolicy = typer.Option(SDLMigrationPolicy.REJECT, "--migration-policy"), +) -> None: + """Inspect admitted typed artifacts without exposing raw values.""" + + _run("inspect", source, contract, output, migration_policy) + + +@app.command("conformance") +def conformance_command( + source: str = typer.Argument(..., help=_SOURCE_HELP), + contract: str = typer.Option(_SDL_CONTRACT_ID, "--contract", help=_CONTRACT_HELP), + output: OutputFormat = typer.Option(OutputFormat.HUMAN, "--output"), + migration_policy: SDLMigrationPolicy = typer.Option(SDLMigrationPolicy.REJECT, "--migration-policy"), +) -> None: + """Run RAES-owned local conformance checks without invoking a target.""" + + _run("conformance", source, contract, output, migration_policy) diff --git a/implementations/python/packages/raes_conformance/conformance/__init__.py b/implementations/python/packages/raes_conformance/conformance/__init__.py index a22c40698..b0ede9fbd 100644 --- a/implementations/python/packages/raes_conformance/conformance/__init__.py +++ b/implementations/python/packages/raes_conformance/conformance/__init__.py @@ -37,6 +37,9 @@ _validate_payload as _validate_payload, ) from raes_conformance.conformance.validators import ( + contract_payload_root, + contract_validation_strength, + supported_contract_ids, validate_contract_payload, ) @@ -46,6 +49,8 @@ "BackendProfileSelector", "ConformanceCaseResult", "backend_conformance_report_payload", + "contract_payload_root", + "contract_validation_strength", "fixtures_root", "observability_evidence_conformance_diagnostics", "profile_for_manifest", @@ -53,5 +58,6 @@ "required_contracts", "run_fixture_suite", "run_target_conformance", + "supported_contract_ids", "validate_contract_payload", ] diff --git a/implementations/python/packages/raes_conformance/conformance/validators.py b/implementations/python/packages/raes_conformance/conformance/validators.py index 77b94587d..4cf2f60b5 100644 --- a/implementations/python/packages/raes_conformance/conformance/validators.py +++ b/implementations/python/packages/raes_conformance/conformance/validators.py @@ -5,6 +5,7 @@ from raes_contracts.behavioral_relation_profiles import BehavioralRelationProfileModel from raes_contracts.behavioral_relations import BehavioralRelationCatalogModel from raes_contracts.contracts import ( + ActivityStreamsActivityTypesSourceModel, AssociatedArtifactManifestModel, BackendManifestV2Model, EvaluationHistoryEventModel, @@ -19,6 +20,7 @@ ExperimentSpecModel, ExperimentStudyModel, ExternalConceptBindingDocumentModel, + FipaCommunicativeActsSourceModel, OperationReceiptModel, OperationStatusModel, OrchestrationPlanModel, @@ -98,6 +100,7 @@ "behavioral-relation-profile-v1": BehavioralRelationProfileModel.model_validate, "behavioral-relations-v1": BehavioralRelationCatalogModel.model_validate, "external-concept-bindings-v1": ExternalConceptBindingDocumentModel.model_validate, + "fipa-communicative-acts-source-v1": FipaCommunicativeActsSourceModel.model_validate, "experiment-apparatus-context-v1": ExperimentApparatusContextModel.model_validate, "experiment-authoring-input-v1": ExperimentSpecModel.model_validate, "experiment-study-v1": ExperimentStudyModel.model_validate, @@ -110,6 +113,7 @@ "participant-opacity-analysis-evidence-v1": ParticipantOpacityAnalysisEvidenceModel.model_validate, "participant-opacity-model-check-input-v1": ParticipantOpacityModelCheckInputModel.model_validate, "participant-opacity-model-check-evidence-v1": ParticipantOpacityModelCheckEvidenceModel.model_validate, + "w3c-activitystreams-activity-types-source-v1": ActivityStreamsActivityTypesSourceModel.model_validate, } @@ -211,3 +215,33 @@ def validate_contract_payload(contract_name: str, payload: object) -> tuple[Diag """Validate one payload through the registered structural contract boundary.""" return tuple(_validate_payload(contract_name, payload)) + + +def supported_contract_ids() -> tuple[str, ...]: + """Return the contract ids owned by the conformance validator registry.""" + + return tuple(sorted((*_MODEL_VALIDATORS, *_STRUCTURAL_ONLY_VALIDATORS, *_EVENT_STREAM_VALIDATORS))) + + +def contract_payload_root(contract_name: str) -> str | None: + """Return the required JSON root shape for a registered contract.""" + + if contract_name in _EVENT_STREAM_VALIDATORS: + return "array" + if contract_name in _MODEL_VALIDATORS or contract_name in _STRUCTURAL_ONLY_VALIDATORS: + return "object" + return None + + +def contract_validation_strength(contract_name: str) -> str | None: + """Return the strongest context-free validation claim for a contract.""" + + if contract_name in _SEMANTIC_CONTEXT_REQUIRED_CONTRACTS: + strength = "structural-context-required" + elif contract_name in _STRUCTURAL_ONLY_VALIDATORS: + strength = "structural" + elif contract_name in _MODEL_VALIDATORS or contract_name in _EVENT_STREAM_VALIDATORS: + strength = "semantic" + else: + strength = None + return strength diff --git a/implementations/python/packages/raes_contracts/behavioral_relation_profiles.py b/implementations/python/packages/raes_contracts/behavioral_relation_profiles.py index 4348b3023..80646fef4 100644 --- a/implementations/python/packages/raes_contracts/behavioral_relation_profiles.py +++ b/implementations/python/packages/raes_contracts/behavioral_relation_profiles.py @@ -6,7 +6,9 @@ from pathlib import Path from typing import Annotated, Literal -from pydantic import Field, model_validator +from pydantic import Field, GetJsonSchemaHandler, model_validator +from pydantic.json_schema import JsonSchemaValue +from pydantic_core import CoreSchema from raes.identifiers import is_portable_identifier from .canonical import canonical_json_digest @@ -21,7 +23,12 @@ from .versions import BEHAVIORAL_RELATION_PROFILE_SCHEMA_VERSION _MAX_PROFILE_BYTES = 256 * 1024 -SUPPORTED_BEHAVIORAL_RELATION_PROFILE_IDS = frozenset({"participant-opacity-baseline-v1"}) +SUPPORTED_BEHAVIORAL_RELATION_PROFILE_IDS = frozenset( + { + "participant-opacity-baseline-v1", + "participant-opacity-theorem-v1", + } +) ProfileId = Annotated[ str, @@ -42,6 +49,17 @@ def _require_sorted_unique(values: tuple[str, ...], label: str) -> None: raise ValueError(f"{label} must be unique and use canonical sorted order") +def _carrier_kind_condition(kind: str, *, nested: bool = False) -> dict[str, object]: + carrier: dict[str, object] = { + "properties": {"kind": {"const": kind}}, + "required": ["kind"], + } + if not nested: + return {"properties": {"carrier": carrier}, "required": ["carrier"]} + parameters = {"properties": {"carrier": carrier}, "required": ["carrier"]} + return {"properties": {"parameters": parameters}, "required": ["parameters"]} + + class BehavioralProfileSourceModel(ContractModel): """Immutable source identity used to reproduce one profile revision.""" @@ -84,12 +102,30 @@ class OpacitySecretPredicateModel(ContractModel): truth_polarity: Literal["one-sided-true"] -class OpacityCarrierModel(ContractModel): +class FiniteOpacityCarrierModel(ContractModel): kind: Literal["finite-possible-points"] reachability_ref: SafeRef reachability_revision: Revision +class AbstractOpacityCarrierModel(ContractModel): + """An abstract carrier whose proof obligations are discharged by a theorem session.""" + + kind: Literal["abstract-possible-points"] + reachability_ref: SafeRef + reachability_revision: Revision + eligibility_ref: SafeRef + eligibility_revision: Revision + correspondence_ref: SafeRef + correspondence_revision: Revision + + +OpacityCarrierModel = Annotated[ + FiniteOpacityCarrierModel | AbstractOpacityCarrierModel, + Field(discriminator="kind"), +] + + class OpacityInitialInformationModel(ContractModel): projection_ref: SafeRef projection_revision: Revision @@ -242,7 +278,7 @@ class ParticipantPredicateOpacityParametersModel(ContractModel): order: OpacityOrderModel time: OpacityTimeModel probability: Literal["outside-baseline"] - bounds: OpacityFiniteBoundsModel + bounds: OpacityFiniteBoundsModel | None = None @model_validator(mode="after") def _validate_domains( @@ -250,9 +286,15 @@ def _validate_domains( ) -> ParticipantPredicateOpacityParametersModel: _require_sorted_unique(self.scheduler_refs, "scheduler refs") _require_sorted_unique(self.environment_refs, "environment refs") + if isinstance(self.carrier, FiniteOpacityCarrierModel) and self.bounds is None: + raise ValueError("finite opacity carriers require declared finite bounds") + if isinstance(self.carrier, AbstractOpacityCarrierModel) and self.bounds is not None: + raise ValueError("abstract theorem carriers must not declare finite bounds") strategy_count = ( len(self.strategy.strategy_refs) if isinstance(self.strategy, ActiveOpacityStrategyModel) else 1 ) + if self.bounds is None: + return self if strategy_count > self.bounds.max_strategies: raise ValueError("declared strategies exceed the finite profile bound") if len(self.order.order_refs) > self.bounds.max_order_variants: @@ -261,6 +303,30 @@ def _validate_domains( raise ValueError("declared scheduler/environment pairs exceed the finite profile bound") return self + @classmethod + def __get_pydantic_json_schema__( + cls, + core_schema: CoreSchema, + handler: GetJsonSchemaHandler, + ) -> JsonSchemaValue: + json_schema = handler.resolve_ref_schema(handler(core_schema)) + json_schema.setdefault("allOf", []).extend( + [ + { + "if": _carrier_kind_condition("finite-possible-points"), + "then": { + "properties": {"bounds": {"type": "object"}}, + "required": ["bounds"], + }, + }, + { + "if": _carrier_kind_condition("abstract-possible-points"), + "then": {"properties": {"bounds": {"type": "null"}}}, + }, + ] + ) + return json_schema + class BehavioralRelationProfileModel(ContractModel): """One resolved relation profile with a closed parameter variant.""" @@ -274,7 +340,10 @@ class BehavioralRelationProfileModel(ContractModel): left_carrier_ref: SafeRef observation_projection_ref: SafeRef observation_projection_revision: Revision - finite_analysis_scope: Literal["declared-complete-finite-carrier"] + finite_analysis_scope: Literal[ + "declared-complete-finite-carrier", + "abstract-parameterized-theorem-carrier", + ] parameters: ParticipantPredicateOpacityParametersModel source_refs: tuple[BehavioralProfileSourceModel, ...] = Field( min_length=1, @@ -295,8 +364,35 @@ def _validate_profile_join(self) -> BehavioralRelationProfileModel: raise ValueError("profile observation projection must match the parameter projection") source_ids = tuple(item.source_ref for item in self.source_refs) _require_sorted_unique(source_ids, "profile source refs") + finite_variant = isinstance(self.parameters.carrier, FiniteOpacityCarrierModel) + if finite_variant != (self.finite_analysis_scope == "declared-complete-finite-carrier"): + raise ValueError("profile assurance scope must match its carrier variant") return self + @classmethod + def __get_pydantic_json_schema__( + cls, + core_schema: CoreSchema, + handler: GetJsonSchemaHandler, + ) -> JsonSchemaValue: + json_schema = handler.resolve_ref_schema(handler(core_schema)) + + json_schema.setdefault("allOf", []).extend( + [ + { + "if": _carrier_kind_condition("finite-possible-points", nested=True), + "then": {"properties": {"finite_analysis_scope": {"const": "declared-complete-finite-carrier"}}}, + }, + { + "if": _carrier_kind_condition("abstract-possible-points", nested=True), + "then": { + "properties": {"finite_analysis_scope": {"const": "abstract-parameterized-theorem-carrier"}} + }, + }, + ] + ) + return json_schema + @property def canonical_digest(self) -> str: """Return the RFC 8785 digest of this exact profile revision.""" @@ -350,14 +446,46 @@ def load_behavioral_relation_profile( ) +_HISTORICAL_PROFILE_PATHS = { + ( + "participant-opacity-baseline-v1", + "sem-231/rev2", + ): behavioral_relation_profiles_root() / "history" / "participant-opacity-baseline-v1-sem-231-rev2.json", +} + + +@cache +def load_behavioral_relation_profile_revision( + profile_id: str, + profile_revision: str, +) -> BehavioralRelationProfileModel: + """Resolve an exact immutable profile revision for evidence replay.""" + + _validate_profile_id(profile_id) + historical_path = _HISTORICAL_PROFILE_PATHS.get((profile_id, profile_revision)) + if historical_path is not None: + profile = load_behavioral_relation_profile_from_path(profile_id, historical_path) + if profile.profile_revision != profile_revision: + raise ValueError("historical behavioral relation profile revision does not match its registry entry") + return profile + current = load_behavioral_relation_profile(profile_id) + if current.profile_revision == profile_revision: + return current + raise ValueError("requested behavioral relation profile revision is unsupported") + + __all__ = [ "ActiveOpacityStrategyModel", + "AbstractOpacityCarrierModel", "BehavioralRelationProfileModel", "CoalitionOpacityObserverModel", + "FiniteOpacityCarrierModel", + "OpacityFiniteBoundsModel", "ParticipantPredicateOpacityParametersModel", "SUPPORTED_BEHAVIORAL_RELATION_PROFILE_IDS", "behavioral_relation_profile_path", "behavioral_relation_profiles_root", "load_behavioral_relation_profile", "load_behavioral_relation_profile_from_path", + "load_behavioral_relation_profile_revision", ] diff --git a/implementations/python/packages/raes_contracts/behavioral_relations.py b/implementations/python/packages/raes_contracts/behavioral_relations.py index e3ea8a7ce..86fb665df 100644 --- a/implementations/python/packages/raes_contracts/behavioral_relations.py +++ b/implementations/python/packages/raes_contracts/behavioral_relations.py @@ -311,6 +311,11 @@ def behavioral_relation_catalog_path() -> Path: return corpus_family_root(CONCEPT_AUTHORITY) / "behavioral-relations-v1.json" +_HISTORICAL_CATALOG_PATHS = { + "rev8": corpus_family_root(CONCEPT_AUTHORITY) / "history" / "behavioral-relations-v1-rev8.json", +} + + @cache def load_behavioral_relation_catalog() -> BehavioralRelationCatalogModel: return BehavioralRelationCatalogModel.model_validate_json( @@ -318,6 +323,27 @@ def load_behavioral_relation_catalog() -> BehavioralRelationCatalogModel: ) +@cache +def load_behavioral_relation_catalog_revision( + taxonomy_revision: str, +) -> BehavioralRelationCatalogModel: + """Resolve the exact catalog revision named by stored evidence.""" + + path = _HISTORICAL_CATALOG_PATHS.get(taxonomy_revision) + if path is not None: + try: + catalog = BehavioralRelationCatalogModel.model_validate_json(path.read_text(encoding="utf-8")) + except (OSError, ValueError): + raise ValueError("historical behavioral relation catalog is invalid") from None + if catalog.taxonomy_revision != taxonomy_revision: + raise ValueError("historical behavioral relation catalog revision does not match its registry entry") + return catalog + current = load_behavioral_relation_catalog() + if current.taxonomy_revision == taxonomy_revision: + return current + raise ValueError("requested behavioral relation catalog revision is unsupported") + + def _resolve_binding_relation( binding: BehavioralClaimBindingModel, catalog: BehavioralRelationCatalogModel, @@ -411,19 +437,23 @@ def validate_behavioral_claim_binding( catalog: BehavioralRelationCatalogModel | None = None, profile: BehavioralRelationProfileModel | None = None, ) -> BehavioralClaimBindingModel: - """Resolve a consumer binding against the canonical catalog.""" + """Resolve a consumer binding against its exact catalog and profile revisions.""" - catalog = load_behavioral_relation_catalog() if catalog is None else catalog + catalog = load_behavioral_relation_catalog_revision(binding.taxonomy_revision) if catalog is None else catalog relation = _resolve_binding_relation(binding, catalog) _validate_binding_requirements(binding, relation) if relation.relation_parameter_profile_required: if profile is None: from .behavioral_relation_profiles import ( - load_behavioral_relation_profile, + load_behavioral_relation_profile_revision, ) assert binding.relation_parameter_profile_ref is not None - profile = load_behavioral_relation_profile(binding.relation_parameter_profile_ref) + assert binding.relation_parameter_profile_revision is not None + profile = load_behavioral_relation_profile_revision( + binding.relation_parameter_profile_ref, + binding.relation_parameter_profile_revision, + ) _validate_binding_profile(binding, catalog, profile) elif profile is not None: raise ValueError("behavioral claim binding supplied a profile for a relation that does not require one") @@ -440,5 +470,6 @@ def validate_behavioral_claim_binding( "ExampleTransitionSystemModel", "behavioral_relation_catalog_path", "load_behavioral_relation_catalog", + "load_behavioral_relation_catalog_revision", "validate_behavioral_claim_binding", ] diff --git a/implementations/python/packages/raes_contracts/contracts/__init__.py b/implementations/python/packages/raes_contracts/contracts/__init__.py index c56d0ef31..6b10e8ea7 100644 --- a/implementations/python/packages/raes_contracts/contracts/__init__.py +++ b/implementations/python/packages/raes_contracts/contracts/__init__.py @@ -15,6 +15,7 @@ validate_artifact_requirement_invariants, ) from ..versions import ( + ACTIVITYSTREAMS_ACTIVITY_TYPES_SOURCE_SCHEMA_VERSION, ARTIFACT_REQUIREMENT_SCHEMA_VERSION, ASSOCIATED_ARTIFACT_MANIFEST_SCHEMA_VERSION, ATLAS_TACTICS_SOURCE_SCHEMA_VERSION, @@ -33,6 +34,7 @@ EXPERIMENT_STUDY_SCHEMA_VERSION, EXPERIMENT_TASK_SCHEMA_VERSION, EXTERNAL_CONCEPT_BINDINGS_SCHEMA_VERSION, + FIPA_COMMUNICATIVE_ACTS_SOURCE_SCHEMA_VERSION, NIST_CSF_DEFENSIVE_CATEGORIES_SOURCE_SCHEMA_VERSION, OPERATION_SCHEMA_VERSION, PARTICIPANT_EPISODE_STATE_SCHEMA_VERSION, @@ -421,6 +423,8 @@ from .validators import _resolve_schema_pointer as _resolve_schema_pointer from .validators import _validate_reference_model_schema_binding as _validate_reference_model_schema_binding from .vocabulary_sources import ( + ActivityStreamsActivityTypeSourceTermModel, + ActivityStreamsActivityTypesSourceModel, AtlasTacticSourceTermModel, AtlasTacticsSourceModel, AttackEnterpriseTacticSourceTermModel, @@ -429,6 +433,8 @@ ControlledVocabularyDefinitionModel, ControlledVocabularySourceModel, ControlledVocabularyTermModel, + FipaCommunicativeActSourceTermModel, + FipaCommunicativeActsSourceModel, NistCsfDefensiveCategorySourceModel, NistCsfDefensiveCategorySourceTermModel, ) diff --git a/implementations/python/packages/raes_contracts/contracts/_exports.py b/implementations/python/packages/raes_contracts/contracts/_exports.py index 3eff9bde0..45687e976 100644 --- a/implementations/python/packages/raes_contracts/contracts/_exports.py +++ b/implementations/python/packages/raes_contracts/contracts/_exports.py @@ -1,6 +1,9 @@ """Canonical public export manifest for the contracts facade.""" PUBLIC_EXPORTS = [ + "ACTIVITYSTREAMS_ACTIVITY_TYPES_SOURCE_SCHEMA_VERSION", + "ActivityStreamsActivityTypeSourceTermModel", + "ActivityStreamsActivityTypesSourceModel", "RaesSemanticInvariantEntryModel", "RaesSemanticInvariantInputModel", "RaesSemanticInvariantProfileModel", @@ -59,6 +62,9 @@ "ExternalConceptSchemeCoordinateModel", "ExternalConceptSubjectModel", "ExternalKnowledgeBindingEffect", + "FIPA_COMMUNICATIVE_ACTS_SOURCE_SCHEMA_VERSION", + "FipaCommunicativeActSourceTermModel", + "FipaCommunicativeActsSourceModel", "CONTROLLED_VOCABULARIES_SCHEMA_VERSION", "ControlledVocabularyCatalogModel", "ControlledVocabularyDefinitionModel", diff --git a/implementations/python/packages/raes_contracts/contracts/base.py b/implementations/python/packages/raes_contracts/contracts/base.py index 4296e359b..21313de17 100644 --- a/implementations/python/packages/raes_contracts/contracts/base.py +++ b/implementations/python/packages/raes_contracts/contracts/base.py @@ -339,7 +339,7 @@ def _validate_claim_strength(self) -> BehavioralClaimBindingModel: ) -_RAES_SEMANTIC_INVARIANT_PROFILE_URI = "https://raesystem.github.io/rae/schemas/semantic-invariants/v1" +_RAES_SEMANTIC_INVARIANT_PROFILE_URI = "https://openrae.github.io/rae/schemas/semantic-invariants/v1" def _canonical_digest(digest: str | None) -> str | None: diff --git a/implementations/python/packages/raes_contracts/contracts/bundle.py b/implementations/python/packages/raes_contracts/contracts/bundle.py index d00cffa6e..331346d92 100644 --- a/implementations/python/packages/raes_contracts/contracts/bundle.py +++ b/implementations/python/packages/raes_contracts/contracts/bundle.py @@ -113,9 +113,11 @@ from .trial_cleanup import SchedulerIsolationProofModel, TrialCleanupPlanModel, TrialCleanupReceiptModel from .validation_disclosure import ValidationBasisDisclosureDocumentModel from .vocabulary_sources import ( + ActivityStreamsActivityTypesSourceModel, AtlasTacticsSourceModel, AttackEnterpriseTacticsSourceModel, ControlledVocabularyCatalogModel, + FipaCommunicativeActsSourceModel, NistCsfDefensiveCategorySourceModel, ) @@ -168,6 +170,8 @@ def _core_schema_bundle() -> dict[str, dict[str, Any]]: "attack-enterprise-tactics-source-v1": AttackEnterpriseTacticsSourceModel.model_json_schema(), "atlas-tactics-source-v1": AtlasTacticsSourceModel.model_json_schema(), "nist-csf-defensive-categories-source-v1": NistCsfDefensiveCategorySourceModel.model_json_schema(), + "w3c-activitystreams-activity-types-source-v1": ActivityStreamsActivityTypesSourceModel.model_json_schema(), + "fipa-communicative-acts-source-v1": FipaCommunicativeActsSourceModel.model_json_schema(), "semantic-profile-v1": SemanticProfileModel.model_json_schema(), "backend-profile-v1": _backend_profile_schema_for_bundle(), "random-stream-profile-v1": RandomStreamProfileModel.model_json_schema(), diff --git a/implementations/python/packages/raes_contracts/contracts/capabilities.py b/implementations/python/packages/raes_contracts/contracts/capabilities.py index bcce9c368..afba29ae1 100644 --- a/implementations/python/packages/raes_contracts/contracts/capabilities.py +++ b/implementations/python/packages/raes_contracts/contracts/capabilities.py @@ -7,7 +7,12 @@ from pydantic_core import CoreSchema from ..artifact_requirements import ArtifactMechanismCapability -from ..vocabulary import RealizationSupportMode, WorkflowFeature, WorkflowStatePredicateFeature +from ..vocabulary import ( + GeneratedArtifactKind, + RealizationSupportMode, + WorkflowFeature, + WorkflowStatePredicateFeature, +) from .base import ContractModel, NonEmptyString from .validators import _validate_controlled_vocabulary_terms @@ -24,6 +29,10 @@ class ProvisionerCapabilitiesModel(ContractModel): supports_acls: bool = False supports_accounts: bool = False supports_generated_artifacts: bool = False + supported_generated_artifact_kinds: list[GeneratedArtifactKind] = Field( + default_factory=list, + json_schema_extra={"uniqueItems": True}, + ) supports_persistent_volumes: bool = False constraints: dict[str, str] = Field(default_factory=dict) @@ -57,6 +66,14 @@ def _validate_account_support(self) -> ProvisionerCapabilitiesModel: raise ValueError("provisioners that support accounts must declare supported_account_features") if not self.supports_accounts and self.supported_account_features: raise ValueError("supported_account_features require supports_accounts=true") + if len(self.supported_generated_artifact_kinds) != len(set(self.supported_generated_artifact_kinds)): + raise ValueError("supported_generated_artifact_kinds must not contain duplicates") + if self.supports_generated_artifacts and not self.supported_generated_artifact_kinds: + raise ValueError( + "provisioners that support generated artifacts must declare supported_generated_artifact_kinds" + ) + if not self.supports_generated_artifacts and self.supported_generated_artifact_kinds: + raise ValueError("supported_generated_artifact_kinds require supports_generated_artifacts=true") return self @classmethod @@ -81,11 +98,32 @@ def __get_pydantic_json_schema__( }, { "if": { - "properties": {"supports_accounts": {"const": False}}, + "properties": {"supported_account_features": {"minItems": 1}}, + "required": ["supported_account_features"], + }, + "then": { "required": ["supports_accounts"], + "properties": {"supports_accounts": {"const": True}}, + }, + }, + { + "if": { + "properties": {"supports_generated_artifacts": {"const": True}}, + "required": ["supports_generated_artifacts"], + }, + "then": { + "required": ["supported_generated_artifact_kinds"], + "properties": {"supported_generated_artifact_kinds": {"minItems": 1}}, + }, + }, + { + "if": { + "properties": {"supported_generated_artifact_kinds": {"minItems": 1}}, + "required": ["supported_generated_artifact_kinds"], }, "then": { - "properties": {"supported_account_features": {"maxItems": 0}}, + "required": ["supports_generated_artifacts"], + "properties": {"supports_generated_artifacts": {"const": True}}, }, }, ] diff --git a/implementations/python/packages/raes_contracts/contracts/experiment_spec.py b/implementations/python/packages/raes_contracts/contracts/experiment_spec.py index c20ab5459..59ae3a8e3 100644 --- a/implementations/python/packages/raes_contracts/contracts/experiment_spec.py +++ b/implementations/python/packages/raes_contracts/contracts/experiment_spec.py @@ -74,14 +74,13 @@ class ExperimentStudyModel(ContractModel): @model_validator(mode="after") def _validate_claim_bearing_study(self) -> ExperimentStudyModel: - from ..behavioral_relations import load_behavioral_relation_catalog, validate_behavioral_claim_binding + from ..behavioral_relations import validate_behavioral_claim_binding - catalog = load_behavioral_relation_catalog() relation_ids = [claim.relation_id for claim in self.behavioral_claims] if len(relation_ids) != len(set(relation_ids)): raise ValueError("study behavioral claim relation ids must be unique") for claim in self.behavioral_claims: - validate_behavioral_claim_binding(claim, catalog) + validate_behavioral_claim_binding(claim) if self.run_allocation is not None: self._validate_run_allocation_blocking_factors(self.run_allocation) self._validate_run_allocation_condition_assignments(self.run_allocation) diff --git a/implementations/python/packages/raes_contracts/contracts/schema_constraints.py b/implementations/python/packages/raes_contracts/contracts/schema_constraints.py index d3f0a77fc..fd5a526ba 100644 --- a/implementations/python/packages/raes_contracts/contracts/schema_constraints.py +++ b/implementations/python/packages/raes_contracts/contracts/schema_constraints.py @@ -270,7 +270,7 @@ def _attach_instantiation_invariants(contract_id: str, json_schema: dict[str, An def _schema_id_for_contract_id(contract_id: str) -> str: if contract_id == "raes-semantic-invariants-v1": return _RAES_SEMANTIC_INVARIANT_PROFILE_URI - return f"https://raesystem.github.io/rae/schemas/{contract_id}.json" + return f"https://openrae.github.io/rae/schemas/{contract_id}.json" def _attach_json_schema_metadata(contract_id: str, json_schema: dict[str, Any]) -> None: @@ -350,7 +350,7 @@ class RaesSemanticInvariantProfileModel(ContractModel): schema_version: Literal[_RAES_SEMANTIC_INVARIANTS_SCHEMA_VERSION] profile_id: Literal["raes-semantic-invariants-v1"] - uri: Literal["https://raesystem.github.io/rae/schemas/semantic-invariants/v1"] + uri: Literal["https://openrae.github.io/rae/schemas/semantic-invariants/v1"] keyword: Literal["x-raes-invariants"] invariant_entry_schema: Literal["#/$defs/RaesSemanticInvariantEntryModel"] profile_reference_schema: Literal["#/$defs/RaesSemanticInvariantProfileReferenceModel"] @@ -361,7 +361,7 @@ class RaesSemanticInvariantProfileReferenceModel(ContractModel): """Host-schema reference to the RAES semantic-invariant profile.""" id: Literal["raes-semantic-invariants-v1"] - uri: Literal["https://raesystem.github.io/rae/schemas/semantic-invariants/v1"] + uri: Literal["https://openrae.github.io/rae/schemas/semantic-invariants/v1"] contract_id: NonEmptyString keyword: Literal["x-raes-invariants"] required: Literal[True] diff --git a/implementations/python/packages/raes_contracts/contracts/schema_invariants.py b/implementations/python/packages/raes_contracts/contracts/schema_invariants.py index 5a13e8ac0..640dd2c27 100644 --- a/implementations/python/packages/raes_contracts/contracts/schema_invariants.py +++ b/implementations/python/packages/raes_contracts/contracts/schema_invariants.py @@ -140,7 +140,9 @@ def _attach_stateful_resource_invariants(contract_id: str, json_schema: dict[str json_schema, "stateful-generated-artifact-semantics", "Generated artifact output names and paths, consumers, and dependency entries must be unique, and " - "generated artifact consumers must be read-only.", + "generated artifact consumers must be read-only. Explicit selections must name declared consumer-selectable " + "outputs; SSH artifact consumers must select outputs and every consumer-selectable SSH output must be " + "selected.", validator="raes.stateful_resources.GeneratedArtifact._unique_outputs_and_consumers", inputs=input_contract, ) diff --git a/implementations/python/packages/raes_contracts/contracts/vocabulary_sources.py b/implementations/python/packages/raes_contracts/contracts/vocabulary_sources.py index e4e854323..93d4cae00 100644 --- a/implementations/python/packages/raes_contracts/contracts/vocabulary_sources.py +++ b/implementations/python/packages/raes_contracts/contracts/vocabulary_sources.py @@ -1,4 +1,4 @@ -"""Controlled-vocabulary and ATT&CK/ATLAS tactics-source contracts.""" +"""Controlled-vocabulary and pinned external vocabulary-source contracts.""" from __future__ import annotations @@ -10,9 +10,11 @@ from pydantic_core import CoreSchema from ..versions import ( + ACTIVITYSTREAMS_ACTIVITY_TYPES_SOURCE_SCHEMA_VERSION, ATLAS_TACTICS_SOURCE_SCHEMA_VERSION, ATTACK_ENTERPRISE_TACTICS_SOURCE_SCHEMA_VERSION, CONTROLLED_VOCABULARIES_SCHEMA_VERSION, + FIPA_COMMUNICATIVE_ACTS_SOURCE_SCHEMA_VERSION, NIST_CSF_DEFENSIVE_CATEGORIES_SOURCE_SCHEMA_VERSION, ) from .base import ( @@ -229,3 +231,84 @@ def _validate_defensive_categories_source(self) -> NistCsfDefensiveCategorySourc if len(term_ids) != len(set(term_ids)): raise ValueError("NIST CSF defensive category source must not contain duplicate term_id values") return self + + +class ActivityStreamsActivityTypeSourceTermModel(ContractModel): + position: PositiveInteger + type_name: Annotated[str, Field(pattern=r"^[A-Z][A-Za-z]+$")] + concept_id: NonEmptyString + + @model_validator(mode="after") + def _validate_concept_iri(self) -> ActivityStreamsActivityTypeSourceTermModel: + expected = f"https://www.w3.org/ns/activitystreams#{self.type_name}" + if self.concept_id != expected: + raise ValueError("ActivityStreams activity type concept_id must be the normative type IRI") + return self + + +class ActivityStreamsActivityTypesSourceModel(ContractModel): + schema_version: Literal[ACTIVITYSTREAMS_ACTIVITY_TYPES_SOURCE_SCHEMA_VERSION] = ( + ACTIVITYSTREAMS_ACTIVITY_TYPES_SOURCE_SCHEMA_VERSION + ) + source_authority: Literal["World Wide Web Consortium"] + source_version: Literal["REC-activitystreams-vocabulary-20170523"] + source_status: Literal["W3C Recommendation"] + source_url: NonEmptyString + source_digest: PrefixedDigestString + citation_urls: list[NonEmptyString] = Field(min_length=1) + retrieved_at: CalendarDateString + license_url: NonEmptyString + license_notice: NonEmptyString + activity_types: list[ActivityStreamsActivityTypeSourceTermModel] = Field(min_length=1) + + @model_validator(mode="after") + def _validate_activity_types(self) -> ActivityStreamsActivityTypesSourceModel: + positions = [term.position for term in self.activity_types] + if len(positions) != len(set(positions)): + raise ValueError("ActivityStreams activity type source must not contain duplicate positions") + if positions != list(range(1, len(positions) + 1)): + raise ValueError("ActivityStreams activity types must preserve contiguous source order") + + type_names = [term.type_name for term in self.activity_types] + if len(type_names) != len(set(type_names)): + raise ValueError("ActivityStreams activity type source must not contain duplicate type_name values") + + concept_ids = [term.concept_id for term in self.activity_types] + if len(concept_ids) != len(set(concept_ids)): + raise ValueError("ActivityStreams activity type source must not contain duplicate concept_id values") + return self + + +class FipaCommunicativeActSourceTermModel(ContractModel): + position: PositiveInteger + concept_id: Annotated[str, Field(pattern=r"^[a-z]+(?:-[a-z]+)*$")] + + +class FipaCommunicativeActsSourceModel(ContractModel): + schema_version: Literal[FIPA_COMMUNICATIVE_ACTS_SOURCE_SCHEMA_VERSION] = ( + FIPA_COMMUNICATIVE_ACTS_SOURCE_SCHEMA_VERSION + ) + source_authority: Literal["Foundation for Intelligent Physical Agents"] + source_version: Literal["SC00037J-2002-12-03"] + source_status: Literal["Standard"] + source_url: NonEmptyString + source_artifact_url: NonEmptyString + source_digest: PrefixedDigestString + citation_urls: list[NonEmptyString] = Field(min_length=1) + retrieved_at: CalendarDateString + license_url: NonEmptyString + license_notice: NonEmptyString + communicative_acts: list[FipaCommunicativeActSourceTermModel] = Field(min_length=1) + + @model_validator(mode="after") + def _validate_communicative_acts(self) -> FipaCommunicativeActsSourceModel: + positions = [act.position for act in self.communicative_acts] + if len(positions) != len(set(positions)): + raise ValueError("FIPA communicative act source must not contain duplicate positions") + if positions != list(range(1, len(positions) + 1)): + raise ValueError("FIPA communicative acts must preserve contiguous specification order") + + concept_ids = [act.concept_id for act in self.communicative_acts] + if len(concept_ids) != len(set(concept_ids)): + raise ValueError("FIPA communicative act source must not contain duplicate concept_id values") + return self diff --git a/implementations/python/packages/raes_contracts/external_concept_bindings.py b/implementations/python/packages/raes_contracts/external_concept_bindings.py index 0b16a2c06..40ab0b28a 100644 --- a/implementations/python/packages/raes_contracts/external_concept_bindings.py +++ b/implementations/python/packages/raes_contracts/external_concept_bindings.py @@ -9,10 +9,12 @@ from pydantic import Field, model_validator from .contracts import ( + ActivityStreamsActivityTypesSourceModel, AttackEnterpriseTacticsSourceModel, ExternalConceptBindingDocumentModel, ExternalConceptSchemeCoordinateModel, ExternalConceptSubjectModel, + FipaCommunicativeActsSourceModel, NistCsfDefensiveCategorySourceModel, ) from .contracts.base import ContractModel, NonEmptyString, PrefixedDigestString @@ -343,13 +345,41 @@ def adapt_nist_csf_defensive_categories_snapshot( ) +def adapt_activitystreams_activity_types_snapshot( + source: ActivityStreamsActivityTypesSourceModel, +) -> ExternalConceptSchemeSnapshotModel: + return ExternalConceptSchemeSnapshotModel( + scheme_id="w3c-activitystreams-activity-types", + authority=source.source_authority, + revision=source.source_version, + source_locator=source.source_url, + source_digest=source.source_digest, + concepts=[ExternalConceptSnapshotTermModel(concept_id=term.concept_id) for term in source.activity_types], + ) + + +def adapt_fipa_communicative_acts_snapshot( + source: FipaCommunicativeActsSourceModel, +) -> ExternalConceptSchemeSnapshotModel: + return ExternalConceptSchemeSnapshotModel( + scheme_id="fipa-communicative-act-library", + authority=source.source_authority, + revision=source.source_version, + source_locator=source.source_url, + source_digest=source.source_digest, + concepts=[ExternalConceptSnapshotTermModel(concept_id=act.concept_id) for act in source.communicative_acts], + ) + + __all__ = [ "ExternalConceptBindingAdmissionReport", "ExternalConceptBindingResolution", "ExternalConceptResolutionOutcome", "ExternalConceptSchemeSnapshotModel", "ExternalConceptSnapshotTermModel", + "adapt_activitystreams_activity_types_snapshot", "adapt_attack_enterprise_tactics_snapshot", + "adapt_fipa_communicative_acts_snapshot", "adapt_nist_csf_defensive_categories_snapshot", "admit_external_concept_bindings", ] diff --git a/implementations/python/packages/raes_contracts/json_ingress.py b/implementations/python/packages/raes_contracts/json_ingress.py index 947378c69..ed66ae670 100644 --- a/implementations/python/packages/raes_contracts/json_ingress.py +++ b/implementations/python/packages/raes_contracts/json_ingress.py @@ -3,6 +3,7 @@ from __future__ import annotations import json +from typing import Literal JSONValue = None | bool | int | float | str | list["JSONValue"] | dict[str, "JSONValue"] @@ -30,12 +31,13 @@ def _reject_non_finite_number(_: str) -> float: raise StrictJsonIngressError("non-finite-number", "JSON contains a non-finite number") -def parse_bounded_json_object( +def parse_bounded_json( source: str | bytes | bytearray, *, max_bytes: int, -) -> dict[str, JSONValue]: - """Parse one bounded JSON object without duplicate members or non-finite numbers.""" + root: Literal["object", "array"], +) -> JSONValue: + """Parse bounded JSON with an explicit, ambiguity-free root shape.""" if max_bytes < 1: raise ValueError("max_bytes must be positive") @@ -54,13 +56,29 @@ def parse_bounded_json_object( raise except (UnicodeDecodeError, json.JSONDecodeError) as exc: raise StrictJsonIngressError("invalid-json", "JSON input is invalid") from exc + expected_type = dict if root == "object" else list + if not isinstance(payload, expected_type): + raise StrictJsonIngressError("invalid-root", f"JSON input must be an {root}") + return payload + + +def parse_bounded_json_object( + source: str | bytes | bytearray, + *, + max_bytes: int, +) -> dict[str, JSONValue]: + """Parse one bounded JSON object without duplicate members or non-finite numbers.""" + + payload = parse_bounded_json(source, max_bytes=max_bytes, root="object") + # The shared parser establishes the selected root type. if not isinstance(payload, dict): - raise StrictJsonIngressError("invalid-root", "JSON input must be an object") + raise AssertionError("object-root parser returned a non-object") return payload __all__ = [ "JSONValue", "StrictJsonIngressError", + "parse_bounded_json", "parse_bounded_json_object", ] diff --git a/implementations/python/packages/raes_contracts/scientific_completeness.py b/implementations/python/packages/raes_contracts/scientific_completeness.py index f2c72b19f..2f22e17a6 100644 --- a/implementations/python/packages/raes_contracts/scientific_completeness.py +++ b/implementations/python/packages/raes_contracts/scientific_completeness.py @@ -103,7 +103,7 @@ def validate_behavioral_claims(self) -> CompletenessProfileModel: if overlap: raise ValueError(f"relations cannot be both claimed and explicitly non-claimed: {overlap}") for claim in self.behavioral_claims: - validate_behavioral_claim_binding(claim, catalog) + validate_behavioral_claim_binding(claim) return self diff --git a/implementations/python/packages/raes_contracts/versions.py b/implementations/python/packages/raes_contracts/versions.py index 3ce7cedd1..a0af58b87 100644 --- a/implementations/python/packages/raes_contracts/versions.py +++ b/implementations/python/packages/raes_contracts/versions.py @@ -21,6 +21,8 @@ ATTACK_ENTERPRISE_TACTICS_SOURCE_SCHEMA_VERSION = "attack-enterprise-tactics-source/v1" ATLAS_TACTICS_SOURCE_SCHEMA_VERSION = "atlas-tactics-source/v1" NIST_CSF_DEFENSIVE_CATEGORIES_SOURCE_SCHEMA_VERSION = "nist-csf-defensive-categories-source/v1" +ACTIVITYSTREAMS_ACTIVITY_TYPES_SOURCE_SCHEMA_VERSION = "w3c-activitystreams-activity-types-source/v1" +FIPA_COMMUNICATIVE_ACTS_SOURCE_SCHEMA_VERSION = "fipa-communicative-acts-source/v1" SEMANTIC_PROFILE_SCHEMA_VERSION = "semantic-profile/v1" BACKEND_PROFILE_SCHEMA_VERSION = "backend-profile/v1" WORKFLOW_STATE_SCHEMA_VERSION = "workflow-step-state/v1" diff --git a/implementations/python/packages/raes_contracts/vocabulary.py b/implementations/python/packages/raes_contracts/vocabulary.py index 2961a6975..4b4bf866d 100644 --- a/implementations/python/packages/raes_contracts/vocabulary.py +++ b/implementations/python/packages/raes_contracts/vocabulary.py @@ -19,6 +19,14 @@ class ProcessorFeature(str, Enum): RUNTIME_CONTROL_PLANE = "runtime-control-plane" +class GeneratedArtifactKind(str, Enum): + """Portable kinds of material a provisioner may generate.""" + + CERTIFICATE_BUNDLE = "certificate_bundle" + RENDERED_CONFIG = "rendered_config" + SSH_KEY_BUNDLE = "ssh_key_bundle" + + class WorkflowFeature(str, Enum): """Portable workflow control features that an orchestrator may support.""" diff --git a/implementations/python/packages/raes_contracts/vocabulary_sources.py b/implementations/python/packages/raes_contracts/vocabulary_sources.py index 6563b1009..3d69bc9e6 100644 --- a/implementations/python/packages/raes_contracts/vocabulary_sources.py +++ b/implementations/python/packages/raes_contracts/vocabulary_sources.py @@ -4,7 +4,12 @@ import json -from .contracts import AttackEnterpriseTacticsSourceModel, NistCsfDefensiveCategorySourceModel +from .contracts import ( + ActivityStreamsActivityTypesSourceModel, + AttackEnterpriseTacticsSourceModel, + FipaCommunicativeActsSourceModel, + NistCsfDefensiveCategorySourceModel, +) from .corpus import CONCEPT_AUTHORITY, corpus_family_root @@ -18,7 +23,19 @@ def load_nist_csf_defensive_categories_source() -> NistCsfDefensiveCategorySourc return NistCsfDefensiveCategorySourceModel.model_validate(json.loads(path.read_text(encoding="utf-8"))) +def load_activitystreams_activity_types_source() -> ActivityStreamsActivityTypesSourceModel: + path = corpus_family_root(CONCEPT_AUTHORITY) / "w3c-activitystreams-activity-types-source-v1.json" + return ActivityStreamsActivityTypesSourceModel.model_validate(json.loads(path.read_text(encoding="utf-8"))) + + +def load_fipa_communicative_acts_source() -> FipaCommunicativeActsSourceModel: + path = corpus_family_root(CONCEPT_AUTHORITY) / "fipa-communicative-acts-source-v1.json" + return FipaCommunicativeActsSourceModel.model_validate(json.loads(path.read_text(encoding="utf-8"))) + + __all__ = [ + "load_activitystreams_activity_types_source", "load_attack_enterprise_tactics_source", + "load_fipa_communicative_acts_source", "load_nist_csf_defensive_categories_source", ] diff --git a/implementations/python/packages/raes_operations/_evidence_run_artifact.py b/implementations/python/packages/raes_operations/_evidence_run_artifact.py index 9d3f5c27f..6e50c8f01 100644 --- a/implementations/python/packages/raes_operations/_evidence_run_artifact.py +++ b/implementations/python/packages/raes_operations/_evidence_run_artifact.py @@ -55,7 +55,7 @@ "No Wazuh detection-quality claim.", "No model-defense robustness claim.", "No byte-equivalence or application-internals equivalence claim between libvirt appliances and APTL containers.", - "No full semantic-equivalence claim beyond the invariant ledger in RAESystem/rae#600.", + "No full semantic-equivalence claim beyond the invariant ledger in OpenRAE/rae#600.", ) @@ -586,7 +586,7 @@ def _invariant_ledger_refs(model: CompiledModel, scenario_section: Mapping[str, "evaluator_outcome", ], "note": ( - "Stable RAES addresses and evidence refs for the RAESystem/rae#600 cross-backend invariant ledger; " + "Stable RAES addresses and evidence refs for the OpenRAE/rae#600 cross-backend invariant ledger; " "no libvirt domain UUIDs, host paths, or APTL-private identifiers." ), } diff --git a/implementations/python/packages/raes_operations/cross_backend_corpus.py b/implementations/python/packages/raes_operations/cross_backend_corpus.py index 660f28769..9b2b39a86 100644 --- a/implementations/python/packages/raes_operations/cross_backend_corpus.py +++ b/implementations/python/packages/raes_operations/cross_backend_corpus.py @@ -61,10 +61,10 @@ ) _LINKS: dict[str, str] = { - "issue": "RAESystem/rae#600", - "authored_scenario_issue": "RAESystem/rae#598", - "libvirt_participant_runtime": "RAESystem/rae#614", - "libvirt_evidence": "RAESystem/rae#615", + "issue": "OpenRAE/rae#600", + "authored_scenario_issue": "OpenRAE/rae#598", + "libvirt_participant_runtime": "OpenRAE/rae#614", + "libvirt_evidence": "OpenRAE/rae#615", "aptl_evidence": "Brad-Edwards/aptl#558", } diff --git a/implementations/python/packages/raes_processor/compiler/placement.py b/implementations/python/packages/raes_processor/compiler/placement.py index 479c17b62..b9e75593b 100644 --- a/implementations/python/packages/raes_processor/compiler/placement.py +++ b/implementations/python/packages/raes_processor/compiler/placement.py @@ -1,15 +1,13 @@ """Content and account placement compilation.""" -import hashlib -import json - -from raes.content import Content +from raes.content import Content, ServiceSearchIndexSchemaMaterialization from raes.nodes import NodeType from raes.scenario import InstantiatedScenario from raes.semantics.domain_topology import ( DomainNodeRole, DomainTopologyAnalysis, ) +from raes_contracts.canonical import canonical_json_digest from ..models import ( AccountPlacement, @@ -17,6 +15,7 @@ Diagnostic, DomainControllerPlacement, ServiceContentMaterializationBinding, + ServiceSearchIndexSchemaMaterializationBinding, ) from .addresses import ( _account_address, @@ -78,7 +77,13 @@ def _compile_service_materialization( content: Content, address: str, diagnostics: list[Diagnostic], -) -> tuple[ServiceContentMaterializationBinding | None, list[str]] | None: +) -> ( + tuple[ + ServiceContentMaterializationBinding | ServiceSearchIndexSchemaMaterializationBinding | None, + list[str], + ] + | None +): binding = content.service_materialization if binding is None: return None, [] @@ -96,25 +101,40 @@ def _compile_service_materialization( node_name, service_name = split consumer_tenant_ref, mutable_state_owner, reset_generation_owner = _service_state_ownership(scenario, binding) requirements = binding.requirements - compiled = ServiceContentMaterializationBinding( - target_service_address=_service_address(node_name, service_name), - interface_profile=binding.interface_profile, - profile_version=binding.profile_version, - content_type=content.type.value, - operation=requirements.operation, - conflict_policy=requirements.conflict_policy, - readback=requirements.readback, - canonical_content_digest=_canonical_content_digest(content), - shared_service_relationship_ref=binding.shared_service_relationship_ref, - consumer_tenant_ref=consumer_tenant_ref, - mutable_state_owner=mutable_state_owner, - reset_generation_owner=reset_generation_owner, - readback_assertion_addresses=tuple(_assertion_address(ref) for ref in binding.readback_assertion_refs), - evidence_requirement_refs=tuple(binding.evidence_requirement_refs), - observation_boundary_addresses=tuple( + common = { + "target_service_address": _service_address(node_name, service_name), + "interface_profile": binding.interface_profile, + "profile_version": binding.profile_version, + "content_type": content.type.value, + "operation": requirements.operation, + "conflict_policy": requirements.conflict_policy, + "readback": requirements.readback, + "canonical_content_digest": _canonical_content_digest(content), + "shared_service_relationship_ref": binding.shared_service_relationship_ref, + "consumer_tenant_ref": consumer_tenant_ref, + "mutable_state_owner": mutable_state_owner, + "reset_generation_owner": reset_generation_owner, + "readback_assertion_addresses": tuple(_assertion_address(ref) for ref in binding.readback_assertion_refs), + "evidence_requirement_refs": tuple(binding.evidence_requirement_refs), + "observation_boundary_addresses": tuple( _observation_boundary_address(ref) for ref in binding.observation_boundary_refs ), - ) + } + if isinstance(binding, ServiceSearchIndexSchemaMaterialization): + field_semantics = { + str(field_name): semantic.value for field_name, semantic in requirements.field_semantics.items() + } + compiled = ServiceSearchIndexSchemaMaterializationBinding( + **common, + field_semantics=field_semantics, + canonical_field_schema_digest=_canonical_field_schema_digest( + binding.interface_profile, + binding.profile_version, + field_semantics, + ), + ) + else: + compiled = ServiceContentMaterializationBinding(**common) dependencies = [_content_address(ref) for ref in binding.ordering_content_refs] return compiled, dependencies @@ -140,8 +160,22 @@ def _service_state_ownership(scenario: InstantiatedScenario, binding: object) -> def _canonical_content_digest(content: object) -> str: payload = _dump(content) payload.pop("service_materialization", None) - encoded = json.dumps(payload, ensure_ascii=True, separators=(",", ":"), sort_keys=True).encode("utf-8") - return "sha256:" + hashlib.sha256(encoded).hexdigest() + return canonical_json_digest(payload) + + +def _canonical_field_schema_digest( + interface_profile: str, + profile_version: str, + field_semantics: dict[str, str], +) -> str: + return canonical_json_digest( + { + "interface_profile": interface_profile, + "profile_version": profile_version, + "projection_scope": "declared-fields", + "field_semantics": field_semantics, + } + ) def _compile_account_placements( diff --git a/implementations/python/packages/raes_processor/compiler/realization_requirements.py b/implementations/python/packages/raes_processor/compiler/realization_requirements.py index a8a7c865a..deb68719c 100644 --- a/implementations/python/packages/raes_processor/compiler/realization_requirements.py +++ b/implementations/python/packages/raes_processor/compiler/realization_requirements.py @@ -252,14 +252,20 @@ def _append_service_materialization_requirements( scenario: InstantiatedScenario, ) -> None: for name, content in scenario.content.items(): - if content.service_materialization is None: + binding = content.service_materialization + if binding is None: continue + requirement_kind = ( + "service-search-index-schema-materialization" + if binding.interface_profile == "service-search-index-schema" + else "service-content-materialization" + ) requirements.append( CompiledRealizationRequirement( field_path=f"content.{name}.service_materialization", address=_content_address(name), domain=REALIZATION_DOMAIN, - requirement_kind="service-content-materialization", + requirement_kind=requirement_kind, explicitness=ExplicitnessClass.EXACT, provenance=ExplicitnessProvenance.AUTHOR_DECLARED, governing_scope=f"#/content/{name}/service_materialization", diff --git a/implementations/python/packages/raes_processor/models/__init__.py b/implementations/python/packages/raes_processor/models/__init__.py index 30dd1caf3..db1045765 100644 --- a/implementations/python/packages/raes_processor/models/__init__.py +++ b/implementations/python/packages/raes_processor/models/__init__.py @@ -187,6 +187,7 @@ ResolvedResource, RuntimeTemplate, ServiceContentMaterializationBinding, + ServiceSearchIndexSchemaMaterializationBinding, map_backend_diagnostic_to_participant_failure, validate_participant_action_result_contract, ) @@ -227,6 +228,7 @@ "ConditionBinding", "ContentPlacement", "ServiceContentMaterializationBinding", + "ServiceSearchIndexSchemaMaterializationBinding", "DomainControllerPlacement", "GeneratedArtifactRuntime", "Diagnostic", diff --git a/implementations/python/packages/raes_processor/models/resources.py b/implementations/python/packages/raes_processor/models/resources.py index fd4b8e5f7..c08edd039 100644 --- a/implementations/python/packages/raes_processor/models/resources.py +++ b/implementations/python/packages/raes_processor/models/resources.py @@ -155,6 +155,38 @@ def __post_init__(self) -> None: ) +@dataclass(frozen=True) +class ServiceSearchIndexSchemaMaterializationBinding: + """Closed compiled requirements for one service-owned search-index schema.""" + + target_service_address: str + interface_profile: str + profile_version: str + content_type: str + operation: str + conflict_policy: str + readback: str + field_semantics: dict[str, str] + canonical_content_digest: str + canonical_field_schema_digest: str + shared_service_relationship_ref: str = "" + consumer_tenant_ref: str = "" + mutable_state_owner: str = "" + reset_generation_owner: str = "" + readback_assertion_addresses: tuple[str, ...] = () + evidence_requirement_refs: tuple[str, ...] = () + observation_boundary_addresses: tuple[str, ...] = () + + def __post_init__(self) -> None: + require_compiled_address( + self.target_service_address, + field_name="ServiceSearchIndexSchemaMaterializationBinding.target_service_address", + ) + + +ServiceMaterializationBinding = ServiceContentMaterializationBinding | ServiceSearchIndexSchemaMaterializationBinding + + @dataclass(frozen=True) class ContentPlacement(ResolvedResource): """Content entry resolved to a concrete node or named service.""" @@ -162,7 +194,7 @@ class ContentPlacement(ResolvedResource): content_name: str = "" target_node: str = "" target_address: str = "" - service_materialization: ServiceContentMaterializationBinding | None = None + service_materialization: ServiceMaterializationBinding | None = None @dataclass(frozen=True) diff --git a/implementations/python/packages/raes_processor/participant_opacity/_model_check.py b/implementations/python/packages/raes_processor/participant_opacity/_model_check.py index 8f98eaded..5433f5db8 100644 --- a/implementations/python/packages/raes_processor/participant_opacity/_model_check.py +++ b/implementations/python/packages/raes_processor/participant_opacity/_model_check.py @@ -6,10 +6,13 @@ from pathlib import Path from pydantic import ValidationError -from raes_contracts.behavioral_relation_profiles import BehavioralRelationProfileModel, load_behavioral_relation_profile +from raes_contracts.behavioral_relation_profiles import ( + BehavioralRelationProfileModel, + load_behavioral_relation_profile_revision, +) from raes_contracts.behavioral_relations import ( BehavioralRelationCatalogModel, - load_behavioral_relation_catalog, + load_behavioral_relation_catalog_revision, ) from raes_contracts.canonical import canonical_json_digest from raes_contracts.diagnostics import DiagnosticModel @@ -292,8 +295,11 @@ def model_check_participant_opacity_file( try: payload = parse_bounded_json_object(path.read_bytes(), max_bytes=_MAX_INPUT_BYTES) request = ParticipantOpacityModelCheckInputModel.model_validate(payload) - profile = load_behavioral_relation_profile(request.profile_id) - catalog = load_behavioral_relation_catalog() + profile = load_behavioral_relation_profile_revision( + request.profile_id, + request.profile_revision, + ) + catalog = load_behavioral_relation_catalog_revision(request.taxonomy_revision) except (OSError, ValidationError, ValueError): raise ParticipantOpacityOperationalError( "participant-opacity model-check input failed bounded closed-world admission" diff --git a/implementations/python/packages/raes_processor/participant_opacity/_service.py b/implementations/python/packages/raes_processor/participant_opacity/_service.py index 2e6a37db9..7b5aaf354 100644 --- a/implementations/python/packages/raes_processor/participant_opacity/_service.py +++ b/implementations/python/packages/raes_processor/participant_opacity/_service.py @@ -10,7 +10,7 @@ ActiveOpacityStrategyModel, BehavioralRelationProfileModel, CoalitionOpacityObserverModel, - load_behavioral_relation_profile, + load_behavioral_relation_profile_revision, ) from raes_contracts.behavioral_relations import ( validate_behavioral_claim_binding, @@ -352,7 +352,10 @@ def analyze_participant_opacity_file( max_bytes=_MAX_INPUT_BYTES, ) request = ParticipantOpacityAnalysisInputModel.model_validate(payload) - profile = load_behavioral_relation_profile(request.profile_id) + profile = load_behavioral_relation_profile_revision( + request.profile_id, + request.profile_revision, + ) except (OSError, ValidationError, ValueError): raise ParticipantOpacityOperationalError( "opacity analysis input failed bounded closed-world admission" diff --git a/implementations/python/packages/raes_processor/planner/__init__.py b/implementations/python/packages/raes_processor/planner/__init__.py index 5fa7db2ad..132ca2fdc 100644 --- a/implementations/python/packages/raes_processor/planner/__init__.py +++ b/implementations/python/packages/raes_processor/planner/__init__.py @@ -3,8 +3,10 @@ from ..semantics.realization import realization_disclosure, sanitize_realization_snapshot from .core import plan from .ordering import snapshot_delete_order +from .stateful_admission import generated_artifact_payload_diagnostic __all__ = [ + "generated_artifact_payload_diagnostic", "plan", "realization_disclosure", "sanitize_realization_snapshot", diff --git a/implementations/python/packages/raes_processor/planner/core.py b/implementations/python/packages/raes_processor/planner/core.py index 4a34a35cd..c64644a43 100644 --- a/implementations/python/packages/raes_processor/planner/core.py +++ b/implementations/python/packages/raes_processor/planner/core.py @@ -139,6 +139,7 @@ def plan( provisioning, manifest.provisioner, manifest.realization_envelope, + manifest.realization_support, ) diagnostics.extend(materialization_diagnostics) provisioning.diagnostics.extend(materialization_diagnostics) diff --git a/implementations/python/packages/raes_processor/planner/manifest_validation.py b/implementations/python/packages/raes_processor/planner/manifest_validation.py index 9d0013310..9f7e3bbcd 100644 --- a/implementations/python/packages/raes_processor/planner/manifest_validation.py +++ b/implementations/python/packages/raes_processor/planner/manifest_validation.py @@ -4,6 +4,7 @@ from ..models import Diagnostic, RuntimeModel from .capability_domains import _account_features, _resource_count_upper_bound, _validate_node_os_family +from .stateful_admission import generated_artifact_payload_diagnostic _ORCHESTRATION_WORKFLOWS_ADDRESS = "orchestration.workflows" @@ -144,6 +145,15 @@ def _validate_artifact_and_volume_support( message="Provisioner does not support generated artifacts.", ) ) + elif model.generated_artifacts: + for artifact in model.generated_artifacts.values(): + diagnostic = generated_artifact_payload_diagnostic( + address=artifact.address, + spec=artifact.spec, + provisioner=provisioner, + ) + if diagnostic is not None: + diagnostics.append(diagnostic) if model.persistent_volumes and not provisioner.supports_persistent_volumes: diagnostics.append( Diagnostic( diff --git a/implementations/python/packages/raes_processor/planner/stateful_admission.py b/implementations/python/packages/raes_processor/planner/stateful_admission.py new file mode 100644 index 000000000..68eb0c911 --- /dev/null +++ b/implementations/python/packages/raes_processor/planner/stateful_admission.py @@ -0,0 +1,63 @@ +"""Shared admission for generated-artifact plan payloads.""" + +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any + +from raes.stateful_resources import GeneratedArtifact +from raes_backend_protocols.capabilities import ProvisionerCapabilities +from raes_contracts.addressing import render_compiled_address + +from ..models import Diagnostic + + +def generated_artifact_payload_diagnostic( + *, + address: str, + spec: object, + provisioner: ProvisionerCapabilities, +) -> Diagnostic | None: + """Validate one compiled or directly submitted generated-artifact spec.""" + + try: + if not isinstance(spec, Mapping): + raise ValueError("generated artifact spec must be an object") + canonical_spec: dict[str, Any] = dict(spec) + consumers = canonical_spec.get("consumers") + if isinstance(consumers, list): + canonical_consumers: list[object] = [] + for consumer in consumers: + if not isinstance(consumer, Mapping): + canonical_consumers.append(consumer) + continue + canonical_consumer = dict(consumer) + target_address = canonical_consumer.pop("target_address", None) + if target_address is not None and target_address != render_compiled_address( + "provision", + "node", + str(canonical_consumer.get("node", "")), + ): + raise ValueError("generated artifact consumer target_address does not match node") + canonical_consumers.append(canonical_consumer) + canonical_spec["consumers"] = canonical_consumers + artifact = GeneratedArtifact.model_validate(canonical_spec) + except (TypeError, ValueError): + return Diagnostic( + code="provisioner.generated-artifact-invalid", + domain="provisioning", + address=address, + message="Submitted generated artifact payload is invalid.", + ) + + if artifact.generator not in provisioner.supported_generated_artifact_kinds: + return Diagnostic( + code="provisioner.unsupported-generated-artifact-kind", + domain="provisioning", + address=address, + message=f"Provisioner does not support generated artifact kind '{artifact.generator.value}'.", + ) + return None + + +__all__ = ["generated_artifact_payload_diagnostic"] diff --git a/implementations/python/packages/raes_processor/semantics/realization_concerns.py b/implementations/python/packages/raes_processor/semantics/realization_concerns.py index 24ffbff6d..675a21aa5 100644 --- a/implementations/python/packages/raes_processor/semantics/realization_concerns.py +++ b/implementations/python/packages/raes_processor/semantics/realization_concerns.py @@ -160,6 +160,7 @@ def _mount_source_kind(item: object) -> object: "generated-artifact": ("spec",), "persistent-volume": ("spec",), "service-content-materialization": ("service_materialization",), + "service-search-index-schema-materialization": ("service_materialization",), } diff --git a/implementations/python/packages/raes_runtime/control_plane_submission.py b/implementations/python/packages/raes_runtime/control_plane_submission.py index fcf2427f9..a24d0e64c 100644 --- a/implementations/python/packages/raes_runtime/control_plane_submission.py +++ b/implementations/python/packages/raes_runtime/control_plane_submission.py @@ -24,6 +24,7 @@ require_plan_operation_identity, ) from raes_contracts.runtime_state import RuntimeSnapshot +from raes_processor.planner import generated_artifact_payload_diagnostic _STATEFUL_ADMISSION_BY_RESOURCE_TYPE = { "generated-artifact": ( @@ -63,6 +64,7 @@ def _submitted_plan_diagnostics( plan, manifest.provisioner, manifest.realization_envelope, + manifest.realization_support, ) if service_materialization_diagnostics: diagnostics.extend(service_materialization_diagnostics[:1]) @@ -81,25 +83,34 @@ def _stateful_submission_diagnostic( plan: ProvisioningPlan, manifest: BackendManifest, ) -> Diagnostic | None: + diagnostic: Diagnostic | None = None + exact_supported = any( + declaration.domain == RUNTIME_REALIZATION_DOMAIN + and DECLARED_CAPABILITY_MATCH_REQUIREMENT_KIND in declaration.supported_exact_requirement_kinds + for declaration in manifest.realization_support + ) for operation in plan.operations: admission = _STATEFUL_ADMISSION_BY_RESOURCE_TYPE.get(operation.resource_type) if admission is None: continue capability_attribute, unsupported_code, resource_label = admission if not getattr(manifest.provisioner, capability_attribute): - return Diagnostic( + diagnostic = Diagnostic( code=unsupported_code, domain="provisioning", address=operation.address, message=f"Provisioner does not support {resource_label}.", ) - exact_supported = any( - declaration.domain == RUNTIME_REALIZATION_DOMAIN - and DECLARED_CAPABILITY_MATCH_REQUIREMENT_KIND in declaration.supported_exact_requirement_kinds - for declaration in manifest.realization_support - ) - if not exact_supported: - return Diagnostic( + elif operation.resource_type == "generated-artifact": + artifact_diagnostic = generated_artifact_payload_diagnostic( + address=operation.address, + spec=operation.payload.get("spec"), + provisioner=manifest.provisioner, + ) + if artifact_diagnostic is not None: + diagnostic = artifact_diagnostic + if diagnostic is None and not exact_supported: + diagnostic = Diagnostic( code="realization.unsupported-exact-requirement", domain="runtime-realization", address=operation.address, @@ -108,7 +119,9 @@ def _stateful_submission_diagnostic( f"{operation.resource_type} resource." ), ) - return None + if diagnostic is not None: + break + return diagnostic def _submitted_operation_diagnostic( diff --git a/implementations/python/tests/test_autonomous_behavior_vocabularies.py b/implementations/python/tests/test_autonomous_behavior_vocabularies.py new file mode 100644 index 000000000..c80e20596 --- /dev/null +++ b/implementations/python/tests/test_autonomous_behavior_vocabularies.py @@ -0,0 +1,297 @@ +"""Pinned autonomous-service and autonomous-agent vocabulary source tests.""" + +from __future__ import annotations + +import importlib.util +import json +import subprocess +import sys +from pathlib import Path + +import pytest +from jsonschema import Draft202012Validator +from pydantic import ValidationError +from raes_conformance.conformance import validate_contract_payload +from raes_contracts.contracts import ( + ActivityStreamsActivityTypesSourceModel, + FipaCommunicativeActsSourceModel, + schema_bundle, +) +from raes_contracts.external_concept_bindings import ( + adapt_activitystreams_activity_types_snapshot, + adapt_fipa_communicative_acts_snapshot, +) +from raes_contracts.vocabulary_sources import ( + load_activitystreams_activity_types_source, + load_fipa_communicative_acts_source, +) + +REPO_ROOT = Path(__file__).resolve().parents[3] +SCHEMA_ROOT = REPO_ROOT / "contracts" / "schemas" / "concept-authority" +CHECKER_PATH = REPO_ROOT / "tools" / "check_autonomous_behavior_vocabularies.py" + +ACTIVITYSTREAMS_TYPES = ( + "Accept", + "Add", + "Announce", + "Arrive", + "Block", + "Create", + "Delete", + "Dislike", + "Flag", + "Follow", + "Ignore", + "Invite", + "Join", + "Leave", + "Like", + "Listen", + "Move", + "Offer", + "Question", + "Reject", + "Read", + "Remove", + "TentativeReject", + "TentativeAccept", + "Travel", + "Undo", + "Update", + "View", +) +FIPA_ACTS = ( + "accept-proposal", + "agree", + "cancel", + "cfp", + "confirm", + "disconfirm", + "failure", + "inform", + "inform-if", + "inform-ref", + "not-understood", + "propagate", + "propose", + "proxy", + "query-if", + "query-ref", + "refuse", + "reject-proposal", + "request", + "request-when", + "request-whenever", + "subscribe", +) + + +def test_activitystreams_source_pins_dated_recommendation_and_normative_activity_types() -> None: + source = load_activitystreams_activity_types_source() + + assert source.source_authority == "World Wide Web Consortium" + assert source.source_version == "REC-activitystreams-vocabulary-20170523" + assert source.source_status == "W3C Recommendation" + assert source.source_url == "https://www.w3.org/TR/2017/REC-activitystreams-vocabulary-20170523/" + assert source.source_digest == "sha256:1418443392160f4bb23dffb5727f5216d1f56d3430377dc67d364016521401db" + assert [term.position for term in source.activity_types] == list(range(1, 29)) + assert [term.type_name for term in source.activity_types] == list(ACTIVITYSTREAMS_TYPES) + assert [term.concept_id for term in source.activity_types] == [ + f"https://www.w3.org/ns/activitystreams#{name}" for name in ACTIVITYSTREAMS_TYPES + ] + assert all(term.type_name not in {"Application", "Service"} for term in source.activity_types) + + +def test_fipa_source_pins_standard_and_exact_communicative_act_symbols() -> None: + source = load_fipa_communicative_acts_source() + + assert source.source_authority == "Foundation for Intelligent Physical Agents" + assert source.source_version == "SC00037J-2002-12-03" + assert source.source_status == "Standard" + assert source.source_url == "https://www.fipa.org/specs/fipa00037/SC00037J.html" + assert source.source_artifact_url == "https://www.fipa.org/specs/fipa00037/SC00037J.pdf" + assert source.source_digest == "sha256:90b3277247ef7e7f614ba4c0d58fb2b86aa53ff69036d27a731c09a26c605227" + assert [act.position for act in source.communicative_acts] == list(range(1, 23)) + assert [act.concept_id for act in source.communicative_acts] == list(FIPA_ACTS) + + +@pytest.mark.parametrize( + ("loader", "field"), + [ + (load_activitystreams_activity_types_source, "activity_types"), + (load_fipa_communicative_acts_source, "communicative_acts"), + ], +) +def test_source_contracts_reject_duplicate_positions_and_identifiers(loader, field: str) -> None: + source = loader() + payload = source.model_dump(mode="json") + payload[field].append(dict(payload[field][0])) + + model_type = ( + ActivityStreamsActivityTypesSourceModel if field == "activity_types" else FipaCommunicativeActsSourceModel + ) + with pytest.raises(ValidationError): + model_type.model_validate(payload) + + +def test_source_adapters_emit_unrelated_neutral_snapshots_without_rewriting_identifiers() -> None: + activitystreams = adapt_activitystreams_activity_types_snapshot(load_activitystreams_activity_types_source()) + fipa = adapt_fipa_communicative_acts_snapshot(load_fipa_communicative_acts_source()) + + assert activitystreams.scheme_id == "w3c-activitystreams-activity-types" + assert activitystreams.authority == "World Wide Web Consortium" + assert activitystreams.revision == "REC-activitystreams-vocabulary-20170523" + assert [term.concept_id for term in activitystreams.concepts] == [ + f"https://www.w3.org/ns/activitystreams#{name}" for name in ACTIVITYSTREAMS_TYPES + ] + + assert fipa.scheme_id == "fipa-communicative-act-library" + assert fipa.authority == "Foundation for Intelligent Physical Agents" + assert fipa.revision == "SC00037J-2002-12-03" + assert [term.concept_id for term in fipa.concepts] == list(FIPA_ACTS) + + +@pytest.mark.parametrize( + ("loader", "adapter", "field"), + [ + (load_activitystreams_activity_types_source, adapt_activitystreams_activity_types_snapshot, "activity_types"), + (load_fipa_communicative_acts_source, adapt_fipa_communicative_acts_snapshot, "communicative_acts"), + ], +) +def test_source_adapters_preserve_duplicate_concept_candidates(loader, adapter, field: str) -> None: + source = loader() + terms = getattr(source, field) + duplicate_source = source.model_copy(update={field: [*terms, terms[0]]}) + + snapshot = adapter(duplicate_source) + + assert sum(term.concept_id == snapshot.concepts[0].concept_id for term in snapshot.concepts) == 2 + + +@pytest.mark.parametrize( + "contract_id", + [ + "w3c-activitystreams-activity-types-source-v1", + "fipa-communicative-acts-source-v1", + ], +) +def test_autonomous_vocabulary_source_schemas_are_published_and_generated_in_parity(contract_id: str) -> None: + path = SCHEMA_ROOT / f"{contract_id}.json" + published = json.loads(path.read_text(encoding="utf-8")) + source = ( + load_activitystreams_activity_types_source() + if contract_id.startswith("w3c-") + else load_fipa_communicative_acts_source() + ) + + Draft202012Validator(published).validate(source.model_dump(mode="json")) + assert schema_bundle()[contract_id] == published + + +@pytest.mark.parametrize( + ("contract_id", "loader", "term_field"), + [ + ( + "w3c-activitystreams-activity-types-source-v1", + load_activitystreams_activity_types_source, + "activity_types", + ), + ("fipa-communicative-acts-source-v1", load_fipa_communicative_acts_source, "communicative_acts"), + ], +) +def test_source_contracts_use_canonical_structural_conformance( + contract_id: str, + loader, + term_field: str, +) -> None: + payload = loader().model_dump(mode="json") + + assert validate_contract_payload(contract_id, payload) == () + + payload[term_field].append(dict(payload[term_field][0])) + diagnostics = validate_contract_payload(contract_id, payload) + + assert {diagnostic.code for diagnostic in diagnostics} == {"conformance.schema-invalid"} + assert payload[term_field][0]["concept_id"] not in diagnostics[0].message + + +def _load_source_checker(): + spec = importlib.util.spec_from_file_location("check_autonomous_behavior_vocabularies", CHECKER_PATH) + assert spec is not None + assert spec.loader is not None + module = importlib.util.module_from_spec(spec) + spec.loader.exec_module(module) + return module + + +@pytest.mark.integration +def test_autonomous_behavior_source_integrity_checker_passes_offline() -> None: + result = subprocess.run( + [sys.executable, str(CHECKER_PATH)], + cwd=REPO_ROOT, + check=False, + capture_output=True, + text=True, + ) + + assert result.returncode == 0, result.stderr + + +def test_source_integrity_checker_rejects_metadata_drift() -> None: + checker = _load_source_checker() + activitystreams = load_activitystreams_activity_types_source().model_copy( + update={"source_digest": f"sha256:{'0' * 64}"} + ) + fipa = load_fipa_communicative_acts_source().model_copy(update={"source_version": "moving-latest"}) + + activitystreams_failures = checker._check_activitystreams_source(activitystreams) + fipa_failures = checker._check_fipa_source(fipa) + + assert any("source_digest" in failure for failure in activitystreams_failures) + assert any("source_version" in failure for failure in fipa_failures) + + +def test_remote_maintenance_fetch_rejects_redirects_outside_official_host(monkeypatch) -> None: + checker = _load_source_checker() + redirect_handler = checker._OfficialHttpsRedirectHandler("www.w3.org") + + with pytest.raises(ValueError, match="allowlisted"): + redirect_handler.redirect_request( + request=None, + fp=None, + code=302, + msg="Found", + headers={}, + newurl="https://example.test/source", + ) + + handlers = [] + + class _Response: + def __enter__(self): + return self + + def __exit__(self, *_args): + return None + + def read(self): + return b"official-source" + + class _Opener: + def open(self, *_args, **_kwargs): + return _Response() + + def _build_opener(*args): + handlers.extend(args) + return _Opener() + + monkeypatch.setattr(checker.urllib.request, "build_opener", _build_opener) + + assert ( + checker._fetch_official_bytes( + "https://www.w3.org/TR/2017/REC-activitystreams-vocabulary-20170523/", + allowed_host="www.w3.org", + ) + == b"official-source" + ) + assert any(isinstance(handler, checker._OfficialHttpsRedirectHandler) for handler in handlers) diff --git a/implementations/python/tests/test_backend_manifest.py b/implementations/python/tests/test_backend_manifest.py index 66465bd8e..cbcc27955 100644 --- a/implementations/python/tests/test_backend_manifest.py +++ b/implementations/python/tests/test_backend_manifest.py @@ -7,6 +7,8 @@ from pathlib import Path import pytest +from jsonschema import Draft202012Validator +from jsonschema import ValidationError as JSONSchemaValidationError from pydantic import ValidationError from raes_backend_protocols.capabilities import ( OBSERVATION_CAPABILITY_CAPTURE_KIND_SCOPE, @@ -105,6 +107,11 @@ def test_backend_manifest_v2_roundtrip_from_stub_manifest(): assert model.compatibility.model_dump(mode="json") == {"processors": ["raes-reference-processor"]} assert model.supported_contract_versions == EXPECTED_SUPPORTED_CONTRACT_VERSIONS_V2 assert model.capabilities.orchestrator is not None + assert model.capabilities.provisioner.supported_generated_artifact_kinds == [ + "certificate_bundle", + "rendered_config", + "ssh_key_bundle", + ] assert model.capabilities.orchestrator.supported_workflow_features == [ WorkflowFeature.CALL, WorkflowFeature.CANCELLATION, @@ -122,6 +129,64 @@ def test_backend_manifest_v2_roundtrip_from_stub_manifest(): assert roundtrip == payload +def test_generated_artifact_capability_requires_explicit_kind_support(): + manifest = create_stub_manifest() + provisioner = manifest.provisioner + empty_kinds: frozenset[str] = frozenset() + rendered_config_kinds = frozenset({"rendered_config"}) + + with pytest.raises(ValueError, match="must declare supported_generated_artifact_kinds"): + replace(provisioner, supported_generated_artifact_kinds=empty_kinds) + + with pytest.raises(ValueError, match="require supports_generated_artifacts=True"): + replace( + provisioner, + supports_generated_artifacts=False, + supported_generated_artifact_kinds=rendered_config_kinds, + ) + + +def test_backend_manifest_v2_rejects_contradictory_generated_artifact_capabilities(): + payload = backend_manifest_payload(create_stub_manifest()) + provisioner = payload["capabilities"]["provisioner"] + + provisioner["supported_generated_artifact_kinds"] = [] + with pytest.raises(ValidationError, match="must declare supported_generated_artifact_kinds"): + BackendManifestV2Model.model_validate(payload) + + provisioner["supports_generated_artifacts"] = False + provisioner["supported_generated_artifact_kinds"] = ["rendered_config"] + with pytest.raises(ValidationError, match="require supports_generated_artifacts=true"): + BackendManifestV2Model.model_validate(payload) + + +@pytest.mark.parametrize( + ("support_flag", "supported_values"), + [ + ("supports_accounts", "supported_account_features"), + ("supports_generated_artifacts", "supported_generated_artifact_kinds"), + ], +) +def test_backend_manifest_schema_requires_true_support_flag_for_nonempty_supported_values( + support_flag: str, + supported_values: str, +) -> None: + schema = BackendManifestV2Model.model_json_schema() + payload = backend_manifest_payload(create_stub_manifest()) + provisioner = payload["capabilities"]["provisioner"] + provisioner.pop(support_flag) + validator = Draft202012Validator(schema) + + with pytest.raises(JSONSchemaValidationError): + validator.validate(payload) + with pytest.raises(ValidationError): + BackendManifestV2Model.model_validate(payload) + + provisioner[supported_values] = [] + validator.validate(payload) + BackendManifestV2Model.model_validate(payload) + + def test_coordinated_reset_manifest_claim_requires_participant_runtime_capabilities(): manifest = create_stub_manifest(with_time=True, with_participant_runtime=False) assert manifest.time is not None diff --git a/implementations/python/tests/test_behavioral_relations.py b/implementations/python/tests/test_behavioral_relations.py index 743c9aaaf..c97db6f5b 100644 --- a/implementations/python/tests/test_behavioral_relations.py +++ b/implementations/python/tests/test_behavioral_relations.py @@ -150,7 +150,7 @@ def test_authoritative_catalog_covers_required_relation_classes_and_dimensions() assert catalog.schema_version == "behavioral-relations/v1" assert catalog.taxonomy_id == "raes-behavioral-relations" - assert catalog.taxonomy_revision == "rev8" + assert catalog.taxonomy_revision == "rev9" assert set(catalog.relations) >= REQUIRED_RELATION_IDS for relation_id, relation in catalog.relations.items(): assert relation.left_carrier diff --git a/implementations/python/tests/test_concept_authority.py b/implementations/python/tests/test_concept_authority.py index 9cb66884f..6ef81566c 100644 --- a/implementations/python/tests/test_concept_authority.py +++ b/implementations/python/tests/test_concept_authority.py @@ -117,7 +117,7 @@ def test_native_family_rejects_authority_metadata(): description="SDL scenarios.", provenance=ConceptProvenanceCategory.NATIVE, authority="RAES", - authority_reference="https://raesystem.github.io/rae/concepts", + authority_reference="https://openrae.github.io/rae/concepts", extension_scope="SDL-native scenario authoring constructs.", relation_rules=["Must remain the scenario authoring layer."], non_ambiguity_constraints=["Must not redefine adopted cyber-domain families."], diff --git a/implementations/python/tests/test_conformance_facade_parity.py b/implementations/python/tests/test_conformance_facade_parity.py index fdfe1c070..3b03a3929 100644 --- a/implementations/python/tests/test_conformance_facade_parity.py +++ b/implementations/python/tests/test_conformance_facade_parity.py @@ -26,6 +26,8 @@ "BackendProfileSelector", "ConformanceCaseResult", "backend_conformance_report_payload", + "contract_payload_root", + "contract_validation_strength", "fixtures_root", "observability_evidence_conformance_diagnostics", "profile_for_manifest", @@ -33,6 +35,7 @@ "required_contracts", "run_fixture_suite", "run_target_conformance", + "supported_contract_ids", "validate_contract_payload", } @@ -50,6 +53,9 @@ "run_fixture_suite": fixture_suite, "profile_for_manifest": target, "run_target_conformance": target, + "contract_payload_root": validators, + "contract_validation_strength": validators, + "supported_contract_ids": validators, "validate_contract_payload": validators, } diff --git a/implementations/python/tests/test_corpus_packaging.py b/implementations/python/tests/test_corpus_packaging.py index 0a22e952b..a44073e65 100644 --- a/implementations/python/tests/test_corpus_packaging.py +++ b/implementations/python/tests/test_corpus_packaging.py @@ -138,6 +138,8 @@ def test_corpus_discoverable_via_importlib_resources_from_installed_wheel(instal " 'backend_profile': (corpus_family_root('profiles')/'backend'/'provisioning-only.json').exists(),\n" " 'scientific_completeness': (corpus_family_root('profiles')/'scientific-completeness'/'scientific-scenario-completeness-rev1.json').exists(),\n" " 'controlled_vocab': (corpus_family_root('concept-authority')/'controlled-vocabularies-v1.json').exists(),\n" + " 'activitystreams_source': (corpus_family_root('concept-authority')/'w3c-activitystreams-activity-types-source-v1.json').exists(),\n" + " 'fipa_source': (corpus_family_root('concept-authority')/'fipa-communicative-acts-source-v1.json').exists(),\n" " 'fixtures_dir': corpus_family_root('fixtures').is_dir(),\n" " 'schemas_dir': corpus_family_root('schemas').is_dir(),\n" "}))\n" @@ -155,6 +157,8 @@ def test_corpus_discoverable_via_importlib_resources_from_installed_wheel(instal assert payload["backend_profile"] is True assert payload["scientific_completeness"] is True assert payload["controlled_vocab"] is True + assert payload["activitystreams_source"] is True + assert payload["fipa_source"] is True assert payload["fixtures_dir"] is True assert payload["schemas_dir"] is True diff --git a/implementations/python/tests/test_external_concept_bindings.py b/implementations/python/tests/test_external_concept_bindings.py index d97ba3bc7..486e0d95a 100644 --- a/implementations/python/tests/test_external_concept_bindings.py +++ b/implementations/python/tests/test_external_concept_bindings.py @@ -26,13 +26,17 @@ from raes_contracts.controlled_vocabularies import load_controlled_vocabulary_catalog from raes_contracts.external_concept_bindings import ( ExternalConceptResolutionOutcome, + adapt_activitystreams_activity_types_snapshot, adapt_attack_enterprise_tactics_snapshot, + adapt_fipa_communicative_acts_snapshot, adapt_nist_csf_defensive_categories_snapshot, admit_external_concept_bindings, ) from raes_contracts.semantic_binding_effects import ExternalKnowledgeBindingEffect from raes_contracts.vocabulary_sources import ( + load_activitystreams_activity_types_source, load_attack_enterprise_tactics_source, + load_fipa_communicative_acts_source, load_nist_csf_defensive_categories_source, ) @@ -41,6 +45,7 @@ VALID_ROOT = FIXTURE_ROOT / "valid" INVALID_ROOT = FIXTURE_ROOT / "invalid" SUBJECT_PATH = FIXTURE_ROOT / "context" / "subject.sdl.yaml" +AUTONOMOUS_BEHAVIOR_SUBJECT_PATH = FIXTURE_ROOT / "context" / "autonomous-behavior-subject.sdl.yaml" SCHEMA_PATH = REPO_ROOT / "contracts" / "schemas" / "concept-authority" / "external-concept-bindings-v1.json" @@ -53,25 +58,35 @@ def _document(path: Path) -> ExternalConceptBindingDocumentModel: def _subjects(): - return external_concept_subjects(load_scenario(SUBJECT_PATH)) + return ( + *external_concept_subjects(load_scenario(SUBJECT_PATH)), + *external_concept_subjects(load_scenario(AUTONOMOUS_BEHAVIOR_SUBJECT_PATH)), + ) def _snapshots(): return ( adapt_attack_enterprise_tactics_snapshot(load_attack_enterprise_tactics_source()), adapt_nist_csf_defensive_categories_snapshot(load_nist_csf_defensive_categories_source()), + adapt_activitystreams_activity_types_snapshot(load_activitystreams_activity_types_source()), + adapt_fipa_communicative_acts_snapshot(load_fipa_communicative_acts_source()), ) @pytest.mark.parametrize("path", sorted(VALID_ROOT.glob("*.json")), ids=lambda path: path.stem) def test_unrelated_scheme_fixtures_share_contract_and_schema(path: Path) -> None: - document = _document(path) + payload = _load_json(path) + document = ExternalConceptBindingDocumentModel.model_validate(payload) published_schema = json.loads(SCHEMA_PATH.read_text(encoding="utf-8")) Draft202012Validator(published_schema).validate(document.model_dump(mode="json", exclude_none=True)) assert document.schema_version == "external-concept-bindings/v1" assert len(document.bindings) == 1 + assert validate_contract_payload("external-concept-bindings-v1", payload) == () + assert {diagnostic.code for diagnostic in _fixture_case_diagnostics("external-concept-bindings-v1", payload)} == { + "conformance.semantic-context-required" + } @pytest.mark.parametrize("path", sorted(VALID_ROOT.glob("*.json")), ids=lambda path: path.stem) @@ -326,6 +341,38 @@ def test_sdl_subject_adapter_uses_canonical_declaration_identity_and_digest() -> assert not any(subject.canonical_ref == "web" for subject in subjects) +@pytest.mark.parametrize( + ("filename", "canonical_ref"), + [ + ("activitystreams-behavior.json", "behavior_specifications.service-publication"), + ("fipa-behavior.json", "behavior_specifications.agent-request"), + ], +) +def test_autonomous_scheme_fixtures_target_exact_behavior_specifications( + filename: str, + canonical_ref: str, +) -> None: + document = _document(VALID_ROOT / filename) + binding = next(iter(document.bindings.values())) + subject = binding.subject + available_subjects = _subjects() + + assert subject.subject_kind == "behavior_specifications" + assert subject.owning_contract_id == "sdl-authoring-input-v1" + assert subject.lifecycle_phase == "normalized-authoring" + assert subject.canonical_ref == canonical_ref + assert subject.artifact_digest.startswith("sha256:") + assert sum(candidate == subject for candidate in available_subjects) == 1 + + report = admit_external_concept_bindings( + document, + subjects=available_subjects, + scheme_snapshots=_snapshots(), + ) + assert report.admitted + assert report.results[0].outcome == ExternalConceptResolutionOutcome.RESOLVED_CURRENT + + @pytest.mark.parametrize( ("vocabulary_id", "enum_type"), [ diff --git a/implementations/python/tests/test_initial_service_state.py b/implementations/python/tests/test_initial_service_state.py index 331961153..09da91396 100644 --- a/implementations/python/tests/test_initial_service_state.py +++ b/implementations/python/tests/test_initial_service_state.py @@ -8,9 +8,12 @@ import pytest import yaml -from raes import SDLValidationError, parse_sdl, parse_sdl_file +from jsonschema import Draft202012Validator +from raes import SDLParseError, SDLValidationError, parse_sdl, parse_sdl_file from raes_backend_protocols.backend_manifest import BackendManifest from raes_backend_stubs.stubs import create_stub_manifest, create_stub_target +from raes_contracts.canonical import canonical_json_digest +from raes_contracts.contracts import schema_bundle from raes_contracts.planning import ChangeAction, ProvisioningPlan, ProvisionOp, RuntimeDomain from raes_contracts.runtime_state import RuntimeSnapshot, SnapshotEntry from raes_processor.compiler import compile_scenario_runtime_model @@ -20,6 +23,8 @@ from raes_runtime.control_plane import RuntimeControlPlane from raes_runtime.registry import RuntimeTarget +REPO_ROOT = Path(__file__).resolve().parents[3] + def _scenario(*replacements: tuple[str, str]): source = """ @@ -108,17 +113,51 @@ def _scenario(*replacements: tuple[str, str]): return parse_sdl(textwrap.dedent(source)) -def _manifest_with_profile() -> BackendManifest: +def _search_index_schema_scenario(*replacements: tuple[str, str]): + profile_replacements = ( + (" items:\n - name: welcome\n", ""), + ("interface_profile: service-content", "interface_profile: service-search-index-schema"), + ("operation: ensure-owned-items", "operation: ensure-search-index-field-schema"), + ("readback: canonical-content-digest", "readback: canonical-portable-field-schema-digest"), + ( + " readback: canonical-portable-field-schema-digest", + " readback: canonical-portable-field-schema-digest\n" + " field_semantics:\n" + " key: exact-token\n" + " status: exact-token\n" + " relations: exact-token", + ), + ) + return _scenario(*profile_replacements, *replacements) + + +def _manifest_with_profile( + profile: str = "service-content-v1", + requirement_kind: str | None = "service-content-materialization", +) -> BackendManifest: manifest = create_stub_manifest() provisioner = replace( manifest.provisioner, - supported_service_materialization_profiles=frozenset({"service-content-v1"}), + supported_service_materialization_profiles=frozenset({profile}), + ) + realization_support = ( + tuple( + replace( + declaration, + supported_exact_requirement_kinds=( + declaration.supported_exact_requirement_kinds | frozenset({requirement_kind}) + ), + ) + for declaration in manifest.realization_support + ) + if requirement_kind is not None + else manifest.realization_support ) return BackendManifest( identity=manifest.identity, supported_contract_versions=manifest.supported_contract_versions, compatibility=manifest.compatibility, - realization_support=manifest.realization_support, + realization_support=realization_support, concept_bindings=manifest.concept_bindings, constraints=manifest.constraints, capabilities=replace(manifest.capabilities, provisioner=provisioner), @@ -126,6 +165,301 @@ def _manifest_with_profile() -> BackendManifest: ) +def test_search_index_schema_profile_is_typed_schema_only_desired_state() -> None: + scenario = _search_index_schema_scenario() + + content = scenario.content["messages"] + assert content.items == [] + assert content.source is None + binding = content.service_materialization + assert binding is not None + assert binding.interface_profile == "service-search-index-schema" + assert binding.requirements.field_semantics == { + "key": "exact-token", + "status": "exact-token", + "relations": "exact-token", + } + + +@pytest.mark.parametrize( + ("replacement", "message"), + [ + ( + (" key: exact-token", " key: keyword"), + "Input should be", + ), + ( + ( + " field_semantics:\n" + " key: exact-token\n" + " status: exact-token\n" + " relations: exact-token", + " field_semantics: {}", + ), + "at least 1 item", + ), + ( + (" relations: exact-token", " relations: exact-token\n native_mapping: {}"), + "Extra inputs are not permitted", + ), + ( + (" service_materialization:", " items:\n - name: forbidden\n service_materialization:"), + "must not carry source or items", + ), + ], +) +def test_search_index_schema_profile_rejects_non_portable_or_payload_shapes( + replacement: tuple[str, str], + message: str, +) -> None: + with pytest.raises(SDLParseError, match=message): + _search_index_schema_scenario(replacement) + + +def test_search_index_schema_compiles_portable_map_digest_and_exact_requirement() -> None: + model = compile_scenario_runtime_model(_search_index_schema_scenario()) + + placement = model.content_placements["provision.content.messages"] + binding = placement.service_materialization + assert binding is not None + assert binding.interface_profile == "service-search-index-schema" + assert binding.profile_version == "1" + assert binding.operation == "ensure-search-index-field-schema" + assert binding.conflict_policy == "reject-unowned-collision" + assert binding.readback == "canonical-portable-field-schema-digest" + assert binding.field_semantics == { + "key": "exact-token", + "status": "exact-token", + "relations": "exact-token", + } + assert binding.canonical_field_schema_digest == canonical_json_digest( + { + "interface_profile": "service-search-index-schema", + "profile_version": "1", + "projection_scope": "declared-fields", + "field_semantics": { + "key": "exact-token", + "status": "exact-token", + "relations": "exact-token", + }, + } + ) + assert any( + requirement.requirement_kind == "service-search-index-schema-materialization" + and requirement.address == placement.address + for requirement in model.realization_requirements + ) + + +def test_search_index_schema_digest_is_order_independent_and_semantic_sensitive() -> None: + original = compile_scenario_runtime_model(_search_index_schema_scenario()) + reordered = compile_scenario_runtime_model( + _search_index_schema_scenario( + ( + " key: exact-token\n status: exact-token\n relations: exact-token", + " relations: exact-token\n key: exact-token\n status: exact-token", + ) + ) + ) + changed = compile_scenario_runtime_model( + _search_index_schema_scenario((" status: exact-token", " status: full-text")) + ) + + original_binding = original.content_placements["provision.content.messages"].service_materialization + reordered_binding = reordered.content_placements["provision.content.messages"].service_materialization + changed_binding = changed.content_placements["provision.content.messages"].service_materialization + assert original_binding is not None + assert reordered_binding is not None + assert changed_binding is not None + assert original_binding.canonical_field_schema_digest == reordered_binding.canonical_field_schema_digest + assert original_binding.canonical_field_schema_digest != changed_binding.canonical_field_schema_digest + + +def test_search_index_schema_profile_requires_separate_capability() -> None: + model = compile_scenario_runtime_model(_search_index_schema_scenario()) + + unsupported = plan(model, _manifest_with_profile()) + assert "provisioner.unsupported-service-materialization-profile" in { + diagnostic.code for diagnostic in unsupported.diagnostics + } + supported = plan( + model, + _manifest_with_profile( + "service-search-index-schema-v1", + "service-search-index-schema-materialization", + ), + ) + assert "provisioner.unsupported-service-materialization-profile" not in { + diagnostic.code for diagnostic in supported.diagnostics + } + + +def test_search_index_schema_profile_is_published_in_every_scenario_contract() -> None: + bundle = schema_bundle() + + for contract_id in ( + "sdl-authoring-input-v1", + "instantiated-scenario-v1", + "instantiated-scenario-snapshot-v1", + "scenario-satisfiability-evidence-v1", + ): + assert "service-search-index-schema" in str(bundle[contract_id]) + + +def test_initial_service_state_example_covers_search_index_schema_profile() -> None: + scenario = parse_sdl_file(REPO_ROOT / "examples" / "scenarios" / "initial-service-state.sdl.yaml") + + binding = scenario.content["job-index-schema"].service_materialization + assert binding is not None + assert binding.interface_profile == "service-search-index-schema" + + +def test_search_index_schema_profile_requires_separate_exact_realization_support() -> None: + model = compile_scenario_runtime_model(_search_index_schema_scenario()) + + unsupported = plan( + model, + _manifest_with_profile("service-search-index-schema-v1", None), + ) + + assert "realization.unsupported-exact-requirement" in {diagnostic.code for diagnostic in unsupported.diagnostics} + + +def test_direct_plan_submission_rejects_tampered_search_index_schema_digest() -> None: + model = compile_scenario_runtime_model(_search_index_schema_scenario()) + placement = model.content_placements["provision.content.messages"] + payload = resource_payload(placement) + changed_payload = dict(payload) + changed_binding = dict(changed_payload["service_materialization"]) + changed_binding["canonical_field_schema_digest"] = "sha256:" + "f" * 64 + changed_payload["service_materialization"] = changed_binding + operation = ProvisionOp( + action=ChangeAction.CREATE, + address=placement.address, + resource_type="content-placement", + payload=changed_payload, + ) + base_target = create_stub_target() + manifest = _manifest_with_profile( + "service-search-index-schema-v1", + "service-search-index-schema-materialization", + ) + target = RuntimeTarget( + name=base_target.name, + manifest=manifest, + provisioner=base_target.provisioner, + orchestrator=base_target.orchestrator, + evaluator=base_target.evaluator, + participant_runtime=base_target.participant_runtime, + ) + + result = RuntimeControlPlane(target).submit_provisioning(ProvisioningPlan(operations=[operation])) + + assert [diagnostic.code for diagnostic in result.diagnostics] == [ + "provisioner.service-materialization-contract-invalid" + ] + + +@pytest.mark.parametrize( + ("field", "value"), + [ + ("source", ""), + ("source", False), + ("items", ""), + ("items", {}), + ], +) +def test_direct_plan_submission_rejects_falsey_malformed_search_index_content( + field: str, + value: object, +) -> None: + model = compile_scenario_runtime_model(_search_index_schema_scenario()) + placement = model.content_placements["provision.content.messages"] + payload = resource_payload(placement) + changed_payload = dict(payload) + changed_spec = dict(changed_payload["spec"]) + changed_spec[field] = value + changed_payload["spec"] = changed_spec + operation = ProvisionOp( + action=ChangeAction.CREATE, + address=placement.address, + resource_type="content-placement", + payload=changed_payload, + ) + + result = RuntimeControlPlane(create_stub_target()).submit_provisioning(ProvisioningPlan(operations=[operation])) + + assert [diagnostic.code for diagnostic in result.diagnostics] == [ + "provisioner.service-materialization-contract-invalid" + ] + + +def test_direct_plan_submission_requires_search_index_schema_readback() -> None: + model = compile_scenario_runtime_model(_search_index_schema_scenario()) + placement = model.content_placements["provision.content.messages"] + operation = ProvisionOp( + action=ChangeAction.CREATE, + address=placement.address, + resource_type="content-placement", + payload=resource_payload(placement), + ) + base_target = create_stub_target() + manifest = _manifest_with_profile( + "service-search-index-schema-v1", + "service-search-index-schema-materialization", + ) + target = RuntimeTarget( + name=base_target.name, + manifest=manifest, + provisioner=base_target.provisioner, + orchestrator=base_target.orchestrator, + evaluator=base_target.evaluator, + participant_runtime=base_target.participant_runtime, + ) + + result = RuntimeControlPlane(target).submit_provisioning(ProvisioningPlan(operations=[operation])) + + assert [diagnostic.code for diagnostic in result.diagnostics] == [ + "provisioner.service-materialization-readback-unsupported" + ] + + +def test_direct_plan_submission_requires_search_index_schema_exact_support() -> None: + model = compile_scenario_runtime_model(_search_index_schema_scenario()) + placement = model.content_placements["provision.content.messages"] + operation = ProvisionOp( + action=ChangeAction.CREATE, + address=placement.address, + resource_type="content-placement", + payload=resource_payload(placement), + ) + base_target = create_stub_target() + manifest = _manifest_with_profile("service-search-index-schema-v1", None) + target = RuntimeTarget( + name=base_target.name, + manifest=manifest, + provisioner=base_target.provisioner, + orchestrator=base_target.orchestrator, + evaluator=base_target.evaluator, + participant_runtime=base_target.participant_runtime, + ) + + result = RuntimeControlPlane(target).submit_provisioning(ProvisioningPlan(operations=[operation])) + + assert [diagnostic.code for diagnostic in result.diagnostics] == ["realization.unsupported-exact-requirement"] + + +def test_service_content_profile_default_remains_backward_compatible() -> None: + scenario = _scenario((" interface_profile: service-content\n", "")) + + binding = scenario.content["messages"].service_materialization + assert binding is not None + assert binding.interface_profile == "service-content" + payload = scenario.model_dump(mode="json", exclude_none=True) + del payload["content"]["messages"]["service_materialization"]["interface_profile"] + assert Draft202012Validator(schema_bundle()["sdl-authoring-input-v1"]).is_valid(payload) + + def test_service_materialization_compiles_through_content_placement() -> None: model = compile_scenario_runtime_model(_scenario()) @@ -337,3 +671,50 @@ def test_module_composition_rewrites_service_materialization_refs(tmp_path: Path assert binding.readback_assertion_refs == ["shared.messages-visible"] assert binding.evidence_requirement_refs == ["shared.service-readback"] assert binding.observation_boundary_refs == ["shared.participant-view"] + + +def test_module_composition_preserves_search_index_field_semantics(tmp_path: Path) -> None: + payload = _search_index_schema_scenario().model_dump(mode="json", exclude_none=True) + payload["module"] = { + "id": "raes/search-index-schema", + "version": "1.0.0", + "exports": { + section: list(payload[section]) + for section in ( + "nodes", + "content", + "propositions", + "assertions", + "observation_boundaries", + "evidence_requirements", + "deployment_tenants", + "deployment_cells", + ) + }, + } + imported = tmp_path / "search-index-schema.yaml" + imported.write_text(yaml.safe_dump(payload, sort_keys=False), encoding="utf-8") + root = tmp_path / "root.yaml" + root.write_text( + textwrap.dedent( + """ + name: root + imports: + - path: search-index-schema.yaml + namespace: shared + version: 1.0.0 + """ + ), + encoding="utf-8", + ) + + scenario = parse_sdl_file(root) + binding = scenario.content["shared.messages"].service_materialization + + assert binding is not None + assert binding.target_service_ref == "nodes.shared.app.services.mail" + assert binding.requirements.field_semantics == { + "key": "exact-token", + "status": "exact-token", + "relations": "exact-token", + } diff --git a/implementations/python/tests/test_issue_811_participant_bisimulation_design.py b/implementations/python/tests/test_issue_811_participant_bisimulation_design.py index f94747654..d2b4d644f 100644 --- a/implementations/python/tests/test_issue_811_participant_bisimulation_design.py +++ b/implementations/python/tests/test_issue_811_participant_bisimulation_design.py @@ -261,7 +261,7 @@ def test_governance_program_is_requirement_backed_acyclic_and_reproduction_gated def test_catalog_has_exact_relation_and_bounded_claim_surface() -> None: catalog = _load_json(CATALOG_PATH) - assert catalog["taxonomy_revision"] == "rev8" + assert catalog["taxonomy_revision"] == "rev9" relation = catalog["relations"]["divergence-preserving-branching-bisimulation"] assert relation["direction"] == "symmetric" assert relation["quantification"]["states"] == "greatest-fixed-point relation" diff --git a/implementations/python/tests/test_issue_812_adversarial_participant_control_design.py b/implementations/python/tests/test_issue_812_adversarial_participant_control_design.py new file mode 100644 index 000000000..392e85e78 --- /dev/null +++ b/implementations/python/tests/test_issue_812_adversarial_participant_control_design.py @@ -0,0 +1,303 @@ +"""Structural acceptance gate for issue #812's adversarial-control program.""" + +from __future__ import annotations + +import json +from collections import deque +from pathlib import Path + +REPO_ROOT = Path(__file__).resolve().parents[3] +PROGRAM_PATH = REPO_ROOT / "docs/research/adversarial-participant-control/implementation-program.json" +MILESTONE = "Participant Information-Flow & Behavioral Equivalence" + +REQUIRED_DELIVERABLES = { + "docs/decisions/adrs/adr-101-adversarial-participant-flow-control.md", + "docs/research/adversarial-participant-control/current-state-assessment.md", + "docs/research/adversarial-participant-control/threat-model.md", + "docs/research/adversarial-participant-control/trust-flow-architecture.md", + "docs/research/adversarial-participant-control/attack-cases.md", + "docs/research/adversarial-participant-control/requirement-disposition.md", + "docs/research/adversarial-participant-control/implementation-program.md", + "specs/formal/participant-semantics/adversarial-flow-control.md", +} +REQUIRED_REQUIREMENTS = { + "SEM-230", + "SEM-233", + "ACT-617", + "API-409", + "API-423", + "RUN-310", + "RUN-319", + "API-407", + "ASR-535", + "ASR-536", +} +REQUIRED_SOURCES = { + "fides", + "camel", + "samos", + "agentdojo", + "ai-control", + "controlarena", + "runtime-shielding", + "capability-security", +} +REQUIRED_THREAT_ACTORS = { + "honest-fallible-participant", + "intentionally-subverting-participant", + "untrusted-content-source", + "adaptive-policy-aware-attacker", + "colluding-participants-or-monitors", +} +REQUIRED_ATTACK_CASES = { + "prompt-or-tool-result-injection", + "confidential-exfiltration", + "adaptive-monitor-evasion", + "control-handoff-manipulation", +} +REQUIRED_CHILDREN = { + "semantic-authority", + "portable-contracts", + "runtime-enforcement", + "apparatus-and-backend-support", + "adversarial-evaluation", + "documentation-and-claims", +} +REQUIRED_OPERATIONS = { + "authentication", + "authorization", + "admission", + "approval", + "declassification", + "integrity-endorsement", + "redaction", + "transformation", + "trusted-editing", + "deferral", + "handoff", + "interruption", + "shutdown", +} +REQUIRED_SINKS = { + "external-action", + "tool-argument", + "participant-output", + "external-serialization", + "stream-chunk", + "error-output", +} +REQUIRED_EVALUATION_VARIABLES = { + "mode", + "main-objective", + "side-objective", + "policy-knowledge", + "monitor-knowledge", + "audit-budget-knowledge", + "prior-outcome-visibility", + "adaptive-strategy", + "collusion", + "monitor-topology", + "monitor-correlation", + "audit-budget", + "intervention-protocol", + "memory-scope", +} + + +def _load_program() -> dict[str, object]: + return json.loads(PROGRAM_PATH.read_text(encoding="utf-8")) + + +def test_program_delivers_primary_source_disposition_and_authority() -> None: + program = _load_program() + + assert program["schema_version"] == "adversarial-participant-control-program/v1" + assert program["parent_issue"] == 812 + assert program["milestone"] == MILESTONE + assert set(program["deliverables"]) >= REQUIRED_DELIVERABLES + assert all((REPO_ROOT / path).is_file() for path in REQUIRED_DELIVERABLES) + + sources = {entry["id"]: entry for entry in program["primary_sources"]} + assert set(sources) >= REQUIRED_SOURCES + for source in sources.values(): + assert source["primary_url"] + assert source["adopted_lessons"] + assert source["raes_boundary"] + assert source["nonclaims"] + + requirements = {entry["uid"]: entry for entry in program["requirement_dispositions"]} + assert set(requirements) >= REQUIRED_REQUIREMENTS + assert requirements["SEM-233"]["disposition"] == "new" + assert requirements["SEM-233"]["status"] == "DRAFT" + assert requirements["SEM-233"]["ground_control_id"] + assert requirements["ASR-536"]["disposition"] == "new" + assert requirements["ASR-536"]["status"] == "DRAFT" + assert requirements["ASR-536"]["ground_control_id"] + assert all(entry["scope"] and entry["rationale"] for entry in requirements.values()) + + +def test_threat_model_separates_subversion_and_closes_declared_explicit_flows() -> None: + program = _load_program() + threat_model = program["threat_model"] + + actors = {entry["id"]: entry for entry in threat_model["actors"]} + assert set(actors) >= REQUIRED_THREAT_ACTORS + assert actors["honest-fallible-participant"]["intentional_subversion"] is False + assert actors["intentionally-subverting-participant"]["intentional_subversion"] is True + assert all(entry["capabilities"] and entry["trust_boundary"] for entry in actors.values()) + + assert set(threat_model["explicit_flow_channels"]) >= { + "observations", + "tool-results", + "retrieved-content", + "participant-context", + "retained-memory", + "proposals", + "action-arguments", + "participant-outputs", + "errors", + "handoffs", + } + assert set(threat_model["crossing_scopes"]) == { + "within-participant", + "cross-participant", + "cross-episode", + } + assert set(threat_model["outside_guarantee"]) >= { + "undeclared-timing-channels", + "covert-storage-channels", + "model-steganography", + "private-reasoning-safety", + "monitor-honesty", + } + + +def test_flow_profile_is_two_coordinate_conservative_and_fail_closed() -> None: + profile = _load_program()["flow_policy_profile"] + + assert profile["profile_id"] == "participant-boundary-flow-policy-v1" + assert profile["revision"] == "rev1" + assert profile["confidentiality"]["independent_coordinate"] is True + assert profile["integrity"]["independent_coordinate"] is True + assert profile["confidentiality"]["join"] == "least-upper-bound" + assert profile["integrity"]["join"] == "conservative-influence-union" + assert profile["unknown_source_default"] == "confidential-and-untrusted" + assert profile["missing_or_unknown_behavior"] == "deny-or-explicitly-unsupported" + assert profile["opaque_transformation"] == "retain-join-of-all-possible-inputs" + assert profile["historical_labels_are_immutable"] is True + assert set(profile["distinct_operations"]) >= REQUIRED_OPERATIONS + assert set(profile["sinks"]) >= REQUIRED_SINKS + assert profile["final_enforcement_boundary"] == ( + "after-last-policy-and-state-cut-resolution-before-external-effect-or-disclosure" + ) + assert profile["decision_committed_before_effect"] is True + assert set(profile["deny_without_side_effect"]) >= { + "missing-label", + "missing-provenance", + "unknown-profile", + "stale-state-cut", + "unsupported-capability", + "policy-deny", + "failed-atomic-commit", + } + + +def test_control_evaluation_profile_exposes_adaptation_and_protocol_variables() -> None: + profile = _load_program()["control_evaluation_profile"] + + assert profile["profile_id"] == "intentional-subversion-control-evaluation-v1" + assert profile["revision"] == "rev1" + variables = {entry["id"]: entry for entry in profile["variables"]} + assert set(variables) >= REQUIRED_EVALUATION_VARIABLES + assert all(entry["domain"] and entry["evidence_boundary"] for entry in variables.values()) + assert set(profile["modes"]) == {"honest", "attack"} + assert set(profile["monitor_roles"]) >= {"trusted", "untrusted", "composed"} + assert set(profile["interventions"]) >= { + "human-approval", + "trusted-editing", + "defer-to-trusted", + "interruption", + "shutdown", + } + assert set(profile["measures"]) >= { + "safety", + "usefulness", + "audit-cost", + "intervention-cost", + "uncertainty", + } + assert profile["monitor_score_authorizes_action"] is False + assert profile["ordinary_negative_tests_establish_subversion_robustness"] is False + + +def test_attack_cases_reach_real_sink_and_require_no_prohibited_side_effects() -> None: + cases = {entry["id"]: entry for entry in _load_program()["attack_cases"]} + + assert set(cases) == REQUIRED_ATTACK_CASES + for case in cases.values(): + assert case["attack_path"] + assert case["why_ordinary_admission_is_insufficient"] + assert case["deterministic_boundary_result"] + assert case["evaluation_variables"] + assert set(case["required_evidence"]) >= { + "semantic-result", + "runtime-target-call-count", + "participant-visible-output", + "append-only-history", + "safe-audit-or-error-evidence", + "replay-result", + } + assert case["runtime_boundary"] == "RuntimeControlPlane-to-RuntimeTarget" + assert case["denial_requires_zero_external_effects"] is True + + +def test_child_program_is_bounded_requirement_backed_and_acyclic() -> None: + program = _load_program() + issues = {entry["key"]: entry for entry in program["implementation_issues"]} + + assert set(issues) == REQUIRED_CHILDREN + issue_numbers: set[int] = set() + for key, entry in issues.items(): + assert isinstance(entry["issue_number"], int), key + assert entry["issue_number"] > 0, key + assert entry["issue_number"] not in issue_numbers + issue_numbers.add(entry["issue_number"]) + assert entry["milestone"] == MILESTONE + assert entry["requirements"] + assert set(entry["requirements"]) <= REQUIRED_REQUIREMENTS + assert {"SEM-233", "ASR-536"} & set(entry["requirements"]) + assert entry["bounded_outcome"] + assert entry["negative_cases"] + assert entry["evidence_required"] + assert entry["explicit_nonclaims"] + assert set(entry["dependencies"]) <= set(issues) + + incoming = {key: len(entry["dependencies"]) for key, entry in issues.items()} + outgoing: dict[str, list[str]] = {key: [] for key in issues} + for key, entry in issues.items(): + for dependency in entry["dependencies"]: + outgoing[dependency].append(key) + queue = deque(key for key, degree in incoming.items() if degree == 0) + visited: list[str] = [] + while queue: + key = queue.popleft() + visited.append(key) + for child in outgoing[key]: + incoming[child] -= 1 + if incoming[child] == 0: + queue.append(child) + assert set(visited) == set(issues) + assert issues["documentation-and-claims"]["dependencies"] == [ + "runtime-enforcement", + "apparatus-and-backend-support", + "adversarial-evaluation", + ] + + boundaries = program["claim_boundaries"] + assert boundaries["issue_812"] == "design-authority-and-implementation-program-only" + assert boundaries["runtime_enforcement"] == "not-established" + assert boundaries["backend_realization"] == "not-established" + assert boundaries["intentional_subversion_robustness"] == "not-established" + assert boundaries["model_alignment"] == "outside-scope" + assert boundaries["chain_of_thought"] == "excluded-from-portable-records" + assert boundaries["covert_channels"] == "undeclared-channels-not-controlled" diff --git a/implementations/python/tests/test_issue_813_cross_backend_participant_control_design.py b/implementations/python/tests/test_issue_813_cross_backend_participant_control_design.py new file mode 100644 index 000000000..8b6f1df97 --- /dev/null +++ b/implementations/python/tests/test_issue_813_cross_backend_participant_control_design.py @@ -0,0 +1,332 @@ +"""Structural acceptance gate for issue #813's cross-backend control program.""" + +from __future__ import annotations + +import json +from collections import deque +from pathlib import Path + +REPO_ROOT = Path(__file__).resolve().parents[3] +PROGRAM_PATH = REPO_ROOT / "docs/research/cross-backend-participant-control/implementation-program.json" +PARTICIPANT_MILESTONE = "Participant Information-Flow & Behavioral Equivalence" +BACKEND_MILESTONE = "Backend Contract & Conformance" + +REQUIRED_DELIVERABLES = { + "docs/decisions/adrs/adr-102-mixed-cross-backend-participant-control.md", + "docs/research/cross-backend-participant-control/prior-art-and-design-criteria.md", + "docs/research/cross-backend-participant-control/current-state-assessment.md", + "docs/research/cross-backend-participant-control/composition-architecture.md", + "docs/research/cross-backend-participant-control/demonstration-protocol.md", + "docs/research/cross-backend-participant-control/requirement-disposition.md", + "docs/research/cross-backend-participant-control/implementation-program.md", + "specs/formal/participant-semantics/cross-backend-participant-control.md", +} +REQUIRED_SOURCES = { + "hla-1516-2025", + "nist-integrated-hla", + "nist-ucef", + "acting-edl-fg", + "cyborg", + "cygil", + "cyberbattlesim", + "fmi-3.0.2", + "helics", + "iso-23247-6", + "digital-twin-consortium", + "ieee-1730.1", + "siso-sirl", + "w3c-prov", + "ro-crate", +} +REQUIRED_REQUIREMENTS = { + "SEM-230", + "SEM-234", + "SCE-002", + "API-407", + "API-423", + "RUN-310", + "RUN-319", + "ASR-535", + "ASR-537", +} +REQUIRED_REALIZATION_FORMS = { + "simulation", + "emulation-or-operational", + "hardware-or-native", + "federated-composition", +} +REQUIRED_ALLOCATION_UNITS = { + "participant-runtime", + "controlled-scope", + "action-family", + "observation-source", + "crossing-boundary", +} +REQUIRED_BOUNDARY_FIELDS = { + "source-component-ref", + "destination-component-ref", + "adapter-ref", + "authority-ref", + "action-or-observation-mapping-ref", + "participant-audience-policy-ref", + "release-or-declassification-basis-ref", + "time-mapping-ref", + "required-support-strength", + "mapping-loss", + "failure-behavior", + "evidence-refs", +} +REQUIRED_OPEN_CLOSED_AXES = { + "control-loop", + "world-assumption", + "federation-membership", +} +REQUIRED_DEMONSTRATION_CASES = { + "pure-simulation", + "pure-emulation-or-operational", + "simultaneous-mixed", + "inter-trial-transition", + "pre-admitted-phase-transition", + "open-loop", + "closed-loop", + "stale-handoff", + "concurrent-intervention", + "unsupported-or-false-capability", + "timestamp-only-or-unmapped-order", + "simulation-only-observation", + "unrealizable-action", + "directed-delivery-failure", + "prior-delivery-retraction", + "bridge-metadata-leakage", +} +REQUIRED_CHILDREN = { + "semantic-authority", + "portable-composition-contracts", + "trial-admission", + "runtime-coordination", + "backend-capability-and-conformance", + "demonstration-and-evaluation", + "documentation-and-claims", +} + + +def _load_program() -> dict[str, object]: + return json.loads(PROGRAM_PATH.read_text(encoding="utf-8")) + + +def test_program_delivers_primary_source_disposition_and_draft_authority() -> None: + program = _load_program() + + assert program["schema_version"] == "cross-backend-participant-control-program/v1" + assert program["parent_issue"] == 813 + assert program["participant_milestone"] == PARTICIPANT_MILESTONE + assert program["backend_coordination_milestone"] == BACKEND_MILESTONE + assert set(program["deliverables"]) >= REQUIRED_DELIVERABLES + assert all((REPO_ROOT / path).is_file() for path in REQUIRED_DELIVERABLES) + + sources = {entry["id"]: entry for entry in program["primary_sources"]} + assert set(sources) >= REQUIRED_SOURCES + for source in sources.values(): + assert source["primary_url"] + assert source["edition_or_version"] + assert source["adopted_lessons"] + assert source["rejected_inferences"] + assert source["raes_consequence"] + assert source["nonclaims"] + assert any(source["stronger_dimension"] for source in sources.values()) + assert sources["hla-1516-2025"]["stronger_dimension"] + assert sources["cyborg"]["empirical_result_boundary"] + assert sources["cygil"]["empirical_result_boundary"] + + requirements = {entry["uid"]: entry for entry in program["requirement_dispositions"]} + assert set(requirements) >= REQUIRED_REQUIREMENTS + for uid in ("SEM-234", "ASR-537"): + assert requirements[uid]["disposition"] == "new" + assert requirements[uid]["status"] == "DRAFT" + assert requirements[uid]["ground_control_id"] + assert requirements[uid]["scope"] + assert requirements[uid]["rationale"] + + +def test_composition_profile_supports_or_and_and_without_authority_conflation() -> None: + profile = _load_program()["composition_profile"] + + assert profile["profile_id"] == "mixed-cross-backend-participant-control-v1" + assert profile["revision"] == "rev1" + assert set(profile["composition_modes"]) == { + "alternative-realization", + "simultaneous-mixed-realization", + } + assert set(profile["realization_forms"]) >= REQUIRED_REALIZATION_FORMS + assert set(profile["allocation_units"]) == REQUIRED_ALLOCATION_UNITS + assert profile["portable_sdl_backend_neutral"] is True + assert profile["runtime_fallback_outside_allocation"] == "reject" + assert set(profile["boundary_required_fields"]) >= REQUIRED_BOUNDARY_FIELDS + + authority = profile["authority_model"] + assert authority["acting_controller_cardinality"] == "exactly-one-per-participant-episode-rev1" + assert authority["hla_ownership_is_controller_authority"] is False + assert authority["backend_responsibility_is_action_admission"] is False + assert authority["routing_is_disclosure_authority"] is False + assert authority["multi_controller_status"] == "not-supported-in-rev1" + assert authority["lease_status"] == "not-supported-in-rev1" + assert authority["joint_or_fused_control_status"] == "not-supported-in-rev1" + assert set(authority["distinct_relations"]) >= { + "participant-identity", + "acting-controller", + "authority-basis-and-scope", + "action-admission", + "backend-realization-responsibility", + "hla-object-or-attribute-ownership", + "delivery-addressing", + "participant-disclosure-authority", + } + + +def test_trial_time_and_open_closed_axes_are_independent_and_fail_closed() -> None: + program = _load_program() + trial = program["trial_realization_profile"] + + assert trial["inter_trial_change"] == "linked-new-plan-entry-and-run" + assert trial["within_run_change"] == "finite-pre-admitted-phase-schedule" + assert trial["all_phase_apparatus_pinned_before_execution"] is True + assert trial["late_unadmitted_join"] == "reject" + assert trial["history_and_participant_knowledge"] == "append-only" + assert trial["trial_identity_rewritten_by_phase_change"] is False + + axes = {entry["id"]: entry for entry in program["open_closed_axes"]} + assert set(axes) == REQUIRED_OPEN_CLOSED_AXES + assert axes["control-loop"]["values"] == ["open-loop", "closed-loop"] + assert set(axes["federation-membership"]["values"]) == {"fixed", "pre-admitted-dynamic"} + assert all(entry["authority_owner"] and entry["adoption"] for entry in axes.values()) + + time = program["time_and_order_profile"] + assert time["cross_clock_mapping_required"] is True + assert time["timestamp_only_strength"] == "disclosed-weak" + assert time["unmapped_clock_relation"] == "partial-or-unknown" + assert time["backend_serialized_requires_readback"] is True + assert time["rollback_or_retraction_erases_delivery"] is False + assert set(time["staleness_coordinates"]) >= { + "controller", + "authority", + "policy-revision", + "state-revision", + "history-head", + "governed-order", + } + + security = program["distribution_and_security_profile"] + assert security["publish_subscribe_authorizes_disclosure"] is False + assert security["ddm_establishes_ifc"] is False + assert security["directed_delivery_is_participant_observation"] is False + assert security["filtering_occurs_after_raes_authorization"] is True + assert set(security["metadata_leakage_surface"]) >= { + "membership", + "subscription", + "object-or-interaction-class", + "region-or-destination", + "message-size", + "timing", + "synchronization", + "ownership-change", + "retraction", + "delivery-failure", + } + + +def test_demonstration_protocol_covers_mixed_transfer_mismatch_and_zero_effects() -> None: + program = _load_program() + protocol = program["demonstration_protocol"] + cases = {entry["id"]: entry for entry in protocol["cases"]} + + assert protocol["same_authored_policy_digest_required"] is True + assert set(cases) == REQUIRED_DEMONSTRATION_CASES + for case in cases.values(): + assert case["composition"] + assert case["boundary"] + assert case["expected_disposition"] + assert set(case["required_evidence"]) >= { + "scenario-and-policy-digests", + "trial-and-run-identity", + "apparatus-and-adapter-identities", + "capability-and-conformance", + "allocation-and-topology", + "time-and-order", + "mapping-loss-and-limitations", + } + assert case["nonclaims"] + + zero_effect_cases = {case_id for case_id, case in cases.items() if case["denial_requires_zero_prohibited_effects"]} + assert zero_effect_cases >= { + "stale-handoff", + "unsupported-or-false-capability", + "unrealizable-action", + "directed-delivery-failure", + } + assert protocol["reporting_relations_are_distinct"] == [ + "bounded-conformance", + "interoperability-readiness", + "empirical-sim-to-em-transfer", + "trace-inclusion", + "bisimulation", + "ifc-or-noninterference", + "backend-equivalence", + ] + + +def test_child_program_is_bounded_requirement_backed_milestoned_and_acyclic() -> None: + program = _load_program() + issues = {entry["key"]: entry for entry in program["implementation_issues"]} + + assert set(issues) == REQUIRED_CHILDREN + issue_numbers: set[int] = set() + for key, entry in issues.items(): + assert isinstance(entry["issue_number"], int), key + assert entry["issue_number"] > 0, key + assert entry["issue_number"] not in issue_numbers + issue_numbers.add(entry["issue_number"]) + assert entry["requirements"] + assert set(entry["requirements"]) <= REQUIRED_REQUIREMENTS + assert {"SEM-234", "ASR-537"} & set(entry["requirements"]) + assert entry["milestone"] in {PARTICIPANT_MILESTONE, BACKEND_MILESTONE} + assert entry["bounded_outcome"] + assert entry["negative_cases"] + assert entry["evidence_required"] + assert entry["explicit_nonclaims"] + assert set(entry["dependencies"]) <= set(issues) + + assert issues["backend-capability-and-conformance"]["milestone"] == BACKEND_MILESTONE + assert all( + entry["milestone"] == PARTICIPANT_MILESTONE + for key, entry in issues.items() + if key != "backend-capability-and-conformance" + ) + + incoming = {key: len(entry["dependencies"]) for key, entry in issues.items()} + outgoing: dict[str, list[str]] = {key: [] for key in issues} + for key, entry in issues.items(): + for dependency in entry["dependencies"]: + outgoing[dependency].append(key) + queue = deque(key for key, degree in incoming.items() if degree == 0) + visited: list[str] = [] + while queue: + key = queue.popleft() + visited.append(key) + for child in outgoing[key]: + incoming[child] -= 1 + if incoming[child] == 0: + queue.append(child) + assert set(visited) == set(issues) + assert issues["documentation-and-claims"]["dependencies"] == [ + "runtime-coordination", + "backend-capability-and-conformance", + "demonstration-and-evaluation", + ] + + boundaries = program["claim_boundaries"] + assert boundaries["issue_813"] == "design-authority-and-implementation-program-only" + assert boundaries["mixed_runtime_implementation"] == "not-established" + assert boundaries["backend_realization"] == "not-established" + assert boundaries["cross_backend_equivalence"] == "not-established" + assert boundaries["ifc_or_noninterference"] == "not-established" + assert boundaries["universal_sim_to_em_transfer"] == "not-established" diff --git a/implementations/python/tests/test_issue_961_participant_opacity.py b/implementations/python/tests/test_issue_961_participant_opacity.py index 3429c3a8d..b445cde4e 100644 --- a/implementations/python/tests/test_issue_961_participant_opacity.py +++ b/implementations/python/tests/test_issue_961_participant_opacity.py @@ -12,11 +12,11 @@ from raes_contracts.behavioral_relation_profiles import ( ActiveOpacityStrategyModel, BehavioralRelationProfileModel, - load_behavioral_relation_profile, load_behavioral_relation_profile_from_path, + load_behavioral_relation_profile_revision, ) from raes_contracts.behavioral_relations import ( - load_behavioral_relation_catalog, + load_behavioral_relation_catalog_revision, validate_behavioral_claim_binding, ) from raes_contracts.contracts import BehavioralClaimBindingModel, schema_bundle @@ -40,6 +40,7 @@ REPO_ROOT = Path(__file__).resolve().parents[3] PROFILE_ID = "participant-opacity-baseline-v1" +PROFILE_REVISION = "sem-231/rev2" PROFILE_PATH = REPO_ROOT / "contracts/profiles/behavioral-relation" / f"{PROFILE_ID}.json" @@ -71,11 +72,11 @@ def _claim(**overrides: object) -> BehavioralClaimBindingModel: def _profile_payload() -> dict[str, object]: - return load_behavioral_relation_profile(PROFILE_ID).model_dump(mode="json") + return load_behavioral_relation_profile_revision(PROFILE_ID, PROFILE_REVISION).model_dump(mode="json") def test_published_profile_closes_every_sem_231_coordinate() -> None: - profile = load_behavioral_relation_profile(PROFILE_ID) + profile = load_behavioral_relation_profile_revision(PROFILE_ID, PROFILE_REVISION) assert profile.schema_version == "behavioral-relation-profile/v1" assert profile.profile_id == PROFILE_ID @@ -97,8 +98,8 @@ def test_published_profile_closes_every_sem_231_coordinate() -> None: def test_claim_resolution_joins_catalog_profile_carrier_and_projection() -> None: - catalog = load_behavioral_relation_catalog() - profile = load_behavioral_relation_profile(PROFILE_ID) + catalog = load_behavioral_relation_catalog_revision("rev8") + profile = load_behavioral_relation_profile_revision(PROFILE_ID, PROFILE_REVISION) assert validate_behavioral_claim_binding(_claim(), catalog, profile) == _claim() @@ -222,7 +223,7 @@ def _request( profile: BehavioralRelationProfileModel | None = None, complete_enumeration: bool = True, ) -> tuple[ParticipantOpacityAnalysisInputModel, BehavioralRelationProfileModel]: - profile = profile or load_behavioral_relation_profile(PROFILE_ID) + profile = profile or load_behavioral_relation_profile_revision(PROFILE_ID, PROFILE_REVISION) strategy_refs = {point.strategy_ref for point in points} run_refs = {point.run_ref for point in points} cut_refs = {point.cut_ref for point in points} diff --git a/implementations/python/tests/test_issue_962_participant_opacity_model_check.py b/implementations/python/tests/test_issue_962_participant_opacity_model_check.py index e7a71012a..9d1711030 100644 --- a/implementations/python/tests/test_issue_962_participant_opacity_model_check.py +++ b/implementations/python/tests/test_issue_962_participant_opacity_model_check.py @@ -11,11 +11,11 @@ from raes_conformance.conformance import _fixture_case_diagnostics from raes_contracts.behavioral_relation_profiles import ( BehavioralRelationProfileModel, - load_behavioral_relation_profile, + load_behavioral_relation_profile_revision, ) from raes_contracts.behavioral_relations import ( BehavioralRelationCatalogModel, - load_behavioral_relation_catalog, + load_behavioral_relation_catalog_revision, ) from raes_contracts.canonical import canonical_json_digest from raes_contracts.contracts.base import BehavioralClaimBindingModel @@ -46,6 +46,15 @@ REPO_ROOT = Path(__file__).resolve().parents[3] PROFILE_ID = "participant-opacity-baseline-v1" +PROFILE_REVISION = "sem-231/rev2" + + +def _historical_profile() -> BehavioralRelationProfileModel: + return load_behavioral_relation_profile_revision(PROFILE_ID, PROFILE_REVISION) + + +def _historical_catalog() -> BehavioralRelationCatalogModel: + return load_behavioral_relation_catalog_revision("rev8") def _claim( @@ -165,8 +174,8 @@ def _request( BehavioralRelationProfileModel, BehavioralRelationCatalogModel, ]: - profile = profile or load_behavioral_relation_profile(PROFILE_ID) - catalog = catalog or load_behavioral_relation_catalog() + profile = profile or _historical_profile() + catalog = catalog or _historical_catalog() counts = ParticipantOpacityModelCheckDeclaredCountsModel( states=len(states), transitions=len(transitions), @@ -500,7 +509,7 @@ def test_model_check_evidence_replay_rejects_model_drift() -> None: def test_active_model_checks_every_strategy_and_keeps_witnesses_same_strategy() -> None: - profile_payload = load_behavioral_relation_profile(PROFILE_ID).model_dump(mode="json") + profile_payload = _historical_profile().model_dump(mode="json") profile_payload["parameters"]["strategy"] = { "kind": "active", "strategy_refs": ["strategy:passive", "strategy:probe"], @@ -596,7 +605,7 @@ def test_observable_control_memory_and_policy_changes_split_model_cells( def test_coalition_model_uses_fused_observation_instead_of_individual_projection() -> None: - profile_payload = load_behavioral_relation_profile(PROFILE_ID).model_dump(mode="json") + profile_payload = _historical_profile().model_dump(mode="json") profile_payload["parameters"]["observer"] = { "kind": "coalition", "member_refs": ["participant:a", "participant:b"], @@ -634,7 +643,7 @@ def test_coalition_model_uses_fused_observation_instead_of_individual_projection def test_non_total_order_and_probability_promotions_fail_closed() -> None: - profile_payload = load_behavioral_relation_profile(PROFILE_ID).model_dump(mode="json") + profile_payload = _historical_profile().model_dump(mode="json") profile_payload["parameters"]["order"]["treatment"] = "partial-order" profile = BehavioralRelationProfileModel.model_validate(profile_payload) request, _, catalog = _request( @@ -701,7 +710,7 @@ def test_incomplete_and_vacuous_models_never_produce_positive_evidence() -> None def test_model_check_enforces_profile_bounds() -> None: - profile_payload = load_behavioral_relation_profile(PROFILE_ID).model_dump(mode="json") + profile_payload = _historical_profile().model_dump(mode="json") profile_payload["parameters"]["bounds"]["max_runs"] = 1 profile = BehavioralRelationProfileModel.model_validate(profile_payload) request, _, catalog = _request( @@ -795,9 +804,9 @@ def test_model_check_contracts_are_published_with_semantic_invariants() -> None: } -def test_catalog_and_profile_advance_only_the_model_check_assurance_axis() -> None: - catalog = load_behavioral_relation_catalog() - profile = load_behavioral_relation_profile(PROFILE_ID) +def test_historical_catalog_and_profile_preserve_the_model_check_assurance_axis() -> None: + catalog = _historical_catalog() + profile = _historical_profile() assurance = catalog.relations["participant-predicate-opacity"].assurance assert catalog.taxonomy_revision == "rev8" diff --git a/implementations/python/tests/test_issue_963_participant_opacity_proof.py b/implementations/python/tests/test_issue_963_participant_opacity_proof.py new file mode 100644 index 000000000..0d1cef55b --- /dev/null +++ b/implementations/python/tests/test_issue_963_participant_opacity_proof.py @@ -0,0 +1,204 @@ +"""SEM-231/ASR-535 mathematical participant-opacity proof assurance.""" + +from __future__ import annotations + +import hashlib +import io +import json +from copy import deepcopy +from pathlib import Path +from urllib.error import URLError + +import pytest +import tools.isabelle_tool as isabelle_tool +from jsonschema import Draft202012Validator +from pydantic import ValidationError +from raes_contracts.behavioral_relation_profiles import ( + AbstractOpacityCarrierModel, + BehavioralRelationProfileModel, + OpacityFiniteBoundsModel, + load_behavioral_relation_profile, + load_behavioral_relation_profile_revision, +) +from raes_contracts.behavioral_relations import ( + load_behavioral_relation_catalog, + load_behavioral_relation_catalog_revision, +) +from tools.check_participant_opacity_proof import ( + ProofEvidenceError, + load_proof_manifest, + validate_proof_manifest, +) +from tools.isabelle_tool import ( + ISABELLE_PROCESS_ADDRESS_SPACE_LIMIT_MIB, + _proof_process_limits, + _proof_sandbox_command, +) + +REPO_ROOT = Path(__file__).resolve().parents[3] +MANIFEST_PATH = REPO_ROOT / "specs/formal/participant-semantics/participant-opacity-proof-evidence.json" +PROFILE_SCHEMA_PATH = REPO_ROOT / "contracts/schemas/profiles/behavioral-relation-profile-v1.json" +FINITE_PROFILE_PATH = REPO_ROOT / "contracts/profiles/behavioral-relation/participant-opacity-baseline-v1.json" +THEOREM_PROFILE_PATH = REPO_ROOT / "contracts/profiles/behavioral-relation/participant-opacity-theorem-v1.json" +THEOREM_PROFILE_ID = "participant-opacity-theorem-v1" +THEOREM_PROFILE_REVISION = "sem-231-proof/rev1" + + +def test_theorem_profile_uses_the_shared_nonfinite_profile_variant() -> None: + profile = load_behavioral_relation_profile_revision( + THEOREM_PROFILE_ID, + THEOREM_PROFILE_REVISION, + ) + + assert profile.finite_analysis_scope == "abstract-parameterized-theorem-carrier" + assert isinstance(profile.parameters.carrier, AbstractOpacityCarrierModel) + assert profile.parameters.bounds is None + assert profile.parameters.carrier.eligibility_ref == "sem-231-eligible-predicate" + assert profile.parameters.carrier.correspondence_ref == "sem-230-sem-231-profile-correspondence" + + +def test_finite_profile_still_requires_bounds() -> None: + profile = load_behavioral_relation_profile("participant-opacity-baseline-v1") + + assert profile.finite_analysis_scope == "declared-complete-finite-carrier" + assert isinstance(profile.parameters.bounds, OpacityFiniteBoundsModel) + + +def test_carrier_variant_rejects_finite_bounds_and_scope_drift() -> None: + theorem_payload = load_behavioral_relation_profile(THEOREM_PROFILE_ID).model_dump(mode="json") + finite_bounds = load_behavioral_relation_profile("participant-opacity-baseline-v1").parameters.bounds + theorem_payload["parameters"]["bounds"] = finite_bounds.model_dump(mode="json") + + with pytest.raises(ValidationError, match="must not declare finite bounds"): + BehavioralRelationProfileModel.model_validate(theorem_payload) + + theorem_payload["parameters"]["bounds"] = None + theorem_payload["finite_analysis_scope"] = "declared-complete-finite-carrier" + with pytest.raises(ValidationError, match="scope must match"): + BehavioralRelationProfileModel.model_validate(theorem_payload) + + +def test_published_schema_rejects_every_carrier_bounds_and_scope_mismatch() -> None: + schema = json.loads(PROFILE_SCHEMA_PATH.read_text(encoding="utf-8")) + finite_profile = json.loads(FINITE_PROFILE_PATH.read_text(encoding="utf-8")) + theorem_profile = json.loads(THEOREM_PROFILE_PATH.read_text(encoding="utf-8")) + + finite_without_bounds = deepcopy(finite_profile) + finite_without_bounds["parameters"].pop("bounds") + abstract_with_bounds = deepcopy(theorem_profile) + abstract_with_bounds["parameters"]["bounds"] = finite_profile["parameters"]["bounds"] + finite_with_abstract_scope = deepcopy(finite_profile) + finite_with_abstract_scope["finite_analysis_scope"] = "abstract-parameterized-theorem-carrier" + abstract_with_finite_scope = deepcopy(theorem_profile) + abstract_with_finite_scope["finite_analysis_scope"] = "declared-complete-finite-carrier" + + validator = Draft202012Validator(schema) + invalid_profiles = { + "finite carrier without bounds": finite_without_bounds, + "abstract carrier with finite bounds": abstract_with_bounds, + "finite carrier with theorem scope": finite_with_abstract_scope, + "abstract carrier with finite scope": abstract_with_finite_scope, + } + for label, payload in invalid_profiles.items(): + assert not validator.is_valid(payload), label + + +def test_proof_sandbox_exposes_only_fixed_inputs_runtime_and_private_state() -> None: + command = _proof_sandbox_command( + bwrap=Path("/usr/bin/bwrap"), + home=Path("/cache/isabelle"), + session_root=Path("/repo/fixed-session"), + state_root=Path("/private/state"), + ) + ro_bindings = { + (command[index + 1], command[index + 2]) for index, value in enumerate(command) if value == "--ro-bind" + } + + assert ("/", "/") not in ro_bindings + assert ("/cache/isabelle", "/opt/isabelle") in ro_bindings + assert ("/repo/fixed-session", "/workspace/session") in ro_bindings + assert "/home" not in command + assert "--unshare-net" in command + assert "--unshare-pid" in command + assert command[-2:] == ["-D", "/workspace/session"] + + +def test_proof_process_limit_enforces_per_process_address_space(monkeypatch: pytest.MonkeyPatch) -> None: + calls: list[tuple[int, tuple[int, int]]] = [] + monkeypatch.setattr(isabelle_tool.resource, "setrlimit", lambda kind, limits: calls.append((kind, limits))) + + _proof_process_limits() + + address_space_bytes = ISABELLE_PROCESS_ADDRESS_SPACE_LIMIT_MIB * 1024 * 1024 + assert (isabelle_tool.resource.RLIMIT_AS, (address_space_bytes, address_space_bytes)) in calls + + +def test_isabelle_download_falls_back_between_integrity_checked_official_mirrors( + monkeypatch: pytest.MonkeyPatch, + tmp_path: Path, +) -> None: + payload = b"pinned-isabelle-archive" + attempted_urls: list[str] = [] + + class DownloadResponse(io.BytesIO): + def __enter__(self) -> DownloadResponse: + return self + + def __exit__(self, *_args: object) -> None: + self.close() + + def fake_urlopen(url: str, *, timeout: int) -> DownloadResponse: + attempted_urls.append(url) + assert timeout == 60 + if len(attempted_urls) == 1: + raise URLError("simulated primary mirror outage") + return DownloadResponse(payload) + + monkeypatch.setattr(isabelle_tool, "ISABELLE_ARCHIVE_URLS", ("https://primary.invalid", "https://fallback.invalid")) + monkeypatch.setattr(isabelle_tool, "ISABELLE_ARCHIVE_BYTES", len(payload)) + monkeypatch.setattr(isabelle_tool, "ISABELLE_ARCHIVE_SHA256", hashlib.sha256(payload).hexdigest()) + monkeypatch.setattr(isabelle_tool, "urlopen", fake_urlopen) + archive_path = tmp_path / "Isabelle.tar.gz" + + isabelle_tool._download_archive(archive_path) + + assert attempted_urls == ["https://primary.invalid", "https://fallback.invalid"] + assert archive_path.read_bytes() == payload + assert not archive_path.with_suffix(".gz.download").exists() + + +def test_current_and_historical_authority_resolve_by_exact_revision() -> None: + current_catalog = load_behavioral_relation_catalog() + historical_catalog = load_behavioral_relation_catalog_revision("rev8") + current_profile = load_behavioral_relation_profile("participant-opacity-baseline-v1") + historical_profile = load_behavioral_relation_profile_revision( + "participant-opacity-baseline-v1", + "sem-231/rev2", + ) + + assert current_catalog.taxonomy_revision == "rev9" + assert current_profile.profile_revision == "sem-231/rev3" + assert current_profile.taxonomy_revision == "rev9" + assert historical_catalog.taxonomy_revision == "rev8" + assert historical_profile.profile_revision == "sem-231/rev2" + assert historical_profile.taxonomy_revision == "rev8" + + +def test_proof_manifest_closes_claim_theorem_assumption_and_digest_joins() -> None: + manifest = load_proof_manifest(MANIFEST_PATH) + + validate_proof_manifest(manifest, repo_root=REPO_ROOT, run_prover=False) + + +def test_proof_manifest_rejects_axis_and_checked_theorem_drift() -> None: + manifest = load_proof_manifest(MANIFEST_PATH) + drifted = deepcopy(manifest) + drifted["positive_theorems"][0]["claim"]["assurance_axis"] = "model-check" + + with pytest.raises(ProofEvidenceError, match="proof claim"): + validate_proof_manifest(drifted, repo_root=REPO_ROOT, run_prover=False) + + missing = deepcopy(manifest) + missing["negative_theorems"].pop() + with pytest.raises(ProofEvidenceError, match="negative theorem"): + validate_proof_manifest(missing, repo_root=REPO_ROOT, run_prover=False) diff --git a/implementations/python/tests/test_json_ingress.py b/implementations/python/tests/test_json_ingress.py new file mode 100644 index 000000000..27dfdccd2 --- /dev/null +++ b/implementations/python/tests/test_json_ingress.py @@ -0,0 +1,25 @@ +"""Tests for bounded, ambiguity-rejecting portable JSON ingress.""" + +from __future__ import annotations + +import pytest +from raes_contracts.json_ingress import StrictJsonIngressError, parse_bounded_json + + +def test_parse_bounded_json_accepts_an_explicit_array_root() -> None: + assert parse_bounded_json(b'[{"event": 1}]', max_bytes=128, root="array") == [{"event": 1}] + + +@pytest.mark.parametrize( + ("source", "code"), + [ + (b'{"member": 1, "member": 2}', "duplicate-member"), + (b'{"member": NaN}', "non-finite-number"), + (b"{}", "invalid-root"), + ], +) +def test_parse_bounded_json_preserves_strict_ingress_failures(source: bytes, code: str) -> None: + with pytest.raises(StrictJsonIngressError) as caught: + parse_bounded_json(source, max_bytes=128, root="array") + + assert caught.value.code == code diff --git a/implementations/python/tests/test_libvirt_evidence_run.py b/implementations/python/tests/test_libvirt_evidence_run.py index b4b4d4d04..042135c7f 100644 --- a/implementations/python/tests/test_libvirt_evidence_run.py +++ b/implementations/python/tests/test_libvirt_evidence_run.py @@ -265,7 +265,7 @@ def test_non_claims_are_carried_verbatim(tmp_path): joined = " ".join(artifact["non_claims"]) assert "No Wazuh detection-quality claim" in joined assert "No byte-equivalence" in joined - assert "RAESystem/rae#600" in joined + assert "OpenRAE/rae#600" in joined # --- redaction gate ------------------------------------------------------------ diff --git a/implementations/python/tests/test_participant_backend_contracts.py b/implementations/python/tests/test_participant_backend_contracts.py index db8a66fcd..8ad633c02 100644 --- a/implementations/python/tests/test_participant_backend_contracts.py +++ b/implementations/python/tests/test_participant_backend_contracts.py @@ -79,7 +79,7 @@ def test_participant_backend_contracts_are_published_closed_world(): assert contract_id in generated schema = generated[contract_id] assert schema["$schema"] == "https://json-schema.org/draft/2020-12/schema" - assert schema["$id"] == f"https://raesystem.github.io/rae/schemas/{contract_id}.json" + assert schema["$id"] == f"https://openrae.github.io/rae/schemas/{contract_id}.json" assert schema["additionalProperties"] is False diff --git a/implementations/python/tests/test_pr_title_guard.py b/implementations/python/tests/test_pr_title_guard.py index 109c50f9b..240499aba 100644 --- a/implementations/python/tests/test_pr_title_guard.py +++ b/implementations/python/tests/test_pr_title_guard.py @@ -173,7 +173,7 @@ def test_retired_identity_in_title_is_rejected(title: str) -> None: [ "fix: rework surfaces and interfaces in namespaces", "refactor: replace traces with spans", - "feat: repoint schema namespace to raesystem.github.io", + "feat: repoint schema namespace to openrae.github.io", ], ) def test_words_containing_the_retired_token_are_not_matched(title: str) -> None: diff --git a/implementations/python/tests/test_public_docs_policy.py b/implementations/python/tests/test_public_docs_policy.py index aa2abfb28..fc0a53c6d 100644 --- a/implementations/python/tests/test_public_docs_policy.py +++ b/implementations/python/tests/test_public_docs_policy.py @@ -5,6 +5,7 @@ import json import os import re +import runpy import sys from pathlib import Path @@ -157,6 +158,14 @@ def test_checked_in_quickstart_scenario_parses() -> None: assert parsed.name == "first-scenario" +def test_public_docs_linkcheck_is_bounded_serialized_and_skips_own_repository() -> None: + config = runpy.run_path(str(REPO_ROOT / "docs" / "public" / "conf.py")) + + assert config["linkcheck_timeout"] == 15 + assert config["linkcheck_workers"] == 1 + assert config["linkcheck_ignore"] == [r"^https://github\.com/(?:RAESystem|OpenRAE)/rae(?:/|$)"] + + def test_readme_quickstart_matches_checked_in_scenario() -> None: readme = (REPO_ROOT / "README.md").read_text(encoding="utf-8") match = re.search( diff --git a/implementations/python/tests/test_public_project_readiness.py b/implementations/python/tests/test_public_project_readiness.py index 400177457..9fab6f27e 100644 --- a/implementations/python/tests/test_public_project_readiness.py +++ b/implementations/python/tests/test_public_project_readiness.py @@ -42,7 +42,7 @@ def test_scorecard_workflow_is_pinned_least_privilege_and_publishes_sarif() -> N def test_best_practices_proposal_is_factual_about_single_maintainer_limits() -> None: proposal = json.loads((REPO_ROOT / ".bestpractices.json").read_text(encoding="utf-8")) - assert proposal["repo_url"] == "https://github.com/RAESystem/rae" + assert proposal["repo_url"] == "https://github.com/OpenRAE/rae" assert proposal["license"] == "MIT" assert proposal["bus_factor_status"] == "Unmet" assert proposal["two_person_review_status"] == "Unmet" @@ -50,6 +50,25 @@ def test_best_practices_proposal_is_factual_about_single_maintainer_limits() -> assert "badge" not in proposal +def test_live_repository_identity_uses_openrae_owner() -> None: + ground_control = yaml.safe_load((REPO_ROOT / ".ground-control.yaml").read_text(encoding="utf-8")) + mcp = json.loads((REPO_ROOT / ".mcp.json").read_text(encoding="utf-8")) + previous_owner = "RAE" + "System" + + assert ground_control["github_repo"] == "OpenRAE/rae" + assert mcp["mcpServers"]["ground-control"]["env"]["GH_REPO"] == "OpenRAE/rae" + + for relative_path in ( + ".bestpractices.json", + ".github/ISSUE_TEMPLATE/config.yml", + "CONTRIBUTING.md", + "README.md", + ): + source = (REPO_ROOT / relative_path).read_text(encoding="utf-8") + assert f"github.com/{previous_owner}" not in source, relative_path + assert f"{previous_owner}/rae" not in source, relative_path + + def test_publishers_build_only_the_curated_public_source() -> None: rtd = yaml.safe_load((REPO_ROOT / ".readthedocs.yaml").read_text(encoding="utf-8")) assert rtd["sphinx"] == { diff --git a/implementations/python/tests/test_repo_policy_tools.py b/implementations/python/tests/test_repo_policy_tools.py index 423e86ec8..481f4ea60 100644 --- a/implementations/python/tests/test_repo_policy_tools.py +++ b/implementations/python/tests/test_repo_policy_tools.py @@ -6,6 +6,7 @@ import shutil import subprocess import sys +import threading import types from contextlib import nullcontext from pathlib import Path @@ -17,6 +18,7 @@ import pytest import tools.check_generated_schemas as check_generated_schemas +import tools.check_json_artifacts as check_json_artifacts import tools.osv_scanner_tool as osv_scanner_tool import tools.policy.conftest_tool as conftest_tool import yaml @@ -27,9 +29,10 @@ evaluate_adr_immutability, ) from tools.check_generated_schemas import _extra_published_schema_paths -from tools.check_json_artifacts import collect_validation_targets, should_run_full_validation +from tools.check_json_artifacts import ValidationTarget, collect_validation_targets, should_run_full_validation from tools.check_schema_publication import schema_content_hash, validate_schema_publication_manifest from tools.gitleaks_tool import _checksums_asset_name, _release_asset_name, gitleaks_binary_path +from tools.parallel_verification import VerificationLane, run_verification_lanes from tools.policy.common import PolicyFailure from tools.policy.conftest_tool import run_conftest_policy from tools.policy.repo_policy import evaluate_repo_policy @@ -137,18 +140,174 @@ def chdir(self, _path: Path): if command[:4] == ("uv", "run", "--frozen", "coverage") ] assert [command[4] for command, _options in coverage_commands] == ["xml", "report"] + assert coverage_commands[-1][0][-2:] == ("--fail-under=50", "--format=total") assert all(options["env"] == {"COVERAGE_FILE": str(coverage_file)} for _, options in coverage_commands) +def test_verification_lanes_run_concurrently_and_preserve_declared_order( + monkeypatch: pytest.MonkeyPatch, + tmp_path: Path, +) -> None: + barrier = threading.Barrier(2, timeout=2) + commands: list[tuple[str, ...]] = [] + commands_lock = threading.Lock() + + def fake_run(command: list[str], **_kwargs: Any) -> subprocess.CompletedProcess[str]: + with commands_lock: + commands.append(tuple(command)) + barrier.wait() + return subprocess.CompletedProcess(command, 0, stdout=f"{command[-1]} passed\n") + + monkeypatch.setattr(subprocess, "run", fake_run) + lanes = ( + VerificationLane(name="static", nox_session="verify-static-lane"), + VerificationLane(name="contracts", nox_session="contracts", posargs=("--base-rev", "base")), + ) + + results = run_verification_lanes( + lanes, + nox_python=Path("/tools/python"), + noxfile=tmp_path / "noxfile.py", + repo_root=tmp_path, + base_env={"RAES_VERIFY_PROJECT_SYNCED": "1"}, + ) + + assert [result.name for result in results] == ["static", "contracts"] + assert all(result.returncode == 0 for result in results) + assert sorted(commands) == sorted( + [ + ( + "/tools/python", + "-m", + "nox", + "-f", + str(tmp_path / "noxfile.py"), + "-s", + "verify-static-lane", + ), + ( + "/tools/python", + "-m", + "nox", + "-f", + str(tmp_path / "noxfile.py"), + "-s", + "contracts", + "--", + "--base-rev", + "base", + ), + ] + ) + + +def test_parallel_verification_reports_every_failed_lane( + monkeypatch: pytest.MonkeyPatch, + tmp_path: Path, +) -> None: + def fake_run(command: list[str], **_kwargs: Any) -> subprocess.CompletedProcess[str]: + session_name = command[command.index("-s") + 1] + return subprocess.CompletedProcess(command, 3 if session_name != "contracts" else 4, stdout=session_name) + + monkeypatch.setattr(subprocess, "run", fake_run) + results = run_verification_lanes( + ( + VerificationLane(name="static", nox_session="verify-static-lane"), + VerificationLane(name="contracts", nox_session="contracts"), + ), + nox_python=Path("/tools/python"), + noxfile=tmp_path / "noxfile.py", + repo_root=tmp_path, + ) + + assert [(result.name, result.returncode) for result in results] == [("static", 3), ("contracts", 4)] + + def test_canonical_verify_does_not_use_change_aware_selection(monkeypatch: pytest.MonkeyPatch) -> None: noxfile = load_noxfile_with_fake_nox(monkeypatch) source = inspect.getsource(noxfile.verify) assert "_run_changed_verification" not in source - assert "_run_contracts" in source - assert "_run_tests" in source - assert "_run_integration_tests" in source - assert "_run_docs" in source + assert "_run_parallel_verification" in source + + lanes = noxfile._verification_lanes( + posargs=["--base-rev", "base"], + coverage_dir=Path("/coverage"), + include_policy=True, + ) + assert [(lane.name, lane.nox_session) for lane in lanes] == [ + ("unit-tests", "verify-tests-lane"), + ("integration-tests", "verify-integration-lane"), + ("contracts", "contracts"), + ("static", "verify-static-lane"), + ("participant-opacity-proof", "participant-opacity-proof"), + ("docs-local", "docs-local"), + ] + lanes_by_name = {lane.name: lane for lane in lanes} + assert lanes_by_name["static"].posargs == ("--include-policy", "--base-rev", "base") + assert lanes_by_name["contracts"].posargs == ("--base-rev", "base") + assert lanes_by_name["unit-tests"].env["RAES_VERIFY_COVERAGE_FILE"] == "/coverage/.coverage.unit" + assert lanes_by_name["integration-tests"].env["RAES_VERIFY_COVERAGE_FILE"] == "/coverage/.coverage.integration" + + +def test_completion_verification_omits_policy_only_from_static_lane( + monkeypatch: pytest.MonkeyPatch, +) -> None: + noxfile = load_noxfile_with_fake_nox(monkeypatch) + + lanes = noxfile._verification_lanes( + posargs=["--requirement-uid", "ASR-535"], + coverage_dir=Path("/coverage"), + include_policy=False, + cpu_count=4, + ) + + lanes_by_name = {lane.name: lane for lane in lanes} + assert lanes_by_name["static"].posargs == ("--requirement-uid", "ASR-535") + assert [lane.name for lane in lanes] == [ + "unit-tests", + "integration-tests", + "contracts", + "static", + "participant-opacity-proof", + "docs-local", + ] + assert lanes_by_name["contracts"].env["RAES_JSON_SCHEMA_WORKERS"] == "1" + assert lanes_by_name["unit-tests"].env["PYTEST_XDIST_AUTO_NUM_WORKERS"] == "2" + assert noxfile._verification_lane_workers(cpu_count=4, lane_count=len(lanes)) == 2 + assert noxfile._verification_lane_workers(cpu_count=16, lane_count=len(lanes)) == 4 + + +def test_parallel_coverage_is_combined_before_reporting( + monkeypatch: pytest.MonkeyPatch, + tmp_path: Path, +) -> None: + noxfile = load_noxfile_with_fake_nox(monkeypatch) + + class FakeSession: + def __init__(self) -> None: + self.commands: list[tuple[tuple[str, ...], dict[str, Any]]] = [] + + def run(self, *args: str, **kwargs: Any) -> None: + self.commands.append((args, kwargs)) + + def chdir(self, _path: Path): + return nullcontext() + + session = FakeSession() + noxfile._finalize_parallel_coverage(session, tmp_path) + + coverage_commands = [ + (command, options) + for command, options in session.commands + if command[:4] == ("uv", "run", "--frozen", "coverage") + ] + assert [command[4] for command, _options in coverage_commands] == ["combine", "xml", "report"] + assert coverage_commands[0][0][5:] == ("--keep", str(tmp_path)) + assert coverage_commands[-1][0][-2:] == ("--fail-under=50", "--format=total") + assert all( + options["env"] == {"COVERAGE_FILE": str(tmp_path / ".coverage")} for _command, options in coverage_commands + ) def test_docs_graph_uses_curated_root_and_reader_style_gate( @@ -204,6 +363,37 @@ def run(self, *args: str, **_kwargs: Any) -> None: ) +def test_local_docs_graph_excludes_external_link_check( + monkeypatch: pytest.MonkeyPatch, + tmp_path: Path, +) -> None: + noxfile = load_noxfile_with_fake_nox(monkeypatch) + commands: list[tuple[str, ...]] = [] + + class FakeSession: + def log(self, _message: str) -> None: + pass + + def run(self, *args: str, **_kwargs: Any) -> None: + commands.append(args) + + fake_vale = tmp_path / "vale" + fake_vale.write_text("", encoding="utf-8") + monkeypatch.setattr(noxfile, "ensure_vale", lambda _repo_root: fake_vale) + monkeypatch.setattr(noxfile, "REPO_ROOT", tmp_path) + monkeypatch.setattr(noxfile, "PROJECT_ROOT", tmp_path / "implementations" / "python") + monkeypatch.setattr(noxfile, "PUBLIC_DOCS_ROOT", tmp_path / "docs" / "public") + monkeypatch.setattr(noxfile, "DOCS_BUILD_ROOT", tmp_path / "docs" / "_build") + reporter = noxfile.SessionReporter(FakeSession(), "docs-local") + + noxfile._run_docs(reporter.session, reporter, include_external_links=False) + + assert "docs / Sphinx link check" not in [result.name for result in reporter.results] + sphinx_commands = [command for command in commands if "sphinx-build" in command] + assert len(sphinx_commands) == 1 + assert "html" in sphinx_commands[0] + + def write_text(path: Path, content: str) -> None: path.parent.mkdir(parents=True, exist_ok=True) path.write_text(content, encoding="utf-8") @@ -558,6 +748,17 @@ def test_module_boundaries_allow_runtime_using_processor_public_api(tmp_path: Pa assert failures == [] +def test_module_boundaries_allow_cli_using_processor_compiler_public_api(tmp_path: Path) -> None: + repo_root = setup_policy_repo(tmp_path) + install_module_boundary_policy(repo_root) + rel = "implementations/python/packages/raes_cli/semantic.py" + write_text(repo_root / rel, "from raes_processor.compiler import compile_scenario_runtime_model\n") + + failures = evaluate_repo_policy(repo_root, [rel], check_set="file-local", structural_runner=structural_runner_stub) + + assert failures == [] + + def test_module_boundaries_reject_runtime_using_non_public_processor_module(tmp_path: Path) -> None: repo_root = setup_policy_repo(tmp_path) install_module_boundary_policy(repo_root) @@ -1973,6 +2174,48 @@ def test_collect_validation_targets_runs_full_scan_when_schema_drivers_change(tm assert any(target.path == "contracts/concept-authority/concept-families-v1.json" for target in targets) +def test_json_validation_batches_by_schema_and_runs_batches_concurrently( + monkeypatch: pytest.MonkeyPatch, +) -> None: + monkeypatch.delenv("RAES_JSON_SCHEMA_WORKERS", raising=False) + barrier = threading.Barrier(3, timeout=2) + calls: list[tuple[str, ...]] = [] + calls_lock = threading.Lock() + + def fake_run(*args: str) -> subprocess.CompletedProcess[str]: + with calls_lock: + calls.append(args) + barrier.wait() + return subprocess.CompletedProcess(args, 0, stdout="", stderr="") + + monkeypatch.setattr(check_json_artifacts, "_run_check_jsonschema", fake_run) + targets = [ + ValidationTarget("contracts/schemas/one.json", None, "metaschema"), + ValidationTarget("contracts/schemas/two.json", None, "metaschema"), + ValidationTarget("contracts/fixtures/one-a.json", "contracts/schemas/one.json", "schema"), + ValidationTarget("contracts/fixtures/one-b.json", "contracts/schemas/one.json", "schema"), + ValidationTarget("contracts/fixtures/two.json", "contracts/schemas/two.json", "schema"), + ] + + assert check_json_artifacts.validate_targets(targets) == [] + assert sorted(calls) == sorted( + [ + ("--check-metaschema", "contracts/schemas/one.json", "contracts/schemas/two.json"), + ( + "--schemafile", + "contracts/schemas/one.json", + "contracts/fixtures/one-a.json", + "contracts/fixtures/one-b.json", + ), + ( + "--schemafile", + "contracts/schemas/two.json", + "contracts/fixtures/two.json", + ), + ] + ) + + def test_gitleaks_release_asset_names_match_platform_conventions(monkeypatch) -> None: monkeypatch.setattr("platform.system", lambda: "Linux") monkeypatch.setattr("platform.machine", lambda: "x86_64") diff --git a/implementations/python/tests/test_runtime_contracts.py b/implementations/python/tests/test_runtime_contracts.py index dd576598e..357eab317 100644 --- a/implementations/python/tests/test_runtime_contracts.py +++ b/implementations/python/tests/test_runtime_contracts.py @@ -127,7 +127,7 @@ def test_closed_world_contract_models_for_runtime_envelopes(): for contract_id, schema in generated.items(): assert schema["$schema"] == "https://json-schema.org/draft/2020-12/schema" - assert schema["$id"].startswith("https://raesystem.github.io/rae/schemas/") + assert schema["$id"].startswith("https://openrae.github.io/rae/schemas/") validate_raes_semantic_invariant_annotations(contract_id, schema) assert generated["raes-semantic-invariants-v1"]["additionalProperties"] is False @@ -176,8 +176,7 @@ def test_experiment_core_schemas_publish_closed_world_contracts(): study_schema = generated["experiment-study-v1"] assert ( - task_schema["x-raes-semantic-profile"]["uri"] - == "https://raesystem.github.io/rae/schemas/semantic-invariants/v1" + task_schema["x-raes-semantic-profile"]["uri"] == "https://openrae.github.io/rae/schemas/semantic-invariants/v1" ) assert "apparatus-archival-times-rfc3339-valid" in _invariant_ids(apparatus_context_schema) assert run_schema["x-raes-semantic-profile"]["required"] is True diff --git a/implementations/python/tests/test_runtime_control_plane.py b/implementations/python/tests/test_runtime_control_plane.py index bb4b29c05..1cac8dca8 100644 --- a/implementations/python/tests/test_runtime_control_plane.py +++ b/implementations/python/tests/test_runtime_control_plane.py @@ -347,14 +347,42 @@ def apply(self, provisioning_plan: ProvisioningPlan, snapshot: RuntimeSnapshot): return self._delegate.apply(provisioning_plan, snapshot) -def _stateful_plan(resource_type: str = "generated-artifact") -> ProvisioningPlan: +def _generated_artifact_spec(generator: str = "rendered_config") -> dict[str, Any]: + consumer: dict[str, Any] = { + "node": "vm", + "mount_destination": "/etc/config.yml", + "access_mode": "read_only", + } + if generator == "ssh_key_bundle": + consumer["selected_outputs"] = ["config"] + return { + "generator": generator, + "lifecycle": "regenerate_on_change", + "provenance": "config.yml", + "outputs": [ + { + "name": "config", + "path": "config.yml", + "sensitivity": "restricted", + "disposition": "consumer_selected", + } + ], + "consumers": [consumer], + } + + +def _stateful_plan( + resource_type: str = "generated-artifact", + *, + spec: dict[str, Any] | None = None, +) -> ProvisioningPlan: return ProvisioningPlan( operations=[ ProvisionOp( action=ChangeAction.CREATE, address=f"provision.{resource_type}.config", resource_type=resource_type, - payload={"spec": {"provenance": "config.yml"}}, + payload={"spec": spec if spec is not None else _generated_artifact_spec()}, ) ] ) @@ -397,11 +425,14 @@ def test_control_plane_rejects_stateful_kind_before_backend_calls( expected_code: str, ) -> None: manifest = create_stub_manifest() + capability_changes: dict[str, Any] = {capability_attribute: False} + if capability_attribute == "supports_generated_artifacts": + capability_changes["supported_generated_artifact_kinds"] = frozenset() unsupported = replace( manifest, capabilities=replace( manifest.capabilities, - provisioner=replace(manifest.provisioner, **{capability_attribute: False}), + provisioner=replace(manifest.provisioner, **capability_changes), ), ) target, provisioner = _target_with_manifest(unsupported) @@ -430,6 +461,69 @@ def test_control_plane_rejects_stateful_plan_without_exact_realization_support() assert provisioner.apply_calls == 0 +def test_control_plane_rejects_malformed_generated_artifact_before_backend_calls() -> None: + target, provisioner = _target_with_manifest(create_stub_manifest()) + + receipt = RuntimeControlPlane(target).submit_provisioning(_stateful_plan(spec={"provenance": "config.yml"})) + + assert receipt.accepted is False + assert [diagnostic.code for diagnostic in receipt.diagnostics] == ["provisioner.generated-artifact-invalid"] + assert provisioner.validate_calls == 0 + assert provisioner.apply_calls == 0 + + +def test_control_plane_rejects_explicitly_empty_generated_artifact_selection() -> None: + target, provisioner = _target_with_manifest(create_stub_manifest()) + spec = _generated_artifact_spec() + spec["consumers"][0]["selected_outputs"] = [] + + receipt = RuntimeControlPlane(target).submit_provisioning(_stateful_plan(spec=spec)) + + assert receipt.accepted is False + assert [diagnostic.code for diagnostic in receipt.diagnostics] == ["provisioner.generated-artifact-invalid"] + assert provisioner.validate_calls == 0 + assert provisioner.apply_calls == 0 + + +def test_control_plane_rejects_mismatched_generated_artifact_consumer_target() -> None: + target, provisioner = _target_with_manifest(create_stub_manifest()) + spec = _generated_artifact_spec() + spec["consumers"][0]["target_address"] = "provision.node.somewhere-else" + + receipt = RuntimeControlPlane(target).submit_provisioning(_stateful_plan(spec=spec)) + + assert receipt.accepted is False + assert [diagnostic.code for diagnostic in receipt.diagnostics] == ["provisioner.generated-artifact-invalid"] + assert provisioner.validate_calls == 0 + assert provisioner.apply_calls == 0 + + +def test_control_plane_rejects_unclaimed_generated_artifact_kind_before_backend_calls() -> None: + manifest = create_stub_manifest() + unsupported = replace( + manifest, + capabilities=replace( + manifest.capabilities, + provisioner=replace( + manifest.provisioner, + supported_generated_artifact_kinds=frozenset({"certificate_bundle", "rendered_config"}), + ), + ), + ) + target, provisioner = _target_with_manifest(unsupported) + + receipt = RuntimeControlPlane(target).submit_provisioning( + _stateful_plan(spec=_generated_artifact_spec("ssh_key_bundle")) + ) + + assert receipt.accepted is False + assert [diagnostic.code for diagnostic in receipt.diagnostics] == [ + "provisioner.unsupported-generated-artifact-kind" + ] + assert provisioner.validate_calls == 0 + assert provisioner.apply_calls == 0 + + def test_control_plane_rejects_exact_support_from_another_domain() -> None: manifest = create_stub_manifest() support = replace(manifest.realization_support[0], domain="orchestration") diff --git a/implementations/python/tests/test_sdl_models.py b/implementations/python/tests/test_sdl_models.py index 211f2c0c8..07933584a 100644 --- a/implementations/python/tests/test_sdl_models.py +++ b/implementations/python/tests/test_sdl_models.py @@ -2337,10 +2337,24 @@ def test_valid_entity_objective(self): # --------------------------------------------------------------------------- from raes.accounts import Account, PasswordStrength -from raes.content import Content, ContentItem, ContentType +from raes.content import Content, ContentItem, ContentType, ServiceSearchIndexSchemaMaterialization from raes.nodes import AssetValue, AssetValueLevel, OSFamily, ServicePort +def _search_index_schema_materialization() -> dict[str, object]: + return { + "interface_profile": "service-search-index-schema", + "profile_version": "1", + "target_service_ref": "search", + "readback_assertion_refs": ["schema-ready"], + "evidence_requirement_refs": ["schema-readback"], + "observation_boundary_refs": ["participant-view"], + "requirements": { + "field_semantics": {"key": "exact-token"}, + }, + } + + class TestContent: def test_file_content(self): c = Content(type="file", target="victim", path="/tmp/flag.txt", text="FLAG{x}") @@ -2392,6 +2406,67 @@ def test_directory_requires_destination(self): ): Content(type="directory", target="victim") + @pytest.mark.parametrize( + ("content", "message"), + [ + ( + { + "type": "file", + "target": "victim", + "path": "/tmp/flag.txt", + "service_materialization": _search_index_schema_materialization(), + }, + "Search-index schema materialization requires dataset content", + ), + ( + { + "type": "dataset", + "target": "victim", + "source": {"name": "schema"}, + "service_materialization": _search_index_schema_materialization(), + }, + "Search-index schema materialization must not carry source or items", + ), + ( + { + "type": "dataset", + "target": "victim", + "items": [{"name": "schema"}], + "service_materialization": _search_index_schema_materialization(), + }, + "Search-index schema materialization must not carry source or items", + ), + ( + { + "type": "file", + "path": "/tmp/flag.txt", + "service_materialization": _search_index_schema_materialization(), + }, + "Content requires 'target'", + ), + ], + ) + def test_search_index_schema_content_shape_rules( + self, + content: dict[str, object], + message: str, + ) -> None: + with pytest.raises(ValidationError, match=message): + Content.model_validate(content) + + def test_search_index_schema_dataset_does_not_require_payload(self) -> None: + content = Content.model_validate( + { + "type": "dataset", + "target": "victim", + "service_materialization": _search_index_schema_materialization(), + } + ) + + assert isinstance(content.service_materialization, ServiceSearchIndexSchemaMaterialization) + assert content.source is None + assert content.items == [] + class TestAccount: def test_basic_account(self): diff --git a/implementations/python/tests/test_sem_230_information_flow_control.py b/implementations/python/tests/test_sem_230_information_flow_control.py index 35fbc5a87..7886bd8cb 100644 --- a/implementations/python/tests/test_sem_230_information_flow_control.py +++ b/implementations/python/tests/test_sem_230_information_flow_control.py @@ -60,7 +60,7 @@ def _crossing(**overrides: object) -> Crossing: def test_catalog_publishes_revisioned_policy_noninterference_claim_surface(): catalog = load_behavioral_relation_catalog() - assert catalog.taxonomy_revision == "rev8" + assert catalog.taxonomy_revision == "rev9" relation = catalog.relations["policy-noninterference"] assert relation.projection_required is True assert relation.quantification.states diff --git a/implementations/python/tests/test_sem_231_participant_predicate_opacity.py b/implementations/python/tests/test_sem_231_participant_predicate_opacity.py index 7baf483c9..dcee4b431 100644 --- a/implementations/python/tests/test_sem_231_participant_predicate_opacity.py +++ b/implementations/python/tests/test_sem_231_participant_predicate_opacity.py @@ -16,14 +16,14 @@ def _opacity_binding(**overrides: object) -> BehavioralClaimBindingModel: payload: dict[str, object] = { "taxonomy_id": "raes-behavioral-relations", - "taxonomy_revision": "rev8", + "taxonomy_revision": "rev9", "relation_id": "participant-predicate-opacity", "subject": "Participant p at the declared exact cut", "left_carrier_ref": "possible-point-carrier:participant-opacity-fixture-v1", "observation_projection_ref": "participant-opacity-observation:complete-v1", "observation_projection_revision": "rev1", "relation_parameter_profile_ref": "participant-opacity-baseline-v1", - "relation_parameter_profile_revision": "sem-231/rev2", + "relation_parameter_profile_revision": "sem-231/rev3", "quantifier_scope": "finite-cases", "evidence_scope": "finite", "assurance_axis": "bounded-test", @@ -41,7 +41,7 @@ def test_catalog_defines_one_sided_participant_predicate_opacity() -> None: catalog = load_behavioral_relation_catalog() relation = catalog.relations["participant-predicate-opacity"] - assert catalog.taxonomy_revision == "rev8" + assert catalog.taxonomy_revision == "rev9" assert relation.relation_class == "epistemic" assert relation.direction == "unary" assert relation.relation_parameter_profile_required is True @@ -54,19 +54,22 @@ def test_catalog_defines_one_sided_participant_predicate_opacity() -> None: assert relation.assurance.checker_status == "implemented" assert relation.assurance.test_status == "bounded" assert relation.assurance.model_check_status == "model-checked" - assert relation.assurance.proof_status == "deliberately-unproved" + assert relation.assurance.proof_status == "proved" assert relation.assurance.runtime_enforcement_status == "not-enforced" assert relation.assurance.backend_declaration_status == "not-declared" assert relation.assurance.backend_realization_status == "not-realized" assert relation.assurance.backend_conformance_status == "not-tested" assert { - "contracts/profiles/behavioral-relation/participant-opacity-baseline-v1.json", + "contracts/profiles/behavioral-relation/history/participant-opacity-baseline-v1-sem-231-rev2.json", + "contracts/profiles/behavioral-relation/participant-opacity-theorem-v1.json", "contracts/schemas/formal-analysis/participant-opacity-model-check-input-v1.json", "contracts/schemas/formal-analysis/participant-opacity-model-check-evidence-v1.json", "implementations/python/packages/raes_processor/participant_opacity/_service.py", "implementations/python/packages/raes_processor/participant_opacity/_model_check.py", "implementations/python/tests/test_issue_961_participant_opacity.py", "implementations/python/tests/test_issue_962_participant_opacity_model_check.py", + "implementations/python/tests/test_issue_963_participant_opacity_proof.py", + "specs/formal/participant-semantics/participant-opacity-proof-evidence.json", } <= set(relation.assurance.evidence_refs) diff --git a/implementations/python/tests/test_semantic_cli.py b/implementations/python/tests/test_semantic_cli.py new file mode 100644 index 000000000..2b5f36fdc --- /dev/null +++ b/implementations/python/tests/test_semantic_cli.py @@ -0,0 +1,405 @@ +"""Behavioral contract for the human-facing RAES semantic CLI.""" + +from __future__ import annotations + +import json +from pathlib import Path + +import pytest +from paths import REPO_ROOT +from raes_cli.main import app +from typer.testing import CliRunner + +_SDL = """\ +name: semantic-cli +nodes: + network: + type: switch +""" + + +def _write_sdl(tmp_path: Path) -> Path: + source = tmp_path / "scenario.sdl.yaml" + source.write_text(_SDL, encoding="utf-8") + return source + + +@pytest.mark.parametrize( + "operation", + ["parse", "validate", "normalize", "resolve", "compile", "transform", "inspect", "conformance"], +) +def test_semantic_surface_exposes_required_operations(operation: str) -> None: + result = CliRunner().invoke(app, ["semantic", operation, "--help"]) + + assert result.exit_code == 0, result.output + + +@pytest.mark.parametrize( + ("operation", "extra", "exit_code", "status", "phase"), + [ + ("parse", [], 0, "success", "parsed-authoring"), + ("validate", [], 0, "success", "validated-authoring"), + ("normalize", [], 0, "success", "normalized-authoring"), + ("resolve", [], 0, "success", "resolved-references"), + ("compile", [], 0, "success", "compiled-runtime-summary"), + ("transform", ["--transform", "canonical"], 0, "success", "transformed"), + ("inspect", [], 0, "success", "inspection"), + ("conformance", [], 3, "unsupported", None), + ], +) +def test_sdl_operations_emit_one_deterministic_typed_json_result( + tmp_path: Path, + operation: str, + extra: list[str], + exit_code: int, + status: str, + phase: str | None, +) -> None: + source = _write_sdl(tmp_path) + argv = [ + "semantic", + operation, + str(source), + "--contract", + "sdl-yaml/v1", + "--output", + "json", + *extra, + ] + + first = CliRunner().invoke(app, argv) + second = CliRunner().invoke(app, argv) + + assert first.exit_code == exit_code, first.output + assert first.stdout == second.stdout + assert first.stderr == "" + assert first.stdout.endswith("\n") + payload = json.loads(first.stdout) + assert payload["operation"] == operation + assert payload["status"] == status + assert payload["contract_id"] == "sdl-yaml/v1" + assert payload["source_format"] == "sdl-yaml/v1" + assert payload["migration_policy"] == "reject" + assert payload["diagnostics"] == [] + if phase is not None: + assert payload["payload"]["phase"] == phase + + +def test_sdl_resolve_and_inspect_have_distinct_phase_results(tmp_path: Path) -> None: + source = _write_sdl(tmp_path) + runner = CliRunner() + common = [str(source), "--contract", "sdl-yaml/v1", "--output", "json"] + + resolve_payload = json.loads(runner.invoke(app, ["semantic", "resolve", *common]).stdout)["payload"] + inspect_payload = json.loads(runner.invoke(app, ["semantic", "inspect", *common]).stdout)["payload"] + + assert resolve_payload["phase"] == "resolved-references" + assert resolve_payload["reference_bindings"] + assert "declarations" not in resolve_payload + assert inspect_payload["phase"] == "inspection" + assert inspect_payload["declarations"] + assert "reference_bindings" not in inspect_payload + + +def test_file_and_stdin_share_the_same_semantic_result(tmp_path: Path) -> None: + source = _write_sdl(tmp_path) + runner = CliRunner() + common = [ + "--contract", + "sdl-yaml/v1", + "--output", + "json", + ] + + file_result = runner.invoke(app, ["semantic", "validate", str(source), *common]) + stdin_result = runner.invoke(app, ["semantic", "validate", "-", *common], input=_SDL) + + assert file_result.exit_code == stdin_result.exit_code == 0 + file_payload = json.loads(file_result.stdout) + stdin_payload = json.loads(stdin_result.stdout) + assert file_payload == stdin_payload + + +def test_portable_contract_conformance_reuses_the_owning_registry() -> None: + source = REPO_ROOT / "contracts" / "fixtures" / "control-plane" / "operation-status-v1" / "valid" / "succeeded.json" + + result = CliRunner().invoke( + app, + [ + "semantic", + "conformance", + str(source), + "--contract", + "operation-status-v1", + "--output", + "json", + ], + ) + + assert result.exit_code == 0, result.output + payload = json.loads(result.stdout) + assert payload["status"] == "success" + assert payload["contract_id"] == "operation-status-v1" + assert payload["validation_strength"] == "semantic" + assert payload["payload"]["phase"] == "contract-conformance" + assert payload["payload"]["passed"] is True + + +def test_portable_operations_keep_distinct_phase_contracts() -> None: + source = REPO_ROOT / "contracts" / "fixtures" / "control-plane" / "operation-status-v1" / "valid" / "succeeded.json" + runner = CliRunner() + common = [str(source), "--contract", "operation-status-v1", "--output", "json"] + + parse_result = runner.invoke(app, ["semantic", "parse", *common]) + validate_result = runner.invoke(app, ["semantic", "validate", *common]) + inspect_result = runner.invoke(app, ["semantic", "inspect", *common]) + + assert parse_result.exit_code == 3 + assert json.loads(parse_result.stdout)["status"] == "unsupported" + assert json.loads(validate_result.stdout)["payload"]["phase"] == "contract-admission" + assert json.loads(validate_result.stdout)["payload"]["admitted"] is True + inspection = json.loads(inspect_result.stdout)["payload"] + assert inspection["phase"] == "inspection" + assert inspection["members"] + assert "admitted" not in inspection + + +@pytest.mark.parametrize( + ("operation", "phase", "outcome_field"), + [ + ("validate", "contract-admission", "admitted"), + ("inspect", "inspection", None), + ("conformance", "contract-conformance", "passed"), + ], +) +def test_portable_operations_reject_invalid_registered_contract_payload( + operation: str, + phase: str, + outcome_field: str | None, +) -> None: + source = ( + REPO_ROOT + / "contracts" + / "fixtures" + / "control-plane" + / "operation-status-v1" + / "invalid" + / "unknown-extra.json" + ) + + result = CliRunner().invoke( + app, + [ + "semantic", + operation, + str(source), + "--contract", + "operation-status-v1", + "--output", + "json", + ], + ) + + assert result.exit_code == 1, result.output + payload = json.loads(result.stdout) + assert payload["status"] == "invalid" + assert payload["diagnostics"] + assert payload["payload"]["phase"] == phase + if outcome_field is not None: + assert payload["payload"][outcome_field] is False + + +def test_portable_event_stream_accepts_array_root_from_stdin() -> None: + source = ( + REPO_ROOT + / "contracts" + / "fixtures" + / "control-plane" + / "workflow-history-event-stream-v1" + / "valid" + / "started.json" + ) + + result = CliRunner().invoke( + app, + [ + "semantic", + "validate", + "-", + "--contract", + "workflow-history-event-stream-v1", + "--output", + "json", + ], + input=source.read_text(encoding="utf-8"), + ) + + assert result.exit_code == 0, result.output + assert json.loads(result.stdout)["payload"]["root_type"] == "array" + + +def test_invalid_input_is_value_free_and_uses_exit_one(tmp_path: Path) -> None: + marker = "SECRET-MARKER" + source = tmp_path / f"{marker}.yaml" + source.write_text(f"name: [{marker}\n", encoding="utf-8") + + result = CliRunner().invoke( + app, + [ + "semantic", + "validate", + str(source), + "--contract", + "sdl-yaml/v1", + "--output", + "json", + ], + ) + + assert result.exit_code == 1 + assert marker not in result.stdout + assert marker not in result.stderr + assert "Traceback" not in result.output + payload = json.loads(result.stdout) + assert payload["status"] == "invalid" + assert payload["diagnostics"] + + +def test_unknown_contract_is_usage_error_exit_two(tmp_path: Path) -> None: + source = _write_sdl(tmp_path) + + result = CliRunner().invoke( + app, + [ + "semantic", + "validate", + str(source), + "--contract", + "unknown-contract-v1", + "--output", + "json", + ], + ) + + assert result.exit_code == 2 + assert "unknown-contract-v1" not in result.output + + +def test_unsupported_contract_operation_uses_exit_three() -> None: + source = REPO_ROOT / "contracts" / "fixtures" / "control-plane" / "operation-status-v1" / "valid" / "succeeded.json" + + result = CliRunner().invoke( + app, + [ + "semantic", + "normalize", + str(source), + "--contract", + "operation-status-v1", + "--output", + "json", + ], + ) + + assert result.exit_code == 3 + assert json.loads(result.stdout)["status"] == "unsupported" + + +def test_bounded_input_failure_uses_exit_four(tmp_path: Path) -> None: + result = CliRunner().invoke( + app, + [ + "semantic", + "validate", + str(tmp_path / "missing.sdl.yaml"), + "--contract", + "sdl-yaml/v1", + "--output", + "json", + ], + ) + + assert result.exit_code == 4 + assert json.loads(result.stdout)["status"] == "operational" + + +def test_unexpected_failure_is_sanitized_and_uses_exit_seventy( + tmp_path: Path, + monkeypatch: pytest.MonkeyPatch, +) -> None: + source = _write_sdl(tmp_path) + + def _unexpected(*args: object, **kwargs: object) -> None: + del args, kwargs + raise RuntimeError("SECRET-MARKER") + + monkeypatch.setattr("raes_cli._semantic_sdl.parse_sdl", _unexpected) + result = CliRunner().invoke( + app, + [ + "semantic", + "validate", + str(source), + "--contract", + "sdl-yaml/v1", + "--output", + "json", + ], + ) + + assert result.exit_code == 70 + assert "SECRET-MARKER" not in result.output + assert json.loads(result.stdout)["status"] == "internal" + + +def test_effective_migration_profile_is_explicit_in_result(tmp_path: Path) -> None: + source = tmp_path / "legacy.sdl.yaml" + source.write_text("Name: migrated\n", encoding="utf-8") + + result = CliRunner().invoke( + app, + [ + "semantic", + "normalize", + str(source), + "--contract", + "sdl-yaml/v1", + "--migration-policy", + "accept", + "--output", + "json", + ], + ) + + assert result.exit_code == 0, result.output + payload = json.loads(result.stdout) + assert payload["migration_policy"] == "accept" + assert payload["normalization_profile"] == "raes-sdl-semantic/v1" + assert payload["diagnostics"][0]["code"] == "sdl.noncanonical_field" + + +def test_semantic_operations_are_offline_and_read_only(tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> None: + source = _write_sdl(tmp_path) + before = sorted(path.relative_to(tmp_path) for path in tmp_path.rglob("*")) + + def _network_forbidden(*args: object, **kwargs: object) -> None: + del args, kwargs + raise AssertionError("semantic CLI attempted network access") + + monkeypatch.setattr("socket.create_connection", _network_forbidden) + result = CliRunner().invoke( + app, + [ + "semantic", + "resolve", + str(source), + "--contract", + "sdl-yaml/v1", + "--output", + "json", + ], + ) + + assert result.exit_code == 0, result.output + after = sorted(path.relative_to(tmp_path) for path in tmp_path.rglob("*")) + assert after == before diff --git a/implementations/python/tests/test_stateful_realization_resources.py b/implementations/python/tests/test_stateful_realization_resources.py index 93dbffdf4..2e4cd592b 100644 --- a/implementations/python/tests/test_stateful_realization_resources.py +++ b/implementations/python/tests/test_stateful_realization_resources.py @@ -3,6 +3,7 @@ from __future__ import annotations import textwrap +from dataclasses import replace from pathlib import Path import pytest @@ -61,6 +62,26 @@ def _scenario(extra: str = ""): ) +def _ssh_scenario(*, outputs: str, consumers: str): + output_block = textwrap.indent(textwrap.dedent(outputs).strip(), " ") + consumer_block = textwrap.indent(textwrap.dedent(consumers).strip(), " ") + return parse_sdl( + "name: ssh-access\n" + "nodes:\n" + " producer: {type: vm, os: linux}\n" + " client: {type: vm, os: linux}\n" + "generated_artifacts:\n" + " access:\n" + " generator: ssh_key_bundle\n" + " lifecycle: regenerate_on_change\n" + " provenance: access/ssh.yml\n" + " outputs:\n" + f"{output_block}\n" + " consumers:\n" + f"{consumer_block}\n" + ) + + def test_stateful_resources_parse_compile_and_plan_in_dependency_order(): manifest = create_stub_manifest() assert manifest.provisioner.supports_generated_artifacts @@ -97,6 +118,152 @@ def test_stateful_resources_parse_compile_and_plan_in_dependency_order(): assert requirements["provision.persistent-volume.indexer-data"].explicitness.value == "exact" +def test_ssh_artifact_output_selection_survives_compile_and_plan(): + scenario = _ssh_scenario( + outputs=""" + - {name: private-key, path: id_ed25519, sensitivity: secret, disposition: producer_private} + - {name: public-key, path: id_ed25519.pub, sensitivity: public, disposition: consumer_selected} + - {name: authorized-keys, path: authorized_keys, sensitivity: restricted, disposition: consumer_selected} + """, + consumers=""" + - node: producer + mount_destination: /run/raes/ssh + access_mode: read_only + selected_outputs: [public-key] + - node: client + mount_destination: /home/operator/.ssh + access_mode: read_only + selected_outputs: [authorized-keys] + """, + ) + + artifact = scenario.generated_artifacts["access"] + assert artifact.generator.value == "ssh_key_bundle" + assert artifact.outputs[0].disposition.value == "producer_private" + assert artifact.consumers[1].selected_outputs == ["authorized-keys"] + + execution = plan(compile_runtime_model(scenario), create_stub_manifest()) + payload = execution.provisioning.resources["provision.generated-artifact.access"].payload["spec"] + assert payload["outputs"][0]["disposition"] == "producer_private" + assert payload["consumers"][0]["selected_outputs"] == ["public-key"] + assert payload["consumers"][1]["selected_outputs"] == ["authorized-keys"] + + +@pytest.mark.parametrize( + ("outputs", "consumers", "message"), + [ + ( + "- {name: public-key, path: id.pub, sensitivity: public, disposition: consumer_selected}", + """ + - node: client + mount_destination: /home/operator/.ssh + access_mode: read_only + """, + "SSH generated artifact consumers must select at least one output", + ), + ( + "- {name: public-key, path: id.pub, sensitivity: public, disposition: consumer_selected}", + """ + - node: client + mount_destination: /home/operator/.ssh + access_mode: read_only + selected_outputs: [] + """, + "at least 1 item", + ), + ( + "- {name: public-key, path: id.pub, sensitivity: public, disposition: consumer_selected}", + """ + - node: client + mount_destination: /home/operator/.ssh + access_mode: read_only + selected_outputs: [public-key, public-key] + """, + "selected_outputs must be unique", + ), + ( + "- {name: public-key, path: id.pub, sensitivity: public, disposition: consumer_selected}", + """ + - node: client + mount_destination: /home/operator/.ssh + access_mode: read_only + selected_outputs: [missing] + """, + "unknown generated artifact output", + ), + ( + "- {name: private-key, path: id, sensitivity: secret, disposition: producer_private}", + """ + - node: client + mount_destination: /home/operator/.ssh + access_mode: read_only + selected_outputs: [private-key] + """, + "producer-private generated artifact output", + ), + ( + """ + - {name: public-key, path: id.pub, sensitivity: public, disposition: consumer_selected} + - {name: authorized-keys, path: authorized_keys, sensitivity: restricted, disposition: consumer_selected} + """, + """ + - node: client + mount_destination: /home/operator/.ssh + access_mode: read_only + selected_outputs: [public-key] + """, + "each consumer-selected SSH output must be selected", + ), + ], +) +def test_ssh_artifact_rejects_invalid_output_selection( + outputs: str, + consumers: str, + message: str, +): + with pytest.raises(SDLParseError, match=message): + _ssh_scenario(outputs=outputs, consumers=consumers) + + +def test_legacy_generated_artifacts_keep_implicit_all_non_private_outputs(): + scenario = _scenario() + artifact = scenario.generated_artifacts["indexer-certs"] + + assert artifact.consumers[0].selected_outputs == [] + execution = plan(compile_runtime_model(scenario), create_stub_manifest()) + payload = execution.provisioning.resources["provision.generated-artifact.indexer-certs"].payload["spec"] + assert "selected_outputs" not in payload["consumers"][0] + + +def test_planner_rejects_ssh_artifact_when_backend_does_not_claim_kind_support(): + scenario = _ssh_scenario( + outputs="- {name: public-key, path: id.pub, sensitivity: public, disposition: consumer_selected}", + consumers=""" + - node: client + mount_destination: /home/operator/.ssh + access_mode: read_only + selected_outputs: [public-key] + """, + ) + manifest = create_stub_manifest() + limited = replace( + manifest, + capabilities=replace( + manifest.capabilities, + provisioner=replace( + manifest.provisioner, + supported_generated_artifact_kinds=frozenset({"certificate_bundle", "rendered_config"}), + ), + ), + ) + + execution = plan(compile_runtime_model(scenario), limited) + + assert "provisioner.unsupported-generated-artifact-kind" in { + diagnostic.code for diagnostic in execution.diagnostics + } + + @pytest.mark.parametrize( ("mutation", "message"), [ diff --git a/implementations/python/tests/test_verification_plan.py b/implementations/python/tests/test_verification_plan.py index 4def6f554..5b5335691 100644 --- a/implementations/python/tests/test_verification_plan.py +++ b/implementations/python/tests/test_verification_plan.py @@ -18,6 +18,7 @@ ChangeRecord, collect_git_changes, plan_for_changes, + select_changed_python_tests, ) @@ -100,6 +101,20 @@ def test_mixed_prose_and_source_changes_take_the_highest_risk_plan() -> None: assert plan.regression +def test_precommit_selects_only_directly_changed_pytest_modules() -> None: + selected = select_changed_python_tests( + [ + "tools/isabelle_tool.py", + "implementations/python/tests/helpers.py", + "implementations/python/tests/test_issue_963_participant_opacity_proof.py", + "implementations/python/tests/test_issue_963_participant_opacity_proof.py", + "implementations/python/tests/test_contract.json", + ] + ) + + assert selected == ["implementations/python/tests/test_issue_963_participant_opacity_proof.py"] + + def test_evidence_prefix_matching_respects_directory_boundaries() -> None: plan = _plan("docs/researcher/notes.md") diff --git a/noxfile.py b/noxfile.py index 3c9f1d320..2b213135e 100644 --- a/noxfile.py +++ b/noxfile.py @@ -5,6 +5,7 @@ from dataclasses import dataclass from pathlib import Path from time import perf_counter +import os import shutil import subprocess import sys @@ -24,10 +25,12 @@ ) from tools.tool_versions import PRE_COMMIT_HOOKS_TOOL_SPEC, RUFF_TOOL_SPEC from tools.vale_tool import ensure_vale +from tools.parallel_verification import VerificationLane, run_verification_lanes from tools.verification_plan import ( collect_git_changes, plan_for_changes, resolve_upstream, + select_changed_python_tests, ) PROJECT_ROOT = REPO_ROOT / "implementations" / "python" @@ -82,6 +85,9 @@ EXCLUDED_PREFIXES = ("research/",) PRIVATE_KEY_EXCLUDE_PREFIXES = ("implementations/python/tests/",) MAX_LARGE_FILE_KB = "500" +VERIFY_PROJECT_SYNCED_ENV = "RAES_VERIFY_PROJECT_SYNCED" +VERIFY_COVERAGE_FILE_ENV = "RAES_VERIFY_COVERAGE_FILE" +JSON_SCHEMA_WORKERS_ENV = "RAES_JSON_SCHEMA_WORKERS" nox.options.default_venv_backend = "none" nox.options.reuse_existing_virtualenvs = True @@ -171,6 +177,8 @@ def _changed_paths(*, staged: bool = False, base_rev: str | None = None) -> list def _sync_project(session: nox.Session) -> None: + if os.environ.get(VERIFY_PROJECT_SYNCED_ENV) == str(os.getppid()): + return _run( session, "uv", @@ -268,6 +276,7 @@ def _run_pytest( "coverage", "report", "--fail-under=50", + "--format=total", env=coverage_env, ) @@ -721,6 +730,18 @@ def _run_contracts(session: nox.Session, reporter: SessionReporter, *args: str) "contracts / NIST CSF defensive vocabulary conformance", lambda: _run_project_python(session, "tools/check_nist_csf_defensive_vocabulary.py"), ) + reporter.run( + "contracts / autonomous behavior vocabulary conformance", + lambda: _run_project_python(session, "tools/check_autonomous_behavior_vocabularies.py"), + ) + + +def _run_participant_opacity_proof(session: nox.Session, reporter: SessionReporter) -> None: + reporter.run( + "formal proof / participant opacity", + lambda: _run_project_python(session, "tools/check_participant_opacity_proof.py"), + detail="Isabelle2025-2 :: offline kernel replay", + ) def _run_lint(session: nox.Session, reporter: SessionReporter) -> None: @@ -847,6 +868,35 @@ def _run_integration_tests( ) +def _finalize_parallel_coverage(session: nox.Session, coverage_dir: Path) -> None: + coverage_file = coverage_dir / ".coverage" + coverage_env = {"COVERAGE_FILE": str(coverage_file)} + with session.chdir(PROJECT_ROOT): + _run( + session, + "uv", + "run", + "--frozen", + "coverage", + "combine", + "--keep", + str(coverage_dir), + env=coverage_env, + ) + _run(session, "uv", "run", "--frozen", "coverage", "xml", env=coverage_env) + _run( + session, + "uv", + "run", + "--frozen", + "coverage", + "report", + "--fail-under=50", + "--format=total", + env=coverage_env, + ) + + def _run_docker_integration_tests(session: nox.Session, reporter: SessionReporter) -> None: reporter.run( "tests / pytest docker integration", @@ -877,7 +927,12 @@ def _scan() -> None: ) -def _run_docs(session: nox.Session, reporter: SessionReporter) -> None: +def _run_docs( + session: nox.Session, + reporter: SessionReporter, + *, + include_external_links: bool = True, +) -> None: _sync_project(session) html_dir = DOCS_BUILD_ROOT / "html" linkcheck_dir = DOCS_BUILD_ROOT / "linkcheck" @@ -947,9 +1002,34 @@ def _build(builder: str, output_dir: Path, *, clean: bool = False) -> None: str(html_dir), ), ) + if include_external_links: + reporter.run( + "docs / Sphinx link check", + lambda: _build("linkcheck", linkcheck_dir), + detail=str(PUBLIC_DOCS_ROOT.relative_to(REPO_ROOT)), + ) + + +def _run_docs_linkcheck(session: nox.Session, reporter: SessionReporter) -> None: + _sync_project(session) + linkcheck_dir = DOCS_BUILD_ROOT / "linkcheck" reporter.run( - "docs / Sphinx link check", - lambda: _build("linkcheck", linkcheck_dir), + "docs / Sphinx external link check", + lambda: _run( + session, + "uv", + "run", + "--project", + str(PROJECT_ROOT), + "--frozen", + "sphinx-build", + "-W", + "--keep-going", + "-b", + "linkcheck", + str(PUBLIC_DOCS_ROOT), + str(linkcheck_dir), + ), detail=str(PUBLIC_DOCS_ROOT.relative_to(REPO_ROOT)), ) @@ -990,6 +1070,17 @@ def contracts(session: nox.Session) -> None: reporter.summary() +@nox.session(name="participant-opacity-proof") +def participant_opacity_proof(session: nox.Session) -> None: + """Replay the pinned, network-isolated SEM-231 mathematical proof.""" + + reporter = SessionReporter(session, "participant-opacity-proof") + try: + _run_participant_opacity_proof(session, reporter) + finally: + reporter.summary() + + @nox.session def tests(session: nox.Session) -> None: reporter = SessionReporter(session, "tests") @@ -1055,6 +1146,28 @@ def docs(session: nox.Session) -> None: reporter.summary() +@nox.session(name="docs-local") +def docs_local(session: nox.Session) -> None: + """Run deterministic documentation checks without external HTTP requests.""" + + reporter = SessionReporter(session, "docs-local") + try: + _run_docs(session, reporter, include_external_links=False) + finally: + reporter.summary() + + +@nox.session(name="docs-links") +def docs_links(session: nox.Session) -> None: + """Check external documentation links; intended for the dedicated CI job.""" + + reporter = SessionReporter(session, "docs-links") + try: + _run_docs_linkcheck(session, reporter) + finally: + reporter.summary() + + @nox.session(name="osv_scan") def osv_scan(session: nox.Session) -> None: """Advisory OSV-Scanner sweep over the Python dependency lockfile (issue #34). @@ -1078,6 +1191,7 @@ def osv_scan(session: nox.Session) -> None: def hook_pre_commit(session: nox.Session) -> None: reporter = SessionReporter(session, "hook-pre-commit") changed = [Path(arg).as_posix() for arg in session.posargs if not arg.startswith("-")] + changed_tests = select_changed_python_tests(changed) try: _run_hygiene(session, reporter, posargs=changed, default_all_files=False) _run_policy(session, reporter, "--staged") @@ -1087,11 +1201,16 @@ def hook_pre_commit(session: nox.Session) -> None: else: reporter.skip("contracts / generated schema drift", "no contract-bearing changes") reporter.skip("contracts / json artifact validation", "no contract-bearing changes") - if _paths_trigger(changed, FULL_TEST_TRIGGER_PREFIXES): + if changed_tests: reporter.run( + "tests / directly changed pytest modules", + lambda: _run_pytest(session, *changed_tests, "-q"), + detail=" ".join(changed_tests), + ) + elif _paths_trigger(changed, FULL_TEST_TRIGGER_PREFIXES): + reporter.skip( "tests / pytest", - lambda: _run_pytest(session, "-q"), - detail="full implementation test sweep", + "no directly changed test module; full regression runs at pre-push and completion", ) elif _paths_trigger(changed, TOOLING_TEST_TRIGGER_PREFIXES): reporter.run( @@ -1175,29 +1294,226 @@ def verify_changed(session: nox.Session) -> None: reporter.summary() -@nox.session -def verify(session: nox.Session) -> None: - reporter = SessionReporter(session, "verify") +def _required_coverage_file() -> Path: + value = os.environ.get(VERIFY_COVERAGE_FILE_ENV) + if not value: + raise RuntimeError(f"{VERIFY_COVERAGE_FILE_ENV} is required for an orchestrated coverage lane") + return Path(value) + + +@nox.session(name="verify-static-lane") +def verify_static_lane(session: nox.Session) -> None: + """Internal lane for full-tree hygiene, policy, and lint checks.""" + + reporter = SessionReporter(session, "verify-static-lane") + posargs = list(session.posargs) + include_policy = "--include-policy" in posargs + if include_policy: + posargs.remove("--include-policy") try: _run_hygiene( session, reporter, - posargs=session.posargs or ["--all-files"], + posargs=posargs or ["--all-files"], default_all_files=True, ) - _run_policy(session, reporter, *session.posargs) + if include_policy: + _run_policy(session, reporter, *posargs) _run_lint(session, reporter) - _run_contracts(session, reporter, *session.posargs) - with tempfile.TemporaryDirectory(prefix="raes-coverage-") as coverage_dir: - coverage_file = Path(coverage_dir) / ".coverage" - _run_tests(session, reporter, coverage_file, finalize_coverage=False) - _run_integration_tests( - session, - reporter, - coverage_file=coverage_file, - append_coverage=True, - finalize_coverage=True, + finally: + reporter.summary() + + +@nox.session(name="verify-tests-lane") +def verify_tests_lane(session: nox.Session) -> None: + """Internal unit-test lane that emits an independently combinable data file.""" + + reporter = SessionReporter(session, "verify-tests-lane") + try: + _run_tests( + session, + reporter, + _required_coverage_file(), + finalize_coverage=False, + ) + finally: + reporter.summary() + + +@nox.session(name="verify-integration-lane") +def verify_integration_lane(session: nox.Session) -> None: + """Internal integration lane with coverage isolated from the unit workers.""" + + reporter = SessionReporter(session, "verify-integration-lane") + try: + _run_integration_tests( + session, + reporter, + coverage_file=_required_coverage_file(), + append_coverage=False, + finalize_coverage=False, + ) + finally: + reporter.summary() + + +def _verification_lanes( + *, + posargs: Sequence[str], + coverage_dir: Path, + include_policy: bool, + cpu_count: int | None = None, +) -> tuple[VerificationLane, ...]: + available_cpus = cpu_count if cpu_count is not None else _available_cpu_count() + shared_posargs = tuple(posargs) + static_posargs = (("--include-policy",) if include_policy else ()) + shared_posargs + return ( + VerificationLane( + name="unit-tests", + nox_session="verify-tests-lane", + env={ + VERIFY_COVERAGE_FILE_ENV: str(coverage_dir / ".coverage.unit"), + "PYTEST_ADDOPTS": f"-o cache_dir={coverage_dir / 'pytest-unit'}", + "PYTEST_XDIST_AUTO_NUM_WORKERS": str(max(1, min(8, available_cpus // 2))), + }, + ), + VerificationLane( + name="integration-tests", + nox_session="verify-integration-lane", + env={ + VERIFY_COVERAGE_FILE_ENV: str(coverage_dir / ".coverage.integration"), + "PYTEST_ADDOPTS": f"-o cache_dir={coverage_dir / 'pytest-integration'}", + }, + ), + VerificationLane( + name="contracts", + nox_session="contracts", + posargs=shared_posargs, + env={JSON_SCHEMA_WORKERS_ENV: str(max(1, min(4, available_cpus // 4)))}, + ), + VerificationLane( + name="static", + nox_session="verify-static-lane", + posargs=static_posargs, + ), + VerificationLane( + name="participant-opacity-proof", + nox_session="participant-opacity-proof", + ), + VerificationLane( + name="docs-local", + nox_session="docs-local", + env={ + "PYTEST_ADDOPTS": f"-o cache_dir={coverage_dir / 'pytest-docs'}", + }, + ), + ) + + +def _available_cpu_count() -> int: + if hasattr(os, "sched_getaffinity"): + try: + return max(1, len(os.sched_getaffinity(0))) + except OSError: + pass + return max(1, os.cpu_count() or 1) + + +def _verification_lane_workers(*, cpu_count: int, lane_count: int) -> int: + return min(lane_count, 4, max(1, cpu_count // 2)) + + +def _run_parallel_verification( + session: nox.Session, + reporter: SessionReporter, + *, + include_policy: bool, +) -> None: + reporter.run( + "verify / locked project environment", + lambda: _sync_project(session), + detail="one synchronization shared by all isolated lanes", + ) + reporter.run( + "verify / shared policy toolchain", + lambda: _run_project_python( + session, + "-c", + "from tools.policy.conftest_tool import ensure_conftest; ensure_conftest()", + ), + detail="prime checksum-verified Conftest before parallel policy tests", + ) + with tempfile.TemporaryDirectory(prefix="raes-coverage-") as coverage_root: + coverage_dir = Path(coverage_root) + available_cpus = _available_cpu_count() + lanes = _verification_lanes( + posargs=session.posargs, + coverage_dir=coverage_dir, + include_policy=include_policy, + cpu_count=available_cpus, + ) + lane_workers = _verification_lane_workers( + cpu_count=available_cpus, + lane_count=len(lanes), + ) + results = [] + + def _execute_lanes() -> None: + results.extend( + run_verification_lanes( + lanes, + nox_python=Path(sys.executable), + noxfile=Path(__file__).resolve(), + repo_root=REPO_ROOT, + base_env={ + VERIFY_PROJECT_SYNCED_ENV: str(os.getpid()), + "PYTHONUNBUFFERED": "1", + }, + max_workers=lane_workers, + ) ) - _run_docs(session, reporter) + for result in results: + session.log( + f"[verify] lane {result.name}: " + f"{'PASS' if result.returncode == 0 else 'FAIL'} ({result.duration_s:.2f}s)" + ) + if result.output: + print(result.output, end="" if result.output.endswith("\n") else "\n") + failures = [result for result in results if result.returncode != 0] + if failures: + failed = ", ".join(f"{result.name} (exit {result.returncode})" for result in failures) + raise RuntimeError(f"parallel verification lanes failed: {failed}") + + reporter.run( + "verify / isolated deterministic lanes", + _execute_lanes, + detail=( + "unit, integration, contracts, static, proof, docs-local :: " + f"{lane_workers} lane workers on {available_cpus} CPUs" + ), + ) + reporter.run( + "verify / combined coverage", + lambda: _finalize_parallel_coverage(session, coverage_dir), + detail="unit + integration data files", + ) + + +@nox.session +def verify(session: nox.Session) -> None: + reporter = SessionReporter(session, "verify") + try: + _run_parallel_verification(session, reporter, include_policy=True) + finally: + reporter.summary() + + +@nox.session(name="verify-completion") +def verify_completion(session: nox.Session) -> None: + """Run the completion graph whose Ground Control pair runs policy next.""" + + reporter = SessionReporter(session, "verify-completion") + try: + _run_parallel_verification(session, reporter, include_policy=False) finally: reporter.summary() diff --git a/specs/concept-authority/autonomous-behavior-vocabularies.md b/specs/concept-authority/autonomous-behavior-vocabularies.md new file mode 100644 index 000000000..bd569f9d1 --- /dev/null +++ b/specs/concept-authority/autonomous-behavior-vocabularies.md @@ -0,0 +1,164 @@ +# Autonomous Behavior Vocabulary Bindings + +## Scope + +This specification defines how RAES behavior specifications may be related to +versioned external vocabularies for autonomous services and agents under +ACT-611. + +It composes two existing authorities: + +- ADR-067 and the participant behavior model own native RAES behavior meaning; +- `external-concept-bindings/v1` owns portable assertions about exact RAES + subjects and arbitrary external concepts. + +ACT-611 adds source snapshots and examples at that composition boundary. It +does not add SDL syntax, a participant subtype, a native autonomous-behavior +taxonomy, or another resolver. + +## Initial Schemes + +### W3C ActivityStreams Activity Types + +The directly adopted external identifiers are the 28 Activity types listed by +the dated W3C Activity Vocabulary Recommendation of 23 May 2017. + +| Coordinate | Value | +| --- | --- | +| `scheme_id` | `w3c-activitystreams-activity-types` | +| `authority` | `World Wide Web Consortium` | +| `revision` | `REC-activitystreams-vocabulary-20170523` | +| source record | `contracts/concept-authority/w3c-activitystreams-activity-types-source-v1.json` | + +Each `concept_id` is the full normative IRI, such as +`https://www.w3.org/ns/activitystreams#Create`. The adapter does not shorten, +case-fold, translate, merge, or deduplicate these identifiers. + +`Application` and `Service` are ActivityStreams Actor/Object types. They are +not members of this behavior scheme, do not become RAES participant types, and +do not prove that an authored behavior is autonomous. + +### FIPA Communicative Act Library + +The second scheme publishes the 22 exact lower-case communicative-act symbols +from FIPA specification SC00037J, Standard status dated 2002-12-03. + +| Coordinate | Value | +| --- | --- | +| `scheme_id` | `fipa-communicative-act-library` | +| `authority` | `Foundation for Intelligent Physical Agents` | +| `revision` | `SC00037J-2002-12-03` | +| source record | `contracts/concept-authority/fipa-communicative-acts-source-v1.json` | + +Symbols such as `inform`, `request`, `cfp`, and `not-understood` are external +annotations only. A binding does not import FIPA mental-state semantics, +feasibility preconditions, rational effects, message transport, content +language, or interaction protocols, and it does not claim FIPA ACL +conformance. + +The required HTML locator contains dynamically rewritten email-protection +markup, so it is not byte-stable. The source record retains that locator and +pins the stable official `SC00037J.pdf` representation by SHA-256. The +maintenance verifier checks the PDF bytes and separately confirms the exact +act identifiers in the HTML specification. + +## Candidate Decisions + +The complete primary-source comparison is recorded in +`docs/decisions/issue-211-act-611-autonomous-behavior-vocabularies-preflight.md`. +Its decisions are: + +- directly adopt the W3C ActivityStreams Activity type IRIs; +- use the FIPA communicative-act symbols only as external annotations; +- do not use PROV-O `Activity`, `Agent`, or `SoftwareAgent` as behavior + classifications because they own provenance and responsibility semantics; +- defer IEEE 1872.2 terms to robot-specific future work that can pin an exact + licensed source revision and prove correspondence to the standard. + +No copied FIPA formal model or purchased IEEE standard text is published. +Source records contain identifiers, citations, rights notices, and locally +authored scope constraints rather than copied definitions. + +## Exact Behavior Subject + +An ACT-611 assertion targets the exact coordinate returned by +`external_concept_subjects()` for a behavior declaration: + +```yaml +subject: + subject_kind: behavior_specifications + owning_contract_id: sdl-authoring-input-v1 + lifecycle_phase: normalized-authoring + canonical_ref: behavior_specifications.service-publication + artifact_digest: sha256: +``` + +The behavior specification remains a complete native aggregate over its +participants, actions, observations, outcomes, authority/scope, behavior mode, +realization, and evidence. The external assertion only relates that aggregate +to another scheme. A map key, `spec_id`, participant name, label, compiled +address, JSON Pointer, or unqualified string is not an identity substitute. + +## Portable Assertion Semantics + +Both initial schemes use the unchanged +`external-concept-bindings/v1` syntax. Relationship, motivation, semantic +effect, perspective, provenance, evidence references, confidence, +approximation or loss, limitations, participant eligibility, and review status +retain their portable contract meanings. + +Conservative behavior bindings use `related-to` and `annotates` with explicit +loss and limitations. Stronger `equivalent-to`, `aligns`, `refines`, or +`constrains` claims require independent review support. Even a resolved +`constrains` assertion has no validation effect unless an existing governed +RAES consumer independently owns that constraint. + +External terms never replace or create: + +- action contracts or executable actions; +- observation boundaries, outcomes, or runtime evidence; +- authority, operating scope, capabilities, or authorization; +- realization or participant information-flow controls; +- behavior modes or proof of autonomous execution. + +Participant availability remains `eligibility-only`; disclosure, exposure, +delivery, and understanding continue through their existing deny-first +boundaries. + +## Offline Admission And Extensibility + +Each source-specific adapter projects its pinned record to +`ExternalConceptSchemeSnapshotModel`. It preserves the concept list, including +candidate multiplicity. Both schemes then use the same structural model, +exact-subject projection, and `admit_external_concept_bindings()` operation. + +Normal loading and admission perform no network, environment, plugin, +subprocess, or latest-version lookup. The resolver continues to report +deterministic `resolved-current`, `unavailable`, `stale`, `ambiguous`, +`superseded`, `unknown-concept`, and `subject-not-found` outcomes. + +A future third scheme adds its own source record/model/schema, corpus loader, +snapshot adapter, source-integrity proof, and fixtures. It must not add a +scheme discriminator to the authored contract, branch the resolver by +`scheme_id`, or create a global external-ontology registry. + +## Conformance + +The two valid fixtures are: + +- `contracts/fixtures/concept-authority/external-concept-bindings-v1/valid/activitystreams-behavior.json`; +- `contracts/fixtures/concept-authority/external-concept-bindings-v1/valid/fipa-behavior.json`. + +They target declarations in the focused +`context/autonomous-behavior-subject.sdl.yaml` artifact and exercise the same +published schema, conformance registration, exact subject adapter, neutral +snapshot, and offline admission function. + +`tools/check_autonomous_behavior_vocabularies.py` enforces pinned metadata and +identifier order offline. Its optional `--verify-remote` maintenance mode is +limited to the official W3C and FIPA HTTPS hosts; normal conformance never +invokes it. + +## Requirement + +- ACT-611: autonomous service and agent behavior vocabularies. diff --git a/specs/concept-authority/concept-authority.md b/specs/concept-authority/concept-authority.md index 7b0c7a1f1..e39b62850 100644 --- a/specs/concept-authority/concept-authority.md +++ b/specs/concept-authority/concept-authority.md @@ -52,6 +52,12 @@ subject to a concept in an arbitrary versioned scheme are governed by complement native manifest `ConceptBinding` entries without changing their scope or authority. +[Autonomous Behavior Vocabulary Bindings](./autonomous-behavior-vocabularies.md) +apply that portable surface to exact participant behavior specifications using +pinned ActivityStreams and FIPA sources. The external identifiers remain +descriptive assertions; they are not new native concept families or SDL +vocabularies. + ## Surface A **surface** is a named, bounded, contract-bearing scope of an RAES artifact @@ -204,7 +210,7 @@ steps from this section and the machine-readable catalog alone: family must satisfy the single structural invariant set enforced by `implementations/python/tests/test_runtime_family_invariants.py` (the runtime SDL cross-family consistency epic - [#439](https://github.com/RAESystem/rae/issues/439) and children + [#439](https://github.com/OpenRAE/rae/issues/439) and children #442 / #443 / #444): a `Runtime` model class, a `singular(collection_name) + "_id"` primary identifier, and a plural typed-child container registered in the registry. A new family that violates @@ -263,3 +269,5 @@ and where their meaning comes from. - GOV-920: Shared semantic profiles ([semantic-profiles.md](./semantic-profiles.md)). - GOV-921: Shared reference models ([reference-models.md](./reference-models.md)). - GOV-922: Controlled vocabularies and enumerations ([controlled-vocabularies.md](./controlled-vocabularies.md)). +- ACT-611: Autonomous service and agent vocabulary assertions + ([autonomous-behavior-vocabularies.md](./autonomous-behavior-vocabularies.md)). diff --git a/specs/concept-authority/external-concept-bindings.md b/specs/concept-authority/external-concept-bindings.md index 3be035114..b60cb2869 100644 --- a/specs/concept-authority/external-concept-bindings.md +++ b/specs/concept-authority/external-concept-bindings.md @@ -205,6 +205,13 @@ snapshot model. ATT&CK Enterprise tactics and NIST CSF defensive categories are the initial unrelated examples. Both use the same authored syntax, schema, subject resolution, and offline admission path. +ACT-611 adds W3C ActivityStreams Activity types and FIPA communicative acts as +two further unrelated schemes targeting exact +`behavior_specifications.` declarations. They use the same authored +syntax and admission path; their source, semantic, and rights boundaries are +specified in +[Autonomous Behavior Vocabulary Bindings](./autonomous-behavior-vocabularies.md). + An adapter projects a pinned source artifact into scheme identity, authority, revision, locator, digest, and a multiplicity-preserving concept candidate list. Candidate ids are not converted into dictionary keys: zero matches are diff --git a/specs/formal/participant-behavior-model/README.md b/specs/formal/participant-behavior-model/README.md index 3a270aef4..b9afaa9d6 100644 --- a/specs/formal/participant-behavior-model/README.md +++ b/specs/formal/participant-behavior-model/README.md @@ -548,6 +548,33 @@ Implementation issue #210 owns the executable SDL field, governed validation, source-integrity checker, generated schemas, documentation, and compiler carry-through for defensive behavior refs. +## ACT-611 - Autonomous Service And Agent Behavior Vocabularies + +Autonomous-service and autonomous-agent vocabulary relationships are portable +external assertions about an exact behavior specification, not another field +inside that specification. ACT-611 uses +`external-concept-bindings/v1` to bind the canonical +`behavior_specifications.` declaration and artifact digest to pinned +ActivityStreams Activity type IRIs or FIPA communicative-act identifiers. + +Rules: + +- the native behavior specification retains participant, action, observation, + outcome, authority/scope, mode, realization, and evidence meaning; +- `behavior_mode: autonomous` remains the governed decision-surface mode and + is not inferred from an external actor, agent, service, or behavior term; +- both schemes use the same neutral snapshot, exact subject adapter, resolver, + conformance registration, and offline outcomes; +- relationship, effect, provenance, confidence, approximation/loss, + limitations, review, and participant eligibility retain the portable + binding contract semantics; +- external terms remain descriptive and never become executable actions, + capabilities, authorization, runtime evidence, outcomes, or proof of + autonomy. + +The source and conformance contract is specified in +[`specs/concept-authority/autonomous-behavior-vocabularies.md`](../../concept-authority/autonomous-behavior-vocabularies.md). + ## ACT-617 - Mixed-Control Participant Operation A behavior specification in `mixed-control` mode carries one explicit @@ -622,6 +649,7 @@ portable occurrence contracts and runtime mediation/persistence respectively. | PBM-09 | Offensive behavior refs are governed vocabulary classifications, not raw action names, roles, goals, tasks, commands, or external technique labels. | ACT-609 | | PBM-10 | Defensive behavior refs classify intent or outcome domains and do not prove incident existence, effectiveness, recovery, or CSF conformance. | ACT-610 | | PBM-11 | Mixed-control authority and ordered control facts are explicit, fail closed, and remain distinct from admission, execution, and observation. | ACT-617 | +| PBM-12 | Autonomous behavior vocabulary terms are external assertions about exact behavior specifications and do not create native or executable behavior meaning. | ACT-611 | ## Child-Issue Mapping @@ -634,6 +662,7 @@ portable occurrence contracts and runtime mediation/persistence respectively. | #208 | ACT-608 | Behavior-mode declaration, selection, controlled-vocabulary validation, and conformance. | | #209 | ACT-609 | Offensive behavior vocabulary declaration, validation, and compiler carry-through. | | #210 | ACT-610 | Defensive behavior vocabulary declaration, validation, source integrity, and compiler carry-through. | +| #211 | ACT-611 | Pinned autonomous behavior schemes, exact behavior-specification assertions, offline resolution, and conformance. | | #251 | ACT-617 | Authored controller/authority state, ordered fail-closed control transitions, composition, and typed compiler projection. | ## Verification Expectations diff --git a/specs/formal/participant-semantics/README.md b/specs/formal/participant-semantics/README.md index ac926899d..1b488a134 100644 --- a/specs/formal/participant-semantics/README.md +++ b/specs/formal/participant-semantics/README.md @@ -15,6 +15,10 @@ This document is the issue #71 formal design artifact for: - `SEM-230` - Participant Information-Flow And Control Semantics - `SEM-231` - Participant-Relative Predicate Opacity Semantics - `SEM-232` - Proof-Bearing Participant-Crossing Bisimulation +- `SEM-233` - Adversarial Participant Boundary Information-Flow Control +- `SEM-234` - Mixed Cross-Backend Participant-Control Composition +- `ASR-536` - Intentional-Subversion Participant Control Evaluation +- `ASR-537` - Cross-Backend Participant-Control Realization And Transfer Evidence - `DSL-437` - Benign Participant Autonomous Execution It is a design artifact, not an implementation artifact. It establishes the @@ -48,6 +52,26 @@ participant/audience projection. It does not report the downstream model-check, runtime mapping, backend conformance, noninterference, or opacity result. +Issue #812 and ADR-101 add the SEM-233 boundary-flow and ASR-536 +intentional-subversion evaluation design. Their normative profiles are in +[`adversarial-flow-control.md`](adversarial-flow-control.md). The design +extends the existing participant, control, crossing, runtime, backend, and +experiment carriers with independent confidentiality and integrity +coordinates, conservative derivation, final-sink mediation, and explicit +attack-protocol variables. It does not report runtime enforcement, backend +realization, monitor honesty, covert-channel control, or adversarial +robustness. + +Issue #813 and ADR-102 add the SEM-234 mixed-composition and ASR-537 +realization/transfer-evidence design. Their normative profiles are in +[`cross-backend-participant-control.md`](cross-backend-participant-control.md). +The design supports both alternative simulation/emulation realization and +simultaneous mixed realization, plus linked inter-trial and finite +pre-admitted within-run changes. It keeps portable SDL backend-neutral and +preserves one acting controller in revision 1. It does not report runtime or +backend realization, multi-controller support, interoperability, transfer, +IFC/noninterference, or cross-backend equivalence. + Issue #861 and ADR-092 add deterministic autonomous execution for ordinary participants. The focused normative composition is [`autonomous-execution.md`](autonomous-execution.md): it binds existing @@ -1732,6 +1756,29 @@ SEM-232 authority, and child program. It does not run the model check. Issues negative mutations, finite equivalence checking, independent reproduction, and reproduction-gated scientific documentation. +## SEM-233 and ASR-536 - Adversarial Participant Flow Control + +SEM-233 and ASR-536 are defined in +[`adversarial-flow-control.md`](adversarial-flow-control.md). + +SEM-233 adds a revisioned participant-neutral explicit-flow profile with +independent confidentiality and integrity coordinates, conservative +propagation, distinct declassification and integrity endorsement, and +deny-first final-sink decisions immediately before external action or +disclosure. Handoff, participant change, and episode reset do not erase labels +or provenance. + +ASR-536 adds a separate control-evaluation profile for honest and attack +modes, main and side objectives, policy and monitor knowledge, adaptive +strategies, collusion and correlated failure, audit and intervention +protocols, memory/replay, and separate safety, usefulness, cost, uncertainty, +limitation, and nonclaim measures. + +Issue #812 supplies the design authority and child program only. SEM-233 and +ASR-536 remain DRAFT; issues #1001, #1002, #1003, #1004, #1007, and #1008 own +their semantic, contract, runtime, apparatus/backend, evaluation, and +documentation work. + ## Required Future Verification The complete participant surface is `FM3`. diff --git a/specs/formal/participant-semantics/adversarial-flow-control.md b/specs/formal/participant-semantics/adversarial-flow-control.md new file mode 100644 index 000000000..2d19c7365 --- /dev/null +++ b/specs/formal/participant-semantics/adversarial-flow-control.md @@ -0,0 +1,344 @@ +# SEM-233 and ASR-536 Adversarial Participant Flow Control + +Status: design authority; positive implementation and evaluation obligations +remain DRAFT. + +Requirements: `SEM-233`, `ASR-536`. + +Decision authority: +[ADR-101](../../../docs/decisions/adrs/adr-101-adversarial-participant-flow-control.md). + +## Scope + +This specification adds two revisioned profiles over the existing SEM-230, +ACT-617, API-409, API-423, RUN-310, RUN-319, API-407, experiment, and ASR-535 +carriers: + +1. `participant-boundary-flow-policy-v1@rev1`, which defines independent + confidentiality and integrity coordinates, conservative explicit-flow + derivation, release operations, and final-sink decisions; and +2. `intentional-subversion-control-evaluation-v1@rev1`, which defines the + experimental variables and evidence boundary for honest and intentionally + subverting participant policies. + +The profiles apply to human, scripted, reinforcement-learning, +large-language-model, and external-service participants. They do not expose or +govern chain-of-thought, private model state, credentials, or undeclared +internal apparatus flows. + +## State and identities + +For participant `p`, episode `e`, memory scope `m`, exact state cut `c`, +flow-policy profile `phi`, source or derived value `x`, and sink `s`, the +governed state reuses: + +- the SEM-230 participant/audience projection, policy decision, memory, + adaptive-strategy, release, order, and provenance coordinates; +- ACT-617 controller and authority state; +- API-409 control occurrences; +- API-423 crossing request, decision, transformation, delivery, observation, + and audit occurrences; +- runtime-fact source, derivation, audience, scope, freshness, and sink + declarations; +- participant proposal, action-admission, attempt, result, and output facts; +- the RUN-310/RUN-319 append-only histories and exact expected heads; +- API-407 declared and effective capability support; and +- experiment task, protocol, study, run, apparatus, evidence, measure, and + traceability records. + +Every derived identity is fresh and binds the source identities, derivation +kind, profile and revision, exact policy/state cut, authority, destination or +sink, and safe evidence refs. No release operation mutates a prior fact. + +## Flow labels + +The effective label of `x` is: + +```text +Label_phi(x,c) = (Conf_phi(x,c), Int_phi(x,c)) +``` + +where: + +- `Conf_phi(x,c)` is ordered by permitted audience, principal, destination, and + sink exposure; higher labels are at least as restrictive; and +- `Int_phi(x,c)` conservatively records origins or possible writers that may + have influenced `x`, plus the sink-required integrity predicate. + +These coordinates are independent. Authentication, signatures, hashes, +markings, sensitivity, confidence, roles, and monitor scores can contribute +governed evidence but cannot define both coordinates. + +### Source defaults + +`SourceLabel_phi(src,c)` resolves through the revisioned source authority. +When the source, profile, revision, or authority cannot be resolved, the +result is the profile's maximum-confidentiality and minimum-trust default. A +deployment may use a narrower deny-only representation, but it cannot default +to public or trusted. + +### Conservative composition + +For a derivation `d` whose possible inputs are `I(d)`: + +```text +Conf_phi(d,c) = join_conf { Conf_phi(x,c) | x in I(d) } +Int_phi(d,c) = join_int { Int_phi(x,c) | x in I(d) } +``` + +`join_conf` is the profile's least upper bound. `join_int` is conservative +influence union under the profile's integrity order. + +An opaque participant, model, service, script, summary, copy, redaction, or +transformation retains the join of every input that could have influenced its +result. A typed transformation can narrow the influence set only when its +closed contract and evidence establish that relation. Apparatus claims alone +cannot do so. + +### Cross-participant and cross-episode carriage + +API-409 handoff, API-423 crossing, controller change, participant change, +shared state, joint state, or episode reset never clears labels or provenance. +A receiving participant inherits the effective upstream label and source +history through the governed crossing. + +Cross-episode replay binds the original source, profile, revision, policy +decisions, release events, SEM-230 memory scope, and expected history heads. +Replay under a later cut receives a fresh decision. + +## Distinct operations + +The following operations are semantically distinct: + +| Operation | Effect | +| --- | --- | +| authentication | establishes principal identity and credential validity | +| authorization | permits an operation for an identity and authority | +| admission | accepts a fact, proposal, action, transition, or evidence record | +| approval | records a supervisory control decision | +| declassification | relaxes confidentiality for an exact result and sink | +| integrity endorsement | changes the admitted origin-trust coordinate for an exact result and sink | +| redaction | derives a new representation and retains influence unless a governed rule states otherwise | +| transformation | derives a new identity under a typed relation | +| trusted editing | derives a fresh proposal that re-enters normal gates | +| handoff | changes controller or authority state | +| deferral | transfers a decision obligation without authorizing the effect | +| interruption or shutdown | changes lifecycle and future enabledness | +| advice | supplies evidence or recommendation without authority | +| execution or delivery | realizes an already permitted effect or disclosure | + +Declassification and endorsement each bind: + +- source and fresh result identity; +- exact changed coordinate and unchanged coordinate; +- destination, audience, or sink; +- authorizing principal and authority basis; +- profile, revision, policy decision, and state cut; +- predecessor and order refs; and +- safe evidence and limitation refs. + +Approval, authentication, admission, monitor output, or trusted role does not +imply either release operation. + +## Final-sink decision + +For effective label `l`, exact cut `c`, sink `s`, authority `a`, destination +`d`, participant `p`, and effective capability posture `k`: + +```text +MayRelease_phi(p,l,s,d,a,c,k) + = FlowPolicy_phi(l,s,d,c) + and Authorized(a,p,s,d,c) + and Admitted(p,s,c) + and EffectiveCapability(k,phi,s) + and FreshHeads(c) +``` + +Every conjunct is deny-first. Heuristic monitor output is not a conjunct that +can turn denial into permission. A profile may require monitor evidence as a +precondition, but only deterministic policy interprets that evidence. + +The runtime evaluates `MayRelease`: + +- after the last label, provenance, policy, authority, destination, + participant, audience, capability, and state-cut resolution; +- immediately before `RuntimeTarget` or a backend performs an external + mutation, tool action, callback, or persistent write; and +- immediately before participant-facing or external serialization, streaming, + delivery, error output, or other disclosure. + +It commits the decision and all predecessor/history changes atomically before +effect. A denial, unsupported result, missing label or provenance, ambiguous +join, stale cut, history-head conflict, or failed commit causes no external +call and no disclosure. + +Each streaming chunk is either governed before release or derived from a +complete materialized value whose entire release is governed by the profile. + +## Deterministic policy and heuristic monitors + +Deterministic policy decides authorization, flow, capability, admission, and +release. A heuristic monitor emits a bounded observation, suspicion result, or +recommendation with identity, revision, visibility, provenance, confidence, +limitations, and safe evidence. + +```text +MonitorResult != Authorization +MonitorFailure does not widen MayRelease +``` + +Monitor roles are apparatus and experiment declarations. A profile states: + +- trusted, untrusted, or composed role; +- inputs and participant-visible outputs; +- policy, threshold, and audit knowledge; +- model or implementation identity where relevant; +- topology and shared inputs; +- independence, correlation, and collusion assumptions; and +- failure and fallback behavior. + +Different monitor or model ids do not establish independence. + +Human or trusted-system intervention names each authority effect. If an +intervention edits a proposal, it creates a fresh proposal with inherited +provenance and effective labels and re-enters validation, policy, capability, +and admission. + +## Intentional-subversion evaluation profile + +An admitted ASR-536 evaluation profile closes: + +```text +Eval = + (mode, + main_objective, + side_objective, + participant_capabilities, + apparatus, + policy_knowledge, + monitor_knowledge, + audit_budget_knowledge, + prior_outcome_visibility, + adaptive_strategy_class, + collusion, + monitor_topology, + monitor_correlation, + audit_budget, + audit_selection, + intervention_protocol, + memory_scope, + replay_scope, + policy_revision_scope, + measures, + limitations, + nonclaims) +``` + +`mode` is `honest` or `attack`. Honest-but-fallible behavior and an attack +policy optimizing a side objective are separate populations. + +The adaptive strategy is quantified over the facts actually visible to the +participant under SEM-230 and ADR-099. Possible feedback includes approvals, +denials, edits, deferrals, audits, handoffs, interruptions, outputs, order, and +declared timing facts. Hidden policy, threshold, audit, monitor, or objective +details do not enter the participant view unless the profile declares them +visible. + +An audit budget is an evaluation-protocol coordinate unless the runtime +actually enforces it as a participant resource. Audit selection, trusted +editing, approval, defer-to-trusted, interruption, and shutdown are closed +protocol operations with explicit authority and evidence effects. + +Measures report safety, usefulness, attack success, false positives, audit +cost, intervention cost, uncertainty, limitations, and nonclaims separately. +A weighted aggregate cannot erase the components. + +Replay evidence is a digest-bound graph of existing episode, behavior, +control, crossing, action/result, experiment, and evidence refs. Hidden +objectives, credentials, private prompts, chain-of-thought, raw secrets, and +private model state remain outside portable evidence. + +## Boundary-faithful required cases + +### Injection + +An untrusted observation or tool result influences a structurally valid +proposal and action argument. The integrity influence reaches the final sink. +The sink denies unless the exact policy admits it or a governed endorsement +creates a fresh result. + +### Confidential exfiltration + +A confidential fact influences a valid tool argument, participant output, +error, or colluding participant. Confidentiality reaches every explicit sink. +The unauthorized destination receives no output without exact declassification +authority. + +### Adaptive monitor evasion + +An attack participant adapts to declared prior outcomes, monitor visibility, +threshold or budget knowledge, and correlated monitors. Monitor success cannot +bypass deterministic policy. Safety and usefulness are reported across the +declared strategy class. + +### Control-handoff manipulation + +Tainted context or external direction crosses a valid API-409 handoff and +induces a receiver proposal. Controller, authority, provenance, effective +labels, receiver admission, API-423 crossing, and final sink are checked at one +exact cut. Handoff grants neither trust nor action admission. + +Every denied case records zero prohibited `RuntimeTarget` calls and zero +participant/external disclosure. Tests also inspect append-only histories, +safe audit/error evidence, and replay. + +## Security and evidence boundary + +- Closed DTOs and request-size guards apply to portable bodies. Touched path, + query, and header values are separately bounded. +- Strict identity, target, role, participant, controller, audience, and + destination binding precedes semantic fact creation. +- Existing runtime-fact, action, API-409, API-423, snapshot, and transition + validators remain the owners of their relations. +- API-407 declared and effective support is deny-first. +- Expected failures use stable bounded diagnostics. Unexpected failures use + the redacted error envelope. +- Logs, diagnostics, audit, and evidence contain safe refs, digests, + classifications, counts, and bounded summaries, never raw confidential data, + prompts, credentials, private state, monitor internals, or hidden objectives. +- Portable semantics add no required environment variable, CLI flag, + subprocess, socket, daemon, sidecar, or host path. + +## Requirement allocation + +| Requirement | Ownership | +| --- | --- | +| SEM-233 | explicit-flow labels, derivation, release operations, sinks, and final decision | +| ASR-536 | intentional-subversion profile, protocol, measures, and evidence claims | +| SEM-230 | participant-relative projection, exact-cut policy, memory, strategies, and noninterference boundary | +| ACT-617 / API-409 | control authority and typed control occurrences | +| API-423 | portable crossing occurrences and order/context relation | +| RUN-310 / RUN-319 | authenticated mediation, persistence, replay, and reference-runtime enforcement | +| API-407 | declared/effective backend support, realization, downgrade, and conformance | +| ASR-535 | bounded flow falsification and evidence/claim discipline | + +SEM-233 and ASR-536 remain DRAFT until their downstream positive obligations +are satisfied. Issue #812 supplies design authority and an implementation +program only. + +## Nonclaims + +- No model-alignment or safe-internal-reasoning result. +- No chain-of-thought, prompt, private model state, or credential carriage. +- No automatic trust in a human, model, monitor, gateway, or backend. +- No protection for undeclared timing, storage, resource, steganographic, or + other covert channels. +- No universal noninterference, shielding, runtime, backend, or + intentional-subversion robustness result. +- No LLM-specific participant semantics, general taint framework, policy + engine, gateway, monitor service, trajectory store, or agent framework. + +## Implementation program + +The dependency-ordered implementation program and canonical issue ids are in +[`implementation-program.json`](../../../docs/research/adversarial-participant-control/implementation-program.json). diff --git a/specs/formal/participant-semantics/cross-backend-participant-control.md b/specs/formal/participant-semantics/cross-backend-participant-control.md new file mode 100644 index 000000000..7535670a5 --- /dev/null +++ b/specs/formal/participant-semantics/cross-backend-participant-control.md @@ -0,0 +1,521 @@ +# Mixed Cross-Backend Participant-Control Composition + +Requirements: SEM-234 and ASR-537. + +Status: DRAFT design. + +Issue: #813. + +This specification composes existing scenario-family, experiment/trial, +participant-control, crossing, time, backend-capability, and evidence +authorities. It defines no wire contract or positive runtime/backend claim. + +## 1. Domains + +Let: + +- \(S\) be an admitted backend-neutral instantiated scenario; +- \(P\) be its participants; +- \(E\) be participant episodes; +- \(U\) be stable compiled allocation units; +- \(C\) be admitted apparatus components; +- \(F\) be realization forms; +- \(A \subseteq U \times C\) be allocation; +- \(T = (C,X)\) be a directed composition topology with edges \(X\); +- \(\Phi = [\phi_0,\dots,\phi_n]\) be an optional finite phase schedule; +- \(K\) be the exact participant-control and crossing state cut; +- \(M\) be admitted cross-clock/order mappings; +- \(Q\) be the participant/audience policy and projection state; +- \(B\) be API-407 effective backend support; +- \(L\) be explicit mapping losses and limitations; and +- \(V\) be evidence and provenance. + +Realization forms are: + +```text +simulation +emulation-or-operational +hardware-or-native +federated-composition +``` + +Composition modes are: + +```text +alternative-realization +simultaneous-mixed-realization +``` + +Allocation units are: + +```text +participant-runtime +controlled-scope +action-family +observation-source +crossing-boundary +``` + +No backend name, adapter type, host, worker, or schedule position is an +allocation-unit identity. + +## 2. Authority decomposition + +For participant \(p\), episode \(e\), and cut \(K\), define: + +- \(\operatorname{controller}(p,e,K)\): one effective acting controller; +- \(\operatorname{authority}(p,e,K)\): authority basis and controlled scope; +- \(\operatorname{admit}(a,K)\): action-admission relation; +- \(\operatorname{provider}(u,\phi,K)\): admitted realization provider; +- \(\operatorname{owner}(o,\alpha,K)\): optional backend-native + object/attribute responsibility; +- \(\operatorname{route}(x,K)\): delivery addressing/transport; and +- \(\operatorname{release}(v,p,q,K)\): participant/audience disclosure + authority. + +These relations are pairwise non-substitutable: + +\[ +\operatorname{owner} \not\Rightarrow \operatorname{controller} +\] + +\[ +\operatorname{provider} \not\Rightarrow \operatorname{admit} +\] + +\[ +\operatorname{route} \not\Rightarrow \operatorname{release} +\] + +\[ +\operatorname{controller} \not\Rightarrow \operatorname{owner} +\] + +Revision 1 requires: + +\[ +|\operatorname{controller}(p,e,K)| = 1 +\] + +It defines no positive lease, simultaneous scoped-controller, joint, or fused +control relation. + +## 3. Backend-neutral authoring + +### MCB-001 — Portable scenario independence + +Scenario identity and membership are independent of \(A\), \(T\), \(\Phi\), +component manifests, and backend availability. + +### MCB-002 — Allocation authority + +Allocation is experiment/trial intent compiled after deterministic scenario +composition and before runtime execution. + +### MCB-003 — Stable allocation targets + +Every \(u \in U\) resolves through the canonical compiled-address authority and +has the same meaning across admitted realizations. + +### MCB-004 — No apparatus-created meaning + +An apparatus component may realize or refuse \(u\). It cannot create a +participant, controlled scope, action family, observation source, or crossing +that is absent from \(S\). + +## 4. Allocation + +### MCB-005 — Completeness + +Every required unit has an admitted provider: + +\[ +\forall u \in U_{\mathrm{required}},\ +\exists c \in C : (u,c) \in A +\] + +### MCB-006 — Effective eligibility + +\[ +(u,c) \in A +\Rightarrow +B(c,u) \geq \operatorname{requiredStrength}(u) +\] + +where \(B\) includes declared support, effective support, required contracts, +realization-envelope membership, limitations, downgrade, and conformance +evidence. + +### MCB-007 — Closed overlap + +If two providers cover the same unit, an accepted revisioned arbitration or +failover profile must define selection and failure. Revision 1 supplies no such +profile, so unexplained overlap is invalid. + +### MCB-008 — No runtime fallback + +A failed or unavailable provider does not authorize another component. +Fallback outside \(A\) is rejection. + +### MCB-009 — Schedule independence + +Allocation identity and sealed plan bytes do not depend on host, worker, +thread, queue, batching, completion order, retry count, wall time, or backend +availability. + +## 5. Composition topology + +Topology class is one of: + +```text +single-component +integrated +unified +federated-or-bridged +nested +``` + +For every edge \(x \in X\), require: + +```text +source component +destination component +adapter or bridge +allocated crossing scope +authority +action or observation mapping +participant/audience policy +release or declassification basis +source and destination clocks +time/order mapping +required support strength +mapping loss +failure behavior +evidence +``` + +### MCB-010 — Edge totality + +An exchange across components is admissible only when its edge fields resolve +to revision/digest-matched authority. + +### MCB-011 — Directionality + +An edge \(c_i \to c_j\) does not imply \(c_j \to c_i\). Bidirectional +interaction uses two directed edges or a closed bidirectional profile. + +### MCB-012 — Nested disclosure + +A nested component exposes its external allocation, edge/time/policy +capabilities, digest, internal-evidence ref, and limitations. Its internal +composition is not inferred by the parent. + +## 6. Control and responsibility transfer + +Transfer states are: + +```text +requested +offered +pending +committed +failed +expired +cancelled +stale +``` + +### MCB-013 — Commit establishes responsibility + +Requested, offered, or pending transfer does not alter effective provider or +controller state. Only an atomic revision-fenced `committed` occurrence does. + +### MCB-014 — Pull/push provenance + +Acquisition initiated by the candidate and transfer initiated by the current +provider retain different initiator/negotiation evidence even when both +converge on the same commit relation. + +### MCB-015 — Stale transition safety + +A controller, authority, policy, capability, state-revision, history-head, or +order mismatch yields `stale` and zero prohibited effects. + +### MCB-016 — No authority laundering + +Provider/owner transfer never changes participant identity, acting controller, +action authority, or disclosure authority by implication. + +### MCB-017 — Oscillation is not progress + +Repeated valid transfers require a bounded cooldown/retry or explicit +livelock/cycle disposition before any progress guarantee may be claimed. +Revision 1 makes no such guarantee. + +## 7. Information distribution + +### MCB-018 — Authorization before routing + +SEM-230/API-423 projection and release are resolved before publish/subscribe, +DDM, bridge filtering, directed delivery, or serialization. + +### MCB-019 — Filtering may only narrow + +For authorized projection \(R\) and bridge filter \(D\): + +\[ +D(R) \subseteq R +\] + +An adapter cannot add participant-visible information. + +### MCB-020 — Delivery stages remain distinct + +Addressing, request, decision, delivery attempt, delivery, observation, and +audit remain distinct occurrences. No earlier stage implies a later stage. + +### MCB-021 — Metadata projection + +The observer profile dispositions: + +```text +membership +subscription or class +region or destination +message size and cadence +synchronization +ownership/responsibility change +retraction +differential failure +``` + +Payload filtering does not establish metadata noninterference. + +### MCB-022 — Audit is a separate audience + +Authorized audit retention does not add a participant observation. + +## 8. Time and order + +Each component records: + +```text +clock identity and authority +time domain and unit +pacing or dilation +regulating or constrained role +advance request and grant behavior +lookahead +delivery order +serialization service +rollback or replay behavior +runtime readback +``` + +### MCB-023 — Cross-clock mapping + +Every edge between different clock domains has an admitted mapping \(M_{ij}\). +Without one, the relation is partial/unknown. + +### MCB-024 — Timestamp weakness + +Timestamps without governed mapping/order/readback support only +`disclosed_weak`. They do not establish causality or exact order. + +### MCB-025 — Backend serialization evidence + +`backend_serialized` requires a named clock, serialization service, runtime +readback, and conformance evidence. + +### MCB-026 — Staleness coordinates + +Staleness is evaluated over: + +```text +controller +authority +capability +policy revision +state revision +history heads +governed order +``` + +Wall-clock age can constrain but not replace those facts. + +### MCB-027 — Knowledge is append-only + +Rollback, replay, concealment, and retraction append occurrences. They do not +erase prior delivery or participant knowledge. + +## 9. Trial and phase realization + +### MCB-028 — Inter-trial change + +A realization change between trials creates a new admitted plan entry and run +id with source lineage. + +### MCB-029 — Derived model identity + +An emulation-derived simulator records source dataset/traces, generator and +profile revisions, model digest, coverage, unknown transitions, and +limitations. + +### MCB-030 — Finite within-run phases + +\(\Phi\) is finite and sealed before execution. Every possible component, +allocation, edge, clock mapping, policy, authority expectation, transition, +progress bound, and failure behavior resolves before plan sealing. + +### MCB-031 — Phase commit before effect + +The transition from \(\phi_i\) to \(\phi_{i+1}\) commits its exact state cut +before the next phase can cause effects. + +### MCB-032 — Phase history + +A transition appends prior/next phase, trigger/order, membership, +allocation, controller/authority/policy/time cuts, commit result, loss, and +evidence. + +### MCB-033 — Identity preservation + +A phase change does not rewrite plan id, plan-entry id, run id, prior control +or crossing histories, prior delivery, or participant knowledge. + +### MCB-034 — Unadmitted join + +A component absent from the sealed possible-membership set cannot join. + +## 10. Open and closed axes + +### MCB-035 — Control-loop posture + +`open-loop` permits observation/replay without external actuation. +`closed-loop` permits a candidate action to reach ordinary control, admission, +policy, capability, time/order, commit, and effect boundaries. The posture +does not grant authority. + +### MCB-036 — World assumption + +`closed-world` rejects unknown entities/actions/observations/mappings. +`bounded-open-world` acknowledges possible unknowns but keeps portable +vocabularies closed and treats unknown mappings as unsupported. + +### MCB-037 — Federation membership + +`fixed` keeps one active component set. +`pre-admitted-dynamic` follows \(\Phi\). No other dynamic membership is +admitted. + +The three axes are independent. + +## 11. Runtime effect boundary + +### MCB-038 — Exact-cut resolution + +Before any adapter call or disclosure, resolve: + +```text +authenticated caller and target +participant, controller, and audience +authority and action admission +allocation and active phase +component and adapter manifests +effective capability +policy and release +clock/order mapping +state revision and history heads +mapping loss and evidence expectations +``` + +### MCB-039 — Commit before effect + +The exact decision and predecessor histories commit atomically before the +effect or serialization. + +### MCB-040 — Zero prohibited effects + +Denial, stale cut, missing/unsupported mapping, failed admission, unsupported +capability, invalid phase, or failed commit produces: + +```text +zero prohibited backend calls +zero participant/external disclosures +unchanged prohibited effect state +append-only safe failure evidence +``` + +### MCB-041 — Adapter distrust + +Backend output is revalidated and mapped through safe diagnostics. Adapter +success cannot synthesize a portable success after a failed RAES gate. + +## 12. Evidence and claims + +ASR-537 evidence binds: + +```text +scenario and policy digests +plan, entry, coordinate, run, and replicate +participant, controller, and authority +apparatus and adapter manifests +allocation, topology, edges, and phase schedule +clocks, mappings, and realized order +capability and conformance +models, datasets, generators, seeds, and random streams +transformations, loss, uncertainty, and limitations +raw evidence, derived measures, and reproduction +``` + +### MCB-042 — Pure and mixed cases + +The protocol covers pure simulation, pure emulation/operation, simultaneous +mixed, inter-trial transition, and pre-admitted phase transition. + +### MCB-043 — Open and closed loops + +The protocol covers open-loop and closed-loop cases under the same profile +identities. + +### MCB-044 — Mandatory mismatches + +The protocol includes stale handoff, concurrent intervention, false/unsupported +capability, timestamp-only/unmapped order, simulation-only observation, +unrealizable action, directed-delivery failure, prior-delivery retraction, and +bridge-metadata leakage. + +### MCB-045 — Claim separation + +These claims remain distinct: + +```text +bounded conformance +interoperability readiness +empirical sim-to-em transfer +trace inclusion +bisimulation +IFC or noninterference +backend equivalence +``` + +Evidence for one does not satisfy another without an explicit governed +relation and binding. + +## 13. Nonclaims + +This design does not establish: + +- portable contract or runtime implementation; +- any backend-native realization; +- HLA, FMI, HELICS, EDL-FG, CybORG, CyGIL, CyberBattleSim, or digital-twin + compatibility; +- distributed, leased, simultaneous scoped-owner, or joint/fused controller + support; +- exact cross-clock order without admitted mappings; +- protection from undeclared covert channels; +- general interoperability; +- universal sim-to-em transfer; +- trace inclusion or bisimulation; +- IFC/noninterference; or +- cross-backend equivalence. diff --git a/specs/formal/participant-semantics/isabelle/Participant_Opacity.thy b/specs/formal/participant-semantics/isabelle/Participant_Opacity.thy new file mode 100644 index 000000000..1451d1060 --- /dev/null +++ b/specs/formal/participant-semantics/isabelle/Participant_Opacity.thy @@ -0,0 +1,388 @@ +theory Participant_Opacity + imports Main +begin + +section \Declared SEM-230 and SEM-231 profile coordinates\ + +datatype coordinate_revision = Declared_Coordinate + +record profile_coordinates = + model_and_carrier_coordinate :: coordinate_revision + observer_and_audience_coordinate :: coordinate_revision + initial_information_coordinate :: coordinate_revision + observation_projection_coordinate :: coordinate_revision + memory_coordinate :: coordinate_revision + exact_cut_and_horizon_coordinate :: coordinate_revision + active_strategy_domain_coordinate :: coordinate_revision + supervisor_visibility_coordinate :: coordinate_revision + policy_and_release_coordinate :: coordinate_revision + scheduler_and_environment_coordinate :: coordinate_revision + nondeterminism_support_coordinate :: coordinate_revision + time_and_progress_coordinate :: coordinate_revision + concurrency_and_order_coordinate :: coordinate_revision + probability_posture_coordinate :: coordinate_revision + +definition declared_coordinates :: profile_coordinates where + "declared_coordinates = + \model_and_carrier_coordinate = Declared_Coordinate, + observer_and_audience_coordinate = Declared_Coordinate, + initial_information_coordinate = Declared_Coordinate, + observation_projection_coordinate = Declared_Coordinate, + memory_coordinate = Declared_Coordinate, + exact_cut_and_horizon_coordinate = Declared_Coordinate, + active_strategy_domain_coordinate = Declared_Coordinate, + supervisor_visibility_coordinate = Declared_Coordinate, + policy_and_release_coordinate = Declared_Coordinate, + scheduler_and_environment_coordinate = Declared_Coordinate, + nondeterminism_support_coordinate = Declared_Coordinate, + time_and_progress_coordinate = Declared_Coordinate, + concurrency_and_order_coordinate = Declared_Coordinate, + probability_posture_coordinate = Declared_Coordinate\" + +record ('point, 'initial, 'observation, 'strategy) semantic_profile = + profile_carrier :: "'point set" + profile_initial_information :: "'point \ 'initial" + profile_observation :: "'point \ 'observation" + profile_strategy :: "'point \ 'strategy" + profile_strategy_domain :: "'strategy set" + profile_declared_coordinates :: profile_coordinates + +definition matching_profiles :: + "('point, 'initial, 'observation, 'strategy) semantic_profile \ + ('point, 'initial, 'observation, 'strategy) semantic_profile \ bool" where + "matching_profiles P Q \ + profile_carrier P = profile_carrier Q \ + profile_initial_information P = profile_initial_information Q \ + profile_observation P = profile_observation Q \ + profile_strategy P = profile_strategy Q \ + profile_strategy_domain P = profile_strategy_domain Q \ + profile_declared_coordinates P = profile_declared_coordinates Q" + +lemma matching_profiles_eq: + assumes "matching_profiles P Q" + shows "P = Q" + using assms by (cases P; cases Q; simp add: matching_profiles_def) + +section \SEM-231 information cells, knowledge, and opacity\ + +definition information_cell where + "information_cell P sigma x = + {y \ profile_carrier P. + profile_strategy P y = sigma \ + profile_initial_information P y = profile_initial_information P x \ + profile_observation P y = profile_observation P x}" + +definition participant_knows where + "participant_knows P Secret sigma x \ + information_cell P sigma x \ {y \ profile_carrier P. Secret y}" + +definition participant_opacity where + "participant_opacity P Secret \ + (\sigma \ profile_strategy_domain P. + \x \ profile_carrier P. + profile_strategy P x = sigma \ Secret x \ + (\y \ information_cell P sigma x. \ Secret y))" + +theorem participant_opacity_kernel: + "participant_opacity P Secret \ + (\sigma \ profile_strategy_domain P. + \x \ profile_carrier P. + profile_strategy P x = sigma \ Secret x \ + (\y \ information_cell P sigma x. \ Secret y))" + unfolding participant_opacity_def by simp + +lemma information_cell_reflexive: + assumes "x \ profile_carrier P" + and "profile_strategy P x = sigma" + shows "x \ information_cell P sigma x" + using assms unfolding information_cell_def by simp + +lemma participant_knowledge_is_factive: + assumes "x \ profile_carrier P" + and "profile_strategy P x = sigma" + and "participant_knows P Secret sigma x" + shows "Secret x" + using assms unfolding participant_knows_def information_cell_def by blast + +theorem participant_opacity_knowledge_characterization: + "participant_opacity P Secret \ + (\sigma \ profile_strategy_domain P. + \x \ profile_carrier P. + profile_strategy P x = sigma \ Secret x \ + \ participant_knows P Secret sigma x)" + unfolding participant_opacity_def participant_knows_def information_cell_def + by blast + +section \Conditional SEM-230 noninterference implication\ + +definition eligible_predicate where + "eligible_predicate P High_Match Secret \ + (\sigma \ profile_strategy_domain P. + \x \ profile_carrier P. + profile_strategy P x = sigma \ Secret x \ + (\y \ profile_carrier P. + profile_strategy P y = sigma \ + profile_initial_information P y = profile_initial_information P x \ + \ Secret y \ + (\z \ profile_carrier P. + profile_strategy P z = sigma \ High_Match y z \ \ Secret z)))" + +definition policy_noninterference where + "policy_noninterference P High_Match \ + (\sigma \ profile_strategy_domain P. + \x \ profile_carrier P. + profile_strategy P x = sigma \ + (\y \ profile_carrier P. + profile_strategy P y = sigma \ + profile_initial_information P y = profile_initial_information P x \ + (\z \ profile_carrier P. + profile_strategy P z = sigma \ + profile_initial_information P z = profile_initial_information P x \ + profile_observation P z = profile_observation P x \ + High_Match y z)))" + +theorem matching_policy_noninterference_implies_participant_opacity: + assumes "matching_profiles Noninterference_Profile Opacity_Profile" + and "eligible_predicate Noninterference_Profile High_Match Secret" + and "policy_noninterference Noninterference_Profile High_Match" + shows "participant_opacity Opacity_Profile Secret" +proof - + have profile_eq: "Opacity_Profile = Noninterference_Profile" + using assms(1) matching_profiles_eq by blast + have target: "participant_opacity Noninterference_Profile Secret" + unfolding participant_opacity_def + proof (intro ballI impI) + fix sigma x + assume sigma: "sigma \ profile_strategy_domain Noninterference_Profile" + assume point: "x \ profile_carrier Noninterference_Profile" + assume strategy: "profile_strategy Noninterference_Profile x = sigma" + assume secret: "Secret x" + from assms(2) sigma point strategy secret obtain y where y: + "y \ profile_carrier Noninterference_Profile" + "profile_strategy Noninterference_Profile y = sigma" + "profile_initial_information Noninterference_Profile y = + profile_initial_information Noninterference_Profile x" + "\ Secret y" + "\z \ profile_carrier Noninterference_Profile. + profile_strategy Noninterference_Profile z = sigma \ High_Match y z + \ \ Secret z" + unfolding eligible_predicate_def by blast + from assms(3) sigma point strategy y(1-3) obtain z where z: + "z \ profile_carrier Noninterference_Profile" + "profile_strategy Noninterference_Profile z = sigma" + "profile_initial_information Noninterference_Profile z = + profile_initial_information Noninterference_Profile x" + "profile_observation Noninterference_Profile z = + profile_observation Noninterference_Profile x" + "High_Match y z" + unfolding policy_noninterference_def by blast + show "\z \ information_cell Noninterference_Profile sigma x. \ Secret z" + unfolding information_cell_def using y(5) z by blast + qed + show ?thesis using profile_eq target by simp +qed + +section \Checked invalid-promotion boundaries\ + +definition opacity_without_noninterference_profile :: + "(bool \ bool, unit, bool, unit) semantic_profile" where + "opacity_without_noninterference_profile = + \profile_carrier = UNIV, + profile_initial_information = (\_. ()), + profile_observation = snd, + profile_strategy = (\_. ()), + profile_strategy_domain = {()}, + profile_declared_coordinates = declared_coordinates\" + +theorem opacity_does_not_imply_policy_noninterference: + "participant_opacity opacity_without_noninterference_profile fst \ + \ policy_noninterference opacity_without_noninterference_profile (=)" + unfolding participant_opacity_def information_cell_def policy_noninterference_def + opacity_without_noninterference_profile_def + by auto + +datatype pair_point = Paired_Secret | Paired_Witness | Uncovered_Secret + +fun pair_observation where + "pair_observation Paired_Secret = False" +| "pair_observation Paired_Witness = False" +| "pair_observation Uncovered_Secret = True" + +fun pair_secret where + "pair_secret Paired_Secret = True" +| "pair_secret Paired_Witness = False" +| "pair_secret Uncovered_Secret = True" + +definition one_pair_profile :: "(pair_point, unit, bool, unit) semantic_profile" where + "one_pair_profile = + \profile_carrier = UNIV, + profile_initial_information = (\_. ()), + profile_observation = pair_observation, + profile_strategy = (\_. ()), + profile_strategy_domain = {()}, + profile_declared_coordinates = declared_coordinates\" + +theorem one_equal_history_pair_is_insufficient: + "Paired_Witness \ information_cell one_pair_profile () Paired_Secret \ + \ pair_secret Paired_Witness \ + \ participant_opacity one_pair_profile pair_secret" + unfolding information_cell_def participant_opacity_def one_pair_profile_def + by (auto intro!: exI[where x=Uncovered_Secret]; + metis pair_point.exhaust pair_observation.simps pair_secret.simps) + +datatype release_point = Release_Secret | Release_Witness + +fun release_secret where + "release_secret Release_Secret = True" +| "release_secret Release_Witness = False" + +definition pre_release_profile :: "(release_point, unit, unit, unit) semantic_profile" where + "pre_release_profile = + \profile_carrier = UNIV, + profile_initial_information = (\_. ()), + profile_observation = (\_. ()), + profile_strategy = (\_. ()), + profile_strategy_domain = {()}, + profile_declared_coordinates = declared_coordinates\" + +definition post_release_profile :: "(release_point, unit, bool, unit) semantic_profile" where + "post_release_profile = + \profile_carrier = UNIV, + profile_initial_information = (\_. ()), + profile_observation = release_secret, + profile_strategy = (\_. ()), + profile_strategy_domain = {()}, + profile_declared_coordinates = declared_coordinates\" + +theorem declassification_can_change_information_and_knowledge: + "participant_opacity pre_release_profile release_secret \ + \ participant_knows pre_release_profile release_secret () Release_Secret \ + participant_knows post_release_profile release_secret () Release_Secret \ + \ participant_opacity post_release_profile release_secret" +proof - + have pre_witness: + "Release_Witness \ information_cell pre_release_profile () x" for x + unfolding information_cell_def pre_release_profile_def by simp + have pre_opacity: "participant_opacity pre_release_profile release_secret" + unfolding participant_opacity_def + proof (intro ballI impI) + fix sigma x + assume sigma_domain: "sigma \ profile_strategy_domain pre_release_profile" + assume "x \ profile_carrier pre_release_profile" + assume "profile_strategy pre_release_profile x = sigma" + assume "release_secret x" + have sigma: "sigma = ()" + using sigma_domain unfolding pre_release_profile_def by simp + show "\y \ information_cell pre_release_profile sigma x. + \ release_secret y" + proof (rule bexI[where x=Release_Witness]) + show "\ release_secret Release_Witness" by simp + show "Release_Witness \ information_cell pre_release_profile sigma x" + using pre_witness[of x] sigma by simp + qed + qed + have pre_not_known: + "\ participant_knows pre_release_profile release_secret () Release_Secret" + unfolding participant_knows_def + proof + assume known: + "information_cell pre_release_profile () Release_Secret \ + {y \ profile_carrier pre_release_profile. release_secret y}" + have + "Release_Witness \ + {y \ profile_carrier pre_release_profile. release_secret y}" + using known pre_witness[of Release_Secret] by auto + then show False by simp + qed + have post_cell: + "information_cell post_release_profile () Release_Secret = {Release_Secret}" + unfolding information_cell_def post_release_profile_def + by (rule set_eqI; rename_tac y; case_tac y; simp) + have post_known: + "participant_knows post_release_profile release_secret () Release_Secret" + unfolding participant_knows_def + apply (simp only: post_cell) + unfolding post_release_profile_def + by simp + have post_not_opacity: + "\ participant_opacity post_release_profile release_secret" + proof + assume opaque: "participant_opacity post_release_profile release_secret" + have + "\y \ information_cell post_release_profile () Release_Secret. + \ release_secret y" + using opaque[unfolded participant_opacity_def, rule_format, of "()" Release_Secret] + unfolding post_release_profile_def + by simp + with post_cell show False by simp + qed + show ?thesis using pre_opacity pre_not_known post_known post_not_opacity by simp +qed + +definition post_revocation_with_memory_profile :: + "(release_point, unit, bool, unit) semantic_profile" where + "post_revocation_with_memory_profile = post_release_profile" + +theorem revocation_does_not_erase_retained_observation: + "information_cell post_revocation_with_memory_profile () Release_Secret = + information_cell post_release_profile () Release_Secret \ + participant_knows post_revocation_with_memory_profile release_secret () Release_Secret" + unfolding post_revocation_with_memory_profile_def + using declassification_can_change_information_and_knowledge by simp + +definition empty_step :: "release_point \ release_point \ bool" where + "empty_step _ _ \ False" + +definition simulation where + "simulation Step R \ + (\p q p'. R p q \ Step p p' \ + (\q'. Step q q' \ R p' q'))" + +definition strong_bisimulation where + "strong_bisimulation Step R \ + simulation Step R \ simulation Step (\p q. R q p)" + +definition singleton_secret_profile :: + "(release_point, unit, unit, unit) semantic_profile" where + "singleton_secret_profile = + \profile_carrier = {Release_Secret}, + profile_initial_information = (\_. ()), + profile_observation = (\_. ()), + profile_strategy = (\_. ()), + profile_strategy_domain = {()}, + profile_declared_coordinates = declared_coordinates\" + +theorem behavioral_relations_without_preservation_do_not_imply_opacity: + "equiv UNIV Id \ + simulation empty_step (=) \ + strong_bisimulation empty_step (=) \ + \ participant_opacity singleton_secret_profile release_secret" + unfolding equiv_def refl_on_def sym_def trans_def + simulation_def strong_bisimulation_def empty_step_def + participant_opacity_def information_cell_def singleton_secret_profile_def + by auto + +definition coarse_observation_profile :: + "(release_point, unit, unit, unit) semantic_profile" where + "coarse_observation_profile = pre_release_profile" + +definition stronger_observation_profile :: + "(release_point, unit, bool, unit) semantic_profile" where + "stronger_observation_profile = post_release_profile" + +theorem untimed_individual_observation_does_not_imply_stronger_observation_opacity: + "participant_opacity coarse_observation_profile release_secret \ + \ participant_opacity stronger_observation_profile release_secret" + unfolding coarse_observation_profile_def stronger_observation_profile_def + using declassification_can_change_information_and_knowledge by simp + +definition secret_weight :: "release_point \ nat" where + "secret_weight p = (if p = Release_Secret then 9 else 1)" + +theorem possibilistic_opacity_does_not_imply_a_probability_bound: + "participant_opacity coarse_observation_profile release_secret \ + \ secret_weight Release_Secret \ secret_weight Release_Witness" + unfolding coarse_observation_profile_def secret_weight_def + using declassification_can_change_information_and_knowledge by simp + +end diff --git a/specs/formal/participant-semantics/isabelle/ROOT b/specs/formal/participant-semantics/isabelle/ROOT new file mode 100644 index 000000000..8d116856c --- /dev/null +++ b/specs/formal/participant-semantics/isabelle/ROOT @@ -0,0 +1,4 @@ +session Participant_Opacity = HOL + + options [document = false] + theories + Participant_Opacity diff --git a/specs/formal/participant-semantics/participant-opacity-proof-evidence.json b/specs/formal/participant-semantics/participant-opacity-proof-evidence.json new file mode 100644 index 000000000..ee3692254 --- /dev/null +++ b/specs/formal/participant-semantics/participant-opacity-proof-evidence.json @@ -0,0 +1,369 @@ +{ + "schema_version": "participant-opacity-proof-evidence/repo-v1", + "evidence_id": "participant-opacity-proof:sem-231/rev1", + "requirements": [ + "ASR-535", + "SEM-231" + ], + "taxonomy": { + "taxonomy_id": "raes-behavioral-relations", + "taxonomy_revision": "rev9", + "path": "contracts/concept-authority/behavioral-relations-v1.json", + "digest": "sha256:ec893a8464f6ddba89e5848c40dccc864ae555f95996d736dbc8f12d56afb971" + }, + "profiles": [ + { + "profile_id": "participant-opacity-theorem-v1", + "profile_revision": "sem-231-proof/rev1", + "path": "contracts/profiles/behavioral-relation/participant-opacity-theorem-v1.json", + "digest": "sha256:646a227f3cda814c666a1463c01e9a52c9dc1a89ec811f728da010ee938113bb" + } + ], + "semantic_sources": [ + { + "requirement": "SEM-230", + "revision": "policy-noninterference/current", + "path": "specs/formal/participant-semantics/information-flow-control.md", + "digest": "sha256:22e56877a1e439acdbe4e7c587e186f2420e06f366a4ab5875daa2bc5d63efb9" + }, + { + "requirement": "SEM-231", + "revision": "participant-predicate-opacity/rev8-baseline", + "path": "specs/formal/participant-semantics/participant-predicate-opacity.md", + "digest": "sha256:6916cdadb618df6149d3e8a3ea84f1c422890b50de005686bf15a32e20220c6e" + } + ], + "dependencies": [ + { + "issue": 810, + "artifact_revision": "adr-081/accepted", + "path": "docs/decisions/adrs/adr-081-behavioral-relation-taxonomy-and-claim-discipline.md", + "digest": "sha256:c8e096b85edb7ca97217a8bb0ac74b8817f966b9cf42b66f114dc3a45ed83a90", + "evidence_boundary": "The taxonomy and independent assurance axes are authority inputs, not proof premises." + }, + { + "issue": 961, + "artifact_revision": "participant-opacity-baseline-v1@sem-231/rev2", + "path": "contracts/profiles/behavioral-relation/history/participant-opacity-baseline-v1-sem-231-rev2.json", + "digest": "sha256:4b6a38cee8d8a80742f03db0e8ef808f505782e18efe315a1439a549faaceace", + "evidence_boundary": "The historical finite profile is a regression oracle and is not imported as a theorem premise." + }, + { + "issue": 962, + "artifact_revision": "participant-opacity-model-check-evidence-v1/rev8", + "path": "contracts/fixtures/formal-analysis/participant-opacity-model-check-evidence-v1/valid/opaque-transition-model.json", + "digest": "sha256:074a5a57b445426a37209bcc928a0dd1ba72a6b6709f3524aaef0e7b1bb692f7", + "evidence_boundary": "The exact finite model-check result is agreement evidence and is not imported as an axiom or proof certificate." + } + ], + "assumptions": [ + { + "assumption_id": "active-same-strategy", + "statement": "The active-strategy quantifier is outside each actual-point obligation, and actual, seed, and selected alternative points use the same admitted strategy." + }, + { + "assumption_id": "complete-low-history-support", + "statement": "SEM-230 policy noninterference supplies a complete equal-initial-information and equal-observation support alternative for every admitted actual point and eligible high variation." + }, + { + "assumption_id": "eligible-label-preservation", + "statement": "Every alternative selected through the declared High_Match correspondence preserves the seed point's nonsecret predicate label." + }, + { + "assumption_id": "eligible-nonsecret-public-class-variation", + "statement": "Every protected actual point has a reachable nonsecret high variation in the same public initial-information class and admitted active strategy." + }, + { + "assumption_id": "exact-information-cell", + "statement": "Knowledge and opacity use exactly the admitted carrier points with the same active strategy, initial public information, and complete accumulated observation." + }, + { + "assumption_id": "matching-profile-coordinates", + "statement": "The SEM-230 and SEM-231 instances have the same model and carrier, observer and audience, initial information, complete observation, memory, exact cut and horizon, active-strategy domain, supervisor visibility, policy and release schedule, scheduler and environment, nondeterminism support, time and progress, concurrency and order, and probability posture." + }, + { + "assumption_id": "reachable-alternative", + "statement": "Every nonsecret seed and noninterference-selected witness remains inside the declared reachable carrier." + }, + { + "assumption_id": "retained-memory-no-erasure", + "statement": "Concealment or revocation does not erase a retained observation; any memory reset would require a separately declared semantic profile." + } + ], + "positive_theorems": [ + { + "theorem_id": "matching_policy_noninterference_implies_participant_opacity", + "statement": "For an eligible predicate and exactly matching SEM-230 and SEM-231 profiles, policy noninterference implies participant predicate opacity.", + "claim": { + "taxonomy_id": "raes-behavioral-relations", + "taxonomy_revision": "rev9", + "relation_id": "participant-predicate-opacity", + "subject": "The conditional implication from a matching SEM-230 policy-noninterference instance to SEM-231 participant-predicate opacity for an eligible predicate.", + "left_carrier_ref": "possible-point-carrier:sem-231-abstract-v1", + "right_carrier_ref": null, + "observation_projection_ref": "participant-opacity-observation:sem-230-complete-support-v1", + "observation_projection_revision": "rev1", + "relation_parameter_profile_ref": "participant-opacity-theorem-v1", + "relation_parameter_profile_revision": "sem-231-proof/rev1", + "quantifier_scope": "all-strategies", + "evidence_scope": "proof", + "assurance_axis": "proof", + "evidence_boundary": "Only the abstract theorem profile under every declared matching-profile, eligible-predicate, reachability, support, strategy, release, memory, scheduler, environment, time, order, and probability-posture assumption.", + "assurance_status": "proved", + "evidence_refs": [ + "specs/formal/participant-semantics/participant-opacity-proof-evidence.json", + "specs/formal/participant-semantics/isabelle/Participant_Opacity.thy", + "isabelle-theorem:matching_policy_noninterference_implies_participant_opacity" + ], + "limitations": [ + "The implication is conditional on exact profile matching and the eligible-predicate premises.", + "No concrete RAES system, runtime, deployment, or backend is instantiated." + ], + "explicit_non_claims": [ + "No reverse implication from predicate opacity to policy noninterference.", + "No timed, probabilistic, quantitative, coalition, all-linearization, partial-order, progress-sensitive, runtime-enforcement, supervisor-synthesis, backend-realization, or backend-conformance result." + ] + } + }, + { + "theorem_id": "participant_opacity_kernel", + "statement": "SEM-231 one-sided active participant opacity holds exactly when every admitted actual secret point has a nonsecret point in its exact information cell under the same strategy.", + "claim": { + "taxonomy_id": "raes-behavioral-relations", + "taxonomy_revision": "rev9", + "relation_id": "participant-predicate-opacity", + "subject": "The SEM-231 one-sided active-strategy participant-predicate-opacity kernel over the abstract declared possible-point carrier.", + "left_carrier_ref": "possible-point-carrier:sem-231-abstract-v1", + "right_carrier_ref": null, + "observation_projection_ref": "participant-opacity-observation:sem-230-complete-support-v1", + "observation_projection_revision": "rev1", + "relation_parameter_profile_ref": "participant-opacity-theorem-v1", + "relation_parameter_profile_revision": "sem-231-proof/rev1", + "quantifier_scope": "all-strategies", + "evidence_scope": "proof", + "assurance_axis": "proof", + "evidence_boundary": "Only the abstract one-sided possibilistic, untimed, progress-insensitive, individual-observer, total-order theorem profile and its exact information-cell definition.", + "assurance_status": "proved", + "evidence_refs": [ + "specs/formal/participant-semantics/participant-opacity-proof-evidence.json", + "specs/formal/participant-semantics/isabelle/Participant_Opacity.thy", + "isabelle-theorem:participant_opacity_kernel" + ], + "limitations": [ + "The carrier and semantic functions are abstract and parameterized.", + "No concrete RAES system, runtime, deployment, or backend is instantiated." + ], + "explicit_non_claims": [ + "No symmetric opacity or guarantee for learning that the predicate is false.", + "No timed, probabilistic, quantitative, coalition, all-linearization, partial-order, progress-sensitive, runtime-enforcement, supervisor-synthesis, backend-realization, or backend-conformance result." + ] + } + }, + { + "theorem_id": "participant_opacity_knowledge_characterization", + "statement": "SEM-231 participant opacity is equivalent to the absence of knowledge that the protected one-sided predicate is true at every admitted actual secret point.", + "claim": { + "taxonomy_id": "raes-behavioral-relations", + "taxonomy_revision": "rev9", + "relation_id": "participant-predicate-opacity", + "subject": "The knowledge characterization of SEM-231 one-sided participant-predicate opacity over the exact information cell.", + "left_carrier_ref": "possible-point-carrier:sem-231-abstract-v1", + "right_carrier_ref": null, + "observation_projection_ref": "participant-opacity-observation:sem-230-complete-support-v1", + "observation_projection_revision": "rev1", + "relation_parameter_profile_ref": "participant-opacity-theorem-v1", + "relation_parameter_profile_revision": "sem-231-proof/rev1", + "quantifier_scope": "all-strategies", + "evidence_scope": "proof", + "assurance_axis": "proof", + "evidence_boundary": "Only knowledge defined by subset containment over the exact same-strategy information cell, whose reflexivity and factivity are separately kernel-checked.", + "assurance_status": "proved", + "evidence_refs": [ + "specs/formal/participant-semantics/participant-opacity-proof-evidence.json", + "specs/formal/participant-semantics/isabelle/Participant_Opacity.thy", + "isabelle-theorem:participant_opacity_knowledge_characterization" + ], + "limitations": [ + "The characterization is one-sided and permits knowledge that the predicate is false.", + "No arbitrary accessibility relation is assumed to be an information cell." + ], + "explicit_non_claims": [ + "Epistemic indistinguishability is information-cell membership and is not itself opacity.", + "No timed, probabilistic, quantitative, coalition, all-linearization, partial-order, progress-sensitive, runtime-enforcement, supervisor-synthesis, backend-realization, or backend-conformance result." + ] + } + } + ], + "supporting_theorems": [ + { + "theorem_id": "information_cell_reflexive", + "statement": "Every admitted point using the selected strategy belongs to its own exact information cell." + }, + { + "theorem_id": "participant_knowledge_is_factive", + "statement": "Knowledge defined over the exact reflexive information cell is factive at every admitted actual point." + } + ], + "negative_theorems": [ + { + "theorem_id": "behavioral_relations_without_preservation_do_not_imply_opacity", + "statement": "Equivalence, simulation, and strong bisimulation can hold on a transition carrier while participant opacity fails when no secret- and observation-preservation premise supplies a nonsecret alternative.", + "mutation_id": "SEM231-MUT-RELATION-SUBSTITUTION" + }, + { + "theorem_id": "declassification_can_change_information_and_knowledge", + "statement": "A release observation can split a formerly opaque information cell, establish knowledge, and falsify post-release opacity.", + "mutation_id": "SEM231-MUT-DECLASSIFICATION" + }, + { + "theorem_id": "one_equal_history_pair_is_insufficient", + "statement": "One secret/nonsecret equal-observation pair leaves another secret point uncovered and does not satisfy universal participant opacity.", + "mutation_id": "SEM231-MUT-ONE-PAIR" + }, + { + "theorem_id": "opacity_does_not_imply_policy_noninterference", + "statement": "One selected predicate can be opaque while complete policy noninterference fails for another high variation.", + "mutation_id": "SEM231-MUT-OPACITY-TO-NONINTERFERENCE" + }, + { + "theorem_id": "possibilistic_opacity_does_not_imply_a_probability_bound", + "statement": "A possibilistically opaque carrier can assign greater weight to its secret point and therefore supplies no quantitative probability bound.", + "mutation_id": "SEM231-MUT-PROBABILITY-PROMOTION" + }, + { + "theorem_id": "revocation_does_not_erase_retained_observation", + "statement": "A post-revocation profile with retained memory has the same revealing information cell and knowledge as the post-release profile.", + "mutation_id": "SEM231-MUT-REVOCATION-MEMORY" + }, + { + "theorem_id": "untimed_individual_observation_does_not_imply_stronger_observation_opacity", + "statement": "Opacity under a coarse untimed individual observation does not imply opacity under a stronger observation such as timing, fused coalition, progress, or order information.", + "mutation_id": "SEM231-MUT-STRONGER-OBSERVATION" + } + ], + "toolchain": { + "prover": "Isabelle/HOL", + "version": "Isabelle2025-2", + "archive_url": "https://www.cl.cam.ac.uk/research/hvg/Isabelle/dist/Isabelle2025-2_linux.tar.gz", + "archive_sha256": "sha256:a20a507bc7c1270d8be96a9f3fbec06345387789d2dc2c4d3df6260d47bfb33c", + "archive_bytes": 1228480874, + "acquire_command": [ + "uv", + "run", + "--project", + "implementations/python", + "--frozen", + "python", + "-m", + "tools.isabelle_tool", + "acquire" + ], + "replay_command": [ + "uv", + "run", + "--project", + "implementations/python", + "--frozen", + "python", + "-m", + "tools.check_participant_opacity_proof" + ], + "working_directory": ".", + "locale": "C.UTF-8", + "platform_boundary": "linux-x86_64", + "network": "explicit-acquire-only; replay-blocked-by-bubblewrap-network-namespace", + "filesystem": "allowlisted-runtime-session-and-private-state-only", + "limits": { + "wall_seconds": 600, + "cpu_seconds": 600, + "threads": 2, + "max_output_bytes": 65536, + "max_file_bytes": 4294967296, + "max_address_space_mib_per_process": 32768, + "java_max_heap_mib": 2048, + "ml_max_heap_mib": 2048, + "memory_scope": "per-process-address-space-and-per-runtime-heaps-not-aggregate-tree", + "generated_artifact_retention": "none" + }, + "tool_sources": [ + { + "path": "tools/check_participant_opacity_proof.py", + "digest": "sha256:21cb9b25a921bb02616d74ee19a9c150e4ddb857a01eccab60fe3d2de30c0554" + }, + { + "path": "tools/isabelle_tool.py", + "digest": "sha256:5100ea993e91b07bb3ac764642fd6ca110e477882b35aba5c49403f314133c85" + } + ] + }, + "session": { + "session_id": "Participant_Opacity", + "root_path": "specs/formal/participant-semantics/isabelle/ROOT", + "root_digest": "sha256:9b1646b56177b1129fffe9a72d44ebf257b0695e446b215ac3eab06fbebcd87e", + "theory_path": "specs/formal/participant-semantics/isabelle/Participant_Opacity.thy", + "theory_digest": "sha256:0d7d268ebabb41ce7f13d167b47e54285ccd10d53f93f0357e4d23f552ee414d", + "imports": [ + "Main" + ], + "forbidden_features": [ + "axiomatization", + "axioms", + "nitpick", + "oops", + "oracle", + "quick_and_dirty", + "skip_proofs", + "sorry" + ], + "generated_artifacts": [] + }, + "kernel_result": { + "prover": "Isabelle/HOL", + "prover_version": "Isabelle2025-2", + "session": "Participant_Opacity", + "result": "kernel-checked", + "network": "blocked-by-bubblewrap-network-namespace", + "filesystem": "allowlisted-runtime-session-and-private-state-only", + "locale": "C.UTF-8", + "platform_boundary": "linux-x86_64", + "result_digest": "sha256:6ad5778c78667a992cca5b958ebc0764f8880115de4ac2f99f22ec6883400325" + }, + "independent_reproduction": { + "command": [ + "uv", + "run", + "--project", + "implementations/python", + "--frozen", + "python", + "-m", + "tools.check_participant_opacity_proof" + ], + "working_directory": ".", + "result": { + "prover": "Isabelle/HOL", + "prover_version": "Isabelle2025-2", + "session": "Participant_Opacity", + "result": "kernel-checked", + "network": "blocked-by-bubblewrap-network-namespace", + "filesystem": "allowlisted-runtime-session-and-private-state-only", + "locale": "C.UTF-8", + "platform_boundary": "linux-x86_64", + "result_digest": "sha256:6ad5778c78667a992cca5b958ebc0764f8880115de4ac2f99f22ec6883400325" + }, + "reproduced_on": "2026-07-31" + }, + "limitations": [ + "The proof is parameterized over abstract possible points and semantic functions and is conditional on the declared matching-profile and eligible-predicate assumptions.", + "The proof does not establish correspondence between the Isabelle definitions and the Python bounded or finite-state model-checking implementation.", + "Memory limits are per-process virtual address space and per-runtime Java and ML heaps; they are not aggregate process-tree or cgroup accounting.", + "The proof profile is one-sided, possibilistic, untimed, progress-insensitive, active-strategy, individual-observer, and total-order." + ], + "explicit_non_claims": [ + "No opacity claim for RAES as a whole, RUN-319, a concrete runtime, deployment, participant, supervisor, policy instance, or backend.", + "No reverse implication from predicate opacity to policy noninterference, and no universal result from one equal-history pair.", + "No erasure of retained knowledge through concealment, revocation, reset, rollback, or supersession.", + "No automatic implication from epistemic indistinguishability, trace equivalence, simulation, refinement, or bisimulation without separately proved secret, reachability, and observation preservation.", + "No symmetric, timed, probabilistic, quantitative, coalition, all-linearization, partial-order, progress-sensitive, runtime-enforcement, supervisor-synthesis, backend-declaration, backend-realization, or backend-conformance result." + ] +} diff --git a/specs/formal/participant-semantics/participant-predicate-opacity.md b/specs/formal/participant-semantics/participant-predicate-opacity.md index 9deddbe52..dd8a20bdd 100644 --- a/specs/formal/participant-semantics/participant-predicate-opacity.md +++ b/specs/formal/participant-semantics/participant-predicate-opacity.md @@ -9,7 +9,7 @@ Decision: [ADR-099](../../../docs/decisions/adrs/adr-099-participant-relative-pr Machine-readable relation authority: `contracts/concept-authority/behavioral-relations-v1.json`, `participant-predicate-opacity`, introduced in taxonomy revision `rev5` and -carried by current revision `rev8`. +carried by current revision `rev9`. ## Scope @@ -255,6 +255,38 @@ unless the new policy stops protecting it or another nonsecret alternative remains. Later concealment does not erase what a remembering participant learned. +## Mathematical Proof Profile + +The `Participant_Opacity` Isabelle/HOL session under +[`isabelle/`](isabelle/) kernel-checks three positive theorem scopes for +`participant-opacity-theorem-v1@sem-231-proof/rev1`: + +1. the one-sided active-strategy SEM-231 opacity kernel; +2. the equivalence between opacity and absence of knowledge that the selected + predicate is true, using the exact reflexive and factive information cell; + and +3. the conditional implication from SEM-230 policy noninterference to SEM-231 + opacity for an eligible predicate under exactly matching profiles. + +The implication assumes the same model and reachable carrier, observer and +audience, initial information, complete observation, memory, exact cut and +horizon, active strategy, supervisor visibility, policy and release schedule, +scheduler and environment, nondeterminism support, time and progress, +concurrency and order, and probability posture. Eligibility supplies a +reachable nonsecret variation in every protected public class and preserves +that nonsecret label through the noninterference-selected correspondence. + +The same session checks countermodels for the reverse implication, one-pair +promotion, declassification, retained memory after revocation, relation +substitution without preservation, stronger observations, and probabilistic +promotion. The closed +[`participant-opacity-proof-evidence.json`](participant-opacity-proof-evidence.json) +binds theorem ids, assumptions, proof-axis claims, source and dependency +digests, the pinned Isabelle distribution, offline replay, resource limits, +and the independently reproduced kernel result. It does not instantiate RAES, +a runtime, a deployment, or a backend, and it establishes no correspondence +theorem for the Python finite-analysis implementation. + ## Independent Assurance Lanes Assurance states are independent: @@ -265,7 +297,7 @@ Assurance states are independent: | checker | closed profile resolution, exact finite carrier admission, deterministic exhaustive scan, replay | implemented | | bounded testing | named finite profiles/cases, full bounds, digests, safe counterexamples | bounded | | model checking | closed finite model, explored bounds, pinned tool/version, result or counterexample | model checked for the exact baseline fixture model | -| mathematical proof | theorem, assumptions, independently checkable proof, tool/digest when mechanized | deliberately unproved | +| mathematical proof | theorem, assumptions, independently checkable proof, tool/digest when mechanized | proved for the abstract conditional theorem profile; no concrete RAES instance | | runtime enforcement | complete supported-channel inventory, fail-closed mediation, durable decisions, security tests | not enforced | | backend declaration | API-407 feature strength, required contracts, limitations, evidence refs | not declared | | backend realization | native implementation, profile mapping, environment and provenance evidence | not realized | @@ -308,9 +340,9 @@ positive assurance axis. Issue #810 defines this architecture. Issue #961 delivers the closed baseline profile and bounded finite falsifier. Issue #962 delivers exact finite-state -model checking for the baseline fixture profile. Issues #963 through #965 -separately own mathematical proof, runtime enforcement, and backend -realization/conformance. +model checking for the historical baseline fixture profile. Issue #963 +delivers the abstract conditional mathematical proof. Issues #964 and #965 +separately own runtime enforcement and backend realization/conformance. ## Bounded Checker Contract diff --git a/specs/sdl/initial-service-state.md b/specs/sdl/initial-service-state.md index 77128ae42..f61660738 100644 --- a/specs/sdl/initial-service-state.md +++ b/specs/sdl/initial-service-state.md @@ -22,7 +22,14 @@ named service is materially different from node placement. ## 2. Service Materialization Binding -`service_materialization` is a closed object with these fields: +`service_materialization` is a closed discriminated profile. Every profile +shares the target, ownership, ordering, assertion, evidence, and observation +references below. + +### 2.1 Owned Content Profile + +The `service-content` version `"1"` profile is a closed object with these +fields: | Field | Shape | Requirement | |---|---|---| @@ -38,6 +45,36 @@ named service is materially different from node placement. | `evidence_requirement_refs` | non-empty unique evidence-requirement references | REQUIRED | | `observation_boundary_refs` | non-empty unique participant-observation-boundary references | REQUIRED | +### 2.2 Search-Index Field-Schema Profile + +The `service-search-index-schema` version `"1"` profile expresses schema-only +desired state for a service-owned search index: + +| Field | Shape | Requirement | +|---|---|---| +| `interface_profile` | literal `service-search-index-schema` | REQUIRED discriminator | +| `profile_version` | literal `"1"` | OPTIONAL; defaults to the literal | +| `requirements.operation` | literal `ensure-search-index-field-schema` | REQUIRED | +| `requirements.conflict_policy` | literal `reject-unowned-collision` | REQUIRED | +| `requirements.readback` | literal `canonical-portable-field-schema-digest` | REQUIRED | +| `requirements.field_semantics` | non-empty portable field-name map | REQUIRED | + +Every map value is one of: + +- `exact-token`: equality or term matching without analysis or tokenization; +- `full-text`: analyzed or tokenized text search; +- `integer`: integral numeric comparison; +- `temporal`: date/time comparison through the backend's portable projection; + or +- `boolean`: two-valued boolean comparison. + +This profile uses `type: dataset` without `source` or `items`. It establishes +the exact portable semantic of every declared top-level field. Undeclared +native fields are outside the version 1 claim. A missing, ambiguous, or weaker +declared field fails reconciliation. Vendor literals, raw mappings, analyzers, +native index names, endpoints, queries, credentials, and arbitrary options are +not valid SDL. + `content.target` remains the owning VM node. `target_service_ref` MUST resolve to an exact `nodes..services.` declaration on that same VM. Every ordering reference MUST resolve to another content declaration; @@ -66,6 +103,8 @@ MUST retain: - exact service and owning-node addresses; - interface profile, profile version, and exact operation requirements; - canonical content digest; +- for the search-index profile, the portable field map and its separate RFC + 8785/JCS canonical field-schema digest; - derived tenant ownership and the shared-service relationship reference; - content ordering; - readback assertion addresses; and @@ -76,11 +115,14 @@ The owning node and ordered content placements are provisioning dependencies. No separate plan, lifecycle engine, scheduler, result store, or reset authority is created. -The provisioner manifest capability term `service-content-v1` in -`supported_service_materialization_profiles` is independent of -`supported_content_types`. Admission requires the content type, exact -interface/profile version, and exact requirements. A claimed profile also -requires a realization-envelope +The provisioner manifest capability terms `service-content-v1` and +`service-search-index-schema-v1` in +`supported_service_materialization_profiles` are independent of +`supported_content_types`. The latter claims the complete closed version 1 +field-semantic set; partial support cannot advertise it. Admission requires the +content type, exact interface/profile version, exact requirements, a +recomputed digest, and profile-specific SEM-218 exact-requirement support. A +claimed profile also requires a realization-envelope `content-placement` concern with `realized` disposition and at least `daemon-observed` independent readback. Missing support is fatal before backend I/O. Direct plan submission MUST repeat these checks. @@ -88,10 +130,13 @@ I/O. Direct plan submission MUST repeat these checks. ## 4. Backend Conformance And Equivalence RAES standardizes the portable profile without selecting a product or backend. -A backend MAY claim `service-content-v1` only when its own conformance evidence -demonstrates native materialization through the RAES control path, fresh -independent readback, reset ownership, and the declared participant projection. -A manifest claim is not execution evidence. +A backend MAY claim either standardized profile only when its own conformance +evidence demonstrates native materialization through the RAES control path, +fresh independent readback, reset ownership, and the declared participant +projection. For the search-index profile, native readback projects exactly the +declared field names back to the portable semantic set before digest comparison. +A mutation acknowledgement, returned desired-state snapshot, cached mapping, or +manifest claim is not execution evidence. Two realizations are equivalent only with respect to the admitted portable contract and declared participant-visible assertions/evidence. They need not diff --git a/specs/sdl/references.md b/specs/sdl/references.md index 53ce2d303..557021420 100644 --- a/specs/sdl/references.md +++ b/specs/sdl/references.md @@ -141,6 +141,7 @@ probe implementations; propositions and assertions carry portable truth. | `content` | `service_materialization.readback_assertion_refs[]` | `assertions` | | `content` | `service_materialization.evidence_requirement_refs[]` | `evidence_requirements` | | `content` | `service_materialization.observation_boundary_refs[]` | `observation_boundaries` | +| `content` | `service_materialization.requirements.field_semantics` keys and values | concrete portable values, not references | | `generated_artifacts` | consumers[].node | `nodes` | | `generated_artifacts` | ordering/refresh dependencies | `generated_artifacts` / `persistent_volumes` (acyclic ordering) | | `persistent_volumes` | consumers[].node | `nodes` | diff --git a/specs/sdl/stateful-resources.md b/specs/sdl/stateful-resources.md index d5db686d7..3e3d900d9 100644 --- a/specs/sdl/stateful-resources.md +++ b/specs/sdl/stateful-resources.md @@ -15,14 +15,67 @@ provisioning address: ## Generated artifacts -A generated artifact declares a `certificate_bundle` or `rendered_config` -generator, its regeneration lifecycle, non-secret provenance, the complete -output set, and every consumer. Each output carries a contained relative path -and a sensitivity class (`public`, `restricted`, or `secret`). The contract -contains desired metadata only; secret values and rendered bytes never enter -SDL, plans, diagnostics, or provenance. Output paths use one canonical POSIX -relative-path spelling. Generated artifacts are immutable inputs to consumers; -every consumer therefore declares `read_only` access. +A generated artifact declares a `certificate_bundle`, `rendered_config`, or +`ssh_key_bundle` generator, its regeneration lifecycle, non-secret provenance, +the complete output set, and every consumer. `ssh_key_bundle` is generated SSH +key/access material; it is separate from X.509 certificate bundles and runtime +SSH server configuration. + +Each output carries a contained relative path, a sensitivity class (`public`, +`restricted`, or `secret`), and a distribution disposition: + +- `consumer_selected` allows read-only projection to consumers that name the + output in `selected_outputs`; +- `producer_private` keeps the output within backend-owned producer state and + cannot be selected by a consumer. + +SSH artifact consumers must select at least one declared, non-private output. +Selections are unique, and every `consumer_selected` SSH output must be selected +by at least one consumer. Existing certificate/config declarations that omit +`selected_outputs` retain their compatibility meaning: all non-private outputs +are available to that consumer. An explicitly present selection must contain at +least one output; an empty list is invalid. New declarations should select +outputs explicitly. + +For example, one SSH artifact can keep a private key producer-private while +projecting only its public forms: + +```yaml +generated_artifacts: + operator-access: + generator: ssh_key_bundle + lifecycle: regenerate_on_change + provenance: access/operator-ssh.yml + outputs: + - name: private-key + path: id_ed25519 + sensitivity: secret + disposition: producer_private + - name: public-key + path: id_ed25519.pub + sensitivity: public + disposition: consumer_selected + - name: authorized-keys + path: authorized_keys + sensitivity: restricted + disposition: consumer_selected + consumers: + - node: bastion + mount_destination: /run/raes/ssh + access_mode: read_only + selected_outputs: [public-key] + - node: workstation + mount_destination: /home/operator/.ssh + access_mode: read_only + selected_outputs: [authorized-keys] +``` + +The contract contains desired metadata only; key values and rendered bytes +never enter SDL, plans, snapshots, diagnostics, or provenance. Output paths use +one canonical POSIX relative-path spelling. Generated artifacts are immutable +inputs to consumers; every consumer therefore declares `read_only` access. +Output selection changes only a consumer projection: generation, lifecycle, +provenance, dependencies, reconciliation, and deletion remain artifact-wide. ## Persistent volumes @@ -44,7 +97,10 @@ The compiler preserves each declaration as an exact SEM-218 realization requirement and emits its typed payload into the provisioning plan. Backends must either honor the complete declared resource or reject the plan; silently substituting an observed mount, generic content placement, or provider-private -configuration is not conformant. +configuration is not conformant. A provisioner that supports generated +artifacts also declares every supported generator in +`supported_generated_artifact_kinds`; the coarse support flag alone does not +authorize an unlisted kind. Published JSON Schemas reject exact duplicate collection members. Relational uniqueness, cross-resource reference resolution, mount ownership, and access diff --git a/tools/check_autonomous_behavior_vocabularies.py b/tools/check_autonomous_behavior_vocabularies.py new file mode 100644 index 000000000..38bc4a662 --- /dev/null +++ b/tools/check_autonomous_behavior_vocabularies.py @@ -0,0 +1,266 @@ +#!/usr/bin/env python3 +"""Validate the ACT-611 autonomous behavior vocabulary source snapshots.""" + +from __future__ import annotations + +import argparse +import hashlib +import json +import re +import sys +import urllib.parse +import urllib.request +from pathlib import Path +from typing import Any + +REPO_ROOT = Path(__file__).resolve().parents[1] +if str(REPO_ROOT) not in sys.path: + sys.path.insert(0, str(REPO_ROOT)) + +from raes_contracts.contracts import ( # noqa: E402 + ActivityStreamsActivityTypesSourceModel, + FipaCommunicativeActsSourceModel, +) + +ACTIVITYSTREAMS_RELATIVE_PATH = "contracts/concept-authority/w3c-activitystreams-activity-types-source-v1.json" +ACTIVITYSTREAMS_AUTHORITY = "World Wide Web Consortium" +ACTIVITYSTREAMS_VERSION = "REC-activitystreams-vocabulary-20170523" +ACTIVITYSTREAMS_STATUS = "W3C Recommendation" +ACTIVITYSTREAMS_URL = "https://www.w3.org/TR/2017/REC-activitystreams-vocabulary-20170523/" +ACTIVITYSTREAMS_DIGEST = "sha256:1418443392160f4bb23dffb5727f5216d1f56d3430377dc67d364016521401db" +ACTIVITYSTREAMS_LATEST_URL = "https://www.w3.org/TR/activitystreams-vocabulary/" +ACTIVITYSTREAMS_CORE_URL = "https://www.w3.org/TR/2017/REC-activitystreams-core-20170523/" +ACTIVITYSTREAMS_LICENSE_URL = "https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document" +ACTIVITYSTREAMS_LICENSE_NOTICE = ( + "Copyright © 2017 Activity Streams Working Group, IBM & SAP SE; W3C permissive document license applies." +) +ACTIVITYSTREAMS_TYPES = ( + "Accept", + "Add", + "Announce", + "Arrive", + "Block", + "Create", + "Delete", + "Dislike", + "Flag", + "Follow", + "Ignore", + "Invite", + "Join", + "Leave", + "Like", + "Listen", + "Move", + "Offer", + "Question", + "Reject", + "Read", + "Remove", + "TentativeReject", + "TentativeAccept", + "Travel", + "Undo", + "Update", + "View", +) + +FIPA_RELATIVE_PATH = "contracts/concept-authority/fipa-communicative-acts-source-v1.json" +FIPA_AUTHORITY = "Foundation for Intelligent Physical Agents" +FIPA_VERSION = "SC00037J-2002-12-03" +FIPA_STATUS = "Standard" +FIPA_URL = "https://www.fipa.org/specs/fipa00037/SC00037J.html" +FIPA_ARTIFACT_URL = "https://www.fipa.org/specs/fipa00037/SC00037J.pdf" +FIPA_DIGEST = "sha256:90b3277247ef7e7f614ba4c0d58fb2b86aa53ff69036d27a731c09a26c605227" +FIPA_REPOSITORY_URL = "https://www.fipa.org/repository/aclspecs.html" +FIPA_LICENSE_NOTICE = ( + "Copyright © 1996-2002 Foundation for Intelligent Physical Agents. " + "The specification notice grants no permission to use third-party intellectual property." +) +FIPA_ACTS = ( + "accept-proposal", + "agree", + "cancel", + "cfp", + "confirm", + "disconfirm", + "failure", + "inform", + "inform-if", + "inform-ref", + "not-understood", + "propagate", + "propose", + "proxy", + "query-if", + "query-ref", + "refuse", + "reject-proposal", + "request", + "request-when", + "request-whenever", + "subscribe", +) + + +def _load_json(path: Path) -> Any: + return json.loads(path.read_text(encoding="utf-8")) + + +def _metadata_failures( + *, + relative_path: str, + source: ActivityStreamsActivityTypesSourceModel | FipaCommunicativeActsSourceModel, + expected: dict[str, str], + required_citations: tuple[str, ...], +) -> list[str]: + failures: list[str] = [] + actual = source.model_dump() + for field, expected_value in expected.items(): + if actual[field] != expected_value: + failures.append(f"{relative_path}: {field} is {actual[field]!r}; expected {expected_value!r}") + for citation in required_citations: + if citation not in source.citation_urls: + failures.append(f"{relative_path}: citation_urls must include {citation}") + return failures + + +def _check_activitystreams_source(source: ActivityStreamsActivityTypesSourceModel) -> list[str]: + failures = _metadata_failures( + relative_path=ACTIVITYSTREAMS_RELATIVE_PATH, + source=source, + expected={ + "source_authority": ACTIVITYSTREAMS_AUTHORITY, + "source_version": ACTIVITYSTREAMS_VERSION, + "source_status": ACTIVITYSTREAMS_STATUS, + "source_url": ACTIVITYSTREAMS_URL, + "source_digest": ACTIVITYSTREAMS_DIGEST, + "license_url": ACTIVITYSTREAMS_LICENSE_URL, + "license_notice": ACTIVITYSTREAMS_LICENSE_NOTICE, + }, + required_citations=( + ACTIVITYSTREAMS_URL, + ACTIVITYSTREAMS_LATEST_URL, + ACTIVITYSTREAMS_CORE_URL, + ACTIVITYSTREAMS_LICENSE_URL, + ), + ) + actual_types = [term.type_name for term in source.activity_types] + if actual_types != list(ACTIVITYSTREAMS_TYPES): + failures.append( + f"{ACTIVITYSTREAMS_RELATIVE_PATH}: activity type order/content differs from the dated Recommendation" + ) + expected_ids = [f"https://www.w3.org/ns/activitystreams#{name}" for name in ACTIVITYSTREAMS_TYPES] + if [term.concept_id for term in source.activity_types] != expected_ids: + failures.append(f"{ACTIVITYSTREAMS_RELATIVE_PATH}: concept ids differ from the normative Activity type IRIs") + return failures + + +def _check_fipa_source(source: FipaCommunicativeActsSourceModel) -> list[str]: + failures = _metadata_failures( + relative_path=FIPA_RELATIVE_PATH, + source=source, + expected={ + "source_authority": FIPA_AUTHORITY, + "source_version": FIPA_VERSION, + "source_status": FIPA_STATUS, + "source_url": FIPA_URL, + "source_artifact_url": FIPA_ARTIFACT_URL, + "source_digest": FIPA_DIGEST, + "license_url": FIPA_URL, + "license_notice": FIPA_LICENSE_NOTICE, + }, + required_citations=(FIPA_URL, FIPA_ARTIFACT_URL, FIPA_REPOSITORY_URL), + ) + if [act.concept_id for act in source.communicative_acts] != list(FIPA_ACTS): + failures.append(f"{FIPA_RELATIVE_PATH}: communicative act order/content differs from SC00037J") + return failures + + +def _validate_official_https_url(url: str, *, allowed_host: str) -> None: + parsed = urllib.parse.urlparse(url) + if parsed.scheme != "https" or parsed.hostname != allowed_host: + raise ValueError("remote verification URL is outside the allowlisted official HTTPS host") + + +class _OfficialHttpsRedirectHandler(urllib.request.HTTPRedirectHandler): + def __init__(self, allowed_host: str) -> None: + self._allowed_host = allowed_host + + def redirect_request(self, request, fp, code, msg, headers, newurl): + _validate_official_https_url(newurl, allowed_host=self._allowed_host) + return super().redirect_request(request, fp, code, msg, headers, newurl) + + +def _fetch_official_bytes(url: str, *, allowed_host: str) -> bytes: + _validate_official_https_url(url, allowed_host=allowed_host) + request = urllib.request.Request(url, headers={"User-Agent": "RAES-ACT-611-source-verifier/1"}) # noqa: S310 + opener = urllib.request.build_opener(_OfficialHttpsRedirectHandler(allowed_host)) + with opener.open(request, timeout=60) as response: # noqa: S310 + return response.read() + + +def _prefixed_sha256(data: bytes) -> str: + return f"sha256:{hashlib.sha256(data).hexdigest()}" + + +def _extract_activitystreams_type_names(data: bytes) -> list[str]: + document = data.decode("utf-8") + start = document.index('
", start) + list_end = document.index("", list_start) + source_list = document[list_start:list_end] + return re.findall(r'data-link-type="dfn">([A-Za-z]+)', source_list) + + +def _check_remote( + activitystreams: ActivityStreamsActivityTypesSourceModel, + fipa: FipaCommunicativeActsSourceModel, +) -> list[str]: + failures: list[str] = [] + activitystreams_bytes = _fetch_official_bytes(activitystreams.source_url, allowed_host="www.w3.org") + if _prefixed_sha256(activitystreams_bytes) != activitystreams.source_digest: + failures.append(f"{ACTIVITYSTREAMS_RELATIVE_PATH}: retrieved Recommendation bytes differ from source_digest") + if _extract_activitystreams_type_names(activitystreams_bytes) != list(ACTIVITYSTREAMS_TYPES): + failures.append(f"{ACTIVITYSTREAMS_RELATIVE_PATH}: retrieved Activity type order/content differs from snapshot") + + fipa_artifact_bytes = _fetch_official_bytes(fipa.source_artifact_url, allowed_host="www.fipa.org") + if _prefixed_sha256(fipa_artifact_bytes) != fipa.source_digest: + failures.append(f"{FIPA_RELATIVE_PATH}: retrieved specification artifact bytes differ from source_digest") + fipa_html_bytes = _fetch_official_bytes(fipa.source_url, allowed_host="www.fipa.org") + for concept_id in FIPA_ACTS: + if re.search(rb">" + re.escape(concept_id.encode("ascii")) + rb"", fipa_html_bytes) is None: + failures.append( + f"{FIPA_RELATIVE_PATH}: retrieved specification does not contain an expected act identifier" + ) + break + return failures + + +def parse_args() -> argparse.Namespace: + parser = argparse.ArgumentParser(description=__doc__) + parser.add_argument( + "--verify-remote", + action="store_true", + help="Fetch the two allowlisted official sources and verify their exact bytes and identifier sets.", + ) + return parser.parse_args() + + +def main() -> int: + args = parse_args() + activitystreams = ActivityStreamsActivityTypesSourceModel.model_validate( + _load_json(REPO_ROOT / ACTIVITYSTREAMS_RELATIVE_PATH) + ) + fipa = FipaCommunicativeActsSourceModel.model_validate(_load_json(REPO_ROOT / FIPA_RELATIVE_PATH)) + failures = _check_activitystreams_source(activitystreams) + failures.extend(_check_fipa_source(fipa)) + if args.verify_remote: + failures.extend(_check_remote(activitystreams, fipa)) + for failure in failures: + print(f"[autonomous-behavior-vocabularies] {failure}", file=sys.stderr) + return 1 if failures else 0 + + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/tools/check_behavioral_relation_claims.py b/tools/check_behavioral_relation_claims.py index f658c8559..e945e25d5 100644 --- a/tools/check_behavioral_relation_claims.py +++ b/tools/check_behavioral_relation_claims.py @@ -223,7 +223,7 @@ def _validate_structured_bindings( continue try: binding = BehavioralClaimBindingModel.model_validate(candidate) - validate_behavioral_claim_binding(binding, catalog) + validate_behavioral_claim_binding(binding) except (ValidationError, ValueError) as exc: failures.append( PolicyFailure( diff --git a/tools/check_json_artifacts.py b/tools/check_json_artifacts.py index fccb36ad7..033383813 100644 --- a/tools/check_json_artifacts.py +++ b/tools/check_json_artifacts.py @@ -3,9 +3,12 @@ from __future__ import annotations import argparse +from collections import defaultdict +from concurrent.futures import ThreadPoolExecutor from dataclasses import dataclass from pathlib import Path import json +import os import subprocess import sys @@ -28,6 +31,7 @@ "implementations/python/packages/raes/", "tools/generate_contract_schemas.py", ) +JSON_SCHEMA_WORKERS_ENV = "RAES_JSON_SCHEMA_WORKERS" @dataclass(frozen=True) @@ -37,6 +41,13 @@ class ValidationTarget: mode: str +@dataclass(frozen=True) +class ValidationBatch: + paths: tuple[str, ...] + schema_path: str | None + mode: str + + def parse_args() -> argparse.Namespace: parser = argparse.ArgumentParser(description="Validate published JSON Schemas and schema-governed JSON artifacts.") parser.add_argument( @@ -256,18 +267,52 @@ def _run_check_jsonschema(*args: str) -> subprocess.CompletedProcess[str]: ) +def _validation_batches(targets: list[ValidationTarget]) -> list[ValidationBatch]: + metaschema_paths = sorted(target.path for target in targets if target.mode == "metaschema") + schema_groups: dict[str, list[str]] = defaultdict(list) + for target in targets: + if target.mode != "schema": + continue + assert target.schema_path is not None + schema_groups[target.schema_path].append(target.path) + + batches: list[ValidationBatch] = [] + if metaschema_paths: + batches.append(ValidationBatch(tuple(metaschema_paths), None, "metaschema")) + batches.extend( + ValidationBatch(tuple(sorted(paths)), schema_path, "schema") + for schema_path, paths in sorted(schema_groups.items()) + ) + return batches + + +def _validate_batch(batch: ValidationBatch) -> subprocess.CompletedProcess[str]: + if batch.mode == "metaschema": + return _run_check_jsonschema("--check-metaschema", *batch.paths) + assert batch.schema_path is not None + return _run_check_jsonschema("--schemafile", batch.schema_path, *batch.paths) + + def validate_targets(targets: list[ValidationTarget]) -> list[str]: + batches = _validation_batches(targets) + if not batches: + return [] + worker_value = os.environ.get(JSON_SCHEMA_WORKERS_ENV, "4") + try: + worker_count = int(worker_value) + except ValueError as exc: + raise ValueError(f"{JSON_SCHEMA_WORKERS_ENV} must be an integer") from exc + if worker_count < 1: + raise ValueError(f"{JSON_SCHEMA_WORKERS_ENV} must be at least one") + with ThreadPoolExecutor(max_workers=min(worker_count, len(batches)), thread_name_prefix="json-schema") as executor: + results = list(executor.map(_validate_batch, batches)) + failures: list[str] = [] - for target in targets: - if target.mode == "metaschema": - proc = _run_check_jsonschema("--check-metaschema", target.path) - else: - assert target.schema_path is not None - proc = _run_check_jsonschema("--schemafile", target.schema_path, target.path) + for batch, proc in zip(batches, results, strict=True): if proc.returncode == 0: continue details = proc.stderr.strip() or proc.stdout.strip() or "schema validation failed" - failures.append(f"{target.path}: {details}") + failures.append(f"{', '.join(batch.paths)}: {details}") return failures diff --git a/tools/check_participant_opacity_proof.py b/tools/check_participant_opacity_proof.py new file mode 100644 index 000000000..b259d8a6c --- /dev/null +++ b/tools/check_participant_opacity_proof.py @@ -0,0 +1,526 @@ +from __future__ import annotations + +import hashlib +import re +import sys +from pathlib import Path +from typing import Any + +REPO_ROOT = Path(__file__).resolve().parents[1] +if str(REPO_ROOT) not in sys.path: + sys.path.insert(0, str(REPO_ROOT)) + +from raes_contracts.behavioral_relation_profiles import ( # noqa: E402 + load_behavioral_relation_profile_revision, +) +from raes_contracts.behavioral_relations import ( # noqa: E402 + load_behavioral_relation_catalog_revision, + validate_behavioral_claim_binding, +) +from raes_contracts.contracts.base import BehavioralClaimBindingModel # noqa: E402 +from raes_contracts.json_ingress import parse_bounded_json_object # noqa: E402 + +from tools.isabelle_tool import ( # noqa: E402 + ISABELLE_ARCHIVE_BYTES, + ISABELLE_ARCHIVE_SHA256, + ISABELLE_ARCHIVE_URL, + ISABELLE_BUILD_TIMEOUT_SECONDS, + ISABELLE_FILE_LIMIT_BYTES, + ISABELLE_JAVA_MAX_HEAP_MIB, + ISABELLE_ML_MAX_HEAP_MIB, + ISABELLE_OUTPUT_LIMIT_BYTES, + ISABELLE_PROCESS_ADDRESS_SPACE_LIMIT_MIB, + ISABELLE_SESSION, + ISABELLE_SESSION_RELATIVE_PATH, + expected_isabelle_result, + run_isabelle_build, +) +from tools.tool_versions import ISABELLE_VERSION # noqa: E402 + +MANIFEST_RELATIVE_PATH = Path("specs/formal/participant-semantics/participant-opacity-proof-evidence.json") +THEORY_RELATIVE_PATH = ISABELLE_SESSION_RELATIVE_PATH / "Participant_Opacity.thy" +ROOT_RELATIVE_PATH = ISABELLE_SESSION_RELATIVE_PATH / "ROOT" +MAX_MANIFEST_BYTES = 2 * 1024 * 1024 + +POSITIVE_THEOREMS = frozenset( + { + "participant_opacity_kernel", + "participant_opacity_knowledge_characterization", + "matching_policy_noninterference_implies_participant_opacity", + } +) +SUPPORTING_THEOREMS = frozenset( + { + "information_cell_reflexive", + "participant_knowledge_is_factive", + } +) +NEGATIVE_THEOREMS = { + "opacity_does_not_imply_policy_noninterference": "SEM231-MUT-OPACITY-TO-NONINTERFERENCE", + "one_equal_history_pair_is_insufficient": "SEM231-MUT-ONE-PAIR", + "declassification_can_change_information_and_knowledge": "SEM231-MUT-DECLASSIFICATION", + "revocation_does_not_erase_retained_observation": "SEM231-MUT-REVOCATION-MEMORY", + "behavioral_relations_without_preservation_do_not_imply_opacity": "SEM231-MUT-RELATION-SUBSTITUTION", + "untimed_individual_observation_does_not_imply_stronger_observation_opacity": ("SEM231-MUT-STRONGER-OBSERVATION"), + "possibilistic_opacity_does_not_imply_a_probability_bound": "SEM231-MUT-PROBABILITY-PROMOTION", +} +ASSUMPTION_IDS = frozenset( + { + "active-same-strategy", + "complete-low-history-support", + "eligible-label-preservation", + "eligible-nonsecret-public-class-variation", + "exact-information-cell", + "matching-profile-coordinates", + "reachable-alternative", + "retained-memory-no-erasure", + } +) +FORBIDDEN_FEATURES = ( + "axiomatization", + "axioms", + "nitpick", + "oops", + "oracle", + "quick_and_dirty", + "skip_proofs", + "sorry", +) +_FORBIDDEN_RE = re.compile(r"\b(?:" + "|".join(FORBIDDEN_FEATURES) + r")\b", re.IGNORECASE) + + +class ProofEvidenceError(ValueError): + """A stable failure from the repository-local mathematical-proof gate.""" + + +def _require_keys(payload: dict[str, Any], expected: set[str], label: str) -> None: + if set(payload) != expected: + raise ProofEvidenceError(f"{label} has an open or incomplete shape") + + +def _require_list(value: Any, label: str) -> list[Any]: + if not isinstance(value, list) or not value: + raise ProofEvidenceError(f"{label} must be a non-empty list") + return value + + +def _require_object(value: Any, label: str) -> dict[str, Any]: + if not isinstance(value, dict): + raise ProofEvidenceError(f"{label} must be an object") + return value + + +def _resolve_repo_path(repo_root: Path, raw_path: Any) -> Path: + if not isinstance(raw_path, str) or not raw_path or "\\" in raw_path: + raise ProofEvidenceError("proof evidence contains an unsafe repository path") + relative = Path(raw_path) + if relative.is_absolute() or ".." in relative.parts: + raise ProofEvidenceError("proof evidence contains an unsafe repository path") + resolved = (repo_root / relative).resolve() + root = repo_root.resolve() + if resolved != root and root not in resolved.parents: + raise ProofEvidenceError("proof evidence path escapes the repository") + if not resolved.is_file(): + raise ProofEvidenceError("proof evidence references a missing repository file") + return resolved + + +def _file_digest(path: Path) -> str: + digest = hashlib.sha256() + with path.open("rb") as stream: + for chunk in iter(lambda: stream.read(1024 * 1024), b""): + digest.update(chunk) + return f"sha256:{digest.hexdigest()}" + + +def _validate_digest_bound_path(repo_root: Path, payload: dict[str, Any], label: str) -> Path: + path = _resolve_repo_path(repo_root, payload.get("path")) + if payload.get("digest") != _file_digest(path): + raise ProofEvidenceError(f"{label} digest does not match its repository source") + return path + + +def load_proof_manifest( + path: Path = REPO_ROOT / MANIFEST_RELATIVE_PATH, +) -> dict[str, Any]: + try: + return parse_bounded_json_object(path.read_bytes(), max_bytes=MAX_MANIFEST_BYTES) + except (OSError, ValueError) as exc: + raise ProofEvidenceError("participant-opacity proof manifest is invalid") from exc + + +def _validate_authorities(manifest: dict[str, Any], repo_root: Path) -> tuple[Any, Any]: + taxonomy = _require_object(manifest["taxonomy"], "taxonomy authority") + _require_keys( + taxonomy, + {"taxonomy_id", "taxonomy_revision", "path", "digest"}, + "taxonomy authority", + ) + if taxonomy["taxonomy_id"] != "raes-behavioral-relations" or taxonomy["taxonomy_revision"] != "rev9": + raise ProofEvidenceError("proof taxonomy authority is not the declared rev9 authority") + if taxonomy["path"] != "contracts/concept-authority/behavioral-relations-v1.json": + raise ProofEvidenceError("proof taxonomy authority path is not canonical") + _validate_digest_bound_path(repo_root, taxonomy, "taxonomy authority") + catalog = load_behavioral_relation_catalog_revision("rev9") + relation = catalog.relations["participant-predicate-opacity"] + if relation.assurance.proof_status != "proved": + raise ProofEvidenceError("participant-opacity catalog proof axis is not proved") + + profiles = _require_list(manifest["profiles"], "proof profiles") + if len(profiles) != 1: + raise ProofEvidenceError("proof evidence must bind exactly one theorem profile") + profile_item = _require_object(profiles[0], "proof profile") + _require_keys( + profile_item, + {"profile_id", "profile_revision", "path", "digest"}, + "proof profile", + ) + if ( + profile_item["profile_id"] != "participant-opacity-theorem-v1" + or profile_item["profile_revision"] != "sem-231-proof/rev1" + or profile_item["path"] != "contracts/profiles/behavioral-relation/participant-opacity-theorem-v1.json" + ): + raise ProofEvidenceError("proof evidence does not bind the exact theorem profile") + _validate_digest_bound_path(repo_root, profile_item, "proof profile") + profile = load_behavioral_relation_profile_revision( + profile_item["profile_id"], + profile_item["profile_revision"], + ) + return catalog, profile + + +def _validate_sources(manifest: dict[str, Any], repo_root: Path) -> None: + sources = _require_list(manifest["semantic_sources"], "semantic sources") + if len(sources) != 2: + raise ProofEvidenceError("proof evidence must bind SEM-230 and SEM-231 sources") + source_requirements: set[str] = set() + for source in sources: + item = _require_object(source, "semantic source") + _require_keys(item, {"requirement", "revision", "path", "digest"}, "semantic source") + source_requirements.add(item["requirement"]) + _validate_digest_bound_path(repo_root, item, "semantic source") + if source_requirements != {"SEM-230", "SEM-231"}: + raise ProofEvidenceError("proof evidence semantic sources do not cover SEM-230 and SEM-231") + + dependencies = _require_list(manifest["dependencies"], "proof dependencies") + dependency_issues: set[int] = set() + for dependency in dependencies: + item = _require_object(dependency, "proof dependency") + _require_keys( + item, + {"issue", "artifact_revision", "path", "digest", "evidence_boundary"}, + "proof dependency", + ) + dependency_issues.add(item["issue"]) + _validate_digest_bound_path(repo_root, item, "proof dependency") + if dependency_issues != {810, 961, 962}: + raise ProofEvidenceError("proof evidence dependency set is incomplete") + + +def _validate_assumptions(manifest: dict[str, Any]) -> None: + assumptions = _require_list(manifest["assumptions"], "proof assumptions") + assumption_ids: list[str] = [] + for assumption in assumptions: + item = _require_object(assumption, "proof assumption") + _require_keys(item, {"assumption_id", "statement"}, "proof assumption") + if not isinstance(item["statement"], str) or not item["statement"].strip(): + raise ProofEvidenceError("proof assumption statement is empty") + assumption_ids.append(item["assumption_id"]) + if assumption_ids != sorted(ASSUMPTION_IDS): + raise ProofEvidenceError("proof assumption set or canonical order is invalid") + + +def _validate_claims(manifest: dict[str, Any], catalog: Any, profile: Any) -> None: + positive = _require_list(manifest["positive_theorems"], "positive theorems") + theorem_ids: list[str] = [] + for theorem in positive: + item = _require_object(theorem, "positive theorem") + _require_keys(item, {"theorem_id", "statement", "claim"}, "positive theorem") + theorem_id = item["theorem_id"] + theorem_ids.append(theorem_id) + try: + claim = BehavioralClaimBindingModel.model_validate(item["claim"]) + validate_behavioral_claim_binding(claim, catalog=catalog, profile=profile) + except ValueError as exc: + raise ProofEvidenceError("proof claim does not resolve against its exact authorities") from exc + expected_refs = [ + MANIFEST_RELATIVE_PATH.as_posix(), + THEORY_RELATIVE_PATH.as_posix(), + f"isabelle-theorem:{theorem_id}", + ] + if ( + claim.assurance_axis != "proof" + or claim.assurance_status != "proved" + or claim.evidence_scope != "proof" + or claim.quantifier_scope != "all-strategies" + or claim.evidence_refs != expected_refs + ): + raise ProofEvidenceError("proof claim axis, scope, status, or evidence refs are invalid") + if theorem_ids != sorted(POSITIVE_THEOREMS): + raise ProofEvidenceError("positive theorem set or canonical order is invalid") + + +def _validate_theorem_inventory(manifest: dict[str, Any], theory_text: str) -> None: + supporting = _require_list(manifest["supporting_theorems"], "supporting theorems") + supporting_ids: list[str] = [] + for theorem in supporting: + item = _require_object(theorem, "supporting theorem") + _require_keys(item, {"theorem_id", "statement"}, "supporting theorem") + supporting_ids.append(item["theorem_id"]) + if supporting_ids != sorted(SUPPORTING_THEOREMS): + raise ProofEvidenceError("supporting theorem set or canonical order is invalid") + + negative = _require_list(manifest["negative_theorems"], "negative theorems") + negative_ids: list[str] = [] + for theorem in negative: + item = _require_object(theorem, "negative theorem") + _require_keys(item, {"theorem_id", "statement", "mutation_id"}, "negative theorem") + theorem_id = item["theorem_id"] + negative_ids.append(theorem_id) + if NEGATIVE_THEOREMS.get(theorem_id) != item["mutation_id"]: + raise ProofEvidenceError("negative theorem mutation binding is invalid") + if negative_ids != sorted(NEGATIVE_THEOREMS): + raise ProofEvidenceError("negative theorem set or canonical order is invalid") + + declared_theorems = POSITIVE_THEOREMS | SUPPORTING_THEOREMS | set(NEGATIVE_THEOREMS) + for theorem_id in declared_theorems: + declaration = re.compile(rf"\b(?:lemma|theorem)\s+{re.escape(theorem_id)}\s*:") + if declaration.search(theory_text) is None: + raise ProofEvidenceError("proof manifest names a theorem absent from the checked theory") + if _FORBIDDEN_RE.search(theory_text) is not None: + raise ProofEvidenceError("checked theory contains an unfinished or undeclared proof feature") + + +def _validate_toolchain(manifest: dict[str, Any], repo_root: Path) -> None: + toolchain = _require_object(manifest["toolchain"], "proof toolchain") + _require_keys( + toolchain, + { + "prover", + "version", + "archive_url", + "archive_sha256", + "archive_bytes", + "acquire_command", + "replay_command", + "working_directory", + "locale", + "platform_boundary", + "network", + "filesystem", + "limits", + "tool_sources", + }, + "proof toolchain", + ) + expected = { + "prover": "Isabelle/HOL", + "version": f"Isabelle{ISABELLE_VERSION}", + "archive_url": ISABELLE_ARCHIVE_URL, + "archive_sha256": f"sha256:{ISABELLE_ARCHIVE_SHA256}", + "archive_bytes": ISABELLE_ARCHIVE_BYTES, + "working_directory": ".", + "locale": "C.UTF-8", + "platform_boundary": "linux-x86_64", + "network": "explicit-acquire-only; replay-blocked-by-bubblewrap-network-namespace", + "filesystem": "allowlisted-runtime-session-and-private-state-only", + } + if any(toolchain.get(key) != value for key, value in expected.items()): + raise ProofEvidenceError("proof toolchain pin or execution posture drifted") + expected_acquire = [ + "uv", + "run", + "--project", + "implementations/python", + "--frozen", + "python", + "-m", + "tools.isabelle_tool", + "acquire", + ] + expected_replay = [ + "uv", + "run", + "--project", + "implementations/python", + "--frozen", + "python", + "-m", + "tools.check_participant_opacity_proof", + ] + if toolchain["acquire_command"] != expected_acquire or toolchain["replay_command"] != expected_replay: + raise ProofEvidenceError("proof toolchain command is not the fixed repository command") + limits = _require_object(toolchain["limits"], "proof process limits") + _require_keys( + limits, + { + "wall_seconds", + "cpu_seconds", + "threads", + "max_output_bytes", + "max_file_bytes", + "max_address_space_mib_per_process", + "java_max_heap_mib", + "ml_max_heap_mib", + "memory_scope", + "generated_artifact_retention", + }, + "proof process limits", + ) + if limits != { + "wall_seconds": ISABELLE_BUILD_TIMEOUT_SECONDS, + "cpu_seconds": ISABELLE_BUILD_TIMEOUT_SECONDS, + "threads": 2, + "max_output_bytes": ISABELLE_OUTPUT_LIMIT_BYTES, + "max_file_bytes": ISABELLE_FILE_LIMIT_BYTES, + "max_address_space_mib_per_process": ISABELLE_PROCESS_ADDRESS_SPACE_LIMIT_MIB, + "java_max_heap_mib": ISABELLE_JAVA_MAX_HEAP_MIB, + "ml_max_heap_mib": ISABELLE_ML_MAX_HEAP_MIB, + "memory_scope": "per-process-address-space-and-per-runtime-heaps-not-aggregate-tree", + "generated_artifact_retention": "none", + }: + raise ProofEvidenceError("proof process limits drifted") + tool_sources = _require_list(toolchain["tool_sources"], "proof tool sources") + if [item.get("path") for item in tool_sources if isinstance(item, dict)] != [ + "tools/check_participant_opacity_proof.py", + "tools/isabelle_tool.py", + ]: + raise ProofEvidenceError("proof tool source set or order is invalid") + for source in tool_sources: + item = _require_object(source, "proof tool source") + _require_keys(item, {"path", "digest"}, "proof tool source") + _validate_digest_bound_path(repo_root, item, "proof tool source") + + +def _validate_session(manifest: dict[str, Any], repo_root: Path) -> str: + session = _require_object(manifest["session"], "proof session") + _require_keys( + session, + { + "session_id", + "root_path", + "root_digest", + "theory_path", + "theory_digest", + "imports", + "forbidden_features", + "generated_artifacts", + }, + "proof session", + ) + if ( + session["session_id"] != ISABELLE_SESSION + or session["root_path"] != ROOT_RELATIVE_PATH.as_posix() + or session["theory_path"] != THEORY_RELATIVE_PATH.as_posix() + or session["imports"] != ["Main"] + or session["forbidden_features"] != list(FORBIDDEN_FEATURES) + or session["generated_artifacts"] != [] + ): + raise ProofEvidenceError("proof session declaration drifted") + root_path = _resolve_repo_path(repo_root, session["root_path"]) + theory_path = _resolve_repo_path(repo_root, session["theory_path"]) + if session["root_digest"] != _file_digest(root_path) or session["theory_digest"] != _file_digest(theory_path): + raise ProofEvidenceError("proof session source digest drifted") + root_text = root_path.read_text(encoding="utf-8") + if "session Participant_Opacity = HOL +" not in root_text or "Participant_Opacity" not in root_text: + raise ProofEvidenceError("proof session root does not bind the fixed HOL session") + theory_text = theory_path.read_text(encoding="utf-8") + if not re.search(r"theory\s+Participant_Opacity\s+imports\s+Main\s+begin", theory_text): + raise ProofEvidenceError("proof theory does not import exactly Isabelle/HOL Main") + return theory_text + + +def _validate_results(manifest: dict[str, Any], *, repo_root: Path, run_prover: bool) -> None: + expected_result = expected_isabelle_result() + kernel_result = _require_object(manifest["kernel_result"], "kernel result") + if kernel_result != expected_result: + raise ProofEvidenceError("proof kernel result or expected digest drifted") + reproduction = _require_object(manifest["independent_reproduction"], "independent reproduction") + _require_keys( + reproduction, + {"command", "working_directory", "result", "reproduced_on"}, + "independent reproduction", + ) + if ( + reproduction["command"] + != [ + "uv", + "run", + "--project", + "implementations/python", + "--frozen", + "python", + "-m", + "tools.check_participant_opacity_proof", + ] + or reproduction["working_directory"] != "." + or reproduction["result"] != expected_result + or reproduction["reproduced_on"] != "2026-07-31" + ): + raise ProofEvidenceError("independent proof reproduction record drifted") + if run_prover and run_isabelle_build(repo_root) != expected_result: + raise ProofEvidenceError("independent Isabelle proof replay did not reproduce") + + +def validate_proof_manifest( + manifest: dict[str, Any], + *, + repo_root: Path = REPO_ROOT, + run_prover: bool = True, +) -> None: + _require_keys( + manifest, + { + "schema_version", + "evidence_id", + "requirements", + "taxonomy", + "profiles", + "semantic_sources", + "dependencies", + "assumptions", + "positive_theorems", + "supporting_theorems", + "negative_theorems", + "toolchain", + "session", + "kernel_result", + "independent_reproduction", + "limitations", + "explicit_non_claims", + }, + "participant-opacity proof manifest", + ) + if ( + manifest["schema_version"] != "participant-opacity-proof-evidence/repo-v1" + or manifest["evidence_id"] != "participant-opacity-proof:sem-231/rev1" + or manifest["requirements"] != ["ASR-535", "SEM-231"] + ): + raise ProofEvidenceError("proof evidence identity or requirements drifted") + if not _require_list(manifest["limitations"], "proof limitations") or not _require_list( + manifest["explicit_non_claims"], "proof explicit nonclaims" + ): + raise ProofEvidenceError("proof boundaries are incomplete") + catalog, profile = _validate_authorities(manifest, repo_root) + _validate_sources(manifest, repo_root) + _validate_assumptions(manifest) + _validate_claims(manifest, catalog, profile) + _validate_toolchain(manifest, repo_root) + theory_text = _validate_session(manifest, repo_root) + _validate_theorem_inventory(manifest, theory_text) + _validate_results(manifest, repo_root=repo_root, run_prover=run_prover) + + +def main() -> int: + try: + manifest = load_proof_manifest() + validate_proof_manifest(manifest) + except ProofEvidenceError as exc: + print(f"participant-opacity-proof: {exc}", file=sys.stderr) + return 1 + print("participant-opacity-proof: verified") + return 0 + + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/tools/generate_contract_schemas.py b/tools/generate_contract_schemas.py index ad934d6be..400f99cfc 100644 --- a/tools/generate_contract_schemas.py +++ b/tools/generate_contract_schemas.py @@ -49,7 +49,9 @@ def _schema_output_path(schemas_dir: Path, name: str) -> Path: if name in { "attack-enterprise-tactics-source-v1", "atlas-tactics-source-v1", + "fipa-communicative-acts-source-v1", "nist-csf-defensive-categories-source-v1", + "w3c-activitystreams-activity-types-source-v1", }: return schemas_dir / "concept-authority" / f"{name}.json" if name == "reusable-asset-trust-policy-v1": diff --git a/tools/isabelle_tool.py b/tools/isabelle_tool.py new file mode 100644 index 000000000..acc82e0b4 --- /dev/null +++ b/tools/isabelle_tool.py @@ -0,0 +1,387 @@ +from __future__ import annotations + +import argparse +import hashlib +import json +import os +import platform +import resource +import shutil +import subprocess +import sys +import tarfile +import tempfile +from pathlib import Path +from urllib.error import HTTPError, URLError +from urllib.request import urlopen + +REPO_ROOT = Path(__file__).resolve().parents[1] +if str(REPO_ROOT) not in sys.path: + sys.path.insert(0, str(REPO_ROOT)) + +from tools.tool_versions import ISABELLE_VERSION # noqa: E402 + +ISABELLE_ARCHIVE_NAME = f"Isabelle{ISABELLE_VERSION}_linux.tar.gz" +ISABELLE_ARCHIVE_URL = f"https://www.cl.cam.ac.uk/research/hvg/Isabelle/dist/{ISABELLE_ARCHIVE_NAME}" +ISABELLE_ARCHIVE_URLS = ( + f"https://isabelle.in.tum.de/website-Isabelle{ISABELLE_VERSION}/dist/{ISABELLE_ARCHIVE_NAME}", + ISABELLE_ARCHIVE_URL, +) +ISABELLE_ARCHIVE_SHA256 = "a20a507bc7c1270d8be96a9f3fbec06345387789d2dc2c4d3df6260d47bfb33c" +ISABELLE_ARCHIVE_BYTES = 1_228_480_874 +ISABELLE_SESSION = "Participant_Opacity" +ISABELLE_SESSION_RELATIVE_PATH = Path("specs/formal/participant-semantics/isabelle") +ISABELLE_BUILD_TIMEOUT_SECONDS = 600 +ISABELLE_OUTPUT_LIMIT_BYTES = 64 * 1024 +ISABELLE_FILE_LIMIT_BYTES = 4 * 1024 * 1024 * 1024 +ISABELLE_PROCESS_ADDRESS_SPACE_LIMIT_MIB = 32768 +ISABELLE_JAVA_MAX_HEAP_MIB = 2048 +ISABELLE_ML_MAX_HEAP_MIB = 2048 +ISABELLE_SANDBOX_HOME = Path("/opt/isabelle") +ISABELLE_SANDBOX_SESSION_ROOT = Path("/workspace/session") +ISABELLE_SANDBOX_STATE_ROOT = Path("/state") +ISABELLE_SYSTEM_RUNTIME_PATHS = ( + Path("/usr/bin"), + Path("/usr/lib"), + Path("/usr/lib64"), + Path("/usr/share/locale"), + Path("/usr/share/fonts"), + Path("/usr/share/zoneinfo"), + Path("/lib"), + Path("/lib64"), + Path("/etc/fonts"), + Path("/etc/ld.so.cache"), + Path("/var/cache/fontconfig"), +) +_DOWNLOAD_CHUNK_BYTES = 1024 * 1024 + + +class IsabelleToolError(RuntimeError): + """A bounded operational failure from the pinned proof tool.""" + + +def isabelle_cache_root(repo_root: Path = REPO_ROOT) -> Path: + return repo_root / ".cache" / "raes-sdl" / "tooling" + + +def isabelle_archive_path(repo_root: Path = REPO_ROOT) -> Path: + return isabelle_cache_root(repo_root) / "archives" / ISABELLE_ARCHIVE_NAME + + +def isabelle_home(repo_root: Path = REPO_ROOT) -> Path: + return isabelle_cache_root(repo_root) / "isabelle" / f"Isabelle{ISABELLE_VERSION}" + + +def _installation_marker(repo_root: Path = REPO_ROOT) -> Path: + return isabelle_home(repo_root).parent / f"Isabelle{ISABELLE_VERSION}.archive.sha256" + + +def _sha256_file(path: Path) -> str: + digest = hashlib.sha256() + with path.open("rb") as stream: + for chunk in iter(lambda: stream.read(_DOWNLOAD_CHUNK_BYTES), b""): + digest.update(chunk) + return digest.hexdigest() + + +def _verify_archive(path: Path) -> None: + try: + size = path.stat().st_size + except OSError as exc: + raise IsabelleToolError("pinned Isabelle archive is unavailable") from exc + if size != ISABELLE_ARCHIVE_BYTES or _sha256_file(path) != ISABELLE_ARCHIVE_SHA256: + raise IsabelleToolError("pinned Isabelle archive checksum or size mismatch") + + +def _download_archive_from_url(url: str, temporary_path: Path) -> None: + digest = hashlib.sha256() + total = 0 + response = urlopen(url, timeout=60) # noqa: S310 - allowlisted official Isabelle release URLs + with response, temporary_path.open("wb") as output: + for chunk in iter(lambda: response.read(_DOWNLOAD_CHUNK_BYTES), b""): + total += len(chunk) + if total > ISABELLE_ARCHIVE_BYTES: + raise IsabelleToolError("download exceeded its declared size") + digest.update(chunk) + output.write(chunk) + if total != ISABELLE_ARCHIVE_BYTES or digest.hexdigest() != ISABELLE_ARCHIVE_SHA256: + raise IsabelleToolError("download checksum or size mismatch") + + +def _download_archive(path: Path) -> None: + path.parent.mkdir(parents=True, exist_ok=True) + temporary_path = path.with_suffix(path.suffix + ".download") + failures: list[str] = [] + for url in ISABELLE_ARCHIVE_URLS: + temporary_path.unlink(missing_ok=True) + try: + _download_archive_from_url(url, temporary_path) + except (HTTPError, URLError, TimeoutError, OSError, IsabelleToolError) as exc: + failures.append(f"{url}: {type(exc).__name__}") + continue + temporary_path.replace(path) + return + temporary_path.unlink(missing_ok=True) + raise IsabelleToolError(f"pinned Isabelle download failed from all official mirrors ({'; '.join(failures)})") + + +def _extract_archive(archive_path: Path, destination: Path) -> None: + expected_root = f"Isabelle{ISABELLE_VERSION}" + destination.parent.mkdir(parents=True, exist_ok=True) + with tempfile.TemporaryDirectory(prefix="isabelle-extract-", dir=destination.parent) as temporary: + temporary_root = Path(temporary) + try: + with tarfile.open(archive_path, mode="r:gz") as archive: + top_levels = {Path(member.name).parts[0] for member in archive.getmembers() if Path(member.name).parts} + if top_levels != {expected_root}: + raise IsabelleToolError("pinned Isabelle archive has an unexpected root") + archive.extractall(temporary_root, filter="data") + except (OSError, tarfile.TarError) as exc: + raise IsabelleToolError("pinned Isabelle archive extraction failed") from exc + extracted = temporary_root / expected_root + binary = extracted / "bin" / "isabelle" + if not binary.is_file() or not os.access(binary, os.X_OK): + raise IsabelleToolError("pinned Isabelle archive lacks its executable") + if destination.exists(): + shutil.rmtree(destination) + extracted.replace(destination) + + +def acquire_isabelle(repo_root: Path = REPO_ROOT) -> Path: + """Acquire and checksum-verify the pinned development-only distribution.""" + + if platform.system() != "Linux" or platform.machine().lower() not in { + "x86_64", + "amd64", + }: + raise IsabelleToolError("the pinned Isabelle proof tool supports Linux x86_64 only") + archive_path = isabelle_archive_path(repo_root) + if not archive_path.exists(): + _download_archive(archive_path) + _verify_archive(archive_path) + home = isabelle_home(repo_root) + if not (home / "bin" / "isabelle").is_file(): + _extract_archive(archive_path, home) + marker = _installation_marker(repo_root) + marker.write_text(f"{ISABELLE_ARCHIVE_SHA256}\n", encoding="ascii") + return home + + +def require_isabelle(repo_root: Path = REPO_ROOT) -> Path: + """Resolve a previously acquired distribution without any network access.""" + + home = isabelle_home(repo_root) + marker = _installation_marker(repo_root) + binary = home / "bin" / "isabelle" + try: + installed_digest = marker.read_text(encoding="ascii").strip() + except OSError as exc: + raise IsabelleToolError("pinned Isabelle is not acquired; run the acquire command first") from exc + if installed_digest != ISABELLE_ARCHIVE_SHA256 or not binary.is_file() or not os.access(binary, os.X_OK): + raise IsabelleToolError("pinned Isabelle installation marker or executable is invalid") + return home + + +def _proof_process_limits() -> None: + resource.setrlimit(resource.RLIMIT_CORE, (0, 0)) + resource.setrlimit( + resource.RLIMIT_CPU, + (ISABELLE_BUILD_TIMEOUT_SECONDS, ISABELLE_BUILD_TIMEOUT_SECONDS), + ) + resource.setrlimit(resource.RLIMIT_FSIZE, (ISABELLE_FILE_LIMIT_BYTES, ISABELLE_FILE_LIMIT_BYTES)) + resource.setrlimit(resource.RLIMIT_NOFILE, (256, 256)) + address_space_bytes = ISABELLE_PROCESS_ADDRESS_SPACE_LIMIT_MIB * 1024 * 1024 + resource.setrlimit(resource.RLIMIT_AS, (address_space_bytes, address_space_bytes)) + + +def _read_bounded_output(path: Path) -> str: + with path.open("rb") as stream: + payload = stream.read(ISABELLE_OUTPUT_LIMIT_BYTES + 1) + if len(payload) > ISABELLE_OUTPUT_LIMIT_BYTES: + raise IsabelleToolError("Isabelle build output exceeded the verification bound") + return payload.decode("utf-8", errors="replace") + + +def expected_isabelle_result() -> dict[str, object]: + result: dict[str, object] = { + "prover": "Isabelle/HOL", + "prover_version": f"Isabelle{ISABELLE_VERSION}", + "session": ISABELLE_SESSION, + "result": "kernel-checked", + "network": "blocked-by-bubblewrap-network-namespace", + "filesystem": "allowlisted-runtime-session-and-private-state-only", + "locale": "C.UTF-8", + "platform_boundary": "linux-x86_64", + } + encoded = json.dumps(result, ensure_ascii=False, separators=(",", ":"), sort_keys=True).encode("utf-8") + result["result_digest"] = f"sha256:{hashlib.sha256(encoded).hexdigest()}" + return result + + +def _proof_sandbox_command( + *, + bwrap: Path, + home: Path, + session_root: Path, + state_root: Path, +) -> list[str]: + """Build the fixed proof sandbox without exposing the host root or home.""" + + command = [ + str(bwrap), + "--unshare-net", + "--unshare-pid", + "--unshare-ipc", + "--unshare-uts", + "--die-with-parent", + "--new-session", + "--clearenv", + "--dir", + "/opt", + "--dir", + "/workspace", + "--dir", + "/usr", + "--dir", + "/usr/share", + "--dir", + "/etc", + "--dir", + "/var", + "--dir", + "/var/cache", + ] + for runtime_path in ISABELLE_SYSTEM_RUNTIME_PATHS: + if runtime_path.exists(): + command.extend(("--ro-bind", str(runtime_path), str(runtime_path))) + command.extend( + ( + "--ro-bind", + str(home), + str(ISABELLE_SANDBOX_HOME), + "--ro-bind", + str(session_root), + str(ISABELLE_SANDBOX_SESSION_ROOT), + "--bind", + str(state_root), + str(ISABELLE_SANDBOX_STATE_ROOT), + "--dev", + "/dev", + "--proc", + "/proc", + "--tmpfs", + "/tmp", # noqa: S108 - private bubblewrap tmpfs, not a shared host path + "--chdir", + "/workspace", + "--setenv", + "PATH", + "/usr/bin", + "--setenv", + "HOME", + "/state/user", + "--setenv", + "USER_HOME", + "/state/user", + "--setenv", + "ISABELLE_HOME_USER", + "/state/isabelle-user", + "--setenv", + "LANG", + "C.UTF-8", + "--setenv", + "LC_ALL", + "C.UTF-8", + "--setenv", + "TZ", + "UTC", + str(ISABELLE_SANDBOX_HOME / "bin" / "isabelle"), + "build", + "-o", + "threads=2", + "-o", + "timeout=300", + "-D", + str(ISABELLE_SANDBOX_SESSION_ROOT), + ) + ) + return command + + +def run_isabelle_build(repo_root: Path = REPO_ROOT) -> dict[str, object]: + """Kernel-check the fixed session in a network-isolated, bounded process.""" + + home = require_isabelle(repo_root) + bwrap = Path("/usr/bin/bwrap") + if not bwrap.is_file(): + raise IsabelleToolError("bubblewrap is required to enforce offline proof replay") + session_root = (repo_root / ISABELLE_SESSION_RELATIVE_PATH).resolve() + if not session_root.is_dir() or repo_root.resolve() not in session_root.parents: + raise IsabelleToolError("the fixed Isabelle session root is unavailable") + + with tempfile.TemporaryDirectory(prefix="isabelle-proof-") as temporary: + state_root = Path(temporary).resolve() + output_path = state_root / "build-output.log" + user_home = state_root / "user" + isabelle_user = state_root / "isabelle-user" + user_home.mkdir() + isabelle_user.mkdir() + (isabelle_user / "etc").mkdir() + (isabelle_user / "etc" / "settings").write_text( + f'ISABELLE_TOOL_JAVA_OPTIONS="-Djava.awt.headless=true -Xms256m -Xmx{ISABELLE_JAVA_MAX_HEAP_MIB}m -Xss8m"\n' + f'ML_OPTIONS="--minheap 256 --maxheap {ISABELLE_ML_MAX_HEAP_MIB}"\n', + encoding="ascii", + ) + command = _proof_sandbox_command( + bwrap=bwrap, + home=home, + session_root=session_root, + state_root=state_root, + ) + try: + with output_path.open("wb") as output: + completed = subprocess.run( # noqa: S603 - fixed checksum-verified tool and argv + command, + cwd=repo_root, + stdin=subprocess.DEVNULL, + stdout=output, + stderr=subprocess.STDOUT, + check=False, + timeout=ISABELLE_BUILD_TIMEOUT_SECONDS, + env={}, + preexec_fn=_proof_process_limits, + ) + except subprocess.TimeoutExpired as exc: + raise IsabelleToolError("Isabelle proof replay exceeded its wall-time bound") from exc + output = _read_bounded_output(output_path) + if completed.returncode != 0: + failure_tail = output.strip()[-4096:] + detail = f":\n{failure_tail}" if failure_tail else "" + raise IsabelleToolError(f"Isabelle kernel rejected the fixed proof session{detail}") + if "Unfinished session(s)" in output or f"Finished {ISABELLE_SESSION}" not in output: + raise IsabelleToolError("Isabelle build did not report a finished proof session") + + return expected_isabelle_result() + + +def _parse_args() -> argparse.Namespace: + parser = argparse.ArgumentParser(description="Acquire or replay the pinned participant-opacity proof tool.") + parser.add_argument("command", choices=("acquire", "verify")) + return parser.parse_args() + + +def main() -> int: + args = _parse_args() + try: + if args.command == "acquire": + acquire_isabelle() + print(f"acquired Isabelle{ISABELLE_VERSION} ({ISABELLE_ARCHIVE_SHA256})") + else: + print(json.dumps(run_isabelle_build(), ensure_ascii=False, sort_keys=True)) + except IsabelleToolError as exc: + print(f"isabelle-tool: {exc}", file=os.sys.stderr) + return 1 + return 0 + + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/tools/parallel_verification.py b/tools/parallel_verification.py new file mode 100644 index 000000000..3eade249f --- /dev/null +++ b/tools/parallel_verification.py @@ -0,0 +1,116 @@ +#!/usr/bin/env python3 +"""Run isolated nox verification lanes concurrently. + +The canonical nox ``verify`` session uses this module to execute independent +lanes in separate processes. Keeping the processes isolated avoids sharing a +``nox.Session`` across threads, while the fixed argv construction preserves the +repository's single nox verification graph. +""" + +from __future__ import annotations + +import os +import subprocess +from collections.abc import Mapping, Sequence +from concurrent.futures import ThreadPoolExecutor +from dataclasses import dataclass, field +from pathlib import Path +from time import perf_counter + + +@dataclass(frozen=True) +class VerificationLane: + """One independently executable nox session in the verification graph.""" + + name: str + nox_session: str + posargs: tuple[str, ...] = () + env: Mapping[str, str] = field(default_factory=dict) + + +@dataclass(frozen=True) +class VerificationLaneResult: + """Captured outcome for one lane.""" + + name: str + returncode: int + output: str + duration_s: float + + +def _run_lane( + lane: VerificationLane, + *, + nox_python: Path, + noxfile: Path, + repo_root: Path, + base_env: Mapping[str, str], +) -> VerificationLaneResult: + command = [ + str(nox_python), + "-m", + "nox", + "-f", + str(noxfile), + "-s", + lane.nox_session, + ] + if lane.posargs: + command.extend(("--", *lane.posargs)) + environment = os.environ.copy() + environment.update(base_env) + environment.update(lane.env) + started = perf_counter() + try: + completed = subprocess.run( + command, + cwd=repo_root, + env=environment, + text=True, + stdout=subprocess.PIPE, + stderr=subprocess.STDOUT, + check=False, + ) + returncode = completed.returncode + output = completed.stdout or "" + except OSError as exc: + returncode = 126 + output = f"unable to start verification lane {lane.name}: {exc}\n" + return VerificationLaneResult( + name=lane.name, + returncode=returncode, + output=output, + duration_s=perf_counter() - started, + ) + + +def run_verification_lanes( + lanes: Sequence[VerificationLane], + *, + nox_python: Path, + noxfile: Path, + repo_root: Path, + base_env: Mapping[str, str] | None = None, + max_workers: int | None = None, +) -> list[VerificationLaneResult]: + """Run all lanes concurrently and return results in declaration order.""" + + if not lanes: + return [] + worker_count = len(lanes) if max_workers is None else max_workers + if worker_count < 1: + raise ValueError("max_workers must be at least one") + environment = dict(base_env or {}) + with ThreadPoolExecutor(max_workers=min(len(lanes), worker_count), thread_name_prefix="verification") as executor: + futures = [ + executor.submit( + _run_lane, + lane, + nox_python=nox_python, + noxfile=noxfile, + repo_root=repo_root, + base_env=environment, + ) + for lane in lanes + ] + return [future.result() for future in futures] diff --git a/tools/policy/adr_policy.yaml b/tools/policy/adr_policy.yaml index 43ecebe62..d314785d3 100644 --- a/tools/policy/adr_policy.yaml +++ b/tools/policy/adr_policy.yaml @@ -218,6 +218,7 @@ module_boundaries: - raes_operations.cross_backend_corpus - raes_operations.techvault_live raes_processor: + - raes_processor.compiler - raes_processor.exploit_path - raes_processor.manifest - raes_processor.models diff --git a/tools/policy/historical_identity_records.json b/tools/policy/historical_identity_records.json index 08194f619..bd89a73ff 100644 --- a/tools/policy/historical_identity_records.json +++ b/tools/policy/historical_identity_records.json @@ -17,7 +17,7 @@ "binding_class": "external-service-project-key", "rationale": "Retains the existing service-owned Ground Control and SonarCloud project designations without treating them as current RAES product identity.", "occurrences": 2, - "content_sha256": "c56a0e9194d21c490e797363b5701d2839195329acf70d110a6eb6ae7069a5e2" + "content_sha256": "f643ca6a31c5d7f0c7adbd82d47a8be0febc9baa815bde16ac1ab3484b2cae24" }, { "path": "sonar-project.properties", @@ -45,9 +45,9 @@ { "path": "docs/decisions/adrs/README.md", "record_class": "historical-index", - "rationale": "Indexes immutable pre-cutover ADR titles, paths, pins, and amendment summaries without making them current identity surf\u0061ces.", + "rationale": "Indexes immutable pre-cutover ADR titles, paths, pins, and amendment summaries without making them current identity surfaces.", "occurrences": 4, - "content_sha256": "af5063b943c1058735df9e4975814688c681248f8c55ed468681722eafa8188c" + "content_sha256": "1112779f7f33a932c90fd5e1bde641199bdf02a9910d89b0207e5ba92ab7562f" }, { "path": "docs/decisions/adrs/adr-000-use-adrs.md", @@ -493,9 +493,9 @@ { "path": "docs/decisions/adrs/adr-index.yaml", "record_class": "historical-index", - "rationale": "Indexes immutable pre-cutover ADR titles, paths, pins, and amendment summaries without making them current identity surf\u0061ces.", + "rationale": "Indexes immutable pre-cutover ADR titles, paths, pins, and amendment summaries without making them current identity surfaces.", "occurrences": 4, - "content_sha256": "550cd54eb8e5636ac8e630efe0aa2cf80e0d36a4561a0f5b640d3ee17d940410" + "content_sha256": "16f7d3e9f87fc6008c7f4333b14e1c8ae993dd6a7925ba4795e0c2b6ce5370a4" }, { "path": "docs/decisions/cage-2-replication-design.md", @@ -1608,21 +1608,21 @@ "record_class": "research-record", "rationale": "Preserves preregistered, frozen, dated, or lineage-bearing research evidence from before the RAES identity cutover.", "occurrences": 1, - "content_sha256": "fff200b23d171334e31ce9da00e921be7ad868b74bf5b4ba21c158277b5db56b" + "content_sha256": "3f8f0205e502add9603834f46fe1931314678429dc3a5b2083d9314bca7d3a50" }, { "path": "docs/research/participant-io-control/current-state-assessment.md", "record_class": "research-record", "rationale": "Preserves preregistered, frozen, dated, or lineage-bearing research evidence from before the RAES identity cutover.", "occurrences": 10, - "content_sha256": "53c30870282bd09b493abddf2f96d966137be04f8af880d1965ad90d655a048e" + "content_sha256": "21cae879bfbd4f35a45b936e6200aa698248eeeb5a5ec37512dfc1f3708ce338" }, { "path": "docs/research/participant-io-control/requirement-disposition.md", "record_class": "research-record", "rationale": "Preserves preregistered, frozen, dated, or lineage-bearing research evidence from before the RAES identity cutover.", "occurrences": 1, - "content_sha256": "b6557a24280525c14a55a209e6c530e8272f255fd6c3e4155a4c37f29dd17d76" + "content_sha256": "7d19d3be360630bc9f50b171323d0cf824e4e48aeae1ad1351aa0621149aca49" }, { "path": "docs/research/primary/index.md", diff --git a/tools/tool_versions.py b/tools/tool_versions.py index 1c1701f8c..afb8ee235 100644 --- a/tools/tool_versions.py +++ b/tools/tool_versions.py @@ -8,3 +8,4 @@ GITLEAKS_VERSION = "8.30.1" OSV_SCANNER_VERSION = "2.4.0" VALE_VERSION = "3.15.2" +ISABELLE_VERSION = "2025-2" diff --git a/tools/verification_plan.py b/tools/verification_plan.py index 337c55607..c715b36d8 100644 --- a/tools/verification_plan.py +++ b/tools/verification_plan.py @@ -46,6 +46,7 @@ class VerificationPlan: "SECURITY.md", } _EVIDENCE_PREFIXES = ("docs/research", "specs") +_PYTHON_TEST_PREFIX = "implementations/python/tests/" def _under(path: str, prefix: str) -> bool: @@ -89,6 +90,24 @@ def plan_for_changes(changes: list[ChangeRecord]) -> VerificationPlan: return FULL_PLAN +def select_changed_python_tests(paths: list[str]) -> list[str]: + """Return directly changed pytest modules in stable first-seen order.""" + + selected: list[str] = [] + seen: set[str] = set() + for path in paths: + candidate = Path(path) + if ( + path.startswith(_PYTHON_TEST_PREFIX) + and candidate.name.startswith("test_") + and candidate.suffix == ".py" + and path not in seen + ): + selected.append(path) + seen.add(path) + return selected + + def _run_git(repo_root: Path, *args: str) -> bytes: proc = subprocess.run( ["git", *args],