Skip to content

refactor: delegate StateManager knowledge loading to KnowledgeTracker (plan 010)#79

Merged
DavertMik merged 3 commits into
fix/incognito-flagfrom
refactor/knowledge-single-owner
Jul 11, 2026
Merged

refactor: delegate StateManager knowledge loading to KnowledgeTracker (plan 010)#79
DavertMik merged 3 commits into
fix/incognito-flagfrom
refactor/knowledge-single-owner

Conversation

@DavertMik

Copy link
Copy Markdown
Contributor

Implements plan 010 (plans/010-delegate-statemanager-knowledge.md) — a P1 bug + dedup refactor.

Stacked PR — base branch is fix/incognito-flag (plan 009), because both touch the StateManager constructor. The options objects are merged ({ knowledgeTracker?, incognito? }). Review/merge #78 first; this diff shows only plan 010's changes.

Problem

StateManager had a second implementation of knowledge loading (scanKnowledgeFiles + its own cache + dir resolution) that had diverged from KnowledgeTracker.loadKnowledgeFiles:

StateManager copy KnowledgeTracker
Scan recursive, rescans every 30s flat, cached forever
${env.X}/${config.X} interpolation no yes

The only production consumer of the StateManager copy is Researcher — so Researcher saw raw ${env.ADMIN_PASSWORD} literal text while every other agent saw interpolated content for the same page. This also violated CLAUDE.md's Code Ownership Map ("Reading/writing ./knowledge + var interpolation → KnowledgeTracker only").

Fix

  • Delete the StateManager copy (scanKnowledgeFiles, knowledgeCache, lastKnowledgeScan, knowledgeDir) and delegate getRelevantKnowledge() to the shared KnowledgeTracker. Explorer now constructs the tracker first and injects it (CLAUDE.md shared-instance rule).
  • Make KnowledgeTracker.loadKnowledgeFiles scan recursively (superset of both).
  • addKnowledge now sets isLoaded = false so a same-instance read (the /learn command) sees what it just wrote — a secondary bug.
  • Unify the two divergent Knowledge types onto one exported interface (re-exported from state-manager for back-compat).

Verification

  • New: recursive-scan test, addKnowledge-invalidation test (knowledge-tracker.test.ts), and an interpolation-through-StateManager regression (state-manager.test.ts) — confirmed it fails on the old code (returns literal ${env.SM_TEST_VAR}) and passes now.
  • bun test tests/unit → 731 pass, 0 fail; bun test tests/integration/researcher.test.ts → 8 pass; bun run lint clean.

Intended behavior deltas (per plan)

30s rescan removed (in-app writes picked up via addKnowledge invalidation; hand-edited files mid-session no longer auto-detected); recursive scan now applies to all consumers; Researcher now receives interpolated knowledge.

🤖 Generated with Claude Code

DavertMik and others added 3 commits July 11, 2026 14:39
StateManager contained a complete second implementation of knowledge-file
loading (scanKnowledgeFiles + its own cache + dir resolution) that had diverged
from KnowledgeTracker.loadKnowledgeFiles — most importantly, the StateManager
copy did NOT run ${env.*}/${config.*} interpolation. Researcher (the only
production consumer of the StateManager copy) therefore saw raw
${env.PASSWORD} text while Navigator, TaskAgent, ExperienceTracker and commands
saw interpolated content for the same page.

Delete the copy and delegate to KnowledgeTracker (the CLAUDE.md single owner of
the knowledge dir), sharing one tracker instance from Explorer. Make the tracker
scan recursively (superset of both implementations), invalidate its isLoaded
cache on addKnowledge (so a same-instance /learn read sees the write), and unify
the two divergent Knowledge types onto one exported interface.

Intended behavior deltas: the 30s rescan is gone (in-app writes picked up via
addKnowledge invalidation), recursive scan now applies to every consumer, and
Researcher now receives interpolated knowledge.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…taleness)

Deleting StateManager's knowledge scanner (which rescanned every 30s) left the
shared KnowledgeTracker caching forever; addKnowledge's isLoaded invalidation is
per-instance, so /learn (which builds its own tracker) and hand-edited files were
never picked up by Explorer's shared instance until restart — and CLAUDE.md's
documented "30-second refresh" existed nowhere.

Restore the refresh in the single owner: loadKnowledgeFiles re-scans when the
cache is older than 30s (KNOWLEDGE_REFRESH_MS), so on-disk changes from any
source reach every consumer. Same-instance addKnowledge still forces an immediate
reload via isLoaded=false.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant