Skip to content

refactor(layers): extract session-runtime/ — ingest gets one grep-able home (#493 PR-1) - #501

Merged
Juliusolsson05 merged 2 commits into
mainfrom
refactor/layer-isolation
Jul 9, 2026
Merged

Juliusolsson05 merged 2 commits into
mainfrom
refactor/layer-isolation

Conversation

@Juliusolsson05

Copy link
Copy Markdown
Owner

Part 1 of 3 for #493 (plan: docs/superpowers/plans/2026-07-09-layer-isolation.md, committed on this branch — read it first; it documents the full four-way code read this stack is built on, including where the code disagrees with the issue sketch).

What

Pure moves (git mv, history preserved) + repo-wide import-specifier rewrites + one type-file split. Zero logic changes.

New folder src/renderer/src/session-runtime/ — the INGEST layer (channels → one clean per-session object):

Moved Was Stage
semantic/{foldEvent,helpers,summarize,streamPhaseMachine}.ts workspace/semantic/ 4–5 (semantic fold, phase machine)
ghosts.ts, mergedEntries.ts workspace/ 6 (ghost bridge)
entries.ts workspace/entries/utils.ts 3 (tool-index primitive)
claudeQueueReconstruction.ts, queueInvariants.ts, feedDebug.ts workspace/ 3 policy/bookkeeping (pure, ingest-only importers — unnamed by the issue, found by the sweep)
taskNotification.ts features/feed/lib/ pure transcript parsing (imports only Entry); ingest depends on it and must not import features/
state.ts workspace/workspaceState.ts the clean object: SessionRuntime + everything it's made of

SpotlightState/ReaderModeState/TileTabsState split OUT to workspace/types.ts — tile-tree view state, not runtime.

What deliberately did NOT move (plan D2)

  • useIpcSubscriptions.ts + workspace/hook/** — the ingress hook is IO wiring interleaved with pane-UI policy (unread badges, condition overlay mirrors, composer picker, bootstrap scroll gating). The layer boundary is the reducers it calls — all of which moved. The issue's acceptance ("session-runtime imports no UI") holds; a future ingress split is scoped in the plan §7 as the top follow-up.
  • providerSessionIdentity.ts — moved, then moved back: it governs SessionMeta (workspace's persisted session model), not SessionRuntime. Layer membership follows the data model a module governs.

The law, verified

grep -rn "@renderer/\(workspace\|features\|app-state\)\|from 'react'" src/renderer/src/session-runtime/   # → empty

Gates

  • tsc -b tsconfig.node.json + tsc --noEmit -p tsconfig.web.json — clean
  • NODE_ENV=test vitest run — 476/476 (the one failing suite, agent-voice-dictation hotkeyBinding.test.ts "no test suite found", pre-exists on main — verified)
  • vite build --config src/remote-client/vite.config.ts — OK (the phone client deep-imports the moved reducers; electron-vite build does not cover it)

Stacked: PR-2 (input contract) and PR-3 (view-seam flip) follow on top.

🤖 Generated with Claude Code

Juliusolsson05 and others added 2 commits July 9, 2026 09:49
…, with deviations

Full four-way read of ingest/decide/render + build wiring; plan documents
where the code disagrees with the issue sketch (type-only back-edges,
already-clean feed direction, groupSemanticActivity PR-2/PR-3 conflict,
ingress UI-entanglement) and frames the stack inside the app-wide
modularity goal.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…e grep-able home (#493 PR-1)

Pure moves + import-specifier rewrites + one type-file split. Zero logic
changes; behavior-preserving by construction.

Moved into src/renderer/src/session-runtime/ (git mv, history preserved):
- semantic/{foldEvent,helpers,summarize,streamPhaseMachine} — stages 4-5
- ghosts.ts, mergedEntries.ts — stage 6 (ghost bridge + merge selector)
- entries.ts (was workspace/entries/utils.ts) — tool-index ingest primitive
- claudeQueueReconstruction.ts, queueInvariants.ts, feedDebug.ts — pure
  stage-3 policy/bookkeeping the issue didn't name but the sweep proved
  are ingest-only
- taskNotification.ts (was features/feed/lib/) — pure transcript parsing
  (imports only Entry); claudeQueueReconstruction depends on it, and the
  ingest layer must not import features/
- state.ts (was workspace/workspaceState.ts) — SessionRuntime + everything
  the runtime object is made of. Layout-view states (Spotlight/Reader/
  TileTabs) split OUT to workspace/types.ts: they are tile-tree view
  state, not runtime.

Deliberately NOT moved:
- useIpcSubscriptions.ts + workspace/hook/** — the ingress hook is IO
  wiring interleaved with pane-UI policy (unread badges, condition
  mirrors, composer picker); the layer boundary is the reducers it
  calls, all of which did move (plan D2).
- providerSessionIdentity.ts — initially moved, then moved back: it
  governs SessionMeta (workspace's persisted session model), not
  SessionRuntime, so its layer home follows its data model.

Dependency law now holds and is grep-verifiable:
  grep -rn "@renderer/(workspace|features|app-state)|from 'react'" \
    src/renderer/src/session-runtime/   # -> empty

foldEvent's SessionKind import now comes from @shared/types/providerKind
(the source of truth) instead of workspace/types' re-export.
workspaceStore.ts keeps serving its ~45 useWorkspace importers; only its
re-export sources were repointed.

Gates: tsc node+web clean, vitest 476/476 (the one failing suite —
agent-voice-dictation hotkeyBinding "no test suite" — pre-exists on
main), remote-client vite build OK (it deep-imports the moved reducers).

Plan: docs/superpowers/plans/2026-07-09-layer-isolation.md

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
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