The opc-ua driver (Eclipse Milo + netty + jaxb universe) exhausts the
16GB hosted runner during the native-image analysis step even with
-J-Xmx10g; it builds fine on larger local machines. Its native image has
never shipped, so dropping it from the matrix removes nothing users
already have. It stays on the JVM line with dnp3/ble/opc-da until the
heap cap is property-driven or a larger runner hosts the job.
Co-Authored-By: Claude Code <noreply@anthropic.com>
Both drivers died at boot with NoClassDefFoundError on
org.slf4j.MarkerFactory: their protocol SDKs (Paho, Modbus4J via the
mangoautomation repository) exercise ServiceLoader paths that
DriverNativeRuntimeHints does not express, and unlike the rest of the
driver line they had no agent snapshot to close the gap. The snapshots
are committed per native_agent_collect.sh's stated-reason exception:
booting each repackaged JAR with the native-image-agent records the
SLF4J/logback binding metadata the closed-world analysis needs.
Verified by rebuilding both native images from scratch and running them
bare against a live broker: both subscribe on untagged dc3.q.* queues
and stay up instead of crash-looping.
Co-Authored-By: Claude Code <noreply@anthropic.com>
Native binaries cannot re-resolve the spring.profiles.active
${NODE_ENV:dev} placeholder at runtime: the AOT pass freezes the dev
profile (and application-dev.yml) into the image. RabbitEnvironmentConfig
then reads spring.env=dev and prefixes every exchange and queue with the
dev_<user> isolation tag, which silently splits the broker topology
against JVM services running with NODE_ENV=test (messages end up
NO_ROUTE between the two lines).
Build-time profile pinning does not reach the AOT snapshot (verified
with NODE_ENV, SPRING_PROFILES_ACTIVE env vars and MAVEN_OPTS system
properties). SPRING_ENV feeds the same EnvironmentPostProcessor through
the system-environment property source, which outranks profile YAML at
runtime, so one ENV default in native-runtime-base covers every native
target. Deployments that want an isolation tag can override the
variable.
Verified by rebuilding dc3-driver-virtual-native and running the image
bare: subscriptions now use untagged dc3.q.* names.
Co-Authored-By: Claude Code <noreply@anthropic.com>
Two fast CI gates caught the tail of the driver native campaign: the
root pom declared swagger-annotations-jakarta twice (the pin already
existed next to the mockito pins - Maven 4 treats the duplicate
dependencyManagement entry as an error, which killed every early plain
mvn invocation on CI while local 3.9 only warned), and the r2dbc
migration gate's literal jdbc: pattern matched the hyphenated
'sqlite-jdbc:' inside a DriverNativeRuntimeHints comment. Remove the
duplicate entry and reword the comment; no gate semantics change.
Co-Authored-By: Claude Code <noreply@anthropic.com>
Sl651DriverCustomServiceImpl reaches the SL651 stack through
Class.forName and a JDK proxy over an optional dependency. Without
registration a native image silently takes the sl651ApiMissing branch:
the driver boots and reports health but never receives a message. Add a
module-level Sl651NativeRuntimeHints registering SL651Server and
ISl651MessageListener, wire it through aot.factories, and carry the
module's tracing snapshot. Functional acceptance remains a live SL651
message round-trip on real hardware.
Co-Authored-By: Claude Code <noreply@anthropic.com>
Batch 3 joins the native line: modbus-rtu, serial, mbus, dlt645, dlms
and zigbee - the jSerialComm serial family. jSerialComm ships no
native-image configuration of its own, so DriverNativeRuntimeHints
registers the embedded per-platform JNI libraries as resources and the
SerialPort JNI surface explicitly (string-based references keep
non-serial drivers unaffected). The tracing snapshots carry the early
boot surface only - serial paths open on device access and stay covered
by the explicit registrations. zigbee is best-effort: no radio hardware
locally, gRPC registration and scheduling are the acceptance line.
Co-Authored-By: Claude Code <noreply@anthropic.com>
Batch 2 joins the native line: mysql, postgresql, sqlserver, oracle,
redis and kafka - database dialects and messaging clients, all pure
Java. DriverNativeRuntimeHints gains the four JDBC dialect driver
constructors (string-based TypeReferences; each class exists only on
its own driver's classpath and native-image ignores hints for absent
classes). Same generated shape as the previous batches: targets, matrix
entries, compose blocks and per-driver agent snapshots.
Co-Authored-By: Claude Code <noreply@anthropic.com>
Batch 1b joins the native line: knx, bacnet-ip, melsec, plcs7, lorawan,
opc-ua, lwm2m and iec61850 - pure-Java protocol SDKs (calimero,
bacnet4j, iot-communication, milo, leshan, openiec61850). iec61850's
GOOSE raw-ethernet paths stay untested on native and are validated in
TCP mode only, as flagged in the CI matrix comment. Same shape as batch
1a: native targets, matrix entries, compose overlay blocks behind the
native-drivers profile, and per-driver agent snapshots.
Co-Authored-By: Claude Code <noreply@anthropic.com>
Batch 1a joins the native line: tcp-udp, listening-virtual, can,
ethernet-ip, fins, http, snmp, iec104 and coap - pure-Java protocol
stacks with no JNI dependencies. Native targets mirror the jar line's
directory layout (listening-virtual keeps its TCP/UDP EXPOSEs), the CI
matrix gains the nine entries, and the compose overlay defines the nine
services behind the native-drivers profile with keys matching
docker-compose.yml so overlay semantics hold (the pilot keys are renamed
to the short main-compose form for the same reason).
Each driver carries a tracing-agent snapshot per the dual-track policy:
RuntimeHints covers the shared SDK surface, snapshots carry the
logback/logstash parsing depth and per-protocol reflective access.
Co-Authored-By: Claude Code <noreply@anthropic.com>
The first native boot of dc3-driver-virtual died in MarkerFactory's
static initializer: the SLF4J->logback binding needs the full logback
config-parsing reflection surface (TurboFilter, DefaultJoranConfigurator,
PatternLayoutEncoder, the logstash encoder family), which the bounded
RuntimeHints subset cannot express. Commit the tracing-agent snapshot -
same dual-track as the six native services - and declare the
MAVEN_OPTS_EXTRA build arg the driver stage references.
Co-Authored-By: Claude Code <noreply@anthropic.com>
Parameterize the agent-collection script with
DC3_NATIVE_AGENT_SERVICES and state the driver policy: snapshots are
diagnostics only, the driver line is driven by RuntimeHints. Extend the
helm README's native section with the pilot batch and the three drivers
that stay on the JVM (dnp3 Rust FFI, ble TinyB/JNA, opc-da vendored
DCOM).
Co-Authored-By: Claude Code <noreply@anthropic.com>
A serial driver loop cannot fit the 360-minute GitHub job cap once the
later batches join. Add a build-native-drivers matrix job (one driver
per job, fail-fast off, max-parallel five, its own gha cache scope) that
pins the NATIVE_SERVICE build arg to the matrix service, and gate the
release job on it.
Co-Authored-By: Claude Code <noreply@anthropic.com>
Define driver-virtual (default) plus driver-mqtt and driver-modbus-tcp
behind a native-drivers profile; they need an external broker / modbus
slave to talk to. Container names, aliases and volumes match
docker-compose.yml one-for-one, so the JVM and native variants never
collide and stay freely mixable with the jar compose stack.
Co-Authored-By: Claude Code <noreply@anthropic.com>
Add a driver-native-builder stage that installs and native-compiles
exactly one driver per build, selected by the NATIVE_SERVICE build arg.
Kept separate from native-builder so the center build's cached layers
stay byte-identical: ARG values participate in the BuildKit cache key,
and the CI matrix needs every job to compile only its own driver. Ship
the pilot targets dc3-driver-{virtual,mqtt,modbus-tcp}-native with the
jar line's directory layout so volumes and log paths keep matching.
Co-Authored-By: Claude Code <noreply@anthropic.com>
Register the driver SDK's reflective runtime paths (Quartz jobs,
@Dc3Listener receivers, Caffeine policies, sqlite-jdbc buffer resources,
logback/gRPC ServiceLoader descriptors) so driver modules can be AOT
processed like the centers.
Driver AOT processing surfaced a latent classpath bug: dc3-common-public
declared the springdoc starter but uses none of it, so its SpringDocHints
registrar (which unconditionally references spring-web) blew up AOT for
every driver - drivers have no spring-web. Drop the stale dependency and
let each real consumer declare its own: model and the gateway common
module take the annotation-only swagger-annotations-jakarta (model sits
on the driver classpath), while data/auth/agentic take the starter for
GroupedOpenApi.
Verified: process-aot on dc3-driver-virtual emits all hints into the
spring-aot reachability metadata; spotless, checkstyle and documentation
gates pass, as do the public and module test suites.
Co-Authored-By: Claude Code <noreply@anthropic.com>
The card wall change quoted the Chinese auto-size label inside code
comments; check_documentation.py rejects non-English comments and the
web CI quality gate failed on it. Quote the English label in those
examples instead. The bilingual button matcher in the responsive e2e
spec is functional code (it matches either locale) and stays.
Co-Authored-By: Claude Code <noreply@anthropic.com>
Raw Windows backslash paths never matched the guardrails'
separator-agnostic directory filters, so the suite passed vacuously on
dev machines while still enforcing on POSIX CI. Normalize to POSIX
separators at the walk source so the guards actually scan everywhere.
Co-Authored-By: Claude Code <noreply@anthropic.com>
Fixed 12-per-page card walls left ragged trailing rows at wide viewports
and over-fetched on narrow ones. Derive the page size from the wall's
measured column count, pad the last row with ghost slots so the grid
never ends ragged, keep the previous page under an activity line while
revalidating (no skeleton flash), and let users pin a size via an
explicit auto/manual select beside the pager. Cursor walls keep their
prev/next controls running beside the select, and size changes reset the
cursor stack where position cannot be preserved. Ships with unit,
component, guardrail and responsive e2e coverage.
Co-Authored-By: Claude Code <noreply@anthropic.com>
Backend versions answer /token/salt with either a {salt} envelope or a
bare salt string; the envelope-only read bricked login on the bare form
before generateToken fired. Resolve both shapes in the login flow and
keep pure payload adapters out of src/api so the transport-contract
matrix stays exact. Covers the bare-string and empty-salt shapes with
unit tests.
Co-Authored-By: Claude Code <noreply@anthropic.com>
The httpOnly-cookie auth refactor changed generateSalt and the token
endpoints to object responses, and the device dashboard wrapper now
carries device_id as a query parameter; the stale mocks, assertions,
and snapshots never ran on CI because earlier gate layers failed
first. Update them to the current contracts.
Co-Authored-By: Claude Code <noreply@anthropic.com>
The agentic component tests drove reactivity through
wrapper.vm.$nextTick(), which the ai-guardrails contract rejects as
coupling to component internals. Use flushPromises from the test utils
surface instead.
Co-Authored-By: Claude Code <noreply@anthropic.com>
Linux jSerialComm throws SerialPortInvalidPortException from
getCommPort on invalid descriptors instead of returning an unopenable
port object, so every serial driver leaked a runtime exception on
adversarial configs instead of failing safe. Wrap the four serial
connection factories (dlt645, mbus, serial, modbus-rtu) and surface the
failure as a ConnectorException.
Surfaced by the adversarial contract on the Linux CI runner, where the
Windows-local run masked it.
Co-Authored-By: Claude Code <noreply@anthropic.com>
The device-scoped dashboard endpoints and the device-status detail route
used @PathVariable paths, violating the route-naming contract that has
been in force since the quality-gate standardization. Move the device id
to a device_id query parameter across the ten routes and align the web
client callers.
Co-Authored-By: Claude Code <noreply@anthropic.com>
The agentic SystemTool must expose a synchronous contract to Spring AI
(reactive returns serialize the publisher, not the result) and the
runtime drives those callbacks on the bounded elastic scheduler, so
both bridges are deliberate and bounded. Document them next to the
existing startup-validator exemption instead of weakening the scan.
Co-Authored-By: Claude Code <noreply@anthropic.com>
The mockito jar sha1 pin still targeted the pre-upgrade artifact while
the build resolves 5.24.0, so every CI run failed the agent-integrity
check even after refetching. Re-pin to the 5.24.0 jar sha1 verified
against Maven Central metadata.
Document the InsightApi.Invoke RPC in the dc3-api-data README so the
proto-to-documentation guard passes.
Co-Authored-By: Claude Code <noreply@anthropic.com>
Spring AI 2.0.1's MethodToolCallback serializes the declared return
value as-is: a Mono return type serialized the publisher object, and
Jackson rendered reactor's isScanAvailable() getter as
{"scanAvailable":true}. Every SystemTool call - including the
pre-existing getSystemHealth - returned that garbage instead of data.
Rewrite SystemTool as synchronous with a bounded block, and run @Tool
callbacks on the bounded elastic scheduler in the runtime so the block
never lands on the event loop. Add a Spring AI bridge regression test
that fails if the serialized shape ever degrades again.
Found by the live agent during the status-tool end-to-end run.
Co-Authored-By: Claude Code <noreply@anthropic.com>
The analytics percentile helper interpreted its input strictly as a
[0,1] fraction, so agent callers spelling percentiles as percentages
(95) or drifting past the scale crashed computeStats with an
ArrayIndexOutOfBoundsException. Normalize percentage-spelled values and
clamp the remainder so the agent surface degrades gracefully.
Found by the live agent during the insight-channel end-to-end run.
Co-Authored-By: Claude Code <noreply@anthropic.com>
spring boot 4.1.1 moved the integration auto-configuration out of the
main autoconfigure jar, no module pulls spring-boot-integration and
none declares @EnableIntegration, so the messaging annotation
infrastructure is absent on every consumer classpath and the
@ServiceActivator endpoints were silent no-ops: the inbound channel
had producers only and the first message killed the paho connection.
subscribe explicit EventDrivenConsumer beans for both directions
(identical to what the annotation machinery would have created),
guard with message-flow tests that reproduce the exact production
exception on the old wiring, and prove the full production path
against a real mosquitto broker via the MqttContainer IT.
Co-Authored-By: Claude Code <noreply@anthropic.com>
Harden the agentic tool gate with two guards: every registered tool's
input schema must be parseable JSON, and every canonical insight
operation must route to its backing service without unknown-operation
errors.
Fix the pre-existing JdbcDriverCustomServiceTest failure where the
connection validity stub used isValid(5) while the production health
probe calls isValid(2), leaving the stub unmatched and the assertion
flipping to OFFLINE.
Co-Authored-By: Claude Code <noreply@anthropic.com>
Register the seven implemented-but-unregistered tool methods
(command/event by-device, by-profile and batch lookups plus driver batch
lookup), expose the four idle StatusHealthFacade fleet-status reads
through SystemTool, and add InsightTool (25 operations via the insight
channel) and HistoryTool (command/event record lookups) to the reactive
registry - growing the surface from 28 to 64 tools.
Lock the exact registry tool-name set in a test so any future orphan
method fails the build instead of silently disappearing.
Co-Authored-By: Claude Code <noreply@anthropic.com>
Add a generalized insight channel (insight.proto + InsightDispatcher +
InsightServer) routing 25 read-only operations - alert analytics,
dashboard stats, the nine analytics agent-surface operations and the
point command status lookup - through JSON payloads so both gRPC and
local transports share one routing implementation with defensive
argument clamping.
Add strong-typed CommandHistoryFacade and EventHistoryFacade contracts
(BO, local implementation, gRPC implementation, stub beans and both
auto-configuration whitelists) so agents can trace command execution
results and reported events.
Co-Authored-By: Claude Code <noreply@anthropic.com>
californium 4.0.0-M6 clients never auto-create a transport endpoint,
so client.getEndpoint().getConfig() NPE'd on every read and write
before any udp packet was sent. build a started endpoint per client
with the configured timeouts (previously the write path never received
them), fail loudly if an endpoint is somehow missing, and guard with
in-jvm coap server end-to-end tests for get and put.
Co-Authored-By: Claude Code <noreply@anthropic.com>
@ConditionalOnBean on a component-scanned handler evaluates during
scanning, before the driver's MqttReceiveServiceImpl definition is
registered, so the subscriber bean was never created: the inbound
channel had producers only, the first message killed the paho
connection with no reconnect, and the mqtt driver could never deliver
data. move the handler, its @ServiceActivator, and the schedule job
into MqttConfig's auto-configuration where conditions evaluate after
all consumer definitions exist; guard with ApplicationContextRunner
tests that fail on the old arrangement (proven by stash-and-rerun).
Co-Authored-By: Claude Code <noreply@anthropic.com>
the fingerprint sync tool only knew two compose distribution points, so
native, scale, single and swarm still defaulted to the pre-attachment
hash while the running database and the other stacks moved on. register
all six compose files as distribution points and resync.
Co-Authored-By: Claude Code <noreply@anthropic.com>
23 of 36 driver modules (and dc3-center-single) never shipped
application-{test,pre,pro}.yml while the compose anchor hardcodes
NODE_ENV=test, so spring.rabbitmq fell back to localhost:5672 and the
containers crash-looped out of the box. the connection placeholders now
live once in dc3-mq-rabbitmq's application-rabbitmq.yml, whose profile
ActiveRabbitProfileConfig already activates in every embedding service;
83 copy-pasted per-module blocks removed (also fixing drifted port
defaults 35672/45672 inside four modules) and a validator
(validate-driver-config) now enforces the single source.
Co-Authored-By: Claude Code <noreply@anthropic.com>
every remaining document was either a living deployment guide, an
active design baseline, or an unimplemented proposal - all retrievable
from git history. the open work they carried now lives in issues:
#259 r2dbc acceptance gates, #260 comparison adoption candidates, plus
the design-direction issues referenced there. all inbound references
(agents, contributing, seven multilingual readmes, compose comments,
gateway config, module readmes, source comments) updated so nothing
points at the removed tree.
Co-Authored-By: Claude Code <noreply@anthropic.com>
the r2dbc migration handoff defined release gates that never ran - the
gate stages moved to issue #259 (full text stays in git history) and
relational-r2dbc.md remains as the semantic baseline. the ai-assistant
tech-debt audit is 10/10 fixed; its one long-term survivor (indexeddb
persistence) is recorded on issue #255. the two competitive comparisons
were open-review reference, never a roadmap; their adoption candidates
moved to issue #260.
Co-Authored-By: Claude Code <noreply@anthropic.com>
mq-abstraction (four broker adapters now tck-gated), storage-abstraction
(flag day, postgres-only runtime), and tsdb-abstraction (single
implementation, no historical adapters) all describe designs that live
in the code now; their semantics are enforced by tests, not prose.
relational-r2dbc stays: it is the design baseline the r2dbc migration
test handoff still validates against. cross-references in the
comparison docs and mcp-runtime-overhaul updated to plain wording.
Co-Authored-By: Claude Code <noreply@anthropic.com>
the web low-defects handoff was fully executed (spot-verified: the
loadMessages streaming guard, menu cycle guard, paged-list clamp,
e2e port fail-fast all landed); its five human-decision items moved
to issue #257 (password-in-url split out to #256). the thing-model
review was a factual capability snapshot; its open gaps moved to
issue #258.
Co-Authored-By: Claude Code <noreply@anthropic.com>
the report served its purpose: every finding is fixed and guarded by
executable tests, the fix history lives in git, and the still-open
items moved to issues #251-#255.
Co-Authored-By: Claude Code <noreply@anthropic.com>
append the wsl docker rebuild campaign: 46 live checks, the two
failures root-caused (attachment identity, spa fallback), the on-disk
fixes, and the decision items observed against the real stack.
Co-Authored-By: Claude Code <noreply@anthropic.com>
the driver status endpoints serialize lowercase online/offline;
align the javadoc and openapi descriptions so consumers are not told
to expect uppercase codes.
Co-Authored-By: Claude Code <noreply@anthropic.com>
the auth salt endpoint now answers with a json object; read the salt
field instead of stripping quotes off a bare text body.
Co-Authored-By: Claude Code <noreply@anthropic.com>
location / only had root and index, so path-shaped urls like /login
returned the default nginx 404 page instead of the app shell; hash
routing masked it, but manual and external links broke. Add try_files
$uri $uri/ /index.html.
Co-Authored-By: Claude Code <noreply@anthropic.com>
dc3_attachment.id lacked GENERATED BY DEFAULT AS IDENTITY (unlike
dc3_session/dc3_message), so R2dbcAttachmentStore inserts without an
id violated NOT NULL and every upload failed with HTTP 500. Add the
identity clause to the canonical initdb DDL, ship idempotent migration
04 for databases initialized before the fix (with a setval guard so
pre-existing explicit ids never collide), and resync the canonical
fingerprint 0d9ad803... across the embedded hash and every distributed
default.
Co-Authored-By: Claude Code <noreply@anthropic.com>
adopts the remaining uncommitted work from the parallel session:
five new guardian test files (client-errors, device-import-template,
entity-id-guard, jwt-guard, option-hygiene) that lock in the error
taxonomy, id encoding, and cli option hygiene; an attachment file
cleaner in the agentic service; attachment controller and service
tests; a salt-type fix in the auth store; ci workflow typecheck step;
and the cli test report. 818 tests total across 37 files.
Co-Authored-By: Claude Code <noreply@anthropic.com>
four columns left the sixth tile dangling on a second row alone;
three columns closes the 2x3 row math to match the point dashboard.
Co-Authored-By: Claude Code <noreply@anthropic.com>