refactor(qa-lab): use native strict object schemas

This commit is contained in:
Peter Steinberger
2026-07-14 19:07:33 +01:00
parent f20324cd3e
commit 045090c2ce
2 changed files with 182 additions and 246 deletions
+123 -165
View File
@@ -19,192 +19,151 @@ const qaEvidenceStatusSchema = z.enum(["pass", "fail", "blocked", "skipped"]);
const nonEmptyStringSchema = z.string().trim().min(1);
const nullableStringSchema = nonEmptyStringSchema.nullable();
const qaEvidenceProfileIdSchema = nonEmptyStringSchema;
const qaEvidenceIdSchema = z.object({ id: nonEmptyStringSchema });
const qaEvidenceIdSchema = z.strictObject({ id: nonEmptyStringSchema });
const qaEvidenceProviderSchema = z
.object({
id: nonEmptyStringSchema,
live: z.boolean(),
model: z
.object({
name: nullableStringSchema,
ref: nullableStringSchema,
})
.strict(),
fixture: nonEmptyStringSchema.optional(),
auth: nonEmptyStringSchema.optional(),
})
.strict();
const qaEvidenceChannelSchema = z
.object({
id: nonEmptyStringSchema,
live: z.boolean(),
driver: nonEmptyStringSchema.optional(),
})
.strict();
const qaEvidenceEnvironmentSchema = z
.object({
const qaEvidenceProviderSchema = z.strictObject({
id: nonEmptyStringSchema,
live: z.boolean(),
model: z.strictObject({
name: nullableStringSchema,
ref: nullableStringSchema,
os: nonEmptyStringSchema,
nodeVersion: nonEmptyStringSchema,
})
.strict();
}),
fixture: nonEmptyStringSchema.optional(),
auth: nonEmptyStringSchema.optional(),
});
const qaEvidencePackageSourceSchema = z
.object({
kind: nonEmptyStringSchema,
spec: nonEmptyStringSchema.optional(),
sha: nonEmptyStringSchema.optional(),
})
.strict();
const qaEvidenceChannelSchema = z.strictObject({
id: nonEmptyStringSchema,
live: z.boolean(),
driver: nonEmptyStringSchema.optional(),
});
const qaEvidenceFailureSchema = z
.object({
class: nonEmptyStringSchema.optional(),
reason: nonEmptyStringSchema,
})
.strict();
const qaEvidenceEnvironmentSchema = z.strictObject({
ref: nullableStringSchema,
os: nonEmptyStringSchema,
nodeVersion: nonEmptyStringSchema,
});
const qaEvidenceTimingSchema = z
.object({
wallMs: z.number().finite().positive().optional(),
rttMs: z.number().finite().positive().optional(),
avgMs: z.number().finite().positive().optional(),
p50Ms: z.number().finite().positive().optional(),
p95Ms: z.number().finite().positive().optional(),
maxMs: z.number().finite().positive().optional(),
samples: z.number().int().positive().optional(),
failedSamples: z.number().int().nonnegative().optional(),
})
.strict();
const qaEvidencePackageSourceSchema = z.strictObject({
kind: nonEmptyStringSchema,
spec: nonEmptyStringSchema.optional(),
sha: nonEmptyStringSchema.optional(),
});
const qaEvidenceTestSchema = z
.object({
kind: nonEmptyStringSchema,
id: nonEmptyStringSchema,
title: nonEmptyStringSchema,
source: z
.object({
path: nonEmptyStringSchema,
})
.strict()
.optional(),
})
.strict();
const qaEvidenceFailureSchema = z.strictObject({
class: nonEmptyStringSchema.optional(),
reason: nonEmptyStringSchema,
});
const qaEvidenceRefSchema = z
.object({
kind: nonEmptyStringSchema,
path: nonEmptyStringSchema,
})
.strict();
const qaEvidenceTimingSchema = z.strictObject({
wallMs: z.number().finite().positive().optional(),
rttMs: z.number().finite().positive().optional(),
avgMs: z.number().finite().positive().optional(),
p50Ms: z.number().finite().positive().optional(),
p95Ms: z.number().finite().positive().optional(),
maxMs: z.number().finite().positive().optional(),
samples: z.number().int().positive().optional(),
failedSamples: z.number().int().nonnegative().optional(),
});
const qaEvidenceCoverageSchema = qaEvidenceIdSchema
.extend({
role: nonEmptyStringSchema,
})
.strict();
const qaEvidenceTestSchema = z.strictObject({
kind: nonEmptyStringSchema,
id: nonEmptyStringSchema,
title: nonEmptyStringSchema,
source: z
.strictObject({
path: nonEmptyStringSchema,
})
.optional(),
});
const qaEvidenceScorecardCountSchema = z
.object({
total: z.number().int().nonnegative(),
fulfilled: z.number().int().nonnegative(),
partial: z.number().int().nonnegative().optional(),
missing: z.number().int().nonnegative(),
fulfillmentPercent: z.number().finite().nonnegative(),
})
.strict();
const qaEvidenceRefSchema = z.strictObject({
kind: nonEmptyStringSchema,
path: nonEmptyStringSchema,
});
const qaEvidenceCoverageSchema = qaEvidenceIdSchema.extend({
role: nonEmptyStringSchema,
});
const qaEvidenceScorecardCountSchema = z.strictObject({
total: z.number().int().nonnegative(),
fulfilled: z.number().int().nonnegative(),
partial: z.number().int().nonnegative().optional(),
missing: z.number().int().nonnegative(),
fulfillmentPercent: z.number().finite().nonnegative(),
});
const qaEvidenceScorecardCoverageCountSchema = qaEvidenceScorecardCountSchema.extend({
secondaryOnly: z.number().int().nonnegative(),
});
const qaEvidenceScorecardCategorySchema = z
.object({
id: nonEmptyStringSchema,
surfaceId: nonEmptyStringSchema,
name: nonEmptyStringSchema,
status: z.enum(["fulfilled", "partial", "missing"]),
features: qaEvidenceScorecardCountSchema,
coverageIds: qaEvidenceScorecardCoverageCountSchema,
missingCoverageIds: z.array(nonEmptyStringSchema),
})
.strict();
const qaEvidenceScorecardCategorySchema = z.strictObject({
id: nonEmptyStringSchema,
surfaceId: nonEmptyStringSchema,
name: nonEmptyStringSchema,
status: z.enum(["fulfilled", "partial", "missing"]),
features: qaEvidenceScorecardCountSchema,
coverageIds: qaEvidenceScorecardCoverageCountSchema,
missingCoverageIds: z.array(nonEmptyStringSchema),
});
const qaEvidenceScorecardSchema = z
.object({
filters: z
.object({
surface: nullableStringSchema,
category: nullableStringSchema,
})
.strict(),
run: z
.object({
evidenceEntryCount: z.number().int().nonnegative(),
})
.strict(),
categories: qaEvidenceScorecardCountSchema,
features: qaEvidenceScorecardCountSchema,
coverageIds: qaEvidenceScorecardCountSchema,
categoryReports: z.array(qaEvidenceScorecardCategorySchema),
})
.strict();
const qaEvidenceScorecardSchema = z.strictObject({
filters: z.strictObject({
surface: nullableStringSchema,
category: nullableStringSchema,
}),
run: z.strictObject({
evidenceEntryCount: z.number().int().nonnegative(),
}),
categories: qaEvidenceScorecardCountSchema,
features: qaEvidenceScorecardCountSchema,
coverageIds: qaEvidenceScorecardCountSchema,
categoryReports: z.array(qaEvidenceScorecardCategorySchema),
});
const qaEvidenceArtifactSchema = z
.object({
kind: nonEmptyStringSchema,
path: nonEmptyStringSchema,
source: nonEmptyStringSchema,
})
.strict();
const qaEvidenceArtifactSchema = z.strictObject({
kind: nonEmptyStringSchema,
path: nonEmptyStringSchema,
source: nonEmptyStringSchema,
});
const qaEvidenceExecutionSchema = z
.object({
runner: nonEmptyStringSchema,
environment: qaEvidenceEnvironmentSchema,
provider: qaEvidenceProviderSchema,
channel: qaEvidenceChannelSchema.optional(),
packageSource: qaEvidencePackageSourceSchema,
artifacts: z.array(qaEvidenceArtifactSchema),
})
.strict();
const qaEvidenceExecutionSchema = z.strictObject({
runner: nonEmptyStringSchema,
environment: qaEvidenceEnvironmentSchema,
provider: qaEvidenceProviderSchema,
channel: qaEvidenceChannelSchema.optional(),
packageSource: qaEvidencePackageSourceSchema,
artifacts: z.array(qaEvidenceArtifactSchema),
});
const qaEvidenceResultSchema = z
.object({
status: qaEvidenceStatusSchema,
failure: qaEvidenceFailureSchema.optional(),
timing: qaEvidenceTimingSchema.optional(),
})
.strict();
const qaEvidenceResultSchema = z.strictObject({
status: qaEvidenceStatusSchema,
failure: qaEvidenceFailureSchema.optional(),
timing: qaEvidenceTimingSchema.optional(),
});
const qaEvidencePostureSchema = z.enum(["direct-gateway", "native-approval", "user-path"]);
const qaEvidenceSummaryEntrySchema = z
.object({
test: qaEvidenceTestSchema,
coverage: z.array(qaEvidenceCoverageSchema),
posture: qaEvidencePostureSchema.optional(),
refs: z.array(qaEvidenceRefSchema).optional(),
runtimeParityTier: nonEmptyStringSchema.optional(),
execution: qaEvidenceExecutionSchema.optional(),
result: qaEvidenceResultSchema,
})
.strict();
const qaEvidenceSummaryEntrySchema = z.strictObject({
test: qaEvidenceTestSchema,
coverage: z.array(qaEvidenceCoverageSchema),
posture: qaEvidencePostureSchema.optional(),
refs: z.array(qaEvidenceRefSchema).optional(),
runtimeParityTier: nonEmptyStringSchema.optional(),
execution: qaEvidenceExecutionSchema.optional(),
result: qaEvidenceResultSchema,
});
const qaEvidenceSummarySchema = z
.object({
kind: z.literal(QA_EVIDENCE_SUMMARY_KIND),
schemaVersion: z.literal(QA_EVIDENCE_SUMMARY_SCHEMA_VERSION),
generatedAt: nonEmptyStringSchema,
evidenceMode: qaScorecardEvidenceModeSchema,
entries: z.array(qaEvidenceSummaryEntrySchema),
profile: qaEvidenceProfileIdSchema.optional(),
scorecard: qaEvidenceScorecardSchema.optional(),
})
.strict();
const qaEvidenceSummarySchema = z.strictObject({
kind: z.literal(QA_EVIDENCE_SUMMARY_KIND),
schemaVersion: z.literal(QA_EVIDENCE_SUMMARY_SCHEMA_VERSION),
generatedAt: nonEmptyStringSchema,
evidenceMode: qaScorecardEvidenceModeSchema,
entries: z.array(qaEvidenceSummaryEntrySchema),
profile: qaEvidenceProfileIdSchema.optional(),
scorecard: qaEvidenceScorecardSchema.optional(),
});
type QaEvidenceProfile = z.infer<typeof qaEvidenceProfileIdSchema>;
export type QaEvidenceStatus = z.infer<typeof qaEvidenceStatusSchema>;
@@ -800,4 +759,3 @@ export function buildLiveTransportEvidenceSummary(
profile,
});
}
/* oxlint-disable max-lines -- TODO: split this grandfathered oversized file. */
+59 -81
View File
@@ -59,11 +59,10 @@ function maturityScoreLabelForScore(score: number) {
}
const qaMaturityScoreObjectSchema = z
.object({
.strictObject({
score: z.number().int().min(0).max(100),
label: z.enum(QA_MATURITY_SCORE_LABELS),
})
.strict()
.superRefine((value, ctx) => {
const expectedLabel = maturityScoreLabelForScore(value.score);
if (value.label !== expectedLabel) {
@@ -91,89 +90,69 @@ const qaMaturityLegacyCoverageShape = {
coverage: qaMaturityScoreObjectSchema.optional(),
} satisfies z.ZodRawShape;
const qaMaturityScoreBundleSchema = z
.object({
...qaMaturityLegacyCoverageShape,
...qaMaturityScoreBundleShape,
})
.strict();
const qaMaturityScoreBundleSchema = z.strictObject({
...qaMaturityLegacyCoverageShape,
...qaMaturityScoreBundleShape,
});
const qaMaturityScoreLastRunSchema = z
.object({
status: z.string().trim().min(1).optional(),
completed_at: z.string().trim().min(1).optional(),
by: z.string().trim().min(1).optional(),
source_ref: z.string().trim().min(1).nullable().optional(),
process_version: z.number().int().positive().optional(),
})
.strict();
const qaMaturityScoreLastRunSchema = z.strictObject({
status: z.string().trim().min(1).optional(),
completed_at: z.string().trim().min(1).optional(),
by: z.string().trim().min(1).optional(),
source_ref: z.string().trim().min(1).nullable().optional(),
process_version: z.number().int().positive().optional(),
});
const qaMaturityScoreCategoryLtsSchema = z
.object({
supported: z.boolean(),
reason: z.string().trim().min(1).optional(),
human_override: z.boolean(),
})
.strict();
const qaMaturityScoreCategoryLtsSchema = z.strictObject({
supported: z.boolean(),
reason: z.string().trim().min(1).optional(),
human_override: z.boolean(),
});
const qaMaturityScoreSurfaceLtsSchema = z
.object({
supported_categories: z.number().int().nonnegative(),
total_categories: z.number().int().nonnegative(),
status: z.string().trim().min(1),
})
.strict();
const qaMaturityScoreSurfaceLtsSchema = z.strictObject({
supported_categories: z.number().int().nonnegative(),
total_categories: z.number().int().nonnegative(),
status: z.string().trim().min(1),
});
const qaMaturityScoreCategorySchema = z
.object({
name: z.string().trim().min(1),
...qaMaturityLegacyCoverageShape,
...qaMaturityScoreBundleShape,
lts: qaMaturityScoreCategoryLtsSchema,
})
.strict();
const qaMaturityScoreCategorySchema = z.strictObject({
name: z.string().trim().min(1),
...qaMaturityLegacyCoverageShape,
...qaMaturityScoreBundleShape,
lts: qaMaturityScoreCategoryLtsSchema,
});
const qaMaturityScoreSurfaceSchema = z
.object({
id: qaScorecardIdSchema,
name: z.string().trim().min(1),
family: z.string().trim().min(1).optional(),
level: z.union([
z.string().trim().min(1),
z
.object({
id: z.string().trim().min(1).optional(),
code: z.string().trim().min(1).optional(),
label: z.string().trim().min(1).optional(),
})
.strict(),
]),
scores: qaMaturityScoreBundleSchema,
categories: z.array(qaMaturityScoreCategorySchema),
lts: qaMaturityScoreSurfaceLtsSchema,
last_score_run: qaMaturityScoreLastRunSchema.optional(),
})
.strict();
const qaMaturityScoreSurfaceSchema = z.strictObject({
id: qaScorecardIdSchema,
name: z.string().trim().min(1),
family: z.string().trim().min(1).optional(),
level: z.union([
z.string().trim().min(1),
z.strictObject({
id: z.string().trim().min(1).optional(),
code: z.string().trim().min(1).optional(),
label: z.string().trim().min(1).optional(),
}),
]),
scores: qaMaturityScoreBundleSchema,
categories: z.array(qaMaturityScoreCategorySchema),
lts: qaMaturityScoreSurfaceLtsSchema,
last_score_run: qaMaturityScoreLastRunSchema.optional(),
});
const qaMaturityScoresSchema = z
.object({
version: z.literal(1),
process_version: z.number().int().positive(),
counts: z
.object({
active_surfaces: z.number().int().nonnegative(),
category_scores: z.number().int().nonnegative(),
})
.strict(),
rollups: z
.object({
surface_average: qaMaturityScoreBundleSchema,
category_average: qaMaturityScoreBundleSchema,
})
.strict(),
surfaces: z.array(qaMaturityScoreSurfaceSchema),
})
.strict();
const qaMaturityScoresSchema = z.strictObject({
version: z.literal(1),
process_version: z.number().int().positive(),
counts: z.strictObject({
active_surfaces: z.number().int().nonnegative(),
category_scores: z.number().int().nonnegative(),
}),
rollups: z.strictObject({
surface_average: qaMaturityScoreBundleSchema,
category_average: qaMaturityScoreBundleSchema,
}),
surfaces: z.array(qaMaturityScoreSurfaceSchema),
});
const qaMaturityFeatureSchema = z.object({
name: z.string().trim().min(1),
@@ -219,11 +198,10 @@ const qaMaturityTaxonomySchema = z
title: z.string().trim().min(1),
summary: z.string().trim().min(1).optional(),
snapshot: z
.object({
.strictObject({
date: z.string().trim().min(1).optional(),
source_ref: z.string().trim().min(1).optional(),
})
.strict()
.optional(),
profiles: z.array(qaScorecardProfileSchema).default([]),
levels: z.array(qaMaturityLevelSchema).default([]),