Skip to content

Commit d897cd0

Browse files
authored
fix: reject malformed nested pilot preregistration input
Reject malformed selection and amendment list entries as structured PRR CLI input errors.
1 parent cb12f03 commit d897cd0

5 files changed

Lines changed: 46 additions & 5 deletions

File tree

‎docs/evidence/METRICS_CURRENT.md‎

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,9 @@ Machine-readable snapshot: `outputs/metrics_snapshot.json` regenerated with `mak
55
> **Purpose:** One authoritative table of current pipeline metrics. If any doc disagrees
66
> with this file, this file wins. Updated whenever benchmark/benchmark config changes.
77
>
8-
> **Last updated:** 2026-09-05 (pilot pre-registration input boundary; benchmark values unchanged)
8+
> **Last updated:** 2026-09-06 (pilot pre-registration nested input boundary; benchmark values unchanged)
99
10-
> **Current verification note (2026-09-05):** Phase AA AA6 exposes the AARG-
10+
> **Current verification note (2026-09-06):** Phase AA AA6 exposes the AARG-
1111
> reproducibility aggregate through a repeatable CLI/make workflow, while Phase
1212
> AB AB5 exposes the ABAG- claim-integrity aggregate, Phase AC AC3 exposes the
1313
> ACDG- aggregate, Phase Y Y5 exposes the YAG- aggregate, and Phase Z Z5
@@ -100,7 +100,7 @@ Machine-readable snapshot: `outputs/metrics_snapshot.json` regenerated with `mak
100100
> Phase AC AC3 exposes the ACDG-
101101
> aggregate disconfirming-evidence gate as a repeatable CLI/make workflow. It
102102
> has 18 focused gate tests plus 2 CLI integration tests. Full pytest
103-
> collection succeeds at 12,438 tests; the live count is enforced by the
103+
> collection succeeds at 12,440 tests; the live count is enforced by the
104104
> current-state alignment test. This artifact does not establish
105105
> biological validation or benchmark improvement.
106106
@@ -122,6 +122,12 @@ Machine-readable snapshot: `outputs/metrics_snapshot.json` regenerated with `mak
122122
> exceptions; it does not authenticate signers or establish assay or biological
123123
> evidence.
124124
125+
> **Pilot pre-registration nested-input note (2026-09-06):** The PRR CLI now
126+
> rejects non-string selection criteria and amendment-reason entries before
127+
> semantic validation. This keeps malformed nested data in the structured input
128+
> error path; it does not authenticate signers or establish assay or biological
129+
> evidence.
130+
125131
> **Pilot freeze-integrity note (2026-08-24):** Locked PRR- records now require
126132
> a deterministic SHA-256 over their canonical content. This catches edits to
127133
> frozen selection criteria and thresholds; it does not authenticate the

‎docs/getting-started/COMMAND_SURFACE.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,7 @@ qualified pilot. A valid record must be locked and carry a matching
141141
checks record integrity only. It does not authenticate a signer, validate an
142142
assay, or establish biological evidence.
143143
Malformed field types are reported as input errors rather than being coerced
144-
or allowed to crash the command.
144+
or allowed to crash the command, including malformed nested list entries.
145145

146146
## Recalibration workflow
147147

‎docs/research/ROADMAP.md‎

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# Roadmap
22

3-
## Current state — 2026-09-05
3+
## Current state — 2026-09-06
44

55
Phase AB is complete as of 2026-07-26. AB5 exposes the existing CSD-, RDR-,
66
EGN-, and EHP- claim-integrity artifacts through an ABAG- aggregate, CLI
@@ -208,6 +208,10 @@ On 2026-09-05, the PRR CLI began rejecting malformed field types as structured
208208
input errors. This prevents permissive coercion or handler crashes at the JSON
209209
boundary while leaving valid locked and editable records unchanged.
210210

211+
On 2026-09-06, the same boundary began validating nested PRR list entries,
212+
preventing malformed amendment or selection items from reaching semantic
213+
validation as unexpected Python types.
214+
211215
This file is the current milestone authority. The older
212216
[`50_LOOP_PLAN.md`](50_LOOP_PLAN.md) is a historical execution record, not a
213217
live status page. Select the next bottleneck from

‎src/openamp_foundry/cli/commands/reports.py‎

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2063,6 +2063,13 @@ def _run_pilot_preregistration_check(args: argparse.Namespace) -> int:
20632063
"error": f"Malformed PRR JSON: {field_name} must be a list",
20642064
}))
20652065
return 2
2066+
for field_name in ("selection_criteria", "amendment_reasons"):
2067+
if any(not isinstance(item, str) for item in entry_dict.get(field_name, [])):
2068+
print(json.dumps({
2069+
"status": "error",
2070+
"error": f"Malformed PRR JSON: {field_name} entries must be strings",
2071+
}))
2072+
return 2
20662073
for field_name in ("dry_lab_only_declaration", "is_locked"):
20672074
if field_name in entry_dict and not isinstance(entry_dict[field_name], bool):
20682075
print(json.dumps({

‎tests/integration/test_pilot_preregistration_cli.py‎

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,3 +108,27 @@ def test_invalid_preregistration_scalar_type_returns_input_error(capsys):
108108
assert rc == 2
109109
result = json.loads(capsys.readouterr().out)
110110
assert "primary_hypothesis must be a string" in result["error"]
111+
112+
113+
def test_invalid_preregistration_list_item_returns_input_error(capsys):
114+
payload = _locked_payload()
115+
payload["amendment_reasons"] = [{"reason": "not-a-string"}]
116+
rc = main([
117+
"pilot-preregistration-check",
118+
"--entry-json", json.dumps(payload),
119+
])
120+
assert rc == 2
121+
result = json.loads(capsys.readouterr().out)
122+
assert "amendment_reasons entries must be strings" in result["error"]
123+
124+
125+
def test_non_string_selection_criterion_returns_input_error(capsys):
126+
payload = _locked_payload()
127+
payload["selection_criteria"] = [42]
128+
rc = main([
129+
"pilot-preregistration-check",
130+
"--entry-json", json.dumps(payload),
131+
])
132+
assert rc == 2
133+
result = json.loads(capsys.readouterr().out)
134+
assert "selection_criteria entries must be strings" in result["error"]

0 commit comments

Comments
 (0)