Two external reviews were conducted on the Atmosphere coordinator module and project documentation. This gist summarizes every issue found and how each was resolved.
Source: Architecture Review Gist
| # | Severity | Issue | Fix | Commit |
|---|---|---|---|---|
| 1 | High | Reflection in LocalAgentTransport — getDeclaredField("protocolHandler") and setAccessible(true) breaks silently on rename |
Created LocalDispatchable interface in atmosphere-a2a; A2aHandler implements it; LocalAgentTransport uses instanceof pattern matching |
fix/coordinator-review-issues |
| 2 | High | Unbounded CompletableFuture.join() in DefaultAgentFleet.parallel() — hung agent blocks coordinator forever |
Added orTimeout(120_000, MILLISECONDS) per agent with clear error message on timeout |
same |
| 3 | Medium | JournalingAgentFleet.evalExecutor never shut down |
JournalingAgentFleet now implements AutoCloseable with close() that shuts down the executor |
same |
| 4 | Medium-High | ThreadLocal<String> activeCoordinationId never remove()d — memory leak on pooled threads |
Added finally { activeCoordinationId.remove(); } in both parallel() and pipeline() |
same |
| 5 | Medium | Error messages in resolveAgentName() omit which coordinator the @AgentRef belongs to |
resolveAgentName() now takes coordinatorName parameter; all errors include coordinator context |
same |
| 6 | Medium | AgentCall.args() uses Map<String, String> — can't pass structured or nested payloads |
Changed to Map<String, Object> across entire API: AgentCall, AgentFleet, AgentProxy, DefaultAgentProxy, AgentTransport, both transports, CoordinationEvent.AgentDispatched, JournalingAgentFleet, stubs, all tests, and sample |
same |
| 7 | Low | weight field stored and logged but never used for routing |
Added Javadoc on AgentProxy.weight() and @AgentRef.weight() documenting intended use for future load-balancing / preference scoring |
same |
| 8 | Medium | Duplicate buildJsonRpc() and extractArtifactText() in LocalAgentTransport and A2aAgentTransport |
Extracted shared JsonRpcUtils utility; both transports delegate to it |
same |
| 9 | Medium | pipeline() doesn't chain results — each step uses original args, not previous output |
Both DefaultAgentFleet.pipeline() and JournalingAgentFleet.pipeline() now merge _previous_result from step N into step N+1's args |
same |
| 10 | Medium | No retry mechanism for transient agent failures | Added int maxRetries() default 0 on @AgentRef; DefaultAgentProxy.call() implements exponential backoff (100ms base) |
same |
Stats: 22 files changed, +380/-242 lines, all 120 coordinator tests pass.
Source: Documentation Audit Gist
| # | Issue | Fix |
|---|---|---|
| 1 | docs/protocols.md references non-existent @McpServer annotation |
Replaced with correct pattern: @Agent(headless = true) with @McpTool methods. Updated annotation list to remove @McpServer |
| 2 | README says "Pick any LLM library" — overstates support | Changed to explicit list: "Works with Spring AI, LangChain4j, Google ADK, Embabel, or the built-in OpenAI-compatible client" |
| 4 | docs/skill-files.md has "planned but not yet implemented" markers buried in table |
Reworded to clear Note: callouts: channels routing is "informational only", guardrails are "LLM-enforced only" |
| 5 | Multi-agent NL routing limitation buried in Known Limitations section | Added inline warning in docs/channels.md "How It Works" section so readers hit it before the limitation section |
| 6 | README has no Maven <dependency> coordinates |
Added dependency blocks for atmosphere-spring-boot-starter and atmosphere-agent with version |
| 7 | README does not state the current version | Version 4.0.28-SNAPSHOT now appears in Maven coordinates section |
| 8 | Marketing tone — rhetorical "Why not use Spring AI / LangChain4j / ADK directly?" with 10-bullet sales pitch | Replaced with factual comparison table (Without Atmosphere vs. With Atmosphere) |
| # | Issue | Status |
|---|---|---|
| 3 | spring-boot-embabel-chat sample referenced but missing |
Correctly commented out in pom.xml with note "Embabel requires Spring Boot 3.5". Not referenced in README sample table. No fix needed. |
| Issue | Status |
|---|---|
Missing docs/agent.md — @Agent lifecycle, headless modes, endpoint paths |
Not yet created |
Missing docs/coordinator.md — @Coordinator, @Fleet, AgentFleet API, journal SPI |
Not yet created |
Missing docs/configuration.md — complete env var / init-param / Spring property catalog |
Not yet created |
Two doc trees (docs/ and atmosphere.github.io/docs/) without declared relationship |
Structural issue acknowledged |
Stats: 5 files changed, +48/-24 lines across README.md, docs/protocols.md, docs/channels.md, docs/skill-files.md.
In addition to fixing review issues, the following features were added:
Pluggable format for rendering coordination journal events. Built-in formats: JournalFormat.STANDARD_LOG (plain text) and JournalFormat.MARKDOWN (table). Users implement the JournalFormat interface for custom formats (Grafana, OpenTelemetry, etc.).
// Programmatic
fleet.journal().formatLog(JournalFormat.MARKDOWN);
// Annotation-driven (auto-emits after @Prompt completes)
@Coordinator(name = "ceo", journalFormat = JournalFormat.Markdown.class)Each sealed event record now formats itself as a single-line log entry, used by JournalFormat.STANDARD_LOG and available for custom logging.
Callback interface in the AI module, invoked by AiEndpointHandler after the @Prompt method returns successfully. Used by the coordinator module to auto-emit journal tool cards without manual code in the prompt method.
New page at atmosphere.github.io/docs/architecture/ covering the two-layer model (Broadcaster transport vs. StreamingSession application), how they compose, why they can't and shouldn't be unified, and where AgentFleet fits as the orchestration layer on top.
38 files stripped of verbose AI-generated Javadoc. Replaced bloated HTML-heavy class-level docs with concise 2-4 line descriptions. Net change: +119/-688 lines.