Skip to content

Commit 33dfeed

Browse files
cschanhniemOpenCode
andauthored
feat: Phase V V5 phase completeness gate schema -- top-level gate asserting PRG+EBM+SRS+ERP all present, closes Phase V, signals batch ready for external scientific review (#1002) (#1002)
Co-authored-by: OpenCode <opencode@example.com>
1 parent 022bb5f commit 33dfeed

3 files changed

Lines changed: 508 additions & 5 deletions

File tree

‎docs/research/NEXT_100_PR_MAP.md‎

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -264,8 +264,8 @@ Gate external sharing on all evidence schemas passing; seal the evidence trail f
264264

265265
| ID | Task | Why it matters | Priority |
266266
|----|------|----------------|----------|
267-
| V1 | Add pre-release audit gateway schema (PRG-). | Single-gate record asserting BRC (batch release checklist), PCC (pipeline completeness), ECI (evidence completeness index) all green; blocks external sharing until all gates pass; required before any batch goes to wet-lab partners or external review. | C |
268-
| V2 | Add evidence bundle manifest schema (EBM-). | Portable listing of all evidence artifact IDs and schema types for a batch; enables reproducibility checks and external handoff; machine-readable index a scientist can use to request any artifact. | C |
269-
| V3 | Add scientific reproducibility seal schema (SRS-). | Immutable record asserting that a batch's evidence trail is complete and auditable; includes pipeline version, schema hash placeholder, and human-reviewed flag; enables preprint data availability statements. | C |
270-
| V4 | Add external review packet schema (ERP-). | Assembles BRC + ECI + FET + PTR + SRS into a single record listing everything a scientist needs to review the batch's computational evidence; dry-lab-only constraint explicit; closes the "what do I send to a reviewer?" question. | C |
271-
| V5 | Add Phase V completeness gate schema (V5G-). | Top-level gate asserting PRG + EBM + SRS + ERP all present; closes Phase V and signals the batch is ready for external scientific review. | C |
267+
| V1 | Add pre-release audit gateway schema (PRG-) (complete). — src/openamp_foundry/evidence/pre_release_audit_gateway.py: 3-gate check (BRC=approved, PCC in A/B, ECI in A/B); 53 tests. | Single-gate record asserting BRC (batch release checklist), PCC (pipeline completeness), ECI (evidence completeness index) all green; blocks external sharing until all gates pass; required before any batch goes to wet-lab partners or external review. | C |
268+
| V2 | Add evidence bundle manifest schema (EBM-) (complete). — src/openamp_foundry/evidence/evidence_bundle_manifest.py: 19 schema types; complete/partial/empty status; 43 tests. | Portable listing of all evidence artifact IDs and schema types for a batch; enables reproducibility checks and external handoff; machine-readable index a scientist can use to request any artifact. | C |
269+
| V3 | Add scientific reproducibility seal schema (SRS-) (complete). — src/openamp_foundry/evidence/scientific_reproducibility_seal.py: sealed/provisional/invalidated statuses; human_reviewed cross-check; PENDING hash placeholder; 50 tests. | Immutable record asserting that a batch's evidence trail is complete and auditable; includes pipeline version, schema hash placeholder, and human-reviewed flag; enables preprint data availability statements. | C |
270+
| V4 | Add external review packet schema (ERP-) (complete). — src/openamp_foundry/evidence/external_review_packet.py: 5 components (BRC/ECI/FET/PTR/SRS); ready/incomplete/draft status; 45 tests. | Assembles BRC + ECI + FET + PTR + SRS into a single record listing everything a scientist needs to review the batch's computational evidence; dry-lab-only constraint explicit; closes the "what do I send to a reviewer?" question. | C |
271+
| V5 | Add Phase V completeness gate schema (V5G-) (complete). — src/openamp_foundry/evidence/phase_v_completeness_gate.py: 4 components (PRG/EBM/SRS/ERP); prefix-validated artifact IDs; ready/blocked verdict; 63 tests. | Top-level gate asserting PRG + EBM + SRS + ERP all present; closes Phase V and signals the batch is ready for external scientific review. | C |
Lines changed: 156 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,156 @@
1+
"""V5G- Phase V completeness gate schema.
2+
3+
Top-level gate asserting that all four Phase V artifacts (PRG, EBM, SRS, ERP)
4+
are present for a batch. A 'ready' verdict signals the batch is cleared for
5+
external scientific review.
6+
"""
7+
8+
from __future__ import annotations
9+
10+
from dataclasses import dataclass
11+
12+
REQUIRED_V5_COMPONENTS: tuple[str, ...] = ("PRG", "EBM", "SRS", "ERP")
13+
14+
VALID_V5G_VERDICTS: frozenset[str] = frozenset({"ready", "blocked"})
15+
16+
_COMPONENT_ID_PREFIXES: dict[str, str] = {
17+
"PRG": "PRG-",
18+
"EBM": "EBM-",
19+
"SRS": "SRS-",
20+
"ERP": "ERP-",
21+
}
22+
23+
24+
@dataclass
25+
class V5ComponentCheck:
26+
component_type: str
27+
artifact_id: str
28+
present: bool
29+
30+
31+
@dataclass
32+
class PhaseVCompletenessGate:
33+
v5g_id: str
34+
batch_id: str
35+
pipeline_version: str
36+
component_checks: list[V5ComponentCheck]
37+
n_components_required: int
38+
n_components_present: int
39+
missing_component_types: list[str]
40+
gate_verdict: str
41+
dry_lab_only: bool
42+
limitations: list[str]
43+
created_at: str
44+
45+
46+
def validate_phase_v_completeness_gate(gate: PhaseVCompletenessGate) -> None:
47+
if not gate.v5g_id.startswith("V5G-"):
48+
raise ValueError(f"v5g_id must start with 'V5G-': {gate.v5g_id!r}")
49+
if not gate.batch_id:
50+
raise ValueError("batch_id must be non-empty")
51+
if not gate.pipeline_version:
52+
raise ValueError("pipeline_version must be non-empty")
53+
seen_types = set()
54+
for check in gate.component_checks:
55+
if check.component_type not in REQUIRED_V5_COMPONENTS:
56+
raise ValueError(
57+
f"component_type {check.component_type!r} not in REQUIRED_V5_COMPONENTS"
58+
)
59+
if check.component_type in seen_types:
60+
raise ValueError(
61+
f"duplicate component_type: {check.component_type!r}"
62+
)
63+
seen_types.add(check.component_type)
64+
expected_prefix = _COMPONENT_ID_PREFIXES[check.component_type]
65+
if check.present and not check.artifact_id.startswith(expected_prefix):
66+
raise ValueError(
67+
f"artifact_id for {check.component_type} must start with "
68+
f"'{expected_prefix}': {check.artifact_id!r}"
69+
)
70+
if gate.n_components_required != len(REQUIRED_V5_COMPONENTS):
71+
raise ValueError(
72+
f"n_components_required must be {len(REQUIRED_V5_COMPONENTS)}"
73+
)
74+
present_count = sum(1 for c in gate.component_checks if c.present)
75+
if gate.n_components_present != present_count:
76+
raise ValueError("n_components_present mismatch")
77+
expected_missing = sorted(
78+
c.component_type for c in gate.component_checks if not c.present
79+
)
80+
if gate.missing_component_types != expected_missing:
81+
raise ValueError("missing_component_types mismatch")
82+
if gate.gate_verdict not in VALID_V5G_VERDICTS:
83+
raise ValueError(
84+
f"gate_verdict {gate.gate_verdict!r} not in VALID_V5G_VERDICTS"
85+
)
86+
if not gate.dry_lab_only:
87+
raise ValueError("dry_lab_only must be True")
88+
if not gate.limitations:
89+
raise ValueError("limitations must be non-empty")
90+
if not gate.created_at:
91+
raise ValueError("created_at must be non-empty")
92+
93+
94+
def build_phase_v_completeness_gate(
95+
*,
96+
v5g_id: str,
97+
batch_id: str,
98+
pipeline_version: str,
99+
prg_artifact_id: str = "",
100+
ebm_artifact_id: str = "",
101+
srs_artifact_id: str = "",
102+
erp_artifact_id: str = "",
103+
limitations: list[str],
104+
created_at: str,
105+
) -> PhaseVCompletenessGate:
106+
artifact_map = {
107+
"PRG": prg_artifact_id,
108+
"EBM": ebm_artifact_id,
109+
"SRS": srs_artifact_id,
110+
"ERP": erp_artifact_id,
111+
}
112+
checks = [
113+
V5ComponentCheck(
114+
component_type=ctype,
115+
artifact_id=artifact_map[ctype],
116+
present=bool(artifact_map[ctype]),
117+
)
118+
for ctype in REQUIRED_V5_COMPONENTS
119+
]
120+
n_present = sum(1 for c in checks if c.present)
121+
missing = sorted(c.component_type for c in checks if not c.present)
122+
verdict = "ready" if n_present == len(REQUIRED_V5_COMPONENTS) else "blocked"
123+
gate = PhaseVCompletenessGate(
124+
v5g_id=v5g_id,
125+
batch_id=batch_id,
126+
pipeline_version=pipeline_version,
127+
component_checks=checks,
128+
n_components_required=len(REQUIRED_V5_COMPONENTS),
129+
n_components_present=n_present,
130+
missing_component_types=missing,
131+
gate_verdict=verdict,
132+
dry_lab_only=True,
133+
limitations=limitations,
134+
created_at=created_at,
135+
)
136+
validate_phase_v_completeness_gate(gate)
137+
return gate
138+
139+
140+
def format_phase_v_completeness_gate(gate: PhaseVCompletenessGate) -> str:
141+
lines = [
142+
f"Phase V Completeness Gate — {gate.v5g_id}",
143+
f"Batch: {gate.batch_id} | Pipeline: {gate.pipeline_version}",
144+
f"Verdict: {gate.gate_verdict} | Present: {gate.n_components_present}/{gate.n_components_required}",
145+
]
146+
lines.append("Components:")
147+
for check in gate.component_checks:
148+
status = "PRESENT" if check.present else "MISSING"
149+
aid = check.artifact_id if check.artifact_id else "(none)"
150+
lines.append(f" {check.component_type}: {status} {aid}")
151+
if gate.missing_component_types:
152+
lines.append(f"Missing: {', '.join(gate.missing_component_types)}")
153+
lines.append(f"Created: {gate.created_at}")
154+
lines.append(f"Limitations: {'; '.join(gate.limitations)}")
155+
lines.append(f"dry_lab_only: {gate.dry_lab_only}")
156+
return "\n".join(lines)

0 commit comments

Comments
 (0)