Harden CAD integration: fix facts write-back & crashes, align types with desktop API, add tests#4
Open
Henrik Cullen (hccullen) wants to merge 8 commits into
Open
Conversation
Bug fixes: - eventsController: add missing break after handleSessionCaseIDChanged, preventing silent fallthrough into session-opened/closed cases - eventsController: log session-opened, session-closed, app.login/logout and unknown events (previously all silently swallowed) - sessionController: leaveSession was calling /realtime/enterSession instead of /realtime/leaveSession - utils: /app/unhideAllAndFocus -> /window/unhideAllAndFocus (wrong callMethod prefix; window endpoints live under /window/) - cortiServices: replace manual REST fetch in updateCaseCustomProperties with /backendproxy/cases/ensureCaseCustomProperties callMethod, removing direct API key handling - handleGroupedFlowValueCollectorBlocksUpdated: log blocks with empty displayValues instead of silently skipping them - handleSessionCaseIDChanged: log case ID changes (was fire-and-forget with no observable output) Add test-manual-flow.js: lightweight script that opens a session via /openCortiSession (simulating a CAD dispatch) and prints a step-by-step checklist for manual event verification against the live desktop app. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
This PR fixes several integration event-handling issues (switch fallthrough, wrong callMethod routes) and improves observability by logging key session events and surfacing grouped Flow Value Collector (FVC) custom properties, plus adds a lightweight manual verification script.
Changes:
- Fixes incorrect callMethod routes for window focus and leaving sessions; routes case custom property updates through backendproxy callMethod.
- Improves event handling/logging (adds missing
break, logs session-open/close, logs case-id-changed, logs empty FVC blocks, logs collector custom properties). - Adds
test-manual-flow.jsto simulate CAD dispatch behavior and provide a manual verification checklist.
Reviewed changes
Copilot reviewed 7 out of 7 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| test-manual-flow.js | Adds a manual flow script to open/leave sessions and guide verification of emitted events/logs. |
| src/utils/utils.ts | Updates window focus callMethod to /window/unhideAllAndFocus. |
| src/services/cortiServices.ts | Switches case custom property updates to backendproxy callMethod. |
| src/eventHandlers/handleSessionCaseIDChanged.ts | Adds logging when a session’s case ID changes. |
| src/eventHandlers/handleGroupedFlowValueCollectorBlocksUpdated.ts | Logs empty collector blocks and surfaces/dedupes collector custom properties for logging. |
| src/controllers/sessionController.ts | Fixes leaveSession to call /realtime/leaveSession. |
| src/controllers/eventsController.ts | Fixes switch fallthrough and adds logging for session/app events and unhandled events. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Keep test-grouped-flow-value-collector-blocks-updated.js — tests the FVC handler with synthetic payloads, no live Corti session needed. Deleted test-session-flow.js and its copy, which were superseded by test-manual-flow.js in the previous commit. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Replaces the sparse original with: - Architecture diagram showing the two-port model (45002 integration, 45001 desktop app callMethod RPC) - Full callMethod endpoint reference table - Documented request/response shapes for /openCortiSession and /events - Per-event-handler explanation with example log output and customisation hints - Configuration, running, and testing instructions covering both test scripts - Extension guide for adding new event handlers and CAD endpoints Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Restructures the docs around the developer journey for a CAD vendor building an integration to Corti Triage: - Opens with what you are building and why, not what the code does - Two clear integration points: /openCortiSession when a call comes in, /events to receive updates back - Per-handler "what you receive / what to do instead" pattern showing exactly which console.log to replace and with what - Explains the customProperties field-mapping pattern for FVC blocks - Moves callMethod reference and project structure to the bottom as supporting material rather than the main narrative Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Title: 'Sample CAD Integration' -> 'CAD Integration' (it's an example, not a sample) - Diagram: remove separate CAD box (implied by the endpoints); show only this integration <-> Corti Desktop App - Make session creation order explicit: startSession (creates) comes before enterSession (opens in UI), with annotations on each step Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Restructures the doc to mirror the test-manual-flow.js sequence: dispatch → session opens → events arrive → call ends. Adds a new section explaining the session-open logic (active/DB/new), shows actual terminal log output for each event handler alongside the TODO replacement examples, and corrects the architecture diagram to accurately reflect when setFactValues is called. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Fixes and hardening
- Fix facts write-back: forward CAD `factValues` to setFactValues as
`{ sessionID, facts }` on all session paths (new + re-entry); previously
the openSession path sent the wrong shape with no sessionID.
- Guard openSession against malformed `activeSessions` responses and wrap
both session handlers in try/catch (return 502 instead of crashing).
- action-block handler: always log the trigger (falling back name -> content
-> id), tolerate missing customProperties, only patch facts when present.
- Implement GET /health liveness probe; split app.ts from index.ts so the
app can be mounted in tests without binding a port.
- leaveSession forwards the documented `sessionID` param when provided.
Types
- Add src/types/shared.ts mirroring the desktop API shared types
(Session, CustomProperty, Fact, UserTypeSerialized) 1:1.
- Fix collectedFactValues to Fact[]; CurrentUserResponse = UserTypeSerialized.
Config
- Replace per-host API_KEY_<ENV> derivation with a single API_KEY.
- Drop unused node-fetch dependency.
Tests
- Add unit + integration tests (Node test runner); integration boots the app
against a stub desktop app and asserts the setFactValues shape and the
malformed-activeSessions regression. Add test:* npm scripts and a live
e2e script. Fix the manual-flow script to stay alive until Ctrl+C.
Docs
- Add DESKTOP_APP_API.md reference; rewrite README to match (environments
model, response codes, /health, single API_KEY, project structure, types).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- updateCaseCustomProperties now returns the cortiCallMethod promise so callers can await completion and observe failures; guard the caller in handleSessionCaseIDChanged with try/catch to avoid unhandled rejections. - Default event handler no longer logs the full event data (potential PII) — logs only the event name and session/external IDs. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Comment on lines
23
to
+26
| cortiCallMethod("/realtime/enterSession", { | ||
| sessionID, | ||
| }).then(() => { | ||
| cortiCallMethod("/app/unhideAllAndFocus"); | ||
| if (facts) { | ||
| cortiCallMethod("/realtime/session/setFactValues", facts); | ||
| cortiCallMethod("/window/unhideAllAndFocus"); |
Comment on lines
+38
to
+41
| cortiCallMethod("/backendproxy/cases/ensureCaseCustomProperties", { | ||
| caseID: caseId, | ||
| customProperties: customPropertiesBody, | ||
| }); |
Comment on lines
+47
to
+53
| // Patch session with new facts (only when the block carried any). | ||
| if (factUpdateBody.length) { | ||
| cortiCallMethod('/realtime/session/setFactValues', { | ||
| sessionID: session.id, | ||
| facts: factUpdateBody, | ||
| }); | ||
| } |
Comment on lines
32
to
34
| default: | ||
| // console.log(data); | ||
| console.log(`Unhandled event: ${event.name}`, data); | ||
| break; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Started as a gap analysis of the README vs the code and grew into a broader hardening pass. Fixes real bugs (including ones that crashed the process against the live desktop app), aligns the TypeScript types 1:1 with the desktop app API, simplifies configuration, and adds a real test suite. Verified end-to-end against the live desktop app (
api.try.motocorti.io).Fixes & hardening
openCortiSessionpath sent the desktop app'ssetFactValuesthe wrong shape (raw{ factValues }, nosessionID). Now forwarded correctly as{ sessionID, facts }on all session paths (new session + active re-entry + DB re-entry).openSessionblew up the whole process when/realtime/activeSessionsreturned an unexpected shape (seen live when the desktop app was mid-shell.quit). Now defaults defensively and both session handlerstry/catch→ return 502 instead of dying.action-block-triggeredwas silent. The handler only logged inside thecustomPropertiesloop and assumed the field always exists — a block with no/empty custom properties produced nothing (and could throw, swallowed by the controller). Now always logs the trigger (label falls backname→content→id), tolerates missingcustomProperties, and only patches facts when present./healthliveness probe implemented;app.tssplit fromindex.tsso the app can be mounted in tests without binding a port.leaveSessionforwards the documentedsessionIDparam when provided.Types (1:1 with
DESKTOP_APP_API.md)src/types/shared.tsmirroring the shared types (Session,CustomProperty,Fact,UserTypeSerialized).collectedFactValuestoFact[](was{ factID, value });CurrentUserResponse = UserTypeSerialized.DESKTOP_APP_API.mdas the reference catalog.Config
API_KEY_<ENV>derivation with a singleAPI_KEY(one integration instance serves one environment).node-fetchdependency.Tests
setFactValuesshape plus a regression for the malformed-activeSessionscrash. 15/15 passing.test:unit/test:integration/test:grouped-fvc/test:e2escripts and a live e2e script.test-manual-flow.jsto actually stay alive until Ctrl+C.Docs
<env>.corti.appfrontend vsapi.<env>.motocorti.ioAPI, per-customer, no shared prod/dev), response codes,/health, singleAPI_KEY, updated project structure, and types pointing atDESKTOP_APP_API.md.Verification
npm test→ 15/15.action-block-triggerednow logs on real triggers.🤖 Generated with Claude Code