2026-08-13: The Nights the Dream Forgot

The job is honest when it works. At 05:25 it gathers the last day, asks a local seat to compress it, and writes one markdown file. When it fails it logs dream FAILED and goes back to sleep. For two weeks that was the whole story.
On disk, before the catch-up, the dreams directory held four files: 2026-07-27, 2026-07-28, 2026-07-30, and a same-day restore on 2026-08-13. The log showed a cycle every morning from 16 July through 13 August. Twenty-five of those mornings left nothing behind.
What failed, and what did not
Section titled “What failed, and what did not”The gather always ran. The seat call did not. From 1 August the error was the same every night: proxyd asked council-local-think and came back ALL SEATS FAILED / error sending, or curl sat 300 seconds and received zero bytes. A tiny “reply OK” through the same proxy could succeed. A day bundle could not.
That was not a missing job. The LaunchAgent was loaded. The kill switch was off. The posture was conserving. The cycle did exactly what it was told: try twice, then leave the date empty.
The real lesion was non-streaming TTFB. The 27B was asked for 4000 completion tokens and only sent HTTP headers when generation finished. At ~9 tok/s that is ~7 minutes of silence. Proxyd’s TTFB budget is 180s. Curl died with an empty body. Tiny prompts finished inside the window; the night never did.
The fix is to stream. TTFB is the first token. dream_cycle.py POSTs stream: true, assembles SSE deltas, and if curl hits max-time (rc=28) after bytes have already arrived, it keeps the partial markdown instead of throwing the night away. Live prove 13 August 19:54: 182s, four sections, seat council-local-think, scratch path /tmp/dream-stream-prove/.
The council verdict from 16 July still holds. The dream is observational. Its only write path is ~/.sanctum/memory/dreams/. Catch-up is the same write path, aimed at a date that never got a file.
How a missed night is written
Section titled “How a missed night is written”dream_gather used to treat “now” as wall-clock. A backfill run this afternoon would have gathered today’s 24 hours and labeled it yesterday. That is a forged dream.
So the gather now has an as-of clock:
| Env | Effect |
|---|---|
DREAM_DATE=YYYY-MM-DD | Gather the 24 hours ending 05:25 that morning. Write that day’s file. |
DREAM_AS_OF= ISO or unix | Same window, explicit instant. |
DREAM_OVERWRITE=1 | Replace a file that already exists. Default is skip. |
python3 dreams/backfill_missing.py lists every date from the first logged cycle (2026-07-16) through yesterday that has no markdown. --run calls dream_cycle.py once per gap. Existing nights are not touched. The three July successes stay the July successes.
The catch-up that refilled 16 July–12 August used council-code and a 2.5 KB cap so the shelf would fill while the 27B path was still non-stream. That is history. 05:25 now runs the designed seat.
| Nightly env | Value |
|---|---|
DREAM_SEAT | council-local-think (27B via proxyd :4040) |
stream | on (in dream_cycle.py, not optional) |
DREAM_ENABLE_THINKING | 0 |
DREAM_MAX_TOKENS | 2000 |
DREAM_TOTAL_CAP | 12000 |
DREAM_CALL_TIMEOUT | 300 |
DREAM_DATE=2026-08-04 python3 dreams/dream_cycle.pyAfter a catch-up, backfill_missing.py with no flags must print no missing dream dates. On 13 August it did: 29 files, 2026-07-16 through 2026-08-13. The three original July successes (council-local-think, morning mtimes) were not overwritten. The 100 July-17 retroactive stubs under ~/.sanctum/dreams/ were moved to ~/.sanctum/dreams-retroactive-stubs-20260717 — they are not the observational cycle.
Why the empty shelf mattered
Section titled “Why the empty shelf mattered”Dreams are how the haus consolidates. Thalamus is the waking workspace — last five broadcasts, gone when the process dies. A dream is the night’s compression, dated, sitting in the vault. Fourteen mornings of FAILED means fourteen days the swarm reacted and never wrote what it saw.
The catch-up does not invent those days. It reads the same five sources the 05:25 job would have read, clipped to that morning, and writes the file the job failed to write. After the run, backfill_missing.py with no flags should print no missing dream dates. That is the test. Not a status word. A directory listing.