Phase 2 transforms the Phase 1 control catalog into measurable risk metrics, scenario-based synthetic observations, optional public breach mappings, and baseline risk scores.
This document focuses on implementation details, design rationale, data contracts, and quality expectations.
Phase 2 is intentionally isolated from Phase 1 to prevent accidental regression in extraction and ground-truth alignment.
Design goals:
Code isolation:
src/prert/phase2/.src/prert/cli/phase2.py.scripts/run_phase2_metrics.py.Artifact isolation:
artifacts/phase-2/.artifacts/phase-1/controls_all.jsonl.artifacts/phase-1/ is performed.artifacts/phase-2/.From the latest phase2_manifest.json run:
pie showData
title Phase 2 Risk Bands (Metric Rows, n=711)
"Low" : 251
"Medium" : 389
"High" : 71
| Figure | What it shows | Result |
|---|---|---|
| Phase 2 Baseline Risk Distribution | Risk-band spread from metric-level score rows | Most rows are medium risk (389), with a smaller high-risk tail (71). |
For the full cross-phase visual report and figure tables, see 09-phase1-phase2-progress-dashboard.md.
metrics.py: Metric creation, level classification, coverage accounting.synthetic.py: Deterministic synthetic generator with scenario profiles.public_mapping.py: Public-data ingestion and canonical mapping with quality flags.scoring.py: Metric, level, and scenario scoring plus risk banding.pipeline.py: Orchestration and artifact writing.types.py: Dataclasses for metric and observation structures.io.py: JSONL/CSV/JSON readers and writers.Each control maps to one metric spec containing:
metric_id: Stable hash-based ID.control_id: Phase 1 normalized control ID.regulation: Source family.level: user, system, or organization.formula: Level-specific score formula string.required_fields: Data prerequisites for scoring.normalization_rule: Clamp to [0, 1].confidence_weight: Derived from parser confidence and bounded in [0.1, 1.0].missing_data_handling: Penalty policy string.Classification is keyword-driven over title+text.
organization to avoid dropped controls.Three scenarios are generated for each metric:
normal: lower failure and missingness, higher confidence.stressed: moderate failure and missingness.adversarial: high failure and missingness, lower confidence.Configured profile parameters:
normal: failure 0.08, missing 0.04, confidence [0.85, 0.98]stressed: failure 0.22, missing 0.12, confidence [0.72, 0.92]adversarial: failure 0.40, missing 0.20, confidence [0.55, 0.85]Per-observation steps:
1 - failure_count / max(total_checks, 1)min(0.4, 0.05 * missing_fields)normalized * (1 - penalty) * observed_confidence * confidence_weight1 - confidence_adjusted_complianceRisk bands:
high if risk >= 0.67medium if risk >= 0.34 and < 0.67low if risk < 0.34Scenario summary uses weighted level compliance:
Composite method label: weighted_sum_v1.
Optional public input is accepted as .csv or .jsonl.
Canonical mapped fields:
event_datecountrysectorrecords_affecteddetection_to_response_hoursseverityRequired fields for row validity:
event_datesectorrecords_affectedRow quality metadata:
dq_missing_required_fieldsdq_validartifacts/phase-2/metric_specs.jsonl
artifacts/phase-2/synthetic_events.jsonl
artifacts/phase-2/public_data_mapped.jsonl
artifacts/phase-2/baseline_scores.jsonl
row_type=metric, row_type=level_summary, row_type=scenario_summary.artifacts/phase-2/phase2_manifest.json
artifacts/phase-2/synthetic_data_dictionary.md
Default execution:
PYTHONPATH=src python scripts/run_phase2_metrics.py
With public dataset:
PYTHONPATH=src python scripts/run_phase2_metrics.py \
--public-input path/to/public_breach_data.csv
Custom output directory:
PYTHONPATH=src python scripts/run_phase2_metrics.py \
--output-dir artifacts/phase-2
Minimum expected checks:
mapped_controls == total_controlsmissing_controls is emptyscenario_summary_rows == 3dq_validCurrent Phase 2 tests validate:
Current limitations:
weighted_sum_v1).Recommended enhancements:
| ⬅ Back | Next ⮕ |