@monster-orange/den 0.0.0-stage → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +67 -0
- package/LICENSE +21 -0
- package/README.md +166 -2
- package/bin/den +61 -0
- package/docs/distributions.md +256 -0
- package/make/demo.mk +82 -0
- package/make/den.mk +80 -0
- package/make/journeys.mk +57 -0
- package/make/local_dev.mk +154 -0
- package/make/security.mk +59 -0
- package/make/test.mk +405 -0
- package/package.json +104 -4
- package/scripts/auth-configure.ts +415 -0
- package/scripts/heal-config.ts +92 -0
- package/scripts/jsonl-playwright-reporter.js +70 -0
- package/scripts/manifest-read.cjs +91 -0
- package/scripts/setup-1password.ts +570 -0
- package/scripts/setup-secrets.ts +149 -0
- package/scripts/view-results.js +156 -0
- package/service/install.sh +112 -0
- package/src/pillars/api/fixtures/index.ts +128 -0
- package/src/pillars/api/fixtures/openapi-validator.ts +111 -0
- package/src/pillars/api/global-setup.ts +103 -0
- package/src/pillars/api/playwright.config.ts +105 -0
- package/src/pillars/api/schemas/example-api.json +110 -0
- package/src/pillars/api/tests/health/health.spec.ts +19 -0
- package/src/pillars/api/tests/health/manifest.yml +6 -0
- package/src/pillars/browser/fixtures/index.ts +232 -0
- package/src/pillars/browser/fixtures/package.json +10 -0
- package/src/pillars/browser/global-setup.ts +140 -0
- package/src/pillars/browser/global-teardown.ts +48 -0
- package/src/pillars/browser/playwright.config.ts +212 -0
- package/src/pillars/browser/setup.ts +219 -0
- package/src/pillars/journeys/app-config.ts +237 -0
- package/src/pillars/journeys/discover.ts +160 -0
- package/src/pillars/journeys/hooks/deny-shell.cjs +44 -0
- package/src/pillars/journeys/observability/events.ts +288 -0
- package/src/pillars/journeys/observability/sdk-mapper.ts +306 -0
- package/src/pillars/journeys/report/friction.ts +304 -0
- package/src/pillars/journeys/report/junit.ts +105 -0
- package/src/pillars/journeys/report/render.ts +273 -0
- package/src/pillars/journeys/report/results.ts +323 -0
- package/src/pillars/journeys/run.ts +673 -0
- package/src/pillars/journeys/runner.ts +1025 -0
- package/src/pillars/journeys/sandbox.ts +406 -0
- package/src/pillars/journeys/spec/loader.ts +152 -0
- package/src/pillars/journeys/spec/schema.ts +208 -0
- package/src/pillars/journeys/teardown.ts +98 -0
- package/src/pillars/journeys/tools/browser-session.ts +219 -0
- package/src/pillars/journeys/tools/browser-tool.ts +914 -0
- package/src/pillars/journeys/tools/http-tool.ts +564 -0
- package/src/pillars/journeys/tools/ledger.ts +278 -0
- package/src/pillars/journeys/tools/snapshot-store.ts +117 -0
- package/src/pillars/journeys/verify/assertions.ts +502 -0
- package/src/pillars/journeys/verify/verdict.ts +71 -0
- package/src/pillars/perf/build-report.ts +36 -0
- package/src/pillars/perf/k6.config.js +112 -0
- package/src/pillars/perf/run.ts +345 -0
- package/src/pillars/perf/scenarios/load-profile.js +97 -0
- package/src/pillars/perf/staging.ts +73 -0
- package/src/pillars/security/discover.ts +108 -0
- package/src/pillars/security/findings.ts +151 -0
- package/src/pillars/security/plan.ts +355 -0
- package/src/pillars/security/run.ts +729 -0
- package/src/pillars/smoke/admin-probe.ts +68 -0
- package/src/pillars/smoke/base-url.ts +56 -0
- package/src/pillars/smoke/cleanup.ts +8 -0
- package/src/pillars/smoke/discover.ts +237 -0
- package/src/pillars/smoke/ensure-smoke-teardown.ts +40 -0
- package/src/pillars/smoke/fixture-manager.ts +217 -0
- package/src/pillars/smoke/fixtures.ts +468 -0
- package/src/pillars/smoke/global-setup-all.ts +262 -0
- package/src/pillars/smoke/global-setup-global.ts +262 -0
- package/src/pillars/smoke/global-setup.ts +273 -0
- package/src/pillars/smoke/global-teardown-all.ts +8 -0
- package/src/pillars/smoke/global-teardown-global.ts +8 -0
- package/src/pillars/smoke/global-teardown.ts +139 -0
- package/src/pillars/smoke/playwright-all.config.ts +147 -0
- package/src/pillars/smoke/playwright-global.config.ts +141 -0
- package/src/pillars/smoke/playwright.config.ts +162 -0
- package/src/pillars/smoke/setup-env.ts +132 -0
- package/src/pillars/smoke/setup-global.ts +126 -0
- package/src/pillars/smoke/setup.ts +115 -0
- package/src/pillars/smoke/smoke-repo.ts +16 -0
- package/src/pillars/smoke/staging.ts +49 -0
- package/src/pillars/suites/run.ts +147 -0
- package/src/scripts/configure-aws-profiles.ts +114 -0
- package/src/scripts/register-repos.ts +307 -0
- package/src/scripts/setup-default-workspace.ts +203 -0
- package/src/shared/applications.ts +138 -0
- package/src/shared/auth/api-token.ts +416 -0
- package/src/shared/auth/auth0-helper.ts +284 -0
- package/src/shared/auth/headless-login.ts +265 -0
- package/src/shared/auth/jwt-helper.ts +186 -0
- package/src/shared/auth/sudo-vault.ts +69 -0
- package/src/shared/auth/test-accounts.ts +98 -0
- package/src/shared/auth/token-injection.ts +184 -0
- package/src/shared/auth/token-providers/auth0.ts +80 -0
- package/src/shared/auth/token-providers/index.ts +182 -0
- package/src/shared/auth/token-refresh.ts +273 -0
- package/src/shared/banner.ts +15 -0
- package/src/shared/brand.ts +79 -0
- package/src/shared/cli-tabs.ts +131 -0
- package/src/shared/constants.ts +128 -0
- package/src/shared/den-config.ts +566 -0
- package/src/shared/dev-metrics/emit.ts +354 -0
- package/src/shared/edge/config.ts +229 -0
- package/src/shared/edge/render.ts +221 -0
- package/src/shared/edge/runtime.ts +268 -0
- package/src/shared/edge/types.ts +62 -0
- package/src/shared/engine.ts +67 -0
- package/src/shared/environment/aws-profiles.ts +49 -0
- package/src/shared/environment/env-selector.ts +161 -0
- package/src/shared/environment/playwright-env.ts +82 -0
- package/src/shared/environment-manager/catalog.ts +77 -0
- package/src/shared/environment-manager/clone-guard.ts +163 -0
- package/src/shared/environment-manager/dag.ts +286 -0
- package/src/shared/environment-manager/default-workspace.ts +182 -0
- package/src/shared/environment-manager/derivation/alias.ts +90 -0
- package/src/shared/environment-manager/derivation/cache.ts +97 -0
- package/src/shared/environment-manager/derivation/derive-graph.ts +421 -0
- package/src/shared/environment-manager/derivation/derived-up.ts +354 -0
- package/src/shared/environment-manager/derivation/load-alias.ts +11 -0
- package/src/shared/environment-manager/derivation/rules-compose.ts +42 -0
- package/src/shared/environment-manager/derivation/rules-events.ts +50 -0
- package/src/shared/environment-manager/derivation/rules-http.ts +247 -0
- package/src/shared/environment-manager/derivation/rules-infra.ts +64 -0
- package/src/shared/environment-manager/derivation/rules-readiness.ts +96 -0
- package/src/shared/environment-manager/derivation/scan.ts +160 -0
- package/src/shared/environment-manager/derivation/text.ts +40 -0
- package/src/shared/environment-manager/derivation/types.ts +69 -0
- package/src/shared/environment-manager/health.ts +589 -0
- package/src/shared/environment-manager/index.ts +6 -0
- package/src/shared/environment-manager/load-applications.ts +78 -0
- package/src/shared/environment-manager/log-tail.ts +212 -0
- package/src/shared/environment-manager/make-targets.ts +78 -0
- package/src/shared/environment-manager/opctl.ts +334 -0
- package/src/shared/environment-manager/readiness.ts +93 -0
- package/src/shared/environment-manager/register-local.ts +72 -0
- package/src/shared/environment-manager/secrets-check.ts +260 -0
- package/src/shared/environment-manager/service-env.ts +110 -0
- package/src/shared/environment-manager/service-runner.ts +1588 -0
- package/src/shared/environment-manager/up-plan.ts +302 -0
- package/src/shared/environment-manager/workspace-manager.ts +905 -0
- package/src/shared/environment-manager/workspaces.ts +860 -0
- package/src/shared/manifest/deps.ts +27 -0
- package/src/shared/manifest/migrate-manifest.ts +101 -0
- package/src/shared/manifest/read-manifest.ts +160 -0
- package/src/shared/manifest/schema.ts +299 -0
- package/src/shared/manifest/service-links.ts +93 -0
- package/src/shared/manifest/validate-manifest.ts +140 -0
- package/src/shared/manifest/workspace-manifests.ts +92 -0
- package/src/shared/open-url.ts +122 -0
- package/src/shared/org.ts +44 -0
- package/src/shared/paths.ts +178 -0
- package/src/shared/perf/optional-fields.ts +105 -0
- package/src/shared/perf/report-normalizer.ts +404 -0
- package/src/shared/perf/report-paths.ts +19 -0
- package/src/shared/perf/report-store.ts +110 -0
- package/src/shared/perf/report-types.ts +70 -0
- package/src/shared/perf/test-paths.ts +25 -0
- package/src/shared/process/log-rotation.ts +147 -0
- package/src/shared/process/spawn-streaming.ts +229 -0
- package/src/shared/product.ts +92 -0
- package/src/shared/profile.ts +141 -0
- package/src/shared/repo-kind.ts +32 -0
- package/src/shared/reporting/jsonl-reporter.ts +131 -0
- package/src/shared/reporting/slack-reporter.ts +340 -0
- package/src/shared/results/result-reader.ts +266 -0
- package/src/shared/results/result-writer.ts +168 -0
- package/src/shared/secrets/doppler.ts +126 -0
- package/src/shared/secrets/env.ts +48 -0
- package/src/shared/secrets/index.ts +197 -0
- package/src/shared/secrets/keys.ts +33 -0
- package/src/shared/secrets/onepassword.ts +75 -0
- package/src/shared/secrets/types.ts +52 -0
- package/src/shared/service-url.ts +119 -0
- package/src/shared/smoke/branch-resolver.ts +141 -0
- package/src/shared/smoke/git-remote.ts +70 -0
- package/src/shared/smoke/repo-cloner.ts +151 -0
- package/src/shared/stacks/config.ts +137 -0
- package/src/shared/stacks/manifest-commands.ts +88 -0
- package/src/shared/stacks/render.ts +253 -0
- package/src/shared/stacks/runtime.ts +334 -0
- package/src/shared/stacks/types.ts +53 -0
- package/src/shared/terminal/tabs.ts +212 -0
- package/src/shared/test-discovery/module-scanner.ts +569 -0
- package/src/shared/types/index.ts +678 -0
- package/src/shared/ui-marker.ts +19 -0
- package/src/ui/cli/applications-command.ts +116 -0
- package/src/ui/cli/config-command.ts +68 -0
- package/src/ui/cli/create-main.ts +9 -0
- package/src/ui/cli/create.ts +360 -0
- package/src/ui/cli/edge-command.ts +91 -0
- package/src/ui/cli/flag-parser.ts +246 -0
- package/src/ui/cli/graph-command.ts +524 -0
- package/src/ui/cli/health-display.ts +63 -0
- package/src/ui/cli/index.ts +3656 -0
- package/src/ui/cli/init.ts +855 -0
- package/src/ui/cli/invocation-target.ts +175 -0
- package/src/ui/cli/logs-command.ts +104 -0
- package/src/ui/cli/module-selection.ts +31 -0
- package/src/ui/cli/prompts.ts +767 -0
- package/src/ui/cli/results-viewer.ts +436 -0
- package/src/ui/cli/secrets-preflight.ts +91 -0
- package/src/ui/cli/stack-command.ts +144 -0
- package/src/ui/cli/stalled-setup-recovery.ts +129 -0
- package/src/ui/cli/test-runner.ts +1312 -0
- package/src/ui/cli/web-command.ts +1073 -0
- package/src/ui/server/changelog-parser.ts +94 -0
- package/src/ui/server/daemon-reaper.ts +129 -0
- package/src/ui/server/editor-manager.ts +301 -0
- package/src/ui/server/github-service.ts +223 -0
- package/src/ui/server/http-helpers.ts +98 -0
- package/src/ui/server/index.ts +3236 -0
- package/src/ui/server/log-history.ts +452 -0
- package/src/ui/server/perf-report.ts +42 -0
- package/src/ui/server/public/environments.html +494 -0
- package/src/ui/server/public/favicon.ico +0 -0
- package/src/ui/server/public/header.js +1371 -0
- package/src/ui/server/public/index.html +2595 -0
- package/src/ui/server/public/local-dev.html +7405 -0
- package/src/ui/server/public/logs.html +1489 -0
- package/src/ui/server/public/perf-report.js +359 -0
- package/src/ui/server/public/release.html +2111 -0
- package/src/ui/server/public/services.html +1098 -0
- package/src/ui/server/public/workspace-picker.js +69 -0
- package/src/ui/server/release-deploy-session.ts +246 -0
- package/src/ui/server/release-service.ts +1125 -0
- package/src/ui/server/sudo-store.ts +111 -0
- package/src/ui/server/workspace-routes.ts +2154 -0
|
@@ -0,0 +1,323 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Journeys JSONL result rows — collect → finalize (plan: jrn-reporting
|
|
3
|
+
* packet; critique carry-over R3-1).
|
|
4
|
+
*
|
|
5
|
+
* The split is load-bearing for the entrypoint's ordering contract
|
|
6
|
+
* (runJourney → verify → report → teardown in finally):
|
|
7
|
+
* - `collectJourneyReport()` runs right after verification and normalizes
|
|
8
|
+
* everything known at that point (verdict, usage, snapshots, friction);
|
|
9
|
+
* - teardown runs;
|
|
10
|
+
* - `finalizeJourneyReport()` runs in the same finally, folding the
|
|
11
|
+
* TeardownReport (deletion failures + unmanaged-mutation warnings) into
|
|
12
|
+
* the JSONL row, the JUnit case, and the rendered markdown report — so
|
|
13
|
+
* teardown outcomes are part of every persisted output.
|
|
14
|
+
*
|
|
15
|
+
* Verdict discipline: the row's status comes EXCLUSIVELY from the
|
|
16
|
+
* deterministic verifier's Verdict. Friction points ride along as metadata
|
|
17
|
+
* and can never flip it (pinned by test).
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
import { mkdir, writeFile } from "fs/promises";
|
|
21
|
+
import * as os from "os";
|
|
22
|
+
import * as path from "path";
|
|
23
|
+
import { resultWriter } from "../../../shared/results/result-writer.js";
|
|
24
|
+
import type { TestResult } from "../../../shared/types/index.js";
|
|
25
|
+
import type { JourneyEvent } from "../observability/events.js";
|
|
26
|
+
import type { FailureKind, RunOutcome } from "../runner.js";
|
|
27
|
+
import type { JourneySpec } from "../spec/schema.js";
|
|
28
|
+
import type { TeardownReport } from "../teardown.js";
|
|
29
|
+
import type { SnapshotIndexEntry } from "../tools/snapshot-store.js";
|
|
30
|
+
import type { AssertionResult } from "../verify/assertions.js";
|
|
31
|
+
import type { Verdict } from "../verify/verdict.js";
|
|
32
|
+
import type { FrictionPoint } from "./friction.js";
|
|
33
|
+
import { renderJourneyReportMarkdown } from "./render.js";
|
|
34
|
+
import type { JourneysJUnitCase } from "./junit.js";
|
|
35
|
+
|
|
36
|
+
/** Spec fields the report consumes (full JourneySpec accepted). */
|
|
37
|
+
export type ReportableSpec = Pick<JourneySpec, "name" | "surface" | "budgets">;
|
|
38
|
+
|
|
39
|
+
export interface CollectJourneyReportInput {
|
|
40
|
+
spec: ReportableSpec;
|
|
41
|
+
env: string;
|
|
42
|
+
outcome: RunOutcome;
|
|
43
|
+
verdict: Verdict;
|
|
44
|
+
frictionPoints: readonly FrictionPoint[];
|
|
45
|
+
/** Defaults to the current OS user. */
|
|
46
|
+
user?: string;
|
|
47
|
+
/** Defaults to now (injectable for deterministic tests). */
|
|
48
|
+
timestamp?: string;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/** Budget consumption snapshot for the JSONL row. */
|
|
52
|
+
export interface BudgetConsumption {
|
|
53
|
+
tokensUsed?: number;
|
|
54
|
+
maxTotalTokens: number;
|
|
55
|
+
timeoutS: number;
|
|
56
|
+
maxTurns: number;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/** Everything known after verification, before teardown. */
|
|
60
|
+
export interface CollectedJourneyReport {
|
|
61
|
+
journeyName: string;
|
|
62
|
+
surface: JourneySpec["surface"];
|
|
63
|
+
environment: string;
|
|
64
|
+
timestamp: string;
|
|
65
|
+
user: string;
|
|
66
|
+
runId: string;
|
|
67
|
+
status: "passed" | "failed";
|
|
68
|
+
failureKind?: FailureKind;
|
|
69
|
+
durationMs: number;
|
|
70
|
+
usageTotalTokens?: number;
|
|
71
|
+
budgetConsumption: BudgetConsumption;
|
|
72
|
+
transcriptPath: string;
|
|
73
|
+
reportDir: string;
|
|
74
|
+
snapshotsDir: string;
|
|
75
|
+
snapshotCount: number;
|
|
76
|
+
snapshotIndex: readonly SnapshotIndexEntry[];
|
|
77
|
+
frictionPoints: readonly FrictionPoint[];
|
|
78
|
+
assertionResults: readonly AssertionResult[];
|
|
79
|
+
/** Structured harness timeline (tool calls, bindings, denials, error). */
|
|
80
|
+
events: readonly JourneyEvent[];
|
|
81
|
+
/** Basename of the events.jsonl sidecar (for the report header). */
|
|
82
|
+
eventsFile: string;
|
|
83
|
+
/** SDK terminal error detail on an agent_error run (previously dropped). */
|
|
84
|
+
agentError?: string;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Normalize one verified journey into report data. Pure — writes nothing.
|
|
89
|
+
* Called BEFORE teardown so the collected data is safe even if teardown
|
|
90
|
+
* itself fails catastrophically.
|
|
91
|
+
*/
|
|
92
|
+
export function collectJourneyReport(
|
|
93
|
+
input: CollectJourneyReportInput,
|
|
94
|
+
): CollectedJourneyReport {
|
|
95
|
+
const reportDir = path.dirname(input.outcome.transcriptPath);
|
|
96
|
+
const collected: CollectedJourneyReport = {
|
|
97
|
+
journeyName: input.spec.name,
|
|
98
|
+
surface: input.spec.surface,
|
|
99
|
+
environment: input.env,
|
|
100
|
+
timestamp: input.timestamp ?? new Date().toISOString(),
|
|
101
|
+
user: input.user ?? process.env.USER ?? os.userInfo().username,
|
|
102
|
+
runId: input.outcome.runId,
|
|
103
|
+
status: input.verdict.passed ? "passed" : "failed",
|
|
104
|
+
durationMs: input.outcome.durationMs,
|
|
105
|
+
budgetConsumption: {
|
|
106
|
+
tokensUsed: input.outcome.usage?.totalTokens,
|
|
107
|
+
maxTotalTokens: input.spec.budgets.max_total_tokens,
|
|
108
|
+
timeoutS: input.spec.budgets.timeout_s,
|
|
109
|
+
maxTurns: input.spec.budgets.max_turns,
|
|
110
|
+
},
|
|
111
|
+
transcriptPath: input.outcome.transcriptPath,
|
|
112
|
+
reportDir,
|
|
113
|
+
snapshotsDir: path.join(reportDir, "snapshots"),
|
|
114
|
+
snapshotCount: input.outcome.snapshotIndex.length,
|
|
115
|
+
snapshotIndex: input.outcome.snapshotIndex,
|
|
116
|
+
frictionPoints: input.frictionPoints,
|
|
117
|
+
assertionResults: input.verdict.results,
|
|
118
|
+
events: input.outcome.events,
|
|
119
|
+
eventsFile: path.basename(input.outcome.eventsPath),
|
|
120
|
+
};
|
|
121
|
+
if (input.outcome.usage !== undefined) {
|
|
122
|
+
collected.usageTotalTokens = input.outcome.usage.totalTokens;
|
|
123
|
+
}
|
|
124
|
+
if (input.verdict.failure_kind !== undefined) {
|
|
125
|
+
collected.failureKind = input.verdict.failure_kind;
|
|
126
|
+
}
|
|
127
|
+
if (input.outcome.error !== undefined) {
|
|
128
|
+
collected.agentError = input.outcome.error;
|
|
129
|
+
}
|
|
130
|
+
return collected;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/** Teardown block embedded in the JSONL row metadata. */
|
|
134
|
+
export interface TeardownRowMetadata {
|
|
135
|
+
attempted: number;
|
|
136
|
+
failed: number;
|
|
137
|
+
failures: Array<{
|
|
138
|
+
resourceType: string;
|
|
139
|
+
id: string;
|
|
140
|
+
cleanup: { method: string; path: string };
|
|
141
|
+
status?: number;
|
|
142
|
+
error?: string;
|
|
143
|
+
}>;
|
|
144
|
+
unmanaged_mutation_warnings: Array<{
|
|
145
|
+
method: string;
|
|
146
|
+
path: string;
|
|
147
|
+
status: number;
|
|
148
|
+
source: string;
|
|
149
|
+
}>;
|
|
150
|
+
/** Browser interception-processing failures (finding 7 — never silent). */
|
|
151
|
+
interception_errors: string[];
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
export interface FinalizedJourneyReport {
|
|
155
|
+
row: TestResult;
|
|
156
|
+
junitCase: JourneysJUnitCase;
|
|
157
|
+
reportPath: string;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/** Injectable output sinks (real writers by default). */
|
|
161
|
+
export interface FinalizeJourneyReportDeps {
|
|
162
|
+
writeResult: (row: TestResult) => Promise<void>;
|
|
163
|
+
writeFile: (filePath: string, contents: string) => Promise<void>;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
async function defaultWriteFile(
|
|
167
|
+
filePath: string,
|
|
168
|
+
contents: string,
|
|
169
|
+
): Promise<void> {
|
|
170
|
+
await mkdir(path.dirname(filePath), { recursive: true });
|
|
171
|
+
await writeFile(filePath, contents);
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
function toTeardownMetadata(
|
|
175
|
+
teardown: TeardownReport | undefined,
|
|
176
|
+
): TeardownRowMetadata {
|
|
177
|
+
return {
|
|
178
|
+
attempted: teardown?.results.length ?? 0,
|
|
179
|
+
failed: teardown?.failures.length ?? 0,
|
|
180
|
+
failures: (teardown?.failures ?? []).map((failure) => ({
|
|
181
|
+
resourceType: failure.entry.resourceType,
|
|
182
|
+
id: failure.entry.id,
|
|
183
|
+
cleanup: failure.entry.cleanup,
|
|
184
|
+
...(failure.status !== undefined ? { status: failure.status } : {}),
|
|
185
|
+
...(failure.error !== undefined ? { error: failure.error } : {}),
|
|
186
|
+
})),
|
|
187
|
+
unmanaged_mutation_warnings: (teardown?.unmanagedWarnings ?? []).map(
|
|
188
|
+
(warning) => ({
|
|
189
|
+
method: warning.method,
|
|
190
|
+
path: warning.path,
|
|
191
|
+
status: warning.status,
|
|
192
|
+
source: warning.source,
|
|
193
|
+
}),
|
|
194
|
+
),
|
|
195
|
+
interception_errors: [...(teardown?.interceptionErrors ?? [])],
|
|
196
|
+
};
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
function failedAssertionMessages(
|
|
200
|
+
results: readonly AssertionResult[],
|
|
201
|
+
): string[] {
|
|
202
|
+
return results
|
|
203
|
+
.filter((result) => !result.passed)
|
|
204
|
+
.map(
|
|
205
|
+
(result) =>
|
|
206
|
+
result.message ??
|
|
207
|
+
`assertion ${result.assertion.kind} failed ` +
|
|
208
|
+
`(expected ${JSON.stringify(result.expected)}, ` +
|
|
209
|
+
`actual ${JSON.stringify(result.actual)})`,
|
|
210
|
+
);
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
/** Snapshot-capture failures (finding 9) — missing required evidence. */
|
|
214
|
+
function snapshotCaptureErrorStrings(
|
|
215
|
+
snapshotIndex: CollectedJourneyReport["snapshotIndex"],
|
|
216
|
+
): string[] {
|
|
217
|
+
return snapshotIndex
|
|
218
|
+
.filter((entry) => entry.captureError !== undefined)
|
|
219
|
+
.map(
|
|
220
|
+
(entry) =>
|
|
221
|
+
`snapshot capture failed for ${entry.action} (seq ${entry.seq}): ` +
|
|
222
|
+
`${entry.captureError}`,
|
|
223
|
+
);
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
function teardownWarningStrings(metadata: TeardownRowMetadata): string[] {
|
|
227
|
+
return [
|
|
228
|
+
...metadata.failures.map(
|
|
229
|
+
(failure) =>
|
|
230
|
+
`teardown failed for ${failure.resourceType} ${failure.id}: ` +
|
|
231
|
+
`${failure.cleanup.method} ${failure.cleanup.path}` +
|
|
232
|
+
(failure.status !== undefined ? ` (${failure.status})` : "") +
|
|
233
|
+
(failure.error !== undefined ? ` — ${failure.error}` : ""),
|
|
234
|
+
),
|
|
235
|
+
...metadata.unmanaged_mutation_warnings.map(
|
|
236
|
+
(warning) =>
|
|
237
|
+
`unmanaged mutation: ${warning.method} ${warning.path} ` +
|
|
238
|
+
`(${warning.status})`,
|
|
239
|
+
),
|
|
240
|
+
...metadata.interception_errors.map(
|
|
241
|
+
(message) => `browser interception error: ${message}`,
|
|
242
|
+
),
|
|
243
|
+
];
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
/**
|
|
247
|
+
* Finalize one journey's persisted outputs AFTER teardown: the JSONL row
|
|
248
|
+
* (via the shared resultWriter → results/journeys-<env>-<date>.jsonl), the
|
|
249
|
+
* JUnit case (aggregated across journeys by the entrypoint), and the
|
|
250
|
+
* rendered markdown report with the snapshot gallery. Teardown warnings —
|
|
251
|
+
* deletion failures and unmanaged mutations — are folded into all three.
|
|
252
|
+
*/
|
|
253
|
+
export async function finalizeJourneyReport(
|
|
254
|
+
collected: CollectedJourneyReport,
|
|
255
|
+
teardown: TeardownReport | undefined,
|
|
256
|
+
deps: Partial<FinalizeJourneyReportDeps> = {},
|
|
257
|
+
): Promise<FinalizedJourneyReport> {
|
|
258
|
+
const writeResult =
|
|
259
|
+
deps.writeResult ?? ((row: TestResult) => resultWriter.writeResult(row));
|
|
260
|
+
const writeReportFile = deps.writeFile ?? defaultWriteFile;
|
|
261
|
+
|
|
262
|
+
const teardownMetadata = toTeardownMetadata(teardown);
|
|
263
|
+
const failureMessages = failedAssertionMessages(collected.assertionResults);
|
|
264
|
+
const snapshotWarnings = snapshotCaptureErrorStrings(collected.snapshotIndex);
|
|
265
|
+
|
|
266
|
+
const errorParts: string[] = [];
|
|
267
|
+
if (collected.failureKind !== undefined) {
|
|
268
|
+
errorParts.push(`failure_kind=${collected.failureKind}`);
|
|
269
|
+
}
|
|
270
|
+
errorParts.push(...failureMessages);
|
|
271
|
+
|
|
272
|
+
const row: TestResult = {
|
|
273
|
+
timestamp: collected.timestamp,
|
|
274
|
+
pillar: "journeys",
|
|
275
|
+
environment: collected.environment,
|
|
276
|
+
test: collected.journeyName,
|
|
277
|
+
status: collected.status,
|
|
278
|
+
duration: collected.durationMs,
|
|
279
|
+
user: collected.user,
|
|
280
|
+
...(collected.status === "failed" && errorParts.length > 0
|
|
281
|
+
? { error: errorParts.join("; ") }
|
|
282
|
+
: {}),
|
|
283
|
+
metadata: {
|
|
284
|
+
surface: collected.surface,
|
|
285
|
+
runId: collected.runId,
|
|
286
|
+
...(collected.failureKind !== undefined
|
|
287
|
+
? { failure_kind: collected.failureKind }
|
|
288
|
+
: {}),
|
|
289
|
+
usage_total_tokens: collected.usageTotalTokens,
|
|
290
|
+
budget_consumption: collected.budgetConsumption,
|
|
291
|
+
transcript_path: collected.transcriptPath,
|
|
292
|
+
snapshot_count: collected.snapshotCount,
|
|
293
|
+
snapshots_dir: collected.snapshotsDir,
|
|
294
|
+
friction_points: collected.frictionPoints,
|
|
295
|
+
teardown: teardownMetadata,
|
|
296
|
+
snapshot_capture_errors: snapshotWarnings,
|
|
297
|
+
},
|
|
298
|
+
};
|
|
299
|
+
|
|
300
|
+
const junitCase: JourneysJUnitCase = {
|
|
301
|
+
name: collected.journeyName,
|
|
302
|
+
environment: collected.environment,
|
|
303
|
+
durationMs: collected.durationMs,
|
|
304
|
+
passed: collected.status === "passed",
|
|
305
|
+
...(collected.failureKind !== undefined
|
|
306
|
+
? { failureKind: collected.failureKind }
|
|
307
|
+
: {}),
|
|
308
|
+
failureDetails: failureMessages,
|
|
309
|
+
teardownWarnings: [
|
|
310
|
+
...snapshotWarnings,
|
|
311
|
+
...teardownWarningStrings(teardownMetadata),
|
|
312
|
+
],
|
|
313
|
+
};
|
|
314
|
+
|
|
315
|
+
const reportPath = path.join(collected.reportDir, "report.md");
|
|
316
|
+
await writeResult(row);
|
|
317
|
+
await writeReportFile(
|
|
318
|
+
reportPath,
|
|
319
|
+
renderJourneyReportMarkdown(collected, teardown),
|
|
320
|
+
);
|
|
321
|
+
|
|
322
|
+
return { row, junitCase, reportPath };
|
|
323
|
+
}
|