///|
fn repetition_error(
code : String,
path : String,
message : String,
) -> @ledger.InputError {
@ledger.InputError::Invalid({
code,
path,
message,
report_id: "",
line: 0,
column: 0,
})
}
///|
fn inventory(summary : @ledger.Summary) -> Array[(String, @ledger.CaseKey)] {
let keys = summary.cases.map(item => (item.environment, item.key))
keys.sort()
keys
}
///|
fn repetition_row(
environment : String,
key : @ledger.CaseKey,
samples : Array[RepetitionSample],
) -> RepetitionCase {
let mut pass_attempts = 0
let mut failed_attempts = 0
let mut error_attempts = 0
let mut skipped_attempts = 0
let mut runs_with_pass = 0
let mut runs_with_failure = 0
let mut recovered_runs = 0
let mut incomplete_runs = 0
for sample in samples {
let mut passed = false
let mut failed = false
if sample.case_summary.verdict == @ledger.Verdict::RecoveredOnRetry {
recovered_runs += 1
}
if sample.case_summary.verdict == @ledger.Verdict::Incomplete {
incomplete_runs += 1
}
for attempt in sample.case_summary.attempts {
match attempt.observation.outcome {
Pass => {
pass_attempts += 1
passed = true
}
Failure => {
failed_attempts += 1
failed = true
}
Error => {
error_attempts += 1
failed = true
}
Skip => skipped_attempts += 1
}
}
if passed {
runs_with_pass += 1
}
if failed {
runs_with_failure += 1
}
}
let kind = if pass_attempts > 0 && failed_attempts + error_attempts > 0 {
MixedOutcomes
} else if failed_attempts + error_attempts > 0 {
FailureObserved
} else if pass_attempts > 0 {
PassObserved
} else if skipped_attempts > 0 {
SkipsOnly
} else {
NoObservations
}
{
environment,
key,
kind,
pass_attempts,
failed_attempts,
error_attempts,
skipped_attempts,
runs_with_pass,
runs_with_failure,
recovered_runs,
incomplete_runs,
samples,
}
}
///|
/// Analyze independent runs at the same revision/policy and exact environment/
/// testcase inventory. Shard moves and selective retry counts may differ.
/// Duplicate run IDs are rejected; incomplete evidence stays inconclusive.
pub fn analyze_repetitions(
inputs : ArrayView[@wire.Evidence],
limits~ : @ledger.Limits = @ledger.Limits::default(),
) -> Repetitions raise @ledger.InputError {
limits.validate()
if inputs.length() < 2 {
raise repetition_error(
"RepetitionRunCount", "/inputs", "Supply at least two independent run archives",
)
}
if inputs.length() > limits.max_reports {
raise repetition_error("ReportLimit", "/inputs", "Too many run archives")
}
let revision = inputs[0].summary().revision
let policy = inputs[0].deny_recovered()
let baseline = inventory(inputs[0].summary())
let ids : Set[String] = Set([])
let entries : Array[(@ledger.Summary, @wire.Evidence)] = []
let mut total_units = 0L
let mut reports = 0L
let mut cases = 0L
let mut problems = 0L
for index, input in inputs {
let path = "/inputs/\{index}"
let summary = input.summary()
if ids.contains(summary.run_id) {
raise repetition_error(
"DuplicateRun", path, "Repeated run IDs would inflate observations; provide distinct producer run IDs",
)
}
ids.add(summary.run_id)
if summary.revision != revision {
raise repetition_error(
"RepetitionRevisionMismatch", path, "Use compare for different revisions; repeated-run analysis requires one exact revision",
)
}
if input.deny_recovered() != policy {
raise repetition_error(
"RepetitionPolicyMismatch", path, "Recovery policy must agree across runs",
)
}
if inventory(summary) != baseline {
raise repetition_error(
"RepetitionInventoryMismatch", path, "Exact environment/classname/name inventory must agree; missing artifacts must not shrink the plan",
)
}
// Canonical archive text bounds both raw XML and plan metadata, and
// revalidates each input against the caller's individual resource limits.
total_units += input.encode(limits~).length().to_int64()
if total_units > limits.max_total_source_units.to_int64() {
raise repetition_error(
"SourceLimit", path, "Combined canonical archive text exceeds the total source budget",
)
}
let snapshot = input.snapshot()
reports += snapshot.plan.reports.length().to_int64()
for report in snapshot.plan.reports {
cases += report.cases.length().to_int64()
}
for item in summary.cases {
for attempt in item.attempts {
problems += attempt.observation.problems.length().to_int64()
}
}
if reports > limits.max_reports.to_int64() {
raise repetition_error(
"ReportLimit", path, "Combined expected report count exceeds the budget",
)
}
if cases > limits.max_cases.to_int64() {
raise repetition_error(
"CaseLimit", path, "Combined expected observations exceed the budget",
)
}
if problems > limits.max_problems.to_int64() {
raise repetition_error(
"ProblemLimit", path, "Combined problem payload count exceeds the budget",
)
}
entries.push((summary, input))
}
entries.sort_by((a, b) => a.0.run_id.compare(b.0.run_id))
let grouped : Map[(String, @ledger.CaseKey), Array[RepetitionSample]] = Map([])
for (summary, _) in entries {
for item in summary.cases {
grouped
.get_or_init((item.environment, item.key), () => [])
.push({ run_id: summary.run_id, case_summary: item, })
}
}
let rows = baseline.map(identity => {
let (environment, key) = identity
repetition_row(environment, key, grouped[identity])
})
{
inputs: entries.map(entry => entry.1),
summaries: entries.map(entry => entry.0),
rows,
}
}