@haystackeditor/cli 0.25.1 → 0.27.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 (109) hide show
  1. package/README.md +39 -463
  2. package/dist/capture/app-config.js +30 -6
  3. package/dist/commands/capture-brief.js +45 -35
  4. package/dist/commands/capture-contract.js +4 -4
  5. package/dist/commands/crawl-report.js +196 -0
  6. package/dist/commands/db-profile-upload.js +3 -3
  7. package/dist/commands/feedback.js +66 -0
  8. package/dist/commands/init-telemetry.js +55 -9
  9. package/dist/commands/init.js +8 -3
  10. package/dist/commands/lockfile-pin.js +307 -0
  11. package/dist/commands/telemetry-token.js +3 -3
  12. package/dist/commands/tokens.js +4 -4
  13. package/dist/commands/verify-explore.js +3 -3
  14. package/dist/commands/verify-history.js +2 -2
  15. package/dist/commands/verify-onboarding.js +13 -16
  16. package/dist/commands/verify-precompute.js +3 -4
  17. package/dist/commands/verify.js +31 -118
  18. package/dist/index.js +55 -968
  19. package/dist/schema.js +4 -10
  20. package/dist/utils/haystack-api.js +8 -36
  21. package/package.json +1 -5
  22. package/schemas/feedback.v1.json +13 -0
  23. package/schemas/pre-verify.v2.json +240 -0
  24. package/schemas/verify-raw.v1.json +1132 -0
  25. package/schemas/verify.v2.json +655 -0
  26. package/dist/assets/hooks/agent-context/detect.ts +0 -316
  27. package/dist/assets/hooks/agent-context/format.ts +0 -100
  28. package/dist/assets/hooks/agent-context/index.ts +0 -41
  29. package/dist/assets/hooks/agent-context/parsers/claude.ts +0 -262
  30. package/dist/assets/hooks/agent-context/parsers/codex.ts +0 -416
  31. package/dist/assets/hooks/agent-context/parsers/gemini.ts +0 -155
  32. package/dist/assets/hooks/agent-context/parsers/opencode.ts +0 -174
  33. package/dist/assets/hooks/agent-context/tsconfig.json +0 -14
  34. package/dist/assets/hooks/agent-context/types.ts +0 -58
  35. package/dist/assets/hooks/llm-rules-template.md +0 -59
  36. package/dist/assets/hooks/package-lock.json +0 -598
  37. package/dist/assets/hooks/package.json +0 -12
  38. package/dist/assets/hooks/scripts/commit-msg.sh +0 -5
  39. package/dist/assets/hooks/scripts/post-commit.sh +0 -5
  40. package/dist/assets/hooks/scripts/pre-commit.sh +0 -175
  41. package/dist/assets/hooks/scripts/pre-push.sh +0 -25
  42. package/dist/assets/hooks/scripts/prepare-commit-msg.sh +0 -5
  43. package/dist/assets/hooks/truncation-checker/ast-analyzer.ts +0 -528
  44. package/dist/assets/hooks/truncation-checker/index.ts +0 -595
  45. package/dist/assets/hooks/truncation-checker/tsconfig.json +0 -13
  46. package/dist/assets/skills/map-cloud-verifier-universe/SKILL.md +0 -2051
  47. package/dist/assets/skills/map-cloud-verifier-universe/agents/openai.yaml +0 -4
  48. package/dist/assets/skills/map-cloud-verifier-universe/references/output-contract.md +0 -3411
  49. package/dist/assets/skills/map-your-system.md +0 -143
  50. package/dist/assets/skills/submit.md +0 -200
  51. package/dist/commands/ask.js +0 -20
  52. package/dist/commands/cloud-verifier-behaviors.js +0 -218
  53. package/dist/commands/cloud-verifier-data-store-census.js +0 -539
  54. package/dist/commands/cloud-verifier-data-store-drift.js +0 -158
  55. package/dist/commands/cloud-verifier-identity-census.js +0 -4060
  56. package/dist/commands/cloud-verifier-materialization.js +0 -704
  57. package/dist/commands/cloud-verifier-pascal-selector-census.js +0 -1382
  58. package/dist/commands/cloud-verifier-python-manifest-selector-census.js +0 -2015
  59. package/dist/commands/cloud-verifier-specialized-operational-census.js +0 -11432
  60. package/dist/commands/cloud-verifier-universe.js +0 -10178
  61. package/dist/commands/config.js +0 -549
  62. package/dist/commands/design-verify.js +0 -311
  63. package/dist/commands/dismiss.js +0 -159
  64. package/dist/commands/hooks.js +0 -226
  65. package/dist/commands/inbox.js +0 -137
  66. package/dist/commands/mcp.js +0 -201
  67. package/dist/commands/policy.js +0 -371
  68. package/dist/commands/pr-status.js +0 -207
  69. package/dist/commands/pr.js +0 -105
  70. package/dist/commands/prepare-universe-review.js +0 -1092
  71. package/dist/commands/production-source-deny-policy.js +0 -100
  72. package/dist/commands/request-review.js +0 -74
  73. package/dist/commands/review.js +0 -191
  74. package/dist/commands/rules.js +0 -98
  75. package/dist/commands/scaffold-provisional-universe.js +0 -806
  76. package/dist/commands/setup.js +0 -1170
  77. package/dist/commands/skills.js +0 -447
  78. package/dist/commands/status.js +0 -35
  79. package/dist/commands/submit.js +0 -745
  80. package/dist/commands/system-map.js +0 -228
  81. package/dist/commands/triage.js +0 -598
  82. package/dist/commands/webhooks.js +0 -241
  83. package/dist/states.js +0 -46
  84. package/dist/tools/detect.js +0 -832
  85. package/dist/triage/astra.js +0 -202
  86. package/dist/triage/prompts.js +0 -188
  87. package/dist/triage/runner.js +0 -200
  88. package/dist/triage/types.js +0 -7
  89. package/dist/types.js +0 -326
  90. package/dist/utils/action-output.js +0 -26
  91. package/dist/utils/analysis-api.js +0 -416
  92. package/dist/utils/config.js +0 -54
  93. package/dist/utils/design-verifier-api.js +0 -294
  94. package/dist/utils/design-verifier-history.js +0 -79
  95. package/dist/utils/design-verifier-result.js +0 -424
  96. package/dist/utils/github-api.js +0 -324
  97. package/dist/utils/pending-state.js +0 -86
  98. package/dist/utils/pr-ref.js +0 -56
  99. package/dist/utils/prompter.js +0 -328
  100. package/schemas/action.v1.json +0 -22
  101. package/schemas/ask.v1.json +0 -40
  102. package/schemas/inbox.v1.json +0 -27
  103. package/schemas/pr-status.v1.json +0 -61
  104. package/schemas/pr.v1.json +0 -97
  105. package/schemas/pr.v3.json +0 -45
  106. package/schemas/setup.v1.json +0 -75
  107. package/schemas/submit.v1.json +0 -90
  108. package/schemas/triage.v1.json +0 -103
  109. package/schemas/triage.v2.json +0 -64
@@ -1,424 +0,0 @@
1
- import { isDeepStrictEqual } from 'node:util';
2
- function findingExplanation(kind) {
3
- if (kind === 'declared-change-not-observed') {
4
- return 'The registered intended behavior change was not observed; investigate the captured outputs before concluding why.';
5
- }
6
- if (kind === 'unexpected-change') {
7
- return 'The proposed revision produced a difference outside this case’s registered intent; this is an anomaly candidate for investigation.';
8
- }
9
- if (kind === 'intended-change-control-confounded') {
10
- return 'The intended difference was observed, but control-before also varied on an intersecting output path; inspect it before claiming causality.';
11
- }
12
- return 'Executed behavior produced a suspicious difference against the registered expectation.';
13
- }
14
- function sameRecordedValue(left, right) {
15
- return isDeepStrictEqual(left, right);
16
- }
17
- function executionSummaries(value) {
18
- if (!Array.isArray(value))
19
- return [];
20
- return value.filter((execution) => !!execution && typeof execution === 'object' &&
21
- ['base1', 'base2', 'head'].includes(execution.side) &&
22
- ['completed', 'failed', 'missing'].includes(execution.status) &&
23
- Array.isArray(execution.diagnostics) && Array.isArray(execution.outputExcerpt));
24
- }
25
- function universeSummaries(value, caseId) {
26
- if (!Array.isArray(value))
27
- return [];
28
- return value.filter((universe) => universe?.version === 'dv-case-universe-summary-v1' && universe.caseId === caseId &&
29
- /^universe-[0-9a-f]{24}$/.test(universe.universeId || '') &&
30
- ['control-before', 'before', 'after'].includes(universe.role) &&
31
- universe.lease && typeof universe.lease.available === 'boolean');
32
- }
33
- function runHealthOf(value) {
34
- if (!value || typeof value !== 'object' || Array.isArray(value))
35
- return null;
36
- const health = value;
37
- if (health.version !== 'dv-run-health-v1' ||
38
- !['healthy', 'degraded', 'invalid'].includes(health.status) ||
39
- !Number.isInteger(health.admitted) || health.admitted < 0 ||
40
- !Array.isArray(health.losses))
41
- return null;
42
- const losses = health.losses.filter((loss) => loss && typeof loss === 'object' &&
43
- typeof loss.code === 'string' && loss.code.length > 0 &&
44
- ['harness', 'case'].includes(loss.owner) &&
45
- ['degraded', 'invalid'].includes(loss.impact) &&
46
- Number.isInteger(loss.count) && loss.count > 0 &&
47
- [loss.caseIds, loss.obligationIds, loss.slotIds, loss.sides]
48
- .every(items => Array.isArray(items) && items.every(item => typeof item === 'string')));
49
- if (losses.length !== health.losses.length)
50
- return null;
51
- const invalidHarnessLoss = losses.some(loss => loss.owner === 'harness' && loss.impact === 'invalid');
52
- const expectedStatus = health.admitted === 0 || invalidHarnessLoss
53
- ? 'invalid'
54
- : losses.length > 0 ? 'degraded' : 'healthy';
55
- if (health.status !== expectedStatus)
56
- return null;
57
- return {
58
- version: health.version,
59
- status: health.status,
60
- admitted: health.admitted,
61
- losses,
62
- };
63
- }
64
- function missingRunHealth() {
65
- return {
66
- version: 'dv-run-health-v1',
67
- status: 'invalid',
68
- admitted: 0,
69
- losses: [{
70
- code: 'run-health-missing',
71
- owner: 'harness',
72
- impact: 'invalid',
73
- count: 1,
74
- caseIds: [],
75
- obligationIds: [],
76
- slotIds: [],
77
- sides: [],
78
- }],
79
- };
80
- }
81
- export function buildDesignVerifierAgentReport(run) {
82
- const repository = `${run.owner}/${run.repo}`;
83
- if (run.status !== 'succeeded' || !run.result) {
84
- return {
85
- ok: false,
86
- status: 'failed',
87
- verdict: 'inconclusive',
88
- headline: 'VERIFICATION INCONCLUSIVE',
89
- explanation: run.error || 'The verifier did not produce a terminal behavioral verdict.',
90
- runId: run.runId,
91
- repository,
92
- pullRequest: run.pr,
93
- revisions: { base: run.baseSha, head: run.headSha },
94
- durationMs: run.durationMs,
95
- timings: null,
96
- changedFiles: [],
97
- cases: [],
98
- runHealth: null,
99
- inspectCommand: `haystack design-verify ${repository}#${run.pr} --run ${run.runId}`,
100
- replay: null,
101
- error: run.error,
102
- exitCode: 2,
103
- };
104
- }
105
- const verdict = run.result.verdict || {};
106
- const summary = verdict.summary || {};
107
- const runHealth = runHealthOf(verdict.runHealth) || missingRunHealth();
108
- const findings = Array.isArray(verdict.findings) ? verdict.findings : [];
109
- const confirmations = Array.isArray(verdict.confirmations) ? verdict.confirmations : [];
110
- const findingsByCase = new Map();
111
- for (const finding of findings) {
112
- const caseFindings = findingsByCase.get(String(finding?.caseId || '')) || [];
113
- caseFindings.push(finding);
114
- findingsByCase.set(String(finding?.caseId || ''), caseFindings);
115
- }
116
- const confirmedIds = new Set(confirmations.map((confirmation) => confirmation.caseId));
117
- const scenarioByCase = new Map(run.result.scenarios.map((scenario) => [scenario.caseId, scenario]));
118
- const probeByCase = new Map(run.result.probes.map((probe) => [probe.caseId, probe]));
119
- const cases = run.result.cases.map((testCase) => {
120
- const id = String(testCase.id || '');
121
- const caseFindings = findingsByCase.get(id) || [];
122
- const finding = caseFindings[0];
123
- const scenario = scenarioByCase.get(id);
124
- const probe = probeByCase.get(id);
125
- const observations = (Array.isArray(scenario?.divergences) ? scenario.divergences : []).map((item) => ({
126
- path: String(item.display || (Array.isArray(item.path) ? item.path.join('.') : 'observation')),
127
- base: item.base,
128
- baseRepeat: item.base2,
129
- head: item.head,
130
- controlObservedAtSamePath: item.controlObservedAtSamePath === true,
131
- controlObservedAtAncestorPath: item.controlObservedAtAncestorPath === true,
132
- controlObservedAtDescendantPath: item.controlObservedAtDescendantPath === true,
133
- }));
134
- const hasControlEvidence = typeof scenario?.noisePathCount === 'number' ||
135
- scenario?.controlScenarioErrorVariation != null;
136
- return {
137
- id,
138
- title: String(testCase.title || scenario?.scenario || id),
139
- story: String(testCase.story || ''),
140
- expectedHead: String(testCase.expected_head_observation || ''),
141
- verdict: caseFindings.length
142
- ? 'finding'
143
- : confirmedIds.has(id)
144
- ? 'confirmed'
145
- : scenario?.status === 'clean'
146
- ? 'clean'
147
- : 'inconclusive',
148
- findingKind: finding?.kind || null,
149
- findingKinds: caseFindings
150
- .map((item) => String(item?.kind || ''))
151
- .filter(Boolean),
152
- baseStable: hasControlEvidence
153
- ? scenario.noisePathCount === 0 && scenario.controlScenarioErrorVariation == null
154
- : observations.length
155
- ? observations.every((item) => sameRecordedValue(item.base, item.baseRepeat))
156
- : scenario?.status === 'clean' ? true : null,
157
- observations,
158
- generatedFiles: probe?.files || [],
159
- executedCommand: probe?.run || null,
160
- executions: executionSummaries(scenario?.executions),
161
- universes: universeSummaries(scenario?.universes, id),
162
- infrastructure: scenario?.infrastructureReceipt &&
163
- typeof scenario.infrastructureReceipt === 'object'
164
- ? {
165
- verified: scenario.infrastructureReceipt.status === 'passed',
166
- recipeId: typeof scenario.infrastructureReceipt.recipeId === 'string'
167
- ? scenario.infrastructureReceipt.recipeId
168
- : null,
169
- freshInstances: Array.isArray(scenario.infrastructureReceipt.environmentInstanceIds)
170
- ? scenario.infrastructureReceipt.environmentInstanceIds.length
171
- : 0,
172
- baseRepeat: typeof scenario.infrastructureReceipt.baseRepeat === 'string'
173
- ? scenario.infrastructureReceipt.baseRepeat
174
- : null,
175
- errors: Array.isArray(scenario.infrastructureReceipt.errors)
176
- ? scenario.infrastructureReceipt.errors.filter((item) => typeof item === 'string')
177
- : [],
178
- }
179
- : null,
180
- };
181
- });
182
- let agentVerdict;
183
- let headline;
184
- let explanation;
185
- let exitCode;
186
- if (runHealth.status === 'invalid') {
187
- agentVerdict = 'inconclusive';
188
- headline = 'VERIFICATION INCONCLUSIVE';
189
- explanation = 'No admissible evidence — this is not a pass.';
190
- exitCode = 2;
191
- }
192
- else if (runHealth.status === 'degraded') {
193
- agentVerdict = 'inconclusive';
194
- headline = 'VERIFICATION INCONCLUSIVE';
195
- explanation = 'Evidence losses degraded this run; inspect the loss table before drawing a conclusion.';
196
- exitCode = 2;
197
- }
198
- else if (findings.length > 0) {
199
- agentVerdict = 'anomaly_candidate';
200
- headline = 'ANOMALY CANDIDATE';
201
- explanation = findingExplanation(String(findings[0]?.kind || ''));
202
- exitCode = 1;
203
- }
204
- else if (summary.caseDesignOutcome === 'no-supported-cases' || Number(summary.scenarios || 0) === 0) {
205
- agentVerdict = 'inconclusive';
206
- headline = 'VERIFICATION INCONCLUSIVE';
207
- explanation = 'The verifier could not design and execute a supported behavioral case.';
208
- exitCode = 2;
209
- }
210
- else if (confirmations.length > 0) {
211
- agentVerdict = 'fix_confirmed';
212
- headline = 'FIX CONFIRMED';
213
- explanation = 'The intended behavior change was observed on output paths that did not vary between control-before and before.';
214
- exitCode = 0;
215
- }
216
- else {
217
- agentVerdict = 'no_unexpected_change';
218
- headline = 'NO UNEXPECTED CHANGE';
219
- explanation = 'The executed cases found no observed difference outside their registered expectations.';
220
- exitCode = 0;
221
- }
222
- return {
223
- ok: exitCode === 0,
224
- status: 'complete',
225
- verdict: agentVerdict,
226
- headline,
227
- explanation,
228
- runId: run.runId,
229
- repository,
230
- pullRequest: run.pr,
231
- revisions: { base: run.baseSha, head: run.headSha },
232
- durationMs: run.durationMs,
233
- timings: run.result.timings || null,
234
- changedFiles: run.result.changedFiles,
235
- cases,
236
- runHealth,
237
- inspectCommand: `haystack design-verify ${repository}#${run.pr} --run ${run.runId}`,
238
- replay: run.result.replay,
239
- error: null,
240
- exitCode,
241
- };
242
- }
243
- function displayValue(value) {
244
- const encoded = JSON.stringify(value);
245
- return encoded === undefined ? String(value) : encoded;
246
- }
247
- function durationLabel(durationMs) {
248
- if (durationMs === null)
249
- return '';
250
- const totalSeconds = Math.round(durationMs / 1000);
251
- const minutes = Math.floor(totalSeconds / 60);
252
- const seconds = totalSeconds % 60;
253
- return minutes ? `${minutes}m ${seconds}s` : `${seconds}s`;
254
- }
255
- function preciseDurationLabel(durationMs) {
256
- if (durationMs === null)
257
- return 'not recorded';
258
- if (durationMs < 1000)
259
- return `${Number(durationMs.toFixed(3))}ms`;
260
- const minutes = Math.floor(durationMs / 60_000);
261
- const seconds = Number(((durationMs % 60_000) / 1000).toFixed(3));
262
- return minutes ? `${minutes}m ${seconds}s` : `${seconds}s`;
263
- }
264
- function timingStageLabel(stage) {
265
- if (stage === 'blast-radius')
266
- return 'blast radius';
267
- if (stage === 'case-design')
268
- return 'case design';
269
- return stage;
270
- }
271
- function commandLabel(command) {
272
- if (!command)
273
- return null;
274
- return command.argv.map((arg) => (/^[A-Za-z0-9_./:=+-]+$/.test(arg) ? arg : JSON.stringify(arg))).join(' ');
275
- }
276
- function executionSideLabel(side) {
277
- if (side === 'base1')
278
- return 'before';
279
- if (side === 'base2')
280
- return 'control-before';
281
- return 'after';
282
- }
283
- function executionNeedsAttention(execution) {
284
- return execution.status !== 'completed' || execution.diagnostics.length > 0;
285
- }
286
- export function formatDesignVerifierAgentReport(report) {
287
- const timing = durationLabel(report.durationMs);
288
- const lines = [
289
- `${report.exitCode === 0 ? '✓' : report.exitCode === 1 ? '✗' : '?'} ${report.headline}${timing ? ` ${timing}` : ''}`,
290
- '',
291
- report.explanation,
292
- ];
293
- if (report.revisions.base || report.revisions.head) {
294
- lines.push('', `Revisions: before ${report.revisions.base || 'unknown'} (control + comparison)`, ` after ${report.revisions.head || 'unknown'} (comparison)`);
295
- }
296
- if (report.timings) {
297
- lines.push('', 'Timing breakdown:');
298
- if (report.timings.admissionMs !== null) {
299
- lines.push(` admission: ${preciseDurationLabel(report.timings.admissionMs)}`);
300
- }
301
- for (const stage of report.timings.stages) {
302
- lines.push(` ${timingStageLabel(stage.stage)}: ${preciseDurationLabel(stage.durationMs)} (${stage.status})`);
303
- }
304
- lines.push(` pipeline total: ${preciseDurationLabel(report.timings.pipelineDurationMs)}`);
305
- if (report.timings.unattributedMs !== null) {
306
- lines.push(` orchestration/finalization not recorded in a phase: ${preciseDurationLabel(report.timings.unattributedMs)}`);
307
- }
308
- }
309
- if (report.runHealth && report.runHealth.status !== 'healthy') {
310
- lines.push('', `Run health: ${report.runHealth.status}; admitted evidence: ${report.runHealth.admitted}`);
311
- if (report.runHealth.losses.length > 0) {
312
- lines.push('Evidence loss table:', ' owner impact count loss / stable identifiers');
313
- for (const loss of report.runHealth.losses) {
314
- const identifiers = [
315
- ...loss.caseIds,
316
- ...loss.obligationIds,
317
- ...loss.slotIds,
318
- ...loss.sides,
319
- ];
320
- lines.push(` ${loss.owner.padEnd(7)} ${loss.impact.padEnd(9)} ${String(loss.count).padStart(5)} ` +
321
- `${loss.code}${identifiers.length ? `: ${identifiers.join(', ')}` : ''}`);
322
- }
323
- }
324
- }
325
- for (const testCase of report.cases) {
326
- lines.push('', `Test: ${testCase.title}`);
327
- if (testCase.story)
328
- lines.push(` Behavior: ${testCase.story}`);
329
- if (testCase.expectedHead)
330
- lines.push(` Expected on head: ${testCase.expectedHead}`);
331
- if (testCase.findingKinds.length > 0) {
332
- lines.push(` Candidate reasons: ${testCase.findingKinds.join(', ')}`);
333
- }
334
- if (testCase.observations.length) {
335
- lines.push(' Observed:');
336
- for (const observation of testCase.observations) {
337
- lines.push(` ${observation.path}`);
338
- lines.push(` control-before: ${displayValue(observation.baseRepeat)}`);
339
- lines.push(` before: ${displayValue(observation.base)}`);
340
- lines.push(` after: ${displayValue(observation.head)}`);
341
- if (observation.controlObservedAtSamePath || observation.controlObservedAtAncestorPath ||
342
- observation.controlObservedAtDescendantPath) {
343
- lines.push(` control evidence: ${observation.controlObservedAtSamePath
344
- ? 'variation observed at this same path'
345
- : observation.controlObservedAtAncestorPath
346
- ? 'variation observed at an ancestor path'
347
- : 'variation observed at a descendant path'}`);
348
- }
349
- }
350
- }
351
- if (testCase.baseStable !== null) {
352
- lines.push(` Control evidence: ${testCase.baseStable
353
- ? 'control-before and before agreed'
354
- : 'control-before and before varied; inspect alongside the difference'}`);
355
- }
356
- if (testCase.infrastructure) {
357
- lines.push(testCase.infrastructure.verified
358
- ? ` Infrastructure: verified; same recipe, ${testCase.infrastructure.freshInstances} fresh instances`
359
- : ` Infrastructure: unverified; ${testCase.infrastructure.errors.join('; ') || 'receipt missing'}`);
360
- }
361
- const executionsWithDiagnostics = testCase.executions.filter(executionNeedsAttention);
362
- if (executionsWithDiagnostics.length) {
363
- lines.push(' Execution diagnostics:');
364
- for (const execution of executionsWithDiagnostics) {
365
- const exit = execution.commandExitCode === null ? 'exit unknown' : `exit ${execution.commandExitCode}`;
366
- const elapsed = execution.durationMs === null ? '' : `, ${durationLabel(execution.durationMs)}`;
367
- lines.push(` ${executionSideLabel(execution.side)} (${exit}${elapsed}):`);
368
- if (execution.scenarioError)
369
- lines.push(` Scenario error: ${execution.scenarioError}`);
370
- for (const diagnostic of execution.diagnostics) {
371
- const identity = [diagnostic.type, diagnostic.code].filter(Boolean).join(', ');
372
- lines.push(` ${diagnostic.kind}${identity ? ` (${identity})` : ''}: ${diagnostic.message}`);
373
- }
374
- if (execution.diagnosticsOmitted > 0) {
375
- lines.push(` ... ${execution.diagnosticsOmitted} additional diagnostics omitted`);
376
- }
377
- if (execution.outputExcerpt.length) {
378
- lines.push(' Relevant command output:');
379
- for (const output of execution.outputExcerpt) {
380
- lines.push(` ${output.stream}: ${output.text}`);
381
- }
382
- if (execution.outputLinesOmitted > 0) {
383
- lines.push(` ... ${execution.outputLinesOmitted} output lines omitted`);
384
- }
385
- }
386
- lines.push(` Full output artifact: ${execution.outputArtifact}`);
387
- lines.push(` Structured trace artifact: ${execution.traceArtifact}`);
388
- }
389
- }
390
- if (testCase.generatedFiles.length)
391
- lines.push(` Generated probe artifact: ${testCase.generatedFiles.join(', ')}`);
392
- const command = commandLabel(testCase.executedCommand);
393
- if (command)
394
- lines.push(` Executed in the sandbox: ${command}`);
395
- for (const universe of testCase.universes.filter(item => item.lease.available)) {
396
- lines.push(` Replay ${universe.role}: haystack design-verify ${report.repository}#${report.pullRequest}` +
397
- ` --run ${report.runId} --case ${testCase.id} --universe ${universe.role} --replay`);
398
- }
399
- }
400
- if (report.changedFiles.length) {
401
- lines.push('', 'Changed files to inspect:', ...report.changedFiles.map((file) => ` ${file}`));
402
- }
403
- lines.push('', `Inspect this exact result again: ${report.inspectCommand}`, `Run: ${report.runId}`);
404
- return lines.join('\n');
405
- }
406
- export function designVerifierStageLabel(stage) {
407
- if (!stage)
408
- return 'Waiting for the run to start';
409
- if (stage === 'prepare' || stage === 'bake')
410
- return 'Preparing the repository';
411
- if (stage === 'blast-radius')
412
- return 'Mapping affected behavior';
413
- if (stage === 'prefetch')
414
- return 'Retrieving relevant failure patterns';
415
- if (stage === 'stage1')
416
- return 'Designing behavioral test cases';
417
- if (stage.startsWith('build:'))
418
- return 'Building an executable probe';
419
- if (stage.startsWith('execute:'))
420
- return 'Running control-before/before/after comparisons';
421
- if (stage === 'verdict')
422
- return 'Comparing observations';
423
- return stage;
424
- }