erdos-problems 0.1.7 → 0.1.8

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 (98) hide show
  1. package/README.md +29 -9
  2. package/docs/RESEARCH_LOOP.md +6 -1
  3. package/package.json +1 -1
  4. package/packs/sunflower/README.md +4 -0
  5. package/packs/sunflower/problems/20/AGENT_START.md +18 -0
  6. package/packs/sunflower/problems/20/CHECKPOINT_PACKET.md +11 -0
  7. package/packs/sunflower/problems/20/REPORT_PACKET.md +10 -0
  8. package/packs/sunflower/problems/20/ROUTE_PACKET.yaml +12 -0
  9. package/packs/sunflower/problems/857/AGENT_START.md +18 -0
  10. package/packs/sunflower/problems/857/CHECKPOINT_PACKET.md +11 -0
  11. package/packs/sunflower/problems/857/REPORT_PACKET.md +10 -0
  12. package/packs/sunflower/problems/857/ROUTE_PACKET.yaml +12 -0
  13. package/problems/1/AGENT_START.md +17 -0
  14. package/problems/1/CHECKPOINT_NOTES.md +11 -0
  15. package/problems/1/EVIDENCE.md +10 -0
  16. package/problems/1/FORMALIZATION.md +8 -0
  17. package/problems/1/REFERENCES.md +9 -0
  18. package/problems/1/ROUTES.md +14 -0
  19. package/problems/1/STATEMENT.md +21 -0
  20. package/problems/1/problem.yaml +44 -0
  21. package/problems/19/AGENT_START.md +17 -0
  22. package/problems/19/CHECKPOINT_NOTES.md +11 -0
  23. package/problems/19/EVIDENCE.md +10 -0
  24. package/problems/19/FORMALIZATION.md +8 -0
  25. package/problems/19/REFERENCES.md +9 -0
  26. package/problems/19/ROUTES.md +14 -0
  27. package/problems/19/STATEMENT.md +15 -0
  28. package/problems/19/problem.yaml +42 -0
  29. package/problems/2/AGENT_START.md +17 -0
  30. package/problems/2/CHECKPOINT_NOTES.md +11 -0
  31. package/problems/2/EVIDENCE.md +10 -0
  32. package/problems/2/FORMALIZATION.md +8 -0
  33. package/problems/2/REFERENCES.md +9 -0
  34. package/problems/2/ROUTES.md +14 -0
  35. package/problems/2/STATEMENT.md +15 -0
  36. package/problems/2/problem.yaml +42 -0
  37. package/problems/21/AGENT_START.md +17 -0
  38. package/problems/21/CHECKPOINT_NOTES.md +11 -0
  39. package/problems/21/EVIDENCE.md +10 -0
  40. package/problems/21/FORMALIZATION.md +8 -0
  41. package/problems/21/REFERENCES.md +9 -0
  42. package/problems/21/ROUTES.md +14 -0
  43. package/problems/21/STATEMENT.md +21 -0
  44. package/problems/21/problem.yaml +46 -0
  45. package/problems/22/AGENT_START.md +17 -0
  46. package/problems/22/CHECKPOINT_NOTES.md +11 -0
  47. package/problems/22/EVIDENCE.md +10 -0
  48. package/problems/22/FORMALIZATION.md +8 -0
  49. package/problems/22/REFERENCES.md +9 -0
  50. package/problems/22/ROUTES.md +14 -0
  51. package/problems/22/STATEMENT.md +21 -0
  52. package/problems/22/problem.yaml +44 -0
  53. package/problems/3/AGENT_START.md +17 -0
  54. package/problems/3/CHECKPOINT_NOTES.md +11 -0
  55. package/problems/3/EVIDENCE.md +10 -0
  56. package/problems/3/FORMALIZATION.md +8 -0
  57. package/problems/3/REFERENCES.md +9 -0
  58. package/problems/3/ROUTES.md +14 -0
  59. package/problems/3/STATEMENT.md +21 -0
  60. package/problems/3/problem.yaml +44 -0
  61. package/problems/4/AGENT_START.md +17 -0
  62. package/problems/4/CHECKPOINT_NOTES.md +11 -0
  63. package/problems/4/EVIDENCE.md +10 -0
  64. package/problems/4/FORMALIZATION.md +8 -0
  65. package/problems/4/REFERENCES.md +9 -0
  66. package/problems/4/ROUTES.md +14 -0
  67. package/problems/4/STATEMENT.md +21 -0
  68. package/problems/4/problem.yaml +44 -0
  69. package/problems/5/AGENT_START.md +17 -0
  70. package/problems/5/CHECKPOINT_NOTES.md +11 -0
  71. package/problems/5/EVIDENCE.md +10 -0
  72. package/problems/5/FORMALIZATION.md +8 -0
  73. package/problems/5/REFERENCES.md +9 -0
  74. package/problems/5/ROUTES.md +14 -0
  75. package/problems/5/STATEMENT.md +21 -0
  76. package/problems/5/problem.yaml +43 -0
  77. package/problems/6/AGENT_START.md +17 -0
  78. package/problems/6/CHECKPOINT_NOTES.md +11 -0
  79. package/problems/6/EVIDENCE.md +10 -0
  80. package/problems/6/FORMALIZATION.md +8 -0
  81. package/problems/6/REFERENCES.md +9 -0
  82. package/problems/6/ROUTES.md +14 -0
  83. package/problems/6/STATEMENT.md +21 -0
  84. package/problems/6/problem.yaml +43 -0
  85. package/problems/7/AGENT_START.md +17 -0
  86. package/problems/7/CHECKPOINT_NOTES.md +11 -0
  87. package/problems/7/EVIDENCE.md +10 -0
  88. package/problems/7/FORMALIZATION.md +8 -0
  89. package/problems/7/REFERENCES.md +9 -0
  90. package/problems/7/ROUTES.md +14 -0
  91. package/problems/7/STATEMENT.md +21 -0
  92. package/problems/7/problem.yaml +42 -0
  93. package/src/commands/problem.js +6 -0
  94. package/src/commands/pull.js +31 -1
  95. package/src/commands/sunflower.js +10 -0
  96. package/src/runtime/maintainer-seed.js +158 -8
  97. package/src/runtime/problem-artifacts.js +36 -1
  98. package/src/runtime/sunflower.js +48 -0
@@ -4,6 +4,39 @@ import { stringify } from 'yaml';
4
4
  import { ensureDir, fileExists, readJson, readText, writeText } from './files.js';
5
5
  import { getProblemDir, getWorkspaceProblemPullDir, repoRoot } from './paths.js';
6
6
 
7
+ const STATEMENT_SKIP_PATTERNS = [
8
+ /^open$/i,
9
+ /^proved(?:\s*\(.*\))?$/i,
10
+ /^disproved(?:\s*\(.*\))?$/i,
11
+ /^decidable$/i,
12
+ /^verifiable$/i,
13
+ /^erd[őo]s problem #\d+/i,
14
+ /^this has been solved/i,
15
+ /^-\s*\$\d+/i,
16
+ /^-$/i,
17
+ /^#\d+\s*:/i,
18
+ /^forum$/i,
19
+ /^inbox$/i,
20
+ /^favourites$/i,
21
+ /^tags$/i,
22
+ /^more$/i,
23
+ /^faq$/i,
24
+ /^prizes$/i,
25
+ /^view the latex source$/i,
26
+ /^view history$/i,
27
+ /^external data from the database/i,
28
+ /^formalised statement\?$/i,
29
+ /\bdisclaimer\b/i,
30
+ /^this is (open|proved|disproved|verifiable|decidable)\b/i,
31
+ /^\s*[a-z][a-z ]+\|\s*$/i,
32
+ ];
33
+
34
+ const STARTER_LOOP_ARTIFACTS = [
35
+ 'AGENT_START.md',
36
+ 'ROUTES.md',
37
+ 'CHECKPOINT_NOTES.md',
38
+ ];
39
+
7
40
  function normalizeTitle(rawTitle, problemId) {
8
41
  const fallback = `Erdos Problem #${problemId}`;
9
42
  if (!rawTitle) {
@@ -29,6 +62,34 @@ function uppercaseBadge(status) {
29
62
  return String(status ?? 'unknown').trim().toUpperCase() || 'UNKNOWN';
30
63
  }
31
64
 
65
+ function normalizeClusterLabel(rawTag) {
66
+ return String(rawTag ?? '')
67
+ .trim()
68
+ .toLowerCase()
69
+ .replace(/[^a-z0-9]+/g, '-')
70
+ .replace(/^-+|-+$/g, '');
71
+ }
72
+
73
+ function inferClusterFromTags(tags) {
74
+ const normalized = Array.isArray(tags) ? tags.map(normalizeClusterLabel).filter(Boolean) : [];
75
+ if (normalized.includes('number-theory')) {
76
+ return 'number-theory';
77
+ }
78
+ if (normalized.includes('graph-theory') || normalized.includes('chromatic-number')) {
79
+ return 'graph-theory';
80
+ }
81
+ if (normalized.includes('geometry')) {
82
+ return 'geometry';
83
+ }
84
+ if (normalized.includes('analysis')) {
85
+ return 'analysis';
86
+ }
87
+ if (normalized.includes('combinatorics') || normalized.includes('intersecting-family')) {
88
+ return 'combinatorics';
89
+ }
90
+ return 'uncategorized';
91
+ }
92
+
32
93
  function getDefaultPullDir(problemId) {
33
94
  return getWorkspaceProblemPullDir(problemId);
34
95
  }
@@ -84,12 +145,22 @@ function deriveTitle(problemId, bundle, titleOverride) {
84
145
  return `Erdos Problem #${problemId}`;
85
146
  }
86
147
 
148
+ function extractStatementCandidates(bundle) {
149
+ const previewLines = Array.isArray(bundle.siteExtract?.previewLines)
150
+ ? bundle.siteExtract.previewLines
151
+ : [];
152
+
153
+ return previewLines
154
+ .map((line) => String(line ?? '').replace(/\s+/g, ' ').trim())
155
+ .filter(Boolean)
156
+ .filter((line) => !STATEMENT_SKIP_PATTERNS.some((pattern) => pattern.test(line)))
157
+ .filter((line) => !/^\w[\w -]+$/.test(line) || line.length > 40);
158
+ }
159
+
87
160
  function deriveShortStatement(problemId, bundle, title) {
88
- const preview = Array.isArray(bundle.siteExtract?.previewLines)
89
- ? bundle.siteExtract.previewLines.find((line) => String(line ?? '').trim())
90
- : null;
91
- if (preview) {
92
- return String(preview).replace(/\s+/g, ' ').trim();
161
+ const statementCandidate = extractStatementCandidates(bundle)[0];
162
+ if (statementCandidate) {
163
+ return statementCandidate;
93
164
  }
94
165
  if (bundle.problemRecord?.title && bundle.problemRecord.title !== title) {
95
166
  return String(bundle.problemRecord.title).trim();
@@ -157,7 +228,7 @@ function buildProblemRecord(problemId, bundle, options) {
157
228
  upstream_status: upstreamRecord.status?.state ?? null,
158
229
  upstream_last_update: upstreamRecord.status?.last_update ?? null,
159
230
  },
160
- cluster: options.cluster,
231
+ cluster: options.cluster ?? inferClusterFromTags(upstreamRecord.tags),
161
232
  prize: {
162
233
  display: upstreamRecord.prize ?? 'unknown',
163
234
  },
@@ -191,6 +262,7 @@ function renderStatementMarkdown(problemId, record, bundle) {
191
262
  const previewLines = Array.isArray(bundle.siteExtract?.previewLines)
192
263
  ? bundle.siteExtract.previewLines.filter((line) => String(line ?? '').trim())
193
264
  : [];
265
+ const statementCandidates = extractStatementCandidates(bundle);
194
266
 
195
267
  return [
196
268
  `# Problem ${problemId} Statement`,
@@ -199,8 +271,19 @@ function renderStatementMarkdown(problemId, record, bundle) {
199
271
  '',
200
272
  'Normalized focus:',
201
273
  `- ${record.statement.short}`,
202
- previewLines.length > 0 ? '- Seeded with preview lines from the public site snapshot' : '- Seeded from upstream public metadata',
274
+ statementCandidates.length > 0
275
+ ? '- Seeded with filtered statement candidates from the public site snapshot'
276
+ : previewLines.length > 0
277
+ ? '- Seeded with preview lines from the public site snapshot'
278
+ : '- Seeded from upstream public metadata',
203
279
  '',
280
+ ...(statementCandidates.length > 0
281
+ ? [
282
+ 'Statement candidates:',
283
+ ...statementCandidates.slice(0, 4).map((line) => `- ${line}`),
284
+ '',
285
+ ]
286
+ : []),
204
287
  ...(previewLines.length > 0
205
288
  ? [
206
289
  'Public-site preview:',
@@ -256,6 +339,69 @@ function renderFormalizationMarkdown(record) {
256
339
  ].join('\n');
257
340
  }
258
341
 
342
+ function renderAgentStartMarkdown(problemId, record) {
343
+ const activeRoute = record.research_state?.active_route ?? 'seed_route_pending';
344
+ const routeMode = activeRoute ? 'route' : 'milestone';
345
+ return [
346
+ '# Agent Start',
347
+ '',
348
+ 'Fast start:',
349
+ `- \`erdos problem show ${problemId}\``,
350
+ '- `erdos workspace show`',
351
+ '- `erdos preflight`',
352
+ `- \`erdos continuation use ${routeMode}\``,
353
+ '- `erdos checkpoints sync`',
354
+ '',
355
+ 'Working assumptions:',
356
+ `- Open problem: ${record.research_state?.open_problem === false ? 'no' : 'yes'}`,
357
+ `- Active route: ${activeRoute}`,
358
+ `- Repo status: ${record.status.repo_status}`,
359
+ `- Harness depth: ${record.harness.depth}`,
360
+ '',
361
+ 'First honest move:',
362
+ `- tighten the local dossier for problem ${problemId} against its pull bundle, references, and upstream provenance before widening claims.`,
363
+ '',
364
+ ].join('\n');
365
+ }
366
+
367
+ function renderRoutesMarkdown(problemId, record) {
368
+ const activeRoute = record.research_state?.active_route ?? 'seed_route_pending';
369
+ return [
370
+ '# Routes',
371
+ '',
372
+ '## Status Ladder',
373
+ '',
374
+ `- Open problem: ${record.research_state?.open_problem === false ? 'no' : 'yes'}`,
375
+ `- Active route: ${activeRoute}`,
376
+ `- Route breakthrough: ${record.research_state?.route_breakthrough ? 'yes' : 'no'}`,
377
+ `- Problem solved: ${record.research_state?.problem_solved ? 'yes' : 'no'}`,
378
+ '',
379
+ '## Starter route notes',
380
+ '',
381
+ `- Current seeded route placeholder for problem ${problemId}: \`${activeRoute}\``,
382
+ '- Treat this as a workspace-level route marker until a curated route tree is written.',
383
+ '- Keep route progress separate from global problem status.',
384
+ '',
385
+ ].join('\n');
386
+ }
387
+
388
+ function renderCheckpointNotesMarkdown(problemId, record) {
389
+ return [
390
+ '# Checkpoint Notes',
391
+ '',
392
+ `- Problem: ${problemId}`,
393
+ `- Repo status: ${record.status.repo_status}`,
394
+ `- Harness depth: ${record.harness.depth}`,
395
+ '',
396
+ 'Checkpoint prompts:',
397
+ '- What changed in the active route since the last honest checkpoint?',
398
+ '- Which claim level is justified right now: Exact, Verified, Heuristic, or Conjecture?',
399
+ '- Which upstream/public truth changed, if any?',
400
+ '- Which artifact or literature bundle should the next agent read first?',
401
+ '',
402
+ ].join('\n');
403
+ }
404
+
259
405
  export function seedProblemFromPullBundle(problemId, options = {}) {
260
406
  const bundle = loadPullBundle(problemId, options.fromPullDir);
261
407
  const destinationRoot = path.resolve(options.destRoot ?? path.join(repoRoot, 'problems'));
@@ -267,7 +413,7 @@ export function seedProblemFromPullBundle(problemId, options = {}) {
267
413
 
268
414
  ensureDir(destinationDir);
269
415
  const record = buildProblemRecord(problemId, bundle, {
270
- cluster: options.cluster ?? 'uncategorized',
416
+ cluster: options.cluster ?? null,
271
417
  repoStatus: options.repoStatus ?? 'cataloged',
272
418
  harnessDepth: options.harnessDepth ?? 'dossier',
273
419
  title: options.title ?? null,
@@ -284,11 +430,15 @@ export function seedProblemFromPullBundle(problemId, options = {}) {
284
430
  writeText(path.join(destinationDir, 'REFERENCES.md'), renderReferencesMarkdown(record, bundle));
285
431
  writeText(path.join(destinationDir, 'EVIDENCE.md'), renderEvidenceMarkdown(problemId, record, bundle));
286
432
  writeText(path.join(destinationDir, 'FORMALIZATION.md'), renderFormalizationMarkdown(record));
433
+ writeText(path.join(destinationDir, 'AGENT_START.md'), renderAgentStartMarkdown(problemId, record));
434
+ writeText(path.join(destinationDir, 'ROUTES.md'), renderRoutesMarkdown(problemId, record));
435
+ writeText(path.join(destinationDir, 'CHECKPOINT_NOTES.md'), renderCheckpointNotesMarkdown(problemId, record));
287
436
 
288
437
  return {
289
438
  destinationDir,
290
439
  record,
291
440
  usedSiteSnapshot: Boolean(bundle.siteExtract || bundle.siteSummary),
292
441
  usedUpstreamRecord: Boolean(bundle.upstreamRecord),
442
+ starterLoopArtifacts: STARTER_LOOP_ARTIFACTS,
293
443
  };
294
444
  }
@@ -13,11 +13,21 @@ const DOSSIER_FILES = [
13
13
  ['FORMALIZATION.md', 'formalizationPath', 'FORMALIZATION.md'],
14
14
  ];
15
15
 
16
+ const STARTER_LOOP_FILES = [
17
+ ['AGENT_START.md', 'AGENT_START.md'],
18
+ ['ROUTES.md', 'ROUTES.md'],
19
+ ['CHECKPOINT_NOTES.md', 'CHECKPOINT_NOTES.md'],
20
+ ];
21
+
16
22
  function getPackContextPath(problem) {
17
23
  if (!problem.cluster) {
18
24
  return null;
19
25
  }
20
- return path.join(getPackDir(problem.cluster), 'README.md');
26
+ const packDir = getPackDir(problem.cluster);
27
+ if (!fs.existsSync(packDir)) {
28
+ return null;
29
+ }
30
+ return path.join(packDir, 'README.md');
21
31
  }
22
32
 
23
33
  function collectFiles(rootDir, relativeDir = '') {
@@ -71,6 +81,15 @@ export function getProblemArtifactInventory(problem) {
71
81
  exists: fs.existsSync(filePath),
72
82
  };
73
83
  });
84
+ const starterArtifacts = STARTER_LOOP_FILES.map(([label, destinationName]) => {
85
+ const filePath = path.join(problem.problemDir, label);
86
+ return {
87
+ label,
88
+ path: filePath,
89
+ destinationName,
90
+ exists: fs.existsSync(filePath),
91
+ };
92
+ }).filter((artifact) => artifact.exists);
74
93
 
75
94
  const packContextPath = getPackContextPath(problem);
76
95
  const packContext = packContextPath
@@ -103,6 +122,7 @@ export function getProblemArtifactInventory(problem) {
103
122
  harnessDepth: problem.harnessDepth,
104
123
  problemDir: problem.problemDir,
105
124
  canonicalArtifacts,
125
+ starterArtifacts,
106
126
  packContext,
107
127
  packProblemArtifacts,
108
128
  computePackets,
@@ -137,6 +157,18 @@ export function scaffoldProblem(problem, destination) {
137
157
  }
138
158
  }
139
159
 
160
+ const copiedStarterArtifacts = [];
161
+ for (const artifact of inventory.starterArtifacts) {
162
+ const destinationPath = path.join(destination, artifact.destinationName);
163
+ if (copyFileIfPresent(artifact.path, destinationPath)) {
164
+ copiedStarterArtifacts.push({
165
+ label: artifact.label,
166
+ sourcePath: artifact.path,
167
+ destinationPath,
168
+ });
169
+ }
170
+ }
171
+
140
172
  if (inventory.packContext?.exists) {
141
173
  const destinationPath = path.join(destination, inventory.packContext.destinationName);
142
174
  if (copyFileIfPresent(inventory.packContext.path, destinationPath)) {
@@ -203,10 +235,12 @@ export function scaffoldProblem(problem, destination) {
203
235
  problemId: problem.problemId,
204
236
  bundledProblemDir: problem.problemDir,
205
237
  copiedArtifacts,
238
+ copiedStarterArtifacts,
206
239
  packProblemArtifacts,
207
240
  computeArtifacts,
208
241
  packContext: inventory.packContext,
209
242
  canonicalArtifacts: inventory.canonicalArtifacts,
243
+ starterArtifacts: inventory.starterArtifacts,
210
244
  packProblemArtifactsInventory: inventory.packProblemArtifacts,
211
245
  computePackets: inventory.computePackets,
212
246
  upstreamSnapshot: inventory.upstreamSnapshot,
@@ -228,6 +262,7 @@ export function scaffoldProblem(problem, destination) {
228
262
  `- Repo status: ${problem.repoStatus}`,
229
263
  `- Harness depth: ${problem.harnessDepth}`,
230
264
  `- Upstream record included: ${inventory.upstreamRecordIncluded ? 'yes' : 'no'}`,
265
+ `- Starter loop artifacts copied: ${copiedStarterArtifacts.length}`,
231
266
  `- Pack problem artifacts copied: ${packProblemArtifacts.length}`,
232
267
  `- Compute packets copied: ${computeArtifacts.length}`,
233
268
  '',
@@ -38,6 +38,22 @@ function getSunflowerContextMarkdownPath(problemId) {
38
38
  return path.join(getSunflowerProblemDir(problemId), 'CONTEXT.md');
39
39
  }
40
40
 
41
+ function getSunflowerRoutePacketPath(problemId) {
42
+ return path.join(getSunflowerProblemDir(problemId), 'ROUTE_PACKET.yaml');
43
+ }
44
+
45
+ function getSunflowerAgentStartPath(problemId) {
46
+ return path.join(getSunflowerProblemDir(problemId), 'AGENT_START.md');
47
+ }
48
+
49
+ function getSunflowerCheckpointPacketPath(problemId) {
50
+ return path.join(getSunflowerProblemDir(problemId), 'CHECKPOINT_PACKET.md');
51
+ }
52
+
53
+ function getSunflowerReportPacketPath(problemId) {
54
+ return path.join(getSunflowerProblemDir(problemId), 'REPORT_PACKET.md');
55
+ }
56
+
41
57
  function parseStringList(value) {
42
58
  if (!Array.isArray(value)) {
43
59
  return [];
@@ -133,6 +149,26 @@ export function readSunflowerContext(problemId) {
133
149
  };
134
150
  }
135
151
 
152
+ function readSunflowerRoutePacket(problemId) {
153
+ const routePacketPath = getSunflowerRoutePacketPath(problemId);
154
+ if (!fs.existsSync(routePacketPath)) {
155
+ return null;
156
+ }
157
+
158
+ const parsed = parse(fs.readFileSync(routePacketPath, 'utf8')) ?? {};
159
+ return {
160
+ routePacketId: compactText(parsed.route_packet_id),
161
+ routeId: compactText(parsed.route_id),
162
+ frontierClaim: compactText(parsed.frontier_claim),
163
+ theoremModule: compactText(parsed.theorem_module),
164
+ checkpointPacket: compactText(parsed.checkpoint_packet),
165
+ reportPacket: compactText(parsed.report_packet),
166
+ readyPrompts: parseStringList(parsed.ready_prompts),
167
+ verificationHook: parseStringList(parsed.verification_hook),
168
+ routePacketPath,
169
+ };
170
+ }
171
+
136
172
  function chooseActivePacket(packets) {
137
173
  if (packets.length === 0) {
138
174
  return null;
@@ -273,10 +309,14 @@ function defaultQuestionLedger(problemId, routeState) {
273
309
 
274
310
  export function buildSunflowerStatusSnapshot(problem) {
275
311
  const context = readSunflowerContext(problem.problemId);
312
+ const routePacket = readSunflowerRoutePacket(problem.problemId);
276
313
  const packets = listSunflowerComputePackets(problem.problemId);
277
314
  const activePacket = chooseActivePacket(packets);
278
315
  const summary = deriveSummary(activePacket);
279
316
  const routeState = deriveRouteState(problem, context);
317
+ const agentStartPath = getSunflowerAgentStartPath(problem.problemId);
318
+ const checkpointPacketPath = getSunflowerCheckpointPacketPath(problem.problemId);
319
+ const reportPacketPath = getSunflowerReportPacketPath(problem.problemId);
280
320
 
281
321
  return {
282
322
  generatedAt: new Date().toISOString(),
@@ -303,6 +343,14 @@ export function buildSunflowerStatusSnapshot(problem) {
303
343
  contextPresent: Boolean(context),
304
344
  contextPath: context?.contextPath ?? null,
305
345
  contextMarkdownPath: context?.contextMarkdownExists ? context.contextMarkdownPath : null,
346
+ routePacketPresent: Boolean(routePacket),
347
+ routePacket,
348
+ agentStartPresent: fs.existsSync(agentStartPath),
349
+ agentStartPath: fs.existsSync(agentStartPath) ? agentStartPath : null,
350
+ checkpointPacketPresent: fs.existsSync(checkpointPacketPath),
351
+ checkpointPacketPath: fs.existsSync(checkpointPacketPath) ? checkpointPacketPath : null,
352
+ reportPacketPresent: fs.existsSync(reportPacketPath),
353
+ reportPacketPath: fs.existsSync(reportPacketPath) ? reportPacketPath : null,
306
354
  computeLanePresent: Boolean(activePacket),
307
355
  computeLaneCount: packets.length,
308
356
  computeSummary: summary.computeSummary,