History

start phase 1

Julius Marminge committed 8 months ago

Commit fefea0b1 parent 6954d1b16 files · +625 −4904Browse files

Unified · Split

16 files
  1. .plans/16-pr89-review-remediation-phases.md +6 −1
  2. .plans/16a-pr89-phase0-canonical-triage.json +0 −3694
  3. .plans/16a-pr89-phase0-canonical-triage.md +0 −201
  4. .plans/16b-pr89-architecture-validity-audit.json +0 −790
  5. .plans/16b-pr89-architecture-validity-audit.md +0 −125
  6. .plans/16c-pr89-remediation-checklist.md +542 −0
  7. apps/server/integration/orchestrationEngine.integration.test.ts +1 −1
  8. apps/server/src/checkpointing/Layers/CheckpointDiffQuery.test.ts +1 −1
  9. apps/server/src/checkpointing/Layers/CheckpointDiffQuery.ts +5 −28
  10. apps/server/src/checkpointing/Refs.ts +0 −10
  11. apps/server/src/checkpointing/Utils.ts +36 −0
  12. apps/server/src/orchestration/Layers/CheckpointReactor.test.ts +25 −16
  13. apps/server/src/orchestration/Layers/CheckpointReactor.ts +4 −23
  14. apps/server/src/orchestration/Layers/ProviderRuntimeIngestion.ts +1 −8
  15. apps/server/src/wsServer.ts +3 −2
  16. apps/web/src/wsTransport.ts +1 −4
.plans/16-pr89-review-remediation-phases.md+6−1
@@ -1,5 +1,10 @@
11 # PR #89 Review Remediation Plan (Phased)
22
3+## How To Use These Files
4+
5+- Working checklist with updateable status per item (single source of truth): `.plans/16c-pr89-remediation-checklist.md`
6+- This file (`16-pr89-review-remediation-phases.md`): phase strategy and grouping.
7+
38 ## Scope
49
510 - Source: GitHub review comments on PR #89 (`Add server-side orchestration engine with event sourcing`).
@@ -14,7 +19,7 @@ · 8 unmodified lines
1419
1520 ## Phase 0: Canonical Triage Lock
1621
17−- Create a single tracking checklist for the 74 unique actionable findings.
22+- Create a single tracking checklist for the 53 currently actionable findings.
1823 - Map every duplicate thread to its canonical item.
1924 - Mark invalid/false-positive items with explicit rationale.
2025
.plans/16a-pr89-phase0-canonical-triage.json+0−3694
@@ -1,3694 +0,0 @@
1−{
2− "pull_request": {
3− "number": 89,
4− "url": "https://github.com/pingdotgg/t3-code/pull/89",
5− "title": "Add server-side orchestration engine with event sourcing",
6− "state": "OPEN",
7− "owner": "pingdotgg",
8− "repo": "t3-code"
9− },
10− "phase0_generated_at": "2026-02-26T02:49:21.091145Z",
11− "summary": {
12− "total_threads": 185,
13− "actionable_canonical": 53,
14− "actionable_duplicates": 24,
15− "filtered_outdated": 94,
16− "filtered_resolved": 6,
17− "filtered_invalid": 8
18− },
19− "canonical_items": [
20− {
21− "canonical_id": "C001",
22− "area": "Event ordering and state consistency",
23− "title": "Non-atomic event appending can corrupt state on retry. If an error occurs mid-loop (lines 96-102) after some events are persisted but before the receipt is written, the command appears to fail. A retry generates new UUIDs via `crypto.randomUUID()` in the decider, appending duplicate events. Consider wrapping the loop in a transaction or using deterministic event IDs derived from `commandId`. <details> <summary>\ud83d\ude80 Reply \"<strong>fix it for me</strong>\" or copy this <strong>AI Prompt</strong> for your agent:</summary>",
24− "severity": "High",
25− "path": "apps/server/src/orchestration/Layers/OrchestrationEngine.ts",
26− "line": 96,
27− "thread_ids": [
28− "PRRT_kwDORLtfbc5wzp4T"
29− ],
30− "thread_indexes": [
31− 169
32− ],
33− "duplicate_count": 0,
34− "authors": [
35− "macroscopeapp"
36− ]
37− },
38− {
39− "canonical_id": "C002",
40− "area": "Runtime resilience and failure handling",
41− "title": "A dispatch error in `processEvent` will terminate the `Effect.forever` loop, permanently halting event ingestion. Consider adding error recovery (e.g., `Effect.catchAll` with logging) around `processEvent` so failures don't kill the fiber.",
42− "severity": "High",
43− "path": "apps/server/src/orchestration/Layers/ProviderRuntimeIngestion.ts",
44− "line": 333,
45− "thread_ids": [
46− "PRRT_kwDORLtfbc5wj4cH",
47− "PRRT_kwDORLtfbc5wnWwF",
48− "PRRT_kwDORLtfbc5wyTaP",
49− "PRRT_kwDORLtfbc5wzliw",
50− "PRRT_kwDORLtfbc5w0_g3",
51− "PRRT_kwDORLtfbc5w1HGT"
52− ],
53− "thread_indexes": [
54− 119,
55− 146,
56− 158,
57− 163,
58− 170,
59− 182
60− ],
61− "duplicate_count": 5,
62− "authors": [
63− "cursor",
64− "macroscopeapp"
65− ]
66− },
67− {
68− "canonical_id": "C003",
69− "area": "WebSocket robustness",
70− "title": "Consider attaching a no-op error listener before `socket.write` (e.g., `socket.on('error', () => {})`) to prevent an unhandled `EPIPE`/`ECONNRESET` from crashing the process if the client disconnects mid-handshake.",
71− "severity": "High",
72− "path": "apps/server/src/wsServer.ts",
73− "line": 75,
74− "thread_ids": [
75− "PRRT_kwDORLtfbc5v-cf4"
76− ],
77− "thread_indexes": [
78− 72
79− ],
80− "duplicate_count": 0,
81− "authors": [
82− "macroscopeapp"
83− ]
84− },
85− {
86− "canonical_id": "C006",
87− "area": "Build/runtime portability",
88− "title": "Build script runs TypeScript file with bare node",
89− "severity": "Medium",
90− "path": "apps/server/package.json",
91− "line": 14,
92− "thread_ids": [
93− "PRRT_kwDORLtfbc5wxsO-"
94− ],
95− "thread_indexes": [
96− 150
97− ],
98− "duplicate_count": 0,
99− "authors": [
100− "cursor"
101− ]
102− },
103− {
104− "canonical_id": "C007",
105− "area": "Build/runtime portability",
106− "title": "Build script uses `node` to run `.ts` file directly",
107− "severity": "Medium",
108− "path": "apps/server/package.json",
109− "line": 14,
110− "thread_ids": [
111− "PRRT_kwDORLtfbc5wiLNS",
112− "PRRT_kwDORLtfbc5wj5fl"
113− ],
114− "thread_indexes": [
115− 106,
116− 123
117− ],
118− "duplicate_count": 1,
119− "authors": [
120− "cursor"
121− ]
122− },
123− {
124− "canonical_id": "C008",
125− "area": "Checkpointing correctness",
126− "title": "Inconsistent input normalization across CheckpointStore methods",
127− "severity": "Medium",
128− "path": "apps/server/src/checkpointing/Layers/CheckpointStore.ts",
129− "line": 94,
130− "thread_ids": [
131− "PRRT_kwDORLtfbc5widJw",
132− "PRRT_kwDORLtfbc5wnWv_",
133− "PRRT_kwDORLtfbc5w0_g7",
134− "PRRT_kwDORLtfbc5w1C36"
135− ],
136− "thread_indexes": [
137− 112,
138− 145,
139− 172,
140− 176
141− ],
142− "duplicate_count": 3,
143− "authors": [
144− "cursor"
145− ]
146− },
147− {
148− "canonical_id": "C009",
149− "area": "Edge-case parsing/platform behavior",
150− "title": "Git's braced rename syntax (e.g., `src/{old => new}/file.ts`) isn't handled correctly. The current slice after ` => ` produces invalid paths like `new}/file.ts`. Consider expanding the braces to construct the full destination path. <details> <summary>\ud83d\ude80 Reply \"<strong>fix it for me</strong>\" or copy this <strong>AI Prompt</strong> for your agent:</summary>",
151− "severity": "Medium",
152− "path": "apps/server/src/git/Layers/GitCore.ts",
153− "line": 41,
154− "thread_ids": [
155− "PRRT_kwDORLtfbc5w1CxT"
156− ],
157− "thread_indexes": [
158− 175
159− ],
160− "duplicate_count": 0,
161− "authors": [
162− "macroscopeapp"
163− ]
164− },
165− {
166− "canonical_id": "C010",
167− "area": "Edge-case parsing/platform behavior",
168− "title": "`loadCustomKeybindingsConfig` fails when the config file doesn't exist, which is expected for new users. Consider catching `ENOENT` and returning an empty array instead. <details> <summary>\ud83d\ude80 Reply \"<strong>fix it for me</strong>\" or copy this <strong>AI Prompt</strong> for your agent:</summary>",
169− "severity": "Medium",
170− "path": "apps/server/src/keybindings.ts",
171− "line": 418,
172− "thread_ids": [
173− "PRRT_kwDORLtfbc5wxvIJ"
174− ],
175− "thread_indexes": [
176− 155
177− ],
178− "duplicate_count": 0,
179− "authors": [
180− "macroscopeapp"
181− ]
182− },
183− {
184− "canonical_id": "C011",
185− "area": "Other",
186− "title": "Template literal `${cause}` throws if `cause` is a `Symbol`. Consider using `String(cause)` instead.",
187− "severity": "Medium",
188− "path": "apps/server/src/orchestration/Errors.ts",
189− "line": 117,
190− "thread_ids": [
191− "PRRT_kwDORLtfbc5wBFv4"
192− ],
193− "thread_indexes": [
194− 86
195− ],
196− "duplicate_count": 0,
197− "authors": [
198− "macroscopeapp"
199− ]
200− },
201− {
202− "canonical_id": "C012",
203− "area": "Runtime resilience and failure handling",
204− "title": "Forked revert dispatch risks read model inconsistency",
205− "severity": "Medium",
206− "path": "apps/server/src/orchestration/Layers/CheckpointReactor.ts",
207− "line": 542,
208− "thread_ids": [
209− "PRRT_kwDORLtfbc5whszW",
210− "PRRT_kwDORLtfbc5wyTaS",
211− "PRRT_kwDORLtfbc5wzli0",
212− "PRRT_kwDORLtfbc5w0_g4",
213− "PRRT_kwDORLtfbc5w1HGX"
214− ],
215− "thread_indexes": [
216− 92,
217− 159,
218− 165,
219− 171,
220− 184
221− ],
222− "duplicate_count": 4,
223− "authors": [
224− "cursor"
225− ]
226− },
227− {
228− "canonical_id": "C013",
229− "area": "Event ordering and state consistency",
230− "title": "If `projectionPipeline.projectEvent` fails after `eventStore.append` succeeds, the event is persisted but `readModel` isn't updated, causing desync. Consider updating the in-memory `readModel` immediately after append (before the external projection), so local state stays consistent regardless of downstream failures.",
231− "severity": "Medium",
232− "path": "apps/server/src/orchestration/Layers/OrchestrationEngine.ts",
233− "line": 99,
234− "thread_ids": [
235− "PRRT_kwDORLtfbc5whtrM"
236− ],
237− "thread_indexes": [
238− 93
239− ],
240− "duplicate_count": 0,
241− "authors": [
242− "macroscopeapp"
243− ]
244− },
245− {
246− "canonical_id": "C014",
247− "area": "Event ordering and state consistency",
248− "title": "Engine error handler catches all errors including non-invariant ones",
249− "severity": "Medium",
250− "path": "apps/server/src/orchestration/Layers/OrchestrationEngine.ts",
251− "line": 144,
252− "thread_ids": [
253− "PRRT_kwDORLtfbc5wkPaJ"
254− ],
255− "thread_indexes": [
256− 130
257− ],
258− "duplicate_count": 0,
259− "authors": [
260− "cursor"
261− ]
262− },
263− {
264− "canonical_id": "C015",
265− "area": "Event ordering and state consistency",
266− "title": "The gap-filling fallback logic can retain messages from turns that are about to be deleted, causing foreign key violations. Consider removing the fallback logic entirely, or filtering `fallbackUserMessages` and `fallbackAssistantMessages` to only include messages whose `turnId` is in `retainedTurnIds`. <details> <summary>\ud83d\ude80 Reply \"<strong>fix it for me</strong>\" or copy this <strong>AI Prompt</strong> for your agent:</summary>",
267− "severity": "Medium",
268− "path": "apps/server/src/orchestration/Layers/ProjectionPipeline.ts",
269− "line": 99,
270− "thread_ids": [
271− "PRRT_kwDORLtfbc5whxJO"
272− ],
273− "thread_indexes": [
274− 101
275− ],
276− "duplicate_count": 0,
277− "authors": [
278− "macroscopeapp"
279− ]
280− },
281− {
282− "canonical_id": "C016",
283− "area": "Event ordering and state consistency",
284− "title": "The in-memory `pendingTurnStartByThreadId` map isn't restored during bootstrap. If the service restarts after processing `thread.turn-start-requested` but before `thread.session-set`, the `userMessageId` and `startedAt` will be lost since bootstrap resumes *after* the committed sequence. Consider persisting this pending state or processing these two events atomically. <details> <summary>\ud83d\ude80 Reply \"<strong>fix it for me</strong>\" or copy this <strong>AI Prompt</strong> for your agent:</summary>",
285− "severity": "Medium",
286− "path": "apps/server/src/orchestration/Layers/ProjectionPipeline.ts",
287− "line": 490,
288− "thread_ids": [
289− "PRRT_kwDORLtfbc5wxvH8"
290− ],
291− "thread_indexes": [
292− 151
293− ],
294− "duplicate_count": 0,
295− "authors": [
296− "macroscopeapp"
297− ]
298− },
299− {
300− "canonical_id": "C017",
301− "area": "Checkpointing correctness",
302− "title": "`REQUIRED_SNAPSHOT_PROJECTORS` includes `pending-approvals` and `thread-turns`, but `getSnapshot` doesn't query their data. If these projectors lag behind, the returned `snapshotSequence` will be lower than what the included data actually reflects, causing clients to replay already-applied events. Consider filtering `REQUIRED_SNAPSHOT_PROJECTORS` to only include projectors whose data is actually fetched in the snapshot. <details> <summary>\ud83d\ude80 Reply \"<strong>fix it for me</strong>\" or copy this <strong>AI Prompt</strong> for your agent:</summary>",
303− "severity": "Medium",
304− "path": "apps/server/src/orchestration/Layers/ProjectionSnapshotQuery.ts",
305− "line": 71,
306− "thread_ids": [
307− "PRRT_kwDORLtfbc5wiLhQ"
308− ],
309− "thread_indexes": [
310− 107
311− ],
312− "duplicate_count": 0,
313− "authors": [
314− "macroscopeapp"
315− ]
316− },
317− {
318− "canonical_id": "C018",
319− "area": "Memory/resource growth",
320− "title": "Unbounded memory growth in turn start deduplication set",
321− "severity": "Medium",
322− "path": "apps/server/src/orchestration/Layers/ProviderCommandReactor.ts",
323− "line": 84,
324− "thread_ids": [
325− "PRRT_kwDORLtfbc5whszQ",
326− "PRRT_kwDORLtfbc5wl2A8",
327− "PRRT_kwDORLtfbc5wyTaT",
328− "PRRT_kwDORLtfbc5wzliz",
329− "PRRT_kwDORLtfbc5w0_g-",
330− "PRRT_kwDORLtfbc5w1HGW"
331− ],
332− "thread_indexes": [
333− 90,
334− 140,
335− 160,
336− 164,
337− 173,
338− 183
339− ],
340− "duplicate_count": 5,
341− "authors": [
342− "cursor",
343− "macroscopeapp"
344− ]
345− },
346− {
347− "canonical_id": "C019",
348− "area": "Runtime resilience and failure handling",
349− "title": "ProviderRuntimeIngestion processes events for wrong thread on race",
350− "severity": "Medium",
351− "path": "apps/server/src/orchestration/Layers/ProviderRuntimeIngestion.ts",
352− "line": 178,
353− "thread_ids": [
354− "PRRT_kwDORLtfbc5wkPaL"
355− ],
356− "thread_indexes": [
357− 131
358− ],
359− "duplicate_count": 0,
360− "authors": [
361− "cursor"
362− ]
363− },
364− {
365− "canonical_id": "C020",
366− "area": "Runtime resilience and failure handling",
367− "title": "On `message.completed`, the message ID is added to the set and `thread.message.assistant.complete` is dispatched. On `turn.completed`, the same set is iterated and `thread.message.assistant.complete` is dispatched again for each ID\u2014including already-completed ones. Consider removing message IDs from the set after dispatching on `message.completed`, or filtering out already-completed IDs before the `turn.completed` loop.",
368− "severity": "Medium",
369− "path": "apps/server/src/orchestration/Layers/ProviderRuntimeIngestion.ts",
370− "line": 266,
371− "thread_ids": [
372− "PRRT_kwDORLtfbc5w1GPr"
373− ],
374− "thread_indexes": [
375− 181
376− ],
377− "duplicate_count": 0,
378− "authors": [
379− "macroscopeapp"
380− ]
381− },
382− {
383− "canonical_id": "C022",
384− "area": "Edge-case parsing/platform behavior",
385− "title": "Fish shell outputs `$PATH` as space-separated, not colon-separated. Consider checking if the shell is fish and using `string join : $PATH` instead, or validating the result contains colons before assigning.",
386− "severity": "Medium",
387− "path": "apps/server/src/os-jank.ts",
388− "line": 10,
389− "thread_ids": [
390− "PRRT_kwDORLtfbc5wkRZM"
391− ],
392− "thread_indexes": [
393− 133
394− ],
395− "duplicate_count": 0,
396− "authors": [
397− "macroscopeapp"
398− ]
399− },
400− {
401− "canonical_id": "C023",
402− "area": "Edge-case parsing/platform behavior",
403− "title": "Using `-il` flags causes the shell to source profile scripts that may print banners or other text, polluting the captured `PATH`. Consider using `-lc` (login only, non-interactive) to reduce unwanted output.",
404− "severity": "Medium",
405− "path": "apps/server/src/os-jank.ts",
406− "line": 10,
407− "thread_ids": [
408− "PRRT_kwDORLtfbc5wj4cM"
409− ],
410− "thread_indexes": [
411− 121
412− ],
413− "duplicate_count": 0,
414− "authors": [
415− "macroscopeapp"
416− ]
417− },
418− {
419− "canonical_id": "C024",
420− "area": "Other",
421− "title": "In `executeUnprepared`, preparing outside an effect and not closing the statement can cause uncaught errors and leaks. Suggest wrapping with `Effect.acquireUseRelease`: prepare in acquire (error-safe) and `finalize` in release.",
422− "severity": "Medium",
423− "path": "apps/server/src/persistence/NodeSqliteClient.ts",
424− "line": 145,
425− "thread_ids": [
426− "PRRT_kwDORLtfbc5whxX9"
427− ],
428− "thread_indexes": [
429− 103
430− ],
431− "duplicate_count": 0,
432− "authors": [
433− "macroscopeapp"
434− ]
435− },
436− {
437− "canonical_id": "C026",
438− "area": "WebSocket robustness",
439− "title": "Consider adding `.catch(() => {})` after `Effect.runPromise(handleMessage(ws, raw))` to prevent unhandled rejections from crashing the server if `encodeResponse` or setup logic fails.",
440− "severity": "Medium",
441− "path": "apps/server/src/wsServer.ts",
442− "line": 545,
443− "thread_ids": [
444− "PRRT_kwDORLtfbc5wj4cE"
445− ],
446− "thread_indexes": [
447− 118
448− ],
449− "duplicate_count": 0,
450− "authors": [
451− "macroscopeapp"
452− ]
453− },
454− {
455− "canonical_id": "C027",
456− "area": "Runtime resilience and failure handling",
457− "title": "WS message handler can cause unhandled promise rejection",
458− "severity": "Medium",
459− "path": "apps/server/src/wsServer.ts",
460− "line": 545,
461− "thread_ids": [
462− "PRRT_kwDORLtfbc5wyTaW",
463− "PRRT_kwDORLtfbc5wzli3"
464− ],
465− "thread_indexes": [
466− 161,
467− 167
468− ],
469− "duplicate_count": 1,
470− "authors": [
471− "cursor"
472− ]
473− },
474− {
475− "canonical_id": "C028",
476− "area": "Other",
477− "title": "Branch sync dispatches both server and stale local update",
478− "severity": "Medium",
479− "path": "apps/web/src/components/BranchToolbar.tsx",
480− "line": 102,
481− "thread_ids": [
482− "PRRT_kwDORLtfbc5v-XCu"
483− ],
484− "thread_indexes": [
485− 60
486− ],
487− "duplicate_count": 0,
488− "authors": [
489− "cursor"
490− ]
491− },
492− {
493− "canonical_id": "C029",
494− "area": "Edge-case parsing/platform behavior",
495− "title": "`parseFileUrlHref` already decodes the path (line 46), but `safeDecode` is called again here, corrupting filenames containing `%` sequences. Consider skipping the decode when `fileUrlTarget` is non-null.",
496− "severity": "Medium",
497− "path": "apps/web/src/markdown-links.ts",
498− "line": 105,
499− "thread_ids": [
500− "PRRT_kwDORLtfbc5wnVsU"
501− ],
502− "thread_indexes": [
503− 143
504− ],
505− "duplicate_count": 0,
506− "authors": [
507− "macroscopeapp"
508− ]
509− },
510− {
511− "canonical_id": "C030",
512− "area": "Edge-case parsing/platform behavior",
513− "title": "`EXTERNAL_SCHEME_PATTERN` matches `script.ts:10` as a scheme because `.ts:` looks like `scheme:`. Consider requiring `://` after the colon, or checking that what follows the colon is not just digits. <details> <summary>\ud83d\ude80 Reply \"<strong>fix it for me</strong>\" or copy this <strong>AI Prompt</strong> for your agent:</summary>",
514− "severity": "Medium",
515− "path": "apps/web/src/markdown-links.ts",
516− "line": 111,
517− "thread_ids": [
518− "PRRT_kwDORLtfbc5wnVsK"
519− ],
520− "thread_indexes": [
521− 142
522− ],
523− "duplicate_count": 0,
524− "authors": [
525− "macroscopeapp"
526− ]
527− },
528− {
529− "canonical_id": "C032",
530− "area": "Other",
531− "title": "Dummy workflow marker accidentally committed to docs",
532− "severity": "Low",
533− "path": "AGENTS.md",
534− "line": 45,
535− "thread_ids": [
536− "PRRT_kwDORLtfbc5wlYgj",
537− "PRRT_kwDORLtfbc5w1C4H"
538− ],
539− "thread_indexes": [
540− 137,
541− 179
542− ],
543− "duplicate_count": 1,
544− "authors": [
545− "cursor"
546− ]
547− },
548− {
549− "canonical_id": "C033",
550− "area": "Checkpointing correctness",
551− "title": "Three error classes defined but never instantiated anywhere",
552− "severity": "Low",
553− "path": "apps/server/src/checkpointing/Errors.ts",
554− "line": 51,
555− "thread_ids": [
556− "PRRT_kwDORLtfbc5wlYgo"
557− ],
558− "thread_indexes": [
559− 138
560− ],
561− "duplicate_count": 0,
562− "authors": [
563− "cursor"
564− ]
565− },
566− {
567− "canonical_id": "C034",
568− "area": "Checkpointing correctness",
569− "title": "Redundant `CheckpointInvariantError` in `CheckpointServiceError` union type",
570− "severity": "Low",
571− "path": "apps/server/src/checkpointing/Errors.ts",
572− "line": 79,
573− "thread_ids": [
574− "PRRT_kwDORLtfbc5wj5fn"
575− ],
576− "thread_indexes": [
577− 124
578− ],
579− "duplicate_count": 0,
580− "authors": [
581− "cursor"
582− ]
583− },
584− {
585− "canonical_id": "C035",
586− "area": "Checkpointing correctness",
587− "title": "Redundant error type in CheckpointServiceError union definition",
588− "severity": "Low",
589− "path": "apps/server/src/checkpointing/Errors.ts",
590− "line": 79,
591− "thread_ids": [
592− "PRRT_kwDORLtfbc5wlYgs",
593− "PRRT_kwDORLtfbc5wxsO6",
594− "PRRT_kwDORLtfbc5w1C4B"
595− ],
596− "thread_indexes": [
597− 139,
598− 149,
599− 178
600− ],
601− "duplicate_count": 2,
602− "authors": [
603− "cursor"
604− ]
605− },
606− {
607− "canonical_id": "C037",
608− "area": "Other",
609− "title": "`Effect.callback` should return a cleanup function to close the server(s) on fiber interruption. Without it, the `Net.Server` handles keep the process alive and leak the port if the effect is cancelled. <details> <summary>\ud83d\ude80 Reply \"<strong>fix it for me</strong>\" or copy this <strong>AI Prompt</strong> for your agent:</summary>",
610− "severity": "Low",
611− "path": "apps/server/src/config.ts",
612− "line": 41,
613− "thread_ids": [
614− "PRRT_kwDORLtfbc5wj4cO"
615− ],
616− "thread_indexes": [
617− 122
618− ],
619− "duplicate_count": 0,
620− "authors": [
621− "macroscopeapp"
622− ]
623− },
624− {
625− "canonical_id": "C038",
626− "area": "Edge-case parsing/platform behavior",
627− "title": "Multi-byte UTF-8 characters split across chunks will be corrupted when decoding each chunk separately. Consider accumulating all chunks first, then decoding once, or use `TextDecoder` with `stream: true`. <details> <summary>\ud83d\ude80 Reply \"<strong>fix it for me</strong>\" or copy this <strong>AI Prompt</strong> for your agent:</summary>",
628− "severity": "Low",
629− "path": "apps/server/src/git/Layers/CodexTextGeneration.ts",
630− "line": 136,
631− "thread_ids": [
632− "PRRT_kwDORLtfbc5w1GPo"
633− ],
634− "thread_indexes": [
635− 180
636− ],
637− "duplicate_count": 0,
638− "authors": [
639− "macroscopeapp"
640− ]
641− },
642− {
643− "canonical_id": "C039",
644− "area": "Edge-case parsing/platform behavior",
645− "title": "The `+` key can be parsed (via trailing `+` handling) but cannot be encoded because `shortcut.key.includes(\"+\")` returns true for the literal `+` key. Consider checking `shortcut.key === \"+\"` separately and encoding it as `\"space\"` style (e.g., a special token), or adjusting the condition to allow the single `+` character. <details> <summary>\ud83d\ude80 Reply \"<strong>fix it for me</strong>\" or copy this <strong>AI Prompt</strong> for your agent:</summary>",
646− "severity": "Low",
647− "path": "apps/server/src/keybindings.ts",
648− "line": 352,
649− "thread_ids": [
650− "PRRT_kwDORLtfbc5wxvIB"
651− ],
652− "thread_indexes": [
653− 154
654− ],
655− "duplicate_count": 0,
656− "authors": [
657− "macroscopeapp"
658− ]
659− },
660− {
661− "canonical_id": "C040",
662− "area": "Edge-case parsing/platform behavior",
663− "title": "`upsertKeybindingRule` has a race condition: concurrent calls read the same file state, then the last write overwrites earlier changes. Consider wrapping the read-modify-write sequence with `Effect.Semaphore` to serialize access. <details> <summary>\ud83d\ude80 Reply \"<strong>fix it for me</strong>\" or copy this <strong>AI Prompt</strong> for your agent:</summary>",
664− "severity": "Low",
665− "path": "apps/server/src/keybindings.ts",
666− "line": 488,
667− "thread_ids": [
668− "PRRT_kwDORLtfbc5wxvIA"
669− ],
670− "thread_indexes": [
671− 153
672− ],
673− "duplicate_count": 0,
674− "authors": [
675− "macroscopeapp"
676− ]
677− },
678− {
679− "canonical_id": "C041",
680− "area": "Other",
681− "title": "Template literal interpolation throws `TypeError` if `cause` is a `Symbol`. Consider using `String(cause)` for safe coercion.",
682− "severity": "Low",
683− "path": "apps/server/src/orchestration/Errors.ts",
684− "line": 126,
685− "thread_ids": [
686− "PRRT_kwDORLtfbc5wBFWs"
687− ],
688− "thread_indexes": [
689− 85
690− ],
691− "duplicate_count": 0,
692− "authors": [
693− "macroscopeapp"
694− ]
695− },
696− {
697− "canonical_id": "C042",
698− "area": "Runtime resilience and failure handling",
699− "title": "Duplicated `resolveThreadWorkspaceCwd` across three files",
700− "severity": "Low",
701− "path": "apps/server/src/orchestration/Layers/CheckpointReactor.ts",
702− "line": 62,
703− "thread_ids": [
704− "PRRT_kwDORLtfbc5wzli2"
705− ],
706− "thread_indexes": [
707− 166
708− ],
709− "duplicate_count": 0,
710− "authors": [
711− "cursor"
712− ]
713− },
714− {
715− "canonical_id": "C043",
716− "area": "Runtime resilience and failure handling",
717− "title": "Duplicated workspace CWD resolution logic across reactor modules",
718− "severity": "Low",
719− "path": "apps/server/src/orchestration/Layers/CheckpointReactor.ts",
720− "line": 62,
721− "thread_ids": [
722− "PRRT_kwDORLtfbc5wnWwM",
723− "PRRT_kwDORLtfbc5w1C3-",
724− "PRRT_kwDORLtfbc5w1HGZ"
725− ],
726− "thread_indexes": [
727− 147,
728− 177,
729− 185
730− ],
731− "duplicate_count": 2,
732− "authors": [
733− "cursor"
734− ]
735− },
736− {
737− "canonical_id": "C044",
738− "area": "Runtime resilience and failure handling",
739− "title": "Checkpoint reactor swallows diff errors silently for `turn.completed`",
740− "severity": "Low",
741− "path": "apps/server/src/orchestration/Layers/CheckpointReactor.ts",
742− "line": 274,
743− "thread_ids": [
744− "PRRT_kwDORLtfbc5wkPaO"
745− ],
746− "thread_indexes": [
747− 132
748− ],
749− "duplicate_count": 0,
750− "authors": [
751− "cursor"
752− ]
753− },
754− {
755− "canonical_id": "C045",
756− "area": "Runtime resilience and failure handling",
757− "title": "`truncateDetail` slices to `limit - 1` then appends `\"...\"` (3 chars), producing strings of length `limit + 2`. Consider slicing to `limit - 3` instead. <details> <summary>\ud83d\ude80 Reply \"<strong>fix it for me</strong>\" or copy this <strong>AI Prompt</strong> for your agent:</summary>",
758− "severity": "Low",
759− "path": "apps/server/src/orchestration/Layers/ProviderRuntimeIngestion.ts",
760− "line": 29,
761− "thread_ids": [
762− "PRRT_kwDORLtfbc5wzp4R"
763− ],
764− "thread_indexes": [
765− 168
766− ],
767− "duplicate_count": 0,
768− "authors": [
769− "macroscopeapp"
770− ]
771− },
772− {
773− "canonical_id": "C046",
774− "area": "Runtime resilience and failure handling",
775− "title": "`latestMessageIdByTurnKey` is written to but never read, and `clearAssistantMessageIdsForTurn` doesn't clear its entries\u2014only `clearTurnStateForSession` does. Consider removing this map entirely if unused, or clearing it alongside `turnMessageIdsByTurnKey` in `clearAssistantMessageIdsForTurn`. <details> <summary>\ud83d\ude80 Reply \"<strong>fix it for me</strong>\" or copy this <strong>AI Prompt</strong> for your agent:</summary>",
776− "severity": "Low",
777− "path": "apps/server/src/orchestration/Layers/ProviderRuntimeIngestion.ts",
778− "line": 133,
779− "thread_ids": [
780− "PRRT_kwDORLtfbc5wxvIQ"
781− ],
782− "thread_indexes": [
783− 156
784− ],
785− "duplicate_count": 0,
786− "authors": [
787− "macroscopeapp"
788− ]
789− },
790− {
791− "canonical_id": "C047",
792− "area": "Other",
793− "title": "`SqlSchema.findOneOption` can produce both SQL errors and decode errors, but `mapError` wraps all as `PersistenceSqlError`. Consider distinguishing `ParseError` from SQL errors and mapping decode failures to `PersistenceDecodeError` instead. <details> <summary>\ud83d\ude80 Reply \"<strong>fix it for me</strong>\" or copy this <strong>AI Prompt</strong> for your agent:</summary>",
794− "severity": "Low",
795− "path": "apps/server/src/persistence/Layers/OrchestrationCommandReceipts.ts",
796− "line": 75,
797− "thread_ids": [
798− "PRRT_kwDORLtfbc5wiaR-"
799− ],
800− "thread_indexes": [
801− 110
802− ],
803− "duplicate_count": 0,
804− "authors": [
805− "macroscopeapp"
806− ]
807− },
808− {
809− "canonical_id": "C048",
810− "area": "Other",
811− "title": "`statement.run()` returns a `RunResult` object, not an array. Casting it to `ReadonlyArray<any>` will cause runtime errors when consumers call array methods. Consider wrapping the result (e.g., `[result]`) or returning a properly typed object.",
812− "severity": "Low",
813− "path": "apps/server/src/persistence/NodeSqliteClient.ts",
814− "line": 99,
815− "thread_ids": [
816− "PRRT_kwDORLtfbc5wio-r"
817− ],
818− "thread_indexes": [
819− 114
820− ],
821− "duplicate_count": 0,
822− "authors": [
823− "macroscopeapp"
824− ]
825− },
826− {
827− "canonical_id": "C049",
828− "area": "Other",
829− "title": "`JSON.stringify(cause)` returns `undefined` for `undefined`, functions, or symbols, violating the `string` return type. Consider coercing the result to a string (e.g., `String(JSON.stringify(cause))`) or adding a fallback.",
830− "severity": "Low",
831− "path": "apps/server/src/provider/Layers/ProviderService.ts",
832− "line": 59,
833− "thread_ids": [
834− "PRRT_kwDORLtfbc5wnVsI"
835− ],
836− "thread_indexes": [
837− 141
838− ],
839− "duplicate_count": 0,
840− "authors": [
841− "macroscopeapp"
842− ]
843− },
844− {
845− "canonical_id": "C050",
846− "area": "Other",
847− "title": "The read-modify-write pattern (`getBySessionId` \u2192 merge \u2192 `upsert`) is susceptible to lost updates under concurrent writes. Consider wrapping in a transaction or adding optimistic concurrency control (e.g., version field) if concurrent session updates are expected. <details> <summary>\ud83d\ude80 Reply \"<strong>fix it for me</strong>\" or copy this <strong>AI Prompt</strong> for your agent:</summary>",
848− "severity": "Low",
849− "path": "apps/server/src/provider/Layers/ProviderSessionDirectory.ts",
850− "line": 94,
851− "thread_ids": [
852− "PRRT_kwDORLtfbc5wiLhY"
853− ],
854− "thread_indexes": [
855− 108
856− ],
857− "duplicate_count": 0,
858− "authors": [
859− "macroscopeapp"
860− ]
861− },
862− {
863− "canonical_id": "C051",
864− "area": "Other",
865− "title": "Using `??` for `providerThreadId` and `adapterKey` makes it impossible to clear these fields by passing `null`, since `null ?? existing` evaluates to `existing`. Consider using explicit `undefined` checks (like `resumeCursor` does) if clearing should be supported. <details> <summary>\ud83d\ude80 Reply \"<strong>fix it for me</strong>\" or copy this <strong>AI Prompt</strong> for your agent:</summary>",
866− "severity": "Low",
867− "path": "apps/server/src/provider/Layers/ProviderSessionDirectory.ts",
868− "line": 119,
869− "thread_ids": [
870− "PRRT_kwDORLtfbc5wxvH9"
871− ],
872− "thread_indexes": [
873− 152
874− ],
875− "duplicate_count": 0,
876− "authors": [
877− "macroscopeapp"
878− ]
879− },
880− {
881− "canonical_id": "C052",
882− "area": "Other",
883− "title": "Race condition: `processHandle` may be `null` when `data` callback fires, since it's assigned after `Bun.spawn` returns. Consider initializing `BunPtyProcess` first, then passing it to the callback to avoid losing initial output. <details> <summary>\ud83d\ude80 Reply \"<strong>fix it for me</strong>\" or copy this <strong>AI Prompt</strong> for your agent:</summary>",
884− "severity": "Low",
885− "path": "apps/server/src/terminal/Layers/BunPTY.ts",
886− "line": 97,
887− "thread_ids": [
888− "PRRT_kwDORLtfbc5w1CxE"
889− ],
890− "thread_indexes": [
891− 174
892− ],
893− "duplicate_count": 0,
894− "authors": [
895− "macroscopeapp"
896− ]
897− },
898− {
899− "canonical_id": "C053",
900− "area": "WebSocket robustness",
901− "title": "Consider using `socket.end(response)` instead of `socket.write(response)` + `socket.destroy()` to ensure the HTTP error response is fully flushed before closing the connection.",
902− "severity": "Low",
903− "path": "apps/server/src/wsServer.ts",
904− "line": 83,
905− "thread_ids": [
906− "PRRT_kwDORLtfbc5v-WPD"
907− ],
908− "thread_indexes": [
909− 57
910− ],
911− "duplicate_count": 0,
912− "authors": [
913− "macroscopeapp"
914− ]
915− },
916− {
917− "canonical_id": "C054",
918− "area": "WebSocket robustness",
919− "title": "When array chunks contain a multi-byte UTF-8 character split across boundaries, decoding each chunk separately produces replacement characters. Consider using `Buffer.concat()` on all chunks before calling `.toString(\"utf8\")`. <details> <summary>\ud83d\ude80 Reply \"<strong>fix it for me</strong>\" or copy this <strong>AI Prompt</strong> for your agent:</summary>",
920− "severity": "Low",
921− "path": "apps/server/src/wsServer.ts",
922− "line": 104,
923− "thread_ids": [
924− "PRRT_kwDORLtfbc5whtrR"
925− ],
926− "thread_indexes": [
927− 96
928− ],
929− "duplicate_count": 0,
930− "authors": [
931− "macroscopeapp"
932− ]
933− },
934− {
935− "canonical_id": "C056",
936− "area": "Other",
937− "title": "When `onOpenChange` is provided without `open`, the internal `_open` state never updates because `setOpenProp` takes precedence. Consider calling `_setOpen` when `openProp === undefined`, regardless of whether `setOpenProp` exists.",
938− "severity": "Low",
939− "path": "apps/web/src/components/ui/sidebar.tsx",
940− "line": 114,
941− "thread_ids": [
942− "PRRT_kwDORLtfbc5wxvIq"
943− ],
944− "thread_indexes": [
945− 157
946− ],
947− "duplicate_count": 0,
948− "authors": [
949− "macroscopeapp"
950− ]
951− },
952− {
953− "canonical_id": "C057",
954− "area": "Other",
955− "title": "The `resizable` object is recreated on every render, causing `SidebarRail`'s `useEffect` to repeatedly read localStorage and update the DOM. Consider memoizing the object with `useMemo`. <details> <summary>\ud83d\ude80 Reply \"<strong>fix it for me</strong>\" or copy this <strong>AI Prompt</strong> for your agent:</summary>",
956− "severity": "Low",
957− "path": "apps/web/src/routes/_chat.$threadId.tsx",
958− "line": 105,
959− "thread_ids": [
960− "PRRT_kwDORLtfbc5wyWz4"
961− ],
962− "thread_indexes": [
963− 162
964− ],
965− "duplicate_count": 0,
966− "authors": [
967− "macroscopeapp"
968− ]
969− },
970− {
971− "canonical_id": "C058",
972− "area": "Other",
973− "title": "When `localStorage.getItem()` returns `null`, `Number(null)` evaluates to `0`, which passes `Number.isFinite(0)`. This causes the sidebar to clamp to `minWidth` on first load, overriding the `DIFF_INLINE_DEFAULT_WIDTH` CSS clamp. Consider checking for `null` or empty string before parsing, e.g. guard with `storedWidth === null || storedWidth === ''`. <details> <summary>\ud83d\ude80 Reply \"<strong>fix it for me</strong>\" or copy this <strong>AI Prompt</strong> for your agent:</summary>",
974− "severity": "Low",
975− "path": "apps/web/src/routes/_chat.$threadId.tsx",
976− "line": 122,
977− "thread_ids": [
978− "PRRT_kwDORLtfbc5wnVsX"
979− ],
980− "thread_indexes": [
981− 144
982− ],
983− "duplicate_count": 0,
984− "authors": [
985− "macroscopeapp"
986− ]
987− },
988− {
989− "canonical_id": "C059",
990− "area": "WebSocket robustness",
991− "title": "Suggestion: don\u2019t spread `params` into `body`; it can override `_tag` and mishandle non-object values. Keep `_tag` separate and nest `params` under a single key (e.g., `data`), or validate `params` is a plain object.",
992− "severity": "Low",
993− "path": "apps/web/src/wsTransport.ts",
994− "line": 59,
995− "thread_ids": [
996− "PRRT_kwDORLtfbc5whtrN"
997− ],
998− "thread_indexes": [
999− 94
1000− ],
1001− "duplicate_count": 0,
1002− "authors": [
1003− "macroscopeapp"
1004− ]
1005− },
1006− {
1007− "canonical_id": "C060",
1008− "area": "Other",
1009− "title": "`defaultModel` should be `Schema.optional(Schema.NullOr(Schema.String))` to allow clearing the value. Currently there's no way to reset it to `null` since omitting means \"no change\" in patch semantics. <details> <summary>\ud83d\ude80 Reply \"<strong>fix it for me</strong>\" or copy this <strong>AI Prompt</strong> for your agent:</summary>",
1010− "severity": "Low",
1011− "path": "packages/contracts/src/orchestration.ts",
1012− "line": 253,
1013− "thread_ids": [
1014− "PRRT_kwDORLtfbc5whxJC"
1015− ],
1016− "thread_indexes": [
1017− 100
1018− ],
1019− "duplicate_count": 0,
1020− "authors": [
1021− "macroscopeapp"
1022− ]
1023− }
1024− ],
1025− "threads": [
1026− {
1027− "index": 1,
1028− "thread_id": "PRRT_kwDORLtfbc5v8_mw",
1029− "path": "apps/server/src/wsServer.ts",
1030− "line": null,
1031− "is_outdated": true,
1032− "is_resolved": false,
1033− "author": "greptile-apps",
1034− "title": "calls can execute concurrently for the same thread, causing out-of-order event processing. If two provider events arrive rapidly (e.g., textDelta then turn/completed), the commands may reach the queue in unpredictable order. While the Effect queue serializes command processing, the async IIFE allows the event handler to return immediately and process the next provider event before previous dispatches complete. This can cause logical inconsistencies in message streaming or session state updates. Consider wrapping the entire event handler in a per-thread mutex or processing provider events sequentially.",
1035− "severity": "Unknown",
1036− "has_false_positive_signal": false,
1037− "phase0_status": "filtered_outdated",
1038− "phase0_reason": "Thread is flagged outdated by GitHub diff context."
1039− },
1040− {
1041− "index": 2,
1042− "thread_id": "PRRT_kwDORLtfbc5v8_m4",
1043− "path": "apps/server/src/wsServer.ts",
1044− "line": null,
1045− "is_outdated": true,
1046− "is_resolved": false,
1047− "author": "greptile-apps",
1048− "title": "returns the current in-memory read model, but it may not reflect recently dispatched commands that are still queued. If a provider event arrives before the previous command's read model update propagates, `thread` lookup may fail or use stale data. This is especially problematic during rapid event streams where session creation and message events arrive in quick succession.",
1049− "severity": "Unknown",
1050− "has_false_positive_signal": false,
1051− "phase0_status": "filtered_outdated",
1052− "phase0_reason": "Thread is flagged outdated by GitHub diff context."
1053− },
1054− {
1055− "index": 3,
1056− "thread_id": "PRRT_kwDORLtfbc5v8_m_",
1057− "path": "apps/server/src/orchestration/engine.ts",
1058− "line": null,
1059− "is_outdated": true,
1060− "is_resolved": false,
1061− "author": "greptile-apps",
1062− "title": "catches an error during event processing (line 201-205), it creates a new Error and calls `envelope.reject()`, but the original error is not logged. This makes debugging event processing failures very difficult. Since the `catch` callback returns `undefined`, the stream continues processing subsequent commands even after failures, which may lead to inconsistent state if error recovery is needed.",
1063− "severity": "Unknown",
1064− "has_false_positive_signal": false,
1065− "phase0_status": "filtered_outdated",
1066− "phase0_reason": "Thread is flagged outdated by GitHub diff context."
1067− },
1068− {
1069− "index": 4,
1070− "thread_id": "PRRT_kwDORLtfbc5v8_nN",
1071− "path": "apps/server/src/orchestration/engine.ts",
1072− "line": null,
1073− "is_outdated": true,
1074− "is_resolved": false,
1075− "author": "greptile-apps",
1076− "title": "runs PubSub publishes in parallel with synchronous listener callbacks (lines 193-198), but the listeners fire before waiting for PubSub to complete. If PubSub publish fails, listeners already received the update, creating inconsistency between Effect subscribers and direct listeners. The envelope is also resolved (line 199) before verifying both PubSub publishes succeeded.",
1077− "severity": "Unknown",
1078− "has_false_positive_signal": false,
1079− "phase0_status": "filtered_outdated",
1080− "phase0_reason": "Thread is flagged outdated by GitHub diff context."
1081− },
1082− {
1083− "index": 5,
1084− "thread_id": "PRRT_kwDORLtfbc5v8_nb",
1085− "path": "apps/server/src/orchestration/reducer.ts",
1086− "line": null,
1087− "is_outdated": true,
1088− "is_resolved": false,
1089− "author": "greptile-apps",
1090− "title": "is false and `message.text.length > 0`, the entire text is replaced (line 150). However, if `message.text` is empty string and `streaming` is false (like the turn/completed event at wsServer.ts:198), it preserves `entry.text` (line 152). This creates an edge case: if a streaming message never sent any text deltas, then receives a finalizing empty-text event, the message keeps empty text from initialization instead of the intended final state.",
1091− "severity": "Unknown",
1092− "has_false_positive_signal": false,
1093− "phase0_status": "filtered_outdated",
1094− "phase0_reason": "Thread is flagged outdated by GitHub diff context."
1095− },
1096− {
1097− "index": 6,
1098− "thread_id": "PRRT_kwDORLtfbc5v8_zA",
1099− "path": "apps/web/src/routes/__root.tsx",
1100− "line": null,
1101− "is_outdated": true,
1102− "is_resolved": true,
1103− "author": "macroscopeapp",
1104− "title": "Race condition: if `getSnapshot()` resolves after `onReadModel` fires, stale data overwrites newer state. Also, pending promises from previous effect runs can overwrite current state. Consider adding a `canceled` flag that's set in the cleanup, and check it before dispatching. \u2705 Resolved in b2f29834553747157b9eba6a5fa9de1b84693dce",
1105− "severity": "High",
1106− "has_false_positive_signal": false,
1107− "phase0_status": "filtered_outdated",
1108− "phase0_reason": "Thread is flagged outdated by GitHub diff context."
1109− },
1110− {
1111− "index": 7,
1112− "thread_id": "PRRT_kwDORLtfbc5v8_zC",
1113− "path": "apps/server/src/orchestration/engine.ts",
1114− "line": null,
1115− "is_outdated": true,
1116− "is_resolved": true,
1117− "author": "macroscopeapp",
1118− "title": "`replayEvents` uses the default `limit` of 1,000 from `readFromSequence`, which may silently truncate results. Consider passing `Number.MAX_SAFE_INTEGER` (like `readAll` does) to return all events. Code refactored as of 9ef01eb97e9a4e7e174e383350febd08951a0dc3",
1119− "severity": "High",
1120− "has_false_positive_signal": false,
1121− "phase0_status": "filtered_outdated",
1122− "phase0_reason": "Thread is flagged outdated by GitHub diff context."
1123− },
1124− {
1125− "index": 8,
1126− "thread_id": "PRRT_kwDORLtfbc5v8_zD",
1127− "path": "apps/server/src/orchestration/engine.ts",
1128− "line": null,
1129− "is_outdated": true,
1130− "is_resolved": true,
1131− "author": "macroscopeapp",
1132− "title": "Consider draining the `commandQueue` and rejecting pending envelopes in `stop()` after interrupting the fiber. Otherwise, callers awaiting `dispatch()` will hang indefinitely. Code refactored as of 9ef01eb97e9a4e7e174e383350febd08951a0dc3",
1133− "severity": "High",
1134− "has_false_positive_signal": false,
1135− "phase0_status": "filtered_outdated",
1136− "phase0_reason": "Thread is flagged outdated by GitHub diff context."
1137− },
1138− {
1139− "index": 9,
1140− "thread_id": "PRRT_kwDORLtfbc5v8_zE",
1141− "path": "apps/server/src/orchestration/engine.ts",
1142− "line": null,
1143− "is_outdated": true,
1144− "is_resolved": true,
1145− "author": "macroscopeapp",
1146− "title": "Listener exceptions after line 187 cause `envelope.reject()` to fire despite the event already being persisted and `readModel` updated. Consider moving listener notifications outside the `try` block (or catching their errors separately) so that persistence success always resolves the promise, preventing duplicate events from retry attempts. Code refactored as of 9ef01eb97e9a4e7e174e383350febd08951a0dc3",
1147− "severity": "High",
1148− "has_false_positive_signal": false,
1149− "phase0_status": "filtered_outdated",
1150− "phase0_reason": "Thread is flagged outdated by GitHub diff context."
1151− },
1152− {
1153− "index": 10,
1154− "thread_id": "PRRT_kwDORLtfbc5v8_zH",
1155− "path": "apps/server/src/orchestration/eventStore.ts",
1156− "line": null,
1157− "is_outdated": true,
1158− "is_resolved": true,
1159− "author": "macroscopeapp",
1160− "title": "`readAll()` loads the entire event table into memory synchronously, which will eventually cause OOM as the store grows. Consider using pagination or streaming, or document why unbounded loading is acceptable for the expected dataset size. Code refactored as of 10bd27da3d7c869d7ea9c4bd824f9ee730bd1792",
1161− "severity": "Medium",
1162− "has_false_positive_signal": false,
1163− "phase0_status": "filtered_outdated",
1164− "phase0_reason": "Thread is flagged outdated by GitHub diff context."
1165− },
1166− {
1167− "index": 11,
1168− "thread_id": "PRRT_kwDORLtfbc5v8_zJ",
1169− "path": "apps/server/src/orchestration/engine.ts",
1170− "line": null,
1171− "is_outdated": true,
1172− "is_resolved": true,
1173− "author": "macroscopeapp",
1174− "title": "`readAll()` loads the entire event history into memory at startup. As the event store grows, this will eventually exceed heap limits and crash the process. Consider paginating the replay (e.g., fetch events in batches of 1000 and reduce incrementally). Code refactored as of 9ef01eb97e9a4e7e174e383350febd08951a0dc3",
1175− "severity": "Medium",
1176− "has_false_positive_signal": false,
1177− "phase0_status": "filtered_outdated",
1178− "phase0_reason": "Thread is flagged outdated by GitHub diff context."
1179− },
1180− {
1181− "index": 12,
1182− "thread_id": "PRRT_kwDORLtfbc5v8_zK",
1183− "path": "apps/web/src/session-logic.ts",
1184− "line": null,
1185− "is_outdated": true,
1186− "is_resolved": true,
1187− "author": "macroscopeapp",
1188− "title": "The regex `(.+?)` stops at the first ` b/`, so paths containing ` b/` (e.g., `folder b/file`) are parsed incorrectly. Consider using the fact that source and destination paths are identical for most cases, or parsing from the `---`/`+++` lines instead. No longer relevant as of ef341394699edcf9ab21af4a7bbf0186a87ebce5",
1189− "severity": "Medium",
1190− "has_false_positive_signal": false,
1191− "phase0_status": "filtered_outdated",
1192− "phase0_reason": "Thread is flagged outdated by GitHub diff context."
1193− },
1194− {
1195− "index": 13,
1196− "thread_id": "PRRT_kwDORLtfbc5v9AdO",
1197− "path": "apps/server/src/wsServer.ts",
1198− "line": null,
1199− "is_outdated": true,
1200− "is_resolved": true,
1201− "author": "cursor",
1202− "title": "Failed turn sets session status to \"ready\" instead of \"error\"",
1203− "severity": "High",
1204− "has_false_positive_signal": false,
1205− "phase0_status": "filtered_outdated",
1206− "phase0_reason": "Thread is flagged outdated by GitHub diff context."
1207− },
1208− {
1209− "index": 14,
1210− "thread_id": "PRRT_kwDORLtfbc5v9AdQ",
1211− "path": "apps/web/src/components/Sidebar.tsx",
1212− "line": 252,
1213− "is_outdated": true,
1214− "is_resolved": true,
1215− "author": "cursor",
1216− "title": "Duplicate project created in Electron add-project flow",
1217− "severity": "High",
1218− "has_false_positive_signal": false,
1219− "phase0_status": "filtered_outdated",
1220− "phase0_reason": "Thread is flagged outdated by GitHub diff context."
1221− },
1222− {
1223− "index": 15,
1224− "thread_id": "PRRT_kwDORLtfbc5v9AdS",
1225− "path": "apps/web/src/components/Sidebar.tsx",
1226− "line": null,
1227− "is_outdated": true,
1228− "is_resolved": true,
1229− "author": "cursor",
1230− "title": "Navigation races ahead of thread creation in store",
1231− "severity": "Medium",
1232− "has_false_positive_signal": false,
1233− "phase0_status": "filtered_outdated",
1234− "phase0_reason": "Thread is flagged outdated by GitHub diff context."
1235− },
1236− {
1237− "index": 16,
1238− "thread_id": "PRRT_kwDORLtfbc5v9AdT",
1239− "path": "apps/server/src/wsServer.ts",
1240− "line": null,
1241− "is_outdated": true,
1242− "is_resolved": true,
1243− "author": "cursor",
1244− "title": "Session close/exit events not reflected in orchestration state",
1245− "severity": "Medium",
1246− "has_false_positive_signal": false,
1247− "phase0_status": "filtered_outdated",
1248− "phase0_reason": "Thread is flagged outdated by GitHub diff context."
1249− },
1250− {
1251− "index": 17,
1252− "thread_id": "PRRT_kwDORLtfbc5v9AdU",
1253− "path": "apps/server/src/wsServer.ts",
1254− "line": null,
1255− "is_outdated": true,
1256− "is_resolved": true,
1257− "author": "cursor",
1258− "title": "Double `getSnapshot()` call may produce inconsistent data",
1259− "severity": "Low",
1260− "has_false_positive_signal": false,
1261− "phase0_status": "filtered_outdated",
1262− "phase0_reason": "Thread is flagged outdated by GitHub diff context."
1263− },
1264− {
1265− "index": 18,
1266− "thread_id": "PRRT_kwDORLtfbc5v9AdW",
1267− "path": "apps/web/src/session-logic.ts",
1268− "line": null,
1269− "is_outdated": true,
1270− "is_resolved": true,
1271− "author": "cursor",
1272− "title": "Timeline entry IDs lose uniqueness-guaranteeing prefix",
1273− "severity": "Low",
1274− "has_false_positive_signal": false,
1275− "phase0_status": "filtered_outdated",
1276− "phase0_reason": "Thread is flagged outdated by GitHub diff context."
1277− },
1278− {
1279− "index": 19,
1280− "thread_id": "PRRT_kwDORLtfbc5v9AdX",
1281− "path": "apps/web/src/components/ChatView.tsx",
1282− "line": null,
1283− "is_outdated": true,
1284− "is_resolved": true,
1285− "author": "cursor",
1286− "title": "Supervised mode approval prompts never shown to users",
1287− "severity": "High",
1288− "has_false_positive_signal": false,
1289− "phase0_status": "filtered_outdated",
1290− "phase0_reason": "Thread is flagged outdated by GitHub diff context."
1291− },
1292− {
1293− "index": 20,
1294− "thread_id": "PRRT_kwDORLtfbc5v9AdY",
1295− "path": "apps/web/src/components/ChatView.tsx",
1296− "line": null,
1297− "is_outdated": true,
1298− "is_resolved": true,
1299− "author": "cursor",
1300− "title": "Checkpoint revert doesn't update orchestration read model state",
1301− "severity": "High",
1302− "has_false_positive_signal": false,
1303− "phase0_status": "filtered_outdated",
1304− "phase0_reason": "Thread is flagged outdated by GitHub diff context."
1305− },
1306− {
1307− "index": 21,
1308− "thread_id": "PRRT_kwDORLtfbc5v9AdZ",
1309− "path": "apps/server/src/wsServer.test.ts",
1310− "line": null,
1311− "is_outdated": true,
1312− "is_resolved": true,
1313− "author": "cursor",
1314− "title": "Test helper omits `stateDir`, writing SQLite to home directory",
1315− "severity": "Medium",
1316− "has_false_positive_signal": false,
1317− "phase0_status": "filtered_outdated",
1318− "phase0_reason": "Thread is flagged outdated by GitHub diff context."
1319− },
1320− {
1321− "index": 22,
1322− "thread_id": "PRRT_kwDORLtfbc5v9Ada",
1323− "path": "apps/server/src/orchestration/engine.ts",
1324− "line": null,
1325− "is_outdated": true,
1326− "is_resolved": true,
1327− "author": "cursor",
1328− "title": "SQLite database connection never closed on engine stop",
1329− "severity": "Medium",
1330− "has_false_positive_signal": false,
1331− "phase0_status": "filtered_outdated",
1332− "phase0_reason": "Thread is flagged outdated by GitHub diff context."
1333− },
1334− {
1335− "index": 23,
1336− "thread_id": "PRRT_kwDORLtfbc5v9Anx",
1337− "path": "apps/server/package.json",
1338− "line": null,
1339− "is_outdated": true,
1340− "is_resolved": false,
1341− "author": "coderabbitai",
1342− "title": "What typically goes wrong",
1343− "severity": "High",
1344− "has_false_positive_signal": false,
1345− "phase0_status": "filtered_outdated",
1346− "phase0_reason": "Thread is flagged outdated by GitHub diff context."
1347− },
1348− {
1349− "index": 24,
1350− "thread_id": "PRRT_kwDORLtfbc5v9Any",
1351− "path": "apps/server/src/orchestration/reducer.ts",
1352− "line": null,
1353− "is_outdated": true,
1354− "is_resolved": true,
1355− "author": "coderabbitai",
1356− "title": "is missing, prefer a deterministic fallback (e.g., `event.eventId`) or drop the event. <details> <summary>\ud83d\udd27 Suggested fix (deterministic IDs)</summary>",
1357− "severity": "High",
1358− "has_false_positive_signal": false,
1359− "phase0_status": "filtered_outdated",
1360− "phase0_reason": "Thread is flagged outdated by GitHub diff context."
1361− },
1362− {
1363− "index": 25,
1364− "thread_id": "PRRT_kwDORLtfbc5v9Anz",
1365− "path": "apps/server/src/wsServer.test.ts",
1366− "line": null,
1367− "is_outdated": true,
1368− "is_resolved": false,
1369− "author": "coderabbitai",
1370− "title": "for runtime setup. Clean up external resources in `finally` blocks.\" <details> <summary>\ud83e\udd16 Prompt for AI Agents</summary>",
1371− "severity": "Medium",
1372− "has_false_positive_signal": false,
1373− "phase0_status": "filtered_outdated",
1374− "phase0_reason": "Thread is flagged outdated by GitHub diff context."
1375− },
1376− {
1377− "index": 26,
1378− "thread_id": "PRRT_kwDORLtfbc5v9An0",
1379− "path": "apps/server/src/wsServer.ts",
1380− "line": null,
1381− "is_outdated": true,
1382− "is_resolved": false,
1383− "author": "coderabbitai",
1384− "title": "stream expected by the web app and hides orchestration dispatch failures, which makes state drift hard to debug. Please broadcast the provider event and log failures. <details> <summary>\ud83d\udd27 Suggested fix (broadcast + logging)</summary>",
1385− "severity": "High",
1386− "has_false_positive_signal": false,
1387− "phase0_status": "filtered_outdated",
1388− "phase0_reason": "Thread is flagged outdated by GitHub diff context."
1389− },
1390− {
1391− "index": 27,
1392− "thread_id": "PRRT_kwDORLtfbc5v9An1",
1393− "path": "apps/server/src/wsServer.ts",
1394− "line": null,
1395− "is_outdated": true,
1396− "is_resolved": false,
1397− "author": "coderabbitai",
1398− "title": "rejects but the server is already listening; this leaves a partially running server with no orchestration worker. <details> <summary>\ud83d\udd27 Suggested fix</summary>",
1399− "severity": "High",
1400− "has_false_positive_signal": false,
1401− "phase0_status": "filtered_outdated",
1402− "phase0_reason": "Thread is flagged outdated by GitHub diff context."
1403− },
1404− {
1405− "index": 28,
1406− "thread_id": "PRRT_kwDORLtfbc5v9An3",
1407− "path": "apps/web/src/components/ChatView.tsx",
1408− "line": null,
1409− "is_outdated": true,
1410− "is_resolved": false,
1411− "author": "coderabbitai",
1412− "title": "and `derivePendingApprovals` means work log entries and pending approvals will never render, and it effectively drops provider event stream consumption. Please wire these to the provider event feed (or the orchestration read-model) instead of hard-coded empties. As per coding guidelines: \"Web app must consume provider event streams via WebSocket push on channel `providers.event`\". <details> <summary>\ud83e\udd16 Prompt for AI Agents</summary>",
1413− "severity": "High",
1414− "has_false_positive_signal": false,
1415− "phase0_status": "filtered_outdated",
1416− "phase0_reason": "Thread is flagged outdated by GitHub diff context."
1417− },
1418− {
1419− "index": 29,
1420− "thread_id": "PRRT_kwDORLtfbc5v9An4",
1421− "path": "apps/web/src/components/ChatView.tsx",
1422− "line": null,
1423− "is_outdated": true,
1424− "is_resolved": false,
1425− "author": "coderabbitai",
1426− "title": "command (SendMessageCommandSchema) omits attachments\u2014only text is sent to orchestration. While attachments are correctly forwarded to the provider API separately (line 1752), the composer images are cleared immediately (line 1723) before attachment metadata can be persisted to the message itself. Since OrchestrationMessageSchema has no attachments field and the read-model's messages derive from orchestration events, user images will vanish on page refresh or if the read-model becomes the authoritative source. To preserve attachments: either add attachment metadata to SendMessageCommandSchema and the message reducer, or maintain a local optimistic state mapping userMessageId \u2192 attachments until the read-model is updated to include attachment data. <details> <summary>\ud83e\udd16 Prompt for AI Agents</summary>",
1427− "severity": "High",
1428− "has_false_positive_signal": false,
1429− "phase0_status": "filtered_outdated",
1430− "phase0_reason": "Thread is flagged outdated by GitHub diff context."
1431− },
1432− {
1433− "index": 30,
1434− "thread_id": "PRRT_kwDORLtfbc5v9An5",
1435− "path": "apps/web/src/components/Sidebar.tsx",
1436− "line": null,
1437− "is_outdated": true,
1438− "is_resolved": false,
1439− "author": "coderabbitai",
1440− "title": "is never populated.** This map is created once and never updated, so the \u201cAwaiting response\u201d pill will never show. Reintroduce `derivePendingApprovals` or feed this from the read-model/provider events. <details> <summary>\ud83e\udd16 Prompt for AI Agents</summary>",
1441− "severity": "Medium",
1442− "has_false_positive_signal": false,
1443− "phase0_status": "filtered_outdated",
1444− "phase0_reason": "Thread is flagged outdated by GitHub diff context."
1445− },
1446− {
1447− "index": 31,
1448− "thread_id": "PRRT_kwDORLtfbc5v9An7",
1449− "path": "apps/web/src/routes/__root.tsx",
1450− "line": 140,
1451− "is_outdated": false,
1452− "is_resolved": false,
1453− "author": "coderabbitai",
1454− "title": "channel.** The web app currently does not consume provider event streams via the `providers.event` channel. While the orchestration API has `onReadModel()` and `onDomainEvent()` subscriptions, the providers event stream subscription is missing. Add a subscription to `ORCHESTRATION_WS_CHANNELS.event` (or the appropriate providers event channel from contracts) in `wsNativeApi.ts` and expose it via the `api.providers` object to comply with the guideline requirement. <details> <summary>\ud83e\udd16 Prompt for AI Agents</summary>",
1455− "severity": "High",
1456− "has_false_positive_signal": false,
1457− "phase0_status": "filtered_invalid",
1458− "phase0_reason": "Invalid by design: provider runtime events are intentionally surfaced through orchestration domain events (`orchestration.domainEvent`), not a separate `providers.event` WebSocket channel in the current architecture."
1459− },
1460− {
1461− "index": 32,
1462− "thread_id": "PRRT_kwDORLtfbc5v9An8",
1463− "path": "apps/web/src/session-logic.ts",
1464− "line": null,
1465− "is_outdated": true,
1466− "is_resolved": false,
1467− "author": "coderabbitai",
1468− "title": "and `deriveWorkLogEntries` are actively consumed in ChatView.tsx but always return empty arrays. They're called with empty event arrays and never process actual data, so pending approvals and work log entries will never appear in the UI. `deriveTurnDiffSummaries` is not consumed anywhere\u2014it's been superseded by the `useTurnDiffSummaries` hook, which reads directly from the orchestration read model (`activeThread.turnDiffSummaries`). Consider removing `derivePendingApprovals` and `deriveWorkLogEntries` entirely or implement them to consume from the orchestration read model, matching the pattern established by `useTurnDiffSummaries`. <details> <summary>\ud83e\udd16 Prompt for AI Agents</summary>",
1469− "severity": "High",
1470− "has_false_positive_signal": false,
1471− "phase0_status": "filtered_outdated",
1472− "phase0_reason": "Thread is flagged outdated by GitHub diff context."
1473− },
1474− {
1475− "index": 33,
1476− "thread_id": "PRRT_kwDORLtfbc5v9An9",
1477− "path": "apps/web/src/session-logic.ts",
1478− "line": null,
1479− "is_outdated": true,
1480− "is_resolved": false,
1481− "author": "coderabbitai",
1482− "title": "(e.g., orchestration turn-diff types) instead of app-local interfaces to keep contracts aligned. As per coding guidelines: `apps/**/*.{ts,tsx}: Use Zod schemas from packages/contracts for shared type contracts covering provider events, WebSocket protocol, and model/session types`. <details> <summary>\ud83e\udd16 Prompt for AI Agents</summary>",
1483− "severity": "High",
1484− "has_false_positive_signal": false,
1485− "phase0_status": "filtered_outdated",
1486− "phase0_reason": "Thread is flagged outdated by GitHub diff context."
1487− },
1488− {
1489− "index": 34,
1490− "thread_id": "PRRT_kwDORLtfbc5v9An-",
1491− "path": "apps/web/src/wsNativeApi.ts",
1492− "line": 165,
1493− "is_outdated": false,
1494− "is_resolved": false,
1495− "author": "coderabbitai",
1496− "title": "push stream, and the callbacks rely on unchecked casts. Please reintroduce a `providers.onEvent` (or equivalent) that subscribes to the `providers.event` channel and decode read-model/domain-event payloads using the shared contracts schemas before invoking callbacks. As per coding guidelines: \"Web app must consume provider event streams via WebSocket push on channel `providers.event`\" and \"Use Zod schemas from `packages/contracts` for shared type contracts covering provider events, WebSocket protocol, and model/session types\". <details> <summary>\ud83e\udd16 Prompt for AI Agents</summary>",
1497− "severity": "High",
1498− "has_false_positive_signal": false,
1499− "phase0_status": "filtered_invalid",
1500− "phase0_reason": "Invalid by design: provider runtime events are intentionally surfaced through orchestration domain events (`orchestration.domainEvent`), not a separate `providers.event` WebSocket channel in the current architecture."
1501− },
1502− {
1503− "index": 35,
1504− "thread_id": "PRRT_kwDORLtfbc5v9RP6",
1505− "path": "apps/server/src/orchestration/reducer.ts",
1506− "line": null,
1507− "is_outdated": true,
1508− "is_resolved": true,
1509− "author": "macroscopeapp",
1510− "title": "After sorting `turnDiffSummaries`, `latestTurnId` should come from the last element of the sorted array, not unconditionally from the incoming event. Out-of-order events would desync `latestTurnId` from the actual latest summary. No longer relevant as of b2f29834553747157b9eba6a5fa9de1b84693dce",
1511− "severity": "High",
1512− "has_false_positive_signal": false,
1513− "phase0_status": "filtered_outdated",
1514− "phase0_reason": "Thread is flagged outdated by GitHub diff context."
1515− },
1516− {
1517− "index": 36,
1518− "thread_id": "PRRT_kwDORLtfbc5v9RP8",
1519− "path": "apps/server/src/orchestration/engine.ts",
1520− "line": null,
1521− "is_outdated": true,
1522− "is_resolved": true,
1523− "author": "macroscopeapp",
1524− "title": "A single command processing error terminates the worker stream, causing all subsequent commands to hang. Consider wrapping the `Effect.tryPromise` in `Effect.catchAll(() => Effect.succeed(undefined))` so the stream continues processing after failures. \u2705 Addressed in c3b7cc713c7f67d5130096bb0f03e14485e26e72",
1525− "severity": "High",
1526− "has_false_positive_signal": false,
1527− "phase0_status": "filtered_outdated",
1528− "phase0_reason": "Thread is flagged outdated by GitHub diff context."
1529− },
1530− {
1531− "index": 37,
1532− "thread_id": "PRRT_kwDORLtfbc5v9RtX",
1533− "path": "apps/server/src/orchestration/engine.ts",
1534− "line": null,
1535− "is_outdated": true,
1536− "is_resolved": false,
1537− "author": "coderabbitai",
1538− "title": "around lines 235 - 240, The loops invoking this.domainEventListeners and this.readModelListeners should wrap each listener call in a try/catch so a thrown error from one listener does not stop subsequent listeners or cause envelope rejection; update the blocks around listener(savedEvent) and listener(this.readModel) to call each listener inside a try { await/ call } catch (err) { processLogger.error(...) or this.logger.error(...) with context including the listener identity and the savedEvent/readModel } and continue to the next listener, ensuring errors are isolated and logged.",
1539− "severity": "High",
1540− "has_false_positive_signal": false,
1541− "phase0_status": "filtered_outdated",
1542− "phase0_reason": "Thread is flagged outdated by GitHub diff context."
1543− },
1544− {
1545− "index": 38,
1546− "thread_id": "PRRT_kwDORLtfbc5v9Rtc",
1547− "path": "apps/server/src/orchestration/eventStore.ts",
1548− "line": null,
1549− "is_outdated": true,
1550− "is_resolved": false,
1551− "author": "coderabbitai",
1552− "title": "with a Bun-compatible SQLite driver.** The `node:sqlite` module is a Node.js 22.6+ built-in that Bun does not support. CI runs exclusively on Bun 1.3.9, and `OrchestrationEngine` (which uses `SqliteEventStore`) is imported in `wsServer.ts` and tested in `engine.test.ts`. When `bun run test` executes in CI, it will fail to load this code with \"No such built-in module: node:sqlite\". Switch to `bun:sqlite` (which is built-in to Bun) or add a packaged SQLite driver (e.g., `better-sqlite3`, `sql.js`) to apps/server dependencies and abstract the driver behind an interface for portability. <details> <summary>\ud83e\udd16 Prompt for AI Agents</summary>",
1553− "severity": "High",
1554− "has_false_positive_signal": false,
1555− "phase0_status": "filtered_outdated",
1556− "phase0_reason": "Thread is flagged outdated by GitHub diff context."
1557− },
1558− {
1559− "index": 39,
1560− "thread_id": "PRRT_kwDORLtfbc5v9SCj",
1561− "path": "apps/server/src/wsServer.ts",
1562− "line": null,
1563− "is_outdated": true,
1564− "is_resolved": false,
1565− "author": "cursor",
1566− "title": "HTTP server accepts connections before engine is ready",
1567− "severity": "Medium",
1568− "has_false_positive_signal": false,
1569− "phase0_status": "filtered_outdated",
1570− "phase0_reason": "Thread is flagged outdated by GitHub diff context."
1571− },
1572− {
1573− "index": 40,
1574− "thread_id": "PRRT_kwDORLtfbc5v9SCk",
1575− "path": "apps/server/src/orchestration/engine.ts",
1576− "line": null,
1577− "is_outdated": true,
1578− "is_resolved": false,
1579− "author": "cursor",
1580− "title": "Unused PubSub instances published to without subscribers",
1581− "severity": "Low",
1582− "has_false_positive_signal": false,
1583− "phase0_status": "filtered_outdated",
1584− "phase0_reason": "Thread is flagged outdated by GitHub diff context."
1585− },
1586− {
1587− "index": 41,
1588− "thread_id": "PRRT_kwDORLtfbc5v9SCp",
1589− "path": "apps/web/src/session-logic.ts",
1590− "line": 127,
1591− "is_outdated": false,
1592− "is_resolved": false,
1593− "author": "cursor",
1594− "title": "Revert uses wrong turn count from positional inference",
1595− "severity": "Medium",
1596− "has_false_positive_signal": false,
1597− "phase0_status": "filtered_invalid",
1598− "phase0_reason": "Invalid after post-rewrite audit: Revert now uses explicit checkpointTurnCount first; positional fallback is non-primary."
1599− },
1600− {
1601− "index": 42,
1602− "thread_id": "PRRT_kwDORLtfbc5v9SCt",
1603− "path": "apps/web/src/components/ChatView.tsx",
1604− "line": null,
1605− "is_outdated": true,
1606− "is_resolved": false,
1607− "author": "cursor",
1608− "title": "`syncCheckpointTurnCounts` discards result, becoming a no-op",
1609− "severity": "Low",
1610− "has_false_positive_signal": false,
1611− "phase0_status": "filtered_outdated",
1612− "phase0_reason": "Thread is flagged outdated by GitHub diff context."
1613− },
1614− {
1615− "index": 43,
1616− "thread_id": "PRRT_kwDORLtfbc5v9gBJ",
1617− "path": "apps/server/src/orchestration/engine.ts",
1618− "line": null,
1619− "is_outdated": true,
1620− "is_resolved": true,
1621− "author": "macroscopeapp",
1622− "title": "Consider adding a guard in `dispatch` to throw if the engine hasn't been started, since the worker fiber won't be running to process commands, causing `Deferred.await` to hang indefinitely. \u2705 Addressed in 9ef01eb97e9a4e7e174e383350febd08951a0dc3",
1623− "severity": "High",
1624− "has_false_positive_signal": false,
1625− "phase0_status": "filtered_outdated",
1626− "phase0_reason": "Thread is flagged outdated by GitHub diff context."
1627− },
1628− {
1629− "index": 44,
1630− "thread_id": "PRRT_kwDORLtfbc5v9gX0",
1631− "path": "apps/web/src/components/Sidebar.tsx",
1632− "line": null,
1633− "is_outdated": true,
1634− "is_resolved": false,
1635− "author": "cursor",
1636− "title": "Double project deletion dispatch in Electron mode",
1637− "severity": "Low",
1638− "has_false_positive_signal": false,
1639− "phase0_status": "filtered_outdated",
1640− "phase0_reason": "Thread is flagged outdated by GitHub diff context."
1641− },
1642− {
1643− "index": 45,
1644− "thread_id": "PRRT_kwDORLtfbc5v9gX1",
1645− "path": "apps/server/src/wsServer.ts",
1646− "line": null,
1647− "is_outdated": true,
1648− "is_resolved": false,
1649− "author": "cursor",
1650− "title": "Every streaming token persisted as separate database event",
1651− "severity": "High",
1652− "has_false_positive_signal": false,
1653− "phase0_status": "filtered_outdated",
1654− "phase0_reason": "Thread is flagged outdated by GitHub diff context."
1655− },
1656− {
1657− "index": 46,
1658− "thread_id": "PRRT_kwDORLtfbc5v9gX2",
1659− "path": "apps/server/src/orchestration/reducer.ts",
1660− "line": null,
1661− "is_outdated": true,
1662− "is_resolved": false,
1663− "author": "cursor",
1664− "title": "Reducer overwrites Codex runtime thread ID with orchestration ID",
1665− "severity": "High",
1666− "has_false_positive_signal": false,
1667− "phase0_status": "filtered_outdated",
1668− "phase0_reason": "Thread is flagged outdated by GitHub diff context."
1669− },
1670− {
1671− "index": 47,
1672− "thread_id": "PRRT_kwDORLtfbc5v9gX4",
1673− "path": "apps/web/src/routes/__root.tsx",
1674− "line": null,
1675− "is_outdated": true,
1676− "is_resolved": false,
1677− "author": "cursor",
1678− "title": "Bootstrap creates duplicate project on server restart",
1679− "severity": "Medium",
1680− "has_false_positive_signal": false,
1681− "phase0_status": "filtered_outdated",
1682− "phase0_reason": "Thread is flagged outdated by GitHub diff context."
1683− },
1684− {
1685− "index": 48,
1686− "thread_id": "PRRT_kwDORLtfbc5v9gcy",
1687− "path": "apps/server/src/orchestration/Layer.ts",
1688− "line": null,
1689− "is_outdated": true,
1690− "is_resolved": false,
1691− "author": "coderabbitai",
1692− "title": "with `catchAll` to avoid catching defects.** Using `catchAllCause` will catch both expected errors and defects (bugs). Per project conventions, use `catchAll` or `mapError` instead so that genuine bugs propagate as failures rather than being silently caught and turned into user-facing errors. <details> <summary>\ud83d\udee1\ufe0f Proposed fix</summary>",
1693− "severity": "High",
1694− "has_false_positive_signal": false,
1695− "phase0_status": "filtered_outdated",
1696− "phase0_reason": "Thread is flagged outdated by GitHub diff context."
1697− },
1698− {
1699− "index": 49,
1700− "thread_id": "PRRT_kwDORLtfbc5v9gc0",
1701− "path": "apps/server/src/persistence/Layers/OrchestrationEvents.ts",
1702− "line": null,
1703− "is_outdated": true,
1704− "is_resolved": false,
1705− "author": "coderabbitai",
1706− "title": "from DB operations\u2014it masks expected failures as defects.** `JSON.parse` and `Schema.decodeUnknownSync` can throw expected errors (invalid payloads, malformed JSON). Converting these to defects via `orDie` crashes orchestration flows instead of handling them predictably. Update `OrchestrationEventRepositoryShape` to return typed errors (e.g., `Effect.Effect<OrchestrationEvent, ParseError | ValidationError>`) and remove `orDie` from both `append` and `readFromSequence`. <details> <summary>Suggested starting point</summary>",
1707− "severity": "High",
1708− "has_false_positive_signal": false,
1709− "phase0_status": "filtered_outdated",
1710− "phase0_reason": "Thread is flagged outdated by GitHub diff context."
1711− },
1712− {
1713− "index": 50,
1714− "thread_id": "PRRT_kwDORLtfbc5v9gc2",
1715− "path": "apps/server/src/persistence/Layers/OrchestrationEvents.ts",
1716− "line": null,
1717− "is_outdated": true,
1718− "is_resolved": true,
1719− "author": "coderabbitai",
1720− "title": "\ud83d\udca1 Result: In **Effect (TypeScript)**, `Effect.try` has two overloads\u2014one that takes just a thunk, and one that takes an object with `try` and a `catch` handler. The **`catch` handler signature** is: - `catch: (error: unknown) => E` (i.e., it receives the thrown value as `unknown` and must map it to your typed error `E`). [1] Type definition (from the docs):",
1721− "severity": "High",
1722− "has_false_positive_signal": false,
1723− "phase0_status": "filtered_outdated",
1724− "phase0_reason": "Thread is flagged outdated by GitHub diff context."
1725− },
1726− {
1727− "index": 51,
1728− "thread_id": "PRRT_kwDORLtfbc5v9gc3",
1729− "path": "apps/server/src/wsServer.ts",
1730− "line": null,
1731− "is_outdated": true,
1732− "is_resolved": true,
1733− "author": "coderabbitai",
1734− "title": "is called twice; the sequence can change between calls. Grab it once and reuse it to keep the push consistent. <details> <summary>\ud83d\udd27 Suggested fix</summary>",
1735− "severity": "Medium",
1736− "has_false_positive_signal": false,
1737− "phase0_status": "filtered_outdated",
1738− "phase0_reason": "Thread is flagged outdated by GitHub diff context."
1739− },
1740− {
1741− "index": 52,
1742− "thread_id": "PRRT_kwDORLtfbc5v-WO9",
1743− "path": "apps/web/src/routes/__root.tsx",
1744− "line": null,
1745− "is_outdated": true,
1746− "is_resolved": true,
1747− "author": "macroscopeapp",
1748− "title": "The `state.threads` check inside the async `.then()` uses a stale closure from when the effect ran, not the current state. Consider moving the thread check inside the `.then()` by re-reading from the store, or fetching threads from the API directly. No longer relevant as of b2f29834553747157b9eba6a5fa9de1b84693dce",
1749− "severity": "Medium",
1750− "has_false_positive_signal": false,
1751− "phase0_status": "filtered_outdated",
1752− "phase0_reason": "Thread is flagged outdated by GitHub diff context."
1753− },
1754− {
1755− "index": 53,
1756− "thread_id": "PRRT_kwDORLtfbc5v-WO-",
1757− "path": "apps/server/src/orchestration/Layer.ts",
1758− "line": null,
1759− "is_outdated": true,
1760− "is_resolved": true,
1761− "author": "macroscopeapp",
1762− "title": "`bootstrapReadModel` should reset `this.readModel` before replaying events. If it fails mid-replay and `start()` is retried, events get applied twice to the partially-updated model. Code refactored as of 9ef01eb97e9a4e7e174e383350febd08951a0dc3",
1763− "severity": "High",
1764− "has_false_positive_signal": false,
1765− "phase0_status": "filtered_outdated",
1766− "phase0_reason": "Thread is flagged outdated by GitHub diff context."
1767− },
1768− {
1769− "index": 54,
1770− "thread_id": "PRRT_kwDORLtfbc5v-WPA",
1771− "path": "apps/server/src/persistence/Layers/OrchestrationEvents.ts",
1772− "line": null,
1773− "is_outdated": true,
1774− "is_resolved": true,
1775− "author": "macroscopeapp",
1776− "title": "Avoid sync throws outside the Effect pipeline: both `Schema.decodeUnknownSync` and `JSON.stringify` can crash execution. Suggest using effectful decoding and wrapping serialization in `Effect.try`/`Effect.sync`, handling failures per-row so one bad record doesn\u2019t take down the whole operation. \u2705 Addressed in 2c8e35ceb8aebd0a0db03970193dbbdd66247df4",
1777− "severity": "High",
1778− "has_false_positive_signal": false,
1779− "phase0_status": "filtered_outdated",
1780− "phase0_reason": "Thread is flagged outdated by GitHub diff context."
1781− },
1782− {
1783− "index": 55,
1784− "thread_id": "PRRT_kwDORLtfbc5v-WPB",
1785− "path": "apps/server/src/wsServer.ts",
1786− "line": null,
1787− "is_outdated": true,
1788− "is_resolved": true,
1789− "author": "macroscopeapp",
1790− "title": "After `providerManager.startSession` returns, the `sessionId` is never dispatched to `OrchestrationEngine`, so `thread.session?.sessionId` remains unset. The `providerManager.on(\"event\")` listener then fails to find the thread and silently drops all streaming events. Consider dispatching a `thread.session` command after `startSession` to link the session with the thread. \u2705 Resolved in af53ae8b4845852a320f108dda30b32afc3c4029",
1791− "severity": "High",
1792− "has_false_positive_signal": false,
1793− "phase0_status": "filtered_outdated",
1794− "phase0_reason": "Thread is flagged outdated by GitHub diff context."
1795− },
1796− {
1797− "index": 56,
1798− "thread_id": "PRRT_kwDORLtfbc5v-WPC",
1799− "path": "apps/server/src/orchestration/engine.ts",
1800− "line": null,
1801− "is_outdated": true,
1802− "is_resolved": true,
1803− "author": "macroscopeapp",
1804− "title": "Race condition: `stop()` called during `start()`'s `bootstrapReadModel()` sees `workerFiber` as `null` and returns immediately, then `start()` resumes and spawns a worker anyway. Consider adding a stopping flag or mutex to coordinate the lifecycle. \u2705 Addressed in 9ef01eb97e9a4e7e174e383350febd08951a0dc3",
1805− "severity": "High",
1806− "has_false_positive_signal": false,
1807− "phase0_status": "filtered_outdated",
1808− "phase0_reason": "Thread is flagged outdated by GitHub diff context."
1809− },
1810− {
1811− "index": 57,
1812− "thread_id": "PRRT_kwDORLtfbc5v-WPD",
1813− "path": "apps/server/src/wsServer.ts",
1814− "line": 83,
1815− "is_outdated": false,
1816− "is_resolved": false,
1817− "author": "macroscopeapp",
1818− "title": "Consider using `socket.end(response)` instead of `socket.write(response)` + `socket.destroy()` to ensure the HTTP error response is fully flushed before closing the connection.",
1819− "severity": "Low",
1820− "has_false_positive_signal": false,
1821− "canonical_id": "C053",
1822− "phase0_status": "actionable_canonical",
1823− "phase0_reason": "Canonical actionable item."
1824− },
1825− {
1826− "index": 58,
1827− "thread_id": "PRRT_kwDORLtfbc5v-XCq",
1828− "path": "apps/server/src/wsServer.ts",
1829− "line": null,
1830− "is_outdated": true,
1831− "is_resolved": false,
1832− "author": "cursor",
1833− "title": "Provider events lost before session association completes",
1834− "severity": "High",
1835− "has_false_positive_signal": false,
1836− "phase0_status": "filtered_outdated",
1837− "phase0_reason": "Thread is flagged outdated by GitHub diff context."
1838− },
1839− {
1840− "index": 59,
1841− "thread_id": "PRRT_kwDORLtfbc5v-XCs",
1842− "path": "apps/server/src/wsServer.ts",
1843− "line": null,
1844− "is_outdated": true,
1845− "is_resolved": false,
1846− "author": "cursor",
1847− "title": "Streaming deltas persisted as individual events cause unbounded growth",
1848− "severity": "High",
1849− "has_false_positive_signal": false,
1850− "phase0_status": "filtered_outdated",
1851− "phase0_reason": "Thread is flagged outdated by GitHub diff context."
1852− },
1853− {
1854− "index": 60,
1855− "thread_id": "PRRT_kwDORLtfbc5v-XCu",
1856− "path": "apps/web/src/components/BranchToolbar.tsx",
1857− "line": 102,
1858− "is_outdated": false,
1859− "is_resolved": false,
1860− "author": "cursor",
1861− "title": "Branch sync dispatches both server and stale local update",
1862− "severity": "Medium",
1863− "has_false_positive_signal": false,
1864− "canonical_id": "C028",
1865− "phase0_status": "actionable_canonical",
1866− "phase0_reason": "Canonical actionable item."
1867− },
1868− {
1869− "index": 61,
1870− "thread_id": "PRRT_kwDORLtfbc5v-XVl",
1871− "path": "apps/server/src/orchestration/engine.test.ts",
1872− "line": null,
1873− "is_outdated": true,
1874− "is_resolved": false,
1875− "author": "coderabbitai",
1876− "title": "usage in `try/finally` or use a helper that guarantees cleanup. Based on learnings: \"For integration tests: Prefer deterministic inputs and explicit state checks; avoid relying on logs or timing assumptions. Keep fixtures cohesive and reuse identities across sequential tests. Synchronize on durable workflow status or snapshot state. Assert on final state and side effects. Use stable helper scripts like `SHELL_SETUP_SCRIPT` for runtime setup. Clean up external resources in `finally` blocks.\" <details> <summary>\ud83e\udd16 Prompt for AI Agents</summary>",
1877− "severity": "Medium",
1878− "has_false_positive_signal": false,
1879− "phase0_status": "filtered_outdated",
1880− "phase0_reason": "Thread is flagged outdated by GitHub diff context."
1881− },
1882− {
1883− "index": 62,
1884− "thread_id": "PRRT_kwDORLtfbc5v-XVo",
1885− "path": "apps/server/src/orchestration/engine.ts",
1886− "line": null,
1887− "is_outdated": true,
1888− "is_resolved": false,
1889− "author": "coderabbitai",
1890− "title": "runs while `workerFiber` is null, the command is queued but never processed, and the returned promise hangs indefinitely. Reject with a clear error (or enforce start) when the engine isn\u2019t running. As per coding guidelines: \"Maintain predictable behavior under load and during failures (session restarts, reconnects, partial streams)\". <details> <summary>\ud83d\udee1\ufe0f Suggested guard</summary>",
1891− "severity": "High",
1892− "has_false_positive_signal": false,
1893− "phase0_status": "filtered_outdated",
1894− "phase0_reason": "Thread is flagged outdated by GitHub diff context."
1895− },
1896− {
1897− "index": 63,
1898− "thread_id": "PRRT_kwDORLtfbc5v-XVt",
1899− "path": "apps/server/src/orchestration/reducer.test.ts",
1900− "line": null,
1901− "is_outdated": true,
1902− "is_resolved": false,
1903− "author": "coderabbitai",
1904− "title": "\ud83d\udca1 Result: For testing **Effect** code with **Vitest** in TypeScript, the standard helper library is **`@effect/vitest`**. It lets you write tests that *return an `Effect`* (instead of manually running it) and gives you a test environment (e.g. `TestClock`) by default. [1][2] ## Install",
1905− "severity": "High",
1906− "has_false_positive_signal": false,
1907− "phase0_status": "filtered_outdated",
1908− "phase0_reason": "Thread is flagged outdated by GitHub diff context."
1909− },
1910− {
1911− "index": 64,
1912− "thread_id": "PRRT_kwDORLtfbc5v-XVx",
1913− "path": "apps/server/src/persistence/Layers/OrchestrationEvents.ts",
1914− "line": null,
1915− "is_outdated": true,
1916− "is_resolved": false,
1917− "author": "coderabbitai",
1918− "title": "and `decodeUnknownSync` both throw uncaught exceptions; when wrapped with `Effect.orDie`, any parse/validation failure crashes the process. For event sourcing replay, this is critical\u2014you must catch and properly handle corrupted rows instead of terminating. Use `Schema.decodeUnknown` (async variant, per project guidelines) wrapped in `Effect.try`, and avoid type assertions in Effect code. <details> <summary>Suggested approach</summary>",
1919− "severity": "High",
1920− "has_false_positive_signal": false,
1921− "phase0_status": "filtered_outdated",
1922− "phase0_reason": "Thread is flagged outdated by GitHub diff context."
1923− },
1924− {
1925− "index": 65,
1926− "thread_id": "PRRT_kwDORLtfbc5v-XVz",
1927− "path": "apps/server/src/persistence/Layers/Projects.test.ts",
1928− "line": null,
1929− "is_outdated": true,
1930− "is_resolved": false,
1931− "author": "coderabbitai",
1932− "title": "in a finally block to prevent resource leaks on assertion failure.** If an assertion fails before `dispose()` is called, the SQLite connection and Effect runtime will leak. Use `try/finally` to ensure cleanup always runs, consistent with other tests in the codebase (e.g., `terminalManager.test.ts`, `filesystemCheckpointStore.test.ts`). <details> <summary>\ud83e\uddf9 Example cleanup pattern</summary>",
1933− "severity": "Medium",
1934− "has_false_positive_signal": false,
1935− "phase0_status": "filtered_outdated",
1936− "phase0_reason": "Thread is flagged outdated by GitHub diff context."
1937− },
1938− {
1939− "index": 66,
1940− "thread_id": "PRRT_kwDORLtfbc5v-XV6",
1941− "path": "apps/server/src/persistence/Layers/Projects.ts",
1942− "line": null,
1943− "is_outdated": true,
1944− "is_resolved": false,
1945− "author": "coderabbitai",
1946− "title": "exists, but the race condition persists: between the `findProjectByCwd` check and `insertProject` call, a concurrent request can insert the same `cwd`, causing the insert to fail. The `.pipe(Effect.orDie)` converts this constraint violation into an unhandled error instead of gracefully returning the existing project. Under concurrent load, this violates the coding guideline to \"maintain predictable behavior under load and during failures.\" Wrap the insert in error handling to catch the constraint violation and re-fetch the existing row, or use a database upsert/on-conflict pattern to ensure atomic, race-free behavior. <details> <summary>\ud83e\udd16 Prompt for AI Agents</summary>",
1947− "severity": "High",
1948− "has_false_positive_signal": false,
1949− "phase0_status": "filtered_outdated",
1950− "phase0_reason": "Thread is flagged outdated by GitHub diff context."
1951− },
1952− {
1953− "index": 67,
1954− "thread_id": "PRRT_kwDORLtfbc5v-XV8",
1955− "path": "apps/server/src/persistence/Services/Projects.ts",
1956− "line": null,
1957− "is_outdated": true,
1958− "is_resolved": false,
1959− "author": "coderabbitai",
1960− "title": "and `pruneMissing()` for consistent error handling.** Both methods perform database operations (`listProjectRows()` and `deleteProject()`) that can fail, but lack error type parameters. Currently they use `Effect.orDie` to convert failures to defects (crashes) instead of returning typed errors. This is inconsistent with `add/remove/updateScripts` which have `Error` channels, and violates the guideline to maintain predictable behavior under failures. Update signatures to:",
1961− "severity": "High",
1962− "has_false_positive_signal": false,
1963− "phase0_status": "filtered_outdated",
1964− "phase0_reason": "Thread is flagged outdated by GitHub diff context."
1965− },
1966− {
1967− "index": 68,
1968− "thread_id": "PRRT_kwDORLtfbc5v-X3U",
1969− "path": "apps/server/src/orchestration/engine.ts",
1970− "line": null,
1971− "is_outdated": true,
1972− "is_resolved": true,
1973− "author": "macroscopeapp",
1974− "title": "Consider resetting `this.readModel` in `stop()` to prevent state corruption if `start()` is called again\u2014`bootstrapReadModel()` would otherwise re-apply all events on top of existing state. \u2705 Addressed in 9ef01eb97e9a4e7e174e383350febd08951a0dc3",
1975− "severity": "High",
1976− "has_false_positive_signal": false,
1977− "phase0_status": "filtered_outdated",
1978− "phase0_reason": "Thread is flagged outdated by GitHub diff context."
1979− },
1980− {
1981− "index": 69,
1982− "thread_id": "PRRT_kwDORLtfbc5v-X3W",
1983− "path": "apps/server/src/wsServer.ts",
1984− "line": null,
1985− "is_outdated": true,
1986− "is_resolved": true,
1987− "author": "macroscopeapp",
1988− "title": "If `orchestrationEngine.dispatch` fails after `providerManager.revertToCheckpoint` succeeds, the filesystem is reverted but the read model isn't updated, causing inconsistency. Consider either dispatching the state update first (since revert can be retried), or wrapping both in a transaction-like pattern that restores the checkpoint on dispatch failure. \u2705 Resolved in af53ae8b4845852a320f108dda30b32afc3c4029",
1989− "severity": "High",
1990− "has_false_positive_signal": false,
1991− "phase0_status": "filtered_outdated",
1992− "phase0_reason": "Thread is flagged outdated by GitHub diff context."
1993− },
1994− {
1995− "index": 70,
1996− "thread_id": "PRRT_kwDORLtfbc5v-X3Y",
1997− "path": "packages/contracts/src/orchestration.ts",
1998− "line": 141,
1999− "is_outdated": false,
2000− "is_resolved": true,
2001− "author": "macroscopeapp",
2002− "title": "`streaming` is required here but optional in `SendMessageCommandSchema`. Messages created without this field will fail validation. Consider using `Schema.optional(Schema.Boolean)` for consistency. No longer relevant as of b2f29834553747157b9eba6a5fa9de1b84693dce",
2003− "severity": "Medium",
2004− "has_false_positive_signal": false,
2005− "phase0_status": "filtered_resolved",
2006− "phase0_reason": "Thread is already resolved on GitHub."
2007− },
2008− {
2009− "index": 71,
2010− "thread_id": "PRRT_kwDORLtfbc5v-Y_d",
2011− "path": "apps/server/src/orchestration/engine.ts",
2012− "line": null,
2013− "is_outdated": true,
2014− "is_resolved": false,
2015− "author": "coderabbitai",
2016− "title": "is called.** Interrupting the worker fiber leaves any queued command envelopes unprocessed, and their `Deferred` results will never resolve. Callers awaiting `dispatch()` will hang indefinitely after stop. Consider draining or failing pending commands before interrupting. <details> <summary>\ud83d\udee1\ufe0f Suggested approach: fail pending commands on stop</summary>",
2017− "severity": "Medium",
2018− "has_false_positive_signal": false,
2019− "phase0_status": "filtered_outdated",
2020− "phase0_reason": "Thread is flagged outdated by GitHub diff context."
2021− },
2022− {
2023− "index": 72,
2024− "thread_id": "PRRT_kwDORLtfbc5v-cf4",
2025− "path": "apps/server/src/wsServer.ts",
2026− "line": 75,
2027− "is_outdated": false,
2028− "is_resolved": false,
2029− "author": "macroscopeapp",
2030− "title": "Consider attaching a no-op error listener before `socket.write` (e.g., `socket.on('error', () => {})`) to prevent an unhandled `EPIPE`/`ECONNRESET` from crashing the process if the client disconnects mid-handshake.",
2031− "severity": "High",
2032− "has_false_positive_signal": false,
2033− "canonical_id": "C003",
2034− "phase0_status": "actionable_canonical",
2035− "phase0_reason": "Canonical actionable item."
2036− },
2037− {
2038− "index": 73,
2039− "thread_id": "PRRT_kwDORLtfbc5v-gEm",
2040− "path": "apps/server/src/orchestration/reducer.ts",
2041− "line": null,
2042− "is_outdated": true,
2043− "is_resolved": false,
2044− "author": "cursor",
2045− "title": "Reducer overwrites Codex thread ID with orchestration ID",
2046− "severity": "High",
2047− "has_false_positive_signal": false,
2048− "phase0_status": "filtered_outdated",
2049− "phase0_reason": "Thread is flagged outdated by GitHub diff context."
2050− },
2051− {
2052− "index": 74,
2053− "thread_id": "PRRT_kwDORLtfbc5v-gEo",
2054− "path": "apps/server/src/orchestration/reducer.ts",
2055− "line": null,
2056− "is_outdated": true,
2057− "is_resolved": false,
2058− "author": "cursor",
2059− "title": "Reducer never sets latestTurnStartedAt breaking completion summary",
2060− "severity": "Medium",
2061− "has_false_positive_signal": false,
2062− "phase0_status": "filtered_outdated",
2063− "phase0_reason": "Thread is flagged outdated by GitHub diff context."
2064− },
2065− {
2066− "index": 75,
2067− "thread_id": "PRRT_kwDORLtfbc5v-gEp",
2068− "path": "apps/web/src/routes/__root.tsx",
2069− "line": null,
2070− "is_outdated": true,
2071− "is_resolved": false,
2072− "author": "cursor",
2073− "title": "Stale closure creates duplicate threads on page refresh",
2074− "severity": "Medium",
2075− "has_false_positive_signal": false,
2076− "phase0_status": "filtered_outdated",
2077− "phase0_reason": "Thread is flagged outdated by GitHub diff context."
2078− },
2079− {
2080− "index": 76,
2081− "thread_id": "PRRT_kwDORLtfbc5v-iPH",
2082− "path": "apps/server/src/persistence/Layers/Projects.ts",
2083− "line": null,
2084− "is_outdated": true,
2085− "is_resolved": true,
2086− "author": "macroscopeapp",
2087− "title": "Consider distinguishing `ENOENT`/`ENOTDIR` (directory truly absent) from transient errors like `EACCES` or `EIO` in `isDirectory`. Currently, any error returns `false`, so `pruneMissing` may delete projects that are present but temporarily inaccessible. No longer relevant as of b2f29834553747157b9eba6a5fa9de1b84693dce",
2088− "severity": "High",
2089− "has_false_positive_signal": false,
2090− "phase0_status": "filtered_outdated",
2091− "phase0_reason": "Thread is flagged outdated by GitHub diff context."
2092− },
2093− {
2094− "index": 77,
2095− "thread_id": "PRRT_kwDORLtfbc5v-iPJ",
2096− "path": "apps/server/src/orchestration/Layer.ts",
2097− "line": null,
2098− "is_outdated": true,
2099− "is_resolved": true,
2100− "author": "macroscopeapp",
2101− "title": "Consider validating events through `reduceEvent` before persisting to avoid \"poison pill\" events. Currently, if `reduceEvent` fails after `eventStore.append`, the error is swallowed but the event remains in the database. On restart, `bootstrapReadModel` will fail on that same event, bricking the service. No longer relevant as of b2f29834553747157b9eba6a5fa9de1b84693dce",
2102− "severity": "High",
2103− "has_false_positive_signal": false,
2104− "phase0_status": "filtered_outdated",
2105− "phase0_reason": "Thread is flagged outdated by GitHub diff context."
2106− },
2107− {
2108− "index": 78,
2109− "thread_id": "PRRT_kwDORLtfbc5v-kr_",
2110− "path": "apps/server/src/orchestration/Layer.ts",
2111− "line": null,
2112− "is_outdated": true,
2113− "is_resolved": false,
2114− "author": "cursor",
2115− "title": "Listener failure falsely fails dispatch after event persistence",
2116− "severity": "High",
2117− "has_false_positive_signal": false,
2118− "phase0_status": "filtered_outdated",
2119− "phase0_reason": "Thread is flagged outdated by GitHub diff context."
2120− },
2121− {
2122− "index": 79,
2123− "thread_id": "PRRT_kwDORLtfbc5v-ksB",
2124− "path": "apps/server/src/orchestration/Layer.ts",
2125− "line": null,
2126− "is_outdated": true,
2127− "is_resolved": false,
2128− "author": "cursor",
2129− "title": "Unused PubSub instances created and published to",
2130− "severity": "Low",
2131− "has_false_positive_signal": false,
2132− "phase0_status": "filtered_outdated",
2133− "phase0_reason": "Thread is flagged outdated by GitHub diff context."
2134− },
2135− {
2136− "index": 80,
2137− "thread_id": "PRRT_kwDORLtfbc5wBEEV",
2138− "path": "apps/server/src/wsServer.ts",
2139− "line": null,
2140− "is_outdated": true,
2141− "is_resolved": false,
2142− "author": "macroscopeapp",
2143− "title": "Consider normalizing `params.cwd` before comparing with `entry.cwd`, since `ProjectRepository.add` normalizes paths (e.g., lowercasing on Windows). Otherwise, valid requests with different casing or formatting won't match and the git read model won't be updated. <details> <summary>\ud83d\ude80 Reply \"<strong>fix it for me</strong>\" or copy this <strong>AI Prompt</strong> for your agent:</summary>",
2144− "severity": "High",
2145− "has_false_positive_signal": false,
2146− "phase0_status": "filtered_outdated",
2147− "phase0_reason": "Thread is flagged outdated by GitHub diff context."
2148− },
2149− {
2150− "index": 81,
2151− "thread_id": "PRRT_kwDORLtfbc5wBEEX",
2152− "path": "apps/server/src/persistence/Layers/OrchestrationEvents.ts",
2153− "line": null,
2154− "is_outdated": true,
2155− "is_resolved": true,
2156− "author": "macroscopeapp",
2157− "title": "`readAll` uses `Number.MAX_SAFE_INTEGER` as the limit, which could exhaust memory as events grow. If this is intentional (e.g., for testing or small datasets), consider adding a comment documenting this constraint. Otherwise, consider implementing pagination or streaming. No longer relevant as of b2f29834553747157b9eba6a5fa9de1b84693dce",
2158− "severity": "Medium",
2159− "has_false_positive_signal": false,
2160− "phase0_status": "filtered_outdated",
2161− "phase0_reason": "Thread is flagged outdated by GitHub diff context."
2162− },
2163− {
2164− "index": 82,
2165− "thread_id": "PRRT_kwDORLtfbc5wBEEY",
2166− "path": "apps/server/src/orchestration/reducer.ts",
2167− "line": null,
2168− "is_outdated": true,
2169− "is_resolved": true,
2170− "author": "macroscopeapp",
2171− "title": "When a duplicate `thread.created` event is processed, the existing thread is fully replaced with a fresh object containing empty `messages`, `session`, and `turnDiffSummaries`. Consider returning the existing thread unchanged (or merging only metadata) to avoid data loss on event replay. No longer relevant as of b2f29834553747157b9eba6a5fa9de1b84693dce",
2172− "severity": "High",
2173− "has_false_positive_signal": false,
2174− "phase0_status": "filtered_outdated",
2175− "phase0_reason": "Thread is flagged outdated by GitHub diff context."
2176− },
2177− {
2178− "index": 83,
2179− "thread_id": "PRRT_kwDORLtfbc5wBEEZ",
2180− "path": "apps/server/src/orchestration/Layer.ts",
2181− "line": null,
2182− "is_outdated": true,
2183− "is_resolved": true,
2184− "author": "macroscopeapp",
2185− "title": "Listener failures abort the notification chain and fail the command's `Deferred`, even though the event was successfully persisted. Consider using `{ concurrency: \"unbounded\" }` with `Effect.forEach` and catching errors per-listener, or using `Effect.catchAll` after each notification call to log and continue. No longer relevant as of b2f29834553747157b9eba6a5fa9de1b84693dce",
2186− "severity": "High",
2187− "has_false_positive_signal": false,
2188− "phase0_status": "filtered_outdated",
2189− "phase0_reason": "Thread is flagged outdated by GitHub diff context."
2190− },
2191− {
2192− "index": 84,
2193− "thread_id": "PRRT_kwDORLtfbc5wBFWr",
2194− "path": "apps/server/src/orchestration/Layer.ts",
2195− "line": null,
2196− "is_outdated": true,
2197− "is_resolved": true,
2198− "author": "macroscopeapp",
2199− "title": "Consider guarding against duplicate `thread.create` commands\u2014currently, sending a create command with an existing thread ID will replace that thread's state (messages, session, etc.) with a fresh empty object. No longer relevant as of b2f29834553747157b9eba6a5fa9de1b84693dce",
2200− "severity": "Medium",
2201− "has_false_positive_signal": false,
2202− "phase0_status": "filtered_outdated",
2203− "phase0_reason": "Thread is flagged outdated by GitHub diff context."
2204− },
2205− {
2206− "index": 85,
2207− "thread_id": "PRRT_kwDORLtfbc5wBFWs",
2208− "path": "apps/server/src/orchestration/Errors.ts",
2209− "line": 126,
2210− "is_outdated": false,
2211− "is_resolved": false,
2212− "author": "macroscopeapp",
2213− "title": "Template literal interpolation throws `TypeError` if `cause` is a `Symbol`. Consider using `String(cause)` for safe coercion.",
2214− "severity": "Low",
2215− "has_false_positive_signal": false,
2216− "canonical_id": "C041",
2217− "phase0_status": "actionable_canonical",
2218− "phase0_reason": "Canonical actionable item."
2219− },
2220− {
2221− "index": 86,
2222− "thread_id": "PRRT_kwDORLtfbc5wBFv4",
2223− "path": "apps/server/src/orchestration/Errors.ts",
2224− "line": 117,
2225− "is_outdated": false,
2226− "is_resolved": false,
2227− "author": "macroscopeapp",
2228− "title": "Template literal `${cause}` throws if `cause` is a `Symbol`. Consider using `String(cause)` instead.",
2229− "severity": "Medium",
2230− "has_false_positive_signal": false,
2231− "canonical_id": "C011",
2232− "phase0_status": "actionable_canonical",
2233− "phase0_reason": "Canonical actionable item."
2234− },
2235− {
2236− "index": 87,
2237− "thread_id": "PRRT_kwDORLtfbc5wBGN5",
2238− "path": "apps/server/src/orchestration/Layer.ts",
2239− "line": null,
2240− "is_outdated": true,
2241− "is_resolved": false,
2242− "author": "cursor",
2243− "title": "Listener failure fails deferred after event already persisted",
2244− "severity": "Medium",
2245− "has_false_positive_signal": false,
2246− "phase0_status": "filtered_outdated",
2247− "phase0_reason": "Thread is flagged outdated by GitHub diff context."
2248− },
2249− {
2250− "index": 88,
2251− "thread_id": "PRRT_kwDORLtfbc5wBGN8",
2252− "path": "apps/server/src/orchestration/Layer.ts",
2253− "line": null,
2254− "is_outdated": true,
2255− "is_resolved": false,
2256− "author": "cursor",
2257− "title": "Unused PubSub instances created but never subscribed to",
2258− "severity": "Low",
2259− "has_false_positive_signal": false,
2260− "phase0_status": "filtered_outdated",
2261− "phase0_reason": "Thread is flagged outdated by GitHub diff context."
2262− },
2263− {
2264− "index": 89,
2265− "thread_id": "PRRT_kwDORLtfbc5wBGN-",
2266− "path": "apps/server/src/wsServer.ts",
2267− "line": null,
2268− "is_outdated": true,
2269− "is_resolved": false,
2270− "author": "cursor",
2271− "title": "Streaming text deltas create excessive persistent events",
2272− "severity": "Medium",
2273− "has_false_positive_signal": false,
2274− "phase0_status": "filtered_outdated",
2275− "phase0_reason": "Thread is flagged outdated by GitHub diff context."
2276− },
2277− {
2278− "index": 90,
2279− "thread_id": "PRRT_kwDORLtfbc5whszQ",
2280− "path": "apps/server/src/orchestration/Layers/ProviderCommandReactor.ts",
2281− "line": 84,
2282− "is_outdated": false,
2283− "is_resolved": false,
2284− "author": "cursor",
2285− "title": "Unbounded memory growth in turn start deduplication set",
2286− "severity": "Medium",
2287− "has_false_positive_signal": false,
2288− "canonical_id": "C018",
2289− "phase0_status": "actionable_canonical",
2290− "phase0_reason": "Canonical actionable item."
2291− },
2292− {
2293− "index": 91,
2294− "thread_id": "PRRT_kwDORLtfbc5whszT",
2295− "path": "apps/server/src/orchestration/Layers/CheckpointReactor.ts",
2296− "line": null,
2297− "is_outdated": true,
2298− "is_resolved": false,
2299− "author": "cursor",
2300− "title": "Fallback session matching compares incompatible identity types",
2301− "severity": "Medium",
2302− "has_false_positive_signal": false,
2303− "phase0_status": "filtered_outdated",
2304− "phase0_reason": "Thread is flagged outdated by GitHub diff context."
2305− },
2306− {
2307− "index": 92,
2308− "thread_id": "PRRT_kwDORLtfbc5whszW",
2309− "path": "apps/server/src/orchestration/Layers/CheckpointReactor.ts",
2310− "line": 542,
2311− "is_outdated": false,
2312− "is_resolved": false,
2313− "author": "cursor",
2314− "title": "Forked revert dispatch risks read model inconsistency",
2315− "severity": "Medium",
2316− "has_false_positive_signal": false,
2317− "canonical_id": "C012",
2318− "phase0_status": "actionable_canonical",
2319− "phase0_reason": "Canonical actionable item."
2320− },
2321− {
2322− "index": 93,
2323− "thread_id": "PRRT_kwDORLtfbc5whtrM",
2324− "path": "apps/server/src/orchestration/Layers/OrchestrationEngine.ts",
2325− "line": 99,
2326− "is_outdated": false,
2327− "is_resolved": false,
2328− "author": "macroscopeapp",
2329− "title": "If `projectionPipeline.projectEvent` fails after `eventStore.append` succeeds, the event is persisted but `readModel` isn't updated, causing desync. Consider updating the in-memory `readModel` immediately after append (before the external projection), so local state stays consistent regardless of downstream failures.",
2330− "severity": "Medium",
2331− "has_false_positive_signal": false,
2332− "canonical_id": "C013",
2333− "phase0_status": "actionable_canonical",
2334− "phase0_reason": "Canonical actionable item."
2335− },
2336− {
2337− "index": 94,
2338− "thread_id": "PRRT_kwDORLtfbc5whtrN",
2339− "path": "apps/web/src/wsTransport.ts",
2340− "line": 59,
2341− "is_outdated": false,
2342− "is_resolved": false,
2343− "author": "macroscopeapp",
2344− "title": "Suggestion: don\u2019t spread `params` into `body`; it can override `_tag` and mishandle non-object values. Keep `_tag` separate and nest `params` under a single key (e.g., `data`), or validate `params` is a plain object.",
2345− "severity": "Low",
2346− "has_false_positive_signal": false,
2347− "canonical_id": "C059",
2348− "phase0_status": "actionable_canonical",
2349− "phase0_reason": "Canonical actionable item."
2350− },
2351− {
2352− "index": 95,
2353− "thread_id": "PRRT_kwDORLtfbc5whtrP",
2354− "path": "apps/server/src/persistence/NodeSqliteClient.ts",
2355− "line": 108,
2356− "is_outdated": false,
2357− "is_resolved": true,
2358− "author": "macroscopeapp",
2359− "title": "`runValues` doesn't call `setReadBigInts` before execution, so cached statements may retain stale bigint settings from prior `runStatement` calls. Consider adding `statement.setReadBigInts(...)` similar to line 98. <details> <summary>\ud83d\ude80 Reply \"<strong>fix it for me</strong>\" or copy this <strong>AI Prompt</strong> for your agent:</summary>",
2360− "severity": "Low",
2361− "has_false_positive_signal": false,
2362− "phase0_status": "filtered_resolved",
2363− "phase0_reason": "Thread is already resolved on GitHub."
2364− },
2365− {
2366− "index": 96,
2367− "thread_id": "PRRT_kwDORLtfbc5whtrR",
2368− "path": "apps/server/src/wsServer.ts",
2369− "line": 104,
2370− "is_outdated": false,
2371− "is_resolved": false,
2372− "author": "macroscopeapp",
2373− "title": "When array chunks contain a multi-byte UTF-8 character split across boundaries, decoding each chunk separately produces replacement characters. Consider using `Buffer.concat()` on all chunks before calling `.toString(\"utf8\")`. <details> <summary>\ud83d\ude80 Reply \"<strong>fix it for me</strong>\" or copy this <strong>AI Prompt</strong> for your agent:</summary>",
2374− "severity": "Low",
2375− "has_false_positive_signal": false,
2376− "canonical_id": "C054",
2377− "phase0_status": "actionable_canonical",
2378− "phase0_reason": "Canonical actionable item."
2379− },
2380− {
2381− "index": 97,
2382− "thread_id": "PRRT_kwDORLtfbc5whtrS",
2383− "path": "apps/server/src/main.ts",
2384− "line": null,
2385− "is_outdated": true,
2386− "is_resolved": true,
2387− "author": "macroscopeapp",
2388− "title": "On Windows, `~\\data` bypasses home expansion because only `~/` is checked. Consider also checking for `~\\` to avoid writing to `${CWD}/~` instead of the home directory. \u2705 Resolved in d102702d9556fac36379e13e7a89d21f230ebcb6",
2389− "severity": "Low",
2390− "has_false_positive_signal": false,
2391− "phase0_status": "filtered_outdated",
2392− "phase0_reason": "Thread is flagged outdated by GitHub diff context."
2393− },
2394− {
2395− "index": 98,
2396− "thread_id": "PRRT_kwDORLtfbc5whtrX",
2397− "path": "apps/server/src/persistence/NodeSqliteClient.ts",
2398− "line": null,
2399− "is_outdated": true,
2400− "is_resolved": true,
2401− "author": "macroscopeapp",
2402− "title": "Consider also checking `options.readonly` before enabling WAL mode\u2014changing journal mode on a read-only connection will throw. \u2705 Resolved in 3379feed8d37d82ba2415e39e8d50958ee680719",
2403− "severity": "Low",
2404− "has_false_positive_signal": false,
2405− "phase0_status": "filtered_outdated",
2406− "phase0_reason": "Thread is flagged outdated by GitHub diff context."
2407− },
2408− {
2409− "index": 99,
2410− "thread_id": "PRRT_kwDORLtfbc5whtrb",
2411− "path": "apps/server/src/main.ts",
2412− "line": null,
2413− "is_outdated": true,
2414− "is_resolved": true,
2415− "author": "macroscopeapp",
2416− "title": "The server shuts down immediately after starting because the scope closes when `makeServerProgram` returns. Consider adding `yield* Effect.never` after logging to keep the process alive. \u2705 Resolved in 68c8eaa6198d766a675eddfb5600482df885ea77",
2417− "severity": "High",
2418− "has_false_positive_signal": false,
2419− "phase0_status": "filtered_outdated",
2420− "phase0_reason": "Thread is flagged outdated by GitHub diff context."
2421− },
2422− {
2423− "index": 100,
2424− "thread_id": "PRRT_kwDORLtfbc5whxJC",
2425− "path": "packages/contracts/src/orchestration.ts",
2426− "line": 253,
2427− "is_outdated": false,
2428− "is_resolved": false,
2429− "author": "macroscopeapp",
2430− "title": "`defaultModel` should be `Schema.optional(Schema.NullOr(Schema.String))` to allow clearing the value. Currently there's no way to reset it to `null` since omitting means \"no change\" in patch semantics. <details> <summary>\ud83d\ude80 Reply \"<strong>fix it for me</strong>\" or copy this <strong>AI Prompt</strong> for your agent:</summary>",
2431− "severity": "Low",
2432− "has_false_positive_signal": false,
2433− "canonical_id": "C060",
2434− "phase0_status": "actionable_canonical",
2435− "phase0_reason": "Canonical actionable item."
2436− },
2437− {
2438− "index": 101,
2439− "thread_id": "PRRT_kwDORLtfbc5whxJO",
2440− "path": "apps/server/src/orchestration/Layers/ProjectionPipeline.ts",
2441− "line": 99,
2442− "is_outdated": false,
2443− "is_resolved": false,
2444− "author": "macroscopeapp",
2445− "title": "The gap-filling fallback logic can retain messages from turns that are about to be deleted, causing foreign key violations. Consider removing the fallback logic entirely, or filtering `fallbackUserMessages` and `fallbackAssistantMessages` to only include messages whose `turnId` is in `retainedTurnIds`. <details> <summary>\ud83d\ude80 Reply \"<strong>fix it for me</strong>\" or copy this <strong>AI Prompt</strong> for your agent:</summary>",
2446− "severity": "Medium",
2447− "has_false_positive_signal": false,
2448− "canonical_id": "C015",
2449− "phase0_status": "actionable_canonical",
2450− "phase0_reason": "Canonical actionable item."
2451− },
2452− {
2453− "index": 102,
2454− "thread_id": "PRRT_kwDORLtfbc5whxXx",
2455− "path": "apps/server/src/persistence/Layers/Sqlite.ts",
2456− "line": 29,
2457− "is_outdated": false,
2458− "is_resolved": true,
2459− "author": "macroscopeapp",
2460− "title": "The `setup` layer always sets `journal_mode = WAL`, ignoring the `disableWAL` config. Consider passing the config to `setup` and conditionally executing the pragma. <details> <summary>\ud83d\ude80 Reply \"<strong>fix it for me</strong>\" or copy this <strong>AI Prompt</strong> for your agent:</summary>",
2461− "severity": "Low",
2462− "has_false_positive_signal": false,
2463− "phase0_status": "filtered_resolved",
2464− "phase0_reason": "Thread is already resolved on GitHub."
2465− },
2466− {
2467− "index": 103,
2468− "thread_id": "PRRT_kwDORLtfbc5whxX9",
2469− "path": "apps/server/src/persistence/NodeSqliteClient.ts",
2470− "line": 145,
2471− "is_outdated": false,
2472− "is_resolved": false,
2473− "author": "macroscopeapp",
2474− "title": "In `executeUnprepared`, preparing outside an effect and not closing the statement can cause uncaught errors and leaks. Suggest wrapping with `Effect.acquireUseRelease`: prepare in acquire (error-safe) and `finalize` in release.",
2475− "severity": "Medium",
2476− "has_false_positive_signal": false,
2477− "canonical_id": "C024",
2478− "phase0_status": "actionable_canonical",
2479− "phase0_reason": "Canonical actionable item."
2480− },
2481− {
2482− "index": 104,
2483− "thread_id": "PRRT_kwDORLtfbc5wiAo6",
2484− "path": "apps/server/src/main.ts",
2485− "line": null,
2486− "is_outdated": true,
2487− "is_resolved": true,
2488− "author": "macroscopeapp",
2489− "title": "There's a TOCTOU race between closing the test server and the actual `server.start()` call in `makeServerProgram`. Consider either passing the bound server directly to the caller, or documenting this as an accepted limitation with a retry strategy at the call site. No longer relevant as of 69d5caa0f94522b5c90285aa752d9410f756a86e",
2490− "severity": "Low",
2491− "has_false_positive_signal": false,
2492− "phase0_status": "filtered_outdated",
2493− "phase0_reason": "Thread is flagged outdated by GitHub diff context."
2494− },
2495− {
2496− "index": 105,
2497− "thread_id": "PRRT_kwDORLtfbc5wiLNN",
2498− "path": "apps/server/integration/OrchestrationEngineHarness.integration.ts",
2499− "line": null,
2500− "is_outdated": true,
2501− "is_resolved": false,
2502− "author": "cursor",
2503− "title": "Duplicate checkpoint ref generation logic across four files",
2504− "severity": "Medium",
2505− "has_false_positive_signal": false,
2506− "phase0_status": "filtered_outdated",
2507− "phase0_reason": "Thread is flagged outdated by GitHub diff context."
2508− },
2509− {
2510− "index": 106,
2511− "thread_id": "PRRT_kwDORLtfbc5wiLNS",
2512− "path": "apps/server/package.json",
2513− "line": 14,
2514− "is_outdated": false,
2515− "is_resolved": false,
2516− "author": "cursor",
2517− "title": "Build script uses `node` to run `.ts` file directly",
2518− "severity": "Medium",
2519− "has_false_positive_signal": false,
2520− "canonical_id": "C007",
2521− "phase0_status": "actionable_canonical",
2522− "phase0_reason": "Canonical actionable item."
2523− },
2524− {
2525− "index": 107,
2526− "thread_id": "PRRT_kwDORLtfbc5wiLhQ",
2527− "path": "apps/server/src/orchestration/Layers/ProjectionSnapshotQuery.ts",
2528− "line": 71,
2529− "is_outdated": false,
2530− "is_resolved": false,
2531− "author": "macroscopeapp",
2532− "title": "`REQUIRED_SNAPSHOT_PROJECTORS` includes `pending-approvals` and `thread-turns`, but `getSnapshot` doesn't query their data. If these projectors lag behind, the returned `snapshotSequence` will be lower than what the included data actually reflects, causing clients to replay already-applied events. Consider filtering `REQUIRED_SNAPSHOT_PROJECTORS` to only include projectors whose data is actually fetched in the snapshot. <details> <summary>\ud83d\ude80 Reply \"<strong>fix it for me</strong>\" or copy this <strong>AI Prompt</strong> for your agent:</summary>",
2533− "severity": "Medium",
2534− "has_false_positive_signal": false,
2535− "canonical_id": "C017",
2536− "phase0_status": "actionable_canonical",
2537− "phase0_reason": "Canonical actionable item."
2538− },
2539− {
2540− "index": 108,
2541− "thread_id": "PRRT_kwDORLtfbc5wiLhY",
2542− "path": "apps/server/src/provider/Layers/ProviderSessionDirectory.ts",
2543− "line": 94,
2544− "is_outdated": false,
2545− "is_resolved": false,
2546− "author": "macroscopeapp",
2547− "title": "The read-modify-write pattern (`getBySessionId` \u2192 merge \u2192 `upsert`) is susceptible to lost updates under concurrent writes. Consider wrapping in a transaction or adding optimistic concurrency control (e.g., version field) if concurrent session updates are expected. <details> <summary>\ud83d\ude80 Reply \"<strong>fix it for me</strong>\" or copy this <strong>AI Prompt</strong> for your agent:</summary>",
2548− "severity": "Low",
2549− "has_false_positive_signal": false,
2550− "canonical_id": "C050",
2551− "phase0_status": "actionable_canonical",
2552− "phase0_reason": "Canonical actionable item."
2553− },
2554− {
2555− "index": 109,
2556− "thread_id": "PRRT_kwDORLtfbc5wiQi9",
2557− "path": "apps/server/src/checkpointing/Layers/CheckpointStore.ts",
2558− "line": 87,
2559− "is_outdated": false,
2560− "is_resolved": true,
2561− "author": "cursor",
2562− "title": "Incorrect `Effect.catch` API usage in `isGitRepository`",
2563− "severity": "High",
2564− "has_false_positive_signal": true,
2565− "phase0_status": "filtered_resolved",
2566− "phase0_reason": "Thread is already resolved on GitHub."
2567− },
2568− {
2569− "index": 110,
2570− "thread_id": "PRRT_kwDORLtfbc5wiaR-",
2571− "path": "apps/server/src/persistence/Layers/OrchestrationCommandReceipts.ts",
2572− "line": 75,
2573− "is_outdated": false,
2574− "is_resolved": false,
2575− "author": "macroscopeapp",
2576− "title": "`SqlSchema.findOneOption` can produce both SQL errors and decode errors, but `mapError` wraps all as `PersistenceSqlError`. Consider distinguishing `ParseError` from SQL errors and mapping decode failures to `PersistenceDecodeError` instead. <details> <summary>\ud83d\ude80 Reply \"<strong>fix it for me</strong>\" or copy this <strong>AI Prompt</strong> for your agent:</summary>",
2577− "severity": "Low",
2578− "has_false_positive_signal": false,
2579− "canonical_id": "C047",
2580− "phase0_status": "actionable_canonical",
2581− "phase0_reason": "Canonical actionable item."
2582− },
2583− {
2584− "index": 111,
2585− "thread_id": "PRRT_kwDORLtfbc5wiaSC",
2586− "path": "apps/web/src/wsTransport.ts",
2587− "line": null,
2588− "is_outdated": true,
2589− "is_resolved": true,
2590− "author": "macroscopeapp",
2591− "title": "If `message.error` exists but lacks a `message` string, the promise resolves with `undefined` instead of rejecting. Consider rejecting with a fallback error message when `message.error` is truthy but doesn't have a valid `message` property. \u2705 Resolved in ef341394699edcf9ab21af4a7bbf0186a87ebce5",
2592− "severity": "Low",
2593− "has_false_positive_signal": false,
2594− "phase0_status": "filtered_outdated",
2595− "phase0_reason": "Thread is flagged outdated by GitHub diff context."
2596− },
2597− {
2598− "index": 112,
2599− "thread_id": "PRRT_kwDORLtfbc5widJw",
2600− "path": "apps/server/src/checkpointing/Layers/CheckpointStore.ts",
2601− "line": 94,
2602− "is_outdated": false,
2603− "is_resolved": false,
2604− "author": "cursor",
2605− "title": "Inconsistent input trimming across CheckpointStore methods",
2606− "severity": "Low",
2607− "has_false_positive_signal": false,
2608− "canonical_id": "C008",
2609− "phase0_status": "actionable_canonical",
2610− "phase0_reason": "Canonical actionable item."
2611− },
2612− {
2613− "index": 113,
2614− "thread_id": "PRRT_kwDORLtfbc5widJx",
2615− "path": "apps/server/package.json",
2616− "line": 14,
2617− "is_outdated": false,
2618− "is_resolved": false,
2619− "author": "cursor",
2620− "title": "Build script requires implicit Node.js TypeScript support",
2621− "severity": "Medium",
2622− "has_false_positive_signal": true,
2623− "phase0_status": "filtered_invalid",
2624− "phase0_reason": "Thread contains explicit false-positive determination in replies."
2625− },
2626− {
2627− "index": 114,
2628− "thread_id": "PRRT_kwDORLtfbc5wio-r",
2629− "path": "apps/server/src/persistence/NodeSqliteClient.ts",
2630− "line": 99,
2631− "is_outdated": false,
2632− "is_resolved": false,
2633− "author": "macroscopeapp",
2634− "title": "`statement.run()` returns a `RunResult` object, not an array. Casting it to `ReadonlyArray<any>` will cause runtime errors when consumers call array methods. Consider wrapping the result (e.g., `[result]`) or returning a properly typed object.",
2635− "severity": "Low",
2636− "has_false_positive_signal": false,
2637− "canonical_id": "C048",
2638− "phase0_status": "actionable_canonical",
2639− "phase0_reason": "Canonical actionable item."
2640− },
2641− {
2642− "index": 115,
2643− "thread_id": "PRRT_kwDORLtfbc5wiqFX",
2644− "path": "apps/server/src/checkpointing/Layers/CheckpointStore.ts",
2645− "line": 284,
2646− "is_outdated": false,
2647− "is_resolved": false,
2648− "author": "cursor",
2649− "title": "Duplicate `checkpointRefForThreadTurn` function in two production files",
2650− "severity": "Low",
2651− "has_false_positive_signal": false,
2652− "phase0_status": "filtered_invalid",
2653− "phase0_reason": "Invalid after post-rewrite audit: No longer duplicated; single production source via Refs.ts."
2654− },
2655− {
2656− "index": 116,
2657− "thread_id": "PRRT_kwDORLtfbc5wjahy",
2658− "path": "apps/server/src/main.ts",
2659− "line": null,
2660− "is_outdated": true,
2661− "is_resolved": true,
2662− "author": "macroscopeapp",
2663− "title": "`Effect.callback` lacks a cleanup function. If the fiber is interrupted while `server` or `fallback` is listening, the socket leaks and the port stays bound. Consider returning a cleanup function that closes the active server. No longer relevant as of 69d5caa0f94522b5c90285aa752d9410f756a86e",
2664− "severity": "Low",
2665− "has_false_positive_signal": false,
2666− "phase0_status": "filtered_outdated",
2667− "phase0_reason": "Thread is flagged outdated by GitHub diff context."
2668− },
2669− {
2670− "index": 117,
2671− "thread_id": "PRRT_kwDORLtfbc5wj4b_",
2672− "path": "apps/server/src/open.ts",
2673− "line": 21,
2674− "is_outdated": false,
2675− "is_resolved": true,
2676− "author": "macroscopeapp",
2677− "title": "Suggestion: avoid synchronous `throw` in `resolveEditorLaunch` when used from `Effect.gen`\u2014it becomes a `Defect` and bypasses `OpenError` handling. Return `Effect<EditorLaunch, OpenError>` or wrap with `Effect.try(...)` so failures are typed and caught. \u2705 Resolved in cbc92519e040e963b3257a3192be47bffad5b8ce",
2678− "severity": "Low",
2679− "has_false_positive_signal": false,
2680− "phase0_status": "filtered_resolved",
2681− "phase0_reason": "Thread is already resolved on GitHub."
2682− },
2683− {
2684− "index": 118,
2685− "thread_id": "PRRT_kwDORLtfbc5wj4cE",
2686− "path": "apps/server/src/wsServer.ts",
2687− "line": 545,
2688− "is_outdated": false,
2689− "is_resolved": false,
2690− "author": "macroscopeapp",
2691− "title": "Consider adding `.catch(() => {})` after `Effect.runPromise(handleMessage(ws, raw))` to prevent unhandled rejections from crashing the server if `encodeResponse` or setup logic fails.",
2692− "severity": "Medium",
2693− "has_false_positive_signal": false,
2694− "canonical_id": "C026",
2695− "phase0_status": "actionable_canonical",
2696− "phase0_reason": "Canonical actionable item."
2697− },
2698− {
2699− "index": 119,
2700− "thread_id": "PRRT_kwDORLtfbc5wj4cH",
2701− "path": "apps/server/src/orchestration/Layers/ProviderRuntimeIngestion.ts",
2702− "line": 333,
2703− "is_outdated": false,
2704− "is_resolved": false,
2705− "author": "macroscopeapp",
2706− "title": "A dispatch error in `processEvent` will terminate the `Effect.forever` loop, permanently halting event ingestion. Consider adding error recovery (e.g., `Effect.catchAll` with logging) around `processEvent` so failures don't kill the fiber.",
2707− "severity": "High",
2708− "has_false_positive_signal": false,
2709− "canonical_id": "C002",
2710− "phase0_status": "actionable_canonical",
2711− "phase0_reason": "Canonical actionable item."
2712− },
2713− {
2714− "index": 120,
2715− "thread_id": "PRRT_kwDORLtfbc5wj4cI",
2716− "path": "apps/server/src/open.ts",
2717− "line": null,
2718− "is_outdated": true,
2719− "is_resolved": true,
2720− "author": "macroscopeapp",
2721− "title": "`Effect.scoped` closes immediately after the generator completes, triggering the `ChildProcess` finalizer and terminating the editor. Consider removing `Effect.scoped` or using a different approach to keep the process alive. \u2705 Resolved in cbc92519e040e963b3257a3192be47bffad5b8ce",
2722− "severity": "Medium",
2723− "has_false_positive_signal": false,
2724− "phase0_status": "filtered_outdated",
2725− "phase0_reason": "Thread is flagged outdated by GitHub diff context."
2726− },
2727− {
2728− "index": 121,
2729− "thread_id": "PRRT_kwDORLtfbc5wj4cM",
2730− "path": "apps/server/src/os-jank.ts",
2731− "line": 10,
2732− "is_outdated": false,
2733− "is_resolved": false,
2734− "author": "macroscopeapp",
2735− "title": "Using `-il` flags causes the shell to source profile scripts that may print banners or other text, polluting the captured `PATH`. Consider using `-lc` (login only, non-interactive) to reduce unwanted output.",
2736− "severity": "Medium",
2737− "has_false_positive_signal": false,
2738− "canonical_id": "C023",
2739− "phase0_status": "actionable_canonical",
2740− "phase0_reason": "Canonical actionable item."
2741− },
2742− {
2743− "index": 122,
2744− "thread_id": "PRRT_kwDORLtfbc5wj4cO",
2745− "path": "apps/server/src/config.ts",
2746− "line": 41,
2747− "is_outdated": false,
2748− "is_resolved": false,
2749− "author": "macroscopeapp",
2750− "title": "`Effect.callback` should return a cleanup function to close the server(s) on fiber interruption. Without it, the `Net.Server` handles keep the process alive and leak the port if the effect is cancelled. <details> <summary>\ud83d\ude80 Reply \"<strong>fix it for me</strong>\" or copy this <strong>AI Prompt</strong> for your agent:</summary>",
2751− "severity": "Low",
2752− "has_false_positive_signal": false,
2753− "canonical_id": "C037",
2754− "phase0_status": "actionable_canonical",
2755− "phase0_reason": "Canonical actionable item."
2756− },
2757− {
2758− "index": 123,
2759− "thread_id": "PRRT_kwDORLtfbc5wj5fl",
2760− "path": "apps/server/package.json",
2761− "line": 14,
2762− "is_outdated": false,
2763− "is_resolved": false,
2764− "author": "cursor",
2765− "title": "Build script uses `node` to run `.ts` file directly",
2766− "severity": "Medium",
2767− "has_false_positive_signal": false,
2768− "canonical_id": "C007",
2769− "phase0_status": "actionable_duplicate",
2770− "phase0_reason": "Duplicate of C007."
2771− },
2772− {
2773− "index": 124,
2774− "thread_id": "PRRT_kwDORLtfbc5wj5fn",
2775− "path": "apps/server/src/checkpointing/Errors.ts",
2776− "line": 79,
2777− "is_outdated": false,
2778− "is_resolved": false,
2779− "author": "cursor",
2780− "title": "Redundant `CheckpointInvariantError` in `CheckpointServiceError` union type",
2781− "severity": "Low",
2782− "has_false_positive_signal": false,
2783− "canonical_id": "C034",
2784− "phase0_status": "actionable_canonical",
2785− "phase0_reason": "Canonical actionable item."
2786− },
2787− {
2788− "index": 125,
2789− "thread_id": "PRRT_kwDORLtfbc5wkGlg",
2790− "path": "apps/server/src/ptyAdapter.ts",
2791− "line": null,
2792− "is_outdated": true,
2793− "is_resolved": true,
2794− "author": "macroscopeapp",
2795− "title": "On Windows with Bun, `layer()` returns `BunPtyAdapterLive` which crashes via `Effect.die`. Consider checking `process.platform !== \"win32\"` before choosing `BunPtyAdapterLive`, falling back to `NodePtyAdapterLive` on Windows. No longer relevant as of 3ff826d7cb50031120321f116c1d40f14b030fb8",
2796− "severity": "High",
2797− "has_false_positive_signal": false,
2798− "phase0_status": "filtered_outdated",
2799− "phase0_reason": "Thread is flagged outdated by GitHub diff context."
2800− },
2801− {
2802− "index": 126,
2803− "thread_id": "PRRT_kwDORLtfbc5wkGll",
2804− "path": "apps/server/src/ptyAdapter.ts",
2805− "line": null,
2806− "is_outdated": true,
2807− "is_resolved": true,
2808− "author": "macroscopeapp",
2809− "title": "Race condition: `emitData` returns early if `didExit` is true, but the terminal data callback may fire after `emitExit` sets `didExit = true`, dropping buffered output. Consider removing the `didExit` guard in `emitData`, or deferring `didExit = true` until after processing any pending data callbacks. No longer relevant as of 3ff826d7cb50031120321f116c1d40f14b030fb8",
2810− "severity": "Medium",
2811− "has_false_positive_signal": false,
2812− "phase0_status": "filtered_outdated",
2813− "phase0_reason": "Thread is flagged outdated by GitHub diff context."
2814− },
2815− {
2816− "index": 127,
2817− "thread_id": "PRRT_kwDORLtfbc5wkGlt",
2818− "path": "apps/server/src/ptyAdapter.ts",
2819− "line": null,
2820− "is_outdated": true,
2821− "is_resolved": true,
2822− "author": "macroscopeapp",
2823− "title": "The `didEnsureSpawnHelperExecutable` flag is set before `chmodSync` succeeds. If chmod fails transiently, subsequent calls skip the fix permanently. Consider moving the flag assignment after the chmod operation. No longer relevant as of 3ff826d7cb50031120321f116c1d40f14b030fb8",
2824− "severity": "Low",
2825− "has_false_positive_signal": false,
2826− "phase0_status": "filtered_outdated",
2827− "phase0_reason": "Thread is flagged outdated by GitHub diff context."
2828− },
2829− {
2830− "index": 128,
2831− "thread_id": "PRRT_kwDORLtfbc5wkPaA",
2832− "path": "apps/server/src/orchestration/decider.ts",
2833− "line": 27,
2834− "is_outdated": false,
2835− "is_resolved": false,
2836− "author": "cursor",
2837− "title": "Shared mutable default metadata object causes stale eventId",
2838− "severity": "Medium",
2839− "has_false_positive_signal": false,
2840− "phase0_status": "filtered_invalid",
2841− "phase0_reason": "Invalid after post-rewrite audit: Stale-eventId claim no longer applies; eventId is regenerated per event."
2842− },
2843− {
2844− "index": 129,
2845− "thread_id": "PRRT_kwDORLtfbc5wkPaG",
2846− "path": "apps/server/src/wsServer.ts",
2847− "line": 128,
2848− "is_outdated": false,
2849− "is_resolved": false,
2850− "author": "cursor",
2851− "title": "Duplicate `checkpointRefForThreadTurn` function across files",
2852− "severity": "Low",
2853− "has_false_positive_signal": false,
2854− "phase0_status": "filtered_invalid",
2855− "phase0_reason": "Invalid after post-rewrite audit: No longer duplicated; helper is centralized."
2856− },
2857− {
2858− "index": 130,
2859− "thread_id": "PRRT_kwDORLtfbc5wkPaJ",
2860− "path": "apps/server/src/orchestration/Layers/OrchestrationEngine.ts",
2861− "line": 144,
2862− "is_outdated": false,
2863− "is_resolved": false,
2864− "author": "cursor",
2865− "title": "Engine error handler catches all errors including non-invariant ones",
2866− "severity": "Medium",
2867− "has_false_positive_signal": false,
2868− "canonical_id": "C014",
2869− "phase0_status": "actionable_canonical",
2870− "phase0_reason": "Canonical actionable item."
2871− },
2872− {
2873− "index": 131,
2874− "thread_id": "PRRT_kwDORLtfbc5wkPaL",
2875− "path": "apps/server/src/orchestration/Layers/ProviderRuntimeIngestion.ts",
2876− "line": 178,
2877− "is_outdated": false,
2878− "is_resolved": false,
2879− "author": "cursor",
2880− "title": "ProviderRuntimeIngestion processes events for wrong thread on race",
2881− "severity": "Medium",
2882− "has_false_positive_signal": false,
2883− "canonical_id": "C019",
2884− "phase0_status": "actionable_canonical",
2885− "phase0_reason": "Canonical actionable item."
2886− },
2887− {
2888− "index": 132,
2889− "thread_id": "PRRT_kwDORLtfbc5wkPaO",
2890− "path": "apps/server/src/orchestration/Layers/CheckpointReactor.ts",
2891− "line": 274,
2892− "is_outdated": false,
2893− "is_resolved": false,
2894− "author": "cursor",
2895− "title": "Checkpoint reactor swallows diff errors silently for `turn.completed`",
2896− "severity": "Low",
2897− "has_false_positive_signal": false,
2898− "canonical_id": "C044",
2899− "phase0_status": "actionable_canonical",
2900− "phase0_reason": "Canonical actionable item."
2901− },
2902− {
2903− "index": 133,
2904− "thread_id": "PRRT_kwDORLtfbc5wkRZM",
2905− "path": "apps/server/src/os-jank.ts",
2906− "line": 10,
2907− "is_outdated": false,
2908− "is_resolved": false,
2909− "author": "macroscopeapp",
2910− "title": "Fish shell outputs `$PATH` as space-separated, not colon-separated. Consider checking if the shell is fish and using `string join : $PATH` instead, or validating the result contains colons before assigning.",
2911− "severity": "Medium",
2912− "has_false_positive_signal": false,
2913− "canonical_id": "C022",
2914− "phase0_status": "actionable_canonical",
2915− "phase0_reason": "Canonical actionable item."
2916− },
2917− {
2918− "index": 134,
2919− "thread_id": "PRRT_kwDORLtfbc5wlXJp",
2920− "path": "apps/web/src/components/ui/sidebar.tsx",
2921− "line": null,
2922− "is_outdated": true,
2923− "is_resolved": true,
2924− "author": "macroscopeapp",
2925− "title": "Consider spreading `...props` onto the outer wrapper `div` (line 207) instead of the inner container (line 240). Currently, props like `className=\"hidden\"` only affect the inner fixed div, leaving the outer layout placeholder visible and causing \"ghost\" space. <details> <summary>\ud83d\ude80 Reply \"<strong>fix it for me</strong>\" or copy this <strong>AI Prompt</strong> for your agent:</summary>",
2926− "severity": "Low",
2927− "has_false_positive_signal": false,
2928− "phase0_status": "filtered_outdated",
2929− "phase0_reason": "Thread is flagged outdated by GitHub diff context."
2930− },
2931− {
2932− "index": 135,
2933− "thread_id": "PRRT_kwDORLtfbc5wlXJr",
2934− "path": "apps/web/src/components/ui/sidebar.tsx",
2935− "line": 122,
2936− "is_outdated": false,
2937− "is_resolved": true,
2938− "author": "macroscopeapp",
2939− "title": "`cookieStore` is only available in Chromium browsers. Consider adding a guard like `if ('cookieStore' in window)` before accessing it to prevent `ReferenceError` in Firefox/Safari.",
2940− "severity": "Medium",
2941− "has_false_positive_signal": false,
2942− "phase0_status": "filtered_resolved",
2943− "phase0_reason": "Thread is already resolved on GitHub."
2944− },
2945− {
2946− "index": 136,
2947− "thread_id": "PRRT_kwDORLtfbc5wlXJz",
2948− "path": "apps/server/src/orchestration/Layers/ProviderCommandReactor.ts",
2949− "line": null,
2950− "is_outdated": true,
2951− "is_resolved": false,
2952− "author": "macroscopeapp",
2953− "title": "The `processDomainEvent` consumer loop lacks error handling. A single `providerService` failure will crash the fiber and stop all subsequent event processing. Consider wrapping with `Effect.catchAll` or `Effect.ignoreLogged` to let the loop continue after errors. <details> <summary>\ud83d\ude80 Reply \"<strong>fix it for me</strong>\" or copy this <strong>AI Prompt</strong> for your agent:</summary>",
2954− "severity": "High",
2955− "has_false_positive_signal": false,
2956− "phase0_status": "filtered_outdated",
2957− "phase0_reason": "Thread is flagged outdated by GitHub diff context."
2958− },
2959− {
2960− "index": 137,
2961− "thread_id": "PRRT_kwDORLtfbc5wlYgj",
2962− "path": "AGENTS.md",
2963− "line": 45,
2964− "is_outdated": false,
2965− "is_resolved": false,
2966− "author": "cursor",
2967− "title": "Dummy workflow marker accidentally committed to docs",
2968− "severity": "Low",
2969− "has_false_positive_signal": false,
2970− "canonical_id": "C032",
2971− "phase0_status": "actionable_canonical",
2972− "phase0_reason": "Canonical actionable item."
2973− },
2974− {
2975− "index": 138,
2976− "thread_id": "PRRT_kwDORLtfbc5wlYgo",
2977− "path": "apps/server/src/checkpointing/Errors.ts",
2978− "line": 51,
2979− "is_outdated": false,
2980− "is_resolved": false,
2981− "author": "cursor",
2982− "title": "Three error classes defined but never instantiated anywhere",
2983− "severity": "Low",
2984− "has_false_positive_signal": false,
2985− "canonical_id": "C033",
2986− "phase0_status": "actionable_canonical",
2987− "phase0_reason": "Canonical actionable item."
2988− },
2989− {
2990− "index": 139,
2991− "thread_id": "PRRT_kwDORLtfbc5wlYgs",
2992− "path": "apps/server/src/checkpointing/Errors.ts",
2993− "line": 79,
2994− "is_outdated": false,
2995− "is_resolved": false,
2996− "author": "cursor",
2997− "title": "Redundant error type in CheckpointServiceError union definition",
2998− "severity": "Low",
2999− "has_false_positive_signal": false,
3000− "canonical_id": "C035",
3001− "phase0_status": "actionable_canonical",
3002− "phase0_reason": "Canonical actionable item."
3003− },
3004− {
3005− "index": 140,
3006− "thread_id": "PRRT_kwDORLtfbc5wl2A8",
3007− "path": "apps/server/src/orchestration/Layers/ProviderCommandReactor.ts",
3008− "line": 84,
3009− "is_outdated": false,
3010− "is_resolved": false,
3011− "author": "macroscopeapp",
3012− "title": "`handledTurnStartKeys` grows indefinitely since keys are never removed. Consider adding TTL-based cleanup or clearing entries after processing completes. <details> <summary>\ud83d\ude80 Reply \"<strong>fix it for me</strong>\" or copy this <strong>AI Prompt</strong> for your agent:</summary>",
3013− "severity": "Low",
3014− "has_false_positive_signal": false,
3015− "canonical_id": "C018",
3016− "phase0_status": "actionable_duplicate",
3017− "phase0_reason": "Duplicate of C018."
3018− },
3019− {
3020− "index": 141,
3021− "thread_id": "PRRT_kwDORLtfbc5wnVsI",
3022− "path": "apps/server/src/provider/Layers/ProviderService.ts",
3023− "line": 59,
3024− "is_outdated": false,
3025− "is_resolved": false,
3026− "author": "macroscopeapp",
3027− "title": "`JSON.stringify(cause)` returns `undefined` for `undefined`, functions, or symbols, violating the `string` return type. Consider coercing the result to a string (e.g., `String(JSON.stringify(cause))`) or adding a fallback.",
3028− "severity": "Low",
3029− "has_false_positive_signal": false,
3030− "canonical_id": "C049",
3031− "phase0_status": "actionable_canonical",
3032− "phase0_reason": "Canonical actionable item."
3033− },
3034− {
3035− "index": 142,
3036− "thread_id": "PRRT_kwDORLtfbc5wnVsK",
3037− "path": "apps/web/src/markdown-links.ts",
3038− "line": 111,
3039− "is_outdated": false,
3040− "is_resolved": false,
3041− "author": "macroscopeapp",
3042− "title": "`EXTERNAL_SCHEME_PATTERN` matches `script.ts:10` as a scheme because `.ts:` looks like `scheme:`. Consider requiring `://` after the colon, or checking that what follows the colon is not just digits. <details> <summary>\ud83d\ude80 Reply \"<strong>fix it for me</strong>\" or copy this <strong>AI Prompt</strong> for your agent:</summary>",
3043− "severity": "Medium",
3044− "has_false_positive_signal": false,
3045− "canonical_id": "C030",
3046− "phase0_status": "actionable_canonical",
3047− "phase0_reason": "Canonical actionable item."
3048− },
3049− {
3050− "index": 143,
3051− "thread_id": "PRRT_kwDORLtfbc5wnVsU",
3052− "path": "apps/web/src/markdown-links.ts",
3053− "line": 105,
3054− "is_outdated": false,
3055− "is_resolved": false,
3056− "author": "macroscopeapp",
3057− "title": "`parseFileUrlHref` already decodes the path (line 46), but `safeDecode` is called again here, corrupting filenames containing `%` sequences. Consider skipping the decode when `fileUrlTarget` is non-null.",
3058− "severity": "Medium",
3059− "has_false_positive_signal": false,
3060− "canonical_id": "C029",
3061− "phase0_status": "actionable_canonical",
3062− "phase0_reason": "Canonical actionable item."
3063− },
3064− {
3065− "index": 144,
3066− "thread_id": "PRRT_kwDORLtfbc5wnVsX",
3067− "path": "apps/web/src/routes/_chat.$threadId.tsx",
3068− "line": 122,
3069− "is_outdated": false,
3070− "is_resolved": false,
3071− "author": "macroscopeapp",
3072− "title": "When `localStorage.getItem()` returns `null`, `Number(null)` evaluates to `0`, which passes `Number.isFinite(0)`. This causes the sidebar to clamp to `minWidth` on first load, overriding the `DIFF_INLINE_DEFAULT_WIDTH` CSS clamp. Consider checking for `null` or empty string before parsing, e.g. guard with `storedWidth === null || storedWidth === ''`. <details> <summary>\ud83d\ude80 Reply \"<strong>fix it for me</strong>\" or copy this <strong>AI Prompt</strong> for your agent:</summary>",
3073− "severity": "Low",
3074− "has_false_positive_signal": false,
3075− "canonical_id": "C058",
3076− "phase0_status": "actionable_canonical",
3077− "phase0_reason": "Canonical actionable item."
3078− },
3079− {
3080− "index": 145,
3081− "thread_id": "PRRT_kwDORLtfbc5wnWv_",
3082− "path": "apps/server/src/checkpointing/Layers/CheckpointStore.ts",
3083− "line": 94,
3084− "is_outdated": false,
3085− "is_resolved": false,
3086− "author": "cursor",
3087− "title": "Inconsistent input normalization across CheckpointStore methods",
3088− "severity": "Medium",
3089− "has_false_positive_signal": false,
3090− "canonical_id": "C008",
3091− "phase0_status": "actionable_duplicate",
3092− "phase0_reason": "Duplicate of C008."
3093− },
3094− {
3095− "index": 146,
3096− "thread_id": "PRRT_kwDORLtfbc5wnWwF",
3097− "path": "apps/server/src/orchestration/Layers/CheckpointReactor.ts",
3098− "line": 584,
3099− "is_outdated": false,
3100− "is_resolved": false,
3101− "author": "cursor",
3102− "title": "Unhandled errors in checkpoint reactor worker crash processing permanently",
3103− "severity": "High",
3104− "has_false_positive_signal": false,
3105− "canonical_id": "C002",
3106− "phase0_status": "actionable_duplicate",
3107− "phase0_reason": "Duplicate of C002."
3108− },
3109− {
3110− "index": 147,
3111− "thread_id": "PRRT_kwDORLtfbc5wnWwM",
3112− "path": "apps/server/src/orchestration/Layers/CheckpointReactor.ts",
3113− "line": 62,
3114− "is_outdated": false,
3115− "is_resolved": false,
3116− "author": "cursor",
3117− "title": "Duplicated workspace CWD resolution logic across reactor modules",
3118− "severity": "Low",
3119− "has_false_positive_signal": false,
3120− "canonical_id": "C043",
3121− "phase0_status": "actionable_canonical",
3122− "phase0_reason": "Canonical actionable item."
3123− },
3124− {
3125− "index": 148,
3126− "thread_id": "PRRT_kwDORLtfbc5wvwag",
3127− "path": "apps/server/src/wsServer.ts",
3128− "line": 128,
3129− "is_outdated": false,
3130− "is_resolved": false,
3131− "author": "cursor",
3132− "title": "Duplicated checkpoint ref computation across two files",
3133− "severity": "Medium",
3134− "has_false_positive_signal": false,
3135− "phase0_status": "filtered_invalid",
3136− "phase0_reason": "Invalid after post-rewrite audit: No longer duplicated; checkpoint ref helper now centralized."
3137− },
3138− {
3139− "index": 149,
3140− "thread_id": "PRRT_kwDORLtfbc5wxsO6",
3141− "path": "apps/server/src/checkpointing/Errors.ts",
3142− "line": 79,
3143− "is_outdated": false,
3144− "is_resolved": false,
3145− "author": "cursor",
3146− "title": "Redundant error type in CheckpointServiceError union",
3147− "severity": "Low",
3148− "has_false_positive_signal": false,
3149− "canonical_id": "C035",
3150− "phase0_status": "actionable_duplicate",
3151− "phase0_reason": "Duplicate of C035."
3152− },
3153− {
3154− "index": 150,
3155− "thread_id": "PRRT_kwDORLtfbc5wxsO-",
3156− "path": "apps/server/package.json",
3157− "line": 14,
3158− "is_outdated": false,
3159− "is_resolved": false,
3160− "author": "cursor",
3161− "title": "Build script runs TypeScript file with bare node",
3162− "severity": "Medium",
3163− "has_false_positive_signal": false,
3164− "canonical_id": "C006",
3165− "phase0_status": "actionable_canonical",
3166− "phase0_reason": "Canonical actionable item."
3167− },
3168− {
3169− "index": 151,
3170− "thread_id": "PRRT_kwDORLtfbc5wxvH8",
3171− "path": "apps/server/src/orchestration/Layers/ProjectionPipeline.ts",
3172− "line": 490,
3173− "is_outdated": false,
3174− "is_resolved": false,
3175− "author": "macroscopeapp",
3176− "title": "The in-memory `pendingTurnStartByThreadId` map isn't restored during bootstrap. If the service restarts after processing `thread.turn-start-requested` but before `thread.session-set`, the `userMessageId` and `startedAt` will be lost since bootstrap resumes *after* the committed sequence. Consider persisting this pending state or processing these two events atomically. <details> <summary>\ud83d\ude80 Reply \"<strong>fix it for me</strong>\" or copy this <strong>AI Prompt</strong> for your agent:</summary>",
3177− "severity": "Medium",
3178− "has_false_positive_signal": false,
3179− "canonical_id": "C016",
3180− "phase0_status": "actionable_canonical",
3181− "phase0_reason": "Canonical actionable item."
3182− },
3183− {
3184− "index": 152,
3185− "thread_id": "PRRT_kwDORLtfbc5wxvH9",
3186− "path": "apps/server/src/provider/Layers/ProviderSessionDirectory.ts",
3187− "line": 119,
3188− "is_outdated": false,
3189− "is_resolved": false,
3190− "author": "macroscopeapp",
3191− "title": "Using `??` for `providerThreadId` and `adapterKey` makes it impossible to clear these fields by passing `null`, since `null ?? existing` evaluates to `existing`. Consider using explicit `undefined` checks (like `resumeCursor` does) if clearing should be supported. <details> <summary>\ud83d\ude80 Reply \"<strong>fix it for me</strong>\" or copy this <strong>AI Prompt</strong> for your agent:</summary>",
3192− "severity": "Low",
3193− "has_false_positive_signal": false,
3194− "canonical_id": "C051",
3195− "phase0_status": "actionable_canonical",
3196− "phase0_reason": "Canonical actionable item."
3197− },
3198− {
3199− "index": 153,
3200− "thread_id": "PRRT_kwDORLtfbc5wxvIA",
3201− "path": "apps/server/src/keybindings.ts",
3202− "line": 488,
3203− "is_outdated": false,
3204− "is_resolved": false,
3205− "author": "macroscopeapp",
3206− "title": "`upsertKeybindingRule` has a race condition: concurrent calls read the same file state, then the last write overwrites earlier changes. Consider wrapping the read-modify-write sequence with `Effect.Semaphore` to serialize access. <details> <summary>\ud83d\ude80 Reply \"<strong>fix it for me</strong>\" or copy this <strong>AI Prompt</strong> for your agent:</summary>",
3207− "severity": "Low",
3208− "has_false_positive_signal": false,
3209− "canonical_id": "C040",
3210− "phase0_status": "actionable_canonical",
3211− "phase0_reason": "Canonical actionable item."
3212− },
3213− {
3214− "index": 154,
3215− "thread_id": "PRRT_kwDORLtfbc5wxvIB",
3216− "path": "apps/server/src/keybindings.ts",
3217− "line": 352,
3218− "is_outdated": false,
3219− "is_resolved": false,
3220− "author": "macroscopeapp",
3221− "title": "The `+` key can be parsed (via trailing `+` handling) but cannot be encoded because `shortcut.key.includes(\"+\")` returns true for the literal `+` key. Consider checking `shortcut.key === \"+\"` separately and encoding it as `\"space\"` style (e.g., a special token), or adjusting the condition to allow the single `+` character. <details> <summary>\ud83d\ude80 Reply \"<strong>fix it for me</strong>\" or copy this <strong>AI Prompt</strong> for your agent:</summary>",
3222− "severity": "Low",
3223− "has_false_positive_signal": false,
3224− "canonical_id": "C039",
3225− "phase0_status": "actionable_canonical",
3226− "phase0_reason": "Canonical actionable item."
3227− },
3228− {
3229− "index": 155,
3230− "thread_id": "PRRT_kwDORLtfbc5wxvIJ",
3231− "path": "apps/server/src/keybindings.ts",
3232− "line": 418,
3233− "is_outdated": false,
3234− "is_resolved": false,
3235− "author": "macroscopeapp",
3236− "title": "`loadCustomKeybindingsConfig` fails when the config file doesn't exist, which is expected for new users. Consider catching `ENOENT` and returning an empty array instead. <details> <summary>\ud83d\ude80 Reply \"<strong>fix it for me</strong>\" or copy this <strong>AI Prompt</strong> for your agent:</summary>",
3237− "severity": "Medium",
3238− "has_false_positive_signal": false,
3239− "canonical_id": "C010",
3240− "phase0_status": "actionable_canonical",
3241− "phase0_reason": "Canonical actionable item."
3242− },
3243− {
3244− "index": 156,
3245− "thread_id": "PRRT_kwDORLtfbc5wxvIQ",
3246− "path": "apps/server/src/orchestration/Layers/ProviderRuntimeIngestion.ts",
3247− "line": 133,
3248− "is_outdated": false,
3249− "is_resolved": false,
3250− "author": "macroscopeapp",
3251− "title": "`latestMessageIdByTurnKey` is written to but never read, and `clearAssistantMessageIdsForTurn` doesn't clear its entries\u2014only `clearTurnStateForSession` does. Consider removing this map entirely if unused, or clearing it alongside `turnMessageIdsByTurnKey` in `clearAssistantMessageIdsForTurn`. <details> <summary>\ud83d\ude80 Reply \"<strong>fix it for me</strong>\" or copy this <strong>AI Prompt</strong> for your agent:</summary>",
3252− "severity": "Low",
3253− "has_false_positive_signal": false,
3254− "canonical_id": "C046",
3255− "phase0_status": "actionable_canonical",
3256− "phase0_reason": "Canonical actionable item."
3257− },
3258− {
3259− "index": 157,
3260− "thread_id": "PRRT_kwDORLtfbc5wxvIq",
3261− "path": "apps/web/src/components/ui/sidebar.tsx",
3262− "line": 114,
3263− "is_outdated": false,
3264− "is_resolved": false,
3265− "author": "macroscopeapp",
3266− "title": "When `onOpenChange` is provided without `open`, the internal `_open` state never updates because `setOpenProp` takes precedence. Consider calling `_setOpen` when `openProp === undefined`, regardless of whether `setOpenProp` exists.",
3267− "severity": "Low",
3268− "has_false_positive_signal": false,
3269− "canonical_id": "C056",
3270− "phase0_status": "actionable_canonical",
3271− "phase0_reason": "Canonical actionable item."
3272− },
3273− {
3274− "index": 158,
3275− "thread_id": "PRRT_kwDORLtfbc5wyTaP",
3276− "path": "apps/server/src/orchestration/Layers/ProviderRuntimeIngestion.ts",
3277− "line": 334,
3278− "is_outdated": false,
3279− "is_resolved": false,
3280− "author": "cursor",
3281− "title": "Worker fibers die permanently on single processing error",
3282− "severity": "High",
3283− "has_false_positive_signal": false,
3284− "canonical_id": "C002",
3285− "phase0_status": "actionable_duplicate",
3286− "phase0_reason": "Duplicate of C002."
3287− },
3288− {
3289− "index": 159,
3290− "thread_id": "PRRT_kwDORLtfbc5wyTaS",
3291− "path": "apps/server/src/orchestration/Layers/CheckpointReactor.ts",
3292− "line": 542,
3293− "is_outdated": false,
3294− "is_resolved": false,
3295− "author": "cursor",
3296− "title": "Revert completion dispatched as fire-and-forget fork",
3297− "severity": "Medium",
3298− "has_false_positive_signal": false,
3299− "canonical_id": "C012",
3300− "phase0_status": "actionable_duplicate",
3301− "phase0_reason": "Duplicate of C012."
3302− },
3303− {
3304− "index": 160,
3305− "thread_id": "PRRT_kwDORLtfbc5wyTaT",
3306− "path": "apps/server/src/orchestration/Layers/ProviderCommandReactor.ts",
3307− "line": 84,
3308− "is_outdated": false,
3309− "is_resolved": false,
3310− "author": "cursor",
3311− "title": "Unbounded memory growth in turn start deduplication set",
3312− "severity": "Medium",
3313− "has_false_positive_signal": false,
3314− "canonical_id": "C018",
3315− "phase0_status": "actionable_duplicate",
3316− "phase0_reason": "Duplicate of C018."
3317− },
3318− {
3319− "index": 161,
3320− "thread_id": "PRRT_kwDORLtfbc5wyTaW",
3321− "path": "apps/server/src/wsServer.ts",
3322− "line": 545,
3323− "is_outdated": false,
3324− "is_resolved": false,
3325− "author": "cursor",
3326− "title": "WS message handler can cause unhandled promise rejection",
3327− "severity": "Medium",
3328− "has_false_positive_signal": false,
3329− "canonical_id": "C027",
3330− "phase0_status": "actionable_canonical",
3331− "phase0_reason": "Canonical actionable item."
3332− },
3333− {
3334− "index": 162,
3335− "thread_id": "PRRT_kwDORLtfbc5wyWz4",
3336− "path": "apps/web/src/routes/_chat.$threadId.tsx",
3337− "line": 105,
3338− "is_outdated": false,
3339− "is_resolved": false,
3340− "author": "macroscopeapp",
3341− "title": "The `resizable` object is recreated on every render, causing `SidebarRail`'s `useEffect` to repeatedly read localStorage and update the DOM. Consider memoizing the object with `useMemo`. <details> <summary>\ud83d\ude80 Reply \"<strong>fix it for me</strong>\" or copy this <strong>AI Prompt</strong> for your agent:</summary>",
3342− "severity": "Low",
3343− "has_false_positive_signal": false,
3344− "canonical_id": "C057",
3345− "phase0_status": "actionable_canonical",
3346− "phase0_reason": "Canonical actionable item."
3347− },
3348− {
3349− "index": 163,
3350− "thread_id": "PRRT_kwDORLtfbc5wzliw",
3351− "path": "apps/server/src/orchestration/Layers/ProviderRuntimeIngestion.ts",
3352− "line": 334,
3353− "is_outdated": false,
3354− "is_resolved": false,
3355− "author": "cursor",
3356− "title": "Reactor worker loops die permanently on single error",
3357− "severity": "High",
3358− "has_false_positive_signal": false,
3359− "canonical_id": "C002",
3360− "phase0_status": "actionable_duplicate",
3361− "phase0_reason": "Duplicate of C002."
3362− },
3363− {
3364− "index": 164,
3365− "thread_id": "PRRT_kwDORLtfbc5wzliz",
3366− "path": "apps/server/src/orchestration/Layers/ProviderCommandReactor.ts",
3367− "line": 84,
3368− "is_outdated": false,
3369− "is_resolved": false,
3370− "author": "cursor",
3371− "title": "Unbounded `handledTurnStartKeys` set causes memory leak",
3372− "severity": "Medium",
3373− "has_false_positive_signal": false,
3374− "canonical_id": "C018",
3375− "phase0_status": "actionable_duplicate",
3376− "phase0_reason": "Duplicate of C018."
3377− },
3378− {
3379− "index": 165,
3380− "thread_id": "PRRT_kwDORLtfbc5wzli0",
3381− "path": "apps/server/src/orchestration/Layers/CheckpointReactor.ts",
3382− "line": 542,
3383− "is_outdated": false,
3384− "is_resolved": false,
3385− "author": "cursor",
3386− "title": "Revert completion dispatch is fire-and-forget via fork",
3387− "severity": "Medium",
3388− "has_false_positive_signal": false,
3389− "canonical_id": "C012",
3390− "phase0_status": "actionable_duplicate",
3391− "phase0_reason": "Duplicate of C012."
3392− },
3393− {
3394− "index": 166,
3395− "thread_id": "PRRT_kwDORLtfbc5wzli2",
3396− "path": "apps/server/src/orchestration/Layers/CheckpointReactor.ts",
3397− "line": 62,
3398− "is_outdated": false,
3399− "is_resolved": false,
3400− "author": "cursor",
3401− "title": "Duplicated `resolveThreadWorkspaceCwd` across three files",
3402− "severity": "Low",
3403− "has_false_positive_signal": false,
3404− "canonical_id": "C042",
3405− "phase0_status": "actionable_canonical",
3406− "phase0_reason": "Canonical actionable item."
3407− },
3408− {
3409− "index": 167,
3410− "thread_id": "PRRT_kwDORLtfbc5wzli3",
3411− "path": "apps/server/src/wsServer.ts",
3412− "line": 545,
3413− "is_outdated": false,
3414− "is_resolved": false,
3415− "author": "cursor",
3416− "title": "WS message handler can cause unhandled promise rejection",
3417− "severity": "Medium",
3418− "has_false_positive_signal": false,
3419− "canonical_id": "C027",
3420− "phase0_status": "actionable_duplicate",
3421− "phase0_reason": "Duplicate of C027."
3422− },
3423− {
3424− "index": 168,
3425− "thread_id": "PRRT_kwDORLtfbc5wzp4R",
3426− "path": "apps/server/src/orchestration/Layers/ProviderRuntimeIngestion.ts",
3427− "line": 29,
3428− "is_outdated": false,
3429− "is_resolved": false,
3430− "author": "macroscopeapp",
3431− "title": "`truncateDetail` slices to `limit - 1` then appends `\"...\"` (3 chars), producing strings of length `limit + 2`. Consider slicing to `limit - 3` instead. <details> <summary>\ud83d\ude80 Reply \"<strong>fix it for me</strong>\" or copy this <strong>AI Prompt</strong> for your agent:</summary>",
3432− "severity": "Low",
3433− "has_false_positive_signal": false,
3434− "canonical_id": "C045",
3435− "phase0_status": "actionable_canonical",
3436− "phase0_reason": "Canonical actionable item."
3437− },
3438− {
3439− "index": 169,
3440− "thread_id": "PRRT_kwDORLtfbc5wzp4T",
3441− "path": "apps/server/src/orchestration/Layers/OrchestrationEngine.ts",
3442− "line": 96,
3443− "is_outdated": false,
3444− "is_resolved": false,
3445− "author": "macroscopeapp",
3446− "title": "Non-atomic event appending can corrupt state on retry. If an error occurs mid-loop (lines 96-102) after some events are persisted but before the receipt is written, the command appears to fail. A retry generates new UUIDs via `crypto.randomUUID()` in the decider, appending duplicate events. Consider wrapping the loop in a transaction or using deterministic event IDs derived from `commandId`. <details> <summary>\ud83d\ude80 Reply \"<strong>fix it for me</strong>\" or copy this <strong>AI Prompt</strong> for your agent:</summary>",
3447− "severity": "High",
3448− "has_false_positive_signal": false,
3449− "canonical_id": "C001",
3450− "phase0_status": "actionable_canonical",
3451− "phase0_reason": "Canonical actionable item."
3452− },
3453− {
3454− "index": 170,
3455− "thread_id": "PRRT_kwDORLtfbc5w0_g3",
3456− "path": "apps/server/src/orchestration/Layers/ProviderRuntimeIngestion.ts",
3457− "line": 334,
3458− "is_outdated": false,
3459− "is_resolved": false,
3460− "author": "cursor",
3461− "title": "Reactor worker fibers die permanently on single error",
3462− "severity": "High",
3463− "has_false_positive_signal": false,
3464− "canonical_id": "C002",
3465− "phase0_status": "actionable_duplicate",
3466− "phase0_reason": "Duplicate of C002."
3467− },
3468− {
3469− "index": 171,
3470− "thread_id": "PRRT_kwDORLtfbc5w0_g4",
3471− "path": "apps/server/src/orchestration/Layers/CheckpointReactor.ts",
3472− "line": 542,
3473− "is_outdated": false,
3474− "is_resolved": false,
3475− "author": "cursor",
3476− "title": "Forked revert completion creates state inconsistency window",
3477− "severity": "Medium",
3478− "has_false_positive_signal": false,
3479− "canonical_id": "C012",
3480− "phase0_status": "actionable_duplicate",
3481− "phase0_reason": "Duplicate of C012."
3482− },
3483− {
3484− "index": 172,
3485− "thread_id": "PRRT_kwDORLtfbc5w0_g7",
3486− "path": "apps/server/src/checkpointing/Layers/CheckpointStore.ts",
3487− "line": 95,
3488− "is_outdated": false,
3489− "is_resolved": false,
3490− "author": "cursor",
3491− "title": "Inconsistent input trimming across CheckpointStore methods",
3492− "severity": "Medium",
3493− "has_false_positive_signal": false,
3494− "canonical_id": "C008",
3495− "phase0_status": "actionable_duplicate",
3496− "phase0_reason": "Duplicate of C008."
3497− },
3498− {
3499− "index": 173,
3500− "thread_id": "PRRT_kwDORLtfbc5w0_g-",
3501− "path": "apps/server/src/orchestration/Layers/ProviderCommandReactor.ts",
3502− "line": 84,
3503− "is_outdated": false,
3504− "is_resolved": false,
3505− "author": "cursor",
3506− "title": "Unbounded `handledTurnStartKeys` Set causes memory leak",
3507− "severity": "Low",
3508− "has_false_positive_signal": false,
3509− "canonical_id": "C018",
3510− "phase0_status": "actionable_duplicate",
3511− "phase0_reason": "Duplicate of C018."
3512− },
3513− {
3514− "index": 174,
3515− "thread_id": "PRRT_kwDORLtfbc5w1CxE",
3516− "path": "apps/server/src/terminal/Layers/BunPTY.ts",
3517− "line": 97,
3518− "is_outdated": false,
3519− "is_resolved": false,
3520− "author": "macroscopeapp",
3521− "title": "Race condition: `processHandle` may be `null` when `data` callback fires, since it's assigned after `Bun.spawn` returns. Consider initializing `BunPtyProcess` first, then passing it to the callback to avoid losing initial output. <details> <summary>\ud83d\ude80 Reply \"<strong>fix it for me</strong>\" or copy this <strong>AI Prompt</strong> for your agent:</summary>",
3522− "severity": "Low",
3523− "has_false_positive_signal": false,
3524− "canonical_id": "C052",
3525− "phase0_status": "actionable_canonical",
3526− "phase0_reason": "Canonical actionable item."
3527− },
3528− {
3529− "index": 175,
3530− "thread_id": "PRRT_kwDORLtfbc5w1CxT",
3531− "path": "apps/server/src/git/Layers/GitCore.ts",
3532− "line": 41,
3533− "is_outdated": false,
3534− "is_resolved": false,
3535− "author": "macroscopeapp",
3536− "title": "Git's braced rename syntax (e.g., `src/{old => new}/file.ts`) isn't handled correctly. The current slice after ` => ` produces invalid paths like `new}/file.ts`. Consider expanding the braces to construct the full destination path. <details> <summary>\ud83d\ude80 Reply \"<strong>fix it for me</strong>\" or copy this <strong>AI Prompt</strong> for your agent:</summary>",
3537− "severity": "Medium",
3538− "has_false_positive_signal": false,
3539− "canonical_id": "C009",
3540− "phase0_status": "actionable_canonical",
3541− "phase0_reason": "Canonical actionable item."
3542− },
3543− {
3544− "index": 176,
3545− "thread_id": "PRRT_kwDORLtfbc5w1C36",
3546− "path": "apps/server/src/checkpointing/Layers/CheckpointStore.ts",
3547− "line": 94,
3548− "is_outdated": false,
3549− "is_resolved": false,
3550− "author": "cursor",
3551− "title": "Inconsistent input trimming across CheckpointStore methods",
3552− "severity": "Medium",
3553− "has_false_positive_signal": false,
3554− "canonical_id": "C008",
3555− "phase0_status": "actionable_duplicate",
3556− "phase0_reason": "Duplicate of C008."
3557− },
3558− {
3559− "index": 177,
3560− "thread_id": "PRRT_kwDORLtfbc5w1C3-",
3561− "path": "apps/server/src/checkpointing/Layers/CheckpointDiffQuery.ts",
3562− "line": 40,
3563− "is_outdated": false,
3564− "is_resolved": false,
3565− "author": "cursor",
3566− "title": "Duplicated resolveThreadWorkspaceCwd utility across files",
3567− "severity": "Low",
3568− "has_false_positive_signal": false,
3569− "canonical_id": "C043",
3570− "phase0_status": "actionable_duplicate",
3571− "phase0_reason": "Duplicate of C043."
3572− },
3573− {
3574− "index": 178,
3575− "thread_id": "PRRT_kwDORLtfbc5w1C4B",
3576− "path": "apps/server/src/checkpointing/Errors.ts",
3577− "line": 79,
3578− "is_outdated": false,
3579− "is_resolved": false,
3580− "author": "cursor",
3581− "title": "Redundant CheckpointInvariantError in service error union type",
3582− "severity": "Low",
3583− "has_false_positive_signal": false,
3584− "canonical_id": "C035",
3585− "phase0_status": "actionable_duplicate",
3586− "phase0_reason": "Duplicate of C035."
3587− },
3588− {
3589− "index": 179,
3590− "thread_id": "PRRT_kwDORLtfbc5w1C4H",
3591− "path": "AGENTS.md",
3592− "line": 45,
3593− "is_outdated": false,
3594− "is_resolved": false,
3595− "author": "cursor",
3596− "title": "Dummy workflow testing marker committed to AGENTS.md",
3597− "severity": "Low",
3598− "has_false_positive_signal": false,
3599− "canonical_id": "C032",
3600− "phase0_status": "actionable_duplicate",
3601− "phase0_reason": "Duplicate of C032."
3602− },
3603− {
3604− "index": 180,
3605− "thread_id": "PRRT_kwDORLtfbc5w1GPo",
3606− "path": "apps/server/src/git/Layers/CodexTextGeneration.ts",
3607− "line": 136,
3608− "is_outdated": false,
3609− "is_resolved": false,
3610− "author": "macroscopeapp",
3611− "title": "Multi-byte UTF-8 characters split across chunks will be corrupted when decoding each chunk separately. Consider accumulating all chunks first, then decoding once, or use `TextDecoder` with `stream: true`. <details> <summary>\ud83d\ude80 Reply \"<strong>fix it for me</strong>\" or copy this <strong>AI Prompt</strong> for your agent:</summary>",
3612− "severity": "Low",
3613− "has_false_positive_signal": false,
3614− "canonical_id": "C038",
3615− "phase0_status": "actionable_canonical",
3616− "phase0_reason": "Canonical actionable item."
3617− },
3618− {
3619− "index": 181,
3620− "thread_id": "PRRT_kwDORLtfbc5w1GPr",
3621− "path": "apps/server/src/orchestration/Layers/ProviderRuntimeIngestion.ts",
3622− "line": 266,
3623− "is_outdated": false,
3624− "is_resolved": false,
3625− "author": "macroscopeapp",
3626− "title": "On `message.completed`, the message ID is added to the set and `thread.message.assistant.complete` is dispatched. On `turn.completed`, the same set is iterated and `thread.message.assistant.complete` is dispatched again for each ID\u2014including already-completed ones. Consider removing message IDs from the set after dispatching on `message.completed`, or filtering out already-completed IDs before the `turn.completed` loop.",
3627− "severity": "Medium",
3628− "has_false_positive_signal": false,
3629− "canonical_id": "C020",
3630− "phase0_status": "actionable_canonical",
3631− "phase0_reason": "Canonical actionable item."
3632− },
3633− {
3634− "index": 182,
3635− "thread_id": "PRRT_kwDORLtfbc5w1HGT",
3636− "path": "apps/server/src/orchestration/Layers/ProviderRuntimeIngestion.ts",
3637− "line": 334,
3638− "is_outdated": false,
3639− "is_resolved": false,
3640− "author": "cursor",
3641− "title": "Reactor worker fibers die permanently on single error",
3642− "severity": "High",
3643− "has_false_positive_signal": false,
3644− "canonical_id": "C002",
3645− "phase0_status": "actionable_duplicate",
3646− "phase0_reason": "Duplicate of C002."
3647− },
3648− {
3649− "index": 183,
3650− "thread_id": "PRRT_kwDORLtfbc5w1HGW",
3651− "path": "apps/server/src/orchestration/Layers/ProviderCommandReactor.ts",
3652− "line": 84,
3653− "is_outdated": false,
3654− "is_resolved": false,
3655− "author": "cursor",
3656− "title": "Unbounded memory growth in turn start deduplication set",
3657− "severity": "Medium",
3658− "has_false_positive_signal": false,
3659− "canonical_id": "C018",
3660− "phase0_status": "actionable_duplicate",
3661− "phase0_reason": "Duplicate of C018."
3662− },
3663− {
3664− "index": 184,
3665− "thread_id": "PRRT_kwDORLtfbc5w1HGX",
3666− "path": "apps/server/src/orchestration/Layers/CheckpointReactor.ts",
3667− "line": 542,
3668− "is_outdated": false,
3669− "is_resolved": false,
3670− "author": "cursor",
3671− "title": "Revert completion dispatch is fire-and-forget, causing stale state",
3672− "severity": "Medium",
3673− "has_false_positive_signal": false,
3674− "canonical_id": "C012",
3675− "phase0_status": "actionable_duplicate",
3676− "phase0_reason": "Duplicate of C012."
3677− },
3678− {
3679− "index": 185,
3680− "thread_id": "PRRT_kwDORLtfbc5w1HGZ",
3681− "path": "apps/server/src/checkpointing/Layers/CheckpointDiffQuery.ts",
3682− "line": 40,
3683− "is_outdated": false,
3684− "is_resolved": false,
3685− "author": "cursor",
3686− "title": "Duplicated utility functions across checkpoint modules",
3687− "severity": "Low",
3688− "has_false_positive_signal": false,
3689− "canonical_id": "C043",
3690− "phase0_status": "actionable_duplicate",
3691− "phase0_reason": "Duplicate of C043."
3692− }
3693− ]
3694−}
.plans/16a-pr89-phase0-canonical-triage.md+0−201
@@ -1,201 +0,0 @@
1−# Phase 0: PR #89 Canonical Triage Lock
2−
3−- PR: https://github.com/pingdotgg/t3-code/pull/89
4−- Title: Add server-side orchestration engine with event sourcing
5−- Generated from latest GitHub data and deduplicated into canonical fix items.
6−
7−## Summary
8−
9−- Total threads: 185
10−- Actionable canonical: 53
11−- Actionable duplicates: 24
12−- Filtered outdated: 94
13−- Filtered resolved: 6
14−- Filtered invalid: 8
15−
16−## Canonical Actionable Checklist
17−
18−### Other (16)
19−
20−- [ ] C011 [Medium] Template literal `${cause}` throws if `cause` is a `Symbol`. Consider using `String(cause)` instead. (apps/server/src/orchestration/Errors.ts:117)
21− - Threads: PRRT_kwDORLtfbc5wBFv4
22−- [ ] C024 [Medium] In `executeUnprepared`, preparing outside an effect and not closing the statement can cause uncaught errors and leaks. Suggest wrapping with `Effect.acquireUseRelease`: prepare in acquire (error-safe) and `finalize` in release. (apps/server/src/persistence/NodeSqliteClient.ts:145)
23− - Threads: PRRT_kwDORLtfbc5whxX9
24−- [ ] C028 [Medium] Branch sync dispatches both server and stale local update (apps/web/src/components/BranchToolbar.tsx:102)
25− - Threads: PRRT_kwDORLtfbc5v-XCu
26−- [ ] C032 [Low] Dummy workflow marker accidentally committed to docs (AGENTS.md:45) (+1 dup)
27− - Threads: PRRT_kwDORLtfbc5wlYgj, PRRT_kwDORLtfbc5w1C4H
28−- [ ] C037 [Low] `Effect.callback` should return a cleanup function to close the server(s) on fiber interruption. Without it, the `Net.Server` handles keep the process alive and leak the port if the effect is cancelled. <details> <summary>🚀 Reply "<strong>fix it for me</strong>" or copy this <strong>AI Prompt</strong> for your agent:</summary> (apps/server/src/config.ts:41)
29− - Threads: PRRT_kwDORLtfbc5wj4cO
30−- [ ] C041 [Low] Template literal interpolation throws `TypeError` if `cause` is a `Symbol`. Consider using `String(cause)` for safe coercion. (apps/server/src/orchestration/Errors.ts:126)
31− - Threads: PRRT_kwDORLtfbc5wBFWs
32−- [ ] C047 [Low] `SqlSchema.findOneOption` can produce both SQL errors and decode errors, but `mapError` wraps all as `PersistenceSqlError`. Consider distinguishing `ParseError` from SQL errors and mapping decode failures to `PersistenceDecodeError` instead. <details> <summary>🚀 Reply "<strong>fix it for me</strong>" or copy this <strong>AI Prompt</strong> for your agent:</summary> (apps/server/src/persistence/Layers/OrchestrationCommandReceipts.ts:75)
33− - Threads: PRRT_kwDORLtfbc5wiaR-
34−- [ ] C048 [Low] `statement.run()` returns a `RunResult` object, not an array. Casting it to `ReadonlyArray<any>` will cause runtime errors when consumers call array methods. Consider wrapping the result (e.g., `[result]`) or returning a properly typed object. (apps/server/src/persistence/NodeSqliteClient.ts:99)
35− - Threads: PRRT_kwDORLtfbc5wio-r
36−- [ ] C049 [Low] `JSON.stringify(cause)` returns `undefined` for `undefined`, functions, or symbols, violating the `string` return type. Consider coercing the result to a string (e.g., `String(JSON.stringify(cause))`) or adding a fallback. (apps/server/src/provider/Layers/ProviderService.ts:59)
37− - Threads: PRRT_kwDORLtfbc5wnVsI
38−- [ ] C050 [Low] The read-modify-write pattern (`getBySessionId` → merge → `upsert`) is susceptible to lost updates under concurrent writes. Consider wrapping in a transaction or adding optimistic concurrency control (e.g., version field) if concurrent session updates are expected. <details> <summary>🚀 Reply "<strong>fix it for me</strong>" or copy this <strong>AI Prompt</strong> for your agent:</summary> (apps/server/src/provider/Layers/ProviderSessionDirectory.ts:94)
39− - Threads: PRRT_kwDORLtfbc5wiLhY
40−- [ ] C051 [Low] Using `??` for `providerThreadId` and `adapterKey` makes it impossible to clear these fields by passing `null`, since `null ?? existing` evaluates to `existing`. Consider using explicit `undefined` checks (like `resumeCursor` does) if clearing should be supported. <details> <summary>🚀 Reply "<strong>fix it for me</strong>" or copy this <strong>AI Prompt</strong> for your agent:</summary> (apps/server/src/provider/Layers/ProviderSessionDirectory.ts:119)
41− - Threads: PRRT_kwDORLtfbc5wxvH9
42−- [ ] C052 [Low] Race condition: `processHandle` may be `null` when `data` callback fires, since it's assigned after `Bun.spawn` returns. Consider initializing `BunPtyProcess` first, then passing it to the callback to avoid losing initial output. <details> <summary>🚀 Reply "<strong>fix it for me</strong>" or copy this <strong>AI Prompt</strong> for your agent:</summary> (apps/server/src/terminal/Layers/BunPTY.ts:97)
43− - Threads: PRRT_kwDORLtfbc5w1CxE
44−- [ ] C056 [Low] When `onOpenChange` is provided without `open`, the internal `_open` state never updates because `setOpenProp` takes precedence. Consider calling `_setOpen` when `openProp === undefined`, regardless of whether `setOpenProp` exists. (apps/web/src/components/ui/sidebar.tsx:114)
45− - Threads: PRRT_kwDORLtfbc5wxvIq
46−- [ ] C057 [Low] The `resizable` object is recreated on every render, causing `SidebarRail`'s `useEffect` to repeatedly read localStorage and update the DOM. Consider memoizing the object with `useMemo`. <details> <summary>🚀 Reply "<strong>fix it for me</strong>" or copy this <strong>AI Prompt</strong> for your agent:</summary> (apps/web/src/routes/_chat.$threadId.tsx:105)
47− - Threads: PRRT_kwDORLtfbc5wyWz4
48−- [ ] C058 [Low] When `localStorage.getItem()` returns `null`, `Number(null)` evaluates to `0`, which passes `Number.isFinite(0)`. This causes the sidebar to clamp to `minWidth` on first load, overriding the `DIFF_INLINE_DEFAULT_WIDTH` CSS clamp. Consider checking for `null` or empty string before parsing, e.g. guard with `storedWidth === null || storedWidth === ''`. <details> <summary>🚀 Reply "<strong>fix it for me</strong>" or copy this <strong>AI Prompt</strong> for your agent:</summary> (apps/web/src/routes/_chat.$threadId.tsx:122)
49− - Threads: PRRT_kwDORLtfbc5wnVsX
50−- [ ] C060 [Low] `defaultModel` should be `Schema.optional(Schema.NullOr(Schema.String))` to allow clearing the value. Currently there's no way to reset it to `null` since omitting means "no change" in patch semantics. <details> <summary>🚀 Reply "<strong>fix it for me</strong>" or copy this <strong>AI Prompt</strong> for your agent:</summary> (packages/contracts/src/orchestration.ts:253)
51− - Threads: PRRT_kwDORLtfbc5whxJC
52−
53−### Runtime resilience and failure handling (10)
54−
55−- [x] C002 [High] A dispatch error in `processEvent` will terminate the `Effect.forever` loop, permanently halting event ingestion. Consider adding error recovery (e.g., `Effect.catchAll` with logging) around `processEvent` so failures don't kill the fiber. (apps/server/src/orchestration/Layers/ProviderRuntimeIngestion.ts:333) (+5 dup)
56− - Threads: PRRT_kwDORLtfbc5wj4cH, PRRT_kwDORLtfbc5wnWwF, PRRT_kwDORLtfbc5wyTaP, PRRT_kwDORLtfbc5wzliw, PRRT_kwDORLtfbc5w0_g3, PRRT_kwDORLtfbc5w1HGT
57−- [x] C012 [Medium] Forked revert dispatch risks read model inconsistency (apps/server/src/orchestration/Layers/CheckpointReactor.ts:542) (+4 dup)
58− - Threads: PRRT_kwDORLtfbc5whszW, PRRT_kwDORLtfbc5wyTaS, PRRT_kwDORLtfbc5wzli0, PRRT_kwDORLtfbc5w0_g4, PRRT_kwDORLtfbc5w1HGX
59−- [ ] C019 [Medium] ProviderRuntimeIngestion processes events for wrong thread on race (apps/server/src/orchestration/Layers/ProviderRuntimeIngestion.ts:178)
60− - Threads: PRRT_kwDORLtfbc5wkPaL
61−- [ ] C020 [Medium] On `message.completed`, the message ID is added to the set and `thread.message.assistant.complete` is dispatched. On `turn.completed`, the same set is iterated and `thread.message.assistant.complete` is dispatched again for each ID—including already-completed ones. Consider removing message IDs from the set after dispatching on `message.completed`, or filtering out already-completed IDs before the `turn.completed` loop. (apps/server/src/orchestration/Layers/ProviderRuntimeIngestion.ts:266)
62− - Threads: PRRT_kwDORLtfbc5w1GPr
63−- [x] C027 [Medium] WS message handler can cause unhandled promise rejection (apps/server/src/wsServer.ts:545) (+1 dup)
64− - Threads: PRRT_kwDORLtfbc5wyTaW, PRRT_kwDORLtfbc5wzli3
65−- [ ] C042 [Low] Duplicated `resolveThreadWorkspaceCwd` across three files (apps/server/src/orchestration/Layers/CheckpointReactor.ts:62)
66− - Threads: PRRT_kwDORLtfbc5wzli2
67−- [ ] C043 [Low] Duplicated workspace CWD resolution logic across reactor modules (apps/server/src/orchestration/Layers/CheckpointReactor.ts:62) (+2 dup)
68− - Threads: PRRT_kwDORLtfbc5wnWwM, PRRT_kwDORLtfbc5w1C3-, PRRT_kwDORLtfbc5w1HGZ
69−- [ ] C044 [Low] Checkpoint reactor swallows diff errors silently for `turn.completed` (apps/server/src/orchestration/Layers/CheckpointReactor.ts:274)
70− - Threads: PRRT_kwDORLtfbc5wkPaO
71−- [ ] C045 [Low] `truncateDetail` slices to `limit - 1` then appends `"..."` (3 chars), producing strings of length `limit + 2`. Consider slicing to `limit - 3` instead. <details> <summary>🚀 Reply "<strong>fix it for me</strong>" or copy this <strong>AI Prompt</strong> for your agent:</summary> (apps/server/src/orchestration/Layers/ProviderRuntimeIngestion.ts:29)
72− - Threads: PRRT_kwDORLtfbc5wzp4R
73−- [ ] C046 [Low] `latestMessageIdByTurnKey` is written to but never read, and `clearAssistantMessageIdsForTurn` doesn't clear its entries—only `clearTurnStateForSession` does. Consider removing this map entirely if unused, or clearing it alongside `turnMessageIdsByTurnKey` in `clearAssistantMessageIdsForTurn`. <details> <summary>🚀 Reply "<strong>fix it for me</strong>" or copy this <strong>AI Prompt</strong> for your agent:</summary> (apps/server/src/orchestration/Layers/ProviderRuntimeIngestion.ts:133)
74− - Threads: PRRT_kwDORLtfbc5wxvIQ
75−
76−### Edge-case parsing/platform behavior (9)
77−
78−- [ ] C009 [Medium] Git's braced rename syntax (e.g., `src/{old => new}/file.ts`) isn't handled correctly. The current slice after ` => ` produces invalid paths like `new}/file.ts`. Consider expanding the braces to construct the full destination path. <details> <summary>🚀 Reply "<strong>fix it for me</strong>" or copy this <strong>AI Prompt</strong> for your agent:</summary> (apps/server/src/git/Layers/GitCore.ts:41)
79− - Threads: PRRT_kwDORLtfbc5w1CxT
80−- [ ] C010 [Medium] `loadCustomKeybindingsConfig` fails when the config file doesn't exist, which is expected for new users. Consider catching `ENOENT` and returning an empty array instead. <details> <summary>🚀 Reply "<strong>fix it for me</strong>" or copy this <strong>AI Prompt</strong> for your agent:</summary> (apps/server/src/keybindings.ts:418)
81− - Threads: PRRT_kwDORLtfbc5wxvIJ
82−- [ ] C022 [Medium] Fish shell outputs `$PATH` as space-separated, not colon-separated. Consider checking if the shell is fish and using `string join : $PATH` instead, or validating the result contains colons before assigning. (apps/server/src/os-jank.ts:10)
83− - Threads: PRRT_kwDORLtfbc5wkRZM
84−- [ ] C023 [Medium] Using `-il` flags causes the shell to source profile scripts that may print banners or other text, polluting the captured `PATH`. Consider using `-lc` (login only, non-interactive) to reduce unwanted output. (apps/server/src/os-jank.ts:10)
85− - Threads: PRRT_kwDORLtfbc5wj4cM
86−- [ ] C029 [Medium] `parseFileUrlHref` already decodes the path (line 46), but `safeDecode` is called again here, corrupting filenames containing `%` sequences. Consider skipping the decode when `fileUrlTarget` is non-null. (apps/web/src/markdown-links.ts:105)
87− - Threads: PRRT_kwDORLtfbc5wnVsU
88−- [ ] C030 [Medium] `EXTERNAL_SCHEME_PATTERN` matches `script.ts:10` as a scheme because `.ts:` looks like `scheme:`. Consider requiring `://` after the colon, or checking that what follows the colon is not just digits. <details> <summary>🚀 Reply "<strong>fix it for me</strong>" or copy this <strong>AI Prompt</strong> for your agent:</summary> (apps/web/src/markdown-links.ts:111)
89− - Threads: PRRT_kwDORLtfbc5wnVsK
90−- [ ] C038 [Low] Multi-byte UTF-8 characters split across chunks will be corrupted when decoding each chunk separately. Consider accumulating all chunks first, then decoding once, or use `TextDecoder` with `stream: true`. <details> <summary>🚀 Reply "<strong>fix it for me</strong>" or copy this <strong>AI Prompt</strong> for your agent:</summary> (apps/server/src/git/Layers/CodexTextGeneration.ts:136)
91− - Threads: PRRT_kwDORLtfbc5w1GPo
92−- [ ] C039 [Low] The `+` key can be parsed (via trailing `+` handling) but cannot be encoded because `shortcut.key.includes("+")` returns true for the literal `+` key. Consider checking `shortcut.key === "+"` separately and encoding it as `"space"` style (e.g., a special token), or adjusting the condition to allow the single `+` character. <details> <summary>🚀 Reply "<strong>fix it for me</strong>" or copy this <strong>AI Prompt</strong> for your agent:</summary> (apps/server/src/keybindings.ts:352)
93− - Threads: PRRT_kwDORLtfbc5wxvIB
94−- [ ] C040 [Low] `upsertKeybindingRule` has a race condition: concurrent calls read the same file state, then the last write overwrites earlier changes. Consider wrapping the read-modify-write sequence with `Effect.Semaphore` to serialize access. <details> <summary>🚀 Reply "<strong>fix it for me</strong>" or copy this <strong>AI Prompt</strong> for your agent:</summary> (apps/server/src/keybindings.ts:488)
95− - Threads: PRRT_kwDORLtfbc5wxvIA
96−
97−### Event ordering and state consistency (5)
98−
99−- [ ] C001 [High] Non-atomic event appending can corrupt state on retry. If an error occurs mid-loop (lines 96-102) after some events are persisted but before the receipt is written, the command appears to fail. A retry generates new UUIDs via `crypto.randomUUID()` in the decider, appending duplicate events. Consider wrapping the loop in a transaction or using deterministic event IDs derived from `commandId`. <details> <summary>🚀 Reply "<strong>fix it for me</strong>" or copy this <strong>AI Prompt</strong> for your agent:</summary> (apps/server/src/orchestration/Layers/OrchestrationEngine.ts:96)
100− - Threads: PRRT_kwDORLtfbc5wzp4T
101−- [ ] C013 [Medium] If `projectionPipeline.projectEvent` fails after `eventStore.append` succeeds, the event is persisted but `readModel` isn't updated, causing desync. Consider updating the in-memory `readModel` immediately after append (before the external projection), so local state stays consistent regardless of downstream failures. (apps/server/src/orchestration/Layers/OrchestrationEngine.ts:99)
102− - Threads: PRRT_kwDORLtfbc5whtrM
103−- [ ] C014 [Medium] Engine error handler catches all errors including non-invariant ones (apps/server/src/orchestration/Layers/OrchestrationEngine.ts:144)
104− - Threads: PRRT_kwDORLtfbc5wkPaJ
105−- [ ] C015 [Medium] The gap-filling fallback logic can retain messages from turns that are about to be deleted, causing foreign key violations. Consider removing the fallback logic entirely, or filtering `fallbackUserMessages` and `fallbackAssistantMessages` to only include messages whose `turnId` is in `retainedTurnIds`. <details> <summary>🚀 Reply "<strong>fix it for me</strong>" or copy this <strong>AI Prompt</strong> for your agent:</summary> (apps/server/src/orchestration/Layers/ProjectionPipeline.ts:99)
106− - Threads: PRRT_kwDORLtfbc5whxJO
107−- [ ] C016 [Medium] The in-memory `pendingTurnStartByThreadId` map isn't restored during bootstrap. If the service restarts after processing `thread.turn-start-requested` but before `thread.session-set`, the `userMessageId` and `startedAt` will be lost since bootstrap resumes *after* the committed sequence. Consider persisting this pending state or processing these two events atomically. <details> <summary>🚀 Reply "<strong>fix it for me</strong>" or copy this <strong>AI Prompt</strong> for your agent:</summary> (apps/server/src/orchestration/Layers/ProjectionPipeline.ts:490)
108− - Threads: PRRT_kwDORLtfbc5wxvH8
109−
110−### WebSocket robustness (5)
111−
112−- [ ] C003 [High] Consider attaching a no-op error listener before `socket.write` (e.g., `socket.on('error', () => {})`) to prevent an unhandled `EPIPE`/`ECONNRESET` from crashing the process if the client disconnects mid-handshake. (apps/server/src/wsServer.ts:75)
113− - Threads: PRRT_kwDORLtfbc5v-cf4
114−- [x] C026 [Medium] Consider adding `.catch(() => {})` after `Effect.runPromise(handleMessage(ws, raw))` to prevent unhandled rejections from crashing the server if `encodeResponse` or setup logic fails. (apps/server/src/wsServer.ts:545)
115− - Threads: PRRT_kwDORLtfbc5wj4cE
116−- [ ] C053 [Low] Consider using `socket.end(response)` instead of `socket.write(response)` + `socket.destroy()` to ensure the HTTP error response is fully flushed before closing the connection. (apps/server/src/wsServer.ts:83)
117− - Threads: PRRT_kwDORLtfbc5v-WPD
118−- [ ] C054 [Low] When array chunks contain a multi-byte UTF-8 character split across boundaries, decoding each chunk separately produces replacement characters. Consider using `Buffer.concat()` on all chunks before calling `.toString("utf8")`. <details> <summary>🚀 Reply "<strong>fix it for me</strong>" or copy this <strong>AI Prompt</strong> for your agent:</summary> (apps/server/src/wsServer.ts:104)
119− - Threads: PRRT_kwDORLtfbc5whtrR
120−- [ ] C059 [Low] Suggestion: don’t spread `params` into `body`; it can override `_tag` and mishandle non-object values. Keep `_tag` separate and nest `params` under a single key (e.g., `data`), or validate `params` is a plain object. (apps/web/src/wsTransport.ts:59)
121− - Threads: PRRT_kwDORLtfbc5whtrN
122−
123−### Checkpointing correctness (5)
124−
125−- [ ] C008 [Medium] Inconsistent input normalization across CheckpointStore methods (apps/server/src/checkpointing/Layers/CheckpointStore.ts:94) (+3 dup)
126− - Threads: PRRT_kwDORLtfbc5widJw, PRRT_kwDORLtfbc5wnWv_, PRRT_kwDORLtfbc5w0_g7, PRRT_kwDORLtfbc5w1C36
127−- [ ] C017 [Medium] `REQUIRED_SNAPSHOT_PROJECTORS` includes `pending-approvals` and `thread-turns`, but `getSnapshot` doesn't query their data. If these projectors lag behind, the returned `snapshotSequence` will be lower than what the included data actually reflects, causing clients to replay already-applied events. Consider filtering `REQUIRED_SNAPSHOT_PROJECTORS` to only include projectors whose data is actually fetched in the snapshot. <details> <summary>🚀 Reply "<strong>fix it for me</strong>" or copy this <strong>AI Prompt</strong> for your agent:</summary> (apps/server/src/orchestration/Layers/ProjectionSnapshotQuery.ts:71)
128− - Threads: PRRT_kwDORLtfbc5wiLhQ
129−- [ ] C033 [Low] Three error classes defined but never instantiated anywhere (apps/server/src/checkpointing/Errors.ts:51)
130− - Threads: PRRT_kwDORLtfbc5wlYgo
131−- [ ] C034 [Low] Redundant `CheckpointInvariantError` in `CheckpointServiceError` union type (apps/server/src/checkpointing/Errors.ts:79)
132− - Threads: PRRT_kwDORLtfbc5wj5fn
133−- [ ] C035 [Low] Redundant error type in CheckpointServiceError union definition (apps/server/src/checkpointing/Errors.ts:79) (+2 dup)
134− - Threads: PRRT_kwDORLtfbc5wlYgs, PRRT_kwDORLtfbc5wxsO6, PRRT_kwDORLtfbc5w1C4B
135−
136−### Build/runtime portability (2)
137−
138−- [ ] C006 [Medium] Build script runs TypeScript file with bare node (apps/server/package.json:14)
139− - Threads: PRRT_kwDORLtfbc5wxsO-
140−- [ ] C007 [Medium] Build script uses `node` to run `.ts` file directly (apps/server/package.json:14) (+1 dup)
141− - Threads: PRRT_kwDORLtfbc5wiLNS, PRRT_kwDORLtfbc5wj5fl
142−
143−### Memory/resource growth (1)
144−
145−- [ ] C018 [Medium] Unbounded memory growth in turn start deduplication set (apps/server/src/orchestration/Layers/ProviderCommandReactor.ts:84) (+5 dup)
146− - Threads: PRRT_kwDORLtfbc5whszQ, PRRT_kwDORLtfbc5wl2A8, PRRT_kwDORLtfbc5wyTaT, PRRT_kwDORLtfbc5wzliz, PRRT_kwDORLtfbc5w0_g-, PRRT_kwDORLtfbc5w1HGW
147−
148−## Invalid / False-Positive Threads
149−
150−- PRRT_kwDORLtfbc5v9An7 | apps/web/src/routes/__root.tsx:140 | channel.** The web app currently does not consume provider event streams via the `providers.event` channel. While the orchestration API has `onReadModel()` and `onDomainEvent()` subscriptions, the providers event stream subscription is missing. Add a subscription to `ORCHESTRATION_WS_CHANNELS.event` (or the appropriate providers event channel from contracts) in `wsNativeApi.ts` and expose it via the `api.providers` object to comply with the guideline requirement. <details> <summary>🤖 Prompt for AI Agents</summary>
151− - Rationale: Invalid by design: provider runtime events are intentionally surfaced through orchestration domain events (`orchestration.domainEvent`), not a separate `providers.event` WebSocket channel in the current architecture.
152−- PRRT_kwDORLtfbc5v9An- | apps/web/src/wsNativeApi.ts:165 | push stream, and the callbacks rely on unchecked casts. Please reintroduce a `providers.onEvent` (or equivalent) that subscribes to the `providers.event` channel and decode read-model/domain-event payloads using the shared contracts schemas before invoking callbacks. As per coding guidelines: "Web app must consume provider event streams via WebSocket push on channel `providers.event`" and "Use Zod schemas from `packages/contracts` for shared type contracts covering provider events, WebSocket protocol, and model/session types". <details> <summary>🤖 Prompt for AI Agents</summary>
153− - Rationale: Invalid by design: provider runtime events are intentionally surfaced through orchestration domain events (`orchestration.domainEvent`), not a separate `providers.event` WebSocket channel in the current architecture.
154−- PRRT_kwDORLtfbc5v9SCp | apps/web/src/session-logic.ts:127 | Revert uses wrong turn count from positional inference
155− - Rationale: Invalid after post-rewrite audit: Revert now uses explicit checkpointTurnCount first; positional fallback is non-primary.
156−- PRRT_kwDORLtfbc5widJx | apps/server/package.json:14 | Build script requires implicit Node.js TypeScript support
157− - Rationale: Thread contains explicit false-positive determination in replies.
158−- PRRT_kwDORLtfbc5wiqFX | apps/server/src/checkpointing/Layers/CheckpointStore.ts:284 | Duplicate `checkpointRefForThreadTurn` function in two production files
159− - Rationale: Invalid after post-rewrite audit: No longer duplicated; single production source via Refs.ts.
160−- PRRT_kwDORLtfbc5wkPaA | apps/server/src/orchestration/decider.ts:27 | Shared mutable default metadata object causes stale eventId
161− - Rationale: Invalid after post-rewrite audit: Stale-eventId claim no longer applies; eventId is regenerated per event.
162−- PRRT_kwDORLtfbc5wkPaG | apps/server/src/wsServer.ts:128 | Duplicate `checkpointRefForThreadTurn` function across files
163− - Rationale: Invalid after post-rewrite audit: No longer duplicated; helper is centralized.
164−- PRRT_kwDORLtfbc5wvwag | apps/server/src/wsServer.ts:128 | Duplicated checkpoint ref computation across two files
165− - Rationale: Invalid after post-rewrite audit: No longer duplicated; checkpoint ref helper now centralized.
166−
167−## Duplicate Mapping
168−
169−- Each duplicate thread is mapped to one canonical fix item.
170−
171−- PRRT_kwDORLtfbc5wj5fl | apps/server/package.json:14 -> C007
172−- PRRT_kwDORLtfbc5wl2A8 | apps/server/src/orchestration/Layers/ProviderCommandReactor.ts:84 -> C018
173−- PRRT_kwDORLtfbc5wnWv_ | apps/server/src/checkpointing/Layers/CheckpointStore.ts:94 -> C008
174−- PRRT_kwDORLtfbc5wnWwF | apps/server/src/orchestration/Layers/CheckpointReactor.ts:584 -> C002
175−- PRRT_kwDORLtfbc5wxsO6 | apps/server/src/checkpointing/Errors.ts:79 -> C035
176−- PRRT_kwDORLtfbc5wyTaP | apps/server/src/orchestration/Layers/ProviderRuntimeIngestion.ts:334 -> C002
177−- PRRT_kwDORLtfbc5wyTaS | apps/server/src/orchestration/Layers/CheckpointReactor.ts:542 -> C012
178−- PRRT_kwDORLtfbc5wyTaT | apps/server/src/orchestration/Layers/ProviderCommandReactor.ts:84 -> C018
179−- PRRT_kwDORLtfbc5wzliw | apps/server/src/orchestration/Layers/ProviderRuntimeIngestion.ts:334 -> C002
180−- PRRT_kwDORLtfbc5wzliz | apps/server/src/orchestration/Layers/ProviderCommandReactor.ts:84 -> C018
181−- PRRT_kwDORLtfbc5wzli0 | apps/server/src/orchestration/Layers/CheckpointReactor.ts:542 -> C012
182−- PRRT_kwDORLtfbc5wzli3 | apps/server/src/wsServer.ts:545 -> C027
183−- PRRT_kwDORLtfbc5w0_g3 | apps/server/src/orchestration/Layers/ProviderRuntimeIngestion.ts:334 -> C002
184−- PRRT_kwDORLtfbc5w0_g4 | apps/server/src/orchestration/Layers/CheckpointReactor.ts:542 -> C012
185−- PRRT_kwDORLtfbc5w0_g7 | apps/server/src/checkpointing/Layers/CheckpointStore.ts:95 -> C008
186−- PRRT_kwDORLtfbc5w0_g- | apps/server/src/orchestration/Layers/ProviderCommandReactor.ts:84 -> C018
187−- PRRT_kwDORLtfbc5w1C36 | apps/server/src/checkpointing/Layers/CheckpointStore.ts:94 -> C008
188−- PRRT_kwDORLtfbc5w1C3- | apps/server/src/checkpointing/Layers/CheckpointDiffQuery.ts:40 -> C043
189−- PRRT_kwDORLtfbc5w1C4B | apps/server/src/checkpointing/Errors.ts:79 -> C035
190−- PRRT_kwDORLtfbc5w1C4H | AGENTS.md:45 -> C032
191−- PRRT_kwDORLtfbc5w1HGT | apps/server/src/orchestration/Layers/ProviderRuntimeIngestion.ts:334 -> C002
192−- PRRT_kwDORLtfbc5w1HGW | apps/server/src/orchestration/Layers/ProviderCommandReactor.ts:84 -> C018
193−- PRRT_kwDORLtfbc5w1HGX | apps/server/src/orchestration/Layers/CheckpointReactor.ts:542 -> C012
194−- PRRT_kwDORLtfbc5w1HGZ | apps/server/src/checkpointing/Layers/CheckpointDiffQuery.ts:40 -> C043
195−
196−## Outdated / Resolved Buckets
197−
198−- Outdated threads: 94
199−- Resolved threads: 6
200−
201−Per-thread mapping source of truth: `.plans/16a-pr89-phase0-canonical-triage.json`.
.plans/16b-pr89-architecture-validity-audit.json+0−790
@@ -1,790 +0,0 @@
1−{
2− "source": ".plans/16a-pr89-phase0-canonical-triage.json",
3− "architecture_assumption": "Provider runtime activity is projected and consumed via orchestration.domainEvent; no separate providers.event push channel is expected.",
4− "summary": {
5− "total_canonical_reviewed": 58,
6− "valid": 34,
7− "partially_valid": 19,
8− "invalid": 5
9− },
10− "records": [
11− {
12− "canonical_id": "C001",
13− "verdict": "valid",
14− "rationale": "Append/project/receipt are non-atomic; retry can duplicate events.",
15− "severity": "High",
16− "area": "Event ordering and state consistency",
17− "path": "apps/server/src/orchestration/Layers/OrchestrationEngine.ts",
18− "line": 96,
19− "title": "Non-atomic event appending can corrupt state on retry. If an error occurs mid-loop (lines 96-102) after some events are persisted but before the receipt is written, the command appears to fail. A retry generates new UUIDs via `crypto.randomUUID()` in the decider, appending duplicate events. Consider wrapping the loop in a transaction or using deterministic event IDs derived from `commandId`. <details> <summary>\ud83d\ude80 Reply \"<strong>fix it for me</strong>\" or copy this <strong>AI Prompt</strong> for your agent:</summary>",
20− "thread_ids": [
21− "PRRT_kwDORLtfbc5wzp4T"
22− ]
23− },
24− {
25− "canonical_id": "C002",
26− "verdict": "valid",
27− "rationale": "Ingestion worker loop can terminate on unhandled processEvent failure.",
28− "severity": "High",
29− "area": "Runtime resilience and failure handling",
30− "path": "apps/server/src/orchestration/Layers/ProviderRuntimeIngestion.ts",
31− "line": 333,
32− "title": "A dispatch error in `processEvent` will terminate the `Effect.forever` loop, permanently halting event ingestion. Consider adding error recovery (e.g., `Effect.catchAll` with logging) around `processEvent` so failures don't kill the fiber.",
33− "thread_ids": [
34− "PRRT_kwDORLtfbc5wj4cH",
35− "PRRT_kwDORLtfbc5wnWwF",
36− "PRRT_kwDORLtfbc5wyTaP",
37− "PRRT_kwDORLtfbc5wzliw",
38− "PRRT_kwDORLtfbc5w0_g3",
39− "PRRT_kwDORLtfbc5w1HGT"
40− ]
41− },
42− {
43− "canonical_id": "C003",
44− "verdict": "valid",
45− "rationale": "Upgrade reject writes then destroys socket without defensive error listener.",
46− "severity": "High",
47− "area": "WebSocket robustness",
48− "path": "apps/server/src/wsServer.ts",
49− "line": 75,
50− "title": "Consider attaching a no-op error listener before `socket.write` (e.g., `socket.on('error', () => {})`) to prevent an unhandled `EPIPE`/`ECONNRESET` from crashing the process if the client disconnects mid-handshake.",
51− "thread_ids": [
52− "PRRT_kwDORLtfbc5v-cf4"
53− ]
54− },
55− {
56− "canonical_id": "C006",
57− "verdict": "partially-valid",
58− "rationale": "Node 24 makes this work, but script still relies on runtime-specific TS execution.",
59− "severity": "Medium",
60− "area": "Build/runtime portability",
61− "path": "apps/server/package.json",
62− "line": 14,
63− "title": "Build script runs TypeScript file with bare node",
64− "thread_ids": [
65− "PRRT_kwDORLtfbc5wxsO-"
66− ]
67− },
68− {
69− "canonical_id": "C007",
70− "verdict": "partially-valid",
71− "rationale": "Same as C006 (duplicate concern).",
72− "severity": "Medium",
73− "area": "Build/runtime portability",
74− "path": "apps/server/package.json",
75− "line": 14,
76− "title": "Build script uses `node` to run `.ts` file directly",
77− "thread_ids": [
78− "PRRT_kwDORLtfbc5wiLNS",
79− "PRRT_kwDORLtfbc5wj5fl"
80− ]
81− },
82− {
83− "canonical_id": "C008",
84− "verdict": "partially-valid",
85− "rationale": "Normalization inconsistency remains, but upstream callsites now mostly canonicalize inputs.",
86− "severity": "Medium",
87− "area": "Checkpointing correctness",
88− "path": "apps/server/src/checkpointing/Layers/CheckpointStore.ts",
89− "line": 94,
90− "title": "Inconsistent input normalization across CheckpointStore methods",
91− "thread_ids": [
92− "PRRT_kwDORLtfbc5widJw",
93− "PRRT_kwDORLtfbc5wnWv_",
94− "PRRT_kwDORLtfbc5w0_g7",
95− "PRRT_kwDORLtfbc5w1C36"
96− ]
97− },
98− {
99− "canonical_id": "C009",
100− "verdict": "valid",
101− "rationale": "Braced rename parsing still breaks paths like src/{old => new}/file.ts.",
102− "severity": "Medium",
103− "area": "Edge-case parsing/platform behavior",
104− "path": "apps/server/src/git/Layers/GitCore.ts",
105− "line": 41,
106− "title": "Git's braced rename syntax (e.g., `src/{old => new}/file.ts`) isn't handled correctly. The current slice after ` => ` produces invalid paths like `new}/file.ts`. Consider expanding the braces to construct the full destination path. <details> <summary>\ud83d\ude80 Reply \"<strong>fix it for me</strong>\" or copy this <strong>AI Prompt</strong> for your agent:</summary>",
107− "thread_ids": [
108− "PRRT_kwDORLtfbc5w1CxT"
109− ]
110− },
111− {
112− "canonical_id": "C010",
113− "verdict": "valid",
114− "rationale": "ENOENT for missing keybindings config still not handled as empty/default.",
115− "severity": "Medium",
116− "area": "Edge-case parsing/platform behavior",
117− "path": "apps/server/src/keybindings.ts",
118− "line": 418,
119− "title": "`loadCustomKeybindingsConfig` fails when the config file doesn't exist, which is expected for new users. Consider catching `ENOENT` and returning an empty array instead. <details> <summary>\ud83d\ude80 Reply \"<strong>fix it for me</strong>\" or copy this <strong>AI Prompt</strong> for your agent:</summary>",
120− "thread_ids": [
121− "PRRT_kwDORLtfbc5wxvIJ"
122− ]
123− },
124− {
125− "canonical_id": "C011",
126− "verdict": "valid",
127− "rationale": "Template-literal interpolation of Symbol still throws.",
128− "severity": "Medium",
129− "area": "Other",
130− "path": "apps/server/src/orchestration/Errors.ts",
131− "line": 117,
132− "title": "Template literal `${cause}` throws if `cause` is a `Symbol`. Consider using `String(cause)` instead.",
133− "thread_ids": [
134− "PRRT_kwDORLtfbc5wBFv4"
135− ]
136− },
137− {
138− "canonical_id": "C012",
139− "verdict": "valid",
140− "rationale": "Revert completion dispatch remains forked; state consistency window remains.",
141− "severity": "Medium",
142− "area": "Runtime resilience and failure handling",
143− "path": "apps/server/src/orchestration/Layers/CheckpointReactor.ts",
144− "line": 542,
145− "title": "Forked revert dispatch risks read model inconsistency",
146− "thread_ids": [
147− "PRRT_kwDORLtfbc5whszW",
148− "PRRT_kwDORLtfbc5wyTaS",
149− "PRRT_kwDORLtfbc5wzli0",
150− "PRRT_kwDORLtfbc5w0_g4",
151− "PRRT_kwDORLtfbc5w1HGX"
152− ]
153− },
154− {
155− "canonical_id": "C013",
156− "verdict": "valid",
157− "rationale": "Persisted event can outpace in-memory projection on mid-flight failure.",
158− "severity": "Medium",
159− "area": "Event ordering and state consistency",
160− "path": "apps/server/src/orchestration/Layers/OrchestrationEngine.ts",
161− "line": 99,
162− "title": "If `projectionPipeline.projectEvent` fails after `eventStore.append` succeeds, the event is persisted but `readModel` isn't updated, causing desync. Consider updating the in-memory `readModel` immediately after append (before the external projection), so local state stays consistent regardless of downstream failures.",
163− "thread_ids": [
164− "PRRT_kwDORLtfbc5whtrM"
165− ]
166− },
167− {
168− "canonical_id": "C014",
169− "verdict": "partially-valid",
170− "rationale": "Broad catch may be intentional for liveness; correctness concern is contextual.",
171− "severity": "Medium",
172− "area": "Event ordering and state consistency",
173− "path": "apps/server/src/orchestration/Layers/OrchestrationEngine.ts",
174− "line": 144,
175− "title": "Engine error handler catches all errors including non-invariant ones",
176− "thread_ids": [
177− "PRRT_kwDORLtfbc5wkPaJ"
178− ]
179− },
180− {
181− "canonical_id": "C015",
182− "verdict": "partially-valid",
183− "rationale": "Message fallback retention issue is real, but prior FK-violation claim is overstated.",
184− "severity": "Medium",
185− "area": "Event ordering and state consistency",
186− "path": "apps/server/src/orchestration/Layers/ProjectionPipeline.ts",
187− "line": 99,
188− "title": "The gap-filling fallback logic can retain messages from turns that are about to be deleted, causing foreign key violations. Consider removing the fallback logic entirely, or filtering `fallbackUserMessages` and `fallbackAssistantMessages` to only include messages whose `turnId` is in `retainedTurnIds`. <details> <summary>\ud83d\ude80 Reply \"<strong>fix it for me</strong>\" or copy this <strong>AI Prompt</strong> for your agent:</summary>",
189− "thread_ids": [
190− "PRRT_kwDORLtfbc5whxJO"
191− ]
192− },
193− {
194− "canonical_id": "C016",
195− "verdict": "valid",
196− "rationale": "Pending turn-start map is in-memory only and not rebuilt on bootstrap.",
197− "severity": "Medium",
198− "area": "Event ordering and state consistency",
199− "path": "apps/server/src/orchestration/Layers/ProjectionPipeline.ts",
200− "line": 490,
201− "title": "The in-memory `pendingTurnStartByThreadId` map isn't restored during bootstrap. If the service restarts after processing `thread.turn-start-requested` but before `thread.session-set`, the `userMessageId` and `startedAt` will be lost since bootstrap resumes *after* the committed sequence. Consider persisting this pending state or processing these two events atomically. <details> <summary>\ud83d\ude80 Reply \"<strong>fix it for me</strong>\" or copy this <strong>AI Prompt</strong> for your agent:</summary>",
202− "thread_ids": [
203− "PRRT_kwDORLtfbc5wxvH8"
204− ]
205− },
206− {
207− "canonical_id": "C017",
208− "verdict": "partially-valid",
209− "rationale": "Snapshot sequence can under-report due to extra projectors, but replay impact is lower now.",
210− "severity": "Medium",
211− "area": "Checkpointing correctness",
212− "path": "apps/server/src/orchestration/Layers/ProjectionSnapshotQuery.ts",
213− "line": 71,
214− "title": "`REQUIRED_SNAPSHOT_PROJECTORS` includes `pending-approvals` and `thread-turns`, but `getSnapshot` doesn't query their data. If these projectors lag behind, the returned `snapshotSequence` will be lower than what the included data actually reflects, causing clients to replay already-applied events. Consider filtering `REQUIRED_SNAPSHOT_PROJECTORS` to only include projectors whose data is actually fetched in the snapshot. <details> <summary>\ud83d\ude80 Reply \"<strong>fix it for me</strong>\" or copy this <strong>AI Prompt</strong> for your agent:</summary>",
215− "thread_ids": [
216− "PRRT_kwDORLtfbc5wiLhQ"
217− ]
218− },
219− {
220− "canonical_id": "C018",
221− "verdict": "valid",
222− "rationale": "handledTurnStartKeys still grows without pruning.",
223− "severity": "Medium",
224− "area": "Memory/resource growth",
225− "path": "apps/server/src/orchestration/Layers/ProviderCommandReactor.ts",
226− "line": 84,
227− "title": "Unbounded memory growth in turn start deduplication set",
228− "thread_ids": [
229− "PRRT_kwDORLtfbc5whszQ",
230− "PRRT_kwDORLtfbc5wl2A8",
231− "PRRT_kwDORLtfbc5wyTaT",
232− "PRRT_kwDORLtfbc5wzliz",
233− "PRRT_kwDORLtfbc5w0_g-",
234− "PRRT_kwDORLtfbc5w1HGW"
235− ]
236− },
237− {
238− "canonical_id": "C019",
239− "verdict": "partially-valid",
240− "rationale": "SessionId-only routing can misassociate events under races/rebinds.",
241− "severity": "Medium",
242− "area": "Runtime resilience and failure handling",
243− "path": "apps/server/src/orchestration/Layers/ProviderRuntimeIngestion.ts",
244− "line": 178,
245− "title": "ProviderRuntimeIngestion processes events for wrong thread on race",
246− "thread_ids": [
247− "PRRT_kwDORLtfbc5wkPaL"
248− ]
249− },
250− {
251− "canonical_id": "C020",
252− "verdict": "partially-valid",
253− "rationale": "Duplicate complete dispatch exists; downstream impact often idempotent.",
254− "severity": "Medium",
255− "area": "Runtime resilience and failure handling",
256− "path": "apps/server/src/orchestration/Layers/ProviderRuntimeIngestion.ts",
257− "line": 266,
258− "title": "On `message.completed`, the message ID is added to the set and `thread.message.assistant.complete` is dispatched. On `turn.completed`, the same set is iterated and `thread.message.assistant.complete` is dispatched again for each ID\u2014including already-completed ones. Consider removing message IDs from the set after dispatching on `message.completed`, or filtering out already-completed IDs before the `turn.completed` loop.",
259− "thread_ids": [
260− "PRRT_kwDORLtfbc5w1GPr"
261− ]
262− },
263− {
264− "canonical_id": "C021",
265− "verdict": "invalid",
266− "rationale": "Stale-eventId claim no longer applies; eventId is regenerated per event.",
267− "severity": "Medium",
268− "area": "Other",
269− "path": "apps/server/src/orchestration/decider.ts",
270− "line": 27,
271− "title": "Shared mutable default metadata object causes stale eventId",
272− "thread_ids": [
273− "PRRT_kwDORLtfbc5wkPaA"
274− ]
275− },
276− {
277− "canonical_id": "C022",
278− "verdict": "valid",
279− "rationale": "fish PATH formatting risk still exists in os-jank path recovery.",
280− "severity": "Medium",
281− "area": "Edge-case parsing/platform behavior",
282− "path": "apps/server/src/os-jank.ts",
283− "line": 10,
284− "title": "Fish shell outputs `$PATH` as space-separated, not colon-separated. Consider checking if the shell is fish and using `string join : $PATH` instead, or validating the result contains colons before assigning.",
285− "thread_ids": [
286− "PRRT_kwDORLtfbc5wkRZM"
287− ]
288− },
289− {
290− "canonical_id": "C023",
291− "verdict": "valid",
292− "rationale": "-ilc shell invocation can pollute captured PATH output.",
293− "severity": "Medium",
294− "area": "Edge-case parsing/platform behavior",
295− "path": "apps/server/src/os-jank.ts",
296− "line": 10,
297− "title": "Using `-il` flags causes the shell to source profile scripts that may print banners or other text, polluting the captured `PATH`. Consider using `-lc` (login only, non-interactive) to reduce unwanted output.",
298− "thread_ids": [
299− "PRRT_kwDORLtfbc5wj4cM"
300− ]
301− },
302− {
303− "canonical_id": "C024",
304− "verdict": "partially-valid",
305− "rationale": "prepare() still outside managed effect boundary; failure handling risk remains.",
306− "severity": "Medium",
307− "area": "Other",
308− "path": "apps/server/src/persistence/NodeSqliteClient.ts",
309− "line": 145,
310− "title": "In `executeUnprepared`, preparing outside an effect and not closing the statement can cause uncaught errors and leaks. Suggest wrapping with `Effect.acquireUseRelease`: prepare in acquire (error-safe) and `finalize` in release.",
311− "thread_ids": [
312− "PRRT_kwDORLtfbc5whxX9"
313− ]
314− },
315− {
316− "canonical_id": "C025",
317− "verdict": "invalid",
318− "rationale": "No longer duplicated; checkpoint ref helper now centralized.",
319− "severity": "Medium",
320− "area": "Checkpointing correctness",
321− "path": "apps/server/src/wsServer.ts",
322− "line": 128,
323− "title": "Duplicated checkpoint ref computation across two files",
324− "thread_ids": [
325− "PRRT_kwDORLtfbc5wvwag"
326− ]
327− },
328− {
329− "canonical_id": "C026",
330− "verdict": "valid",
331− "rationale": "runPromise result still not caught; rejection can surface unhandled.",
332− "severity": "Medium",
333− "area": "WebSocket robustness",
334− "path": "apps/server/src/wsServer.ts",
335− "line": 545,
336− "title": "Consider adding `.catch(() => {})` after `Effect.runPromise(handleMessage(ws, raw))` to prevent unhandled rejections from crashing the server if `encodeResponse` or setup logic fails.",
337− "thread_ids": [
338− "PRRT_kwDORLtfbc5wj4cE"
339− ]
340− },
341− {
342− "canonical_id": "C027",
343− "verdict": "valid",
344− "rationale": "Same unhandled rejection path remains in WS message handler.",
345− "severity": "Medium",
346− "area": "Runtime resilience and failure handling",
347− "path": "apps/server/src/wsServer.ts",
348− "line": 545,
349− "title": "WS message handler can cause unhandled promise rejection",
350− "thread_ids": [
351− "PRRT_kwDORLtfbc5wyTaW",
352− "PRRT_kwDORLtfbc5wzli3"
353− ]
354− },
355− {
356− "canonical_id": "C028",
357− "verdict": "partially-valid",
358− "rationale": "Optimistic local+server dual update is intentional but can temporarily diverge.",
359− "severity": "Medium",
360− "area": "Other",
361− "path": "apps/web/src/components/BranchToolbar.tsx",
362− "line": 102,
363− "title": "Branch sync dispatches both server and stale local update",
364− "thread_ids": [
365− "PRRT_kwDORLtfbc5v-XCu"
366− ]
367− },
368− {
369− "canonical_id": "C029",
370− "verdict": "valid",
371− "rationale": "file URL decoding still double-decodes in one path.",
372− "severity": "Medium",
373− "area": "Edge-case parsing/platform behavior",
374− "path": "apps/web/src/markdown-links.ts",
375− "line": 105,
376− "title": "`parseFileUrlHref` already decodes the path (line 46), but `safeDecode` is called again here, corrupting filenames containing `%` sequences. Consider skipping the decode when `fileUrlTarget` is non-null.",
377− "thread_ids": [
378− "PRRT_kwDORLtfbc5wnVsU"
379− ]
380− },
381− {
382− "canonical_id": "C030",
383− "verdict": "valid",
384− "rationale": "Scheme regex still misclassifies script.ts:10 as external scheme.",
385− "severity": "Medium",
386− "area": "Edge-case parsing/platform behavior",
387− "path": "apps/web/src/markdown-links.ts",
388− "line": 111,
389− "title": "`EXTERNAL_SCHEME_PATTERN` matches `script.ts:10` as a scheme because `.ts:` looks like `scheme:`. Consider requiring `://` after the colon, or checking that what follows the colon is not just digits. <details> <summary>\ud83d\ude80 Reply \"<strong>fix it for me</strong>\" or copy this <strong>AI Prompt</strong> for your agent:</summary>",
390− "thread_ids": [
391− "PRRT_kwDORLtfbc5wnVsK"
392− ]
393− },
394− {
395− "canonical_id": "C031",
396− "verdict": "invalid",
397− "rationale": "Revert now uses explicit checkpointTurnCount first; positional fallback is non-primary.",
398− "severity": "Medium",
399− "area": "Event ordering and state consistency",
400− "path": "apps/web/src/session-logic.ts",
401− "line": 127,
402− "title": "Revert uses wrong turn count from positional inference",
403− "thread_ids": [
404− "PRRT_kwDORLtfbc5v9SCp"
405− ]
406− },
407− {
408− "canonical_id": "C032",
409− "verdict": "valid",
410− "rationale": "Dummy workflow marker comment is still present in docs.",
411− "severity": "Low",
412− "area": "Other",
413− "path": "AGENTS.md",
414− "line": 45,
415− "title": "Dummy workflow marker accidentally committed to docs",
416− "thread_ids": [
417− "PRRT_kwDORLtfbc5wlYgj",
418− "PRRT_kwDORLtfbc5w1C4H"
419− ]
420− },
421− {
422− "canonical_id": "C033",
423− "verdict": "partially-valid",
424− "rationale": "Original claim overstated; some errors used, others appear unused.",
425− "severity": "Low",
426− "area": "Checkpointing correctness",
427− "path": "apps/server/src/checkpointing/Errors.ts",
428− "line": 51,
429− "title": "Three error classes defined but never instantiated anywhere",
430− "thread_ids": [
431− "PRRT_kwDORLtfbc5wlYgo"
432− ]
433− },
434− {
435− "canonical_id": "C034",
436− "verdict": "valid",
437− "rationale": "CheckpointInvariantError remains redundantly included in service union.",
438− "severity": "Low",
439− "area": "Checkpointing correctness",
440− "path": "apps/server/src/checkpointing/Errors.ts",
441− "line": 79,
442− "title": "Redundant `CheckpointInvariantError` in `CheckpointServiceError` union type",
443− "thread_ids": [
444− "PRRT_kwDORLtfbc5wj5fn"
445− ]
446− },
447− {
448− "canonical_id": "C035",
449− "verdict": "valid",
450− "rationale": "Same as C034.",
451− "severity": "Low",
452− "area": "Checkpointing correctness",
453− "path": "apps/server/src/checkpointing/Errors.ts",
454− "line": 79,
455− "title": "Redundant error type in CheckpointServiceError union definition",
456− "thread_ids": [
457− "PRRT_kwDORLtfbc5wlYgs",
458− "PRRT_kwDORLtfbc5wxsO6",
459− "PRRT_kwDORLtfbc5w1C4B"
460− ]
461− },
462− {
463− "canonical_id": "C036",
464− "verdict": "invalid",
465− "rationale": "No longer duplicated; single production source via Refs.ts.",
466− "severity": "Low",
467− "area": "Checkpointing correctness",
468− "path": "apps/server/src/checkpointing/Layers/CheckpointStore.ts",
469− "line": 284,
470− "title": "Duplicate `checkpointRefForThreadTurn` function in two production files",
471− "thread_ids": [
472− "PRRT_kwDORLtfbc5wiqFX"
473− ]
474− },
475− {
476− "canonical_id": "C037",
477− "verdict": "partially-valid",
478− "rationale": "Callback cleanup missing, but practical exposure is low in one-shot startup path.",
479− "severity": "Low",
480− "area": "Other",
481− "path": "apps/server/src/config.ts",
482− "line": 41,
483− "title": "`Effect.callback` should return a cleanup function to close the server(s) on fiber interruption. Without it, the `Net.Server` handles keep the process alive and leak the port if the effect is cancelled. <details> <summary>\ud83d\ude80 Reply \"<strong>fix it for me</strong>\" or copy this <strong>AI Prompt</strong> for your agent:</summary>",
484− "thread_ids": [
485− "PRRT_kwDORLtfbc5wj4cO"
486− ]
487− },
488− {
489− "canonical_id": "C038",
490− "verdict": "valid",
491− "rationale": "Chunk-by-chunk UTF-8 decode can still corrupt split multibyte characters.",
492− "severity": "Low",
493− "area": "Edge-case parsing/platform behavior",
494− "path": "apps/server/src/git/Layers/CodexTextGeneration.ts",
495− "line": 136,
496− "title": "Multi-byte UTF-8 characters split across chunks will be corrupted when decoding each chunk separately. Consider accumulating all chunks first, then decoding once, or use `TextDecoder` with `stream: true`. <details> <summary>\ud83d\ude80 Reply \"<strong>fix it for me</strong>\" or copy this <strong>AI Prompt</strong> for your agent:</summary>",
497− "thread_ids": [
498− "PRRT_kwDORLtfbc5w1GPo"
499− ]
500− },
501− {
502− "canonical_id": "C039",
503− "verdict": "partially-valid",
504− "rationale": "Parser/encoder mismatch remains, but encoder path currently low-use.",
505− "severity": "Low",
506− "area": "Edge-case parsing/platform behavior",
507− "path": "apps/server/src/keybindings.ts",
508− "line": 352,
509− "title": "The `+` key can be parsed (via trailing `+` handling) but cannot be encoded because `shortcut.key.includes(\"+\")` returns true for the literal `+` key. Consider checking `shortcut.key === \"+\"` separately and encoding it as `\"space\"` style (e.g., a special token), or adjusting the condition to allow the single `+` character. <details> <summary>\ud83d\ude80 Reply \"<strong>fix it for me</strong>\" or copy this <strong>AI Prompt</strong> for your agent:</summary>",
510− "thread_ids": [
511− "PRRT_kwDORLtfbc5wxvIB"
512− ]
513− },
514− {
515− "canonical_id": "C040",
516− "verdict": "valid",
517− "rationale": "upsertKeybindingRule read-modify-write remains race-prone.",
518− "severity": "Low",
519− "area": "Edge-case parsing/platform behavior",
520− "path": "apps/server/src/keybindings.ts",
521− "line": 488,
522− "title": "`upsertKeybindingRule` has a race condition: concurrent calls read the same file state, then the last write overwrites earlier changes. Consider wrapping the read-modify-write sequence with `Effect.Semaphore` to serialize access. <details> <summary>\ud83d\ude80 Reply \"<strong>fix it for me</strong>\" or copy this <strong>AI Prompt</strong> for your agent:</summary>",
523− "thread_ids": [
524− "PRRT_kwDORLtfbc5wxvIA"
525− ]
526− },
527− {
528− "canonical_id": "C041",
529− "verdict": "valid",
530− "rationale": "Same Symbol interpolation hazard as C011 remains.",
531− "severity": "Low",
532− "area": "Other",
533− "path": "apps/server/src/orchestration/Errors.ts",
534− "line": 126,
535− "title": "Template literal interpolation throws `TypeError` if `cause` is a `Symbol`. Consider using `String(cause)` for safe coercion.",
536− "thread_ids": [
537− "PRRT_kwDORLtfbc5wBFWs"
538− ]
539− },
540− {
541− "canonical_id": "C042",
542− "verdict": "partially-valid",
543− "rationale": "Duplication exists but one instance is variant logic, so impact is moderate.",
544− "severity": "Low",
545− "area": "Runtime resilience and failure handling",
546− "path": "apps/server/src/orchestration/Layers/CheckpointReactor.ts",
547− "line": 62,
548− "title": "Duplicated `resolveThreadWorkspaceCwd` across three files",
549− "thread_ids": [
550− "PRRT_kwDORLtfbc5wzli2"
551− ]
552− },
553− {
554− "canonical_id": "C043",
555− "verdict": "valid",
556− "rationale": "Workspace CWD resolution duplication still present across modules.",
557− "severity": "Low",
558− "area": "Runtime resilience and failure handling",
559− "path": "apps/server/src/orchestration/Layers/CheckpointReactor.ts",
560− "line": 62,
561− "title": "Duplicated workspace CWD resolution logic across reactor modules",
562− "thread_ids": [
563− "PRRT_kwDORLtfbc5wnWwM",
564− "PRRT_kwDORLtfbc5w1C3-",
565− "PRRT_kwDORLtfbc5w1HGZ"
566− ]
567− },
568− {
569− "canonical_id": "C044",
570− "verdict": "partially-valid",
571− "rationale": "Errors are swallowed to empty diff with warning; not fully silent but still lossy.",
572− "severity": "Low",
573− "area": "Runtime resilience and failure handling",
574− "path": "apps/server/src/orchestration/Layers/CheckpointReactor.ts",
575− "line": 274,
576− "title": "Checkpoint reactor swallows diff errors silently for `turn.completed`",
577− "thread_ids": [
578− "PRRT_kwDORLtfbc5wkPaO"
579− ]
580− },
581− {
582− "canonical_id": "C045",
583− "verdict": "valid",
584− "rationale": "truncateDetail still overshoots limit.",
585− "severity": "Low",
586− "area": "Runtime resilience and failure handling",
587− "path": "apps/server/src/orchestration/Layers/ProviderRuntimeIngestion.ts",
588− "line": 29,
589− "title": "`truncateDetail` slices to `limit - 1` then appends `\"...\"` (3 chars), producing strings of length `limit + 2`. Consider slicing to `limit - 3` instead. <details> <summary>\ud83d\ude80 Reply \"<strong>fix it for me</strong>\" or copy this <strong>AI Prompt</strong> for your agent:</summary>",
590− "thread_ids": [
591− "PRRT_kwDORLtfbc5wzp4R"
592− ]
593− },
594− {
595− "canonical_id": "C046",
596− "verdict": "valid",
597− "rationale": "latestMessageIdByTurnKey still unused/unpruned in per-turn clear path.",
598− "severity": "Low",
599− "area": "Runtime resilience and failure handling",
600− "path": "apps/server/src/orchestration/Layers/ProviderRuntimeIngestion.ts",
601− "line": 133,
602− "title": "`latestMessageIdByTurnKey` is written to but never read, and `clearAssistantMessageIdsForTurn` doesn't clear its entries\u2014only `clearTurnStateForSession` does. Consider removing this map entirely if unused, or clearing it alongside `turnMessageIdsByTurnKey` in `clearAssistantMessageIdsForTurn`. <details> <summary>\ud83d\ude80 Reply \"<strong>fix it for me</strong>\" or copy this <strong>AI Prompt</strong> for your agent:</summary>",
603− "thread_ids": [
604− "PRRT_kwDORLtfbc5wxvIQ"
605− ]
606− },
607− {
608− "canonical_id": "C047",
609− "verdict": "valid",
610− "rationale": "Decode and SQL errors still collapsed into one persistence error kind.",
611− "severity": "Low",
612− "area": "Other",
613− "path": "apps/server/src/persistence/Layers/OrchestrationCommandReceipts.ts",
614− "line": 75,
615− "title": "`SqlSchema.findOneOption` can produce both SQL errors and decode errors, but `mapError` wraps all as `PersistenceSqlError`. Consider distinguishing `ParseError` from SQL errors and mapping decode failures to `PersistenceDecodeError` instead. <details> <summary>\ud83d\ude80 Reply \"<strong>fix it for me</strong>\" or copy this <strong>AI Prompt</strong> for your agent:</summary>",
616− "thread_ids": [
617− "PRRT_kwDORLtfbc5wiaR-"
618− ]
619− },
620− {
621− "canonical_id": "C048",
622− "verdict": "partially-valid",
623− "rationale": "Unsafe run() result cast remains; runtime risk depends on raw-result consumers.",
624− "severity": "Low",
625− "area": "Other",
626− "path": "apps/server/src/persistence/NodeSqliteClient.ts",
627− "line": 99,
628− "title": "`statement.run()` returns a `RunResult` object, not an array. Casting it to `ReadonlyArray<any>` will cause runtime errors when consumers call array methods. Consider wrapping the result (e.g., `[result]`) or returning a properly typed object.",
629− "thread_ids": [
630− "PRRT_kwDORLtfbc5wio-r"
631− ]
632− },
633− {
634− "canonical_id": "C049",
635− "verdict": "valid",
636− "rationale": "JSON.stringify(cause) may return undefined despite string expectations.",
637− "severity": "Low",
638− "area": "Other",
639− "path": "apps/server/src/provider/Layers/ProviderService.ts",
640− "line": 59,
641− "title": "`JSON.stringify(cause)` returns `undefined` for `undefined`, functions, or symbols, violating the `string` return type. Consider coercing the result to a string (e.g., `String(JSON.stringify(cause))`) or adding a fallback.",
642− "thread_ids": [
643− "PRRT_kwDORLtfbc5wnVsI"
644− ]
645− },
646− {
647− "canonical_id": "C050",
648− "verdict": "valid",
649− "rationale": "ProviderSessionDirectory upsert remains read-merge-write without concurrency control.",
650− "severity": "Low",
651− "area": "Other",
652− "path": "apps/server/src/provider/Layers/ProviderSessionDirectory.ts",
653− "line": 94,
654− "title": "The read-modify-write pattern (`getBySessionId` \u2192 merge \u2192 `upsert`) is susceptible to lost updates under concurrent writes. Consider wrapping in a transaction or adding optimistic concurrency control (e.g., version field) if concurrent session updates are expected. <details> <summary>\ud83d\ude80 Reply \"<strong>fix it for me</strong>\" or copy this <strong>AI Prompt</strong> for your agent:</summary>",
655− "thread_ids": [
656− "PRRT_kwDORLtfbc5wiLhY"
657− ]
658− },
659− {
660− "canonical_id": "C051",
661− "verdict": "partially-valid",
662− "rationale": "Null-clearing issue is real for providerThreadId; adapterKey part overstated.",
663− "severity": "Low",
664− "area": "Other",
665− "path": "apps/server/src/provider/Layers/ProviderSessionDirectory.ts",
666− "line": 119,
667− "title": "Using `??` for `providerThreadId` and `adapterKey` makes it impossible to clear these fields by passing `null`, since `null ?? existing` evaluates to `existing`. Consider using explicit `undefined` checks (like `resumeCursor` does) if clearing should be supported. <details> <summary>\ud83d\ude80 Reply \"<strong>fix it for me</strong>\" or copy this <strong>AI Prompt</strong> for your agent:</summary>",
668− "thread_ids": [
669− "PRRT_kwDORLtfbc5wxvH9"
670− ]
671− },
672− {
673− "canonical_id": "C052",
674− "verdict": "valid",
675− "rationale": "Data callback may race before processHandle assignment.",
676− "severity": "Low",
677− "area": "Other",
678− "path": "apps/server/src/terminal/Layers/BunPTY.ts",
679− "line": 97,
680− "title": "Race condition: `processHandle` may be `null` when `data` callback fires, since it's assigned after `Bun.spawn` returns. Consider initializing `BunPtyProcess` first, then passing it to the callback to avoid losing initial output. <details> <summary>\ud83d\ude80 Reply \"<strong>fix it for me</strong>\" or copy this <strong>AI Prompt</strong> for your agent:</summary>",
681− "thread_ids": [
682− "PRRT_kwDORLtfbc5w1CxE"
683− ]
684− },
685− {
686− "canonical_id": "C053",
687− "verdict": "valid",
688− "rationale": "Still uses write+destroy rather than end() for rejection response.",
689− "severity": "Low",
690− "area": "WebSocket robustness",
691− "path": "apps/server/src/wsServer.ts",
692− "line": 83,
693− "title": "Consider using `socket.end(response)` instead of `socket.write(response)` + `socket.destroy()` to ensure the HTTP error response is fully flushed before closing the connection.",
694− "thread_ids": [
695− "PRRT_kwDORLtfbc5v-WPD"
696− ]
697− },
698− {
699− "canonical_id": "C054",
700− "verdict": "valid",
701− "rationale": "Array chunk UTF-8 decode remains vulnerable to split multibyte corruption.",
702− "severity": "Low",
703− "area": "WebSocket robustness",
704− "path": "apps/server/src/wsServer.ts",
705− "line": 104,
706− "title": "When array chunks contain a multi-byte UTF-8 character split across boundaries, decoding each chunk separately produces replacement characters. Consider using `Buffer.concat()` on all chunks before calling `.toString(\"utf8\")`. <details> <summary>\ud83d\ude80 Reply \"<strong>fix it for me</strong>\" or copy this <strong>AI Prompt</strong> for your agent:</summary>",
707− "thread_ids": [
708− "PRRT_kwDORLtfbc5whtrR"
709− ]
710− },
711− {
712− "canonical_id": "C055",
713− "verdict": "invalid",
714− "rationale": "No longer duplicated; helper is centralized.",
715− "severity": "Low",
716− "area": "Checkpointing correctness",
717− "path": "apps/server/src/wsServer.ts",
718− "line": 128,
719− "title": "Duplicate `checkpointRefForThreadTurn` function across files",
720− "thread_ids": [
721− "PRRT_kwDORLtfbc5wkPaG"
722− ]
723− },
724− {
725− "canonical_id": "C056",
726− "verdict": "partially-valid",
727− "rationale": "Bug pattern exists, but current callsites mostly avoid triggering it.",
728− "severity": "Low",
729− "area": "Other",
730− "path": "apps/web/src/components/ui/sidebar.tsx",
731− "line": 114,
732− "title": "When `onOpenChange` is provided without `open`, the internal `_open` state never updates because `setOpenProp` takes precedence. Consider calling `_setOpen` when `openProp === undefined`, regardless of whether `setOpenProp` exists.",
733− "thread_ids": [
734− "PRRT_kwDORLtfbc5wxvIq"
735− ]
736− },
737− {
738− "canonical_id": "C057",
739− "verdict": "valid",
740− "rationale": "Resizable object recreation still retriggers effect/storage reads.",
741− "severity": "Low",
742− "area": "Other",
743− "path": "apps/web/src/routes/_chat.$threadId.tsx",
744− "line": 105,
745− "title": "The `resizable` object is recreated on every render, causing `SidebarRail`'s `useEffect` to repeatedly read localStorage and update the DOM. Consider memoizing the object with `useMemo`. <details> <summary>\ud83d\ude80 Reply \"<strong>fix it for me</strong>\" or copy this <strong>AI Prompt</strong> for your agent:</summary>",
746− "thread_ids": [
747− "PRRT_kwDORLtfbc5wyWz4"
748− ]
749− },
750− {
751− "canonical_id": "C058",
752− "verdict": "valid",
753− "rationale": "Number(null) -> 0 path still forces min width on initial load.",
754− "severity": "Low",
755− "area": "Other",
756− "path": "apps/web/src/routes/_chat.$threadId.tsx",
757− "line": 122,
758− "title": "When `localStorage.getItem()` returns `null`, `Number(null)` evaluates to `0`, which passes `Number.isFinite(0)`. This causes the sidebar to clamp to `minWidth` on first load, overriding the `DIFF_INLINE_DEFAULT_WIDTH` CSS clamp. Consider checking for `null` or empty string before parsing, e.g. guard with `storedWidth === null || storedWidth === ''`. <details> <summary>\ud83d\ude80 Reply \"<strong>fix it for me</strong>\" or copy this <strong>AI Prompt</strong> for your agent:</summary>",
759− "thread_ids": [
760− "PRRT_kwDORLtfbc5wnVsX"
761− ]
762− },
763− {
764− "canonical_id": "C059",
765− "verdict": "partially-valid",
766− "rationale": "Transport _tag override risk exists but current callsites are constrained.",
767− "severity": "Low",
768− "area": "WebSocket robustness",
769− "path": "apps/web/src/wsTransport.ts",
770− "line": 59,
771− "title": "Suggestion: don\u2019t spread `params` into `body`; it can override `_tag` and mishandle non-object values. Keep `_tag` separate and nest `params` under a single key (e.g., `data`), or validate `params` is a plain object.",
772− "thread_ids": [
773− "PRRT_kwDORLtfbc5whtrN"
774− ]
775− },
776− {
777− "canonical_id": "C060",
778− "verdict": "valid",
779− "rationale": "Schema still cannot express null clear for defaultModel patch.",
780− "severity": "Low",
781− "area": "Other",
782− "path": "packages/contracts/src/orchestration.ts",
783− "line": 253,
784− "title": "`defaultModel` should be `Schema.optional(Schema.NullOr(Schema.String))` to allow clearing the value. Currently there's no way to reset it to `null` since omitting means \"no change\" in patch semantics. <details> <summary>\ud83d\ude80 Reply \"<strong>fix it for me</strong>\" or copy this <strong>AI Prompt</strong> for your agent:</summary>",
785− "thread_ids": [
786− "PRRT_kwDORLtfbc5whxJC"
787− ]
788− }
789− ]
790−}
.plans/16b-pr89-architecture-validity-audit.md+0−125
@@ -1,125 +0,0 @@
1−# PR #89 Post-Rewrite Validity Audit
2−
3−Architecture baseline used for this audit:
4−- Provider runtime activity is projected into orchestration domain events.
5−- Web client consumes `orchestration.domainEvent`; no separate `providers.event` channel is expected.
6−
7−## Summary
8−
9−- Canonical items reviewed: 58
10−- Valid: 34
11−- Partially valid: 19
12−- Invalid (stale/no longer applicable): 5
13−
14−## Invalid Items To Close
15−
16−- C021 [Medium] Shared mutable default metadata object causes stale eventId (apps/server/src/orchestration/decider.ts:27)
17− - Reason: Stale-eventId claim no longer applies; eventId is regenerated per event.
18− - Threads: PRRT_kwDORLtfbc5wkPaA
19−- C025 [Medium] Duplicated checkpoint ref computation across two files (apps/server/src/wsServer.ts:128)
20− - Reason: No longer duplicated; checkpoint ref helper now centralized.
21− - Threads: PRRT_kwDORLtfbc5wvwag
22−- C031 [Medium] Revert uses wrong turn count from positional inference (apps/web/src/session-logic.ts:127)
23− - Reason: Revert now uses explicit checkpointTurnCount first; positional fallback is non-primary.
24− - Threads: PRRT_kwDORLtfbc5v9SCp
25−- C036 [Low] Duplicate `checkpointRefForThreadTurn` function in two production files (apps/server/src/checkpointing/Layers/CheckpointStore.ts:284)
26− - Reason: No longer duplicated; single production source via Refs.ts.
27− - Threads: PRRT_kwDORLtfbc5wiqFX
28−- C055 [Low] Duplicate `checkpointRefForThreadTurn` function across files (apps/server/src/wsServer.ts:128)
29− - Reason: No longer duplicated; helper is centralized.
30− - Threads: PRRT_kwDORLtfbc5wkPaG
31−
32−## Partially Valid Items (de-scope or lower priority)
33−
34−- C006 [Medium] Build script runs TypeScript file with bare node (apps/server/package.json:14)
35− - Note: Node 24 makes this work, but script still relies on runtime-specific TS execution.
36−- C007 [Medium] Build script uses `node` to run `.ts` file directly (apps/server/package.json:14)
37− - Note: Same as C006 (duplicate concern).
38−- C008 [Medium] Inconsistent input normalization across CheckpointStore methods (apps/server/src/checkpointing/Layers/CheckpointStore.ts:94)
39− - Note: Normalization inconsistency remains, but upstream callsites now mostly canonicalize inputs.
40−- C014 [Medium] Engine error handler catches all errors including non-invariant ones (apps/server/src/orchestration/Layers/OrchestrationEngine.ts:144)
41− - Note: Broad catch may be intentional for liveness; correctness concern is contextual.
42−- C015 [Medium] The gap-filling fallback logic can retain messages from turns that are about to be deleted, causing foreign key violations. Consider removing the fallback logic entirely, or filtering `fallbackUserMessages` and `fallbackAssistantMessages` to only include messages whose `turnId` is in `retainedTurnIds`. <details> <summary>🚀 Reply "<strong>fix it for me</strong>" or copy this <strong>AI Prompt</strong> for your agent:</summary> (apps/server/src/orchestration/Layers/ProjectionPipeline.ts:99)
43− - Note: Message fallback retention issue is real, but prior FK-violation claim is overstated.
44−- C017 [Medium] `REQUIRED_SNAPSHOT_PROJECTORS` includes `pending-approvals` and `thread-turns`, but `getSnapshot` doesn't query their data. If these projectors lag behind, the returned `snapshotSequence` will be lower than what the included data actually reflects, causing clients to replay already-applied events. Consider filtering `REQUIRED_SNAPSHOT_PROJECTORS` to only include projectors whose data is actually fetched in the snapshot. <details> <summary>🚀 Reply "<strong>fix it for me</strong>" or copy this <strong>AI Prompt</strong> for your agent:</summary> (apps/server/src/orchestration/Layers/ProjectionSnapshotQuery.ts:71)
45− - Note: Snapshot sequence can under-report due to extra projectors, but replay impact is lower now.
46−- C019 [Medium] ProviderRuntimeIngestion processes events for wrong thread on race (apps/server/src/orchestration/Layers/ProviderRuntimeIngestion.ts:178)
47− - Note: SessionId-only routing can misassociate events under races/rebinds.
48−- C020 [Medium] On `message.completed`, the message ID is added to the set and `thread.message.assistant.complete` is dispatched. On `turn.completed`, the same set is iterated and `thread.message.assistant.complete` is dispatched again for each ID—including already-completed ones. Consider removing message IDs from the set after dispatching on `message.completed`, or filtering out already-completed IDs before the `turn.completed` loop. (apps/server/src/orchestration/Layers/ProviderRuntimeIngestion.ts:266)
49− - Note: Duplicate complete dispatch exists; downstream impact often idempotent.
50−- C024 [Medium] In `executeUnprepared`, preparing outside an effect and not closing the statement can cause uncaught errors and leaks. Suggest wrapping with `Effect.acquireUseRelease`: prepare in acquire (error-safe) and `finalize` in release. (apps/server/src/persistence/NodeSqliteClient.ts:145)
51− - Note: prepare() still outside managed effect boundary; failure handling risk remains.
52−- C028 [Medium] Branch sync dispatches both server and stale local update (apps/web/src/components/BranchToolbar.tsx:102)
53− - Note: Optimistic local+server dual update is intentional but can temporarily diverge.
54−- C033 [Low] Three error classes defined but never instantiated anywhere (apps/server/src/checkpointing/Errors.ts:51)
55− - Note: Original claim overstated; some errors used, others appear unused.
56−- C037 [Low] `Effect.callback` should return a cleanup function to close the server(s) on fiber interruption. Without it, the `Net.Server` handles keep the process alive and leak the port if the effect is cancelled. <details> <summary>🚀 Reply "<strong>fix it for me</strong>" or copy this <strong>AI Prompt</strong> for your agent:</summary> (apps/server/src/config.ts:41)
57− - Note: Callback cleanup missing, but practical exposure is low in one-shot startup path.
58−- C039 [Low] The `+` key can be parsed (via trailing `+` handling) but cannot be encoded because `shortcut.key.includes("+")` returns true for the literal `+` key. Consider checking `shortcut.key === "+"` separately and encoding it as `"space"` style (e.g., a special token), or adjusting the condition to allow the single `+` character. <details> <summary>🚀 Reply "<strong>fix it for me</strong>" or copy this <strong>AI Prompt</strong> for your agent:</summary> (apps/server/src/keybindings.ts:352)
59− - Note: Parser/encoder mismatch remains, but encoder path currently low-use.
60−- C042 [Low] Duplicated `resolveThreadWorkspaceCwd` across three files (apps/server/src/orchestration/Layers/CheckpointReactor.ts:62)
61− - Note: Duplication exists but one instance is variant logic, so impact is moderate.
62−- C044 [Low] Checkpoint reactor swallows diff errors silently for `turn.completed` (apps/server/src/orchestration/Layers/CheckpointReactor.ts:274)
63− - Note: Errors are swallowed to empty diff with warning; not fully silent but still lossy.
64−- C048 [Low] `statement.run()` returns a `RunResult` object, not an array. Casting it to `ReadonlyArray<any>` will cause runtime errors when consumers call array methods. Consider wrapping the result (e.g., `[result]`) or returning a properly typed object. (apps/server/src/persistence/NodeSqliteClient.ts:99)
65− - Note: Unsafe run() result cast remains; runtime risk depends on raw-result consumers.
66−- C051 [Low] Using `??` for `providerThreadId` and `adapterKey` makes it impossible to clear these fields by passing `null`, since `null ?? existing` evaluates to `existing`. Consider using explicit `undefined` checks (like `resumeCursor` does) if clearing should be supported. <details> <summary>🚀 Reply "<strong>fix it for me</strong>" or copy this <strong>AI Prompt</strong> for your agent:</summary> (apps/server/src/provider/Layers/ProviderSessionDirectory.ts:119)
67− - Note: Null-clearing issue is real for providerThreadId; adapterKey part overstated.
68−- C056 [Low] When `onOpenChange` is provided without `open`, the internal `_open` state never updates because `setOpenProp` takes precedence. Consider calling `_setOpen` when `openProp === undefined`, regardless of whether `setOpenProp` exists. (apps/web/src/components/ui/sidebar.tsx:114)
69− - Note: Bug pattern exists, but current callsites mostly avoid triggering it.
70−- C059 [Low] Suggestion: don’t spread `params` into `body`; it can override `_tag` and mishandle non-object values. Keep `_tag` separate and nest `params` under a single key (e.g., `data`), or validate `params` is a plain object. (apps/web/src/wsTransport.ts:59)
71− - Note: Transport _tag override risk exists but current callsites are constrained.
72−
73−## Valid Items (actionable unless marked completed)
74−
75−- C001 [High] Non-atomic event appending can corrupt state on retry. If an error occurs mid-loop (lines 96-102) after some events are persisted but before the receipt is written, the command appears to fail. A retry generates new UUIDs via `crypto.randomUUID()` in the decider, appending duplicate events. Consider wrapping the loop in a transaction or using deterministic event IDs derived from `commandId`. <details> <summary>🚀 Reply "<strong>fix it for me</strong>" or copy this <strong>AI Prompt</strong> for your agent:</summary> (apps/server/src/orchestration/Layers/OrchestrationEngine.ts:96)
76−- C002 [High] A dispatch error in `processEvent` will terminate the `Effect.forever` loop, permanently halting event ingestion. Consider adding error recovery (e.g., `Effect.catchAll` with logging) around `processEvent` so failures don't kill the fiber. (apps/server/src/orchestration/Layers/ProviderRuntimeIngestion.ts:333)
77− - Status: Completed in Phase 1.
78−- C003 [High] Consider attaching a no-op error listener before `socket.write` (e.g., `socket.on('error', () => {})`) to prevent an unhandled `EPIPE`/`ECONNRESET` from crashing the process if the client disconnects mid-handshake. (apps/server/src/wsServer.ts:75)
79−- C009 [Medium] Git's braced rename syntax (e.g., `src/{old => new}/file.ts`) isn't handled correctly. The current slice after ` => ` produces invalid paths like `new}/file.ts`. Consider expanding the braces to construct the full destination path. <details> <summary>🚀 Reply "<strong>fix it for me</strong>" or copy this <strong>AI Prompt</strong> for your agent:</summary> (apps/server/src/git/Layers/GitCore.ts:41)
80−- C010 [Medium] `loadCustomKeybindingsConfig` fails when the config file doesn't exist, which is expected for new users. Consider catching `ENOENT` and returning an empty array instead. <details> <summary>🚀 Reply "<strong>fix it for me</strong>" or copy this <strong>AI Prompt</strong> for your agent:</summary> (apps/server/src/keybindings.ts:418)
81−- C011 [Medium] Template literal `${cause}` throws if `cause` is a `Symbol`. Consider using `String(cause)` instead. (apps/server/src/orchestration/Errors.ts:117)
82−- C012 [Medium] Forked revert dispatch risks read model inconsistency (apps/server/src/orchestration/Layers/CheckpointReactor.ts:542)
83− - Status: Completed in Phase 1.
84−- C013 [Medium] If `projectionPipeline.projectEvent` fails after `eventStore.append` succeeds, the event is persisted but `readModel` isn't updated, causing desync. Consider updating the in-memory `readModel` immediately after append (before the external projection), so local state stays consistent regardless of downstream failures. (apps/server/src/orchestration/Layers/OrchestrationEngine.ts:99)
85−- C016 [Medium] The in-memory `pendingTurnStartByThreadId` map isn't restored during bootstrap. If the service restarts after processing `thread.turn-start-requested` but before `thread.session-set`, the `userMessageId` and `startedAt` will be lost since bootstrap resumes *after* the committed sequence. Consider persisting this pending state or processing these two events atomically. <details> <summary>🚀 Reply "<strong>fix it for me</strong>" or copy this <strong>AI Prompt</strong> for your agent:</summary> (apps/server/src/orchestration/Layers/ProjectionPipeline.ts:490)
86−- C018 [Medium] Unbounded memory growth in turn start deduplication set (apps/server/src/orchestration/Layers/ProviderCommandReactor.ts:84)
87−- C022 [Medium] Fish shell outputs `$PATH` as space-separated, not colon-separated. Consider checking if the shell is fish and using `string join : $PATH` instead, or validating the result contains colons before assigning. (apps/server/src/os-jank.ts:10)
88−- C023 [Medium] Using `-il` flags causes the shell to source profile scripts that may print banners or other text, polluting the captured `PATH`. Consider using `-lc` (login only, non-interactive) to reduce unwanted output. (apps/server/src/os-jank.ts:10)
89−- C026 [Medium] Consider adding `.catch(() => {})` after `Effect.runPromise(handleMessage(ws, raw))` to prevent unhandled rejections from crashing the server if `encodeResponse` or setup logic fails. (apps/server/src/wsServer.ts:545)
90− - Status: Completed in Phase 1.
91−- C027 [Medium] WS message handler can cause unhandled promise rejection (apps/server/src/wsServer.ts:545)
92− - Status: Completed in Phase 1.
93−- C029 [Medium] `parseFileUrlHref` already decodes the path (line 46), but `safeDecode` is called again here, corrupting filenames containing `%` sequences. Consider skipping the decode when `fileUrlTarget` is non-null. (apps/web/src/markdown-links.ts:105)
94−- C030 [Medium] `EXTERNAL_SCHEME_PATTERN` matches `script.ts:10` as a scheme because `.ts:` looks like `scheme:`. Consider requiring `://` after the colon, or checking that what follows the colon is not just digits. <details> <summary>🚀 Reply "<strong>fix it for me</strong>" or copy this <strong>AI Prompt</strong> for your agent:</summary> (apps/web/src/markdown-links.ts:111)
95−- C032 [Low] Dummy workflow marker accidentally committed to docs (AGENTS.md:45)
96−- C034 [Low] Redundant `CheckpointInvariantError` in `CheckpointServiceError` union type (apps/server/src/checkpointing/Errors.ts:79)
97−- C035 [Low] Redundant error type in CheckpointServiceError union definition (apps/server/src/checkpointing/Errors.ts:79)
98−- C038 [Low] Multi-byte UTF-8 characters split across chunks will be corrupted when decoding each chunk separately. Consider accumulating all chunks first, then decoding once, or use `TextDecoder` with `stream: true`. <details> <summary>🚀 Reply "<strong>fix it for me</strong>" or copy this <strong>AI Prompt</strong> for your agent:</summary> (apps/server/src/git/Layers/CodexTextGeneration.ts:136)
99−- C040 [Low] `upsertKeybindingRule` has a race condition: concurrent calls read the same file state, then the last write overwrites earlier changes. Consider wrapping the read-modify-write sequence with `Effect.Semaphore` to serialize access. <details> <summary>🚀 Reply "<strong>fix it for me</strong>" or copy this <strong>AI Prompt</strong> for your agent:</summary> (apps/server/src/keybindings.ts:488)
100−- C041 [Low] Template literal interpolation throws `TypeError` if `cause` is a `Symbol`. Consider using `String(cause)` for safe coercion. (apps/server/src/orchestration/Errors.ts:126)
101−- C043 [Low] Duplicated workspace CWD resolution logic across reactor modules (apps/server/src/orchestration/Layers/CheckpointReactor.ts:62)
102−- C045 [Low] `truncateDetail` slices to `limit - 1` then appends `"..."` (3 chars), producing strings of length `limit + 2`. Consider slicing to `limit - 3` instead. <details> <summary>🚀 Reply "<strong>fix it for me</strong>" or copy this <strong>AI Prompt</strong> for your agent:</summary> (apps/server/src/orchestration/Layers/ProviderRuntimeIngestion.ts:29)
103−- C046 [Low] `latestMessageIdByTurnKey` is written to but never read, and `clearAssistantMessageIdsForTurn` doesn't clear its entries—only `clearTurnStateForSession` does. Consider removing this map entirely if unused, or clearing it alongside `turnMessageIdsByTurnKey` in `clearAssistantMessageIdsForTurn`. <details> <summary>🚀 Reply "<strong>fix it for me</strong>" or copy this <strong>AI Prompt</strong> for your agent:</summary> (apps/server/src/orchestration/Layers/ProviderRuntimeIngestion.ts:133)
104−- C047 [Low] `SqlSchema.findOneOption` can produce both SQL errors and decode errors, but `mapError` wraps all as `PersistenceSqlError`. Consider distinguishing `ParseError` from SQL errors and mapping decode failures to `PersistenceDecodeError` instead. <details> <summary>🚀 Reply "<strong>fix it for me</strong>" or copy this <strong>AI Prompt</strong> for your agent:</summary> (apps/server/src/persistence/Layers/OrchestrationCommandReceipts.ts:75)
105−- C049 [Low] `JSON.stringify(cause)` returns `undefined` for `undefined`, functions, or symbols, violating the `string` return type. Consider coercing the result to a string (e.g., `String(JSON.stringify(cause))`) or adding a fallback. (apps/server/src/provider/Layers/ProviderService.ts:59)
106−- C050 [Low] The read-modify-write pattern (`getBySessionId` → merge → `upsert`) is susceptible to lost updates under concurrent writes. Consider wrapping in a transaction or adding optimistic concurrency control (e.g., version field) if concurrent session updates are expected. <details> <summary>🚀 Reply "<strong>fix it for me</strong>" or copy this <strong>AI Prompt</strong> for your agent:</summary> (apps/server/src/provider/Layers/ProviderSessionDirectory.ts:94)
107−- C052 [Low] Race condition: `processHandle` may be `null` when `data` callback fires, since it's assigned after `Bun.spawn` returns. Consider initializing `BunPtyProcess` first, then passing it to the callback to avoid losing initial output. <details> <summary>🚀 Reply "<strong>fix it for me</strong>" or copy this <strong>AI Prompt</strong> for your agent:</summary> (apps/server/src/terminal/Layers/BunPTY.ts:97)
108−- C053 [Low] Consider using `socket.end(response)` instead of `socket.write(response)` + `socket.destroy()` to ensure the HTTP error response is fully flushed before closing the connection. (apps/server/src/wsServer.ts:83)
109−- C054 [Low] When array chunks contain a multi-byte UTF-8 character split across boundaries, decoding each chunk separately produces replacement characters. Consider using `Buffer.concat()` on all chunks before calling `.toString("utf8")`. <details> <summary>🚀 Reply "<strong>fix it for me</strong>" or copy this <strong>AI Prompt</strong> for your agent:</summary> (apps/server/src/wsServer.ts:104)
110−- C057 [Low] The `resizable` object is recreated on every render, causing `SidebarRail`'s `useEffect` to repeatedly read localStorage and update the DOM. Consider memoizing the object with `useMemo`. <details> <summary>🚀 Reply "<strong>fix it for me</strong>" or copy this <strong>AI Prompt</strong> for your agent:</summary> (apps/web/src/routes/_chat.$threadId.tsx:105)
111−- C058 [Low] When `localStorage.getItem()` returns `null`, `Number(null)` evaluates to `0`, which passes `Number.isFinite(0)`. This causes the sidebar to clamp to `minWidth` on first load, overriding the `DIFF_INLINE_DEFAULT_WIDTH` CSS clamp. Consider checking for `null` or empty string before parsing, e.g. guard with `storedWidth === null || storedWidth === ''`. <details> <summary>🚀 Reply "<strong>fix it for me</strong>" or copy this <strong>AI Prompt</strong> for your agent:</summary> (apps/web/src/routes/_chat.$threadId.tsx:122)
112−- C060 [Low] `defaultModel` should be `Schema.optional(Schema.NullOr(Schema.String))` to allow clearing the value. Currently there's no way to reset it to `null` since omitting means "no change" in patch semantics. <details> <summary>🚀 Reply "<strong>fix it for me</strong>" or copy this <strong>AI Prompt</strong> for your agent:</summary> (packages/contracts/src/orchestration.ts:253)
113−
114−## By Area
115−
116−- Build/runtime portability: valid=0, partially-valid=2, invalid=0
117−- Checkpointing correctness: valid=2, partially-valid=3, invalid=3
118−- Edge-case parsing/platform behavior: valid=8, partially-valid=1, invalid=0
119−- Event ordering and state consistency: valid=3, partially-valid=2, invalid=1
120−- Memory/resource growth: valid=1, partially-valid=0, invalid=0
121−- Other: valid=10, partially-valid=6, invalid=1
122−- Runtime resilience and failure handling: valid=6, partially-valid=4, invalid=0
123−- WebSocket robustness: valid=4, partially-valid=1, invalid=0
124−
125−Machine-readable mapping: `.plans/16b-pr89-architecture-validity-audit.json`.
.plans/16c-pr89-remediation-checklist.md+542−0
@@ -0,0 +1,542 @@
1+# PR #89 Remediation Checklist (Consolidated)
2+
3+_Last updated: 2026-02-26_
4+
5+This is the working checklist for remediation execution.
6+
7+Status values:
8+- `TODO`: Not started
9+- `IN_PROGRESS`: Currently being worked
10+- `BLOCKED`: Waiting on decision/dependency
11+- `DONE`: Implemented and verified
12+- `CLOSED_INVALID`: Stale/invalid review finding
13+
14+Counts: active `53` (`valid=34`, `partially-valid=19`), closed-invalid `5`
15+
16+## Active Checklist
17+
18+### Phase 1
19+
20+- [x] `C002` A dispatch error in `processEvent` will terminate the `Effect.forever` loop, permanently halting event ingestion. Consider adding error recovery (e.g., `Effect.catchAll` with logging) around `processEvent` so failures don't kill the fiber.
21+ - Status: `DONE`
22+ - Verdict: `valid`
23+ - Severity: `High`
24+ - Area: `Runtime resilience and failure handling`
25+ - File: `apps/server/src/orchestration/Layers/ProviderRuntimeIngestion.ts:333`
26+ - Threads: PRRT_kwDORLtfbc5wj4cH, PRRT_kwDORLtfbc5wnWwF, PRRT_kwDORLtfbc5wyTaP, PRRT_kwDORLtfbc5wzliw, PRRT_kwDORLtfbc5w0_g3, PRRT_kwDORLtfbc5w1HGT (+5 duplicate thread(s))
27+ - Audit note: Ingestion worker loop can terminate on unhandled processEvent failure.
28+
29+- [x] `C003` Consider attaching a no-op error listener before `socket.write` (e.g., `socket.on('error', () => {})`) to prevent an unhandled `EPIPE`/`ECONNRESET` from crashing the process if the client disconnects mid-handshake.
30+ - Status: `DONE`
31+ - Verdict: `valid`
32+ - Severity: `High`
33+ - Area: `WebSocket robustness`
34+ - File: `apps/server/src/wsServer.ts:75`
35+ - Threads: PRRT_kwDORLtfbc5v-cf4
36+ - Audit note: Upgrade reject writes then destroys socket without defensive error listener.
37+
38+- [x] `C012` Forked revert dispatch risks read model inconsistency
39+ - Status: `DONE`
40+ - Verdict: `valid`
41+ - Severity: `Medium`
42+ - Area: `Runtime resilience and failure handling`
43+ - File: `apps/server/src/orchestration/Layers/CheckpointReactor.ts:542`
44+ - Threads: PRRT_kwDORLtfbc5whszW, PRRT_kwDORLtfbc5wyTaS, PRRT_kwDORLtfbc5wzli0, PRRT_kwDORLtfbc5w0_g4, PRRT_kwDORLtfbc5w1HGX (+4 duplicate thread(s))
45+ - Audit note: Revert completion dispatch remains forked; state consistency window remains.
46+
47+- [ ] `C019` ProviderRuntimeIngestion processes events for wrong thread on race
48+ - Status: `TODO`
49+ - Verdict: `partially-valid`
50+ - Severity: `Medium`
51+ - Area: `Runtime resilience and failure handling`
52+ - File: `apps/server/src/orchestration/Layers/ProviderRuntimeIngestion.ts:178`
53+ - Threads: PRRT_kwDORLtfbc5wkPaL
54+ - Audit note: SessionId-only routing can misassociate events under races/rebinds.
55+
56+- [ ] `C020` On `message.completed`, the message ID is added to the set and `thread.message.assistant.complete` is dispatched. On `turn.completed`, the same set is iterated and `thread.message.assistant.complete` is dispatched again for each ID—including already-completed ones. Consider removing message IDs from the set after dispatching on `message.completed`, or filtering out already-completed IDs before the `turn.completed` loop.
57+ - Status: `TODO`
58+ - Verdict: `partially-valid`
59+ - Severity: `Medium`
60+ - Area: `Runtime resilience and failure handling`
61+ - File: `apps/server/src/orchestration/Layers/ProviderRuntimeIngestion.ts:266`
62+ - Threads: PRRT_kwDORLtfbc5w1GPr
63+ - Audit note: Duplicate complete dispatch exists; downstream impact often idempotent.
64+
65+- [x] `C026` Consider adding `.catch(() => {})` after `Effect.runPromise(handleMessage(ws, raw))` to prevent unhandled rejections from crashing the server if `encodeResponse` or setup logic fails.
66+ - Status: `DONE`
67+ - Verdict: `valid`
68+ - Severity: `Medium`
69+ - Area: `WebSocket robustness`
70+ - File: `apps/server/src/wsServer.ts:545`
71+ - Threads: PRRT_kwDORLtfbc5wj4cE
72+ - Audit note: runPromise result still not caught; rejection can surface unhandled.
73+
74+- [x] `C027` WS message handler can cause unhandled promise rejection
75+ - Status: `DONE`
76+ - Verdict: `valid`
77+ - Severity: `Medium`
78+ - Area: `Runtime resilience and failure handling`
79+ - File: `apps/server/src/wsServer.ts:545`
80+ - Threads: PRRT_kwDORLtfbc5wyTaW, PRRT_kwDORLtfbc5wzli3 (+1 duplicate thread(s))
81+ - Audit note: Same unhandled rejection path remains in WS message handler.
82+
83+- [ ] `C042` Duplicated `resolveThreadWorkspaceCwd` across three files
84+ - Status: `TODO`
85+ - Verdict: `partially-valid`
86+ - Severity: `Low`
87+ - Area: `Runtime resilience and failure handling`
88+ - File: `apps/server/src/orchestration/Layers/CheckpointReactor.ts:62`
89+ - Threads: PRRT_kwDORLtfbc5wzli2
90+ - Audit note: Duplication exists but one instance is variant logic, so impact is moderate.
91+
92+- [x] `C043` Duplicated workspace CWD resolution logic across reactor modules
93+ - Status: `DONE`
94+ - Verdict: `valid`
95+ - Severity: `Low`
96+ - Area: `Runtime resilience and failure handling`
97+ - File: `apps/server/src/orchestration/Layers/CheckpointReactor.ts:62`
98+ - Threads: PRRT_kwDORLtfbc5wnWwM, PRRT_kwDORLtfbc5w1C3-, PRRT_kwDORLtfbc5w1HGZ (+2 duplicate thread(s))
99+ - Audit note: Workspace CWD resolution duplication still present across modules.
100+
101+- [ ] `C044` Checkpoint reactor swallows diff errors silently for `turn.completed`
102+ - Status: `TODO`
103+ - Verdict: `partially-valid`
104+ - Severity: `Low`
105+ - Area: `Runtime resilience and failure handling`
106+ - File: `apps/server/src/orchestration/Layers/CheckpointReactor.ts:274`
107+ - Threads: PRRT_kwDORLtfbc5wkPaO
108+ - Audit note: Errors are swallowed to empty diff with warning; not fully silent but still lossy.
109+
110+- [x] `C045` `truncateDetail` slices to `limit - 1` then appends `"..."` (3 chars), producing strings of length `limit + 2`. Consider slicing to `limit - 3` instead. <details> <summary>🚀 Reply "<strong>fix it for me</strong>" or copy this <strong>AI Prompt</strong> for your agent:</summary>
111+ - Status: `DONE`
112+ - Verdict: `valid`
113+ - Severity: `Low`
114+ - Area: `Runtime resilience and failure handling`
115+ - File: `apps/server/src/orchestration/Layers/ProviderRuntimeIngestion.ts:29`
116+ - Threads: PRRT_kwDORLtfbc5wzp4R
117+ - Audit note: truncateDetail still overshoots limit.
118+
119+- [x] `C046` `latestMessageIdByTurnKey` is written to but never read, and `clearAssistantMessageIdsForTurn` doesn't clear its entries—only `clearTurnStateForSession` does. Consider removing this map entirely if unused, or clearing it alongside `turnMessageIdsByTurnKey` in `clearAssistantMessageIdsForTurn`. <details> <summary>🚀 Reply "<strong>fix it for me</strong>" or copy this <strong>AI Prompt</strong> for your agent:</summary>
120+ - Status: `DONE`
121+ - Verdict: `valid`
122+ - Severity: `Low`
123+ - Area: `Runtime resilience and failure handling`
124+ - File: `apps/server/src/orchestration/Layers/ProviderRuntimeIngestion.ts:133`
125+ - Threads: PRRT_kwDORLtfbc5wxvIQ
126+ - Audit note: latestMessageIdByTurnKey still unused/unpruned in per-turn clear path.
127+
128+- [x] `C053` Consider using `socket.end(response)` instead of `socket.write(response)` + `socket.destroy()` to ensure the HTTP error response is fully flushed before closing the connection.
129+ - Status: `DONE`
130+ - Verdict: `valid`
131+ - Severity: `Low`
132+ - Area: `WebSocket robustness`
133+ - File: `apps/server/src/wsServer.ts:83`
134+ - Threads: PRRT_kwDORLtfbc5v-WPD
135+ - Audit note: Still uses write+destroy rather than end() for rejection response.
136+
137+- [ ] `C054` When array chunks contain a multi-byte UTF-8 character split across boundaries, decoding each chunk separately produces replacement characters. Consider using `Buffer.concat()` on all chunks before calling `.toString("utf8")`. <details> <summary>🚀 Reply "<strong>fix it for me</strong>" or copy this <strong>AI Prompt</strong> for your agent:</summary>
138+ - Status: `TODO`
139+ - Verdict: `valid`
140+ - Severity: `Low`
141+ - Area: `WebSocket robustness`
142+ - File: `apps/server/src/wsServer.ts:104`
143+ - Threads: PRRT_kwDORLtfbc5whtrR
144+ - Audit note: Array chunk UTF-8 decode remains vulnerable to split multibyte corruption.
145+
146+- [x] `C059` Suggestion: don’t spread `params` into `body`; it can override `_tag` and mishandle non-object values. Keep `_tag` separate and nest `params` under a single key (e.g., `data`), or validate `params` is a plain object.
147+ - Status: `DONE`
148+ - Verdict: `partially-valid`
149+ - Severity: `Low`
150+ - Area: `WebSocket robustness`
151+ - File: `apps/web/src/wsTransport.ts:59`
152+ - Threads: PRRT_kwDORLtfbc5whtrN
153+ - Audit note: Transport _tag override risk exists but current callsites are constrained.
154+
155+### Phase 2
156+
157+- [ ] `C001` Non-atomic event appending can corrupt state on retry. If an error occurs mid-loop (lines 96-102) after some events are persisted but before the receipt is written, the command appears to fail. A retry generates new UUIDs via `crypto.randomUUID()` in the decider, appending duplicate events. Consider wrapping the loop in a transaction or using deterministic event IDs derived from `commandId`. <details> <summary>🚀 Reply "<strong>fix it for me</strong>" or copy this <strong>AI Prompt</strong> for your agent:</summary>
158+ - Status: `TODO`
159+ - Verdict: `valid`
160+ - Severity: `High`
161+ - Area: `Event ordering and state consistency`
162+ - File: `apps/server/src/orchestration/Layers/OrchestrationEngine.ts:96`
163+ - Threads: PRRT_kwDORLtfbc5wzp4T
164+ - Audit note: Append/project/receipt are non-atomic; retry can duplicate events.
165+
166+- [ ] `C013` If `projectionPipeline.projectEvent` fails after `eventStore.append` succeeds, the event is persisted but `readModel` isn't updated, causing desync. Consider updating the in-memory `readModel` immediately after append (before the external projection), so local state stays consistent regardless of downstream failures.
167+ - Status: `TODO`
168+ - Verdict: `valid`
169+ - Severity: `Medium`
170+ - Area: `Event ordering and state consistency`
171+ - File: `apps/server/src/orchestration/Layers/OrchestrationEngine.ts:99`
172+ - Threads: PRRT_kwDORLtfbc5whtrM
173+ - Audit note: Persisted event can outpace in-memory projection on mid-flight failure.
174+
175+- [ ] `C014` Engine error handler catches all errors including non-invariant ones
176+ - Status: `TODO`
177+ - Verdict: `partially-valid`
178+ - Severity: `Medium`
179+ - Area: `Event ordering and state consistency`
180+ - File: `apps/server/src/orchestration/Layers/OrchestrationEngine.ts:144`
181+ - Threads: PRRT_kwDORLtfbc5wkPaJ
182+ - Audit note: Broad catch may be intentional for liveness; correctness concern is contextual.
183+
184+- [ ] `C015` The gap-filling fallback logic can retain messages from turns that are about to be deleted, causing foreign key violations. Consider removing the fallback logic entirely, or filtering `fallbackUserMessages` and `fallbackAssistantMessages` to only include messages whose `turnId` is in `retainedTurnIds`. <details> <summary>🚀 Reply "<strong>fix it for me</strong>" or copy this <strong>AI Prompt</strong> for your agent:</summary>
185+ - Status: `TODO`
186+ - Verdict: `partially-valid`
187+ - Severity: `Medium`
188+ - Area: `Event ordering and state consistency`
189+ - File: `apps/server/src/orchestration/Layers/ProjectionPipeline.ts:99`
190+ - Threads: PRRT_kwDORLtfbc5whxJO
191+ - Audit note: Message fallback retention issue is real, but prior FK-violation claim is overstated.
192+
193+- [ ] `C016` The in-memory `pendingTurnStartByThreadId` map isn't restored during bootstrap. If the service restarts after processing `thread.turn-start-requested` but before `thread.session-set`, the `userMessageId` and `startedAt` will be lost since bootstrap resumes *after* the committed sequence. Consider persisting this pending state or processing these two events atomically. <details> <summary>🚀 Reply "<strong>fix it for me</strong>" or copy this <strong>AI Prompt</strong> for your agent:</summary>
194+ - Status: `TODO`
195+ - Verdict: `valid`
196+ - Severity: `Medium`
197+ - Area: `Event ordering and state consistency`
198+ - File: `apps/server/src/orchestration/Layers/ProjectionPipeline.ts:490`
199+ - Threads: PRRT_kwDORLtfbc5wxvH8
200+ - Audit note: Pending turn-start map is in-memory only and not rebuilt on bootstrap.
201+
202+### Phase 3
203+
204+- [ ] `C008` Inconsistent input normalization across CheckpointStore methods
205+ - Status: `TODO`
206+ - Verdict: `partially-valid`
207+ - Severity: `Medium`
208+ - Area: `Checkpointing correctness`
209+ - File: `apps/server/src/checkpointing/Layers/CheckpointStore.ts:94`
210+ - Threads: PRRT_kwDORLtfbc5widJw, PRRT_kwDORLtfbc5wnWv_, PRRT_kwDORLtfbc5w0_g7, PRRT_kwDORLtfbc5w1C36 (+3 duplicate thread(s))
211+ - Audit note: Normalization inconsistency remains, but upstream callsites now mostly canonicalize inputs.
212+
213+- [ ] `C017` `REQUIRED_SNAPSHOT_PROJECTORS` includes `pending-approvals` and `thread-turns`, but `getSnapshot` doesn't query their data. If these projectors lag behind, the returned `snapshotSequence` will be lower than what the included data actually reflects, causing clients to replay already-applied events. Consider filtering `REQUIRED_SNAPSHOT_PROJECTORS` to only include projectors whose data is actually fetched in the snapshot. <details> <summary>🚀 Reply "<strong>fix it for me</strong>" or copy this <strong>AI Prompt</strong> for your agent:</summary>
214+ - Status: `TODO`
215+ - Verdict: `partially-valid`
216+ - Severity: `Medium`
217+ - Area: `Checkpointing correctness`
218+ - File: `apps/server/src/orchestration/Layers/ProjectionSnapshotQuery.ts:71`
219+ - Threads: PRRT_kwDORLtfbc5wiLhQ
220+ - Audit note: Snapshot sequence can under-report due to extra projectors, but replay impact is lower now.
221+
222+- [ ] `C033` Three error classes defined but never instantiated anywhere
223+ - Status: `TODO`
224+ - Verdict: `partially-valid`
225+ - Severity: `Low`
226+ - Area: `Checkpointing correctness`
227+ - File: `apps/server/src/checkpointing/Errors.ts:51`
228+ - Threads: PRRT_kwDORLtfbc5wlYgo
229+ - Audit note: Original claim overstated; some errors used, others appear unused.
230+
231+- [ ] `C034` Redundant `CheckpointInvariantError` in `CheckpointServiceError` union type
232+ - Status: `TODO`
233+ - Verdict: `valid`
234+ - Severity: `Low`
235+ - Area: `Checkpointing correctness`
236+ - File: `apps/server/src/checkpointing/Errors.ts:79`
237+ - Threads: PRRT_kwDORLtfbc5wj5fn
238+ - Audit note: CheckpointInvariantError remains redundantly included in service union.
239+
240+- [ ] `C035` Redundant error type in CheckpointServiceError union definition
241+ - Status: `TODO`
242+ - Verdict: `valid`
243+ - Severity: `Low`
244+ - Area: `Checkpointing correctness`
245+ - File: `apps/server/src/checkpointing/Errors.ts:79`
246+ - Threads: PRRT_kwDORLtfbc5wlYgs, PRRT_kwDORLtfbc5wxsO6, PRRT_kwDORLtfbc5w1C4B (+2 duplicate thread(s))
247+ - Audit note: Same as C034.
248+
249+### Phase 4
250+
251+- [ ] `C018` Unbounded memory growth in turn start deduplication set
252+ - Status: `TODO`
253+ - Verdict: `valid`
254+ - Severity: `Medium`
255+ - Area: `Memory/resource growth`
256+ - File: `apps/server/src/orchestration/Layers/ProviderCommandReactor.ts:84`
257+ - Threads: PRRT_kwDORLtfbc5whszQ, PRRT_kwDORLtfbc5wl2A8, PRRT_kwDORLtfbc5wyTaT, PRRT_kwDORLtfbc5wzliz, PRRT_kwDORLtfbc5w0_g-, PRRT_kwDORLtfbc5w1HGW (+5 duplicate thread(s))
258+ - Audit note: handledTurnStartKeys still grows without pruning.
259+
260+### Phase 5
261+
262+- [ ] `C009` Git's braced rename syntax (e.g., `src/{old => new}/file.ts`) isn't handled correctly. The current slice after ` => ` produces invalid paths like `new}/file.ts`. Consider expanding the braces to construct the full destination path. <details> <summary>🚀 Reply "<strong>fix it for me</strong>" or copy this <strong>AI Prompt</strong> for your agent:</summary>
263+ - Status: `TODO`
264+ - Verdict: `valid`
265+ - Severity: `Medium`
266+ - Area: `Edge-case parsing/platform behavior`
267+ - File: `apps/server/src/git/Layers/GitCore.ts:41`
268+ - Threads: PRRT_kwDORLtfbc5w1CxT
269+ - Audit note: Braced rename parsing still breaks paths like src/{old => new}/file.ts.
270+
271+- [ ] `C010` `loadCustomKeybindingsConfig` fails when the config file doesn't exist, which is expected for new users. Consider catching `ENOENT` and returning an empty array instead. <details> <summary>🚀 Reply "<strong>fix it for me</strong>" or copy this <strong>AI Prompt</strong> for your agent:</summary>
272+ - Status: `TODO`
273+ - Verdict: `valid`
274+ - Severity: `Medium`
275+ - Area: `Edge-case parsing/platform behavior`
276+ - File: `apps/server/src/keybindings.ts:418`
277+ - Threads: PRRT_kwDORLtfbc5wxvIJ
278+ - Audit note: ENOENT for missing keybindings config still not handled as empty/default.
279+
280+- [ ] `C022` Fish shell outputs `$PATH` as space-separated, not colon-separated. Consider checking if the shell is fish and using `string join : $PATH` instead, or validating the result contains colons before assigning.
281+ - Status: `TODO`
282+ - Verdict: `valid`
283+ - Severity: `Medium`
284+ - Area: `Edge-case parsing/platform behavior`
285+ - File: `apps/server/src/os-jank.ts:10`
286+ - Threads: PRRT_kwDORLtfbc5wkRZM
287+ - Audit note: fish PATH formatting risk still exists in os-jank path recovery.
288+
289+- [ ] `C023` Using `-il` flags causes the shell to source profile scripts that may print banners or other text, polluting the captured `PATH`. Consider using `-lc` (login only, non-interactive) to reduce unwanted output.
290+ - Status: `TODO`
291+ - Verdict: `valid`
292+ - Severity: `Medium`
293+ - Area: `Edge-case parsing/platform behavior`
294+ - File: `apps/server/src/os-jank.ts:10`
295+ - Threads: PRRT_kwDORLtfbc5wj4cM
296+ - Audit note: -ilc shell invocation can pollute captured PATH output.
297+
298+- [ ] `C029` `parseFileUrlHref` already decodes the path (line 46), but `safeDecode` is called again here, corrupting filenames containing `%` sequences. Consider skipping the decode when `fileUrlTarget` is non-null.
299+ - Status: `TODO`
300+ - Verdict: `valid`
301+ - Severity: `Medium`
302+ - Area: `Edge-case parsing/platform behavior`
303+ - File: `apps/web/src/markdown-links.ts:105`
304+ - Threads: PRRT_kwDORLtfbc5wnVsU
305+ - Audit note: file URL decoding still double-decodes in one path.
306+
307+- [ ] `C030` `EXTERNAL_SCHEME_PATTERN` matches `script.ts:10` as a scheme because `.ts:` looks like `scheme:`. Consider requiring `://` after the colon, or checking that what follows the colon is not just digits. <details> <summary>🚀 Reply "<strong>fix it for me</strong>" or copy this <strong>AI Prompt</strong> for your agent:</summary>
308+ - Status: `TODO`
309+ - Verdict: `valid`
310+ - Severity: `Medium`
311+ - Area: `Edge-case parsing/platform behavior`
312+ - File: `apps/web/src/markdown-links.ts:111`
313+ - Threads: PRRT_kwDORLtfbc5wnVsK
314+ - Audit note: Scheme regex still misclassifies script.ts:10 as external scheme.
315+
316+- [ ] `C038` Multi-byte UTF-8 characters split across chunks will be corrupted when decoding each chunk separately. Consider accumulating all chunks first, then decoding once, or use `TextDecoder` with `stream: true`. <details> <summary>🚀 Reply "<strong>fix it for me</strong>" or copy this <strong>AI Prompt</strong> for your agent:</summary>
317+ - Status: `TODO`
318+ - Verdict: `valid`
319+ - Severity: `Low`
320+ - Area: `Edge-case parsing/platform behavior`
321+ - File: `apps/server/src/git/Layers/CodexTextGeneration.ts:136`
322+ - Threads: PRRT_kwDORLtfbc5w1GPo
323+ - Audit note: Chunk-by-chunk UTF-8 decode can still corrupt split multibyte characters.
324+
325+- [ ] `C039` The `+` key can be parsed (via trailing `+` handling) but cannot be encoded because `shortcut.key.includes("+")` returns true for the literal `+` key. Consider checking `shortcut.key === "+"` separately and encoding it as `"space"` style (e.g., a special token), or adjusting the condition to allow the single `+` character. <details> <summary>🚀 Reply "<strong>fix it for me</strong>" or copy this <strong>AI Prompt</strong> for your agent:</summary>
326+ - Status: `TODO`
327+ - Verdict: `partially-valid`
328+ - Severity: `Low`
329+ - Area: `Edge-case parsing/platform behavior`
330+ - File: `apps/server/src/keybindings.ts:352`
331+ - Threads: PRRT_kwDORLtfbc5wxvIB
332+ - Audit note: Parser/encoder mismatch remains, but encoder path currently low-use.
333+
334+- [ ] `C040` `upsertKeybindingRule` has a race condition: concurrent calls read the same file state, then the last write overwrites earlier changes. Consider wrapping the read-modify-write sequence with `Effect.Semaphore` to serialize access. <details> <summary>🚀 Reply "<strong>fix it for me</strong>" or copy this <strong>AI Prompt</strong> for your agent:</summary>
335+ - Status: `TODO`
336+ - Verdict: `valid`
337+ - Severity: `Low`
338+ - Area: `Edge-case parsing/platform behavior`
339+ - File: `apps/server/src/keybindings.ts:488`
340+ - Threads: PRRT_kwDORLtfbc5wxvIA
341+ - Audit note: upsertKeybindingRule read-modify-write remains race-prone.
342+
343+### Phase 6
344+
345+- [ ] `C006` Build script runs TypeScript file with bare node
346+ - Status: `TODO`
347+ - Verdict: `partially-valid`
348+ - Severity: `Medium`
349+ - Area: `Build/runtime portability`
350+ - File: `apps/server/package.json:14`
351+ - Threads: PRRT_kwDORLtfbc5wxsO-
352+ - Audit note: Node 24 makes this work, but script still relies on runtime-specific TS execution.
353+
354+- [ ] `C007` Build script uses `node` to run `.ts` file directly
355+ - Status: `TODO`
356+ - Verdict: `partially-valid`
357+ - Severity: `Medium`
358+ - Area: `Build/runtime portability`
359+ - File: `apps/server/package.json:14`
360+ - Threads: PRRT_kwDORLtfbc5wiLNS, PRRT_kwDORLtfbc5wj5fl (+1 duplicate thread(s))
361+ - Audit note: Same as C006 (duplicate concern).
362+
363+- [ ] `C011` Template literal `${cause}` throws if `cause` is a `Symbol`. Consider using `String(cause)` instead.
364+ - Status: `TODO`
365+ - Verdict: `valid`
366+ - Severity: `Medium`
367+ - Area: `Other`
368+ - File: `apps/server/src/orchestration/Errors.ts:117`
369+ - Threads: PRRT_kwDORLtfbc5wBFv4
370+ - Audit note: Template-literal interpolation of Symbol still throws.
371+
372+- [ ] `C024` In `executeUnprepared`, preparing outside an effect and not closing the statement can cause uncaught errors and leaks. Suggest wrapping with `Effect.acquireUseRelease`: prepare in acquire (error-safe) and `finalize` in release.
373+ - Status: `TODO`
374+ - Verdict: `partially-valid`
375+ - Severity: `Medium`
376+ - Area: `Other`
377+ - File: `apps/server/src/persistence/NodeSqliteClient.ts:145`
378+ - Threads: PRRT_kwDORLtfbc5whxX9
379+ - Audit note: prepare() still outside managed effect boundary; failure handling risk remains.
380+
381+- [ ] `C028` Branch sync dispatches both server and stale local update
382+ - Status: `TODO`
383+ - Verdict: `partially-valid`
384+ - Severity: `Medium`
385+ - Area: `Other`
386+ - File: `apps/web/src/components/BranchToolbar.tsx:102`
387+ - Threads: PRRT_kwDORLtfbc5v-XCu
388+ - Audit note: Optimistic local+server dual update is intentional but can temporarily diverge.
389+
390+- [ ] `C032` Dummy workflow marker accidentally committed to docs
391+ - Status: `TODO`
392+ - Verdict: `valid`
393+ - Severity: `Low`
394+ - Area: `Other`
395+ - File: `AGENTS.md:45`
396+ - Threads: PRRT_kwDORLtfbc5wlYgj, PRRT_kwDORLtfbc5w1C4H (+1 duplicate thread(s))
397+ - Audit note: Dummy workflow marker comment is still present in docs.
398+
399+- [ ] `C037` `Effect.callback` should return a cleanup function to close the server(s) on fiber interruption. Without it, the `Net.Server` handles keep the process alive and leak the port if the effect is cancelled. <details> <summary>🚀 Reply "<strong>fix it for me</strong>" or copy this <strong>AI Prompt</strong> for your agent:</summary>
400+ - Status: `TODO`
401+ - Verdict: `partially-valid`
402+ - Severity: `Low`
403+ - Area: `Other`
404+ - File: `apps/server/src/config.ts:41`
405+ - Threads: PRRT_kwDORLtfbc5wj4cO
406+ - Audit note: Callback cleanup missing, but practical exposure is low in one-shot startup path.
407+
408+- [ ] `C041` Template literal interpolation throws `TypeError` if `cause` is a `Symbol`. Consider using `String(cause)` for safe coercion.
409+ - Status: `TODO`
410+ - Verdict: `valid`
411+ - Severity: `Low`
412+ - Area: `Other`
413+ - File: `apps/server/src/orchestration/Errors.ts:126`
414+ - Threads: PRRT_kwDORLtfbc5wBFWs
415+ - Audit note: Same Symbol interpolation hazard as C011 remains.
416+
417+- [ ] `C047` `SqlSchema.findOneOption` can produce both SQL errors and decode errors, but `mapError` wraps all as `PersistenceSqlError`. Consider distinguishing `ParseError` from SQL errors and mapping decode failures to `PersistenceDecodeError` instead. <details> <summary>🚀 Reply "<strong>fix it for me</strong>" or copy this <strong>AI Prompt</strong> for your agent:</summary>
418+ - Status: `TODO`
419+ - Verdict: `valid`
420+ - Severity: `Low`
421+ - Area: `Other`
422+ - File: `apps/server/src/persistence/Layers/OrchestrationCommandReceipts.ts:75`
423+ - Threads: PRRT_kwDORLtfbc5wiaR-
424+ - Audit note: Decode and SQL errors still collapsed into one persistence error kind.
425+
426+- [ ] `C048` `statement.run()` returns a `RunResult` object, not an array. Casting it to `ReadonlyArray<any>` will cause runtime errors when consumers call array methods. Consider wrapping the result (e.g., `[result]`) or returning a properly typed object.
427+ - Status: `TODO`
428+ - Verdict: `partially-valid`
429+ - Severity: `Low`
430+ - Area: `Other`
431+ - File: `apps/server/src/persistence/NodeSqliteClient.ts:99`
432+ - Threads: PRRT_kwDORLtfbc5wio-r
433+ - Audit note: Unsafe run() result cast remains; runtime risk depends on raw-result consumers.
434+
435+- [ ] `C049` `JSON.stringify(cause)` returns `undefined` for `undefined`, functions, or symbols, violating the `string` return type. Consider coercing the result to a string (e.g., `String(JSON.stringify(cause))`) or adding a fallback.
436+ - Status: `TODO`
437+ - Verdict: `valid`
438+ - Severity: `Low`
439+ - Area: `Other`
440+ - File: `apps/server/src/provider/Layers/ProviderService.ts:59`
441+ - Threads: PRRT_kwDORLtfbc5wnVsI
442+ - Audit note: JSON.stringify(cause) may return undefined despite string expectations.
443+
444+- [ ] `C050` The read-modify-write pattern (`getBySessionId` → merge → `upsert`) is susceptible to lost updates under concurrent writes. Consider wrapping in a transaction or adding optimistic concurrency control (e.g., version field) if concurrent session updates are expected. <details> <summary>🚀 Reply "<strong>fix it for me</strong>" or copy this <strong>AI Prompt</strong> for your agent:</summary>
445+ - Status: `TODO`
446+ - Verdict: `valid`
447+ - Severity: `Low`
448+ - Area: `Other`
449+ - File: `apps/server/src/provider/Layers/ProviderSessionDirectory.ts:94`
450+ - Threads: PRRT_kwDORLtfbc5wiLhY
451+ - Audit note: ProviderSessionDirectory upsert remains read-merge-write without concurrency control.
452+
453+- [ ] `C051` Using `??` for `providerThreadId` and `adapterKey` makes it impossible to clear these fields by passing `null`, since `null ?? existing` evaluates to `existing`. Consider using explicit `undefined` checks (like `resumeCursor` does) if clearing should be supported. <details> <summary>🚀 Reply "<strong>fix it for me</strong>" or copy this <strong>AI Prompt</strong> for your agent:</summary>
454+ - Status: `TODO`
455+ - Verdict: `partially-valid`
456+ - Severity: `Low`
457+ - Area: `Other`
458+ - File: `apps/server/src/provider/Layers/ProviderSessionDirectory.ts:119`
459+ - Threads: PRRT_kwDORLtfbc5wxvH9
460+ - Audit note: Null-clearing issue is real for providerThreadId; adapterKey part overstated.
461+
462+- [ ] `C052` Race condition: `processHandle` may be `null` when `data` callback fires, since it's assigned after `Bun.spawn` returns. Consider initializing `BunPtyProcess` first, then passing it to the callback to avoid losing initial output. <details> <summary>🚀 Reply "<strong>fix it for me</strong>" or copy this <strong>AI Prompt</strong> for your agent:</summary>
463+ - Status: `TODO`
464+ - Verdict: `valid`
465+ - Severity: `Low`
466+ - Area: `Other`
467+ - File: `apps/server/src/terminal/Layers/BunPTY.ts:97`
468+ - Threads: PRRT_kwDORLtfbc5w1CxE
469+ - Audit note: Data callback may race before processHandle assignment.
470+
471+- [ ] `C056` When `onOpenChange` is provided without `open`, the internal `_open` state never updates because `setOpenProp` takes precedence. Consider calling `_setOpen` when `openProp === undefined`, regardless of whether `setOpenProp` exists.
472+ - Status: `TODO`
473+ - Verdict: `partially-valid`
474+ - Severity: `Low`
475+ - Area: `Other`
476+ - File: `apps/web/src/components/ui/sidebar.tsx:114`
477+ - Threads: PRRT_kwDORLtfbc5wxvIq
478+ - Audit note: Bug pattern exists, but current callsites mostly avoid triggering it.
479+
480+- [ ] `C057` The `resizable` object is recreated on every render, causing `SidebarRail`'s `useEffect` to repeatedly read localStorage and update the DOM. Consider memoizing the object with `useMemo`. <details> <summary>🚀 Reply "<strong>fix it for me</strong>" or copy this <strong>AI Prompt</strong> for your agent:</summary>
481+ - Status: `TODO`
482+ - Verdict: `valid`
483+ - Severity: `Low`
484+ - Area: `Other`
485+ - File: `apps/web/src/routes/_chat.$threadId.tsx:105`
486+ - Threads: PRRT_kwDORLtfbc5wyWz4
487+ - Audit note: Resizable object recreation still retriggers effect/storage reads.
488+
489+- [ ] `C058` When `localStorage.getItem()` returns `null`, `Number(null)` evaluates to `0`, which passes `Number.isFinite(0)`. This causes the sidebar to clamp to `minWidth` on first load, overriding the `DIFF_INLINE_DEFAULT_WIDTH` CSS clamp. Consider checking for `null` or empty string before parsing, e.g. guard with `storedWidth === null || storedWidth === ''`. <details> <summary>🚀 Reply "<strong>fix it for me</strong>" or copy this <strong>AI Prompt</strong> for your agent:</summary>
490+ - Status: `TODO`
491+ - Verdict: `valid`
492+ - Severity: `Low`
493+ - Area: `Other`
494+ - File: `apps/web/src/routes/_chat.$threadId.tsx:122`
495+ - Threads: PRRT_kwDORLtfbc5wnVsX
496+ - Audit note: Number(null) -> 0 path still forces min width on initial load.
497+
498+- [ ] `C060` `defaultModel` should be `Schema.optional(Schema.NullOr(Schema.String))` to allow clearing the value. Currently there's no way to reset it to `null` since omitting means "no change" in patch semantics. <details> <summary>🚀 Reply "<strong>fix it for me</strong>" or copy this <strong>AI Prompt</strong> for your agent:</summary>
499+ - Status: `TODO`
500+ - Verdict: `valid`
501+ - Severity: `Low`
502+ - Area: `Other`
503+ - File: `packages/contracts/src/orchestration.ts:253`
504+ - Threads: PRRT_kwDORLtfbc5whxJC
505+ - Audit note: Schema still cannot express null clear for defaultModel patch.
506+
507+## Closed Invalid Items
508+
509+- [x] `C021` Shared mutable default metadata object causes stale eventId
510+ - Status: `CLOSED_INVALID`
511+ - Severity: `Medium`
512+ - File: `apps/server/src/orchestration/decider.ts:27`
513+ - Threads: PRRT_kwDORLtfbc5wkPaA
514+ - Rationale: Stale-eventId claim no longer applies; eventId is regenerated per event.
515+
516+- [x] `C025` Duplicated checkpoint ref computation across two files
517+ - Status: `CLOSED_INVALID`
518+ - Severity: `Medium`
519+ - File: `apps/server/src/wsServer.ts:128`
520+ - Threads: PRRT_kwDORLtfbc5wvwag
521+ - Rationale: No longer duplicated; checkpoint ref helper now centralized.
522+
523+- [x] `C031` Revert uses wrong turn count from positional inference
524+ - Status: `CLOSED_INVALID`
525+ - Severity: `Medium`
526+ - File: `apps/web/src/session-logic.ts:127`
527+ - Threads: PRRT_kwDORLtfbc5v9SCp
528+ - Rationale: Revert now uses explicit checkpointTurnCount first; positional fallback is non-primary.
529+
530+- [x] `C036` Duplicate `checkpointRefForThreadTurn` function in two production files
531+ - Status: `CLOSED_INVALID`
532+ - Severity: `Low`
533+ - File: `apps/server/src/checkpointing/Layers/CheckpointStore.ts:284`
534+ - Threads: PRRT_kwDORLtfbc5wiqFX
535+ - Rationale: No longer duplicated; single production source via Refs.ts.
536+
537+- [x] `C055` Duplicate `checkpointRefForThreadTurn` function across files
538+ - Status: `CLOSED_INVALID`
539+ - Severity: `Low`
540+ - File: `apps/server/src/wsServer.ts:128`
541+ - Threads: PRRT_kwDORLtfbc5wkPaG
542+ - Rationale: No longer duplicated; helper is centralized.
apps/server/integration/orchestrationEngine.integration.test.ts+1−1
@@ -22,7 +22,7 @@ import { · 21 unmodified lines
2222 makeOrchestrationIntegrationHarness,
2323 type OrchestrationIntegrationHarness,
2424 } from "./OrchestrationEngineHarness.integration.ts";
25−import { checkpointRefForThreadTurn } from "../src/checkpointing/Refs.ts";
25+import { checkpointRefForThreadTurn } from "../src/checkpointing/Utils.ts";
2626
2727 const asMessageId = (value: string): MessageId => MessageId.makeUnsafe(value);
2828 const asProjectId = (value: string): ProjectId => ProjectId.makeUnsafe(value);
apps/server/src/checkpointing/Layers/CheckpointDiffQuery.test.ts+1−1
@@ -9,7 +9,7 @@ import { Effect, Layer } from "effect"; · 8 unmodified lines
99 import { describe, expect, it } from "vitest";
1010
1111 import { ProjectionSnapshotQuery } from "../../orchestration/Services/ProjectionSnapshotQuery.ts";
12−import { checkpointRefForThreadTurn } from "../Refs.ts";
12+import { checkpointRefForThreadTurn } from "../Utils.ts";
1313 import { CheckpointDiffQueryLive } from "./CheckpointDiffQuery.ts";
1414 import { CheckpointStore, type CheckpointStoreShape } from "../Services/CheckpointStore.ts";
1515 import { CheckpointDiffQuery } from "../Services/CheckpointDiffQuery.ts";
apps/server/src/checkpointing/Layers/CheckpointDiffQuery.ts+5−28
@@ -9,35 +9,12 @@ import { Effect, Layer, Schema } from "effect"; · 8 unmodified lines
99
1010 import { ProjectionSnapshotQuery } from "../../orchestration/Services/ProjectionSnapshotQuery.ts";
1111 import { CheckpointInvariantError, CheckpointUnavailableError } from "../Errors.ts";
12−import { checkpointRefForThreadTurn } from "../Refs.ts";
12+import { checkpointRefForThreadTurn, resolveThreadWorkspaceCwd } from "../Utils.ts";
1313 import { CheckpointStore } from "../Services/CheckpointStore.ts";
14−import { CheckpointDiffQuery, type CheckpointDiffQueryShape } from "../Services/CheckpointDiffQuery.ts";
15−
16−function trimToNonEmpty(value: string | null | undefined): string | undefined {
17− const normalized = value?.trim();
18− return normalized && normalized.length > 0 ? normalized : undefined;
19−}
20−
21−function resolveThreadWorkspaceCwd(input: {
22− readonly thread: {
23− readonly projectId: ProjectId;
24− readonly worktreePath: string | null;
25− };
26− readonly projects: ReadonlyArray<{
27− readonly id: ProjectId;
28− readonly workspaceRoot: string;
29− }>;
30−}): string | undefined {
31− const worktreeCwd = trimToNonEmpty(input.thread.worktreePath);
32− if (worktreeCwd) {
33− return worktreeCwd;
34− }
35−
36− const workspaceRoot = input.projects.find(
37− (project) => project.id === input.thread.projectId,
38− )?.workspaceRoot;
39− return trimToNonEmpty(workspaceRoot);
40−}
14+import {
15+ CheckpointDiffQuery,
16+ type CheckpointDiffQueryShape,
17+} from "../Services/CheckpointDiffQuery.ts";
4118
4219 const isTurnDiffResult = Schema.is(OrchestrationGetTurnDiffResult);
4320
apps/server/src/checkpointing/Refs.ts+0−10
@@ -1,10 +0,0 @@
1−import { Encoding } from "effect";
2−import { CheckpointRef, type ThreadId } from "@t3tools/contracts";
3−
4−export const CHECKPOINT_REFS_PREFIX = "refs/t3/checkpoints";
5−
6−export function checkpointRefForThreadTurn(threadId: ThreadId, turnCount: number): CheckpointRef {
7− return CheckpointRef.makeUnsafe(
8− `${CHECKPOINT_REFS_PREFIX}/${Encoding.encodeBase64Url(threadId)}/turn/${turnCount}`,
9− );
10−}
apps/server/src/checkpointing/Utils.ts+36−0
@@ -0,0 +1,36 @@
1+import { Encoding } from "effect";
2+import { CheckpointRef, ProjectId, type ThreadId } from "@t3tools/contracts";
3+
4+export const CHECKPOINT_REFS_PREFIX = "refs/t3/checkpoints";
5+
6+export function checkpointRefForThreadTurn(threadId: ThreadId, turnCount: number): CheckpointRef {
7+ return CheckpointRef.makeUnsafe(
8+ `${CHECKPOINT_REFS_PREFIX}/${Encoding.encodeBase64Url(threadId)}/turn/${turnCount}`,
9+ );
10+}
11+
12+function trimToNonEmpty(value: string | null | undefined): string | undefined {
13+ const normalized = value?.trim();
14+ return normalized && normalized.length > 0 ? normalized : undefined;
15+}
16+
17+export function resolveThreadWorkspaceCwd(input: {
18+ readonly thread: {
19+ readonly projectId: ProjectId;
20+ readonly worktreePath: string | null;
21+ };
22+ readonly projects: ReadonlyArray<{
23+ readonly id: ProjectId;
24+ readonly workspaceRoot: string;
25+ }>;
26+}): string | undefined {
27+ const worktreeCwd = trimToNonEmpty(input.thread.worktreePath);
28+ if (worktreeCwd) {
29+ return worktreeCwd;
30+ }
31+
32+ const workspaceRoot = input.projects.find(
33+ (project) => project.id === input.thread.projectId,
34+ )?.workspaceRoot;
35+ return trimToNonEmpty(workspaceRoot);
36+}
apps/server/src/orchestration/Layers/CheckpointReactor.test.ts+25−16
@@ -35,7 +35,7 @@ import { · 34 unmodified lines
3535 ProviderService,
3636 type ProviderServiceShape,
3737 } from "../../provider/Services/ProviderService.ts";
38−import { checkpointRefForThreadTurn } from "../../checkpointing/Refs.ts";
38+import { checkpointRefForThreadTurn } from "../../checkpointing/Utils.ts";
3939
4040 const asProjectId = (value: string): ProjectId => ProjectId.makeUnsafe(value);
4141 const asSessionId = (value: string): ProviderSessionId => ProviderSessionId.makeUnsafe(value);
@@ -334,7 +334,10 @@ describe("CheckpointReactor", () => { · 292 unmodified lines
334334 threadId: ProviderThreadId.makeUnsafe("provider-thread-1"),
335335 turnId: asTurnId("turn-1"),
336336 });
337− await waitForGitRefExists(harness.cwd, checkpointRefForThreadTurn(ThreadId.makeUnsafe("thread-1"), 0));
337+ await waitForGitRefExists(
338+ harness.cwd,
339+ checkpointRefForThreadTurn(ThreadId.makeUnsafe("thread-1"), 0),
340+ );
338341
339342 fs.writeFileSync(path.join(harness.cwd, "README.md"), "v2\n", "utf8");
340343 harness.provider.emit({
@@ -354,12 +357,12 @@ describe("CheckpointReactor", () => { · 13 unmodified lines
354357 (entry) => entry.latestTurnId === "turn-1" && entry.checkpoints.length === 1,
355358 );
356359 expect(thread.checkpoints[0]?.checkpointTurnCount).toBe(1);
357− expect(gitRefExists(harness.cwd, checkpointRefForThreadTurn(ThreadId.makeUnsafe("thread-1"), 0))).toBe(
358− true,
359− );
360− expect(gitRefExists(harness.cwd, checkpointRefForThreadTurn(ThreadId.makeUnsafe("thread-1"), 1))).toBe(
361− true,
362− );
360+ expect(
361+ gitRefExists(harness.cwd, checkpointRefForThreadTurn(ThreadId.makeUnsafe("thread-1"), 0)),
362+ ).toBe(true);
363+ expect(
364+ gitRefExists(harness.cwd, checkpointRefForThreadTurn(ThreadId.makeUnsafe("thread-1"), 1)),
365+ ).toBe(true);
363366 expect(
364367 gitShowFileAtRef(
365368 harness.cwd,
@@ -398,7 +401,10 @@ describe("CheckpointReactor", () => { · 32 unmodified lines
398401 }),
399402 );
400403
401− await waitForGitRefExists(harness.cwd, checkpointRefForThreadTurn(ThreadId.makeUnsafe("thread-1"), 0));
404+ await waitForGitRefExists(
405+ harness.cwd,
406+ checkpointRefForThreadTurn(ThreadId.makeUnsafe("thread-1"), 0),
407+ );
402408 expect(
403409 gitShowFileAtRef(
404410 harness.cwd,
@@ -448,9 +454,9 @@ describe("CheckpointReactor", () => { · 43 unmodified lines
448454 });
449455
450456 await waitForEvent(harness.engine, (event) => event.type === "thread.turn-diff-completed");
451− expect(gitRefExists(harness.cwd, checkpointRefForThreadTurn(ThreadId.makeUnsafe("thread-1"), 1))).toBe(
452− true,
453− );
457+ expect(
458+ gitRefExists(harness.cwd, checkpointRefForThreadTurn(ThreadId.makeUnsafe("thread-1"), 1)),
459+ ).toBe(true);
454460 expect(
455461 gitShowFileAtRef(
456462 harness.cwd,
@@ -556,7 +562,10 @@ describe("CheckpointReactor", () => { · 99 unmodified lines
556562 turnId: asTurnId("turn-after-runtime-failure"),
557563 });
558564
559− await waitForGitRefExists(harness.cwd, checkpointRefForThreadTurn(ThreadId.makeUnsafe("thread-1"), 0));
565+ await waitForGitRefExists(
566+ harness.cwd,
567+ checkpointRefForThreadTurn(ThreadId.makeUnsafe("thread-1"), 0),
568+ );
560569 expect(
561570 gitRefExists(harness.cwd, checkpointRefForThreadTurn(ThreadId.makeUnsafe("thread-1"), 0)),
562571 ).toBe(true);
@@ -636,9 +645,9 @@ describe("CheckpointReactor", () => { · 73 unmodified lines
636645 numTurns: 1,
637646 });
638647 expect(fs.readFileSync(path.join(harness.cwd, "README.md"), "utf8")).toBe("v2\n");
639− expect(gitRefExists(harness.cwd, checkpointRefForThreadTurn(ThreadId.makeUnsafe("thread-1"), 2))).toBe(
640− false,
641− );
648+ expect(
649+ gitRefExists(harness.cwd, checkpointRefForThreadTurn(ThreadId.makeUnsafe("thread-1"), 2)),
650+ ).toBe(false);
642651 });
643652
644653 it("processes consecutive revert requests with deterministic rollback sequencing", async () => {
apps/server/src/orchestration/Layers/CheckpointReactor.ts+4−23
@@ -5,14 +5,16 @@ import { · 4 unmodified lines
55 ProviderSessionId,
66 ThreadId,
77 TurnId,
8− type ProjectId,
98 type OrchestrationEvent,
109 type ProviderRuntimeEvent,
1110 } from "@t3tools/contracts";
1211 import { Cause, Effect, Layer, Option, Queue, Stream } from "effect";
1312
1413 import { parseTurnDiffFilesFromUnifiedDiff } from "../../checkpointing/Diffs.ts";
15−import { checkpointRefForThreadTurn } from "../../checkpointing/Refs.ts";
14+import {
15+ checkpointRefForThreadTurn,
16+ resolveThreadWorkspaceCwd,
17+} from "../../checkpointing/Utils.ts";
1618 import { CheckpointStore } from "../../checkpointing/Services/CheckpointStore.ts";
1719 import { ProviderService } from "../../provider/Services/ProviderService.ts";
1820 import { CheckpointReactor, type CheckpointReactorShape } from "../Services/CheckpointReactor.ts";
@@ -40,27 +42,6 @@ function trimToNonEmpty(value: string | null | undefined): string | undefined { · 21 unmodified lines
4042 return normalized && normalized.length > 0 ? normalized : undefined;
4143 }
4244
43−function resolveThreadWorkspaceCwd(input: {
44− readonly thread: {
45− readonly projectId: ProjectId;
46− readonly worktreePath: string | null;
47− };
48− readonly projects: ReadonlyArray<{
49− readonly id: ProjectId;
50− readonly workspaceRoot: string;
51− }>;
52−}): string | undefined {
53− const worktreeCwd = trimToNonEmpty(input.thread.worktreePath);
54− if (worktreeCwd) {
55− return worktreeCwd;
56− }
57−
58− const workspaceRoot = input.projects.find(
59− (project) => project.id === input.thread.projectId,
60− )?.workspaceRoot;
61− return trimToNonEmpty(workspaceRoot);
62−}
63−
6445 function checkpointStatusFromRuntime(status: string | undefined): "ready" | "missing" | "error" {
6546 switch (status) {
6647 case "failed":
apps/server/src/orchestration/Layers/ProviderRuntimeIngestion.ts+1−8
@@ -26,7 +26,7 @@ function toTurnId(value: string | undefined): TurnId | undefined { · 25 unmodified lines
2626 }
2727
2828 function truncateDetail(value: string, limit = 180): string {
29− return value.length > limit ? `${value.slice(0, limit - 1)}...` : value;
29+ return value.length > limit ? `${value.slice(0, limit - 3)}...` : value;
3030 }
3131
3232 function runtimeEventToActivities(
@@ -130,7 +130,6 @@ const make = Effect.gen(function* () { · 97 unmodified lines
130130 const providerService = yield* ProviderService;
131131
132132 const turnMessageIdsByTurnKey = new Map<string, Set<MessageId>>();
133− const latestMessageIdByTurnKey = new Map<string, MessageId>();
134133
135134 const rememberAssistantMessageId = (
136135 sessionId: ProviderSessionId,
@@ -144,7 +143,6 @@ const make = Effect.gen(function* () { · 7 unmodified lines
144143 } else {
145144 turnMessageIdsByTurnKey.set(key, new Set([messageId]));
146145 }
147− latestMessageIdByTurnKey.set(key, messageId);
148146 };
149147
150148 const getAssistantMessageIdsForTurn = (sessionId: ProviderSessionId, turnId: TurnId) => {
@@ -162,11 +160,6 @@ const make = Effect.gen(function* () { · 11 unmodified lines
162160 turnMessageIdsByTurnKey.delete(key);
163161 }
164162 }
165− for (const key of latestMessageIdByTurnKey.keys()) {
166− if (key.startsWith(prefix)) {
167− latestMessageIdByTurnKey.delete(key);
168− }
169− }
170163 };
171164
172165 const processEvent = (event: ProviderRuntimeEvent) =>
apps/server/src/wsServer.ts+3−2
@@ -72,7 +72,7 @@ const isServerNotRunningError = (error: unknown): boolean => { · 71 unmodified lines
7272 };
7373
7474 function rejectUpgrade(socket: Duplex, statusCode: number, message: string): void {
75− socket.write(
75+ socket.end(
7676 `HTTP/1.1 ${statusCode} ${statusCode === 401 ? "Unauthorized" : "Bad Request"}\r\n` +
7777 "Connection: close\r\n" +
7878 "Content-Type: text/plain\r\n" +
@@ -80,7 +80,6 @@ function rejectUpgrade(socket: Duplex, statusCode: number, message: string): voi · 1 unmodified line
8080 "\r\n" +
8181 message,
8282 );
83− socket.destroy();
8483 }
8584
8685 function parseBooleanEnv(value: string | undefined): boolean | undefined {
@@ -506,6 +505,8 @@ export const createServer = Effect.fn(function* (options: ServerOptions = {}): E · 419 unmodified lines
506505 });
507506
508507 httpServer.on("upgrade", (request, socket, head) => {
508+ socket.on("error", () => {}); // Prevent unhandled `EPIPE`/`ECONNRESET` from crashing the process if the client disconnects mid-handshake
509+
509510 if (authToken) {
510511 let providedToken: string | null = null;
511512 try {
apps/web/src/wsTransport.ts+1−4
@@ -53,10 +53,7 @@ export class WsTransport { · 52 unmodified lines
5353 throw new Error("Request method is required");
5454 }
5555 const id = String(this.nextId++);
56− const body =
57− params !== undefined
58− ? { _tag: method, ...(params as Record<string, unknown>) }
59− : { _tag: method };
56+ const body = params != null ? { ...params, _tag: method } : { _tag: method };
6057 const message: WsRequestEnvelope = { id, body };
6158
6259 return new Promise<T>((resolve, reject) => {