///|
/// Escape text for XML/HTML content and quoted attributes.
fn evidence_escape(text : String) -> String {
text
.replace(old="&", new="&")
.replace(old="<", new="<")
.replace(old=">", new=">")
.replace(old="\"", new=""")
.replace(old="'", new="'")
}
///|
/// Self-contained viewer. Target data lives in escaped inert text, never in a
/// script literal or innerHTML. No network, CDN, tracking, or active target IO.
pub fn evidence_html(report : Json) -> String {
let page =
#|
#|
#|
#|MoonStateLens · Evidence Observatory
#|MODEL INFERENCE / FRESH REPLAY / AUDITABLE EVIDENCE
MoonStateLens Observatory
#|
Model predictions and actual observations have different scopes. An incomplete run is never an unconditional pass. Coverage refers to the learned model. Differing contexts are not independent bug counts.
#|
Inspect evidence
Case / context
Status
Inputs
Evidence
#|
Trace explorer
Select a row to inspect predicted and actual outputs step by step.
#|
Model transitions
#|Full evidence JSON and reproducible configuration
#|
#|
let tail =
#|
page + evidence_escape(report.stringify(indent=2)) + tail
}
///|
/// CI consumes one testcase per original assertion plus an explicit failure
/// when evidence is incomplete. Unknown formats are rejected.
pub fn regression_junit(report : Json) -> String raise LensError {
guard report
is {
"format": "moonstatelens.regression-run",
"cases": Array(cases),
"execution_complete": complete,
"suite_evidence": { "generation_complete": generated, .. },
..
} else {
raise InvalidArgument("expected regression-run report")
}
let lines = []
let mut failures = 0
let mut skipped = 0
for entry in cases {
guard entry is { "case": id, "status": String(status), .. } else {
raise InvalidArgument("invalid regression testcase")
}
lines.push(
"",
)
match status {
"passed" => ()
"failed" => {
failures += 1
lines.push(
"" +
evidence_escape(entry.stringify()) +
"",
)
}
"not-run" => {
skipped += 1
lines.push("")
}
_ => raise InvalidArgument("unknown regression testcase status")
}
lines.push("")
}
let incomplete = complete != Json(true) || generated != Json(true)
if incomplete {
failures += 1
lines.push(
"",
)
}
let total = cases.length() + (if incomplete { 1 } else { 0 })
"\n\n" +
lines.join("\n") +
"\n\n"
}