* fix(dream): ground commit messages and cursor advance in the real git diff
Dream consolidation could emit a /dream-log audit record that did not match
the actual file changes: build_dream_commit_message appended the LLM's
unverified resp.content, dream_run_completed only checked the stop reason, and
file contents were deliberately omitted from the prompt. The combination let a
single-turn self-report become the durable audit record.
- gitstore: add summarize_working_tree() — a structured, machine-derived
summary (per-file +N/-M, totals, capped unified diff) of working-tree
changes vs HEAD. Pure filesystem/git ground truth, never LLM narrative.
- memory: build_dream_commit_message now takes the diff body instead of resp;
dream_content_diff() exposes the real delta over SOUL/USER/MEMORY.md only
(excludes .dream_cursor so cursor writes aren't mistaken for edits);
build_dream_prompt embeds current file contents so the model edits reality,
not a stale mental model.
- builtin/cli: both Dream paths now compute the diff, gate cursor advance on
a non-empty delta (no-op runs no longer swallow history), and commit with
the diff-grounded message. Non-git workspaces fall back to the completion
check.
- dream.md: document that contents are embedded, and add a chain-of-
verification guardrail so the model's summary cannot claim unmade edits.
A regression test proves a lying resp.content never reaches the audit log
while the real diff does.
* fix(dream): mark non-UTF-8 memory files as binary in diff summary
Address review feedback (Q1 on PR #4673): summarize_working_tree read
working-tree files with errors="replace", which would emit U+FFFD
replacement chars into the audit record if a memory file ever held
invalid UTF-8 — misrepresenting the diff it is meant to make truthful.
Switch to errors="strict" and catch UnicodeDecodeError: a non-UTF-8
(or binary/corrupt) file is now recorded as "{path}: binary or
non-UTF-8 file changed" and omitted from the unified diff, so the
audit record stays honest. An empty diff block is also suppressed when
all changes are binary.
Adds a defensive regression test asserting no replacement char leaks.
Treat `.git` files the same as `.git` directories so GitStore refuses to initialize inside git worktrees, and add a focused regression test for that checkout shape.
Made-with: Cursor
GitStore.init() now checks if the workspace is already inside a git
repository before calling porcelain.init(). If so, it refuses to create
a nested repo. Additionally, existing .gitignore files are preserved
by appending only missing Dream-specific entries rather than overwriting.
Closes#2980
Three improvements to Dream's memory consolidation:
1. Per-line git-blame age annotations: MEMORY.md lines get `← Nd` suffixes
(N>14) from dulwich annotate. SOUL.md/USER.md excluded as permanent.
LLM uses content judgment, not just age, to decide what to prune.
2. Dedup-aware Phase 1 prompt: reframed as dual-task (extract facts +
deduplicate existing files) with explicit redundancy patterns to scan for.
Validated through 20 experiments (exp-002 prompt + max_iter=15 was best,
averaging -1643 chars/5.4% compression per run).
3. Phase 1 analysis as commit body: dream git commits now include the full
Phase 1 analysis for transparency via /dream-log.
4. max_iterations raised from 10 to 15: 30% improvement over 10 with no
risk; 20 showed diminishing returns (exp-020: -701 vs exp-017: -1643).