Skip to content

feat: Phase 2 — persistence, boundary dispatcher, enhanced renderer#2

Merged
KooshaPari merged 1 commit into
mainfrom
helios-phase2
Feb 28, 2026
Merged

feat: Phase 2 — persistence, boundary dispatcher, enhanced renderer#2
KooshaPari merged 1 commit into
mainfrom
helios-phase2

Conversation

@KooshaPari

@KooshaPari KooshaPari commented Feb 27, 2026

Copy link
Copy Markdown
Owner

Summary

  • GoldfishDB schema v8 with helios_settings, helios_lanes, helios_audit collections
  • Real persistence adapter (CRUD operations via GoldfishDB) replacing Phase 1 type stubs
  • Boundary dispatcher integration in bus-RPC bridge with audit trail on lifecycle commands
  • Enhanced renderer: persisted lanes table, audit trail display, diagnostics panel
  • New RPC endpoints: heliosGetLanes, heliosGetAudit

Test plan

  • HELIOS_SURFACE_EDITOR=false bun run build:dev boots with helios renderer
  • Lane create → session attach → terminal spawn persists to GoldfishDB
  • Session tab shows persisted lanes table
  • Right rail shows audit trail entries
  • Refresh State button reloads persisted data
  • Existing co(lab) mode (HELIOS_SURFACE_EDITOR=true) unaffected

🤖 Generated with Claude Code

Summary by CodeRabbit

Release Notes

  • New Features
    • Added comprehensive audit trail tracking to record workspace activities, including timestamps, actions, and relevant context.
    • Introduced lane persistence to maintain workspace lane state and configuration across sessions.
    • Added settings management support for workspace preferences.
    • Enhanced UI with new panels displaying recent lanes and audit history.

GoldfishDB:
- Add schema v8 with helios_settings, helios_lanes, helios_audit collections
- Wire persistence adapter with upsertLane, writeAuditEntry, loadSettings
- Settings loaded on bootstrap, lanes persisted after lifecycle commands

Bridge:
- Route commands through boundary dispatcher (local_control, tool_interop, a2a)
- tool_interop and agent_delegation return stub errors (Phase 3)
- Audit trail written on every lifecycle command

Renderer:
- Session tab shows persisted lanes table (id, transport, session, updated)
- Right rail shows audit trail from GoldfishDB
- Persisted data loaded on startup and refresh
- New RPC endpoints: heliosGetLanes, heliosGetAudit

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@gemini-code-assist

Copy link
Copy Markdown

Warning

You have reached your daily quota limit. Please wait up to 24 hours and I will start processing your requests again!

@coderabbitai

coderabbitai Bot commented Feb 27, 2026

Copy link
Copy Markdown
📝 Walkthrough

Walkthrough

This pull request introduces a comprehensive persistence layer for Helios, enabling lanes and audit trails to be stored in the database. It updates the RPC bridge to integrate persistence operations, extends the bootstrap process to load settings, adds database schema definitions for Helios collections, and expands the renderer UI to display persisted lanes and audit entries.

Changes

Cohort / File(s) Summary
Persistence API
src/helios/bridge/persistence.ts
Replaces legacy document type exports with a new operation-based API: adds loadSettings, saveSettings, upsertLane, getLanesForWorkspace, writeAuditEntry, and getRecentAudit functions. Introduces HeliosSettings and PersistedLane types.
Database Schema
src/main/goldfishdb/schema/add_helios_collections_8.ts, src/main/goldfishdb/db.ts
Adds schema8 defining three new Helios collections (helios_settings, helios_lanes, helios_audit) with appropriate fields and constraints. Activates schema8 in the database configuration.
Bootstrap & Runtime
src/helios/bridge/helios-main-bootstrap.ts
Loads HeliosSettings during bootstrap and exposes settings on HeliosRuntime. Adds getHeliosRuntime() public function to retrieve the runtime instance.
RPC Bridge
src/helios/bridge/bus-rpc-bridge.ts
Introduces boundary dispatcher for command routing. Adds persistence hooks (upsertLane, writeAuditEntry) after lane.create, session.attach, and terminal.spawn commands. Broadcasts dispatcher-derived state after each command.
RPC API Surface
src/main/index.ts, src/renderers/ivde/rpc.ts
Adds heliosGetLanes and heliosGetAudit RPC methods to fetch workspace lanes and recent audit entries. Wires methods in main process and declares signatures in renderer RPC schema.
Renderer UI
src/renderers/helios/index.html, src/renderers/helios/index.ts
Adds CSS styling for lane table with columns for laneId, transport, session, and lastUpdated. Introduces loadPersistedData function to fetch lanes and audits via RPC. Extends doRefreshState to load persisted data and render lane/audit tables in the UI.

Sequence Diagram

sequenceDiagram
    participant Renderer as Renderer<br/>(Helios UI)
    participant Main as Main Process<br/>(index.ts)
    participant Bridge as RPC Bridge<br/>(bus-rpc-bridge.ts)
    participant Persistence as Persistence<br/>(persistence.ts)
    participant DB as Database<br/>(GoldfishDB)

    Renderer->>Main: lane.create() via RPC
    Main->>Bridge: Command received
    Bridge->>Persistence: upsertLane()
    Persistence->>DB: Store lane record
    DB-->>Persistence: Confirm
    Bridge->>Persistence: writeAuditEntry()
    Persistence->>DB: Store audit entry
    DB-->>Persistence: Confirm
    Bridge-->>Main: Updated state
    Main-->>Renderer: State broadcast

    Renderer->>Main: heliosGetLanes() RPC
    Main->>Persistence: getLanesForWorkspace()
    Persistence->>DB: Query lanes
    DB-->>Persistence: Lane records
    Persistence-->>Main: Lanes array
    Main-->>Renderer: Render lane table

    Renderer->>Main: heliosGetAudit() RPC
    Main->>Persistence: getRecentAudit(50)
    Persistence->>DB: Query audit
    DB-->>Persistence: Audit entries
    Persistence-->>Main: Audit array
    Main-->>Renderer: Render audit trail
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Poem

🐰 Hopping through persistence, lanes now stay,
Audit trails whisper what happened today,
Settings remembered, lanes stored with care,
RPC calls dancing through database air,
A bridge full of purpose—Helios takes flight!

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 41.67% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main changes: introducing persistence (Phase 2), a boundary dispatcher, and renderer enhancements.

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

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch helios-phase2

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@coderabbitai coderabbitai 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.

Actionable comments posted: 7

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/helios/bridge/bus-rpc-bridge.ts`:
- Around line 102-109: The audit write using writeAuditEntry currently runs
unguarded and can cause handleRequest to reject if the DB write fails; wrap the
call to writeAuditEntry (the block building action: method, workspaceId, laneId,
sessionId from result?.session_id, and detail using
decision.boundary/decision.adapter and response.status) in a try/catch so any
thrown error is caught and swallowed or logged (via processLogger/errorLogger)
without propagating, ensuring the lifecycle command returns the original
successful result even if the audit write fails.

In `@src/helios/bridge/persistence.ts`:
- Around line 68-70: The current lookup only matches by laneId and can overwrite
lanes across workspaces; change the existence check to scope by workspaceId as
well. Update the query/find used around db.collection("helios_lanes").query()
and the existing assignment (existing = data.find(...)) to require both d.laneId
=== lane.laneId && d.workspaceId === lane.workspaceId (or add an equivalent
filter in the collection query) so upserts only affect records in the same
workspace; ensure any subsequent insert/update also sets/uses lane.workspaceId
consistently.
- Around line 129-140: getRecentAudit currently queries all rows from
db.collection("helios_audit") and returns a global top-N, causing
cross-workspace audit leakage; change getRecentAudit to accept a workspaceId
parameter (or require one) and filter the query results by workspaceId before
sorting and slicing, e.g. filter the array from
db.collection("helios_audit").query() for entries where workspaceId matches the
provided value, then sort by timestamp and slice to limit; update any callers of
getRecentAudit to pass the appropriate workspaceId so callers retrieve only that
workspace's audits.

In `@src/renderers/helios/index.ts`:
- Around line 191-200: Silent catches in loadPersistedData are hiding failures;
replace the empty catch blocks with error logging that includes context and the
caught error so developers can diagnose issues: when awaiting
electrobun.rpc?.request.heliosGetLanes() and
electrobun.rpc?.request.heliosGetAudit(), catch errors and log descriptive
messages referencing the operation (e.g., "failed to load lanes" and "failed to
load audit") along with the error object before continuing, and keep the
existing behavior of only assigning to persistedLanes and auditEntries when the
responses are arrays.
- Around line 319-324: The loop over auditEntries uses unguarded
entry.timestamp.slice and entry.detail.slice which will throw if those
properties are missing; update the loop handling in the block that iterates
auditEntries (the for (const entry of auditEntries.slice(0, 10)) loop) to
defensively access these fields—e.g., coerce to a safe string before slicing or
check typeof before calling slice (use something like const ts =
(entry.timestamp || '').slice(11,19) and const detail = (entry.detail ||
'').slice(0,40) or equivalent guarded checks) and then use ts and detail when
building the elements so missing values won’t cause exceptions.
- Around line 286-294: The loop over persistedLanes calls lane.laneId.slice(...)
and lane.lastUpdated.slice(...), which can throw if those fields are
null/undefined; update the rendering in src/renderers/helios/index.ts to
defensively access these properties (e.g., coerce to a safe string or use
nullish checks) before slicing and provide a safe fallback display (like "—" or
an empty string) so malformed RPC data won't cause a TypeError; apply this to
the code that builds row elements inside the persistedLanes iteration
(references: persistedLanes, lane.laneId, lane.lastUpdated, row.appendChild
calls).
- Around line 173-180: The PersistedLane type in this renderer is missing fields
returned by the backend; update the renderer's PersistedLane type (or import the
backend definition) so it includes the id and workspaceId fields that
heliosGetLanes returns (the backend type is defined in
src/helios/bridge/persistence.ts). Modify the PersistedLane declaration used in
this file (or replace it with an import of the backend PersistedLane type) to
include id: string and workspaceId: string (and ensure sessionId/terminalId
types still match).

ℹ️ Review info

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 902e403 and 6977573.

📒 Files selected for processing (9)
  • src/helios/bridge/bus-rpc-bridge.ts
  • src/helios/bridge/helios-main-bootstrap.ts
  • src/helios/bridge/persistence.ts
  • src/main/goldfishdb/db.ts
  • src/main/goldfishdb/schema/add_helios_collections_8.ts
  • src/main/index.ts
  • src/renderers/helios/index.html
  • src/renderers/helios/index.ts
  • src/renderers/ivde/rpc.ts
📜 Review details
🧰 Additional context used
🧬 Code graph analysis (6)
src/renderers/helios/index.ts (2)
src/helios/bridge/persistence.ts (1)
  • PersistedLane (56-65)
src/renderers/ivde/init.ts (1)
  • electrobun (662-662)
src/main/index.ts (1)
src/helios/bridge/persistence.ts (2)
  • getLanesForWorkspace (94-108)
  • getRecentAudit (129-149)
src/helios/bridge/bus-rpc-bridge.ts (4)
src/helios/runtime/protocol/bus.ts (1)
  • InMemoryLocalBus (51-244)
src/helios/runtime/protocol/boundary_adapter.ts (2)
  • createBoundaryDispatcher (90-138)
  • getBoundaryDispatchDecision (77-88)
src/helios/bridge/persistence.ts (2)
  • upsertLane (67-92)
  • writeAuditEntry (112-127)
src/main/workspaceWindows.ts (1)
  • broadcastToAllWindowsInWorkspace (32-44)
src/main/goldfishdb/db.ts (1)
src/main/goldfishdb/schema/add_helios_collections_8.ts (1)
  • schema8 (15-140)
src/helios/bridge/persistence.ts (1)
src/helios/desktop/settings.ts (1)
  • DEFAULT_SETTINGS (12-15)
src/helios/bridge/helios-main-bootstrap.ts (2)
src/helios/runtime/protocol/bus.ts (1)
  • InMemoryLocalBus (51-244)
src/helios/bridge/persistence.ts (2)
  • HeliosSettings (12-15)
  • loadSettings (24-40)
🔇 Additional comments (2)
src/renderers/helios/index.ts (2)

166-169: LGTM!

Extending doRefreshState to also reload persisted data is appropriate for ensuring the UI reflects the latest state from the database.


360-364: LGTM!

The double-render pattern is appropriate here: it shows the UI shell immediately while persisted data loads asynchronously, then updates with the fetched data.

Comment on lines +102 to +109
// Audit trail
writeAuditEntry({
action: method,
workspaceId,
laneId,
sessionId: (result?.session_id as string) ?? null,
detail: `${method} via ${decision.boundary}/${decision.adapter} — ${response.status}`,
});

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Don’t let audit-write failures fail successful lifecycle commands.

Line 103 writes audit outside a guard. A DB write error can reject handleRequest even when the lifecycle command itself succeeded.

🔧 Proposed fix
-        // Audit trail
-        writeAuditEntry({
-          action: method,
-          workspaceId,
-          laneId,
-          sessionId: (result?.session_id as string) ?? null,
-          detail: `${method} via ${decision.boundary}/${decision.adapter} — ${response.status}`,
-        });
+        // Audit trail (best-effort; must not fail command path)
+        try {
+          writeAuditEntry({
+            action: method,
+            workspaceId,
+            laneId,
+            sessionId: (result?.session_id as string) ?? null,
+            detail: `${method} via ${decision.boundary}/${decision.adapter} — ${response.status}`,
+          });
+        } catch {
+          // Don't fail the command if audit persistence fails
+        }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// Audit trail
writeAuditEntry({
action: method,
workspaceId,
laneId,
sessionId: (result?.session_id as string) ?? null,
detail: `${method} via ${decision.boundary}/${decision.adapter}${response.status}`,
});
// Audit trail (best-effort; must not fail command path)
try {
writeAuditEntry({
action: method,
workspaceId,
laneId,
sessionId: (result?.session_id as string) ?? null,
detail: `${method} via ${decision.boundary}/${decision.adapter}${response.status}`,
});
} catch {
// Don't fail the command if audit persistence fails
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/helios/bridge/bus-rpc-bridge.ts` around lines 102 - 109, The audit write
using writeAuditEntry currently runs unguarded and can cause handleRequest to
reject if the DB write fails; wrap the call to writeAuditEntry (the block
building action: method, workspaceId, laneId, sessionId from result?.session_id,
and detail using decision.boundary/decision.adapter and response.status) in a
try/catch so any thrown error is caught and swallowed or logged (via
processLogger/errorLogger) without propagating, ensuring the lifecycle command
returns the original successful result even if the audit write fails.

Comment on lines +68 to +70
const { data } = db.collection("helios_lanes").query();
const existing = data.find((d) => d.laneId === lane.laneId);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Scope lane upsert by workspaceId to prevent cross-workspace overwrite.

Line 69 matches existing rows by laneId only. If two workspaces reuse the same lane id, one workspace will overwrite the other.

🔧 Proposed fix
 export function upsertLane(lane: Omit<PersistedLane, "id">): PersistedLane {
-  const { data } = db.collection("helios_lanes").query();
-  const existing = data.find((d) => d.laneId === lane.laneId);
+  const { data } = db.collection("helios_lanes").query({
+    where: (d) => d.workspaceId === lane.workspaceId && d.laneId === lane.laneId,
+  });
+  const existing = data[0];
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const { data } = db.collection("helios_lanes").query();
const existing = data.find((d) => d.laneId === lane.laneId);
const { data } = db.collection("helios_lanes").query({
where: (d) => d.workspaceId === lane.workspaceId && d.laneId === lane.laneId,
});
const existing = data[0];
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/helios/bridge/persistence.ts` around lines 68 - 70, The current lookup
only matches by laneId and can overwrite lanes across workspaces; change the
existence check to scope by workspaceId as well. Update the query/find used
around db.collection("helios_lanes").query() and the existing assignment
(existing = data.find(...)) to require both d.laneId === lane.laneId &&
d.workspaceId === lane.workspaceId (or add an equivalent filter in the
collection query) so upserts only affect records in the same workspace; ensure
any subsequent insert/update also sets/uses lane.workspaceId consistently.

Comment on lines +129 to +140
export function getRecentAudit(limit = 50): Array<{
timestamp: string;
action: string;
workspaceId: string;
laneId: string | null;
sessionId: string | null;
detail: string;
};

/** Collection names for use with GoldfishDB */
export const HELIOS_COLLECTIONS = {
settings: "helios_settings",
workspaces: "helios_workspaces",
lanes: "helios_lanes",
audit: "helios_audit",
} as const;
}> {
const { data } = db.collection("helios_audit").query();
return data
.sort((a, b) => b.timestamp.localeCompare(a.timestamp))
.slice(0, limit)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Filter audit reads by workspace to avoid cross-workspace audit leakage.

Lines 137-140 read/sort all audit rows and return a global top-50. That leaks other workspaces’ lifecycle activity.

🔧 Proposed fix
-export function getRecentAudit(limit = 50): Array<{
+export function getRecentAudit(workspaceId: string, limit = 50): Array<{
   timestamp: string;
   action: string;
   workspaceId: string;
   laneId: string | null;
   sessionId: string | null;
   detail: string;
 }> {
-  const { data } = db.collection("helios_audit").query();
-  return data
+  const { data } = db.collection("helios_audit").query({
+    where: (d) => d.workspaceId === workspaceId,
+  });
+  return [...data]
     .sort((a, b) => b.timestamp.localeCompare(a.timestamp))
     .slice(0, limit)
     .map((d) => ({
       timestamp: d.timestamp,
       action: d.action,
       workspaceId: d.workspaceId,
       laneId: d.laneId ?? null,
       sessionId: d.sessionId ?? null,
       detail: d.detail,
     }));
 }

Also update caller:

- return getRecentAudit(50);
+ return getRecentAudit(workspaceId, 50);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/helios/bridge/persistence.ts` around lines 129 - 140, getRecentAudit
currently queries all rows from db.collection("helios_audit") and returns a
global top-N, causing cross-workspace audit leakage; change getRecentAudit to
accept a workspaceId parameter (or require one) and filter the query results by
workspaceId before sorting and slicing, e.g. filter the array from
db.collection("helios_audit").query() for entries where workspaceId matches the
provided value, then sort by timestamp and slice to limit; update any callers of
getRecentAudit to pass the appropriate workspaceId so callers retrieve only that
workspace's audits.

Comment on lines +173 to +180
type PersistedLane = {
laneId: string;
state: string;
transport: string;
sessionId: string | null;
terminalId: string | null;
lastUpdated: string;
};

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

# Check the renderer's PersistedLane type definition
cat -n src/renderers/helios/index.ts | sed -n '170,185p'

Repository: KooshaPari/colab

Length of output: 472


🏁 Script executed:

# Check the backend PersistedLane type definition
cat -n src/helios/bridge/persistence.ts | sed -n '50,70p'

Repository: KooshaPari/colab

Length of output: 687


🏁 Script executed:

# Search for heliosGetLanes RPC endpoint to understand data flow
rg -n 'heliosGetLanes' --type ts -B 2 -A 10

Repository: KooshaPari/colab

Length of output: 2138


🏁 Script executed:

# Search for any type definitions or interfaces related to PersistedLane across codebase
rg -n 'type PersistedLane|interface PersistedLane' --type ts

Repository: KooshaPari/colab

Length of output: 182


🏁 Script executed:

# Find getLanesForWorkspace implementation to see what it returns
rg -n 'function getLanesForWorkspace|const getLanesForWorkspace' --type ts -A 8

Repository: KooshaPari/colab

Length of output: 716


🏁 Script executed:

# Also search for any return statements in getLanesForWorkspace
rg -n 'getLanesForWorkspace' --type ts -B 2 -A 12 | head -60

Repository: KooshaPari/colab

Length of output: 2719


Renderer PersistedLane type is missing fields returned by the backend.

The heliosGetLanes RPC endpoint returns the full backend PersistedLane type from src/helios/bridge/persistence.ts (which includes id and workspaceId fields), but the renderer's type definition at lines 173-180 omits these fields. Update the type to match the actual data being received, or import the type from the backend definition to keep them in sync.

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

In `@src/renderers/helios/index.ts` around lines 173 - 180, The PersistedLane type
in this renderer is missing fields returned by the backend; update the
renderer's PersistedLane type (or import the backend definition) so it includes
the id and workspaceId fields that heliosGetLanes returns (the backend type is
defined in src/helios/bridge/persistence.ts). Modify the PersistedLane
declaration used in this file (or replace it with an import of the backend
PersistedLane type) to include id: string and workspaceId: string (and ensure
sessionId/terminalId types still match).

Comment on lines +191 to +200
async function loadPersistedData() {
try {
const lanes = await electrobun.rpc?.request.heliosGetLanes();
if (Array.isArray(lanes)) persistedLanes = lanes;
} catch { /* ignore */ }
try {
const audit = await electrobun.rpc?.request.heliosGetAudit();
if (Array.isArray(audit)) auditEntries = audit.slice(0, 20);
} catch { /* ignore */ }
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Silent error swallowing hides failures.

Catching exceptions with empty blocks makes debugging difficult and provides no feedback when data fails to load. At minimum, log the error for developer visibility.

🛠️ Proposed fix
 async function loadPersistedData() {
   try {
     const lanes = await electrobun.rpc?.request.heliosGetLanes();
     if (Array.isArray(lanes)) persistedLanes = lanes;
-  } catch { /* ignore */ }
+  } catch (e) {
+    console.warn("Failed to load persisted lanes:", e);
+  }
   try {
     const audit = await electrobun.rpc?.request.heliosGetAudit();
     if (Array.isArray(audit)) auditEntries = audit.slice(0, 20);
-  } catch { /* ignore */ }
+  } catch (e) {
+    console.warn("Failed to load audit entries:", e);
+  }
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
async function loadPersistedData() {
try {
const lanes = await electrobun.rpc?.request.heliosGetLanes();
if (Array.isArray(lanes)) persistedLanes = lanes;
} catch { /* ignore */ }
try {
const audit = await electrobun.rpc?.request.heliosGetAudit();
if (Array.isArray(audit)) auditEntries = audit.slice(0, 20);
} catch { /* ignore */ }
}
async function loadPersistedData() {
try {
const lanes = await electrobun.rpc?.request.heliosGetLanes();
if (Array.isArray(lanes)) persistedLanes = lanes;
} catch (e) {
console.warn("Failed to load persisted lanes:", e);
}
try {
const audit = await electrobun.rpc?.request.heliosGetAudit();
if (Array.isArray(audit)) auditEntries = audit.slice(0, 20);
} catch (e) {
console.warn("Failed to load audit entries:", e);
}
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/renderers/helios/index.ts` around lines 191 - 200, Silent catches in
loadPersistedData are hiding failures; replace the empty catch blocks with error
logging that includes context and the caught error so developers can diagnose
issues: when awaiting electrobun.rpc?.request.heliosGetLanes() and
electrobun.rpc?.request.heliosGetAudit(), catch errors and log descriptive
messages referencing the operation (e.g., "failed to load lanes" and "failed to
load audit") along with the error object before continuing, and keep the
existing behavior of only assigning to persistedLanes and auditEntries when the
responses are arrays.

Comment on lines +286 to +294
for (const lane of persistedLanes) {
const row = el("div", "lane-row");
row.appendChild(el("span", "lane-id", lane.laneId.slice(0, 12)));
row.appendChild(el("span", "lane-transport", lane.transport));
row.appendChild(el("span", "lane-session", lane.sessionId ? lane.sessionId.slice(0, 12) : "—"));
row.appendChild(el("span", "lane-updated", lane.lastUpdated.slice(11, 19)));
table.appendChild(row);
}
center.appendChild(table);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Unguarded property access may throw on malformed data.

lane.laneId.slice() and lane.lastUpdated.slice() will throw TypeError if these properties are undefined or null. Since data comes from an external RPC source, add defensive checks.

🛠️ Proposed fix with defensive access
       for (const lane of persistedLanes) {
         const row = el("div", "lane-row");
-        row.appendChild(el("span", "lane-id", lane.laneId.slice(0, 12)));
-        row.appendChild(el("span", "lane-transport", lane.transport));
+        row.appendChild(el("span", "lane-id", lane.laneId?.slice(0, 12) ?? "—"));
+        row.appendChild(el("span", "lane-transport", lane.transport ?? "—"));
         row.appendChild(el("span", "lane-session", lane.sessionId ? lane.sessionId.slice(0, 12) : "—"));
-        row.appendChild(el("span", "lane-updated", lane.lastUpdated.slice(11, 19)));
+        row.appendChild(el("span", "lane-updated", lane.lastUpdated?.slice(11, 19) ?? "—"));
         table.appendChild(row);
       }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
for (const lane of persistedLanes) {
const row = el("div", "lane-row");
row.appendChild(el("span", "lane-id", lane.laneId.slice(0, 12)));
row.appendChild(el("span", "lane-transport", lane.transport));
row.appendChild(el("span", "lane-session", lane.sessionId ? lane.sessionId.slice(0, 12) : "—"));
row.appendChild(el("span", "lane-updated", lane.lastUpdated.slice(11, 19)));
table.appendChild(row);
}
center.appendChild(table);
for (const lane of persistedLanes) {
const row = el("div", "lane-row");
row.appendChild(el("span", "lane-id", lane.laneId?.slice(0, 12) ?? "—"));
row.appendChild(el("span", "lane-transport", lane.transport ?? "—"));
row.appendChild(el("span", "lane-session", lane.sessionId ? lane.sessionId.slice(0, 12) : "—"));
row.appendChild(el("span", "lane-updated", lane.lastUpdated?.slice(11, 19) ?? "—"));
table.appendChild(row);
}
center.appendChild(table);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/renderers/helios/index.ts` around lines 286 - 294, The loop over
persistedLanes calls lane.laneId.slice(...) and lane.lastUpdated.slice(...),
which can throw if those fields are null/undefined; update the rendering in
src/renderers/helios/index.ts to defensively access these properties (e.g.,
coerce to a safe string or use nullish checks) before slicing and provide a safe
fallback display (like "—" or an empty string) so malformed RPC data won't cause
a TypeError; apply this to the code that builds row elements inside the
persistedLanes iteration (references: persistedLanes, lane.laneId,
lane.lastUpdated, row.appendChild calls).

Comment on lines +319 to +324
for (const entry of auditEntries.slice(0, 10)) {
const row = el("div", "log-entry");
row.appendChild(el("span", "log-ts", entry.timestamp.slice(11, 19)));
row.appendChild(el("span", "log-label", `${entry.action}: ${entry.detail.slice(0, 40)}`));
auditContainer.appendChild(row);
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Same unguarded access pattern for audit entries.

entry.timestamp.slice() and entry.detail.slice() will throw if the values are missing. Apply the same defensive pattern as for persisted lanes.

🛠️ Proposed fix
     for (const entry of auditEntries.slice(0, 10)) {
       const row = el("div", "log-entry");
-      row.appendChild(el("span", "log-ts", entry.timestamp.slice(11, 19)));
-      row.appendChild(el("span", "log-label", `${entry.action}: ${entry.detail.slice(0, 40)}`));
+      row.appendChild(el("span", "log-ts", entry.timestamp?.slice(11, 19) ?? "—"));
+      row.appendChild(el("span", "log-label", `${entry.action ?? "?"}: ${entry.detail?.slice(0, 40) ?? ""}`));
       auditContainer.appendChild(row);
     }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
for (const entry of auditEntries.slice(0, 10)) {
const row = el("div", "log-entry");
row.appendChild(el("span", "log-ts", entry.timestamp.slice(11, 19)));
row.appendChild(el("span", "log-label", `${entry.action}: ${entry.detail.slice(0, 40)}`));
auditContainer.appendChild(row);
}
for (const entry of auditEntries.slice(0, 10)) {
const row = el("div", "log-entry");
row.appendChild(el("span", "log-ts", entry.timestamp?.slice(11, 19) ?? "—"));
row.appendChild(el("span", "log-label", `${entry.action ?? "?"}: ${entry.detail?.slice(0, 40) ?? ""}`));
auditContainer.appendChild(row);
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/renderers/helios/index.ts` around lines 319 - 324, The loop over
auditEntries uses unguarded entry.timestamp.slice and entry.detail.slice which
will throw if those properties are missing; update the loop handling in the
block that iterates auditEntries (the for (const entry of auditEntries.slice(0,
10)) loop) to defensively access these fields—e.g., coerce to a safe string
before slicing or check typeof before calling slice (use something like const ts
= (entry.timestamp || '').slice(11,19) and const detail = (entry.detail ||
'').slice(0,40) or equivalent guarded checks) and then use ts and detail when
building the elements so missing values won’t cause exceptions.

@KooshaPari KooshaPari merged commit 683b07b into main Feb 28, 2026
1 check passed
@KooshaPari KooshaPari deleted the helios-phase2 branch February 28, 2026 07:51
KooshaPari added a commit that referenced this pull request Mar 25, 2026
feat(config): polyglot-config-core contract scaffold
@KooshaPari KooshaPari added pr-created PR was created labels Jun 9, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

pr-created PR was created

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant