feat(plugin): synapse-coder-reporter learning-loop integration + companion plugins#1
Conversation
Detects LSP diagnostics after edit/write/apply_patch, holds the failing edit as pending, and reports an original->corrected pair to the Synapse Coder staging MCP (coder_report_correction) only when a follow-up same-file edit lands clean — the live schema requires non-empty original/corrected, so one-sided detections are dropped after 30 min. - Env-var opt-in gate (SYNAPSE_CODER_REPORTER_ENABLED, default off) with first-use TUI toast (once-per-project marker) - Offline queue (.opencode/synapse-coder-queue.json) with retry on load + 5-min timer; fire-and-forget hooks (no await on report path) - MCP wiring for synapse-coder + Alterspective servers in .opencode/opencode.jsonc (local entries fixed to schema shape) - 28 tests covering detection, pairing rules, opt-in, queue, model tracking, fire-and-forget, first-use toast - Plan/evidence docs under docs/implementation/current/SYN-001-*
Statically injects Alterspective standards awareness (rule-ID citation, RAG-first routing via rag_search/rag_ask, standards index pointers) into the chat system prompt via the experimental.chat.system.transform hook. Opt-out via ALTERSPECTIVE_STANDARDS_INJECTION_DISABLED=true or ALTERSPECTIVE_STANDARDS_INJECTION_ENABLED=false. 6 tests.
Standalone HTTP sidecar exposing /health and /version (upstream probe optional via OPENCODE_SERVER_URL) — the fork-local fallback for operational visibility, since adding routes would touch high-churn upstream server files. 5 tests.
There was a problem hiding this comment.
Pull request overview
Adds fork-local Alterspective integrations to opencode via .opencode/ plugins/config and companion docs/tests, keeping core src/ untouched to minimize upstream merge churn.
Changes:
- Introduces the
synapse-coder-reporterlearning-loop plugin (paired correction reporting, opt-in gating, offline queue/retry) and a comprehensive test suite. - Adds
alterspective-rag-standardssystem-prompt injection plugin with opt-out env gates and tests. - Adds a standalone
/health+/versionsidecar script plus tests, and wires multiple MCP servers via.opencode/opencode.jsonc.
Reviewed changes
Copilot reviewed 31 out of 31 changed files in this pull request and generated 11 comments.
Show a summary per file
| File | Description |
|---|---|
| .opencode/plugin/synapse-coder-reporter.ts | Implements paired correction detection/reporting + opt-in + queue/retry for Synapse Coder. |
| .opencode/plugin/alterspective-rag-standards.ts | Injects Alterspective standards routing guidance into the system prompt. |
| .opencode/scripts/health-check.ts | Adds a fork-local HTTP sidecar exposing /health and /version. |
| .opencode/opencode.jsonc | Configures MCP servers (remote + local) for the fork environment. |
| .opencode/.gitignore | Ignores local Synapse queue/marker files. |
| packages/opencode/test/plugin/synapse-coder-reporter/synapse-coder-reporter.test.ts | Tests correction detection, pairing, opt-in gate, queueing, model tracking, and non-blocking behavior. |
| packages/opencode/test/plugin/synapse-coder-reporter/health-check.test.ts | Integration tests for the health/version sidecar endpoints. |
| packages/opencode/test/plugin/alterspective-rag-standards/alterspective-rag-standards.test.ts | Tests for standards system-prompt injection and env gating. |
| docs/implementation/current/SYN-001-synapse-coder-reporter/README.md | Feature overview and scope documentation. |
| docs/implementation/current/SYN-001-synapse-coder-reporter/requirements.md | Requirements and assumptions for SYN-001. |
| docs/implementation/current/SYN-001-synapse-coder-reporter/technical-design.md | Architecture and hook-point design write-up. |
| docs/implementation/current/SYN-001-synapse-coder-reporter/acceptance-criteria.md | Acceptance criteria and verification plan. |
| docs/implementation/current/SYN-001-synapse-coder-reporter/checklist.md | Task checklist and wave plan. |
| docs/implementation/current/SYN-001-synapse-coder-reporter/status.md | Current implementation/verification status. |
| docs/implementation/current/SYN-001-synapse-coder-reporter/issues.md | Issue log and resolutions discovered during E2E. |
| docs/implementation/current/SYN-001-synapse-coder-reporter/impact-analysis.md | Risk/impact analysis for fork-local approach. |
| docs/implementation/current/SYN-001-synapse-coder-reporter/module-register.md | Module inventory and dependency mapping. |
| docs/implementation/current/SYN-001-synapse-coder-reporter/INDEX.md | High-level index for the SYN-001 documentation set. |
| docs/implementation/current/SYN-001-synapse-coder-reporter/ai-memory.md | Captures key decisions/gotchas for continuity. |
| docs/implementation/current/SYN-001-synapse-coder-reporter/ai-handover.md | Handover notes for continuing the work. |
| docs/implementation/current/SYN-001-synapse-coder-reporter/evidence/phase1-mcp-verification.md | Evidence for MCP wiring/tool discovery verification. |
| docs/implementation/current/SYN-001-synapse-coder-reporter/evidence/phase4-e2e-verification.md | Evidence for E2E validation and schema mismatch discovery. |
| docs/implementation/current/SYN-001-synapse-coder-reporter/evidence/investigation-findings.md | Investigation report for relevant hook points and constraints. |
| docs/implementation/current/SYN-001-synapse-coder-reporter/modules/synapse-coder-reporter/README.md | Module-level overview for the plugin. |
| docs/implementation/current/SYN-001-synapse-coder-reporter/modules/synapse-coder-reporter/requirements.md | Module-level requirements. |
| docs/implementation/current/SYN-001-synapse-coder-reporter/modules/synapse-coder-reporter/technical-design.md | Module-level design sketch. |
| docs/implementation/current/SYN-001-synapse-coder-reporter/modules/synapse-coder-reporter/checklist.md | Module-level checklist. |
| docs/implementation/current/SYN-001-synapse-coder-reporter/modules/synapse-coder-reporter/status.md | Module-level status tracking. |
| docs/implementation/current/SYN-001-synapse-coder-reporter/modules/synapse-coder-reporter/INDEX.md | Module document index. |
| docs/implementation/current/SYN-001-synapse-coder-reporter/modules/synapse-coder-reporter/ai-memory.md | Module gotchas and decisions. |
| docs/implementation/current/SYN-001-synapse-coder-reporter/modules/synapse-coder-reporter/ai-handover.md | Module-level continuity notes. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| import { dirname, resolve as pathResolve, join as pathJoin } from "node:path" | ||
|
|
||
| const PORT = Number.parseInt(process.env.HEALTH_CHECK_PORT ?? "4040", 10) || 4040 | ||
| const HOST = process.env.HEALTH_CHECK_HOST ?? "0.0.0.0" | ||
| const BUILD_SHA = process.env.BUILD_SHA ?? "unknown" | ||
| const BUILD_DATE = process.env.BUILD_DATE ?? "unknown" | ||
| const OPENCODE_SERVER_URL = process.env.OPENCODE_SERVER_URL ?? "" | ||
|
|
||
| const startedAt = Date.now() | ||
|
|
||
| function readOpencodeVersion(): string { | ||
| // Walk up from .opencode/scripts/ to repo root, then packages/opencode/package.json. | ||
| const here = dirname(fileURLToPath(import.meta.url)) | ||
| const candidates = [ | ||
| pathResolve(here, "..", "..", "packages", "opencode", "package.json"), | ||
| pathResolve(here, "..", "..", "package.json"), | ||
| ] |
| import { resolve as pathResolve } from "node:path" | ||
|
|
||
| const scriptPath = pathResolve(import.meta.dir, "..", "..", "..", "..", "..", ".opencode", "scripts", "health-check.ts") | ||
|
|
||
| function startSidecar(env: Record<string, string>): ChildProcessWithoutNullStreams { | ||
| return spawn(process.execPath, [scriptPath], { | ||
| env: { ...process.env, ...env }, | ||
| stdio: ["pipe", "pipe", "pipe"], | ||
| }) | ||
| } |
| async function reportToSynapse(payload: ReportPayload): Promise<void> { | ||
| const token = process.env.SYNAPSE_CODER_STAGING_BEARER_TOKEN | ||
| if (!token) return | ||
|
|
| const res = await fetch(SYNAPSE_URL, { | ||
| method: "POST", | ||
| headers: { | ||
| "Content-Type": "application/json", | ||
| Accept: "application/json, text/event-stream", | ||
| Authorization: `Bearer ${token}`, | ||
| }, | ||
| body: JSON.stringify(body), | ||
| signal: controller.signal, | ||
| }) | ||
| if (!res.ok) throw new Error(`synapse-coder responded ${res.status}`) |
| **Payload:** | ||
| - `original`: `input.args.newString` (edit), `input.args.content` (write), or `input.args.patchText` (apply_patch) — the LLM's proposed code | ||
| - `corrected`: `""` (one-sided — the next-turn fix is not available in this hook; Synapse may accept one-sided reports with `reason` containing the diagnostics) | ||
| - `category`: `"lsp-typecheck"` | ||
| - `language`: derived from file extension (`input.args.filePath` → extension → language map) | ||
| - `reason`: `"LSP diagnostics: <formatted errors from metadata.diagnostics>"` | ||
| - `reporterModel`: from the per-session model map (populated by `chat.message` hook) | ||
|
|
| # SYN-001: Synapse Coder Learning Loop Integration | ||
|
|
||
| **Feature ID:** SYN-001 | ||
| **Status:** Planning |
| **Status:** Planning — awaiting review | ||
| **Last updated:** 2026-07-18 | ||
|
|
||
| No implementation started. See parent [status.md](../../status.md). |
| | Task | Status | | ||
| |------|--------| | ||
| | Create plugin file with `chat.message` hook | PENDING | | ||
| | Implement `tool.execute.after` hook for LSP diagnostics | PENDING | | ||
| | Implement `event` hook for permission rejections | PENDING | | ||
| | Implement language derivation utility | PENDING | | ||
| | Implement reporter module (MCP call) | PENDING | | ||
| | Implement user opt-in gate | PENDING | | ||
| | Implement offline queue | PENDING | | ||
| | Implement async fire-and-forget | PENDING | | ||
| | Unit tests | PENDING | | ||
| | Integration tests | PENDING | |
| function extractFilePath(args: any): string { | ||
| return args?.filePath ?? args?.path ?? "" | ||
| } |
| const filePath = extractFilePath(hookInput.args) | ||
| const pendingKey = `${hookInput.sessionID}:${filePath}` | ||
| const reporterModel = sessionModels.get(hookInput.sessionID) ?? "unknown" | ||
|
|
|
Reviewer configuration note (COP-06 gap): this is a personal fork outside the org — no CI checks run on the branch and Copilot review was requested but never attached ( Local verification evidence (observed 2026-07-19, worktree
Review request: a human pass over |
What
Alterspective integration for the fork, all plugin/config-level (zero \src/\ changes — fork-local compliant, upstream merges stay clean):
Key design constraint discovered (E2E)
The live \coder_report_correction\ schema requires \ ool, \model, and non-empty \original/\corrected\ (\�dditionalProperties: false) — one-sided reports are rejected (MCP -32602). The plugin therefore only reports paired corrections; unpaired detections are dropped after a 30-min window. No placeholder values are sent (learning-corpus pollution avoided). Full evidence: \docs/implementation/current/SYN-001-synapse-coder-reporter/evidence/phase4-e2e-verification.md.
Validation performed (observed, this session)
Docs