erdos-problems 0.1.3 → 0.1.5

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.
@@ -0,0 +1,289 @@
1
+ import fs from 'node:fs';
2
+ import path from 'node:path';
3
+ import { parse } from 'yaml';
4
+ import { writeJson } from './files.js';
5
+ import { getPackDir, getPackProblemDir, getWorkspaceComputeRegistryDir } from './paths.js';
6
+
7
+ const CLAIM_LEVEL_PRIORITY = {
8
+ Exact: 4,
9
+ Verified: 3,
10
+ Heuristic: 2,
11
+ Conjecture: 1,
12
+ };
13
+
14
+ const STATUS_PRIORITY = {
15
+ paid_active: 7,
16
+ local_scout_running: 6,
17
+ ready_for_paid_transfer: 5,
18
+ ready_for_local_scout: 4,
19
+ active: 3,
20
+ blocked: 2,
21
+ complete: 1,
22
+ unknown: 0,
23
+ };
24
+
25
+ function getSunflowerComputeDir(problemId) {
26
+ return path.join(getPackDir('sunflower'), 'compute', String(problemId));
27
+ }
28
+
29
+ function getSunflowerProblemDir(problemId) {
30
+ return getPackProblemDir('sunflower', problemId);
31
+ }
32
+
33
+ function getSunflowerContextPath(problemId) {
34
+ return path.join(getSunflowerProblemDir(problemId), 'context.yaml');
35
+ }
36
+
37
+ function getSunflowerContextMarkdownPath(problemId) {
38
+ return path.join(getSunflowerProblemDir(problemId), 'CONTEXT.md');
39
+ }
40
+
41
+ function parseStringList(value) {
42
+ if (!Array.isArray(value)) {
43
+ return [];
44
+ }
45
+ return value
46
+ .map((entry) => String(entry ?? '').trim())
47
+ .filter(Boolean);
48
+ }
49
+
50
+ function compactText(value) {
51
+ const text = String(value ?? '').trim();
52
+ return text || null;
53
+ }
54
+
55
+ function readComputePacket(packetPath) {
56
+ const parsed = parse(fs.readFileSync(packetPath, 'utf8')) ?? {};
57
+ return {
58
+ laneId: String(parsed.lane_id ?? '').trim(),
59
+ problemId: String(parsed.problem_id ?? '').trim(),
60
+ cluster: String(parsed.cluster ?? 'sunflower').trim(),
61
+ question: String(parsed.question ?? '').trim(),
62
+ claimLevelGoal: String(parsed.claim_level_goal ?? '').trim(),
63
+ status: String(parsed.status ?? 'unknown').trim() || 'unknown',
64
+ priceCheckedLocalDate: String(parsed.price_checked_local_date ?? '').trim(),
65
+ recommendation: String(parsed.recommendation ?? '').trim(),
66
+ approvalRequired: Boolean(parsed.approval_required),
67
+ summary: String(parsed.summary ?? '').trim(),
68
+ packetPath,
69
+ packetFileName: path.basename(packetPath),
70
+ sourceRepo: parsed.source_repo ?? null,
71
+ publicFeature: parsed.public_feature ?? null,
72
+ rungs: Array.isArray(parsed.rungs) ? parsed.rungs : [],
73
+ };
74
+ }
75
+
76
+ export function listSunflowerComputePackets(problemId) {
77
+ const computeDir = getSunflowerComputeDir(problemId);
78
+ if (!fs.existsSync(computeDir)) {
79
+ return [];
80
+ }
81
+
82
+ return fs
83
+ .readdirSync(computeDir)
84
+ .filter((entry) => entry.endsWith('.yaml') || entry.endsWith('.yml'))
85
+ .sort()
86
+ .map((entry) => readComputePacket(path.join(computeDir, entry)));
87
+ }
88
+
89
+ export function readSunflowerContext(problemId) {
90
+ const contextPath = getSunflowerContextPath(problemId);
91
+ const contextMarkdownPath = getSunflowerContextMarkdownPath(problemId);
92
+ if (!fs.existsSync(contextPath)) {
93
+ return null;
94
+ }
95
+
96
+ const parsed = parse(fs.readFileSync(contextPath, 'utf8')) ?? {};
97
+ return {
98
+ problemId: String(parsed.problem_id ?? problemId).trim(),
99
+ familyRole: compactText(parsed.family_role),
100
+ harnessProfile: compactText(parsed.harness_profile),
101
+ defaultActiveRoute: compactText(parsed.default_active_route),
102
+ bootstrapFocus: compactText(parsed.bootstrap_focus),
103
+ relatedCoreProblems: parseStringList(parsed.related_core_problems),
104
+ literatureFocus: parseStringList(parsed.literature_focus),
105
+ artifactFocus: parseStringList(parsed.artifact_focus),
106
+ contextPath,
107
+ contextMarkdownPath,
108
+ contextMarkdownExists: fs.existsSync(contextMarkdownPath),
109
+ };
110
+ }
111
+
112
+ function chooseActivePacket(packets) {
113
+ if (packets.length === 0) {
114
+ return null;
115
+ }
116
+
117
+ const ranked = [...packets].sort((left, right) => {
118
+ const statusDelta =
119
+ (STATUS_PRIORITY[right.status] ?? STATUS_PRIORITY.unknown)
120
+ - (STATUS_PRIORITY[left.status] ?? STATUS_PRIORITY.unknown);
121
+ if (statusDelta !== 0) {
122
+ return statusDelta;
123
+ }
124
+ const claimDelta =
125
+ (CLAIM_LEVEL_PRIORITY[right.claimLevelGoal] ?? 0)
126
+ - (CLAIM_LEVEL_PRIORITY[left.claimLevelGoal] ?? 0);
127
+ if (claimDelta !== 0) {
128
+ return claimDelta;
129
+ }
130
+ return right.laneId.localeCompare(left.laneId);
131
+ });
132
+
133
+ return ranked[0];
134
+ }
135
+
136
+ function deriveSummary(packet) {
137
+ if (!packet) {
138
+ return {
139
+ computeSummary: 'No packaged compute lane is registered for this sunflower problem yet.',
140
+ computeNextAction: 'Stay in the atlas/dossier lane until a frozen benchmark and artifact bundle exist.',
141
+ budgetState: 'not_applicable',
142
+ };
143
+ }
144
+
145
+ const budgetState = packet.approvalRequired ? 'approval_required' : 'not_required';
146
+ if (packet.summary) {
147
+ return {
148
+ computeSummary: packet.summary,
149
+ computeNextAction:
150
+ packet.status === 'ready_for_local_scout'
151
+ ? 'Run the local scout first, then decide whether paid compute is honestly earned.'
152
+ : packet.status === 'ready_for_paid_transfer'
153
+ ? 'If budget approval is granted, launch the preferred paid rung and mirror the artifacts back into the workspace.'
154
+ : packet.status === 'paid_active'
155
+ ? 'Let the active metered run finish and pull back logs, artifacts, and impact notes before upgrading any claim.'
156
+ : packet.status === 'complete'
157
+ ? 'Review the completed artifact bundle and decide whether the next move is replay, certificate assembly, or a new frozen lane.'
158
+ : 'Refresh the compute lane status before making it part of the next route decision.',
159
+ budgetState,
160
+ };
161
+ }
162
+
163
+ if (packet.status === 'ready_for_local_scout') {
164
+ return {
165
+ computeSummary: `${packet.laneId} is packaged and ready for its local scout.`,
166
+ computeNextAction: 'Run the local scout first, then decide whether paid compute is honestly earned.',
167
+ budgetState,
168
+ };
169
+ }
170
+
171
+ if (packet.status === 'ready_for_paid_transfer') {
172
+ return {
173
+ computeSummary: `${packet.laneId} cleared the scout and is ready for the ${packet.recommendation || 'paid'} rung.`,
174
+ computeNextAction: 'If budget approval is granted, launch the preferred paid rung and mirror the artifacts back into the workspace.',
175
+ budgetState,
176
+ };
177
+ }
178
+
179
+ if (packet.status === 'paid_active') {
180
+ return {
181
+ computeSummary: `${packet.laneId} is actively using metered compute.`,
182
+ computeNextAction: 'Let the active metered run finish and pull back logs, artifacts, and impact notes before upgrading any claim.',
183
+ budgetState,
184
+ };
185
+ }
186
+
187
+ if (packet.status === 'complete') {
188
+ return {
189
+ computeSummary: `${packet.laneId} has a completed compute packet.`,
190
+ computeNextAction: 'Review the completed artifact bundle and decide whether the next move is replay, certificate assembly, or a new frozen lane.',
191
+ budgetState,
192
+ };
193
+ }
194
+
195
+ return {
196
+ computeSummary: `${packet.laneId} is packaged with status ${packet.status}.`,
197
+ computeNextAction: 'Refresh the compute lane status before making it part of the next route decision.',
198
+ budgetState,
199
+ };
200
+ }
201
+
202
+ function compactPacket(packet) {
203
+ if (!packet) {
204
+ return null;
205
+ }
206
+
207
+ return {
208
+ laneId: packet.laneId,
209
+ status: packet.status,
210
+ claimLevelGoal: packet.claimLevelGoal,
211
+ question: packet.question,
212
+ recommendation: packet.recommendation,
213
+ approvalRequired: packet.approvalRequired,
214
+ priceCheckedLocalDate: packet.priceCheckedLocalDate,
215
+ packetFileName: packet.packetFileName,
216
+ sourceRepo: packet.sourceRepo,
217
+ };
218
+ }
219
+
220
+ function deriveRouteState(problem, context) {
221
+ const researchState = problem.researchState ?? {};
222
+ const solvedBySite = String(problem.siteStatus ?? '').toLowerCase() === 'solved';
223
+
224
+ return {
225
+ activeRoute: researchState.active_route ?? context?.defaultActiveRoute ?? null,
226
+ routeBreakthrough:
227
+ typeof researchState.route_breakthrough === 'boolean'
228
+ ? researchState.route_breakthrough
229
+ : false,
230
+ openProblem:
231
+ typeof researchState.open_problem === 'boolean'
232
+ ? researchState.open_problem
233
+ : !solvedBySite,
234
+ problemSolved:
235
+ typeof researchState.problem_solved === 'boolean'
236
+ ? researchState.problem_solved
237
+ : solvedBySite,
238
+ };
239
+ }
240
+
241
+ export function buildSunflowerStatusSnapshot(problem) {
242
+ const context = readSunflowerContext(problem.problemId);
243
+ const packets = listSunflowerComputePackets(problem.problemId);
244
+ const activePacket = chooseActivePacket(packets);
245
+ const summary = deriveSummary(activePacket);
246
+ const routeState = deriveRouteState(problem, context);
247
+
248
+ return {
249
+ generatedAt: new Date().toISOString(),
250
+ problemId: problem.problemId,
251
+ displayName: problem.displayName,
252
+ title: problem.title,
253
+ cluster: problem.cluster,
254
+ activeRoute: routeState.activeRoute,
255
+ routeBreakthrough: routeState.routeBreakthrough,
256
+ openProblem: routeState.openProblem,
257
+ problemSolved: routeState.problemSolved,
258
+ familyRole: context?.familyRole ?? null,
259
+ harnessProfile: context?.harnessProfile ?? null,
260
+ bootstrapFocus: context?.bootstrapFocus ?? null,
261
+ relatedCoreProblems: context?.relatedCoreProblems ?? [],
262
+ literatureFocus: context?.literatureFocus ?? [],
263
+ artifactFocus: context?.artifactFocus ?? [],
264
+ contextPresent: Boolean(context),
265
+ contextPath: context?.contextPath ?? null,
266
+ contextMarkdownPath: context?.contextMarkdownExists ? context.contextMarkdownPath : null,
267
+ computeLanePresent: Boolean(activePacket),
268
+ computeLaneCount: packets.length,
269
+ computeSummary: summary.computeSummary,
270
+ computeNextAction: summary.computeNextAction,
271
+ budgetState: summary.budgetState,
272
+ activePacket: compactPacket(activePacket),
273
+ computePackets: packets.map((packet) => compactPacket(packet)),
274
+ };
275
+ }
276
+
277
+ export function writeSunflowerStatusRecord(problem, snapshot, workspaceRoot) {
278
+ const registryDir = getWorkspaceComputeRegistryDir(workspaceRoot);
279
+ const timestamp = new Date().toISOString().replaceAll(':', '-');
280
+ const timestampedPath = path.join(registryDir, `${timestamp}__p${problem.problemId}.json`);
281
+ const latestPath = path.join(registryDir, `latest__p${problem.problemId}.json`);
282
+ writeJson(timestampedPath, snapshot);
283
+ writeJson(latestPath, snapshot);
284
+ return {
285
+ registryDir,
286
+ timestampedPath,
287
+ latestPath,
288
+ };
289
+ }
@@ -2,6 +2,8 @@ import fs from 'node:fs';
2
2
  import {
3
3
  getCurrentProblemPath,
4
4
  getWorkspaceDir,
5
+ getWorkspaceProblemArtifactDir,
6
+ getWorkspaceProblemLiteratureDir,
5
7
  getWorkspaceProblemPullDir,
6
8
  getWorkspaceProblemScaffoldDir,
7
9
  getWorkspaceRoot,
@@ -68,6 +70,8 @@ export function getWorkspaceSummary() {
68
70
  upstreamDir: getWorkspaceUpstreamDir(),
69
71
  scaffoldDir: activeProblem ? getWorkspaceProblemScaffoldDir(activeProblem) : getWorkspaceProblemScaffoldDir('<problem-id>'),
70
72
  pullDir: activeProblem ? getWorkspaceProblemPullDir(activeProblem) : getWorkspaceProblemPullDir('<problem-id>'),
73
+ artifactDir: activeProblem ? getWorkspaceProblemArtifactDir(activeProblem) : getWorkspaceProblemArtifactDir('<problem-id>'),
74
+ literatureDir: activeProblem ? getWorkspaceProblemLiteratureDir(activeProblem) : getWorkspaceProblemLiteratureDir('<problem-id>'),
71
75
  updatedAt: state?.updatedAt ?? null,
72
76
  };
73
77
  }