erdos-problems 0.1.5 → 0.1.7

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 CHANGED
@@ -38,6 +38,14 @@ erdos sunflower status 857
38
38
  erdos dossier show 857
39
39
  ```
40
40
 
41
+ For an unseeded problem, the one-step self-seeding flow is now:
42
+
43
+ ```bash
44
+ erdos seed problem 1 --include-site --cluster number-theory
45
+ erdos problem show 1
46
+ erdos workspace show
47
+ ```
48
+
41
49
  What `bootstrap` does:
42
50
  - sets the active workspace problem
43
51
  - scaffolds the canonical dossier files into `.erdos/scaffolds/<id>/`
@@ -45,6 +53,13 @@ What `bootstrap` does:
45
53
  - copies pack-specific context and compute packets when the problem has them
46
54
  - gives an agent a ready-to-read local artifact bundle immediately after install
47
55
 
56
+ What `seed` does:
57
+ - creates a pull bundle for any problem in the upstream snapshot
58
+ - promotes that bundle into `.erdos/seeded-problems/<id>/`
59
+ - auto-selects the problem in the workspace
60
+ - syncs the staged research loop state and checkpoint shelf
61
+ - makes the new dossier visible to the atlas commands immediately inside that workspace
62
+
48
63
  ## Pull lanes
49
64
 
50
65
  For any problem number in the upstream snapshot, you can create a workspace bundle even if the problem is not yet seeded locally:
@@ -138,6 +153,7 @@ erdos upstream diff
138
153
  erdos scaffold problem 857
139
154
  erdos bootstrap problem 857
140
155
  erdos bootstrap problem 857 --sync-upstream
156
+ erdos seed problem 1 --include-site --cluster number-theory
141
157
  erdos pull problem 857
142
158
  erdos pull artifacts 857
143
159
  erdos pull literature 857
@@ -166,6 +182,7 @@ The CLI can surface these directly:
166
182
  - `erdos problem artifacts <id> --json` emits machine-readable inventory
167
183
  - `erdos scaffold problem <id>` copies the seeded dossier into the active workspace
168
184
  - `erdos bootstrap problem <id>` selects the problem and creates the scaffold in one step
185
+ - `erdos seed problem <id>` self-seeds an unseeded problem into `.erdos/seeded-problems/` and syncs the loop
169
186
  - `erdos pull problem <id>` creates a workspace bundle for any problem in the upstream snapshot
170
187
  - `erdos maintainer seed problem <id>` promotes a pull bundle into a canonical local dossier
171
188
 
@@ -184,3 +201,38 @@ For sunflower problems, the CLI also surfaces pack-specific artifacts:
184
201
  - `docs/ERDOS_PROBLEMS_REPO_SPEC.md`
185
202
  - `docs/ERDOS_PROBLEMS_PROBLEM_SCHEMA.md`
186
203
  - `docs/ERDOS_SUNFLOWER_CLUSTER_SEED_PLAN.md`
204
+
205
+ ## Research loop
206
+
207
+ `erdos-problems` now carries the staged loop we defined in the sunflower lab and the `.gpd`-style harness work:
208
+
209
+ ```bash
210
+ erdos problem use 857
211
+ erdos state sync
212
+ erdos preflight
213
+ erdos continuation use route
214
+ erdos checkpoints sync
215
+ erdos workspace show
216
+ ```
217
+
218
+ This runtime writes:
219
+ - `.erdos/config.json`
220
+ - `.erdos/state.json`
221
+ - `.erdos/STATE.md`
222
+ - `.erdos/QUESTION-LEDGER.md`
223
+ - `.erdos/checkpoints/CHECKPOINTS.md`
224
+ - `.erdos/checkpoints/CHECKPOINTS.json`
225
+ - `.erdos/registry/preflight/`
226
+
227
+ The public package uses the same status ladder we settled on in the lab:
228
+ - open problem
229
+ - active route
230
+ - route breakthrough
231
+ - problem solved
232
+
233
+ That means a fresh install now supports two clean research starts:
234
+ - `erdos bootstrap problem <seeded-id>` for native packaged dossiers
235
+ - `erdos seed problem <unseeded-id>` for workspace-local self-seeding with the same loop
236
+
237
+ See also:
238
+ - `docs/RESEARCH_LOOP.md`
@@ -0,0 +1,58 @@
1
+ # Research Loop
2
+
3
+ `erdos-problems` now carries the staged research loop that was proven out in the sunflower lab and refined by the `.gpd` flow in `longevity-research`.
4
+
5
+ ## Runtime layout
6
+
7
+ Workspace runtime files live under `.erdos/`:
8
+ - `config.json`
9
+ - `state.json`
10
+ - `STATE.md`
11
+ - `QUESTION-LEDGER.md`
12
+ - `checkpoints/CHECKPOINTS.md`
13
+ - `checkpoints/CHECKPOINTS.json`
14
+ - `registry/preflight/`
15
+ - `registry/compute/`
16
+
17
+ ## Core loop
18
+
19
+ 1. Select or bootstrap a problem.
20
+ 2. Sync state.
21
+ 3. Run preflight.
22
+ 4. Set continuation mode.
23
+ 5. Sync checkpoints.
24
+ 6. Pull or scaffold artifacts.
25
+ 7. Work the active route.
26
+ 8. Sync checkpoints again at honest boundaries.
27
+
28
+ ## Commands
29
+
30
+ ```bash
31
+ erdos problem use 857
32
+ erdos state sync
33
+ erdos preflight
34
+ erdos continuation use route
35
+ erdos checkpoints sync
36
+ erdos workspace show
37
+ ```
38
+
39
+ For problems that are not yet packaged as native dossiers, the loop can start with one-step self-seeding:
40
+
41
+ ```bash
42
+ erdos seed problem 1 --include-site --cluster number-theory
43
+ erdos preflight
44
+ erdos continuation use route
45
+ erdos checkpoints sync
46
+ ```
47
+
48
+ That flow writes the local dossier into `.erdos/seeded-problems/<id>/`, makes it visible to the atlas inside the current workspace, and immediately syncs the same state/checkpoint machinery used by packaged dossiers.
49
+
50
+ ## Status ladder
51
+
52
+ The public package uses the same ladder we converged on in the lab:
53
+ - open problem
54
+ - active route
55
+ - route breakthrough
56
+ - problem solved
57
+
58
+ The key rule is that route breakthroughs are never silently inflated into solved-problem claims.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "erdos-problems",
3
- "version": "0.1.5",
3
+ "version": "0.1.7",
4
4
  "description": "CLI atlas and staged research harness for Paul Erdos problems.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -0,0 +1,16 @@
1
+ lane_id: u3_uniform_transfer_window_v0
2
+ problem_id: "20"
3
+ cluster: sunflower
4
+ question: Can the uniform k=3 lane be frozen into a transfer-ready reduction packet that talks cleanly to the weak 857 export route?
5
+ claim_level_goal: Verified
6
+ status: ready_for_local_scout
7
+ price_checked_local_date: 2026-03-25
8
+ recommendation: local_scout_first
9
+ approval_required: false
10
+ summary: Problem 20 now has a frozen local-scout packet for the uniform k=3 transfer window. The job is to verify a small explicit reduction bundle before any paid compute rung is considered.
11
+ source_repo: /Volumes/Code_2TB/code/sunflower-coda/repo
12
+ public_feature: uniform_k3_frontier
13
+ rungs:
14
+ - label: local_scout
15
+ mode: local
16
+ goal: verify the reduction packet, pull artifacts, and checkpoint the first honest route result
@@ -7,3 +7,8 @@ Role in family:
7
7
  Bootstrap focus:
8
8
  - start from the uniform k=3 lane
9
9
  - keep explicit bridges back to 857 whenever a route or method transfers cleanly
10
+
11
+ Frontier framing:
12
+ - the live goal is not “solve strong sunflower in one jump”
13
+ - the live goal is to package the uniform k=3 lane into a recurrence-ready and transfer-ready route
14
+ - checkpoint every route breakthrough before widening the public claim surface
@@ -3,6 +3,11 @@ family_role: strong_sunflower_core
3
3
  harness_profile: deep
4
4
  default_active_route: uniform_k3_frontier
5
5
  bootstrap_focus: Frame the strong or uniform k=3 sunflower lane as the direct sibling frontier to the weak 857 route.
6
+ route_story: Keep the uniform k=3 lane explicit, preserve every clean bridge to problem 857, and do not let local route work masquerade as full strong-sunflower closure.
7
+ frontier_label: uniform_k3_frontier
8
+ frontier_detail: Tighten the uniform k=3 route into a recurrence-ready and transfer-ready reduction packet that can talk honestly to the weak 857 export program.
9
+ checkpoint_focus: Record honest uniform-family route claims, bridge notes to 857, and any reusable reductions without overstating global closure.
10
+ next_honest_move: Pull the uniform k=3 dossier, sync checkpoints, and pressure the smallest recurrence-facing or reduction-facing obligation.
6
11
  related_core_problems:
7
12
  - "857"
8
13
  - "536"
@@ -16,3 +21,11 @@ artifact_focus:
16
21
  - uniform-family reductions
17
22
  - k=3 active route notes
18
23
  - bridge notes to 857
24
+ question_ledger:
25
+ open_questions:
26
+ - Which uniform k=3 reduction is the next smallest honest route step?
27
+ - What bridge result would cleanly transfer from problem 20 back into the weak 857 program?
28
+ active_route_notes:
29
+ - Keep the active route stated in uniform-family language, not generic sunflower shorthand.
30
+ route_breakthroughs:
31
+ - If a route breakthrough lands, checkpoint it before widening to strong-sunflower victory language.
@@ -7,3 +7,8 @@ Role in family:
7
7
  Bootstrap focus:
8
8
  - preserve the live route framing in the scaffold
9
9
  - keep literature, artifact, and compute packets aligned with the active frontier rather than generic sunflower chatter
10
+
11
+ Frontier framing:
12
+ - preserve the active export/compression route as the live frontier
13
+ - keep the recurrence-facing remainder terms explicit in every checkpoint
14
+ - do not blur route breakthroughs into claims that the open problem is solved
@@ -3,6 +3,11 @@ family_role: weak_sunflower_core
3
3
  harness_profile: deep
4
4
  default_active_route: anchored_selector_linearization
5
5
  bootstrap_focus: Start from the weak sunflower asymptotic route and preserve the active export/compression frontier in the scaffold.
6
+ route_story: Keep the weak sunflower route pointed at recurrence-facing export and compression work, and preserve the distinction between route breakthroughs and full problem closure.
7
+ frontier_label: anchored_selector_linearization
8
+ frontier_detail: Preserve the live export/compression frontier and keep the recurrence-facing remainder terms explicit rather than flattening them into generic sunflower notes.
9
+ checkpoint_focus: Record route breakthroughs, keep the open-problem versus active-route distinction sharp, and preserve the live remainder/compression obligations in every checkpoint.
10
+ next_honest_move: Sync checkpoints, then keep compressing the explicit O1a export into a true recurrence-facing step.
6
11
  related_core_problems:
7
12
  - "20"
8
13
  - "536"
@@ -16,3 +21,12 @@ artifact_focus:
16
21
  - active route notes
17
22
  - formal frontier checkpoints
18
23
  - compute lane packets when frozen
24
+ question_ledger:
25
+ open_questions:
26
+ - Which explicit compression step is the next honest reduction on the active weak-sunflower route?
27
+ - Which exported remainder term is still dominating the recurrence-facing frontier?
28
+ active_route_notes:
29
+ - Keep active-route notes tied to the explicit export/compression frontier, not generic sunflower chatter.
30
+ - Preserve the distinction between route breakthrough and full-problem solution in every artifact.
31
+ route_breakthroughs:
32
+ - When a route breakthrough lands, checkpoint it before selecting the next active route.
@@ -1,18 +1,15 @@
1
1
  import fs from 'node:fs';
2
2
  import path from 'node:path';
3
3
  import { parse } from 'yaml';
4
- import { getProblemDir, repoRoot } from '../runtime/paths.js';
4
+ import { getProblemDir, getWorkspaceRoot, getWorkspaceSeededProblemsDir, repoRoot } from '../runtime/paths.js';
5
5
 
6
- let cachedProblems = null;
7
-
8
- function readProblemRecord(problemId) {
9
- const problemDir = getProblemDir(problemId);
6
+ function readProblemRecordFromDir(problemDir) {
10
7
  const yamlPath = path.join(problemDir, 'problem.yaml');
11
8
  const record = parse(fs.readFileSync(yamlPath, 'utf8'));
12
9
  return { problemDir, record };
13
10
  }
14
11
 
15
- function toCatalogProblem(problemDir, record) {
12
+ function toCatalogProblem(problemDir, record, sourceKind) {
16
13
  const statementRelative = record.statement?.normalized_md_path ?? 'STATEMENT.md';
17
14
  const referencesRelative = record.references_path ?? 'REFERENCES.md';
18
15
  const evidenceRelative = record.evidence_path ?? 'EVIDENCE.md';
@@ -47,47 +44,58 @@ function toCatalogProblem(problemDir, record) {
47
44
  problemDir,
48
45
  problemYamlPath: path.join(problemDir, 'problem.yaml'),
49
46
  record,
47
+ sourceKind,
50
48
  };
51
49
  }
52
50
 
53
- export function loadLocalProblems() {
54
- if (cachedProblems) {
55
- return cachedProblems;
51
+ function listProblemDirectories(rootDir) {
52
+ if (!fs.existsSync(rootDir)) {
53
+ return [];
56
54
  }
57
- const problemsRoot = path.join(repoRoot, 'problems');
58
- const directories = fs
59
- .readdirSync(problemsRoot, { withFileTypes: true })
55
+ return fs
56
+ .readdirSync(rootDir, { withFileTypes: true })
60
57
  .filter((entry) => entry.isDirectory())
61
- .map((entry) => entry.name)
62
- .sort((a, b) => Number(a) - Number(b));
58
+ .map((entry) => path.join(rootDir, entry.name));
59
+ }
60
+
61
+ export function loadLocalProblems(workspaceRoot = getWorkspaceRoot()) {
62
+ const packageRoot = path.join(repoRoot, 'problems');
63
+ const workspaceRootDir = getWorkspaceSeededProblemsDir(workspaceRoot);
64
+ const merged = new Map();
65
+
66
+ for (const problemDir of listProblemDirectories(packageRoot)) {
67
+ const { record } = readProblemRecordFromDir(problemDir);
68
+ merged.set(String(record.problem_id), toCatalogProblem(problemDir, record, 'package'));
69
+ }
70
+
71
+ for (const problemDir of listProblemDirectories(workspaceRootDir)) {
72
+ const { record } = readProblemRecordFromDir(problemDir);
73
+ merged.set(String(record.problem_id), toCatalogProblem(problemDir, record, 'workspace'));
74
+ }
63
75
 
64
- cachedProblems = directories.map((problemId) => {
65
- const { problemDir, record } = readProblemRecord(problemId);
66
- return toCatalogProblem(problemDir, record);
67
- });
68
- return cachedProblems;
76
+ return [...merged.values()].sort((left, right) => Number(left.problemId) - Number(right.problemId));
69
77
  }
70
78
 
71
- export function listProblems(filters = {}) {
79
+ export function listProblems(filters = {}, workspaceRoot = getWorkspaceRoot()) {
72
80
  const cluster = filters.cluster ? String(filters.cluster).toLowerCase() : null;
73
81
  const repoStatus = filters.repoStatus ? String(filters.repoStatus).toLowerCase() : null;
74
82
  const harnessDepth = filters.harnessDepth ? String(filters.harnessDepth).toLowerCase() : null;
75
83
  const siteStatus = filters.siteStatus ? String(filters.siteStatus).toLowerCase() : null;
76
84
 
77
- return loadLocalProblems()
85
+ return loadLocalProblems(workspaceRoot)
78
86
  .filter((entry) => (cluster ? entry.cluster === cluster : true))
79
87
  .filter((entry) => (repoStatus ? entry.repoStatus === repoStatus : true))
80
88
  .filter((entry) => (harnessDepth ? entry.harnessDepth === harnessDepth : true))
81
89
  .filter((entry) => (siteStatus ? entry.siteStatus === siteStatus : true));
82
90
  }
83
91
 
84
- export function getProblem(problemId) {
85
- return loadLocalProblems().find((entry) => entry.problemId === String(problemId));
92
+ export function getProblem(problemId, workspaceRoot = getWorkspaceRoot()) {
93
+ return loadLocalProblems(workspaceRoot).find((entry) => entry.problemId === String(problemId));
86
94
  }
87
95
 
88
- export function getCluster(clusterName) {
96
+ export function getCluster(clusterName, workspaceRoot = getWorkspaceRoot()) {
89
97
  const name = String(clusterName).toLowerCase();
90
- const problems = listProblems({ cluster: name });
98
+ const problems = listProblems({ cluster: name }, workspaceRoot);
91
99
  if (problems.length === 0) {
92
100
  return null;
93
101
  }
@@ -99,11 +107,11 @@ export function getCluster(clusterName) {
99
107
  };
100
108
  }
101
109
 
102
- export function listClusters() {
103
- const names = [...new Set(loadLocalProblems().map((entry) => entry.cluster))].sort();
104
- return names.map((name) => getCluster(name));
110
+ export function listClusters(workspaceRoot = getWorkspaceRoot()) {
111
+ const names = [...new Set(loadLocalProblems(workspaceRoot).map((entry) => entry.cluster))].sort();
112
+ return names.map((name) => getCluster(name, workspaceRoot));
105
113
  }
106
114
 
107
115
  export function clearCatalogCache() {
108
- cachedProblems = null;
116
+ return null;
109
117
  }
package/src/cli/index.js CHANGED
@@ -1,10 +1,15 @@
1
1
  import { runBootstrapCommand } from '../commands/bootstrap.js';
2
+ import { runCheckpointsCommand } from '../commands/checkpoints.js';
2
3
  import { runClusterCommand } from '../commands/cluster.js';
4
+ import { runContinuationCommand } from '../commands/continuation.js';
3
5
  import { runDossierCommand } from '../commands/dossier.js';
4
6
  import { runMaintainerCommand } from '../commands/maintainer.js';
7
+ import { runPreflightCommand } from '../commands/preflight.js';
5
8
  import { runProblemCommand } from '../commands/problem.js';
6
9
  import { runPullCommand } from '../commands/pull.js';
7
10
  import { runScaffoldCommand } from '../commands/scaffold.js';
11
+ import { runSeedCommand } from '../commands/seed.js';
12
+ import { runStateCommand } from '../commands/state.js';
8
13
  import { runSunflowerCommand } from '../commands/sunflower.js';
9
14
  import { runUpstreamCommand } from '../commands/upstream.js';
10
15
  import { runWorkspaceCommand } from '../commands/workspace.js';
@@ -21,6 +26,12 @@ function printUsage() {
21
26
  console.log(' erdos cluster list');
22
27
  console.log(' erdos cluster show <name>');
23
28
  console.log(' erdos workspace show');
29
+ console.log(' erdos state sync [--json]');
30
+ console.log(' erdos state show [--json]');
31
+ console.log(' erdos continuation show [--json]');
32
+ console.log(' erdos continuation use <atom|route|phase|milestone> [--json]');
33
+ console.log(' erdos preflight [--allow-dirty] [--json]');
34
+ console.log(' erdos checkpoints sync [--json]');
24
35
  console.log(' erdos sunflower status [<id>] [--json]');
25
36
  console.log(' erdos dossier show <id>');
26
37
  console.log(' erdos upstream show');
@@ -28,6 +39,7 @@ function printUsage() {
28
39
  console.log(' erdos upstream diff [--write-package-report]');
29
40
  console.log(' erdos scaffold problem <id> [--dest <path>]');
30
41
  console.log(' erdos bootstrap problem <id> [--dest <path>] [--sync-upstream]');
42
+ 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]');
31
43
  console.log(' erdos pull problem <id> [--dest <path>] [--include-site] [--refresh-upstream]');
32
44
  console.log(' erdos pull artifacts <id> [--dest <path>] [--refresh-upstream]');
33
45
  console.log(' erdos pull literature <id> [--dest <path>] [--include-site] [--refresh-upstream]');
@@ -47,6 +59,14 @@ if (!command || command === 'help' || command === '--help') {
47
59
  exitCode = runClusterCommand(rest);
48
60
  } else if (command === 'workspace') {
49
61
  exitCode = runWorkspaceCommand(rest);
62
+ } else if (command === 'state') {
63
+ exitCode = runStateCommand(rest);
64
+ } else if (command === 'continuation') {
65
+ exitCode = runContinuationCommand(rest);
66
+ } else if (command === 'preflight') {
67
+ exitCode = runPreflightCommand(rest);
68
+ } else if (command === 'checkpoints') {
69
+ exitCode = runCheckpointsCommand(rest);
50
70
  } else if (command === 'sunflower') {
51
71
  exitCode = runSunflowerCommand(rest);
52
72
  } else if (command === 'dossier') {
@@ -57,6 +77,8 @@ if (!command || command === 'help' || command === '--help') {
57
77
  exitCode = runScaffoldCommand(rest);
58
78
  } else if (command === 'bootstrap') {
59
79
  exitCode = await runBootstrapCommand(rest);
80
+ } else if (command === 'seed') {
81
+ exitCode = await runSeedCommand(rest);
60
82
  } else if (command === 'pull') {
61
83
  exitCode = await runPullCommand(rest);
62
84
  } else if (command === 'maintainer') {
@@ -1,7 +1,9 @@
1
1
  import path from 'node:path';
2
2
  import { getProblem } from '../atlas/catalog.js';
3
+ import { syncCheckpoints } from '../runtime/checkpoints.js';
3
4
  import { scaffoldProblem } from '../runtime/problem-artifacts.js';
4
5
  import { getWorkspaceProblemScaffoldDir } from '../runtime/paths.js';
6
+ import { syncState } from '../runtime/state.js';
5
7
  import { setCurrentProblem } from '../runtime/workspace.js';
6
8
  import { syncUpstream } from '../upstream/sync.js';
7
9
 
@@ -71,11 +73,16 @@ export async function runBootstrapCommand(args) {
71
73
  ? path.resolve(parsed.destination)
72
74
  : getWorkspaceProblemScaffoldDir(problem.problemId);
73
75
  const result = scaffoldProblem(problem, destination);
76
+ const state = syncState();
77
+ const checkpoints = syncCheckpoints();
74
78
 
75
79
  console.log(`Bootstrapped problem ${problem.problemId} (${problem.title})`);
76
80
  console.log(`Active problem: ${problem.problemId}`);
81
+ console.log(`Active route: ${state.activeRoute ?? '(none)'}`);
77
82
  console.log(`Scaffold dir: ${result.destination}`);
78
83
  console.log(`Artifacts copied: ${result.copiedArtifacts.length}`);
79
84
  console.log(`Upstream record included: ${result.inventory.upstreamRecordIncluded ? 'yes' : 'no'}`);
85
+ console.log(`Checkpoint shelf: ${checkpoints.indexPath}`);
86
+ console.log(`Next honest move: ${state.nextHonestMove}`);
80
87
  return 0;
81
88
  }
@@ -0,0 +1,36 @@
1
+ import { syncCheckpoints } from '../runtime/checkpoints.js';
2
+
3
+ export function runCheckpointsCommand(args) {
4
+ const [subcommand, ...rest] = args;
5
+ const asJson = rest.includes('--json');
6
+ const unknown = rest.filter((arg) => arg !== '--json');
7
+
8
+ if (!subcommand || subcommand === 'help' || subcommand === '--help') {
9
+ console.log('Usage:');
10
+ console.log(' erdos checkpoints sync [--json]');
11
+ return 0;
12
+ }
13
+
14
+ if (subcommand !== 'sync') {
15
+ console.error(`Unknown checkpoints subcommand: ${subcommand}`);
16
+ return 1;
17
+ }
18
+
19
+ if (unknown.length > 0) {
20
+ console.error(`Unknown checkpoints option: ${unknown[0]}`);
21
+ return 1;
22
+ }
23
+
24
+ const result = syncCheckpoints();
25
+ if (asJson) {
26
+ console.log(JSON.stringify(result, null, 2));
27
+ return 0;
28
+ }
29
+
30
+ console.log('Checkpoint shelf synced');
31
+ console.log(`Index path: ${result.indexPath}`);
32
+ console.log(`Checkpoint JSON: ${result.checkpointJsonPath}`);
33
+ console.log(`Checkpoint count: ${result.checkpoints.length}`);
34
+ console.log(`Last checkpoint sync: ${result.state.lastCheckpointSyncAt}`);
35
+ return 0;
36
+ }
@@ -0,0 +1,60 @@
1
+ import { ensureConfig, loadConfig, saveConfig } from '../runtime/config.js';
2
+ import { continuationDisplay, continuationModes, resolveContinuation } from '../runtime/continuation.js';
3
+ import { syncState } from '../runtime/state.js';
4
+
5
+ function printContinuation(payload) {
6
+ console.log('Continuation mode');
7
+ console.log(`Requested: ${payload.requestedMode}`);
8
+ console.log(`Resolved: ${continuationDisplay(payload)}`);
9
+ console.log(`Review cadence: ${payload.reviewCadence}`);
10
+ console.log(`Max unattended minutes: ${payload.maxUnattendedMinutes}`);
11
+ console.log(`Checkpoint after load-bearing result: ${payload.checkpointAfterLoadBearingResult ? 'yes' : 'no'}`);
12
+ console.log(`Stop rule: ${payload.stopRule}`);
13
+ }
14
+
15
+ export function runContinuationCommand(args) {
16
+ const [subcommand, value, ...rest] = args;
17
+ const asJson = rest.includes('--json');
18
+
19
+ if (!subcommand || subcommand === 'help' || subcommand === '--help') {
20
+ console.log('Usage:');
21
+ console.log(' erdos continuation show [--json]');
22
+ console.log(` erdos continuation use <${continuationModes().join('|')}> [--json]`);
23
+ return 0;
24
+ }
25
+
26
+ if (subcommand === 'show') {
27
+ const config = ensureConfig();
28
+ const continuation = resolveContinuation({ requestedMode: config.continuation });
29
+ if (asJson) {
30
+ console.log(JSON.stringify(continuation, null, 2));
31
+ return 0;
32
+ }
33
+ printContinuation(continuation);
34
+ return 0;
35
+ }
36
+
37
+ if (subcommand === 'use') {
38
+ if (!value) {
39
+ console.error('Missing continuation mode.');
40
+ return 1;
41
+ }
42
+ if (!continuationModes().includes(value)) {
43
+ console.error(`Unknown continuation mode: ${value}`);
44
+ return 1;
45
+ }
46
+ const config = loadConfig();
47
+ saveConfig({ ...config, continuation: value });
48
+ const state = syncState();
49
+ if (asJson) {
50
+ console.log(JSON.stringify(state.continuation, null, 2));
51
+ return 0;
52
+ }
53
+ console.log(`Continuation mode set to ${continuationDisplay(state.continuation)}`);
54
+ printContinuation(state.continuation);
55
+ return 0;
56
+ }
57
+
58
+ console.error(`Unknown continuation subcommand: ${subcommand}`);
59
+ return 1;
60
+ }
@@ -0,0 +1,44 @@
1
+ import { buildPreflightReport } from '../runtime/preflight.js';
2
+
3
+ function printChecks(checks) {
4
+ for (const [label, payload] of Object.entries(checks)) {
5
+ console.log(`- ${label}: ${payload.ok ? 'ok' : 'attention'} (${payload.detail})`);
6
+ }
7
+ }
8
+
9
+ export function runPreflightCommand(args) {
10
+ const asJson = args.includes('--json');
11
+ const allowDirty = args.includes('--allow-dirty');
12
+ const unknown = args.filter((arg) => arg !== '--json' && arg !== '--allow-dirty');
13
+
14
+ if (args.length > 0 && (args[0] === 'help' || args[0] === '--help')) {
15
+ console.log('Usage:');
16
+ console.log(' erdos preflight [--allow-dirty] [--json]');
17
+ return 0;
18
+ }
19
+
20
+ if (unknown.length > 0) {
21
+ console.error(`Unknown preflight option: ${unknown[0]}`);
22
+ return 1;
23
+ }
24
+
25
+ const report = buildPreflightReport({ allowDirty });
26
+ if (asJson) {
27
+ console.log(JSON.stringify(report, null, 2));
28
+ return report.verdict === 'blocked' ? 2 : 0;
29
+ }
30
+
31
+ console.log('Research preflight');
32
+ console.log(`- Workspace root: ${report.workspaceRoot}`);
33
+ console.log(`- Open problem: ${report.activeProblem ?? '(none)'}`);
34
+ console.log(`- Active route: ${report.activeRoute ?? '(none)'}`);
35
+ console.log(`- Route breakthrough: ${report.routeBreakthrough ? 'yes' : 'no'}`);
36
+ console.log(`- Problem solved: ${report.problemSolved ? 'yes' : 'no'}`);
37
+ console.log(`- Continuation policy: ${report.continuationDisplay}`);
38
+ console.log(`- Current frontier: ${report.currentFrontier.kind} / ${report.currentFrontier.detail}`);
39
+ console.log(`- Next honest move: ${report.nextHonestMove}`);
40
+ console.log('Checks:');
41
+ printChecks(report.checks);
42
+ console.log(`Verdict: ${report.verdict}`);
43
+ return report.verdict === 'blocked' ? 2 : 0;
44
+ }
@@ -1,5 +1,6 @@
1
1
  import { getProblem, listProblems } from '../atlas/catalog.js';
2
2
  import { getProblemArtifactInventory } from '../runtime/problem-artifacts.js';
3
+ import { syncState } from '../runtime/state.js';
3
4
  import { readCurrentProblem, setCurrentProblem } from '../runtime/workspace.js';
4
5
 
5
6
  function parseListFilters(args) {
@@ -200,7 +201,10 @@ export function runProblemCommand(args) {
200
201
  return 1;
201
202
  }
202
203
  setCurrentProblem(problem.problemId);
204
+ const state = syncState();
203
205
  console.log(`Active problem set to ${problem.problemId} (${problem.title})`);
206
+ console.log(`Active route: ${state.activeRoute ?? '(none)'}`);
207
+ console.log(`Next honest move: ${state.nextHonestMove}`);
204
208
  return 0;
205
209
  }
206
210