Skip to content

bug: 13 engine-layer fields use volatile on non-thread-safe types (Sonar S3077) #424

@jlouvel

Description

@jlouvel

Component

Core Engine

Description

Actual behavior:

13 fields across the engine layer (io.naftiko core + io.naftiko.engine.*) are declared volatile on non-thread-safe types — volatile NaftikoSpec, volatile List<ServerAdapter>, volatile Map<String, Object>, volatile StdioJsonRpcHandler, volatile Thread, etc. These are flagged by SonarQube rule java:S3077"Non-thread-safe fields should not be volatile".

volatile only publishes the reference, not the contents: if thread A reads volatile List<ServerAdapter> and thread B mutates the list elements, behavior is undefined. Engine classes have stronger concurrency requirements than spec POJOs because they are touched on the request path:

  • Capability.java collects adapters during start() and exposes them to request threads.
  • A future "hot reload via Control port" feature will mutate these fields at runtime.
  • TelemetryBootstrap holds a process-wide singleton handed off across threads.

Expected behavior:

Apply the same AtomicReference<T> + immutable snapshot pattern established in Phase 2 (#422 / PR #423). For the singleton holder in TelemetryBootstrap, prefer the initialization-on-demand holder idiom when a true singleton — fall back to AtomicReference only if reset at runtime is needed.

Steps to Reproduce

  1. Run the full SonarQube scan (Quality Gate workflow).
  2. Filter issues by rule = java:S3077 AND component path under io.naftiko.engine.* or io.naftiko.Capability.
  3. Observe 9 occurrences flagged across the engine layer (run #1516, main @ dcfd01c).

By file:

File Volatile fields S3077 hits
io/naftiko/Capability.java 7 7
io/naftiko/engine/consumes/ClientAdapter.java 2 varies
io/naftiko/engine/exposes/mcp/McpServerAdapter.java 2 varies
io/naftiko/engine/scripting/ScriptStepExecutor.java 1 1
io/naftiko/engine/observability/TelemetryBootstrap.java 1 (static) 1

Capability File (if relevant)

Not capability-specific.

Logs & Stacktrace

Not a runtime failure (latent thread-safety issue). Sonar evidence: Quality Gate run #1516 — main @ dcfd01c.

Version

1.0.0-alpha3-SNAPSHOT (current main)

Runtime

JVM

Agent Context (optional)

agent_name: GitHub Copilot
llm: claude-opus-4.7
tool: copilot-chat
confidence: high
source_event: SonarQube quality gate run #1516 (main @ dcfd01c)
discovery_method: code_review
files_suspected:
  - src/main/java/io/naftiko/Capability.java
  - src/main/java/io/naftiko/engine/consumes/ClientAdapter.java
  - src/main/java/io/naftiko/engine/exposes/mcp/McpServerAdapter.java
  - src/main/java/io/naftiko/engine/observability/TelemetryBootstrap.java
  - src/main/java/io/naftiko/engine/scripting/ScriptStepExecutor.java

Proposed Fix (Phase 3 of sonar-bug-remediation)

Apply the same Pattern A/B/C established in Phase 2:

File Field Recommendation
Capability.java spec AtomicReference<NaftikoSpec>
Capability.java serverAdapters AtomicReference<List<ServerAdapter>> with List.copyOf
Capability.java clientAdapters AtomicReference<List<ClientAdapter>> with List.copyOf
Capability.java aggregates AtomicReference<List<Aggregate>> with List.copyOf
Capability.java bindings AtomicReference<Map<String, Object>> with Map.copyOf
Capability.java scriptingSpec AtomicReference<ScriptingManagementSpec>
Capability.java stepHandlerRegistry AtomicReference<StepHandlerRegistry>
ClientAdapter.java capability, spec AtomicReference<T>
McpServerAdapter.java stdioHandler, stdioThread AtomicReference<T>
ScriptStepExecutor.java scriptingSpec AtomicReference<ScriptingManagementSpec>
TelemetryBootstrap.java instance (static) Initialization-on-demand holder idiom or AtomicReference<TelemetryBootstrap> if reset is needed

Public API contract preserved: getters return plain types. Setters take plain types and store immutable snapshots for collections.

Scope of this issue: 5 engine files. Spec POJO layer (Phase 2, #422) and char[] auth fields (Phase 4) are tracked separately.

Out of scope: fluent builder methods on engine classes — they will follow once the spec layer builders land.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions