Commit 5cb0d71
authored
refactor(iris): split ContextStore into persistence/scoring/repository/snapshot units (#122)
* test(iris): cover active-clear-without-presence and migration-session quirks in ContextStore
Two safety-net tests added before the upcoming ContextStore split refactor:
1. removeExercise/removeCourse clears activeContext when the requested id
matches activeContext.id, even if the item is absent from
recentExercises/allExercises (the current code is id-match driven, not
list-presence driven).
2. migrateState() preserves sessions and activeSessionId across version
bumps, while loadState() strips them for current-version records. The
asymmetry is intentional and now under test.
These quirks are otherwise uncovered by the existing 39-test suite and
would be easy to silently lose during the upcoming class extraction.
* refactor(iris): extract priority scoring from ContextStore
Move PRIORITY/TIME_WINDOW weight tables, MS_PER_DAY/MS_PER_HOUR units,
the two list comparators, and calculateExercisePriority /
calculateCoursePriority into a new pure module
src/extension/services/iris/contextPriorityScorer.ts.
The calculate functions become free functions (they only depended on
their argument and Date.now()). PRIORITY and TIME_WINDOW stay
module-internal. ContextStore drops from 611 to 498 LOC and now imports
the four public functions.
No behavior change. ContextStore test suite (incl. the 3 Task 0
safety-net tests) still green.
* refactor(iris): extract ContextStore persistence layer
Move the load/save/migrate persistence logic out of ContextStore into a
dedicated ContextPersistence class. Move the StoredState interface to a
small shared types file (contextStateTypes.ts) so persistence and
ContextStore can share the type without one importing the other's class.
Behavior is preserved verbatim, including the asymmetry covered by the
Task 0 migration safety-net test:
- load() of a current-version record strips sessions and activeSessionId
- migrate() of an older-version record preserves both via ?? fallbacks
ContextStore: 498 → 435 LOC. New files: contextPersistence.ts (62 LOC),
contextStateTypes.ts (12 LOC).
* refactor(iris): extract ContextStore snapshot projection
Move the snapshot building logic out of ContextStore into a pure
buildContextSnapshot function in contextSnapshot.ts. SESSION_KEY_SEPARATOR
and getContextKey move with it (they were only used by snapshot in this
file; SessionManager has its own private copies).
ContextStore.snapshot() is now a one-liner that delegates to the pure
function. ContextStore: 435 → 401 LOC.
* refactor(iris): extract tracked-item repository from ContextStore
Move all exercise/course tracking logic out of ContextStore into a new
TrackedItemRepository class that mirrors SessionManager's
callback-injection pattern. ARCHIVE_LIMITS, ExerciseInput, and CourseInput
move with it; ContextStore re-exports the two input types so any future
callers that import them through the facade keep working.
The repository owns: upsertExercise / upsertCourse, removeExercise /
removeCourse (no active-context interaction — that stays in the facade),
recalculate*Priorities (recent-only, preserving invariant), trim*History,
getExerciseById, getWorkspaceExercise, plus the private workspace-flag
clearing and upsertList helpers. All mutation rules are ported verbatim:
existing-lookup order (allExercises first), workspace-flag exclusivity
(cleared in both lists before merge), recent-only priority recalc.
ContextStore is now a thin facade that wires the four collaborators
(persistence, snapshot, repository, session manager) and keeps active
context state + the change event. removeExercise/removeCourse preserve
the current double-save and id-match-driven clearing semantics
(invariants 6 and 7), locked in by Task 0 safety-net tests.
ContextStore: 401 → 225 LOC. New file: trackedItemRepository.ts (218 LOC).
No behavior change.
* refactor(iris): restore explicit ExerciseInput/CourseInput on ContextStore facade
After Task 4, registerExercise / registerCourse exposed
Parameters<TrackedItemRepository[...]>[0] derived types in their public
signatures, which structurally matched the original ExerciseInput /
CourseInput but coupled the facade's public API to the repository class.
Import the two interfaces explicitly and reference them by name in the
parameter positions. The facade re-exports them so existing import paths
through ContextStore keep working. Pure source-level cleanup, no
behavior or runtime change.
* refactor(iris): reorganize services/iris into chat/ context/ transport/
Sort the now-17 iris/ files into three concern-based subfolders so the
directory listing maps to architecture instead of alphabet:
- chat/ UI/webview routing (chat*, helpContent, messageUtils, irisWebSocketMessageHandler)
- context/ state storage (contextStore + the Task 1-4 splits, sessionManager, sessionSyncUtils)
- transport/ WS session infrastructure (irisWebSocketSessionClient)
iris/index.ts public surface is unchanged — every existing import via
'../services/iris' keeps working. Only one external file
(chatViewStatePresenter) used a deep path and was updated. Internal
imports between iris/ files were rewritten to the new relative paths.
Mechanical move via git mv (so renames are tracked); no behavior change.
* chore(iris): demote unused exports to module-private to satisfy knip
Knip flagged getContextKey, BuildSnapshotOptions, ExerciseInput/CourseInput
re-export, and TrackedItemRepositoryOptions as unused exports. None are
consumed outside their declaring modules — drop the export keyword.1 parent 691abd6 commit 5cb0d71
24 files changed
Lines changed: 863 additions & 675 deletions
File tree
- extension
- src/extension
- provider
- services/iris
- chat
- context
- transport
- test/unit
- provider
- services
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1 | 1 | | |
2 | 2 | | |
3 | | - | |
| 3 | + | |
4 | 4 | | |
5 | 5 | | |
6 | 6 | | |
| |||
Lines changed: 5 additions & 5 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1 | 1 | | |
2 | | - | |
3 | | - | |
4 | | - | |
5 | | - | |
6 | | - | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
7 | 7 | | |
8 | 8 | | |
9 | 9 | | |
| |||
Lines changed: 5 additions & 5 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1 | | - | |
2 | | - | |
3 | | - | |
4 | | - | |
5 | | - | |
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
6 | 6 | | |
7 | 7 | | |
8 | 8 | | |
| |||
Lines changed: 8 additions & 8 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1 | 1 | | |
2 | | - | |
3 | | - | |
| 2 | + | |
| 3 | + | |
4 | 4 | | |
5 | | - | |
6 | | - | |
7 | | - | |
8 | | - | |
9 | | - | |
10 | | - | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
11 | 11 | | |
12 | 12 | | |
13 | 13 | | |
| |||
Lines changed: 6 additions & 6 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1 | | - | |
2 | | - | |
| 1 | + | |
| 2 | + | |
3 | 3 | | |
4 | | - | |
5 | | - | |
6 | | - | |
7 | | - | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
8 | 8 | | |
9 | 9 | | |
10 | 10 | | |
| |||
Lines changed: 6 additions & 6 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1 | 1 | | |
2 | | - | |
3 | | - | |
4 | | - | |
5 | | - | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
6 | 6 | | |
7 | | - | |
8 | | - | |
| 7 | + | |
| 8 | + | |
9 | 9 | | |
10 | 10 | | |
11 | 11 | | |
| |||
Lines changed: 1 addition & 1 deletion
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1 | | - | |
| 1 | + | |
2 | 2 | | |
3 | 3 | | |
4 | 4 | | |
| |||
Lines changed: 62 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
Lines changed: 120 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
| 89 | + | |
| 90 | + | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
| 95 | + | |
| 96 | + | |
| 97 | + | |
| 98 | + | |
| 99 | + | |
| 100 | + | |
| 101 | + | |
| 102 | + | |
| 103 | + | |
| 104 | + | |
| 105 | + | |
| 106 | + | |
| 107 | + | |
| 108 | + | |
| 109 | + | |
| 110 | + | |
| 111 | + | |
| 112 | + | |
| 113 | + | |
| 114 | + | |
| 115 | + | |
| 116 | + | |
| 117 | + | |
| 118 | + | |
| 119 | + | |
| 120 | + | |
0 commit comments