Version: v0.40.8.0
Repro
# Run the command doctor explicitly recommends:
gbrain dream --source default --dir /data/brain
# Wait for completion (full 16-phase cycle, exit 0).
gbrain doctor --json | jq '.checks[] | select(.name=="cycle_freshness")'
# Still reports "Source 'default' has never completed a full cycle"
psql $DATABASE_URL -c "SELECT id, config->>'last_full_cycle_at' FROM sources;"
# NULL for all sources
Root cause
src/commands/dream.ts:36-44 DreamArgs interface has no source field:
interface DreamArgs {
json: boolean;
dryRun: boolean;
pull: boolean;
phase: CyclePhase | null;
dir: string | null;
// ... no source field
}
dream.ts:278-288 calls runCycle() without propagating sourceId:
const report = await runCycle(engine, {
brainDir,
dryRun: opts.dryRun,
pull: opts.pull,
phases,
// ← MISSING: sourceId: opts.source ?? undefined
synthInputFile: opts.inputFile ?? undefined,
// ...
});
cycle.ts:1738 gates the per-source marker write on opts.sourceId truthy:
if (opts.sourceId && engine && !dryRun && (status === 'ok' || 'clean' || 'partial')) {
await engine.updateSourceConfig(opts.sourceId, { last_full_cycle_at: new Date().toISOString() });
}
With opts.sourceId = undefined, the write is silently skipped (no warning, by design — best-effort).
Why this matters
Doctor at src/commands/doctor.ts:2067 recommends Run 'gbrain dream --source <id>' for each stale source as the fix. Following the recommendation has no effect. Users either accept a persistent warn forever or install gbrain autopilot as a daemon — but no autopilot.service ships in the repo.
gbrain sync --source <id> accepts and propagates the flag correctly. Dream is the odd one out — likely missed during the v0.38 per-source cycle tracking refactor.
Suggested fix (~15 lines, src/commands/dream.ts)
// 1. Add to DreamArgs interface
interface DreamArgs {
// ... existing fields
source: string | null; // per-source cycle tracking
}
// 2. Add to args initialization
const args: DreamArgs = { ..., source: null };
// 3. Add to argv parser
} else if (arg === '--source') {
args.source = argv[++i] ?? null;
}
// 4. Pass to runCycle (line 278)
const report = await runCycle(engine, {
brainDir,
dryRun: opts.dryRun,
pull: opts.pull,
phases,
sourceId: opts.source ?? undefined, // ← new line
synthInputFile: opts.inputFile ?? undefined,
// ...
});
// 5. Update docstring (line 12-18) to document --source <id>
Happy to PR if helpful.
Version: v0.40.8.0
Repro
Root cause
src/commands/dream.ts:36-44DreamArgs interface has nosourcefield:dream.ts:278-288callsrunCycle()without propagating sourceId:cycle.ts:1738gates the per-source marker write onopts.sourceIdtruthy:With
opts.sourceId = undefined, the write is silently skipped (no warning, by design — best-effort).Why this matters
Doctor at
src/commands/doctor.ts:2067recommendsRun 'gbrain dream --source <id>' for each stale sourceas the fix. Following the recommendation has no effect. Users either accept a persistent warn forever or installgbrain autopilotas a daemon — but no autopilot.service ships in the repo.gbrain sync --source <id>accepts and propagates the flag correctly. Dream is the odd one out — likely missed during the v0.38 per-source cycle tracking refactor.Suggested fix (~15 lines, src/commands/dream.ts)
Happy to PR if helpful.