

















@@ -2,7 +2,7 @@ import {
22buildLiveTransportCoverageLaneSummaries,
33type LiveTransportCoverageLaneSummary,
44} from "./live-transports/shared/live-transport-scenarios.js";
5-import type { QaSeedScenarioWithSource } from "./scenario-catalog.js";
5+import { QA_SCENARIO_PACKS, type QaSeedScenarioWithSource } from "./scenario-catalog.js";
6677type QaCoverageScenarioSummary = {
88id: string;
@@ -24,6 +24,14 @@ type QaCoverageFeatureSummary = {
2424scenarios: QaCoverageScenarioReference[];
2525};
262627+type QaCoverageScenarioPackSummary = {
28+id: string;
29+title: string;
30+scenarioIds: string[];
31+coverageIds: string[];
32+missingScenarioIds: string[];
33+};
34+2735type QaCoverageInventory = {
2836scenarioCount: number;
2937coverageIdCount: number;
@@ -34,6 +42,7 @@ type QaCoverageInventory = {
3442missingCoverage: QaCoverageScenarioSummary[];
3543byTheme: Record<string, QaCoverageFeatureSummary[]>;
3644bySurface: Record<string, QaCoverageFeatureSummary[]>;
45+scenarioPacks: QaCoverageScenarioPackSummary[];
3746liveTransportLanes: LiveTransportCoverageLaneSummary[];
3847};
3948@@ -65,6 +74,36 @@ function sortFeatures(features: readonly QaCoverageFeatureSummary[]) {
6574return features.toSorted((left, right) => left.id.localeCompare(right.id));
6675}
677677+function buildScenarioPackSummaries(
78+scenarios: readonly QaSeedScenarioWithSource[],
79+): QaCoverageScenarioPackSummary[] {
80+const scenariosById = new Map(scenarios.map((scenario) => [scenario.id, scenario]));
81+return QA_SCENARIO_PACKS.map((pack) => {
82+const coverageIds = new Set<string>();
83+const missingScenarioIds: string[] = [];
84+for (const scenarioId of pack.scenarioIds) {
85+const scenario = scenariosById.get(scenarioId);
86+if (!scenario) {
87+missingScenarioIds.push(scenarioId);
88+continue;
89+}
90+for (const coverageId of [
91+ ...(scenario.coverage?.primary ?? []),
92+ ...(scenario.coverage?.secondary ?? []),
93+]) {
94+coverageIds.add(coverageId);
95+}
96+}
97+return {
98+id: pack.id,
99+title: pack.title,
100+scenarioIds: [...pack.scenarioIds],
101+coverageIds: [...coverageIds].toSorted(),
102+ missingScenarioIds,
103+};
104+}).toSorted((left, right) => left.id.localeCompare(right.id));
105+}
106+68107export function buildQaCoverageInventory(
69108scenarios: readonly QaSeedScenarioWithSource[],
70109): QaCoverageInventory {
@@ -137,6 +176,7 @@ export function buildQaCoverageInventory(
137176 missingCoverage,
138177 byTheme,
139178 bySurface,
179+scenarioPacks: buildScenarioPackSummaries(scenarios),
140180liveTransportLanes: buildLiveTransportCoverageLaneSummaries(),
141181};
142182}
@@ -172,6 +212,17 @@ function pushLiveTransportLines(
172212}
173213}
174214215+function pushScenarioPackLines(lines: string[], packs: readonly QaCoverageScenarioPackSummary[]) {
216+for (const pack of packs) {
217+const missing =
218+pack.missingScenarioIds.length > 0 ? pack.missingScenarioIds.join(", ") : "none";
219+lines.push(
220+`- ${pack.id} (${pack.title}): ${pack.scenarioIds.length} scenarios; coverage: ${pack.coverageIds.join(", ")}; missing scenarios: ${missing}`,
221+);
222+lines.push(` - scenarios: ${pack.scenarioIds.join(", ")}`);
223+}
224+}
225+175226export function renderQaCoverageMarkdownReport(inventory: QaCoverageInventory): string {
176227const lines: string[] = [
177228"# QA Coverage Inventory",
@@ -183,10 +234,15 @@ export function renderQaCoverageMarkdownReport(inventory: QaCoverageInventory):
183234`- Overlapping coverage IDs: ${inventory.overlappingCoverage.length}`,
184235`- Missing coverage metadata: ${inventory.missingCoverage.length}`,
185236"",
186-"## By Theme",
187-"",
188237];
189238239+if (inventory.scenarioPacks.length > 0) {
240+lines.push("## Scenario Packs", "");
241+pushScenarioPackLines(lines, inventory.scenarioPacks);
242+lines.push("");
243+}
244+245+lines.push("## By Theme", "");
190246for (const theme of Object.keys(inventory.byTheme).toSorted()) {
191247lines.push(`### ${theme}`, "");
192248pushFeatureLines(lines, inventory.byTheme[theme] ?? []);
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。