BOLT-1322 [sync-3/N]: refactor manufacturer commandIssuedEventHandler to RETURN CommandExecutedEvent instead of publishing internally
completedSergey directive 2026-06-19T06:44Z (BOLT-1322 thread): asked why commandIssuedEventHandler needs publisher. Investigation revealed handlers publish BOTH command.executed AND device.detected. I committed at 06:46Z to fix-option (1): handlers RETURN command.executed, outer Kafka wrapper publishes; sync HTTP path returns over HTTP without Kafka publish. device.detected side-effects stay where they are (per option-A decision at 06:46Z).
Current state on PR #12557 (merged or about-to-merge): executeCommand core exists but per-manufacturer handlers still call publishWithRetry(publisher, ..., commandExecutedEvent) themselves. Means sync HTTP path double-publishes: handler-internal command.executed + caller writing Command row from HTTP response = race condition.
In-scope:
- Change EventHandler<CommandIssuedEvent> type signature so the contract returns `Promise<CommandExecutedEvent | void>` (void preserves existing handlers that publish internally during transition).
- Update Tesla manufacturer handler (adapters/oem/src/manufacturers/tesla/events/command.issued/index.ts and its switch/handlers) to RETURN the CommandExecutedEvent instead of calling publishWithRetry for it. device.detected publishing stays.
- Update executeCommand.ts: if handler returns a CommandExecutedEvent, use it as the result; otherwise (legacy handlers that still publish internally) keep existing { status: 'completed' } behavior. Document the transition path.
- Update adapters/oem/src/events/command.issued/index.ts Kafka outer wrapper: when executeCommand returns a CommandExecutedEvent, publish it. When it returns the legacy stub, do NOT double-publish.
- Update tests for Tesla handler: assert it RETURNS the event, no longer expect publishWithRetry call for command.executed.
- Update integration test for /v1/commands/execute: assert the HTTP response body matches the CommandExecutedEvent and verify no command.executed Kafka publish from the sync path.
Non-Tesla manufacturers: NOT refactored in this task. Their handlers continue publishing command.executed internally — they don't support sync path yet so the race doesn't exist. Add TODO comment per manufacturer.
Branch: havoc/bolt-1322-handler-return-refactor
Depends on: PR #12557 + the [sync-2/N] auth-widening PR (to avoid stacking conflicts on routers/middlewares).
Done when: Tesla command.issued no longer double-publishes; /v1/commands/execute sync path verified Kafka-publish-free in tests; PR opened; CI green; Sergey-reviewed.
Self-link: see Slack DM 1781883984.255239 in BOLT-1322 thread for context.
Event Timeline
created
status_change
queued → completed