@jevitate/cli 0.9.0 → 0.11.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.
Files changed (190) hide show
  1. package/dist/anchor-baselines.d.ts +26 -0
  2. package/dist/anchor-baselines.js +25 -0
  3. package/dist/anchor-baselines.js.map +1 -0
  4. package/dist/approval-provenance.d.ts +32 -2
  5. package/dist/approval-provenance.js +92 -5
  6. package/dist/approval-provenance.js.map +1 -1
  7. package/dist/approved-demo.d.ts +86 -0
  8. package/dist/approved-demo.js +184 -0
  9. package/dist/approved-demo.js.map +1 -0
  10. package/dist/bin.js +13352 -7050
  11. package/dist/build-info.generated.js +2 -2
  12. package/dist/campaign-api.d.ts +15 -0
  13. package/dist/campaign-api.js +67 -6
  14. package/dist/campaign-api.js.map +1 -1
  15. package/dist/campaign-cli.js +7 -2
  16. package/dist/campaign-cli.js.map +1 -1
  17. package/dist/campaign-preflight.d.ts +76 -0
  18. package/dist/campaign-preflight.js +117 -0
  19. package/dist/campaign-preflight.js.map +1 -0
  20. package/dist/catalog-analysis.js +14 -0
  21. package/dist/catalog-analysis.js.map +1 -1
  22. package/dist/catalog-api.js +12 -4
  23. package/dist/catalog-api.js.map +1 -1
  24. package/dist/catalog-bundle-api.d.ts +83 -0
  25. package/dist/catalog-bundle-api.js +309 -0
  26. package/dist/catalog-bundle-api.js.map +1 -0
  27. package/dist/catalog-bundle-findings.d.ts +64 -0
  28. package/dist/catalog-bundle-findings.js +326 -0
  29. package/dist/catalog-bundle-findings.js.map +1 -0
  30. package/dist/catalog-bundle.d.ts +296 -0
  31. package/dist/catalog-bundle.js +777 -0
  32. package/dist/catalog-bundle.js.map +1 -0
  33. package/dist/catalog-cli.d.ts +6 -0
  34. package/dist/catalog-cli.js +181 -5
  35. package/dist/catalog-cli.js.map +1 -1
  36. package/dist/catalog-refs.d.ts +42 -0
  37. package/dist/catalog-refs.js +188 -0
  38. package/dist/catalog-refs.js.map +1 -0
  39. package/dist/catalog-review.d.ts +3 -1
  40. package/dist/catalog-review.js +61 -0
  41. package/dist/catalog-review.js.map +1 -1
  42. package/dist/catalog.d.ts +27 -3
  43. package/dist/catalog.js +46 -2
  44. package/dist/catalog.js.map +1 -1
  45. package/dist/check-api.js +180 -9
  46. package/dist/check-api.js.map +1 -1
  47. package/dist/check-cli.d.ts +2 -0
  48. package/dist/check-cli.js +96 -2
  49. package/dist/check-cli.js.map +1 -1
  50. package/dist/check-execute.d.ts +18 -0
  51. package/dist/check-execute.js +56 -3
  52. package/dist/check-execute.js.map +1 -1
  53. package/dist/check-types.d.ts +105 -0
  54. package/dist/check-types.js.map +1 -1
  55. package/dist/cli-output.d.ts +6 -0
  56. package/dist/cli-output.js +38 -1
  57. package/dist/cli-output.js.map +1 -1
  58. package/dist/cli-shared.d.ts +10 -0
  59. package/dist/cli-shared.js +0 -4
  60. package/dist/cli-shared.js.map +1 -1
  61. package/dist/cold-start-report.d.ts +32 -0
  62. package/dist/cold-start-report.js +31 -0
  63. package/dist/cold-start-report.js.map +1 -0
  64. package/dist/defect-evidence.js +10 -5
  65. package/dist/defect-evidence.js.map +1 -1
  66. package/dist/demo-aspect-api.d.ts +11 -0
  67. package/dist/demo-aspect-api.js +27 -2
  68. package/dist/demo-aspect-api.js.map +1 -1
  69. package/dist/demo-aspect-cli.js +5 -0
  70. package/dist/demo-aspect-cli.js.map +1 -1
  71. package/dist/demo-capture.d.ts +79 -2
  72. package/dist/demo-capture.js +504 -12
  73. package/dist/demo-capture.js.map +1 -1
  74. package/dist/environments.d.ts +8 -1
  75. package/dist/environments.js +14 -3
  76. package/dist/environments.js.map +1 -1
  77. package/dist/exit-codes.js +16 -0
  78. package/dist/exit-codes.js.map +1 -1
  79. package/dist/explore-adversarial.js +2 -2
  80. package/dist/explore-adversarial.js.map +1 -1
  81. package/dist/explore-shared.d.ts +11 -0
  82. package/dist/explore-shared.js +9 -0
  83. package/dist/explore-shared.js.map +1 -1
  84. package/dist/findings-filing.js +7 -3
  85. package/dist/findings-filing.js.map +1 -1
  86. package/dist/forge-verify.d.ts +224 -0
  87. package/dist/forge-verify.js +649 -0
  88. package/dist/forge-verify.js.map +1 -0
  89. package/dist/github-issue-filer.js +15 -9
  90. package/dist/github-issue-filer.js.map +1 -1
  91. package/dist/init-codeowners.d.ts +19 -0
  92. package/dist/init-codeowners.js +66 -0
  93. package/dist/init-codeowners.js.map +1 -1
  94. package/dist/job-draft-api.d.ts +52 -0
  95. package/dist/job-draft-api.js +110 -0
  96. package/dist/job-draft-api.js.map +1 -0
  97. package/dist/journeeze-api.d.ts +77 -0
  98. package/dist/journeeze-api.js +371 -0
  99. package/dist/journeeze-api.js.map +1 -0
  100. package/dist/journeeze-connect.d.ts +156 -0
  101. package/dist/journeeze-connect.js +357 -0
  102. package/dist/journeeze-connect.js.map +1 -0
  103. package/dist/journey-anchor-api.d.ts +37 -0
  104. package/dist/journey-anchor-api.js +58 -0
  105. package/dist/journey-anchor-api.js.map +1 -0
  106. package/dist/journey-anchor-cli.d.ts +17 -0
  107. package/dist/journey-anchor-cli.js +104 -0
  108. package/dist/journey-anchor-cli.js.map +1 -0
  109. package/dist/journey-anchor-gate.d.ts +52 -0
  110. package/dist/journey-anchor-gate.js +101 -0
  111. package/dist/journey-anchor-gate.js.map +1 -0
  112. package/dist/journey-api.d.ts +30 -1
  113. package/dist/journey-api.js +118 -16
  114. package/dist/journey-api.js.map +1 -1
  115. package/dist/journey-cli.js +93 -10
  116. package/dist/journey-cli.js.map +1 -1
  117. package/dist/journey-demo-api.d.ts +29 -0
  118. package/dist/journey-demo-api.js +29 -7
  119. package/dist/journey-demo-api.js.map +1 -1
  120. package/dist/journey-heal.js +1 -1
  121. package/dist/journey-heal.js.map +1 -1
  122. package/dist/journey-lint-sarif.d.ts +3 -2
  123. package/dist/journey-lint-sarif.js +11 -2
  124. package/dist/journey-lint-sarif.js.map +1 -1
  125. package/dist/journey-migrate-api.d.ts +54 -0
  126. package/dist/journey-migrate-api.js +64 -0
  127. package/dist/journey-migrate-api.js.map +1 -0
  128. package/dist/journey-network-checks.d.ts +11 -0
  129. package/dist/journey-network-checks.js +36 -13
  130. package/dist/journey-network-checks.js.map +1 -1
  131. package/dist/journey-proposal-store.d.ts +9 -0
  132. package/dist/journey-proposal-store.js +23 -0
  133. package/dist/journey-proposal-store.js.map +1 -1
  134. package/dist/journey-result-record.d.ts +2 -0
  135. package/dist/journey-result-record.js +5 -0
  136. package/dist/journey-result-record.js.map +1 -1
  137. package/dist/journey-review-api.js +9 -1
  138. package/dist/journey-review-api.js.map +1 -1
  139. package/dist/journey-review.d.ts +11 -1
  140. package/dist/journey-review.js +77 -5
  141. package/dist/journey-review.js.map +1 -1
  142. package/dist/journey-stale-api.d.ts +40 -0
  143. package/dist/journey-stale-api.js +57 -0
  144. package/dist/journey-stale-api.js.map +1 -0
  145. package/dist/load-api.js +4 -2
  146. package/dist/load-api.js.map +1 -1
  147. package/dist/locator-health-api.d.ts +101 -0
  148. package/dist/locator-health-api.js +203 -0
  149. package/dist/locator-health-api.js.map +1 -0
  150. package/dist/locator-health.d.ts +195 -0
  151. package/dist/locator-health.js +419 -0
  152. package/dist/locator-health.js.map +1 -0
  153. package/dist/mcp-api.d.ts +3 -1
  154. package/dist/mcp-api.js +21 -2
  155. package/dist/mcp-api.js.map +1 -1
  156. package/dist/mcp-cli-tools.d.ts +4 -1
  157. package/dist/mcp-cli-tools.js +82 -10
  158. package/dist/mcp-cli-tools.js.map +1 -1
  159. package/dist/openrouter-call.d.ts +23 -10
  160. package/dist/openrouter-call.js +14 -11
  161. package/dist/openrouter-call.js.map +1 -1
  162. package/dist/png-pixels.d.ts +12 -0
  163. package/dist/png-pixels.js +96 -0
  164. package/dist/png-pixels.js.map +1 -0
  165. package/dist/project-config.d.ts +29 -0
  166. package/dist/project-config.js +76 -0
  167. package/dist/project-config.js.map +1 -0
  168. package/dist/regression-api.js +2 -1
  169. package/dist/regression-api.js.map +1 -1
  170. package/dist/server-log-verify.js +2 -1
  171. package/dist/server-log-verify.js.map +1 -1
  172. package/dist/signal-triage.js +7 -3
  173. package/dist/signal-triage.js.map +1 -1
  174. package/dist/source-run-api.js +2 -2
  175. package/dist/source-run-api.js.map +1 -1
  176. package/dist/verify-fix-api.d.ts +29 -0
  177. package/dist/verify-fix-api.js +43 -2
  178. package/dist/verify-fix-api.js.map +1 -1
  179. package/dist/verify-fix-cli.js +4 -0
  180. package/dist/verify-fix-cli.js.map +1 -1
  181. package/dist/zip-store.d.ts +15 -0
  182. package/dist/zip-store.js +93 -0
  183. package/dist/zip-store.js.map +1 -0
  184. package/package.json +12 -10
  185. package/skills/jevitate-ci-check/SKILL.md +16 -0
  186. package/skills/jevitate-demo/SKILL.md +4 -1
  187. package/skills/jevitate-getting-started/SKILL.md +7 -2
  188. package/skills/jevitate-run-journey/SKILL.md +15 -0
  189. package/skills/jevitate-test-campaign/SKILL.md +26 -0
  190. package/skills/jevitate-verify-fix/SKILL.md +5 -0
@@ -0,0 +1,326 @@
1
+ import { createHash } from "node:crypto";
2
+ import { existsSync, readdirSync, readFileSync, statSync } from "node:fs";
3
+ import { join, resolve } from "node:path";
4
+ import { consolidate, runFromMissionResult, runFromUxReport } from "@jevitate/findings";
5
+ import { contractRouteTemplate, uxFindingFingerprint } from "@jevitate/ux";
6
+ import { findingIssues, isRouteTemplate } from "./catalog-bundle.js";
7
+ import { dedupeSuggestions } from "./locator-health.js";
8
+ import { journeyLocatorHealth } from "./locator-health-api.js";
9
+ import { defaultReportSources, loadRunFile, scanRuns } from "./report-api.js";
10
+ const KNOWN_CLAIMS = new Set(["next-step-unclear", "no-feedback", "blocked-action", "error-unrecoverable", "destructive-unguarded", "fact-conflict"]);
11
+ const PRODUCER_CLAIM_RE = /^[a-z][a-z0-9-]{0,63}$/u;
12
+ const FINGERPRINT_RE = /^[0-9a-f]{16}$/u;
13
+ const TFLOW_ID_RE = /^[a-z0-9._:-]{1,96}$/u;
14
+ const COMMIT_RE = /^[0-9a-f]{7,40}$/u;
15
+ const TARGET_ID_RE = /^[A-Za-z0-9_.-]{1,64}$/u;
16
+ const JOURNEY_ID_RE = /^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$/u;
17
+ const DATE_TIME_RE = /^[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}(\.[0-9]{1,9})?(Z|[+-][0-9]{2}:[0-9]{2})$/u;
18
+ const CITATION_SOURCE_RE = /^[a-z0-9][a-z0-9._-]{0,63}$/u;
19
+ const CITATION_REF_RE = /^[A-Za-z0-9][A-Za-z0-9._:-]{0,63}$/u;
20
+ const SEVERITIES = new Set(["info", "minor", "major"]);
21
+ const RESERVED_ANCHORS = new Set(["job_start", "job_end"]);
22
+ const MAX_CONTROLS = 10;
23
+ const MAX_FINDINGS = 5000;
24
+ function isRecord(v) {
25
+ return v !== null && typeof v === "object" && !Array.isArray(v);
26
+ }
27
+ const str = (v) => (typeof v === "string" && v !== "" ? v : undefined);
28
+ const strings = (v) => (Array.isArray(v) ? v.filter((x) => typeof x === "string" && x !== "") : []);
29
+ /** Would this text pass the builder's guard as a finding's `observation` (≤600) / a control (≤120)? */
30
+ function safeText(text, as) {
31
+ if (text === undefined)
32
+ return false;
33
+ const probe = as === "observation"
34
+ ? { fingerprint: "0000000000000000", kind: "defect", severity: "major", at: "2000-01-01T00:00:00Z", observation: text }
35
+ : { fingerprint: "0000000000000000", kind: "defect", severity: "major", at: "2000-01-01T00:00:00Z", observation: "probe", controls: [text] };
36
+ return findingIssues(probe).length === 0;
37
+ }
38
+ /** A route as the contract's template, or undefined when it cannot be one. */
39
+ function bundleRoute(raw) {
40
+ if (raw === undefined)
41
+ return undefined;
42
+ const route = contractRouteTemplate(raw);
43
+ return isRouteTemplate(route) ? route : undefined;
44
+ }
45
+ /** Where it was seen: the Journey step a journey-anchored run branched from. */
46
+ function seenAt(branch) {
47
+ if (branch === undefined || !JOURNEY_ID_RE.test(branch.journeyId))
48
+ return {};
49
+ const step = Number.isInteger(branch.step) && branch.step >= 1 && branch.step <= 200 ? branch.step : undefined;
50
+ const anchor = branch.anchor !== undefined && JOURNEY_ID_RE.test(branch.anchor) && !RESERVED_ANCHORS.has(branch.anchor) ? branch.anchor : undefined;
51
+ return { journey: branch.journeyId, ...(step === undefined ? {} : { step }), ...(anchor === undefined ? {} : { anchor }) };
52
+ }
53
+ function runStamp(run) {
54
+ return {
55
+ ...(run.targetBuild !== undefined && COMMIT_RE.test(run.targetBuild) ? { commit: run.targetBuild } : {}),
56
+ ...(run.targetName !== undefined && TARGET_ID_RE.test(run.targetName) ? { target: run.targetName } : {}),
57
+ };
58
+ }
59
+ /** One defect/hang of the consolidated report as a bundle finding. */
60
+ function defectFinding(d, runs) {
61
+ if (d.category !== "defect" && d.category !== "invariant" && d.category !== "hang")
62
+ return null;
63
+ const fingerprint = d.identity.fingerprint;
64
+ if (fingerprint === undefined || !FINGERPRINT_RE.test(fingerprint))
65
+ return { drop: `${d.category} ${d.key}: its fingerprint is not 16 hex characters` };
66
+ if (d.lastSeen === undefined || !DATE_TIME_RE.test(d.lastSeen))
67
+ return { drop: `finding ${fingerprint}: no run names when it was seen` };
68
+ const latest = d.modes
69
+ .flatMap((m) => m.runs)
70
+ .sort((a, b) => (a.startedAt ?? "").localeCompare(b.startedAt ?? ""))
71
+ .at(-1);
72
+ const run = latest === undefined ? undefined : runs.get(latest.path);
73
+ const route = bundleRoute(d.identity.route);
74
+ const control = d.identity.control;
75
+ const tflowId = d.identity.tflowId;
76
+ const described = `${d.category === "hang" ? "Hang" : "Defect"} (${d.identity.signal}) on ${route ?? "an unknown route"}`;
77
+ return {
78
+ finding: {
79
+ fingerprint,
80
+ kind: d.category === "hang" ? "hang" : "defect",
81
+ severity: "major",
82
+ ...(run === undefined ? {} : runStamp(run)),
83
+ at: d.lastSeen,
84
+ ...seenAt(d.branches?.[0]),
85
+ ...(route === undefined ? {} : { route }),
86
+ ...(tflowId !== undefined && TFLOW_ID_RE.test(tflowId) ? { tflowId } : {}),
87
+ ...(safeText(control, "control") ? { controls: [control] } : {}),
88
+ observation: safeText(d.title, "observation") ? d.title : described,
89
+ },
90
+ };
91
+ }
92
+ /** One shown finding of a UX report as a bundle finding (the contract's derived fingerprint). */
93
+ function uxFinding(f, run) {
94
+ const rubric = str(f.rubricItemId) ?? "unknown";
95
+ const route = bundleRoute(str(f.route));
96
+ if (route === undefined)
97
+ return { drop: `UX finding (${rubric}): its route is not a route template` };
98
+ const type = isRecord(f.claim) ? str(f.claim.type) : undefined;
99
+ const known = type !== undefined && KNOWN_CLAIMS.has(type);
100
+ const producerClaim = known ? undefined : (type ?? rubric);
101
+ if (producerClaim !== undefined && !PRODUCER_CLAIM_RE.test(producerClaim))
102
+ return { drop: `UX finding on ${route}: its claim type is not a producer claim name` };
103
+ const claim = (known ? type : "other");
104
+ const severity = str(f.severity);
105
+ const confidence = f.confidence;
106
+ if (severity === undefined || !SEVERITIES.has(severity))
107
+ return { drop: `UX finding (${claim}) on ${route}: no contract severity` };
108
+ if (typeof confidence !== "number" || !(confidence >= 0 && confidence <= 1))
109
+ return { drop: `UX finding (${claim}) on ${route}: no confidence in [0, 1]` };
110
+ if (run.startedAt === undefined || !DATE_TIME_RE.test(run.startedAt))
111
+ return { drop: `UX finding (${claim}) on ${route}: its run names no start time` };
112
+ const observation = str(f.observation);
113
+ if (observation === undefined)
114
+ return { drop: `UX finding (${claim}) on ${route}: no observation` };
115
+ const tflowRaw = str(f.tflowId);
116
+ const tflowId = tflowRaw !== undefined && TFLOW_ID_RE.test(tflowRaw) ? tflowRaw : undefined;
117
+ const controls = strings(f.controls).slice(0, MAX_CONTROLS);
118
+ const fingerprint = uxFindingFingerprint({ claim, ...(producerClaim === undefined ? {} : { producerClaim }), route, ...(tflowId === undefined ? {} : { tflowId }), controls });
119
+ const citation = isRecord(f.citation) ? { source: str(f.citation.source), ref: str(f.citation.ref) } : undefined;
120
+ const userImpact = str(f.userImpact);
121
+ const recommendation = str(f.recommendation);
122
+ return {
123
+ finding: {
124
+ fingerprint,
125
+ kind: "ux",
126
+ claim,
127
+ ...(producerClaim === undefined ? {} : { producerClaim }),
128
+ severity: severity,
129
+ confidence,
130
+ ...runStamp(run),
131
+ at: run.startedAt,
132
+ ...seenAt(run.branch),
133
+ route,
134
+ ...(tflowId === undefined ? {} : { tflowId }),
135
+ ...(controls.length === 0 ? {} : { controls }),
136
+ observation,
137
+ ...(userImpact === undefined ? {} : { userImpact }),
138
+ ...(recommendation === undefined ? {} : { recommendation }),
139
+ ...(citation?.source !== undefined && citation.ref !== undefined && CITATION_SOURCE_RE.test(citation.source) && CITATION_REF_RE.test(citation.ref)
140
+ ? { citation: { source: citation.source, ref: citation.ref } }
141
+ : {}),
142
+ },
143
+ };
144
+ }
145
+ /** The warning for a finding the builder's guard drops: the fingerprint and rule, never the offending text. */
146
+ function findingDropWarning(fingerprint, kind, issues) {
147
+ return `finding ${fingerprint} (${kind}): ${issues.map((i) => i.replace(/^finding [0-9a-f]+: /u, "").replace(/ "[^"]*"/gu, "")).join("; ")} — left out of the bundle`;
148
+ }
149
+ /** The bundle's findings from what the runs persisted (pure): one per fingerprint, latest sighting first-class. */
150
+ export function bundleFindings(src) {
151
+ const warnings = [];
152
+ const latest = new Map();
153
+ const keep = (m) => {
154
+ if (m === null)
155
+ return;
156
+ if ("drop" in m) {
157
+ warnings.push(`${m.drop} — left out of the bundle`);
158
+ return;
159
+ }
160
+ const issues = findingIssues(m.finding);
161
+ if (issues.length > 0) {
162
+ // Name the fingerprint and the rule only: the offending text never reaches a warning.
163
+ warnings.push(findingDropWarning(m.finding.fingerprint, m.finding.kind, issues));
164
+ return;
165
+ }
166
+ const prev = latest.get(m.finding.fingerprint);
167
+ if (prev === undefined || prev.at <= m.finding.at)
168
+ latest.set(m.finding.fingerprint, m.finding);
169
+ };
170
+ const byPath = new Map(src.runs.map((r) => [r.path, r]));
171
+ for (const d of consolidate(src.runs))
172
+ keep(defectFinding(d, byPath));
173
+ for (const { report, run } of src.uxReports) {
174
+ if (!isRecord(report) || !Array.isArray(report.findings))
175
+ continue;
176
+ for (const f of report.findings)
177
+ if (isRecord(f))
178
+ keep(uxFinding(f, run));
179
+ }
180
+ let findings = [...latest.values()].sort((a, b) => a.at.localeCompare(b.at) || a.fingerprint.localeCompare(b.fingerprint));
181
+ if (findings.length > MAX_FINDINGS) {
182
+ warnings.push(`${findings.length} findings: only the latest ${MAX_FINDINGS} are exported`);
183
+ findings = findings.slice(-MAX_FINDINGS);
184
+ }
185
+ return { findings, warnings };
186
+ }
187
+ /**
188
+ * #479 (minor 1) — the locator findings: one per brittle ELEMENT (§4.4, spec bundle-minor1 §1). Each
189
+ * promoted Journey's locator health (`journeyLocatorHealth`) becomes suggestions, de-duplicated by
190
+ * element across Journeys; each suggestion is a `kind: "ux"` / claim `other` / producerClaim
191
+ * `locator-brittle` finding, dated at the latest approval of the Journeys it occurs in. A suggestion
192
+ * whose route cannot be a template, that has no approval time, or that fails the builder's privacy
193
+ * guard is LEFT OUT with a warning. Pure: no clock, no I/O.
194
+ */
195
+ export function locatorFindings(journeys, testIdAttributes) {
196
+ const warnings = [];
197
+ const suggestions = dedupeSuggestions(journeys.map((cj) => journeyLocatorHealth(cj.journey, testIdAttributes).suggestions));
198
+ const approvalAt = new Map();
199
+ for (const cj of journeys) {
200
+ const at = cj.approval?.at;
201
+ if (at !== undefined && DATE_TIME_RE.test(at))
202
+ approvalAt.set(cj.id, at);
203
+ }
204
+ const findings = [];
205
+ for (const s of suggestions) {
206
+ const route = bundleRoute(s.route);
207
+ if (route === undefined) {
208
+ // Journeeze requires a route template on every UX finding (catalog bundle v1 §4.4).
209
+ warnings.push(`locator ${s.key}: ${s.route === undefined ? "its page has no route" : "its route is not a route template"} — left out of the bundle`);
210
+ continue;
211
+ }
212
+ const first = s.occurrences[0];
213
+ if (first === undefined)
214
+ continue;
215
+ const at = s.occurrences
216
+ .map((o) => (o.journeyId === undefined ? undefined : approvalAt.get(o.journeyId)))
217
+ .filter((v) => v !== undefined)
218
+ .sort()
219
+ .at(-1);
220
+ if (at === undefined) {
221
+ warnings.push(`locator ${s.key}: no approval time to date it — left out of the bundle`);
222
+ continue;
223
+ }
224
+ const key = s.key.slice(s.key.indexOf("|") + 1);
225
+ const fingerprint = createHash("sha256").update(`ux\nlocator-brittle\n${route ?? ""}\n${key}`, "utf8").digest("hex").slice(0, 16);
226
+ const step = first.index + 1;
227
+ // The fix names the page by its raw path; the bundle only ever carries the route template.
228
+ const fix = s.route !== undefined && route !== undefined && s.route !== route ? s.fix.split(s.route).join(route) : s.fix;
229
+ const finding = {
230
+ fingerprint,
231
+ kind: "ux",
232
+ claim: "other",
233
+ producerClaim: "locator-brittle",
234
+ severity: "minor",
235
+ // Static classification of the recorded locator, not a model judgement: certain.
236
+ confidence: 1,
237
+ at,
238
+ ...(first.journeyId === undefined ? {} : { journey: first.journeyId }),
239
+ ...(step < 1 || step > 200 ? {} : { step }),
240
+ route,
241
+ observation: `${s.element} on ${route} is found by a brittle locator (${s.reasons.join(", ")})`,
242
+ recommendation: fix,
243
+ locator: { element: s.element, attribute: s.attribute, testId: s.testId, fix, steps: s.occurrences.length },
244
+ };
245
+ const issues = findingIssues(finding);
246
+ if (issues.length > 0) {
247
+ warnings.push(findingDropWarning(fingerprint, finding.kind, issues));
248
+ continue;
249
+ }
250
+ findings.push(finding);
251
+ }
252
+ return { findings, warnings };
253
+ }
254
+ // ── I/O: where the project's findings live ──────────────────────────────────────────────────
255
+ const OFFLINE_UX_REPORT = /^ux-\d{4}-\d{2}-\d{2}T\d{2}-\d{2}-\d{2}-\d{3}Z\.json$/u;
256
+ function readJsonOrNull(path) {
257
+ try {
258
+ return JSON.parse(readFileSync(path, "utf8"));
259
+ }
260
+ catch {
261
+ return null; // unreadable/partial: not a source (never a fabricated one)
262
+ }
263
+ }
264
+ /** The ledger's entries as runs: each is a redacted mission result holding one defect or hang. */
265
+ function ledgerRuns(dataDir) {
266
+ if (dataDir === null)
267
+ return [];
268
+ const dir = join(dataDir, "regressions", "ledger");
269
+ if (!existsSync(dir))
270
+ return [];
271
+ const out = [];
272
+ for (const f of readdirSync(dir).sort()) {
273
+ if (!/^[0-9a-f]{16}\.json$/u.test(f))
274
+ continue;
275
+ const entry = readJsonOrNull(join(dir, f));
276
+ if (!isRecord(entry) || !isRecord(entry.ledger) || !isRecord(entry.result))
277
+ continue;
278
+ const meta = entry.ledger;
279
+ const source = isRecord(meta.source) ? meta.source : {};
280
+ const run = runFromMissionResult(join(dir, f), {
281
+ missionOutcome: str(source.missionOutcome) ?? "defects-found",
282
+ result: { ...(str(meta.addedAt) === undefined ? {} : { startedAt: str(meta.addedAt) }), ...entry.result },
283
+ });
284
+ if (run !== null)
285
+ out.push(run);
286
+ }
287
+ return out;
288
+ }
289
+ /** Reads the project's runs, UX reports and ledger, and returns the bundle's findings. */
290
+ export async function collectBundleFindings(opts) {
291
+ const sources = defaultReportSources(false, { cwd: () => opts.root, ...opts.index });
292
+ const runs = scanRuns(sources.dirs);
293
+ const seen = new Set(runs.map((r) => resolve(r.path)));
294
+ for (const f of sources.files) {
295
+ if (seen.has(resolve(f)))
296
+ continue;
297
+ seen.add(resolve(f));
298
+ const run = loadRunFile(f);
299
+ if (run !== null)
300
+ runs.push(run);
301
+ }
302
+ const uxReports = [];
303
+ for (const run of runs) {
304
+ if (run.mode !== "usability")
305
+ continue;
306
+ const raw = readJsonOrNull(run.path);
307
+ const report = isRecord(raw) && Array.isArray(raw.findings) ? raw : isRecord(raw) && isRecord(raw.result) ? raw.result.report : undefined;
308
+ if (report !== undefined)
309
+ uxReports.push({ report, run });
310
+ }
311
+ for (const dir of sources.dirs) {
312
+ if (!existsSync(dir) || !statSync(dir).isDirectory())
313
+ continue;
314
+ for (const f of readdirSync(dir).sort()) {
315
+ if (!OFFLINE_UX_REPORT.test(f))
316
+ continue;
317
+ const path = join(dir, f);
318
+ const raw = readJsonOrNull(path);
319
+ const run = runFromUxReport(path, raw);
320
+ if (run !== null)
321
+ uxReports.push({ report: raw, run });
322
+ }
323
+ }
324
+ return bundleFindings({ runs: [...runs, ...ledgerRuns(opts.dataDir)], uxReports });
325
+ }
326
+ //# sourceMappingURL=catalog-bundle-findings.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"catalog-bundle-findings.js","sourceRoot":"","sources":["../src/catalog-bundle-findings.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,296 @@
1
+ import { JOURNEY_RUN_OUTCOMES, type MissionOutcome } from "@jevitate/domain";
2
+ import { CatalogInputError, type Catalog } from "./catalog.js";
3
+ /**
4
+ * #464 (d464a) — the PURE builder of a Journeeze catalog bundle, version 1.0 (journeeze-saas
5
+ * `docs/contract/catalog-bundle-v1.md` at 61f8c92, schema `catalog-bundle.v1.json`). No I/O, no
6
+ * clock: catalog-bundle-api.ts loads the catalog, the raw persona entries, the `check.json` records
7
+ * and the producer identity, and writes what this returns.
8
+ *
9
+ * What goes out, and how (each rule is the contract's):
10
+ * - personas: `{id, description, role, otherFields, approval}` — every descriptive key, so §8's
11
+ * persona hash (`{id, …description, role and otherFields}`) recomputes to jevitate's
12
+ * `personaContentHash`. Session keys (`storageState`, `login`) never leave.
13
+ * - jobs: the `jobs.json` entry as loaded (every jtbd and campaign field — the hash input), with its
14
+ * approval reduced to the contract's `{contentHash, at, channel}` (approval is outside the hash).
15
+ * - journeys: PROMOTED Journeys only, the file as jevitate reads it (the review-hash input), with
16
+ * approval provenance reduced to `{channel, agentSignals}` (no OS user, no reason, no PR reviewer —
17
+ * bookkeeping outside the hash), and `link {job, persona, anchors, serves}` from its metadata.
18
+ * - checks: one per check item that ran, keyed (target.id, commit, runId); a baseline only from a
19
+ * clean run whose `journeyHash` is the exported Journey's approved hash.
20
+ * - findings: whatever the d464c source hands in (`CatalogBundleFinding`), guarded; none by default.
21
+ * - demos and media (#471): one `demos[]` entry per exported, APPROVED Journey that has an
22
+ * approved-demo record (approved-demo.ts: written by `demo approve` only on a `synthetic: true`
23
+ * environment, from a jz-mask-v1 render), whose `renderedFrom` is the Journey's current approved
24
+ * hash. Its `privacy` is the record's attestation. Media is only what the record proved masked
25
+ * and the API re-verified (present, same sha256, the right file type): `media/<id>/step-NN.png`,
26
+ * `media/<id>/demo.webm` and `demo.vtt` (subtitles only with the video), each listed in `files[]`.
27
+ * Over a §10 limit (2 MiB / 50 MiB / 256 KiB per file, 512 MiB and 4,000 files per bundle), a
28
+ * file is left out with a warning, never sent. A demo whose caption breaks §7's text rules is
29
+ * left out whole (its subtitles carry the same text). A draft demo has no record: never exported.
30
+ * - `generatedAt` is left out on purpose: the same catalog gives the same bytes, so the upload's
31
+ * `Idempotency-Key` (sha256 of bundle.json) dedupes a re-publish.
32
+ *
33
+ * Failure policy: personal data or a credential typed in clear anywhere, or a job the bundle cannot
34
+ * carry (a structural reference problem, text that is not one line), REFUSES the export
35
+ * (`CatalogBundleInputError`, exit 64) — nothing is guessed or silently rewritten. So does a
36
+ * PROMOTED Journey the bundle cannot carry (#478: never a silent omission). A draft Journey, or a
37
+ * check the bundle cannot carry, is LEFT OUT with a warning (nothing else references it in a way the
38
+ * reader would refuse). A persona key the bundle cannot carry drops that key and the persona's
39
+ * approval (its hash could not recompute) with a warning.
40
+ */
41
+ export declare const BUNDLE_KIND: "journeeze.catalog-bundle";
42
+ export declare const BUNDLE_VERSION: 1;
43
+ /** The schema minor this producer is built against (minor 1, journeeze-saas #173: optional `finding.locator` and `check.appVersion`). */
44
+ export declare const BUNDLE_MINOR: 1;
45
+ export interface BundleApproval {
46
+ readonly contentHash: string;
47
+ readonly at: string;
48
+ readonly channel?: string;
49
+ }
50
+ export interface BundlePersona {
51
+ readonly id: string;
52
+ readonly description?: string;
53
+ readonly role?: string;
54
+ readonly otherFields?: Readonly<Record<string, string | number | boolean>>;
55
+ readonly approval?: BundleApproval;
56
+ }
57
+ /** A `jobs.json` entry as loaded, with its approval in the contract's shape. */
58
+ export type BundleJob = Readonly<Record<string, unknown>> & {
59
+ readonly id: string;
60
+ readonly approval?: BundleApproval;
61
+ };
62
+ export interface BundleAnchor {
63
+ readonly name: string;
64
+ /** 1-based step of the Journey's flat step list. */
65
+ readonly step: number;
66
+ readonly jobStep?: string;
67
+ readonly boundary?: "start" | "end";
68
+ }
69
+ export interface BundleLink {
70
+ readonly job: string;
71
+ readonly persona?: string;
72
+ readonly anchors?: readonly BundleAnchor[];
73
+ readonly serves?: readonly string[];
74
+ }
75
+ export interface BundleJourneyEntry {
76
+ /** The Journey file (opaque to the reader beyond a few metadata fields). */
77
+ readonly journey: Readonly<Record<string, unknown>>;
78
+ readonly link?: BundleLink;
79
+ }
80
+ export declare const CHECK_TARGET_KINDS: readonly ["journey", "goal", "mission", "invariant", "verify_fix", "regression"];
81
+ export type BundleCheckTargetKind = (typeof CHECK_TARGET_KINDS)[number];
82
+ export interface BundleBaselinePoint {
83
+ /** An anchor name, or the reserved `job_start` / `job_end`. */
84
+ readonly anchor: string;
85
+ readonly step: number;
86
+ /** Milliseconds from the first step's start to this step's completion. */
87
+ readonly atMs: number;
88
+ }
89
+ export interface BundleBaseline {
90
+ readonly steps: number;
91
+ readonly totalMs: number;
92
+ readonly anchors: readonly BundleBaselinePoint[];
93
+ }
94
+ export interface BundleCheck {
95
+ readonly target: {
96
+ readonly id: string;
97
+ readonly kind?: BundleCheckTargetKind;
98
+ };
99
+ readonly commit: string;
100
+ /** #479 (spec minor 1 §2): the app's release/version label the check ran against; `commit` stays the build identity. */
101
+ readonly appVersion?: string;
102
+ readonly at: string;
103
+ readonly runId?: string;
104
+ readonly journey?: string;
105
+ readonly journeyHash?: string;
106
+ readonly outcome: MissionOutcome;
107
+ readonly exitCode: number;
108
+ readonly journeyOutcome?: (typeof JOURNEY_RUN_OUTCOMES)[number];
109
+ readonly failureKind?: string;
110
+ readonly durationMs?: number;
111
+ readonly baseline?: BundleBaseline;
112
+ }
113
+ export interface BundleLocator {
114
+ /** The element in words, e.g. `the "Save" button`. One printable line, 1-200, no URL or personal data. */
115
+ readonly element: string;
116
+ /** The attribute the fix adds (the convention's first). */
117
+ readonly attribute: string;
118
+ /** The suggested test id. */
119
+ readonly testId: string;
120
+ /** The fix, e.g. `add data-testid="save-contact" to the "Save" button on /contacts/new`. One line, 1-300. */
121
+ readonly fix: string;
122
+ /** The steps (across Journeys) that use the element. */
123
+ readonly steps: number;
124
+ }
125
+ /**
126
+ * d464c HOOK: one machine finding as the contract's `findings[]` carries it (§4.4) — UX claims with
127
+ * the derived fingerprint, defects and hangs with jevitate's. 0.10 exports no media, so no
128
+ * `screenshot`/`box`. The d464c deliverable produces these (fingerprint + PII scan) and passes them in
129
+ * through `CatalogBundleInput.findings`; until then the bundle carries `findings: []`.
130
+ */
131
+ export interface CatalogBundleFinding {
132
+ readonly fingerprint: string;
133
+ readonly kind: "ux" | "defect" | "hang";
134
+ readonly claim?: "next-step-unclear" | "no-feedback" | "blocked-action" | "error-unrecoverable" | "destructive-unguarded" | "fact-conflict" | "other";
135
+ readonly producerClaim?: string;
136
+ readonly severity: "info" | "minor" | "major";
137
+ readonly confidence?: number;
138
+ readonly commit?: string;
139
+ readonly at: string;
140
+ readonly target?: string;
141
+ readonly journey?: string;
142
+ readonly step?: number;
143
+ readonly anchor?: string;
144
+ /** A route TEMPLATE: no query, fragment, host or record id. */
145
+ readonly route?: string;
146
+ readonly tflowId?: string;
147
+ readonly controls?: readonly string[];
148
+ readonly observation: string;
149
+ readonly userImpact?: string;
150
+ readonly recommendation?: string;
151
+ /** Minor 1 (§1): the brittle-element fix; only on kind `ux` + claim `other` + producerClaim `locator-brittle`, required there. */
152
+ readonly locator?: BundleLocator;
153
+ readonly citation?: {
154
+ readonly source: string;
155
+ readonly ref: string;
156
+ };
157
+ }
158
+ /** #471: one guide step of a demo (contract §4.2). */
159
+ export interface BundleDemoStep {
160
+ readonly number: number;
161
+ readonly caption: string;
162
+ readonly expected?: string;
163
+ /** `media/<journey>/step-NN.png`. */
164
+ readonly screenshot?: string;
165
+ }
166
+ /** #471: the jz-mask-v1 + synthetic-data attestation every demo carries (contract §7). */
167
+ export interface BundlePrivacy {
168
+ readonly mask: "jz-mask-v1";
169
+ readonly data: "synthetic";
170
+ readonly method: "dom-before-capture" | "pixels-after-capture";
171
+ readonly regions: number;
172
+ }
173
+ /** #471: one approved demo's media manifest (contract §4.2). */
174
+ export interface BundleDemo {
175
+ readonly journey: string;
176
+ readonly renderedFrom: string;
177
+ readonly status: "approved";
178
+ readonly title?: string;
179
+ readonly steps: readonly BundleDemoStep[];
180
+ readonly video?: string;
181
+ readonly subtitles?: string;
182
+ readonly privacy: BundlePrivacy;
183
+ }
184
+ export type BundleFileType = "image/png" | "image/webp" | "video/webm" | "text/vtt";
185
+ /** #471: one media file of the bundle (contract §2): listed ⇔ present ⇔ referenced. */
186
+ export interface BundleFile {
187
+ readonly path: string;
188
+ readonly sha256: string;
189
+ readonly bytes: number;
190
+ readonly type: BundleFileType;
191
+ }
192
+ export interface CatalogBundleV1 {
193
+ readonly kind: typeof BUNDLE_KIND;
194
+ readonly version: typeof BUNDLE_VERSION;
195
+ readonly minor: typeof BUNDLE_MINOR;
196
+ readonly producer: {
197
+ readonly tool: "jevitate";
198
+ readonly version: string;
199
+ readonly commit?: string;
200
+ };
201
+ readonly product: {
202
+ readonly name: string;
203
+ };
204
+ readonly catalog: {
205
+ readonly personas: readonly BundlePersona[];
206
+ readonly jobs: readonly BundleJob[];
207
+ readonly journeys: readonly BundleJourneyEntry[];
208
+ };
209
+ /** #471: present (with `files`) only when at least one approved demo is exported. */
210
+ readonly demos?: readonly BundleDemo[];
211
+ readonly checks: readonly BundleCheck[];
212
+ readonly findings: readonly CatalogBundleFinding[];
213
+ readonly files?: readonly BundleFile[];
214
+ }
215
+ /**
216
+ * #471: an approved demo as the API hands it in: the record's manifest, and the media files the API
217
+ * re-verified on disk (present, sha256 and size as recorded, the right file type), by record name.
218
+ */
219
+ export interface CatalogBundleDemoInput {
220
+ readonly journey: string;
221
+ readonly renderedFrom: string;
222
+ readonly title?: string;
223
+ readonly steps: ReadonlyArray<{
224
+ readonly number: number;
225
+ readonly caption: string;
226
+ readonly expected?: string;
227
+ readonly screenshot?: string;
228
+ }>;
229
+ readonly video?: string;
230
+ readonly subtitles?: string;
231
+ readonly privacy: BundlePrivacy;
232
+ /** Verified media by record file name (`step-01.png`, `demo.webm`, `demo.vtt`): `source` is the file on disk. */
233
+ readonly media: Readonly<Record<string, {
234
+ readonly source: string;
235
+ readonly sha256: string;
236
+ readonly bytes: number;
237
+ }>>;
238
+ }
239
+ /** #471: a media file to place in the bundle: `source` on disk → `path` under the bundle root. */
240
+ export interface BundleMediaCopy {
241
+ readonly path: string;
242
+ readonly source: string;
243
+ }
244
+ /** One `jevitate check` record (`check.json`'s `data`, or the bare result) and where it came from. */
245
+ export interface CheckRecordInput {
246
+ readonly source: string;
247
+ readonly record: unknown;
248
+ }
249
+ export interface CatalogBundleInput {
250
+ /** `producer.version` (semver) and `producer.commit` (the product repo's HEAD, when known). */
251
+ readonly producer: {
252
+ readonly version: string;
253
+ readonly commit?: string;
254
+ };
255
+ readonly productName: string;
256
+ readonly catalog: Catalog;
257
+ /** Each persona's raw `personas.json` keys (all but its `name`/`id`) — the persona hash input. */
258
+ readonly personaFields: ReadonlyMap<string, Readonly<Record<string, unknown>>>;
259
+ readonly checks: readonly CheckRecordInput[];
260
+ /** d464c: the machine findings to export (default none). */
261
+ readonly findings?: readonly CatalogBundleFinding[];
262
+ /** #471: approved demos with their verified media (default none). */
263
+ readonly demos?: readonly CatalogBundleDemoInput[];
264
+ }
265
+ export interface CatalogBundleBuild {
266
+ readonly bundle: CatalogBundleV1;
267
+ /** #471: the media files to place beside bundle.json (exactly `bundle.files`, with their sources). */
268
+ readonly media: readonly BundleMediaCopy[];
269
+ /** Items left out or degraded, each with why. */
270
+ readonly warnings: readonly string[];
271
+ }
272
+ /** The catalog cannot be exported as it is (personal data, a credential typed in clear, a job the bundle cannot carry) — exit 64. */
273
+ export declare class CatalogBundleInputError extends CatalogInputError {
274
+ readonly issues: readonly string[];
275
+ readonly code: string;
276
+ constructor(issues: readonly string[]);
277
+ }
278
+ /** #471: contract §10's media limits. */
279
+ export declare const MEDIA_LIMITS: {
280
+ readonly screenshotBytes: number;
281
+ readonly videoBytes: number;
282
+ readonly subtitlesBytes: number;
283
+ readonly totalBytes: number;
284
+ readonly files: 4000;
285
+ readonly demoSteps: 200;
286
+ };
287
+ /** Looks like personal data (an email, or 9+ digits) — the contract's `noPersonalData`. */
288
+ export declare function looksPersonal(s: string): boolean;
289
+ /** The contract's `routeTemplate`: a path template — no query string, fragment, host or record id. */
290
+ export declare function isRouteTemplate(route: string): boolean;
291
+ /** Why a subtitles file's text breaks §7 (a cue line that is not machine text, a DRAFT note), or null. */
292
+ export declare function subtitlesTextProblem(vtt: string): string | null;
293
+ /** Why a finding handed in by the d464c source breaks the contract's privacy rules (§7), or []. */
294
+ export declare function findingIssues(f: CatalogBundleFinding): string[];
295
+ /** Builds the bundle (pure). Throws `CatalogBundleInputError` when the catalog cannot be exported. */
296
+ export declare function buildCatalogBundle(input: CatalogBundleInput): CatalogBundleBuild;