diff --git a/deploy/deploy.yaml b/deploy/deploy.yaml index 5ac749c0..de4e2375 100644 --- a/deploy/deploy.yaml +++ b/deploy/deploy.yaml @@ -852,6 +852,7 @@ lanes: HWLAB_KAFKA_AGENTRUN_EVENT_CONSUME_ENABLED: "true" HWLAB_KAFKA_DIRECT_PUBLISH_ENABLED: "true" HWLAB_WORKBENCH_LIVE_KAFKA_SSE_ENABLED: "true" + HWLAB_WORKBENCH_KAFKA_REFRESH_REPLAY_ENABLED: "true" HWLAB_KAFKA_TRANSACTIONAL_PROJECTOR_ENABLED: "false" HWLAB_KAFKA_PROJECTION_OUTBOX_RELAY_ENABLED: "false" HWLAB_WORKBENCH_PROJECTION_REALTIME_ENABLED: "false" diff --git a/internal/cloud/kafka-event-bridge.test.ts b/internal/cloud/kafka-event-bridge.test.ts index 68b5ecd2..0bfd118c 100644 --- a/internal/cloud/kafka-event-bridge.test.ts +++ b/internal/cloud/kafka-event-bridge.test.ts @@ -48,6 +48,16 @@ const LIVE_ENV = Object.freeze({ HWLAB_KAFKA_HWLAB_EVENT_GROUP_ID: "hwlab-live-fanout-fixed" }); +const LIVE_REFRESH_ENV = Object.freeze({ + ...LIVE_ENV, + HWLAB_WORKBENCH_KAFKA_REFRESH_REPLAY_ENABLED: "true", + HWLAB_WORKBENCH_KAFKA_REFRESH_REPLAY_GROUP_PREFIX: "hwlab-live-refresh-test", + HWLAB_WORKBENCH_KAFKA_REFRESH_REPLAY_TIMEOUT_MS: "30000", + HWLAB_WORKBENCH_KAFKA_REFRESH_REPLAY_SCAN_LIMIT: "1000000", + HWLAB_WORKBENCH_KAFKA_REFRESH_REPLAY_MATCHED_EVENT_LIMIT: "2000", + HWLAB_WORKBENCH_KAFKA_REFRESH_REPLAY_LIVE_BUFFER_LIMIT: "2000" +}); + test("projects AgentRun assistant_message Kafka event into HWLAB trace event", () => { const projected = projectAgentRunKafkaEventToHwlabEvent({ schema: "agentrun.event.v1", @@ -357,6 +367,36 @@ test("live Kafka startup does not touch transactional v8 readiness", async () => await bridge.stop(); }); +test("Cloud API starts with all six Kafka capabilities and without transactional v8 schema", async () => { + let transactionalV8Reads = 0; + const runtimeStore = new Proxy({}, { + get(_target, property) { + if (["assertWorkbenchTransactionalRealtimeReady", "workbenchTransactionalRealtimeReadiness"].includes(String(property))) { + transactionalV8Reads += 1; + throw new Error("transactional v8 schema must not gate live Kafka Cloud API startup"); + } + return undefined; + } + }); + const kafkaFactory = () => ({ + consumer() { return { async connect() {}, async subscribe() {}, async run() {}, async stop() {}, async disconnect() {} }; }, + producer() { return { async connect() {}, async send() {}, async disconnect() {} }; } + }); + let bunServeCalls = 0; + const cloud = await createCloudApiBunServer({ + env: { ...LIVE_REFRESH_ENV }, + runtimeStore, + kafkaFactory, + accessController: { async ensureBootstrap() {}, async authenticate() { return { ok: false }; } }, + bunServe() { bunServeCalls += 1; return { port: 31888, stop() {} }; }, + installSignalHandlers: false, + logger: { log() {}, info() {}, warn() {}, error() {} } + }); + assert.equal(bunServeCalls, 1); + assert.equal(transactionalV8Reads, 0); + await cloud.stop("test"); +}); + test("projects AgentRun run-created envelope even when no source event is present", () => { const projected = projectAgentRunKafkaEventToHwlabEvent({ schema: "agentrun.event.v1", diff --git a/scripts/gitops-render.test.ts b/scripts/gitops-render.test.ts index 531707e8..af3f13f6 100644 --- a/scripts/gitops-render.test.ts +++ b/scripts/gitops-render.test.ts @@ -689,6 +689,7 @@ test("v03 render keeps node identity as data instead of generated structure", as assert.equal(cloudApiEnv.get("HWLAB_KAFKA_AGENTRUN_EVENT_CONSUME_ENABLED"), "true"); assert.equal(cloudApiEnv.get("HWLAB_KAFKA_DIRECT_PUBLISH_ENABLED"), "true"); assert.equal(cloudApiEnv.get("HWLAB_WORKBENCH_LIVE_KAFKA_SSE_ENABLED"), "true"); + assert.equal(cloudApiEnv.get("HWLAB_WORKBENCH_KAFKA_REFRESH_REPLAY_ENABLED"), "true"); assert.equal(cloudApiEnv.get("HWLAB_KAFKA_TRANSACTIONAL_PROJECTOR_ENABLED"), "false"); assert.equal(cloudApiEnv.get("HWLAB_KAFKA_PROJECTION_OUTBOX_RELAY_ENABLED"), "false"); assert.equal(cloudApiEnv.get("HWLAB_WORKBENCH_PROJECTION_REALTIME_ENABLED"), "false"); diff --git a/scripts/runtime-realtime-capabilities-config.test.mjs b/scripts/runtime-realtime-capabilities-config.test.mjs index b24f08b1..e9fe59c6 100644 --- a/scripts/runtime-realtime-capabilities-config.test.mjs +++ b/scripts/runtime-realtime-capabilities-config.test.mjs @@ -6,6 +6,7 @@ import { readStructuredFile } from "./src/structured-config.mjs"; const CLOUD_API_ARCHITECTURE_ENV = Object.freeze({ HWLAB_KAFKA_DIRECT_PUBLISH_ENABLED: "true", HWLAB_WORKBENCH_LIVE_KAFKA_SSE_ENABLED: "true", + HWLAB_WORKBENCH_KAFKA_REFRESH_REPLAY_ENABLED: "true", HWLAB_KAFKA_TRANSACTIONAL_PROJECTOR_ENABLED: "false", HWLAB_KAFKA_PROJECTION_OUTBOX_RELAY_ENABLED: "false", HWLAB_WORKBENCH_PROJECTION_REALTIME_ENABLED: "false"