refactor: rename dream → learning; consolidate .devflow/dream/ + .devflow/decisions/ → .devflow/learning/ - #261
Conversation
…and HUD notifications stack Commit 1 of 5 (Coder A). Clears the learning namespace for the dream→learning rename by removing retired artifacts: - Delete purge-learning-pipeline-v1 + purge-learning-global-v1 migrations and their _dropLearningKeyFromConfig helper (IDs remain inert strings in migrations.json; no live readers of old learning/ artifacts remain) - Neutralize consolidate-to-devflow-dir: remove learning/ mkdir and 9 memMap entries (learning-log.jsonl, learning.json, *.learning-* files) - Strip .learning-manifest.json from purge-orphaned-sidecar-judgment-state - Delete src/cli/utils/learning-cleanup.ts (only used by deleted migration) - Delete dead HUD notifications stack (no writer of .decisions-notifications.json exists): notifications.ts, components/notifications.ts, notifications-shape.ts, and all registrations in index.ts, render.ts, config.ts, types.ts - Delete tests/learning/hud-notifications.test.ts, tests/learning-cleanup.test.ts, tests/integration/learning/end-to-end.test.ts - Fold tests/learning/ live-code tests into tests/decisions/ (fix import depths) - Remove purge-learning describe blocks from migrations.test.ts; re-anchor ordering assert to purge-orphaned-dream-commit-hook-v1
…to learning/ Commit 2 of 5 (Coder A). Renames path accessors in lockstep across project-paths.ts and project-paths.cjs, then repoints every caller. Path renames: - getDreamDir + getDecisionsDir → getLearningDir (.devflow/learning/) - getDreamConfigPath → getFeatureConfigPath (.devflow/config.json) - getDreamPendingTurnsPath → getLearningPendingTurnsPath - getDreamPendingTurnsProcessingPath → getLearningPendingTurnsProcessingPath - getDecisionsConfigPath → getLearningTuningConfigPath (.devflow/learning/learning.json) - getObservationsLockDir: repoints to .devflow/learning/.observations.lock - All getDecisions* content accessors: keep names, repoint dir segment from decisions/ to learning/ (rule: accessors follow the file they point to) Callers updated: dream-config.ts, decisions-ledger-migration.ts, legacy-decisions-purge.ts, dream-cleanup.ts, decisions-config.ts, decisions.ts, tests/project-paths.test.ts, tests/decisions/cli-subcommands.test.ts The TS/CJS full-export parity test catches any future one-sided drift.
…decisions→learning key
- dream-config.ts → feature-config.ts: FeatureConfig {memory,learning,knowledge}
- coerceConfig reads learning, coalesces from legacy decisions (decisions wins)
- writeConfig mkdirs .devflow/ root (config.json at neutral root)
- Repoint callers: init.ts, decisions.ts, memory.ts, knowledge/toggle.ts
- tests/dream-config.test.ts → tests/learning-config.test.ts + coalesce cases
…rning, global tuning rename - consolidate-dream-decisions-to-learning-v1 (per-project): moves .devflow/dream/ + .devflow/decisions/ → .devflow/learning/; writes .devflow/config.json from dream config; drops lock dirs + orphaned telemetry; re-renders index.md footer paths - rename-global-decisions-config-v1 (global): ~/.devflow/decisions.json → learning.json - 13 tests for consolidation + 6 tests for global rename - Update v3-independent test: seed/read learning/ (post-path-repoint) + pre-apply consolidation
…ning - ensure-devflow-init: fast-path and mkdir use learning/ (not dream/+decisions/) - NEW learning-lock: learning_lock_acquire/release (replaces dream-lock functions) - queue-append: _QG_LEARNING/_QG_DECISIONS → _QG_LEARNING, learning-lock callers, .learning jq/node config field, queue_append_both param names - capture-prompt/turn/question: LEARNING_DIR, $DEVFLOW_DIR/config.json (neutral), LEARNING_ENABLED, source learning-lock, learning/ queue paths - session-start-context: LEARNING_DIR, FEATURE_CONFIG, LEARNING_ENABLED, --- LEARNING MAINTENANCE --- directive, subagent_type="Learning", model resolution from learning/learning.json → ~/.devflow/learning.json - session-start-memory, memory-worker, background-memory-update, pre-compact-memory: remove DREAM_DIR, DREAM_CONFIG → FEATURE_CONFIG at $DEVFLOW_DIR/config.json - render-decisions.cjs: '.devflow','decisions' → '.devflow','learning' (2 sites) - Test pins updated: dream-lock → learning-lock in harness source chains; $DECISIONS → $LEARNING in queue_read_gates assertions; writeDreamConfig → writeFeatureConfig writing to .devflow/config.json; dream/ paths → learning/; .decisions-usage.json in learning/; session-start-context directive strings
… green)
Update all test files and two source files to align with the dream/decisions
→ learning consolidation from commits 2–5:
Source fixes:
- decisions-config.ts: global tuning config reads ~/.devflow/learning.json
(was decisions.json); update JSDoc comment
- legacy-decisions-purge.ts: revert memoryDir fallback to decisions/ —
.memory/decisions/ is a content identifier (legacy purge target), not a
system identifier to rename
Test updates (16 files):
- config-disable-guards.test.ts: feature config at .devflow/config.json;
learning: false field; usage/TL;DR paths in learning/
- eager-memory-refresh.test.ts: writeDreamConfig writes to .devflow/config.json
- decisions/config.test.ts: global learning.json + project learning/learning.json
- decisions/cli-subcommands.test.ts: config.learning field (was config.decisions)
- decisions/decisions-format.test.ts: seed dir .devflow/learning/ for assign-anchor tests
- decisions/{ledger-ops,render-decisions,decisions-ledger-migration,
index-content,decisions-usage-scan,dream-curation}.test.ts: bulk path rename
- hud-decisions-counts.test.ts, legacy-decisions-purge.test.ts,
memory.test.ts: bulk path rename
All 1977 tests passing.
…acy-hooks module - Rename decisions.ts → learning.ts (command: 'learning', export learningCommand) - Rename dream.ts → legacy-hooks.ts (keep removeDreamHook/hasDreamHook names per KEEP list) - Rename dream-cleanup.ts → learning-queue-cleanup.ts (drainDreamQueue→drainLearningQueue; sweepLegacyDreamMarkers keeps name) - Rename decisions-config.ts → learning-tuning-config.ts (DecisionsConfig→LearningTuningConfig, global path ~/.devflow/learning.json) - Fix latent bug in handleConfigure: was calling getMemoryDir() instead of getLearningDir() - Simplify handleReset to single-dir semantics: fs.rm(getLearningDir(), recursive+force) - Update init.ts: --learning/--no-learning flags, dream-lock in LEGACY_HOOK_FILES, manifest write uses learning key - Update manifest.ts: ManifestData.features.learning + self-heal features.decisions→.learning on read - Update cli.ts, list.ts, uninstall.ts for new imports and learning terminology - Update migrations.ts: import sweepLegacyDreamMarkers from learning-queue-cleanup - Test updates: cli-subcommands/config tests repoint imports, fix reset idempotency paths, add AC-C2 unknown-command test, update config-disable-guards path for learning dir
…data types - Rename decisions-counts.ts → learning-counts.ts (gatherDecisionsCounts→gatherLearningCounts, default export learningCounts) - Update types.ts: ComponentId 'decisionsCounts'→'learningCounts', DecisionsCountsData→LearningCountsData, GatherContext.decisionsCounts→learningCounts - Update config.ts: HUD_COMPONENTS entry 'decisionsCounts'→'learningCounts' - Update render.ts: import + COMPONENT_MAP + LINE_GROUPS updated - Update index.ts: needsDecisionsCounts→needsLearningCounts, gatherDecisionsCounts→gatherLearningCounts, context field renamed - Rename test file hud-decisions-counts.test.ts → hud-learning-counts.test.ts with all references updated - Update hud-render.test.ts: learningCounts field in GatherContext helper
…epoint index paths - Create shared/agents/learning.md: name Learning, all .devflow/dream/ paths → .devflow/learning/, unlink PF-003 preserved - Update plugin manifests (core-skills, ambient): agents: ['dream'] → ['learning'] - Update src/cli/plugins.ts: agents arrays updated, 'dream' added to LEGACY_AGENT_NAMES - Update scripts/build-plugins.ts: add post-copy pruning of stale shared-agent copies not in manifest - Update commands/_partials/_decisions.mds: index path .devflow/decisions/ → .devflow/learning/ - Update commands/_partials/_knowledge.mds: config gate .devflow/dream/config.json → .devflow/config.json - Update shared/skills/apply-decisions/SKILL.md: decisions.md/pitfalls.md path references updated - Build distributes learning.md to plugin agents/; dream.md pruned by new prune logic - Rename tests/dream-agent.test.ts → tests/learning-agent.test.ts with all path/name assertions updated plus lockstep tests: 900s staleness, no .devflow/dream/ in shipped artifacts, no dream.md after build, AC-C9 (none) fallback cases for decisions_load() - Rename tests/decisions/dream-curation.test.ts → tests/decisions/learning-curation.test.ts (curation contract now pins learning agent paths, .devflow/learning/ helper paths) - Update tests/build-mds.test.ts: pin .devflow/learning/index.md (not decisions/) - Update tests/plugins.test.ts: pin dream in LEGACY_AGENT_NAMES, learning in core-skills/ambient
…nt structure - list-logic.test.ts: decisions→learning in allOff constant and test fixtures; update expected output strings from 'decisions' to 'learning' - manifest.test.ts: decisions→learning in valid-data round-trip fixture; normalizes-without-hud and normalizes-without-decisions assertions use .learning - command-adoption.test.ts: .devflow/decisions/index.md→.devflow/learning/index.md to match the repointed _decisions.mds partial (commit 8 change) - build.test.ts: add LEGACY_AGENTS exclusion for dream.md (orphan guard skips the legacy agent file pending deletion in commit 9 by Coder C)
Remove inline history notes that explain what directories used to be called before the dream→learning rename — per ADR-003 "leave the end-state, not the transition": - ARCHITECTURE block: drop the "PR 5b" and "dream→learning rename consolidated" lines (kept the sync-counterpart guidance) - getLearningDir JSDoc: drop "(dream queue + decisions content consolidated)" - getFeaturesDir JSDoc: drop "(promoted from .features/)" - getDocsDir JSDoc: drop "(promoted from .docs/)" - Section header: "Learning queue files (formerly under dream/)" → "Learning queue files" - Section header + note: "Learning content files (formerly under decisions/) / Accessor names follow the file they point to — only the dir segment changed." → "Learning content files" Applied identically to both mirror files: scripts/hooks/lib/project-paths.cjs src/cli/utils/project-paths.ts Build and full test suite (63 files / 1988 tests) pass.
- Delete shared/agents/dream.md (replaced by learning.md in commit 8) - Remove LEGACY_AGENTS bridge exclusion from tests/build.test.ts - Update tests/decisions/decisions-format.test.ts: path + describe block renamed from dream.md → learning.md, comment at line 418 updated - Remove dream.md pending-deletion carve-out from tests/learning-agent.test.ts Shared-agent count returns to exactly 16 (all referenced by manifests). npm run build prune logic verified: no plugins/*/agents/dream.md survives.
Replace every system identifier (dream→learning, decisions→learning, Dream agent→Learning agent, .devflow/dream/→.devflow/learning/, devflow decisions→devflow learning) across CLAUDE.md, README.md, docs/cli-reference.md, docs/reference/file-organization.md, docs/reference/skills-architecture.md, docs/working-memory.md, shared/skills/docs-framework/SKILL.md, and prose comments in src/cli/commands/memory.ts. Adds worktree edge case note to migrations paragraph (D37): per-project discovery reads ~/.claude/history.jsonl, so a linked worktree that never hosted a Claude session is not swept even after removing the marker; recovery requires opening a Claude session there first. No rename narration, no tombstones — ADR-003.
The feature area has been fully renamed to learning. The dream-capture-system KB slug is obsolete — callers would now look up learning-capture-system or similar. Removing the stale entry prevents misleading KB matches.
The consolidation moved the rendered index/decisions/pitfalls to
.devflow/learning/ (producers: render-decisions.cjs, session-start-context,
_decisions.mds, apply-decisions skill), but several downstream consumers were
missed and still read the now-dead .devflow/decisions/ directory:
- commands/_partials/_preamble.mds, _engine.mds — produce DECISIONS_CONTEXT
for the dynamic-* workflow commands; read .devflow/decisions/index.md
- shared/agents/skimmer.md — TL;DR read of decisions.md (ungated by CONTEXT)
- shared/agents/coder.md — decisions/pitfalls fallback + citation guidance
- shared/agents/{reviewer,designer,triager,scrutinizer}.md — canonical
DECISIONS_CONTEXT description string
- plugins/devflow-release/commands/release.md — Phase 1b decisions read
On a migrated project these all resolved to a non-existent path, silently
dropping ADR/PF context (DECISIONS_CONTEXT -> (none)). Repoint the directory
segment only; content file names (index.md/decisions.md/pitfalls.md) are
unchanged per the naming-boundary KEEP list. Update the canonical-description
pin in command-adoption.test.ts to match. Rebuilt plugin/command artifacts.
Drop `dream`/`decisions` from the comment line in both gitignore writers (ensure-root-gitignore line ~50 and DEVFLOW_GITIGNORE_BLOCK in post-install.ts) so the emitted comment reads `memory, learning, docs, locks`. Both emitted blocks remain byte-identical; functional ignore lines, sentinel, and the .root-gitignore-configured-v2 marker version are unchanged. Also update stale dev-comments in the same files (lines ~5, ~17, ~19 in ensure-root-gitignore; line ~44 in post-install.ts) and the render-decisions.cjs doc comment for LEDGER_FILENAME (`.devflow/decisions/` → `.devflow/learning/`). The LEDGER_FILENAME constant itself (`decisions-ledger.jsonl`) is untouched.
Code Review: PR #261 — Rename Dream → LearningStatus: Summary: This is a well-executed rename refactor with strong end-state correctness. However, there are 9 blocking/should-fix issues that must be resolved before merge. Multiple reviewers independently flagged the same items (dead file, half-renamed symbols, stale comments), elevating priority. Blocking Issues (Must Fix Before Merge)1. HIGH: Test-isolation TOCTOU race in
|
| const violations: string[] = []; | ||
| for (const f of files) { | ||
| const content = fsSync.readFileSync(f, 'utf-8'); | ||
| if (content.includes('.devflow/dream/')) { |
There was a problem hiding this comment.
[Testing] HIGH (88%) — TOCTOU race: file list via readdir can be stale when readFileSync runs; if build-mds.test.ts deletes transient fixtures between calls, test crashes with ENOENT. Fix: guard reads with try/catch for ENOENT, continue on file not found.
| // 6. Re-render index.md so footer paths reference learning/ not decisions/. | ||
| // Without this, workflow commands hand sub-agents dead paths until the next | ||
| // Learning-agent render. No-op when ledger is absent. | ||
| const { renderDecisionsIndex } = await import('./decisions-ledger-migration.js'); |
There was a problem hiding this comment.
[Testing/Reliability] MEDIUM (82%) — renderDecisionsIndex called after irreversible dir moves with no try/catch; if throw occurs post-move, migration strands in broken state. Fix: wrap in try/catch→warn, inject rendererPath into tests.
| await fs.mkdir(memoryDir, { recursive: true }); | ||
| const projectConfigPath = getDecisionsConfigPath(process.cwd()); | ||
| // FIX: mkdir the learning dir (parent of learning.json), not the memory dir | ||
| const learningDir = getLearningDir(process.cwd()); |
There was a problem hiding this comment.
[Architecture] MEDIUM (80%) — handleConfigure writes to $HOME/.devflow/learning.json but readers use getDevFlowDirectory(); silent no-op when DEVFLOW_DIR is set. Fix: route through canonical accessor via getDevFlowDirectory().
| import { addContextHook, removeContextHook, hasContextHook } from './context.js'; | ||
| import { writeFileAtomicExclusive } from '../utils/fs-atomic.js'; | ||
| import { writeConfig as writeDreamConfig } from '../utils/dream-config.js'; | ||
| import { writeConfig as writeDreamConfig } from '../utils/feature-config.js'; |
There was a problem hiding this comment.
[Consistency] MEDIUM (88%) — alias 'writeConfig as writeDreamConfig' repointed to feature-config.js but name retained; function now writes {memory,learning,knowledge}, unrelated to dream. Fix: drop alias or rename to writeFeatureConfig.
|
|
||
| /** .devflow/decisions/.decisions-manifest.json */ | ||
| /** .devflow/learning/.decisions-manifest.json */ | ||
| export function getDecisionsManifestPath(projectRoot: string): string { |
There was a problem hiding this comment.
[Architecture] MEDIUM (85%) — dead getDecisionsManifestPath re-pathed instead of deleted; builds path for files this PR's consolidate migration drops (zero production refs). Fix: delete the constructor and test case.
| id: 'consolidate-dream-decisions-to-learning-v1', | ||
| description: 'Consolidate .devflow/dream/ + .devflow/decisions/ into .devflow/learning/ and write .devflow/config.json', | ||
| scope: 'per-project', | ||
| async run(ctx: PerProjectMigrationContext): Promise<MigrationRunResult> { |
There was a problem hiding this comment.
[Complexity] MEDIUM (84%) — 96-line run() duplicates coerceConfig coalesce logic and hardcodes DEFAULT_CONFIG; maintainability debt. Fix: extract seedFeatureConfigFromDream helper, export DEFAULT_CONFIG, drop run() to ~70 lines.
| **Claude Code Flags**: Typed registry (`src/cli/utils/flags.ts`) for managing Claude Code feature flags (env vars and top-level settings). Pure functions `applyFlags`/`stripFlags`/`getDefaultFlags` follow the `applyViewMode`/`stripViewMode` pattern. Flags (20 total): default ON — `tui`, `tool-search`, `lsp`, `prompt-caching-1h`, `show-turn-duration`, `clear-context-on-plan`, `disable-bundled-skills`, `pin-sonnet-4-6`; default OFF — `brief`, `thinking-summaries`, `subprocess-env-scrub`, `disable-nonessential-traffic`, `forked-subagents`, `disable-adaptive-thinking`, `always-thinking`, `disable-git-instructions`, `disable-compact`, `disable-1m-context`, `disable-autoupdater`, `agent-teams`. Manageable via `devflow flags --enable/--disable/--status/--list`. Stored in manifest `features.flags: string[]`. View mode (`default`/`verbose`/`focus`) stored in manifest `features.viewMode?: string` and applied to `settings.json` as the `viewMode` key; `applyViewMode`/`stripViewMode` utilities colocated in `flags.ts`. | ||
|
|
||
| **Feature Knowledge Bases**: Per-feature `.devflow/features/` directory containing KNOWLEDGE.md files that capture area-specific patterns, conventions, architecture, and gotchas. Uses a **write-through** model: load = direct file-I/O reading `.devflow/features/index.md` (regenerable cache) with frontmatter-glob fallback over `features/*/KNOWLEDGE.md` (source of truth) + verify-against-code on read; save = in-command write-through via a simplified Knowledge agent that writes `KNOWLEDGE.md` + the `index.md` line directly (no `.create-result.json`, no external scripts, no lock). **Git-tracked & shared (amends ADR-021 for `features/`)**: the root `.gitignore` carve-out (`.devflow/*` + level-by-level `!` re-includes, written byte-identically by `ensure-root-gitignore` / `ensureDevflowGitignore`) un-ignores `.devflow/features/index.md` + every `{slug}/KNOWLEDGE.md` while the rest of `.devflow/` stays local; after writing, the **Knowledge agent commits those two paths to the current worktree branch itself** by running git via its Bash tool (scoped `commit --only` pathspec, never `git add -A`, **never push, never force**, no commit script — per the LLM-vs-plumbing principle the commit is the agent's, not a deterministic helper). A user opts back out by re-adding `.devflow/features/` to their own `.gitignore`. Existing installs upgrade once via the versioned `.root-gitignore-configured-v2` marker. Freshness = write-through + verify-on-read (NO git-staleness, NO SessionEnd eval, NO Dream task). `index.md` line format: `- **{slug}** — {areas} — {Use-when description}`; frontmatter is authoritative if the line is lost. MDS module: `commands/_partials/_knowledge.mds` (defines/exports `knowledge_load` and `knowledge_writeback` partials) + 9 host `.mds` sources in `commands/` compiled to plugin commands at build time by `scripts/build-mds.ts` (`npm run build:mds`). `knowledge_load` is used up-front by: implement, plan, resolve, code-review, self-review, research, bug-analysis. `knowledge_writeback` is used at workflow end by: implement, resolve, self-review, explore, debug. explore/debug do NOT load up-front (intentional asymmetry). Config gate: single `knowledge: true|false` in dream config (default true) — gates write-back only; load is ungated. CLI: `devflow knowledge list` (read index.md / frontmatter glob), `devflow knowledge --enable/--disable/--status` (flip config). Note: `/debug` keeps FEATURE_KNOWLEDGE orchestrator-local (investigation workers examine code without pre-loaded context). Toggleable via `devflow knowledge --enable/--disable/--status` or `devflow init --knowledge/--no-knowledge`. | ||
| **Feature Knowledge Bases**: Per-feature `.devflow/features/` directory containing KNOWLEDGE.md files that capture area-specific patterns, conventions, architecture, and gotchas. Uses a **write-through** model: load = direct file-I/O reading `.devflow/features/index.md` (regenerable cache) with frontmatter-glob fallback over `features/*/KNOWLEDGE.md` (source of truth) + verify-against-code on read; save = in-command write-through via a simplified Knowledge agent that writes `KNOWLEDGE.md` + the `index.md` line directly (no `.create-result.json`, no external scripts, no lock). **Git-tracked & shared (amends ADR-021 for `features/`)**: the root `.gitignore` carve-out (`.devflow/*` + level-by-level `!` re-includes, written byte-identically by `ensure-root-gitignore` / `ensureDevflowGitignore`) un-ignores `.devflow/features/index.md` + every `{slug}/KNOWLEDGE.md` while the rest of `.devflow/` stays local; after writing, the **Knowledge agent commits those two paths to the current worktree branch itself** by running git via its Bash tool (scoped `commit --only` pathspec, never `git add -A`, **never push, never force**, no commit script — per the LLM-vs-plumbing principle the commit is the agent's, not a deterministic helper). A user opts back out by re-adding `.devflow/features/` to their own `.gitignore`. Existing installs upgrade once via the versioned `.root-gitignore-configured-v2` marker. Freshness = write-through + verify-on-read (NO git-staleness, NO SessionEnd eval, NO Dream task). `index.md` line format: `- **{slug}** — {areas} — {Use-when description}`; frontmatter is authoritative if the line is lost. MDS module: `commands/_partials/_knowledge.mds` (defines/exports `knowledge_load` and `knowledge_writeback` partials) + 9 host `.mds` sources in `commands/` compiled to plugin commands at build time by `scripts/build-mds.ts` (`npm run build:mds`). `knowledge_load` is used up-front by: implement, plan, resolve, code-review, self-review, research, bug-analysis. `knowledge_writeback` is used at workflow end by: implement, resolve, self-review, explore, debug. explore/debug do NOT load up-front (intentional asymmetry). Config gate: single `knowledge: true|false` in feature config (default true) — gates write-back only; load is ungated. CLI: `devflow knowledge list` (read index.md / frontmatter glob), `devflow knowledge --enable/--disable/--status` (flip config). Note: `/debug` keeps FEATURE_KNOWLEDGE orchestrator-local (investigation workers examine code without pre-loaded context). Toggleable via `devflow knowledge --enable/--disable/--status` or `devflow init --knowledge/--no-knowledge`. |
There was a problem hiding this comment.
[Consistency/Documentation] MEDIUM (90%) — 'NO Dream task' is stale; KB renamed to Learning. Fix: change to 'NO Learning task'.
| | `--reset` | Removes `.devflow/learning/` state; prints pinned message: `Reset complete — removed .devflow/learning/ state.` | | ||
|
|
||
| ### Migrations | ||
|
|
There was a problem hiding this comment.
[Documentation] MEDIUM (90%) — mislabels both migrations as per-project, but rename-global-decisions-config-v1 is global (load-bearing for D37). Fix: relabel one per-project, one global.
| * Parse and narrow an unknown JSON value into a FeatureConfig, merging onto | ||
| * DEFAULT_CONFIG. Pure function — no I/O, no side effects. | ||
| * | ||
| * Coalesces legacy `decisions` key into `learning` when both are present: |
There was a problem hiding this comment.
[Documentation] MEDIUM (85%) — JSDoc says 'mirrors manifest kb→knowledge' but implementation is reversed: knowledge from manifest wins, then decisions→learning. Fix: reword to match precedence.
…tory() handleConfigure was building the global config path with `process.env.HOME || '~'`, bypassing the DEVFLOW_DIR override that loadLearningTuningConfig (the reader) uses via getDevFlowDirectory(). When DEVFLOW_DIR is set, this made the writer and reader disagree on the global learning.json path, causing a silent write to the wrong location. The || '~' fallback was also a footgun — a missing HOME would create a literal ~/ directory rather than throwing a clear error. Routes the global-scope write through the same getDevFlowDirectory() accessor already imported in the module so writer and reader are in sync. Co-Authored-By: Claude <noreply@anthropic.com>
ISS-05: Remove the `writeConfig as writeDreamConfig` alias — import and call `writeConfig` directly. No behavior change; the alias was a half-renamed leftover from the Dream→Learning rename. ISS-08: Update stale comments that still described the system as Dream: - Line 1146: "dream config" → "feature config" - Line 1155: strip tombstone "no longer live here — see the dream hook"; replace with clean end-state (Learning agent handles detection) - Lines 1169–1171: "spawns the Dream agent" → Learning agent via session-start-context directive - Lines 1203/1206: "dream config.json" / "dream-config.ts" → ".devflow/config.json" / "feature-config.ts" Surviving `[Dd]ream` references are all intentional legacy-sweep entries (removeDreamHook imports, LEGACY_HOOK_FILES array, migration docs). applies ADR-003 Co-Authored-By: Claude <noreply@anthropic.com>
…ertion
ISS-01: Guard readFileSync in rename-completeness sweeps against ENOENT.
build-mds.test.ts plants and unlinks _test-*.mds fixtures in commands/
under vitest's default parallelism; a file vanishing between readdir and
readFileSync caused a sporadic crash. A vanished file cannot be a shipping
violation — skip on ENOENT, rethrow all other errors.
ISS-13: Remove vacuous `catch { return; }` around the session-start-context
read — an unreadable/missing hook must fail loudly, not silently pass. Also
tighten the 900s assertion from toMatch(/900/) to toContain('PROCESSING_STALE_SECS=900')
so it matches the exact constant rather than any substring (avoids PF-008).
Co-Authored-By: Claude <noreply@anthropic.com>
…ct-shape guard ISS-11: Change `LearningTuningConfig.model` from `string` to the closed union `LearningModelAlias = 'opus' | 'sonnet' | 'haiku'`. The parse path now uses `isValidModel()` to reject out-of-domain strings before accepting them, matching the parse-don't-validate principle — on-disk values outside the domain fall through to `config.model`. ISS-12: Add the same object-shape guard used by `coerceConfig` in feature-config.ts before casting the parsed JSON to `Record<string, unknown>`. A JSON array, null, or primitive can no longer slip through the unsafe `as Record<string, unknown>` cast. Regression tests added for both issues in tests/decisions/config.test.ts. Co-Authored-By: Claude <noreply@anthropic.com>
getDecisionsManifestPath, getDecisionsNotificationsPath, and getDecisionsBatchIdsPath were re-pathed during the dream→learning rename instead of deleted. Nothing in the repo calls them; the purge-orphaned- sidecar-judgment-state migration explicitly drops the files they address. Applies ADR-003: leave a clean end-state, delete dead code rather than re-pathing it.
- Export DEFAULT_CONFIG so migrations.ts can import it instead of hardcoding the same literal (ISS-07a, applies ADR-003) - Correct the coerceConfig JSDoc that falsely claimed the semantics "mirror the manifest kb→knowledge self-heal": the semantics are intentionally inverted — legacy-decisions-wins is the opposite of manifest.ts's new-key-wins, which is by design for migration-compat (ISS-10) Co-Authored-By: Claude <noreply@anthropic.com>
ISS-08 (comment-only): update stale "Dream" references to "Learning"
- "directive-spawned Dream agent" → "Learning agent" (~line 829)
- "next Dream run" → "next Learning-agent render" (~line 888)
ISS-07b: extract seedFeatureConfigFromDream helper; use DEFAULT_CONFIG
- Import DEFAULT_CONFIG + FeatureConfig type from feature-config.ts
- Extract step-1 config parsing into a named helper that reads ONLY
the `decisions` key and ignores `learning` (migration-compat guard);
starts from DEFAULT_CONFIG so future fields default correctly
- Replace inline hardcoded `{memory:true, learning:true, knowledge:true}`
literal with `{...DEFAULT_CONFIG}` (applies ADR-003)
- Existing test CL-5 verifies the critical semantic guard: decisions-wins
over a pre-existing learning key (test green before and after)
ISS-14: unlink orphaned file-type entries before moveDirContents
- fs.unlink .decisions-usage.json / .decisions-manifest.json /
.decisions-notifications.json / .decisions-batch-ids from decisions/
BEFORE moveDirContents so they cannot block the best-effort rmdir
(applies ADR-003 clean end-state; ENOENT-tolerant, rethrows others)
- decisionsSkip set updated: "drop" comments → "defence-in-depth" for
the now-unlinked entries
ISS-02: guard renderDecisionsIndex; move before rmdirs; injectable path
- Add rendererPath?: string to PerProjectMigrationContext for tests
- Move render call to BEFORE the best-effort rmdirs (step 6 before 7)
so the ledger is already in learning/ when the renderer reads it
- Wrap in try/catch that appends a non-fatal warning and continues;
a render-lock timeout (30 s) no longer strands the migration
- Forward ctx.rendererPath to renderDecisionsIndex opts
Co-Authored-By: Claude <noreply@anthropic.com>
…e comment - Rewrite seedFeatureConfigFromDream to use single-return ternary style, consistent with coerceConfig in feature-config.ts. Eliminates the locally-mutated spread variable; semantics are unchanged (p.decisions maps to learning, p.learning is still intentionally ignored). - Remove // FIX: tombstone comment from handleConfigure in learning.ts; getLearningDir() is self-documenting.
- CLAUDE.md: 'NO Dream task' -> 'NO Learning task' (ISS-08b) - learning-capture-system KB: label migrations per-project vs global; rename-global-decisions-config-v1 is scope:global (ISS-09) applies ADR-003
Finish the incomplete rename by clearing genuine residue while leaving
must-stay historical anchors intact.
- .gitignore: fix the agent ignore rule (dream.md → learning.md) so the
generated Learning agent copy stops leaking into git; refresh the stale
runtime-dir comment
- untrack leaked build-output agent copies: plugins/devflow-{ambient,
core-skills}/agents/learning.md and plugins/devflow-plan/agents/designer.md
- rename stale "dream" comments/identifiers to learning in
background-memory-update, init.ts, knowledge/toggle.ts, and the
dreamDir → learningDir param in learning-queue-cleanup.ts
- fix dangling dream-curation.test.ts reference → learning-curation.test.ts
Left unchanged by design: migration IDs, legacy-hook cleanup literals,
guard tests, and sweepLegacyDreamMarkers (which documents the retired
dream pipeline it sweeps).
Summary
The "dream" placeholder codename (capture hooks + background agent + decisions pipeline) is renamed to learning end-to-end. Directories consolidate to a flat
.devflow/learning/; agentDream→Learning(shared/agents/learning.md, directive--- LEARNING MAINTENANCE ---withsubagent_type="Learning"); CLIdevflow decisions→devflow learning(clean break, no alias); init flags--learning/--no-learning; feature toggles move to a neutral.devflow/config.json{memory, learning, knowledge}(legacydecisionskey coalesces and wins); tuning configdecisions.json→learning.json(project.devflow/learning/learning.json+ global~/.devflow/learning.json); TS modules per naming map (feature-config.ts,learning.ts,learning-tuning-config.ts,learning-queue-cleanup.ts,legacy-hooks.ts, HUDlearning-counts.ts); shell layer (LEARNING_DIR,_QG_LEARNING,learning-lock).Changes
Naming Boundary: Content identifiers deliberately KEEP their names (
decisions.md,pitfalls.md,decisions-ledger.jsonl,decisions-log.jsonl,index.md,decisions_status,DECISIONS_CONTEXT,decisions_load(),render-decisions.cjs,decisions-format.cjs,decisions-usage-scan.cjs, ADR-NNN/PF-NNN) — user data compatibility.Migrations: New
consolidate-dream-decisions-to-learning-v1(per-project: config-first with legacy-key coalesce, queue + content moves via moveFile/moveDirContents, 9-entry skip-set drops locks/telemetry, index re-render) +rename-global-decisions-config-v1(global). The hazardous retired-pipeline migrationspurge-learning-pipeline-v1/purge-learning-global-v1(which would have destroyed the new.devflow/learning/) are deleted;consolidate-to-devflow-dirlearning-handling neutralized (ID unchanged). Legacy sweeps:LEGACY_AGENT_NAMES += 'dream',LEGACY_HOOK_FILES += 'dream-lock';build-plugins.tsnow prunes shared-agent copies absent from plugin manifests.Scope: Explicitly out of scope / unchanged: learnings stay local + gitignored (git-tracking was evaluated and dropped — gitignore functional lines, sentinel, and marker version byte-unchanged); no
devflow decisionsalias; queue-emptiness stays the sole directive gate (no new locks/throttles/state); 900s staleness, 120s memory throttle, 200→100 queue cap unchanged.Documentation: Docs rewritten to the learning end-state (CLAUDE.md, README, cli-reference incl. removal of documented-but-unimplemented
--review/--purge, file-organization, working-memory, docs-framework); feature KBdream-capture-systemreplaced bylearning-capture-system.Verification
Test Files 63 passed (63)/Tests 1988 passed (1988); build deterministic (npm run build+build:mdsleave the tree clean)..devflow/decisions/index.mdconsumers in MDS partials/shared agents/release command) + Evaluator (final verdict ALIGNED — 30/30 acceptance criteria incl. AC-P5) + Tester (11/11 scenario seeds PASS against sandboxed fixtures: full migration, idempotent re-init, clean break, stale-agent sweep, HUD, directive gating, global tuning rename).Known Follow-Ups
build-mds.test.tstemp fixture (commands/_test-dest-safety.mds) can race the rename-completeness sweep scan inlearning-agent.test.tsunder full-suite parallelism (observed once, second run clean).Related Issues
None specified in this PR.