Skip to content
This repository was archived by the owner on Jun 8, 2026. It is now read-only.

Integrate Engineer Start Planning with real Loop records - #34

Merged
shafty023 merged 5 commits into
mainfrom
FEAT-77
Mar 19, 2026
Merged

shafty023 merged 5 commits into
mainfrom
FEAT-77

Conversation

@shafty023

Copy link
Copy Markdown
Contributor

Gateway-side changes for the Engineer Start Planning integration with the platform Loop system.

  • Replace single gateway plan-loop operation with prepare/confirm pattern
  • Confirm handler computes loop-style worktree from artifactSlug
  • Cancel handler uses JobStore for correct worktree PID lookup
  • Allow localhost in SSRF guard for local dev loop callbacks
  • Forward DELETE request bodies through CloudRelay executor
  • Add JobStore with active/terminal migration and staleness expiry
  • Add job snapshot enrichment with ghost QUEUED job expiry (60s)
  • Status handler falls back to JobStore worktree path
  • Persist loopId/artifactId in gateway session schema
  • Add running/completed job IPC handlers with reconciliation

Comment thread apps/desktop/src/server/operations/symphony-loop.ts Outdated
Comment thread apps/desktop/src/server/operations/symphony-job-snapshot.ts Outdated
Comment thread apps/desktop/src/server/operations/symphony-plan-loop.ts Outdated
Comment thread apps/desktop/src/server/operations/symphony-plan-loop.ts
Comment thread apps/desktop/src/server/operations/symphony-plan-loop.ts
Comment thread apps/desktop/src/server/operations/symphony-plan-loop.ts Outdated
Comment thread apps/desktop/src/server/operations/symphony-plan-loop.ts
Comment thread apps/desktop/src/renderer/index.html Outdated
Comment thread apps/desktop/src/renderer/index.html Outdated
Comment thread apps/desktop/src/server/operations/symphony-loop.ts Outdated
Comment thread apps/desktop/src/server/operations/symphony-job-snapshot.ts Outdated
Comment thread apps/desktop/src/server/operations/symphony-plan-loop.ts
Comment thread apps/desktop/src/main/app.ts Outdated
@closedloop-ai-stage

Copy link
Copy Markdown

Code Review Summary

Status: Changes Requested

Reviewers: Bug Hunter A, Bug Hunter B, Unified Auditor, Premise Reviewer, cloud-command-executor-specialist

Findings

Severity Count
Blocking 1
High 3
Medium 10

BLOCKING Issues (must fix)

  1. [P0] [symphony-loop.ts:134] validateApiBaseUrl now allows SSRF to localhost/127.0.0.1 with no dev-mode guard — The SSRF-prevention function unconditionally allows localhost/127.0.0.1 in production builds. Guard with app.isPackaged or remove the early-return.

HIGH Issues (should fix)

  1. [P1] [symphony-plan-loop.ts:491] Cancel handler aborts on 404 without killing local process — A 404 from the DB cancel step causes early return before SIGTERM/SIGKILL is sent; the local Claude process keeps running.
  2. [P1] [app.ts:163] list-running-jobs returns terminal-status jobs when handleProcessCompletion races — Concurrent process exit during await Promise.all(enrichJobSnapshot) can cause terminated jobs to appear in the running list.
  3. [P1] [symphony-job-snapshot.ts:20] isProcessRunning duplicated from symphony-utils.ts — Byte-for-byte copy; import from the existing export instead.

MEDIUM Issues (consider)

  1. [P2] [symphony-plan-loop.ts:193] Duplicate prepare handler bodies violate DRY — Two identical 40-line prepare handlers; extract handlePrepare().
  2. [P2] [symphony-plan-loop.ts:341] Confirm handler body (~97 lines) duplicated for select-artifact route — Extract handleConfirm().
  3. [P2] [symphony-plan-loop.ts:134] >90% structural duplication across prepare/confirm handler pairs.
  4. [P2] [symphony-plan-loop.ts:316] Confirm handler unconditionally overwrites RUNNING status with QUEUED — Race condition when relay dispatches before confirm arrives.
  5. [P2] [symphony-plan-loop.ts:156] Debug console.log statements left in production route handler.
  6. [P2] [symphony-job-snapshot.ts:233] Private isTerminalStatus duplicates exported isTerminalJobStatus from job-store.ts.
  7. [P2] [app.ts:815] Terminal-status snapshot incorrectly included in stillRunning list (related to P1 race at line 163).
  8. [P2] [symphony-loop.ts:134] Dead code: if (hostname === 'localhost') { return false; } unreachable after new early-return.
  9. [P2] [index.html:1773] refreshJobs guard checks api.listRunningJobs but not api.listCompletedJobs.
  10. [P3] [index.html:1727] renderJobCard uses job.command without null/undefined guard.

Validation Stats

  • Total findings from agents: 20
  • Validated: 14
  • Discarded — duplicate: 5
  • Discarded — line not changed: 1

Recommendation: Address the SSRF security issue and cancel handler bug before merging. The duplicate handler DRY violations are significant tech debt but not blocking.

shafty023 added a commit that referenced this pull request Mar 19, 2026
- Remove duplicate isProcessRunning/isTerminalStatus from job-snapshot
- Extract shared handlePrepare/handleConfirm to deduplicate routes
- Remove debug console.log from prepare handler
- Cancel handler: treat 404 as success for DB step (loop already gone)
- Confirm handler: don't overwrite RUNNING with QUEUED (add existing guard)
- Fix list-running-jobs: exclude terminal snapshots from running list
- Fix refreshJobs: add symmetric listCompletedJobs guard
- Fix renderJobCard: null-safe job.command fallback
Gateway-side changes for the Engineer Start Planning integration with
the platform Loop system.

- Replace single gateway plan-loop operation with prepare/confirm pattern
- Confirm handler computes loop-style worktree from artifactSlug
- Cancel handler uses JobStore for correct worktree PID lookup
- Allow localhost in SSRF guard for local dev loop callbacks
- Forward DELETE request bodies through CloudRelay executor
- Add JobStore with active/terminal migration and staleness expiry
- Add job snapshot enrichment with ghost QUEUED job expiry (60s)
- Status handler falls back to JobStore worktree path
- Persist loopId/artifactId in gateway session schema
- Add running/completed job IPC handlers with reconciliation
Stop trusting body.apiBaseUrl from relay payloads. The loop handler
now derives the callback URL from the gateway's configured API origin
(getApiOrigin) instead of the caller-supplied value. This eliminates
the SSRF primitive where a relay command could redirect loop event
callbacks to arbitrary endpoints.

- Derive apiBaseUrl from getApiOrigin() at request start, return 503
  if not configured
- Thread trusted origin through all callback paths: started event,
  error events, completion handler, artifact upload
- Mark body.apiBaseUrl as deprecated/optional in LoopRequestBody
- Delete validateApiBaseUrl, extractIPv4, isPrivateIPv4 (no callers)
- Add SSRF tests proving all outbound requests use configured origin
  regardless of body.apiBaseUrl content
- Remove duplicate isProcessRunning/isTerminalStatus from job-snapshot
- Extract shared handlePrepare/handleConfirm to deduplicate routes
- Remove debug console.log from prepare handler
- Cancel handler: treat 404 as success for DB step (loop already gone)
- Confirm handler: don't overwrite RUNNING with QUEUED (add existing guard)
- Fix list-running-jobs: exclude terminal snapshots from running list
- Fix refreshJobs: add symmetric listCompletedJobs guard
- Fix renderJobCard: null-safe job.command fallback
- Remove unused `expandHome` import in symphony-plan-loop.ts
- Update readLaunchMetadata / writeLaunchMetadata test expectations
  to include new LaunchMetadata fields (artifactId, issueId, loopId,
  ticketTitle) added on main

Testing: `just desktop-lint`, `just desktop-typecheck`, `just desktop-test` all pass
Risks: None -- test-only + trivial lint fix
@shafty023
shafty023 merged commit 46f5bc2 into main Mar 19, 2026
2 checks passed
@shafty023
shafty023 deleted the FEAT-77 branch March 19, 2026 15:31
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant