"use strict"; const test = require("node:test"); const assert = require("node:assert/strict"); const fs = require("node:fs"); const path = require("node:path"); const workflow = require("../../Web/manual-financial-workflow.js"); const repositoryRoot = path.resolve(__dirname, "..", ".."); const bridge = fs.readFileSync( path.join(repositoryRoot, "MainWindow.ManualFinancial.cs"), "utf8"); const playoutBridge = fs.readFileSync( path.join(repositoryRoot, "MainWindow.Playout.cs"), "utf8"); const operatorGate = fs.readFileSync( path.join(repositoryRoot, "src", "MBN_STOCK_WEBVIEW.Core", "Playout", "OperatorMutationGate.cs"), "utf8"); test("native partial exposes every strict workflow request and response", () => { for (const [name, value] of Object.entries(workflow.bridgeContract)) { if (name.endsWith("RequestType") || name.endsWith("ResultType") || name.endsWith("ErrorType")) { assert.match(bridge, new RegExp(`"${value}"`)); } } assert.match(bridge, /private bool TryHandleManualFinancialRequest\(/); assert.match(bridge, /HasOnlyProperties\(payload, "requestId", "screen", "stock", "record"\)/); assert.match(bridge, /element\.GetArrayLength\(\) != 5/); assert.match(bridge, /element\.GetArrayLength\(\) != 4/); assert.match(bridge, /element\.GetArrayLength\(\) != 6/); }); test("runtime helper composes the typed service with the non-retrying Oracle executor", () => { assert.match(bridge, /new LegacyManualFinancialScreenService\(\s*runtime\.Executor,\s*new OracleManualFinancialMutationExecutor\(/s); assert.match(bridge, /runtime\.ConnectionFactory/); assert.match(bridge, /runtime\.Options\.Resilience/); }); test("list, load and selection reads own independent correlation lanes", () => { assert.match(bridge, /Dictionary _manualFinancialReadLanes/); assert.match(bridge, /new ManualFinancialReadRequest\(\s*operation,\s*requestId,/s); assert.match(bridge, /RegisterManualFinancialRead\(request\)/); assert.match(bridge, /_manualFinancialReadLanes\[request\.Lane\] = request/); assert.doesNotMatch(bridge, /_manualFinancialReadCancellation/); assert.match(bridge, /await _databaseActivityGate\.WaitAsync\(requestToken\)/); assert.ok((bridge.match(/Volatile\.Read\(ref _playoutCommandInFlight\) != 0/g) || []).length >= 2); assert.match(bridge, /browserGeneration != Volatile\.Read\(ref _manualFinancialBrowserGeneration\)/); assert.match(bridge, /!TryCompleteManualFinancialReadIfCurrent\(request\)/); }); test("same-lane supersede emits one correlated terminal cancellation", () => { assert.match(bridge, /CancelRequest\(superseded\.Cancellation\)/); assert.match(bridge, /superseded\?\.TryComplete\(\)/); assert.match(bridge, /"CANCELLED"/); assert.match(bridge, /newer request replaced it/); assert.match(bridge, /Interlocked\.CompareExchange\(ref _terminalState, 1, 0\) == 0/); assert.match(bridge, /TryCompleteManualFinancialReadIfCurrent\(request\)[\s\S]*PostMessage\(reply\.MessageType/s); assert.match(bridge, /ReferenceEquals\(current, request\) &&[\s\S]*request\.TryComplete\(\)/s); }); test("writes are single-flight and impossible during command, PREPARED, PROGRAM or refresh", () => { assert.match(bridge, /_manualFinancialWriteGate\.WaitAsync\(0\)/); assert.match(bridge, /_playoutCommandGate\.WaitAsync\(0, requestToken\)/); assert.match(bridge, /_databaseActivityGate\.WaitAsync\(0, requestToken\)/); assert.match(bridge, /CanStartManualFinancialWrite\(\)/); assert.match(bridge, /CanStartOperatorMutation\(IsManualFinancialWriteQuarantined\(\)\)/); assert.match(playoutBridge, /private bool CanStartOperatorMutation\(/); assert.match(playoutBridge, /new OperatorMutationGateSnapshot\(/); assert.match(playoutBridge, /IsEngineAvailable: engine is not null/); assert.match(playoutBridge, /IsWorkflowAvailable: workflow is not null/); assert.match(playoutBridge, /IsRefreshTaskRunning: _legacyRefreshTask is \{ IsCompleted: false \}/); for (const condition of [ "IsCommandAvailable", "IsPlayCompletionPending", "PreparedSceneName", "OnAirSceneName", "PreparedCutCode", "OnAirCutCode", "IsRefreshActive", "IsRefreshTaskRunning" ]) { assert.match(operatorGate, new RegExp(`snapshot\\.${condition}`)); } assert.match(bridge, /"PLAYOUT_ACTIVE"/); }); test("OutcomeUnknown and browser correlation loss latch a process-lifetime no-retry quarantine", () => { assert.match(bridge, /catch \(ManualFinancialMutationException exception\)/); assert.match(bridge, /if \(exception\.OutcomeUnknown\)/); assert.match(bridge, /Interlocked\.CompareExchange\(ref _manualFinancialWriteQuarantined, 1, 0\)/); assert.match(bridge, /retryable = false/); assert.match(bridge, /rolled back and was not retried/i); assert.doesNotMatch(bridge, /for\s*\([^)]*retry|while\s*\([^)]*retry/i); }); test("browser, playout and shutdown hooks cancel correlation without clearing quarantine", () => { assert.match(bridge, /private void InvalidateManualFinancialBrowserRequests\(\)/); assert.match(bridge, /Interlocked\.Increment\(ref _manualFinancialBrowserGeneration\)/); assert.match(bridge, /Volatile\.Read\(ref _manualFinancialWriteInFlight\) != 0/); assert.match(bridge, /Interlocked\.Exchange\(ref _manualFinancialWriteCancellation, null\)/); assert.match(bridge, /private void CancelManualFinancialReadsForPlayout\(\)/); assert.match(bridge, /private void ShutdownManualFinancialRuntime\(\)/); assert.ok((bridge.match(/SnapshotManualFinancialReads\(clear: true\)/g) || []).length >= 2); assert.match(bridge, /CancelManualFinancialReadsForPlayout\(\)[\s\S]*SnapshotManualFinancialReads\(clear: false\)/s); }); test("selection and restore boundaries re-read row version before exposing a cut", () => { assert.match(bridge, /var snapshot = await service\.GetAsync\(identity, cancellationToken\)/); assert.match(bridge, /EnsureManualFinancialRowVersion\(snapshot, rowVersion\)/); assert.match(bridge, /ResolveManualFinancialStockAsync\(/); assert.match(bridge, /ManualFinancialCutContracts\.CreateSelection\(snapshot, verified\)/); assert.match(bridge, /"manual-financial-selection-results"/); }); test("successful writes return the real transaction receipt fields", () => { assert.match(bridge, /operationId = receipt\.OperationId\.ToString\("N"/); assert.match(bridge, /receipt\.CommittedAt/); assert.match(bridge, /receipt\.AffectedRows/); });