fix: prevent double IPC registration + empty service placeholder

- 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 <virgil@lethean.io>
This commit is contained in:
Snider 2026-03-24 17:14:51 +00:00
parent 2d017980dd
commit 9b5f6df6da

View file

@ -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)
}
}
}
}
}