You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Draft planning artifact generated via spec-kit — see specs/005-tibco-ems/ (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/005-tibco-ems/tasks.md)
Phase 1: Setup
T001 [P] Add the JMS API artifact (javax.jms/jakarta.jms matching the pinned EMS client namespace — research R7) to gradle/libs.versions.toml and wire it as a compile+test dependency in build.gradle.kts, pinned to a single version, Dependabot-tracked (FR-014, CONTRACT-LIB-5; research R1/R7) (needs build env)
T002 [P] Add the in-process non-TIBCO JMS test double dependency (test scope only — embeddable Apache-2.0 broker such as ActiveMQ Artemis, or a mocking library; final choice in T011) to gradle/libs.versions.toml + build.gradle.kts, pinned, Apache-2.0-compatible (FR-012/FR-014, CONTRACT-LIB-5; research R3) (needs build env)
T003 [P] Declare the externalized proprietary EMS jar (tibjms.jar + companions) via a build property pointing at a local/secured path in build.gradle.kts — runtime/integration scope only, never committed — mirroring the Rendezvous-jar externalization (FR-010/FR-014, CONTRACT-LIB-1; research R8) (needs build env)
T004 [P] Add the opt-in, environment-gated ems-integration test profile/flag in build.gradle.kts, skipped by default, so the default build/test runs without the EMS jar or a broker (FR-011, CONTRACT-LIB-2/4/6; research R3/R8) (needs build env)
T005 Create the package src/main/org/rvsnoop/transport/ems/ and src/test/org/rvsnoop/transport/ems/ (with Apache-2.0 license headers) for the adapter and its tests, plus src/test/org/rvsnoop/transport/ems/support/ for the JMS test double
Phase 2: Foundational (Blocking Prerequisites)
T006 Confirm feature 004's delivered transport port + registry + NeutralMessage API against the provisional surface assumed in plan.md/data-model.md (connect/subscribe/receive/close; registry kind registration; neutral field-tree API); record any signature deltas and re-check the contract/Constitution gate (FR-001/FR-015; research R2, CONTRACT-EMS-2) (blocked until 004 lands)
T007 Implement the jar-free compile seam: code the adapter against the standard JMS API only, and reach the EMS-specific ConnectionFactory (com.tibco.tibjms.TibjmsConnectionFactory or JNDI) reflectively/by configuration so the proprietary type never lands on the compile classpath, in src/main/org/rvsnoop/transport/ems/EmsConnectionFactoryProvider.java (FR-010/FR-011, CONTRACT-CONV-7/LIB-2; research R1) (needs build env to verify factory class/JNDI name)
T010 [P] Implement EmsProviderAvailability runtime guard (guarded Class.forName of the EMS factory; clear "library must be provisioned" message when absent; never throw NoClassDefFoundError into the UI) in src/main/org/rvsnoop/transport/ems/EmsProviderAvailability.java (FR-016; research R9, CONTRACT-ERR-4)
T011 Implement the in-process non-TIBCO JMS test double (Connection/Session/MessageConsumer/QueueBrowser + the five Message subtypes, with injectable connect/auth/disconnect failures), in src/test/org/rvsnoop/transport/ems/support/FakeJmsProvider.java — the broker-free, jar-free harness for all Phase 3–5 tests (FR-012, CONTRACT-LIB-6; research R3) ([CLARIFY] mock vs embedded Artemis — research R3)
Phase 3: User Story 1 - Trace messages from an EMS topic (Priority: P1) 🎯 MVP
T012 [P] [US1] Connection lifecycle test (start → CONNECTED, selectable as source; stop → delivery ceases, sessions/consumers/connection released) in src/test/org/rvsnoop/transport/ems/EmsTransportTest.java (CONTRACT-EMS-1/3; FR-002/FR-009, SC-001) (needs build env)
T013 [P] [US1] Topic subscription test (messages published to a subscribed topic appear as records attributed to connection+topic) in src/test/org/rvsnoop/transport/ems/EmsSubscriptionTest.java (CONTRACT-SUB-1; FR-003/FR-004, SC-001) (needs build env)
T014 [P] [US1] JmsMessageConverter test covering all five body kinds + headers/properties + empty-body + very-large + uninterpretable body, run with the proprietary jar absent from the classpath (CONTRACT-CONV-1..7; FR-005/FR-006, SC-003) in src/test/org/rvsnoop/transport/ems/JmsMessageConverterTest.java (needs build env)
T015 [P] [US1] Core-field population test (subject/destination, timestamp, type, originating connection, sequence) consistent with other transports, in src/test/org/rvsnoop/transport/ems/JmsMessageConverterTest.java (CONTRACT-CONV-8; FR-007) (needs build env)
T016 [P] [US1] RV-coexistence test: an EMS connection (faked) and an RV connection both feed the same trace, each record attributed to its originating connection, RV behaviour unchanged, in src/test/org/rvsnoop/transport/ems/EmsCoexistenceTest.java (CONTRACT-EMS-4; FR-015, SC-006) (needs build env)
T017 [US1] Implement JmsMessageConverter (JMS → NeutralMessage): standard headers → headers subtree, user properties → properties subtree (typed); body by type — text→text field, bytes→raw-bytes, map→nested fields, stream→ordered fields, object→opaque raw bytes + marker (no Java deserialization); unknown/uninterpretable→raw bytes + marker, never throws; populate core fields, in src/main/org/rvsnoop/transport/ems/JmsMessageConverter.java (FR-005/FR-006/FR-007; data-model, CONTRACT-CONV-1..8) ([CLARIFY] object-body policy + exact header set — research R4)
T018 [US1] Implement EmsSubscription (destination, optional selector, mode enum {OBSERVE, CONSUME} default OBSERVE) in src/main/org/rvsnoop/transport/ems/EmsSubscription.java; topic path attaches a live MessageConsumer (FR-003; data-model)
T019 [US1] Implement EmsTransport connect/start (factory via T007 → Connection + ExceptionListener → Session(s) → Connection.start(); CONNECTED), topic subscribe (MessageConsumer + MessageListener → converter → existing event/ledger pipeline off the UI thread), and close (release consumers/sessions/connection), in src/main/org/rvsnoop/transport/ems/EmsTransport.java (FR-002/FR-004/FR-009; research R6, CONTRACT-EMS-1/3, CONTRACT-SUB-1)
T020 [US1] Add the additive Guice binding registering EmsTransport under transport kind "ems" in 004's registry (no core/UI/RV change) in src/main/org/rvsnoop/transport/ems/EmsTransportModule.java, and contribute the module to the application's injector (FR-001/FR-015, CONTRACT-EMS-2) (depends on T006 registry mechanism)
Phase 4: User Story 2 - Trace messages from an EMS queue (Priority: P2)
T022 [P] [US2] Queue subscription test: enqueued messages appear as records attributed to connection+queue; topic is the default kind and queue is an explicit choice, in src/test/org/rvsnoop/transport/ems/EmsSubscriptionTest.java (CONTRACT-SUB-2/3; FR-003/FR-004, SC-002) (needs build env)
T023 [P] [US2] Non-destructive-default test: a queue subscription in OBSERVE mode leaves the queue's messages intact (browse semantics); CONSUME mode used only on explicit opt-in, in src/test/org/rvsnoop/transport/ems/EmsQueueObserveTest.java (CONTRACT-SUB-4; FR-013, SC-002) (needs build env)
T024 [P] [US2] Duplicate-subscription test: subscribing to the same destination twice on one connection is rejected with a clear message or de-duplicated (no double-delivery surprises), in src/test/org/rvsnoop/transport/ems/EmsSubscriptionTest.java (CONTRACT-SUB-5; edge case) (needs build env)
T025 [US2] Extend EmsTransport subscribe to resolve queue destinations: QUEUE + OBSERVE → non-destructive QueueBrowser (default); QUEUE + CONSUME → MessageConsumer only on explicit opt-in, in src/main/org/rvsnoop/transport/ems/EmsTransport.java (FR-003/FR-013; research R5, CONTRACT-SUB-2/4) ([CLARIFY] queue observe semantics: browse vs non-ack consume — research R5)
T026 [US2] Implement duplicate-destination handling on a connection (reject-with-message or de-duplicate) in src/main/org/rvsnoop/transport/ems/EmsTransport.java (CONTRACT-SUB-5; edge case)
Phase 5: User Story 3 - Provide the EMS client library without committing it (Priority: P3)
T028 [P] [US3] Runtime-missing-library test: with the EMS provider absent at runtime, attempting an EMS connection yields a clear "must be provisioned" message and other transports stay usable — no uncaught NoClassDefFoundError reaches the UI, in src/test/org/rvsnoop/transport/ems/EmsErrorHandlingTest.java (CONTRACT-ERR-4; FR-016, SC-007) (needs build env)
T029 [P] [US3] Repository-inspection check: the proprietary EMS jar appears nowhere in version control (verifiable now) — assert via a build/CI check or test in src/test/org/rvsnoop/transport/ems/EmsLibraryAbsenceTest.java (CONTRACT-LIB-1; FR-010, SC-005)
T030 [P] [US3] Default-build / broker-free-suite assertion: the complete EMS suite (lifecycle, subscription, conversion, error handling) compiles and passes with the EMS jar absent and no live broker (CONTRACT-LIB-2/6; FR-011/FR-012, SC-004/SC-005) — gate in CI default stage (needs build env)
T031 [US3] Wire CI to obtain the EMS jar through a secured mechanism (not version control) for the ems-integration stage only; ensure absence of the secured source does not break the default build/test stages, in .github/workflows/*.yml (feature 001 files) (FR-010/FR-011, CONTRACT-LIB-4; research R8) (needs build env)
T032 [US3] Verify quickstart Scenario 7 (jar-free build + broker-free suite) and Scenario 8 (jar never committed; secured CI provisioning) (SC-004/SC-005) (needs build env)
T033 [US3] ⚙ Integration smoke (opt-in ems-integration profile): provision the EMS jar, connect to a reachable EMS server, subscribe to a real topic and queue, confirm runtime availability and tracing parity with the faked scenarios — quickstart Scenario 9; skipped by default (CONTRACT-LIB-3; FR-010, SC-005) (needs broker/jar)
Phase 6: Polish & Cross-Cutting Concerns
T034 [US?] Error & stability handling for unreachable/wrong address (bounded connect timeout — no hang), authentication failure, and mid-trace disconnect via the ExceptionListener (clear actionable messages, stopped/error state, trace uncorrupted, no crash) in src/main/org/rvsnoop/transport/ems/EmsTransport.java, with tests in src/test/org/rvsnoop/transport/ems/EmsErrorHandlingTest.java (CONTRACT-ERR-1/2/3; FR-008, SC-007; research R6) (needs build env)
T035 [P] Update README/developer docs: a second EMS transport, how to provision the proprietary jar externally (never committed), the default broker-free test path, and the opt-in ems-integration profile (FR-010/FR-016)
T036 [P] Update dependency/governance notes: JMS API + test double added (Apache-2.0-compatible, pinned, Dependabot-tracked); proprietary EMS jar externalized and pinned — reaffirms Principles I, IV, V (FR-014, CONTRACT-LIB-5)
T037 Run the full quickstart.md validation (Scenarios 1–8; Scenario 9 only if the integration profile is provisioned), confirming zero crashes across all error scenarios (SC-001..SC-007) (needs build env; Scenario 9 needs broker/jar)
Draft planning artifact generated via spec-kit — see
specs/005-tibco-ems/(spec, plan, research, data-model, contracts, quickstart, tasks).t/yolo-d76fe7(not yet pushed).Tasks (mirrors
specs/005-tibco-ems/tasks.md)Phase 1: Setup
javax.jms/jakarta.jmsmatching the pinned EMS client namespace — research R7) to gradle/libs.versions.toml and wire it as a compile+test dependency in build.gradle.kts, pinned to a single version, Dependabot-tracked (FR-014, CONTRACT-LIB-5; research R1/R7) (needs build env)tibjms.jar+ companions) via a build property pointing at a local/secured path in build.gradle.kts — runtime/integration scope only, never committed — mirroring the Rendezvous-jar externalization (FR-010/FR-014, CONTRACT-LIB-1; research R8) (needs build env)ems-integrationtest profile/flag in build.gradle.kts, skipped by default, so the default build/test runs without the EMS jar or a broker (FR-011, CONTRACT-LIB-2/4/6; research R3/R8) (needs build env)Phase 2: Foundational (Blocking Prerequisites)
NeutralMessageAPI against the provisional surface assumed in plan.md/data-model.md (connect/subscribe/receive/close; registry kind registration; neutral field-tree API); record any signature deltas and re-check the contract/Constitution gate (FR-001/FR-015; research R2, CONTRACT-EMS-2) (blocked until 004 lands)ConnectionFactory(com.tibco.tibjms.TibjmsConnectionFactoryor JNDI) reflectively/by configuration so the proprietary type never lands on the compile classpath, in src/main/org/rvsnoop/transport/ems/EmsConnectionFactoryProvider.java (FR-010/FR-011, CONTRACT-CONV-7/LIB-2; research R1) (needs build env to verify factory class/JNDI name)EmsDestination(name + kind enum {TOPIC, QUEUE}, default TOPIC) in src/main/org/rvsnoop/transport/ems/EmsDestination.java (FR-003; data-model)EmsConnectionconfig type (id, serverUrl required, optional username/password/clientId, fixed transportKind"ems", bounded connect timeout) realizing 004's neutral connection, in src/main/org/rvsnoop/transport/ems/EmsConnection.java (FR-002; data-model, CONTRACT-EMS-1)EmsProviderAvailabilityruntime guard (guardedClass.forNameof the EMS factory; clear "library must be provisioned" message when absent; never throwNoClassDefFoundErrorinto the UI) in src/main/org/rvsnoop/transport/ems/EmsProviderAvailability.java (FR-016; research R9, CONTRACT-ERR-4)Phase 3: User Story 1 - Trace messages from an EMS topic (Priority: P1) 🎯 MVP
JmsMessageConvertertest covering all five body kinds + headers/properties + empty-body + very-large + uninterpretable body, run with the proprietary jar absent from the classpath (CONTRACT-CONV-1..7; FR-005/FR-006, SC-003) in src/test/org/rvsnoop/transport/ems/JmsMessageConverterTest.java (needs build env)JmsMessageConverter(JMS →NeutralMessage): standard headers →headerssubtree, user properties →propertiessubtree (typed); body by type — text→text field, bytes→raw-bytes, map→nested fields, stream→ordered fields, object→opaque raw bytes + marker (no Java deserialization); unknown/uninterpretable→raw bytes + marker, never throws; populate core fields, in src/main/org/rvsnoop/transport/ems/JmsMessageConverter.java (FR-005/FR-006/FR-007; data-model, CONTRACT-CONV-1..8) ([CLARIFY] object-body policy + exact header set — research R4)EmsSubscription(destination, optional selector, mode enum {OBSERVE, CONSUME} default OBSERVE) in src/main/org/rvsnoop/transport/ems/EmsSubscription.java; topic path attaches a liveMessageConsumer(FR-003; data-model)EmsTransportconnect/start (factory via T007 → Connection +ExceptionListener→ Session(s) →Connection.start(); CONNECTED), topic subscribe (MessageConsumer +MessageListener→ converter → existing event/ledger pipeline off the UI thread), and close (release consumers/sessions/connection), in src/main/org/rvsnoop/transport/ems/EmsTransport.java (FR-002/FR-004/FR-009; research R6, CONTRACT-EMS-1/3, CONTRACT-SUB-1)EmsTransportunder transport kind"ems"in 004's registry (no core/UI/RV change) in src/main/org/rvsnoop/transport/ems/EmsTransportModule.java, and contribute the module to the application's injector (FR-001/FR-015, CONTRACT-EMS-2) (depends on T006 registry mechanism)Phase 4: User Story 2 - Trace messages from an EMS queue (Priority: P2)
EmsTransportsubscribe to resolve queue destinations: QUEUE + OBSERVE → non-destructiveQueueBrowser(default); QUEUE + CONSUME →MessageConsumeronly on explicit opt-in, in src/main/org/rvsnoop/transport/ems/EmsTransport.java (FR-003/FR-013; research R5, CONTRACT-SUB-2/4) ([CLARIFY] queue observe semantics: browse vs non-ack consume — research R5)Phase 5: User Story 3 - Provide the EMS client library without committing it (Priority: P3)
NoClassDefFoundErrorreaches the UI, in src/test/org/rvsnoop/transport/ems/EmsErrorHandlingTest.java (CONTRACT-ERR-4; FR-016, SC-007) (needs build env)ems-integrationstage only; ensure absence of the secured source does not break the default build/test stages, in .github/workflows/*.yml (feature 001 files) (FR-010/FR-011, CONTRACT-LIB-4; research R8) (needs build env)ems-integrationprofile): provision the EMS jar, connect to a reachable EMS server, subscribe to a real topic and queue, confirm runtime availability and tracing parity with the faked scenarios — quickstart Scenario 9; skipped by default (CONTRACT-LIB-3; FR-010, SC-005) (needs broker/jar)Phase 6: Polish & Cross-Cutting Concerns
ExceptionListener(clear actionable messages, stopped/error state, trace uncorrupted, no crash) in src/main/org/rvsnoop/transport/ems/EmsTransport.java, with tests in src/test/org/rvsnoop/transport/ems/EmsErrorHandlingTest.java (CONTRACT-ERR-1/2/3; FR-008, SC-007; research R6) (needs build env)ems-integrationprofile (FR-010/FR-016)