Skip to content

Commit 8ddd816

Browse files
authored
Merge pull request #13 from SolidKeyAB/feat/format-adapters
Docs: LOGAN v2 architecture (modular reusable core + migration path)
2 parents 7c9aeee + 42bf3cb commit 8ddd816

1 file changed

Lines changed: 182 additions & 0 deletions

File tree

docs/ARCHITECTURE_V2.md

Lines changed: 182 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,182 @@
1+
# LOGAN v2 — Modular, Reusable, High-Performance Architecture
2+
3+
A target architecture and a **safe, incremental** migration path. The goal: turn LOGAN
4+
from a working-but-monolithic Electron app into a layered system whose **editor/viewer
5+
core is reusable** (logs today, code/diff/nexum tomorrow, web later) without a risky
6+
big-bang rewrite.
7+
8+
This is a proposal. Nothing here requires throwing away working code — every phase below
9+
is shippable on its own with tests green.
10+
11+
---
12+
13+
## 1. Principles
14+
15+
1. **One core, many surfaces.** A log line, a code line, and a diff hunk are the same
16+
thing: *addressable text with decorations*. Build that once; specialize on top.
17+
2. **Depend on ports, not platforms.** Features talk to interfaces (Host, Document,
18+
CommandBus), never directly to Electron IPC. The platform becomes swappable → web.
19+
3. **One contract for UI and agent.** Anything the UI can do, the MCP agent can do,
20+
because both call the *same* command bus. No parallel code paths to drift.
21+
4. **Performance is structural, not heroic.** Never load a whole file; virtualize
22+
rendering; compute heavy decorations off the main thread; cancel everything.
23+
5. **Features are plugins.** Each feature is self-contained: it contributes panels,
24+
commands, decorations, and (optionally) MCP tools. Toggle on/off without surgery.
25+
26+
---
27+
28+
## 2. Where we are today (honest assessment)
29+
30+
| Area | Today | Pain |
31+
|------|-------|------|
32+
| Renderer | `src/renderer/renderer.ts`, ~7000 lines, one file, inline types, global `state`/`elements` | Hard to reuse, test, or port; features interleaved |
33+
| Platform coupling | Renderer calls `window.api.*` (Electron IPC) everywhere | Blocks web; ties UI to Electron |
34+
| Data paths | IPC (renderer↔main) **and** HTTP (`api-server.ts` for the agent) | Some duplicated handlers (e.g. trends exist in both) |
35+
| Source model | `sourceAdapter.ts` normalizes (text/JSONL/protobuf/MF4) | Downstream still assumes "log lines", not a generic Document |
36+
| Engines | `fileHandler` (line index), `analyzers`, `trendEngine`, `recipes` | Good! Already modular and mostly platform-agnostic |
37+
| Bridge | `api-server.ts` (HTTP) + `mcp-server` (stdio) | Already a clean service seam — underused by the UI |
38+
39+
**Good news:** the *backend* is already fairly modular (FileHandler, analyzers, trendEngine,
40+
recipes are clean). The debt is concentrated in the renderer monolith and the
41+
platform/transport coupling. That's exactly what the phases below target.
42+
43+
---
44+
45+
## 3. Target architecture (layers)
46+
47+
```
48+
┌──────────────────────────────────────────────────────────────┐
49+
│ L4 WORKBENCH / SHELL (UX) │
50+
│ activity bar · panels · tabs · command palette · status │
51+
│ composes feature contributions; owns layout + theming │
52+
├──────────────────────────────────────────────────────────────┤
53+
│ L3 FEATURE MODULES (plugins — each self-contained) │
54+
│ log: levels·filter·analysis·trends·time-gaps·baselines· │
55+
│ live·investigate(triage) │
56+
│ code (future): syntax·symbols·git-diff·review │
57+
│ each contributes: panels + commands + decorations + tools │
58+
├──────────────────────────────────────────────────────────────┤
59+
│ L2 EDITOR / VIEWER CORE ★ the reusable heart ★ │
60+
│ virtualized text surface · gutter · minimap · selection │
61+
│ DECORATION API (highlights/annotations/findings/bookmarks │
62+
│ are all "decorations") · commands · word-wrap · zoom │
63+
│ knows nothing about logs or code — just Document+Decoration│
64+
├──────────────────────────────────────────────────────────────┤
65+
│ L1 DOCUMENT MODEL │
66+
│ Document = line-addressable text + metadata (cols, level, │
67+
│ timestamp, language). Built from SourceAdapter output. │
68+
│ O(1) random access; search index; chunked/lazy │
69+
├──────────────────────────────────────────────────────────────┤
70+
│ L0 HOST PORT + COMMAND BUS (the swappable platform seam) │
71+
│ Host: files, storage, processes, dialogs │
72+
│ ElectronHost (IPC/Node) | WebHost (HTTP/fetch) │
73+
│ CommandBus: one typed contract; transports = IPC/HTTP/ │
74+
│ in-proc; UI + MCP agent both call it │
75+
└──────────────────────────────────────────────────────────────┘
76+
```
77+
78+
### The key idea: one Command Bus for UI **and** agent
79+
80+
Today there are two ways to "search": the renderer's `window.api.search` (IPC) and the
81+
agent's `POST /api/search` (HTTP). Define each operation **once** as a typed command:
82+
83+
```ts
84+
// shared/commands.ts — the single source of truth
85+
interface Commands {
86+
'doc.search': (q: SearchQuery) => SearchResult;
87+
'doc.getLines': (r: LineRange) => Line[];
88+
'analyze.run': (o: AnalyzeOpts) => AnalysisResult;
89+
'triage.recipe':(o: RecipeOptions)=> RecipeResult;
90+
// …every capability, once
91+
}
92+
```
93+
94+
Then transports just *carry* commands: Electron IPC, localhost HTTP (agent), and direct
95+
in-process calls all implement the same `CommandBus`. The MCP server becomes a thin
96+
adapter over the bus. Result: **the agent can do exactly what the UI can, automatically**,
97+
and the duplicated trend/recipe handlers collapse into one. (The triage recipe engine
98+
already previews this — it's written against an abstract `ApiCall`, so the UI runs it via
99+
localhost and the agent runs it via MCP, *same engine*.)
100+
101+
### The Decoration model unifies the visual language
102+
103+
Highlights, annotations, agent findings, bookmarks, search hits, filter dimming — today
104+
each is bespoke. In L2 they're all **decorations** on a line/range with a style + gutter
105+
marker + minimap marker + optional click action. One model →
106+
consistent UX, one render path, and new feature markers are free.
107+
108+
---
109+
110+
## 4. Performance strategy
111+
112+
- **Keep the line-offset index** (`fileHandler`) — never read the whole file. This is
113+
already LOGAN's superpower (1M-line random access); formalize it in L1.
114+
- **Virtualized viewport** (already in the renderer) becomes the L2 core; only visible
115+
lines + a small overscan are in the DOM.
116+
- **Off-main-thread decorations**: syntax tokenizing and large highlight/finding sets
117+
computed in a Web Worker (renderer) / worker thread (main), streamed in as ranges.
118+
- **Cancellation everywhere**: the existing `*Signal = {cancelled}` pattern becomes a
119+
standard `AbortSignal` threaded through every command.
120+
- **Web path**: `WebHost` uses HTTP range requests against a server that holds the index;
121+
the viewer code doesn't change — it just asks the Document for line ranges.
122+
123+
---
124+
125+
## 5. UX strategy (architect + UX hats)
126+
127+
- **Command palette** (Ctrl/Cmd-P) as the universal entry point. Every feature command is
128+
discoverable and keyboard-driven — the single best anti-YAGNI move (features stop
129+
hiding in panels nobody opens). The Investigate symptoms, Trends cells, baselines, etc.
130+
all register here.
131+
- **One pinning model.** Agent findings and user annotations are the same decoration, so
132+
"the agent pinned this / I pinned this" look and behave identically (already converging
133+
via `logan_report_finding` + the Investigate panel).
134+
- **Feature toggle = plugin manager.** The existing Features gear becomes enable/disable
135+
for L3 modules — the app you see is the features you turned on.
136+
- **Surfaces, not modes.** Logs, code, and diff are just different Document types in the
137+
same shell; switching is opening a different document, not a different app.
138+
139+
---
140+
141+
## 6. Migration path — incremental, each phase shippable
142+
143+
No big-bang. Order chosen so the highest-value, lowest-risk work comes first and nothing
144+
breaks between phases.
145+
146+
| Phase | What | Risk | Payoff |
147+
|-------|------|------|--------|
148+
| **0. Modularize the renderer** | Carve `renderer.ts` into ES modules **by feature** (viewer, search, filter, analysis, trends, investigate, live…), sharing today's `state`/`elements` via explicit imports. Behavior-preserving. | Low (mechanical) | Huge readability/testability win; makes every later phase tractable |
149+
| **1. Host port** | Wrap `window.api` behind a `Host` interface; renderer depends on `Host`, not Electron. | Low–med | Unlocks web; isolates platform |
150+
| **2. Editor/Viewer core + Decoration API** | Extract the virtualized viewer as a standalone module; migrate highlights/annotations/findings/bookmarks to one decoration model. | Med | The reusable heart; consistent UX |
151+
| **3. Unify the Command Bus** | Define typed commands once; route IPC + HTTP + MCP through them; delete duplicated handlers. | Med | Agent = UI parity; kills drift/dup |
152+
| **4. Document model** | Formalize L1 around `sourceAdapter`; features become Document-based, not log-line-based. | Med | Code/diff become "just another Document" |
153+
| **5. Package the core** | Ship L0–L2 as a reusable lib consumed by LOGAN (logs) **and** a nexum code-view surface (and a future web LOGAN). | Med | The original goal: reuse across nexum |
154+
155+
**Recommended first step: Phase 0**, and within it a *thin vertical slice* as proof —
156+
e.g. extract the Investigate feature (it's new, self-contained, and already engine-backed)
157+
into its own module + a `Host`-routed call. That validates the module boundaries and the
158+
Host seam on one feature before touching the rest. Small PR, tests green, reversible.
159+
160+
---
161+
162+
## 7. What this buys nexum
163+
164+
- The **editor/viewer core + decoration + command bus** (L0–L2) is the "annotate-anything"
165+
package the code-viewing infra needs. LOGAN's logs become *one consumer* of it; a nexum
166+
code-review surface becomes another, sharing the agent-pins-findings loop verbatim.
167+
- The **web port** (separate, larger effort) reduces to writing a `WebHost` + serving the
168+
same L2–L4 — because by Phase 3 nothing in the UI talks to Electron directly.
169+
170+
---
171+
172+
## 8. Risk & recommendation
173+
174+
This is **weeks of work across phases, not one PR** — and a working app is being
175+
refactored, so discipline matters. Recommendation:
176+
177+
1. Approve the layering + the Command Bus idea as the north star.
178+
2. Start with **Phase 0 modularization** + the Investigate vertical slice as proof.
179+
3. Re-evaluate after Phase 0: the readability win alone may reorder priorities.
180+
181+
Do **not** attempt L2/L3 extraction before Phase 0 — moving features out of the monolith
182+
is only safe once the monolith has seams.

0 commit comments

Comments
 (0)