erdos-problems 0.1.8 → 0.1.10

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.
@@ -9,6 +9,7 @@ import {
9
9
  import { getProblemArtifactInventory, scaffoldProblem } from '../runtime/problem-artifacts.js';
10
10
  import { loadActiveUpstreamSnapshot, syncUpstream } from '../upstream/sync.js';
11
11
  import { fetchProblemSiteSnapshot } from '../upstream/site.js';
12
+ import { buildProblemSearchQueries, fetchProblemPublicSearchReview } from '../upstream/public-search.js';
12
13
 
13
14
  function normalizeClusterLabel(rawTag) {
14
15
  return String(rawTag ?? '')
@@ -48,6 +49,7 @@ function parsePullArgs(args) {
48
49
 
49
50
  let destination = null;
50
51
  let includeSite = false;
52
+ let includePublicSearch = false;
51
53
  let refreshUpstream = false;
52
54
 
53
55
  for (let index = 0; index < rest.length; index += 1) {
@@ -64,6 +66,10 @@ function parsePullArgs(args) {
64
66
  includeSite = true;
65
67
  continue;
66
68
  }
69
+ if (token === '--include-public-search') {
70
+ includePublicSearch = true;
71
+ continue;
72
+ }
67
73
  if (token === '--refresh-upstream') {
68
74
  refreshUpstream = true;
69
75
  continue;
@@ -76,6 +82,7 @@ function parsePullArgs(args) {
76
82
  problemId: value,
77
83
  destination,
78
84
  includeSite,
85
+ includePublicSearch,
79
86
  refreshUpstream,
80
87
  };
81
88
  }
@@ -165,6 +172,8 @@ async function maybeWriteSiteBundle(problemId, destination, includeSite) {
165
172
  url: siteSnapshot.url,
166
173
  fetchedAt: siteSnapshot.fetchedAt,
167
174
  title: siteSnapshot.title,
175
+ siteStatus: siteSnapshot.siteStatus,
176
+ siteStatusRaw: siteSnapshot.siteStatusRaw,
168
177
  previewLines: siteSnapshot.previewLines,
169
178
  });
170
179
  writeText(
@@ -175,6 +184,8 @@ async function maybeWriteSiteBundle(problemId, destination, includeSite) {
175
184
  `Source: ${siteSnapshot.url}`,
176
185
  `Fetched at: ${siteSnapshot.fetchedAt}`,
177
186
  `Title: ${siteSnapshot.title}`,
187
+ `Site status: ${siteSnapshot.siteStatus}`,
188
+ `Status line: ${siteSnapshot.siteStatusRaw ?? '(unknown)'}`,
178
189
  '',
179
190
  '## Preview',
180
191
  '',
@@ -182,14 +193,132 @@ async function maybeWriteSiteBundle(problemId, destination, includeSite) {
182
193
  '',
183
194
  ].join('\n'),
184
195
  );
185
- return { attempted: true, included: true, error: null };
196
+ return {
197
+ attempted: true,
198
+ included: true,
199
+ error: null,
200
+ siteStatus: siteSnapshot.siteStatus,
201
+ siteStatusRaw: siteSnapshot.siteStatusRaw,
202
+ title: siteSnapshot.title,
203
+ previewLines: siteSnapshot.previewLines,
204
+ };
186
205
  } catch (error) {
187
206
  writeText(path.join(destination, 'SITE_FETCH_ERROR.txt'), String(error.message ?? error));
188
- return { attempted: true, included: false, error: String(error.message ?? error) };
207
+ return {
208
+ attempted: true,
209
+ included: false,
210
+ error: String(error.message ?? error),
211
+ siteStatus: 'unknown',
212
+ siteStatusRaw: null,
213
+ title: null,
214
+ previewLines: [],
215
+ };
216
+ }
217
+ }
218
+
219
+ async function maybeWritePublicSearchBundle(problemId, title, destination, includePublicSearch) {
220
+ const queries = buildProblemSearchQueries(problemId, title);
221
+ const briefLines = [
222
+ `# Erdős Problem #${problemId} Agent Websearch Brief`,
223
+ '',
224
+ 'Why this exists:',
225
+ '- do not rely on erdosproblems.com alone as the canonical public truth surface',
226
+ '- compare the site status with current publicized discussion, literature, and formalization chatter',
227
+ '',
228
+ 'Suggested queries:',
229
+ ...queries.map((query) => `- ${query}`),
230
+ '',
231
+ 'Review prompts:',
232
+ '- Does the problem still appear publicly open?',
233
+ '- Are there recent solution claims, partial claims, or major status updates?',
234
+ '- Are there recent formalization artifacts, surveys, or project pages worth pulling into the dossier?',
235
+ '',
236
+ ];
237
+
238
+ writeText(path.join(destination, 'AGENT_WEBSEARCH_BRIEF.md'), briefLines.join('\n'));
239
+
240
+ if (!includePublicSearch) {
241
+ writeText(
242
+ path.join(destination, 'PUBLIC_STATUS_REVIEW.md'),
243
+ [
244
+ `# Erdős Problem #${problemId} Public Status Review`,
245
+ '',
246
+ '- A live public search was not requested for this pull bundle.',
247
+ '- Use `AGENT_WEBSEARCH_BRIEF.md` to run the suggested queries before widening public-status claims.',
248
+ '',
249
+ ].join('\n'),
250
+ );
251
+ return {
252
+ attempted: false,
253
+ included: false,
254
+ error: null,
255
+ queries,
256
+ combinedResults: [],
257
+ };
258
+ }
259
+
260
+ try {
261
+ const review = await fetchProblemPublicSearchReview(problemId, title);
262
+ writeJson(path.join(destination, 'PUBLIC_STATUS_REVIEW.json'), review);
263
+ writeText(
264
+ path.join(destination, 'PUBLIC_STATUS_REVIEW.md'),
265
+ [
266
+ `# Erdős Problem #${problemId} Public Status Review`,
267
+ '',
268
+ `Fetched at: ${review.fetchedAt}`,
269
+ `Provider: ${review.provider}`,
270
+ '',
271
+ 'Queries run:',
272
+ ...review.queries.map((query) => `- ${query}`),
273
+ '',
274
+ 'Top public results:',
275
+ ...(review.combinedResults.length > 0
276
+ ? review.combinedResults.map((result) => `- [${result.title}](${result.url})${result.snippet ? ` — ${result.snippet}` : ''}`)
277
+ : ['- *(no results captured)*']),
278
+ '',
279
+ ...(review.errors.length > 0
280
+ ? [
281
+ 'Search notes:',
282
+ ...review.errors.map((entry) => `- ${entry.query}: ${entry.error}`),
283
+ '',
284
+ ]
285
+ : []),
286
+ ].join('\n'),
287
+ );
288
+ return {
289
+ attempted: true,
290
+ included: true,
291
+ error: null,
292
+ queries: review.queries,
293
+ combinedResults: review.combinedResults,
294
+ };
295
+ } catch (error) {
296
+ const message = String(error?.message ?? error);
297
+ writeText(
298
+ path.join(destination, 'PUBLIC_STATUS_REVIEW.md'),
299
+ [
300
+ `# Erdős Problem #${problemId} Public Status Review`,
301
+ '',
302
+ '- A live public search was attempted but did not complete cleanly.',
303
+ `- Error: ${message}`,
304
+ '',
305
+ 'Suggested queries:',
306
+ ...queries.map((query) => `- ${query}`),
307
+ '',
308
+ ].join('\n'),
309
+ );
310
+ writeText(path.join(destination, 'PUBLIC_STATUS_REVIEW_ERROR.txt'), message);
311
+ return {
312
+ attempted: true,
313
+ included: false,
314
+ error: message,
315
+ queries,
316
+ combinedResults: [],
317
+ };
189
318
  }
190
319
  }
191
320
 
192
- async function writeLiteratureLane(problemId, destination, localProblem, upstreamRecord, includeSite) {
321
+ async function writeLiteratureLane(problemId, destination, localProblem, upstreamRecord, includeSite, includePublicSearch) {
193
322
  ensureDir(destination);
194
323
 
195
324
  const includedFiles = [];
@@ -220,6 +349,12 @@ async function writeLiteratureLane(problemId, destination, localProblem, upstrea
220
349
  }
221
350
 
222
351
  const siteStatus = await maybeWriteSiteBundle(problemId, destination, includeSite);
352
+ const publicSearch = await maybeWritePublicSearchBundle(
353
+ problemId,
354
+ localProblem?.title ?? upstreamRecord?.title ?? `Erdos Problem #${problemId}`,
355
+ destination,
356
+ includePublicSearch,
357
+ );
223
358
  const problemRecord = buildProblemRecord(problemId, localProblem, upstreamRecord);
224
359
  writeJson(path.join(destination, 'PROBLEM.json'), problemRecord);
225
360
  writeJson(path.join(destination, 'LITERATURE_INDEX.json'), {
@@ -229,6 +364,10 @@ async function writeLiteratureLane(problemId, destination, localProblem, upstrea
229
364
  includedUpstreamRecord: Boolean(upstreamRecord),
230
365
  includedSiteSnapshot: siteStatus.included,
231
366
  siteSnapshotError: siteStatus.error,
367
+ siteStatus: siteStatus.siteStatus,
368
+ includedPublicSearch: publicSearch.included,
369
+ publicSearchError: publicSearch.error,
370
+ publicSearchQueries: publicSearch.queries,
232
371
  });
233
372
  writeText(
234
373
  path.join(destination, 'README.md'),
@@ -240,6 +379,7 @@ async function writeLiteratureLane(problemId, destination, localProblem, upstrea
240
379
  `- Local dossier included: ${localProblem ? 'yes' : 'no'}`,
241
380
  `- Upstream record included: ${upstreamRecord ? 'yes' : 'no'}`,
242
381
  `- Live site snapshot included: ${siteStatus.included ? 'yes' : 'no'}`,
382
+ `- Public search review included: ${publicSearch.included ? 'yes' : 'no'}`,
243
383
  '',
244
384
  ].join('\n'),
245
385
  );
@@ -248,6 +388,7 @@ async function writeLiteratureLane(problemId, destination, localProblem, upstrea
248
388
  destination,
249
389
  includedFiles,
250
390
  siteStatus,
391
+ publicSearch,
251
392
  };
252
393
  }
253
394
 
@@ -292,9 +433,9 @@ export async function runPullCommand(args, options = {}) {
292
433
  if (args.length === 0 || args[0] === 'help' || args[0] === '--help') {
293
434
  if (!silent) {
294
435
  console.log('Usage:');
295
- console.log(' erdos pull problem <id> [--dest <path>] [--include-site] [--refresh-upstream]');
436
+ console.log(' erdos pull problem <id> [--dest <path>] [--include-site] [--include-public-search] [--refresh-upstream]');
296
437
  console.log(' erdos pull artifacts <id> [--dest <path>] [--refresh-upstream]');
297
- console.log(' erdos pull literature <id> [--dest <path>] [--include-site] [--refresh-upstream]');
438
+ console.log(' erdos pull literature <id> [--dest <path>] [--include-site] [--include-public-search] [--refresh-upstream]');
298
439
  }
299
440
  return 0;
300
441
  }
@@ -346,15 +487,26 @@ export async function runPullCommand(args, options = {}) {
346
487
  const destination = parsed.destination
347
488
  ? path.resolve(parsed.destination)
348
489
  : getWorkspaceProblemLiteratureDir(parsed.problemId);
349
- const result = await writeLiteratureLane(String(parsed.problemId), destination, localProblem, upstreamRecord, parsed.includeSite);
490
+ const result = await writeLiteratureLane(
491
+ String(parsed.problemId),
492
+ destination,
493
+ localProblem,
494
+ upstreamRecord,
495
+ parsed.includeSite,
496
+ parsed.includePublicSearch,
497
+ );
350
498
  if (!silent) {
351
499
  console.log(`Literature bundle created: ${destination}`);
352
500
  console.log(`Local dossier context included: ${localProblem ? 'yes' : 'no'}`);
353
501
  console.log(`Upstream record included: ${upstreamRecord ? 'yes' : 'no'}`);
354
502
  console.log(`Live site snapshot included: ${result.siteStatus.included ? 'yes' : 'no'}`);
503
+ console.log(`Public search review included: ${result.publicSearch.included ? 'yes' : 'no'}`);
355
504
  if (result.siteStatus.error) {
356
505
  console.log(`Live site snapshot note: ${result.siteStatus.error}`);
357
506
  }
507
+ if (result.publicSearch.error) {
508
+ console.log(`Public search note: ${result.publicSearch.error}`);
509
+ }
358
510
  }
359
511
  return 0;
360
512
  }
@@ -367,7 +519,14 @@ export async function runPullCommand(args, options = {}) {
367
519
 
368
520
  writeRootProblemBundle(rootDestination, String(parsed.problemId), localProblem, upstreamRecord, snapshot, artifactDestination, literatureDestination);
369
521
  const artifactResult = writeArtifactsLane(String(parsed.problemId), artifactDestination, localProblem, upstreamRecord, snapshot);
370
- const literatureResult = await writeLiteratureLane(String(parsed.problemId), literatureDestination, localProblem, upstreamRecord, parsed.includeSite);
522
+ const literatureResult = await writeLiteratureLane(
523
+ String(parsed.problemId),
524
+ literatureDestination,
525
+ localProblem,
526
+ upstreamRecord,
527
+ parsed.includeSite,
528
+ parsed.includePublicSearch,
529
+ );
371
530
 
372
531
  writeJson(path.join(rootDestination, 'PULL_STATUS.json'), {
373
532
  generatedAt: new Date().toISOString(),
@@ -382,6 +541,10 @@ export async function runPullCommand(args, options = {}) {
382
541
  siteSnapshotAttempted: literatureResult.siteStatus.attempted,
383
542
  siteSnapshotIncluded: literatureResult.siteStatus.included,
384
543
  siteSnapshotError: literatureResult.siteStatus.error,
544
+ siteStatus: literatureResult.siteStatus.siteStatus,
545
+ publicSearchAttempted: literatureResult.publicSearch.attempted,
546
+ publicSearchIncluded: literatureResult.publicSearch.included,
547
+ publicSearchError: literatureResult.publicSearch.error,
385
548
  });
386
549
 
387
550
  if (!silent) {
@@ -391,9 +554,13 @@ export async function runPullCommand(args, options = {}) {
391
554
  console.log(`Local canonical dossier included: ${localProblem ? 'yes' : 'no'}`);
392
555
  console.log(`Upstream record included: ${upstreamRecord ? 'yes' : 'no'}`);
393
556
  console.log(`Live site snapshot included: ${literatureResult.siteStatus.included ? 'yes' : 'no'}`);
557
+ console.log(`Public search review included: ${literatureResult.publicSearch.included ? 'yes' : 'no'}`);
394
558
  if (literatureResult.siteStatus.error) {
395
559
  console.log(`Live site snapshot note: ${literatureResult.siteStatus.error}`);
396
560
  }
561
+ if (literatureResult.publicSearch.error) {
562
+ console.log(`Public search note: ${literatureResult.publicSearch.error}`);
563
+ }
397
564
  }
398
565
  return 0;
399
566
  }
@@ -2,6 +2,7 @@ import path from 'node:path';
2
2
  import { getProblem } from '../atlas/catalog.js';
3
3
  import { syncCheckpoints } from '../runtime/checkpoints.js';
4
4
  import { seedProblemFromPullBundle } from '../runtime/maintainer-seed.js';
5
+ import { syncOrpWorkspaceKit } from '../runtime/orp.js';
5
6
  import { getWorkspaceProblemPullDir, getWorkspaceRoot, getWorkspaceSeededProblemsDir } from '../runtime/paths.js';
6
7
  import { syncState } from '../runtime/state.js';
7
8
  import { readCurrentProblem, setCurrentProblem } from '../runtime/workspace.js';
@@ -15,7 +16,8 @@ function parseSeedArgs(args) {
15
16
 
16
17
  const parsed = {
17
18
  problemId: value,
18
- includeSite: false,
19
+ includeSite: true,
20
+ includePublicSearch: true,
19
21
  refreshUpstream: false,
20
22
  cluster: null,
21
23
  repoStatus: 'local_seeded',
@@ -27,6 +29,7 @@ function parseSeedArgs(args) {
27
29
  activeRoute: null,
28
30
  routeBreakthrough: false,
29
31
  problemSolved: false,
32
+ allowNonOpen: false,
30
33
  destRoot: null,
31
34
  noActivate: false,
32
35
  noLoopSync: false,
@@ -40,6 +43,18 @@ function parseSeedArgs(args) {
40
43
  parsed.includeSite = true;
41
44
  continue;
42
45
  }
46
+ if (token === '--no-site') {
47
+ parsed.includeSite = false;
48
+ continue;
49
+ }
50
+ if (token === '--include-public-search') {
51
+ parsed.includePublicSearch = true;
52
+ continue;
53
+ }
54
+ if (token === '--no-public-search') {
55
+ parsed.includePublicSearch = false;
56
+ continue;
57
+ }
43
58
  if (token === '--refresh-upstream') {
44
59
  parsed.refreshUpstream = true;
45
60
  continue;
@@ -118,6 +133,10 @@ function parseSeedArgs(args) {
118
133
  parsed.problemSolved = true;
119
134
  continue;
120
135
  }
136
+ if (token === '--allow-non-open') {
137
+ parsed.allowNonOpen = true;
138
+ continue;
139
+ }
121
140
  if (token === '--dest-root') {
122
141
  parsed.destRoot = rest[index + 1];
123
142
  if (!parsed.destRoot) {
@@ -151,7 +170,7 @@ function parseSeedArgs(args) {
151
170
  export async function runSeedCommand(args) {
152
171
  if (args.length === 0 || args[0] === 'help' || args[0] === '--help') {
153
172
  console.log('Usage:');
154
- console.log(' erdos seed problem <id> [--include-site] [--refresh-upstream] [--cluster <name>] [--repo-status <status>] [--harness-depth <depth>] [--title <title>] [--family-tag <tag>] [--related <id>] [--formalization-status <status>] [--active-route <route>] [--route-breakthrough] [--problem-solved] [--dest-root <path>] [--no-activate] [--no-loop-sync] [--force] [--json]');
173
+ console.log(' erdos seed problem <id> [--include-site|--no-site] [--include-public-search|--no-public-search] [--refresh-upstream] [--cluster <name>] [--repo-status <status>] [--harness-depth <depth>] [--title <title>] [--family-tag <tag>] [--related <id>] [--formalization-status <status>] [--active-route <route>] [--route-breakthrough] [--problem-solved] [--allow-non-open] [--dest-root <path>] [--no-activate] [--no-loop-sync] [--force] [--json]');
155
174
  return 0;
156
175
  }
157
176
 
@@ -166,6 +185,7 @@ export async function runSeedCommand(args) {
166
185
  }
167
186
 
168
187
  const workspaceRoot = getWorkspaceRoot();
188
+ const orp = syncOrpWorkspaceKit(workspaceRoot);
169
189
  const pullDir = getWorkspaceProblemPullDir(parsed.problemId, workspaceRoot);
170
190
  const defaultSeedRoot = getWorkspaceSeededProblemsDir(workspaceRoot);
171
191
  const destinationRoot = parsed.destRoot
@@ -177,6 +197,9 @@ export async function runSeedCommand(args) {
177
197
  if (parsed.includeSite) {
178
198
  pullArgs.push('--include-site');
179
199
  }
200
+ if (parsed.includePublicSearch) {
201
+ pullArgs.push('--include-public-search');
202
+ }
180
203
  if (parsed.refreshUpstream) {
181
204
  pullArgs.push('--refresh-upstream');
182
205
  }
@@ -200,6 +223,7 @@ export async function runSeedCommand(args) {
200
223
  activeRoute: parsed.activeRoute ?? (parsed.problemSolved ? null : 'seed_route_pending'),
201
224
  routeBreakthrough: parsed.routeBreakthrough,
202
225
  problemSolved: parsed.problemSolved,
226
+ allowNonOpen: parsed.allowNonOpen,
203
227
  force: parsed.force,
204
228
  });
205
229
 
@@ -231,7 +255,9 @@ export async function runSeedCommand(args) {
231
255
  checkpointShelf: checkpoints?.indexPath ?? null,
232
256
  usedUpstreamRecord: result.usedUpstreamRecord,
233
257
  usedSiteSnapshot: result.usedSiteSnapshot,
258
+ usedPublicStatusReview: result.usedPublicStatusReview,
234
259
  workspaceOverlayVisible: seedsIntoWorkspaceOverlay,
260
+ orpProtocol: orp.protocolPath,
235
261
  };
236
262
 
237
263
  if (parsed.asJson) {
@@ -247,6 +273,8 @@ export async function runSeedCommand(args) {
247
273
  console.log(`Harness depth: ${result.record.harness.depth}`);
248
274
  console.log(`Upstream record used: ${result.usedUpstreamRecord ? 'yes' : 'no'}`);
249
275
  console.log(`Site snapshot used: ${result.usedSiteSnapshot ? 'yes' : 'no'}`);
276
+ console.log(`Public status review used: ${result.usedPublicStatusReview ? 'yes' : 'no'}`);
277
+ console.log(`ORP protocol: ${orp.protocolPath}`);
250
278
  console.log(`Workspace overlay visible: ${seedsIntoWorkspaceOverlay ? 'yes' : 'no'}`);
251
279
  console.log(`Activated: ${activated ? 'yes' : 'no'}`);
252
280
  console.log(`Loop synced: ${loopSynced ? 'yes' : 'no'}`);
@@ -1,4 +1,5 @@
1
1
  import { getWorkspaceQuestionLedgerPath, getWorkspaceStateMarkdownPath } from '../runtime/paths.js';
2
+ import { syncOrpWorkspaceKit } from '../runtime/orp.js';
2
3
  import { loadState, syncState } from '../runtime/state.js';
3
4
 
4
5
  function printState(state) {
@@ -33,6 +34,7 @@ export function runStateCommand(args) {
33
34
  }
34
35
 
35
36
  if (subcommand === 'sync') {
37
+ syncOrpWorkspaceKit();
36
38
  const state = syncState();
37
39
  if (asJson) {
38
40
  console.log(JSON.stringify(state, null, 2));
@@ -57,6 +57,8 @@ function printSunflowerStatus(snapshot, registryPaths) {
57
57
  console.log(`Compute lane present: ${snapshot.computeLanePresent ? 'yes' : 'no'}`);
58
58
  console.log(`Compute lane count: ${snapshot.computeLaneCount}`);
59
59
  console.log(`Compute summary: ${snapshot.computeSummary}`);
60
+ console.log(`Compute reason: ${snapshot.computeReason ?? '(none)'}`);
61
+ console.log(`Compute when: ${snapshot.computeWhen}`);
60
62
  console.log(`Compute next: ${snapshot.computeNextAction}`);
61
63
  if (snapshot.activePacket) {
62
64
  console.log(`Compute lane: ${snapshot.activePacket.laneId} [${snapshot.activePacket.status}]`);
@@ -66,6 +68,11 @@ function printSunflowerStatus(snapshot, registryPaths) {
66
68
  console.log(`Price checked: ${snapshot.activePacket.priceCheckedLocalDate || '(unknown)'}`);
67
69
  console.log(`Packet file: ${snapshot.activePacket.packetFileName}`);
68
70
  }
71
+ if (snapshot.computeGovernance) {
72
+ console.log(`Breakthroughs engine: ${snapshot.computeGovernance.engine}`);
73
+ console.log(`Dispatch action: ${snapshot.computeGovernance.dispatchResult.action}`);
74
+ console.log(`Dispatch rung: ${snapshot.computeGovernance.selectedRung.label} [${snapshot.computeGovernance.selectedRung.spendClass}]`);
75
+ }
69
76
  console.log(`Registry record: ${registryPaths.latestPath}`);
70
77
  }
71
78
 
@@ -28,6 +28,10 @@ export function runWorkspaceCommand(args) {
28
28
  console.log(`State markdown: ${summary.stateMarkdownPath}`);
29
29
  console.log(`Question ledger: ${summary.questionLedgerPath}`);
30
30
  console.log(`Checkpoint shelf: ${summary.checkpointIndexPath}`);
31
+ console.log(`Workspace ORP dir: ${summary.orpDir}`);
32
+ console.log(`Workspace ORP protocol: ${summary.orpProtocolPath}`);
33
+ console.log(`Workspace ORP integration: ${summary.orpIntegrationPath}`);
34
+ console.log(`Workspace ORP templates: ${summary.orpTemplatesDir}`);
31
35
  console.log(`Workspace upstream dir: ${summary.upstreamDir}`);
32
36
  console.log(`Workspace seeded-problems dir: ${summary.seededProblemsDir}`);
33
37
  console.log(`Workspace scaffold dir: ${summary.scaffoldDir}`);
@@ -0,0 +1,197 @@
1
+ import {
2
+ buildOrpComputeGateResult,
3
+ buildOrpComputePacket,
4
+ defineComputePacket,
5
+ defineDecision,
6
+ definePolicy,
7
+ defineRung,
8
+ evaluateDispatch,
9
+ } from 'breakthroughs';
10
+
11
+ function normalizeRungId(value, fallback) {
12
+ const text = String(value ?? '').trim().toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/^-+|-+$/g, '');
13
+ return text || fallback;
14
+ }
15
+
16
+ function parseSpendClass(rawRung) {
17
+ const raw = String(rawRung?.role ?? rawRung?.mode ?? '').trim().toLowerCase();
18
+ if (raw === 'local_unmetered' || raw === 'local') {
19
+ return 'local_unmetered';
20
+ }
21
+ return 'paid_metered';
22
+ }
23
+
24
+ function buildRungs(packet) {
25
+ const rawRungs = Array.isArray(packet?.rungs) ? packet.rungs : [];
26
+ const rungs = rawRungs.map((rawRung, index) => {
27
+ const label = String(rawRung?.name ?? rawRung?.label ?? `rung_${index + 1}`).trim();
28
+ return defineRung({
29
+ id: normalizeRungId(label, `rung-${index + 1}`),
30
+ label,
31
+ spendClass: parseSpendClass(rawRung),
32
+ admitted: true,
33
+ metadata: {
34
+ note: String(rawRung?.note ?? rawRung?.goal ?? '').trim(),
35
+ },
36
+ });
37
+ });
38
+
39
+ if (rungs.length > 0) {
40
+ return rungs;
41
+ }
42
+
43
+ return [
44
+ defineRung({
45
+ id: 'local-scout',
46
+ label: 'local_scout',
47
+ spendClass: 'local_unmetered',
48
+ admitted: true,
49
+ }),
50
+ ];
51
+ }
52
+
53
+ function selectRung(packet, rungs) {
54
+ const localRung = rungs.find((rung) => rung.spendClass === 'local_unmetered') ?? rungs[0];
55
+ const paidRung = rungs.find((rung) => rung.spendClass === 'paid_metered') ?? rungs[0];
56
+ const status = String(packet?.status ?? '').trim().toLowerCase();
57
+
58
+ if (status === 'ready_for_paid_transfer' || status === 'paid_active') {
59
+ return paidRung;
60
+ }
61
+ return localRung;
62
+ }
63
+
64
+ function buildPolicy(packet, selectedRung) {
65
+ const approvedRungs = [];
66
+ const status = String(packet?.status ?? '').trim().toLowerCase();
67
+ if (
68
+ selectedRung.spendClass === 'paid_metered'
69
+ && (status === 'paid_active' || packet?.approvalRequired === false)
70
+ ) {
71
+ approvedRungs.push(selectedRung.id);
72
+ }
73
+
74
+ return definePolicy({
75
+ local: {
76
+ defaultAction: 'allow',
77
+ },
78
+ paid: {
79
+ defaultAction: 'require_explicit_approval',
80
+ approvedRungs,
81
+ },
82
+ });
83
+ }
84
+
85
+ function buildRequiredOutputs(packet) {
86
+ const base = [
87
+ 'run_manifest.json',
88
+ 'impact_note.md',
89
+ 'traceability_record.json',
90
+ ];
91
+ const canonicalPacket = packet?.sourceRepo?.canonical_packet_path;
92
+ if (canonicalPacket) {
93
+ base.push(canonicalPacket);
94
+ }
95
+ return [...new Set(base)];
96
+ }
97
+
98
+ function describeWhen(dispatchAction, selectedRung) {
99
+ if (!dispatchAction || !selectedRung) {
100
+ return 'No admitted compute rung is currently selected.';
101
+ }
102
+ if (dispatchAction === 'run_local') {
103
+ return `Run now on the local ${selectedRung.label} rung if the packet is still bounded and the local scout artifacts can be captured cleanly.`;
104
+ }
105
+ if (dispatchAction === 'request_paid_approval') {
106
+ return `Do not launch yet; request explicit approval before using the ${selectedRung.label} paid rung.`;
107
+ }
108
+ if (dispatchAction === 'run_paid') {
109
+ return `A paid rung is already admitted for this packet; run only with traceable artifact capture on ${selectedRung.label}.`;
110
+ }
111
+ return 'Hold the packet until the compute policy mismatch is resolved.';
112
+ }
113
+
114
+ export function buildBreakthroughsComputeView(problem, packet) {
115
+ if (!packet) {
116
+ return null;
117
+ }
118
+
119
+ const requiredOutputs = buildRequiredOutputs(packet);
120
+ const decision = defineDecision({
121
+ id: `erdos-${problem.problemId}-${packet.laneId}`,
122
+ question: packet.question,
123
+ requiredOutputs,
124
+ metadata: {
125
+ problemId: problem.problemId,
126
+ cluster: problem.cluster,
127
+ claimLevelGoal: packet.claimLevelGoal,
128
+ },
129
+ });
130
+
131
+ const rungs = buildRungs(packet);
132
+ const selectedRung = selectRung(packet, rungs);
133
+ const policy = buildPolicy(packet, selectedRung);
134
+ const computePacket = defineComputePacket({
135
+ id: packet.laneId,
136
+ decisionId: decision.id,
137
+ rungId: selectedRung.id,
138
+ question: packet.question,
139
+ successBar: {
140
+ claimLevelGoal: packet.claimLevelGoal,
141
+ statusTarget: packet.status,
142
+ },
143
+ stopCondition: 'Hold if the packet stops reducing uncertainty honestly or the required artifact bundle cannot be returned cleanly.',
144
+ requiredOutputs,
145
+ metadata: {
146
+ problemId: problem.problemId,
147
+ sourceRepo: packet.sourceRepo,
148
+ recommendation: packet.recommendation,
149
+ },
150
+ });
151
+ const dispatchResult = evaluateDispatch({
152
+ decision,
153
+ rung: selectedRung,
154
+ policy,
155
+ packet: computePacket,
156
+ });
157
+
158
+ const gate = buildOrpComputeGateResult({
159
+ gateId: `breakthroughs_${packet.laneId}`,
160
+ command: `erdos sunflower status ${problem.problemId}`,
161
+ status: dispatchResult.action === 'hold_packet' ? 'fail' : 'pass',
162
+ exitCode: dispatchResult.action === 'hold_packet' ? 1 : 0,
163
+ durationMs: 0,
164
+ evidencePaths: requiredOutputs,
165
+ evidenceStatus: 'process_only',
166
+ evidenceNote: 'This is a compute-admission record only. Evidence remains in canonical artifact paths.',
167
+ });
168
+
169
+ const orpPacket = buildOrpComputePacket({
170
+ repoRoot: packet.sourceRepo?.canonical_packet_path ?? '',
171
+ decision,
172
+ packet: computePacket,
173
+ dispatchResult: {
174
+ ...dispatchResult,
175
+ runId: `${packet.laneId}-${problem.problemId}`,
176
+ },
177
+ gateResults: [gate],
178
+ boardId: `${problem.cluster}_compute`,
179
+ problemId: problem.problemId,
180
+ stateNote: `Compute policy evaluated for ${packet.laneId} with action ${dispatchResult.action}.`,
181
+ });
182
+
183
+ return {
184
+ engine: 'breakthroughs',
185
+ decisionId: decision.id,
186
+ question: decision.question,
187
+ selectedRung: {
188
+ id: selectedRung.id,
189
+ label: selectedRung.label,
190
+ spendClass: selectedRung.spendClass,
191
+ },
192
+ dispatchResult,
193
+ when: describeWhen(dispatchResult.action, selectedRung),
194
+ requiredOutputs,
195
+ orpPacket,
196
+ };
197
+ }