Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
@@ -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
.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

PYTHON := $(shell [ -f .venv/bin/python ] && echo .venv/bin/python || echo python3)
PYTEST := $(shell [ -f .venv/bin/pytest ] && echo .venv/bin/pytest || echo pytest)
Expand Down Expand Up @@ -685,3 +685,10 @@ result-quality-filter:
--results-json /tmp/rq_input.json \
--out-json /tmp/rq_output.json --out-md /tmp/rq_output.md
@echo "Result quality filter done. See /tmp/rq_output.json"

synthetic-result-policy-check:
echo '[{"candidate_id":"AMP001","current_level":2,"proposed_level":3,"evidence_source":"synthetic"},{"candidate_id":"AMP002","current_level":2,"proposed_level":2,"evidence_source":"synthetic"},{"candidate_id":"AMP003","current_level":2,"proposed_level":3,"evidence_source":"lab"}]' > /tmp/srp_input.json
.venv/bin/openamp-foundry synthetic-result-policy-check \
--proposals-json /tmp/srp_input.json \
--out-json /tmp/srp_output.json --out-md /tmp/srp_output.md
@echo "Synthetic result policy check done. See /tmp/srp_output.json"
5 changes: 3 additions & 2 deletions docs/evidence/METRICS_CURRENT.md
Original file line number Diff line number Diff line change
Expand Up @@ -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 G G7 — result-quality flag propagation — v0.5.85)
> **Last updated:** 2026-07-09 (Phase G G8 — synthetic-result policy — v0.5.86)
> **New in v0.5.86:** Synthetic-result policy enforcement (G8) — `check_synthetic_result_policy()` and `run_policy_batch()` enforce that synthetic/simulation outputs cannot raise the proof-ladder level of a candidate. Levels 4+ require wet-lab evidence; synthetic/unknown sources are rejected for such proposals. CLI (`openamp-foundry synthetic-result-policy-check`) accepts `--proposals-json`, `--out-json`, `--out-md`. Schema (`schemas/synthetic_result_policy_check.schema.json`). `make synthetic-result-policy-check` target. 27 tests. 3049 total. Anti-overclaim safeguard.
> **New in v0.5.85:** Result-quality flag propagation (G7) — `assess_result_quality()` and `filter_results_for_calibration()` propagate result-quality flags into the calibration engine. Candidates with contamination or assay interference are excluded; candidates with 2+ quality flags are excluded; candidates with 1 flag are included with caution; clean candidates are fully included. `QUALITY_FLAGS` dictionary (8 flags). `ResultQualityReport` dataclass. CLI (`openamp-foundry result-quality-filter`) accepts `--results-json`, `--out-json`, `--out-md`. JSON + Markdown output. Schema (`schemas/result_quality_report.schema.json`). `make result-quality-filter` target. 27 tests. 3022 total.
> **New in v0.5.84:** Calibration-overfit warning (G6) — `check_cohort_overfit_risk()` and `run_overfit_check()` flag when a calibration cohort is too small relative to model parameters. Warns at three severity levels (critical/warning/caution/none). CLI (`openamp-foundry calibration-overfit-check`) accepts comma-separated cohort sizes, model params, n features. JSON + Markdown output. Schema (`schemas/calibration_overfit_check.schema.json`). `make calibration-overfit-check` target. 21 tests. 2995 total.
> **New in v0.5.83:** Batch-2 selection rationale report (G5) — CLI (`openamp-foundry batch-rationale`) that generates a synthetic candidate pool, runs the batch-2 selector with configurable weights, and produces a per-candidate rationale report classifying each selected candidate into exploit / explore / diversity / combined roles. Reports weight configuration, role breakdown summary, per-candidate contributions (ensemble×weight, uncertainty×weight, diversity×weight), safety gate impact, and caveats. Schema (`schemas/batch_rationale_report.schema.json`). `make batch-rationale` target. 19 tests. 2974 total.
Expand Down Expand Up @@ -77,7 +78,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.5.85 (G7)
> **Pipeline version:** v0.5.86 (G8)
> **Branch:** main

---
Expand Down
62 changes: 62 additions & 0 deletions docs/research/ROADMAP.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,67 @@
# Roadmap

## v0.5.86 — Loop 86: Phase G G8 — Synthetic-Result Policy (Anti-Overclaim) ✓ (2026-07-09)

`check_synthetic_result_policy()` and `run_policy_batch()` enforce that synthetic/
simulation results cannot raise the proof-ladder level of a candidate. Levels 4+
require wet-lab evidence; synthetic or unknown sources are blocked for such proposals.
CLI (`openamp-foundry synthetic-result-policy-check`). Schema
(`schemas/synthetic_result_policy_check.schema.json`). `make synthetic-result-policy-check`
target. 27 tests. 3049 total. Anti-overclaim safeguard.

## v0.5.86 — Loop 86: Phase G G8 — Synthetic Result Policy — Anti-Overclaim ✓ (2026-07-09)

`check_synthetic_result_policy()` enforces that synthetic/simulation outputs cannot
raise a candidate's proof-ladder level. Simulation outputs are anti-overclaim —
they must not be used as evidence to move a candidate up the proof ladder.

Changes:
- `src/openamp_foundry/evidence/synthetic_result_policy.py` (G8) — Core module with
`PROOF_LADDER_LEVELS` dictionary (1–6 mapping to descriptions),
`SyntheticResultPolicyCheck` dataclass (8 fields: candidate_id, current_level,
proposed_level, evidence_source, policy_pass, violation, recommendation,
dry_lab_only), `check_synthetic_result_policy()` applying multi-tier rules
(synthetic cannot raise, synthetic cannot lower, levels 4+ require wet-lab
evidence, invalid level raises ValueError), `run_policy_batch()` aggregating
results with summary counts and any_violation flag,
`write_policy_check_json()` and `write_policy_check_markdown()` for output.
- `schemas/synthetic_result_policy_check.schema.json` (G8) — JSON Schema Draft 07
for single or batch policy check results. Validates all 8 required fields
including evidence_source enum constraint and dry_lab_only const=true.
- `src/openamp_foundry/evidence/__init__.py` — Exports all synthetic result policy
symbols.
- `src/openamp_foundry/cli/commands/reports.py` — Added
`_run_synthetic_result_policy_check()` CLI handler with `--proposals-json`,
`--out-json`, `--out-md` flags.
- `src/openamp_foundry/cli/main.py` — Registered `synthetic-result-policy-check`
subcommand with all argument flags and dispatch to handler.
- `Makefile` — Added `synthetic-result-policy-check` target with default example
data writing to `/tmp/srp_output.json` and `/tmp/srp_output.md`. Added to
`.PHONY`.
- `tests/evidence/test_synthetic_result_policy.py` — 27 tests covering: synthetic
raising level, synthetic maintaining level, synthetic lowering level, lab raising
level, literature raising level, proposed_level > 3 with synthetic/unknown source
violation, proposed_level > 3 with lab/literature pass, invalid current_level,
invalid proposed_level, unknown source normalization, unknown source + level 4
violation, dry_lab_only always True, run_policy_batch summary counts, all-pass
batch, any_violation flag, to_dict output, PROOF_LADDER_LEVELS completeness,
JSON writer (single + batch), Markdown writer (single + batch), recommendation
non-empty for violation, recommendation for pass, empty batch list.
- `docs/evidence/METRICS_CURRENT.md` — v0.5.86 G8 changelog. Test count: 3049.
- `tests/test_test_count_regression.py` — baseline updated to 3049.

Honest boundaries:
- This policy check validates evidence-source discipline, not biological truth.
A PASS does not confirm biological activity or safety.
- Synthetic evidence can still be useful for negative-result documentation and
exploratory research — the policy restricts proof-ladder movement, not usage.
- Level 4+ wet-lab evidence requirement is a policy rule, not a biological
guarantee. Wet-lab evidence can be wrong, inconclusive, or non-reproducible.
- The evidence_source classification relies on the submitter's honest labeling.
A "lab" source may still be noisy or erroneous.
- All proof-ladder determinations require qualified human review regardless of
policy check results.

## v0.5.85 — Loop 85: Phase G G7 — Result-Quality Flag Propagation into Calibration Engine ✓ (2026-07-09)

`assess_result_quality()` and `filter_results_for_calibration()` propagate
Expand Down
58 changes: 58 additions & 0 deletions schemas/synthetic_result_policy_check.schema.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"$id": "https://openamp.ai/schemas/synthetic_result_policy_check.schema.json",
"title": "Synthetic Result Policy Check",
"description": "Schema for a synthetic result policy check result. Dry-lab only — does not measure biological activity.",
"type": "object",
"properties": {
"candidate_id": {
"type": "string",
"description": "Identifier for the candidate peptide."
},
"current_level": {
"type": "integer",
"minimum": 1,
"maximum": 6,
"description": "Current proof-ladder level of the candidate."
},
"proposed_level": {
"type": "integer",
"minimum": 1,
"maximum": 6,
"description": "Proposed proof-ladder level for the candidate."
},
"evidence_source": {
"type": "string",
"enum": ["synthetic", "lab", "literature", "unknown"],
"description": "Source of the evidence for the proposed level."
},
"policy_pass": {
"type": "boolean",
"description": "Whether the proposal passes the synthetic result policy."
},
"violation": {
"type": "string",
"description": "Description of the policy violation, if any."
},
"recommendation": {
"type": "string",
"description": "Human-readable recommendation."
},
"dry_lab_only": {
"type": "boolean",
"description": "Always true. This is a computational assessment, not biological proof.",
"const": true
}
},
"required": [
"candidate_id",
"current_level",
"proposed_level",
"evidence_source",
"policy_pass",
"violation",
"recommendation",
"dry_lab_only"
],
"additionalProperties": false
}
48 changes: 48 additions & 0 deletions src/openamp_foundry/cli/commands/reports.py
Original file line number Diff line number Diff line change
Expand Up @@ -1032,6 +1032,54 @@ def _run_calibration_overfit_check(args: argparse.Namespace) -> int:
return 0


def _run_synthetic_result_policy_check(args: argparse.Namespace) -> int:
"""Check whether synthetic/simulation results raise proof-ladder level."""
from pathlib import Path
from openamp_foundry.evidence.synthetic_result_policy import (
check_synthetic_result_policy,
run_policy_batch,
write_policy_check_json,
write_policy_check_markdown,
)

proposals_path = Path(args.proposals_json)
if not proposals_path.exists():
print(json.dumps({
"status": "error",
"error": f"proposals JSON not found: {proposals_path}",
}))
return 2

with proposals_path.open() as f:
proposals = json.load(f)

if not isinstance(proposals, list):
print(json.dumps({
"status": "error",
"error": "proposals JSON must be a list of {candidate_id, current_level, proposed_level, evidence_source} objects",
}))
return 2

result = run_policy_batch(proposals)

if args.out_json:
write_policy_check_json(result, args.out_json)
if args.out_md:
write_policy_check_markdown(result, args.out_md)

print(json.dumps({
"status": "ok",
"total": result["summary"]["total"],
"passed": result["summary"]["passed"],
"failed": result["summary"]["failed"],
"any_violation": result["any_violation"],
"dry_lab_only": result["dry_lab_only"],
"out_json": args.out_json,
"out_md": args.out_md,
}, indent=2))
return 3 if result["any_violation"] else 0


def _run_result_quality_filter(args: argparse.Namespace) -> int:
"""Filter lab results by quality flags for calibration eligibility."""
import json
Expand Down
33 changes: 32 additions & 1 deletion src/openamp_foundry/cli/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
from openamp_foundry.cli.commands.selection import _run_pilot_panel, _run_pilot_confident, _run_diversity_check, _run_select_batch, _run_batch_rationale
from openamp_foundry.cli.commands.external import _run_external_predict, _run_external_consensus
from openamp_foundry.cli.commands.qc import _run_synthesis_order, _run_presynth_qc
from openamp_foundry.cli.commands.reports import _run_reviewer_questionnaire, _run_ip_report, _run_batch_pack, _run_gold_standard, _run_novelty_check_broad, _run_lab_result_report, _run_calibration_intake, _run_recalibration_gate, _run_recalibration_engine, _run_validate_policy_version, _run_calibration_audit, _run_calibration_overfit_check, _run_result_quality_filter
from openamp_foundry.cli.commands.reports import _run_reviewer_questionnaire, _run_ip_report, _run_batch_pack, _run_gold_standard, _run_novelty_check_broad, _run_lab_result_report, _run_calibration_intake, _run_recalibration_gate, _run_recalibration_engine, _run_validate_policy_version, _run_calibration_audit, _run_calibration_overfit_check, _run_result_quality_filter, _run_synthetic_result_policy_check
from openamp_foundry.cli.commands.gates import _run_gate_check

import argparse
Expand Down Expand Up @@ -1280,6 +1280,34 @@ def build_parser() -> argparse.ArgumentParser:
help="Optional output path for markdown report.",
)

# ── Synthetic result policy check ──────────────────────────────
srp = sub.add_parser(
"synthetic-result-policy-check",
help=(
"Check whether synthetic/simulation results are used to raise "
"a candidate's proof-ladder level. Anti-overclaim safeguard. "
"Dry-lab only."
),
)
srp.add_argument(
"--proposals-json",
required=True,
help=(
"Path to JSON file with list of {candidate_id, current_level, "
"proposed_level, evidence_source} objects."
),
)
srp.add_argument(
"--out-json",
default=None,
help="Optional output path for policy check JSON.",
)
srp.add_argument(
"--out-md",
default=None,
help="Optional output path for policy check markdown report.",
)

return parser


Expand Down Expand Up @@ -1426,6 +1454,9 @@ def main(argv: list[str] | None = None) -> int:
if args.command == "result-quality-filter":
return _run_result_quality_filter(args)

if args.command == "synthetic-result-policy-check":
return _run_synthetic_result_policy_check(args)

parser.error("unknown command")
return 2

Expand Down
18 changes: 18 additions & 0 deletions src/openamp_foundry/evidence/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,30 @@

Builds machine-readable candidate evidence certificates and validates
them against `schemas/candidate.schema.json`.

Includes synthetic result policy (Phase G G8) which enforces that
synthetic/simulation outputs cannot raise the proof-ladder level
of a candidate — anti-overclaim safeguard.
"""

from openamp_foundry.evidence.certificate import build_certificate
from openamp_foundry.evidence.schemas import validate_json_schema
from openamp_foundry.evidence.synthetic_result_policy import (
PROOF_LADDER_LEVELS,
SyntheticResultPolicyCheck,
check_synthetic_result_policy,
run_policy_batch,
write_policy_check_json,
write_policy_check_markdown,
)

__all__ = [
"build_certificate",
"validate_json_schema",
"PROOF_LADDER_LEVELS",
"SyntheticResultPolicyCheck",
"check_synthetic_result_policy",
"run_policy_batch",
"write_policy_check_json",
"write_policy_check_markdown",
]
Loading
Loading