--- phase: 03-agent-registry-sse-push plan: 01 subsystem: agent-registry tags: [concurrenthashmap, lifecycle, heartbeat, rest-api, spring-scheduled] # Dependency graph requires: - phase: 01-ingestion-pipeline provides: IngestionBeanConfig pattern, @Scheduled pattern, ProtocolVersionInterceptor provides: - AgentRegistryService with register/heartbeat/lifecycle/command management - AgentInfo record with wither-style immutable state transitions - AgentCommand record with delivery status tracking - AgentEventListener interface for SSE bridge (Plan 02) - POST /api/v1/agents/register endpoint - POST /api/v1/agents/{id}/heartbeat endpoint - GET /api/v1/agents endpoint with ?status= filter - AgentLifecycleMonitor with LIVE->STALE->DEAD transitions - AgentRegistryConfig with all timing properties affects: [03-02-sse-push, 04-security] # Tech tracking tech-stack: added: [] patterns: [immutable-record-with-wither, compute-if-present-atomic-swap, agent-lifecycle-state-machine] key-files: created: - cameleer-server-core/src/main/java/com/cameleer/server/core/agent/AgentInfo.java - cameleer-server-core/src/main/java/com/cameleer/server/core/agent/AgentState.java - cameleer-server-core/src/main/java/com/cameleer/server/core/agent/AgentCommand.java - cameleer-server-core/src/main/java/com/cameleer/server/core/agent/CommandStatus.java - cameleer-server-core/src/main/java/com/cameleer/server/core/agent/CommandType.java - cameleer-server-core/src/main/java/com/cameleer/server/core/agent/AgentRegistryService.java - cameleer-server-core/src/main/java/com/cameleer/server/core/agent/AgentEventListener.java - cameleer-server-core/src/test/java/com/cameleer/server/core/agent/AgentRegistryServiceTest.java - cameleer-server-app/src/main/java/com/cameleer/server/app/config/AgentRegistryConfig.java - cameleer-server-app/src/main/java/com/cameleer/server/app/config/AgentRegistryBeanConfig.java - cameleer-server-app/src/main/java/com/cameleer/server/app/agent/AgentLifecycleMonitor.java - cameleer-server-app/src/main/java/com/cameleer/server/app/controller/AgentRegistrationController.java - cameleer-server-app/src/test/java/com/cameleer/server/app/controller/AgentRegistrationControllerIT.java modified: - cameleer-server-app/src/main/java/com/cameleer/server/app/CameleerServerApplication.java - cameleer-server-app/src/main/resources/application.yml key-decisions: - "AgentInfo as Java record with wither-style methods for immutable ConcurrentHashMap swapping" - "Dead threshold measured from staleTransitionTime, not lastHeartbeat (matches requirement precisely)" - "spring.mvc.async.request-timeout=-1 set now for SSE support in Plan 02" patterns-established: - "Immutable record + ConcurrentHashMap.compute for thread-safe state transitions" - "AgentEventListener interface in core module as bridge to SSE layer in app module" requirements-completed: [AGNT-01, AGNT-02, AGNT-03] # Metrics duration: 15min completed: 2026-03-11 --- # Phase 3 Plan 1: Agent Registry Summary **In-memory agent registry with ConcurrentHashMap, LIVE/STALE/DEAD lifecycle via @Scheduled, and REST endpoints for registration/heartbeat/listing** ## Performance - **Duration:** 15 min - **Started:** 2026-03-11T17:26:34Z - **Completed:** 2026-03-11T17:41:24Z - **Tasks:** 2 - **Files modified:** 15 ## Accomplishments - Agent registry domain model with 5 types (AgentInfo, AgentState, AgentCommand, CommandStatus, CommandType) - Full lifecycle management: register, heartbeat, LIVE->STALE->DEAD transitions with configurable thresholds - Command queue with PENDING/DELIVERED/ACKNOWLEDGED/EXPIRED status tracking and event listener bridge - REST endpoints: POST /register, POST /{id}/heartbeat, GET /agents with ?status= filter - 23 unit tests + 7 integration tests all passing ## Task Commits Each task was committed atomically: 1. **Task 1 (RED): Failing tests for agent registry** - `4cd7ed9` (test) 2. **Task 1 (GREEN): Implement agent registry service** - `61f3902` (feat) 3. **Task 2: Controllers, config, lifecycle monitor, integration tests** - `0372be2` (feat) _Note: Task 1 used TDD with separate RED/GREEN commits_ ## Files Created/Modified - `AgentInfo.java` - Immutable record with wither-style methods for atomic state transitions - `AgentState.java` - LIVE, STALE, DEAD lifecycle enum - `AgentCommand.java` - Command record with delivery status tracking - `CommandStatus.java` - PENDING, DELIVERED, ACKNOWLEDGED, EXPIRED enum - `CommandType.java` - CONFIG_UPDATE, DEEP_TRACE, REPLAY enum - `AgentRegistryService.java` - Core registry: register, heartbeat, lifecycle, commands - `AgentEventListener.java` - Interface for SSE bridge (Plan 02 integration point) - `AgentRegistryConfig.java` - @ConfigurationProperties for all timing settings - `AgentRegistryBeanConfig.java` - @Configuration wiring AgentRegistryService - `AgentLifecycleMonitor.java` - @Scheduled lifecycle check and command expiry - `AgentRegistrationController.java` - REST endpoints for agents - `AgentRegistryServiceTest.java` - 23 unit tests - `AgentRegistrationControllerIT.java` - 7 integration tests - `CameleerServerApplication.java` - Added AgentRegistryConfig to @EnableConfigurationProperties - `application.yml` - Added agent-registry config section and spring.mvc.async.request-timeout ## Decisions Made - Used Java record with wither-style methods for AgentInfo instead of mutable class -- ConcurrentHashMap.compute provides atomic swapping without needing synchronized fields - Dead threshold measured from staleTransitionTime field (not lastHeartbeat) to match the "5 minutes after going STALE" requirement precisely - Set spring.mvc.async.request-timeout=-1 proactively for SSE support needed in Plan 02 - Command queue uses ConcurrentLinkedQueue per agent for lock-free command management ## Deviations from Plan None - plan executed exactly as written. ## Issues Encountered - DiagramRenderControllerIT has a pre-existing flaky failure (EmptyResultDataAccess in seedDiagram) unrelated to Phase 3 changes. Logged in deferred-items.md. ## User Setup Required None - no external service configuration required. ## Next Phase Readiness - AgentRegistryService ready for SSE integration via AgentEventListener interface - Plan 02 (SSE Push) can wire SseConnectionManager as AgentEventListener implementation - All agent endpoints under /api/v1/agents/ already covered by ProtocolVersionInterceptor --- *Phase: 03-agent-registry-sse-push* *Completed: 2026-03-11*