refactor(workstation): extract rebase-plan input handlers into surfaces/rebase/input.ts - #1802
Conversation
…es/rebase/input.ts Consolidates the four `activeView === 'rebase' && state.rebasePlan` branches scattered across getLogInkInputEvents (Esc discard-guard, J/K/p/s/f/d/e/r/Enter keymap, up/k cursor, down/j cursor) into a single handleRebaseInput() call site, mirroring the surfaces/bisect pattern already shipped for the bisect surface.
There was a problem hiding this comment.
🔎 Agent review (sonnet→opus) — BLOCK
REVIEW: BLOCK
RESOLVES: partial
The extraction is structurally faithful (single handleRebaseInput, verbatim blocks, one call site), but placing it at the earliest precedence position — ahead of the pendingKey==='g' chord handlers — introduces a real, untested regression: gs/gd/gp/gr/gk/gK stop navigating and instead fire the rebase surface's s/d/p/r/k/K bindings whenever a rebase plan is active. This exact hazard is the primary risk called out in the plan and is precisely what the sibling bisect/input.ts guards against with pendingKey !== 'g', yet the PR neither adds the guard nor documents the tradeoff.
1 blocker — 1 inline on the diff
There was a problem hiding this comment.
🔎 Agent review (sonnet→opus) — LGTM
REVIEW: LGTM
RESOLVES: full
The four rebase branches are faithfully consolidated into handleRebaseInput, and the g-chord precedence regression flagged by the first pass is fixed with a single pendingKey==='g' bow-out guard (mirroring the bisect surface), backed by new gs/gd/gk regression tests. The Esc discard-guard still fires ahead of generic popView, and g+Esc is already short-circuited upstream, so ordering is sound.
1 nit — 1 inline on the diff
There was a problem hiding this comment.
🔎 Agent review (sonnet→opus) — BLOCK
REVIEW: BLOCK
RESOLVES: partial
The mechanical extraction is faithful (four blocks moved verbatim, single call site, null fall-through), but hoisting the retag block from its original post-chord position (old line ~2468) to the earliest slot (inkInput.ts:2085) inverts precedence against the pendingKey==='g' chord resolvers at inkInput.ts:2138-2354, silently breaking gs/gd/gp/gr/gk/gK navigation while a rebase plan is active. This is a real, untested regression.
- ⛔ Unconditional rebase keys shadow gs/gd/gp/gr/gk/gK chords —
src/workstation/surfaces/rebase/input.ts:45— handleRebaseInput is now invoked at inkInput.ts:2085, ahead of thestate.pendingKey === 'g'chord resolvers at inkInput.ts:2138-2354 (gs→status, gd→diff, gp→PR, gr→reflog, gk/gK→config editors). Originally the retag block sat at old line ~2468, AFTER those resolvers, so g-chords won; none of these single-letter branches check pendingKey, so with a rebase plan active, pressing g then s/d/p/r/k/K now retags/reorders/opens-reword instead of navigating — and pendingKey is left dangling at 'g'. The sibling surfaces/bisect/input.ts:51 is invoked at inkInput.ts:2360 (after the chords) and additionally guards itsbbinding withpendingKey !== 'g'; this surface has neither protection. ⚠️ No test exercises the pendingKey='g' interaction —src/workstation/runtime/inkInput.test.ts:2342— Therebase plan surface keys (#1359)suite only exercises s/J/r/Enter/j/k with a fresh rebase state and never setspendingKey: 'g'first, so the chord regression merges green. A regression test that sets pendingKey='g' then presses s/d/p/r/k/K and asserts the navigation chord fires should accompany the fix.- 🧹 Prior LGTM review describes code not on this branch — The attached plan and an earlier review pass claim the g-chord regression was already fixed via a
pendingKey === 'g'bow-out plus new gs/gd/gk tests. The branch has a single commit (001252c) and no such guard or tests exist in the working tree, so that LGTM should not be relied on when deciding to merge.
There was a problem hiding this comment.
🔎 Agent re-review (sonnet, delta) — LGTM
REVIEW: LGTM
RESOLVES: full
The revise correctly guards the g-chord letters (p/s/d/r/k/K) with state.pendingKey !== 'g' so those keystrokes fall through to the existing chord resolvers instead of being swallowed by the rebase surface, and the pre-existing catch-all at inkInput.ts:2354 still clears a dangling pendingKey for non-chord letters like f/e. All rebase and inkInput tests pass unmodified.
There was a problem hiding this comment.
🔎 Agent review (sonnet→opus) — CONCERNS
REVIEW: CONCERNS
RESOLVES: full
The working tree already adds the pendingKey==='g' bow-out guard and 7 passing regression tests (gs/gd/gp/gr/gk/gK plus a bare-letter sanity), fully resolving both first-pass findings; the guard is correctly placed and mirrors the bisect precedent, and the rest of the extraction is behavior-preserving. The only remaining issue is that these changes are uncommitted/unpushed, so the PR on GitHub still ships the g-chord regression until they are committed.
1 concern — 1 inline on the diff
…ct-rebase-plan-handlers-into-surfac # Conflicts: # src/workstation/runtime/inkInput.ts
There was a problem hiding this comment.
🔎 Agent re-review (sonnet, delta) — LGTM
REVIEW: LGTM
RESOLVES: full
The revise committed the previously-uncommitted Esc discard-guard fix; the diff remains a clean, verbatim extraction of all four rebase blocks into handleRebaseInput with ordering and fall-through preserved, and jest/lint pass.
What
Consolidates the four
state.activeView === 'rebase' && state.rebasePlanbranches ingetLogInkInputEvents(inkInput.ts) — the Esc discard-guard, the J/K/p/s/f/d/e/r/Enter keymap, the up/kcursor branch, and the down/jcursor branch — into a singlehandleRebaseInput()function in a newsrc/workstation/surfaces/rebase/input.ts, called from one fall-through site at the position of the earliest (Esc) block.Why
Plane: OSS-1063
Sub-item 3/4 of OSS-950 (consolidating the monolithic ink input router into per-surface handler modules), mirroring the already-shipped
surfaces/bisect/input.tspattern.How
src/workstation/surfaces/rebase/input.tsexportshandleRebaseInput(state, inputValue, key, context): LogInkInputEvent[] | null, gated by a singleactiveView === 'rebase' && rebasePlanguard, with all four original blocks moved verbatim in their original internal order.inkInput.ts: single call site inserted at the former line-2088 position (const rebaseEvents = handleRebaseInput(...); if (rebaseEvents) return rebaseEvents), falling through to the rest of the router onnull. The three later blocks (keymap, up-cursor, down-cursor) are deleted from their old spots.Testing
npm run test:jest -- inkInput— 431/431 passed, including the rebase plan surface key cases, unmodifiednpm run lint— 0 errors (pre-existing unrelated warnings only)npm test— hit a sandbox heap-OOM on the unfiltered jest run (environment resource limit in this worktree, not a test failure); CI will confirmgrep -n "activeView === 'rebase'" src/workstation/runtime/inkInput.tsnow returns zero matches🤖 Generated by the harbor agent loop. Reviewed by a human before merge.