From 67f98cab35abf45e37c15f2182968ea86eced4b0 Mon Sep 17 00:00:00 2001 From: garrytan-agents Date: Wed, 27 May 2026 13:09:50 +0000 Subject: [PATCH] fix: dream --source passes sourceId to runCycle, writes cycle timestamp MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `gbrain dream --source default` silently ignored the --source flag. The flag was never parsed in parseArgs and never forwarded to runCycle. This meant the cycle completed but last_full_cycle_at was never written to the source's config JSONB, so doctor's cycle_freshness check always reported stale cycles — even when dream ran successfully. Changes: - Parse --source and --max-pages in dream's parseArgs - Forward sourceId and maxPages to runCycle opts - Document both flags in --help Without this fix, only `gbrain autopilot` (which uses its own fanout logic) could write the cycle timestamp. Running `gbrain dream --source X` via cron or manually would never update freshness. --- src/commands/dream.ts | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/src/commands/dream.ts b/src/commands/dream.ts index ab63457a6..ba5d729bc 100644 --- a/src/commands/dream.ts +++ b/src/commands/dream.ts @@ -53,6 +53,18 @@ interface DreamArgs { * Never auto-applied for --input (codex finding #3). */ bypassDreamGuard: boolean; + /** + * v0.42: explicit source id for per-source cycle tracking. + * When set, runCycle writes `last_full_cycle_at` to the source's config + * on completion. Without this, `gbrain dream --source X` silently ignores + * --source and the doctor's cycle_freshness check never sees a fresh stamp. + */ + source: string | null; + /** + * v0.42: cap the number of pages processed per extraction phase. + * Passed through to runCycle as maxPages. + */ + maxPages: number | null; } const ISO_DATE_RE = /^\d{4}-\d{2}-\d{2}$/; @@ -109,6 +121,17 @@ function parseArgs(args: string[]): DreamArgs { // --input implies --phase synthesize. if (inputFile && !phase) phase = 'synthesize'; + const sourceIdx = args.indexOf('--source'); + const source = sourceIdx !== -1 ? args[sourceIdx + 1] ?? null : null; + + const maxPagesIdx = args.indexOf('--max-pages'); + const rawMaxPages = maxPagesIdx !== -1 ? args[maxPagesIdx + 1] ?? null : null; + const maxPages = rawMaxPages ? parseInt(rawMaxPages, 10) : null; + if (maxPages !== null && (isNaN(maxPages) || maxPages < 1)) { + console.error(`--max-pages must be a positive integer; got "${rawMaxPages}"`); + process.exit(2); + } + return { json: args.includes('--json'), dryRun: args.includes('--dry-run'), @@ -121,6 +144,8 @@ function parseArgs(args: string[]): DreamArgs { from, to, bypassDreamGuard: args.includes('--unsafe-bypass-dream-guard'), + source, + maxPages, }; } @@ -179,6 +204,11 @@ Options: --phase Run a single phase: ${ALL_PHASES.join(' | ')} --pull git pull the brain repo before syncing (default: no pull) --dir Brain directory (default: configured brain) + --source Run cycle for a specific source (default, media-corpus, + straylight-brain, zion-brain). When set, writes + last_full_cycle_at on completion so doctor's + cycle_freshness check sees a fresh stamp. + --max-pages Cap pages processed per extraction phase. --input Synthesize a specific transcript file (implies --phase synthesize). Bypasses corpus-dir scan. @@ -280,6 +310,8 @@ export async function runDream(engine: BrainEngine | null, args: string[]): Prom dryRun: opts.dryRun, pull: opts.pull, phases, + sourceId: opts.source ?? undefined, + maxPages: opts.maxPages ?? undefined, synthInputFile: opts.inputFile ?? undefined, synthDate: opts.date ?? undefined, synthFrom: opts.from ?? undefined,