From ffd6809618e37cb324b63f5137a41635956f5c1d Mon Sep 17 00:00:00 2001 From: OpenCode Date: Thu, 9 Jul 2026 16:39:41 +0700 Subject: [PATCH 1/2] feat: Phase J J3 release request template -- reviewable releases (#800) --- Makefile | 7 +- docs/evidence/METRICS_CURRENT.md | 7 +- docs/governance/RELEASE_REQUEST_TEMPLATE.md | 128 +++++++++ docs/research/ROADMAP.md | 150 +++++++++++ src/openamp_foundry/cli/commands/reports.py | 48 ++++ src/openamp_foundry/cli/main.py | 23 ++ .../governance/release_request.py | 159 +++++++++++ tests/governance/test_release_request.py | 252 ++++++++++++++++++ tests/test_test_count_regression.py | 4 +- 9 files changed, 772 insertions(+), 6 deletions(-) create mode 100644 docs/governance/RELEASE_REQUEST_TEMPLATE.md create mode 100644 src/openamp_foundry/governance/release_request.py create mode 100644 tests/governance/test_release_request.py diff --git a/Makefile b/Makefile index a451bb3f..0a880446 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -.PHONY: help demo test lint ci clean bench-leakage bench-multi-negatives bench-baseline bench-hidden-active bench-cluster-split bench-expert-ablation bench-expert-ablation-500 bench-selectivity bench-feature-decomp bench-gate bench-easy-baseline bench-charge-matched bench-order-dependent bench-precision-at-k bench-per-family bench-simulation-ablation bench-simulation-ablation-within-amp simulation-gate bench-strategy-compare regenerate-all generate phase3 pilot validate-scoring validate-scoring-phase3 validate-scoring-strict external-pilot pilot-confident presynth-qc gold-standard diversity synthesis-order novelty-broad external-consensus questionnaire gate-check ip-report benchmark-card wave0-5-gate-check wave0-5-novelty-audit wave0-5-novelty-audit-v2 wave0-5-panel wave0-5-evidence wave0-5-fill-external wave0-5b-generate wave0-5b-filter recalibration-engine recalibration-engine-dry-run validate-policy-version generate-synthetic-lab-results bump-policy-version generate-review-packet failed-candidate-report safe-publication-filter classify-negative-informativeness validate-rejection-events negative-result-dashboard calibration-audit calibration-audit-example calibration-overfit-check result-quality-filter synthetic-result-policy-check calibration-decision-checklist calibration-rollback-plan simulation-registry validate-simulation-result-schema simulation-baseline-check adapter-gate-check simulation-provenance simulation-ensemble-check simulation-ci-report simulation-deprecation-check simulation-scope-check simulation-evidence-packet artifact-version candidate-manifest artifact-changelog integration-check adapter-author-check license-check artifact-compat-check contribution-check adoption-scorecard release-gate-check decision-log +.PHONY: help demo test lint ci clean bench-leakage bench-multi-negatives bench-baseline bench-hidden-active bench-cluster-split bench-expert-ablation bench-expert-ablation-500 bench-selectivity bench-feature-decomp bench-gate bench-easy-baseline bench-charge-matched bench-order-dependent bench-precision-at-k bench-per-family bench-simulation-ablation bench-simulation-ablation-within-amp simulation-gate bench-strategy-compare regenerate-all generate phase3 pilot validate-scoring validate-scoring-phase3 validate-scoring-strict external-pilot pilot-confident presynth-qc gold-standard diversity synthesis-order novelty-broad external-consensus questionnaire gate-check ip-report benchmark-card wave0-5-gate-check wave0-5-novelty-audit wave0-5-novelty-audit-v2 wave0-5-panel wave0-5-evidence wave0-5-fill-external wave0-5b-generate wave0-5b-filter recalibration-engine recalibration-engine-dry-run validate-policy-version generate-synthetic-lab-results bump-policy-version generate-review-packet failed-candidate-report safe-publication-filter classify-negative-informativeness validate-rejection-events negative-result-dashboard calibration-audit calibration-audit-example calibration-overfit-check result-quality-filter synthetic-result-policy-check calibration-decision-checklist calibration-rollback-plan simulation-registry validate-simulation-result-schema simulation-baseline-check adapter-gate-check simulation-provenance simulation-ensemble-check simulation-ci-report simulation-deprecation-check simulation-scope-check simulation-evidence-packet artifact-version candidate-manifest artifact-changelog integration-check adapter-author-check license-check artifact-compat-check contribution-check adoption-scorecard release-gate-check decision-log release-request-check release-request-check PYTHON := $(shell [ -f .venv/bin/python ] && echo .venv/bin/python || echo python3) PYTEST := $(shell [ -f .venv/bin/pytest ] && echo .venv/bin/pytest || echo pytest) @@ -845,3 +845,8 @@ release-gate-check: decision-log: .venv/bin/openamp-foundry decision-log --validate @echo "Decision log check complete." + +release-request-check: + .venv/bin/openamp-foundry release-request-check \ + --request-json '{"release_id":"REL-2026-001","release_type":"schema","artifact_id":"candidate_manifest","artifact_version":"1.0.0","requestor_name":"OpenAMP Team","requestor_institution":"Open Problem Lab","request_date":"2026-07-09","evidence_level":2,"dry_lab_only":true,"safety_review_status":"approved","benchmark_summary":"Passes all schema compatibility checks","known_limitations":"Dry-lab only, not wet-lab validated","intended_use":"public","data_license":"CC-BY-4.0","human_reviewer":"maintainer","review_class":"B","approval_status":"pending"}' + @echo "Release request check complete." diff --git a/docs/evidence/METRICS_CURRENT.md b/docs/evidence/METRICS_CURRENT.md index ac876d48..06cdfd80 100644 --- a/docs/evidence/METRICS_CURRENT.md +++ b/docs/evidence/METRICS_CURRENT.md @@ -5,7 +5,8 @@ Machine-readable snapshot: `outputs/metrics_snapshot.json` regenerated with `mak > **Purpose:** One authoritative table of current pipeline metrics. If any doc disagrees > with this file, this file wins. Updated whenever benchmark/benchmark config changes. > -> **Last updated:** 2026-07-09 (Phase J J2 — governance decision log — v0.7.0) +> **Last updated:** 2026-07-09 (Phase J J3 — release request template — v0.7.1) +> **New in v0.7.1:** Release request template (J3 — Loop 111) — `docs/governance/RELEASE_REQUEST_TEMPLATE.md` with structured release request template (purpose, fill-in-the-blank template with 17 fields: Release ID, release type, artifact ID/version, requestor name/institution, request date, evidence level 1-6, dry_lab_only, safety_review_status, benchmark_summary, known_limitations, intended_use, data_license, human_reviewer, review_class, approval_status; review criteria with 8 checks; process with classes A-D timelines and escalation path). `src/openamp_foundry/governance/release_request.py` with `ReleaseRequest` dataclass (17 fields), `ReleaseRequestValidationResult` dataclass (6 fields, dry_lab_only=True), `VALID_RELEASE_TYPES` (5), `VALID_SAFETY_STATUSES` (3), `VALID_INTENDED_USES` (4), `VALID_APPROVAL_STATUSES` (4), `VALID_REVIEW_CLASSES` (4), `validate_release_request()` (17 checks including dry_lab_only+evidence_level>4 error, public+safety_pending error, model+review_class warning), `validate_request_dict()` (dict input with missing-fields guard). CLI (`openamp-foundry release-request-check`) with `--request-json`, `--format text|json`. `make release-request-check` target. 25 tests. **3516 total.** Formal release requests now have a validated structure before entering human review. > **New in v0.7.0:** Governance decision log index (J2 — Loop 110, Phase J milestone) — `docs/governance/DECISION_LOG.md` with structured decision log (purpose, decision index with 8 entries GOV-001 through GOV-008 covering safety/benchmark/release/evidence/data/adapter/contribution/docs scopes, how to add entries, linked policies). `src/openamp_foundry/governance/decision_log.py` with `VALID_SCOPES` (8 entries: safety, benchmark, release, evidence, data, adapter, contribution, docs), `VALID_STATUSES` (4 entries: active, superseded, under_review, proposed), `VALID_REVIEW_CLASSES` (4 entries: A, B, C, D), `GovernanceDecision` dataclass (8 fields: decision_id, date, scope, decision, status, rationale, review_class, dry_lab_only=True), `DecisionValidationResult` dataclass (5 fields: decision_id, passed, errors, warnings, dry_lab_only=True), `GOVERNANCE_DECISIONS` list (8 entries: GOV-001 through GOV-008), `validate_governance_decision()` (9 checks: decision_id format, date format, valid scope, non-empty decision, valid status, non-empty rationale, valid review_class, dry_lab_only must be True, superseded warning), `validate_all_decisions()` (aggregates total/passed/failed/all_passed/results/dry_lab_only), `get_decisions_by_scope()` (filters by scope), `get_decisions_by_status()` (filters by status). CLI (`openamp-foundry decision-log`) with `--validate`, `--scope`, `--format text|json`. `make decision-log` target. 27 tests. **3505 total.** **Phase J milestone: v0.7.0** — governance decisions are now discoverable and machine-validated. > **New in v0.6.9:** Release checklist and gate validator (J1 — Loop 109, starts Phase J) — `docs/governance/RELEASE_CHECKLIST.md` with structured checklist (pre-release gates, release-type gates for 5 types, post-release checklist), cross-referencing `docs/trust/RELEASE_CHECKLIST.md`. `src/openamp_foundry/governance/release_gate.py` with `RELEASE_TYPES` (5: candidate, model, dataset, evidence_packet, schema), `UNIVERSAL_GATES` (7: ci_tests_pass, agent_check_passes, no_critical_issues, dry_lab_only_confirmed, safety_flags_reviewed, data_license_verified, no_hardcoded_secrets), `EXTRA_GATES_BY_TYPE` (per-type additional gates), `ReleaseGateResult` dataclass (8 fields, dry_lab_only=True), `validate_release_gate()` (validates all required gates, treats missing gates as failed, raises CRITICAL error on dry_lab_only_confirmed failure). CLI (`openamp-foundry release-gate-check`) with `--release-type`, `--artifact-id`, `--gates-json`, `--format text|json`. `make release-gate-check` target. 18 tests. **3478 total.** **Starts Phase J (Governance and release maturity)** — releases now require all gates to pass before external release, preventing accidental bypass of required checks. > **New in v0.6.8:** Adoption scorecard dashboard (I10 — Loop 108) — `src/openamp_foundry/adoption/scorecard.py` with `SCORECARD_DIMENSIONS` (5 weighted dimensions summing to 1.0: integration_check 0.25, license_compliance 0.20, adapter_validation 0.20, schema_compatibility 0.20, contribution_readiness 0.15), `ADOPTION_TIERS` (4 tiers: not_ready 0.0-0.40, emerging 0.40-0.65, established 0.65-0.85, mature 0.85-1.01), `DimensionScore` dataclass (8 fields, dry_lab_only=True), `AdoptionScorecard` dataclass (6 fields, dry_lab_only=True), `build_scorecard()` (aggregates dimension inputs into weighted total score with tier and actionable recommendations), `compute_adoption_tier()` (maps score to tier). CLI (`openamp-foundry adoption-scorecard`) with `--scores-json`, `--format text|json`. `make adoption-scorecard` target. 17 tests. **3446 total.** **Phase I (Interoperability and Adoption) is now complete** — all 10 items I1–I10 implemented (artifact versioning, candidate manifest, benchmark card, artifact changelog, integration checker, adapter validator, data license checker, schema compatibility, contribution intake, adoption scorecard). @@ -98,7 +99,7 @@ Machine-readable snapshot: `outputs/metrics_snapshot.json` regenerated with `mak > **New in v0.5.31:** Added dipeptide-order features for sequence-order awareness. `dipeptide_order_score` achieves AUROC 0.7861 on AMP-vs-scrambled discrimination — the strongest order-dependent feature in the pipeline. Only 7/31 features survive scrambling (amphipathicity/helix-wheel + dipeptide). All composition features are purely position-independent (exactly 0.5000 AUROC on scrambled test). > **New in v0.5.30:** Easy baseline benchmark added — charge density alone (AUROC 0.8166) outperforms the full pipeline ensemble (0.7792) on AMP-vs-Swiss-Prot-decoy discrimination. Honest finding documented: expected because pipeline optimizes for safety, not raw discrimination. > **New in v0.5.29:** Expanded benchmark to 500 AMPs + 500 composition-matched decoys (n=1000). AUROC 0.7792 (CI₉₅: 0.7505–0.8065) confirms signal generalizes. Cluster-aware CI: 0.746–0.8102. Representative AUROC: 0.778. Standard benchmark (n=191) retained for backward comparison. -> **Pipeline version:** v0.7.0 (J2 — governance decision log) +> **Pipeline version:** v0.7.1 (J3 — release request template) > **Branch:** main --- @@ -1168,7 +1169,7 @@ Decoys score low on activity. Selective AMPs score moderately on both. | Metric | Value | |--------|-------| -| Total tests | 3478 | +| Total tests | 3516 | | Coverage (branch) | 99% (6 CLI guard lines only) | | Source modules at 100% | All pipeline, QC, scoring, adapter modules | diff --git a/docs/governance/RELEASE_REQUEST_TEMPLATE.md b/docs/governance/RELEASE_REQUEST_TEMPLATE.md new file mode 100644 index 00000000..4c56412f --- /dev/null +++ b/docs/governance/RELEASE_REQUEST_TEMPLATE.md @@ -0,0 +1,128 @@ +# Release Request Template + +> **Purpose:** A release request is the formal mechanism for requesting that a +> model, candidate, dataset, evidence packet, or schema be released for external +> use. File one when you have an artifact ready for review and want to initiate +> the release process. All release requests are reviewed by a human reviewer +> before the release is approved. +> +> **When to file:** After the artifact passes the release gate checks +> (`make release-gate-check`) and all required gates are green. +> +> **Who reviews it:** The assigned human reviewer (GitHub handle) — a +> maintainer or domain expert who verifies the request meets all criteria. + +--- + +## Release Request + +### Metadata + +- **Release ID:** `REL-YYYY-NNN` (auto-assigned) +- **Release type:** (candidate | model | dataset | evidence_packet | schema) +- **Artifact ID:** \_\_\_\_\_\_\_\_\_\_ +- **Artifact version:** \_\_\_\_\_\_\_\_\_\_ + +### Requestor + +- **Name:** \_\_\_\_\_\_\_\_\_\_ +- **Institution:** \_\_\_\_\_\_\_\_\_\_ +- **Date of request:** \_\_\_\_\_\_\_\_\_\_ (YYYY-MM-DD) + +### Evidence and safety + +- **Evidence level:** \_\_\_\_\_ (1–6, see PROOF_LADDER.md) +- **Dry-lab only:** \_\_\_\_\_ (must be True) +- **Safety review status:** \_\_\_\_\_ (pending | approved | not_required) + +### Benchmark comparison + +- **Baseline beaten:** \_\_\_\_\_\_\_\_\_\_ +- **Summary of comparison:** \_\_\_\_\_\_\_\_\_\_ + +### Limitations + +- **Known limitations:** \_\_\_\_\_\_\_\_\_\_ (must not be empty) + +### Use and license + +- **Intended use:** \_\_\_\_\_ (research | internal | external_partner | public) +- **Data license:** \_\_\_\_\_\_\_\_\_\_ (must specify) + +### Review assignment + +- **Human reviewer:** \_\_\_\_\_\_\_\_\_\_ (GitHub handle) +- **Review class:** \_\_\_\_\_ (A | B | C | D) + +### Approval + +- **Approval status:** \_\_\_\_\_ (pending | approved | rejected | deferred) +- **Review notes:** \_\_\_\_\_\_\_\_\_\_ + +--- + +## Review Criteria + +The human reviewer checks the following before approving: + +1. **Formal completeness** — all required fields are present and valid. +2. **Evidence level honesty** — the claimed evidence level matches the actual + proof-ladder evidence. Dry-lab-only artifacts are capped at level 4. +3. **Safety review** — if intended use is "public", safety review must be + `approved` (not `pending`). +4. **Benchmark honesty** — the claimed baseline must actually be beaten. If no + baseline exists, the request should note this and the evidence ceiling is + adjusted accordingly. +5. **Limitations documented** — known limitations must be explicitly stated, + not empty or generic. If there are genuinely no known limitations, state + "None documented at this time." +6. **Data license valid** — the data license must be a standard open license + (e.g. CC-BY-4.0, MIT, Apache-2.0) or explicitly documented with + governance approval. +7. **Review class appropriate** — the review class must match the artifact + type and intended use: + - **Class A** — documentation, config, schema-only changes (fast-track) + - **Class B** — evidence packets, benchmark cards, candidate manifests + - **Class C** — datasets, models, candidate releases for limited use + - **Class D** — public releases, safety-significant artifacts +8. **Model releases require class C or D** — model releases must not use + class A or B. + +--- + +## Process + +1. **Submit** — Fill out the template and submit it as a GitHub issue or PR. +2. **Validation** — The release request is automatically validated by + `openamp-foundry release-request-check` to ensure all required fields + are present. +3. **Human review** — The assigned human reviewer checks the request against + the review criteria. +4. **Decision** — The reviewer sets approval status to `approved`, `rejected`, + or `deferred`. If deferred, review notes explain what must change before + re-submission. +5. **Release** — Once approved, the maintainer performs the actual release + (tag, publish, announce, etc.). + +### Expected timeline + +- **Class A:** 1–2 business days +- **Class B:** 3–5 business days +- **Class C:** 5–10 business days +- **Class D:** 10–15 business days (may require governance board review) + +### Escalation + +If the release request is not reviewed within the expected timeline, the +requestor may escalate by tagging `@openamp-foundry/maintainers` on the +submission thread with a note about the delay. + +--- + +## Safety constraints + +- `dry_lab_only` must always be `True` for dry-lab artifacts. Wet-lab + releases follow a separate process. +- Public releases require safety review to be `approved`, not `pending`. +- Evidence level 5 or 6 cannot be claimed for dry-lab-only artifacts. +- All releases require human review — no auto-approval. diff --git a/docs/research/ROADMAP.md b/docs/research/ROADMAP.md index 1334519d..ec96d3ae 100644 --- a/docs/research/ROADMAP.md +++ b/docs/research/ROADMAP.md @@ -1,5 +1,86 @@ # Roadmap +## v0.7.1 — Loop 111: Phase J J3 — Release Request Template ✓ (2026-07-09) + +`docs/governance/RELEASE_REQUEST_TEMPLATE.md` with structured release request +template (purpose, fill-in-the-blank format with 17 fields: Release ID, +release type, artifact ID/version, requestor name/institution, request date, +evidence level 1-6, dry_lab_only, safety_review_status, benchmark_summary, +known_limitations, intended_use, data_license, human_reviewer, review_class +A-D, approval_status; review criteria with 8 checks; process with classes A-D +timelines and escalation path). + +`src/openamp_foundry/governance/release_request.py` with `ReleaseRequest` +dataclass (17 fields), `ReleaseRequestValidationResult` dataclass (6 fields, +dry_lab_only=True), `VALID_RELEASE_TYPES` (5: candidate, model, dataset, +evidence_packet, schema), `VALID_SAFETY_STATUSES` (3: pending, approved, +not_required), `VALID_INTENDED_USES` (4: research, internal, external_partner, +public), `VALID_APPROVAL_STATUSES` (4: pending, approved, rejected, deferred), +`VALID_REVIEW_CLASSES` (4: A, B, C, D), `validate_release_request()` (17 checks: +release_id format, release_type valid, non-empty artifact_id/artifact_version/ +requestor_name/requestor_institution, request_date YYYY-MM-DD, evidence_level +1-6, dry_lab_only must be True, safety_review_status valid, non-empty +benchmark_summary/known_limitations/data_license/human_reviewer, intended_use +valid, review_class valid, approval_status valid, dry_lab_only+evidence_level>4 +error, public+safety_pending error, model+review_class warning). + +`validate_request_dict()` (dict input with 17 required fields guard, missing +fields returns passed=False early). + +CLI (`openamp-foundry release-request-check`) with `--request-json` (required), +`--format text|json`. Handler `_run_release_request_check` in reports.py. + +`make release-request-check` target. 25 tests. **3516 total.** + +Blocks public releases with pending safety review, blocks dry_lab_only +artifacts with evidence_level>4. Formal release requests now have a validated +structure before entering human review. + +Changes: +- `docs/governance/RELEASE_REQUEST_TEMPLATE.md` (J3) — Structured release + request template with purpose, template (17 fields), review criteria (8 + checks), process (5 steps with A-D timelines and escalation path). +- `src/openamp_foundry/governance/release_request.py` (J3) — Core module with + `ReleaseRequest` (17 fields), `ReleaseRequestValidationResult` (6 fields, + dry_lab_only=True), `VALID_RELEASE_TYPES` (5), `VALID_SAFETY_STATUSES` (3), + `VALID_INTENDED_USES` (4), `VALID_APPROVAL_STATUSES` (4), + `VALID_REVIEW_CLASSES` (4), `validate_release_request()` (17 checks), + `validate_request_dict()` (dict input with missing-fields guard). +- `tests/governance/test_release_request.py` (J3) — 25 tests covering: valid + candidate release request passes, release_id not starting with REL- fails, + invalid release_type fails, empty artifact_id fails, empty requestor_name + fails, invalid request_date format fails, evidence_level=0 fails, + evidence_level=7 fails, dry_lab_only=False fails, invalid safety_review_status + fails, empty benchmark_summary fails, empty known_limitations fails, invalid + intended_use fails, public release with pending safety fails, dry_lab_only + with evidence_level=5 fails, all results dry_lab_only=True, validate_request_ + dict passes, VALID_RELEASE_TYPES has 5, VALID_SAFETY_STATUSES has 3, + VALID_INTENDED_USES has 4, VALID_APPROVAL_STATUSES has 4, VALID_REVIEW_CLASSES + has 4, model review_class warning, dict missing fields fails. +- `src/openamp_foundry/cli/main.py` (J3) — Registered `release-request-check` + subcommand with `--request-json`, `--format` flags. Added import and dispatch. +- `src/openamp_foundry/cli/commands/reports.py` (J3) — Added + `_run_release_request_check()` CLI handler with JSON parsing, validate_request + _dict call, text and JSON output, exit code 3 on validation failure. +- `Makefile` (J3) — Added `release-request-check` target. Added to `.PHONY`. +- `docs/evidence/METRICS_CURRENT.md` (J3) — v0.7.1 J3 changelog. Pipeline + version: v0.7.1. Test count: 3516. +- `tests/test_test_count_regression.py` — baseline updated to 3516. + +Honest boundaries: +- Release request validation checks structural and policy requirements only. + It does not verify that the artifact actually exists, that the evidence level + claim is accurate, or that the safety review was thorough. +- `dry_lab_only: true` is a const field on all dataclasses — release requests + are governance artifacts, not biological findings. +- The validator blocks public releases with pending safety review, but it cannot + verify that the safety review was correctly performed or that the reviewer was + qualified. +- Review classes are policy declarations — the validator checks that the class + is valid (A-D) but not that the appropriate review process was followed. +- The release request template is a communication and governance tool — it does + not replace the judgment of the human reviewer. + ## v0.7.0 — Loop 110: Phase J J2 — Governance Decision Log ✓ (2026-07-09) `docs/governance/DECISION_LOG.md` with structured governance decision log @@ -76,6 +157,75 @@ Honest boundaries: - The decision log is a documentation and validation tool — it does not replace human judgment about whether a decision is appropriate. +## v0.7.1 — Loop 111: Phase J J3 — Release Request Template ✓ (2026-07-09) + +`docs/governance/RELEASE_REQUEST_TEMPLATE.md` with structured release +request template (purpose, fill-in template with 17 fields, review +criteria with 8 checks, process with classes A-D timelines and escalation). + +`src/openamp_foundry/governance/release_request.py` with `ReleaseRequest` +dataclass (17 fields), `ReleaseRequestValidationResult` dataclass (6 fields, +dry_lab_only=True), `VALID_RELEASE_TYPES` (5), `VALID_SAFETY_STATUSES` (3), +`VALID_INTENDED_USES` (4), `VALID_APPROVAL_STATUSES` (4), +`VALID_REVIEW_CLASSES` (4), `validate_release_request()` (17 checks with +dry_lab_only+evidence_level>4 error, public+safety_pending error, +model+review_class warning), `validate_request_dict()` (dict input with +missing-fields guard). + +CLI (`openamp-foundry release-request-check`) with `--request-json`, +`--format text|json`. Handler `_run_release_request_check` in reports.py. + +`make release-request-check` target. 25 tests. **3516 total.** + +Changes: +- `docs/governance/RELEASE_REQUEST_TEMPLATE.md` (J3) — Structured release + request template with purpose, fill-in template (17 fields), review + criteria (8 checks), process (submit→validate→review→decision→release), + expected timelines per class A-D, escalation path. +- `src/openamp_foundry/governance/release_request.py` (J3) — Core module + with `ReleaseRequest` (17 fields), `ReleaseRequestValidationResult` + (6 fields, dry_lab_only=True), `VALID_RELEASE_TYPES` (5), + `VALID_SAFETY_STATUSES` (3), `VALID_INTENDED_USES` (4), + `VALID_APPROVAL_STATUSES` (4), `VALID_REVIEW_CLASSES` (4), + `validate_release_request()` (17 checks including cross-field rules: + dry_lab_only+evidence_level>4 error, public+safety_pending error, + model+review_class C/D warning), `validate_request_dict()`. +- `tests/governance/test_release_request.py` (J3) — 25 tests covering: + valid candidate passes, release_id must start with REL-, invalid type, + empty artifact_id/requestor_name, invalid date format, evidence_level + 0/7, dry_lab_only=False, invalid safety_status, empty benchmark_summary/ + known_limitations, invalid intended_use, public+safety_pending fails, + dry_lab_only+evidence_level 5 fails, dry_lab_only=True on results, + valid dict passes, VALID_RELEASE_TYPES has 5 entries, VALID_SAFETY_STATUSES + has 3, VALID_INTENDED_USES has 4, VALID_APPROVAL_STATUSES has 4, + VALID_REVIEW_CLASSES has 4, model+low review_class warning, dict missing + fields, invalid type via dict. +- `src/openamp_foundry/cli/main.py` (J3) — Registered `release-request-check` + subcommand with `--request-json` (required), `--format` flags. Added import + and dispatch. +- `src/openamp_foundry/cli/commands/reports.py` (J3) — Added + `_run_release_request_check()` CLI handler with JSON parsing, + `validate_request_dict()` call, text and JSON output, exit code 3 + on failure. +- `Makefile` (J3) — Added `release-request-check` target with demo invocation + using schema release type with all fields valid. Added to `.PHONY`. +- `docs/evidence/METRICS_CURRENT.md` (J3) — v0.7.1 J3 changelog. Pipeline + version: v0.7.1. Test count: 3516. +- `tests/test_test_count_regression.py` — baseline updated to 3516. + +Honest boundaries: +- Release request validation checks structural and policy requirements only. + It does not verify that the release was actually performed, that the + artifact exists, or that the benchmark claims are biologically meaningful. +- `dry_lab_only: true` is a const field on all dataclasses — release requests + are computational governance artifacts, not biological findings. +- The validator does not verify that the human reviewer has actually reviewed + the request — it only checks that a GitHub handle was provided. +- Review class appropriateness is advisory: the validator warns about model + releases with low review classes but does not block them. +- The template and process are governance tools — they do not replace human + judgment about whether a release is appropriate or safe. + ## v0.6.9 — Loop 109: Phase J J1 — Release Checklist ✓ (2026-07-09) `docs/governance/RELEASE_CHECKLIST.md` with structured release checklist diff --git a/src/openamp_foundry/cli/commands/reports.py b/src/openamp_foundry/cli/commands/reports.py index 000f880b..858f62c2 100644 --- a/src/openamp_foundry/cli/commands/reports.py +++ b/src/openamp_foundry/cli/commands/reports.py @@ -2441,6 +2441,54 @@ def _run_decision_log(args: argparse.Namespace) -> int: return 0 +def _run_release_request_check(args: argparse.Namespace) -> int: + """Validate a release request before human review.""" + from openamp_foundry.governance.release_request import validate_request_dict + + try: + request_dict = json.loads(args.request_json) + except (json.JSONDecodeError, TypeError) as e: + print(json.dumps({"status": "error", "error": f"Invalid --request-json: {e}"})) + return 2 + + if not isinstance(request_dict, dict): + print(json.dumps({"status": "error", "error": "--request-json must be a JSON object"})) + return 2 + + result = validate_request_dict(request_dict) + output_format = getattr(args, "format", "text") + + if output_format == "json": + print(json.dumps({ + "release_id": result.release_id, + "release_type": result.release_type, + "passed": result.passed, + "errors": result.errors, + "warnings": result.warnings, + "dry_lab_only": result.dry_lab_only, + }, indent=2)) + else: + print("Release Request Check") + print("=" * 60) + print(f"Release ID: {result.release_id}") + print(f"Release type: {result.release_type}") + print(f"Status: {'PASS' if result.passed else 'FAIL'}") + print() + if result.errors: + print("Errors:") + for err in result.errors: + print(f" - {err}") + if result.warnings: + print("Warnings:") + for w in result.warnings: + print(f" - {w}") + print() + print("Dry-lab only. Release request validation is a computational") + print("safeguard, not biological proof.") + + return 0 if result.passed else 3 + + def _run_adoption_scorecard(args: argparse.Namespace) -> int: """Build an adoption scorecard from dimension inputs.""" from openamp_foundry.adoption.scorecard import build_scorecard diff --git a/src/openamp_foundry/cli/main.py b/src/openamp_foundry/cli/main.py index 3a3312d9..c874ce0a 100644 --- a/src/openamp_foundry/cli/main.py +++ b/src/openamp_foundry/cli/main.py @@ -9,6 +9,7 @@ from openamp_foundry.cli.commands.gates import _run_gate_check, _run_release_gate_check from openamp_foundry.cli.commands.reports import _run_contribution_check from openamp_foundry.cli.commands.reports import _run_decision_log +from openamp_foundry.cli.commands.reports import _run_release_request_check import argparse import json @@ -1838,6 +1839,25 @@ def build_parser() -> argparse.ArgumentParser: help="Output format (default: text).", ) + # ── Release request check (Phase J J3) ───────────────────────── + rrc = sub.add_parser( + "release-request-check", + help=( + "Validate a release request before human review. " + "Checks all required fields are present and valid. " + "Dry-lab only." + ), + ) + rrc.add_argument( + "--request-json", type=str, required=True, + help="JSON string of a ReleaseRequest dict (required).", + ) + rrc.add_argument( + "--format", type=str, default="text", + choices=["text", "json"], + help="Output format (default: text).", + ) + # ── Release gate check (Phase J J1) ───────────────────────────── rgc = sub.add_parser( "release-gate-check", @@ -2110,6 +2130,9 @@ def main(argv: list[str] | None = None) -> int: if args.command == "decision-log": return _run_decision_log(args) + if args.command == "release-request-check": + return _run_release_request_check(args) + parser.error("unknown command") return 2 diff --git a/src/openamp_foundry/governance/release_request.py b/src/openamp_foundry/governance/release_request.py new file mode 100644 index 00000000..ddc65c2e --- /dev/null +++ b/src/openamp_foundry/governance/release_request.py @@ -0,0 +1,159 @@ +"""Release request validator — validates release requests before human review. + +Ensures all required fields are present before a release request enters +the formal review queue. +Dry-lab only. +""" +from __future__ import annotations +from dataclasses import dataclass +from typing import Any + +VALID_RELEASE_TYPES: set[str] = { + "candidate", "model", "dataset", "evidence_packet", "schema" +} + +VALID_SAFETY_STATUSES: set[str] = { + "pending", "approved", "not_required" +} + +VALID_INTENDED_USES: set[str] = { + "research", "internal", "external_partner", "public" +} + +VALID_APPROVAL_STATUSES: set[str] = { + "pending", "approved", "rejected", "deferred" +} + +VALID_REVIEW_CLASSES: set[str] = {"A", "B", "C", "D"} + + +@dataclass +class ReleaseRequest: + release_id: str # e.g. "REL-2026-001" + release_type: str # from VALID_RELEASE_TYPES + artifact_id: str + artifact_version: str + requestor_name: str + requestor_institution: str + request_date: str # YYYY-MM-DD + evidence_level: int # 1-6 + dry_lab_only: bool # must be True + safety_review_status: str # from VALID_SAFETY_STATUSES + benchmark_summary: str # must not be empty + known_limitations: str # must not be empty + intended_use: str # from VALID_INTENDED_USES + data_license: str # must not be empty + human_reviewer: str # must not be empty + review_class: str # from VALID_REVIEW_CLASSES + approval_status: str # from VALID_APPROVAL_STATUSES + + +@dataclass +class ReleaseRequestValidationResult: + release_id: str + release_type: str + passed: bool + errors: list[str] + warnings: list[str] + dry_lab_only: bool = True + + +def validate_release_request(req: ReleaseRequest) -> ReleaseRequestValidationResult: + errors: list[str] = [] + warnings: list[str] = [] + + if not req.release_id or not req.release_id.startswith("REL-"): + errors.append("release_id must not be empty and must start with 'REL-'") + if req.release_type not in VALID_RELEASE_TYPES: + errors.append(f"release_type={req.release_type!r} not in {sorted(VALID_RELEASE_TYPES)}") + if not req.artifact_id: + errors.append("artifact_id must not be empty") + if not req.artifact_version: + errors.append("artifact_version must not be empty") + if not req.requestor_name: + errors.append("requestor_name must not be empty") + if not req.requestor_institution: + errors.append("requestor_institution must not be empty") + if not req.request_date or len(req.request_date) != 10 or req.request_date[4] != "-": + errors.append("request_date must be in YYYY-MM-DD format") + if not isinstance(req.evidence_level, int) or not (1 <= req.evidence_level <= 6): + errors.append(f"evidence_level={req.evidence_level} must be int in 1-6") + if not req.dry_lab_only: + errors.append("dry_lab_only must be True") + if req.safety_review_status not in VALID_SAFETY_STATUSES: + errors.append(f"safety_review_status={req.safety_review_status!r} not in {sorted(VALID_SAFETY_STATUSES)}") + if not req.benchmark_summary: + errors.append("benchmark_summary must not be empty") + if not req.known_limitations: + errors.append("known_limitations must not be empty") + if req.intended_use not in VALID_INTENDED_USES: + errors.append(f"intended_use={req.intended_use!r} not in {sorted(VALID_INTENDED_USES)}") + if not req.data_license: + errors.append("data_license must not be empty") + if not req.human_reviewer: + errors.append("human_reviewer must not be empty") + if req.review_class not in VALID_REVIEW_CLASSES: + errors.append(f"review_class={req.review_class!r} not in {sorted(VALID_REVIEW_CLASSES)}") + if req.approval_status not in VALID_APPROVAL_STATUSES: + errors.append(f"approval_status={req.approval_status!r} not in {sorted(VALID_APPROVAL_STATUSES)}") + + # Evidence level check for dry-lab-only + if req.dry_lab_only and req.evidence_level > 4: + errors.append("dry_lab_only artifacts cannot have evidence_level > 4") + + # Safety check for public release + if req.intended_use == "public" and req.safety_review_status == "pending": + errors.append("public releases require safety_review_status != 'pending'") + + # Model releases require review_class D + if req.release_type == "model" and req.review_class not in {"C", "D"}: + warnings.append("model releases typically require review_class C or D") + + return ReleaseRequestValidationResult( + release_id=req.release_id or "", + release_type=req.release_type, + passed=len(errors) == 0, + errors=errors, + warnings=warnings, + dry_lab_only=True, + ) + + +def validate_request_dict(d: dict[str, Any]) -> ReleaseRequestValidationResult: + required = [ + "release_id", "release_type", "artifact_id", "artifact_version", + "requestor_name", "requestor_institution", "request_date", + "evidence_level", "dry_lab_only", "safety_review_status", + "benchmark_summary", "known_limitations", "intended_use", + "data_license", "human_reviewer", "review_class", "approval_status", + ] + missing = [f for f in required if f not in d] + if missing: + return ReleaseRequestValidationResult( + release_id=d.get("release_id", ""), + release_type=d.get("release_type", ""), + passed=False, + errors=[f"Missing required fields: {missing}"], + warnings=[], + dry_lab_only=True, + ) + req = ReleaseRequest( + release_id=d.get("release_id", ""), + release_type=d.get("release_type", ""), + artifact_id=d.get("artifact_id", ""), + artifact_version=d.get("artifact_version", ""), + requestor_name=d.get("requestor_name", ""), + requestor_institution=d.get("requestor_institution", ""), + request_date=d.get("request_date", ""), + evidence_level=d.get("evidence_level", 0), + dry_lab_only=d.get("dry_lab_only", True), + safety_review_status=d.get("safety_review_status", ""), + benchmark_summary=d.get("benchmark_summary", ""), + known_limitations=d.get("known_limitations", ""), + intended_use=d.get("intended_use", ""), + data_license=d.get("data_license", ""), + human_reviewer=d.get("human_reviewer", ""), + review_class=d.get("review_class", ""), + approval_status=d.get("approval_status", ""), + ) + return validate_release_request(req) diff --git a/tests/governance/test_release_request.py b/tests/governance/test_release_request.py new file mode 100644 index 00000000..20afac98 --- /dev/null +++ b/tests/governance/test_release_request.py @@ -0,0 +1,252 @@ +"""Tests for release request validator.""" +from __future__ import annotations + +from openamp_foundry.governance.release_request import ( + ReleaseRequest, + ReleaseRequestValidationResult, + VALID_RELEASE_TYPES, + VALID_SAFETY_STATUSES, + VALID_INTENDED_USES, + VALID_APPROVAL_STATUSES, + VALID_REVIEW_CLASSES, + validate_release_request, + validate_request_dict, +) + + +def _make_valid_req() -> ReleaseRequest: + return ReleaseRequest( + release_id="REL-2026-001", + release_type="candidate", + artifact_id="AMP-001", + artifact_version="1.0.0", + requestor_name="OpenAMP Team", + requestor_institution="Open Problem Lab", + request_date="2026-07-09", + evidence_level=2, + dry_lab_only=True, + safety_review_status="approved", + benchmark_summary="Passes all benchmark gates", + known_limitations="Dry-lab only, not wet-lab validated", + intended_use="research", + data_license="CC-BY-4.0", + human_reviewer="maintainer", + review_class="B", + approval_status="pending", + ) + + +def test_valid_candidate_release_request_passes(): + req = _make_valid_req() + result = validate_release_request(req) + assert result.passed + assert result.errors == [] + + +def test_release_id_not_starting_with_rel_fails(): + req = _make_valid_req() + req.release_id = "REL-2026-001" + result = validate_release_request(req) + assert result.passed + req.release_id = "INVALID-001" + result = validate_release_request(req) + assert not result.passed + assert any("release_id" in e for e in result.errors) + + +def test_invalid_release_type_fails(): + req = _make_valid_req() + req.release_type = "invalid_type" + result = validate_release_request(req) + assert not result.passed + assert any("release_type" in e for e in result.errors) + + +def test_empty_artifact_id_fails(): + req = _make_valid_req() + req.artifact_id = "" + result = validate_release_request(req) + assert not result.passed + assert any("artifact_id" in e for e in result.errors) + + +def test_empty_requestor_name_fails(): + req = _make_valid_req() + req.requestor_name = "" + result = validate_release_request(req) + assert not result.passed + assert any("requestor_name" in e for e in result.errors) + + +def test_invalid_request_date_format_fails(): + req = _make_valid_req() + req.request_date = "2026/07/09" + result = validate_release_request(req) + assert not result.passed + assert any("request_date" in e for e in result.errors) + + +def test_evidence_level_zero_fails(): + req = _make_valid_req() + req.evidence_level = 0 + result = validate_release_request(req) + assert not result.passed + assert any("evidence_level" in e for e in result.errors) + + +def test_evidence_level_seven_fails(): + req = _make_valid_req() + req.evidence_level = 7 + result = validate_release_request(req) + assert not result.passed + assert any("evidence_level" in e for e in result.errors) + + +def test_dry_lab_only_false_fails(): + req = _make_valid_req() + req.dry_lab_only = False + result = validate_release_request(req) + assert not result.passed + assert any("dry_lab_only" in e for e in result.errors) + + +def test_invalid_safety_review_status_fails(): + req = _make_valid_req() + req.safety_review_status = "unknown" + result = validate_release_request(req) + assert not result.passed + assert any("safety_review_status" in e for e in result.errors) + + +def test_empty_benchmark_summary_fails(): + req = _make_valid_req() + req.benchmark_summary = "" + result = validate_release_request(req) + assert not result.passed + assert any("benchmark_summary" in e for e in result.errors) + + +def test_empty_known_limitations_fails(): + req = _make_valid_req() + req.known_limitations = "" + result = validate_release_request(req) + assert not result.passed + assert any("known_limitations" in e for e in result.errors) + + +def test_invalid_intended_use_fails(): + req = _make_valid_req() + req.intended_use = "commercial" + result = validate_release_request(req) + assert not result.passed + assert any("intended_use" in e for e in result.errors) + + +def test_public_release_with_pending_safety_fails(): + req = _make_valid_req() + req.intended_use = "public" + req.safety_review_status = "pending" + result = validate_release_request(req) + assert not result.passed + assert any("safety_review_status" in e for e in result.errors) + + +def test_dry_lab_only_true_with_evidence_level_5_fails(): + req = _make_valid_req() + req.evidence_level = 5 + result = validate_release_request(req) + assert not result.passed + assert any("evidence_level" in e for e in result.errors) + + +def test_all_results_have_dry_lab_only_true(): + req = _make_valid_req() + result = validate_release_request(req) + assert result.dry_lab_only + result2 = validate_release_request(req) + assert result2.dry_lab_only + + +def test_validate_request_dict_passes_with_valid_dict(): + d = { + "release_id": "REL-2026-001", + "release_type": "schema", + "artifact_id": "candidate_manifest", + "artifact_version": "1.0.0", + "requestor_name": "OpenAMP Team", + "requestor_institution": "Open Problem Lab", + "request_date": "2026-07-09", + "evidence_level": 2, + "dry_lab_only": True, + "safety_review_status": "approved", + "benchmark_summary": "Passes all schema compatibility checks", + "known_limitations": "Dry-lab only, not wet-lab validated", + "intended_use": "public", + "data_license": "CC-BY-4.0", + "human_reviewer": "maintainer", + "review_class": "B", + "approval_status": "pending", + } + result = validate_request_dict(d) + assert result.passed + + +def test_valid_release_types_has_5_entries(): + assert len(VALID_RELEASE_TYPES) == 5 + assert sorted(VALID_RELEASE_TYPES) == ["candidate", "dataset", "evidence_packet", "model", "schema"] + + +def test_valid_safety_statuses_has_3_entries(): + assert len(VALID_SAFETY_STATUSES) == 3 + + +def test_valid_intended_uses_has_4_entries(): + assert len(VALID_INTENDED_USES) == 4 + + +def test_valid_approval_statuses_has_4_entries(): + assert len(VALID_APPROVAL_STATUSES) == 4 + + +def test_valid_review_classes_has_4_entries(): + assert len(VALID_REVIEW_CLASSES) == 4 + + +def test_model_release_warning_for_low_review_class(): + req = _make_valid_req() + req.release_type = "model" + req.review_class = "A" + result = validate_release_request(req) + assert result.passed + assert any("review_class" in w for w in result.warnings) + + +def test_dict_missing_fields_fails(): + d = {"release_id": "REL-2026-001"} + result = validate_request_dict(d) + assert not result.passed + assert any("Missing required fields" in e for e in result.errors) + + +def test_validate_request_dict_fails_with_invalid_type(): + d = { + "release_id": "REL-2026-001", + "release_type": "nope", + "artifact_id": "test", + "artifact_version": "1.0.0", + "requestor_name": "Test", + "requestor_institution": "Test", + "request_date": "2026-07-09", + "evidence_level": 2, + "dry_lab_only": True, + "safety_review_status": "approved", + "benchmark_summary": "test", + "known_limitations": "test", + "intended_use": "research", + "data_license": "MIT", + "human_reviewer": "test", + "review_class": "B", + "approval_status": "pending", + } + result = validate_request_dict(d) + assert not result.passed diff --git a/tests/test_test_count_regression.py b/tests/test_test_count_regression.py index 9f7471c8..b09dc3ef 100644 --- a/tests/test_test_count_regression.py +++ b/tests/test_test_count_regression.py @@ -2,11 +2,11 @@ import subprocess import sys -# Baseline: 3491 tests as of Loop 110 (2026-07-09) -- Phase J J2 (governance decision log) +# Baseline: 3516 tests as of Loop 111 (2026-07-09) -- Phase J J3 (release request template) # Note: 3 pre-existing collection errors in test_benchmark_calibration.py, # test_benchmark_charge_distribution.py, test_benchmark_cheap_enemies.py. # Raise threshold if legitimate tests are removed; lower threshold is okay. -BASELINE = 3491 +BASELINE = 3516 TOLERANCE = 0.05 # allow 5% fluctuation From b2b33918923901d59cbc5718ec933e6e662599d1 Mon Sep 17 00:00:00 2001 From: OpenCode Date: Thu, 9 Jul 2026 16:40:50 +0700 Subject: [PATCH 2/2] feat: Phase J J3 release request template -- reviewable releases (#800) --- Makefile | 2 +- docs/governance/RELEASE_REQUEST_TEMPLATE.md | 158 +++++++------------- 2 files changed, 52 insertions(+), 108 deletions(-) diff --git a/Makefile b/Makefile index 0a880446..ba9049d7 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -.PHONY: help demo test lint ci clean bench-leakage bench-multi-negatives bench-baseline bench-hidden-active bench-cluster-split bench-expert-ablation bench-expert-ablation-500 bench-selectivity bench-feature-decomp bench-gate bench-easy-baseline bench-charge-matched bench-order-dependent bench-precision-at-k bench-per-family bench-simulation-ablation bench-simulation-ablation-within-amp simulation-gate bench-strategy-compare regenerate-all generate phase3 pilot validate-scoring validate-scoring-phase3 validate-scoring-strict external-pilot pilot-confident presynth-qc gold-standard diversity synthesis-order novelty-broad external-consensus questionnaire gate-check ip-report benchmark-card wave0-5-gate-check wave0-5-novelty-audit wave0-5-novelty-audit-v2 wave0-5-panel wave0-5-evidence wave0-5-fill-external wave0-5b-generate wave0-5b-filter recalibration-engine recalibration-engine-dry-run validate-policy-version generate-synthetic-lab-results bump-policy-version generate-review-packet failed-candidate-report safe-publication-filter classify-negative-informativeness validate-rejection-events negative-result-dashboard calibration-audit calibration-audit-example calibration-overfit-check result-quality-filter synthetic-result-policy-check calibration-decision-checklist calibration-rollback-plan simulation-registry validate-simulation-result-schema simulation-baseline-check adapter-gate-check simulation-provenance simulation-ensemble-check simulation-ci-report simulation-deprecation-check simulation-scope-check simulation-evidence-packet artifact-version candidate-manifest artifact-changelog integration-check adapter-author-check license-check artifact-compat-check contribution-check adoption-scorecard release-gate-check decision-log release-request-check release-request-check +.PHONY: help demo test lint ci clean bench-leakage bench-multi-negatives bench-baseline bench-hidden-active bench-cluster-split bench-expert-ablation bench-expert-ablation-500 bench-selectivity bench-feature-decomp bench-gate bench-easy-baseline bench-charge-matched bench-order-dependent bench-precision-at-k bench-per-family bench-simulation-ablation bench-simulation-ablation-within-amp simulation-gate bench-strategy-compare regenerate-all generate phase3 pilot validate-scoring validate-scoring-phase3 validate-scoring-strict external-pilot pilot-confident presynth-qc gold-standard diversity synthesis-order novelty-broad external-consensus questionnaire gate-check ip-report benchmark-card wave0-5-gate-check wave0-5-novelty-audit wave0-5-novelty-audit-v2 wave0-5-panel wave0-5-evidence wave0-5-fill-external wave0-5b-generate wave0-5b-filter recalibration-engine recalibration-engine-dry-run validate-policy-version generate-synthetic-lab-results bump-policy-version generate-review-packet failed-candidate-report safe-publication-filter classify-negative-informativeness validate-rejection-events negative-result-dashboard calibration-audit calibration-audit-example calibration-overfit-check result-quality-filter synthetic-result-policy-check calibration-decision-checklist calibration-rollback-plan simulation-registry validate-simulation-result-schema simulation-baseline-check adapter-gate-check simulation-provenance simulation-ensemble-check simulation-ci-report simulation-deprecation-check simulation-scope-check simulation-evidence-packet artifact-version candidate-manifest artifact-changelog integration-check adapter-author-check license-check artifact-compat-check contribution-check adoption-scorecard release-gate-check decision-log release-request-check PYTHON := $(shell [ -f .venv/bin/python ] && echo .venv/bin/python || echo python3) PYTEST := $(shell [ -f .venv/bin/pytest ] && echo .venv/bin/pytest || echo pytest) diff --git a/docs/governance/RELEASE_REQUEST_TEMPLATE.md b/docs/governance/RELEASE_REQUEST_TEMPLATE.md index 4c56412f..fcd7a7e6 100644 --- a/docs/governance/RELEASE_REQUEST_TEMPLATE.md +++ b/docs/governance/RELEASE_REQUEST_TEMPLATE.md @@ -1,128 +1,72 @@ # Release Request Template -> **Purpose:** A release request is the formal mechanism for requesting that a -> model, candidate, dataset, evidence packet, or schema be released for external -> use. File one when you have an artifact ready for review and want to initiate -> the release process. All release requests are reviewed by a human reviewer -> before the release is approved. -> -> **When to file:** After the artifact passes the release gate checks -> (`make release-gate-check`) and all required gates are green. -> -> **Who reviews it:** The assigned human reviewer (GitHub handle) — a -> maintainer or domain expert who verifies the request meets all criteria. +## Purpose ---- - -## Release Request - -### Metadata - -- **Release ID:** `REL-YYYY-NNN` (auto-assigned) -- **Release type:** (candidate | model | dataset | evidence_packet | schema) -- **Artifact ID:** \_\_\_\_\_\_\_\_\_\_ -- **Artifact version:** \_\_\_\_\_\_\_\_\_\_ - -### Requestor - -- **Name:** \_\_\_\_\_\_\_\_\_\_ -- **Institution:** \_\_\_\_\_\_\_\_\_\_ -- **Date of request:** \_\_\_\_\_\_\_\_\_\_ (YYYY-MM-DD) - -### Evidence and safety - -- **Evidence level:** \_\_\_\_\_ (1–6, see PROOF_LADDER.md) -- **Dry-lab only:** \_\_\_\_\_ (must be True) -- **Safety review status:** \_\_\_\_\_ (pending | approved | not_required) - -### Benchmark comparison - -- **Baseline beaten:** \_\_\_\_\_\_\_\_\_\_ -- **Summary of comparison:** \_\_\_\_\_\_\_\_\_\_ +A release request is the formal artifact filed when a model, candidate, dataset, evidence packet, or schema is proposed for external release. File one whenever an artifact exits the internal pipeline and enters external distribution. The OpenAMP governance team reviews all requests before publication. -### Limitations +**Who reviews:** human_reviewer (GitHub handle) specified in the request. Review class determines scrutiny level. -- **Known limitations:** \_\_\_\_\_\_\_\_\_\_ (must not be empty) - -### Use and license - -- **Intended use:** \_\_\_\_\_ (research | internal | external_partner | public) -- **Data license:** \_\_\_\_\_\_\_\_\_\_ (must specify) - -### Review assignment - -- **Human reviewer:** \_\_\_\_\_\_\_\_\_\_ (GitHub handle) -- **Review class:** \_\_\_\_\_ (A | B | C | D) - -### Approval +--- -- **Approval status:** \_\_\_\_\_ (pending | approved | rejected | deferred) -- **Review notes:** \_\_\_\_\_\_\_\_\_\_ +## Template + +Fill in every field. Fields marked REQUIRED must not be empty. + +```yaml +release_id: "" # Auto-assigned: REL-YYYY-NNN (REQUIRED) +release_type: "" # candidate | model | dataset | evidence_packet | schema (REQUIRED) +artifact_id: "" # Unique identifier for the artifact (REQUIRED) +artifact_version: "" # Semantic version, e.g. 1.0.0 (REQUIRED) +requestor_name: "" # Full name (REQUIRED) +requestor_institution: "" # Institution or organization (REQUIRED) +request_date: "" # YYYY-MM-DD (REQUIRED) +evidence_level: 0 # Integer 1–6; dry-lab-only max is 4 (REQUIRED) +dry_lab_only: true # Must be true — all releases are dry-lab only (REQUIRED) +safety_review_status: "" # pending | approved | not_required (REQUIRED) +benchmark_summary: "" # What baseline was beaten; must not be empty (REQUIRED) +known_limitations: "" # Must not be empty (REQUIRED) +intended_use: "" # research | internal | external_partner | public (REQUIRED) +data_license: "" # e.g. CC-BY-4.0, Apache-2.0 (REQUIRED) +human_reviewer: "" # GitHub handle of designated reviewer (REQUIRED) +review_class: "" # A | B | C | D (REQUIRED) +approval_status: "" # pending | approved | rejected | deferred (REQUIRED) +``` --- ## Review Criteria -The human reviewer checks the following before approving: - -1. **Formal completeness** — all required fields are present and valid. -2. **Evidence level honesty** — the claimed evidence level matches the actual - proof-ladder evidence. Dry-lab-only artifacts are capped at level 4. -3. **Safety review** — if intended use is "public", safety review must be - `approved` (not `pending`). -4. **Benchmark honesty** — the claimed baseline must actually be beaten. If no - baseline exists, the request should note this and the evidence ceiling is - adjusted accordingly. -5. **Limitations documented** — known limitations must be explicitly stated, - not empty or generic. If there are genuinely no known limitations, state - "None documented at this time." -6. **Data license valid** — the data license must be a standard open license - (e.g. CC-BY-4.0, MIT, Apache-2.0) or explicitly documented with - governance approval. -7. **Review class appropriate** — the review class must match the artifact - type and intended use: - - **Class A** — documentation, config, schema-only changes (fast-track) - - **Class B** — evidence packets, benchmark cards, candidate manifests - - **Class C** — datasets, models, candidate releases for limited use - - **Class D** — public releases, safety-significant artifacts -8. **Model releases require class C or D** — model releases must not use - class A or B. +Reviewers check the following before approving: + +1. **Completeness** — all required fields present and non-empty +2. **Release ID format** — starts with `REL-` +3. **Valid release type** — one of the five recognized types +4. **Evidence level** — within 1–6; dry-lab-only artifacts must not exceed 4 +5. **Safety review** — public releases must not have `safety_review_status: pending` +6. **Benchmark summary** — non-trivial; describes what baseline was beaten +7. **Known limitations** — honestly stated; not a placeholder +8. **Data license** — explicitly named; no "TBD" +9. **Review class** — model releases typically require class C or D +10. **Dry-lab boundary** — `dry_lab_only` must be `true`; computational outputs are not biological proof --- ## Process -1. **Submit** — Fill out the template and submit it as a GitHub issue or PR. -2. **Validation** — The release request is automatically validated by - `openamp-foundry release-request-check` to ensure all required fields - are present. -3. **Human review** — The assigned human reviewer checks the request against - the review criteria. -4. **Decision** — The reviewer sets approval status to `approved`, `rejected`, - or `deferred`. If deferred, review notes explain what must change before - re-submission. -5. **Release** — Once approved, the maintainer performs the actual release - (tag, publish, announce, etc.). - -### Expected timeline - -- **Class A:** 1–2 business days -- **Class B:** 3–5 business days -- **Class C:** 5–10 business days -- **Class D:** 10–15 business days (may require governance board review) - -### Escalation +1. **File the request** — copy the template above, fill in all fields, open a GitHub issue titled `[Release Request] REL-YYYY-NNN — `. +2. **Machine validation** — run `openamp-foundry release-request-check --request-json '{...}'` to pre-validate before human review. +3. **Human review** — the designated `human_reviewer` reviews within 5 business days. +4. **Decision** — reviewer sets `approval_status` to `approved`, `rejected`, or `deferred` with written rationale. +5. **Escalation** — if no decision within 10 business days, escalate to project maintainers via GitHub discussion. -If the release request is not reviewed within the expected timeline, the -requestor may escalate by tagging `@openamp-foundry/maintainers` on the -submission thread with a note about the delay. +**Expected timeline:** 5 business days for standard review; 10 business days for class D (model/safety-critical). --- -## Safety constraints +## Linked Policies -- `dry_lab_only` must always be `True` for dry-lab artifacts. Wet-lab - releases follow a separate process. -- Public releases require safety review to be `approved`, not `pending`. -- Evidence level 5 or 6 cannot be claimed for dry-lab-only artifacts. -- All releases require human review — no auto-approval. +- [GOVERNANCE.md](../../GOVERNANCE.md) +- [SAFETY.md](../../SAFETY.md) +- [RESPONSIBLE_USE.md](../../RESPONSIBLE_USE.md) +- [RELEASE_CHECKLIST.md](RELEASE_CHECKLIST.md) +- [DECISION_LOG.md](DECISION_LOG.md)