65 lines
2.3 KiB
TypeScript
65 lines
2.3 KiB
TypeScript
import type { Evidence } from "../domain/evidence.js";
|
|
import type { ReconstructionObligation } from "../domain/reconstructionObligationLedgerSchemas.js";
|
|
import { evidenceSupportsOriginalAuthority } from "./ReconstructionObligationAuthority.js";
|
|
import type { ReconstructionObligationCandidate } from "./ReconstructionObligationCandidates.js";
|
|
|
|
type Binding = NonNullable<ReconstructionObligation["binding"]>;
|
|
type Diagnostic = ReconstructionObligation["diagnostics"][number];
|
|
|
|
/** Merge generated and manifest-supplied original observations canonically. */
|
|
export const originalCasesFor = (
|
|
candidate: ReconstructionObligationCandidate,
|
|
binding: Binding | null,
|
|
): ReconstructionObligation["observed_cases"] =>
|
|
[
|
|
...new Map(
|
|
[...candidate.observed_cases, ...(binding?.original_cases ?? [])].map(
|
|
(observed) => [
|
|
`${observed.kind}:${observed.evidence_id}:${observed.location}`,
|
|
observed,
|
|
],
|
|
),
|
|
).values(),
|
|
].sort((left, right) =>
|
|
`${left.kind}:${left.evidence_id}:${left.location}`.localeCompare(
|
|
`${right.kind}:${right.evidence_id}:${right.location}`,
|
|
),
|
|
);
|
|
|
|
/** Report original cases that are absent or lack comparable Evidence authority. */
|
|
export const originalCaseDiagnostics = (
|
|
candidate: ReconstructionObligationCandidate,
|
|
binding: Binding | null,
|
|
evidenceById: ReadonlyMap<string, Evidence>,
|
|
): Diagnostic[] => {
|
|
const diagnostics: Diagnostic[] = [];
|
|
const originalCases = originalCasesFor(candidate, binding);
|
|
for (const caseKind of candidate.required_case_kinds) {
|
|
const cases = originalCases.filter(({ kind }) => kind === caseKind);
|
|
if (cases.length === 0) {
|
|
diagnostics.push({
|
|
code: "missing-original-case",
|
|
detail: `Original ${caseKind} behavior has not been observed.`,
|
|
});
|
|
continue;
|
|
}
|
|
if (
|
|
!cases.some(({ evidence_id: evidenceId }) => {
|
|
const evidence = evidenceById.get(evidenceId);
|
|
return (
|
|
evidence !== undefined &&
|
|
evidenceSupportsOriginalAuthority(
|
|
evidence,
|
|
candidate.required_original_authority,
|
|
)
|
|
);
|
|
})
|
|
)
|
|
diagnostics.push({
|
|
code: "weak-original-case-authority",
|
|
detail: `Original ${caseKind} behavior lacks ${candidate.required_original_authority} Evidence.`,
|
|
});
|
|
}
|
|
return diagnostics;
|
|
};
|