Skip to content

Commit 6462efd

Browse files
authored
fix: validate lab result calendar dates
Reject impossible and non-canonical assay dates while preserving structured invalid-file provenance.
1 parent c895a1b commit 6462efd

12 files changed

Lines changed: 89 additions & 7 deletions

File tree

‎AGENTS.md‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,10 @@ If these docs conflict, safety and claim discipline win.
100100
relative `raw_data_file` field. Missing files, path escape, or mismatches are
101101
structured verification blockers; matching bytes do not validate assay
102102
contents, reviewer identity, biology, or release readiness.
103+
- Lab-result `assay_date` values are checked as real, canonical `YYYY-MM-DD`
104+
calendar dates after schema validation. Impossible or non-canonical dates are
105+
retained as structured invalid-file errors and cannot enter reports or
106+
metrics; this is temporal input integrity, not assay validation.
103107
- The Phase R scientific-review readiness gate is available through
104108
`scientific-review-readiness-check` and
105109
`make scientific-review-readiness-check`; only a

‎SKILL.md‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,10 @@ When a caller supplies `--raw-data-dir`, records with `raw_data_file` can be
155155
independently checked against their declared SHA-256. Missing files, path
156156
escape, and mismatches block clean calibration intake; matching bytes prove
157157
file identity only, not assay validity or biology.
158+
Lab-result `assay_date` values are additionally checked as real, canonical
159+
`YYYY-MM-DD` calendar dates because JSON Schema's date format annotation is not
160+
enforced by the generic validator. Impossible or non-canonical dates are
161+
retained as structured invalid-file errors and cannot enter reports or metrics.
158162

159163
- `make bench-easy-baseline`: trivial length/charge baselines.
160164
- `make bench-charge-matched`: adversarial check that removes charge-density

‎docs/engineering/AGENTS.md‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,9 @@ turning artifact presence into scientific validation.
2020
- `ARCHITECTURE.md` also records the Phase Z ZAG- CLI/Make surface; all four
2121
per-family accountability artifacts are required, but presence is not
2222
benchmark validation.
23+
- `ARCHITECTURE.md` records that lab-result `assay_date` values undergo
24+
canonical calendar validation before they can enter sorted reports or
25+
calibration metrics.
2326

2427
## Diagrams (Mermaid)
2528

‎docs/engineering/ARCHITECTURE.md‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,10 @@ missing. An optional `raw_data_file` reference can be verified by supplying
117117
`--raw-data-dir`; the verifier hashes files independently, rejects path escape,
118118
and blocks clean calibration intake on missing or mismatched files. This binds
119119
the declaration to file bytes only and does not validate assay contents.
120+
The loader also validates `assay_date` as a real, canonical `YYYY-MM-DD`
121+
calendar date because the generic JSON Schema helper does not enforce format
122+
annotations. Invalid dates remain structured file errors and cannot enter
123+
sorted reports or calibration metrics.
120124
Results whose candidate IDs are absent from the submitted calibration panel are
121125
retained as orphan provenance but block clean intake because they cannot be
122126
joined to prior predictions. This prevents a broader result directory from

‎docs/evidence/AGENTS.md‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,9 @@ Gate workflows are structural review controls, never biological proof.
2222
- The Phase R SRG- workflow exposes scientific-review readiness through the CLI
2323
and Make surface; conditional, incomplete, safety-blocked, or malformed
2424
records must fail closed.
25+
- Impossible or non-canonical lab-result `assay_date` values remain structured
26+
invalid-file evidence and cannot support downstream metrics; this is temporal
27+
input integrity, not assay validation.
2528

2629
## Diagrams (Mermaid)
2730

‎docs/evidence/METRICS_CURRENT.md‎

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ 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-07-24 (frozen external-review package identity check; benchmark values unchanged)
8+
> **Last updated:** 2026-07-25 (lab-result assay-date integrity check; benchmark values unchanged)
99
1010
> **Current verification note (2026-07-24):** Phase AA AA6 exposes the AARG-
1111
> reproducibility aggregate through a repeatable CLI/make workflow, while Phase
@@ -161,6 +161,14 @@ Machine-readable snapshot: `outputs/metrics_snapshot.json` regenerated with `mak
161161
compatible. File identity is not assay validation, reviewer authentication,
162162
biological proof, or release authorization.
163163

164+
### External-result intake integrity — reject impossible assay dates
165+
- Lab-result loading now validates `assay_date` as a real, canonical
166+
`YYYY-MM-DD` calendar date after schema validation.
167+
- Impossible or non-canonical dates are retained as structured invalid-file
168+
errors and cannot enter sorted reports or calibration metrics.
169+
- This closes a temporal input-integrity gap; it does not validate assay
170+
contents, reviewer identity, biological activity, or release readiness.
171+
164172

165173
### External-result intake integrity — reject invalid result paths
166174
- Lab-result directory loading now fails closed when the input path is missing

‎docs/research/AGENTS.md‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,9 @@ work and preserve the external-truth bottleneck.
2323
records that provide the relative `raw_data_file` field. Missing files, path
2424
escape, and mismatches block clean calibration intake; matching file bytes do
2525
not validate assay contents or biology.
26+
- Lab-result loading also rejects impossible or non-canonical `assay_date`
27+
values as structured invalid-file errors before they reach reports or
28+
calibration metrics.
2629
- The next executable review boundary is the Phase R SRG- workflow. Its default
2730
example is intentionally blocked because qualified wet-lab evidence is not
2831
present; do not treat the gate as validation.

‎docs/research/ROADMAP.md‎

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

3-
## Current state — 2026-07-24
3+
## Current state — 2026-07-25
44

55
Phase Z is complete as of 2026-07-23. Z5 exposes the existing FBH-, BXR-,
66
ARG-, and CBF- per-family accountability artifacts through a ZAG- aggregate,
@@ -107,6 +107,13 @@ records. This binds a review record to package bytes, but does not authenticate
107107
the reviewer, establish independence, validate the science, or create
108108
biological evidence.
109109

110+
On 2026-07-25, lab-result loading also began checking `assay_date` as a real,
111+
canonical `YYYY-MM-DD` calendar date. JSON Schema's date format annotation is
112+
not enforced by the generic validator, so impossible or non-canonical dates
113+
are now retained as structured invalid-file errors and cannot enter sorted
114+
reports or calibration metrics. This is temporal input integrity, not assay
115+
validation or biological evidence.
116+
110117
This file is the current milestone authority. The older
111118
[`50_LOOP_PLAN.md`](50_LOOP_PLAN.md) is a historical execution record, not a
112119
live status page. Select the next bottleneck from

‎src/openamp_foundry/data/AGENTS.md‎

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,15 +7,17 @@ descriptive evidence plumbing, not biological validation.
77

88
## Key Components
99

10-
- `lab_results.py`: input-path validation, schema validation, structured
11-
invalid-file provenance, and candidate-level summaries. Rollups expose raw
10+
- `lab_results.py`: input-path validation, schema and canonical calendar-date
11+
validation, structured invalid-file provenance, and candidate-level summaries.
12+
Rollups expose raw
1213
observations separately from control-passing outcome flags and counts;
1314
batch-level qualitative summaries follow the same raw-versus-usable split.
1415
Calibration intake may additionally verify an optional frozen `panel_id`.
1516
Reports expose declared `raw_data_sha256` coverage separately from verified
1617
evidence; a declared hash is never presented as independently checked unless
1718
the caller opts into `verify_raw_data_provenance()` with a raw-data directory
18-
and `raw_data_file` references.
19+
and `raw_data_file` references. Invalid or non-canonical `assay_date` values
20+
remain structured file errors and cannot enter sorted reports or metrics.
1921
- `__init__.py`: stable public loader exports.
2022

2123
## Diagrams (Mermaid)

‎src/openamp_foundry/data/lab_results.py‎

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212

1313
import hashlib
1414
import json
15+
from datetime import date
1516
from pathlib import Path
1617
from typing import Any
1718

@@ -29,6 +30,18 @@ def load_lab_result(path: str | Path) -> dict[str, Any]:
2930
with p.open("r", encoding="utf-8") as f:
3031
result = json.load(f)
3132
validate_json_schema(result, LAB_RESULT_SCHEMA)
33+
assay_date = result["assay_date"]
34+
try:
35+
parsed_assay_date = date.fromisoformat(assay_date)
36+
except (TypeError, ValueError) as exc:
37+
raise ValueError(
38+
"assay_date must be a valid ISO 8601 calendar date (YYYY-MM-DD)"
39+
) from exc
40+
if parsed_assay_date.isoformat() != assay_date:
41+
raise ValueError(
42+
"assay_date must use the canonical ISO 8601 calendar date form "
43+
"(YYYY-MM-DD)"
44+
)
3245
return result
3346

3447

0 commit comments

Comments
 (0)