mirror of
https://github.com/morluto/rea.git
synced 2026-10-26 17:35:11 +00:00
refactor(readiness): share canonical stage validation
This commit is contained in:
1 parent
d8948efb81
commit
adfde012ec
5 files changed
+55
-46
No files matched your search
@@ -1,15 +1,15 @@
|
||||
import { createEvidence } from "../domain/evidence.js";
|
||||
import { createEvidenceBundle } from "../domain/evidenceBundle.js";
|
||||
import {
|
||||
READINESS_REQUIRED_CHECKS,
|
||||
READINESS_STAGE_IDS,
|
||||
} from "../domain/reconstructionReadinessJourneyFindings.js";
|
||||
import { READINESS_REQUIRED_CHECKS } from "../domain/reconstructionReadinessJourneyFindings.js";
|
||||
import {
|
||||
reconstructionObligationLedgerClosureDigest,
|
||||
summarizeReconstructionObligations,
|
||||
} from "../domain/reconstructionObligationLedgerIntegrity.js";
|
||||
import type { ReconstructionObligationLedger } from "../domain/reconstructionObligationLedgerSchemas.js";
|
||||
import type { ReconstructionReadinessInput } from "../domain/reconstructionReadinessSchemas.js";
|
||||
import {
|
||||
readinessStageIdSchema,
|
||||
type ReconstructionReadinessInput,
|
||||
} from "../domain/reconstructionReadinessSchemas.js";
|
||||
|
||||
const HASH = "a".repeat(64);
|
||||
const sourceEvidence = (variant: string) =>
|
||||
@@ -397,7 +397,7 @@ export const RECONSTRUCTION_READINESS_EXAMPLE: ReconstructionReadinessInput = {
|
||||
stale_input_detected: true,
|
||||
evidence_ids: [EVIDENCE_ID],
|
||||
},
|
||||
stages: READINESS_STAGE_IDS.map((stageId) => ({
|
||||
stages: readinessStageIdSchema.options.map((stageId) => ({
|
||||
stage_id: stageId,
|
||||
required: true,
|
||||
status: "pass",
|
||||
|
||||
@@ -9,6 +9,7 @@ import {
|
||||
} from "./reconstructionObligationLedgerIntegrity.js";
|
||||
import { reconstructionObligationLedgerSchema } from "./reconstructionObligationLedgerSchemas.js";
|
||||
import {
|
||||
reconstructionReadinessReportSchema,
|
||||
reconstructionReadinessInputSchema,
|
||||
type ReconstructionReadinessInput,
|
||||
} from "./reconstructionReadinessSchemas.js";
|
||||
@@ -181,6 +182,31 @@ describe("readiness obligation ledger integrity", () => {
|
||||
);
|
||||
});
|
||||
|
||||
describe("readiness stage identity", () => {
|
||||
it.each(["input", "report"] as const)(
|
||||
"rejects repeated stage IDs in the %s contract",
|
||||
(kind) => {
|
||||
const value =
|
||||
kind === "input"
|
||||
? input()
|
||||
: createReconstructionReadinessReport(input());
|
||||
value.stages[1] = { ...value.stages[0]! };
|
||||
const schema =
|
||||
kind === "input"
|
||||
? reconstructionReadinessInputSchema
|
||||
: reconstructionReadinessReportSchema;
|
||||
const parsed = schema.safeParse(value);
|
||||
expect(parsed.success).toBe(false);
|
||||
if (parsed.success) throw new Error("Duplicate stage ID was accepted");
|
||||
expect(parsed.error.issues).toContainEqual({
|
||||
code: "custom",
|
||||
path: ["stages", 1, "stage_id"],
|
||||
message: "Readiness stage IDs must be unique",
|
||||
});
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
describe("readiness missing Evidence references", () => {
|
||||
it("reports each absent Evidence ID once per stage across stage and check references", () => {
|
||||
const value = input();
|
||||
|
||||
@@ -1,12 +1,10 @@
|
||||
import { digestCanonicalValue } from "./canonicalDigest.js";
|
||||
import { authenticateParsedEvidenceBundle } from "./evidenceBundle.js";
|
||||
import { readinessFindingOrder } from "./reconstructionReadinessFindingHelpers.js";
|
||||
import {
|
||||
READINESS_STAGE_IDS,
|
||||
readinessJourneyFindings,
|
||||
} from "./reconstructionReadinessJourneyFindings.js";
|
||||
import { readinessJourneyFindings } from "./reconstructionReadinessJourneyFindings.js";
|
||||
import { readinessIntegrityFindings } from "./reconstructionReadinessIntegrityFindings.js";
|
||||
import {
|
||||
readinessStageIdSchema,
|
||||
reconstructionReadinessInputSchema,
|
||||
reconstructionReadinessReportSchema,
|
||||
type ReadinessFinding,
|
||||
@@ -71,7 +69,7 @@ const effectiveStages = (
|
||||
input: ReconstructionReadinessInput,
|
||||
findings: readonly ReadinessFinding[],
|
||||
): ReconstructionReadinessReport["stages"] =>
|
||||
READINESS_STAGE_IDS.map((stageId) => {
|
||||
readinessStageIdSchema.options.map((stageId) => {
|
||||
const stage = input.stages.find(({ stage_id: id }) => id === stageId);
|
||||
const stageFindings = findings.filter(({ stage_id: id }) => id === stageId);
|
||||
const status = stageFindings.some(
|
||||
|
||||
@@ -64,8 +64,6 @@ export const READINESS_REQUIRED_CHECKS: Readonly<
|
||||
],
|
||||
};
|
||||
|
||||
export const READINESS_STAGE_IDS = readinessStageIdSchema.options;
|
||||
|
||||
export const readinessJourneyFindings = (
|
||||
input: ReconstructionReadinessInput,
|
||||
evidenceIds: ReadonlySet<string>,
|
||||
@@ -142,7 +140,7 @@ const stageFindings = (
|
||||
evidenceIds: ReadonlySet<string>,
|
||||
): ReadinessFinding[] => {
|
||||
const findings: ReadinessFinding[] = [];
|
||||
for (const stageId of READINESS_STAGE_IDS) {
|
||||
for (const stageId of readinessStageIdSchema.options) {
|
||||
const matching = input.stages.filter(({ stage_id: id }) => id === stageId);
|
||||
if (matching.length !== 1) {
|
||||
findings.push(
|
||||
|
||||
@@ -4,8 +4,7 @@ import { STABLE_IDENTIFIER_PATTERN } from "./stringPatterns.js";
|
||||
|
||||
import { evidenceBundleSchema } from "./evidenceBundle.js";
|
||||
import { reconstructionObligationLedgerSchema } from "./reconstructionObligationLedgerSchemas.js";
|
||||
import { digestSchema } from "./../domain/digests.js";
|
||||
import { prefixedDigestSchema } from "./../domain/digests.js";
|
||||
import { digestSchema, prefixedDigestSchema } from "./digests.js";
|
||||
|
||||
const evidenceIdSchema = prefixedDigestSchema("ev");
|
||||
const stableIdSchema = z.string().regex(STABLE_IDENTIFIER_PATTERN);
|
||||
@@ -185,6 +184,22 @@ const stageSchema = z.strictObject({
|
||||
checks: z.array(stageCheckSchema),
|
||||
});
|
||||
|
||||
const readinessStagesSchema = z
|
||||
.array(stageSchema)
|
||||
.length(readinessStageIdSchema.options.length)
|
||||
.superRefine((stages, context) => {
|
||||
const seen = new Set<string>();
|
||||
stages.forEach((stage, index) => {
|
||||
if (seen.has(stage.stage_id))
|
||||
context.addIssue({
|
||||
code: "custom",
|
||||
path: [index, "stage_id"],
|
||||
message: "Readiness stage IDs must be unique",
|
||||
});
|
||||
seen.add(stage.stage_id);
|
||||
});
|
||||
});
|
||||
|
||||
const replaySchema = z.strictObject({
|
||||
expected_source_digest: digestSchema.nullable(),
|
||||
deterministic: z.boolean(),
|
||||
@@ -220,21 +235,7 @@ export const reconstructionReadinessInputSchema = z.strictObject({
|
||||
closure_history: z.array(closureObservationSchema).min(2),
|
||||
delegation_checks: z.array(delegationCheckSchema).min(1),
|
||||
replay: replaySchema,
|
||||
stages: z
|
||||
.array(stageSchema)
|
||||
.length(9)
|
||||
.superRefine((stages, context) => {
|
||||
const seen = new Set<string>();
|
||||
stages.forEach((stage, index) => {
|
||||
if (seen.has(stage.stage_id))
|
||||
context.addIssue({
|
||||
code: "custom",
|
||||
path: [index, "stage_id"],
|
||||
message: "Readiness stage IDs must be unique",
|
||||
});
|
||||
seen.add(stage.stage_id);
|
||||
});
|
||||
}),
|
||||
stages: readinessStagesSchema,
|
||||
});
|
||||
|
||||
const findingSchema = z.strictObject({
|
||||
@@ -271,21 +272,7 @@ export const reconstructionReadinessReportSchema = z.strictObject({
|
||||
cleanup_leak_count: z.number().int().min(0),
|
||||
nondeterministic_replay_count: z.number().int().min(0),
|
||||
}),
|
||||
stages: z
|
||||
.array(stageSchema)
|
||||
.length(9)
|
||||
.superRefine((stages, context) => {
|
||||
const seen = new Set<string>();
|
||||
stages.forEach((stage, index) => {
|
||||
if (seen.has(stage.stage_id))
|
||||
context.addIssue({
|
||||
code: "custom",
|
||||
path: [index, "stage_id"],
|
||||
message: "Readiness stage IDs must be unique",
|
||||
});
|
||||
seen.add(stage.stage_id);
|
||||
});
|
||||
}),
|
||||
stages: readinessStagesSchema,
|
||||
findings: z.array(findingSchema),
|
||||
evidence_links: z.array(evidenceIdSchema),
|
||||
snapshot: reconstructionReadinessInputSchema,
|
||||
|
||||
Reference in new issue
Block a user