Nightly architectural bug hunt flagged a severity:high lead asserting that
ClientNodeManager and ServerNodeManager use incompatible concurrency primitives
(Mutex+StateFlow vs. ThreadLocal+direct DB writes) and lack a shared protocol
for “CREATED → READY” node lifecycle transitions, risking divergent state during
concurrent requests.
The hypothesis was a false positive. Three specific claims were made; all were incorrect:
“CREATED → READY” transition — NodeState contains no READY value. The
local model hallucinated a state machine that does not exist in the codebase.
ThreadLocal is “fragile across dispatcher hops” — PropagationContextElement
correctly implements ThreadContextElement<PropagationContext?>, the KotlinX-coroutines
mechanism designed specifically to propagate thread-local values across coroutine
dispatchers. updateThreadContext / restoreThreadContext install and restore the
value on the worker thread for the full duration of a coroutine, including after any
suspension. The scanned code at ServerNodeManager.kt:72-92 is the correct and
idiomatic implementation.
Architectural mismatch — ClientNodeManager (in-memory StateFlows for
Compose UI) and ServerNodeManager (H2 database + SharedFlow for SSE) are
intentionally different because they serve different roles. The client receives
updates from the server via SSE/REST; they are not competing concurrent writers to
shared state. The difference between the two managers is the design, not a gap.
No production code change. Added PropagationContextPropagationTest in
server/src/jvmTest/ to explicitly prove:
suppressPublish = true in an ambient
PropagationContext correctly suppresses update()’s observable-flow publication
when pinned via PropagationContextElement.invoke() is inherited by
the NodePublication emitted from update() in the same coroutine.ThreadContextElement contract: PropagationContextElement correctly installs
the context on the coroutine’s thread and restores the prior context when the
coroutine exits.NodeState value by name, verify the
value exists before treating the lead as actionable. The state machine is the
ground truth; local-model descriptions of it are not.ThreadContextElement is the correct KMP/JVM pattern for threading non-suspending
context through coroutine dispatch. Don’t mistake it for a raw ThreadLocal with
no coroutine awareness.ServerNodeManagerFlowTest, ServerNodeManagerStateChangeTest, and
ServerNodeManagerCompletionTest provide good coverage of the publish gate and
completion contract. PropagationContextPropagationTest now adds explicit proof of
the ThreadContextElement dispatch behaviour so future leads against this design
have a named test to cite.