dream_observation: drop the 'go quiet' rule from select_mode
The earlier behavior never went quiet — it dreamed every night, even when that meant repeating itself. The 'return None on null delta' rule was a synthesis-doc invention (the dreamer-design-spec.md I treated as authoritative is itself LLM-generated) that didn't match the actual desired UX. Aaron called this out. The repetition problem the quiet rule was claimed to solve is already addressed in the retrieve layer: - LLM-generated queries from the observation signal vary nightly - MMR diversity prevents within-night cluster lock-in - NREM bias toward under-processed chunks (low consolidation_count) ensures fresh material gets selected over recently-replayed material So select_mode now always returns a mode. NREM is the default. Staleness still routes to Late REM at 3+ days for cross-domain variety. Journal entries still route to Early REM.
This commit is contained in:
@@ -186,50 +186,38 @@ def observe_corpus():
|
|||||||
# ─── Stage 2: select_mode ───────────────────────────────────────────────────
|
# ─── Stage 2: select_mode ───────────────────────────────────────────────────
|
||||||
|
|
||||||
def select_mode(signal, task=None, explicit_mode=None):
|
def select_mode(signal, task=None, explicit_mode=None):
|
||||||
"""Return one of {'nrem', 'early-rem', 'late-rem', 'lucid'} or None.
|
"""Return one of {'nrem', 'early-rem', 'late-rem', 'lucid'}. Never None.
|
||||||
|
|
||||||
Selection logic from spec (lines 69–74):
|
The dreamer fires every scheduled night. The earlier "go quiet on null
|
||||||
- Explicit mode argument → use that mode
|
delta" rule was a synthesis-doc invention that didn't match the actual
|
||||||
|
desired UX — the original dreamer always dreamed, even if it repeated
|
||||||
|
itself. The cure for repetition lives in the retrieve layer
|
||||||
|
(LLM-generated queries from the observation signal, MMR diversity,
|
||||||
|
cursor bias toward under-processed chunks), not in skipping nights.
|
||||||
|
|
||||||
|
Routing logic:
|
||||||
|
- explicit_mode argument wins
|
||||||
- task supplied → 'lucid' (question-anchored)
|
- task supplied → 'lucid' (question-anchored)
|
||||||
- Active journal entry → Early REM (emotional/personal register)
|
- days_since_dream ≥ STALENESS_TRIGGER_DAYS → 'late-rem' (shake loose
|
||||||
- Corpus unchanged ≥ STALENESS_TRIGGER_DAYS → Late REM (shake loose)
|
via cross-domain pairs when nothing's been added in a while)
|
||||||
- New chunks above threshold → NREM
|
- new journal entry → 'early-rem' (emotional/personal register)
|
||||||
- Otherwise → None ("dreamer goes quiet rather than manufacturing novelty")
|
- default → 'nrem' (replay-and-consolidation; always has something to
|
||||||
|
do because the corpus always has under-processed chunks)
|
||||||
The None return is load-bearing. Per spec line 67, it's the canonical
|
|
||||||
answer to the repetition problem: when nothing has changed, do not
|
|
||||||
manufacture a dream just to fill the schedule slot.
|
|
||||||
"""
|
"""
|
||||||
if explicit_mode:
|
if explicit_mode:
|
||||||
return explicit_mode
|
return explicit_mode
|
||||||
if task:
|
if task:
|
||||||
return "lucid"
|
return "lucid"
|
||||||
|
|
||||||
new_chunks = signal["new_chunks"]
|
|
||||||
new_journal = signal["new_journal_entries"]
|
|
||||||
days_since = signal["days_since_dream"]
|
days_since = signal["days_since_dream"]
|
||||||
|
new_journal = signal["new_journal_entries"]
|
||||||
|
|
||||||
# Spec line 72: corpus unchanged ≥3 days → Late REM ("shake things loose").
|
|
||||||
# This rule has to win against the "go quiet" rule below — the spec uses
|
|
||||||
# quiet as the default for 1-2 days of silence, then deliberately fires
|
|
||||||
# Late REM at 3+ days to break the stasis. Checking staleness first is
|
|
||||||
# what implements that intent. (Previous version checked "go quiet" first
|
|
||||||
# and never reached this branch.)
|
|
||||||
if days_since >= STALENESS_TRIGGER_DAYS:
|
if days_since >= STALENESS_TRIGGER_DAYS:
|
||||||
return "late-rem"
|
return "late-rem"
|
||||||
|
|
||||||
# Spec line 71: journal entry → Early REM
|
|
||||||
# We treat "any new journal entry" as the trigger. Refining to detect
|
|
||||||
# emotional/personal register requires LLM sentiment tagging, which
|
|
||||||
# is left for a later iteration.
|
|
||||||
if new_journal:
|
if new_journal:
|
||||||
return "early-rem"
|
return "early-rem"
|
||||||
|
|
||||||
# Spec line 67: nothing changed within the staleness window → quiet
|
|
||||||
if new_chunks < NEW_CHUNK_THRESHOLD and not new_journal:
|
|
||||||
return None
|
|
||||||
|
|
||||||
# Default: new chunks above threshold → NREM
|
|
||||||
return "nrem"
|
return "nrem"
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user