erdos-problems 0.2.10 → 0.3.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.
- package/README.md +45 -21
- package/data/upstream/erdosproblems/SYNC_MANIFEST.json +4 -4
- package/docs/CANONICAL_REPO_MIGRATION_PLAN.md +279 -0
- package/docs/DEEP_RESEARCH_BUNDLE_SPEC.md +129 -0
- package/docs/ERDOS_PROBLEMS_PROBLEM_SCHEMA.md +27 -20
- package/docs/ERDOS_PROBLEMS_REPO_SPEC.md +22 -13
- package/docs/PAPER_WRITER_MODE.md +118 -0
- package/package.json +1 -1
- package/problems/1/AGENT_START.md +1 -1
- package/problems/1/EVIDENCE.md +1 -1
- package/problems/1/FORMALIZATION.md +2 -2
- package/problems/1/problem.yaml +6 -6
- package/problems/1008/problem.yaml +5 -5
- package/problems/18/problem.yaml +5 -5
- package/problems/19/AGENT_START.md +1 -1
- package/problems/19/EVIDENCE.md +1 -1
- package/problems/19/FORMALIZATION.md +2 -2
- package/problems/19/problem.yaml +6 -6
- package/problems/2/AGENT_START.md +1 -1
- package/problems/2/EVIDENCE.md +1 -1
- package/problems/2/FORMALIZATION.md +2 -2
- package/problems/2/problem.yaml +6 -6
- package/problems/20/problem.yaml +5 -5
- package/problems/21/AGENT_START.md +1 -1
- package/problems/21/EVIDENCE.md +1 -1
- package/problems/21/FORMALIZATION.md +2 -2
- package/problems/21/problem.yaml +6 -6
- package/problems/22/AGENT_START.md +1 -1
- package/problems/22/EVIDENCE.md +1 -1
- package/problems/22/FORMALIZATION.md +2 -2
- package/problems/22/problem.yaml +6 -6
- package/problems/3/AGENT_START.md +1 -1
- package/problems/3/EVIDENCE.md +1 -1
- package/problems/3/FORMALIZATION.md +2 -2
- package/problems/3/problem.yaml +6 -6
- package/problems/4/AGENT_START.md +1 -1
- package/problems/4/EVIDENCE.md +1 -1
- package/problems/4/FORMALIZATION.md +2 -2
- package/problems/4/problem.yaml +6 -6
- package/problems/5/AGENT_START.md +1 -1
- package/problems/5/EVIDENCE.md +1 -1
- package/problems/5/FORMALIZATION.md +2 -2
- package/problems/5/problem.yaml +6 -6
- package/problems/536/problem.yaml +5 -5
- package/problems/542/problem.yaml +5 -5
- package/problems/6/AGENT_START.md +1 -1
- package/problems/6/EVIDENCE.md +1 -1
- package/problems/6/FORMALIZATION.md +2 -2
- package/problems/6/problem.yaml +6 -6
- package/problems/7/AGENT_START.md +1 -1
- package/problems/7/EVIDENCE.md +1 -1
- package/problems/7/FORMALIZATION.md +2 -2
- package/problems/7/problem.yaml +6 -6
- package/problems/856/problem.yaml +5 -5
- package/problems/857/problem.yaml +5 -5
- package/problems/89/problem.yaml +5 -5
- package/src/atlas/catalog.js +6 -5
- package/src/cli/index.js +10 -5
- package/src/commands/bootstrap.js +1 -1
- package/src/commands/dossier.js +1 -1
- package/src/commands/maintainer.js +2 -2
- package/src/commands/paper.js +147 -0
- package/src/commands/problem.js +9 -9
- package/src/commands/pull.js +8 -8
- package/src/commands/scaffold.js +1 -1
- package/src/commands/seed.js +1 -1
- package/src/commands/upstream.js +27 -24
- package/src/runtime/maintainer-seed.js +12 -12
- package/src/runtime/paper.js +720 -0
- package/src/runtime/paths.js +16 -0
- package/src/runtime/problem-artifacts.js +2 -2
- package/src/runtime/state.js +1 -1
- package/src/upstream/sync.js +18 -18
|
@@ -0,0 +1,720 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { getProblem } from '../atlas/catalog.js';
|
|
4
|
+
import { fileExists, readJson, writeJson, writeText } from './files.js';
|
|
5
|
+
import { getProblemArtifactInventory } from './problem-artifacts.js';
|
|
6
|
+
import {
|
|
7
|
+
getRepoAnalysisDir,
|
|
8
|
+
getRepoPaperDir,
|
|
9
|
+
getRepoProblemPaperDir,
|
|
10
|
+
getWorkspaceProblemPaperDir,
|
|
11
|
+
getWorkspaceRoot,
|
|
12
|
+
repoRoot,
|
|
13
|
+
} from './paths.js';
|
|
14
|
+
|
|
15
|
+
const CANONICAL_REPO_URL = 'https://github.com/SproutSeeds/erdos-problems';
|
|
16
|
+
const BUNDLE_VERSION = 1;
|
|
17
|
+
|
|
18
|
+
const SECTION_SPECS = [
|
|
19
|
+
{
|
|
20
|
+
key: 'abstract',
|
|
21
|
+
fileName: 'ABSTRACT.md',
|
|
22
|
+
title: 'Abstract',
|
|
23
|
+
purpose: 'State the exact scope of the paper and separate proved statements from targets or heuristics.',
|
|
24
|
+
inputLabels: ['STATEMENT.md', 'EVIDENCE.md', 'FRONTIER_NOTE.md'],
|
|
25
|
+
guardrails: [
|
|
26
|
+
'Open with the exact problem framing and current status.',
|
|
27
|
+
'Do not imply a full proof unless the public record supports it.',
|
|
28
|
+
'If the route is incomplete, describe this as progress, structure, or a route note.',
|
|
29
|
+
],
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
key: 'introduction',
|
|
33
|
+
fileName: 'INTRODUCTION.md',
|
|
34
|
+
title: 'Introduction',
|
|
35
|
+
purpose: 'Explain why the problem matters, what the current route is, and how the paper is organized.',
|
|
36
|
+
inputLabels: ['STATEMENT.md', 'REFERENCES.md', 'FRONTIER_NOTE.md', 'PACK_CONTEXT.md'],
|
|
37
|
+
guardrails: [
|
|
38
|
+
'Ground motivation in public sources and cited literature.',
|
|
39
|
+
'Explain the active route without overselling its maturity.',
|
|
40
|
+
'State the paper organization at the end of the section.',
|
|
41
|
+
],
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
key: 'preliminaries',
|
|
45
|
+
fileName: 'PRELIMINARIES.md',
|
|
46
|
+
title: 'Preliminaries',
|
|
47
|
+
purpose: 'Define notation, setup, and prior results that the rest of the paper relies on.',
|
|
48
|
+
inputLabels: ['STATEMENT.md', 'REFERENCES.md', 'FORMALIZATION.md'],
|
|
49
|
+
guardrails: [
|
|
50
|
+
'Define every symbol before it is used in a claim.',
|
|
51
|
+
'Cite prior results rather than paraphrasing them from memory.',
|
|
52
|
+
'Keep imported facts distinct from new statements in this repo.',
|
|
53
|
+
],
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
key: 'related_work',
|
|
57
|
+
fileName: 'RELATED_WORK.md',
|
|
58
|
+
title: 'Related Work',
|
|
59
|
+
purpose: 'Place the current route in the context of prior literature and nearby approaches.',
|
|
60
|
+
inputLabels: ['REFERENCES.md', 'EVIDENCE.md', 'FRONTIER_NOTE.md'],
|
|
61
|
+
guardrails: [
|
|
62
|
+
'Each literature claim should have a ledger entry in CITATION_LEDGER.md.',
|
|
63
|
+
'Describe competing or historical approaches fairly and briefly.',
|
|
64
|
+
'Mark unresolved comparisons as open rather than implied.',
|
|
65
|
+
],
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
key: 'main_results',
|
|
69
|
+
fileName: 'MAIN_RESULTS.md',
|
|
70
|
+
title: 'Main Results',
|
|
71
|
+
purpose: 'List the exact theorems, propositions, or route claims supported by the current public record.',
|
|
72
|
+
inputLabels: ['EVIDENCE.md', 'FORMALIZATION.md', 'FRONTIER_NOTE.md'],
|
|
73
|
+
guardrails: [
|
|
74
|
+
'Separate proved results, conditional results, heuristics, and targets.',
|
|
75
|
+
'Use theorem language only for claims backed by the current public record.',
|
|
76
|
+
'When in doubt, downgrade to a route claim or open objective.',
|
|
77
|
+
],
|
|
78
|
+
},
|
|
79
|
+
{
|
|
80
|
+
key: 'proof_overview',
|
|
81
|
+
fileName: 'PROOF_OVERVIEW.md',
|
|
82
|
+
title: 'Proof Overview',
|
|
83
|
+
purpose: 'Give the roadmap of the argument and the dependency chain between major steps.',
|
|
84
|
+
inputLabels: ['EVIDENCE.md', 'ATOMIC_BOARD.md', 'FRONTIER_NOTE.md'],
|
|
85
|
+
guardrails: [
|
|
86
|
+
'Explain the dependency chain before entering technical details.',
|
|
87
|
+
'Call out any open seam, blocked lemma, or incomplete dependency explicitly.',
|
|
88
|
+
'Keep route state and proved state separate.',
|
|
89
|
+
],
|
|
90
|
+
},
|
|
91
|
+
{
|
|
92
|
+
key: 'proof_details',
|
|
93
|
+
fileName: 'PROOF_DETAILS.md',
|
|
94
|
+
title: 'Proof Details',
|
|
95
|
+
purpose: 'Write the technical proof content or the best current public decomposition when the proof is incomplete.',
|
|
96
|
+
inputLabels: ['EVIDENCE.md', 'ATOMIC_BOARD.md', 'ROUTE_PACKET.yaml'],
|
|
97
|
+
guardrails: [
|
|
98
|
+
'Do not skip unresolved steps by rhetorical compression.',
|
|
99
|
+
'If a subclaim is computational or formal, point to the exact public evidence packet.',
|
|
100
|
+
'Use local labels for lemmas and keep missing subproofs visible.',
|
|
101
|
+
],
|
|
102
|
+
},
|
|
103
|
+
{
|
|
104
|
+
key: 'computational_and_formal_evidence',
|
|
105
|
+
fileName: 'COMPUTATIONAL_AND_FORMAL_EVIDENCE.md',
|
|
106
|
+
title: 'Computational and Formal Evidence',
|
|
107
|
+
purpose: 'Summarize computational packets, certificates, and formalization posture without inflating them into stronger claims.',
|
|
108
|
+
inputLabels: ['FORMALIZATION.md'],
|
|
109
|
+
includeAllComputePackets: true,
|
|
110
|
+
guardrails: [
|
|
111
|
+
'State what was checked, what was not checked, and what level of confidence the computation supports.',
|
|
112
|
+
'Keep verification surface, compute surface, and proof surface distinct.',
|
|
113
|
+
'If no formal artifact is public yet, say so directly.',
|
|
114
|
+
],
|
|
115
|
+
},
|
|
116
|
+
{
|
|
117
|
+
key: 'limitations_and_open_problems',
|
|
118
|
+
fileName: 'LIMITATIONS_AND_OPEN_PROBLEMS.md',
|
|
119
|
+
title: 'Limitations and Open Problems',
|
|
120
|
+
purpose: 'Leave a clean handoff for the next researcher with honest boundaries and unresolved tasks.',
|
|
121
|
+
inputLabels: ['FRONTIER_NOTE.md', 'ATOMIC_BOARD.md', 'CHECKPOINT_NOTES.md'],
|
|
122
|
+
guardrails: [
|
|
123
|
+
'List the current bottlenecks plainly.',
|
|
124
|
+
'Separate near-term route tasks from broader mathematical open problems.',
|
|
125
|
+
'Do not hide failure modes or uncertainty.',
|
|
126
|
+
],
|
|
127
|
+
},
|
|
128
|
+
];
|
|
129
|
+
|
|
130
|
+
function toPosixPath(value) {
|
|
131
|
+
return String(value).split(path.sep).join('/');
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
function getRepoRelativePath(targetPath) {
|
|
135
|
+
if (!targetPath) {
|
|
136
|
+
return null;
|
|
137
|
+
}
|
|
138
|
+
const relative = path.relative(repoRoot, path.resolve(targetPath));
|
|
139
|
+
if (relative === '') {
|
|
140
|
+
return '.';
|
|
141
|
+
}
|
|
142
|
+
if (relative.startsWith('..') || path.isAbsolute(relative)) {
|
|
143
|
+
return null;
|
|
144
|
+
}
|
|
145
|
+
return toPosixPath(relative);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
function isInsideRepo(targetPath) {
|
|
149
|
+
return Boolean(getRepoRelativePath(targetPath));
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
function isWithinCanonicalRepo(workspaceRoot = getWorkspaceRoot()) {
|
|
153
|
+
return isInsideRepo(workspaceRoot);
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
function serializePublicPath(targetPath) {
|
|
157
|
+
const repoRelativePath = getRepoRelativePath(targetPath);
|
|
158
|
+
if (repoRelativePath) {
|
|
159
|
+
return {
|
|
160
|
+
scope: 'repo',
|
|
161
|
+
path: repoRelativePath,
|
|
162
|
+
};
|
|
163
|
+
}
|
|
164
|
+
return {
|
|
165
|
+
scope: 'local_omitted',
|
|
166
|
+
path: null,
|
|
167
|
+
note: 'Local-only path omitted to keep the paper bundle public-safe.',
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
function serializeArtifactEntry(artifact, kind) {
|
|
172
|
+
const publicPath = serializePublicPath(artifact.path);
|
|
173
|
+
return {
|
|
174
|
+
label: artifact.label,
|
|
175
|
+
kind,
|
|
176
|
+
scope: publicPath.scope,
|
|
177
|
+
path: publicPath.path,
|
|
178
|
+
note: publicPath.note ?? null,
|
|
179
|
+
exists: artifact.exists,
|
|
180
|
+
status: artifact.status ?? null,
|
|
181
|
+
claimLevelGoal: artifact.claimLevelGoal ?? null,
|
|
182
|
+
};
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
function maybeRepoDirectory(label, targetPath, purpose) {
|
|
186
|
+
if (!fs.existsSync(targetPath)) {
|
|
187
|
+
return null;
|
|
188
|
+
}
|
|
189
|
+
const publicPath = serializePublicPath(targetPath);
|
|
190
|
+
return {
|
|
191
|
+
label,
|
|
192
|
+
purpose,
|
|
193
|
+
scope: publicPath.scope,
|
|
194
|
+
path: publicPath.path,
|
|
195
|
+
note: publicPath.note ?? null,
|
|
196
|
+
};
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
function listRepoBundlePointers(problemId) {
|
|
200
|
+
const pointers = [
|
|
201
|
+
maybeRepoDirectory('paper_root', getRepoPaperDir(), 'Repo-only paper workspace root'),
|
|
202
|
+
maybeRepoDirectory('problem_research_bundle', path.join(repoRoot, 'research', 'problems', String(problemId)), 'Deeper public problem research bundle'),
|
|
203
|
+
maybeRepoDirectory('formal_lean_root', path.join(repoRoot, 'formal', 'lean'), 'Repo-local Lean and formalization root'),
|
|
204
|
+
maybeRepoDirectory('analysis_problem_flat', path.join(getRepoAnalysisDir(), `problem${problemId}`), 'Problem-specific analysis bundle'),
|
|
205
|
+
maybeRepoDirectory('analysis_problem_nested', path.join(getRepoAnalysisDir(), 'problems', String(problemId)), 'Nested problem analysis bundle'),
|
|
206
|
+
];
|
|
207
|
+
|
|
208
|
+
return pointers.filter(Boolean);
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
function buildEvidenceLookup(inventory) {
|
|
212
|
+
const entries = [
|
|
213
|
+
...inventory.canonicalArtifacts,
|
|
214
|
+
...inventory.starterArtifacts,
|
|
215
|
+
...inventory.packProblemArtifacts,
|
|
216
|
+
...inventory.computePackets,
|
|
217
|
+
];
|
|
218
|
+
|
|
219
|
+
if (inventory.packContext) {
|
|
220
|
+
entries.push(inventory.packContext);
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
const lookup = new Map();
|
|
224
|
+
for (const entry of entries) {
|
|
225
|
+
const repoRelativePath = getRepoRelativePath(entry.path);
|
|
226
|
+
if (repoRelativePath) {
|
|
227
|
+
lookup.set(entry.label, repoRelativePath);
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
return lookup;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
function getSectionInputs(spec, evidenceLookup, inventory) {
|
|
234
|
+
const inputs = [];
|
|
235
|
+
|
|
236
|
+
for (const label of spec.inputLabels ?? []) {
|
|
237
|
+
const repoRelativePath = evidenceLookup.get(label);
|
|
238
|
+
if (repoRelativePath) {
|
|
239
|
+
inputs.push(repoRelativePath);
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
if (spec.includeAllComputePackets) {
|
|
244
|
+
for (const packet of inventory.computePackets) {
|
|
245
|
+
const repoRelativePath = evidenceLookup.get(packet.label);
|
|
246
|
+
if (repoRelativePath && !inputs.includes(repoRelativePath)) {
|
|
247
|
+
inputs.push(repoRelativePath);
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
return inputs;
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
function buildSuggestedReadingOrder(problem, inventory, evidenceLookup, repoBundlePointers) {
|
|
256
|
+
const entries = [];
|
|
257
|
+
|
|
258
|
+
function pushReading(label, why) {
|
|
259
|
+
const repoRelativePath = evidenceLookup.get(label);
|
|
260
|
+
if (!repoRelativePath) {
|
|
261
|
+
return;
|
|
262
|
+
}
|
|
263
|
+
entries.push({
|
|
264
|
+
label,
|
|
265
|
+
path: repoRelativePath,
|
|
266
|
+
why,
|
|
267
|
+
});
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
pushReading('problem.yaml', 'Canonical problem record and current public metadata.');
|
|
271
|
+
pushReading('STATEMENT.md', 'Shortest clean statement of the problem.');
|
|
272
|
+
pushReading('REFERENCES.md', 'Reference ledger and public literature trail.');
|
|
273
|
+
pushReading('EVIDENCE.md', 'Current evidence posture and public route notes.');
|
|
274
|
+
pushReading('FORMALIZATION.md', 'Formalization posture and proof assistant boundary.');
|
|
275
|
+
pushReading('PACK_CONTEXT.md', 'Family-level framing when the problem lives in a deeper pack.');
|
|
276
|
+
pushReading('FRONTIER_NOTE.md', 'Current frontier and next honest move.');
|
|
277
|
+
pushReading('ATOMIC_BOARD.md', 'Operational dependency graph for the active route.');
|
|
278
|
+
pushReading('CHECKPOINT_NOTES.md', 'Handoff shelf and recent checkpoint posture.');
|
|
279
|
+
|
|
280
|
+
for (const packet of inventory.computePackets) {
|
|
281
|
+
const repoRelativePath = evidenceLookup.get(packet.label);
|
|
282
|
+
if (!repoRelativePath) {
|
|
283
|
+
continue;
|
|
284
|
+
}
|
|
285
|
+
entries.push({
|
|
286
|
+
label: packet.label,
|
|
287
|
+
path: repoRelativePath,
|
|
288
|
+
why: 'Computational or certification packet relevant to proof and verification scope.',
|
|
289
|
+
});
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
for (const pointer of repoBundlePointers) {
|
|
293
|
+
if (!pointer.path) {
|
|
294
|
+
continue;
|
|
295
|
+
}
|
|
296
|
+
entries.push({
|
|
297
|
+
label: pointer.label,
|
|
298
|
+
path: pointer.path,
|
|
299
|
+
why: pointer.purpose,
|
|
300
|
+
});
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
return entries;
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
function buildSectionIndex(problem, inventory, evidenceLookup) {
|
|
307
|
+
return {
|
|
308
|
+
generatedAt: new Date().toISOString(),
|
|
309
|
+
problemId: problem.problemId,
|
|
310
|
+
sections: SECTION_SPECS.map((spec) => ({
|
|
311
|
+
key: spec.key,
|
|
312
|
+
fileName: spec.fileName,
|
|
313
|
+
title: spec.title,
|
|
314
|
+
purpose: spec.purpose,
|
|
315
|
+
primaryInputs: getSectionInputs(spec, evidenceLookup, inventory),
|
|
316
|
+
})),
|
|
317
|
+
};
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
function buildPublicEvidenceIndex(problem, inventory, evidenceLookup, repoBundlePointers) {
|
|
321
|
+
return {
|
|
322
|
+
generatedAt: new Date().toISOString(),
|
|
323
|
+
problemId: problem.problemId,
|
|
324
|
+
title: problem.title,
|
|
325
|
+
sourceUrl: problem.sourceUrl,
|
|
326
|
+
canonicalRepo: CANONICAL_REPO_URL,
|
|
327
|
+
externalSource: problem.externalSource ?? null,
|
|
328
|
+
researchState: problem.researchState ?? null,
|
|
329
|
+
canonicalArtifacts: inventory.canonicalArtifacts.map((artifact) => serializeArtifactEntry(artifact, 'canonical_dossier')),
|
|
330
|
+
starterArtifacts: inventory.starterArtifacts.map((artifact) => serializeArtifactEntry(artifact, 'starter_loop')),
|
|
331
|
+
packContext: inventory.packContext ? serializeArtifactEntry(inventory.packContext, 'pack_context') : null,
|
|
332
|
+
packProblemArtifacts: inventory.packProblemArtifacts.map((artifact) => serializeArtifactEntry(artifact, 'pack_problem')),
|
|
333
|
+
computePackets: inventory.computePackets.map((packet) => serializeArtifactEntry(packet, 'compute_packet')),
|
|
334
|
+
repoBundlePointers,
|
|
335
|
+
suggestedReadingOrder: buildSuggestedReadingOrder(problem, inventory, evidenceLookup, repoBundlePointers),
|
|
336
|
+
};
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
function buildManifest(problem, inventory, bundleDir, previousManifest) {
|
|
340
|
+
const evidenceLookup = buildEvidenceLookup(inventory);
|
|
341
|
+
const repoBundlePointers = listRepoBundlePointers(problem.problemId);
|
|
342
|
+
const publicEvidenceIndex = buildPublicEvidenceIndex(problem, inventory, evidenceLookup, repoBundlePointers);
|
|
343
|
+
const sectionIndex = buildSectionIndex(problem, inventory, evidenceLookup);
|
|
344
|
+
const bundlePublicPath = serializePublicPath(bundleDir);
|
|
345
|
+
const packProblemDir = problem.cluster ? path.join(repoRoot, 'packs', problem.cluster, 'problems', problem.problemId) : null;
|
|
346
|
+
|
|
347
|
+
const manifest = {
|
|
348
|
+
bundleVersion: BUNDLE_VERSION,
|
|
349
|
+
createdAt: previousManifest?.createdAt ?? new Date().toISOString(),
|
|
350
|
+
lastInitializedAt: new Date().toISOString(),
|
|
351
|
+
canonicalRepo: CANONICAL_REPO_URL,
|
|
352
|
+
problem: {
|
|
353
|
+
problemId: problem.problemId,
|
|
354
|
+
displayName: problem.displayName,
|
|
355
|
+
title: problem.title,
|
|
356
|
+
cluster: problem.cluster,
|
|
357
|
+
sourceUrl: problem.sourceUrl,
|
|
358
|
+
siteStatus: problem.siteStatus,
|
|
359
|
+
repoStatus: problem.repoStatus,
|
|
360
|
+
harnessDepth: problem.harnessDepth,
|
|
361
|
+
formalizationStatus: problem.formalizationStatus,
|
|
362
|
+
sourceKind: problem.sourceKind,
|
|
363
|
+
activeRoute: problem.researchState?.active_route ?? null,
|
|
364
|
+
routeBreakthrough: problem.researchState?.route_breakthrough ?? false,
|
|
365
|
+
problemSolved: problem.researchState?.problem_solved ?? false,
|
|
366
|
+
openProblem: problem.researchState?.open_problem ?? null,
|
|
367
|
+
},
|
|
368
|
+
paperMode: problem.researchState?.problem_solved
|
|
369
|
+
? 'proof_or_archive_paper'
|
|
370
|
+
: 'claim_safe_progress_or_route_paper',
|
|
371
|
+
bundlePath: bundlePublicPath.path,
|
|
372
|
+
bundlePathScope: bundlePublicPath.scope,
|
|
373
|
+
bundlePathNote: bundlePublicPath.note ?? null,
|
|
374
|
+
canonicalPaths: {
|
|
375
|
+
problemDir: serializePublicPath(problem.problemDir),
|
|
376
|
+
packProblemDir: serializePublicPath(packProblemDir),
|
|
377
|
+
paperDir: serializePublicPath(getRepoPaperDir()),
|
|
378
|
+
},
|
|
379
|
+
publicEvidenceSummary: {
|
|
380
|
+
canonicalArtifacts: inventory.canonicalArtifacts.length,
|
|
381
|
+
starterArtifacts: inventory.starterArtifacts.length,
|
|
382
|
+
packProblemArtifacts: inventory.packProblemArtifacts.length,
|
|
383
|
+
computePackets: inventory.computePackets.length,
|
|
384
|
+
importedRecordIncluded: inventory.upstreamRecordIncluded,
|
|
385
|
+
},
|
|
386
|
+
externalProvenance: problem.externalSource ?? null,
|
|
387
|
+
policy: {
|
|
388
|
+
privacy: [
|
|
389
|
+
'Do not include secrets, credentials, tokens, or unpublished private correspondence.',
|
|
390
|
+
'Do not serialize local absolute filesystem paths into committed paper artifacts.',
|
|
391
|
+
'Treat only repo-public material and explicitly cited public sources as publication inputs.',
|
|
392
|
+
],
|
|
393
|
+
claimSafety: [
|
|
394
|
+
'Use theorem-style language only for claims supported by the current public record.',
|
|
395
|
+
'Mark heuristics, computational evidence, and route targets with their true status.',
|
|
396
|
+
'Leave unresolved seams visible instead of smoothing them over in prose.',
|
|
397
|
+
],
|
|
398
|
+
citationDiscipline: [
|
|
399
|
+
'Every external mathematical claim should have a row in CITATION_LEDGER.md before it lands in prose.',
|
|
400
|
+
'Imported external atlases are provenance inputs, not canonical authority.',
|
|
401
|
+
'Prefer exact URLs, paper identifiers, theorem labels, and publication metadata when available.',
|
|
402
|
+
],
|
|
403
|
+
},
|
|
404
|
+
publicEvidenceIndexFile: 'PUBLIC_EVIDENCE_INDEX.json',
|
|
405
|
+
sectionIndexFile: 'SECTION_INDEX.json',
|
|
406
|
+
};
|
|
407
|
+
|
|
408
|
+
return {
|
|
409
|
+
manifest,
|
|
410
|
+
publicEvidenceIndex,
|
|
411
|
+
sectionIndex,
|
|
412
|
+
};
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
function renderBundleReadme(problem, manifest) {
|
|
416
|
+
return [
|
|
417
|
+
`# ${problem.displayName} Paper Bundle`,
|
|
418
|
+
'',
|
|
419
|
+
`This bundle is the public-safe paper workspace for **${problem.title}**.`,
|
|
420
|
+
'',
|
|
421
|
+
'Use it to start a new paper from scratch or resume an existing draft without overwriting your section files.',
|
|
422
|
+
'',
|
|
423
|
+
'Start here:',
|
|
424
|
+
'- `WRITER_BRIEF.md` for the agent-safe workflow',
|
|
425
|
+
'- `MANIFEST.json` for machine-readable problem status and public bundle metadata',
|
|
426
|
+
'- `PUBLIC_EVIDENCE_INDEX.json` for the exact public inputs available today',
|
|
427
|
+
'- `SECTION_STATUS.md` for the writing queue and handoff state',
|
|
428
|
+
'- `PRIVACY_REVIEW.md` before anything public is released',
|
|
429
|
+
'',
|
|
430
|
+
'Current posture:',
|
|
431
|
+
`- paper mode: ${manifest.paperMode}`,
|
|
432
|
+
`- active route: ${problem.researchState?.active_route ?? '(none)'}`,
|
|
433
|
+
`- open problem: ${problem.researchState?.open_problem ? 'yes' : 'no'}`,
|
|
434
|
+
`- problem solved: ${problem.researchState?.problem_solved ? 'yes' : 'no'}`,
|
|
435
|
+
'',
|
|
436
|
+
].join('\n');
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
function renderWriterBrief(problem, sectionIndex, manifest) {
|
|
440
|
+
return [
|
|
441
|
+
`# ${problem.displayName} Writer Brief`,
|
|
442
|
+
'',
|
|
443
|
+
'Mission:',
|
|
444
|
+
`- turn the current public record for **${problem.title}** into a paper draft that is readable, citation-safe, and claim-safe`,
|
|
445
|
+
'- preserve privacy boundaries while making the paper bundle easy for agents and future researchers to extend',
|
|
446
|
+
'',
|
|
447
|
+
'Hard rules:',
|
|
448
|
+
'- do not include secrets, tokens, private messages, unpublished private notes, or local absolute paths',
|
|
449
|
+
'- treat only the canonical repo record and explicitly cited public sources as publication inputs',
|
|
450
|
+
'- cite every nontrivial external claim in `CITATION_LEDGER.md` before relying on it in prose',
|
|
451
|
+
'- distinguish rigorously between theorem/proposition, conjecture, heuristic, and computational evidence',
|
|
452
|
+
'- leave open seams visible and move them into `LIMITATIONS_AND_OPEN_PROBLEMS.md` instead of hiding them',
|
|
453
|
+
'',
|
|
454
|
+
'Recommended loop:',
|
|
455
|
+
'1. Read `MANIFEST.json` and `PUBLIC_EVIDENCE_INDEX.json`.',
|
|
456
|
+
'2. Read the suggested inputs in `SECTION_INDEX.json`.',
|
|
457
|
+
'3. Update `OUTLINE.md` and `SECTION_STATUS.md` before drafting.',
|
|
458
|
+
'4. Add external literature rows to `CITATION_LEDGER.md` as soon as a source enters the draft.',
|
|
459
|
+
'5. Write or refine section files one at a time.',
|
|
460
|
+
'6. Run the checklist in `PRIVACY_REVIEW.md` before public release or PR submission.',
|
|
461
|
+
'',
|
|
462
|
+
'Current public status:',
|
|
463
|
+
`- paper mode: ${manifest.paperMode}`,
|
|
464
|
+
`- site status: ${problem.siteStatus}`,
|
|
465
|
+
`- repo status: ${problem.repoStatus}`,
|
|
466
|
+
`- active route: ${problem.researchState?.active_route ?? '(none)'}`,
|
|
467
|
+
`- imported record included: ${manifest.publicEvidenceSummary.importedRecordIncluded ? 'yes' : 'no'}`,
|
|
468
|
+
'',
|
|
469
|
+
'Section files in this bundle:',
|
|
470
|
+
...sectionIndex.sections.map((section) => `- ${section.fileName}: ${section.purpose}`),
|
|
471
|
+
'',
|
|
472
|
+
].join('\n');
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
function renderSectionStatus(sectionIndex) {
|
|
476
|
+
const rows = [
|
|
477
|
+
'# Section Status',
|
|
478
|
+
'',
|
|
479
|
+
'| Section | Status | Primary public inputs | Notes |',
|
|
480
|
+
'| --- | --- | --- | --- |',
|
|
481
|
+
];
|
|
482
|
+
|
|
483
|
+
for (const section of sectionIndex.sections) {
|
|
484
|
+
const inputs = section.primaryInputs.length > 0
|
|
485
|
+
? section.primaryInputs.join('<br>')
|
|
486
|
+
: '(add public inputs)';
|
|
487
|
+
rows.push(`| ${section.title} | not started | ${inputs} | Keep claims honest and source-backed. |`);
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
return rows.join('\n') + '\n';
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
function renderOutline(problem) {
|
|
494
|
+
const paperShape = problem.researchState?.problem_solved
|
|
495
|
+
? 'proof/archive paper'
|
|
496
|
+
: 'claim-safe progress paper or route paper';
|
|
497
|
+
|
|
498
|
+
return [
|
|
499
|
+
'# Outline',
|
|
500
|
+
'',
|
|
501
|
+
`Working paper shape: ${paperShape}`,
|
|
502
|
+
'',
|
|
503
|
+
'Recommended order:',
|
|
504
|
+
'1. Abstract',
|
|
505
|
+
'2. Introduction',
|
|
506
|
+
'3. Preliminaries',
|
|
507
|
+
'4. Related Work',
|
|
508
|
+
'5. Main Results',
|
|
509
|
+
'6. Proof Overview',
|
|
510
|
+
'7. Proof Details',
|
|
511
|
+
'8. Computational and Formal Evidence',
|
|
512
|
+
'9. Limitations and Open Problems',
|
|
513
|
+
'',
|
|
514
|
+
'Angle:',
|
|
515
|
+
`- problem: ${problem.displayName}`,
|
|
516
|
+
`- active route: ${problem.researchState?.active_route ?? '(none)'}`,
|
|
517
|
+
`- open problem: ${problem.researchState?.open_problem ? 'yes' : 'no'}`,
|
|
518
|
+
'- rewrite this outline once the paper scope is fixed',
|
|
519
|
+
'',
|
|
520
|
+
].join('\n');
|
|
521
|
+
}
|
|
522
|
+
|
|
523
|
+
function renderStyleGuide(problem) {
|
|
524
|
+
return [
|
|
525
|
+
'# Style Guide',
|
|
526
|
+
'',
|
|
527
|
+
'Claim-safe language:',
|
|
528
|
+
'- use "we prove" only when the proof is fully present in the public record',
|
|
529
|
+
'- use "we outline", "we propose", or "we isolate" for route structure that is not yet proved',
|
|
530
|
+
'- use "computational evidence suggests" for search- or certificate-based support',
|
|
531
|
+
'- use "the current public route leaves open" when a dependency chain is incomplete',
|
|
532
|
+
'',
|
|
533
|
+
'Citation discipline:',
|
|
534
|
+
'- every external theorem, definition, or historical claim should be traceable through `CITATION_LEDGER.md`',
|
|
535
|
+
'- prefer exact theorem labels, page references, DOIs, arXiv IDs, or URLs over vague mentions',
|
|
536
|
+
'- imported atlas metadata should be described as provenance, not as final authority',
|
|
537
|
+
'',
|
|
538
|
+
'Public truth posture:',
|
|
539
|
+
`- this bundle is for ${problem.researchState?.problem_solved ? 'proof/archive exposition' : 'progress writing without status inflation'}`,
|
|
540
|
+
'- if the route is incomplete, say exactly which seam remains open',
|
|
541
|
+
'- conclude with a handoff that makes the next research move easy to see',
|
|
542
|
+
'',
|
|
543
|
+
].join('\n');
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
function renderPrivacyReview(problem) {
|
|
547
|
+
return [
|
|
548
|
+
'# Privacy Review',
|
|
549
|
+
'',
|
|
550
|
+
'Do not publish until each item below has been checked:',
|
|
551
|
+
'',
|
|
552
|
+
'- [ ] No secrets, credentials, tokens, or access links appear anywhere in this bundle.',
|
|
553
|
+
'- [ ] No absolute local filesystem paths appear anywhere in this bundle.',
|
|
554
|
+
'- [ ] No private correspondence, direct messages, or unpublished private notes are quoted or paraphrased.',
|
|
555
|
+
'- [ ] Every external mathematical claim has a matching row in `CITATION_LEDGER.md`.',
|
|
556
|
+
'- [ ] Every statement described as proved is backed by the current public record.',
|
|
557
|
+
'- [ ] Open seams, missing lemmas, and uncertainty are explicitly recorded in `LIMITATIONS_AND_OPEN_PROBLEMS.md`.',
|
|
558
|
+
'- [ ] The final abstract and introduction do not oversell the current status of the problem.',
|
|
559
|
+
'',
|
|
560
|
+
'Review block:',
|
|
561
|
+
`- problem: ${problem.displayName}`,
|
|
562
|
+
'- reviewer: ',
|
|
563
|
+
'- date: ',
|
|
564
|
+
'- release scope: ',
|
|
565
|
+
'',
|
|
566
|
+
].join('\n');
|
|
567
|
+
}
|
|
568
|
+
|
|
569
|
+
function renderCitationLedger(problem) {
|
|
570
|
+
const rows = [
|
|
571
|
+
'# Citation Ledger',
|
|
572
|
+
'',
|
|
573
|
+
'| Source | Kind | Used For | Status | Notes |',
|
|
574
|
+
'| --- | --- | --- | --- | --- |',
|
|
575
|
+
`| ${problem.sourceUrl} | source page | statement, status, public framing | seeded | Canonical public problem source page. |`,
|
|
576
|
+
];
|
|
577
|
+
|
|
578
|
+
if (problem.externalSource?.repo) {
|
|
579
|
+
rows.push(`| ${problem.externalSource.repo} | external import atlas | imported provenance | seeded | Comparison and provenance only; not canonical authority. |`);
|
|
580
|
+
}
|
|
581
|
+
|
|
582
|
+
rows.push('| (add source) | paper / book / note / dataset | theorem, history, comparison, or method | pending | Add exact identifiers before using in prose. |');
|
|
583
|
+
return rows.join('\n') + '\n';
|
|
584
|
+
}
|
|
585
|
+
|
|
586
|
+
function renderSectionFile(problem, section, inputs) {
|
|
587
|
+
return [
|
|
588
|
+
`# ${section.title}`,
|
|
589
|
+
'',
|
|
590
|
+
`Problem: ${problem.displayName} — ${problem.title}`,
|
|
591
|
+
`Section role: ${section.purpose}`,
|
|
592
|
+
'',
|
|
593
|
+
'Primary public inputs:',
|
|
594
|
+
...(inputs.length > 0
|
|
595
|
+
? inputs.map((input) => `- ${input}`)
|
|
596
|
+
: ['- (add repo-public inputs here before drafting)']),
|
|
597
|
+
'',
|
|
598
|
+
'Writing guardrails:',
|
|
599
|
+
...section.guardrails.map((guardrail) => `- ${guardrail}`),
|
|
600
|
+
'',
|
|
601
|
+
'Draft:',
|
|
602
|
+
'',
|
|
603
|
+
'> Start writing here. Keep every claim matched to public evidence or clearly labeled as conjectural, heuristic, or computational.',
|
|
604
|
+
'',
|
|
605
|
+
].join('\n');
|
|
606
|
+
}
|
|
607
|
+
|
|
608
|
+
function writeIfMissing(targetPath, text, createdFiles, preservedFiles) {
|
|
609
|
+
if (fileExists(targetPath)) {
|
|
610
|
+
preservedFiles.push(path.basename(targetPath));
|
|
611
|
+
return;
|
|
612
|
+
}
|
|
613
|
+
writeText(targetPath, text);
|
|
614
|
+
createdFiles.push(path.basename(targetPath));
|
|
615
|
+
}
|
|
616
|
+
|
|
617
|
+
export function resolvePaperBundleDir(problemId, options = {}) {
|
|
618
|
+
const workspaceRoot = options.workspaceRoot ?? getWorkspaceRoot();
|
|
619
|
+
if (options.destination) {
|
|
620
|
+
return path.resolve(options.destination);
|
|
621
|
+
}
|
|
622
|
+
if (isWithinCanonicalRepo(workspaceRoot) && fs.existsSync(getRepoPaperDir())) {
|
|
623
|
+
return getRepoProblemPaperDir(problemId);
|
|
624
|
+
}
|
|
625
|
+
return getWorkspaceProblemPaperDir(problemId, workspaceRoot);
|
|
626
|
+
}
|
|
627
|
+
|
|
628
|
+
export function initPaperBundle(problemId, options = {}) {
|
|
629
|
+
const workspaceRoot = options.workspaceRoot ?? getWorkspaceRoot();
|
|
630
|
+
const problem = getProblem(problemId, workspaceRoot);
|
|
631
|
+
if (!problem) {
|
|
632
|
+
throw new Error(`Unknown problem: ${problemId}`);
|
|
633
|
+
}
|
|
634
|
+
|
|
635
|
+
const bundleDir = resolvePaperBundleDir(problem.problemId, options);
|
|
636
|
+
fs.mkdirSync(bundleDir, { recursive: true });
|
|
637
|
+
|
|
638
|
+
const inventory = getProblemArtifactInventory(problem);
|
|
639
|
+
const manifestPath = path.join(bundleDir, 'MANIFEST.json');
|
|
640
|
+
const previousManifest = fileExists(manifestPath) ? readJson(manifestPath) : null;
|
|
641
|
+
const { manifest, publicEvidenceIndex, sectionIndex } = buildManifest(problem, inventory, bundleDir, previousManifest);
|
|
642
|
+
|
|
643
|
+
const bundlePreviouslyInitialized = previousManifest !== null || fs.readdirSync(bundleDir).length > 0;
|
|
644
|
+
const createdFiles = [];
|
|
645
|
+
const preservedFiles = [];
|
|
646
|
+
const updatedFiles = [];
|
|
647
|
+
|
|
648
|
+
writeJson(manifestPath, manifest);
|
|
649
|
+
updatedFiles.push('MANIFEST.json');
|
|
650
|
+
|
|
651
|
+
writeJson(path.join(bundleDir, 'PUBLIC_EVIDENCE_INDEX.json'), publicEvidenceIndex);
|
|
652
|
+
updatedFiles.push('PUBLIC_EVIDENCE_INDEX.json');
|
|
653
|
+
|
|
654
|
+
writeJson(path.join(bundleDir, 'SECTION_INDEX.json'), sectionIndex);
|
|
655
|
+
updatedFiles.push('SECTION_INDEX.json');
|
|
656
|
+
|
|
657
|
+
writeIfMissing(path.join(bundleDir, 'README.md'), renderBundleReadme(problem, manifest), createdFiles, preservedFiles);
|
|
658
|
+
writeIfMissing(path.join(bundleDir, 'WRITER_BRIEF.md'), renderWriterBrief(problem, sectionIndex, manifest), createdFiles, preservedFiles);
|
|
659
|
+
writeIfMissing(path.join(bundleDir, 'SECTION_STATUS.md'), renderSectionStatus(sectionIndex), createdFiles, preservedFiles);
|
|
660
|
+
writeIfMissing(path.join(bundleDir, 'OUTLINE.md'), renderOutline(problem), createdFiles, preservedFiles);
|
|
661
|
+
writeIfMissing(path.join(bundleDir, 'STYLE_GUIDE.md'), renderStyleGuide(problem), createdFiles, preservedFiles);
|
|
662
|
+
writeIfMissing(path.join(bundleDir, 'PRIVACY_REVIEW.md'), renderPrivacyReview(problem), createdFiles, preservedFiles);
|
|
663
|
+
writeIfMissing(path.join(bundleDir, 'CITATION_LEDGER.md'), renderCitationLedger(problem), createdFiles, preservedFiles);
|
|
664
|
+
|
|
665
|
+
for (const section of SECTION_SPECS) {
|
|
666
|
+
const inputs = sectionIndex.sections.find((candidate) => candidate.fileName === section.fileName)?.primaryInputs ?? [];
|
|
667
|
+
writeIfMissing(path.join(bundleDir, section.fileName), renderSectionFile(problem, section, inputs), createdFiles, preservedFiles);
|
|
668
|
+
}
|
|
669
|
+
|
|
670
|
+
return {
|
|
671
|
+
problemId: problem.problemId,
|
|
672
|
+
title: problem.title,
|
|
673
|
+
bundleDir,
|
|
674
|
+
bundlePublicPath: manifest.bundlePath,
|
|
675
|
+
mode: bundlePreviouslyInitialized ? 'resumed' : 'initialized',
|
|
676
|
+
createdFiles,
|
|
677
|
+
preservedFiles,
|
|
678
|
+
updatedFiles,
|
|
679
|
+
manifest,
|
|
680
|
+
publicEvidenceIndex,
|
|
681
|
+
sectionIndex,
|
|
682
|
+
};
|
|
683
|
+
}
|
|
684
|
+
|
|
685
|
+
export function getPaperBundleOverview(problemId, options = {}) {
|
|
686
|
+
const workspaceRoot = options.workspaceRoot ?? getWorkspaceRoot();
|
|
687
|
+
const effectiveProblemId = problemId ?? null;
|
|
688
|
+
const bundleDir = resolvePaperBundleDir(effectiveProblemId, options);
|
|
689
|
+
const manifestPath = path.join(bundleDir, 'MANIFEST.json');
|
|
690
|
+
if (!fileExists(manifestPath)) {
|
|
691
|
+
throw new Error(`Paper bundle not initialized: ${bundleDir}`);
|
|
692
|
+
}
|
|
693
|
+
|
|
694
|
+
const manifest = readJson(manifestPath);
|
|
695
|
+
const sectionIndexPath = path.join(bundleDir, 'SECTION_INDEX.json');
|
|
696
|
+
const sectionIndex = fileExists(sectionIndexPath) ? readJson(sectionIndexPath) : { sections: [] };
|
|
697
|
+
|
|
698
|
+
return {
|
|
699
|
+
problemId: manifest.problem.problemId,
|
|
700
|
+
title: manifest.problem.title,
|
|
701
|
+
bundleDir,
|
|
702
|
+
bundlePublicPath: manifest.bundlePath,
|
|
703
|
+
paperMode: manifest.paperMode,
|
|
704
|
+
createdAt: manifest.createdAt,
|
|
705
|
+
lastInitializedAt: manifest.lastInitializedAt,
|
|
706
|
+
publicEvidenceSummary: manifest.publicEvidenceSummary,
|
|
707
|
+
paths: {
|
|
708
|
+
manifest: 'MANIFEST.json',
|
|
709
|
+
writerBrief: 'WRITER_BRIEF.md',
|
|
710
|
+
sectionStatus: 'SECTION_STATUS.md',
|
|
711
|
+
evidenceIndex: 'PUBLIC_EVIDENCE_INDEX.json',
|
|
712
|
+
privacyReview: 'PRIVACY_REVIEW.md',
|
|
713
|
+
citationLedger: 'CITATION_LEDGER.md',
|
|
714
|
+
},
|
|
715
|
+
sections: sectionIndex.sections.map((section) => ({
|
|
716
|
+
...section,
|
|
717
|
+
exists: fileExists(path.join(bundleDir, section.fileName)),
|
|
718
|
+
})),
|
|
719
|
+
};
|
|
720
|
+
}
|