import test from 'node:test'; import assert from 'node:assert/strict'; import { readFileSync } from 'node:fs'; const source = readFileSync(new URL('../src/apps/history-writer.mjs', import.meta.url), 'utf8'); test('history writer replays durable topics but joins the raw quote firehose live', () => { assert.match(source, /durableHistoryConsumerCount\s*=\s*3/); assert.match(source, /durableConsumers\.push\(await createConsumer/); assert.match(source, /liveEvidenceConsumerCount\s*=\s*2/); assert.match(source, /groupId:\s*`\$\{config\.kafkaConsumerGroupHistory\}-live`/); assert.match(source, /groupId:\s*`\$\{config\.kafkaConsumerGroupHistory\}-raw`/); assert.match(source, /liveEvidenceTopics\s*=\s*\[[\s\S]+config\.kafkaTopicNormSwapDemand[\s\S]+config\.kafkaTopicDecisionTradeDecision/); assert.match(source, /current quote\/decision truth visible/); assert.match(source, /rawQuoteConsumer\.subscribe\(\{[\s\S]+fromBeginning:\s*false/); assert.match(source, /historyConsumer\.subscribe\(\{[\s\S]+fromBeginning:\s*true/); assert.match(source, /liveEvidenceTopics[\s\S]+fromBeginning:\s*false/); assert.match(source, /Raw quote volume is a live firehose/); assert.match(source, /runHistoryConsumer\(historyConsumer\)/); assert.match(source, /runHistoryConsumer\(rawQuoteConsumer\)/); assert.match(source, /eachBatch/); assert.match(source, /insertHistoryEvents/); assert.match(source, /quoteLifecycleRetentionMaintenanceIntervalMs\s*=\s*60 \* 1000/); assert.match(source, /runQuoteLifecycleRetentionMaintenance/); assert.match(source, /loadQuoteLifecycleRetentionSummary/); assert.match(source, /maybeRunQuoteLifecycleRetentionMaintenance/); assert.match(source, /quoteLifecycleRetentionMaintenanceInFlight/); assert.match(source, /quoteLifecycleRetentionMaintenanceTimer\s*=\s*setInterval/); assert.match(source, /quoteLifecycleRetentionStartupTimer\s*=\s*setTimeout/); assert.match(source, /void maybeRunQuoteLifecycleRetentionMaintenance\(\{\s*force:\s*true\s*\}\)/); assert.match(source, /clearTimeout\(quoteLifecycleRetentionStartupTimer\)/); assert.match(source, /clearInterval\(quoteLifecycleRetentionMaintenanceTimer\)/); assert.match(source, /retention_mode/); assert.match(source, /storage_pressure/); assert.doesNotMatch(source, /RetainRecentMs/); assert.doesNotMatch(source, /PruneBatchSize/); assert.doesNotMatch(source, /pruneRawNearIntentsQuoteHistory/); assert.doesNotMatch(source, /pruneNonSuccessfulQuoteLifecycleHistory/); }); test('history writer passes tracked assets into portfolio valuation', () => { assert.match(source, /trackedAssets:\s*tradingConfig\.trackedAssets/); assert.match(source, /valuationAssets:\s*inputs\.valuationAssets \|\| \[\]/); assert.match(source, /inputs\.valuationAssets[\s\S]+asset\.priceId/); }); test('history writer startup outcome refresh publishes newly computed ntfy notifications', () => { assert.match(source, /historyWriterStartedAt\s*=\s*new Date\(\)\.toISOString\(\)/); assert.match(source, /refreshQuoteOutcomeAttributions\(\)\.then\(\(records\) => publishQuoteOutcomeNotifications\(records, \{\s*minObservedAt:\s*historyWriterStartedAt,\s*\}\)\)/); assert.match(source, /refreshIntentRequestOutcomeAttributions\(\)\.then\(\(records\) => publishIntentRequestOutcomeNotifications\(records, \{\s*minObservedAt:\s*historyWriterStartedAt,\s*\}\)\)/); assert.match(source, /outcomeNotificationObservedAtOrAfter/); });