Skip to content

refactor(app): modularize session todo and blocker state#394

Merged
Astro-Han merged 8 commits into
devfrom
pawwork/fix-composer-dock-regressions
May 3, 2026
Merged

refactor(app): modularize session todo and blocker state#394
Astro-Han merged 8 commits into
devfrom
pawwork/fix-composer-dock-regressions

Conversation

@Astro-Han

@Astro-Han Astro-Han commented May 2, 2026

Copy link
Copy Markdown
Owner

Summary

  • Extract session todo source selection, lifecycle signatures, and dock lifecycle transitions into dedicated todos/ domain modules.
  • Extract blocking request tree lookup, running-question fallback detection, session-scoped question refetch/reconcile, and per-session refetch running into dedicated blockers/ modules.
  • Slim session-composer-state.ts down to composer wiring and test probe reporting.
  • Keep the composer dock regressions fixed: active todowrite parts can beat lagging backend todos, terminal todowrite parts preserve the completing lifecycle, completed-only historical sessions do not reopen the dock, terminal content-only refreshes do not restart the hide lifecycle, session switches consume transient todo completion history, and question fallback refetch is session-scoped/cancel-safe.
  • Separate todo data snapshots from composer dock eligibility so the status summary can still display completed-only historical todos.
  • Keep the small PatchEdit files tool label update and zh/zht translations in this PR.

Why

The original #394 patch fixed symptoms inside session-composer-state.ts, but the real problem was that composer owned too many unrelated policies: todo source arbitration, todo lifecycle/timers, request tree selection, question fallback recovery, and permission response state. This refactor makes those policies independently reviewable and unit-testable without changing backend APIs or SDK types.

Related Issue

No linked issue; found during manual regression testing.

Human Review Status

Pending. A human should make the final merge decision after reviewing the final diff and verification evidence.

Review Focus

  • packages/app/src/pages/session/todos/todo-source.ts: data snapshot vs dock snapshot split, especially terminal parts preserving lifecycle while historical terminal sessions stay hidden.
  • packages/app/src/pages/session/todos/todo-dock-machine.ts: active → terminal lifecycle, terminal refresh behavior, session switch behavior, and transient active history cleanup.
  • packages/app/src/pages/session/blockers/question-reconcile.ts: session-scoped retry, async cancellation checks, and target-session-only apply.
  • packages/app/src/pages/session/blockers/question-refetch-runner.ts: per-session inflight tracking, disposal, and current fallback restart after session changes.
  • packages/app/src/pages/session/blockers/use-session-blockers.ts and packages/app/src/pages/session/todos/use-session-todos.ts: Solid wiring around the pure modules.
  • packages/app/src/pages/session/composer/session-composer-state.ts: should now only compose domain modules and expose UI-facing state.

Risk Notes

Medium UI behavior risk in the session composer dock and blocking question UI. No backend schema/API/SDK/generated/dependency changes. This still does not implement SSE replay; question fallback remains a bounded frontend recovery path.

How To Verify

Focused unit tests: 64 passed
Command: bun test --preload ./happydom.ts ./src/pages/session/todos/todo-model.test.ts ./src/pages/session/todos/todo-source.test.ts ./src/pages/session/todos/todo-dock-machine.test.ts ./src/pages/session/blockers/request-tree.test.ts ./src/pages/session/blockers/question-fallback.test.ts ./src/pages/session/blockers/question-reconcile.test.ts ./src/pages/session/blockers/question-refetch-runner.test.ts ./src/pages/session/session-todos.test.ts ./src/pages/session/session-status-extractors.test.ts

Todo dock e2e: 12 passed
Command: bun test:e2e -- session/session-composer-dock.spec.ts -g "todo dock"

Typecheck: passed
Command: bun run typecheck

Diff check: passed with no output
Command: git diff --check / git diff --cached --check

Earlier attempted question dock e2e: blocked question flow failed during test seeding before UI assertions
Command: bun test:e2e -- session/session-composer-dock.spec.ts -g "blocked question flow unblocks after submit"
Result: Timed out seeding question request; TestLLMServer still had 1 queued response

Screenshots or Recordings

Not attached. The visible todo dock behavior is covered by focused e2e tests; question fallback behavior is covered by deterministic unit-level fallback/reconcile/runner coverage.

Checklist

  • Human review status is stated above as pending, approved, or not required
  • I linked the related issue, or stated why there is no issue
  • This PR has type, scope, and priority labels, or I requested maintainer labeling
  • I described the review focus and any meaningful risks
  • I listed the relevant verification steps and the key result for each
  • I did not introduce unrelated dependencies, generated files, or file changes beyond the stated scope
  • I manually checked visible UI or copy changes when needed, with screenshots or recordings
  • I considered macOS and Windows impact for desktop, packaging, updater, signing, paths, shell, or permissions changes
  • I called out docs, release notes, dependencies, permissions, credentials, deletion behavior, generated content, or local file changes when relevant
  • I reviewed the final diff for unrelated changes and suspicious dependency changes
  • I am targeting dev, and my PR title and commit messages use Conventional Commits in English

Maintainer labeling request: please add appropriate type, scope, and priority labels if needed.

Summary by CodeRabbit

  • New Features

    • Improved session permission/question recovery and more robust todo dock visibility behavior (preserves dock state across terminal-only refreshes).
  • Bug Fixes

    • Ensure todo dock hide timing and visibility are consistent during session transitions.
  • Refactor

    • Internal restructuring of session and todo processing for clearer separation of concerns.
  • Tests

    • Added end-to-end and unit tests covering todo dock, todo selection, and question refetch/recovery flows.
  • Chores

    • Updated UI label "Patch" → "Edit files" in English, Simplified Chinese, and Traditional Chinese.

@coderabbitai

coderabbitai Bot commented May 2, 2026

Copy link
Copy Markdown
Contributor

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 547e3e89-9f63-47b7-b8a9-e96d4a8d8e2c

📥 Commits

Reviewing files that changed from the base of the PR and between 7faa84e and f5437dc.

📒 Files selected for processing (3)
  • packages/app/src/pages/session/blockers/use-session-blockers.ts
  • packages/app/src/pages/session/todos/todo-dock-machine.test.ts
  • packages/app/src/pages/session/todos/todo-dock-machine.ts
✅ Files skipped from review due to trivial changes (1)
  • packages/app/src/pages/session/blockers/use-session-blockers.ts
🚧 Files skipped from review as they are similar to previous changes (2)
  • packages/app/src/pages/session/todos/todo-dock-machine.test.ts
  • packages/app/src/pages/session/todos/todo-dock-machine.ts

📝 Walkthrough

Walkthrough

Refactors session composer state by extracting blockers and todo/dock responsibilities into createSessionBlockers and createSessionTodoModel; adds a todo snapshot/model, a todo-dock state machine and reducer, question-fallback detection, a bounded question-refetcher and runner, multiple unit and e2e tests, and small i18n label updates.

Changes

Session State Refactor & Todo/Dock

Layer / File(s) Summary
Data Shape
packages/app/src/pages/session/todos/todo-model.ts
Adds TodoSnapshot, TodoPhase, TodoSourceKind, dockEligible, historicalTerminal, and lifecycle/display signature helpers.
Selection Logic
packages/app/src/pages/session/todos/todo-source.ts, packages/app/src/pages/session/todos/todo-source.test.ts
Introduces selectSessionTodoDataSnapshot and selectSessionTodoDockSnapshot with ordered precedence (primary.parts → primary.backend → fallback.parts → fallback.backend); selectSessionTodos returns .items from data snapshot.
State Machine
packages/app/src/pages/session/todos/todo-dock-machine.ts, packages/app/src/pages/session/todos/todo-dock-machine.test.ts
Defines TodoDockMachineState union, TodoDockTransition, reduceTodoDockState, and completing/hide/animation-frame transition rules with session/lifecycle matching.
Model Wiring
packages/app/src/pages/session/todos/use-session-todos.ts
Adds createSessionTodoModel: composer pull integration, snapshot memo, dock reducer wiring (rAF + hide timeout), dispatch loop, and cleanup.
Composer Integration
packages/app/src/pages/session/composer/session-composer-state.ts, packages/app/src/pages/session/session-todos.ts
createSessionComposerState delegates blockers/todos to new models; session-todos.ts re-exports todo-source selectors/types.
Blocker Model
packages/app/src/pages/session/blockers/use-session-blockers.ts
Adds createSessionBlockers: memoized question/permission requests, decide handler, permissionResponding, blocked, and integration with question refetch runner and reconcile application.
Question Detection
packages/app/src/pages/session/blockers/question-fallback.ts, .../question-fallback.test.ts
Adds QUESTION_FALLBACK_LOOKBACK_MESSAGES and findRunningQuestionFallbackSession to detect recent running question tool parts.
Question Refetching
packages/app/src/pages/session/blockers/question-reconcile.ts, .../question-reconcile.test.ts
Adds refetchPendingQuestionsForSession with bounded retries, cancellation checks, filtering/sorting and apply-on-match behavior.
Refetch Runner
packages/app/src/pages/session/blockers/question-refetch-runner.ts, .../question-refetch-runner.test.ts
Adds createQuestionRefetchRunner to serialize/dedupe refetches, schedule fallback starts, and support disposal.
Imports / Wiring
packages/app/src/pages/layout/sidebar-items.tsx, packages/app/src/pages/session/blockers/request-tree.test.ts
Updated imports to use new blockers/request-tree path for permission/question request helpers.
Tests / E2E
packages/app/e2e/session/session-composer-dock.spec.ts, multiple .../todos and .../blockers tests
Adds e2e test verifying dock hide-timer preserved across terminal-only refreshes; many unit tests covering todo signatures, selection precedence, dock reducer behavior, question-fallback logic, refetch retry, and runner sequencing.

i18n Label Update

Layer / File(s) Summary
Translations
packages/ui/src/i18n/en.ts, packages/ui/src/i18n/zh.ts, packages/ui/src/i18n/zht.ts
Changes ui.tool.patch from "Patch"/"批量修改"/"修補" to "Edit files"/"修改文件"/"修改檔案" respectively.

Sequence Diagram(s)

sequenceDiagram
    participant Composer as Composer State
    participant TodoModel as Session Todo Model
    participant Dock as Todo Dock Machine
    participant RAF as rAF / Timers

    Composer->>TodoModel: compute snapshot (primary/fallback/composer)
    TodoModel->>Dock: dispatch "snapshot" transition
    Dock->>RAF: schedule animationFrame / hide timeout (if completing)
    RAF->>Dock: send animationFrameElapsed / hideTimerElapsed
    Dock-->>Composer: expose dock/opening/completing getters
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

Suggested labels

enhancement, P2, app, harness

Poem

🐰 I hopped through state and split the load,
Blockers and todos now march on their road.
Timers tick softly, dock hides on cue,
Tests keep order and signatures true.
🥕✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 11.11% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and accurately summarizes the main change: modularizing session todo and blocker state by extracting them into dedicated domain modules.
Description check ✅ Passed The description comprehensively covers all required template sections: summary, rationale, verification steps with results, review focus, risk notes, and a completed checklist.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch pawwork/fix-composer-dock-regressions

Tip

💬 Introducing Slack Agent: The best way for teams to turn conversations into code.

Slack Agent is built on CodeRabbit's deep understanding of your code, so your team can collaborate across the entire SDLC without losing context.

  • Generate code and open pull requests
  • Plan features and break down work
  • Investigate incidents and troubleshoot customer tickets together
  • Automate recurring tasks and respond to alerts with triggers
  • Summarize progress and report instantly

Built for teams:

  • Shared memory across your entire org—no repeating context
  • Per-thread sandboxes to safely plan and execute work
  • Governance built-in—scoped access, auditability, and budget controls

One agent for your entire SDLC. Right inside Slack.

👉 Get your free trial and get 200 agent minutes per Slack user (a $50 value).


Review rate limit: 8/10 reviews remaining, refill in 9 minutes and 6 seconds.

Comment @coderabbitai help to get the list of available commands and usage tips.

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces helper functions and refactors the session composer state to improve the reliability of question refetching and todo dock behavior. It adds a refetchPendingQuestions utility with retry logic and updates the todo signature calculation to ignore content changes, which prevents the dock from resetting its hide timer during terminal-only refreshes. Feedback on the refetchPendingQuestions function identifies potential issues with premature termination when questions for other sessions are returned and unnecessary delays in the retry loop, providing a suggestion to refine the loop's exit conditions.

Comment thread packages/app/src/pages/session/composer/session-composer-state-helpers.ts Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (1)
packages/app/src/pages/session/composer/session-composer-state.test.ts (1)

108-131: ⚡ Quick win

Add a cross-session retry test case for refetch fallback.

Current coverage doesn’t lock behavior when list() returns pending questions for a different session before the target session appears. That’s the key edge for this fallback path.

Suggested test shape
 describe("refetchPendingQuestions", () => {
   test("retries when the running question tool appears before the pending question is listed", async () => {
@@
   })
+
+  test("does not stop early when only another session has pending questions", async () => {
+    const target = question("q-target", "root")
+    const other = question("q-other", "other")
+    let attempts = 0
+    const applied: Record<string, QuestionRequest[] | undefined> = {}
+
+    await refetchPendingQuestions({
+      maxAttempts: 3,
+      delayMs: 1,
+      sleep: async () => {},
+      shouldContinue: () => true,
+      list: async () => {
+        attempts += 1
+        if (attempts === 1) return [other]
+        return [target]
+      },
+      apply(sessionID, questions) {
+        applied[sessionID] = questions
+      },
+    })
+
+    expect(applied.root?.map((item) => item.id)).toEqual(["q-target"])
+  })
 })
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/app/src/pages/session/composer/session-composer-state.test.ts`
around lines 108 - 131, Add a new test in session-composer-state.test.ts that
exercises refetchPendingQuestions when list() first returns a pending question
for a different session and only later returns the target session’s pending
item: mock list() to return [] or a pending for a different session on initial
attempts and then return the desired pending (e.g., question("q-late","root"))
on a subsequent attempt, keep maxAttempts/delayMs/sleep similar to the existing
test, capture calls via the apply(sessionID, questions) handler into an applied
map, and assert that refetchPendingQuestions retries (attempts count) and that
applied.root contains the expected "q-late" id; reference the
refetchPendingQuestions invocation and the list/apply mocks so the test locks
the cross-session retry fallback behavior.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@packages/app/src/pages/session/composer/session-composer-state-helpers.ts`:
- Around line 22-37: The code obtains questions via input.list() then applies
grouped results without re-checking cancellation; after the await you must call
input.shouldContinue() again and abort if it returns false to avoid applying
stale results, and additionally guard before calling input.apply for each
session by checking input.shouldContinue() (or break) to prevent partial
application; update the block around QuestionRequest processing and the loop
that calls input.apply(sessionID, ...) to perform this re-check and return false
when canceled.

In `@packages/app/src/pages/session/composer/session-composer-state.ts`:
- Around line 61-64: The refetch helper is currently fetching all pending
questions via sdk.client.question.list() which can make the retry stop early if
another session has a pending question; update the list provider in the
refetchPendingQuestions call so it only returns questions for the triggering
session (use the sid passed into apply/handler) by filtering the result of
sdk.client.question.list() to q.session_id === sid (or the equivalent session
identifier field), keeping shouldContinue using questionFallbackSessionID() ===
sessionID and leaving apply(sid, qs) logic unchanged.

---

Nitpick comments:
In `@packages/app/src/pages/session/composer/session-composer-state.test.ts`:
- Around line 108-131: Add a new test in session-composer-state.test.ts that
exercises refetchPendingQuestions when list() first returns a pending question
for a different session and only later returns the target session’s pending
item: mock list() to return [] or a pending for a different session on initial
attempts and then return the desired pending (e.g., question("q-late","root"))
on a subsequent attempt, keep maxAttempts/delayMs/sleep similar to the existing
test, capture calls via the apply(sessionID, questions) handler into an applied
map, and assert that refetchPendingQuestions retries (attempts count) and that
applied.root contains the expected "q-late" id; reference the
refetchPendingQuestions invocation and the list/apply mocks so the test locks
the cross-session retry fallback behavior.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 7f1f5e20-db94-4bfb-bc92-cad4dac67795

📥 Commits

Reviewing files that changed from the base of the PR and between 51bbc2f and 02d5f94.

📒 Files selected for processing (4)
  • packages/app/e2e/session/session-composer-dock.spec.ts
  • packages/app/src/pages/session/composer/session-composer-state-helpers.ts
  • packages/app/src/pages/session/composer/session-composer-state.test.ts
  • packages/app/src/pages/session/composer/session-composer-state.ts

Comment thread packages/app/src/pages/session/composer/session-composer-state-helpers.ts Outdated
Comment thread packages/app/src/pages/session/composer/session-composer-state.ts Outdated
@Astro-Han Astro-Han changed the title fix(app): stabilize composer dock fallbacks refactor(app): modularize session todo and blocker state May 3, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (2)
packages/app/src/pages/session/composer/session-composer-state.ts (1)

27-36: ⚡ Quick win

Consider forwarding completing from the todo model too.

The refactor still tracks completing on the model and sends it to the probe, but direct consumers of createSessionComposerState() can no longer read that phase from the returned state.

Suggested follow-up
   return {
     blocked: blockers.blocked,
     questionRequest: blockers.questionRequest,
     permissionRequest: blockers.permissionRequest,
     permissionResponding: blockers.permissionResponding,
     decide: blockers.decide,
     todos: todo.todos,
     dock: todo.dock,
     opening: todo.opening,
+    completing: todo.completing,
   }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/app/src/pages/session/composer/session-composer-state.ts` around
lines 27 - 36, The returned state from createSessionComposerState() omits the
todo model's completing flag so consumers can't read that phase; update the
returned object to forward the completing property from the todo model (i.e.,
include completing: todo.completing alongside todos, dock, opening) so both
probes and direct consumers see the completing state.
packages/app/src/pages/session/todos/todo-model.test.ts (1)

44-50: ⚡ Quick win

Add the missing status-diff assertion.

This test says todoDisplaySignature tracks status too, but it only proves content and priority changes. A completed vs cancelled case would pin down the status component that the renderer depends on.

Suggested addition
   test("tracks content, priority, and status for rendering-sensitive comparisons", () => {
     expect(todoDisplaySignature([todo("first", "completed", "high")])).not.toBe(
       todoDisplaySignature([todo("first refreshed", "completed", "high")]),
     )
     expect(todoDisplaySignature([todo("first", "completed", "high")])).not.toBe(
       todoDisplaySignature([todo("first", "completed", "low")]),
     )
+    expect(todoDisplaySignature([todo("first", "completed", "high")])).not.toBe(
+      todoDisplaySignature([todo("first", "cancelled", "high")]),
+    )
   })
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/app/src/pages/session/todos/todo-model.test.ts` around lines 44 -
50, The test claims todoDisplaySignature tracks status but lacks a status-change
assertion; update the test inside the "tracks content, priority, and status for
rendering-sensitive comparisons" block to add an assertion that a change in
status produces a different signature — e.g., call
todoDisplaySignature([todo("first", "completed", "high")]) and assert it is not
equal to todoDisplaySignature([todo("first", "cancelled", "high")]); this
ensures the status component is exercised alongside the existing content and
priority checks.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@packages/app/src/pages/session/blockers/use-session-blockers.ts`:
- Around line 37-56: The code drops new sessionIDs when questionRefetchInflight
is true causing missed reconciles; change the logic in the createEffect that
watches questionFallbackSessionID so that instead of returning when
questionRefetchInflight is true it enqueues the latest sessionID (e.g., store
pendingSessionID variable) and after refetchPendingQuestionsForSession completes
(in the .finally where questionRefetchInflight is set false) check for a
pendingSessionID different from the just-completed session and trigger
refetchPendingQuestionsForSession again for that pendingSessionID (clearing
pendingSessionID once scheduled); update references to questionRefetchInflight,
questionFallbackSessionID, and refetchPendingQuestionsForSession accordingly to
implement queuing and re-triggering.

---

Nitpick comments:
In `@packages/app/src/pages/session/composer/session-composer-state.ts`:
- Around line 27-36: The returned state from createSessionComposerState() omits
the todo model's completing flag so consumers can't read that phase; update the
returned object to forward the completing property from the todo model (i.e.,
include completing: todo.completing alongside todos, dock, opening) so both
probes and direct consumers see the completing state.

In `@packages/app/src/pages/session/todos/todo-model.test.ts`:
- Around line 44-50: The test claims todoDisplaySignature tracks status but
lacks a status-change assertion; update the test inside the "tracks content,
priority, and status for rendering-sensitive comparisons" block to add an
assertion that a change in status produces a different signature — e.g., call
todoDisplaySignature([todo("first", "completed", "high")]) and assert it is not
equal to todoDisplaySignature([todo("first", "cancelled", "high")]); this
ensures the status component is exercised alongside the existing content and
priority checks.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 4f169cb7-6881-4b06-9d28-c1398c2ceba4

📥 Commits

Reviewing files that changed from the base of the PR and between 07f201c and 3bbd1ab.

📒 Files selected for processing (17)
  • packages/app/src/pages/layout/sidebar-items.tsx
  • packages/app/src/pages/session/blockers/question-fallback.test.ts
  • packages/app/src/pages/session/blockers/question-fallback.ts
  • packages/app/src/pages/session/blockers/question-reconcile.test.ts
  • packages/app/src/pages/session/blockers/question-reconcile.ts
  • packages/app/src/pages/session/blockers/request-tree.test.ts
  • packages/app/src/pages/session/blockers/request-tree.ts
  • packages/app/src/pages/session/blockers/use-session-blockers.ts
  • packages/app/src/pages/session/composer/session-composer-state.ts
  • packages/app/src/pages/session/session-todos.ts
  • packages/app/src/pages/session/todos/todo-dock-machine.test.ts
  • packages/app/src/pages/session/todos/todo-dock-machine.ts
  • packages/app/src/pages/session/todos/todo-model.test.ts
  • packages/app/src/pages/session/todos/todo-model.ts
  • packages/app/src/pages/session/todos/todo-source.test.ts
  • packages/app/src/pages/session/todos/todo-source.ts
  • packages/app/src/pages/session/todos/use-session-todos.ts
✅ Files skipped from review due to trivial changes (1)
  • packages/app/src/pages/session/todos/todo-source.test.ts

Comment thread packages/app/src/pages/session/blockers/use-session-blockers.ts Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
packages/app/src/pages/session/todos/todo-source.ts (1)

90-90: Consider removing the unused selectSessionTodoSnapshot alias or renaming it to clarify dock-specific semantics.

The alias points to selectSessionTodoDockSnapshot, which intentionally filters out terminal-only parts to prevent reopening the dock. The generic name masks this behavior. While the alias is currently unused in the codebase, it remains a misleading export that could cause confusion if reused later. Either rename it to selectSessionTodoDockSnapshot (drop the alias) or explicitly document its dock-specific behavior.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/app/src/pages/session/todos/todo-source.ts` at line 90, The exported
alias selectSessionTodoSnapshot simply points to selectSessionTodoDockSnapshot
but masks dock-specific behavior; remove the alias export to avoid confusion or
replace it with an explicit export name (export { selectSessionTodoDockSnapshot
} or rename the export to selectSessionTodoDockSnapshot) and, if keeping a
second name, add a clear comment documenting that it intentionally filters out
terminal-only parts to prevent reopening the dock; update any imports to use
selectSessionTodoDockSnapshot where needed.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@packages/app/src/pages/session/todos/todo-model.ts`:
- Around line 27-32: The current todoLifecycleSignature and todoDisplaySignature
use delimiter characters (\u0000, \u0001) which can collide with todo content
and produce identical signatures; replace the delimiter-based scheme with a
structured, unambiguous encoding (e.g., map the todos to plain objects
containing only the needed fields and return a JSON.stringify of that array or
compute a stable hash of that JSON) so signatures are deterministic and cannot
be spoofed by content containing the delimiters; update both
todoLifecycleSignature (use an array of statuses) and todoDisplaySignature (use
array of {status, priority, content}) to produce the JSON/string-hash output
instead of join(...) with delimiters.

---

Nitpick comments:
In `@packages/app/src/pages/session/todos/todo-source.ts`:
- Line 90: The exported alias selectSessionTodoSnapshot simply points to
selectSessionTodoDockSnapshot but masks dock-specific behavior; remove the alias
export to avoid confusion or replace it with an explicit export name (export {
selectSessionTodoDockSnapshot } or rename the export to
selectSessionTodoDockSnapshot) and, if keeping a second name, add a clear
comment documenting that it intentionally filters out terminal-only parts to
prevent reopening the dock; update any imports to use
selectSessionTodoDockSnapshot where needed.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 898e44b0-1015-44bd-89bb-b8ee3697b5b3

📥 Commits

Reviewing files that changed from the base of the PR and between 3bbd1ab and c37bed1.

📒 Files selected for processing (10)
  • packages/app/src/pages/session/blockers/question-reconcile.ts
  • packages/app/src/pages/session/blockers/question-refetch-runner.test.ts
  • packages/app/src/pages/session/blockers/question-refetch-runner.ts
  • packages/app/src/pages/session/blockers/use-session-blockers.ts
  • packages/app/src/pages/session/session-todos.test.ts
  • packages/app/src/pages/session/session-todos.ts
  • packages/app/src/pages/session/todos/todo-model.ts
  • packages/app/src/pages/session/todos/todo-source.test.ts
  • packages/app/src/pages/session/todos/todo-source.ts
  • packages/app/src/pages/session/todos/use-session-todos.ts
✅ Files skipped from review due to trivial changes (3)
  • packages/app/src/pages/session/session-todos.test.ts
  • packages/app/src/pages/session/todos/todo-source.test.ts
  • packages/app/src/pages/session/todos/use-session-todos.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/app/src/pages/session/blockers/use-session-blockers.ts

Comment thread packages/app/src/pages/session/todos/todo-model.ts Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (2)
packages/app/src/pages/session/composer/session-composer-state.ts (1)

27-37: ⚡ Quick win

Expose completing in the returned composer state.

The model and probe both track completing, but the returned state omits it. Adding it keeps the composer state surface aligned with the delegated todo model and avoids accidental consumer regressions.

✅ Minimal fix
   return {
     blocked: blockers.blocked,
     recoveringQuestion: blockers.recoveringQuestion,
     questionRequest: blockers.questionRequest,
     permissionRequest: blockers.permissionRequest,
     permissionResponding: blockers.permissionResponding,
     decide: blockers.decide,
     todos: todo.todos,
     dock: todo.dock,
     opening: todo.opening,
+    completing: todo.completing,
   }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/app/src/pages/session/composer/session-composer-state.ts` around
lines 27 - 37, The returned composer state omits the completing flag tracked by
the todo model/probe; add completing to the returned object so consumers see it
(e.g., include completing: todo.completing alongside todos: todo.todos, dock:
todo.dock, opening: todo.opening in the returned state).
packages/app/src/pages/session/todos/todo-source.ts (1)

21-102: ⚡ Quick win

Extract shared snapshot-selection flow to one helper.

selectSessionTodoDataSnapshot and selectSessionTodoDockSnapshot currently duplicate almost all precedence/branch logic. Consolidating this reduces policy drift risk when one path is updated later.

♻️ Suggested direction
+function selectSnapshot(
+  input: SelectSessionTodosInput,
+  mode: "data" | "dock",
+): TodoSnapshot {
+  // shared precedence logic here
+  // tweak only the small mode-specific defaults/overrides
+}
+
 export function selectSessionTodoDataSnapshot(input: SelectSessionTodosInput): TodoSnapshot {
-  // duplicated logic...
+  return selectSnapshot(input, "data")
 }
 
 export function selectSessionTodoDockSnapshot(input: SelectSessionTodosInput): TodoSnapshot {
-  // duplicated logic...
+  return selectSnapshot(input, "dock")
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/app/src/pages/session/todos/todo-source.ts` around lines 21 - 102,
Both functions duplicate the same precedence/branch logic; extract that into a
single helper (e.g., selectSessionTodoSnapshot) that takes
SelectSessionTodosInput plus a small options object to control final fields (for
example {forceDockEligible?: boolean|undefined, defaultDockEligible?: boolean,
includeDockEligible?: boolean}) and returns TodoSnapshot. Move the common flow
that computes primaryParts/fallbackParts, calls todoPhase, and builds the
snapshot into that helper, wiring dockEligible and historicalTerminal from the
phase when includeDockEligible is true (or using defaultDockEligible /
forceDockEligible overrides), and preserve the final "none" fallback sessionID
behavior (use input.primary.sessionID). Replace selectSessionTodoDataSnapshot
and selectSessionTodoDockSnapshot to call the new helper with the appropriate
options (data: includeDockEligible false; dock: includeDockEligible true with
defaultDockEligible false).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@packages/app/src/pages/session/composer/session-composer-state.ts`:
- Around line 27-37: The returned composer state omits the completing flag
tracked by the todo model/probe; add completing to the returned object so
consumers see it (e.g., include completing: todo.completing alongside todos:
todo.todos, dock: todo.dock, opening: todo.opening in the returned state).

In `@packages/app/src/pages/session/todos/todo-source.ts`:
- Around line 21-102: Both functions duplicate the same precedence/branch logic;
extract that into a single helper (e.g., selectSessionTodoSnapshot) that takes
SelectSessionTodosInput plus a small options object to control final fields (for
example {forceDockEligible?: boolean|undefined, defaultDockEligible?: boolean,
includeDockEligible?: boolean}) and returns TodoSnapshot. Move the common flow
that computes primaryParts/fallbackParts, calls todoPhase, and builds the
snapshot into that helper, wiring dockEligible and historicalTerminal from the
phase when includeDockEligible is true (or using defaultDockEligible /
forceDockEligible overrides), and preserve the final "none" fallback sessionID
behavior (use input.primary.sessionID). Replace selectSessionTodoDataSnapshot
and selectSessionTodoDockSnapshot to call the new helper with the appropriate
options (data: includeDockEligible false; dock: includeDockEligible true with
defaultDockEligible false).

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: fe2ce84d-5ea9-44ec-9de4-0679dac2c204

📥 Commits

Reviewing files that changed from the base of the PR and between c37bed1 and 7faa84e.

📒 Files selected for processing (11)
  • packages/app/src/pages/session/blockers/question-refetch-runner.test.ts
  • packages/app/src/pages/session/blockers/question-refetch-runner.ts
  • packages/app/src/pages/session/blockers/use-session-blockers.ts
  • packages/app/src/pages/session/composer/session-composer-state.ts
  • packages/app/src/pages/session/todos/todo-dock-machine.test.ts
  • packages/app/src/pages/session/todos/todo-dock-machine.ts
  • packages/app/src/pages/session/todos/todo-model.test.ts
  • packages/app/src/pages/session/todos/todo-model.ts
  • packages/app/src/pages/session/todos/todo-source.test.ts
  • packages/app/src/pages/session/todos/todo-source.ts
  • packages/app/src/pages/session/todos/use-session-todos.ts
✅ Files skipped from review due to trivial changes (2)
  • packages/app/src/pages/session/todos/todo-model.test.ts
  • packages/app/src/pages/session/todos/todo-source.test.ts
🚧 Files skipped from review as they are similar to previous changes (5)
  • packages/app/src/pages/session/blockers/question-refetch-runner.test.ts
  • packages/app/src/pages/session/blockers/question-refetch-runner.ts
  • packages/app/src/pages/session/blockers/use-session-blockers.ts
  • packages/app/src/pages/session/todos/todo-dock-machine.test.ts
  • packages/app/src/pages/session/todos/use-session-todos.ts

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant