Skip to content

[roadmap] 006 — NATS Transport #6

@oluies

Description

@oluies

Draft planning artifact generated via spec-kit — see specs/006-nats/ (spec, plan, research, data-model, contracts, quickstart, tasks).

⚠️ Unverified draft: authored without a build environment (no Gradle/JDK 17/network/TIBCO/DuckDB). On branch t/yolo-d76fe7 (not yet pushed).

Tasks (mirrors specs/006-nats/tasks.md)

Phase 1: Setup

  • T001 (build-env) Add io.nats:jnats (Apache-2.0, pure-Java, single pinned version — research R6, verify latest) to gradle/libs.versions.toml and wire it into build.gradle.kts (feature 001 files); confirm it resolves and loads on the Java 17 toolchain (FR-018; CONTRACT-NATS-DEP-1/2; SC-006)
  • T002 [P] Create the package src/main/org/rvsnoop/transport/nats/ (Apache-2.0 file headers) for the adapter, config, converter, subjects, factory, and Guice module classes
  • T003 [P] Create the test package src/test/org/rvsnoop/transport/nats/ (Apache-2.0 file headers) for the offline unit tests and the opt-in integration test
  • T004 (build-env, gate) Evaluate an Apache-2.0 + Java-17 in-process/embeddable NATS server harness (candidate io.nats:jnats-server-runner — research R5) and, if it qualifies, add it as a pinned dev/test-scoped dependency in gradle/libs.versions.toml + build.gradle.kts; if none qualifies, record the fallback to mock-only tests in research.md (FR-018/FR-019; CONTRACT-NATS-DEP-1, CONTRACT-NATS-TEST-2; SC-005/SC-006)

Phase 2: Foundational (Blocking Prerequisites)

  • T005 (gate; depends on feature 004) Reconcile against the feature-004 surface: confirm the exact Transport port signature (connect/subscribe/publish/close), the registry registration mechanism, the neutral connection model, and the common connection-state model; record any deltas in research.md (R3, R7). If the 004 port differs from the planned surface, only the thin adapter classes change (plan Complexity Tracking; FR-001, FR-011)
  • T006 (gate; depends on features 004/002) Confirm the shared NeutralMessage permits a single raw-bytes leaf and string / string-list fields, and that the record detail view renders bytes (hex/text) without mangling; if it lacks a raw-bytes leaf, coordinate a small additive extension once with 004/002 (do NOT duplicate the neutral model) — research R1 (FR-009/FR-010; CONTRACT-NATS-MSG-2; SC-002)
  • T007 Define NatsAuthMode enum (ANONYMOUS | USER_PASSWORD | TOKEN | CREDS_FILE) in src/main/org/rvsnoop/transport/nats/NatsAuthMode.java per data-model.md (FR-003)
  • T008 [P] Implement NatsSubjects (subject validation + local NATS wildcard matcher: * = exactly one token, > = one-or-more trailing tokens only as final token, reject empty tokens / non-tail >) in src/main/org/rvsnoop/transport/nats/NatsSubjects.java — research R2 (FR-006, FR-014; CONTRACT-NATS-SUBJ-1/2/3/4/6; SC-003)
  • T009 [P] Implement NatsClientFactory seam over the jnats Connection/dispatcher (mockable for offline tests; production impl wraps jnats) in src/main/org/rvsnoop/transport/nats/NatsClientFactory.java — research R5 (FR-019; CONTRACT-NATS-TEST-1)
  • T010 Implement NatsConnectionConfig (transportKind="nats", name, serverUrls ≥1, authMode + credential fields, tlsEnabled, reconnectionPolicy, subscriptions) and NatsSubscriptionConfig (subject, optional queueGroup, runtime active) with validation rules, in src/main/org/rvsnoop/transport/nats/NatsConnectionConfig.java and src/main/org/rvsnoop/transport/nats/NatsSubscription.java, specializing the feature-004 neutral connection model — data-model.md (FR-002/003/004/005/007/014)
  • T011 Implement NatsMessageConverter: NATS msg → shared NeutralMessage — concrete delivery subject, single raw-bytes payload leaf, headers as named string/string-list fields, reply-to when present, and envelope (timestamp, originating connection, sequence); no structural body parsing, in src/main/org/rvsnoop/transport/nats/NatsMessageConverter.java — research R1, data-model.md (FR-008/009/010; CONTRACT-NATS-MSG-1/2; SC-002)

Phase 3: User Story 1 - Capture messages from a NATS subject (Priority: P1) 🎯 MVP

  • T012 [P] [US1] NatsSubjectsTest — wildcard match correctness across the tested subject set (foo.* matches foo.a/foo.b not foo.a.b; foo.> matches foo.a.b/foo.a; reject > not in tail position and empty tokens) with zero false matches/misses, in src/test/org/rvsnoop/transport/nats/NatsSubjectsTest.java (CONTRACT-NATS-SUBJ-2/3/4/6; FR-006; SC-003)
  • T013 [P] [US1] NatsMessageConverterTest — conversion preserves subject + raw payload bytes; binary payload byte-for-byte (no truncation/mangling); empty payload not dropped; no-headers and multi-valued headers; reply-to recorded, in src/test/org/rvsnoop/transport/nats/NatsMessageConverterTest.java (CONTRACT-NATS-MSG-1/2/3/4/5/6; FR-009/010; SC-002)
  • T014 [P] [US1] NatsTransportLifecycleTest (subscribe/deliver slice) — via the mock seam, a published message on a subscribed subject delivers a NeutralMessage record; stopping/removing a subscription produces no further records; overlapping subscriptions yield one record per delivery received and do not corrupt the trace, in src/test/org/rvsnoop/transport/nats/NatsTransportLifecycleTest.java (CONTRACT-NATS-LIFE-5/6; FR-005/013)
  • T015 [US1] Implement NatsTransport core — connect(NatsConnectionConfig) opening a jnats connection via the seam, and close() draining/unsubscribing and releasing the connection, in src/main/org/rvsnoop/transport/nats/NatsTransport.java (implements the 004 Transport port) (FR-001; CONTRACT-NATS-PORT-1)
  • T016 [US1] Implement subscribe(subject, queueGroup?) in NatsTransport: subject passed to NATS verbatim, optional queue-group, message delivery on jnats dispatcher threads handing NeutralMessage records to the existing async ledger path off the UI thread; publish(...) is a no-op (passive tracer), in src/main/org/rvsnoop/transport/nats/NatsTransport.java (FR-005/006/007/008/013/020; CONTRACT-NATS-SUBJ-1/5, CONTRACT-NATS-LIFE-6/7, CONTRACT-NATS-MSG-1)
  • T017 [US1] Implement NatsTransportModule (Guice) registering the adapter under transport kind "nats" in the feature-004 registry — additive, no core/UI/other-adapter edits, in src/main/org/rvsnoop/transport/nats/NatsTransportModule.java (FR-001/021; CONTRACT-NATS-PORT-1/2)
  • T018 [US1] (depends on feature 004) Install NatsTransportModule in the app's Guice bootstrap (one binding line) in src/main/org/rvsnoop/RvSnoopModule.java (or the app's module) — additive only (FR-001/021; CONTRACT-NATS-PORT-1)
  • T019 [US1] Verify quickstart Scenario 1 (capture from foo.bar), Scenario 2 (wildcards foo.*/foo.>), Scenario 3 (stop subscription), Scenario 4 (filter/search over NATS records), and Scenario 5 (payload-fidelity edge cases) via the mock seam (SC-001/002/003)

Phase 4: User Story 2 - Configure and persist a NATS connection (Priority: P2)

  • T020 [US2] Map the four auth modes onto jnats Options/AuthHandler (anonymous; userInfo; token; credentials authenticator for .creds) and the TLS toggle (secure/sslContext) in NatsTransport.connect, in src/main/org/rvsnoop/transport/nats/NatsTransport.java — research R4, data-model.md (FR-003/004; CONTRACT-NATS-CFG-2/3)
  • T021 [US2] Implement config validation surfacing clear errors with no zombie connection: ≥1 well-formed server URL, the credential required by the selected auth mode present, .creds file readable/parseable; reject before any connect attempt, in src/main/org/rvsnoop/transport/nats/NatsConnectionConfig.java (FR-014; CONTRACT-NATS-CFG-1/4)
  • T022 [US2] Distinguish authentication failures from network/connectivity failures by inspecting the jnats auth-violation callback/exception type, and ensure credentials (password, token, .creds path/contents) are never written to logs in plaintext, in src/main/org/rvsnoop/transport/nats/NatsTransport.java — research R4 (FR-015/017; CONTRACT-NATS-CFG-5/6)
  • T023 [US2] (depends on feature 002) Persist/restore NatsConnectionConfig + its NatsSubscriptionConfig list through the existing project-store path (the 004 neutral connection model, kind "nats"); secrets follow the project credential policy, in the store-integration glue (per feature-002 store path) (FR-016/017; CONTRACT-NATS-CFG-7, CONTRACT-NATS-MSG-7)
  • T024 [P] [US2] Implement NatsConnectionPanel plugging into the shared new-connection dialog (server URLs, auth-mode selector + credential fields, TLS toggle, subscriptions) — no NATS-specific top-level flow, in src/main/org/rvsnoop/ui/NatsConnectionPanel.java (FR-002/003/004/005/007; SC-001; CONTRACT-NATS-PORT-1)
  • T025 [P] [US2] Add i18n labels for the panel in src/main/org/rvsnoop/ui/NatsConnectionPanel.properties (mirrors the existing *.properties convention)
  • T026 [P] [US2] NatsConnectionConfigTest — config validation (malformed URL, missing credential, unreadable .creds), all four auth modes configure/persist/restore, TLS toggle, auth-vs-network error distinction, no-plaintext-secret in logs, in src/test/org/rvsnoop/transport/nats/NatsConnectionConfigTest.java (CONTRACT-NATS-CFG-1/2/3/4/5/6; FR-003/004/014/015/017; SC-004)
  • T027 [US2] Verify quickstart Scenario 6 (persist all auth modes), Scenario 7 (auth + TLS at start), and Scenario 8 (invalid config + auth-vs-network errors) (SC-004)

Phase 5: User Story 3 - Resilient connection lifecycle (Priority: P3)

  • T028 [US3] Map jnats ConnectionListener events (CONNECTED/DISCONNECTED/RECONNECTED/CLOSED/LAME_DUCK — verify exact enum names) onto the feature-004 common connection-state model (started, paused, resumed, disconnected, reconnected, failed) and surface them through the same UI path as other transports, in src/main/org/rvsnoop/transport/nats/NatsTransport.java — research R3, data-model.md (FR-011; CONTRACT-NATS-LIFE-1/2)
  • T029 [US3] Drive jnats reconnection options (maxReconnects, reconnectWait) from the per-connection reconnectionPolicy; on exhausted reconnect surface a failed state with a clear reason while the app stays usable, in src/main/org/rvsnoop/transport/nats/NatsTransport.java — research R3 (FR-012; CONTRACT-NATS-LIFE-3; SC-008)
  • T030 [US3] Implement user pause/resume: pause suspends record dispatch (drain/unsubscribe or suspend the dispatcher, keeping TCP where practical) and resume re-enables delivery, in src/main/org/rvsnoop/transport/nats/NatsTransport.java — research R3 (FR-011; CONTRACT-NATS-LIFE-4)
  • T031 [P] [US3] Extend NatsTransportLifecycleTest — via the mock seam: simulated transient disconnect resumes capture and transitions disconnected→reconnected; pause stops records until resume; exhausted reconnect → failed with a clear reason; capture/connect operations do not block the UI thread, in src/test/org/rvsnoop/transport/nats/NatsTransportLifecycleTest.java (CONTRACT-NATS-LIFE-1/2/3/4/7; FR-011/012/020; SC-008)
  • T032 [US3] Verify quickstart Scenario 9 (disconnect/reconnect resume; pause/resume; exhausted reconnect → failed) via the mock seam (SC-008)

Phase 6: Polish & Cross-Cutting Concerns

  • T033 [P] (broker / opt-in) Implement NatsTransportIntegrationTest against an in-process embeddable NATS server (real subscribe/wildcard delivery + reconnection), gated by an environment/profile flag and skipped by default; if no Apache-2.0 server qualified (T004), document the mock-only fallback, in src/test/org/rvsnoop/transport/nats/NatsTransportIntegrationTest.java (CONTRACT-NATS-TEST-1/2; FR-019; SC-005)
  • T034 [US?]-none (build-env) Run the full NATS test suite with no external server and confirm it passes on the mock seam (offline/CI), per quickstart Scenario 12 (FR-019; SC-005; CONTRACT-NATS-TEST-1)
  • T035 [P] Verify additivity/coexistence (quickstart Scenario 10): a NATS connection and another transport's connection coexist, both feed the same trace with per-connection attribution, and the existing transports' tests pass unchanged — confirm no NATS/jnats type leaks outside org.rvsnoop.transport.nats (+ its UI panel) (FR-021; CONTRACT-NATS-PORT-2/3; SC-007)
  • T036 [P] (build-env) Inspect the dependency graph (quickstart Scenario 12): jnats Apache-2.0 and pinned to one version, no new copyleft, no proprietary jar; reaffirm Dependabot (feature 001) tracks jnats and any test-only server (FR-018; CONTRACT-NATS-DEP-1/2; SC-006; Principles I & V)
  • T037 [P] Update developer docs/README: NATS as a new transport, supported auth modes, JetStream/publish/content-decoding out of scope, offline-test approach
  • T038 Run the full quickstart.md validation (Scenarios 1–12), validating earliest the high-risk Scenarios 5 (payload fidelity), 9 (lifecycle/reconnect), and 12 (offline-only + Apache-2.0 gate)

Metadata

Metadata

Assignees

No one assigned

    Labels

    roadmapSpec-kit roadmap feature (draft plan)

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions