From 3a9ac82275c2f02a8fe6e6097bde1420dbe86a2a Mon Sep 17 00:00:00 2001 From: Snider Date: Tue, 24 Mar 2026 17:14:51 +0000 Subject: [PATCH] fix: prevent double IPC registration + empty service placeholder MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - HandleIPCEvents only auto-registered for services the factory didn't register itself (prevents double handler registration) - Auto-discovery only creates Service{} placeholder when factory didn't call c.Service() — factories that register themselves keep full lifecycle Addresses Codex review findings 1 and 2 from third pass. Co-Authored-By: Virgil --- contract.go | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/contract.go b/contract.go index 6abc98a..70db9d7 100644 --- a/contract.go +++ b/contract.go @@ -146,10 +146,10 @@ func WithService(factory func(*Core) Result) CoreOption { return r } - // If the factory returned a service instance, auto-discover and register + // If the factory returned a service instance, auto-discover and register. + // Only applies when the factory didn't register the service itself. if r.Value != nil { instance := r.Value - // Service name discovery from package path typeOf := reflect.TypeOf(instance) if typeOf.Kind() == reflect.Ptr { typeOf = typeOf.Elem() @@ -159,18 +159,19 @@ func WithService(factory func(*Core) Result) CoreOption { name := Lower(parts[len(parts)-1]) if name != "" { - // IPC handler discovery - instanceValue := reflect.ValueOf(instance) - handlerMethod := instanceValue.MethodByName("HandleIPCEvents") - if handlerMethod.IsValid() { - if handler, ok := handlerMethod.Interface().(func(*Core, Message) Result); ok { - c.RegisterAction(handler) - } - } - - // Register the service if not already registered by the factory + // Only auto-register if the factory didn't already do it if sr := c.Service(name); !sr.OK { c.Service(name, Service{}) + + // IPC handler discovery — only on auto-registered services + // to avoid double-registration when the factory already wired handlers + instanceValue := reflect.ValueOf(instance) + handlerMethod := instanceValue.MethodByName("HandleIPCEvents") + if handlerMethod.IsValid() { + if handler, ok := handlerMethod.Interface().(func(*Core, Message) Result); ok { + c.RegisterAction(handler) + } + } } } }