From 79dc5b73d7c7cc479a2c5b7b06f4fb9797107cbe Mon Sep 17 00:00:00 2001 From: fraware Date: Mon, 29 Jun 2026 02:52:50 -0700 Subject: [PATCH 01/80] chore: ignore generated out/ artifacts Keep local review outputs out of version control. --- .gitignore | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.gitignore b/.gitignore index 565d76b..018ad21 100644 --- a/.gitignore +++ b/.gitignore @@ -18,3 +18,6 @@ venv/ .scope/ + +out/ + From 3a9736be521b234e2001c0cce22acb94a4e0516b Mon Sep 17 00:00:00 2001 From: fraware Date: Mon, 29 Jun 2026 02:53:25 -0700 Subject: [PATCH 02/80] build: release 0.8.0 in pyproject.toml Align package metadata with the v0.8 institutional audit line. --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 2394796..4647cfd 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta" [project] name = "scope-protocol" -version = "0.7.0" +version = "0.8.0" description = "Scoped Scientific Authorization Protocol for AI-shaped science" readme = "README.md" license = { text = "MIT" } From 021be94a657c7d0dd6338e21d9db0e3ad4e627c3 Mon Sep 17 00:00:00 2001 From: fraware Date: Mon, 29 Jun 2026 02:53:25 -0700 Subject: [PATCH 03/80] build: set scope._version to 0.8.0 Single source for runtime version reporting. --- scope/_version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scope/_version.py b/scope/_version.py index 02d8239..d6977ce 100644 --- a/scope/_version.py +++ b/scope/_version.py @@ -1,3 +1,3 @@ """Package version (single source of truth).""" -__version__ = "0.7.0" +__version__ = "0.8.0" From 1a32948ebe55d624d088eb86b8aa22dd08ce222e Mon Sep 17 00:00:00 2001 From: fraware Date: Mon, 29 Jun 2026 02:53:25 -0700 Subject: [PATCH 04/80] docs: add CHANGELOG section for v0.8.0 Document session mode, reviewer binding, and pilot fixtures. --- CHANGELOG.md | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3cbb1c7..c7cf232 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,16 @@ # Changelog +## v0.8.0 (2026-06-29) + +Session workflow and provenance release: + +- **`scope akta review --session`**: multi-role packets create a review session first; session summary schema (`scope_akta_review_session_summary.schema.json`) +- **`--reviewer-id` binding**: CLI and REST pass reviewer ID to `run_akta_review()`; must match reviewer artifact for registry signing +- **Session grant provenance**: `scope/session_provenance.py` aggregates contributing IAL/SAL, authority checks, veto roles, and quorum policy hash on session grants +- **Pilot fixture pack**: `examples/pilot/` with five institutional scenarios +- Quality report `report_version` `0.8` +- Policy bundle tagged `scope-core-v0.8`; AKTA review contract `scope-akta-review-v0.8` + ## v0.7.0 (2026-06-28) Institutional pilot hardening release: From cb4d62a58da9a36cc6635974093cedee9e95f585 Mon Sep 17 00:00:00 2001 From: fraware Date: Mon, 29 Jun 2026 02:53:26 -0700 Subject: [PATCH 05/80] policy: tag approval_scopes.yaml as scope-core-v0.8 Bump core policy bundle version for v0.8 releases. --- policy/approval_scopes.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/policy/approval_scopes.yaml b/policy/approval_scopes.yaml index 0070e8e..bddc262 100644 --- a/policy/approval_scopes.yaml +++ b/policy/approval_scopes.yaml @@ -1,4 +1,4 @@ -version: scope-core-v0.7 +version: scope-core-v0.8 hierarchy: - no_action - clarification_only From 327ec7b62e20be71681b10dd25ac2d3000e4cee4 Mon Sep 17 00:00:00 2001 From: fraware Date: Mon, 29 Jun 2026 02:53:26 -0700 Subject: [PATCH 06/80] policy: tag blocked_tool_severity.yaml as scope-core-v0.8 Bump core policy bundle version for v0.8 releases. --- policy/blocked_tool_severity.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/policy/blocked_tool_severity.yaml b/policy/blocked_tool_severity.yaml index 793bd44..8a8f6de 100644 --- a/policy/blocked_tool_severity.yaml +++ b/policy/blocked_tool_severity.yaml @@ -1,4 +1,4 @@ -version: scope-core-v0.7 +version: scope-core-v0.8 high_severity: - robot_queue.submit - protocol_editor.update_active_protocol From 37e690932e57bf33f77b4095b9a38263aea59aec Mon Sep 17 00:00:00 2001 From: fraware Date: Mon, 29 Jun 2026 02:53:26 -0700 Subject: [PATCH 07/80] policy: tag decision_options.yaml as scope-core-v0.8 Bump core policy bundle version for v0.8 releases. --- policy/decision_options.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/policy/decision_options.yaml b/policy/decision_options.yaml index 445713f..6a10d98 100644 --- a/policy/decision_options.yaml +++ b/policy/decision_options.yaml @@ -1,4 +1,4 @@ -version: scope-core-v0.7 +version: scope-core-v0.8 decision_types: - approve - approve_with_modifications From 931d70ae25074a49b08328d4ba90cb799917678c Mon Sep 17 00:00:00 2001 From: fraware Date: Mon, 29 Jun 2026 02:53:26 -0700 Subject: [PATCH 08/80] policy: tag expiration_rules.yaml as scope-core-v0.8 Bump core policy bundle version for v0.8 releases. --- policy/expiration_rules.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/policy/expiration_rules.yaml b/policy/expiration_rules.yaml index 143bf53..d61dee3 100644 --- a/policy/expiration_rules.yaml +++ b/policy/expiration_rules.yaml @@ -1,4 +1,4 @@ -version: scope-core-v0.7 +version: scope-core-v0.8 default_expiration: protocol_draft: expires_after: From a2a3c9d7c4b4a173497e1c249ff4ab6b58dcf3e0 Mon Sep 17 00:00:00 2001 From: fraware Date: Mon, 29 Jun 2026 02:53:27 -0700 Subject: [PATCH 09/80] policy: tag identity_mapping.yaml as scope-core-v0.8 Bump core policy bundle version for v0.8 releases. --- policy/identity_mapping.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/policy/identity_mapping.yaml b/policy/identity_mapping.yaml index 9d4a951..53e689d 100644 --- a/policy/identity_mapping.yaml +++ b/policy/identity_mapping.yaml @@ -1,4 +1,4 @@ -version: scope-core-v0.7 +version: scope-core-v0.8 description: Map OIDC JWT claims to SCOPE reviewer identity. claim_mappings: reviewer_id: sub From 6c6a574d3639b22c519acfbb8d573622bde59f7a Mon Sep 17 00:00:00 2001 From: fraware Date: Mon, 29 Jun 2026 02:53:27 -0700 Subject: [PATCH 10/80] policy: tag minimum_signing_assurance.yaml as scope-core-v0.8 Bump core policy bundle version for v0.8 releases. --- policy/minimum_signing_assurance.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/policy/minimum_signing_assurance.yaml b/policy/minimum_signing_assurance.yaml index c5e6550..76f6810 100644 --- a/policy/minimum_signing_assurance.yaml +++ b/policy/minimum_signing_assurance.yaml @@ -1,4 +1,4 @@ -version: scope-core-v0.7 +version: scope-core-v0.8 minimum_level: SAL1 high_risk_minimum_level: SAL3 enforce_in_development: false From cba45814cd4630a23714710c347f4e820db51c6b Mon Sep 17 00:00:00 2001 From: fraware Date: Mon, 29 Jun 2026 02:53:27 -0700 Subject: [PATCH 11/80] policy: tag org_rbac.yaml as scope-core-v0.8 Bump core policy bundle version for v0.8 releases. --- policy/org_rbac.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/policy/org_rbac.yaml b/policy/org_rbac.yaml index 085ee9a..e8511fd 100644 --- a/policy/org_rbac.yaml +++ b/policy/org_rbac.yaml @@ -1,4 +1,4 @@ -version: scope-core-v0.7 +version: scope-core-v0.8 org_units: genomics_lab: members: From 7066492e0a1642753c86c31dafa912331bd6f2ef Mon Sep 17 00:00:00 2001 From: fraware Date: Mon, 29 Jun 2026 02:53:27 -0700 Subject: [PATCH 12/80] policy: tag quality_metrics.yaml as scope-core-v0.8 Bump core policy bundle version for v0.8 releases. --- policy/quality_metrics.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/policy/quality_metrics.yaml b/policy/quality_metrics.yaml index a03c92f..701af90 100644 --- a/policy/quality_metrics.yaml +++ b/policy/quality_metrics.yaml @@ -1,4 +1,4 @@ -version: scope-core-v0.7 +version: scope-core-v0.8 thresholds: rubber_stamp_min_review_seconds: 20 rubber_stamp_high_risk_count: 10 From 63a5387d3f96e50dd3d673819d224e59aee33f2f Mon Sep 17 00:00:00 2001 From: fraware Date: Mon, 29 Jun 2026 02:53:28 -0700 Subject: [PATCH 13/80] policy: tag reviewer_assignments.yaml as scope-core-v0.8 Bump core policy bundle version for v0.8 releases. --- policy/reviewer_assignments.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/policy/reviewer_assignments.yaml b/policy/reviewer_assignments.yaml index fc7caa6..861e6ef 100644 --- a/policy/reviewer_assignments.yaml +++ b/policy/reviewer_assignments.yaml @@ -1,4 +1,4 @@ -version: scope-core-v0.7 +version: scope-core-v0.8 description: Default reviewer assignments by role for auto-assignment. assignments: domain_scientist: ds1 From 2f001f85e94c912d7d856472960b63189853a1a4 Mon Sep 17 00:00:00 2001 From: fraware Date: Mon, 29 Jun 2026 02:53:28 -0700 Subject: [PATCH 14/80] policy: tag reviewer_key_registry.yaml as scope-core-v0.8 Bump core policy bundle version for v0.8 releases. --- policy/reviewer_key_registry.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/policy/reviewer_key_registry.yaml b/policy/reviewer_key_registry.yaml index daae7ce..783a22d 100644 --- a/policy/reviewer_key_registry.yaml +++ b/policy/reviewer_key_registry.yaml @@ -1,4 +1,4 @@ -version: scope-core-v0.7 +version: scope-core-v0.8 description: | Optional local registry mapping reviewer_id to expected public key references. Institutions populate this file; empty registry skips identity binding checks. From 0ae847fab00d456bea78e0cda110ad2ca90f0d08 Mon Sep 17 00:00:00 2001 From: fraware Date: Mon, 29 Jun 2026 02:53:28 -0700 Subject: [PATCH 15/80] policy: tag reviewer_roles.yaml as scope-core-v0.8 Bump core policy bundle version for v0.8 releases. --- policy/reviewer_roles.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/policy/reviewer_roles.yaml b/policy/reviewer_roles.yaml index 3617b08..25b0835 100644 --- a/policy/reviewer_roles.yaml +++ b/policy/reviewer_roles.yaml @@ -1,4 +1,4 @@ -version: scope-core-v0.7 +version: scope-core-v0.8 roles: domain_scientist: description: Reviews scientific plausibility, domain assumptions, and interpretation. From c7079a39bd3e43a11998f3bd8b8523172cf0d70a Mon Sep 17 00:00:00 2001 From: fraware Date: Mon, 29 Jun 2026 02:53:28 -0700 Subject: [PATCH 16/80] policy: tag role_to_action_matrix.yaml as scope-core-v0.8 Bump core policy bundle version for v0.8 releases. --- policy/role_to_action_matrix.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/policy/role_to_action_matrix.yaml b/policy/role_to_action_matrix.yaml index 9760347..f69632b 100644 --- a/policy/role_to_action_matrix.yaml +++ b/policy/role_to_action_matrix.yaml @@ -1,4 +1,4 @@ -version: scope-core-v0.7 +version: scope-core-v0.8 matrix: A3_evidence_interpretation_consequential: required_roles: From 85e94a9d828d19e5f8a940f4b27106463f919d19 Mon Sep 17 00:00:00 2001 From: fraware Date: Mon, 29 Jun 2026 02:53:29 -0700 Subject: [PATCH 17/80] policy: tag scope_to_tool_matrix.yaml as scope-core-v0.8 Bump core policy bundle version for v0.8 releases. --- policy/scope_to_tool_matrix.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/policy/scope_to_tool_matrix.yaml b/policy/scope_to_tool_matrix.yaml index 7b4c7b9..412cf79 100644 --- a/policy/scope_to_tool_matrix.yaml +++ b/policy/scope_to_tool_matrix.yaml @@ -1,4 +1,4 @@ -version: scope-core-v0.7 +version: scope-core-v0.8 scopes: no_action: allowed_tools: [] From 8822935c6aea0cd64f3bec556fa1266351385041 Mon Sep 17 00:00:00 2001 From: fraware Date: Mon, 29 Jun 2026 02:53:29 -0700 Subject: [PATCH 18/80] policy: tag workflow_escalation.yaml as scope-core-v0.8 Bump core policy bundle version for v0.8 releases. --- policy/workflow_escalation.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/policy/workflow_escalation.yaml b/policy/workflow_escalation.yaml index 96dba53..24eb0fe 100644 --- a/policy/workflow_escalation.yaml +++ b/policy/workflow_escalation.yaml @@ -1,4 +1,4 @@ -version: scope-core-v0.7 +version: scope-core-v0.8 escalation_reviewer: reviewer_id: pi1 role: principal_investigator From bb08b9bc7c85f08557290c816793bcbd88aaf5bc Mon Sep 17 00:00:00 2001 From: fraware Date: Mon, 29 Jun 2026 02:53:29 -0700 Subject: [PATCH 19/80] feat(integration): scope-akta-review-v0.8 contract version Keep adapter contract constant in sync with v0.8 review outputs. --- scope/integration_versions.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scope/integration_versions.py b/scope/integration_versions.py index 79005b6..d27e61e 100644 --- a/scope/integration_versions.py +++ b/scope/integration_versions.py @@ -4,5 +4,5 @@ PF_CORE_VERSION = "pf-core-v0.5" PCS_MANIFEST_VERSION = "pcs-v0.5" -SCOPE_CORE_VERSION = "scope-core-v0.7" -AKTA_REVIEW_CONTRACT_VERSION = "scope-akta-review-v0.7" +SCOPE_CORE_VERSION = "scope-core-v0.8" +AKTA_REVIEW_CONTRACT_VERSION = "scope-akta-review-v0.8" From 879621d7036d6709e0bd47845aa387633b1fc306 Mon Sep 17 00:00:00 2001 From: fraware Date: Mon, 29 Jun 2026 02:53:29 -0700 Subject: [PATCH 20/80] feat(quality): quality report_version 0.8 Report generation identifies the v0.8 metrics baseline. --- scope/quality.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scope/quality.py b/scope/quality.py index 1251480..f752d32 100644 --- a/scope/quality.py +++ b/scope/quality.py @@ -256,7 +256,7 @@ def analyze_ledger(events: list[dict[str, Any]], policy: PolicyStore) -> dict[st by_action_type = _by_action_type(decisions, stale) return { - "report_version": "0.7", + "report_version": "0.8", "policy_version": policy.version, "summary": { "total_decisions": len(decisions), From 6b53241ca3a292282a3a1735ffbe16c7acc30cc6 Mon Sep 17 00:00:00 2001 From: fraware Date: Mon, 29 Jun 2026 02:54:04 -0700 Subject: [PATCH 21/80] feat(schema): AKTA review session summary artifact Validate session_required summaries emitted under out_dir. --- ...pe_akta_review_session_summary.schema.json | 30 +++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 schemas/scope_akta_review_session_summary.schema.json diff --git a/schemas/scope_akta_review_session_summary.schema.json b/schemas/scope_akta_review_session_summary.schema.json new file mode 100644 index 0000000..d295bea --- /dev/null +++ b/schemas/scope_akta_review_session_summary.schema.json @@ -0,0 +1,30 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://scope.dev/schemas/scope_akta_review_session_summary.schema.json", + "title": "SCOPE AKTA Review Session Summary", + "type": "object", + "required": [ + "status", + "packet_id", + "session_id", + "required_roles", + "message", + "adapter_contract_version", + "production_mode" + ], + "properties": { + "status": { "const": "session_required" }, + "packet_id": { "type": "string" }, + "session_id": { "type": "string" }, + "required_roles": { + "type": "array", + "items": { "type": "string" } + }, + "message": { "type": "string" }, + "requested_scope": { "type": ["string", "null"] }, + "packet_path": { "type": "string" }, + "adapter_contract_version": { "type": "string" }, + "production_mode": { "type": "boolean" } + }, + "additionalProperties": true +} From b6ebd2034325b154e2c269a22fa5e65c624ee251 Mon Sep 17 00:00:00 2001 From: fraware Date: Mon, 29 Jun 2026 02:54:05 -0700 Subject: [PATCH 22/80] fix(akta): create session before multi-role rejection when --session Multi-role packets can enter review session workflow instead of failing at the gate. --- scope/akta_review.py | 78 +++++++++++++++++++++++++++++++++++++------- 1 file changed, 67 insertions(+), 11 deletions(-) diff --git a/scope/akta_review.py b/scope/akta_review.py index 9cb4af0..90a7b44 100644 --- a/scope/akta_review.py +++ b/scope/akta_review.py @@ -103,6 +103,54 @@ def _resolve_signer( return None +def _resolve_reviewer_id( + reviewer_data: dict[str, Any], + reviewer_id: str | None, +) -> str: + """Validate optional CLI reviewer_id against reviewer artifact.""" + artifact_id = reviewer_data.get("reviewer_id") + if reviewer_id is not None: + if not artifact_id: + raise ScopeValidationError("Reviewer artifact missing reviewer_id") + if str(reviewer_id) != str(artifact_id): + raise ScopeValidationError( + f"--reviewer-id {reviewer_id!r} does not match reviewer artifact " + f"reviewer_id {artifact_id!r}" + ) + return str(reviewer_id) + if not artifact_id: + raise ScopeValidationError("Reviewer artifact missing reviewer_id") + return str(artifact_id) + + +def _write_session_summary( + out: Path, + *, + packet: dict[str, Any], + session_id: str, + required_roles: list[str], + packet_path: Path, +) -> dict[str, Any]: + summary_path = out / "summary.json" + requested_scope = packet["review_request"].get("requested_scope") + summary: dict[str, Any] = { + "status": "session_required", + "packet_id": packet["packet_id"], + "session_id": session_id, + "required_roles": required_roles, + "message": "Multi-role review session created; submit votes before grant issue.", + "requested_scope": requested_scope, + "packet_path": str(packet_path), + "adapter_contract_version": AKTA_REVIEW_CONTRACT_VERSION, + "production_mode": is_production_mode(), + } + validate_artifact(summary, "scope_akta_review_session_summary.schema.json") + with summary_path.open("w", encoding="utf-8") as fh: + json.dump(summary, fh, indent=2, sort_keys=True) + fh.write("\n") + return summary + + def run_akta_review( engine: ScopeEngine, *, @@ -114,6 +162,7 @@ def run_akta_review( out_dir: str | Path, signing_key: str | Path | None = None, signing_provider: str | None = None, + reviewer_id: str | None = None, queue_dir: str | Path | None = None, identity_token: str | None = None, session_mode: bool = False, @@ -130,19 +179,26 @@ def run_akta_review( with Path(reviewer).open(encoding="utf-8") as fh: reviewer_data = json.load(fh) - _check_multi_role_requirement(engine, packet) + resolved_reviewer_id = _resolve_reviewer_id(reviewer_data, reviewer_id) if session_mode: session = engine.create_review_session(packet) - return { - "status": "session_required", - "packet_id": packet["packet_id"], - "session_id": session.session_id, - "required_roles": resolve_review_assignment(packet, engine.policy).get( - "required_roles", [] - ), - "message": "Multi-role review session created; submit votes before grant issue.", - } + required_roles = resolve_review_assignment(packet, engine.policy).get( + "required_roles", [] + ) + packet_path = out / "scope_review_packet.json" + with packet_path.open("w", encoding="utf-8") as fh: + json.dump(packet, fh, indent=2, sort_keys=True) + fh.write("\n") + return _write_session_summary( + out, + packet=packet, + session_id=session.session_id, + required_roles=required_roles, + packet_path=packet_path, + ) + + _check_multi_role_requirement(engine, packet) if engine.ledger.path: engine.open_review(packet["packet_id"], actor_id=reviewer_data.get("reviewer_id")) @@ -162,7 +218,7 @@ def run_akta_review( engine, signing_key=signing_key, signing_provider=signing_provider, - reviewer_id=str(reviewer_data.get("reviewer_id", "")), + reviewer_id=resolved_reviewer_id, ) if is_production_mode(): if signer is None: From 9f9aad21934c20180a89e988ea93657f8ca3bda6 Mon Sep 17 00:00:00 2001 From: fraware Date: Mon, 29 Jun 2026 02:54:05 -0700 Subject: [PATCH 23/80] feat(cli): echo session_required outcome from akta review Surface session id and required roles when --session defers grant issue. --- scope/cli.py | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/scope/cli.py b/scope/cli.py index 27e8945..239b2c1 100644 --- a/scope/cli.py +++ b/scope/cli.py @@ -388,14 +388,21 @@ def akta_review( out_dir=out_dir, signing_key=signing_key, signing_provider=signing_provider, + reviewer_id=reviewer_id, queue_dir=queue_dir, identity_token=identity_token, session_mode=session, ) - click.echo( - f"AKTA review complete: grant {summary['grant_id']} " - f"({summary['approved_scope']}) -> {out_dir}" - ) + if summary.get("status") == "session_required": + click.echo( + f"Multi-role session required: {summary['session_id']} " + f"(roles: {', '.join(summary['required_roles'])}) -> {out_dir}" + ) + else: + click.echo( + f"AKTA review complete: grant {summary['grant_id']} " + f"({summary['approved_scope']}) -> {out_dir}" + ) @main.group("export") From e95e7e46df05c9e28a544b17bdc128c05882a2a4 Mon Sep 17 00:00:00 2001 From: fraware Date: Mon, 29 Jun 2026 02:54:05 -0700 Subject: [PATCH 24/80] test(akta): session mode summary and packet artifacts Lock control-flow and schema validation for --session. --- tests/test_akta_review_session_mode.py | 138 +++++++++++++++++++++++++ 1 file changed, 138 insertions(+) create mode 100644 tests/test_akta_review_session_mode.py diff --git a/tests/test_akta_review_session_mode.py b/tests/test_akta_review_session_mode.py new file mode 100644 index 0000000..391ce8a --- /dev/null +++ b/tests/test_akta_review_session_mode.py @@ -0,0 +1,138 @@ +"""Tests for scope akta review --session control flow (SCOPE-1).""" + +from __future__ import annotations + +import json +from pathlib import Path + +import pytest +from click.testing import CliRunner + +from scope import ScopeEngine +from scope.akta_review import run_akta_review +from scope.cli import main +from scope.errors import ScopeValidationError +from scope.schema_util import validate_artifact + +ROOT = Path(__file__).resolve().parent.parent +WEAK = ROOT / "examples" / "weak_evidence_validation_review" + + +def _a6_trigger() -> dict: + return { + "akta_admissibility": "review_required", + "scientific_action_type": "A6_experimental_planning", + "requested_action": "plan_validation", + "requested_tool": "experiment_planner.create_validation_plan", + "requested_scope": "single_validation_plan", + "scientific_context": { + "protocol_version": "protocol_v1", + "evidence_state": "E1_hypothesis", + }, + } + + +def test_multi_role_without_session_fails_explicit_message(tmp_path: Path) -> None: + engine = ScopeEngine.from_policy_dir(ROOT / "policy") + with pytest.raises(ScopeValidationError, match="multi-role review session"): + run_akta_review( + engine, + akta_record={ + "record_id": "AKTA-A6", + "scientific_action_type": "A6_experimental_planning", + }, + akta_trigger=_a6_trigger(), + grant_scope="single_validation_plan", + reviewer={"reviewer_id": "ds1", "role": "domain_scientist"}, + decision_rationale="solo attempt", + out_dir=tmp_path / "out", + ) + + +def test_multi_role_with_session_creates_session(tmp_path: Path) -> None: + engine = ScopeEngine.from_policy_dir(ROOT / "policy") + out_dir = tmp_path / "session_out" + summary = run_akta_review( + engine, + akta_record={ + "record_id": "AKTA-A6", + "scientific_action_type": "A6_experimental_planning", + }, + akta_trigger=_a6_trigger(), + grant_scope="single_validation_plan", + reviewer=WEAK / "reviewer_protocol_owner.json", + decision_rationale="session path", + out_dir=out_dir, + session_mode=True, + ) + assert summary["status"] == "session_required" + assert summary["session_id"].startswith("SCOPE-SESS-") + assert set(summary["required_roles"]) == {"domain_scientist", "protocol_owner"} + assert (out_dir / "scope_review_packet.json").exists() + assert (out_dir / "summary.json").exists() + assert not (out_dir / "scope_grant.json").exists() + + on_disk = json.loads((out_dir / "summary.json").read_text(encoding="utf-8")) + validate_artifact(on_disk, "scope_akta_review_session_summary.schema.json") + assert on_disk["adapter_contract_version"] == "scope-akta-review-v0.8" + + +def test_akta_review_cli_session_flag(tmp_path: Path) -> None: + out_dir = tmp_path / "cli_session" + runner = CliRunner() + result = runner.invoke( + main, + [ + "akta", + "review", + "--akta-trigger", + str(WEAK / "review_trigger.json"), + "--akta-record", + str(WEAK / "akta_record.json"), + "--grant-scope", + "single_validation_run_draft", + "--reviewer", + str(WEAK / "reviewer_protocol_owner.json"), + "--decision-rationale", + "Need co-review.", + "--out-dir", + str(out_dir), + "--session", + "--policy", + str(ROOT / "policy"), + ], + ) + assert result.exit_code == 0, result.output + assert "Multi-role session required" in result.output + summary = json.loads((out_dir / "summary.json").read_text(encoding="utf-8")) + assert summary["status"] == "session_required" + validate_artifact(summary, "scope_akta_review_session_summary.schema.json") + + +def test_akta_review_cli_multi_role_without_session_fails(tmp_path: Path) -> None: + out_dir = tmp_path / "cli_fail" + runner = CliRunner() + result = runner.invoke( + main, + [ + "akta", + "review", + "--akta-trigger", + str(WEAK / "review_trigger.json"), + "--akta-record", + str(WEAK / "akta_record.json"), + "--grant-scope", + "single_validation_run_draft", + "--reviewer", + str(WEAK / "reviewer_protocol_owner.json"), + "--decision-rationale", + "Solo attempt.", + "--out-dir", + str(out_dir), + "--policy", + str(ROOT / "policy"), + ], + ) + assert result.exit_code != 0 + message = str(result.exception or result.output) + assert "multi-role review session" in message.lower() or "--session" in message From 44af64344240542280f6c10c3643121b35a3408c Mon Sep 17 00:00:00 2001 From: fraware Date: Mon, 29 Jun 2026 02:54:06 -0700 Subject: [PATCH 25/80] eval: extended scenario akta_review_session_mode Regression for session summary contract in eval harness. --- .../extended/akta_review_session_mode.json | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 evals/scenarios/extended/akta_review_session_mode.json diff --git a/evals/scenarios/extended/akta_review_session_mode.json b/evals/scenarios/extended/akta_review_session_mode.json new file mode 100644 index 0000000..dad200c --- /dev/null +++ b/evals/scenarios/extended/akta_review_session_mode.json @@ -0,0 +1,27 @@ +{ + "name": "akta_review_session_mode", + "run_akta_review": true, + "session_mode": true, + "akta_record": { + "record_id": "AKTA-EVAL-SESSION", + "scientific_action_type": "A6_experimental_planning" + }, + "akta_trigger": { + "akta_admissibility": "review_required", + "scientific_action_type": "A6_experimental_planning", + "requested_action": "plan_validation", + "requested_tool": "experiment_planner.create_validation_plan", + "requested_scope": "single_validation_plan", + "scientific_context": { + "protocol_version": "protocol_v1", + "evidence_state": "E1_hypothesis" + } + }, + "reviewer": {"reviewer_id": "po1", "role": "protocol_owner"}, + "decision": { + "type": "approve_narrower_scope", + "approved_scope": "single_validation_plan", + "rationale": "Session mode AKTA review contract validation" + }, + "grant_scope": "single_validation_plan" +} From 7cbac17842b49031a8dda6cb2d4d3b20d639e348 Mon Sep 17 00:00:00 2001 From: fraware Date: Mon, 29 Jun 2026 02:54:06 -0700 Subject: [PATCH 26/80] test(akta): --reviewer-id binding to reviewer artifact Reject mismatched CLI reviewer_id before signing. --- tests/test_akta_review_reviewer_id_binding.py | 121 ++++++++++++++++++ 1 file changed, 121 insertions(+) create mode 100644 tests/test_akta_review_reviewer_id_binding.py diff --git a/tests/test_akta_review_reviewer_id_binding.py b/tests/test_akta_review_reviewer_id_binding.py new file mode 100644 index 0000000..c316550 --- /dev/null +++ b/tests/test_akta_review_reviewer_id_binding.py @@ -0,0 +1,121 @@ +"""Tests for --reviewer-id binding in akta review (SCOPE-2).""" + +from __future__ import annotations + +import json +import shutil +from pathlib import Path + +import pytest +import yaml +from click.testing import CliRunner + +from scope import ScopeEngine +from scope.akta_review import run_akta_review +from scope.cli import main +from scope.errors import ScopeValidationError +from scope.key_registry import register_reviewer_key +from scope.signing import Ed25519Signer + +ROOT = Path(__file__).resolve().parent.parent +EX = ROOT / "examples" / "protocol_change_review" + + +def _policy_with_registry_signer(tmp_path: Path) -> tuple[Path, Path]: + policy_dir = tmp_path / "policy" + shutil.copytree(ROOT / "policy", policy_dir) + key = tmp_path / "reviewer.pem" + pub = tmp_path / "reviewer.pub" + Ed25519Signer.generate_keypair(key, pub) + register_reviewer_key(policy_dir, "reviewer_001", pub) + registry_path = policy_dir / "reviewer_key_registry.yaml" + registry = yaml.safe_load(registry_path.read_text(encoding="utf-8")) + registry["reviewers"]["reviewer_001"]["signing_key_path"] = str(key) + registry_path.write_text(yaml.safe_dump(registry, sort_keys=False), encoding="utf-8") + return policy_dir, key + + +def test_reviewer_id_mismatch_fails(tmp_path: Path) -> None: + engine = ScopeEngine.from_policy_dir(ROOT / "policy") + with pytest.raises(ScopeValidationError, match="does not match reviewer artifact"): + run_akta_review( + engine, + akta_record=EX / "akta_record.json", + akta_trigger=EX / "review_trigger.json", + grant_scope="protocol_draft", + reviewer=EX / "reviewer_protocol_owner.json", + decision_rationale="mismatch test", + out_dir=tmp_path / "out", + reviewer_id="wrong_reviewer_id", + ) + + +def test_reviewer_id_passed_to_registry_signing(tmp_path: Path) -> None: + policy_dir, _key = _policy_with_registry_signer(tmp_path) + engine = ScopeEngine.from_policy_dir(policy_dir) + out_dir = tmp_path / "signed_out" + summary = run_akta_review( + engine, + akta_record=EX / "akta_record.json", + akta_trigger=EX / "review_trigger.json", + grant_scope="protocol_draft", + reviewer=EX / "reviewer_protocol_owner.json", + decision_rationale="registry signing", + out_dir=out_dir, + signing_provider="registry", + reviewer_id="reviewer_001", + ) + assert summary["status"] == "completed" + decision = json.loads((out_dir / "scope_decision.json").read_text(encoding="utf-8")) + assert decision.get("decision_signature") + assert decision["reviewer"]["reviewer_id"] == "reviewer_001" + + +def test_cli_passes_reviewer_id_to_run(tmp_path: Path) -> None: + policy_dir, _key = _policy_with_registry_signer(tmp_path) + out_dir = tmp_path / "cli_out" + runner = CliRunner() + result = runner.invoke( + main, + [ + "akta", + "review", + "--akta-trigger", + str(EX / "review_trigger.json"), + "--akta-record", + str(EX / "akta_record.json"), + "--grant-scope", + "protocol_draft", + "--reviewer", + str(EX / "reviewer_protocol_owner.json"), + "--decision-rationale", + "CLI registry path.", + "--out-dir", + str(out_dir), + "--signing-provider", + "registry", + "--reviewer-id", + "reviewer_001", + "--policy", + str(policy_dir), + ], + ) + assert result.exit_code == 0, result.output + decision = json.loads((out_dir / "scope_decision.json").read_text(encoding="utf-8")) + assert decision.get("decision_signature") + + +def test_registry_uses_artifact_reviewer_id_without_cli_flag(tmp_path: Path) -> None: + policy_dir, _key = _policy_with_registry_signer(tmp_path) + engine = ScopeEngine.from_policy_dir(policy_dir) + with pytest.raises(ScopeValidationError, match="No registry entry"): + run_akta_review( + engine, + akta_record=EX / "akta_record.json", + akta_trigger=EX / "review_trigger.json", + grant_scope="protocol_draft", + reviewer={"reviewer_id": "unknown_reviewer", "role": "protocol_owner"}, + decision_rationale="no registry entry", + out_dir=tmp_path / "out", + signing_provider="registry", + ) From 6bf43f151343061bcca21dbc3ec54201151ff3cc Mon Sep 17 00:00:00 2001 From: fraware Date: Mon, 29 Jun 2026 02:54:06 -0700 Subject: [PATCH 27/80] feat(rest): pass reviewer_id and session_mode on akta review Expose v0.8 AKTA review parameters on the generic REST adapter. --- adapters/generic_rest/server.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/adapters/generic_rest/server.py b/adapters/generic_rest/server.py index 28434f5..aeeac1e 100644 --- a/adapters/generic_rest/server.py +++ b/adapters/generic_rest/server.py @@ -212,6 +212,11 @@ class AktaReviewRequest(BaseModel): decision_rationale: str out_dir: str | None = None signing_key_path: str | None = None + signing_provider: str | None = None + reviewer_id: str | None = None + identity_token: str | None = None + queue_dir: str | None = None + session_mode: bool = False def _http_error(exc: Exception) -> HTTPException: @@ -397,6 +402,11 @@ def akta_review(req: AktaReviewRequest) -> dict[str, Any]: decision_rationale=req.decision_rationale, out_dir=out_dir, signing_key=req.signing_key_path, + signing_provider=req.signing_provider, + reviewer_id=req.reviewer_id, + identity_token=req.identity_token, + queue_dir=req.queue_dir, + session_mode=req.session_mode, ) return summary except HTTPException: From d267d7e9269ab8d7f41a86db5ac2763a84cd1928 Mon Sep 17 00:00:00 2001 From: fraware Date: Mon, 29 Jun 2026 02:54:06 -0700 Subject: [PATCH 28/80] test(rest): akta review session and reviewer_id HTTP paths Cover REST session summaries and reviewer_id mismatch errors. --- tests/test_rest_api.py | 45 ++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 43 insertions(+), 2 deletions(-) diff --git a/tests/test_rest_api.py b/tests/test_rest_api.py index bd0b1c0..00d14d9 100644 --- a/tests/test_rest_api.py +++ b/tests/test_rest_api.py @@ -336,8 +336,8 @@ def test_quality_endpoint(client): resp = client.get("/v0/quality") assert resp.status_code == 200 body = resp.json() - assert body["report_version"] == "0.7" - assert body["policy_version"] == "scope-core-v0.7" + assert body["report_version"] == "0.8" + assert body["policy_version"] == "scope-core-v0.8" assert "metrics" in body assert "warnings" in body @@ -387,6 +387,47 @@ def test_akta_review_rest_endpoint(client, tmp_path): assert (out_dir / "scope_grant.json").exists() +def test_akta_review_rest_session_mode(client, tmp_path): + from scope.schema_util import validate_artifact + + weak = ROOT / "examples" / "weak_evidence_validation_review" + out_dir = tmp_path / "akta_session" + payload = { + "akta_record": _load("akta_record.json", weak), + "akta_trigger": _load("review_trigger.json", weak), + "grant_scope": "single_validation_run_draft", + "reviewer": _load("reviewer_protocol_owner.json", weak), + "decision_rationale": "REST session mode.", + "out_dir": str(out_dir), + "session_mode": True, + } + resp = client.post("/v0/akta/review", json=payload) + assert resp.status_code == 200 + summary = resp.json() + assert summary["status"] == "session_required" + assert summary["session_id"].startswith("SCOPE-SESS-") + assert summary["adapter_contract_version"] == "scope-akta-review-v0.8" + validate_artifact(summary, "scope_akta_review_session_summary.schema.json") + assert (out_dir / "scope_review_packet.json").exists() + assert not (out_dir / "scope_grant.json").exists() + + +def test_akta_review_rest_reviewer_id_mismatch(client, tmp_path): + out_dir = tmp_path / "akta_mismatch" + payload = { + "akta_record": _load("akta_record.json", DRIFT), + "akta_trigger": _load("review_trigger.json", DRIFT), + "grant_scope": "protocol_draft", + "reviewer": _load("reviewer_protocol_owner.json", DRIFT), + "decision_rationale": "Mismatch test.", + "out_dir": str(out_dir), + "reviewer_id": "wrong_reviewer_id", + } + resp = client.post("/v0/akta/review", json=payload) + assert resp.status_code == 400 + assert "does not match" in resp.json()["detail"] + + def test_drift_example_packet(client): payload = { "akta_record": _load("akta_record.json", DRIFT), From 4a98e642bd3a421031dee21d6bfcb5d26feebf54 Mon Sep 17 00:00:00 2001 From: fraware Date: Mon, 29 Jun 2026 02:54:07 -0700 Subject: [PATCH 29/80] feat(provenance): aggregate session grant provenance Merge multi-review identity and authority fields into session grants. --- scope/session_provenance.py | 74 +++++++++++++++++++++++++++++++++++++ 1 file changed, 74 insertions(+) create mode 100644 scope/session_provenance.py diff --git a/scope/session_provenance.py b/scope/session_provenance.py new file mode 100644 index 0000000..fbf8116 --- /dev/null +++ b/scope/session_provenance.py @@ -0,0 +1,74 @@ +"""Aggregate provenance from multi-reviewer session grants.""" + +from __future__ import annotations + +from typing import Any + +from scope.hash import compute_hash +from scope.identity_assurance import IAL0, IAL1, IAL2, IAL3, IAL4 +from scope.review_session import ReviewSession +from scope.signing_assurance import SAL0, SAL1, SAL2, SAL3, SAL4, resolve_signing_assurance_level + +IAL_RANK = {IAL0: 0, IAL1: 1, IAL2: 2, IAL3: 3, IAL4: 4} +SAL_RANK = {SAL0: 0, SAL1: 1, SAL2: 2, SAL3: 3, SAL4: 4} + + +def _minimum_level(levels: list[str], rank: dict[str, int], default: str) -> str: + if not levels: + return default + return min(levels, key=lambda level: rank.get(level, -1)) + + +def aggregate_session_grant_provenance( + session: ReviewSession, + contributing_decisions: list[dict[str, Any]], +) -> dict[str, Any]: + """Build session-specific provenance fields for a multi-reviewer grant.""" + contributing_identity_assurance_levels: list[dict[str, Any]] = [] + contributing_authority_checks: list[dict[str, Any]] = [] + identity_levels: list[str] = [] + signing_levels: list[str] = [] + + for decision in contributing_decisions: + reviewer = decision.get("reviewer") or {} + reviewer_id = reviewer.get("reviewer_id", "") + decision_id = decision.get("decision_id", "") + dec_prov = decision.get("provenance") or {} + ial = str(dec_prov.get("identity_assurance_level", IAL0)) + identity_levels.append(ial) + contributing_identity_assurance_levels.append( + { + "decision_id": decision_id, + "reviewer_id": reviewer_id, + "reviewer_role": reviewer.get("role"), + "identity_assurance_level": ial, + "role_resolution_source": dec_prov.get("role_resolution_source"), + "identity_source": dec_prov.get("identity_source"), + } + ) + authority_checks = dec_prov.get("authority_checks") + if authority_checks is not None: + contributing_authority_checks.append( + { + "decision_id": decision_id, + "reviewer_id": reviewer_id, + "authority_checks": authority_checks, + } + ) + signing_levels.append( + resolve_signing_assurance_level( + decision, + reviewer_id=reviewer_id or None, + ) + ) + + veto_roles = session.quorum_policy.get("safety_veto_roles") or [] + + return { + "contributing_identity_assurance_levels": contributing_identity_assurance_levels, + "contributing_authority_checks": contributing_authority_checks, + "minimum_identity_assurance_level": _minimum_level(identity_levels, IAL_RANK, IAL0), + "minimum_signing_assurance_level": _minimum_level(signing_levels, SAL_RANK, SAL0), + "veto_roles_applied": list(veto_roles), + "quorum_policy_hash": compute_hash(session.quorum_policy), + } From 026dcc3de8f070eb9eb0a6c3f5058327d007b497 Mon Sep 17 00:00:00 2001 From: fraware Date: Mon, 29 Jun 2026 02:54:07 -0700 Subject: [PATCH 30/80] feat(schema): session provenance fields on scope_grant Schema support for aggregated multi-review grant provenance. --- schemas/scope_grant.schema.json | 46 +++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/schemas/scope_grant.schema.json b/schemas/scope_grant.schema.json index fa513f2..c1ec9e8 100644 --- a/schemas/scope_grant.schema.json +++ b/schemas/scope_grant.schema.json @@ -100,6 +100,52 @@ "delegation_id": { "type": ["string", "null"] } }, "additionalProperties": false + }, + "contributing_identity_assurance_levels": { + "type": "array", + "items": { + "type": "object", + "required": ["decision_id", "reviewer_id", "identity_assurance_level"], + "properties": { + "decision_id": { "type": "string" }, + "reviewer_id": { "type": "string" }, + "reviewer_role": { "type": "string" }, + "identity_assurance_level": { + "type": "string", + "enum": ["IAL0", "IAL1", "IAL2", "IAL3", "IAL4"] + }, + "role_resolution_source": { "type": "string" }, + "identity_source": { "type": "string" } + } + } + }, + "contributing_authority_checks": { + "type": "array", + "items": { + "type": "object", + "required": ["decision_id", "reviewer_id", "authority_checks"], + "properties": { + "decision_id": { "type": "string" }, + "reviewer_id": { "type": "string" }, + "authority_checks": { "type": "object" } + } + } + }, + "minimum_identity_assurance_level": { + "type": "string", + "enum": ["IAL0", "IAL1", "IAL2", "IAL3", "IAL4"] + }, + "minimum_signing_assurance_level": { + "type": "string", + "enum": ["SAL0", "SAL1", "SAL2", "SAL3", "SAL4"] + }, + "veto_roles_applied": { + "type": "array", + "items": { "type": "string" } + }, + "quorum_policy_hash": { + "type": "string", + "pattern": "^sha256:" } }, "additionalProperties": true From b266554faf38ef0500fab255f2275cb65c7e2844 Mon Sep 17 00:00:00 2001 From: fraware Date: Mon, 29 Jun 2026 02:54:07 -0700 Subject: [PATCH 31/80] feat(engine): wire session provenance into issue_grant_from_session Attach aggregated provenance and refresh grant hash after session resolution. --- scope/__init__.py | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/scope/__init__.py b/scope/__init__.py index 6306364..162b967 100644 --- a/scope/__init__.py +++ b/scope/__init__.py @@ -1,4 +1,4 @@ -"""Scoped Scientific Authorization Protocol (SCOPE) v0.7.0.""" +"""Scoped Scientific Authorization Protocol (SCOPE) v0.8.0.""" from __future__ import annotations @@ -477,6 +477,8 @@ def issue_grant_from_session( packet: dict[str, Any], decisions: list[dict[str, Any]], ) -> dict[str, Any]: + from scope.session_provenance import aggregate_session_grant_provenance + resolution = session.resolve() first_id = resolution["contributing_decisions"][0] primary = next(d for d in decisions if d["decision_id"] == first_id) @@ -484,8 +486,10 @@ def issue_grant_from_session( merged["decision"]["approved_scope"] = resolution["approved_scope"] merged["session_resolution"] = resolution contributing_signatures = [] + contributing_decisions: list[dict[str, Any]] = [] for decision in decisions: if decision["decision_id"] in resolution["contributing_decisions"]: + contributing_decisions.append(decision) entry = { "decision_id": decision["decision_id"], "reviewer_id": decision["reviewer"]["reviewer_id"], @@ -506,6 +510,13 @@ def issue_grant_from_session( contributing_signatures=contributing_signatures, ) grant = self._finalize_grant_provenance(grant, merged) + session_provenance = aggregate_session_grant_provenance(session, contributing_decisions) + provenance = dict(grant.get("provenance") or {}) + provenance.update(session_provenance) + grant["provenance"] = provenance + from scope.hash import attach_hash + + grant = attach_hash(grant, "grant_hash") self._grant_engine.validate(grant) akta_blocked = packet.get("akta_constraints", {}).get("blocked_tools", []) grant_blocked = grant.get("authorization", {}).get("blocked_tools", []) From 465e1a03839c191d19d86150b93d76d675d2dde3 Mon Sep 17 00:00:00 2001 From: fraware Date: Mon, 29 Jun 2026 02:54:08 -0700 Subject: [PATCH 32/80] test(provenance): session grant provenance aggregation Assert contributing assurance and authority checks on session grants. --- tests/test_session_grant_provenance.py | 105 +++++++++++++++++++++++++ 1 file changed, 105 insertions(+) create mode 100644 tests/test_session_grant_provenance.py diff --git a/tests/test_session_grant_provenance.py b/tests/test_session_grant_provenance.py new file mode 100644 index 0000000..c93c9d4 --- /dev/null +++ b/tests/test_session_grant_provenance.py @@ -0,0 +1,105 @@ +"""Tests for session grant provenance aggregation (SCOPE-3).""" + +from __future__ import annotations + +from pathlib import Path + +from scope import ScopeEngine +from scope.hash import compute_hash +from scope.schema_util import validate_artifact +from scope.session_provenance import aggregate_session_grant_provenance + +ROOT = Path(__file__).resolve().parent.parent + + +def _a6_packet(engine: ScopeEngine) -> dict: + trigger = { + "akta_admissibility": "review_required", + "scientific_action_type": "A6_experimental_planning", + "requested_action": "plan_validation", + "requested_tool": "experiment_planner.create_validation_plan", + "requested_scope": "single_validation_plan", + "scientific_context": {"protocol_version": "protocol_v1"}, + } + record = {"record_id": "AKTA-A6-PROV", "scientific_action_type": "A6_experimental_planning"} + return engine.create_packet(record, trigger) + + +def test_session_grant_includes_aggregated_provenance() -> None: + engine = ScopeEngine.from_policy_dir(ROOT / "policy") + packet = _a6_packet(engine) + session = engine.create_review_session( + packet, + quorum_policy={ + "mode": "require_all", + "required_roles": packet["review_request"]["required_review_roles"], + "safety_veto_roles": ["safety_officer"], + }, + ) + d1 = engine.submit_session_decision( + session, + packet, + {"reviewer_id": "ds1", "role": "domain_scientist"}, + { + "type": "approve_narrower_scope", + "approved_scope": "single_validation_plan", + "rationale": "ok", + }, + ) + d2 = engine.submit_session_decision( + session, + packet, + {"reviewer_id": "po1", "role": "protocol_owner"}, + { + "type": "approve_narrower_scope", + "approved_scope": "single_validation_plan", + "rationale": "ok", + }, + ) + grant = engine.issue_grant_from_session(session, packet, [d1, d2]) + prov = grant["provenance"] + + assert len(prov["contributing_identity_assurance_levels"]) == 2 + reviewer_ids = { + entry["reviewer_id"] for entry in prov["contributing_identity_assurance_levels"] + } + assert reviewer_ids == {"ds1", "po1"} + + assert len(prov["contributing_authority_checks"]) == 2 + assert prov["minimum_identity_assurance_level"] == "IAL0" + assert prov["minimum_signing_assurance_level"] == "SAL0" + assert prov["veto_roles_applied"] == ["safety_officer"] + assert prov["quorum_policy_hash"] == compute_hash(session.quorum_policy) + assert prov["quorum_policy_hash"].startswith("sha256:") + + session_fields = ( + "contributing_identity_assurance_levels", + "contributing_authority_checks", + "minimum_identity_assurance_level", + "minimum_signing_assurance_level", + "veto_roles_applied", + "quorum_policy_hash", + ) + for field in session_fields: + assert field in prov, f"missing session provenance field: {field}" + validate_artifact(grant, "scope_grant.schema.json") + + +def test_aggregate_session_grant_provenance_unit() -> None: + engine = ScopeEngine.from_policy_dir(ROOT / "policy") + packet = _a6_packet(engine) + session = engine.create_review_session(packet) + d1 = engine.submit_session_decision( + session, + packet, + {"reviewer_id": "ds1", "role": "domain_scientist"}, + { + "type": "approve_narrower_scope", + "approved_scope": "single_validation_plan", + "rationale": "ok", + }, + ) + aggregated = aggregate_session_grant_provenance(session, [d1]) + assert aggregated["minimum_identity_assurance_level"] == "IAL0" + assert aggregated["contributing_identity_assurance_levels"][0]["reviewer_id"] == "ds1" + assert aggregated["veto_roles_applied"] == [] From 49cd67c19ecfe0d51ded48880ff2083af2b547f6 Mon Sep 17 00:00:00 2001 From: fraware Date: Mon, 29 Jun 2026 02:54:08 -0700 Subject: [PATCH 33/80] feat(evals): run akta_review_session_mode in extended suite Include v0.8 session contract in extended review cases. --- evals/run_review_cases.py | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/evals/run_review_cases.py b/evals/run_review_cases.py index 808ca0f..4132441 100644 --- a/evals/run_review_cases.py +++ b/evals/run_review_cases.py @@ -1,4 +1,4 @@ -"""Evaluation scenario runner for SCOPE v0.7.""" +"""Evaluation scenario runner for SCOPE v0.8.""" from __future__ import annotations @@ -233,6 +233,7 @@ def _run_akta_review_scenario( from scope.schema_util import validate_artifact name = scenario["name"] + session_mode = bool(scenario.get("session_mode")) with tempfile.TemporaryDirectory() as out_dir: signing_key: Path | None = None if scenario.get("sign_before_grant"): @@ -249,8 +250,26 @@ def _run_akta_review_scenario( decision_rationale=scenario["decision"]["rationale"], out_dir=out_dir, signing_key=signing_key, + session_mode=session_mode, ) + if session_mode: + validate_artifact(summary, "scope_akta_review_session_summary.schema.json") + if summary.get("status") != "session_required": + return ScenarioResult( + name, + False, + f"Expected session_required, got {summary.get('status')}", + ) + if not summary.get("session_id", "").startswith("SCOPE-SESS-"): + return ScenarioResult(name, False, "Missing session_id") + packet_path = Path(summary["packet_path"]) + if not packet_path.is_file(): + return ScenarioResult(name, False, "Missing packet_path artifact") + if Path(out_dir, "scope_grant.json").is_file(): + return ScenarioResult(name, False, "Grant should not be issued in session mode") + return ScenarioResult(name, True, "AKTA session summary contract OK") + validate_artifact(summary, "scope_akta_review_summary.schema.json") expected_sal = scenario.get("expect_signing_assurance_level") if expected_sal and summary.get("signing_assurance_level") != expected_sal: @@ -495,6 +514,7 @@ def _run_scenario_with_engine( "queue_invalid_transition.json", "fail_closed_grant_blocked.json", "akta_review_signed_summary.json", + "akta_review_session_mode.json", ] @@ -515,7 +535,7 @@ def main() -> int: parser.add_argument( "--extended", action="store_true", - help="Also run extended v0.7 scenarios (IAL, SAL, queue, ledger, AKTA contract)", + help="Also run extended v0.8 scenarios (IAL, SAL, queue, ledger, AKTA contract)", ) args = parser.parse_args() From 187ffa9426e25791c92e7a9e189d39ca7aff47f6 Mon Sep 17 00:00:00 2001 From: fraware Date: Mon, 29 Jun 2026 02:54:08 -0700 Subject: [PATCH 34/80] test(evals): expect 22 extended review scenarios Count includes akta session mode regression. --- tests/test_eval_extended.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_eval_extended.py b/tests/test_eval_extended.py index 337e31e..1a79fd5 100644 --- a/tests/test_eval_extended.py +++ b/tests/test_eval_extended.py @@ -19,4 +19,4 @@ def test_extended_eval_scenarios_pass(): env=env, ) assert result.returncode == 0, result.stdout + result.stderr - assert "21/21 scenarios passed" in result.stdout + assert "22/22 scenarios passed" in result.stdout From 32413fd9ded899c560743842d42b3201f30d9889 Mon Sep 17 00:00:00 2001 From: fraware Date: Mon, 29 Jun 2026 02:54:31 -0700 Subject: [PATCH 35/80] docs(akta): v0.8 review contract and session summary Document session_required summary fields alongside completed review artifacts. --- docs/akta_review_contract.md | 59 +++++++++++++++++++++++++++++++----- 1 file changed, 52 insertions(+), 7 deletions(-) diff --git a/docs/akta_review_contract.md b/docs/akta_review_contract.md index 50fd57f..9edc47c 100644 --- a/docs/akta_review_contract.md +++ b/docs/akta_review_contract.md @@ -1,19 +1,19 @@ # AKTA Review Output Contract -SCOPE v0.7 freezes the `scope akta review` output contract under `out_dir/`. +SCOPE v0.8 freezes the `scope akta review` output contract under `out_dir/`. ## Artifacts | File | Description | |------|-------------| | `scope_review_packet.json` | Review packet | -| `scope_decision.json` | Signed or unsigned decision | -| `scope_grant.json` | Issued grant | +| `scope_decision.json` | Signed or unsigned decision (completed path only) | +| `scope_grant.json` | Issued grant (completed path only) | | `summary.json` | Adapter summary (validated against schema) | -## summary.json contract +## summary.json contract (completed review) -Contract version constant: `scope-akta-review-v0.7` (`scope.integration_versions.AKTA_REVIEW_CONTRACT_VERSION`). +Contract version constant: `scope-akta-review-v0.8` (`scope.integration_versions.AKTA_REVIEW_CONTRACT_VERSION`). Required fields: @@ -24,7 +24,7 @@ Required fields: "grant_path": "...", "approved_scope": "...", "requested_scope": "...", - "adapter_contract_version": "scope-akta-review-v0.7", + "adapter_contract_version": "scope-akta-review-v0.8", "identity_assurance_level": "IAL0", "signing_assurance_level": "SAL1", "production_mode": false @@ -35,14 +35,58 @@ Optional fields: `status`, `packet_id`, `decision_id`, `grant_id`, `allowed_tool Schema: `schemas/scope_akta_review_summary.schema.json` +## summary.json contract (session mode) + +When multi-role review is required and `--session` is passed, `run_akta_review` creates a review session and writes a session summary instead of decision/grant artifacts. + +Required fields: + +```json +{ + "status": "session_required", + "packet_id": "SCOPE-PKT-...", + "session_id": "SCOPE-SESS-...", + "required_roles": ["domain_scientist", "protocol_owner"], + "message": "Multi-role review session created; submit votes before grant issue.", + "adapter_contract_version": "scope-akta-review-v0.8", + "production_mode": false +} +``` + +Optional fields: `requested_scope`, `packet_path`. + +Schema: `schemas/scope_akta_review_session_summary.schema.json` + +Without `--session`, multi-role packets fail with an explicit error directing operators to re-run with `--session` or use `scope review session create`. + +## Session grant provenance + +When a grant is issued from a multi-reviewer session (`issue_grant_from_session`), provenance includes aggregated session fields: + +| Field | Description | +|-------|-------------| +| `contributing_identity_assurance_levels` | Per-decision IAL with reviewer ID and role | +| `contributing_authority_checks` | Per-decision `authority_checks` blocks | +| `minimum_identity_assurance_level` | Weakest IAL across contributing decisions | +| `minimum_signing_assurance_level` | Weakest SAL across contributing decisions | +| `veto_roles_applied` | Safety veto roles from quorum policy | +| `quorum_policy_hash` | Digest of session quorum policy | + +These fields are optional in `schemas/scope_grant.schema.json` (present only on session grants). Single-reviewer grants omit them. + +## Reviewer ID binding + +When `--signing-provider registry` is used, pass `--reviewer-id` to bind the registry lookup. If provided, it must match `reviewer.json` `reviewer_id`; mismatch fails before signing. + ## Acceptance criteria `scope akta review` enforces: -- Summary validates against schema +- Summary validates against schema (completed or session mode) - Overbroad approval fails (approved scope stronger than requested) - Unsigned production grant fails without signing key/provider - Missing reviewer authority fails (two-stage RBAC + SCOPE policy) +- Multi-role packets without `--session` fail with session guidance ## Primary AKTA path @@ -53,3 +97,4 @@ Schema: `schemas/scope_akta_review_summary.schema.json` - [akta_integration.md](akta_integration.md) — integration overview - [akta_scope_demo.md](akta_scope_demo.md) — full cross-repo demo - [external_integration_contracts.md](external_integration_contracts.md) — AKTA field mappings +- [key_management.md](key_management.md) — registry signing and `--reviewer-id` From 922771b473d6d6c015ec8df8a2d1243e9703ee6c Mon Sep 17 00:00:00 2001 From: fraware Date: Mon, 29 Jun 2026 02:54:32 -0700 Subject: [PATCH 36/80] docs: README v0.8 badge, session, and pilot examples Point institutional adopters at session mode and examples/pilot. --- README.md | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index fb86b93..bd8b5e3 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ **Scoped authorization for AI-shaped scientific work** -[![Version](https://img.shields.io/badge/version-0.7.0-blue)](https://github.com/fraware/SCOPE/releases) +[![Version](https://img.shields.io/badge/version-0.8.0-blue)](https://github.com/fraware/SCOPE/releases) [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE) [![Python 3.10+](https://img.shields.io/badge/python-3.10%2B-blue.svg)](https://www.python.org/downloads/) [![CI](https://github.com/fraware/SCOPE/actions/workflows/ci.yml/badge.svg)](https://github.com/fraware/SCOPE/actions/workflows/ci.yml) @@ -61,7 +61,7 @@ pip install -e ".[dev]" pytest ``` -Run the bundled evaluation scenarios (8 core; add `--extended` for 13 more, 21 total): +Run the bundled evaluation scenarios (8 core; add `--extended` for 14 more, 22 total): ```bash python evals/run_review_cases.py @@ -93,6 +93,10 @@ Outputs in `./out/akta_review/`: Full contract: [docs/akta_review_contract.md](docs/akta_review_contract.md). End-to-end demo: [docs/akta_scope_demo.md](docs/akta_scope_demo.md). +For multi-role actions (for example A6 experimental planning), pass `--session` to create a review session instead of issuing a grant immediately. The command writes `summary.json` with `status: session_required` and a `session_id` for the vote workflow. + +Institutional pilot scenarios with regenerated artifacts: [examples/pilot/](examples/pilot/). + --- ## Core workflows @@ -162,7 +166,7 @@ Returns `ALLOWED` or `BLOCKED`. Revoke or inspect status via `scope grant revoke Integration field mappings: [docs/external_integration_contracts.md](docs/external_integration_contracts.md). Optional REST API: install with `pip install -e ".[rest]"` and run `uvicorn adapters.generic_rest.server:app`. -Institutional pilots: start with [docs/institutional_pilot_guide.md](docs/institutional_pilot_guide.md) and sample fixtures in [examples/institutional_pilot/](examples/institutional_pilot/). +Institutional pilots: start with [docs/institutional_pilot_guide.md](docs/institutional_pilot_guide.md). Workshop fixtures: [examples/institutional_pilot/](examples/institutional_pilot/). v0.8 pilot pack: [examples/pilot/](examples/pilot/). --- @@ -211,7 +215,7 @@ bash scripts/ci.sh .\scripts\ci.ps1 ``` -CI runs on Python 3.10, 3.11, and 3.12: `ruff` lint, `mypy` typecheck, `pytest`, and all 21 evaluation scenarios with `--extended`. +CI runs on Python 3.10, 3.11, and 3.12: `ruff` lint, `mypy` typecheck, `pytest`, and all 22 evaluation scenarios with `--extended`. Individual commands: @@ -232,7 +236,7 @@ python evals/run_review_cases.py --extended | `policy/` | YAML policy bundles and domain overlays | | `adapters/` | AKTA, VSA, PF-Core, PCS, and REST integrations | | `examples/` | Scenario fixtures for docs and evals | -| `evals/` | 8 core + 13 extended evaluation scenarios | +| `evals/` | 8 core + 14 extended evaluation scenarios | | `tests/` | Pytest suite | | `docs/` | Protocol and integration documentation | From 0f2632f5b2cffd0fc13749d3cbb24ce8b3acd2fa Mon Sep 17 00:00:00 2001 From: fraware Date: Mon, 29 Jun 2026 02:54:32 -0700 Subject: [PATCH 37/80] docs: limitations for v0.8 session and provenance Clarify what session mode does and does not guarantee. --- docs/limitations.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/docs/limitations.md b/docs/limitations.md index a7da8c3..9b408f8 100644 --- a/docs/limitations.md +++ b/docs/limitations.md @@ -1,5 +1,13 @@ # Limitations +## Implemented in v0.8 + +- `scope akta review --session` for multi-role packets: session summary schema, explicit failure without `--session` +- `--reviewer-id` binding for registry signing (must match reviewer artifact) +- Session grant provenance aggregation: contributing IAL/SAL, authority checks, veto roles, quorum policy hash +- Pilot fixture pack under `examples/pilot/` (five institutional scenarios) +- Policy bundle `scope-core-v0.8`; AKTA review contract `scope-akta-review-v0.8` + ## Implemented in v0.7 - Identity assurance levels (IAL0–IAL4) with provenance on decisions and grants From 561ba913088ff6d2cbfc40b9d491367348f12edf Mon Sep 17 00:00:00 2001 From: fraware Date: Mon, 29 Jun 2026 02:54:32 -0700 Subject: [PATCH 38/80] docs: trusted boundary updates for v0.8 Align trust assumptions with session grants and reviewer binding. --- docs/trusted_boundary.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/docs/trusted_boundary.md b/docs/trusted_boundary.md index 0d7b6f3..51e3a1b 100644 --- a/docs/trusted_boundary.md +++ b/docs/trusted_boundary.md @@ -1,6 +1,6 @@ # Trusted Boundary -SCOPE v0.7 assumes: +SCOPE v0.8 assumes: - Reviewer identity is provided by a trusted caller, OIDC/JWT verification, or configured registry - Reviewer role assignments are correctly configured in policy YAML and, when enabled, `org_rbac.yaml` @@ -11,7 +11,7 @@ SCOPE v0.7 assumes: - Session stores (JSON/SQLite) are protected at the filesystem level - Ledger delivery mode matches institutional risk tolerance (`SCOPE_LEDGER_DELIVERY_MODE`) -SCOPE v0.7 does not guarantee reviewer competence, honesty, scientific truth, domain safety, legal compliance, or physical lab safety. +SCOPE v0.8 does not guarantee reviewer competence, honesty, scientific truth, domain safety, legal compliance, or physical lab safety. ## Production mode and signing @@ -86,7 +86,9 @@ Duplicate votes from the same reviewer are rejected. Votes are recorded in both ## Policy version -Active policy is tagged `scope-core-v0.7`. Grants record `provenance.scope_policy_version`; runtime context may include matching `scope_policy_version` for expiration checks. +Active policy is tagged `scope-core-v0.8`. Grants record `provenance.scope_policy_version`; runtime context may include matching `scope_policy_version` for expiration checks. + +Session grants additionally record aggregated provenance: `contributing_identity_assurance_levels`, `contributing_authority_checks`, `minimum_identity_assurance_level`, `minimum_signing_assurance_level`, `veto_roles_applied`, and `quorum_policy_hash`. See [akta_review_contract.md](akta_review_contract.md). ## Trust root From 59c7aa7b3a3ccfa0822b360935fcd8cc3920d765 Mon Sep 17 00:00:00 2001 From: fraware Date: Mon, 29 Jun 2026 02:54:33 -0700 Subject: [PATCH 39/80] docs: institutional pilot guide v0.8 workflow Update pilot steps for session-correct AKTA review. --- docs/institutional_pilot_guide.md | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/docs/institutional_pilot_guide.md b/docs/institutional_pilot_guide.md index 0ae08d4..8a03ef5 100644 --- a/docs/institutional_pilot_guide.md +++ b/docs/institutional_pilot_guide.md @@ -1,6 +1,13 @@ # Institutional Pilot Guide -This guide supports workshop, funder, and lab pilots of SCOPE v0.7 alongside AKTA. +This guide supports workshop, funder, and lab pilots of SCOPE v0.8 alongside AKTA. + +## v0.8 institutional additions + +- **`scope akta review --session`** for multi-role packets — session summary schema and vote workflow before grant issue — [akta_review_contract.md](akta_review_contract.md) +- **`--reviewer-id` binding** when using `--signing-provider registry` — [key_management.md](key_management.md) +- **Session grant provenance** on multi-reviewer grants (contributing IAL/SAL, authority checks, veto roles, quorum hash) +- **Pilot fixture pack** — [examples/pilot/](../examples/pilot/) with five regenerated scenarios ## v0.7 institutional additions @@ -38,7 +45,7 @@ This guide supports workshop, funder, and lab pilots of SCOPE v0.7 alongside AKT 7. **Verify** — `scope verify --public-key` for auditor demonstration 8. **Export** — PCS bundle for institutional record-keeping -Sample artifacts: [examples/institutional_pilot/](../examples/institutional_pilot/) +Sample artifacts: [examples/institutional_pilot/](../examples/institutional_pilot/). v0.8 pilot pack: [examples/pilot/](../examples/pilot/). ## Multi-reviewer pilot (A6) @@ -64,7 +71,7 @@ Report includes reviewer metrics, warnings, queue counts, and event counts. Non- ## Lab integration checklist -- [ ] Policy YAML reviewed and version-pinned (`scope-core-v0.7`) +- [ ] Policy YAML reviewed and version-pinned (`scope-core-v0.8`) - [ ] Reviewer roles mapped to lab personnel - [ ] Ed25519 keypairs generated per reviewer role; public keys registered - [ ] PF-Core runtime configured to enforce grant obligations From 625dd58ba63d756f53ebe1790353c5081d6f7ab7 Mon Sep 17 00:00:00 2001 From: fraware Date: Mon, 29 Jun 2026 02:54:33 -0700 Subject: [PATCH 40/80] docs: institutional guide v0.8 references Refresh institutional adoption pointers for the v0.8 line. --- docs/institutional_guide.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/institutional_guide.md b/docs/institutional_guide.md index 583c006..be884a2 100644 --- a/docs/institutional_guide.md +++ b/docs/institutional_guide.md @@ -1,10 +1,10 @@ # Institutional Guide -Institutions adopting SCOPE v0.7 should start with the [institutional pilot guide](institutional_pilot_guide.md), which covers workshop flow, checklist, and v0.7 features (identity assurance, signing assurance, review queue, ledger delivery). +Institutions adopting SCOPE v0.8 should start with the [institutional pilot guide](institutional_pilot_guide.md), which covers workshop flow, checklist, and v0.8 features (session mode, reviewer ID binding, session grant provenance, pilot fixtures). ## Adoption checklist -1. Configure and version-pin `policy/` files (`scope-core-v0.7`) for local role assignments and scope boundaries +1. Configure and version-pin `policy/` files (`scope-core-v0.8`) for local role assignments and scope boundaries 2. Map lab personnel to reviewer roles; generate Ed25519 keypairs and register public keys 3. Integrate AKTA review triggers via `scope akta review` or `scope packet create` 4. Enable production mode (`SCOPE_PRODUCTION_MODE=true`) and minimum signing assurance for grant enforcement From fd2849e4bb69b467cf80f1b09913e7221a6add30 Mon Sep 17 00:00:00 2001 From: fraware Date: Mon, 29 Jun 2026 02:54:33 -0700 Subject: [PATCH 41/80] docs(examples): institutional pilot README for v0.8 Keep bundled institutional walkthrough in sync with v0.8. --- examples/institutional_pilot/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/institutional_pilot/README.md b/examples/institutional_pilot/README.md index 01fb08c..b011757 100644 --- a/examples/institutional_pilot/README.md +++ b/examples/institutional_pilot/README.md @@ -1,6 +1,6 @@ # Institutional Pilot Examples -Sample artifacts for SCOPE v0.7 institutional pilot workshops. See [docs/institutional_pilot_guide.md](../../docs/institutional_pilot_guide.md). +Sample artifacts for SCOPE v0.8 institutional pilot workshops. See [docs/institutional_pilot_guide.md](../../docs/institutional_pilot_guide.md). For v0.8 pilot scenarios with queue and session workflows, see [examples/pilot/](../pilot/). | File | Description | |------|-------------| @@ -15,7 +15,7 @@ Sample artifacts for SCOPE v0.7 institutional pilot workshops. See [docs/institu | decision.json | Decision input fixture | | current_context.json | Runtime context for grant check | -Artifacts use policy bundle `scope-core-v0.7`. In production mode, sign decisions before grant issue; see [docs/trusted_boundary.md](../../docs/trusted_boundary.md). +Artifacts use policy bundle `scope-core-v0.8`. In production mode, sign decisions before grant issue; see [docs/trusted_boundary.md](../../docs/trusted_boundary.md). To regenerate PCS export from these artifacts: From b9c465b86590787386c4ca2a1037fd12a1fc158d Mon Sep 17 00:00:00 2001 From: fraware Date: Mon, 29 Jun 2026 02:54:34 -0700 Subject: [PATCH 42/80] examples: refresh institutional_pilot current_context.json for v0.8 policy Update fixture metadata after scope-core-v0.8 bump. --- examples/institutional_pilot/current_context.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/institutional_pilot/current_context.json b/examples/institutional_pilot/current_context.json index b5958b9..64906e4 100644 --- a/examples/institutional_pilot/current_context.json +++ b/examples/institutional_pilot/current_context.json @@ -2,5 +2,5 @@ "protocol_version": "protocol_v3", "evidence_state": "E2_preliminary_signal", "project_id": "drift_demo", - "scope_policy_version": "scope-core-v0.7" + "scope_policy_version": "scope-core-v0.8" } From 29d1c526a421b77832cd45177127330e8040b31f Mon Sep 17 00:00:00 2001 From: fraware Date: Mon, 29 Jun 2026 02:54:34 -0700 Subject: [PATCH 43/80] examples: refresh institutional_pilot scope_decision.json for v0.8 policy Update fixture metadata after scope-core-v0.8 bump. --- examples/institutional_pilot/scope_decision.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/institutional_pilot/scope_decision.json b/examples/institutional_pilot/scope_decision.json index a89a8a3..4e2e564 100644 --- a/examples/institutional_pilot/scope_decision.json +++ b/examples/institutional_pilot/scope_decision.json @@ -35,9 +35,9 @@ "packet_id": "SCOPE-PKT-764195", "provenance": { "reviewer_key_registry_hash": "sha256:1dec33e3bda7220f7c3ab33641c3384c4d550be30e468e27e1600eee85751e8d", - "reviewer_key_registry_version": "scope-core-v0.7", + "reviewer_key_registry_version": "scope-core-v0.8", "scope_policy_hash": "sha256:b8594a04fc2c29ca3c5280bb8a30734463a576af19d2b0f7cc9fb5b8bcb5ed8d", - "scope_policy_version": "scope-core-v0.7", + "scope_policy_version": "scope-core-v0.8", "scope_trust_root_hash": "sha256:90de41557b588620c483ebd060707566a520c73a39416b381ba9f769ef3b87d7" }, "reviewer": { From 347602e268c13dc0d55d7af3cf2d81f37a0b88ce Mon Sep 17 00:00:00 2001 From: fraware Date: Mon, 29 Jun 2026 02:54:34 -0700 Subject: [PATCH 44/80] examples: refresh institutional_pilot scope_grant.json for v0.8 policy Update fixture metadata after scope-core-v0.8 bump. --- examples/institutional_pilot/scope_grant.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/institutional_pilot/scope_grant.json b/examples/institutional_pilot/scope_grant.json index 1e6c6ba..ab21d44 100644 --- a/examples/institutional_pilot/scope_grant.json +++ b/examples/institutional_pilot/scope_grant.json @@ -37,14 +37,14 @@ }, "grant_hash": "sha256:bf8788ee0f31ea9f639973e535e6c79fcb1ceb0eb3fa2bed30a51de8903239b0", "grant_id": "SCOPE-GRANT-52BA47", - "grant_version": "0.7.0", + "grant_version": "0.8.0", "provenance": { "akta_policy_hash": null, "reviewer_key_registry_hash": "sha256:1dec33e3bda7220f7c3ab33641c3384c4d550be30e468e27e1600eee85751e8d", - "reviewer_key_registry_version": "scope-core-v0.7", + "reviewer_key_registry_version": "scope-core-v0.8", "reviewer_role_policy_hash": "sha256:b8594a04fc2c29ca3c5280bb8a30734463a576af19d2b0f7cc9fb5b8bcb5ed8d", "scope_policy_hash": "sha256:b8594a04fc2c29ca3c5280bb8a30734463a576af19d2b0f7cc9fb5b8bcb5ed8d", - "scope_policy_version": "scope-core-v0.7", + "scope_policy_version": "scope-core-v0.8", "scope_trust_root_hash": "sha256:90de41557b588620c483ebd060707566a520c73a39416b381ba9f769ef3b87d7" }, "source": { From 0a0b16448f7e005e11ca26568e6f66e697b982d2 Mon Sep 17 00:00:00 2001 From: fraware Date: Mon, 29 Jun 2026 02:54:35 -0700 Subject: [PATCH 45/80] examples: refresh protocol_change_review current_context.json for v0.8 policy Update fixture metadata after scope-core-v0.8 bump. --- examples/protocol_change_review/current_context.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/protocol_change_review/current_context.json b/examples/protocol_change_review/current_context.json index 3db32e1..c9693f6 100644 --- a/examples/protocol_change_review/current_context.json +++ b/examples/protocol_change_review/current_context.json @@ -1,5 +1,5 @@ { "protocol_version": "protocol_v3", "evidence_state": "E2_preliminary_signal", - "scope_policy_version": "scope-core-v0.7" + "scope_policy_version": "scope-core-v0.8" } From e77353fb3a681bba7caf8f05715cdc83df13d57c Mon Sep 17 00:00:00 2001 From: fraware Date: Mon, 29 Jun 2026 02:54:35 -0700 Subject: [PATCH 46/80] examples: refresh protocol_drift current_context.json for v0.8 policy Update fixture metadata after scope-core-v0.8 bump. --- examples/protocol_drift/current_context.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/protocol_drift/current_context.json b/examples/protocol_drift/current_context.json index b5958b9..64906e4 100644 --- a/examples/protocol_drift/current_context.json +++ b/examples/protocol_drift/current_context.json @@ -2,5 +2,5 @@ "protocol_version": "protocol_v3", "evidence_state": "E2_preliminary_signal", "project_id": "drift_demo", - "scope_policy_version": "scope-core-v0.7" + "scope_policy_version": "scope-core-v0.8" } From ab9622302d2be55c959253098b929c40142d4d8c Mon Sep 17 00:00:00 2001 From: fraware Date: Mon, 29 Jun 2026 02:54:35 -0700 Subject: [PATCH 47/80] examples: refresh stale_grant_attempt current_context.json for v0.8 policy Update fixture metadata after scope-core-v0.8 bump. --- examples/stale_grant_attempt/current_context.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/stale_grant_attempt/current_context.json b/examples/stale_grant_attempt/current_context.json index 3db32e1..c9693f6 100644 --- a/examples/stale_grant_attempt/current_context.json +++ b/examples/stale_grant_attempt/current_context.json @@ -1,5 +1,5 @@ { "protocol_version": "protocol_v3", "evidence_state": "E2_preliminary_signal", - "scope_policy_version": "scope-core-v0.7" + "scope_policy_version": "scope-core-v0.8" } From e5ce15ea0d20405343c990ec435cf319c7d38503 Mon Sep 17 00:00:00 2001 From: fraware Date: Mon, 29 Jun 2026 02:54:35 -0700 Subject: [PATCH 48/80] examples: refresh stale_grant_attempt stale_context.json for v0.8 policy Update fixture metadata after scope-core-v0.8 bump. --- examples/stale_grant_attempt/stale_context.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/stale_grant_attempt/stale_context.json b/examples/stale_grant_attempt/stale_context.json index 8aed41e..1f21be4 100644 --- a/examples/stale_grant_attempt/stale_context.json +++ b/examples/stale_grant_attempt/stale_context.json @@ -1,5 +1,5 @@ { "protocol_version": "protocol_v4", "evidence_state": "E2_preliminary_signal", - "scope_policy_version": "scope-core-v0.7" + "scope_policy_version": "scope-core-v0.8" } From 9fd568bf63444066ceb63b3e93f5186fdffc665f Mon Sep 17 00:00:00 2001 From: fraware Date: Mon, 29 Jun 2026 02:54:36 -0700 Subject: [PATCH 49/80] examples: refresh weak_evidence_validation_review current_context.json for v0.8 policy Update fixture metadata after scope-core-v0.8 bump. --- examples/weak_evidence_validation_review/current_context.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/weak_evidence_validation_review/current_context.json b/examples/weak_evidence_validation_review/current_context.json index 1c3bd61..faa560c 100644 --- a/examples/weak_evidence_validation_review/current_context.json +++ b/examples/weak_evidence_validation_review/current_context.json @@ -1,5 +1,5 @@ { "protocol_version": "protocol_v2", "evidence_state": "E1_weak_signal", - "scope_policy_version": "scope-core-v0.7" + "scope_policy_version": "scope-core-v0.8" } From a5c1ccbdbc058c12e787c63ef90ee8a89a086e32 Mon Sep 17 00:00:00 2001 From: fraware Date: Mon, 29 Jun 2026 02:54:36 -0700 Subject: [PATCH 50/80] docs(examples): pilot fixture pack overview Describe institutional pilot scenarios under examples/pilot. --- examples/pilot/README.md | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 examples/pilot/README.md diff --git a/examples/pilot/README.md b/examples/pilot/README.md new file mode 100644 index 0000000..b795f00 --- /dev/null +++ b/examples/pilot/README.md @@ -0,0 +1,13 @@ +# SCOPE Pilot Fixture Pack (v0.8) + +Institutional pilot scenarios generated with SCOPE v0.8 CLI and engine APIs. Each subdirectory is self-contained with review artifacts, queue state where applicable, rendered packet markdown, and a quality report snippet. + +| Scenario | Directory | Highlights | +|----------|-----------|------------| +| Single-reviewer protocol draft | [single_reviewer_protocol_draft](single_reviewer_protocol_draft/) | One-shot `scope akta review` | +| Multi-role genomics co-review | [multi_role_genomics_review](multi_role_genomics_review/) | `--session` creates pending session | +| Expired queue reopen | [expired_queue_reopen](expired_queue_reopen/) | Queue `expired` then `reopen` | +| Needs information flow | [needs_information_flow](needs_information_flow/) | `needs_information` to `in_review` | +| Registry-signed decision | [registry_signed_decision](registry_signed_decision/) | `--signing-provider registry --reviewer-id` | + +Policy bundle: `scope-core-v0.8`. AKTA review contract: `scope-akta-review-v0.8`. From c63759bed771e85b0246e6774872c0c1a4745a44 Mon Sep 17 00:00:00 2001 From: fraware Date: Mon, 29 Jun 2026 02:54:36 -0700 Subject: [PATCH 51/80] examples(pilot): single_reviewer_protocol_draft scenario Single-reviewer protocol draft happy path fixtures. --- .../single_reviewer_protocol_draft/README.md | 29 ++++++++ .../packet_rendered.md | 72 +++++++++++++++++++ .../quality_report_snippet.json | 3 + .../scope_decision.json | 59 +++++++++++++++ .../scope_grant.json | 66 +++++++++++++++++ .../scope_review_packet.json | 46 ++++++++++++ .../summary.json | 25 +++++++ 7 files changed, 300 insertions(+) create mode 100644 examples/pilot/single_reviewer_protocol_draft/README.md create mode 100644 examples/pilot/single_reviewer_protocol_draft/packet_rendered.md create mode 100644 examples/pilot/single_reviewer_protocol_draft/quality_report_snippet.json create mode 100644 examples/pilot/single_reviewer_protocol_draft/scope_decision.json create mode 100644 examples/pilot/single_reviewer_protocol_draft/scope_grant.json create mode 100644 examples/pilot/single_reviewer_protocol_draft/scope_review_packet.json create mode 100644 examples/pilot/single_reviewer_protocol_draft/summary.json diff --git a/examples/pilot/single_reviewer_protocol_draft/README.md b/examples/pilot/single_reviewer_protocol_draft/README.md new file mode 100644 index 0000000..7a5185c --- /dev/null +++ b/examples/pilot/single_reviewer_protocol_draft/README.md @@ -0,0 +1,29 @@ +# Single reviewer protocol draft + +Scenario: protocol owner approves a narrowed `protocol_draft` scope for an A5 protocol modification (protocol drift demo inputs). + +## Artifacts + +| File | Description | +|------|-------------| +| `scope_review_packet.json` | Review packet | +| `scope_decision.json` | Reviewer decision | +| `scope_grant.json` | Issued grant | +| `summary.json` | Completed AKTA review summary | +| `packet_rendered.md` | Markdown packet render | +| `quality_report_snippet.json` | Policy version from quality report | + +## Regenerate + +```bash +scope akta review \ + --akta-trigger examples/protocol_drift/review_trigger.json \ + --akta-record examples/protocol_drift/akta_record.json \ + --grant-scope protocol_draft \ + --reviewer examples/protocol_drift/reviewer_protocol_owner.json \ + --decision-rationale "Pilot single-reviewer protocol draft approval." \ + --out-dir examples/pilot/single_reviewer_protocol_draft \ + --policy policy +``` + +Expected: `summary.json` status `completed`, approved scope `protocol_draft`. diff --git a/examples/pilot/single_reviewer_protocol_draft/packet_rendered.md b/examples/pilot/single_reviewer_protocol_draft/packet_rendered.md new file mode 100644 index 0000000..336e947 --- /dev/null +++ b/examples/pilot/single_reviewer_protocol_draft/packet_rendered.md @@ -0,0 +1,72 @@ +# SCOPE Review Packet + +*This display is for review coordination only. It does not constitute certification, legal authorization, or institutional approval.* + +## Identification + +- Packet ID: SCOPE-PKT-D2FA4B +- AKTA Record: AKTA-SAR-DRIFT-001 +- Created: 2026-06-29T09:19:13Z + +## Requested Action + +- Action: update_active_protocol +- Tool: protocol_editor.update_active_protocol +- Action type: A5_protocol_modification +- Requested scope: protocol_draft +- Review route: none +- Scope inference source: akta_trigger +- Admissibility: review_required + +## Required Reviewers + +- Roles: protocol_owner + +## Scientific Context + +- Domain: materials +- Evidence state: E2_preliminary_signal +- Validation status: V1_literature_supported +- Verification status: Q0_unchecked +- Protocol version: protocol_v3 + +## Blocked Tools (severity) + +- robot_queue.submit (high severity — operational or escalation risk) + +## AKTA Constraints + +- Blocked tools: robot_queue.submit +- Allowed next steps: approve protocol draft for validation review + +## Approval Scope Context + +- protocol_draft: Draft protocol changes without activation. + +## Approval Permits + +- protocol_editor.draft_change + +## Approval Does NOT Permit + +- protocol_editor.update_active_protocol +- lab_scheduler.prioritize +- robot_queue.submit + +## Decision Options + +- Allowed: approve_narrower_scope, reject, request_more_evidence, escalate_to_higher_authority, abstain_conflict_or_insufficient_expertise + +## Reviewer Checklist + +- Confirm your role is one of: protocol_owner +- Verify requested action and tool match the scientific context +- Select the weakest approval scope supported by evidence +- Document rationale for approve, reject, or request-more-evidence +- Declare conflicts of interest before submitting a decision +- Allowed decision types: approve_narrower_scope, reject, request_more_evidence, escalate_to_higher_authority, abstain_conflict_or_insufficient_expertise + + +--- + +This display is for review coordination only. It does not constitute certification, legal authorization, or institutional approval. diff --git a/examples/pilot/single_reviewer_protocol_draft/quality_report_snippet.json b/examples/pilot/single_reviewer_protocol_draft/quality_report_snippet.json new file mode 100644 index 0000000..f874dfa --- /dev/null +++ b/examples/pilot/single_reviewer_protocol_draft/quality_report_snippet.json @@ -0,0 +1,3 @@ +{ + "policy_version": "scope-core-v0.8" +} diff --git a/examples/pilot/single_reviewer_protocol_draft/scope_decision.json b/examples/pilot/single_reviewer_protocol_draft/scope_decision.json new file mode 100644 index 0000000..4137a00 --- /dev/null +++ b/examples/pilot/single_reviewer_protocol_draft/scope_decision.json @@ -0,0 +1,59 @@ +{ + "confidence": { + "requires_second_review": false, + "reviewer_confidence": 0.5 + }, + "decided_at": "2026-06-29T09:19:13Z", + "decision": { + "approved_scope": "protocol_draft", + "rationale": "Pilot single-reviewer protocol draft approval.", + "rejected_scope": [ + "protocol_diff_review", + "single_validation_plan", + "single_validation_run_draft", + "active_protocol_update", + "single_run_queue_priority", + "bounded_batch_priority", + "tool_permission_escalation", + "execution_payload_preparation", + "robot_queue_submission", + "publication_claim", + "scientific_memory_import" + ], + "type": "approve_narrower_scope" + }, + "decision_hash": "sha256:d2ed694763dfa1ac3275c717f69aef08ab03853eefe0c80f5c5e5cf0525adfb0", + "decision_id": "SCOPE-DEC-874920", + "expiration": { + "expires_on": [ + "protocol_version_change", + "evidence_state_change", + "policy_version_change" + ], + "mode": "event_based" + }, + "packet_id": "SCOPE-PKT-D2FA4B", + "provenance": { + "authority_checks": { + "delegation_id": null, + "rbac_enforced": false, + "rbac_role_valid": false, + "scope_approval_valid": true, + "scope_role_valid": true + }, + "identity_assurance_level": "IAL0", + "identity_source": "caller_json", + "reviewer_key_registry_hash": "sha256:13f8cdcc054ca19f6a2560cd9ae688c39ac289ddf3f2d3da4e6dd0081e883692", + "reviewer_key_registry_version": "scope-core-v0.8", + "role_resolution_source": "caller_supplied", + "scope_policy_hash": "sha256:68e578ddc7a35d2cfa38c5cb95bc51182d8801548158a28b35ca1e7a035e28ea", + "scope_policy_version": "scope-core-v0.8", + "scope_trust_root_hash": "sha256:6334c56aa73915315692177499c217399e2895bbab1ed6794040b1a2d49f0a77" + }, + "reviewer": { + "conflict_declared": false, + "declared_expertise": [], + "reviewer_id": "reviewer_protocol_owner_drift", + "role": "protocol_owner" + } +} diff --git a/examples/pilot/single_reviewer_protocol_draft/scope_grant.json b/examples/pilot/single_reviewer_protocol_draft/scope_grant.json new file mode 100644 index 0000000..17faa1e --- /dev/null +++ b/examples/pilot/single_reviewer_protocol_draft/scope_grant.json @@ -0,0 +1,66 @@ +{ + "authorization": { + "allowed_tools": [ + "protocol_editor.draft_change" + ], + "approved_actions": [ + "A5_protocol_modification" + ], + "approved_scope": "protocol_draft", + "blocked_tools": [ + "lab_scheduler.prioritize", + "protocol_editor.update_active_protocol", + "robot_queue.submit" + ], + "max_responsibility_level": "R4_methodological_modification" + }, + "constraints": { + "domain_overlay": null, + "evidence_state": "E2_preliminary_signal", + "model_version": null, + "project_id": "drift_demo", + "protocol_version": "protocol_v3", + "requires_pf_core_trace": true, + "requires_recording": true, + "single_use": false, + "tool_registry_version": null, + "validation_status": "V1_literature_supported" + }, + "created_at": "2026-06-29T09:19:13Z", + "expiration": { + "absolute_expiration": null, + "expires_after": [ + "protocol_version_change", + "evidence_state_change", + "policy_version_change" + ] + }, + "grant_hash": "sha256:15695ae2507d6f6060ae51f184c1d48bb11964406add7997b8176a67ee9c30e3", + "grant_id": "SCOPE-GRANT-BCC845", + "grant_version": "0.8.0", + "provenance": { + "akta_policy_hash": null, + "authority_checks": { + "delegation_id": null, + "rbac_enforced": false, + "rbac_role_valid": false, + "scope_approval_valid": true, + "scope_role_valid": true + }, + "identity_assurance_level": "IAL0", + "identity_source": "caller_json", + "reviewer_key_registry_hash": "sha256:13f8cdcc054ca19f6a2560cd9ae688c39ac289ddf3f2d3da4e6dd0081e883692", + "reviewer_key_registry_version": "scope-core-v0.8", + "reviewer_role_policy_hash": "sha256:68e578ddc7a35d2cfa38c5cb95bc51182d8801548158a28b35ca1e7a035e28ea", + "role_resolution_source": "caller_supplied", + "scope_policy_hash": "sha256:68e578ddc7a35d2cfa38c5cb95bc51182d8801548158a28b35ca1e7a035e28ea", + "scope_policy_version": "scope-core-v0.8", + "scope_trust_root_hash": "sha256:6334c56aa73915315692177499c217399e2895bbab1ed6794040b1a2d49f0a77", + "signing_assurance_level": "SAL0" + }, + "source": { + "akta_record_id": "AKTA-SAR-DRIFT-001", + "decision_id": "SCOPE-DEC-874920", + "packet_id": "SCOPE-PKT-D2FA4B" + } +} diff --git a/examples/pilot/single_reviewer_protocol_draft/scope_review_packet.json b/examples/pilot/single_reviewer_protocol_draft/scope_review_packet.json new file mode 100644 index 0000000..35d703a --- /dev/null +++ b/examples/pilot/single_reviewer_protocol_draft/scope_review_packet.json @@ -0,0 +1,46 @@ +{ + "akta_constraints": { + "allowed_next_steps": [ + "approve protocol draft for validation review" + ], + "blocked_tools": [ + "robot_queue.submit" + ] + }, + "created_at": "2026-06-29T09:19:13Z", + "decision_options": [ + "approve_narrower_scope", + "reject", + "request_more_evidence", + "escalate_to_higher_authority", + "abstain_conflict_or_insufficient_expertise" + ], + "packet_hash": "sha256:3e5303be8276273134c17123b3f1db0f1ff39d14d18b5c6b1312980455b94465", + "packet_id": "SCOPE-PKT-D2FA4B", + "packet_version": "0.8.0", + "review_artifacts": {}, + "review_request": { + "akta_admissibility": "review_required", + "requested_action": "update_active_protocol", + "requested_scope": "protocol_draft", + "requested_tool": "protocol_editor.update_active_protocol", + "required_review_roles": [ + "protocol_owner" + ], + "responsibility_level": "R4_methodological_modification", + "scientific_action_type": "A5_protocol_modification", + "scope_inference_source": "akta_trigger" + }, + "scientific_context": { + "domain": "materials", + "evidence_state": "E2_preliminary_signal", + "project_id": "drift_demo", + "protocol_version": "protocol_v3", + "validation_status": "V1_literature_supported", + "verification_status": "Q0_unchecked" + }, + "source": { + "akta_record_id": "AKTA-SAR-DRIFT-001", + "review_trigger_id": "AKTA-REVTRIG-DRIFT-001" + } +} diff --git a/examples/pilot/single_reviewer_protocol_draft/summary.json b/examples/pilot/single_reviewer_protocol_draft/summary.json new file mode 100644 index 0000000..2a1f20f --- /dev/null +++ b/examples/pilot/single_reviewer_protocol_draft/summary.json @@ -0,0 +1,25 @@ +{ + "adapter_contract_version": "scope-akta-review-v0.8", + "allowed_tools": [ + "protocol_editor.draft_change" + ], + "approved_scope": "protocol_draft", + "blocked_tools": [ + "lab_scheduler.prioritize", + "protocol_editor.update_active_protocol", + "robot_queue.submit" + ], + "decision_id": "SCOPE-DEC-874920", + "decision_path": "examples\\pilot\\single_reviewer_protocol_draft\\scope_decision.json", + "decision_type": "approve_narrower_scope", + "grant_id": "SCOPE-GRANT-BCC845", + "grant_path": "examples\\pilot\\single_reviewer_protocol_draft\\scope_grant.json", + "identity_assurance_level": "IAL0", + "packet_id": "SCOPE-PKT-D2FA4B", + "packet_path": "examples\\pilot\\single_reviewer_protocol_draft\\scope_review_packet.json", + "production_mode": false, + "requested_scope": "protocol_draft", + "scope_trust_root_hash": "sha256:6334c56aa73915315692177499c217399e2895bbab1ed6794040b1a2d49f0a77", + "signing_assurance_level": "SAL0", + "status": "completed" +} From 4042940ce35cd1b3871ae3c7cd3b041ec547863e Mon Sep 17 00:00:00 2001 From: fraware Date: Mon, 29 Jun 2026 02:54:38 -0700 Subject: [PATCH 52/80] examples(pilot): multi_role_genomics_review scenario Multi-role genomics review session fixtures. --- .../multi_role_genomics_review/README.md | 39 ++++++++++ .../decision_domain_scientist.json | 6 ++ .../decision_protocol_owner.json | 7 ++ .../packet_rendered.md | 73 +++++++++++++++++++ .../quality_report_snippet.json | 4 + .../reviewer_domain_scientist.json | 6 ++ .../reviewer_protocol_owner.json | 6 ++ .../scope_review_packet.json | 52 +++++++++++++ .../multi_role_genomics_review/summary.json | 14 ++++ 9 files changed, 207 insertions(+) create mode 100644 examples/pilot/multi_role_genomics_review/README.md create mode 100644 examples/pilot/multi_role_genomics_review/decision_domain_scientist.json create mode 100644 examples/pilot/multi_role_genomics_review/decision_protocol_owner.json create mode 100644 examples/pilot/multi_role_genomics_review/packet_rendered.md create mode 100644 examples/pilot/multi_role_genomics_review/quality_report_snippet.json create mode 100644 examples/pilot/multi_role_genomics_review/reviewer_domain_scientist.json create mode 100644 examples/pilot/multi_role_genomics_review/reviewer_protocol_owner.json create mode 100644 examples/pilot/multi_role_genomics_review/scope_review_packet.json create mode 100644 examples/pilot/multi_role_genomics_review/summary.json diff --git a/examples/pilot/multi_role_genomics_review/README.md b/examples/pilot/multi_role_genomics_review/README.md new file mode 100644 index 0000000..adb4e8c --- /dev/null +++ b/examples/pilot/multi_role_genomics_review/README.md @@ -0,0 +1,39 @@ +# Multi-role genomics review + +Scenario: weak-evidence experimental planning (A6) requires both `domain_scientist` and `protocol_owner`. `scope akta review --session` creates a review session instead of issuing a grant immediately. + +## Artifacts + +| File | Description | +|------|-------------| +| `scope_review_packet.json` | Review packet | +| `summary.json` | Session-required summary (`status: session_required`) | +| `reviewer_protocol_owner.json` | Protocol owner reviewer fixture | +| `reviewer_domain_scientist.json` | Domain scientist reviewer fixture | +| `decision_protocol_owner.json` | Vote input for protocol owner | +| `decision_domain_scientist.json` | Vote input for domain scientist | +| `packet_rendered.md` | Markdown packet render | +| `quality_report_snippet.json` | Session-pending quality note | + +## Regenerate session + +```bash +scope akta review \ + --akta-trigger examples/weak_evidence_validation_review/review_trigger.json \ + --akta-record examples/weak_evidence_validation_review/akta_record.json \ + --grant-scope single_validation_run_draft \ + --reviewer examples/weak_evidence_validation_review/reviewer_protocol_owner.json \ + --decision-rationale "Session required for genomics co-review." \ + --out-dir examples/pilot/multi_role_genomics_review \ + --session \ + --policy policy +``` + +## Complete grant (after regeneration) + +```bash +scope review session vote --session ... +scope review session issue-grant ... +``` + +See `examples/weak_evidence_validation_review/README.md` for the full vote workflow. diff --git a/examples/pilot/multi_role_genomics_review/decision_domain_scientist.json b/examples/pilot/multi_role_genomics_review/decision_domain_scientist.json new file mode 100644 index 0000000..5cc0976 --- /dev/null +++ b/examples/pilot/multi_role_genomics_review/decision_domain_scientist.json @@ -0,0 +1,6 @@ +{ + "type": "approve_narrower_scope", + "approved_scope": "single_validation_run_draft", + "rationale": "Co-review confirms draft-only validation scope given weak evidence.", + "reviewer_confidence": 0.72 +} diff --git a/examples/pilot/multi_role_genomics_review/decision_protocol_owner.json b/examples/pilot/multi_role_genomics_review/decision_protocol_owner.json new file mode 100644 index 0000000..eaa6297 --- /dev/null +++ b/examples/pilot/multi_role_genomics_review/decision_protocol_owner.json @@ -0,0 +1,7 @@ +{ + "type": "approve_narrower_scope", + "approved_scope": "single_validation_run_draft", + "rationale": "Weak evidence supports validation draft only; robot submission remains blocked.", + "rejected_scope": ["robot_queue_submission", "active_protocol_update"], + "reviewer_confidence": 0.65 +} diff --git a/examples/pilot/multi_role_genomics_review/packet_rendered.md b/examples/pilot/multi_role_genomics_review/packet_rendered.md new file mode 100644 index 0000000..5f0f894 --- /dev/null +++ b/examples/pilot/multi_role_genomics_review/packet_rendered.md @@ -0,0 +1,73 @@ +# SCOPE Review Packet + +*This display is for review coordination only. It does not constitute certification, legal authorization, or institutional approval.* + +## Identification + +- Packet ID: SCOPE-PKT-42A16F +- AKTA Record: AKTA-SAR-S03 +- Created: 2026-06-29T09:19:52Z + +## Requested Action + +- Action: plan_validation_experiment +- Tool: experiment_planner.create_validation_plan +- Action type: A6_experimental_planning +- Requested scope: single_validation_run_draft +- Review route: none +- Scope inference source: tool_registry +- Admissibility: review_required + +## Required Reviewers + +- Roles: domain_scientist, protocol_owner + +## Scientific Context + +- Domain: materials +- Evidence state: E1_weak_signal +- Validation status: V0_unvalidated +- Verification status: unknown +- Protocol version: protocol_v2 + +## Blocked Tools (severity) + +- robot_queue.submit (high severity — operational or escalation risk) + +## AKTA Constraints + +- Blocked tools: robot_queue.submit +- Allowed next steps: approve validation draft only, request additional evidence, reject experimental plan + +## Approval Scope Context + +- single_validation_run_draft: One validation run draft. + +## Approval Permits + +- experiment_planner.create_validation_plan +- protocol_editor.draft_change + +## Approval Does NOT Permit + +- protocol_editor.update_active_protocol +- lab_scheduler.prioritize +- robot_queue.submit + +## Decision Options + +- Allowed: approve, approve_narrower_scope, reject, request_more_evidence, abstain_conflict_or_insufficient_expertise + +## Reviewer Checklist + +- Confirm your role is one of: domain_scientist, protocol_owner +- Verify requested action and tool match the scientific context +- Select the weakest approval scope supported by evidence +- Document rationale for approve, reject, or request-more-evidence +- Declare conflicts of interest before submitting a decision +- Allowed decision types: approve, approve_narrower_scope, reject, request_more_evidence, abstain_conflict_or_insufficient_expertise + + +--- + +This display is for review coordination only. It does not constitute certification, legal authorization, or institutional approval. diff --git a/examples/pilot/multi_role_genomics_review/quality_report_snippet.json b/examples/pilot/multi_role_genomics_review/quality_report_snippet.json new file mode 100644 index 0000000..0fca031 --- /dev/null +++ b/examples/pilot/multi_role_genomics_review/quality_report_snippet.json @@ -0,0 +1,4 @@ +{ + "policy_version": "scope-core-v0.8", + "note": "session pending votes" +} diff --git a/examples/pilot/multi_role_genomics_review/reviewer_domain_scientist.json b/examples/pilot/multi_role_genomics_review/reviewer_domain_scientist.json new file mode 100644 index 0000000..84900ce --- /dev/null +++ b/examples/pilot/multi_role_genomics_review/reviewer_domain_scientist.json @@ -0,0 +1,6 @@ +{ + "reviewer_id": "reviewer_ds_001", + "role": "domain_scientist", + "declared_expertise": ["experimental_design", "validation_methods"], + "conflict_declared": false +} diff --git a/examples/pilot/multi_role_genomics_review/reviewer_protocol_owner.json b/examples/pilot/multi_role_genomics_review/reviewer_protocol_owner.json new file mode 100644 index 0000000..0c7fbc7 --- /dev/null +++ b/examples/pilot/multi_role_genomics_review/reviewer_protocol_owner.json @@ -0,0 +1,6 @@ +{ + "reviewer_id": "rev_po", + "role": "protocol_owner", + "declared_expertise": ["materials_protocols", "validation_design"], + "conflict_declared": false +} diff --git a/examples/pilot/multi_role_genomics_review/scope_review_packet.json b/examples/pilot/multi_role_genomics_review/scope_review_packet.json new file mode 100644 index 0000000..24cb735 --- /dev/null +++ b/examples/pilot/multi_role_genomics_review/scope_review_packet.json @@ -0,0 +1,52 @@ +{ + "akta_constraints": { + "allowed_next_steps": [ + "approve validation draft only", + "request additional evidence", + "reject experimental plan" + ], + "blocked_tools": [ + "robot_queue.submit" + ] + }, + "created_at": "2026-06-29T09:19:52Z", + "decision_options": [ + "approve", + "approve_narrower_scope", + "reject", + "request_more_evidence", + "abstain_conflict_or_insufficient_expertise" + ], + "packet_hash": "sha256:a5f3c42561b8dfdde708c963dc014bd3e5fffe450ec587bc798c42e66d9f4241", + "packet_id": "SCOPE-PKT-42A16F", + "packet_version": "0.8.0", + "review_artifacts": { + "ai_output_summary": "Proposed validation run based on weak preliminary signal.", + "evidence_report_ref": "VSA-REP-000012" + }, + "review_request": { + "akta_admissibility": "review_required", + "requested_action": "plan_validation_experiment", + "requested_scope": "single_validation_run_draft", + "requested_tool": "experiment_planner.create_validation_plan", + "required_review_roles": [ + "domain_scientist", + "protocol_owner" + ], + "responsibility_level": "R5_experimental_planning", + "scientific_action_type": "A6_experimental_planning", + "scope_inference_source": "tool_registry" + }, + "scientific_context": { + "domain": "materials", + "evidence_state": "E1_weak_signal", + "project_id": "demo_project", + "protocol_version": "protocol_v2", + "validation_status": "V0_unvalidated" + }, + "source": { + "akta_decision_id": "AKTA-DEC-S03", + "akta_record_id": "AKTA-SAR-S03", + "review_trigger_id": "TRIG-S03" + } +} diff --git a/examples/pilot/multi_role_genomics_review/summary.json b/examples/pilot/multi_role_genomics_review/summary.json new file mode 100644 index 0000000..643da03 --- /dev/null +++ b/examples/pilot/multi_role_genomics_review/summary.json @@ -0,0 +1,14 @@ +{ + "adapter_contract_version": "scope-akta-review-v0.8", + "message": "Multi-role review session created; submit votes before grant issue.", + "packet_id": "SCOPE-PKT-42A16F", + "packet_path": "examples/pilot/multi_role_genomics_review/scope_review_packet.json", + "production_mode": false, + "requested_scope": "single_validation_run_draft", + "required_roles": [ + "domain_scientist", + "protocol_owner" + ], + "session_id": "SCOPE-SESS-26AC2A", + "status": "session_required" +} From 3b73a3b714ce91c663cb3b27bcbe09890f098427 Mon Sep 17 00:00:00 2001 From: fraware Date: Mon, 29 Jun 2026 02:54:38 -0700 Subject: [PATCH 53/80] examples(pilot): expired_queue_reopen scenario Expired queue reopen before grant issue. --- examples/pilot/expired_queue_reopen/README.md | 23 ++++++ .../expired_queue_reopen/packet_rendered.md | 72 +++++++++++++++++++ .../quality_report_snippet.json | 3 + .../review_queue_expired.json | 22 ++++++ .../review_queue_reopened.json | 23 ++++++ .../expired_queue_reopen/scope_events.jsonl | 4 ++ .../scope_review_packet.json | 40 +++++++++++ 7 files changed, 187 insertions(+) create mode 100644 examples/pilot/expired_queue_reopen/README.md create mode 100644 examples/pilot/expired_queue_reopen/packet_rendered.md create mode 100644 examples/pilot/expired_queue_reopen/quality_report_snippet.json create mode 100644 examples/pilot/expired_queue_reopen/review_queue_expired.json create mode 100644 examples/pilot/expired_queue_reopen/review_queue_reopened.json create mode 100644 examples/pilot/expired_queue_reopen/scope_events.jsonl create mode 100644 examples/pilot/expired_queue_reopen/scope_review_packet.json diff --git a/examples/pilot/expired_queue_reopen/README.md b/examples/pilot/expired_queue_reopen/README.md new file mode 100644 index 0000000..cf2d5a4 --- /dev/null +++ b/examples/pilot/expired_queue_reopen/README.md @@ -0,0 +1,23 @@ +# Expired queue reopen + +Scenario: a review queue entry expires while in review; operators must reopen before grant issuance. + +## Artifacts + +| File | Description | +|------|-------------| +| `scope_review_packet.json` | Review packet | +| `review_queue_expired.json` | Queue entry in `expired` status | +| `review_queue_reopened.json` | Same entry after `reopen` (`open` status) | +| `scope_events.jsonl` | Ledger trail | +| `packet_rendered.md` | Markdown packet render | +| `quality_report_snippet.json` | Quality metrics snippet | + +## Workflow + +1. Assign reviewer and mark `in_review` +2. `expire` when SLA elapses +3. `reopen` before resuming review +4. Grant issuance is blocked until reopen + +`mark_granted` from `expired` raises a validation error directing operators to reopen first. diff --git a/examples/pilot/expired_queue_reopen/packet_rendered.md b/examples/pilot/expired_queue_reopen/packet_rendered.md new file mode 100644 index 0000000..510303b --- /dev/null +++ b/examples/pilot/expired_queue_reopen/packet_rendered.md @@ -0,0 +1,72 @@ +# SCOPE Review Packet + +*This display is for review coordination only. It does not constitute certification, legal authorization, or institutional approval.* + +## Identification + +- Packet ID: SCOPE-PKT-2F8C44 +- AKTA Record: AKTA-PILOT-EXPIRED +- Created: 2026-06-29T09:20:28Z + +## Requested Action + +- Action: draft_protocol +- Tool: protocol_editor.draft_change +- Action type: A5_protocol_modification +- Requested scope: protocol_draft +- Review route: none +- Scope inference source: akta_trigger +- Admissibility: review_required + +## Required Reviewers + +- Roles: protocol_owner + +## Scientific Context + +- Domain: None +- Evidence state: E0_unknown +- Validation status: None +- Verification status: None +- Protocol version: unknown + +## Evidence and Validation Warnings + +- Evidence state is weak or unknown: E0_unknown + +## AKTA Constraints + +- Blocked tools: none +- Allowed next steps: none + +## Approval Scope Context + +- protocol_draft: Draft protocol changes without activation. + +## Approval Permits + +- protocol_editor.draft_change + +## Approval Does NOT Permit + +- protocol_editor.update_active_protocol +- lab_scheduler.prioritize +- robot_queue.submit + +## Decision Options + +- Allowed: approve_narrower_scope, reject, request_more_evidence, escalate_to_higher_authority, abstain_conflict_or_insufficient_expertise + +## Reviewer Checklist + +- Confirm your role is one of: protocol_owner +- Verify requested action and tool match the scientific context +- Select the weakest approval scope supported by evidence +- Document rationale for approve, reject, or request-more-evidence +- Declare conflicts of interest before submitting a decision +- Allowed decision types: approve_narrower_scope, reject, request_more_evidence, escalate_to_higher_authority, abstain_conflict_or_insufficient_expertise + + +--- + +This display is for review coordination only. It does not constitute certification, legal authorization, or institutional approval. diff --git a/examples/pilot/expired_queue_reopen/quality_report_snippet.json b/examples/pilot/expired_queue_reopen/quality_report_snippet.json new file mode 100644 index 0000000..f874dfa --- /dev/null +++ b/examples/pilot/expired_queue_reopen/quality_report_snippet.json @@ -0,0 +1,3 @@ +{ + "policy_version": "scope-core-v0.8" +} diff --git a/examples/pilot/expired_queue_reopen/review_queue_expired.json b/examples/pilot/expired_queue_reopen/review_queue_expired.json new file mode 100644 index 0000000..13245b3 --- /dev/null +++ b/examples/pilot/expired_queue_reopen/review_queue_expired.json @@ -0,0 +1,22 @@ +{ + "assigned_at": "2026-06-29T09:20:28Z", + "created_at": "2026-06-29T09:20:28Z", + "due_at": "2026-07-02T09:20:28Z", + "expired_at": "2026-06-29T09:20:28Z", + "in_review_at": "2026-06-29T09:20:28Z", + "packet_id": "SCOPE-PKT-2F8C44", + "packet_snapshot": { + "akta_admissibility": "review_required", + "packet_id": "SCOPE-PKT-2F8C44", + "requested_tool": "protocol_editor.draft_change", + "scientific_action_type": "A5_protocol_modification" + }, + "queue_id": "SCOPE-QUEUE-840C50", + "queue_version": "0.8.0", + "reviewer": { + "reviewer_id": "reviewer_001", + "role": "protocol_owner" + }, + "sla_hours": 72, + "status": "expired" +} diff --git a/examples/pilot/expired_queue_reopen/review_queue_reopened.json b/examples/pilot/expired_queue_reopen/review_queue_reopened.json new file mode 100644 index 0000000..0813f8f --- /dev/null +++ b/examples/pilot/expired_queue_reopen/review_queue_reopened.json @@ -0,0 +1,23 @@ +{ + "assigned_at": "2026-06-29T09:20:28Z", + "created_at": "2026-06-29T09:20:28Z", + "due_at": "2026-07-02T09:20:28Z", + "expired_at": "2026-06-29T09:20:28Z", + "in_review_at": "2026-06-29T09:20:28Z", + "packet_id": "SCOPE-PKT-2F8C44", + "packet_snapshot": { + "akta_admissibility": "review_required", + "packet_id": "SCOPE-PKT-2F8C44", + "requested_tool": "protocol_editor.draft_change", + "scientific_action_type": "A5_protocol_modification" + }, + "queue_id": "SCOPE-QUEUE-840C50", + "queue_version": "0.8.0", + "reopened_at": "2026-06-29T09:20:28Z", + "reviewer": { + "reviewer_id": "reviewer_001", + "role": "protocol_owner" + }, + "sla_hours": 72, + "status": "open" +} diff --git a/examples/pilot/expired_queue_reopen/scope_events.jsonl b/examples/pilot/expired_queue_reopen/scope_events.jsonl new file mode 100644 index 0000000..fd1e474 --- /dev/null +++ b/examples/pilot/expired_queue_reopen/scope_events.jsonl @@ -0,0 +1,4 @@ +{"delivery_state": "delivered", "event_hash": "sha256:74c0114bb0d52b309ce6cb81fc571ed6f8ab116a1954efebb09af5e0f96e3bf5", "event_id": "SCOPE-EVT-ACB0A794", "event_type": "packet_created", "metadata": {"created_at": "2026-06-29T09:20:28Z"}, "packet_id": "SCOPE-PKT-2F8C44", "previous_event_hash": "sha256:0000000000000000000000000000000000000000000000000000000000000000", "timestamp": "2026-06-29T09:20:28Z"} +{"delivery_state": "delivered", "event_hash": "sha256:36cc8f920ba2ab2695abd5914e4081c338ae03383ee474ff14f11233d1cb381e", "event_id": "SCOPE-EVT-20421EAB", "event_type": "review_assigned", "metadata": {"action_type": "A5_protocol_modification", "domain_overlay": null, "packet_id": "SCOPE-PKT-2F8C44", "quorum_mode": "require_all", "required_roles": ["protocol_owner"]}, "packet_id": "SCOPE-PKT-2F8C44", "previous_event_hash": "sha256:74c0114bb0d52b309ce6cb81fc571ed6f8ab116a1954efebb09af5e0f96e3bf5", "timestamp": "2026-06-29T09:20:28Z"} +{"delivery_state": "delivered", "event_hash": "sha256:b0fd9ddcaf4105ffd6de4804681adb1faff78850beda44a17cec37c3650c6f8a", "event_id": "SCOPE-EVT-9E8A0E21", "event_type": "packet_created", "metadata": {"created_at": "2026-06-29T09:20:28Z"}, "packet_id": "SCOPE-PKT-92CBAD", "previous_event_hash": "sha256:36cc8f920ba2ab2695abd5914e4081c338ae03383ee474ff14f11233d1cb381e", "timestamp": "2026-06-29T09:20:28Z"} +{"delivery_state": "delivered", "event_hash": "sha256:39c30f86b22e0f637f6bd2c07651cb73d4c5f32466324bb6ff1644533cf8ab6d", "event_id": "SCOPE-EVT-A2339EF7", "event_type": "review_assigned", "metadata": {"action_type": "A5_protocol_modification", "domain_overlay": null, "packet_id": "SCOPE-PKT-92CBAD", "quorum_mode": "require_all", "required_roles": ["protocol_owner"]}, "packet_id": "SCOPE-PKT-92CBAD", "previous_event_hash": "sha256:b0fd9ddcaf4105ffd6de4804681adb1faff78850beda44a17cec37c3650c6f8a", "timestamp": "2026-06-29T09:20:28Z"} diff --git a/examples/pilot/expired_queue_reopen/scope_review_packet.json b/examples/pilot/expired_queue_reopen/scope_review_packet.json new file mode 100644 index 0000000..fdde0f3 --- /dev/null +++ b/examples/pilot/expired_queue_reopen/scope_review_packet.json @@ -0,0 +1,40 @@ +{ + "akta_constraints": { + "allowed_next_steps": [], + "blocked_tools": [] + }, + "created_at": "2026-06-29T09:20:28Z", + "decision_options": [ + "approve_narrower_scope", + "reject", + "request_more_evidence", + "escalate_to_higher_authority", + "abstain_conflict_or_insufficient_expertise" + ], + "packet_hash": "sha256:e36961b97952bb5fddb4c4b031837bc353fe569fdeedc06931299db2f1eebf0c", + "packet_id": "SCOPE-PKT-2F8C44", + "packet_version": "0.8.0", + "review_artifacts": {}, + "review_request": { + "akta_admissibility": "review_required", + "requested_action": "draft_protocol", + "requested_scope": "protocol_draft", + "requested_tool": "protocol_editor.draft_change", + "required_review_roles": [ + "protocol_owner" + ], + "scientific_action_type": "A5_protocol_modification", + "scope_inference_source": "akta_trigger" + }, + "scientific_context": { + "deployment_profile": null, + "domain": null, + "domain_overlay": null, + "evidence_state": "E0_unknown", + "validation_status": null, + "verification_status": null + }, + "source": { + "akta_record_id": "AKTA-PILOT-EXPIRED" + } +} From a46d14511342382cf71ebfd2935a05696636a11b Mon Sep 17 00:00:00 2001 From: fraware Date: Mon, 29 Jun 2026 02:54:38 -0700 Subject: [PATCH 54/80] examples(pilot): needs_information_flow scenario Needs-information queue workflow fixtures. --- .../pilot/needs_information_flow/README.md | 23 ++++++ .../needs_information_flow/packet_rendered.md | 72 +++++++++++++++++++ .../quality_report_snippet.json | 3 + .../review_queue_in_review.json | 24 +++++++ .../review_queue_needs_information.json | 23 ++++++ .../reviewer_protocol_owner.json | 4 ++ .../scope_review_packet.json | 40 +++++++++++ 7 files changed, 189 insertions(+) create mode 100644 examples/pilot/needs_information_flow/README.md create mode 100644 examples/pilot/needs_information_flow/packet_rendered.md create mode 100644 examples/pilot/needs_information_flow/quality_report_snippet.json create mode 100644 examples/pilot/needs_information_flow/review_queue_in_review.json create mode 100644 examples/pilot/needs_information_flow/review_queue_needs_information.json create mode 100644 examples/pilot/needs_information_flow/reviewer_protocol_owner.json create mode 100644 examples/pilot/needs_information_flow/scope_review_packet.json diff --git a/examples/pilot/needs_information_flow/README.md b/examples/pilot/needs_information_flow/README.md new file mode 100644 index 0000000..a0d286c --- /dev/null +++ b/examples/pilot/needs_information_flow/README.md @@ -0,0 +1,23 @@ +# Needs information flow + +Scenario: reviewer requests additional information; queue transitions `in_review` -> `needs_information` -> `in_review` before a decision. + +## Artifacts + +| File | Description | +|------|-------------| +| `scope_review_packet.json` | Review packet | +| `review_queue_needs_information.json` | Queue in `needs_information` with reason | +| `review_queue_in_review.json` | Queue after `mark_information_received` | +| `reviewer_protocol_owner.json` | Assigned reviewer | +| `packet_rendered.md` | Markdown packet render | +| `quality_report_snippet.json` | Quality metrics snippet | + +## Workflow + +1. Assign reviewer, mark `in_review` +2. `mark_needs_information(reason=...)` when data is missing +3. `mark_information_received()` when submitter provides data +4. Proceed to `mark_decided` / `mark_granted` + +Direct transitions from `needs_information` to `decided` or `granted` are forbidden. diff --git a/examples/pilot/needs_information_flow/packet_rendered.md b/examples/pilot/needs_information_flow/packet_rendered.md new file mode 100644 index 0000000..0745998 --- /dev/null +++ b/examples/pilot/needs_information_flow/packet_rendered.md @@ -0,0 +1,72 @@ +# SCOPE Review Packet + +*This display is for review coordination only. It does not constitute certification, legal authorization, or institutional approval.* + +## Identification + +- Packet ID: SCOPE-PKT-92CBAD +- AKTA Record: AKTA-PILOT-EXPIRED +- Created: 2026-06-29T09:20:28Z + +## Requested Action + +- Action: draft_protocol +- Tool: protocol_editor.draft_change +- Action type: A5_protocol_modification +- Requested scope: protocol_draft +- Review route: none +- Scope inference source: akta_trigger +- Admissibility: review_required + +## Required Reviewers + +- Roles: protocol_owner + +## Scientific Context + +- Domain: None +- Evidence state: E0_unknown +- Validation status: None +- Verification status: None +- Protocol version: unknown + +## Evidence and Validation Warnings + +- Evidence state is weak or unknown: E0_unknown + +## AKTA Constraints + +- Blocked tools: none +- Allowed next steps: none + +## Approval Scope Context + +- protocol_draft: Draft protocol changes without activation. + +## Approval Permits + +- protocol_editor.draft_change + +## Approval Does NOT Permit + +- protocol_editor.update_active_protocol +- lab_scheduler.prioritize +- robot_queue.submit + +## Decision Options + +- Allowed: approve_narrower_scope, reject, request_more_evidence, escalate_to_higher_authority, abstain_conflict_or_insufficient_expertise + +## Reviewer Checklist + +- Confirm your role is one of: protocol_owner +- Verify requested action and tool match the scientific context +- Select the weakest approval scope supported by evidence +- Document rationale for approve, reject, or request-more-evidence +- Declare conflicts of interest before submitting a decision +- Allowed decision types: approve_narrower_scope, reject, request_more_evidence, escalate_to_higher_authority, abstain_conflict_or_insufficient_expertise + + +--- + +This display is for review coordination only. It does not constitute certification, legal authorization, or institutional approval. diff --git a/examples/pilot/needs_information_flow/quality_report_snippet.json b/examples/pilot/needs_information_flow/quality_report_snippet.json new file mode 100644 index 0000000..f874dfa --- /dev/null +++ b/examples/pilot/needs_information_flow/quality_report_snippet.json @@ -0,0 +1,3 @@ +{ + "policy_version": "scope-core-v0.8" +} diff --git a/examples/pilot/needs_information_flow/review_queue_in_review.json b/examples/pilot/needs_information_flow/review_queue_in_review.json new file mode 100644 index 0000000..6d01b65 --- /dev/null +++ b/examples/pilot/needs_information_flow/review_queue_in_review.json @@ -0,0 +1,24 @@ +{ + "assigned_at": "2026-06-29T09:20:28Z", + "created_at": "2026-06-29T09:20:28Z", + "due_at": "2026-07-02T09:20:28Z", + "in_review_at": "2026-06-29T09:20:28Z", + "information_received_at": "2026-06-29T09:20:28Z", + "needs_information_at": "2026-06-29T09:20:28Z", + "needs_information_reason": "Missing validation dataset manifest", + "packet_id": "SCOPE-PKT-92CBAD", + "packet_snapshot": { + "akta_admissibility": "review_required", + "packet_id": "SCOPE-PKT-92CBAD", + "requested_tool": "protocol_editor.draft_change", + "scientific_action_type": "A5_protocol_modification" + }, + "queue_id": "SCOPE-QUEUE-B5F040", + "queue_version": "0.8.0", + "reviewer": { + "reviewer_id": "reviewer_001", + "role": "protocol_owner" + }, + "sla_hours": 72, + "status": "in_review" +} diff --git a/examples/pilot/needs_information_flow/review_queue_needs_information.json b/examples/pilot/needs_information_flow/review_queue_needs_information.json new file mode 100644 index 0000000..35a3776 --- /dev/null +++ b/examples/pilot/needs_information_flow/review_queue_needs_information.json @@ -0,0 +1,23 @@ +{ + "assigned_at": "2026-06-29T09:20:28Z", + "created_at": "2026-06-29T09:20:28Z", + "due_at": "2026-07-02T09:20:28Z", + "in_review_at": "2026-06-29T09:20:28Z", + "needs_information_at": "2026-06-29T09:20:28Z", + "needs_information_reason": "Missing validation dataset manifest", + "packet_id": "SCOPE-PKT-92CBAD", + "packet_snapshot": { + "akta_admissibility": "review_required", + "packet_id": "SCOPE-PKT-92CBAD", + "requested_tool": "protocol_editor.draft_change", + "scientific_action_type": "A5_protocol_modification" + }, + "queue_id": "SCOPE-QUEUE-B5F040", + "queue_version": "0.8.0", + "reviewer": { + "reviewer_id": "reviewer_001", + "role": "protocol_owner" + }, + "sla_hours": 72, + "status": "needs_information" +} diff --git a/examples/pilot/needs_information_flow/reviewer_protocol_owner.json b/examples/pilot/needs_information_flow/reviewer_protocol_owner.json new file mode 100644 index 0000000..5adbc56 --- /dev/null +++ b/examples/pilot/needs_information_flow/reviewer_protocol_owner.json @@ -0,0 +1,4 @@ +{ + "reviewer_id": "reviewer_protocol_owner_drift", + "role": "protocol_owner" +} diff --git a/examples/pilot/needs_information_flow/scope_review_packet.json b/examples/pilot/needs_information_flow/scope_review_packet.json new file mode 100644 index 0000000..ded3ab2 --- /dev/null +++ b/examples/pilot/needs_information_flow/scope_review_packet.json @@ -0,0 +1,40 @@ +{ + "akta_constraints": { + "allowed_next_steps": [], + "blocked_tools": [] + }, + "created_at": "2026-06-29T09:20:28Z", + "decision_options": [ + "approve_narrower_scope", + "reject", + "request_more_evidence", + "escalate_to_higher_authority", + "abstain_conflict_or_insufficient_expertise" + ], + "packet_hash": "sha256:30fd1b4021714344e70015335343e0dcdc06e723a666f3fcaabe08d06c1b0cd8", + "packet_id": "SCOPE-PKT-92CBAD", + "packet_version": "0.8.0", + "review_artifacts": {}, + "review_request": { + "akta_admissibility": "review_required", + "requested_action": "draft_protocol", + "requested_scope": "protocol_draft", + "requested_tool": "protocol_editor.draft_change", + "required_review_roles": [ + "protocol_owner" + ], + "scientific_action_type": "A5_protocol_modification", + "scope_inference_source": "akta_trigger" + }, + "scientific_context": { + "deployment_profile": null, + "domain": null, + "domain_overlay": null, + "evidence_state": "E0_unknown", + "validation_status": null, + "verification_status": null + }, + "source": { + "akta_record_id": "AKTA-PILOT-EXPIRED" + } +} From 414b88ce9d6e918c997e75bebf00e9586b4bd45f Mon Sep 17 00:00:00 2001 From: fraware Date: Mon, 29 Jun 2026 02:54:39 -0700 Subject: [PATCH 55/80] examples(pilot): registry_signed_decision fixtures Signed decision path with reviewer key registry enforcement. --- .../pilot/registry_signed_decision/README.md | 34 +++++++++ .../packet_rendered.md | 72 +++++++++++++++++++ .../quality_report_snippet.json | 3 + .../registry_signed_decision/reviewer.pem | 3 + .../registry_signed_decision/reviewer.pub | 3 + .../reviewer_protocol_owner.json | 6 ++ .../scope_decision.json | 67 +++++++++++++++++ .../registry_signed_decision/scope_grant.json | 69 ++++++++++++++++++ .../scope_review_packet.json | 57 +++++++++++++++ .../registry_signed_decision/summary.json | 25 +++++++ 10 files changed, 339 insertions(+) create mode 100644 examples/pilot/registry_signed_decision/README.md create mode 100644 examples/pilot/registry_signed_decision/packet_rendered.md create mode 100644 examples/pilot/registry_signed_decision/quality_report_snippet.json create mode 100644 examples/pilot/registry_signed_decision/reviewer.pem create mode 100644 examples/pilot/registry_signed_decision/reviewer.pub create mode 100644 examples/pilot/registry_signed_decision/reviewer_protocol_owner.json create mode 100644 examples/pilot/registry_signed_decision/scope_decision.json create mode 100644 examples/pilot/registry_signed_decision/scope_grant.json create mode 100644 examples/pilot/registry_signed_decision/scope_review_packet.json create mode 100644 examples/pilot/registry_signed_decision/summary.json diff --git a/examples/pilot/registry_signed_decision/README.md b/examples/pilot/registry_signed_decision/README.md new file mode 100644 index 0000000..ffe85d9 --- /dev/null +++ b/examples/pilot/registry_signed_decision/README.md @@ -0,0 +1,34 @@ +# Registry-signed decision + +Scenario: institutional pilot uses `RegistryKeyProvider` with `--reviewer-id` binding to sign a decision via `reviewer_key_registry.yaml`. + +## Artifacts + +| File | Description | +|------|-------------| +| `scope_review_packet.json` | Review packet | +| `scope_decision.json` | Registry-signed decision (`decision_signature` present) | +| `scope_grant.json` | Issued grant | +| `summary.json` | Completed AKTA review summary | +| `reviewer_protocol_owner.json` | Reviewer identity (`reviewer_001`) | +| `policy/reviewer_key_registry.yaml` | Registry with `signing_key_path` (pilot only) | +| `reviewer.pem` / `reviewer.pub` | Local Ed25519 keypair (pilot only; do not use in production) | +| `packet_rendered.md` | Markdown packet render | +| `quality_report_snippet.json` | Policy version snippet | + +## Regenerate + +```bash +scope akta review \ + --akta-trigger examples/protocol_change_review/review_trigger.json \ + --akta-record examples/protocol_change_review/akta_record.json \ + --grant-scope protocol_draft \ + --reviewer examples/protocol_change_review/reviewer_protocol_owner.json \ + --decision-rationale "Registry-signed pilot approval." \ + --signing-provider registry \ + --reviewer-id reviewer_001 \ + --out-dir examples/pilot/registry_signed_decision \ + --policy examples/pilot/registry_signed_decision/policy +``` + +`--reviewer-id` must match `reviewer.json` `reviewer_id`. Mismatch fails before signing. diff --git a/examples/pilot/registry_signed_decision/packet_rendered.md b/examples/pilot/registry_signed_decision/packet_rendered.md new file mode 100644 index 0000000..afd710c --- /dev/null +++ b/examples/pilot/registry_signed_decision/packet_rendered.md @@ -0,0 +1,72 @@ +# SCOPE Review Packet + +*This display is for review coordination only. It does not constitute certification, legal authorization, or institutional approval.* + +## Identification + +- Packet ID: SCOPE-PKT-CBFEF4 +- AKTA Record: AKTA-SAR-000001 +- Created: 2026-06-29T09:21:11Z + +## Requested Action + +- Action: update_active_protocol +- Tool: protocol_editor.update_active_protocol +- Action type: A5_protocol_modification +- Requested scope: active_protocol_update +- Review route: none +- Scope inference source: tool_registry +- Admissibility: review_required + +## Required Reviewers + +- Roles: protocol_owner + +## Scientific Context + +- Domain: materials +- Evidence state: E2_preliminary_signal +- Validation status: V1_literature_supported +- Verification status: Q0_unchecked +- Protocol version: protocol_v3 + +## Blocked Tools (severity) + +- robot_queue.submit (high severity — operational or escalation risk) +- lab_scheduler.prioritize (policy blocked) + +## AKTA Constraints + +- Blocked tools: robot_queue.submit, lab_scheduler.prioritize +- Allowed next steps: approve protocol draft for validation review, request additional evidence, reject active protocol update + +## Approval Scope Context + +- active_protocol_update: Update the active protocol. + +## Approval Permits + +- protocol_editor.update_active_protocol +- protocol_editor.draft_change + +## Approval Does NOT Permit + +- robot_queue.submit + +## Decision Options + +- Allowed: approve_narrower_scope, reject, request_more_evidence, escalate_to_higher_authority, abstain_conflict_or_insufficient_expertise + +## Reviewer Checklist + +- Confirm your role is one of: protocol_owner +- Verify requested action and tool match the scientific context +- Select the weakest approval scope supported by evidence +- Document rationale for approve, reject, or request-more-evidence +- Declare conflicts of interest before submitting a decision +- Allowed decision types: approve_narrower_scope, reject, request_more_evidence, escalate_to_higher_authority, abstain_conflict_or_insufficient_expertise + + +--- + +This display is for review coordination only. It does not constitute certification, legal authorization, or institutional approval. diff --git a/examples/pilot/registry_signed_decision/quality_report_snippet.json b/examples/pilot/registry_signed_decision/quality_report_snippet.json new file mode 100644 index 0000000..f874dfa --- /dev/null +++ b/examples/pilot/registry_signed_decision/quality_report_snippet.json @@ -0,0 +1,3 @@ +{ + "policy_version": "scope-core-v0.8" +} diff --git a/examples/pilot/registry_signed_decision/reviewer.pem b/examples/pilot/registry_signed_decision/reviewer.pem new file mode 100644 index 0000000..8c69d7a --- /dev/null +++ b/examples/pilot/registry_signed_decision/reviewer.pem @@ -0,0 +1,3 @@ +-----BEGIN PRIVATE KEY----- +MC4CAQAwBQYDK2VwBCIEIKOWzXD+Sh6n6uTpkYHHXGPL0BfHM4tUeqtpvlBYbdeV +-----END PRIVATE KEY----- diff --git a/examples/pilot/registry_signed_decision/reviewer.pub b/examples/pilot/registry_signed_decision/reviewer.pub new file mode 100644 index 0000000..e70aa3f --- /dev/null +++ b/examples/pilot/registry_signed_decision/reviewer.pub @@ -0,0 +1,3 @@ +-----BEGIN PUBLIC KEY----- +MCowBQYDK2VwAyEAL0Qlz0hGCKfQ8F1q+CUBgwk2LprjMRbdkDqbd+ZuIic= +-----END PUBLIC KEY----- diff --git a/examples/pilot/registry_signed_decision/reviewer_protocol_owner.json b/examples/pilot/registry_signed_decision/reviewer_protocol_owner.json new file mode 100644 index 0000000..eebd734 --- /dev/null +++ b/examples/pilot/registry_signed_decision/reviewer_protocol_owner.json @@ -0,0 +1,6 @@ +{ + "reviewer_id": "reviewer_001", + "role": "protocol_owner", + "declared_expertise": ["materials_protocols", "instrument_workflow"], + "conflict_declared": false +} diff --git a/examples/pilot/registry_signed_decision/scope_decision.json b/examples/pilot/registry_signed_decision/scope_decision.json new file mode 100644 index 0000000..8724ebe --- /dev/null +++ b/examples/pilot/registry_signed_decision/scope_decision.json @@ -0,0 +1,67 @@ +{ + "confidence": { + "requires_second_review": false, + "reviewer_confidence": 0.5 + }, + "decided_at": "2026-06-29T09:21:11Z", + "decision": { + "approved_scope": "protocol_draft", + "rationale": "Registry-signed pilot approval.", + "rejected_scope": [ + "protocol_diff_review", + "single_validation_plan", + "single_validation_run_draft", + "active_protocol_update", + "single_run_queue_priority", + "bounded_batch_priority", + "tool_permission_escalation", + "execution_payload_preparation", + "robot_queue_submission", + "publication_claim", + "scientific_memory_import" + ], + "type": "approve_narrower_scope" + }, + "decision_hash": "sha256:bcb57da9be8afe2ddd5458e6ac76c7431f0cc6a533f6c7c92a95a02408ede6c1", + "decision_id": "SCOPE-DEC-6A5596", + "decision_signature": "fjNgL4Zy23t7hp/ERqcByRAY4pMoR9FY5LVmM3aAlEeJViL+bjfww/wiQbHynn3Nw+yWjr5LeFl9ryZbstMhBw==", + "expiration": { + "expires_on": [ + "protocol_version_change", + "evidence_state_change", + "policy_version_change" + ], + "mode": "event_based" + }, + "packet_id": "SCOPE-PKT-CBFEF4", + "provenance": { + "authority_checks": { + "delegation_id": null, + "rbac_enforced": false, + "rbac_role_valid": false, + "scope_approval_valid": true, + "scope_role_valid": true + }, + "identity_assurance_level": "IAL1", + "identity_source": "local_signed_key", + "reviewer_key_registry_hash": "sha256:81922800365a353ba12fada4f663bcdcb609726b2380b6f27f765956b7b3bfa7", + "reviewer_key_registry_version": "scope-core-v0.8", + "role_resolution_source": "local_signed_key", + "scope_policy_hash": "sha256:68e578ddc7a35d2cfa38c5cb95bc51182d8801548158a28b35ca1e7a035e28ea", + "scope_policy_version": "scope-core-v0.8", + "scope_trust_root_hash": "sha256:9b28e2d9bcabdc76e9db48dc9edbe3e62e87f46f55cd26c017233debb69ddc77" + }, + "reviewer": { + "conflict_declared": false, + "declared_expertise": [ + "materials_protocols", + "instrument_workflow" + ], + "reviewer_id": "reviewer_001", + "reviewer_public_key_ref": "sha256:2912c11a2264f747a8fe50f5496274a321c6592bd80e005cffb3ce1a2c987174", + "role": "protocol_owner" + }, + "reviewer_public_key_ref": "sha256:2912c11a2264f747a8fe50f5496274a321c6592bd80e005cffb3ce1a2c987174", + "signature_algorithm": "ed25519", + "signed_payload_hash": "sha256:bcb57da9be8afe2ddd5458e6ac76c7431f0cc6a533f6c7c92a95a02408ede6c1" +} diff --git a/examples/pilot/registry_signed_decision/scope_grant.json b/examples/pilot/registry_signed_decision/scope_grant.json new file mode 100644 index 0000000..a11b7f3 --- /dev/null +++ b/examples/pilot/registry_signed_decision/scope_grant.json @@ -0,0 +1,69 @@ +{ + "authorization": { + "allowed_tools": [ + "protocol_editor.draft_change" + ], + "approved_actions": [ + "A5_protocol_modification" + ], + "approved_scope": "protocol_draft", + "blocked_tools": [ + "lab_scheduler.prioritize", + "protocol_editor.update_active_protocol", + "robot_queue.submit" + ], + "max_responsibility_level": "R4_methodological_modification" + }, + "constraints": { + "domain_overlay": "materials_v0.1", + "evidence_state": "E2_preliminary_signal", + "model_version": null, + "project_id": "demo_project", + "protocol_version": "protocol_v3", + "requires_pf_core_trace": true, + "requires_recording": true, + "single_use": false, + "tool_registry_version": null, + "validation_status": "V1_literature_supported" + }, + "created_at": "2026-06-29T09:21:11Z", + "expiration": { + "absolute_expiration": null, + "expires_after": [ + "protocol_version_change", + "evidence_state_change", + "policy_version_change" + ] + }, + "grant_hash": "sha256:3e113cb897b5043af3610fc65a238c4811197257d4d17e5b2e4aa1c43005fbbd", + "grant_id": "SCOPE-GRANT-2E7A58", + "grant_version": "0.8.0", + "provenance": { + "akta_policy_hash": null, + "authority_checks": { + "delegation_id": null, + "rbac_enforced": false, + "rbac_role_valid": false, + "scope_approval_valid": true, + "scope_role_valid": true + }, + "identity_assurance_level": "IAL1", + "identity_source": "local_signed_key", + "reviewer_key_registry_hash": "sha256:81922800365a353ba12fada4f663bcdcb609726b2380b6f27f765956b7b3bfa7", + "reviewer_key_registry_version": "scope-core-v0.8", + "reviewer_role_policy_hash": "sha256:68e578ddc7a35d2cfa38c5cb95bc51182d8801548158a28b35ca1e7a035e28ea", + "role_resolution_source": "local_signed_key", + "scope_policy_hash": "sha256:68e578ddc7a35d2cfa38c5cb95bc51182d8801548158a28b35ca1e7a035e28ea", + "scope_policy_version": "scope-core-v0.8", + "scope_trust_root_hash": "sha256:9b28e2d9bcabdc76e9db48dc9edbe3e62e87f46f55cd26c017233debb69ddc77", + "signing_assurance_level": "SAL3" + }, + "reviewer_public_key_ref": "sha256:2912c11a2264f747a8fe50f5496274a321c6592bd80e005cffb3ce1a2c987174", + "signature_algorithm": "ed25519", + "signed_payload_hash": "sha256:bcb57da9be8afe2ddd5458e6ac76c7431f0cc6a533f6c7c92a95a02408ede6c1", + "source": { + "akta_record_id": "AKTA-SAR-000001", + "decision_id": "SCOPE-DEC-6A5596", + "packet_id": "SCOPE-PKT-CBFEF4" + } +} diff --git a/examples/pilot/registry_signed_decision/scope_review_packet.json b/examples/pilot/registry_signed_decision/scope_review_packet.json new file mode 100644 index 0000000..ca31238 --- /dev/null +++ b/examples/pilot/registry_signed_decision/scope_review_packet.json @@ -0,0 +1,57 @@ +{ + "akta_constraints": { + "allowed_next_steps": [ + "approve protocol draft for validation review", + "request additional evidence", + "reject active protocol update" + ], + "blocked_tools": [ + "robot_queue.submit", + "lab_scheduler.prioritize" + ] + }, + "created_at": "2026-06-29T09:21:11Z", + "decision_options": [ + "approve_narrower_scope", + "reject", + "request_more_evidence", + "escalate_to_higher_authority", + "abstain_conflict_or_insufficient_expertise" + ], + "packet_hash": "sha256:c1d45994a32787986ee0add61e4490d39d5dafbd2845946725de13beefae679e", + "packet_id": "SCOPE-PKT-CBFEF4", + "packet_version": "0.8.0", + "review_artifacts": { + "ai_output_ref": "sha256:abc123", + "ai_output_summary": "The agent adjusted the timing window and acceptance threshold.", + "evidence_report_ref": "VSA-REP-000004", + "protocol_diff_ref": "sha256:def456" + }, + "review_request": { + "akta_admissibility": "review_required", + "requested_action": "update_active_protocol", + "requested_scope": "active_protocol_update", + "requested_tool": "protocol_editor.update_active_protocol", + "required_review_roles": [ + "protocol_owner" + ], + "responsibility_level": "R4_methodological_modification", + "scientific_action_type": "A5_protocol_modification", + "scope_inference_source": "tool_registry" + }, + "scientific_context": { + "deployment_profile": "P4_protocol_drafting_assistant", + "domain": "materials", + "domain_overlay": "materials_v0.1", + "evidence_state": "E2_preliminary_signal", + "project_id": "demo_project", + "protocol_version": "protocol_v3", + "validation_status": "V1_literature_supported", + "verification_status": "Q0_unchecked" + }, + "source": { + "akta_decision_id": "AKTA-DEC-000001", + "akta_record_id": "AKTA-SAR-000001", + "review_trigger_id": "AKTA-REVTRIG-000001" + } +} diff --git a/examples/pilot/registry_signed_decision/summary.json b/examples/pilot/registry_signed_decision/summary.json new file mode 100644 index 0000000..6ec1ef0 --- /dev/null +++ b/examples/pilot/registry_signed_decision/summary.json @@ -0,0 +1,25 @@ +{ + "adapter_contract_version": "scope-akta-review-v0.8", + "allowed_tools": [ + "protocol_editor.draft_change" + ], + "approved_scope": "protocol_draft", + "blocked_tools": [ + "lab_scheduler.prioritize", + "protocol_editor.update_active_protocol", + "robot_queue.submit" + ], + "decision_id": "SCOPE-DEC-6A5596", + "decision_path": "c:\\Users\\mateo\\SCOPE\\examples\\pilot\\registry_signed_decision\\scope_decision.json", + "decision_type": "approve_narrower_scope", + "grant_id": "SCOPE-GRANT-2E7A58", + "grant_path": "c:\\Users\\mateo\\SCOPE\\examples\\pilot\\registry_signed_decision\\scope_grant.json", + "identity_assurance_level": "IAL1", + "packet_id": "SCOPE-PKT-CBFEF4", + "packet_path": "c:\\Users\\mateo\\SCOPE\\examples\\pilot\\registry_signed_decision\\scope_review_packet.json", + "production_mode": false, + "requested_scope": "active_protocol_update", + "scope_trust_root_hash": "sha256:9b28e2d9bcabdc76e9db48dc9edbe3e62e87f46f55cd26c017233debb69ddc77", + "signing_assurance_level": "SAL3", + "status": "completed" +} From adeea91b68dbe4853fdcdd616944cf67b5ddd7fc Mon Sep 17 00:00:00 2001 From: fraware Date: Mon, 29 Jun 2026 02:54:39 -0700 Subject: [PATCH 56/80] examples(pilot): registry_signed_decision policy snapshot Pin examples/pilot/registry_signed_decision/policy/approval_scopes.yaml for reproducible registry signing demo. --- .../policy/approval_scopes.yaml | 54 +++++++++++++++++++ 1 file changed, 54 insertions(+) create mode 100644 examples/pilot/registry_signed_decision/policy/approval_scopes.yaml diff --git a/examples/pilot/registry_signed_decision/policy/approval_scopes.yaml b/examples/pilot/registry_signed_decision/policy/approval_scopes.yaml new file mode 100644 index 0000000..bddc262 --- /dev/null +++ b/examples/pilot/registry_signed_decision/policy/approval_scopes.yaml @@ -0,0 +1,54 @@ +version: scope-core-v0.8 +hierarchy: + - no_action + - clarification_only + - hypothesis_discussion + - evidence_interpretation_only + - draft_recommendation + - protocol_draft + - protocol_diff_review + - single_validation_plan + - single_validation_run_draft + - active_protocol_update + - single_run_queue_priority + - bounded_batch_priority + - tool_permission_escalation + - execution_payload_preparation + - robot_queue_submission + - publication_claim + - scientific_memory_import +semantics: + no_action: + description: No authorized action; review only. + clarification_only: + description: Clarify or annotate without changing scientific state. + hypothesis_discussion: + description: Discuss hypotheses without operational effect. + evidence_interpretation_only: + description: Interpret evidence without downstream action. + draft_recommendation: + description: Non-binding recommendation draft. + protocol_draft: + description: Draft protocol changes without activation. + protocol_diff_review: + description: Review protocol diff without applying. + single_validation_plan: + description: One validation experiment plan. + single_validation_run_draft: + description: One validation run draft. + active_protocol_update: + description: Update the active protocol. + single_run_queue_priority: + description: Priority for a single run. + bounded_batch_priority: + description: Priority for a bounded batch. + tool_permission_escalation: + description: Escalated tool permissions. + execution_payload_preparation: + description: Prepare execution payload without submission. + robot_queue_submission: + description: Submit to robot queue. + publication_claim: + description: Escalate to publication claim. + scientific_memory_import: + description: Import into scientific memory. From 73500fbce60b0175623e17296121b4049d195e7d Mon Sep 17 00:00:00 2001 From: fraware Date: Mon, 29 Jun 2026 02:54:39 -0700 Subject: [PATCH 57/80] examples(pilot): registry_signed_decision policy snapshot Pin examples/pilot/registry_signed_decision/policy/blocked_tool_severity.yaml for reproducible registry signing demo. --- .../policy/blocked_tool_severity.yaml | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 examples/pilot/registry_signed_decision/policy/blocked_tool_severity.yaml diff --git a/examples/pilot/registry_signed_decision/policy/blocked_tool_severity.yaml b/examples/pilot/registry_signed_decision/policy/blocked_tool_severity.yaml new file mode 100644 index 0000000..8a8f6de --- /dev/null +++ b/examples/pilot/registry_signed_decision/policy/blocked_tool_severity.yaml @@ -0,0 +1,8 @@ +version: scope-core-v0.8 +high_severity: + - robot_queue.submit + - protocol_editor.update_active_protocol + - scientific_memory.import + - workflow.mutate_permissions +policy_blocked_label: policy blocked +all_tools_label: all tools blocked From 9208947092b1ed2bdb2480d07368f8dd7dcdb161 Mon Sep 17 00:00:00 2001 From: fraware Date: Mon, 29 Jun 2026 02:54:40 -0700 Subject: [PATCH 58/80] examples(pilot): registry_signed_decision policy snapshot Pin examples/pilot/registry_signed_decision/policy/decision_options.yaml for reproducible registry signing demo. --- .../policy/decision_options.yaml | 48 +++++++++++++++++++ 1 file changed, 48 insertions(+) create mode 100644 examples/pilot/registry_signed_decision/policy/decision_options.yaml diff --git a/examples/pilot/registry_signed_decision/policy/decision_options.yaml b/examples/pilot/registry_signed_decision/policy/decision_options.yaml new file mode 100644 index 0000000..6a10d98 --- /dev/null +++ b/examples/pilot/registry_signed_decision/policy/decision_options.yaml @@ -0,0 +1,48 @@ +version: scope-core-v0.8 +decision_types: + - approve + - approve_with_modifications + - approve_narrower_scope + - reject + - request_more_evidence + - request_replication + - escalate_to_higher_authority + - abstain_conflict_or_insufficient_expertise +allowed_by_action: + A5_protocol_modification: + - approve_narrower_scope + - reject + - request_more_evidence + - escalate_to_higher_authority + - abstain_conflict_or_insufficient_expertise + A6_experimental_planning: + - approve + - approve_narrower_scope + - reject + - request_more_evidence + - abstain_conflict_or_insufficient_expertise + A7_resource_or_queue_prioritization: + - approve + - approve_narrower_scope + - reject + - escalate_to_higher_authority + - abstain_conflict_or_insufficient_expertise + A10_publication_or_claim_escalation: + - approve + - approve_narrower_scope + - reject + - request_more_evidence + - abstain_conflict_or_insufficient_expertise + default: + - approve + - approve_with_modifications + - approve_narrower_scope + - reject + - request_more_evidence + - request_replication + - escalate_to_higher_authority + - abstain_conflict_or_insufficient_expertise +approval_decisions: + - approve + - approve_with_modifications + - approve_narrower_scope From 31ecafe07e6cafb9c8cb7a5d9c6af8b60ce69c44 Mon Sep 17 00:00:00 2001 From: fraware Date: Mon, 29 Jun 2026 02:54:40 -0700 Subject: [PATCH 59/80] examples(pilot): registry_signed_decision policy snapshot Pin examples/pilot/registry_signed_decision/policy/expiration_rules.yaml for reproducible registry signing demo. --- .../policy/expiration_rules.yaml | 51 +++++++++++++++++++ 1 file changed, 51 insertions(+) create mode 100644 examples/pilot/registry_signed_decision/policy/expiration_rules.yaml diff --git a/examples/pilot/registry_signed_decision/policy/expiration_rules.yaml b/examples/pilot/registry_signed_decision/policy/expiration_rules.yaml new file mode 100644 index 0000000..d61dee3 --- /dev/null +++ b/examples/pilot/registry_signed_decision/policy/expiration_rules.yaml @@ -0,0 +1,51 @@ +version: scope-core-v0.8 +default_expiration: + protocol_draft: + expires_after: + - protocol_version_change + - evidence_state_change + - policy_version_change + single_validation_run_draft: + expires_after: + - single_use + - protocol_version_change + - evidence_state_change + - policy_version_change + active_protocol_update: + expires_after: + - protocol_version_change + - policy_version_change + robot_queue_submission: + expires_after: + - single_use + - protocol_version_change + - safety_incident + publication_claim: + expires_after: + - evidence_state_change + - policy_version_change + default: + expires_after: + - policy_version_change + - evidence_state_change +modes: + - single_use + - time_based + - event_based + - version_based + - evidence_based + - policy_based + - reviewer_withdrawal + - manual_revocation +triggers: + protocol_version_change: Invalidate when protocol_version differs from grant constraints. + evidence_state_change: Invalidate when evidence_state differs from grant context. + validation_status_change: Invalidate when validation_status changes. + policy_version_change: Invalidate when scope policy version changes. + domain_overlay_change: Invalidate when domain_overlay differs from grant constraints. + model_version_change: Invalidate when model_version differs from grant constraints. + tool_registry_change: Invalidate when tool_registry_version differs from grant context. + reviewer_withdrawal: Invalidate when reviewer withdraws approval (grant_revoked). + single_use: Invalidate after first successful tool use. + safety_incident: Invalidate on recorded safety incident. + completion_of_single_validation_run: Invalidate after validation run completes. From ef66548e0eee92968c2f68ea752bc853446235e2 Mon Sep 17 00:00:00 2001 From: fraware Date: Mon, 29 Jun 2026 02:54:40 -0700 Subject: [PATCH 60/80] examples(pilot): registry_signed_decision policy snapshot Pin examples/pilot/registry_signed_decision/policy/identity_mapping.yaml for reproducible registry signing demo. --- .../policy/identity_mapping.yaml | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 examples/pilot/registry_signed_decision/policy/identity_mapping.yaml diff --git a/examples/pilot/registry_signed_decision/policy/identity_mapping.yaml b/examples/pilot/registry_signed_decision/policy/identity_mapping.yaml new file mode 100644 index 0000000..53e689d --- /dev/null +++ b/examples/pilot/registry_signed_decision/policy/identity_mapping.yaml @@ -0,0 +1,14 @@ +version: scope-core-v0.8 +description: Map OIDC JWT claims to SCOPE reviewer identity. +claim_mappings: + reviewer_id: sub + role_claim: scope_role + groups_claim: groups +group_to_role: + scope-domain-scientist: domain_scientist + scope-system-owner: system_owner + scope-biosecurity: biosecurity_reviewer + scope-clinical: clinical_reviewer +default_role: domain_scientist +issuer_required: true +audience_required: true From 519d704a17c2f259633846d9c8daece6c098ec8c Mon Sep 17 00:00:00 2001 From: fraware Date: Mon, 29 Jun 2026 02:54:41 -0700 Subject: [PATCH 61/80] examples(pilot): registry_signed_decision policy snapshot Pin examples/pilot/registry_signed_decision/policy/minimum_signing_assurance.yaml for reproducible registry signing demo. --- .../policy/minimum_signing_assurance.yaml | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 examples/pilot/registry_signed_decision/policy/minimum_signing_assurance.yaml diff --git a/examples/pilot/registry_signed_decision/policy/minimum_signing_assurance.yaml b/examples/pilot/registry_signed_decision/policy/minimum_signing_assurance.yaml new file mode 100644 index 0000000..76f6810 --- /dev/null +++ b/examples/pilot/registry_signed_decision/policy/minimum_signing_assurance.yaml @@ -0,0 +1,10 @@ +version: scope-core-v0.8 +minimum_level: SAL1 +high_risk_minimum_level: SAL3 +enforce_in_development: false +high_risk_scopes: + - robot_queue_submission + - tool_permission_escalation + - publication_claim + - active_protocol_update + - execution_payload_preparation From fbb988e363b9e4cd1296d1ae8301e8ae05135ef6 Mon Sep 17 00:00:00 2001 From: fraware Date: Mon, 29 Jun 2026 02:54:41 -0700 Subject: [PATCH 62/80] examples(pilot): registry_signed_decision policy snapshot Pin examples/pilot/registry_signed_decision/policy/org_rbac.yaml for reproducible registry signing demo. --- .../policy/org_rbac.yaml | 33 +++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 examples/pilot/registry_signed_decision/policy/org_rbac.yaml diff --git a/examples/pilot/registry_signed_decision/policy/org_rbac.yaml b/examples/pilot/registry_signed_decision/policy/org_rbac.yaml new file mode 100644 index 0000000..e8511fd --- /dev/null +++ b/examples/pilot/registry_signed_decision/policy/org_rbac.yaml @@ -0,0 +1,33 @@ +version: scope-core-v0.8 +org_units: + genomics_lab: + members: + ds1: + roles: [domain_scientist] + so1: + roles: [system_owner] + bio1: + roles: [biosecurity_reviewer] + clinical_research: + members: + clin1: + roles: [clinical_reviewer, domain_scientist] +delegations: + - delegate_reviewer_id: ds1 + role: domain_scientist + granted_to: ds2 + valid_until: "2099-12-31T23:59:59Z" + granted_by: principal_investigator +role_permissions: + domain_scientist: + can_submit_decisions: true + can_vote_in_session: true + system_owner: + can_submit_decisions: true + can_vote_in_session: true + biosecurity_reviewer: + can_submit_decisions: true + can_vote_in_session: true + clinical_reviewer: + can_submit_decisions: true + can_vote_in_session: true From ecdb7de9224384606506d258b27c6a93400117e7 Mon Sep 17 00:00:00 2001 From: fraware Date: Mon, 29 Jun 2026 02:54:41 -0700 Subject: [PATCH 63/80] examples(pilot): registry_signed_decision policy snapshot Pin examples/pilot/registry_signed_decision/policy/quality_metrics.yaml for reproducible registry signing demo. --- .../policy/quality_metrics.yaml | 132 ++++++++++++++++++ 1 file changed, 132 insertions(+) create mode 100644 examples/pilot/registry_signed_decision/policy/quality_metrics.yaml diff --git a/examples/pilot/registry_signed_decision/policy/quality_metrics.yaml b/examples/pilot/registry_signed_decision/policy/quality_metrics.yaml new file mode 100644 index 0000000..701af90 --- /dev/null +++ b/examples/pilot/registry_signed_decision/policy/quality_metrics.yaml @@ -0,0 +1,132 @@ +version: scope-core-v0.8 +thresholds: + rubber_stamp_min_review_seconds: 20 + rubber_stamp_high_risk_count: 10 + scope_overbreadth_tolerance: 0 + stale_grant_rate_warning: 0.05 + approval_without_comment_rate_warning: 0.3 +warning_types: + rubber_stamp_risk: + description: Reviewer approved high-risk actions with very short review time. + scope_overbreadth: + description: Reviewer approved a scope stronger than requested or permitted. + stale_grant_attempt: + description: Grant use attempted after expiration condition. + scope_violation_attempt: + description: Runtime attempted tool outside grant scope. + approval_despite_low_evidence: + description: Approval granted despite weak evidence state. + residual_block_violation: + description: Approval did not preserve AKTA residual blocks. +metrics: + review_turnaround_time: + category: core + description: Median time from packet creation to decision submission. + v0_4_status: implemented + approval_rate: + category: core + v0_4_status: implemented + rejection_rate: + category: core + v0_4_status: implemented + request_more_evidence_rate: + category: core + v0_4_status: implemented + escalation_rate: + category: core + v0_4_status: implemented + abstention_rate: + category: core + v0_4_status: implemented + reviewer_confidence_mean: + category: core + v0_4_status: implemented + reviewer_confidence_variance: + category: core + v0_4_status: implemented + approval_without_comment_rate: + category: rubber_stamp + v0_4_status: implemented + approval_under_minimum_review_time: + category: rubber_stamp + v0_4_status: implemented + repeat_approval_rate: + category: rubber_stamp + v0_4_status: implemented + high_risk_approval_rate: + category: rubber_stamp + v0_4_status: implemented + approval_despite_low_evidence_rate: + category: rubber_stamp + v0_4_status: implemented + approval_despite_akta_block_rate: + category: rubber_stamp + v0_4_status: implemented + scope_overbreadth_rate: + category: scope_quality + v0_4_status: implemented + stale_grant_rate: + category: scope_quality + v0_4_status: implemented + expired_grant_attempt_rate: + category: scope_quality + v0_4_status: implemented + scope_violation_attempt_rate: + category: scope_quality + v0_4_status: implemented + narrowed_scope_rate: + category: scope_quality + v0_4_status: implemented + residual_block_preservation_rate: + category: scope_quality + v0_4_status: implemented + review_queue_length: + category: burden + v0_4_status: implemented + open_queue_count: + category: burden + description: Open review queue entries persisted on disk. + v0_5_status: implemented + overdue_queue_count: + category: burden + description: Assigned or open queue entries past SLA due date. + v0_5_status: implemented + median_time_to_decision: + category: burden + v0_4_status: implemented + reviewer_load: + category: burden + v0_4_status: implemented + duplicate_review_rate: + category: burden + v0_4_status: implemented + unnecessary_review_rate: + category: burden + v0_4_status: implemented + false_review_trigger_rate: + category: burden + v0_4_status: implemented + post_approval_failure_rate: + category: outcome + v0_4_status: implemented + post_approval_protocol_drift_rate: + category: outcome + v0_4_status: implemented + post_approval_evidence_downgrade_rate: + category: outcome + v0_4_status: implemented + open_queue_count: + category: queue + description: Open or assigned review queue entries on disk. + v0_5_status: implemented + overdue_queue_count: + category: queue + description: Queue entries past due_at still awaiting decision. + v0_5_status: implemented + post_approval_runtime_violation_rate: + category: outcome + v0_4_status: implemented + ledger_delivery_failure_count: + category: outcome + description: Ledger events with failed or spooled remote delivery state. + v0_7_status: implemented From c07f4f32351aae0f8227109821e0545dd56da889 Mon Sep 17 00:00:00 2001 From: fraware Date: Mon, 29 Jun 2026 02:54:41 -0700 Subject: [PATCH 64/80] examples(pilot): registry_signed_decision policy snapshot Pin examples/pilot/registry_signed_decision/policy/reviewer_assignments.yaml for reproducible registry signing demo. --- .../policy/reviewer_assignments.yaml | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 examples/pilot/registry_signed_decision/policy/reviewer_assignments.yaml diff --git a/examples/pilot/registry_signed_decision/policy/reviewer_assignments.yaml b/examples/pilot/registry_signed_decision/policy/reviewer_assignments.yaml new file mode 100644 index 0000000..861e6ef --- /dev/null +++ b/examples/pilot/registry_signed_decision/policy/reviewer_assignments.yaml @@ -0,0 +1,10 @@ +version: scope-core-v0.8 +description: Default reviewer assignments by role for auto-assignment. +assignments: + domain_scientist: ds1 + system_owner: so1 + biosecurity_reviewer: bio1 + clinical_reviewer: clin1 + protocol_owner: po1 + principal_investigator: pi1 +round_robin_from_registry: true From 776217ba6a00aea073a6181f176d3f33ada19391 Mon Sep 17 00:00:00 2001 From: fraware Date: Mon, 29 Jun 2026 02:54:42 -0700 Subject: [PATCH 65/80] examples(pilot): registry_signed_decision policy snapshot Pin examples/pilot/registry_signed_decision/policy/reviewer_key_registry.yaml for reproducible registry signing demo. --- .../policy/reviewer_key_registry.yaml | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 examples/pilot/registry_signed_decision/policy/reviewer_key_registry.yaml diff --git a/examples/pilot/registry_signed_decision/policy/reviewer_key_registry.yaml b/examples/pilot/registry_signed_decision/policy/reviewer_key_registry.yaml new file mode 100644 index 0000000..20232d9 --- /dev/null +++ b/examples/pilot/registry_signed_decision/policy/reviewer_key_registry.yaml @@ -0,0 +1,11 @@ +version: scope-core-v0.8 +description: 'Optional local registry mapping reviewer_id to expected public key references. + + Institutions populate this file; empty registry skips identity binding checks. + + ' +reviewers: + reviewer_001: + public_key_ref: sha256:2912c11a2264f747a8fe50f5496274a321c6592bd80e005cffb3ce1a2c987174 + public_key_file: C:\Users\mateo\SCOPE\examples\pilot\registry_signed_decision\reviewer.pub + signing_key_path: c:\Users\mateo\SCOPE\examples\pilot\registry_signed_decision\reviewer.pem From d04ea1ea341597e7e62ecc2c6c37f054b87c680c Mon Sep 17 00:00:00 2001 From: fraware Date: Mon, 29 Jun 2026 02:54:42 -0700 Subject: [PATCH 66/80] examples(pilot): registry_signed_decision policy snapshot Pin examples/pilot/registry_signed_decision/policy/reviewer_roles.yaml for reproducible registry signing demo. --- .../policy/reviewer_roles.yaml | 104 ++++++++++++++++++ 1 file changed, 104 insertions(+) create mode 100644 examples/pilot/registry_signed_decision/policy/reviewer_roles.yaml diff --git a/examples/pilot/registry_signed_decision/policy/reviewer_roles.yaml b/examples/pilot/registry_signed_decision/policy/reviewer_roles.yaml new file mode 100644 index 0000000..25b0835 --- /dev/null +++ b/examples/pilot/registry_signed_decision/policy/reviewer_roles.yaml @@ -0,0 +1,104 @@ +version: scope-core-v0.8 +roles: + domain_scientist: + description: Reviews scientific plausibility, domain assumptions, and interpretation. + can_approve_scopes: + - clarification_only + - hypothesis_discussion + - evidence_interpretation_only + - draft_recommendation + - protocol_draft + - single_validation_plan + - single_validation_run_draft + - publication_claim + protocol_owner: + description: Reviews protocol diffs, method changes, thresholds, and active protocol updates. + can_approve_scopes: + - clarification_only + - hypothesis_discussion + - protocol_draft + - protocol_diff_review + - single_validation_plan + - single_validation_run_draft + - active_protocol_update + statistical_reviewer: + description: Reviews statistical validity, uncertainty, and analysis assumptions. + can_approve_scopes: + - clarification_only + - evidence_interpretation_only + - draft_recommendation + - single_validation_plan + data_steward: + description: Reviews data provenance, privacy, consent, and data quality. + can_approve_scopes: + - clarification_only + - evidence_interpretation_only + instrument_owner: + description: Reviews instrument settings, calibration, and run compatibility. + can_approve_scopes: + - clarification_only + - protocol_draft + - single_validation_run_draft + lab_operations_lead: + description: Reviews queue changes, resource allocation, and operational feasibility. + can_approve_scopes: + - clarification_only + - single_run_queue_priority + - bounded_batch_priority + - execution_payload_preparation + - robot_queue_submission + principal_investigator: + description: Reviews consequential prioritization and strategic research direction. + can_approve_scopes: + - clarification_only + - draft_recommendation + - single_run_queue_priority + - bounded_batch_priority + - publication_claim + system_owner: + description: Reviews tool permissions, workflow mutation, and deployment escalation. + can_approve_scopes: + - clarification_only + - tool_permission_escalation + - execution_payload_preparation + - robot_queue_submission + safety_officer: + description: Reviews general lab safety and physical risk. + can_approve_scopes: + - clarification_only + biosecurity_reviewer: + description: | + Reviews dual-use, pathogen, and synthetic biology risk for consequential actions. + Institutions configure overlay policies for mandatory biosecurity participation. + can_approve_scopes: + - clarification_only + - hypothesis_discussion + - evidence_interpretation_only + - protocol_draft + - protocol_diff_review + - tool_permission_escalation + - single_validation_plan + - draft_recommendation + clinical_reviewer: + description: | + Reviews patient-facing claims, diagnostic assertions, and clinical translation risk. + Required by institutional policy for clinically tagged domains and overlays. + can_approve_scopes: + - clarification_only + - evidence_interpretation_only + - draft_recommendation + - publication_claim + - protocol_draft + - single_validation_plan + - hypothesis_discussion + ethics_reviewer: + description: Reviews human-subject, dual-use, or institutional ethics concerns. + can_approve_scopes: + - clarification_only + publication_reviewer: + description: Reviews claim escalation into papers, reports, and public communication. + can_approve_scopes: + - clarification_only + - draft_recommendation + - publication_claim + - scientific_memory_import From f7ec5f2a84513bdda01a9ec185fba4fe28b86d63 Mon Sep 17 00:00:00 2001 From: fraware Date: Mon, 29 Jun 2026 02:54:42 -0700 Subject: [PATCH 67/80] examples(pilot): registry_signed_decision policy snapshot Pin examples/pilot/registry_signed_decision/policy/role_to_action_matrix.yaml for reproducible registry signing demo. --- .../policy/role_to_action_matrix.yaml | 39 +++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 examples/pilot/registry_signed_decision/policy/role_to_action_matrix.yaml diff --git a/examples/pilot/registry_signed_decision/policy/role_to_action_matrix.yaml b/examples/pilot/registry_signed_decision/policy/role_to_action_matrix.yaml new file mode 100644 index 0000000..f69632b --- /dev/null +++ b/examples/pilot/registry_signed_decision/policy/role_to_action_matrix.yaml @@ -0,0 +1,39 @@ +version: scope-core-v0.8 +matrix: + A3_evidence_interpretation_consequential: + required_roles: + - domain_scientist + - statistical_reviewer + require_any: true + A4_recommendation: + required_roles: + - domain_scientist + A5_protocol_modification: + required_roles: + - protocol_owner + A6_experimental_planning: + required_roles: + - domain_scientist + - protocol_owner + require_all: true + A7_resource_or_queue_prioritization: + required_roles: + - principal_investigator + - lab_operations_lead + require_any: true + A8_tool_or_workflow_mutation: + required_roles: + - system_owner + - domain_scientist + require_all: true + A9_execution_adjacent_or_external_action: + required_roles: + - system_owner + - lab_operations_lead + - domain_scientist + require_all: true + A10_publication_or_claim_escalation: + required_roles: + - publication_reviewer + - domain_scientist + require_all: true From b4cc8676b0d04a0fd229902e80a8786cc39977a7 Mon Sep 17 00:00:00 2001 From: fraware Date: Mon, 29 Jun 2026 02:54:43 -0700 Subject: [PATCH 68/80] examples(pilot): registry_signed_decision policy snapshot Pin examples/pilot/registry_signed_decision/policy/scope_to_tool_matrix.yaml for reproducible registry signing demo. --- .../policy/scope_to_tool_matrix.yaml | 74 +++++++++++++++++++ 1 file changed, 74 insertions(+) create mode 100644 examples/pilot/registry_signed_decision/policy/scope_to_tool_matrix.yaml diff --git a/examples/pilot/registry_signed_decision/policy/scope_to_tool_matrix.yaml b/examples/pilot/registry_signed_decision/policy/scope_to_tool_matrix.yaml new file mode 100644 index 0000000..412cf79 --- /dev/null +++ b/examples/pilot/registry_signed_decision/policy/scope_to_tool_matrix.yaml @@ -0,0 +1,74 @@ +version: scope-core-v0.8 +scopes: + no_action: + allowed_tools: [] + blocked_tools: ["*"] + clarification_only: + allowed_tools: ["comment.add"] + blocked_tools: ["robot_queue.submit", "protocol_editor.update_active_protocol"] + hypothesis_discussion: + allowed_tools: ["comment.add", "hypothesis.discuss"] + blocked_tools: ["robot_queue.submit", "protocol_editor.update_active_protocol"] + evidence_interpretation_only: + allowed_tools: ["evidence.interpret"] + blocked_tools: ["robot_queue.submit", "protocol_editor.update_active_protocol"] + draft_recommendation: + allowed_tools: ["recommendation.draft"] + blocked_tools: ["robot_queue.submit", "protocol_editor.update_active_protocol"] + protocol_draft: + allowed_tools: ["protocol_editor.draft_change"] + blocked_tools: + - protocol_editor.update_active_protocol + - lab_scheduler.prioritize + - robot_queue.submit + protocol_diff_review: + allowed_tools: ["protocol_editor.view_diff"] + blocked_tools: + - protocol_editor.update_active_protocol + - robot_queue.submit + single_validation_plan: + allowed_tools: + - experiment_planner.create_validation_plan + - protocol_editor.draft_change + blocked_tools: + - protocol_editor.update_active_protocol + - robot_queue.submit + single_validation_run_draft: + allowed_tools: + - experiment_planner.create_validation_plan + - protocol_editor.draft_change + blocked_tools: + - protocol_editor.update_active_protocol + - lab_scheduler.prioritize + - robot_queue.submit + active_protocol_update: + allowed_tools: + - protocol_editor.update_active_protocol + - protocol_editor.draft_change + blocked_tools: + - robot_queue.submit + single_run_queue_priority: + allowed_tools: ["lab_scheduler.prioritize"] + blocked_tools: ["robot_queue.submit"] + bounded_batch_priority: + allowed_tools: ["lab_scheduler.prioritize_batch"] + blocked_tools: ["robot_queue.submit"] + tool_permission_escalation: + allowed_tools: ["workflow.mutate_permissions"] + blocked_tools: ["robot_queue.submit"] + execution_payload_preparation: + allowed_tools: ["execution.prepare_payload"] + blocked_tools: ["robot_queue.submit"] + robot_queue_submission: + allowed_tools: ["robot_queue.submit"] + requires_roles: + - system_owner + - lab_operations_lead + - domain_scientist + blocked_tools: [] + publication_claim: + allowed_tools: ["publication.draft_claim"] + blocked_tools: ["scientific_memory.import"] + scientific_memory_import: + allowed_tools: ["scientific_memory.import"] + blocked_tools: [] From 0a9de71ea610821f75ad05874302d364e56ad8bc Mon Sep 17 00:00:00 2001 From: fraware Date: Mon, 29 Jun 2026 02:54:43 -0700 Subject: [PATCH 69/80] examples(pilot): registry_signed_decision policy snapshot Pin examples/pilot/registry_signed_decision/policy/workflow_escalation.yaml for reproducible registry signing demo. --- .../policy/workflow_escalation.yaml | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 examples/pilot/registry_signed_decision/policy/workflow_escalation.yaml diff --git a/examples/pilot/registry_signed_decision/policy/workflow_escalation.yaml b/examples/pilot/registry_signed_decision/policy/workflow_escalation.yaml new file mode 100644 index 0000000..24eb0fe --- /dev/null +++ b/examples/pilot/registry_signed_decision/policy/workflow_escalation.yaml @@ -0,0 +1,6 @@ +version: scope-core-v0.8 +escalation_reviewer: + reviewer_id: pi1 + role: principal_investigator +auto_escalate_status: true +emit_ledger_events: true From 9b73b51a12419b315b4da14889ce49abaf67a354 Mon Sep 17 00:00:00 2001 From: fraware Date: Mon, 29 Jun 2026 02:54:43 -0700 Subject: [PATCH 70/80] examples(pilot): registry_signed_decision policy snapshot Pin examples/pilot/registry_signed_decision/policy/domain_overlays/clinical_research.yaml for reproducible registry signing demo. --- .../domain_overlays/clinical_research.yaml | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 examples/pilot/registry_signed_decision/policy/domain_overlays/clinical_research.yaml diff --git a/examples/pilot/registry_signed_decision/policy/domain_overlays/clinical_research.yaml b/examples/pilot/registry_signed_decision/policy/domain_overlays/clinical_research.yaml new file mode 100644 index 0000000..9915312 --- /dev/null +++ b/examples/pilot/registry_signed_decision/policy/domain_overlays/clinical_research.yaml @@ -0,0 +1,21 @@ +version: scope-overlay-v0.6 +overlay_id: clinical_research +description: Clinical research overlay requiring clinical and biosecurity co-review. +mandatory_session_roles: + - clinical_reviewer + - biosecurity_reviewer +matrix_overrides: + A10_publication_or_claim_escalation: + required_roles: + - domain_scientist + - clinical_reviewer + - biosecurity_reviewer + require_all: true + A6_validation_or_interpretation: + required_roles: + - domain_scientist + - clinical_reviewer + require_all: true +notes: | + Enable via scientific_context.domain_overlay for patient-facing or clinical translation work. + Multi-role actions require review sessions; single-reviewer decisions are rejected. From be83687420aff324a4bf56431fcafebf042f5cd0 Mon Sep 17 00:00:00 2001 From: fraware Date: Mon, 29 Jun 2026 02:54:43 -0700 Subject: [PATCH 71/80] examples(pilot): registry_signed_decision policy snapshot Pin examples/pilot/registry_signed_decision/policy/domain_overlays/genomics_research.yaml for reproducible registry signing demo. --- .../policy/domain_overlays/genomics_research.yaml | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 examples/pilot/registry_signed_decision/policy/domain_overlays/genomics_research.yaml diff --git a/examples/pilot/registry_signed_decision/policy/domain_overlays/genomics_research.yaml b/examples/pilot/registry_signed_decision/policy/domain_overlays/genomics_research.yaml new file mode 100644 index 0000000..1f7e035 --- /dev/null +++ b/examples/pilot/registry_signed_decision/policy/domain_overlays/genomics_research.yaml @@ -0,0 +1,15 @@ +version: scope-overlay-v0.6 +overlay_id: genomics_research +description: Genomics research overlay requiring biosecurity co-review on tool mutations. +mandatory_session_roles: + - biosecurity_reviewer +matrix_overrides: + A8_tool_or_workflow_mutation: + required_roles: + - system_owner + - domain_scientist + - biosecurity_reviewer + require_all: true +notes: | + Institutional genomics labs may enable this overlay via scientific_context.domain_overlay. + Biosecurity reviewer participation is mandatory for workflow permission changes. From 6585bbc003b38a4052a291b368d48df607716dc8 Mon Sep 17 00:00:00 2001 From: fraware Date: Mon, 29 Jun 2026 02:54:44 -0700 Subject: [PATCH 72/80] test(pilot): validate examples/pilot fixture pack Schema and narrative checks for institutional pilot scenarios. --- tests/test_pilot_fixtures.py | 118 +++++++++++++++++++++++++++++++++++ 1 file changed, 118 insertions(+) create mode 100644 tests/test_pilot_fixtures.py diff --git a/tests/test_pilot_fixtures.py b/tests/test_pilot_fixtures.py new file mode 100644 index 0000000..8e4986a --- /dev/null +++ b/tests/test_pilot_fixtures.py @@ -0,0 +1,118 @@ +"""Validate examples/pilot fixture pack completeness (SCOPE-4).""" + +from __future__ import annotations + +import json +from pathlib import Path + +import pytest + +from scope.schema_util import validate_artifact + +ROOT = Path(__file__).resolve().parent.parent +PILOT = ROOT / "examples" / "pilot" + +SCENARIOS = { + "single_reviewer_protocol_draft": { + "required_files": [ + "scope_review_packet.json", + "scope_decision.json", + "scope_grant.json", + "summary.json", + "packet_rendered.md", + "quality_report_snippet.json", + "README.md", + ], + "summary_status": "completed", + }, + "multi_role_genomics_review": { + "required_files": [ + "scope_review_packet.json", + "summary.json", + "reviewer_protocol_owner.json", + "reviewer_domain_scientist.json", + "decision_protocol_owner.json", + "decision_domain_scientist.json", + "packet_rendered.md", + "quality_report_snippet.json", + "README.md", + ], + "summary_status": "session_required", + "forbidden_files": ["scope_grant.json"], + }, + "expired_queue_reopen": { + "required_files": [ + "scope_review_packet.json", + "review_queue_expired.json", + "review_queue_reopened.json", + "scope_events.jsonl", + "packet_rendered.md", + "quality_report_snippet.json", + "README.md", + ], + }, + "needs_information_flow": { + "required_files": [ + "scope_review_packet.json", + "review_queue_needs_information.json", + "review_queue_in_review.json", + "reviewer_protocol_owner.json", + "packet_rendered.md", + "quality_report_snippet.json", + "README.md", + ], + }, + "registry_signed_decision": { + "required_files": [ + "scope_review_packet.json", + "scope_decision.json", + "scope_grant.json", + "summary.json", + "reviewer_protocol_owner.json", + "packet_rendered.md", + "quality_report_snippet.json", + "README.md", + ], + "summary_status": "completed", + }, +} + + +@pytest.mark.parametrize("scenario", list(SCENARIOS)) +def test_pilot_fixture_files_present(scenario: str) -> None: + spec = SCENARIOS[scenario] + base = PILOT / scenario + for name in spec["required_files"]: + assert (base / name).is_file(), f"{scenario}: missing {name}" + for name in spec.get("forbidden_files", []): + assert not (base / name).exists(), f"{scenario}: unexpected {name}" + + +@pytest.mark.parametrize("scenario", list(SCENARIOS)) +def test_pilot_quality_snippet_policy_version(scenario: str) -> None: + snippet_path = PILOT / scenario / "quality_report_snippet.json" + snippet = json.loads(snippet_path.read_text(encoding="utf-8")) + assert snippet.get("policy_version") == "scope-core-v0.8" + + +@pytest.mark.parametrize( + "scenario", + [name for name, spec in SCENARIOS.items() if "summary_status" in spec], +) +def test_pilot_summary_contract(scenario: str) -> None: + spec = SCENARIOS[scenario] + summary = json.loads((PILOT / scenario / "summary.json").read_text(encoding="utf-8")) + assert summary["status"] == spec["summary_status"] + assert summary["adapter_contract_version"] == "scope-akta-review-v0.8" + schema = ( + "scope_akta_review_session_summary.schema.json" + if spec["summary_status"] == "session_required" + else "scope_akta_review_summary.schema.json" + ) + validate_artifact(summary, schema) + + +def test_pilot_index_readme() -> None: + readme = (PILOT / "README.md").read_text(encoding="utf-8") + for scenario in SCENARIOS: + assert scenario in readme From 780db44c4dddd8a4383403c5cdda3bae376b88bd Mon Sep 17 00:00:00 2001 From: fraware Date: Mon, 29 Jun 2026 02:54:44 -0700 Subject: [PATCH 73/80] test: expect scope-core-v0.8 in test_akta_golden.py Update assertions after policy bundle version bump. --- tests/test_akta_golden.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_akta_golden.py b/tests/test_akta_golden.py index 21552e4..88b90e4 100644 --- a/tests/test_akta_golden.py +++ b/tests/test_akta_golden.py @@ -35,4 +35,4 @@ def test_nested_akta_record_golden_mapping(): assert constraints["allowed_next_steps"] == golden["allowed_next_steps"] assert req["requested_scope"] == golden["inferred_requested_scope"] assert req["scope_inference_source"] == golden["scope_inference_source"] - assert packet["packet_version"] == "0.7.0" + assert packet["packet_version"] == "0.8.0" From 39a21856140747f21ebba7fdd81430f079351de3 Mon Sep 17 00:00:00 2001 From: fraware Date: Mon, 29 Jun 2026 02:54:44 -0700 Subject: [PATCH 74/80] test: expect scope-core-v0.8 in test_akta_review_command.py Update assertions after policy bundle version bump. --- tests/test_akta_review_command.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_akta_review_command.py b/tests/test_akta_review_command.py index 617bb79..b41e2d0 100644 --- a/tests/test_akta_review_command.py +++ b/tests/test_akta_review_command.py @@ -54,7 +54,7 @@ def test_akta_review_command_happy_path(tmp_path): assert summary["decision_path"].endswith("scope_decision.json") assert summary["grant_path"].endswith("scope_grant.json") assert summary["approved_scope"] == "protocol_draft" - assert summary["adapter_contract_version"] == "scope-akta-review-v0.7" + assert summary["adapter_contract_version"] == "scope-akta-review-v0.8" assert summary["identity_assurance_level"] == "IAL0" assert "signing_assurance_level" in summary assert isinstance(summary["blocked_tools"], list) From 84ce1cb2f54908a0b5ca4e3c876239c12ff4dbfb Mon Sep 17 00:00:00 2001 From: fraware Date: Mon, 29 Jun 2026 02:54:45 -0700 Subject: [PATCH 75/80] test: expect scope-core-v0.8 in test_akta_scope_chain.py Update assertions after policy bundle version bump. --- tests/test_akta_scope_chain.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_akta_scope_chain.py b/tests/test_akta_scope_chain.py index caf5b5b..737efe6 100644 --- a/tests/test_akta_scope_chain.py +++ b/tests/test_akta_scope_chain.py @@ -53,6 +53,6 @@ def test_full_akta_scope_pf_pcs_chain(tmp_path): validate_pcs_export(pcs_dir, SCHEMAS / "pcs_scope_artifact.schema.json") report = engine.quality_report() - assert report["report_version"] == "0.7" + assert report["report_version"] == "0.8" assert report["summary"]["total_grants"] >= 1 assert "by_reviewer" in report From ccc1ea6a33c33d418cfc48be9b7e8068f399f968 Mon Sep 17 00:00:00 2001 From: fraware Date: Mon, 29 Jun 2026 02:54:45 -0700 Subject: [PATCH 76/80] test: expect scope-core-v0.8 in test_institutional_pilot.py Update assertions after policy bundle version bump. --- tests/test_institutional_pilot.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_institutional_pilot.py b/tests/test_institutional_pilot.py index e2e3271..7241258 100644 --- a/tests/test_institutional_pilot.py +++ b/tests/test_institutional_pilot.py @@ -15,7 +15,7 @@ def test_institutional_pilot_packet_regenerates(): trigger = json.loads((PILOT / "review_trigger.json").read_text(encoding="utf-8")) packet = engine.create_packet(record, trigger) assert packet["review_request"]["scientific_action_type"] == "A5_protocol_modification" - assert packet["packet_version"] == "0.7.0" + assert packet["packet_version"] == "0.8.0" fixture = json.loads((PILOT / "scope_packet.json").read_text(encoding="utf-8")) for key in ( "packet_version", From d10693a69507298239fb035fcc26a7081d0e8c0b Mon Sep 17 00:00:00 2001 From: fraware Date: Mon, 29 Jun 2026 02:54:46 -0700 Subject: [PATCH 77/80] test: expect scope-core-v0.8 in test_key_registry.py Update assertions after policy bundle version bump. --- tests/test_key_registry.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_key_registry.py b/tests/test_key_registry.py index 4587481..d93d37c 100644 --- a/tests/test_key_registry.py +++ b/tests/test_key_registry.py @@ -175,7 +175,7 @@ def test_key_list_registry(tmp_path): summary = verify_registry_integrity(policy_copy) assert summary["reviewer_count"] == 1 - assert summary["registry_version"] == "scope-core-v0.7" + assert summary["registry_version"] == "scope-core-v0.8" def test_pcs_export_includes_registry_metadata(tmp_path): From ecbf03899b517d9c7e5d290a0fc56f691217c1e6 Mon Sep 17 00:00:00 2001 From: fraware Date: Mon, 29 Jun 2026 02:54:46 -0700 Subject: [PATCH 78/80] test: expect scope-core-v0.8 in test_quality_metrics_complete.py Update assertions after policy bundle version bump. --- tests/test_quality_metrics_complete.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_quality_metrics_complete.py b/tests/test_quality_metrics_complete.py index 0d23680..85fc8af 100644 --- a/tests/test_quality_metrics_complete.py +++ b/tests/test_quality_metrics_complete.py @@ -42,7 +42,7 @@ def test_all_deferred_metrics_present(): ] for key in expected: assert key in metrics, f"Missing metric: {key}" - assert report["report_version"] == "0.7" + assert report["report_version"] == "0.8" def test_low_evidence_warning_and_rate(tmp_path): From cd09f487e537ae1018755ba762b1d737a1071b07 Mon Sep 17 00:00:00 2001 From: fraware Date: Mon, 29 Jun 2026 02:54:46 -0700 Subject: [PATCH 79/80] test: expect scope-core-v0.8 in test_rbac_scope_authority.py Update assertions after policy bundle version bump. --- tests/test_rbac_scope_authority.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_rbac_scope_authority.py b/tests/test_rbac_scope_authority.py index 6e1b5bf..325b3b7 100644 --- a/tests/test_rbac_scope_authority.py +++ b/tests/test_rbac_scope_authority.py @@ -113,7 +113,7 @@ def test_expired_delegation_invalidates_authority(tmp_path: Path) -> None: policy_dir = tmp_path / "policy" shutil.copytree(ROOT / "policy", policy_dir) org_rbac = { - "version": "scope-core-v0.7", + "version": "scope-core-v0.8", "org_units": {}, "delegations": [ { From 746dd2312ae2e2964ef6637acbb193d88b3c8231 Mon Sep 17 00:00:00 2001 From: fraware Date: Mon, 29 Jun 2026 02:54:47 -0700 Subject: [PATCH 80/80] test: expect scope-core-v0.8 in test_signing_identity.py Update assertions after policy bundle version bump. --- tests/test_signing_identity.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_signing_identity.py b/tests/test_signing_identity.py index 042486e..8acd6ad 100644 --- a/tests/test_signing_identity.py +++ b/tests/test_signing_identity.py @@ -90,7 +90,7 @@ def test_sign_enforces_reviewer_key_registry(tmp_path): registry_path.write_text( yaml.dump( { - "version": "scope-core-v0.7", + "version": "scope-core-v0.8", "reviewers": {"rev1": expected_ref}, } ),