@iceinvein/agent-skills 0.23.9 → 0.23.13

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 (75) hide show
  1. package/package.json +1 -1
  2. package/skills/index.json +2 -2
  3. package/skills/magpie/SKILL.md +21 -20
  4. package/skills/magpie/bin/magpie.ts +63 -2
  5. package/skills/magpie/evals/quality/README.md +74 -1
  6. package/skills/magpie/evals/quality/__tests__/probe-specialist.test.ts +498 -0
  7. package/skills/magpie/evals/quality/__tests__/replay-full.test.ts +9 -0
  8. package/skills/magpie/evals/quality/probe-specialist.ts +672 -0
  9. package/skills/magpie/evals/quality/replay-full.ts +6 -2
  10. package/skills/magpie/fixtures/fake-gh-with-lockfile.sh +37 -2
  11. package/skills/magpie/fixtures/fake-gh.sh +49 -2
  12. package/skills/magpie/references/critic.md +20 -4
  13. package/skills/magpie/references/proof.md +102 -0
  14. package/skills/magpie/references/scout.md +6 -1
  15. package/skills/magpie/references/specialists.md +15 -9
  16. package/skills/magpie/scripts/__tests__/cleanup-cmd.test.ts +103 -7
  17. package/skills/magpie/scripts/__tests__/cli.test.ts +69 -0
  18. package/skills/magpie/scripts/__tests__/critic-cmd.test.ts +46 -0
  19. package/skills/magpie/scripts/__tests__/critic.test.ts +11 -1
  20. package/skills/magpie/scripts/__tests__/dedupe-cmd.test.ts +20 -1
  21. package/skills/magpie/scripts/__tests__/git-diff.test.ts +23 -4
  22. package/skills/magpie/scripts/__tests__/handoff-cmd.test.ts +68 -0
  23. package/skills/magpie/scripts/__tests__/history.test.ts +232 -0
  24. package/skills/magpie/scripts/__tests__/impact-cmd.test.ts +477 -0
  25. package/skills/magpie/scripts/__tests__/impact-render.test.ts +365 -0
  26. package/skills/magpie/scripts/__tests__/impact.test.ts +915 -0
  27. package/skills/magpie/scripts/__tests__/incremental.test.ts +59 -8
  28. package/skills/magpie/scripts/__tests__/pipeline-e2e.test.ts +1 -1
  29. package/skills/magpie/scripts/__tests__/post-cmd.test.ts +58 -0
  30. package/skills/magpie/scripts/__tests__/pr-activity.test.ts +281 -0
  31. package/skills/magpie/scripts/__tests__/preview-cmd.test.ts +4 -4
  32. package/skills/magpie/scripts/__tests__/previous-findings.test.ts +267 -0
  33. package/skills/magpie/scripts/__tests__/proof-cmd.test.ts +260 -0
  34. package/skills/magpie/scripts/__tests__/proof.test.ts +226 -0
  35. package/skills/magpie/scripts/__tests__/refresh.test.ts +71 -0
  36. package/skills/magpie/scripts/__tests__/render-annotation.test.ts +34 -0
  37. package/skills/magpie/scripts/__tests__/render-findings.test.ts +75 -0
  38. package/skills/magpie/scripts/__tests__/render-progress.test.ts +9 -0
  39. package/skills/magpie/scripts/__tests__/setup-cmd.test.ts +376 -1
  40. package/skills/magpie/scripts/__tests__/shard-coverage.test.ts +79 -0
  41. package/skills/magpie/scripts/__tests__/skill-lint.test.ts +48 -2
  42. package/skills/magpie/scripts/__tests__/status-cmd.test.ts +20 -8
  43. package/skills/magpie/scripts/__tests__/types.test.ts +46 -0
  44. package/skills/magpie/scripts/cleanup-cmd.ts +88 -0
  45. package/skills/magpie/scripts/critic-cmd.ts +2 -0
  46. package/skills/magpie/scripts/critic.ts +4 -0
  47. package/skills/magpie/scripts/dedupe-cmd.ts +4 -0
  48. package/skills/magpie/scripts/evidence-filter.ts +10 -0
  49. package/skills/magpie/scripts/git-diff.ts +50 -19
  50. package/skills/magpie/scripts/handoff-cmd.ts +42 -3
  51. package/skills/magpie/scripts/history.ts +143 -0
  52. package/skills/magpie/scripts/impact-cmd.ts +202 -0
  53. package/skills/magpie/scripts/impact-render.ts +158 -0
  54. package/skills/magpie/scripts/impact.ts +622 -0
  55. package/skills/magpie/scripts/incremental.ts +44 -5
  56. package/skills/magpie/scripts/labels-cmd.ts +7 -3
  57. package/skills/magpie/scripts/post-cmd.ts +46 -0
  58. package/skills/magpie/scripts/pr-activity.ts +243 -0
  59. package/skills/magpie/scripts/preview-cmd.ts +3 -0
  60. package/skills/magpie/scripts/previous-findings.ts +181 -0
  61. package/skills/magpie/scripts/proof-cmd.ts +226 -0
  62. package/skills/magpie/scripts/proof.ts +150 -0
  63. package/skills/magpie/scripts/refresh.ts +11 -0
  64. package/skills/magpie/scripts/render-annotation.ts +17 -0
  65. package/skills/magpie/scripts/render-cmd.ts +12 -0
  66. package/skills/magpie/scripts/render-findings.ts +37 -1
  67. package/skills/magpie/scripts/render-progress.ts +3 -0
  68. package/skills/magpie/scripts/setup-cmd.ts +142 -11
  69. package/skills/magpie/scripts/shard-coverage.ts +53 -0
  70. package/skills/magpie/scripts/status-cmd.ts +2 -0
  71. package/skills/magpie/scripts/types.ts +39 -0
  72. package/skills/magpie/skill.json +1 -1
  73. package/skills/magpie/templates/styles.css +30 -0
  74. package/skills/sluice/scripts/status.sh +32 -13
  75. package/skills/sluice/skill.json +1 -1
@@ -0,0 +1,226 @@
1
+ import { expect, test } from 'bun:test'
2
+ import {
3
+ applyProofResults,
4
+ buildProofPrompts,
5
+ type ProofResult,
6
+ parseProofResult,
7
+ selectForProof,
8
+ } from '../proof.ts'
9
+ import type { ReviewFinding, Risk } from '../types.ts'
10
+
11
+ function finding(id: string, risk: Risk): ReviewFinding {
12
+ return {
13
+ id,
14
+ file: 'src/a.ts',
15
+ line: 10,
16
+ severity: 'high',
17
+ risk,
18
+ title: `title ${id}`,
19
+ description: `description ${id}`,
20
+ domain: 'bugs',
21
+ evidence: 'return cache[key]',
22
+ }
23
+ }
24
+
25
+ const HIGH_SHOULD: Risk = {
26
+ impact: 'high',
27
+ likelihood: 'possible',
28
+ confidence: 'medium',
29
+ action: 'should-fix',
30
+ }
31
+ const CRITICAL_MUST: Risk = {
32
+ impact: 'critical',
33
+ likelihood: 'likely',
34
+ confidence: 'high',
35
+ action: 'must-fix',
36
+ }
37
+ const MEDIUM_SHOULD: Risk = { ...HIGH_SHOULD, impact: 'medium' }
38
+ const HIGH_CONSIDER: Risk = { ...HIGH_SHOULD, action: 'consider' }
39
+
40
+ const REPRO = {
41
+ path: 'src/__tests__/magpie-proof-a.test.ts',
42
+ command: 'bun test src/__tests__/magpie-proof-a.test.ts',
43
+ source: "test('x', () => expect(get('k')).toBe(1))",
44
+ output: 'expected 1, received undefined',
45
+ }
46
+
47
+ test('findings marked must-fix or should-fix are selected whatever their impact', () => {
48
+ const selected = selectForProof(
49
+ [
50
+ finding('high-should', HIGH_SHOULD),
51
+ finding('medium-should', MEDIUM_SHOULD),
52
+ finding('low-should', { ...HIGH_SHOULD, impact: 'low' }),
53
+ finding('high-consider', HIGH_CONSIDER),
54
+ finding('high-optional', { ...HIGH_SHOULD, action: 'optional' }),
55
+ finding('critical-must', CRITICAL_MUST),
56
+ ],
57
+ 8,
58
+ )
59
+ expect(selected.map((f) => f.id)).toEqual([
60
+ 'critical-must',
61
+ 'high-should',
62
+ 'medium-should',
63
+ 'low-should',
64
+ ])
65
+ })
66
+
67
+ test('selection keeps the highest-scoring findings when there are more than the cap', () => {
68
+ const selected = selectForProof(
69
+ [
70
+ finding('low-score', { ...HIGH_SHOULD, likelihood: 'edge-case' }),
71
+ finding('top', CRITICAL_MUST),
72
+ finding('middle', HIGH_SHOULD),
73
+ ],
74
+ 2,
75
+ )
76
+ expect(selected.map((f) => f.id)).toEqual(['top', 'middle'])
77
+ })
78
+
79
+ const TEMPLATE = 'F=<<FINDING>> W=<<WORKTREE>> D=<<DIFF_PATH>> O=<<OUTPUT_PATH>>'
80
+
81
+ test('one prompt per finding, each naming its own output file', () => {
82
+ const prompts = buildProofPrompts({
83
+ template: TEMPLATE,
84
+ findings: [finding('a', HIGH_SHOULD)],
85
+ worktree: '/wt',
86
+ diffPath: '/run/diff.patch',
87
+ runDir: '/run',
88
+ })
89
+ expect(prompts).toHaveLength(1)
90
+ expect(prompts[0]?.id).toBe('a')
91
+ expect(prompts[0]?.outputPath).toBe('/run/proof-a.json')
92
+ expect(prompts[0]?.prompt).toBe(
93
+ `F=${JSON.stringify(
94
+ {
95
+ id: 'a',
96
+ file: 'src/a.ts',
97
+ line: 10,
98
+ risk: HIGH_SHOULD,
99
+ domain: 'bugs',
100
+ title: 'title a',
101
+ description: 'description a',
102
+ evidence: 'return cache[key]',
103
+ },
104
+ null,
105
+ 2,
106
+ )} W=/wt D=/run/diff.patch O=/run/proof-a.json`,
107
+ )
108
+ })
109
+
110
+ test('a template missing a placeholder is rejected, naming it', () => {
111
+ expect(() =>
112
+ buildProofPrompts({
113
+ template: 'F=<<FINDING>> W=<<WORKTREE>> D=<<DIFF_PATH>>',
114
+ findings: [],
115
+ worktree: '/wt',
116
+ diffPath: '/d',
117
+ runDir: '/run',
118
+ }),
119
+ ).toThrow('<<OUTPUT_PATH>>')
120
+ })
121
+
122
+ test('an id that is not safe in a file name is rejected', () => {
123
+ expect(() =>
124
+ buildProofPrompts({
125
+ template: TEMPLATE,
126
+ findings: [finding('../x', HIGH_SHOULD)],
127
+ worktree: '/wt',
128
+ diffPath: '/d',
129
+ runDir: '/run',
130
+ }),
131
+ ).toThrow('../x')
132
+ })
133
+
134
+ test('a reproduced result carries its repro', () => {
135
+ expect(
136
+ parseProofResult(
137
+ { id: 'a', outcome: 'reproduced', reason: 'fails as described', repro: REPRO },
138
+ 'proof-a.json',
139
+ ),
140
+ ).toEqual({ id: 'a', outcome: 'reproduced', reason: 'fails as described', repro: REPRO })
141
+ })
142
+
143
+ test('a not-proven result needs only a reason', () => {
144
+ expect(
145
+ parseProofResult({ id: 'a', outcome: 'not-proven', reason: 'no test runner' }, 'proof-a.json'),
146
+ ).toEqual({ id: 'a', outcome: 'not-proven', reason: 'no test runner' })
147
+ })
148
+
149
+ test('a reproduced or disproved result without a repro is rejected', () => {
150
+ expect(() =>
151
+ parseProofResult({ id: 'a', outcome: 'reproduced', reason: 'r' }, 'proof-a.json'),
152
+ ).toThrow('proof-a.json: reproduced needs a repro with path, command, source and output')
153
+ expect(() =>
154
+ parseProofResult(
155
+ { id: 'a', outcome: 'disproved', reason: 'r', repro: { ...REPRO, output: '' } },
156
+ 'proof-a.json',
157
+ ),
158
+ ).toThrow('proof-a.json: disproved needs a repro with path, command, source and output')
159
+ })
160
+
161
+ test('an unknown outcome is rejected', () => {
162
+ expect(() =>
163
+ parseProofResult({ id: 'a', outcome: 'maybe', reason: 'r' }, 'proof-a.json'),
164
+ ).toThrow('proof-a.json: outcome must be reproduced, disproved or not-proven')
165
+ })
166
+
167
+ test('applying results marks reproduced findings, raises their confidence and keeps the repro', () => {
168
+ // high impact (0.4 x 7) + possible (0.25 x 6) + high confidence (0.2 x 10) + must-fix (0.15 x 10)
169
+ const risk: Risk = { ...HIGH_SHOULD, action: 'must-fix' }
170
+ const a = finding('a', risk)
171
+ const result = applyProofResults({
172
+ findings: [a],
173
+ results: [{ id: 'a', outcome: 'reproduced', reason: 'fails as described', repro: REPRO }],
174
+ })
175
+ expect(result.findings).toEqual([
176
+ {
177
+ ...a,
178
+ risk: { ...risk, confidence: 'high' },
179
+ score: 7.8,
180
+ proof: { status: 'reproduced', reason: 'fails as described', repro: REPRO },
181
+ },
182
+ ])
183
+ expect(result.dropped).toEqual([])
184
+ })
185
+
186
+ test('a not-proven finding keeps its risk and records why', () => {
187
+ const a = finding('a', HIGH_SHOULD)
188
+ const result = applyProofResults({
189
+ findings: [a],
190
+ results: [{ id: 'a', outcome: 'not-proven', reason: 'needs a live database' }],
191
+ })
192
+ expect(result.findings).toEqual([
193
+ { ...a, proof: { status: 'not-proven', reason: 'needs a live database' } },
194
+ ])
195
+ })
196
+
197
+ test('a disproved finding is removed and recorded with its repro', () => {
198
+ const result = applyProofResults({
199
+ findings: [finding('a', HIGH_SHOULD), finding('b', MEDIUM_SHOULD)],
200
+ results: [{ id: 'a', outcome: 'disproved', reason: 'the guard at a.ts:4 holds', repro: REPRO }],
201
+ })
202
+ expect(result.findings.map((f) => f.id)).toEqual(['b'])
203
+ expect(result.dropped).toEqual([
204
+ {
205
+ id: 'a',
206
+ file: 'src/a.ts',
207
+ line: 10,
208
+ title: 'title a',
209
+ reason: 'the guard at a.ts:4 holds',
210
+ repro: REPRO,
211
+ },
212
+ ])
213
+ })
214
+
215
+ test('findings with no result pass through unchanged', () => {
216
+ const b = finding('b', MEDIUM_SHOULD)
217
+ const result = applyProofResults({ findings: [b], results: [] })
218
+ expect(result.findings).toEqual([b])
219
+ })
220
+
221
+ test('a result for an id not in the findings is rejected', () => {
222
+ const results: ProofResult[] = [{ id: 'ghost', outcome: 'not-proven', reason: 'r' }]
223
+ expect(() => applyProofResults({ findings: [], results })).toThrow(
224
+ 'proof result for unknown id: ghost',
225
+ )
226
+ })
@@ -151,3 +151,74 @@ test('refreshFindings rejects on a truncated events line and leaves the previous
151
151
  const kept = await readFile(join(runDir, 'screen', 'findings.html'), 'utf8')
152
152
  expect(kept).toBe('<html>OLD</html>')
153
153
  })
154
+
155
+ test('refreshFindings keeps the disproved-by-test panel on re-render', async () => {
156
+ await writeFile(join(runDir, 'findings.final.json'), JSON.stringify([sampleFinding]))
157
+ await writeFile(
158
+ join(runDir, 'proof-dropped.json'),
159
+ JSON.stringify([
160
+ {
161
+ id: 'b',
162
+ file: 'src/y.ts',
163
+ line: 4,
164
+ title: 'Cache never evicts',
165
+ reason: 'evict runs on every put',
166
+ repro: { path: 'p', command: 'bun test p', source: 's', output: 'o' },
167
+ },
168
+ ]),
169
+ )
170
+ await refreshFindings(runDir)
171
+ const fresh = await readFile(join(runDir, 'screen', 'findings.html'), 'utf8')
172
+ expect(fresh).toContain('Disproved by test (1)')
173
+ expect(fresh).toContain('Cache never evicts: evict runs on every put')
174
+ })
175
+
176
+ test('refreshFindings keeps the skipped-shards note on re-render', async () => {
177
+ await writeFile(join(runDir, 'findings.final.json'), JSON.stringify([sampleFinding]))
178
+ await mkdir(join(runDir, 'shards'))
179
+ await writeFile(
180
+ join(runDir, 'shards', 'manifest.json'),
181
+ JSON.stringify({
182
+ budget: 6000,
183
+ maxFiles: 80,
184
+ totalFiles: 2,
185
+ totalLines: 20,
186
+ shards: [
187
+ { id: 1, path: 'shards/shard-1.patch', files: ['src/x.ts'], lines: 10 },
188
+ { id: 2, path: 'shards/shard-2.patch', files: ['src/z.ts'], lines: 10 },
189
+ ],
190
+ }),
191
+ )
192
+ await writeFile(
193
+ join(runDir, 'log.jsonl'),
194
+ `${JSON.stringify({ stage: 'shard-coverage', status: 'partial', reviewed: [1], skipped: [2] })}\n`,
195
+ )
196
+ await refreshFindings(runDir)
197
+ const fresh = await readFile(join(runDir, 'screen', 'findings.html'), 'utf8')
198
+ expect(fresh).toContain('Not reviewed: shard 2 (1 file)')
199
+ })
200
+
201
+ test('refreshFindings keeps the previous-run line on a re-review', async () => {
202
+ await writeFile(join(runDir, 'findings.final.json'), JSON.stringify([sampleFinding]))
203
+ await writeFile(
204
+ join(runDir, 'previous-findings.json'),
205
+ JSON.stringify({
206
+ previousRunId: 'pr-7-100',
207
+ findings: [
208
+ {
209
+ id: 'bugs-1',
210
+ fromRunId: 'pr-7-100',
211
+ file: 'src/x.ts',
212
+ line: 1,
213
+ title: 't',
214
+ domain: 'bugs',
215
+ label: 'posted',
216
+ anchor: 'changed',
217
+ },
218
+ ],
219
+ }),
220
+ )
221
+ await refreshFindings(runDir)
222
+ const fresh = await readFile(join(runDir, 'screen', 'findings.html'), 'utf8')
223
+ expect(fresh).toContain('Last review: 1 posted · 1 on changed code · 0 on unchanged code')
224
+ })
@@ -221,4 +221,38 @@ describe('renderAnnotation', () => {
221
221
  expect(reasons).toEqual(['wrong', 'not-worth-it', 'duplicate', 'style'])
222
222
  expect(html).not.toContain('data-dismissed=')
223
223
  })
224
+ test('a reproduced finding shows a reproduced chip and its repro', () => {
225
+ const html = renderAnnotation(
226
+ {
227
+ ...finding,
228
+ proof: {
229
+ status: 'reproduced',
230
+ reason: 'fails as described',
231
+ repro: {
232
+ path: 'cache.test.ts',
233
+ command: 'bun test cache.test.ts',
234
+ source: 'expect(a).toBe(b)',
235
+ output: 'expected <b>',
236
+ },
237
+ },
238
+ },
239
+ { checked: false, posted: false, asCard: true, highlighter: hl },
240
+ )
241
+ expect(html).toContain(
242
+ '<span class="proof-chip reproduced" title="fails as described">REPRODUCED</span>',
243
+ )
244
+ expect(html).toContain('<code class="inline-code">bun test cache.test.ts</code>')
245
+ expect(html).toContain('<pre class="repro">expect(a).toBe(b)</pre>')
246
+ expect(html).toContain('<pre class="repro">expected &lt;b&gt;</pre>')
247
+ })
248
+
249
+ test('a not-proven finding shows a not-proven chip with the reason', () => {
250
+ const html = renderAnnotation(
251
+ { ...finding, proof: { status: 'not-proven', reason: 'needs a live database' } },
252
+ { checked: false, posted: false, asCard: true, highlighter: hl },
253
+ )
254
+ expect(html).toContain(
255
+ '<span class="proof-chip not-proven" title="needs a live database">NOT PROVEN</span>',
256
+ )
257
+ })
224
258
  })
@@ -381,6 +381,81 @@ test('findings header notes a locally-built diff', () => {
381
381
  expect(html).toContain('aaaaaaaaaaaa')
382
382
  })
383
383
 
384
+ test('findings header carries the previous-run line on a re-review', () => {
385
+ const html = renderFindingsHtml({
386
+ findings: [],
387
+ postStatus: {},
388
+ pr: { number: 7, branch: 'feature-x', headSha: 'abc123abc123' },
389
+ previousRun: 'Last review: 3 posted · 2 on changed code · 1 on unchanged code',
390
+ dismissed: new Map(),
391
+ topN: DEFAULT_TOP_N,
392
+ highlighter: hl,
393
+ })
394
+ expect(html).toContain('Last review: 3 posted · 2 on changed code · 1 on unchanged code')
395
+ })
396
+
397
+ test('the page lists findings a passing test disproved, folded, with reason and repro', () => {
398
+ const html = renderFindingsHtml({
399
+ findings: [],
400
+ postStatus: {},
401
+ pr: { number: 7, branch: 'feature-x', headSha: 'abc123abc123' },
402
+ disproved: [
403
+ {
404
+ id: 'bugs-2',
405
+ file: 'src/cache.ts',
406
+ line: 40,
407
+ title: 'Cache <never> evicts',
408
+ reason: 'evict() runs on every put at cache.ts:12',
409
+ repro: {
410
+ path: 'cache.magpie-proof-bugs-2.test.ts',
411
+ command: 'bun test cache.magpie-proof-bugs-2.test.ts',
412
+ source: 'expect(size()).toBe(1)',
413
+ output: '1 pass',
414
+ },
415
+ },
416
+ ],
417
+ dismissed: new Map(),
418
+ topN: DEFAULT_TOP_N,
419
+ highlighter: hl,
420
+ })
421
+ expect(html).toContain(
422
+ '<details class="pr-brief disproved"><summary class="brief-summary">Disproved by test (1)</summary>',
423
+ )
424
+ expect(html).toContain(
425
+ '<li><code>src/cache.ts:40</code> Cache &lt;never&gt; evicts: evict() runs on every put at cache.ts:12',
426
+ )
427
+ expect(html).toContain('<code>bun test cache.magpie-proof-bugs-2.test.ts</code>')
428
+ expect(html).toContain('<pre class="repro">expect(size()).toBe(1)</pre>')
429
+ expect(html).toContain('<pre class="repro">1 pass</pre>')
430
+ })
431
+
432
+ test('the page has no disproved panel when proof dropped nothing', () => {
433
+ const html = renderFindingsHtml({
434
+ findings: [],
435
+ postStatus: {},
436
+ pr: { number: 7, branch: 'feature-x', headSha: 'abc123abc123' },
437
+ dismissed: new Map(),
438
+ topN: DEFAULT_TOP_N,
439
+ highlighter: hl,
440
+ })
441
+ expect(html).not.toContain('Disproved by test')
442
+ })
443
+
444
+ test('findings header names the shards nobody reviewed, with their files on hover', () => {
445
+ const html = renderFindingsHtml({
446
+ findings: [],
447
+ postStatus: {},
448
+ pr: { number: 7, branch: 'feature-x', headSha: 'abc123abc123' },
449
+ unreviewed: { skipped: [{ id: 3, files: ['docs/d.md', 'src/<x>.ts'] }] },
450
+ dismissed: new Map(),
451
+ topN: DEFAULT_TOP_N,
452
+ highlighter: hl,
453
+ })
454
+ expect(html).toContain(
455
+ '<span class="diff-source" title="docs/d.md, src/&lt;x&gt;.ts">Not reviewed: shard 3 (2 files)</span>',
456
+ )
457
+ })
458
+
384
459
  test('findings header stays quiet when the diff came from gh', () => {
385
460
  const html = renderFindingsHtml({
386
461
  findings: [],
@@ -13,6 +13,7 @@ test('renderProgressHtml shows all stages with status classes and PR header', ()
13
13
  dedupe: 'pending',
14
14
  critic: 'pending',
15
15
  'peer-review': 'pending',
16
+ proof: 'pending',
16
17
  report: 'pending',
17
18
  post: 'pending',
18
19
  },
@@ -44,6 +45,7 @@ test('renderProgressHtml renders empty specialists-line before any focus reports
44
45
  dedupe: 'pending',
45
46
  critic: 'pending',
46
47
  'peer-review': 'pending',
48
+ proof: 'pending',
47
49
  report: 'pending',
48
50
  post: 'pending',
49
51
  },
@@ -64,6 +66,7 @@ test('pipeline carries a --done-count style for the filling connector line', ()
64
66
  dedupe: 'running',
65
67
  critic: 'pending',
66
68
  'peer-review': 'pending',
69
+ proof: 'pending',
67
70
  report: 'pending',
68
71
  post: 'pending',
69
72
  },
@@ -85,6 +88,7 @@ test('each pipeline stage exposes a short sublabel so first-timers can learn wha
85
88
  dedupe: 'pending',
86
89
  critic: 'pending',
87
90
  'peer-review': 'pending',
91
+ proof: 'pending',
88
92
  report: 'pending',
89
93
  post: 'pending',
90
94
  },
@@ -107,6 +111,7 @@ test('renderProgressHtml includes the archived banner element', () => {
107
111
  dedupe: 'pending',
108
112
  critic: 'pending',
109
113
  'peer-review': 'pending',
114
+ proof: 'pending',
110
115
  report: 'pending',
111
116
  post: 'pending',
112
117
  },
@@ -127,6 +132,7 @@ test('emits the shared pr-header chrome', () => {
127
132
  dedupe: 'pending',
128
133
  critic: 'pending',
129
134
  'peer-review': 'pending',
135
+ proof: 'pending',
130
136
  report: 'pending',
131
137
  post: 'pending',
132
138
  },
@@ -149,6 +155,7 @@ test('progress-pane block replaces diff-pane on the progress page', () => {
149
155
  dedupe: 'pending',
150
156
  critic: 'pending',
151
157
  'peer-review': 'pending',
158
+ proof: 'pending',
152
159
  report: 'pending',
153
160
  post: 'pending',
154
161
  },
@@ -170,6 +177,7 @@ test('progress names the shard count while specialists run', () => {
170
177
  dedupe: 'pending',
171
178
  critic: 'pending',
172
179
  'peer-review': 'pending',
180
+ proof: 'pending',
173
181
  report: 'pending',
174
182
  post: 'pending',
175
183
  },
@@ -191,6 +199,7 @@ test('progress keeps the single-shard wording when there is one shard', () => {
191
199
  dedupe: 'pending',
192
200
  critic: 'pending',
193
201
  'peer-review': 'pending',
202
+ proof: 'pending',
194
203
  report: 'pending',
195
204
  post: 'pending',
196
205
  },