Search/Add Modules to a Modular Network Service While Keeping Its Boundaries

Add Modules to a Modular Network Service While Keeping Its Boundaries

Use when an AI changes or extends a network service built from modules. It connects modules only through shared interfaces, builds and tests with the repository's own tools, returns errors that are safe for clients, and shares no state between requests.

To use this AI rule
## Connect modules through shared interfaces, not each other's internals - Treat the module system as the central extension boundary. Authentication, storage, validation, transformation, routing, and protocol endpoints should implement shared framework interfaces rather than call one another through private details. - Keep stable interfaces, configuration primitives, address handling, error types, and logging contracts in a reusable framework layer. Put concrete implementations in internal role-based packages. - Keep the executable entry point thin. It should load the service package, ensure built-in modules are registered, and invoke the startup sequence. - Wire top-level modules through configuration and a lazy registry. Route each request or message through an explicit pipeline of validators, modifiers, and destination targets selected by matching rules. - Avoid circular dependencies by making implementations depend on stable interfaces, not on sibling implementations. ## Build with the repository's build wrapper and run the affected tests - Use the repository's build wrapper as the canonical build path, including its supported build-tag or feature options. Do not replace it with an ad hoc compiler command that omits version metadata or required flags. - Run the complete unit-test suite for cross-cutting changes. Run the integration harness from its documented working directory when behavior spans protocol, storage, or delivery boundaries. - Preserve version injection performed by the build system. If the runtime uses a native-backed dependency, verify that the required native compiler and libraries are available before diagnosing source code. - Prefer a focused package test during iteration, then run the directly affected integration path before completion. Report any skipped test and the concrete environmental reason. ## Add a new module in its role folder and register it 1. Place the implementation under the internal directory for its role, such as validation, destination, authentication, storage, lookup, transformation, or endpoint handling. 2. Implement both the common module lifecycle interface and the role-specific interface. Keep role contracts in the stable framework layer. 3. Register the factory during package initialization using the established role-prefixed naming convention. 4. Add the implementation to the service's built-in module wiring through the repository's designated registration import or manifest. Registration code must remain side-effect-only when that is the established pattern. 5. Start from an existing role skeleton or helper when available. Use the stateless helper only when the module truly keeps no request-spanning mutable state. 6. Add focused tests for configuration, registration, success behavior, temporary failures, and boundary error mapping. ## Return errors that show whether to retry and hide internal details - Use the framework's structured error package for errors that cross module boundaries. Do not return an unclassified formatted error when the caller needs protocol status, retry behavior, or module attribution. - Include the external status code, enhanced status or subtype when supported, a generic client-safe message, and the responsible check or destination name. - Mark transient failures explicitly so dispatchers can distinguish retryable conditions from permanent rejection. - Keep client-visible messages free of server configuration, internal paths, credentials, and implementation details. - Attach structured diagnostic fields to unexpected internal failures and log them through the framework logger. Preserve the original cause without exposing it to remote clients. ## Share no state between requests and recover panics in background tasks - Never share mutable per-request state between requests or messages. Assume checks and transformations run concurrently unless the framework contract explicitly serializes them. - Any spawned goroutine or background task must recover panics at its boundary, record the failure, and prevent one task from crashing the entire service. - Normalize external identifiers before comparison or storage. For domain-like identifiers, apply the framework's required Unicode representation, normalization form, and case folding rather than inventing local cleanup. - Parse module configuration through the shared configuration map and lifecycle method. Reject unknown or invalid settings consistently with existing modules. - Use the framework logger instead of the language's global logger. Create operation-scoped or delivery-scoped loggers where the framework provides them so related events retain context. - Before merging, verify registration, configuration parsing, concurrent execution, normalization, structured failures, and logs with tests at the narrowest boundary that proves each behavior.