@prmichaelsen/remember-mcp 3.14.11 → 3.14.14

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (34) hide show
  1. package/CHANGELOG.md +20 -0
  2. package/agent/milestones/milestone-18-performance-tuning.md +45 -0
  3. package/agent/progress.yaml +86 -2
  4. package/agent/tasks/task-77-parallelize-checkiffriend.md +62 -0
  5. package/agent/tasks/task-78-cache-checkiffriend.md +78 -0
  6. package/agent/tasks/task-79-memoize-core-services.md +75 -0
  7. package/agent/tasks/task-80-parallelize-startup-health-checks.md +57 -0
  8. package/agent/tasks/task-81-optimize-ghost-config-block-unblock.md +64 -0
  9. package/agent/tasks/task-82-native-weaviate-offset.md +69 -0
  10. package/agent/tasks/task-83-eliminate-redundant-validatetoken.md +53 -0
  11. package/agent/tasks/task-84-static-imports-server-factory.md +52 -0
  12. package/dist/core-services.d.ts +3 -1
  13. package/dist/server-factory.js +250 -482
  14. package/dist/server.js +29 -140
  15. package/dist/services/access-control.d.ts +5 -5
  16. package/dist/services/ghost-config.service.d.ts +2 -0
  17. package/package.json +1 -1
  18. package/src/core-services.ts +16 -2
  19. package/src/server-factory.ts +5 -3
  20. package/src/server.ts +5 -3
  21. package/src/services/access-control.spec.ts +11 -11
  22. package/src/services/access-control.ts +74 -8
  23. package/src/services/ghost-config.service.spec.ts +22 -15
  24. package/src/services/ghost-config.service.ts +9 -15
  25. package/src/tools/query-memory.ts +1 -2
  26. package/src/tools/search-memory.ts +5 -8
  27. package/dist/services/trust-enforcement.d.ts +0 -83
  28. package/dist/services/trust-enforcement.spec.d.ts +0 -2
  29. package/dist/utils/weaviate-filters.d.ts +0 -56
  30. package/dist/utils/weaviate-filters.spec.d.ts +0 -8
  31. package/src/services/trust-enforcement.spec.ts +0 -309
  32. package/src/services/trust-enforcement.ts +0 -197
  33. package/src/utils/weaviate-filters.spec.ts +0 -312
  34. package/src/utils/weaviate-filters.ts +0 -236
package/CHANGELOG.md CHANGED
@@ -5,6 +5,26 @@ All notable changes to this project will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [3.14.14] - 2026-03-04
9
+
10
+ ### Changed
11
+
12
+ - Parallelize `checkIfFriend` Firestore queries with `Promise.all` (task-77)
13
+ - Add 60-second TTL cache to `checkIfFriend` for friend status lookups (task-78)
14
+ - Memoize `createCoreServices` per userId to avoid per-request service instantiation (task-79)
15
+ - Parallelize startup health checks (`testWeaviateConnection` + `testFirestoreConnection`) (task-80)
16
+ - Optimize `blockUser`/`unblockUser` with `FieldValue.arrayUnion`/`arrayRemove` — eliminates read RPC (task-81)
17
+ - Use native Weaviate `offset` parameter in `search-memory` instead of JS `slice()` (task-82)
18
+ - Convert dynamic `import()` to static imports for ghost-config and access-control in server-factory (task-84)
19
+
20
+ ## [3.14.13] - 2026-03-04
21
+
22
+ ### Fixed
23
+
24
+ - Fix `resolveAccessorTrustLevel` call sites to match new async 3-param signature (ownerUserId added for friend detection)
25
+ - Rewrite `checkIfFriend` to use `queryDocuments` from firebase-admin-sdk-v8 (was using nonexistent `getFirestore()`)
26
+ - Update access-control tests to use async/await with ownerUserId parameter
27
+
8
28
  ## [3.14.0] - 2026-02-28
9
29
 
10
30
  ### Changed
@@ -0,0 +1,45 @@
1
+ # Milestone 18: Performance Tuning
2
+
3
+ **Status**: Not Started
4
+ **Priority**: Medium
5
+ **Estimated Weeks**: 1
6
+ **Dependencies**: None
7
+
8
+ ---
9
+
10
+ ## Objective
11
+
12
+ Optimize remember-mcp server performance by eliminating redundant database calls, adding caching for rarely-changing data, parallelizing independent operations, and reducing per-request overhead.
13
+
14
+ ---
15
+
16
+ ## Success Criteria
17
+
18
+ - [ ] Ghost mode requests do not make redundant Firestore queries for friend status
19
+ - [ ] Core services are cached per-user instead of recreated on every tool call
20
+ - [ ] Server startup parallelizes independent health checks
21
+ - [ ] No functional regressions — all existing tests pass
22
+ - [ ] Measurable latency improvement for ghost mode access checks
23
+
24
+ ---
25
+
26
+ ## Tasks
27
+
28
+ | # | Task | Status | Est. Hours |
29
+ |---|------|--------|------------|
30
+ | 77 | Parallelize checkIfFriend Firestore queries | Not Started | 0.5 |
31
+ | 78 | Add TTL cache to checkIfFriend | Not Started | 1 |
32
+ | 79 | Memoize createCoreServices per userId | Not Started | 1 |
33
+ | 80 | Parallelize startup health checks | Not Started | 0.5 |
34
+ | 81 | Optimize ghost-config block/unblock with FieldValue | Not Started | 1 |
35
+ | 82 | Use native Weaviate offset in search-memory | Not Started | 0.5 |
36
+ | 83 | Eliminate redundant validateToken in confirm flow | Not Started | 1 |
37
+ | 84 | Convert dynamic imports to static in server-factory | Not Started | 0.5 |
38
+
39
+ ---
40
+
41
+ ## Notes
42
+
43
+ - Task 63 in remember-core covers Weaviate collection pooling (separate project)
44
+ - Credential provider stub async overhead (#9 from audit) and esbuild parallelization (#10) are too trivial to warrant tasks
45
+ - All changes are internal — no API changes for consumers
@@ -341,6 +341,17 @@ milestones:
341
341
  3 tools deferred (search_memory, query_memory, ghost_config) — require core ghost/trust support.
342
342
  See: agent/milestones/milestone-17-remember-core-migration.md
343
343
 
344
+ - id: M18
345
+ name: Performance Tuning
346
+ status: in_progress
347
+ progress: 87%
348
+ estimated_weeks: 1
349
+ tasks_completed: 7
350
+ tasks_total: 8
351
+ notes: |
352
+ Optimize server performance: parallel queries, caching, memoization.
353
+ See: agent/milestones/milestone-18-performance-tuning.md
354
+
344
355
  tasks:
345
356
  milestone_1:
346
357
  - id: task-1
@@ -986,11 +997,84 @@ tasks:
986
997
  ✅ Removed empty src/constants/ and src/collections/ directories.
987
998
  ✅ Build passing, 390 tests (389 passed, 1 skipped).
988
999
 
1000
+ milestone_18:
1001
+ - id: task-77
1002
+ name: Parallelize checkIfFriend Firestore Queries
1003
+ status: completed
1004
+ completed_date: 2026-03-04
1005
+ file: agent/tasks/task-77-parallelize-checkiffriend.md
1006
+ estimated_hours: 0.5
1007
+ notes: |
1008
+ Run forward + reverse friend queries in Promise.all
1009
+
1010
+ - id: task-78
1011
+ name: Add TTL Cache to checkIfFriend
1012
+ status: completed
1013
+ completed_date: 2026-03-04
1014
+ file: agent/tasks/task-78-cache-checkiffriend.md
1015
+ estimated_hours: 1
1016
+ dependencies: [task-77]
1017
+ notes: |
1018
+ 60s TTL cache for friend status lookups
1019
+
1020
+ - id: task-79
1021
+ name: Memoize createCoreServices per userId
1022
+ status: completed
1023
+ completed_date: 2026-03-04
1024
+ file: agent/tasks/task-79-memoize-core-services.md
1025
+ estimated_hours: 1
1026
+ notes: |
1027
+ Cache CoreServices instances per userId
1028
+
1029
+ - id: task-80
1030
+ name: Parallelize Startup Health Checks
1031
+ status: completed
1032
+ completed_date: 2026-03-04
1033
+ file: agent/tasks/task-80-parallelize-startup-health-checks.md
1034
+ estimated_hours: 0.5
1035
+ notes: |
1036
+ Promise.all for testWeaviateConnection + testFirestoreConnection
1037
+
1038
+ - id: task-81
1039
+ name: Optimize ghost-config block/unblock with FieldValue
1040
+ status: completed
1041
+ completed_date: 2026-03-04
1042
+ file: agent/tasks/task-81-optimize-ghost-config-block-unblock.md
1043
+ estimated_hours: 1
1044
+ notes: |
1045
+ Use FieldValue.arrayUnion/arrayRemove to skip read RPC
1046
+
1047
+ - id: task-82
1048
+ name: Use Native Weaviate Offset in search-memory
1049
+ status: completed
1050
+ completed_date: 2026-03-04
1051
+ file: agent/tasks/task-82-native-weaviate-offset.md
1052
+ estimated_hours: 0.5
1053
+ notes: |
1054
+ Pass offset to Weaviate instead of JS slice
1055
+
1056
+ - id: task-83
1057
+ name: Eliminate Redundant validateToken in Confirm Flow
1058
+ status: deferred
1059
+ file: agent/tasks/task-83-eliminate-redundant-validatetoken.md
1060
+ estimated_hours: 1
1061
+ notes: |
1062
+ Remove peek-then-consume double read
1063
+
1064
+ - id: task-84
1065
+ name: Convert Dynamic Imports to Static in server-factory
1066
+ status: completed
1067
+ completed_date: 2026-03-04
1068
+ file: agent/tasks/task-84-static-imports-server-factory.md
1069
+ estimated_hours: 0.5
1070
+ notes: |
1071
+ Static imports for ghost-config and access-control
1072
+
989
1073
  documentation:
990
1074
  design_documents: 31
991
- milestone_documents: 13
1075
+ milestone_documents: 14
992
1076
  pattern_documents: 7
993
- task_documents: 83
1077
+ task_documents: 91
994
1078
 
995
1079
  progress:
996
1080
  planning: 100%
@@ -0,0 +1,62 @@
1
+ # Task 77: Parallelize checkIfFriend Firestore Queries
2
+
3
+ **Milestone**: M18 - Performance Tuning
4
+ **Estimated Time**: 0.5 hours
5
+ **Dependencies**: None
6
+ **Status**: Not Started
7
+
8
+ ---
9
+
10
+ ## Objective
11
+
12
+ Run the two directional friendship queries in `checkIfFriend` concurrently with `Promise.all` instead of sequentially, cutting worst-case latency from ~400ms to ~200ms.
13
+
14
+ ---
15
+
16
+ ## Context
17
+
18
+ `src/services/access-control.ts` `checkIfFriend()` queries Firestore twice sequentially (owner→accessor, then accessor→owner). These are independent queries that can run in parallel.
19
+
20
+ ---
21
+
22
+ ## Steps
23
+
24
+ ### 1. Refactor checkIfFriend to use Promise.all
25
+
26
+ **File**: `src/services/access-control.ts`
27
+
28
+ Replace the sequential pattern:
29
+ ```typescript
30
+ const results = await queryDocuments(...forward...);
31
+ if (results.length > 0) return true;
32
+ const reverseResults = await queryDocuments(...reverse...);
33
+ return reverseResults.length > 0;
34
+ ```
35
+
36
+ With parallel:
37
+ ```typescript
38
+ const [forward, reverse] = await Promise.all([
39
+ queryDocuments(...forward...),
40
+ queryDocuments(...reverse...),
41
+ ]);
42
+ return forward.length > 0 || reverse.length > 0;
43
+ ```
44
+
45
+ ### 2. Verify tests pass
46
+
47
+ Run `npx jest --testPathPattern=access-control`.
48
+
49
+ ---
50
+
51
+ ## Verification
52
+
53
+ - [ ] Both queries run in parallel via Promise.all
54
+ - [ ] All access-control tests pass
55
+ - [ ] TypeScript compiles without errors
56
+
57
+ ---
58
+
59
+ ## Expected Output
60
+
61
+ **Files Modified**:
62
+ - `src/services/access-control.ts`
@@ -0,0 +1,78 @@
1
+ # Task 78: Add TTL Cache to checkIfFriend
2
+
3
+ **Milestone**: M18 - Performance Tuning
4
+ **Estimated Time**: 1 hour
5
+ **Dependencies**: Task 77
6
+ **Status**: Not Started
7
+
8
+ ---
9
+
10
+ ## Objective
11
+
12
+ Cache friend status lookups with a short TTL so repeated ghost mode access checks for the same user pair don't hit Firestore on every memory.
13
+
14
+ ---
15
+
16
+ ## Context
17
+
18
+ `checkIfFriend` is called from `resolveAccessorTrustLevel` → `checkMemoryAccess`, which runs per-memory in prompt/hybrid enforcement modes. Friend status rarely changes during a session. A 60-second TTL cache eliminates redundant Firestore reads.
19
+
20
+ ---
21
+
22
+ ## Steps
23
+
24
+ ### 1. Add TTL Map cache
25
+
26
+ **File**: `src/services/access-control.ts`
27
+
28
+ ```typescript
29
+ const friendCache = new Map<string, { result: boolean; expiresAt: number }>();
30
+ const FRIEND_CACHE_TTL_MS = 60_000; // 60 seconds
31
+ ```
32
+
33
+ ### 2. Check cache before querying
34
+
35
+ In `checkIfFriend`, check both directions (key `a:b` and `b:a` are the same friendship):
36
+ ```typescript
37
+ const key = [ownerUserId, accessorUserId].sort().join(':');
38
+ const cached = friendCache.get(key);
39
+ if (cached && Date.now() < cached.expiresAt) return cached.result;
40
+ ```
41
+
42
+ ### 3. Store result in cache after query
43
+
44
+ ```typescript
45
+ friendCache.set(key, { result, expiresAt: Date.now() + FRIEND_CACHE_TTL_MS });
46
+ ```
47
+
48
+ ### 4. Export cache invalidation for tests
49
+
50
+ ```typescript
51
+ export function invalidateFriendCache(): void {
52
+ friendCache.clear();
53
+ }
54
+ ```
55
+
56
+ ### 5. Add tests
57
+
58
+ - Cache hit returns without Firestore call
59
+ - Cache expires after TTL
60
+ - `invalidateFriendCache()` clears cache
61
+
62
+ ---
63
+
64
+ ## Verification
65
+
66
+ - [ ] Repeated calls for same user pair don't hit Firestore
67
+ - [ ] Cache expires after 60 seconds
68
+ - [ ] invalidateFriendCache works
69
+ - [ ] All existing tests pass
70
+ - [ ] New cache tests pass
71
+
72
+ ---
73
+
74
+ ## Expected Output
75
+
76
+ **Files Modified**:
77
+ - `src/services/access-control.ts`
78
+ - `src/services/access-control.spec.ts`
@@ -0,0 +1,75 @@
1
+ # Task 79: Memoize createCoreServices per userId
2
+
3
+ **Milestone**: M18 - Performance Tuning
4
+ **Estimated Time**: 1 hour
5
+ **Dependencies**: None
6
+ **Status**: Not Started
7
+
8
+ ---
9
+
10
+ ## Objective
11
+
12
+ Cache `CoreServices` instances per `userId` so that repeated tool calls don't instantiate new `MemoryService`, `RelationshipService`, and `SpaceService` objects on every invocation.
13
+
14
+ ---
15
+
16
+ ## Context
17
+
18
+ `src/core-services.ts` `createCoreServices(userId)` is called by every tool handler. Each call creates 3 new service instances and calls `getMemoryCollection(userId)` (which calls `client.collections.get()`). In factory mode, the server is scoped to one userId, making all these allocations pure overhead after the first call.
19
+
20
+ ---
21
+
22
+ ## Steps
23
+
24
+ ### 1. Add Map cache
25
+
26
+ **File**: `src/core-services.ts`
27
+
28
+ ```typescript
29
+ const coreServicesCache = new Map<string, CoreServices>();
30
+
31
+ export function createCoreServices(userId: string): CoreServices {
32
+ const cached = coreServicesCache.get(userId);
33
+ if (cached) return cached;
34
+
35
+ const collection = getMemoryCollection(userId);
36
+ const weaviateClient = getWeaviateClient();
37
+
38
+ const services: CoreServices = {
39
+ memory: new MemoryService(collection, userId, coreLogger),
40
+ relationship: new RelationshipService(collection, userId, coreLogger),
41
+ space: new SpaceService(weaviateClient, collection, userId, tokenService, coreLogger),
42
+ preferences: preferencesService,
43
+ token: tokenService,
44
+ };
45
+
46
+ coreServicesCache.set(userId, services);
47
+ return services;
48
+ }
49
+ ```
50
+
51
+ ### 2. Export invalidation for tests
52
+
53
+ ```typescript
54
+ export function invalidateCoreServicesCache(): void {
55
+ coreServicesCache.clear();
56
+ }
57
+ ```
58
+
59
+ ### 3. Verify all tests pass
60
+
61
+ ---
62
+
63
+ ## Verification
64
+
65
+ - [ ] Second call for same userId returns cached instance
66
+ - [ ] Different userIds get different instances
67
+ - [ ] All existing tests pass
68
+ - [ ] TypeScript compiles without errors
69
+
70
+ ---
71
+
72
+ ## Expected Output
73
+
74
+ **Files Modified**:
75
+ - `src/core-services.ts`
@@ -0,0 +1,57 @@
1
+ # Task 80: Parallelize Startup Health Checks
2
+
3
+ **Milestone**: M18 - Performance Tuning
4
+ **Estimated Time**: 0.5 hours
5
+ **Dependencies**: None
6
+ **Status**: Not Started
7
+
8
+ ---
9
+
10
+ ## Objective
11
+
12
+ Run `testWeaviateConnection()` and `testFirestoreConnection()` in parallel during server startup to reduce init latency.
13
+
14
+ ---
15
+
16
+ ## Context
17
+
18
+ `src/server.ts` lines 61-63 run these two independent health checks sequentially. Each is a network round-trip (50-200ms). Running them in parallel saves the latency of the slower one.
19
+
20
+ ---
21
+
22
+ ## Steps
23
+
24
+ ### 1. Update server.ts
25
+
26
+ **File**: `src/server.ts`
27
+
28
+ Replace:
29
+ ```typescript
30
+ const weaviateOk = await testWeaviateConnection();
31
+ const firestoreOk = await testFirestoreConnection();
32
+ ```
33
+
34
+ With:
35
+ ```typescript
36
+ const [weaviateOk, firestoreOk] = await Promise.all([
37
+ testWeaviateConnection(),
38
+ testFirestoreConnection(),
39
+ ]);
40
+ ```
41
+
42
+ ### 2. Verify startup works
43
+
44
+ ---
45
+
46
+ ## Verification
47
+
48
+ - [ ] Server starts successfully
49
+ - [ ] Both connection tests still run
50
+ - [ ] TypeScript compiles without errors
51
+
52
+ ---
53
+
54
+ ## Expected Output
55
+
56
+ **Files Modified**:
57
+ - `src/server.ts`
@@ -0,0 +1,64 @@
1
+ # Task 81: Optimize ghost-config block/unblock with FieldValue
2
+
3
+ **Milestone**: M18 - Performance Tuning
4
+ **Estimated Time**: 1 hour
5
+ **Dependencies**: None
6
+ **Status**: Not Started
7
+
8
+ ---
9
+
10
+ ## Objective
11
+
12
+ Replace read-modify-write pattern in `blockUser` and `unblockUser` with Firestore `FieldValue.arrayUnion` / `FieldValue.arrayRemove` to eliminate the read RPC.
13
+
14
+ ---
15
+
16
+ ## Context
17
+
18
+ `src/services/ghost-config.service.ts` `blockUser()` and `unblockUser()` each:
19
+ 1. Read the entire GhostConfig document from Firestore
20
+ 2. Modify the `blocked_users` array in memory
21
+ 3. Write the document back
22
+
23
+ Firestore's `FieldValue.arrayUnion/arrayRemove` can atomically add/remove array elements without reading first, halving the RPC count for these operations.
24
+
25
+ ---
26
+
27
+ ## Steps
28
+
29
+ ### 1. Update blockUser
30
+
31
+ **File**: `src/services/ghost-config.service.ts`
32
+
33
+ Replace read-modify-write with:
34
+ ```typescript
35
+ await setDocument(collectionPath, docId, {
36
+ blocked_users: FieldValue.arrayUnion(targetUserId),
37
+ }, { merge: true });
38
+ ```
39
+
40
+ ### 2. Update unblockUser
41
+
42
+ ```typescript
43
+ await setDocument(collectionPath, docId, {
44
+ blocked_users: FieldValue.arrayRemove(targetUserId),
45
+ }, { merge: true });
46
+ ```
47
+
48
+ ### 3. Verify ghost-config tests pass
49
+
50
+ ---
51
+
52
+ ## Verification
53
+
54
+ - [ ] blockUser works without reading first
55
+ - [ ] unblockUser works without reading first
56
+ - [ ] All ghost-config tests pass
57
+ - [ ] TypeScript compiles without errors
58
+
59
+ ---
60
+
61
+ ## Expected Output
62
+
63
+ **Files Modified**:
64
+ - `src/services/ghost-config.service.ts`
@@ -0,0 +1,69 @@
1
+ # Task 82: Use Native Weaviate Offset in search-memory
2
+
3
+ **Milestone**: M18 - Performance Tuning
4
+ **Estimated Time**: 0.5 hours
5
+ **Dependencies**: None
6
+ **Status**: Not Started
7
+
8
+ ---
9
+
10
+ ## Objective
11
+
12
+ Pass `offset` directly to Weaviate's hybrid search query instead of fetching `limit + offset` results and slicing in JavaScript.
13
+
14
+ ---
15
+
16
+ ## Context
17
+
18
+ `src/tools/search-memory.ts` currently fetches extra records and uses `slice(offset)` to implement pagination. Weaviate v3 API supports native `offset` in query options, which reduces network payload for paginated searches.
19
+
20
+ ---
21
+
22
+ ## Steps
23
+
24
+ ### 1. Update search query options
25
+
26
+ **File**: `src/tools/search-memory.ts`
27
+
28
+ Replace:
29
+ ```typescript
30
+ const searchOptions: any = {
31
+ alpha: alpha,
32
+ limit: limit + offset,
33
+ };
34
+ // ...
35
+ const paginatedResults = results.objects.slice(offset);
36
+ ```
37
+
38
+ With:
39
+ ```typescript
40
+ const searchOptions: any = {
41
+ alpha: alpha,
42
+ limit: limit,
43
+ offset: offset,
44
+ };
45
+ // ... use results.objects directly
46
+ ```
47
+
48
+ ### 2. Check if same pattern exists in other search tools
49
+
50
+ Check `query-memory.ts`, `search-space.ts`, `query-space.ts`, `find-similar.ts` for the same pattern.
51
+
52
+ ### 3. Verify tests pass
53
+
54
+ ---
55
+
56
+ ## Verification
57
+
58
+ - [ ] Offset handled by Weaviate, not JS slice
59
+ - [ ] Pagination still works correctly
60
+ - [ ] All search-related tests pass
61
+ - [ ] TypeScript compiles without errors
62
+
63
+ ---
64
+
65
+ ## Expected Output
66
+
67
+ **Files Modified**:
68
+ - `src/tools/search-memory.ts`
69
+ - Possibly other search tool files
@@ -0,0 +1,53 @@
1
+ # Task 83: Eliminate Redundant validateToken in Confirm Flow
2
+
3
+ **Milestone**: M18 - Performance Tuning
4
+ **Estimated Time**: 1 hour
5
+ **Dependencies**: None
6
+ **Status**: Not Started
7
+
8
+ ---
9
+
10
+ ## Objective
11
+
12
+ Remove the redundant `validateToken` call in the confirm tool's delete_memory path, where `confirmRequest` already retrieves the full token payload.
13
+
14
+ ---
15
+
16
+ ## Context
17
+
18
+ `src/tools/confirm.ts` calls `tokenService.validateToken()` to peek at the token action type, then immediately calls `tokenService.confirmRequest()` which reads the token again. For the delete_memory path, this is two sequential storage reads when one would suffice.
19
+
20
+ ---
21
+
22
+ ## Steps
23
+
24
+ ### 1. Analyze confirm.ts flow
25
+
26
+ Read `src/tools/confirm.ts` to understand all action type branches and whether `confirmRequest` returns sufficient data to eliminate the validate step.
27
+
28
+ ### 2. Refactor to single call
29
+
30
+ If `confirmRequest` returns the full request payload on success, use it directly:
31
+ ```typescript
32
+ const confirmed = await tokenService.confirmRequest(userId, args.token);
33
+ if (!confirmed) { return error; }
34
+ // Use confirmed.action to determine path
35
+ ```
36
+
37
+ ### 3. Verify all confirm-related tests pass
38
+
39
+ ---
40
+
41
+ ## Verification
42
+
43
+ - [ ] Only one storage read per confirm call
44
+ - [ ] All action types still handled correctly
45
+ - [ ] All confirm/deny tests pass
46
+ - [ ] TypeScript compiles without errors
47
+
48
+ ---
49
+
50
+ ## Expected Output
51
+
52
+ **Files Modified**:
53
+ - `src/tools/confirm.ts`
@@ -0,0 +1,52 @@
1
+ # Task 84: Convert Dynamic Imports to Static in server-factory
2
+
3
+ **Milestone**: M18 - Performance Tuning
4
+ **Estimated Time**: 0.5 hours
5
+ **Dependencies**: None
6
+ **Status**: Not Started
7
+
8
+ ---
9
+
10
+ ## Objective
11
+
12
+ Replace dynamic `import()` calls for ghost-config and access-control modules in `server-factory.ts` with static top-level imports to eliminate async module resolution overhead on the hot path.
13
+
14
+ ---
15
+
16
+ ## Context
17
+
18
+ `src/server-factory.ts` lines 177-179 use `await import(...)` for `ghost-config.service.js` and `access-control.js` even though both modules are statically available. Dynamic imports add unnecessary microtask overhead on every server-factory instantiation with ghost mode.
19
+
20
+ ---
21
+
22
+ ## Steps
23
+
24
+ ### 1. Move imports to top level
25
+
26
+ **File**: `src/server-factory.ts`
27
+
28
+ Add static imports at the top:
29
+ ```typescript
30
+ import { getGhostConfig } from './services/ghost-config.service.js';
31
+ import { resolveAccessorTrustLevel } from './services/access-control.js';
32
+ ```
33
+
34
+ Remove the dynamic imports inside the `if (options.ghostMode)` block.
35
+
36
+ ### 2. Verify tests pass
37
+
38
+ ---
39
+
40
+ ## Verification
41
+
42
+ - [ ] No dynamic imports for ghost-config or access-control
43
+ - [ ] Ghost mode still works correctly
44
+ - [ ] All server-factory tests pass
45
+ - [ ] TypeScript compiles without errors
46
+
47
+ ---
48
+
49
+ ## Expected Output
50
+
51
+ **Files Modified**:
52
+ - `src/server-factory.ts`
@@ -17,9 +17,11 @@ declare const coreLogger: Logger;
17
17
  declare const tokenService: ConfirmationTokenService;
18
18
  declare const preferencesService: PreferencesDatabaseService;
19
19
  /**
20
- * Create core services scoped to a specific user.
20
+ * Create (or return cached) core services scoped to a specific user.
21
21
  * Call after databases have been initialized (initWeaviateClient + initFirestore).
22
22
  */
23
23
  export declare function createCoreServices(userId: string): CoreServices;
24
+ /** Clear the core services cache (for tests or forced refresh) */
25
+ export declare function invalidateCoreServicesCache(): void;
24
26
  export { coreLogger, tokenService, preferencesService };
25
27
  //# sourceMappingURL=core-services.d.ts.map