Reporting¶
Matplotlib-based visualisation for coherence analysis and phase dynamics.
Requires the plot optional extra:
Purpose in operations¶
This is the production evidence surface for post-run understanding. CoherencePlot
intentionally reads from the same audit records that operators and reviewers already use
for compliance and replay, so every figure can be traced back to immutable records.
Use this API when:
- you need trend evidence for safety gate review (coherence and regime trajectories),
- you need a compact action audit before a change-control meeting,
- or you need explainable outputs from a run that is already fully replayable.
The module is deterministic by construction: identical audit inputs produce identical plot assets and JSON summaries.
CoherencePlot¶
The reporting module provides a single class CoherencePlot that
consumes JSONL audit log data and produces diagnostic figures.
The constructor accepts a list of parsed audit log records (from
ReplayEngine.load() or direct JSON parsing). It filters to step
records containing "step" and "layers" fields.
Available plots¶
| Method | Output | Description |
|---|---|---|
plot_r_timeline(output_path) |
PNG | Per-layer R over simulation steps |
plot_regime_timeline(output_path) |
PNG | Regime epochs as coloured horizontal bands |
plot_action_audit(output_path) |
PNG | R(t) with actuation event markers |
plot_amplitude_timeline(output_path) |
PNG | Mean amplitude and subcritical fraction |
plot_pac_heatmap(output_path) |
PNG | Phase-amplitude coupling matrix |
All methods return Path to the saved figure.
Regime colour conventions¶
| Regime | Colour | Hex |
|---|---|---|
| NOMINAL | Green | #2ecc71 |
| DEGRADED | Orange | #f39c12 |
| CRITICAL | Red | #e74c3c |
| RECOVERY | Blue | #3498db |
Pipeline integration¶
AuditLogger.log_step() ──→ audit.jsonl
│
↓
ReplayEngine.load()
│
↓
CoherencePlot(log_data)
│
┌────────────────┼────────────────┐
↓ ↓ ↓
plot_r_timeline plot_regime_timeline plot_action_audit
│ │ │
↓ ↓ ↓
r_timeline.png regime.png actions.png
The reporting module consumes audit log output. It does not connect to the engine directly — all data passes through the audit trail, ensuring that plots match the auditable record.
When the audit trail contains a run header, spo report --json-out includes
the resolved binding_summary. N-channel runs also expose channel_algebra at
the top level of the JSON report so downstream tools can read channel groups,
derived channels, runtime evidence, and missing required channel evidence
without re-parsing the binding spec.
The text report also prints a compact channel-algebra line when the audit header contains one, including required/optional/derived/delayed/uncertain counts and any missing required channel evidence.
If the audit stream includes passive integrated-information monitor records
with monitor: integrated_information, the JSON summary includes an
integrated_information block with latest Phi proxy values, normalised Phi
values, series data, record count, and the claim boundary. The text report
prints a compact line with the latest Phi proxy, normalised Phi, total
integration, and number of monitor records.
Programmatic tools can use build_audit_report_summary() directly to get the
same JSON-ready report payload as spo report --json-out.
Usage¶
from scpn_phase_orchestrator.runtime.replay import ReplayEngine
from scpn_phase_orchestrator.reporting.plots import CoherencePlot
# Load audit log
replay = ReplayEngine("audit.jsonl")
entries = replay.load()
# Generate diagnostic plots
plotter = CoherencePlot(entries)
plotter.plot_r_timeline("output/r_timeline.png")
plotter.plot_regime_timeline("output/regime.png")
plotter.plot_action_audit("output/actions.png")
plotter.plot_amplitude_timeline("output/amplitude.png")
plotter.plot_pac_heatmap("output/pac.png")
Internal extraction methods¶
| Method | Returns | Description |
|---|---|---|
_extract_r_series |
(steps, n_layers, series) |
Per-layer R arrays |
_extract_regime_epochs |
[(regime, start, end)] |
Regime change boundaries |
_extract_actions |
(steps, r_global, knob_steps) |
Action event indices |
_extract_amplitude |
(steps, amps, sub_frac) |
Amplitude time series |
_extract_pac_matrix |
(n, matrix) |
PAC from last log record |
plots ¶
Optional matplotlib diagnostics for audit logs.
CoherencePlot renders coherence, regime, action, amplitude, and PAC views
from already-recorded audit data. Matplotlib is imported lazily and a
non-interactive backend is selected for production/headless use; malformed or
missing plot inputs raise ValueError rather than emitting partial figures.
Classes¶
CoherencePlot ¶
Audit log visualisation from JSONL step records.
Source code in src/scpn_phase_orchestrator/reporting/plots.py
Methods:¶
plot_r_timeline ¶
Line chart of per-layer R over simulation steps.
Parameters¶
output_path : str | Path Destination path for the artefact.
Returns¶
Path Line chart of per-layer R over simulation steps.
Source code in src/scpn_phase_orchestrator/reporting/plots.py
plot_regime_timeline ¶
Coloured horizontal bands per regime epoch.
Parameters¶
output_path : str | Path Destination path for the artefact.
Returns¶
Path Coloured horizontal bands per regime epoch.
Source code in src/scpn_phase_orchestrator/reporting/plots.py
plot_action_audit ¶
Vertical markers at steps where control actions fired.
Parameters¶
output_path : str | Path Destination path for the artefact.
Returns¶
Path Vertical markers at steps where control actions fired.
Source code in src/scpn_phase_orchestrator/reporting/plots.py
plot_amplitude_timeline ¶
Mean amplitude per step with subcritical threshold line.
Reads 'mean_amplitude' from step records. Falls back to zero if the field is absent (phase-only simulation).
Parameters¶
output_path : str | Path Destination path for the artefact.
Returns¶
Path Mean amplitude per step with subcritical threshold line.
Source code in src/scpn_phase_orchestrator/reporting/plots.py
plot_pac_heatmap ¶
N x N PAC modulation index heatmap.
Reads the last 'pac_matrix' event/record from log data. The matrix should be stored as a flat list with shape (N, N).
Parameters¶
output_path : str | Path Destination path for the artefact.
Returns¶
Path N x N PAC modulation index heatmap.
Source code in src/scpn_phase_orchestrator/reporting/plots.py
Summary Builder¶
summary ¶
Reusable audit report summaries for CLI, notebooks, and tools.
Functions:¶
build_audit_report_summary ¶
build_audit_report_summary(
entries: list[dict[str, object]],
*,
hash_chain_ok: bool,
hash_chain_verified: int,
) -> dict[str, object]
Build a JSON-ready report summary from audit log entries.
Parameters¶
entries : list[dict[str, object]] Audit-log entries. hash_chain_ok : bool Whether the hash chain verified. hash_chain_verified : int Whether the hash chain verified.
Returns¶
dict[str, object] A JSON-ready report summary from audit log entries.
Raises¶
ValueError If the inputs are invalid or inconsistent.
Source code in src/scpn_phase_orchestrator/reporting/summary.py
Explainability¶
Human-readable report helpers that translate audit and supervisor records into plain diagnostic summaries for notebooks, demos, and operator-facing reports.
explainability ¶
Human-readable explanations derived from audit records.
Explainability reports summarise regimes, transitions, layer coherence, stability metrics, action justifications, events, and hash-chain integrity. Inputs are parsed audit entries; missing step records or invalid report parameters fail explicitly instead of producing misleading empty reports.
Classes¶
ActionExplanation
dataclass
¶
ActionExplanation(
step: int,
regime: str,
knob: str,
scope: str,
value: float,
ttl_s: float,
reason: str,
evidence: tuple[str, ...],
)
Human-readable explanation for one control action.
ExplainabilityReport
dataclass
¶
ExplainabilityReport(
steps: int,
layers: int,
hash_chain_ok: bool,
hash_chain_verified: int,
final_regime: str,
final_stability: float,
regime_counts: dict[str, int],
regime_transitions: tuple[str, ...],
action_explanations: tuple[ActionExplanation, ...],
events: tuple[str, ...],
metric_summary: tuple[str, ...],
)
Structured explainability summary derived from an audit JSONL file.
Functions:¶
build_explainability_report ¶
build_explainability_report(
entries: list[dict[str, Any]], *, max_actions: int = 12
) -> ExplainabilityReport
Build a structured explanation from parsed audit records.
Parameters¶
entries : list[dict[str, Any]] Audit-log entries. max_actions : int Maximum number of actions to include.
Returns¶
ExplainabilityReport A structured explanation from parsed audit records.
Raises¶
ValueError If the inputs are invalid or inconsistent.
Source code in src/scpn_phase_orchestrator/reporting/explainability.py
render_markdown ¶
Render a structured report as Markdown.
Parameters¶
report : ExplainabilityReport The report mapping.
Returns¶
str Render a structured report as Markdown.
Source code in src/scpn_phase_orchestrator/reporting/explainability.py
write_markdown ¶
Write Markdown report and return the output path.
Parameters¶
report : ExplainabilityReport The report mapping. output_path : str | Path Destination path for the artefact.
Returns¶
Path Write Markdown report and return the output path.
Source code in src/scpn_phase_orchestrator/reporting/explainability.py
markdown_to_pdf_bytes ¶
Return Markdown text rendered as a deterministic, dependency-free PDF.
The renderer wraps the text to the page width (upper-casing heading lines) and emits a minimal single-font PDF. It contains no timestamp or other non-deterministic field, so the bytes are reproducible for a given input.
Parameters¶
markdown : str The Markdown (or plain text) document to render.
Returns¶
bytes The rendered text PDF.
Source code in src/scpn_phase_orchestrator/reporting/explainability.py
write_pdf ¶
Write a dependency-free text PDF report and return the output path.
Parameters¶
report : ExplainabilityReport The report mapping. output_path : str | Path Destination path for the artefact.
Returns¶
Path Write a dependency-free text PDF report and return the output path.
Source code in src/scpn_phase_orchestrator/reporting/explainability.py
Operator copilot¶
reporting.operator_copilot turns an ExplainabilityReport into a grounded
question-answering surface for a control-room operator. It renders the audit
evidence — regime distribution, transitions, every control action with its
recorded reason and evidence, the metric summary — into the prompt and instructs
the language model to answer only from that evidence and to decline when it is
silent, so the model explains and locates what the audit records rather than
inventing control history or recommending actuation. The model is any provider
with a complete(prompt) -> str method (a local HTTP model, or a deterministic
stub for tests), so no network backend is required and the prompt is fully
testable.
operator_copilot ¶
A grounded LLM copilot that answers operator questions from audit evidence.
The copilot turns a hash-verified :class:~scpn_phase_orchestrator.reporting.
explainability.ExplainabilityReport into a question-answering surface for a
control-room operator. It does not let the language model speak freely: it
renders the report — regime distribution, transitions, every control action with
its recorded reason and evidence, the metric summary — into the prompt, and
instructs the model to answer only from that evidence and to decline when the
evidence is silent. The model therefore explains and locates what the audit
already records; it does not invent control history or recommend actuation.
The language model is any provider with a complete(prompt) -> str method
(:class:OperatorLLM) — a local HTTP model, or a deterministic stub for tests —
so no network backend is required and the prompt construction is fully testable.
Classes¶
OperatorLLM ¶
Bases: Protocol
A language-model backend that completes a prompt to an answer.
OperatorCopilot
dataclass
¶
A grounded operator copilot over one explainability report.
Parameters¶
llm : OperatorLLM The language-model backend. report : ExplainabilityReport The hash-verified audit evidence the answers are grounded in. max_actions : int The most control actions to include in the grounding context.
Methods:¶
answer ¶
Answer an operator question grounded in the audit evidence.
Parameters¶
question : str The operator's question.
Returns¶
str The grounded model answer.
Raises¶
ValueError
If question is empty.
Source code in src/scpn_phase_orchestrator/reporting/operator_copilot.py
build_prompt ¶
Render the grounded prompt for an operator question.
Parameters¶
question : str The operator's question.
Returns¶
str The prompt: the grounding instruction, the rendered evidence, and the question.