{"numTotalTestSuites":253,"numPassedTestSuites":236,"numFailedTestSuites":17,"numPendingTestSuites":0,"numTotalTests":787,"numPassedTests":741,"numFailedTests":26,"numPendingTests":20,"numTodoTests":0,"snapshot":{"added":0,"failure":false,"filesAdded":0,"filesRemoved":0,"filesRemovedList":[],"filesUnmatched":0,"filesUpdated":0,"matched":99,"total":99,"unchecked":0,"uncheckedKeysByFile":[],"unmatched":0,"updated":0,"didUpdate":false},"startTime":1781440226639,"success":false,"testResults":[{"assertionResults":[{"ancestorTitles":["Antigravity → OpenAI"],"fullName":"Antigravity → OpenAI functionResponse + functionCall in same content keeps both","status":"passed","title":"functionResponse + functionCall in same content keeps both","duration":818.4814159999996,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["Antigravity → OpenAI"],"fullName":"Antigravity → OpenAI functionCall without id keeps a stable matchable id","status":"passed","title":"functionCall without id keeps a stable matchable id","duration":74.03700000000026,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["Antigravity → OpenAI"],"fullName":"Antigravity → OpenAI signature-only part does not produce empty text","status":"passed","title":"signature-only part does not produce empty text","duration":0.6551249999993161,"failureMessages":[],"meta":{},"tags":[]}],"startTime":1781440238137,"endTime":1781440239030.655,"status":"passed","message":"","name":"/Users/Working/router4/app/tests/translator/bugs-antigravity.test.js"},{"assertionResults":[{"ancestorTitles":["Claude Code CLI context → OpenAI"],"fullName":"Claude Code CLI context → OpenAI system array keeps all text parts","status":"passed","title":"system array keeps all text parts","duration":591.4295419999999,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["Claude Code CLI context → OpenAI"],"fullName":"Claude Code CLI context → OpenAI assistant thinking block survives Claude→Claude passthrough","status":"passed","title":"assistant thinking block survives Claude→Claude passthrough","duration":25.44854200000009,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["Claude Code CLI context → OpenAI"],"fullName":"Claude Code CLI context → OpenAI redacted_thinking block is not silently dropped","status":"passed","title":"redacted_thinking block is not silently dropped","duration":30.774749999999585,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["Claude Code CLI context → OpenAI"],"fullName":"Claude Code CLI context → OpenAI tool_result image block is preserved","status":"passed","title":"tool_result image block is preserved","duration":28.637624999999844,"failureMessages":[],"meta":{},"tags":[]}],"startTime":1781440230738,"endTime":1781440231420.6377,"status":"passed","message":"","name":"/Users/Working/router4/app/tests/translator/bugs-claudeCode-context.test.js"},{"assertionResults":[{"ancestorTitles":["Codex CLI Responses → OpenAI"],"fullName":"Codex CLI Responses → OpenAI assistant has no empty tool_calls array when all names are empty","status":"passed","title":"assistant has no empty tool_calls array when all names are empty","duration":446.7486250000002,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["Codex CLI Responses → OpenAI"],"fullName":"Codex CLI Responses → OpenAI function_call arguments end up as a string","status":"passed","title":"function_call arguments end up as a string","duration":99.4066670000002,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["Codex CLI Responses → OpenAI"],"fullName":"Codex CLI Responses → OpenAI input_image with file_id is not used as a raw url","status":"passed","title":"input_image with file_id is not used as a raw url","duration":67.71637499999997,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["OpenAI → Codex Responses (reverse)"],"fullName":"OpenAI → Codex Responses (reverse) call_id longer than 64 chars is clamped","status":"passed","title":"call_id longer than 64 chars is clamped","duration":0.9164579999996931,"failureMessages":[],"meta":{},"tags":[]}],"startTime":1781440236798,"endTime":1781440237412.9165,"status":"passed","message":"","name":"/Users/Working/router4/app/tests/translator/bugs-codexCli-responses.test.js"},{"assertionResults":[{"ancestorTitles":["OpenAI → Gemini"],"fullName":"OpenAI → Gemini multiple system messages are all kept","status":"passed","title":"multiple system messages are all kept","duration":491.2704160000003,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["OpenAI → Cursor"],"fullName":"OpenAI → Cursor image content is preserved","status":"passed","title":"image content is preserved","duration":20.085291999999754,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["OpenAI → Cursor"],"fullName":"OpenAI → Cursor respects client max_tokens","status":"passed","title":"respects client max_tokens","duration":2.820415999999568,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["OpenAI → CommandCode"],"fullName":"OpenAI → CommandCode malformed tool arguments are not silently emptied","status":"passed","title":"malformed tool arguments are not silently emptied","duration":57.42524999999932,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["OpenAI → CommandCode"],"fullName":"OpenAI → CommandCode image content is preserved","status":"passed","title":"image content is preserved","duration":1.5707920000004378,"failureMessages":[],"meta":{},"tags":[]}],"startTime":1781440235797,"endTime":1781440236371.5708,"status":"passed","message":"","name":"/Users/Working/router4/app/tests/translator/bugs-gemini-cursor-commandcode.test.js"},{"assertionResults":[{"ancestorTitles":["OpenAI → Kiro"],"fullName":"OpenAI → Kiro malformed tool arguments do not throw the whole request","status":"passed","title":"malformed tool arguments do not throw the whole request","duration":696.8525829999999,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["OpenAI → Kiro"],"fullName":"OpenAI → Kiro respects client max_tokens","status":"passed","title":"respects client max_tokens","duration":25.70916600000055,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["OpenAI → Kiro"],"fullName":"OpenAI → Kiro remote image url is preserved as an image, not text","status":"passed","title":"remote image url is preserved as an image, not text","duration":145.05000000000018,"failureMessages":[],"meta":{},"tags":[]}],"startTime":1781440235585,"endTime":1781440236453.05,"status":"passed","message":"","name":"/Users/Working/router4/app/tests/translator/bugs-kiro.test.js"},{"assertionResults":[{"ancestorTitles":["bug: Claude → OpenAI bridge data loss"],"fullName":"bug: Claude → OpenAI bridge data loss image with source.type=url is preserved (NOT dropped)","status":"passed","title":"image with source.type=url is preserved (NOT dropped)","duration":938.6302499999997,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["bug: Claude → OpenAI bridge data loss"],"fullName":"bug: Claude → OpenAI bridge data loss thinking block survives round-trip Claude→OpenAI→Claude","status":"passed","title":"thinking block survives round-trip Claude→OpenAI→Claude","duration":9.75504200000023,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["bug: Claude → OpenAI bridge data loss"],"fullName":"bug: Claude → OpenAI bridge data loss tool_result with image block is not turned into raw JSON / dropped","status":"passed","title":"tool_result with image block is not turned into raw JSON / dropped","duration":33.409999999999854,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["bug: Claude → OpenAI bridge data loss"],"fullName":"bug: Claude → OpenAI bridge data loss tool_result is_error flag is preserved","status":"passed","title":"tool_result is_error flag is preserved","duration":41.61799999999994,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["bug: Claude → OpenAI bridge data loss"],"fullName":"bug: Claude → OpenAI bridge data loss system array non-text parts are not silently dropped","status":"passed","title":"system array non-text parts are not silently dropped","duration":0.8463329999999587,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["bug: tool_call id stability across bridge"],"fullName":"bug: tool_call id stability across bridge sanitized tool id stays matched between call and result","status":"passed","title":"sanitized tool id stays matched between call and result","duration":0.4185419999998885,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["bug: empty content message handling"],"fullName":"bug: empty content message handling assistant message with only tool_calls is not dropped","status":"passed","title":"assistant message with only tool_calls is not dropped","duration":0.21508300000004965,"failureMessages":[],"meta":{},"tags":[]}],"startTime":1781440238989,"endTime":1781440240017.4185,"status":"passed","message":"","name":"/Users/Working/router4/app/tests/translator/bugs-openai-bridge.test.js"},{"assertionResults":[{"ancestorTitles":["OpenAI → Claude context mapping"],"fullName":"OpenAI → Claude context mapping does not inject Claude Code system prompt for compatible providers","status":"passed","title":"does not inject Claude Code system prompt for compatible providers","duration":1208.7600840000005,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["OpenAI → Claude context mapping"],"fullName":"OpenAI → Claude context mapping assistant reasoning_content becomes a thinking block","status":"passed","title":"assistant reasoning_content becomes a thinking block","duration":73.45058299999982,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["OpenAI → Claude context mapping"],"fullName":"OpenAI → Claude context mapping tool_choice=none is not turned into auto","status":"passed","title":"tool_choice=none is not turned into auto","duration":7.623207999999977,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["OpenAI → Claude context mapping"],"fullName":"OpenAI → Claude context mapping input_audio content is preserved","status":"passed","title":"input_audio content is preserved","duration":4.647957999999562,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["OpenAI → Claude context mapping"],"fullName":"OpenAI → Claude context mapping remote http image_url is preserved","status":"passed","title":"remote http image_url is preserved","duration":1.1671669999996084,"failureMessages":[],"meta":{},"tags":[]}],"startTime":1781440238354,"endTime":1781440239651.1672,"status":"passed","message":"","name":"/Users/Working/router4/app/tests/translator/bugs-toClaude-context.test.js"},{"assertionResults":[{"ancestorTitles":["coverage: every model translates without throwing"],"fullName":"coverage: every model translates without throwing 'alicode-intl': all models OpenAI→target","status":"passed","title":"'alicode-intl': all models OpenAI→target","duration":325.014375,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["coverage: every model translates without throwing"],"fullName":"coverage: every model translates without throwing 'alicode': all models OpenAI→target","status":"passed","title":"'alicode': all models OpenAI→target","duration":1.6849999999999454,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["coverage: every model translates without throwing"],"fullName":"coverage: every model translates without throwing 'anthropic': all models OpenAI→target","status":"passed","title":"'anthropic': all models OpenAI→target","duration":1.9551249999999527,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["coverage: every model translates without throwing"],"fullName":"coverage: every model translates without throwing 'ag': all models OpenAI→target","status":"passed","title":"'ag': all models OpenAI→target","duration":24.805583000000297,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["coverage: every model translates without throwing"],"fullName":"coverage: every model translates without throwing 'assemblyai': all models OpenAI→target","status":"passed","title":"'assemblyai': all models OpenAI→target","duration":153.66604199999983,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["coverage: every model translates without throwing"],"fullName":"coverage: every model translates without throwing 'black-forest-labs': all models OpenAI→target","status":"passed","title":"'black-forest-labs': all models OpenAI→target","duration":0.5702909999999974,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["coverage: every model translates without throwing"],"fullName":"coverage: every model translates without throwing 'blackbox': all models OpenAI→target","status":"passed","title":"'blackbox': all models OpenAI→target","duration":0.6257080000000315,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["coverage: every model translates without throwing"],"fullName":"coverage: every model translates without throwing 'byteplus': all models OpenAI→target","status":"passed","title":"'byteplus': all models OpenAI→target","duration":36.12416699999994,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["coverage: every model translates without throwing"],"fullName":"coverage: every model translates without throwing 'cerebras': all models OpenAI→target","status":"passed","title":"'cerebras': all models OpenAI→target","duration":44.01291699999956,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["coverage: every model translates without throwing"],"fullName":"coverage: every model translates without throwing 'cc': all models OpenAI→target","status":"passed","title":"'cc': all models OpenAI→target","duration":1.525916000000052,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["coverage: every model translates without throwing"],"fullName":"coverage: every model translates without throwing 'cl': all models OpenAI→target","status":"passed","title":"'cl': all models OpenAI→target","duration":0.43858399999999165,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["coverage: every model translates without throwing"],"fullName":"coverage: every model translates without throwing 'cloudflare-ai': all models OpenAI→target","status":"passed","title":"'cloudflare-ai': all models OpenAI→target","duration":0.7170830000000024,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["coverage: every model translates without throwing"],"fullName":"coverage: every model translates without throwing 'cx': all models OpenAI→target","status":"passed","title":"'cx': all models OpenAI→target","duration":4.474834000000101,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["coverage: every model translates without throwing"],"fullName":"coverage: every model translates without throwing 'cohere': all models OpenAI→target","status":"passed","title":"'cohere': all models OpenAI→target","duration":1.0050840000003518,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["coverage: every model translates without throwing"],"fullName":"coverage: every model translates without throwing 'comfyui': all models OpenAI→target","status":"passed","title":"'comfyui': all models OpenAI→target","duration":0.25408299999980954,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["coverage: every model translates without throwing"],"fullName":"coverage: every model translates without throwing 'commandcode': all models OpenAI→target","status":"passed","title":"'commandcode': all models OpenAI→target","duration":7.160458999999719,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["coverage: every model translates without throwing"],"fullName":"coverage: every model translates without throwing 'cu': all models OpenAI→target","status":"passed","title":"'cu': all models OpenAI→target","duration":1.4149999999999636,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["coverage: every model translates without throwing"],"fullName":"coverage: every model translates without throwing 'deepgram': all models OpenAI→target","status":"passed","title":"'deepgram': all models OpenAI→target","duration":0.16575000000011642,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["coverage: every model translates without throwing"],"fullName":"coverage: every model translates without throwing 'deepseek': all models OpenAI→target","status":"passed","title":"'deepseek': all models OpenAI→target","duration":0.3374579999999696,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["coverage: every model translates without throwing"],"fullName":"coverage: every model translates without throwing 'fal-ai': all models OpenAI→target","status":"passed","title":"'fal-ai': all models OpenAI→target","duration":0.4013749999999163,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["coverage: every model translates without throwing"],"fullName":"coverage: every model translates without throwing 'fireworks': all models OpenAI→target","status":"passed","title":"'fireworks': all models OpenAI→target","duration":0.2039999999997235,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["coverage: every model translates without throwing"],"fullName":"coverage: every model translates without throwing 'gc': all models OpenAI→target","status":"passed","title":"'gc': all models OpenAI→target","duration":0.6300410000003467,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["coverage: every model translates without throwing"],"fullName":"coverage: every model translates without throwing 'gemini': all models OpenAI→target","status":"passed","title":"'gemini': all models OpenAI→target","duration":1.2508750000001783,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["coverage: every model translates without throwing"],"fullName":"coverage: every model translates without throwing 'gh': all models OpenAI→target","status":"passed","title":"'gh': all models OpenAI→target","duration":0.913749999999709,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["coverage: every model translates without throwing"],"fullName":"coverage: every model translates without throwing 'glm-cn': all models OpenAI→target","status":"passed","title":"'glm-cn': all models OpenAI→target","duration":0.1920829999999114,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["coverage: every model translates without throwing"],"fullName":"coverage: every model translates without throwing 'glm': all models OpenAI→target","status":"passed","title":"'glm': all models OpenAI→target","duration":0.24400000000014188,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["coverage: every model translates without throwing"],"fullName":"coverage: every model translates without throwing 'grok-web': all models OpenAI→target","status":"passed","title":"'grok-web': all models OpenAI→target","duration":0.29458299999987503,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["coverage: every model translates without throwing"],"fullName":"coverage: every model translates without throwing 'groq': all models OpenAI→target","status":"passed","title":"'groq': all models OpenAI→target","duration":0.2231669999996484,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["coverage: every model translates without throwing"],"fullName":"coverage: every model translates without throwing 'huggingface': all models OpenAI→target","status":"passed","title":"'huggingface': all models OpenAI→target","duration":0.14674999999988358,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["coverage: every model translates without throwing"],"fullName":"coverage: every model translates without throwing 'hyperbolic': all models OpenAI→target","status":"passed","title":"'hyperbolic': all models OpenAI→target","duration":0.9026659999999538,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["coverage: every model translates without throwing"],"fullName":"coverage: every model translates without throwing 'if': all models OpenAI→target","status":"passed","title":"'if': all models OpenAI→target","duration":0.34420799999998053,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["coverage: every model translates without throwing"],"fullName":"coverage: every model translates without throwing 'kc': all models OpenAI→target","status":"passed","title":"'kc': all models OpenAI→target","duration":0.1835000000000946,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["coverage: every model translates without throwing"],"fullName":"coverage: every model translates without throwing 'kmc': all models OpenAI→target","status":"passed","title":"'kmc': all models OpenAI→target","duration":0.1641660000000229,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["coverage: every model translates without throwing"],"fullName":"coverage: every model translates without throwing 'kimi': all models OpenAI→target","status":"passed","title":"'kimi': all models OpenAI→target","duration":0.13762500000029831,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["coverage: every model translates without throwing"],"fullName":"coverage: every model translates without throwing 'kr': all models OpenAI→target","status":"passed","title":"'kr': all models OpenAI→target","duration":252.10375000000022,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["coverage: every model translates without throwing"],"fullName":"coverage: every model translates without throwing 'mmf': all models OpenAI→target","status":"passed","title":"'mmf': all models OpenAI→target","duration":0.27283299999999144,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["coverage: every model translates without throwing"],"fullName":"coverage: every model translates without throwing 'minimax-cn': all models OpenAI→target","status":"passed","title":"'minimax-cn': all models OpenAI→target","duration":12.868832999999995,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["coverage: every model translates without throwing"],"fullName":"coverage: every model translates without throwing 'minimax': all models OpenAI→target","status":"passed","title":"'minimax': all models OpenAI→target","duration":86.7140000000004,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["coverage: every model translates without throwing"],"fullName":"coverage: every model translates without throwing 'mistral': all models OpenAI→target","status":"passed","title":"'mistral': all models OpenAI→target","duration":0.2966250000004038,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["coverage: every model translates without throwing"],"fullName":"coverage: every model translates without throwing 'nanobanana': all models OpenAI→target","status":"passed","title":"'nanobanana': all models OpenAI→target","duration":0.09066700000039418,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["coverage: every model translates without throwing"],"fullName":"coverage: every model translates without throwing 'nebius': all models OpenAI→target","status":"passed","title":"'nebius': all models OpenAI→target","duration":0.07379099999980099,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["coverage: every model translates without throwing"],"fullName":"coverage: every model translates without throwing 'nvidia': all models OpenAI→target","status":"passed","title":"'nvidia': all models OpenAI→target","duration":0.14562500000010914,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["coverage: every model translates without throwing"],"fullName":"coverage: every model translates without throwing 'ollama': all models OpenAI→target","status":"passed","title":"'ollama': all models OpenAI→target","duration":0.7478750000000218,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["coverage: every model translates without throwing"],"fullName":"coverage: every model translates without throwing 'openai': all models OpenAI→target","status":"passed","title":"'openai': all models OpenAI→target","duration":0.6216669999998885,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["coverage: every model translates without throwing"],"fullName":"coverage: every model translates without throwing 'opencode-go': all models OpenAI→target","status":"passed","title":"'opencode-go': all models OpenAI→target","duration":0.2603329999997186,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["coverage: every model translates without throwing"],"fullName":"coverage: every model translates without throwing 'openrouter': all models OpenAI→target","status":"passed","title":"'openrouter': all models OpenAI→target","duration":0.2811660000002121,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["coverage: every model translates without throwing"],"fullName":"coverage: every model translates without throwing 'perplexity-web': all models OpenAI→target","status":"passed","title":"'perplexity-web': all models OpenAI→target","duration":0.13758299999972223,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["coverage: every model translates without throwing"],"fullName":"coverage: every model translates without throwing 'perplexity': all models OpenAI→target","status":"passed","title":"'perplexity': all models OpenAI→target","duration":0.2262500000001637,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["coverage: every model translates without throwing"],"fullName":"coverage: every model translates without throwing 'qd': all models OpenAI→target","status":"passed","title":"'qd': all models OpenAI→target","duration":45.541833000000224,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["coverage: every model translates without throwing"],"fullName":"coverage: every model translates without throwing 'qw': all models OpenAI→target","status":"passed","title":"'qw': all models OpenAI→target","duration":0.23137500000029831,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["coverage: every model translates without throwing"],"fullName":"coverage: every model translates without throwing 'recraft': all models OpenAI→target","status":"passed","title":"'recraft': all models OpenAI→target","duration":0.1200410000001284,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["coverage: every model translates without throwing"],"fullName":"coverage: every model translates without throwing 'runwayml': all models OpenAI→target","status":"passed","title":"'runwayml': all models OpenAI→target","duration":0.19516599999997197,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["coverage: every model translates without throwing"],"fullName":"coverage: every model translates without throwing 'sdwebui': all models OpenAI→target","status":"passed","title":"'sdwebui': all models OpenAI→target","duration":0.10041700000010678,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["coverage: every model translates without throwing"],"fullName":"coverage: every model translates without throwing 'siliconflow': all models OpenAI→target","status":"passed","title":"'siliconflow': all models OpenAI→target","duration":0.43699999999989814,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["coverage: every model translates without throwing"],"fullName":"coverage: every model translates without throwing 'stability-ai': all models OpenAI→target","status":"passed","title":"'stability-ai': all models OpenAI→target","duration":60.93212500000027,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["coverage: every model translates without throwing"],"fullName":"coverage: every model translates without throwing 'together': all models OpenAI→target","status":"passed","title":"'together': all models OpenAI→target","duration":0.3486250000000837,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["coverage: every model translates without throwing"],"fullName":"coverage: every model translates without throwing 'vertex-partner': all models OpenAI→target","status":"passed","title":"'vertex-partner': all models OpenAI→target","duration":0.13316699999995762,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["coverage: every model translates without throwing"],"fullName":"coverage: every model translates without throwing 'vertex': all models OpenAI→target","status":"passed","title":"'vertex': all models OpenAI→target","duration":3.052582999999686,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["coverage: every model translates without throwing"],"fullName":"coverage: every model translates without throwing 'volcengine-ark': all models OpenAI→target","status":"passed","title":"'volcengine-ark': all models OpenAI→target","duration":0.3069580000001224,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["coverage: every model translates without throwing"],"fullName":"coverage: every model translates without throwing 'voyage-ai': all models OpenAI→target","status":"passed","title":"'voyage-ai': all models OpenAI→target","duration":8.862916999999925,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["coverage: every model translates without throwing"],"fullName":"coverage: every model translates without throwing 'xai': all models OpenAI→target","status":"passed","title":"'xai': all models OpenAI→target","duration":0.18024999999988722,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["coverage: every model translates without throwing"],"fullName":"coverage: every model translates without throwing 'xiaomi-mimo': all models OpenAI→target","status":"passed","title":"'xiaomi-mimo': all models OpenAI→target","duration":0.14550000000008367,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["coverage: every model translates without throwing"],"fullName":"coverage: every model translates without throwing 'xiaomi-tokenplan': all models OpenAI→target","status":"passed","title":"'xiaomi-tokenplan': all models OpenAI→target","duration":0.2420830000000933,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["coverage: every model translates without throwing"],"fullName":"coverage: every model translates without throwing 'openai-tts-models': all models OpenAI→target","status":"passed","title":"'openai-tts-models': all models OpenAI→target","duration":0.09050000000024738,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["coverage: every model translates without throwing"],"fullName":"coverage: every model translates without throwing 'openai-tts-voices': all models OpenAI→target","status":"passed","title":"'openai-tts-voices': all models OpenAI→target","duration":0.27504199999975754,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["coverage: every model translates without throwing"],"fullName":"coverage: every model translates without throwing 'openrouter-tts-models': all models OpenAI→target","status":"passed","title":"'openrouter-tts-models': all models OpenAI→target","duration":0.08395900000004985,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["coverage: every model translates without throwing"],"fullName":"coverage: every model translates without throwing 'openrouter-tts-voices': all models OpenAI→target","status":"passed","title":"'openrouter-tts-voices': all models OpenAI→target","duration":0.2577080000000933,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["coverage: every model translates without throwing"],"fullName":"coverage: every model translates without throwing 'elevenlabs-tts-models': all models OpenAI→target","status":"passed","title":"'elevenlabs-tts-models': all models OpenAI→target","duration":0.10062500000003638,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["coverage: every model translates without throwing"],"fullName":"coverage: every model translates without throwing 'edge-tts': all models OpenAI→target","status":"passed","title":"'edge-tts': all models OpenAI→target","duration":0.22791599999982282,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["coverage: every model translates without throwing"],"fullName":"coverage: every model translates without throwing 'local-device': all models OpenAI→target","status":"passed","title":"'local-device': all models OpenAI→target","duration":0.04937500000005457,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["coverage: every model translates without throwing"],"fullName":"coverage: every model translates without throwing 'google-tts': all models OpenAI→target","status":"passed","title":"'google-tts': all models OpenAI→target","duration":1.1268749999999272,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["coverage: every model translates without throwing"],"fullName":"coverage: every model translates without throwing 'gemini-tts-models': all models OpenAI→target","status":"passed","title":"'gemini-tts-models': all models OpenAI→target","duration":0.07345800000030067,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["coverage: every model translates without throwing"],"fullName":"coverage: every model translates without throwing 'gemini-tts-voices': all models OpenAI→target","status":"passed","title":"'gemini-tts-voices': all models OpenAI→target","duration":7.601541999999881,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["coverage: image-strip models drop image content"],"fullName":"coverage: image-strip models drop image content 'kr'/'deepseek-3.2' strips image when strip=[image]","status":"passed","title":"'kr'/'deepseek-3.2' strips image when strip=[image]","duration":16.16687499999989,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["coverage: image-strip models drop image content"],"fullName":"coverage: image-strip models drop image content 'kr'/'qwen3-coder-next' strips image when strip=[image]","status":"passed","title":"'kr'/'qwen3-coder-next' strips image when strip=[image]","duration":3.492833000000246,"failureMessages":[],"meta":{},"tags":[]}],"startTime":1781440230788,"endTime":1781440231935.493,"status":"passed","message":"","name":"/Users/Working/router4/app/tests/translator/coverage-all-models.test.js"},{"assertionResults":[{"ancestorTitles":["roundtrip: Claude source preserves core fields → OpenAI"],"fullName":"roundtrip: Claude source preserves core fields → OpenAI system → system role","status":"passed","title":"system → system role","duration":3.439374999999984,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["roundtrip: Claude source preserves core fields → OpenAI"],"fullName":"roundtrip: Claude source preserves core fields → OpenAI tool_use → assistant.tool_calls with matching id","status":"passed","title":"tool_use → assistant.tool_calls with matching id","duration":0.5636250000000018,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["roundtrip: Claude source preserves core fields → OpenAI"],"fullName":"roundtrip: Claude source preserves core fields → OpenAI tool_result → tool message with matching id","status":"passed","title":"tool_result → tool message with matching id","duration":0.39100000000001955,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["roundtrip: Claude source preserves core fields → OpenAI"],"fullName":"roundtrip: Claude source preserves core fields → OpenAI tool arguments are valid JSON string","status":"passed","title":"tool arguments are valid JSON string","duration":1.1201249999999732,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["roundtrip: OpenAI tools → Claude → keeps tool name"],"fullName":"roundtrip: OpenAI tools → Claude → keeps tool name tool name survives openai→claude","status":"passed","title":"tool name survives openai→claude","duration":0.3375419999999849,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["roundtrip: parallel tool calls keep distinct ids"],"fullName":"roundtrip: parallel tool calls keep distinct ids two tool_calls, two distinct ids","status":"passed","title":"two tool_calls, two distinct ids","duration":0.31674999999995634,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["roundtrip: parallel tool calls keep distinct ids"],"fullName":"roundtrip: parallel tool calls keep distinct ids each tool_call has a matching tool result","status":"passed","title":"each tool_call has a matching tool result","duration":0.41100000000000136,"failureMessages":[],"meta":{},"tags":[]}],"startTime":1781440251765,"endTime":1781440251772.411,"status":"passed","message":"","name":"/Users/Working/router4/app/tests/translator/format-roundtrip.test.js"},{"assertionResults":[{"ancestorTitles":["GOLDEN request: OpenAI → Claude"],"fullName":"GOLDEN request: OpenAI → Claude full body (system/image/tool/tool_result)","status":"passed","title":"full body (system/image/tool/tool_result)","duration":366.55991599999993,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["GOLDEN request: OpenAI → Claude"],"fullName":"GOLDEN request: OpenAI → Claude reasoning_effort → thinking budget","status":"passed","title":"reasoning_effort → thinking budget","duration":1.4106249999999818,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["GOLDEN request: OpenAI → Gemini"],"fullName":"GOLDEN request: OpenAI → Gemini full body (system/image/tool/tool_result)","status":"passed","title":"full body (system/image/tool/tool_result)","duration":3.6192919999998594,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["GOLDEN request: OpenAI → Kiro"],"fullName":"GOLDEN request: OpenAI → Kiro full body (image base64 + tool_result)","status":"passed","title":"full body (image base64 + tool_result)","duration":5.137541999999939,"failureMessages":[],"meta":{},"tags":[]}],"startTime":1781440230741,"endTime":1781440231118.1375,"status":"passed","message":"","name":"/Users/Working/router4/app/tests/translator/golden-request.test.js"},{"assertionResults":[{"ancestorTitles":["GOLDEN response stream: Claude → OpenAI"],"fullName":"GOLDEN response stream: Claude → OpenAI text + thinking + tool_use + usage + finish","status":"passed","title":"text + thinking + tool_use + usage + finish","duration":721.7815830000004,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["GOLDEN response stream: Gemini → OpenAI"],"fullName":"GOLDEN response stream: Gemini → OpenAI text + thought(no-sig) + functionCall + usage + finish","status":"passed","title":"text + thought(no-sig) + functionCall + usage + finish","duration":101.54204200000004,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["GOLDEN response stream: Gemini → OpenAI"],"fullName":"GOLDEN response stream: Gemini → OpenAI image output (inlineData → delta.images)","status":"passed","title":"image output (inlineData → delta.images)","duration":22.590749999999844,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["GOLDEN response stream: Kiro → OpenAI"],"fullName":"GOLDEN response stream: Kiro → OpenAI text + reasoning + toolUse + usage + stop","status":"passed","title":"text + reasoning + toolUse + usage + stop","duration":2.7278329999999187,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["GOLDEN response stream: Ollama → OpenAI"],"fullName":"GOLDEN response stream: Ollama → OpenAI content + thinking + tool_calls + done usage","status":"passed","title":"content + thinking + tool_calls + done usage","duration":1.015374999999949,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["GOLDEN response stream: OpenAI-Responses (codex) → OpenAI"],"fullName":"GOLDEN response stream: OpenAI-Responses (codex) → OpenAI text + reasoning + tool_call + completed usage","status":"passed","title":"text + reasoning + tool_call + completed usage","duration":1.217124999999669,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["GOLDEN response stream: OpenAI-Responses (codex) → OpenAI"],"fullName":"GOLDEN response stream: OpenAI-Responses (codex) → OpenAI error event → error chunk (fallback id/created)","status":"passed","title":"error event → error chunk (fallback id/created)","duration":0.3099160000001575,"failureMessages":[],"meta":{},"tags":[]}],"startTime":1781440238945,"endTime":1781440239797.3098,"status":"passed","message":"","name":"/Users/Working/router4/app/tests/translator/golden-response-stream.test.js"},{"assertionResults":[{"ancestorTitles":["GOLDEN response stream: CommandCode → OpenAI"],"fullName":"GOLDEN response stream: CommandCode → OpenAI text + reasoning + tool + finish-step usage","status":"passed","title":"text + reasoning + tool + finish-step usage","duration":1026.226291,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["GOLDEN response stream: Kiro → OpenAI (finish after tool)"],"fullName":"GOLDEN response stream: Kiro → OpenAI (finish after tool) toolUse then stop — lock current finish_reason behavior","status":"passed","title":"toolUse then stop — lock current finish_reason behavior","duration":26.410875000000033,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["GOLDEN response stream: Ollama → OpenAI (finish after tool)"],"fullName":"GOLDEN response stream: Ollama → OpenAI (finish after tool) tool_calls then done_reason=stop — lock current finish_reason","status":"passed","title":"tool_calls then done_reason=stop — lock current finish_reason","duration":44.83966600000031,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["GOLDEN passthrough: same format = no translation"],"fullName":"GOLDEN passthrough: same format = no translation response openai→openai returns chunk unchanged","status":"passed","title":"response openai→openai returns chunk unchanged","duration":3.052582999999686,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["GOLDEN passthrough: same format = no translation"],"fullName":"GOLDEN passthrough: same format = no translation request openai→openai keeps messages (filterToOpenAIFormat normalize)","status":"passed","title":"request openai→openai keeps messages (filterToOpenAIFormat normalize)","duration":146.0737079999999,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["GOLDEN usage math: Claude prompt = input + cache (lock)"],"fullName":"GOLDEN usage math: Claude prompt = input + cache (lock) prompt_tokens sums input + cache_read + cache_creation","status":"passed","title":"prompt_tokens sums input + cache_read + cache_creation","duration":1.2776660000008633,"failureMessages":[],"meta":{},"tags":[]}],"startTime":1781440239568,"endTime":1781440240818.2776,"status":"passed","message":"","name":"/Users/Working/router4/app/tests/translator/golden-translator-concerns.test.js"},{"assertionResults":[{"ancestorTitles":["GOLDEN buildUrl (default executor providers)"],"fullName":"GOLDEN buildUrl (default executor providers) alicode → url (stream + non-stream)","status":"passed","title":"alicode → url (stream + non-stream)","duration":4.083458000000064,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["GOLDEN buildUrl (default executor providers)"],"fullName":"GOLDEN buildUrl (default executor providers) alicode-intl → url (stream + non-stream)","status":"passed","title":"alicode-intl → url (stream + non-stream)","duration":0.8622909999999138,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["GOLDEN buildUrl (default executor providers)"],"fullName":"GOLDEN buildUrl (default executor providers) anthropic → url (stream + non-stream)","status":"passed","title":"anthropic → url (stream + non-stream)","duration":0.48608299999978044,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["GOLDEN buildUrl (default executor providers)"],"fullName":"GOLDEN buildUrl (default executor providers) assemblyai → url (stream + non-stream)","status":"passed","title":"assemblyai → url (stream + non-stream)","duration":0.5214999999998327,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["GOLDEN buildUrl (default executor providers)"],"fullName":"GOLDEN buildUrl (default executor providers) blackbox → url (stream + non-stream)","status":"passed","title":"blackbox → url (stream + non-stream)","duration":0.4259159999996882,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["GOLDEN buildUrl (default executor providers)"],"fullName":"GOLDEN buildUrl (default executor providers) byteplus → url (stream + non-stream)","status":"passed","title":"byteplus → url (stream + non-stream)","duration":0.2525829999999587,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["GOLDEN buildUrl (default executor providers)"],"fullName":"GOLDEN buildUrl (default executor providers) cerebras → url (stream + non-stream)","status":"passed","title":"cerebras → url (stream + non-stream)","duration":0.35420899999962785,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["GOLDEN buildUrl (default executor providers)"],"fullName":"GOLDEN buildUrl (default executor providers) chutes → url (stream + non-stream)","status":"passed","title":"chutes → url (stream + non-stream)","duration":0.2428340000001299,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["GOLDEN buildUrl (default executor providers)"],"fullName":"GOLDEN buildUrl (default executor providers) claude → url (stream + non-stream)","status":"passed","title":"claude → url (stream + non-stream)","duration":2.3325410000002194,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["GOLDEN buildUrl (default executor providers)"],"fullName":"GOLDEN buildUrl (default executor providers) cline → url (stream + non-stream)","status":"passed","title":"cline → url (stream + non-stream)","duration":0.5232499999997344,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["GOLDEN buildUrl (default executor providers)"],"fullName":"GOLDEN buildUrl (default executor providers) cloudflare-ai → url (stream + non-stream)","status":"passed","title":"cloudflare-ai → url (stream + non-stream)","duration":0.3628750000002583,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["GOLDEN buildUrl (default executor providers)"],"fullName":"GOLDEN buildUrl (default executor providers) codebuddy → url (stream + non-stream)","status":"passed","title":"codebuddy → url (stream + non-stream)","duration":0.1604170000000522,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["GOLDEN buildUrl (default executor providers)"],"fullName":"GOLDEN buildUrl (default executor providers) cohere → url (stream + non-stream)","status":"passed","title":"cohere → url (stream + non-stream)","duration":0.13554199999998673,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["GOLDEN buildUrl (default executor providers)"],"fullName":"GOLDEN buildUrl (default executor providers) deepgram → url (stream + non-stream)","status":"passed","title":"deepgram → url (stream + non-stream)","duration":0.11420799999996234,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["GOLDEN buildUrl (default executor providers)"],"fullName":"GOLDEN buildUrl (default executor providers) deepseek → url (stream + non-stream)","status":"passed","title":"deepseek → url (stream + non-stream)","duration":0.16320900000027905,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["GOLDEN buildUrl (default executor providers)"],"fullName":"GOLDEN buildUrl (default executor providers) fireworks → url (stream + non-stream)","status":"passed","title":"fireworks → url (stream + non-stream)","duration":0.20537500000000364,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["GOLDEN buildUrl (default executor providers)"],"fullName":"GOLDEN buildUrl (default executor providers) gemini → url (stream + non-stream)","status":"passed","title":"gemini → url (stream + non-stream)","duration":0.1231670000001941,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["GOLDEN buildUrl (default executor providers)"],"fullName":"GOLDEN buildUrl (default executor providers) gitlab → url (stream + non-stream)","status":"passed","title":"gitlab → url (stream + non-stream)","duration":0.11541699999997945,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["GOLDEN buildUrl (default executor providers)"],"fullName":"GOLDEN buildUrl (default executor providers) glm → url (stream + non-stream)","status":"passed","title":"glm → url (stream + non-stream)","duration":0.11908300000004601,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["GOLDEN buildUrl (default executor providers)"],"fullName":"GOLDEN buildUrl (default executor providers) glm-cn → url (stream + non-stream)","status":"passed","title":"glm-cn → url (stream + non-stream)","duration":0.11262499999975262,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["GOLDEN buildUrl (default executor providers)"],"fullName":"GOLDEN buildUrl (default executor providers) groq → url (stream + non-stream)","status":"passed","title":"groq → url (stream + non-stream)","duration":0.10854199999994307,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["GOLDEN buildUrl (default executor providers)"],"fullName":"GOLDEN buildUrl (default executor providers) hyperbolic → url (stream + non-stream)","status":"passed","title":"hyperbolic → url (stream + non-stream)","duration":0.1073750000000473,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["GOLDEN buildUrl (default executor providers)"],"fullName":"GOLDEN buildUrl (default executor providers) kilocode → url (stream + non-stream)","status":"passed","title":"kilocode → url (stream + non-stream)","duration":0.11208399999986796,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["GOLDEN buildUrl (default executor providers)"],"fullName":"GOLDEN buildUrl (default executor providers) kimi → url (stream + non-stream)","status":"passed","title":"kimi → url (stream + non-stream)","duration":0.11416600000029575,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["GOLDEN buildUrl (default executor providers)"],"fullName":"GOLDEN buildUrl (default executor providers) kimi-coding → url (stream + non-stream)","status":"passed","title":"kimi-coding → url (stream + non-stream)","duration":0.20404199999984485,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["GOLDEN buildUrl (default executor providers)"],"fullName":"GOLDEN buildUrl (default executor providers) minimax → url (stream + non-stream)","status":"passed","title":"minimax → url (stream + non-stream)","duration":0.1496249999995598,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["GOLDEN buildUrl (default executor providers)"],"fullName":"GOLDEN buildUrl (default executor providers) minimax-cn → url (stream + non-stream)","status":"passed","title":"minimax-cn → url (stream + non-stream)","duration":0.12170900000000984,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["GOLDEN buildUrl (default executor providers)"],"fullName":"GOLDEN buildUrl (default executor providers) mistral → url (stream + non-stream)","status":"passed","title":"mistral → url (stream + non-stream)","duration":0.11929099999997561,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["GOLDEN buildUrl (default executor providers)"],"fullName":"GOLDEN buildUrl (default executor providers) mmf → url (stream + non-stream)","status":"passed","title":"mmf → url (stream + non-stream)","duration":0.11866600000030303,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["GOLDEN buildUrl (default executor providers)"],"fullName":"GOLDEN buildUrl (default executor providers) nanobanana → url (stream + non-stream)","status":"passed","title":"nanobanana → url (stream + non-stream)","duration":0.11416600000029575,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["GOLDEN buildUrl (default executor providers)"],"fullName":"GOLDEN buildUrl (default executor providers) nebius → url (stream + non-stream)","status":"passed","title":"nebius → url (stream + non-stream)","duration":0.11550000000033833,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["GOLDEN buildUrl (default executor providers)"],"fullName":"GOLDEN buildUrl (default executor providers) nvidia → url (stream + non-stream)","status":"passed","title":"nvidia → url (stream + non-stream)","duration":0.15162499999996726,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["GOLDEN buildUrl (default executor providers)"],"fullName":"GOLDEN buildUrl (default executor providers) ollama → url (stream + non-stream)","status":"passed","title":"ollama → url (stream + non-stream)","duration":0.12579199999981938,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["GOLDEN buildUrl (default executor providers)"],"fullName":"GOLDEN buildUrl (default executor providers) openai → url (stream + non-stream)","status":"passed","title":"openai → url (stream + non-stream)","duration":0.1089999999999236,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["GOLDEN buildUrl (default executor providers)"],"fullName":"GOLDEN buildUrl (default executor providers) openrouter → url (stream + non-stream)","status":"passed","title":"openrouter → url (stream + non-stream)","duration":0.11129200000004857,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["GOLDEN buildUrl (default executor providers)"],"fullName":"GOLDEN buildUrl (default executor providers) perplexity → url (stream + non-stream)","status":"passed","title":"perplexity → url (stream + non-stream)","duration":0.10637499999984357,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["GOLDEN buildUrl (default executor providers)"],"fullName":"GOLDEN buildUrl (default executor providers) siliconflow → url (stream + non-stream)","status":"passed","title":"siliconflow → url (stream + non-stream)","duration":0.10429199999998673,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["GOLDEN buildUrl (default executor providers)"],"fullName":"GOLDEN buildUrl (default executor providers) together → url (stream + non-stream)","status":"passed","title":"together → url (stream + non-stream)","duration":0.10474999999996726,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["GOLDEN buildUrl (default executor providers)"],"fullName":"GOLDEN buildUrl (default executor providers) vercel-ai-gateway → url (stream + non-stream)","status":"passed","title":"vercel-ai-gateway → url (stream + non-stream)","duration":0.10483399999975518,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["GOLDEN buildUrl (default executor providers)"],"fullName":"GOLDEN buildUrl (default executor providers) volcengine-ark → url (stream + non-stream)","status":"passed","title":"volcengine-ark → url (stream + non-stream)","duration":0.10029200000008132,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["GOLDEN buildUrl (default executor providers)"],"fullName":"GOLDEN buildUrl (default executor providers) xai → url (stream + non-stream)","status":"passed","title":"xai → url (stream + non-stream)","duration":0.1056669999998121,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["GOLDEN buildUrl (default executor providers)"],"fullName":"GOLDEN buildUrl (default executor providers) xiaomi-mimo → url (stream + non-stream)","status":"passed","title":"xiaomi-mimo → url (stream + non-stream)","duration":0.10266700000011042,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["GOLDEN buildHeaders (default executor providers)"],"fullName":"GOLDEN buildHeaders (default executor providers) alicode → headers (apiKey / oauth)","status":"passed","title":"alicode → headers (apiKey / oauth)","duration":0.9642079999998714,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["GOLDEN buildHeaders (default executor providers)"],"fullName":"GOLDEN buildHeaders (default executor providers) alicode-intl → headers (apiKey / oauth)","status":"passed","title":"alicode-intl → headers (apiKey / oauth)","duration":0.23045900000033726,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["GOLDEN buildHeaders (default executor providers)"],"fullName":"GOLDEN buildHeaders (default executor providers) anthropic → headers (apiKey / oauth)","status":"passed","title":"anthropic → headers (apiKey / oauth)","duration":0.38383299999986775,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["GOLDEN buildHeaders (default executor providers)"],"fullName":"GOLDEN buildHeaders (default executor providers) assemblyai → headers (apiKey / oauth)","status":"passed","title":"assemblyai → headers (apiKey / oauth)","duration":0.18854200000032506,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["GOLDEN buildHeaders (default executor providers)"],"fullName":"GOLDEN buildHeaders (default executor providers) blackbox → headers (apiKey / oauth)","status":"passed","title":"blackbox → headers (apiKey / oauth)","duration":0.16975000000002183,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["GOLDEN buildHeaders (default executor providers)"],"fullName":"GOLDEN buildHeaders (default executor providers) byteplus → headers (apiKey / oauth)","status":"passed","title":"byteplus → headers (apiKey / oauth)","duration":0.3229590000000826,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["GOLDEN buildHeaders (default executor providers)"],"fullName":"GOLDEN buildHeaders (default executor providers) cerebras → headers (apiKey / oauth)","status":"passed","title":"cerebras → headers (apiKey / oauth)","duration":0.19733300000007148,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["GOLDEN buildHeaders (default executor providers)"],"fullName":"GOLDEN buildHeaders (default executor providers) chutes → headers (apiKey / oauth)","status":"passed","title":"chutes → headers (apiKey / oauth)","duration":0.1697079999999005,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["GOLDEN buildHeaders (default executor providers)"],"fullName":"GOLDEN buildHeaders (default executor providers) claude → headers (apiKey / oauth)","status":"passed","title":"claude → headers (apiKey / oauth)","duration":0.5587920000002669,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["GOLDEN buildHeaders (default executor providers)"],"fullName":"GOLDEN buildHeaders (default executor providers) cline → headers (apiKey / oauth)","status":"passed","title":"cline → headers (apiKey / oauth)","duration":0.5070840000003045,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["GOLDEN buildHeaders (default executor providers)"],"fullName":"GOLDEN buildHeaders (default executor providers) cloudflare-ai → headers (apiKey / oauth)","status":"passed","title":"cloudflare-ai → headers (apiKey / oauth)","duration":0.2231669999996484,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["GOLDEN buildHeaders (default executor providers)"],"fullName":"GOLDEN buildHeaders (default executor providers) codebuddy → headers (apiKey / oauth)","status":"passed","title":"codebuddy → headers (apiKey / oauth)","duration":0.17054099999995742,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["GOLDEN buildHeaders (default executor providers)"],"fullName":"GOLDEN buildHeaders (default executor providers) cohere → headers (apiKey / oauth)","status":"passed","title":"cohere → headers (apiKey / oauth)","duration":0.16224999999985812,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["GOLDEN buildHeaders (default executor providers)"],"fullName":"GOLDEN buildHeaders (default executor providers) deepgram → headers (apiKey / oauth)","status":"passed","title":"deepgram → headers (apiKey / oauth)","duration":0.15929099999993923,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["GOLDEN buildHeaders (default executor providers)"],"fullName":"GOLDEN buildHeaders (default executor providers) deepseek → headers (apiKey / oauth)","status":"passed","title":"deepseek → headers (apiKey / oauth)","duration":0.16720799999984592,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["GOLDEN buildHeaders (default executor providers)"],"fullName":"GOLDEN buildHeaders (default executor providers) fireworks → headers (apiKey / oauth)","status":"passed","title":"fireworks → headers (apiKey / oauth)","duration":0.15358399999968242,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["GOLDEN buildHeaders (default executor providers)"],"fullName":"GOLDEN buildHeaders (default executor providers) gemini → headers (apiKey / oauth)","status":"passed","title":"gemini → headers (apiKey / oauth)","duration":0.1792089999999007,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["GOLDEN buildHeaders (default executor providers)"],"fullName":"GOLDEN buildHeaders (default executor providers) gitlab → headers (apiKey / oauth)","status":"passed","title":"gitlab → headers (apiKey / oauth)","duration":0.1593750000001819,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["GOLDEN buildHeaders (default executor providers)"],"fullName":"GOLDEN buildHeaders (default executor providers) glm → headers (apiKey / oauth)","status":"passed","title":"glm → headers (apiKey / oauth)","duration":0.20087499999999636,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["GOLDEN buildHeaders (default executor providers)"],"fullName":"GOLDEN buildHeaders (default executor providers) glm-cn → headers (apiKey / oauth)","status":"passed","title":"glm-cn → headers (apiKey / oauth)","duration":0.7633749999999964,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["GOLDEN buildHeaders (default executor providers)"],"fullName":"GOLDEN buildHeaders (default executor providers) groq → headers (apiKey / oauth)","status":"passed","title":"groq → headers (apiKey / oauth)","duration":0.3634999999999309,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["GOLDEN buildHeaders (default executor providers)"],"fullName":"GOLDEN buildHeaders (default executor providers) hyperbolic → headers (apiKey / oauth)","status":"passed","title":"hyperbolic → headers (apiKey / oauth)","duration":0.37191699999993943,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["GOLDEN buildHeaders (default executor providers)"],"fullName":"GOLDEN buildHeaders (default executor providers) kilocode → headers (apiKey / oauth)","status":"passed","title":"kilocode → headers (apiKey / oauth)","duration":0.29120899999998073,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["GOLDEN buildHeaders (default executor providers)"],"fullName":"GOLDEN buildHeaders (default executor providers) kimi → headers (apiKey / oauth)","status":"passed","title":"kimi → headers (apiKey / oauth)","duration":0.22000000000025466,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["GOLDEN buildHeaders (default executor providers)"],"fullName":"GOLDEN buildHeaders (default executor providers) kimi-coding → headers (apiKey / oauth)","status":"passed","title":"kimi-coding → headers (apiKey / oauth)","duration":0.39091599999983373,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["GOLDEN buildHeaders (default executor providers)"],"fullName":"GOLDEN buildHeaders (default executor providers) minimax → headers (apiKey / oauth)","status":"passed","title":"minimax → headers (apiKey / oauth)","duration":0.18487499999991996,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["GOLDEN buildHeaders (default executor providers)"],"fullName":"GOLDEN buildHeaders (default executor providers) minimax-cn → headers (apiKey / oauth)","status":"passed","title":"minimax-cn → headers (apiKey / oauth)","duration":0.17766699999992852,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["GOLDEN buildHeaders (default executor providers)"],"fullName":"GOLDEN buildHeaders (default executor providers) mistral → headers (apiKey / oauth)","status":"passed","title":"mistral → headers (apiKey / oauth)","duration":0.15987499999982901,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["GOLDEN buildHeaders (default executor providers)"],"fullName":"GOLDEN buildHeaders (default executor providers) mmf → headers (apiKey / oauth)","status":"passed","title":"mmf → headers (apiKey / oauth)","duration":0.16437500000029104,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["GOLDEN buildHeaders (default executor providers)"],"fullName":"GOLDEN buildHeaders (default executor providers) nanobanana → headers (apiKey / oauth)","status":"passed","title":"nanobanana → headers (apiKey / oauth)","duration":0.14566699999977573,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["GOLDEN buildHeaders (default executor providers)"],"fullName":"GOLDEN buildHeaders (default executor providers) nebius → headers (apiKey / oauth)","status":"passed","title":"nebius → headers (apiKey / oauth)","duration":0.14454200000000128,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["GOLDEN buildHeaders (default executor providers)"],"fullName":"GOLDEN buildHeaders (default executor providers) nvidia → headers (apiKey / oauth)","status":"passed","title":"nvidia → headers (apiKey / oauth)","duration":0.1475420000001577,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["GOLDEN buildHeaders (default executor providers)"],"fullName":"GOLDEN buildHeaders (default executor providers) ollama → headers (apiKey / oauth)","status":"passed","title":"ollama → headers (apiKey / oauth)","duration":0.14937499999996362,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["GOLDEN buildHeaders (default executor providers)"],"fullName":"GOLDEN buildHeaders (default executor providers) openai → headers (apiKey / oauth)","status":"passed","title":"openai → headers (apiKey / oauth)","duration":0.3275000000003274,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["GOLDEN buildHeaders (default executor providers)"],"fullName":"GOLDEN buildHeaders (default executor providers) openrouter → headers (apiKey / oauth)","status":"passed","title":"openrouter → headers (apiKey / oauth)","duration":0.24454199999991033,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["GOLDEN buildHeaders (default executor providers)"],"fullName":"GOLDEN buildHeaders (default executor providers) perplexity → headers (apiKey / oauth)","status":"passed","title":"perplexity → headers (apiKey / oauth)","duration":0.17566600000009203,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["GOLDEN buildHeaders (default executor providers)"],"fullName":"GOLDEN buildHeaders (default executor providers) siliconflow → headers (apiKey / oauth)","status":"passed","title":"siliconflow → headers (apiKey / oauth)","duration":2.4016249999999673,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["GOLDEN buildHeaders (default executor providers)"],"fullName":"GOLDEN buildHeaders (default executor providers) together → headers (apiKey / oauth)","status":"passed","title":"together → headers (apiKey / oauth)","duration":0.28412500000013097,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["GOLDEN buildHeaders (default executor providers)"],"fullName":"GOLDEN buildHeaders (default executor providers) vercel-ai-gateway → headers (apiKey / oauth)","status":"passed","title":"vercel-ai-gateway → headers (apiKey / oauth)","duration":0.20195800000010422,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["GOLDEN buildHeaders (default executor providers)"],"fullName":"GOLDEN buildHeaders (default executor providers) volcengine-ark → headers (apiKey / oauth)","status":"passed","title":"volcengine-ark → headers (apiKey / oauth)","duration":0.1678340000003118,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["GOLDEN buildHeaders (default executor providers)"],"fullName":"GOLDEN buildHeaders (default executor providers) xai → headers (apiKey / oauth)","status":"passed","title":"xai → headers (apiKey / oauth)","duration":0.1540829999999005,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["GOLDEN buildHeaders (default executor providers)"],"fullName":"GOLDEN buildHeaders (default executor providers) xiaomi-mimo → headers (apiKey / oauth)","status":"passed","title":"xiaomi-mimo → headers (apiKey / oauth)","duration":0.14979200000016135,"failureMessages":[],"meta":{},"tags":[]}],"startTime":1781440250559,"endTime":1781440250587.2842,"status":"passed","message":"","name":"/Users/Working/router4/app/tests/translator/golden-url-header.test.js"},{"assertionResults":[{"ancestorTitles":["Antigravity cache behavior (real API)"],"fullName":"Antigravity cache behavior (real API) has at least one active AG connection with refreshToken","status":"skipped","title":"has at least one active AG connection with refreshToken","failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["Antigravity cache behavior (real API)"],"fullName":"Antigravity cache behavior (real API) same sessionId → cache hit on repeated call","status":"skipped","title":"same sessionId → cache hit on repeated call","failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["Antigravity cache behavior (real API)"],"fullName":"Antigravity cache behavior (real API) different sessionId (same account) → cache still hits (session-independent)","status":"skipped","title":"different sessionId (same account) → cache still hits (session-independent)","failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["Antigravity cache behavior (real API)"],"fullName":"Antigravity cache behavior (real API) cross-account → cache SHARED (content-based global cache)","status":"skipped","title":"cross-account → cache SHARED (content-based global cache)","failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["Antigravity cache behavior (real API)"],"fullName":"Antigravity cache behavior (real API) codex-style sessionId vs random sessionId on unique prompt","status":"skipped","title":"codex-style sessionId vs random sessionId on unique prompt","failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["Antigravity cache behavior (real API)"],"fullName":"Antigravity cache behavior (real API) unique prompt (never seen) → explore when cache starts hitting","status":"skipped","title":"unique prompt (never seen) → explore when cache starts hitting","failureMessages":[],"meta":{},"tags":[]}],"startTime":1781440226639,"endTime":1781440226639,"status":"passed","message":"","name":"/Users/Working/router4/app/tests/unit/antigravity-cache.test.js"},{"assertionResults":[{"ancestorTitles":["Antigravity MITM model handling"],"fullName":"Antigravity MITM model handling flags the out-of-box agent/Default model mandatory","status":"failed","title":"flags the out-of-box agent/Default model mandatory","duration":4.9560419999999965,"failureMessages":["AssertionError: expected undefined to be true // Object.is equality\n at /Users/Working/router4/app/tests/unit/antigravity-mitm.test.js:17:86\n at file:///Users/hoanganh/.npm/_npx/69c381f8ad94b576/node_modules/@vitest/runner/dist/chunk-artifact.js:302:11\n at file:///Users/hoanganh/.npm/_npx/69c381f8ad94b576/node_modules/@vitest/runner/dist/chunk-artifact.js:1903:26\n at file:///Users/hoanganh/.npm/_npx/69c381f8ad94b576/node_modules/@vitest/runner/dist/chunk-artifact.js:2326:20\n at new Promise ()\n at runWithCancel (file:///Users/hoanganh/.npm/_npx/69c381f8ad94b576/node_modules/@vitest/runner/dist/chunk-artifact.js:2323:10)\n at file:///Users/hoanganh/.npm/_npx/69c381f8ad94b576/node_modules/@vitest/runner/dist/chunk-artifact.js:2305:20\n at new Promise ()\n at runWithTimeout (file:///Users/hoanganh/.npm/_npx/69c381f8ad94b576/node_modules/@vitest/runner/dist/chunk-artifact.js:2272:10)\n at file:///Users/hoanganh/.npm/_npx/69c381f8ad94b576/node_modules/@vitest/runner/dist/chunk-artifact.js:2955:64"],"meta":{},"tags":[]},{"ancestorTitles":["Antigravity MITM model handling"],"fullName":"Antigravity MITM model handling leaves models not proven auto-sent optional","status":"passed","title":"leaves models not proven auto-sent optional","duration":0.3435410000000161,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["Antigravity MITM model handling"],"fullName":"Antigravity MITM model handling excludes tab-autocomplete model 'tab_jump_flash_lite_preview' from re-routing","status":"passed","title":"excludes tab-autocomplete model 'tab_jump_flash_lite_preview' from re-routing","duration":0.12083399999997368,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["Antigravity MITM model handling"],"fullName":"Antigravity MITM model handling excludes tab-autocomplete model 'tab_flash_lite_preview' from re-routing","status":"passed","title":"excludes tab-autocomplete model 'tab_flash_lite_preview' from re-routing","duration":0.22262499999999363,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["Antigravity MITM model handling"],"fullName":"Antigravity MITM model handling does not exclude real agent models from re-routing","status":"passed","title":"does not exclude real agent models from re-routing","duration":0.17554100000000972,"failureMessages":[],"meta":{},"tags":[]}],"startTime":1781440227031,"endTime":1781440227036.3435,"status":"failed","message":"","name":"/Users/Working/router4/app/tests/unit/antigravity-mitm.test.js"},{"assertionResults":[{"ancestorTitles":["antigravity oauth client (deduped)"],"fullName":"antigravity oauth client (deduped) shared source holds the canonical credentials","status":"passed","title":"shared source holds the canonical credentials","duration":4.8775409999999795,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["antigravity oauth client (deduped)"],"fullName":"antigravity oauth client (deduped) registry transport keeps clientId/clientSecret","status":"passed","title":"registry transport keeps clientId/clientSecret","duration":3.5512080000000026,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["antigravity oauth client (deduped)"],"fullName":"antigravity oauth client (deduped) google client shared by gemini + gemini-cli","status":"passed","title":"google client shared by gemini + gemini-cli","duration":4.118207999999981,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["antigravity oauth client (deduped)"],"fullName":"antigravity oauth client (deduped) src oauth.js imports shared client + keeps full shape","status":"passed","title":"src oauth.js imports shared client + keeps full shape","duration":2.052166999999997,"failureMessages":[],"meta":{},"tags":[]}],"startTime":1781440250809,"endTime":1781440250823.0522,"status":"passed","message":"","name":"/Users/Working/router4/app/tests/unit/antigravity-oauth-client.test.js"},{"assertionResults":[{"ancestorTitles":["antigravity computeRetryDelay hook (D3)"],"fullName":"antigravity computeRetryDelay hook (D3) uses Retry-After header (seconds → ms) when within cap","status":"passed","title":"uses Retry-After header (seconds → ms) when within cap","duration":2.374041000000034,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["antigravity computeRetryDelay hook (D3)"],"fullName":"antigravity computeRetryDelay hook (D3) vetoes (false) when Retry-After exceeds cap","status":"passed","title":"vetoes (false) when Retry-After exceeds cap","duration":0.43870899999996027,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["antigravity computeRetryDelay hook (D3)"],"fullName":"antigravity computeRetryDelay hook (D3) parses retry time from error body when no header","status":"passed","title":"parses retry time from error body when no header","duration":0.5752919999999904,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["antigravity computeRetryDelay hook (D3)"],"fullName":"antigravity computeRetryDelay hook (D3) exponential backoff for 429 when no retry info","status":"passed","title":"exponential backoff for 429 when no retry info","duration":0.6159999999999854,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["antigravity computeRetryDelay hook (D3)"],"fullName":"antigravity computeRetryDelay hook (D3) 503 without retry info → veto (no auto backoff)","status":"passed","title":"503 without retry info → veto (no auto backoff)","duration":0.20591699999999946,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["antigravity computeRetryDelay hook (D3)"],"fullName":"antigravity computeRetryDelay hook (D3) buildHeaders includes cached session id after transformRequest","status":"passed","title":"buildHeaders includes cached session id after transformRequest","duration":0.6917920000000208,"failureMessages":[],"meta":{},"tags":[]}],"startTime":1781440251676,"endTime":1781440251681.692,"status":"passed","message":"","name":"/Users/Working/router4/app/tests/unit/antigravity-retry-hook.test.js"},{"assertionResults":[{"ancestorTitles":["BaseExecutor.execute — retry by status (config-driven)"],"fullName":"BaseExecutor.execute — retry by status (config-driven) retries 502 `attempts` times then succeeds","status":"passed","title":"retries 502 `attempts` times then succeeds","duration":290.3187090000001,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["BaseExecutor.execute — retry by status (config-driven)"],"fullName":"BaseExecutor.execute — retry by status (config-driven) stops after exhausting 502 attempts on a single url and throws","status":"passed","title":"stops after exhausting 502 attempts on a single url and throws","duration":41.724333000000115,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["BaseExecutor.execute — baseUrls fallback"],"fullName":"BaseExecutor.execute — baseUrls fallback falls over to the next url on 429 (shouldRetry)","status":"passed","title":"falls over to the next url on 429 (shouldRetry)","duration":50.89816699999983,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["BaseExecutor.execute — network error retry/fallback"],"fullName":"BaseExecutor.execute — network error retry/fallback maps network exception to 502 retry config","status":"passed","title":"maps network exception to 502 retry config","duration":33.02283400000033,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["BaseExecutor.execute — network error retry/fallback"],"fullName":"BaseExecutor.execute — network error retry/fallback throws when the only url fails with network error and no retries left","status":"passed","title":"throws when the only url fails with network error and no retries left","duration":34.121083,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["BaseExecutor.execute — computeRetryDelay hook veto"],"fullName":"BaseExecutor.execute — computeRetryDelay hook veto hook returning false skips retry (uses fallback path)","status":"passed","title":"hook returning false skips retry (uses fallback path)","duration":0.8415000000004511,"failureMessages":[],"meta":{},"tags":[]}],"startTime":1781440241196,"endTime":1781440241669.8416,"status":"passed","message":"","name":"/Users/Working/router4/app/tests/unit/base-executor-retry.test.js"},{"assertionResults":[{"ancestorTitles":["PR #1175 - buildOutput filter detection"],"fullName":"PR #1175 - buildOutput filter detection detects npm install output","status":"passed","title":"detects npm install output","duration":3.4810829999998987,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["PR #1175 - buildOutput filter detection"],"fullName":"PR #1175 - buildOutput filter detection detects cargo build output (no longer misdetected as git-status)","status":"passed","title":"detects cargo build output (no longer misdetected as git-status)","duration":1.9381250000001273,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["PR #1175 - buildOutput compression behavior"],"fullName":"PR #1175 - buildOutput compression behavior compresses npm install with deprecations","status":"passed","title":"compresses npm install with deprecations","duration":2.1507910000000265,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["PR #1175 - buildOutput compression behavior"],"fullName":"PR #1175 - buildOutput compression behavior compresses cargo build output","status":"passed","title":"compresses cargo build output","duration":0.891832999999906,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["PR #1175 - buildOutput compression behavior"],"fullName":"PR #1175 - buildOutput compression behavior keeps cargo errors verbatim","status":"passed","title":"keeps cargo errors verbatim","duration":0.694208000000117,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["PR #1175 - buildOutput compression behavior"],"fullName":"PR #1175 - buildOutput compression behavior keeps maven BUILD FAILED as error","status":"passed","title":"keeps maven BUILD FAILED as error","duration":0.3845420000000104,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["PR #1175 - porcelain regex fix edge cases"],"fullName":"PR #1175 - porcelain regex fix edge cases git status --porcelain workdir-only (space first char) STILL detects as gitStatus (minimal fix preserved old regex)","status":"passed","title":"git status --porcelain workdir-only (space first char) STILL detects as gitStatus (minimal fix preserved old regex)","duration":0.3725000000001728,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["PR #1175 - porcelain regex fix edge cases"],"fullName":"PR #1175 - porcelain regex fix edge cases git status --porcelain with staged (status code first char) still detects","status":"passed","title":"git status --porcelain with staged (status code first char) still detects","duration":0.14908300000001873,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["PR #1175 - porcelain regex fix edge cases"],"fullName":"PR #1175 - porcelain regex fix edge cases cargo Compiling lines NOT detected as git-status (porcelain false positive fix)","status":"passed","title":"cargo Compiling lines NOT detected as git-status (porcelain false positive fix)","duration":0.7886249999999109,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["PR #1175 - porcelain regex fix edge cases"],"fullName":"PR #1175 - porcelain regex fix edge cases long-form git status with 'On branch' always detects","status":"passed","title":"long-form git status with 'On branch' always detects","duration":0.1848339999999098,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["PR #1175 - false positive risks"],"fullName":"PR #1175 - false positive risks generic app log with 'ERROR:' triggers buildOutput (potential false positive)","status":"passed","title":"generic app log with 'ERROR:' triggers buildOutput (potential false positive)","duration":1.1539169999998649,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["PR #1175 - false positive risks"],"fullName":"PR #1175 - false positive risks generic 'Compiling templates' (non-build context) triggers buildOutput","status":"passed","title":"generic 'Compiling templates' (non-build context) triggers buildOutput","duration":0.4332079999999223,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["PR #1175 - false positive risks"],"fullName":"PR #1175 - false positive risks plain text with no patterns falls through (no false positive)","status":"passed","title":"plain text with no patterns falls through (no false positive)","duration":0.2675420000000486,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["PR #1175 - safety: no data corruption"],"fullName":"PR #1175 - safety: no data corruption empty input returns input","status":"passed","title":"empty input returns input","duration":0.20445900000004258,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["PR #1175 - safety: no data corruption"],"fullName":"PR #1175 - safety: no data corruption input with only errors preserves all errors","status":"passed","title":"input with only errors preserves all errors","duration":0.1357500000001437,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["PR #1175 - safety: no data corruption"],"fullName":"PR #1175 - safety: no data corruption input with no recognized patterns returns input (fallback)","status":"passed","title":"input with no recognized patterns returns input (fallback)","duration":0.09470800000008239,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["PR #1175 - safety: no data corruption"],"fullName":"PR #1175 - safety: no data corruption limits warnings to 5 + summary line","status":"passed","title":"limits warnings to 5 + summary line","duration":0.25741599999992104,"failureMessages":[],"meta":{},"tags":[]}],"startTime":1781440250489,"endTime":1781440250504.2573,"status":"passed","message":"","name":"/Users/Working/router4/app/tests/unit/buildOutputFilter.test.js"},{"assertionResults":[{"ancestorTitles":["PR #1175 - priority with overlapping patterns"],"fullName":"PR #1175 - priority with overlapping patterns git-diff wins over buildOutput when both present","status":"passed","title":"git-diff wins over buildOutput when both present","duration":2.1507500000000164,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["PR #1175 - priority with overlapping patterns"],"fullName":"PR #1175 - priority with overlapping patterns git-status (long form) wins over buildOutput","status":"passed","title":"git-status (long form) wins over buildOutput","duration":0.44633299999986775,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["PR #1175 - DETECT_WINDOW boundary"],"fullName":"PR #1175 - DETECT_WINDOW boundary build pattern beyond DETECT_WINDOW chars: NOT detected","status":"passed","title":"build pattern beyond DETECT_WINDOW chars: NOT detected","duration":1.260957999999846,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["PR #1175 - DETECT_WINDOW boundary"],"fullName":"PR #1175 - DETECT_WINDOW boundary build pattern at very start: detected","status":"passed","title":"build pattern at very start: detected","duration":0.2860410000000684,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["PR #1175 - line endings & whitespace"],"fullName":"PR #1175 - line endings & whitespace CRLF line endings still detect","status":"passed","title":"CRLF line endings still detect","duration":0.1512920000000122,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["PR #1175 - line endings & whitespace"],"fullName":"PR #1175 - line endings & whitespace Tab-prefixed Compiling (real cargo output uses leading spaces, not tab)","status":"passed","title":"Tab-prefixed Compiling (real cargo output uses leading spaces, not tab)","duration":0.13408299999991868,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["PR #1175 - line endings & whitespace"],"fullName":"PR #1175 - line endings & whitespace Compiling without leading spaces","status":"passed","title":"Compiling without leading spaces","duration":0.24870800000007875,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["PR #1175 - adversarial: user code containing build strings"],"fullName":"PR #1175 - adversarial: user code containing build strings user JS code with console.log('npm warn ...') triggers buildOutput","status":"passed","title":"user JS code with console.log('npm warn ...') triggers buildOutput","duration":6.643583000000035,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["PR #1175 - adversarial: user code containing build strings"],"fullName":"PR #1175 - adversarial: user code containing build strings file content with 'BUILD SUCCESS' on its own line triggers buildOutput","status":"passed","title":"file content with 'BUILD SUCCESS' on its own line triggers buildOutput","duration":42.91762500000027,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["PR #1175 - adversarial: user code containing build strings"],"fullName":"PR #1175 - adversarial: user code containing build strings real cargo error spanning multiple lines preserves context","status":"passed","title":"real cargo error spanning multiple lines preserves context","duration":0.7795839999998861,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["PR #1175 - corruption safety"],"fullName":"PR #1175 - corruption safety input with only progress lines (no errors/warnings/summary) returns input fallback","status":"passed","title":"input with only progress lines (no errors/warnings/summary) returns input fallback","duration":0.38537499999983993,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["PR #1175 - corruption safety"],"fullName":"PR #1175 - corruption safety input with only Downloading lines","status":"passed","title":"input with only Downloading lines","duration":0.11970800000017334,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["PR #1175 - corruption safety"],"fullName":"PR #1175 - corruption safety input with ONLY a single ERROR: line","status":"passed","title":"input with ONLY a single ERROR: line","duration":0.09520800000018426,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["PR #1175 - corruption safety"],"fullName":"PR #1175 - corruption safety unicode/emoji in deprecation warning preserved (minimal fix keeps first 3 verbatim)","status":"passed","title":"unicode/emoji in deprecation warning preserved (minimal fix keeps first 3 verbatim)","duration":0.9641670000000886,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["PR #1175 - corruption safety"],"fullName":"PR #1175 - corruption safety more than 3 deprecations: keep first 3 verbatim + count rest","status":"passed","title":"more than 3 deprecations: keep first 3 verbatim + count rest","duration":0.21325000000024374,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["PR #1175 - corruption safety"],"fullName":"PR #1175 - corruption safety safeApply wraps buildOutput against panics","status":"passed","title":"safeApply wraps buildOutput against panics","duration":0.14133399999991525,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["PR #1175 - integration with compressMessages"],"fullName":"PR #1175 - integration with compressMessages npm install output above MIN_COMPRESS_SIZE → compressed","status":"passed","title":"npm install output above MIN_COMPRESS_SIZE → compressed","duration":84.38654199999974,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["PR #1175 - integration with compressMessages"],"fullName":"PR #1175 - integration with compressMessages input below MIN_COMPRESS_SIZE → NOT compressed","status":"passed","title":"input below MIN_COMPRESS_SIZE → NOT compressed","duration":0.23566699999992125,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["PR #1175 - integration with compressMessages"],"fullName":"PR #1175 - integration with compressMessages compressed output never grows input (safety guard)","status":"passed","title":"compressed output never grows input (safety guard)","duration":0.18566599999985556,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["PR #1175 - integration with compressMessages"],"fullName":"PR #1175 - integration with compressMessages tool_result with is_error:true is NOT compressed (preserve error traces)","status":"passed","title":"tool_result with is_error:true is NOT compressed (preserve error traces)","duration":0.33154100000001563,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["PR #1175 - porcelain regression deeper"],"fullName":"PR #1175 - porcelain regression deeper mixed staged + workdir + untracked porcelain → detected (has status code first char)","status":"passed","title":"mixed staged + workdir + untracked porcelain → detected (has status code first char)","duration":0.10795800000005329,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["PR #1175 - porcelain regression deeper"],"fullName":"PR #1175 - porcelain regression deeper 100% workdir-only porcelain → STILL detects gitStatus (minimal fix preserved old regex)","status":"passed","title":"100% workdir-only porcelain → STILL detects gitStatus (minimal fix preserved old regex)","duration":0.08558399999992616,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["PR #1175 - porcelain regression deeper"],"fullName":"PR #1175 - porcelain regression deeper manual gitStatus() call on workdir-only porcelain still parses correctly","status":"passed","title":"manual gitStatus() call on workdir-only porcelain still parses correctly","duration":0.4145410000000993,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["PR #1175 - pathological"],"fullName":"PR #1175 - pathological very long single line (no newlines) with build pattern","status":"passed","title":"very long single line (no newlines) with build pattern","duration":0.1321669999997539,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["PR #1175 - pathological"],"fullName":"PR #1175 - pathological 10000 Compiling lines don't crash","status":"passed","title":"10000 Compiling lines don't crash","duration":146.06466599999976,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["PR #1175 - pathological"],"fullName":"PR #1175 - pathological input with only newlines","status":"passed","title":"input with only newlines","duration":17.494916000000103,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["PR #1175 - pathological"],"fullName":"PR #1175 - pathological null/undefined safety via safeApply","status":"passed","title":"null/undefined safety via safeApply","duration":3.1592499999997017,"failureMessages":[],"meta":{},"tags":[]}],"startTime":1781440248098,"endTime":1781440248409.1592,"status":"passed","message":"","name":"/Users/Working/router4/app/tests/unit/buildOutputFilterAdversarial.test.js"},{"assertionResults":[{"ancestorTitles":["cloakClaudeTools"],"fullName":"cloakClaudeTools suffixes client tool names and maps them back","status":"passed","title":"suffixes client tool names and maps them back","duration":2.4225829999999746,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["cloakClaudeTools"],"fullName":"cloakClaudeTools suffixes a forced tool_choice to match the renamed tool","status":"passed","title":"suffixes a forced tool_choice to match the renamed tool","duration":0.8550000000000182,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["cloakClaudeTools"],"fullName":"cloakClaudeTools suffixes only the chosen tool when several are present","status":"passed","title":"suffixes only the chosen tool when several are present","duration":0.32529199999999037,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["cloakClaudeTools"],"fullName":"cloakClaudeTools leaves non-forced tool_choice untouched","status":"passed","title":"leaves non-forced tool_choice untouched","duration":0.4022499999999809,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["cloakClaudeTools"],"fullName":"cloakClaudeTools does not suffix a forced choice that targets a non-client (decoy/built-in) tool","status":"passed","title":"does not suffix a forced choice that targets a non-client (decoy/built-in) tool","duration":0.1822080000000028,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["cloakClaudeTools"],"fullName":"cloakClaudeTools renames tool_use names in message history","status":"passed","title":"renames tool_use names in message history","duration":0.15379200000000992,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["cloakClaudeTools"],"fullName":"cloakClaudeTools returns the body unchanged when there are no tools","status":"passed","title":"returns the body unchanged when there are no tools","duration":0.40504199999998036,"failureMessages":[],"meta":{},"tags":[]}],"startTime":1781440251490,"endTime":1781440251495.405,"status":"passed","message":"","name":"/Users/Working/router4/app/tests/unit/claude-cloaking.test.js"},{"assertionResults":[{"ancestorTitles":["claudeHeaderCache"],"fullName":"claudeHeaderCache returns null before any headers are cached (cold start)","status":"passed","title":"returns null before any headers are cached (cold start)","duration":10.82737499999999,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["claudeHeaderCache"],"fullName":"claudeHeaderCache caches headers when user-agent contains 'claude-code'","status":"passed","title":"caches headers when user-agent contains 'claude-code'","duration":1.406499999999994,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["claudeHeaderCache"],"fullName":"claudeHeaderCache caches headers when user-agent contains 'claude-cli'","status":"passed","title":"caches headers when user-agent contains 'claude-cli'","duration":0.8496250000000032,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["claudeHeaderCache"],"fullName":"claudeHeaderCache caches headers when x-app is 'cli' (regardless of user-agent)","status":"passed","title":"caches headers when x-app is 'cli' (regardless of user-agent)","duration":0.45729199999999537,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["claudeHeaderCache"],"fullName":"claudeHeaderCache does NOT cache headers for non-Claude clients","status":"passed","title":"does NOT cache headers for non-Claude clients","duration":0.2845829999999978,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["claudeHeaderCache"],"fullName":"claudeHeaderCache refreshes cache on each matching request","status":"passed","title":"refreshes cache on each matching request","duration":0.3721670000000188,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["claudeHeaderCache"],"fullName":"claudeHeaderCache ignores calls with null or non-object headers","status":"passed","title":"ignores calls with null or non-object headers","duration":0.9399999999999977,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["claudeHeaderCache"],"fullName":"claudeHeaderCache only stores keys that are actually present in the headers object","status":"passed","title":"only stores keys that are actually present in the headers object","duration":0.7812919999999792,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["DefaultExecutor.buildHeaders() — claude provider"],"fullName":"DefaultExecutor.buildHeaders() — claude provider overlays live cached headers over static provider defaults","status":"passed","title":"overlays live cached headers over static provider defaults","duration":562.682417,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["DefaultExecutor.buildHeaders() — claude provider"],"fullName":"DefaultExecutor.buildHeaders() — claude provider removes conflicting Title-Case static keys when cached lowercase keys exist","status":"passed","title":"removes conflicting Title-Case static keys when cached lowercase keys exist","duration":8.574167000000102,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["DefaultExecutor.buildHeaders() — claude provider"],"fullName":"DefaultExecutor.buildHeaders() — claude provider sets x-api-key auth when apiKey is provided","status":"passed","title":"sets x-api-key auth when apiKey is provided","duration":12.438792000000035,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["DefaultExecutor.buildHeaders() — claude provider"],"fullName":"DefaultExecutor.buildHeaders() — claude provider sets Bearer Authorization when only accessToken is provided","status":"passed","title":"sets Bearer Authorization when only accessToken is provided","duration":15.693791000000033,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["DefaultExecutor.buildHeaders() — claude provider"],"fullName":"DefaultExecutor.buildHeaders() — claude provider includes Accept: text/event-stream when stream=true","status":"passed","title":"includes Accept: text/event-stream when stream=true","duration":10.141166000000112,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["DefaultExecutor.buildHeaders() — claude provider"],"fullName":"DefaultExecutor.buildHeaders() — claude provider omits Accept: text/event-stream when stream=false","status":"passed","title":"omits Accept: text/event-stream when stream=false","duration":8.100082999999927,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["DefaultExecutor.buildHeaders() — claude provider cold start (no cache)"],"fullName":"DefaultExecutor.buildHeaders() — claude provider cold start (no cache) falls back to static provider headers when cache is empty","status":"passed","title":"falls back to static provider headers when cache is empty","duration":7.441042000000039,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["DefaultExecutor.buildHeaders() — claude provider cold start (no cache)"],"fullName":"DefaultExecutor.buildHeaders() — claude provider cold start (no cache) does not throw when cache returns null","status":"passed","title":"does not throw when cache returns null","duration":12.988124999999968,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["DefaultExecutor.buildHeaders() — anthropic-compatible stripping"],"fullName":"DefaultExecutor.buildHeaders() — anthropic-compatible stripping strips x-app and anthropic-dangerous-direct-browser-access for non-Anthropic host","status":"passed","title":"strips x-app and anthropic-dangerous-direct-browser-access for non-Anthropic host","duration":10.786166999999978,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["DefaultExecutor.buildHeaders() — anthropic-compatible stripping"],"fullName":"DefaultExecutor.buildHeaders() — anthropic-compatible stripping removes claude-code-20250219 from anthropic-beta for non-Anthropic host","status":"passed","title":"removes claude-code-20250219 from anthropic-beta for non-Anthropic host","duration":6.458459000000062,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["DefaultExecutor.buildHeaders() — anthropic-compatible stripping"],"fullName":"DefaultExecutor.buildHeaders() — anthropic-compatible stripping keeps other beta flags intact after stripping","status":"passed","title":"keeps other beta flags intact after stripping","duration":10.874042000000031,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["DefaultExecutor.buildHeaders() — anthropic-compatible stripping"],"fullName":"DefaultExecutor.buildHeaders() — anthropic-compatible stripping does NOT strip headers when baseUrl is api.anthropic.com","status":"passed","title":"does NOT strip headers when baseUrl is api.anthropic.com","duration":6.226625000000013,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["DefaultExecutor.buildHeaders() — anthropic-compatible stripping"],"fullName":"DefaultExecutor.buildHeaders() — anthropic-compatible stripping does NOT strip headers when baseUrl is empty (defaults to Anthropic)","status":"passed","title":"does NOT strip headers when baseUrl is empty (defaults to Anthropic)","duration":9.714707999999973,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["proxyAwareFetch — api.anthropic.com routing"],"fullName":"proxyAwareFetch — api.anthropic.com routing routes api.anthropic.com to gotScraping (non-streaming) and returns ok response","status":"failed","title":"routes api.anthropic.com to gotScraping (non-streaming) and returns ok response","duration":561.883625,"failureMessages":["AssertionError: expected \"vi.fn()\" to be called once, but got 0 times\n at /Users/Working/router4/app/tests/unit/claude-header-forwarding.test.js:354:25\n at processTicksAndRejections (node:internal/process/task_queues:105:5)\n at file:///Users/hoanganh/.npm/_npx/69c381f8ad94b576/node_modules/@vitest/runner/dist/chunk-artifact.js:1903:20"],"meta":{},"tags":[]},{"ancestorTitles":["proxyAwareFetch — api.anthropic.com routing"],"fullName":"proxyAwareFetch — api.anthropic.com routing falls back gracefully when got-scraping throws on non-streaming path","status":"passed","title":"falls back gracefully when got-scraping throws on non-streaming path","duration":12.14633300000014,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["proxyAwareFetch — api.anthropic.com routing"],"fullName":"proxyAwareFetch — api.anthropic.com routing does NOT route non-Anthropic hosts through gotScraping","status":"passed","title":"does NOT route non-Anthropic hosts through gotScraping","duration":6.228542000000061,"failureMessages":[],"meta":{},"tags":[]}],"startTime":1781440227017,"endTime":1781440228296.2285,"status":"failed","message":"","name":"/Users/Working/router4/app/tests/unit/claude-header-forwarding.test.js"},{"assertionResults":[{"ancestorTitles":["CodexExecutor image handling"],"fullName":"CodexExecutor image handling fetches 1MB remote image and inlines it as base64 data URI","status":"passed","title":"fetches 1MB remote image and inlines it as base64 data URI","duration":65.05504199999996,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["CodexExecutor image handling"],"fullName":"CodexExecutor image handling passes through existing data URIs without calling fetch","status":"passed","title":"passes through existing data URIs without calling fetch","duration":1.0308340000001408,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["CodexExecutor image handling"],"fullName":"CodexExecutor image handling falls back to original URL when remote fetch fails","status":"passed","title":"falls back to original URL when remote fetch fails","duration":0.6707079999996495,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["CodexExecutor image handling"],"fullName":"CodexExecutor image handling execute() prefetches images before sending to upstream","status":"passed","title":"execute() prefetches images before sending to upstream","duration":401.3317910000005,"failureMessages":[],"meta":{},"tags":[]}],"startTime":1781440244342,"endTime":1781440244810.3318,"status":"passed","message":"","name":"/Users/Working/router4/app/tests/unit/codex-image-fetch.test.js"},{"assertionResults":[{"ancestorTitles":["Codex Refresh Token","refreshCodexToken"],"fullName":"Codex Refresh Token refreshCodexToken should return new refresh_token when server provides one (token rotation)","status":"passed","title":"should return new refresh_token when server provides one (token rotation)","duration":427.964375,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["Codex Refresh Token","refreshCodexToken"],"fullName":"Codex Refresh Token refreshCodexToken should keep old refresh_token when server does not return new one","status":"passed","title":"should keep old refresh_token when server does not return new one","duration":10.10512499999993,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["Codex Refresh Token","CodexExecutor credential lifecycle"],"fullName":"Codex Refresh Token CodexExecutor credential lifecycle should refresh Codex credentials and preserve omitted id_token","status":"passed","title":"should refresh Codex credentials and preserve omitted id_token","duration":107.58495900000003,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["Codex Refresh Token","CodexExecutor credential lifecycle"],"fullName":"Codex Refresh Token CodexExecutor credential lifecycle should refresh Codex when lastRefreshAt is older than the upstream stale window","status":"passed","title":"should refresh Codex when lastRefreshAt is older than the upstream stale window","duration":54.752250000000004,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["Codex Refresh Token","CodexExecutor credential lifecycle"],"fullName":"Codex Refresh Token CodexExecutor credential lifecycle should de-duplicate concurrent refreshes for the same Codex connection","status":"passed","title":"should de-duplicate concurrent refreshes for the same Codex connection","duration":9.887749999999983,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["Codex Refresh Token","getRefreshLeadMs (early refresh config)"],"fullName":"Codex Refresh Token getRefreshLeadMs (early refresh config) should return provider-specific lead time for OAuth providers","status":"passed","title":"should return provider-specific lead time for OAuth providers","duration":7.434582999999975,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["Codex Refresh Token","getRefreshLeadMs (early refresh config)"],"fullName":"Codex Refresh Token getRefreshLeadMs (early refresh config) should fallback to default buffer for unknown providers","status":"passed","title":"should fallback to default buffer for unknown providers","duration":8.956667000000039,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["Codex Refresh Token","getRefreshLeadMs (early refresh config)"],"fullName":"Codex Refresh Token getRefreshLeadMs (early refresh config) codex lead should be greater than default buffer","status":"passed","title":"codex lead should be greater than default buffer","duration":8.780040999999983,"failureMessages":[],"meta":{},"tags":[]}],"startTime":1781440227865,"endTime":1781440228501.78,"status":"passed","message":"","name":"/Users/Working/router4/app/tests/unit/codex-refresh-token.test.js"},{"assertionResults":[{"ancestorTitles":["combo round-robin routing"],"fullName":"combo round-robin routing keeps existing one-request round-robin behavior by default","status":"passed","title":"keeps existing one-request round-robin behavior by default","duration":2.6501670000000104,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["combo round-robin routing"],"fullName":"combo round-robin routing sticks to each combo model for the configured number of requests","status":"passed","title":"sticks to each combo model for the configured number of requests","duration":0.5531249999999943,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["combo round-robin routing"],"fullName":"combo round-robin routing tracks sticky rotation independently per combo","status":"passed","title":"tracks sticky rotation independently per combo","duration":0.42754099999999085,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["combo round-robin routing"],"fullName":"combo round-robin routing does not rotate fallback combos","status":"passed","title":"does not rotate fallback combos","duration":0.6315830000000062,"failureMessages":[],"meta":{},"tags":[]}],"startTime":1781440251324,"endTime":1781440251328.6316,"status":"passed","message":"","name":"/Users/Working/router4/app/tests/unit/combo-routing.test.js"},{"assertionResults":[{"ancestorTitles":["commandcode-to-openai — text-delta"],"fullName":"commandcode-to-openai — text-delta emits assistant role on first delta then content-only","status":"passed","title":"emits assistant role on first delta then content-only","duration":2.6215839999999844,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["commandcode-to-openai — reasoning-delta"],"fullName":"commandcode-to-openai — reasoning-delta maps reasoning-delta to reasoning_content delta","status":"passed","title":"maps reasoning-delta to reasoning_content delta","duration":0.3926660000000197,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["commandcode-to-openai — tool-input-* with id field (live schema)"],"fullName":"commandcode-to-openai — tool-input-* with id field (live schema) registers tool index using event.id (NOT toolCallId)","status":"passed","title":"registers tool index using event.id (NOT toolCallId)","duration":0.4715840000000071,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["commandcode-to-openai — tool-input-* with id field (live schema)"],"fullName":"commandcode-to-openai — tool-input-* with id field (live schema) ignores tool-input-delta when id is unknown (no prior start)","status":"passed","title":"ignores tool-input-delta when id is unknown (no prior start)","duration":0.2364170000000172,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["commandcode-to-openai — final tool-call event"],"fullName":"commandcode-to-openai — final tool-call event does NOT re-emit tool_calls when tool-input-* deltas already fired","status":"passed","title":"does NOT re-emit tool_calls when tool-input-* deltas already fired","duration":0.7663749999999823,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["commandcode-to-openai — final tool-call event"],"fullName":"commandcode-to-openai — final tool-call event emits a consolidated tool_calls when only the final tool-call event arrives","status":"passed","title":"emits a consolidated tool_calls when only the final tool-call event arrives","duration":0.5747089999999844,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["commandcode-to-openai — finish"],"fullName":"commandcode-to-openai — finish emits a final chunk with finish_reason=tool_calls when finishReason is tool-calls","status":"passed","title":"emits a final chunk with finish_reason=tool_calls when finishReason is tool-calls","duration":0.8030410000000074,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["commandcode-to-openai — finish"],"fullName":"commandcode-to-openai — finish includes usage on the final chunk when totalUsage provided","status":"passed","title":"includes usage on the final chunk when totalUsage provided","duration":1.0805420000000368,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["commandcode-to-openai — error event"],"fullName":"commandcode-to-openai — error event stringifies object errors so client sees readable message","status":"passed","title":"stringifies object errors so client sees readable message","duration":1.1251249999999686,"failureMessages":[],"meta":{},"tags":[]}],"startTime":1781440250843,"endTime":1781440250852.1252,"status":"passed","message":"","name":"/Users/Working/router4/app/tests/unit/commandcode-to-openai.test.js"},{"assertionResults":[{"ancestorTitles":["compatible provider connections API"],"fullName":"compatible provider connections API creates one API-key connection for an OpenAI-compatible node","status":"passed","title":"creates one API-key connection for an OpenAI-compatible node","duration":490.858625,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["compatible provider connections API"],"fullName":"compatible provider connections API creates one API-key connection for an Anthropic-compatible node","status":"passed","title":"creates one API-key connection for an Anthropic-compatible node","duration":22.306375000000003,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["compatible provider connections API"],"fullName":"compatible provider connections API returns 400 for a duplicate connection on the same compatible node","status":"passed","title":"returns 400 for a duplicate connection on the same compatible node","duration":22.529999999999973,"failureMessages":[],"meta":{},"tags":[]}],"startTime":1781440228062,"endTime":1781440228597.53,"status":"passed","message":"","name":"/Users/Working/router4/app/tests/unit/compatible-provider-connections.test.js"},{"assertionResults":[{"ancestorTitles":["CursorExecutor Composer thinking-field responses"],"fullName":"CursorExecutor Composer thinking-field responses uses visible content after for non-streaming Composer responses","status":"passed","title":"uses visible content after for non-streaming Composer responses","duration":23.38754199999994,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["CursorExecutor Composer thinking-field responses"],"fullName":"CursorExecutor Composer thinking-field responses streams only visible content after for Composer responses","status":"passed","title":"streams only visible content after for Composer responses","duration":2.1574580000001333,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["CursorExecutor Composer thinking-field responses"],"fullName":"CursorExecutor Composer thinking-field responses does not treat thinking as visible output for non-Composer models","status":"passed","title":"does not treat thinking as visible output for non-Composer models","duration":0.6414580000000569,"failureMessages":[],"meta":{},"tags":[]}],"startTime":1781440250645,"endTime":1781440250670.6414,"status":"passed","message":"","name":"/Users/Working/router4/app/tests/unit/cursor-composer-thinking.test.js"},{"assertionResults":[{"ancestorTitles":["dashboard guard public LLM API access"],"fullName":"dashboard guard public LLM API access allows loopback public LLM API without API key","status":"passed","title":"allows loopback public LLM API without API key","duration":147.63379200000008,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["dashboard guard public LLM API access"],"fullName":"dashboard guard public LLM API access rejects remote rewritten public LLM API without API key","status":"passed","title":"rejects remote rewritten public LLM API without API key","duration":95.58312500000011,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["dashboard guard public LLM API access"],"fullName":"dashboard guard public LLM API access allows loopback rewritten public LLM API without API key","status":"passed","title":"allows loopback rewritten public LLM API without API key","duration":0.6984580000000733,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["dashboard guard public LLM API access"],"fullName":"dashboard guard public LLM API access rejects remote beta public LLM API without API key","status":"passed","title":"rejects remote beta public LLM API without API key","duration":0.4438749999999345,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["dashboard guard public LLM API access"],"fullName":"dashboard guard public LLM API access rejects remote rewritten beta public LLM API without API key","status":"passed","title":"rejects remote rewritten beta public LLM API without API key","duration":0.520917000000054,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["dashboard guard public LLM API access"],"fullName":"dashboard guard public LLM API access allows remote public LLM API with valid bearer API key","status":"passed","title":"allows remote public LLM API with valid bearer API key","duration":1.400583000000097,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["dashboard guard public LLM API access"],"fullName":"dashboard guard public LLM API access allows remote public LLM API with valid x-api-key","status":"passed","title":"allows remote public LLM API with valid x-api-key","duration":18.75412499999993,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["dashboard guard public LLM API access"],"fullName":"dashboard guard public LLM API access allows remote rewritten beta public LLM API with valid API key","status":"passed","title":"allows remote rewritten beta public LLM API with valid API key","duration":0.6022910000001502,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["dashboard guard local-only access"],"fullName":"dashboard guard local-only access rejects local-only route from non-loopback host without CLI token","status":"passed","title":"rejects local-only route from non-loopback host without CLI token","duration":17.796249999999873,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["dashboard guard local-only access"],"fullName":"dashboard guard local-only access rejects local-only route on loopback when requireLogin=true and no JWT","status":"passed","title":"rejects local-only route on loopback when requireLogin=true and no JWT","duration":0.7559579999999642,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["dashboard guard local-only access"],"fullName":"dashboard guard local-only access allows local-only route on loopback when requireLogin=false","status":"passed","title":"allows local-only route on loopback when requireLogin=false","duration":0.5265000000001692,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["dashboard guard local-only access"],"fullName":"dashboard guard local-only access rejects local-only route from tunnel host even when requireLogin=false","status":"passed","title":"rejects local-only route from tunnel host even when requireLogin=false","duration":0.20425000000000182,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["dashboard guard local-only access"],"fullName":"dashboard guard local-only access rejects local-only route when Origin is non-loopback (CSRF block)","status":"passed","title":"rejects local-only route when Origin is non-loopback (CSRF block)","duration":10.837291999999934,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["dashboard guard local-only access"],"fullName":"dashboard guard local-only access allows local-only route with valid CLI token","status":"passed","title":"allows local-only route with valid CLI token","duration":8.691874999999982,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["dashboard guard helpers"],"fullName":"dashboard guard helpers extracts bearer API keys before x-api-key","status":"passed","title":"extracts bearer API keys before x-api-key","duration":0.23354199999994307,"failureMessages":[],"meta":{},"tags":[]}],"startTime":1781440247990,"endTime":1781440248323.2336,"status":"passed","message":"","name":"/Users/Working/router4/app/tests/unit/dashboard-guard.test.js"},{"assertionResults":[{"ancestorTitles":["DB Benchmark — SQLite vs Lowdb"],"fullName":"DB Benchmark — SQLite vs Lowdb INSERT 500 provider connections","status":"passed","title":"INSERT 500 provider connections","duration":10692.2605,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["DB Benchmark — SQLite vs Lowdb"],"fullName":"DB Benchmark — SQLite vs Lowdb READ 200 filtered queries","status":"passed","title":"READ 200 filtered queries","duration":12266.538999999999,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["DB Benchmark — SQLite vs Lowdb"],"fullName":"DB Benchmark — SQLite vs Lowdb READ 200 by id (point lookup)","status":"passed","title":"READ 200 by id (point lookup)","duration":1093.0495420000007,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["DB Benchmark — SQLite vs Lowdb"],"fullName":"DB Benchmark — SQLite vs Lowdb saveRequestUsage 500 entries","status":"passed","title":"saveRequestUsage 500 entries","duration":1785.1479999999974,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["DB Benchmark — SQLite vs Lowdb"],"fullName":"DB Benchmark — SQLite vs Lowdb getUsageStats(24h) repeat 50x","status":"passed","title":"getUsageStats(24h) repeat 50x","duration":652.6957079999993,"failureMessages":[],"meta":{},"tags":[]}],"startTime":1781440227461,"endTime":1781440253950.6958,"status":"passed","message":"","name":"/Users/Working/router4/app/tests/unit/db-benchmark.test.js"},{"assertionResults":[{"ancestorTitles":["DB Concurrency — atomic safety"],"fullName":"DB Concurrency — atomic safety 100 parallel saveRequestUsage → no count loss","status":"passed","title":"100 parallel saveRequestUsage → no count loss","duration":34.500958999999966,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["DB Concurrency — atomic safety"],"fullName":"DB Concurrency — atomic safety 200 parallel saveRequestDetail → all flushed","status":"passed","title":"200 parallel saveRequestDetail → all flushed","duration":6012.181667,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["DB Concurrency — atomic safety"],"fullName":"DB Concurrency — atomic safety mixed concurrent: usage + details + connections + aliases","status":"passed","title":"mixed concurrent: usage + details + connections + aliases","duration":136.6715409999997,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["DB Concurrency — atomic safety"],"fullName":"DB Concurrency — atomic safety updateSettings parallel → no merge loss","status":"passed","title":"updateSettings parallel → no merge loss","duration":130.56679199999962,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["DB Concurrency — atomic safety"],"fullName":"DB Concurrency — atomic safety OAuth refresh race: parallel updateProviderConnection on same id","status":"passed","title":"OAuth refresh race: parallel updateProviderConnection on same id","duration":9.51025000000027,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["DB Concurrency — atomic safety"],"fullName":"DB Concurrency — atomic safety addCustomModel race: parallel duplicate adds → only 1 inserted","status":"passed","title":"addCustomModel race: parallel duplicate adds → only 1 inserted","duration":1.153584000000592,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["DB Concurrency — atomic safety"],"fullName":"DB Concurrency — atomic safety updatePricing race: parallel adds different models → all merged","status":"passed","title":"updatePricing race: parallel adds different models → all merged","duration":32.835165999999845,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["DB Concurrency — atomic safety"],"fullName":"DB Concurrency — atomic safety daily summary aggregates correctly under parallel writes","status":"passed","title":"daily summary aggregates correctly under parallel writes","duration":153.90091699999994,"failureMessages":[],"meta":{},"tags":[]}],"startTime":1781440227454,"endTime":1781440233966.901,"status":"passed","message":"","name":"/Users/Working/router4/app/tests/unit/db-concurrent.test.js"},{"assertionResults":[{"ancestorTitles":["Driver fallback chain"],"fullName":"Driver fallback chain default → picks better-sqlite3 when available","status":"passed","title":"default → picks better-sqlite3 when available","duration":45.51133300000001,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["Driver fallback chain"],"fullName":"Driver fallback chain falls back to node:sqlite when better-sqlite3 unavailable","status":"passed","title":"falls back to node:sqlite when better-sqlite3 unavailable","duration":24.35454199999998,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["Driver fallback chain"],"fullName":"Driver fallback chain falls back to sql.js when both native drivers unavailable","status":"passed","title":"falls back to sql.js when both native drivers unavailable","duration":88.18058299999998,"failureMessages":[],"meta":{},"tags":[]}],"startTime":1781440228505,"endTime":1781440228663.1807,"status":"passed","message":"","name":"/Users/Working/router4/app/tests/unit/db-driver-chain.test.js"},{"assertionResults":[{"ancestorTitles":["Schema migrations"],"fullName":"Schema migrations fresh DB → applies migrations & stamps schemaVersion","status":"passed","title":"fresh DB → applies migrations & stamps schemaVersion","duration":38.864374999999995,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["Schema migrations"],"fullName":"Schema migrations existing DB at older schemaVersion → re-applies pending migrations on restart","status":"passed","title":"existing DB at older schemaVersion → re-applies pending migrations on restart","duration":16.683750000000003,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["Schema migrations"],"fullName":"Schema migrations fresh DB + legacy db.json → imports data automatically","status":"passed","title":"fresh DB + legacy db.json → imports data automatically","duration":12.337416000000019,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["Schema migrations"],"fullName":"Schema migrations auto-sync re-creates missing index when DB lacks it","status":"passed","title":"auto-sync re-creates missing index when DB lacks it","duration":13.456540999999987,"failureMessages":[],"meta":{},"tags":[]}],"startTime":1781440228867,"endTime":1781440228948.4565,"status":"passed","message":"","name":"/Users/Working/router4/app/tests/unit/db-migration-chain.test.js"},{"assertionResults":[{"ancestorTitles":["DB SQLite layer — public API parity"],"fullName":"DB SQLite layer — public API parity settings: get → defaults; update → merge","status":"passed","title":"settings: get → defaults; update → merge","duration":1.9669169999999951,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["DB SQLite layer — public API parity"],"fullName":"DB SQLite layer — public API parity isCloudEnabled reflects settings","status":"passed","title":"isCloudEnabled reflects settings","duration":0.7008329999999887,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["DB SQLite layer — public API parity"],"fullName":"DB SQLite layer — public API parity apiKeys: create/get/validate/delete","status":"passed","title":"apiKeys: create/get/validate/delete","duration":10.959958999999998,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["DB SQLite layer — public API parity"],"fullName":"DB SQLite layer — public API parity providerConnections: CRUD + reorder by priority","status":"passed","title":"providerConnections: CRUD + reorder by priority","duration":3.1304169999999942,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["DB SQLite layer — public API parity"],"fullName":"DB SQLite layer — public API parity providerConnections: optional fields persisted via JSON column","status":"passed","title":"providerConnections: optional fields persisted via JSON column","duration":0.8291250000000048,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["DB SQLite layer — public API parity"],"fullName":"DB SQLite layer — public API parity providerNodes: CRUD","status":"passed","title":"providerNodes: CRUD","duration":1.5003750000000196,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["DB SQLite layer — public API parity"],"fullName":"DB SQLite layer — public API parity proxyPools: CRUD with sort by updatedAt desc","status":"passed","title":"proxyPools: CRUD with sort by updatedAt desc","duration":12.551416999999987,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["DB SQLite layer — public API parity"],"fullName":"DB SQLite layer — public API parity combos: CRUD","status":"passed","title":"combos: CRUD","duration":0.7917089999999973,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["DB SQLite layer — public API parity"],"fullName":"DB SQLite layer — public API parity modelAliases: KV ops","status":"passed","title":"modelAliases: KV ops","duration":0.7902080000000069,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["DB SQLite layer — public API parity"],"fullName":"DB SQLite layer — public API parity customModels: add/list/delete with dedupe","status":"passed","title":"customModels: add/list/delete with dedupe","duration":0.46970799999999713,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["DB SQLite layer — public API parity"],"fullName":"DB SQLite layer — public API parity mitmAlias: get/set per tool","status":"passed","title":"mitmAlias: get/set per tool","duration":0.35504200000002584,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["DB SQLite layer — public API parity"],"fullName":"DB SQLite layer — public API parity disabledModels: add/remove per provider","status":"passed","title":"disabledModels: add/remove per provider","duration":0.7008749999999964,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["DB SQLite layer — public API parity"],"fullName":"DB SQLite layer — public API parity usage: saveRequestUsage + getUsageHistory + getUsageStats","status":"passed","title":"usage: saveRequestUsage + getUsageHistory + getUsageStats","duration":5.426124999999985,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["DB SQLite layer — public API parity"],"fullName":"DB SQLite layer — public API parity usage: pending tracking in-memory","status":"passed","title":"usage: pending tracking in-memory","duration":18.061000000000007,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["DB SQLite layer — public API parity"],"fullName":"DB SQLite layer — public API parity requestDetails: save → query with paging","status":"passed","title":"requestDetails: save → query with paging","duration":202.606625,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["DB SQLite layer — public API parity"],"fullName":"DB SQLite layer — public API parity exportDb / importDb roundtrip","status":"passed","title":"exportDb / importDb roundtrip","duration":2.0260830000000283,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["DB SQLite layer — public API parity"],"fullName":"DB SQLite layer — public API parity pricing: user pricing merged with constants","status":"passed","title":"pricing: user pricing merged with constants","duration":0.6902499999999918,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["DB SQLite layer — public API parity"],"fullName":"DB SQLite layer — public API parity getChartData: 24h buckets","status":"passed","title":"getChartData: 24h buckets","duration":1.8073340000000258,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["DB SQLite layer — public API parity"],"fullName":"DB SQLite layer — public API parity getChartData: 7d buckets","status":"passed","title":"getChartData: 7d buckets","duration":0.6544999999999845,"failureMessages":[],"meta":{},"tags":[]}],"startTime":1781440227454,"endTime":1781440227720.6545,"status":"passed","message":"","name":"/Users/Working/router4/app/tests/unit/db-sqlite-vs-lowdb.test.js"},{"assertionResults":[],"startTime":1781440226639,"endTime":1781440226639,"status":"failed","message":"Cannot find module '/cloud/src/handlers/embeddings.js' imported from /Users/Working/router4/app/tests/unit/embeddings.cloud.test.js","name":"/Users/Working/router4/app/tests/unit/embeddings.cloud.test.js"},{"assertionResults":[{"ancestorTitles":["buildEmbeddingsBody"],"fullName":"buildEmbeddingsBody single string input — includes model and input, default encoding_format=float","status":"passed","title":"single string input — includes model and input, default encoding_format=float","duration":286.26179200000024,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["buildEmbeddingsBody"],"fullName":"buildEmbeddingsBody array input — passes array as-is","status":"passed","title":"array input — passes array as-is","duration":5.429291999999805,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["buildEmbeddingsBody"],"fullName":"buildEmbeddingsBody custom encoding_format is forwarded","status":"passed","title":"custom encoding_format is forwarded","duration":1.3002910000004704,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["buildEmbeddingsBody"],"fullName":"buildEmbeddingsBody no encoding_format in body → defaults to float","status":"passed","title":"no encoding_format in body → defaults to float","duration":0.7759999999998399,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["buildEmbeddingsBody"],"fullName":"buildEmbeddingsBody gemini single input forwards dimensions as outputDimensionality","status":"passed","title":"gemini single input forwards dimensions as outputDimensionality","duration":14.352374999999483,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["buildEmbeddingsBody"],"fullName":"buildEmbeddingsBody gemini batch input forwards dimensions on each request","status":"passed","title":"gemini batch input forwards dimensions on each request","duration":1.707749999999578,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["buildEmbeddingsUrl"],"fullName":"buildEmbeddingsUrl openai → https://api.openai.com/v1/embeddings","status":"passed","title":"openai → https://api.openai.com/v1/embeddings","duration":0.7505000000001019,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["buildEmbeddingsUrl"],"fullName":"buildEmbeddingsUrl openrouter → https://openrouter.ai/api/v1/embeddings","status":"passed","title":"openrouter → https://openrouter.ai/api/v1/embeddings","duration":0.4989580000001297,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["buildEmbeddingsUrl"],"fullName":"buildEmbeddingsUrl vercel-ai-gateway → https://ai-gateway.vercel.sh/v1/embeddings","status":"passed","title":"vercel-ai-gateway → https://ai-gateway.vercel.sh/v1/embeddings","duration":1.859958000000006,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["buildEmbeddingsUrl"],"fullName":"buildEmbeddingsUrl openai-compatible-* → uses baseUrl from providerSpecificData","status":"passed","title":"openai-compatible-* → uses baseUrl from providerSpecificData","duration":0.723667000000205,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["buildEmbeddingsUrl"],"fullName":"buildEmbeddingsUrl openai-compatible-* strips trailing slash from baseUrl","status":"passed","title":"openai-compatible-* strips trailing slash from baseUrl","duration":0.597500000000764,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["buildEmbeddingsUrl"],"fullName":"buildEmbeddingsUrl openai-compatible-* without baseUrl → falls back to api.openai.com","status":"passed","title":"openai-compatible-* without baseUrl → falls back to api.openai.com","duration":0.40987500000028376,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["buildEmbeddingsUrl"],"fullName":"buildEmbeddingsUrl unsupported provider (e.g. gemini-cli) → 400 error, no fetch called","status":"passed","title":"unsupported provider (e.g. gemini-cli) → 400 error, no fetch called","duration":1.4325410000001284,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["buildEmbeddingsUrl"],"fullName":"buildEmbeddingsUrl antigravity (non-openai-compatible, no URL mapping) → 400","status":"passed","title":"antigravity (non-openai-compatible, no URL mapping) → 400","duration":0.3958330000004935,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["buildEmbeddingsHeaders"],"fullName":"buildEmbeddingsHeaders openai → Authorization: Bearer, Content-Type: application/json","status":"passed","title":"openai → Authorization: Bearer, Content-Type: application/json","duration":7.565333999999893,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["buildEmbeddingsHeaders"],"fullName":"buildEmbeddingsHeaders openai — uses accessToken when apiKey is absent","status":"passed","title":"openai — uses accessToken when apiKey is absent","duration":0.6228330000003552,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["buildEmbeddingsHeaders"],"fullName":"buildEmbeddingsHeaders openrouter → adds HTTP-Referer and X-Title headers","status":"passed","title":"openrouter → adds HTTP-Referer and X-Title headers","duration":0.4500420000003942,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["buildEmbeddingsHeaders"],"fullName":"buildEmbeddingsHeaders openai-compatible-* → Authorization: Bearer only (no extra headers)","status":"passed","title":"openai-compatible-* → Authorization: Bearer only (no extra headers)","duration":0.4054580000001806,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["handleEmbeddingsCore — input validation"],"fullName":"handleEmbeddingsCore — input validation missing input → 400 Bad Request","status":"passed","title":"missing input → 400 Bad Request","duration":0.338542000000416,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["handleEmbeddingsCore — input validation"],"fullName":"handleEmbeddingsCore — input validation input is a number → 400 Bad Request","status":"passed","title":"input is a number → 400 Bad Request","duration":0.2781250000007276,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["handleEmbeddingsCore — input validation"],"fullName":"handleEmbeddingsCore — input validation input is an object → 400 Bad Request","status":"passed","title":"input is an object → 400 Bad Request","duration":0.2782500000002983,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["handleEmbeddingsCore — input validation"],"fullName":"handleEmbeddingsCore — input validation input is null → 400 Bad Request","status":"passed","title":"input is null → 400 Bad Request","duration":0.199083000000428,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["handleEmbeddingsCore — input validation"],"fullName":"handleEmbeddingsCore — input validation empty string input passes validation","status":"passed","title":"empty string input passes validation","duration":0.2592500000000655,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["handleEmbeddingsCore — input validation"],"fullName":"handleEmbeddingsCore — input validation empty array input passes validation and reaches provider","status":"passed","title":"empty array input passes validation and reaches provider","duration":0.3546249999999418,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["handleEmbeddingsCore — success path"],"fullName":"handleEmbeddingsCore — success path returns success=true with Response on 200","status":"passed","title":"returns success=true with Response on 200","duration":0.476582999999664,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["handleEmbeddingsCore — success path"],"fullName":"handleEmbeddingsCore — success path response body is valid OpenAI-format JSON","status":"passed","title":"response body is valid OpenAI-format JSON","duration":0.5149580000006608,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["handleEmbeddingsCore — success path"],"fullName":"handleEmbeddingsCore — success path response includes CORS header Access-Control-Allow-Origin: *","status":"passed","title":"response includes CORS header Access-Control-Allow-Origin: *","duration":0.39637500000026193,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["handleEmbeddingsCore — success path"],"fullName":"handleEmbeddingsCore — success path response Content-Type is application/json","status":"passed","title":"response Content-Type is application/json","duration":0.39708299999983865,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["handleEmbeddingsCore — success path"],"fullName":"handleEmbeddingsCore — success path calls onRequestSuccess callback on success","status":"passed","title":"calls onRequestSuccess callback on success","duration":0.28641700000025594,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["handleEmbeddingsCore — success path"],"fullName":"handleEmbeddingsCore — success path does not call onRequestSuccess on provider error","status":"passed","title":"does not call onRequestSuccess on provider error","duration":0.5095000000001164,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["handleEmbeddingsCore — success path"],"fullName":"handleEmbeddingsCore — success path provider response with non-standard format is passed through as-is","status":"passed","title":"provider response with non-standard format is passed through as-is","duration":0.9333749999996144,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["handleEmbeddingsCore — provider error handling"],"fullName":"handleEmbeddingsCore — provider error handling provider 400 → returns success=false with status 400","status":"passed","title":"provider 400 → returns success=false with status 400","duration":0.6925830000000133,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["handleEmbeddingsCore — provider error handling"],"fullName":"handleEmbeddingsCore — provider error handling provider 429 → returns success=false with status 429","status":"passed","title":"provider 429 → returns success=false with status 429","duration":0.7240419999998267,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["handleEmbeddingsCore — provider error handling"],"fullName":"handleEmbeddingsCore — provider error handling provider 500 → returns success=false with status 500","status":"passed","title":"provider 500 → returns success=false with status 500","duration":0.4126249999999345,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["handleEmbeddingsCore — provider error handling"],"fullName":"handleEmbeddingsCore — provider error handling network error (fetch throws) → returns 502 Bad Gateway","status":"passed","title":"network error (fetch throws) → returns 502 Bad Gateway","duration":7.2251249999999345,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["handleEmbeddingsCore — provider error handling"],"fullName":"handleEmbeddingsCore — provider error handling invalid JSON from provider → returns 502","status":"passed","title":"invalid JSON from provider → returns 502","duration":0.6033340000003591,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["handleEmbeddingsCore — provider error handling"],"fullName":"handleEmbeddingsCore — provider error handling error result response has OpenAI-format error body","status":"passed","title":"error result response has OpenAI-format error body","duration":0.44012500000008004,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["handleEmbeddingsCore — token refresh on 401/403"],"fullName":"handleEmbeddingsCore — token refresh on 401/403 on 401, attempts retry after refresh; succeeds if refresh gives new token","status":"passed","title":"on 401, attempts retry after refresh; succeeds if refresh gives new token","duration":0.5136659999998301,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["handleEmbeddingsCore — token refresh on 401/403"],"fullName":"handleEmbeddingsCore — token refresh on 401/403 on 401 with no refresh token, falls back gracefully (no crash)","status":"passed","title":"on 401 with no refresh token, falls back gracefully (no crash)","duration":0.3491669999993974,"failureMessages":[],"meta":{},"tags":[]}],"startTime":1781440244538,"endTime":1781440244883.5137,"status":"passed","message":"","name":"/Users/Working/router4/app/tests/unit/embeddingsCore.test.js"},{"assertionResults":[{"ancestorTitles":["forceStream provider config"],"fullName":"forceStream provider config only openai/codex/commandcode force streaming","status":"passed","title":"only openai/codex/commandcode force streaming","duration":1256.069958,"failureMessages":[],"meta":{},"tags":[]}],"startTime":1781440233172,"endTime":1781440234428.07,"status":"passed","message":"","name":"/Users/Working/router4/app/tests/unit/force-stream-config.test.js"},{"assertionResults":[{"ancestorTitles":["Gemini CLI usage project id resolution"],"fullName":"Gemini CLI usage project id resolution uses the projectId stored on the provider connection","status":"passed","title":"uses the projectId stored on the provider connection","duration":425.1496659999998,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["Gemini CLI usage project id resolution"],"fullName":"Gemini CLI usage project id resolution normalizes project objects returned by loadCodeAssist","status":"passed","title":"normalizes project objects returned by loadCodeAssist","duration":47.896540999999615,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["Gemini CLI usage project id resolution"],"fullName":"Gemini CLI usage project id resolution returns actionable guidance when no project id is available","status":"passed","title":"returns actionable guidance when no project id is available","duration":0.632415999999921,"failureMessages":[],"meta":{},"tags":[]}],"startTime":1781440248846,"endTime":1781440249320.6323,"status":"passed","message":"","name":"/Users/Working/router4/app/tests/unit/gemini-usage-projectid.test.js"},{"assertionResults":[{"ancestorTitles":["GithubExecutor.supportsResponsesEndpoint"],"fullName":"GithubExecutor.supportsResponsesEndpoint excludes Gemini models from the /responses endpoint","status":"passed","title":"excludes Gemini models from the /responses endpoint","duration":2.2881250000000364,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["GithubExecutor.supportsResponsesEndpoint"],"fullName":"GithubExecutor.supportsResponsesEndpoint excludes Claude models from the /responses endpoint","status":"passed","title":"excludes Claude models from the /responses endpoint","duration":0.7120830000000069,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["GithubExecutor.supportsResponsesEndpoint"],"fullName":"GithubExecutor.supportsResponsesEndpoint allows OpenAI/codex models on the /responses endpoint","status":"passed","title":"allows OpenAI/codex models on the /responses endpoint","duration":0.32737500000001774,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["GithubExecutor.supportsResponsesEndpoint"],"fullName":"GithubExecutor.supportsResponsesEndpoint is null-safe","status":"passed","title":"is null-safe","duration":0.35779200000001765,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["GithubExecutor.execute cached-route guard (#1062)"],"fullName":"GithubExecutor.execute cached-route guard (#1062) does NOT use /responses for a Gemini model even if it was wrongly cached as codex","status":"passed","title":"does NOT use /responses for a Gemini model even if it was wrongly cached as codex","duration":2.048000000000002,"failureMessages":[],"meta":{},"tags":[]}],"startTime":1781440251191,"endTime":1781440251197.048,"status":"passed","message":"","name":"/Users/Working/router4/app/tests/unit/github-responses-routing.test.js"},{"assertionResults":[{"ancestorTitles":["HuggingFace model alias parsing"],"fullName":"HuggingFace model alias parsing resolves hf alias to huggingface provider","status":"passed","title":"resolves hf alias to huggingface provider","duration":2.3545839999999885,"failureMessages":[],"meta":{},"tags":[]}],"startTime":1781440251483,"endTime":1781440251485.3545,"status":"passed","message":"","name":"/Users/Working/router4/app/tests/unit/hf-model-routing.test.js"},{"assertionResults":[{"ancestorTitles":["handleImageGenerationCore"],"fullName":"handleImageGenerationCore validates required prompt field","status":"passed","title":"validates required prompt field","duration":116.44887500000004,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["handleImageGenerationCore"],"fullName":"handleImageGenerationCore rejects unsupported provider","status":"passed","title":"rejects unsupported provider","duration":51.99424999999974,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["handleImageGenerationCore"],"fullName":"handleImageGenerationCore generates image with OpenAI format","status":"passed","title":"generates image with OpenAI format","duration":44.68674999999985,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["handleImageGenerationCore"],"fullName":"handleImageGenerationCore generates image with Gemini format","status":"passed","title":"generates image with Gemini format","duration":48.772915999999896,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["handleImageGenerationCore"],"fullName":"handleImageGenerationCore generates image with Minimax format","status":"passed","title":"generates image with Minimax format","duration":1.3557080000000497,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["handleImageGenerationCore"],"fullName":"handleImageGenerationCore generates image with NanoBanana format","status":"passed","title":"generates image with NanoBanana format","duration":18.004790999999386,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["handleImageGenerationCore"],"fullName":"handleImageGenerationCore generates image with SD WebUI format","status":"passed","title":"generates image with SD WebUI format","duration":61.929167000000234,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["handleImageGenerationCore"],"fullName":"handleImageGenerationCore handles OpenRouter with HTTP-Referer header","status":"passed","title":"handles OpenRouter with HTTP-Referer header","duration":0.863166000000092,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["handleImageGenerationCore"],"fullName":"handleImageGenerationCore handles Vercel AI Gateway image generation as OpenAI-compatible","status":"passed","title":"handles Vercel AI Gateway image generation as OpenAI-compatible","duration":58.17070799999965,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["handleImageGenerationCore"],"fullName":"handleImageGenerationCore handles HuggingFace binary response","status":"passed","title":"handles HuggingFace binary response","duration":28.27375000000029,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["handleImageGenerationCore"],"fullName":"handleImageGenerationCore generates image with Codex gpt-5.5-image using current Codex version header","status":"passed","title":"generates image with Codex gpt-5.5-image using current Codex version header","duration":2.4030830000001515,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["handleImageGenerationCore"],"fullName":"handleImageGenerationCore generates image with Cloudflare Workers AI JSON response","status":"passed","title":"generates image with Cloudflare Workers AI JSON response","duration":48.30149999999958,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["handleImageGenerationCore"],"fullName":"handleImageGenerationCore uses multipart form data for Cloudflare FLUX.2 models","status":"passed","title":"uses multipart form data for Cloudflare FLUX.2 models","duration":43.22045799999978,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["handleImageGenerationCore"],"fullName":"handleImageGenerationCore resolves Cloudflare img2img and inpainting URL inputs before sending","status":"passed","title":"resolves Cloudflare img2img and inpainting URL inputs before sending","duration":7.746000000000095,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["handleImageGenerationCore"],"fullName":"handleImageGenerationCore handles provider error responses","status":"passed","title":"handles provider error responses","duration":0.6755000000002838,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["handleImageGenerationCore"],"fullName":"handleImageGenerationCore handles network errors","status":"passed","title":"handles network errors","duration":3.9432080000005953,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["handleImageGenerationCore"],"fullName":"handleImageGenerationCore calls onRequestSuccess callback on success","status":"passed","title":"calls onRequestSuccess callback on success","duration":0.5312920000005761,"failureMessages":[],"meta":{},"tags":[]}],"startTime":1781440247604,"endTime":1781440248151.5312,"status":"passed","message":"","name":"/Users/Working/router4/app/tests/unit/image-generation.test.js"},{"assertionResults":[{"ancestorTitles":["Kiro MITM model slots"],"fullName":"Kiro MITM model slots exposes the kiro mitm tool","status":"passed","title":"exposes the kiro mitm tool","duration":1.4941249999999968,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["Kiro MITM model slots"],"fullName":"Kiro MITM model slots offers a mappable slot for the agent default model id 'auto'","status":"failed","title":"offers a mappable slot for the agent default model id 'auto'","duration":4.322208999999987,"failureMessages":["AssertionError: expected undefined to be truthy\n at /Users/Working/router4/app/tests/unit/kiro-model-slots.test.js:21:18\n at file:///Users/hoanganh/.npm/_npx/69c381f8ad94b576/node_modules/@vitest/runner/dist/chunk-artifact.js:302:11\n at file:///Users/hoanganh/.npm/_npx/69c381f8ad94b576/node_modules/@vitest/runner/dist/chunk-artifact.js:1903:26\n at file:///Users/hoanganh/.npm/_npx/69c381f8ad94b576/node_modules/@vitest/runner/dist/chunk-artifact.js:2326:20\n at new Promise ()\n at runWithCancel (file:///Users/hoanganh/.npm/_npx/69c381f8ad94b576/node_modules/@vitest/runner/dist/chunk-artifact.js:2323:10)\n at file:///Users/hoanganh/.npm/_npx/69c381f8ad94b576/node_modules/@vitest/runner/dist/chunk-artifact.js:2305:20\n at new Promise ()\n at runWithTimeout (file:///Users/hoanganh/.npm/_npx/69c381f8ad94b576/node_modules/@vitest/runner/dist/chunk-artifact.js:2272:10)\n at file:///Users/hoanganh/.npm/_npx/69c381f8ad94b576/node_modules/@vitest/runner/dist/chunk-artifact.js:2955:64"],"meta":{},"tags":[]},{"ancestorTitles":["Kiro MITM model slots"],"fullName":"Kiro MITM model slots offers a mappable slot for the background sub-task model id 'simple-task'","status":"passed","title":"offers a mappable slot for the background sub-task model id 'simple-task'","duration":0.17487500000001432,"failureMessages":[],"meta":{},"tags":[]}],"startTime":1781440227029,"endTime":1781440227034.3223,"status":"failed","message":"","name":"/Users/Working/router4/app/tests/unit/kiro-model-slots.test.js"},{"assertionResults":[{"ancestorTitles":["generateSessionId"],"fullName":"generateSessionId uses the ses_ prefix and a 24-char random suffix","status":"passed","title":"uses the ses_ prefix and a 24-char random suffix","duration":2.767207999999755,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["generateSessionId"],"fullName":"generateSessionId only emits lowercase alphanumeric characters in the suffix","status":"passed","title":"only emits lowercase alphanumeric characters in the suffix","duration":0.6282909999999902,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["generateSessionId"],"fullName":"generateSessionId produces a fresh id on each call","status":"passed","title":"produces a fresh id on each call","duration":1.3412499999999454,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["generateFingerprint"],"fullName":"generateFingerprint returns a 64-char hex sha256 digest","status":"passed","title":"returns a 64-char hex sha256 digest","duration":3.8752089999998134,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["generateFingerprint"],"fullName":"generateFingerprint is stable per machine (deterministic across calls)","status":"passed","title":"is stable per machine (deterministic across calls)","duration":0.5915410000002339,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["parseJwtExp"],"fullName":"parseJwtExp derives the expiry from the JWT exp claim (ms)","status":"passed","title":"derives the expiry from the JWT exp claim (ms)","duration":0.44395799999983865,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["parseJwtExp"],"fullName":"parseJwtExp falls back to a future timestamp when the JWT is unparseable","status":"passed","title":"falls back to a future timestamp when the JWT is unparseable","duration":0.5318750000001273,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["injectSystemMarker"],"fullName":"injectSystemMarker prepends a system message with the marker when none is present","status":"passed","title":"prepends a system message with the marker when none is present","duration":0.5165420000002996,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["injectSystemMarker"],"fullName":"injectSystemMarker preserves the original user message after injection","status":"passed","title":"preserves the original user message after injection","duration":0.982332999999926,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["injectSystemMarker"],"fullName":"injectSystemMarker keeps a caller-provided system prompt alongside the marker","status":"passed","title":"keeps a caller-provided system prompt alongside the marker","duration":0.3062079999999696,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["injectSystemMarker"],"fullName":"injectSystemMarker does not duplicate the marker when already present","status":"passed","title":"does not duplicate the marker when already present","duration":0.34104200000001583,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["injectSystemMarker"],"fullName":"injectSystemMarker leaves a body without a messages array untouched","status":"passed","title":"leaves a body without a messages array untouched","duration":0.12483399999973699,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["bootstrapJwt"],"fullName":"bootstrapJwt returns the jwt from the bootstrap response","status":"passed","title":"returns the jwt from the bootstrap response","duration":0.8125840000002427,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["bootstrapJwt"],"fullName":"bootstrapJwt sends the machine fingerprint as the bootstrap client","status":"passed","title":"sends the machine fingerprint as the bootstrap client","duration":0.6606660000002194,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["bootstrapJwt"],"fullName":"bootstrapJwt caches the jwt and does not re-fetch while still valid","status":"passed","title":"caches the jwt and does not re-fetch while still valid","duration":0.5828330000003916,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["bootstrapJwt"],"fullName":"bootstrapJwt re-fetches once the cached jwt is within the expiry buffer","status":"passed","title":"re-fetches once the cached jwt is within the expiry buffer","duration":0.4650419999998121,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["bootstrapJwt"],"fullName":"bootstrapJwt throws when the bootstrap response is not ok","status":"passed","title":"throws when the bootstrap response is not ok","duration":1.7925419999996848,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["bootstrapJwt"],"fullName":"bootstrapJwt throws when the bootstrap response has no jwt","status":"passed","title":"throws when the bootstrap response has no jwt","duration":0.36258300000008603,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["MimoFreeExecutor"],"fullName":"MimoFreeExecutor buildUrl returns the free-ai chat endpoint","status":"passed","title":"buildUrl returns the free-ai chat endpoint","duration":0.1421660000000884,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["MimoFreeExecutor"],"fullName":"MimoFreeExecutor buildHeaders includes the MiMo source and session affinity","status":"passed","title":"buildHeaders includes the MiMo source and session affinity","duration":0.22962500000039654,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["MimoFreeExecutor"],"fullName":"MimoFreeExecutor transformRequest injects the system marker","status":"passed","title":"transformRequest injects the system marker","duration":0.13637500000004366,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["MimoFreeExecutor"],"fullName":"MimoFreeExecutor execute injects the marker and sends a Bearer JWT to the chat endpoint","status":"passed","title":"execute injects the marker and sends a Bearer JWT to the chat endpoint","duration":1.206749999999829,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["MimoFreeExecutor"],"fullName":"MimoFreeExecutor re-bootstraps and retries once on a 403 from the chat endpoint","status":"passed","title":"re-bootstraps and retries once on a 403 from the chat endpoint","duration":0.5784589999998389,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["MiMo Free provider registration"],"fullName":"MiMo Free provider registration registers a specialized executor for mimo-free and the mmf alias","status":"passed","title":"registers a specialized executor for mimo-free and the mmf alias","duration":0.6152499999998327,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["MiMo Free provider registration"],"fullName":"MiMo Free provider registration registers mimo-free as a no-auth provider in open-sse config","status":"passed","title":"registers mimo-free as a no-auth provider in open-sse config","duration":0.1747920000002523,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["MiMo Free provider registration"],"fullName":"MiMo Free provider registration exposes only mimo-auto (the sole free-channel model)","status":"passed","title":"exposes only mimo-auto (the sole free-channel model)","duration":0.2902079999998932,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["MiMo Free provider registration"],"fullName":"MiMo Free provider registration maps the mimo-free alias to mmf","status":"passed","title":"maps the mimo-free alias to mmf","duration":0.11845799999991868,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["MiMo Free provider registration"],"fullName":"MiMo Free provider registration lists mimo-free in the dashboard FREE_PROVIDERS catalog","status":"passed","title":"lists mimo-free in the dashboard FREE_PROVIDERS catalog","duration":0.12691700000004857,"failureMessages":[],"meta":{},"tags":[]}],"startTime":1781440250812,"endTime":1781440250835.127,"status":"passed","message":"","name":"/Users/Working/router4/app/tests/unit/mimo-free.test.js"},{"assertionResults":[{"ancestorTitles":["MiniMax TTS"],"fullName":"MiniMax TTS sends MiniMax T2A payload and converts hex audio to base64 JSON","status":"passed","title":"sends MiniMax T2A payload and converts hex audio to base64 JSON","duration":174.38649999999961,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["MiniMax TTS"],"fullName":"MiniMax TTS uses the default MiniMax voice when no voice is provided","status":"passed","title":"uses the default MiniMax voice when no voice is provided","duration":42.68741599999976,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["MiniMax TTS"],"fullName":"MiniMax TTS surfaces MiniMax base_resp errors","status":"passed","title":"surfaces MiniMax base_resp errors","duration":98.98262499999964,"failureMessages":[],"meta":{},"tags":[]}],"startTime":1781440246000,"endTime":1781440246315.9827,"status":"passed","message":"","name":"/Users/Working/router4/app/tests/unit/minimax-tts.test.js"},{"assertionResults":[{"ancestorTitles":["MiniMax usage"],"fullName":"MiniMax usage parses token-plan TTS quota counts as used counts","status":"passed","title":"parses token-plan TTS quota counts as used counts","duration":266.38412500000004,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["MiniMax usage"],"fullName":"MiniMax usage parses coding-plan TTS quota counts as remaining counts","status":"passed","title":"parses coding-plan TTS quota counts as remaining counts","duration":1.3455000000003565,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["MiniMax usage"],"fullName":"MiniMax usage keeps non-TTS MiniMax quota rows instead of filtering to text only","status":"passed","title":"keeps non-TTS MiniMax quota rows instead of filtering to text only","duration":1.2041250000002037,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["MiniMax usage"],"fullName":"MiniMax usage includes M-series percent-only buckets that have no count totals","status":"passed","title":"includes M-series percent-only buckets that have no count totals","duration":1.1812079999999696,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["MiniMax usage"],"fullName":"MiniMax usage normalizes M-series percent-only buckets on the coding_plan (countMeansRemaining) endpoint too","status":"passed","title":"normalizes M-series percent-only buckets on the coding_plan (countMeansRemaining) endpoint too","duration":0.8810410000005504,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["MiniMax usage"],"fullName":"MiniMax usage renders the M3-era MiniMax-M* wildcard as a friendly series label","status":"passed","title":"renders the M3-era MiniMax-M* wildcard as a friendly series label","duration":0.9630000000006476,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["MiniMax usage"],"fullName":"MiniMax usage prefers the upstream-provided remaining percent when counts are also present","status":"passed","title":"prefers the upstream-provided remaining percent when counts are also present","duration":1.0831250000001091,"failureMessages":[],"meta":{},"tags":[]}],"startTime":1781440245770,"endTime":1781440246043.083,"status":"passed","message":"","name":"/Users/Working/router4/app/tests/unit/minimax-usage.test.js"},{"assertionResults":[{"ancestorTitles":["MiniMax voices API"],"fullName":"MiniMax voices API fetches global MiniMax voices with stored API key","status":"passed","title":"fetches global MiniMax voices with stored API key","duration":290.1783330000003,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["MiniMax voices API"],"fullName":"MiniMax voices API fetches China MiniMax voices when provider=minimax-cn","status":"passed","title":"fetches China MiniMax voices when provider=minimax-cn","duration":97.29454099999975,"failureMessages":[],"meta":{},"tags":[]}],"startTime":1781440247341,"endTime":1781440247728.2944,"status":"passed","message":"","name":"/Users/Working/router4/app/tests/unit/minimax-voices.test.js"},{"assertionResults":[{"ancestorTitles":["model name regex fallback (C2)"],"fullName":"model name regex fallback (C2) derives display name from id per family","status":"passed","title":"derives display name from id per family","duration":3.0278749999999945,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["model name regex fallback (C2)"],"fullName":"model name regex fallback (C2) falls back to id verbatim when no pattern matches","status":"passed","title":"falls back to id verbatim when no pattern matches","duration":0.6455840000000137,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["model name regex fallback (C2)"],"fullName":"model name regex fallback (C2) normalizeModel: explicit name always wins over regex","status":"passed","title":"normalizeModel: explicit name always wins over regex","duration":0.23745800000000372,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["model name regex fallback (C2)"],"fullName":"model name regex fallback (C2) normalizeModel: terse string id becomes object with derived name","status":"passed","title":"normalizeModel: terse string id becomes object with derived name","duration":0.6356250000000045,"failureMessages":[],"meta":{},"tags":[]}],"startTime":1781440251407,"endTime":1781440251411.6357,"status":"passed","message":"","name":"/Users/Working/router4/app/tests/unit/model-name-regex.test.js"},{"assertionResults":[{"ancestorTitles":["model test route kind routing"],"fullName":"model test route kind routing routes image model tests to /api/v1/images/generations","status":"passed","title":"routes image model tests to /api/v1/images/generations","duration":157.81449999999998,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["model test route kind routing"],"fullName":"model test route kind routing routes embedding model tests to /api/v1/embeddings","status":"passed","title":"routes embedding model tests to /api/v1/embeddings","duration":2.5424170000000004,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["model test route kind routing"],"fullName":"model test route kind routing fails embedding model tests when provider returns no embedding data","status":"passed","title":"fails embedding model tests when provider returns no embedding data","duration":3.0079999999999814,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["model test route kind routing"],"fullName":"model test route kind routing routes stt model tests to /api/v1/audio/transcriptions","status":"passed","title":"routes stt model tests to /api/v1/audio/transcriptions","duration":2.2927080000000046,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["model test route kind routing"],"fullName":"model test route kind routing returns formatted HTTP errors for non-2xx embedding responses","status":"passed","title":"returns formatted HTTP errors for non-2xx embedding responses","duration":1.286457999999982,"failureMessages":[],"meta":{},"tags":[]}],"startTime":1781440228671,"endTime":1781440228838.2864,"status":"passed","message":"","name":"/Users/Working/router4/app/tests/unit/model-test-routing.test.js"},{"assertionResults":[{"ancestorTitles":["openai→claude: image_url.detail is dropped (docs 11 §4)"],"fullName":"openai→claude: image_url.detail is dropped (docs 11 §4) converts image to base64 source WITHOUT a detail field","status":"passed","title":"converts image to base64 source WITHOUT a detail field","duration":5.40908300000001,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["openai→claude: image_url.detail is dropped (docs 11 §4)"],"fullName":"openai→claude: image_url.detail is dropped (docs 11 §4) drops input_audio entirely (claude has no audio block)","status":"passed","title":"drops input_audio entirely (claude has no audio block)","duration":0.4934170000000222,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["openai→gemini: input_audio is mapped to inlineData (docs 11 §4)"],"fullName":"openai→gemini: input_audio is mapped to inlineData (docs 11 §4) maps wav → audio/wav inlineData","status":"passed","title":"maps wav → audio/wav inlineData","duration":0.5047500000000014,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["openai→gemini: input_audio is mapped to inlineData (docs 11 §4)"],"fullName":"openai→gemini: input_audio is mapped to inlineData (docs 11 §4) maps mp3 → audio/mpeg inlineData","status":"passed","title":"maps mp3 → audio/mpeg inlineData","duration":0.3126670000000331,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["openai→gemini: input_audio is mapped to inlineData (docs 11 §4)"],"fullName":"openai→gemini: input_audio is mapped to inlineData (docs 11 §4) drops image_url.detail (not carried into inlineData)","status":"passed","title":"drops image_url.detail (not carried into inlineData)","duration":0.40629200000000765,"failureMessages":[],"meta":{},"tags":[]}],"startTime":1781440251400,"endTime":1781440251408.4062,"status":"passed","message":"","name":"/Users/Working/router4/app/tests/unit/multimodal-drop-lock.test.js"},{"assertionResults":[{"ancestorTitles":["GET /api/oauth/cursor/auto-import"],"fullName":"GET /api/oauth/cursor/auto-import returns not-found when no macOS cursor db paths are accessible","status":"failed","title":"returns not-found when no macOS cursor db paths are accessible","duration":42.33625000000001,"failureMessages":["AssertionError: expected 'Cursor database not found. Checked lo…' to contain 'Cursor database not found in known ma…'\n at /Users/Working/router4/app/tests/unit/oauth-cursor-auto-import.test.js:74:33\n at processTicksAndRejections (node:internal/process/task_queues:105:5)\n at file:///Users/hoanganh/.npm/_npx/69c381f8ad94b576/node_modules/@vitest/runner/dist/chunk-artifact.js:1903:20"],"meta":{},"tags":[]},{"ancestorTitles":["GET /api/oauth/cursor/auto-import"],"fullName":"GET /api/oauth/cursor/auto-import returns descriptive error if macOS db file exists but cannot be opened","status":"failed","title":"returns descriptive error if macOS db file exists but cannot be opened","duration":56.373625000000004,"failureMessages":["AssertionError: the given combination of arguments (undefined and string) is invalid for this assertion. You can use an array, a map, an object, a set, a string, or a weakset instead of a string\n at Proxy. (file:///Users/hoanganh/.npm/_npx/69c381f8ad94b576/node_modules/@vitest/expect/dist/index.js:1319:15)\n at Proxy. (file:///Users/hoanganh/.npm/_npx/69c381f8ad94b576/node_modules/@vitest/expect/dist/index.js:1156:15)\n at Proxy.methodWrapper (file:///Users/hoanganh/.npm/_npx/69c381f8ad94b576/node_modules/chai/index.js:1700:25)\n at /Users/Working/router4/app/tests/unit/oauth-cursor-auto-import.test.js:84:33\n at file:///Users/hoanganh/.npm/_npx/69c381f8ad94b576/node_modules/@vitest/runner/dist/chunk-artifact.js:1903:20"],"meta":{},"tags":[]},{"ancestorTitles":["GET /api/oauth/cursor/auto-import"],"fullName":"GET /api/oauth/cursor/auto-import extracts tokens using exact keys","status":"failed","title":"extracts tokens using exact keys","duration":42.886833000000024,"failureMessages":["AssertionError: expected false to be true // Object.is equality\n at /Users/Working/router4/app/tests/unit/oauth-cursor-auto-import.test.js:101:33\n at file:///Users/hoanganh/.npm/_npx/69c381f8ad94b576/node_modules/@vitest/runner/dist/chunk-artifact.js:1903:20"],"meta":{},"tags":[]},{"ancestorTitles":["GET /api/oauth/cursor/auto-import"],"fullName":"GET /api/oauth/cursor/auto-import unwraps JSON-encoded string values","status":"failed","title":"unwraps JSON-encoded string values","duration":41.894165999999984,"failureMessages":["AssertionError: expected false to be true // Object.is equality\n at /Users/Working/router4/app/tests/unit/oauth-cursor-auto-import.test.js:118:33\n at processTicksAndRejections (node:internal/process/task_queues:105:5)\n at file:///Users/hoanganh/.npm/_npx/69c381f8ad94b576/node_modules/@vitest/runner/dist/chunk-artifact.js:1903:20"],"meta":{},"tags":[]},{"ancestorTitles":["GET /api/oauth/cursor/auto-import"],"fullName":"GET /api/oauth/cursor/auto-import falls back to fuzzy key matching on macOS when exact keys are missing","status":"failed","title":"falls back to fuzzy key matching on macOS when exact keys are missing","duration":35.46941700000002,"failureMessages":["AssertionError: expected false to be true // Object.is equality\n at /Users/Working/router4/app/tests/unit/oauth-cursor-auto-import.test.js:142:33\n at processTicksAndRejections (node:internal/process/task_queues:105:5)\n at file:///Users/hoanganh/.npm/_npx/69c381f8ad94b576/node_modules/@vitest/runner/dist/chunk-artifact.js:1903:20"],"meta":{},"tags":[]},{"ancestorTitles":["GET /api/oauth/cursor/auto-import"],"fullName":"GET /api/oauth/cursor/auto-import returns login-prompt error when tokens are missing even after fallback","status":"failed","title":"returns login-prompt error when tokens are missing even after fallback","duration":32.475750000000005,"failureMessages":["AssertionError: the given combination of arguments (undefined and string) is invalid for this assertion. You can use an array, a map, an object, a set, a string, or a weakset instead of a string\n at Proxy. (file:///Users/hoanganh/.npm/_npx/69c381f8ad94b576/node_modules/@vitest/expect/dist/index.js:1319:15)\n at Proxy. (file:///Users/hoanganh/.npm/_npx/69c381f8ad94b576/node_modules/@vitest/expect/dist/index.js:1156:15)\n at Proxy.methodWrapper (file:///Users/hoanganh/.npm/_npx/69c381f8ad94b576/node_modules/chai/index.js:1700:25)\n at /Users/Working/router4/app/tests/unit/oauth-cursor-auto-import.test.js:156:33\n at processTicksAndRejections (node:internal/process/task_queues:105:5)\n at file:///Users/hoanganh/.npm/_npx/69c381f8ad94b576/node_modules/@vitest/runner/dist/chunk-artifact.js:1903:20"],"meta":{},"tags":[]},{"ancestorTitles":["GET /api/oauth/cursor/auto-import"],"fullName":"GET /api/oauth/cursor/auto-import linux uses single hardcoded path and original error message","status":"failed","title":"linux uses single hardcoded path and original error message","duration":1.7235839999999598,"failureMessages":["AssertionError: expected 'Cursor database not found. Checked lo…' to be 'Cursor database not found. Make sure …' // Object.is equality\n at /Users/Working/router4/app/tests/unit/oauth-cursor-auto-import.test.js:169:33\n at processTicksAndRejections (node:internal/process/task_queues:105:5)\n at file:///Users/hoanganh/.npm/_npx/69c381f8ad94b576/node_modules/@vitest/runner/dist/chunk-artifact.js:1903:20"],"meta":{},"tags":[]},{"ancestorTitles":["GET /api/oauth/cursor/auto-import"],"fullName":"GET /api/oauth/cursor/auto-import unsupported platform returns 400","status":"failed","title":"unsupported platform returns 400","duration":0.5219160000000329,"failureMessages":["AssertionError: expected 200 to be 400 // Object.is equality\n at /Users/Working/router4/app/tests/unit/oauth-cursor-auto-import.test.js:181:29\n at processTicksAndRejections (node:internal/process/task_queues:105:5)\n at file:///Users/hoanganh/.npm/_npx/69c381f8ad94b576/node_modules/@vitest/runner/dist/chunk-artifact.js:1903:20"],"meta":{},"tags":[]}],"startTime":1781440226994,"endTime":1781440227247.7236,"status":"failed","message":"","name":"/Users/Working/router4/app/tests/unit/oauth-cursor-auto-import.test.js"},{"assertionResults":[{"ancestorTitles":["OpenAI Responses streaming termination"],"fullName":"OpenAI Responses streaming termination emits a response.failed event when a Responses stream closes before a terminal event","status":"passed","title":"emits a response.failed event when a Responses stream closes before a terminal event","duration":845.7108749999998,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["OpenAI Responses streaming termination"],"fullName":"OpenAI Responses streaming termination does not add response.failed when a Responses stream already completed","status":"passed","title":"does not add response.failed when a Responses stream already completed","duration":53.350500000000466,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["OpenAI Responses streaming termination"],"fullName":"OpenAI Responses streaming termination emits response.failed before DONE when a Responses stream sends DONE without a terminal event","status":"passed","title":"emits response.failed before DONE when a Responses stream sends DONE without a terminal event","duration":4.378791000000092,"failureMessages":[],"meta":{},"tags":[]}],"startTime":1781440234893,"endTime":1781440235797.379,"status":"passed","message":"","name":"/Users/Working/router4/app/tests/unit/openai-responses-terminal-event.test.js"},{"assertionResults":[{"ancestorTitles":["openaiToClaudeResponse tool argument sanitization"],"fullName":"openaiToClaudeResponse tool argument sanitization drops invalid Read pages and clamps numeric bounds","status":"passed","title":"drops invalid Read pages and clamps numeric bounds","duration":3.4414999999999623,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["openaiToClaudeResponse tool argument sanitization"],"fullName":"openaiToClaudeResponse tool argument sanitization keeps valid PDF pages","status":"passed","title":"keeps valid PDF pages","duration":0.6235000000000355,"failureMessages":[],"meta":{},"tags":[]}],"startTime":1781440251789,"endTime":1781440251793.6235,"status":"passed","message":"","name":"/Users/Working/router4/app/tests/unit/openai-to-claude-response-tools.test.js"},{"assertionResults":[{"ancestorTitles":["openaiToClaudeRequest","response_format handling"],"fullName":"openaiToClaudeRequest response_format handling should inject JSON schema instructions for json_schema type","status":"passed","title":"should inject JSON schema instructions for json_schema type","duration":2.226374999999962,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["openaiToClaudeRequest","response_format handling"],"fullName":"openaiToClaudeRequest response_format handling should inject basic JSON instructions for json_object type","status":"passed","title":"should inject basic JSON instructions for json_object type","duration":0.3129999999999882,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["openaiToClaudeRequest","response_format handling"],"fullName":"openaiToClaudeRequest response_format handling should not modify system prompt when response_format is missing","status":"passed","title":"should not modify system prompt when response_format is missing","duration":0.18016599999998562,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["openaiToClaudeRequest","response_format handling"],"fullName":"openaiToClaudeRequest response_format handling should preserve existing system messages when adding response_format","status":"passed","title":"should preserve existing system messages when adding response_format","duration":0.15837499999997817,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["openaiToClaudeRequest","tool_choice handling"],"fullName":"openaiToClaudeRequest tool_choice handling converts OpenAI forced tool ({type:'function'}) to Claude {type:'tool'}","status":"passed","title":"converts OpenAI forced tool ({type:'function'}) to Claude {type:'tool'}","duration":0.5042920000000777,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["openaiToClaudeRequest","tool_choice handling"],"fullName":"openaiToClaudeRequest tool_choice handling maps string tool_choice values","status":"passed","title":"maps string tool_choice values","duration":0.5132500000000846,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["openaiToClaudeRequest","tool_choice handling"],"fullName":"openaiToClaudeRequest tool_choice handling passes through Claude-native tool_choice objects unchanged","status":"passed","title":"passes through Claude-native tool_choice objects unchanged","duration":0.47195800000008603,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["openaiToClaudeRequest","tool_choice handling"],"fullName":"openaiToClaudeRequest tool_choice handling never leaks an invalid type (falls back to auto)","status":"passed","title":"never leaks an invalid type (falls back to auto)","duration":0.21833300000002964,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["openaiToClaudeRequest","tool_choice handling"],"fullName":"openaiToClaudeRequest tool_choice handling omits tool_choice entirely when the request has none","status":"passed","title":"omits tool_choice entirely when the request has none","duration":0.4906669999999167,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["openaiToClaudeResponse"],"fullName":"openaiToClaudeResponse omits empty Read pages tool argument before emitting Claude input deltas","status":"failed","title":"omits empty Read pages tool argument before emitting Claude input deltas","duration":7.328666999999996,"failureMessages":["AssertionError: expected undefined to be defined\n at /Users/Working/router4/app/tests/unit/openai-to-claude.test.js:199:24\n at file:///Users/hoanganh/.npm/_npx/69c381f8ad94b576/node_modules/@vitest/runner/dist/chunk-artifact.js:302:11\n at file:///Users/hoanganh/.npm/_npx/69c381f8ad94b576/node_modules/@vitest/runner/dist/chunk-artifact.js:1903:26\n at file:///Users/hoanganh/.npm/_npx/69c381f8ad94b576/node_modules/@vitest/runner/dist/chunk-artifact.js:2326:20\n at new Promise ()\n at runWithCancel (file:///Users/hoanganh/.npm/_npx/69c381f8ad94b576/node_modules/@vitest/runner/dist/chunk-artifact.js:2323:10)\n at file:///Users/hoanganh/.npm/_npx/69c381f8ad94b576/node_modules/@vitest/runner/dist/chunk-artifact.js:2305:20\n at new Promise ()\n at runWithTimeout (file:///Users/hoanganh/.npm/_npx/69c381f8ad94b576/node_modules/@vitest/runner/dist/chunk-artifact.js:2272:10)\n at file:///Users/hoanganh/.npm/_npx/69c381f8ad94b576/node_modules/@vitest/runner/dist/chunk-artifact.js:2955:64"],"meta":{},"tags":[]}],"startTime":1781440227615,"endTime":1781440227628.3286,"status":"failed","message":"","name":"/Users/Working/router4/app/tests/unit/openai-to-claude.test.js"},{"assertionResults":[{"ancestorTitles":["openaiToCommandCodeRequest — basic envelope"],"fullName":"openaiToCommandCodeRequest — basic envelope returns the expected top-level envelope shape","status":"passed","title":"returns the expected top-level envelope shape","duration":4.764084000000025,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["openaiToCommandCodeRequest — system handling"],"fullName":"openaiToCommandCodeRequest — system handling hoists system messages to params.system (string), not messages[]","status":"passed","title":"hoists system messages to params.system (string), not messages[]","duration":1.5939159999999788,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["openaiToCommandCodeRequest — system handling"],"fullName":"openaiToCommandCodeRequest — system handling joins multiple system messages with blank line","status":"passed","title":"joins multiple system messages with blank line","duration":0.4689999999999941,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["openaiToCommandCodeRequest — system handling"],"fullName":"openaiToCommandCodeRequest — system handling omits params.system when no system messages","status":"passed","title":"omits params.system when no system messages","duration":0.22866700000002993,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["openaiToCommandCodeRequest — content shape"],"fullName":"openaiToCommandCodeRequest — content shape MUST always emit content as Array (never string) for user","status":"passed","title":"MUST always emit content as Array (never string) for user","duration":0.8625410000000215,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["openaiToCommandCodeRequest — content shape"],"fullName":"openaiToCommandCodeRequest — content shape MUST always emit content as Array for assistant","status":"passed","title":"MUST always emit content as Array for assistant","duration":0.4039579999999887,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["openaiToCommandCodeRequest — tool role / tool-result (AI SDK)"],"fullName":"openaiToCommandCodeRequest — tool role / tool-result (AI SDK) converts role:\"tool\" to role:\"tool\" with tool-result block; output is {type:\"text\",value}","status":"passed","title":"converts role:\"tool\" to role:\"tool\" with tool-result block; output is {type:\"text\",value}","duration":0.45341700000000174,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["openaiToCommandCodeRequest — assistant tool_calls / tool-call"],"fullName":"openaiToCommandCodeRequest — assistant tool_calls / tool-call converts assistant.tool_calls[] into content blocks of type tool-call","status":"passed","title":"converts assistant.tool_calls[] into content blocks of type tool-call","duration":0.365791999999999,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["openaiToCommandCodeRequest — tools schema conversion"],"fullName":"openaiToCommandCodeRequest — tools schema conversion converts OpenAI {type:\"function\", function:{...}} to Anthropic plain {name, input_schema}","status":"passed","title":"converts OpenAI {type:\"function\", function:{...}} to Anthropic plain {name, input_schema}","duration":1.1795000000000186,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["openaiToCommandCodeRequest — tools schema conversion"],"fullName":"openaiToCommandCodeRequest — tools schema conversion preserves description on converted tool","status":"passed","title":"preserves description on converted tool","duration":0.28079200000001947,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["openaiToCommandCodeRequest — tools schema conversion"],"fullName":"openaiToCommandCodeRequest — tools schema conversion does not include tools field when input has none","status":"passed","title":"does not include tools field when input has none","duration":0.28624999999999545,"failureMessages":[],"meta":{},"tags":[]}],"startTime":1781440251025,"endTime":1781440251037.2861,"status":"passed","message":"","name":"/Users/Working/router4/app/tests/unit/openai-to-commandcode.test.js"},{"assertionResults":[{"ancestorTitles":["openaiToKiroRequest","basic message conversion"],"fullName":"openaiToKiroRequest basic message conversion should convert a simple text message","status":"passed","title":"should convert a simple text message","duration":6.480208000000005,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["openaiToKiroRequest","basic message conversion"],"fullName":"openaiToKiroRequest basic message conversion should not include images field when no images are present","status":"passed","title":"should not include images field when no images are present","duration":0.32233300000001464,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["openaiToKiroRequest","image forwarding"],"fullName":"openaiToKiroRequest image forwarding should forward base64 image from image_url content part","status":"passed","title":"should forward base64 image from image_url content part","duration":1.6363329999999792,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["openaiToKiroRequest","image forwarding"],"fullName":"openaiToKiroRequest image forwarding should forward multiple base64 images","status":"passed","title":"should forward multiple base64 images","duration":0.8163749999999936,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["openaiToKiroRequest","image forwarding"],"fullName":"openaiToKiroRequest image forwarding should not include images field when images array is empty","status":"passed","title":"should not include images field when images array is empty","duration":0.44974999999999454,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["openaiToKiroRequest","image forwarding"],"fullName":"openaiToKiroRequest image forwarding should include both images and text content together","status":"passed","title":"should include both images and text content together","duration":0.5253749999999968,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["openaiToKiroRequest","image forwarding"],"fullName":"openaiToKiroRequest image forwarding should treat http image URLs as text fallback (Kiro only supports base64)","status":"passed","title":"should treat http image URLs as text fallback (Kiro only supports base64)","duration":0.2562910000000329,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["openaiToKiroRequest","tool interaction without client-provided tools"],"fullName":"openaiToKiroRequest tool interaction without client-provided tools should flatten OpenAI tool_calls + tool result into history text with no tools array","status":"passed","title":"should flatten OpenAI tool_calls + tool result into history text with no tools array","duration":0.6817500000000223,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["openaiToKiroRequest","tool interaction without client-provided tools"],"fullName":"openaiToKiroRequest tool interaction without client-provided tools should flatten Claude tool_use / tool_result blocks with no tools array","status":"passed","title":"should flatten Claude tool_use / tool_result blocks with no tools array","duration":1.7921249999999986,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["openaiToKiroRequest","tool interaction without client-provided tools"],"fullName":"openaiToKiroRequest tool interaction without client-provided tools should keep structured tools when the client DOES provide a tools array","status":"passed","title":"should keep structured tools when the client DOES provide a tools array","duration":3.070042000000001,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["openaiToKiroRequest","tool interaction without client-provided tools"],"fullName":"openaiToKiroRequest tool interaction without client-provided tools should salvage orphaned tool_result content as text instead of discarding it","status":"passed","title":"should salvage orphaned tool_result content as text instead of discarding it","duration":0.6450000000000387,"failureMessages":[],"meta":{},"tags":[]}],"startTime":1781440250913,"endTime":1781440250930.645,"status":"passed","message":"","name":"/Users/Working/router4/app/tests/unit/openai-to-kiro.test.js"},{"assertionResults":[{"ancestorTitles":["parseOpenAIMessages"],"fullName":"parseOpenAIMessages extracts system + history + current msg","status":"passed","title":"extracts system + history + current msg","duration":3.222666000000004,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["parseOpenAIMessages"],"fullName":"parseOpenAIMessages treats developer role as system","status":"passed","title":"treats developer role as system","duration":0.6043339999999944,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["parseOpenAIMessages"],"fullName":"parseOpenAIMessages handles multi-part content (array of text blocks)","status":"passed","title":"handles multi-part content (array of text blocks)","duration":0.23608399999994845,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["parseOpenAIMessages"],"fullName":"parseOpenAIMessages skips empty content messages","status":"passed","title":"skips empty content messages","duration":0.2745830000000069,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["buildQuery"],"fullName":"buildQuery first turn: returns JSON with instructions + query","status":"passed","title":"first turn: returns JSON with instructions + query","duration":1.3688750000000027,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["buildQuery"],"fullName":"buildQuery follow-up (with backendUuid): returns plain currentMsg, no JSON","status":"passed","title":"follow-up (with backendUuid): returns plain currentMsg, no JSON","duration":0.3449590000000171,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["buildQuery"],"fullName":"buildQuery includes history when present on first turn","status":"passed","title":"includes history when present on first turn","duration":0.4057080000000042,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["buildQuery"],"fullName":"buildQuery injects tools into instructions on first turn","status":"passed","title":"injects tools into instructions on first turn","duration":0.3346250000000168,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["buildQuery"],"fullName":"buildQuery ignores tools on follow-up turn (uses session)","status":"passed","title":"ignores tools on follow-up turn (uses session)","duration":0.8226660000000265,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["buildQuery"],"fullName":"buildQuery truncates query if JSON exceeds 96000 chars","status":"passed","title":"truncates query if JSON exceeds 96000 chars","duration":1.163458999999989,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["formatToolsHint"],"fullName":"formatToolsHint returns empty string for no tools","status":"passed","title":"returns empty string for no tools","duration":0.34737499999999955,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["formatToolsHint"],"fullName":"formatToolsHint handles OpenAI tool schema (function wrapper)","status":"passed","title":"handles OpenAI tool schema (function wrapper)","duration":0.146000000000015,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["formatToolsHint"],"fullName":"formatToolsHint handles flat tool schema","status":"passed","title":"handles flat tool schema","duration":0.38545799999997143,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["formatToolsHint"],"fullName":"formatToolsHint truncates long descriptions to first line, max 200 chars","status":"passed","title":"truncates long descriptions to first line, max 200 chars","duration":0.3047910000000229,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["buildPplxRequestBody"],"fullName":"buildPplxRequestBody sets query_str at both top-level AND params (required by upstream API)","status":"passed","title":"sets query_str at both top-level AND params (required by upstream API)","duration":95.85374999999999,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["buildPplxRequestBody"],"fullName":"buildPplxRequestBody includes required params","status":"passed","title":"includes required params","duration":14.62941699999999,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["PerplexityWebExecutor.execute"],"fullName":"PerplexityWebExecutor.execute maps pplx-auto → mode=concise, pref=pplx_pro","status":"passed","title":"maps pplx-auto → mode=concise, pref=pplx_pro","duration":452.068125,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["PerplexityWebExecutor.execute"],"fullName":"PerplexityWebExecutor.execute applies THINKING_MAP when reasoning_effort is set","status":"passed","title":"applies THINKING_MAP when reasoning_effort is set","duration":1.6633339999998498,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["PerplexityWebExecutor.execute"],"fullName":"PerplexityWebExecutor.execute sends Cookie header when credentials.apiKey provided","status":"passed","title":"sends Cookie header when credentials.apiKey provided","duration":1.5959169999998721,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["PerplexityWebExecutor.execute"],"fullName":"PerplexityWebExecutor.execute sends Bearer header when credentials.accessToken provided","status":"passed","title":"sends Bearer header when credentials.accessToken provided","duration":1.202291999999943,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["PerplexityWebExecutor.execute"],"fullName":"PerplexityWebExecutor.execute injects body.tools into query_str instructions","status":"passed","title":"injects body.tools into query_str instructions","duration":2.386874999999918,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["PerplexityWebExecutor.execute"],"fullName":"PerplexityWebExecutor.execute returns 400 on missing messages","status":"passed","title":"returns 400 on missing messages","duration":98.60691599999996,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["PerplexityWebExecutor.execute"],"fullName":"PerplexityWebExecutor.execute surfaces upstream 401 with friendly auth message","status":"passed","title":"surfaces upstream 401 with friendly auth message","duration":87.15650000000005,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["PerplexityWebExecutor.execute"],"fullName":"PerplexityWebExecutor.execute surfaces 429 with rate-limit message","status":"passed","title":"surfaces 429 with rate-limit message","duration":61.53200000000015,"failureMessages":[],"meta":{},"tags":[]}],"startTime":1781440229411,"endTime":1781440230250.532,"status":"passed","message":"","name":"/Users/Working/router4/app/tests/unit/perplexity-web.test.js"},{"assertionResults":[{"ancestorTitles":["provider display split (E1)"],"fullName":"provider display split (E1) AI_PROVIDERS entries still carry merged display + transport","status":"passed","title":"AI_PROVIDERS entries still carry merged display + transport","duration":841.9808750000001,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["provider display split (E1)"],"fullName":"provider display split (E1) display fields source from providersDisplay.js","status":"passed","title":"display fields source from providersDisplay.js","duration":289.303042,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["provider display split (E1)"],"fullName":"provider display split (E1) helpers still work after split","status":"passed","title":"helpers still work after split","duration":0.6887500000000273,"failureMessages":[],"meta":{},"tags":[]}],"startTime":1781440229984,"endTime":1781440231115.6887,"status":"passed","message":"","name":"/Users/Working/router4/app/tests/unit/provider-display-split.test.js"},{"assertionResults":[{"ancestorTitles":["MiniMax-M3 model registration"],"fullName":"MiniMax-M3 model registration includes MiniMax-M3 in PROVIDER_MODELS.minimax","status":"passed","title":"includes MiniMax-M3 in PROVIDER_MODELS.minimax","duration":4.315500000000043,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["MiniMax-M3 model registration"],"fullName":"MiniMax-M3 model registration includes MiniMax-M3 in PROVIDER_MODELS['minimax-cn']","status":"passed","title":"includes MiniMax-M3 in PROVIDER_MODELS['minimax-cn']","duration":1.1124580000000037,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["MiniMax-M3 model registration"],"fullName":"MiniMax-M3 model registration exposes MiniMax-M3 through getModelsByProviderId for both provider IDs","status":"passed","title":"exposes MiniMax-M3 through getModelsByProviderId for both provider IDs","duration":0.9917500000000246,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["MiniMax-M3 model registration"],"fullName":"MiniMax-M3 model registration does not regress the existing M2.7 / M2.5 / M2.1 entries","status":"passed","title":"does not regress the existing M2.7 / M2.5 / M2.1 entries","duration":2.5518749999999955,"failureMessages":[],"meta":{},"tags":[]}],"startTime":1781440250999,"endTime":1781440251008.5518,"status":"passed","message":"","name":"/Users/Working/router4/app/tests/unit/provider-models-minimax-m3.test.js"},{"assertionResults":[{"ancestorTitles":["MiniMax-M3 pricing"],"fullName":"MiniMax-M3 pricing includes MiniMax-M3 in MODEL_PRICING","status":"passed","title":"includes MiniMax-M3 in MODEL_PRICING","duration":2.2283749999999998,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["MiniMax-M3 pricing"],"fullName":"MiniMax-M3 pricing MiniMax-M3 pricing has numeric shape (input, output, cached)","status":"passed","title":"MiniMax-M3 pricing has numeric shape (input, output, cached)","duration":1.65300000000002,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["MiniMax-M3 pricing"],"fullName":"MiniMax-M3 pricing MiniMax-M3 input price matches the design spec (0.30)","status":"passed","title":"MiniMax-M3 input price matches the design spec (0.30)","duration":0.30620799999999804,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["MiniMax-M3 pricing"],"fullName":"MiniMax-M3 pricing MiniMax-M3 output price matches the design spec (1.20)","status":"passed","title":"MiniMax-M3 output price matches the design spec (1.20)","duration":0.28054199999999696,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["MiniMax-M3 pricing"],"fullName":"MiniMax-M3 pricing MiniMax-M3 cached price matches the design spec (0.06)","status":"passed","title":"MiniMax-M3 cached price matches the design spec (0.06)","duration":0.16045900000000302,"failureMessages":[],"meta":{},"tags":[]}],"startTime":1781440251072,"endTime":1781440251077.1604,"status":"passed","message":"","name":"/Users/Working/router4/app/tests/unit/provider-pricing-minimax-m3.test.js"},{"assertionResults":[{"ancestorTitles":["provider test-models route kind routing"],"fullName":"provider test-models route kind routing routes huggingface image models to /api/v1/images/generations","status":"passed","title":"routes huggingface image models to /api/v1/images/generations","duration":141.85212499999997,"failureMessages":[],"meta":{},"tags":[]}],"startTime":1781440228786,"endTime":1781440228927.852,"status":"passed","message":"","name":"/Users/Working/router4/app/tests/unit/provider-test-models-routing.test.js"},{"assertionResults":[{"ancestorTitles":["Provider Validation API","OpenAI Compatible"],"fullName":"Provider Validation API OpenAI Compatible should return valid:true when /models succeeds","status":"passed","title":"should return valid:true when /models succeeds","duration":8.71550000000002,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["Provider Validation API","OpenAI Compatible"],"fullName":"Provider Validation API OpenAI Compatible should fallback to chat/completions when /models fails and modelId provided","status":"passed","title":"should fallback to chat/completions when /models fails and modelId provided","duration":0.5422080000000733,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["Provider Validation API","OpenAI Compatible"],"fullName":"Provider Validation API OpenAI Compatible should return error when /models fails and no modelId","status":"passed","title":"should return error when /models fails and no modelId","duration":0.621791999999914,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["Provider Validation API","Anthropic Compatible"],"fullName":"Provider Validation API Anthropic Compatible should normalize URL by removing /messages suffix","status":"passed","title":"should normalize URL by removing /messages suffix","duration":0.4884580000000369,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["Provider Validation API","Anthropic Compatible"],"fullName":"Provider Validation API Anthropic Compatible should send correct headers for Anthropic API","status":"passed","title":"should send correct headers for Anthropic API","duration":32.7930409999999,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["Provider Validation API","Error Messages - Network"],"fullName":"Provider Validation API Error Messages - Network should map ECONNREFUSED to user-friendly message","status":"passed","title":"should map ECONNREFUSED to user-friendly message","duration":0.47195799999985866,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["Provider Validation API","Error Messages - Network"],"fullName":"Provider Validation API Error Messages - Network should map ENOTFOUND to user-friendly message","status":"passed","title":"should map ENOTFOUND to user-friendly message","duration":0.39220799999998235,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["Provider Validation API","Error Messages - Network"],"fullName":"Provider Validation API Error Messages - Network should map timeout to user-friendly message","status":"passed","title":"should map timeout to user-friendly message","duration":0.21349999999983993,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["Provider Validation API","Error Messages - Network"],"fullName":"Provider Validation API Error Messages - Network should map CERT_HAS_EXPIRED to user-friendly message","status":"passed","title":"should map CERT_HAS_EXPIRED to user-friendly message","duration":1.618167000000085,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["Provider Validation API","URL Validation"],"fullName":"Provider Validation API URL Validation should validate correct URL format","status":"passed","title":"should validate correct URL format","duration":27.323666999999887,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["Provider Validation API","Error Messages - /models Status Codes"],"fullName":"Provider Validation API Error Messages - /models Status Codes should return auth error for 401","status":"passed","title":"should return auth error for 401","duration":0.40145800000004783,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["Provider Validation API","Error Messages - /models Status Codes"],"fullName":"Provider Validation API Error Messages - /models Status Codes should return auth error for 403","status":"passed","title":"should return auth error for 403","duration":0.12129200000003948,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["Provider Validation API","Error Messages - /models Status Codes"],"fullName":"Provider Validation API Error Messages - /models Status Codes should return not found for 404","status":"passed","title":"should return not found for 404","duration":0.09608400000001893,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["Provider Validation API","Error Messages - /models Status Codes"],"fullName":"Provider Validation API Error Messages - /models Status Codes should return server error for 500","status":"passed","title":"should return server error for 500","duration":0.0810830000000351,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["Provider Validation API","Error Messages - /models Status Codes"],"fullName":"Provider Validation API Error Messages - /models Status Codes should return server error for 502","status":"passed","title":"should return server error for 502","duration":0.07825000000002547,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["Provider Validation API","Error Messages - /models Status Codes"],"fullName":"Provider Validation API Error Messages - /models Status Codes should return unexpected for other codes","status":"passed","title":"should return unexpected for other codes","duration":35.93616599999996,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["Provider Validation API","Error Messages - /chat/completions Status Codes"],"fullName":"Provider Validation API Error Messages - /chat/completions Status Codes should return auth error for 401","status":"passed","title":"should return auth error for 401","duration":0.2880000000000109,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["Provider Validation API","Error Messages - /chat/completions Status Codes"],"fullName":"Provider Validation API Error Messages - /chat/completions Status Codes should return invalid model for 400","status":"passed","title":"should return invalid model for 400","duration":0.11683300000004238,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["Provider Validation API","Error Messages - /chat/completions Status Codes"],"fullName":"Provider Validation API Error Messages - /chat/completions Status Codes should return not found for 404","status":"passed","title":"should return not found for 404","duration":0.09816599999999198,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["Provider Validation API","Error Messages - /chat/completions Status Codes"],"fullName":"Provider Validation API Error Messages - /chat/completions Status Codes should return server error for 503","status":"passed","title":"should return server error for 503","duration":0.09408299999995506,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["Provider Validation API","Error Messages - /chat/completions Status Codes"],"fullName":"Provider Validation API Error Messages - /chat/completions Status Codes should return failed for other codes","status":"passed","title":"should return failed for other codes","duration":0.09216700000001765,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["Provider Validation API","Response Format"],"fullName":"Provider Validation API Response Format should return correct format for success via /models","status":"passed","title":"should return correct format for success via /models","duration":0.18783300000018244,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["Provider Validation API","Response Format"],"fullName":"Provider Validation API Response Format should return correct format for success via chat","status":"passed","title":"should return correct format for success via chat","duration":93.09904099999994,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["Provider Validation API","Response Format"],"fullName":"Provider Validation API Response Format should return correct format for failure with error","status":"passed","title":"should return correct format for failure with error","duration":0.4357079999999769,"failureMessages":[],"meta":{},"tags":[]}],"startTime":1781440249904,"endTime":1781440250110.4358,"status":"passed","message":"","name":"/Users/Working/router4/app/tests/unit/provider-validation.test.js"},{"assertionResults":[{"ancestorTitles":["QODER_MODEL_MAP"],"fullName":"QODER_MODEL_MAP allows Qoder's latest model key","status":"passed","title":"allows Qoder's latest model key","duration":2.4155829999999696,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["QODER_MODEL_MAP"],"fullName":"QODER_MODEL_MAP exposes Qoder's latest model in the static provider catalog","status":"passed","title":"exposes Qoder's latest model in the static provider catalog","duration":0.648417000000336,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["qoderEncodeBody"],"fullName":"qoderEncodeBody preserves base64 length (input length divisible by 3)","status":"passed","title":"preserves base64 length (input length divisible by 3)","duration":0.33670900000015536,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["qoderEncodeBody"],"fullName":"qoderEncodeBody preserves base64 length (input length not divisible by 3)","status":"passed","title":"preserves base64 length (input length not divisible by 3)","duration":0.5270000000000437,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["qoderEncodeBody"],"fullName":"qoderEncodeBody handles empty input without throwing","status":"passed","title":"handles empty input without throwing","duration":0.19862499999999272,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["qoderEncodeBody"],"fullName":"qoderEncodeBody accepts string and Buffer inputs equivalently","status":"passed","title":"accepts string and Buffer inputs equivalently","duration":0.3047920000008162,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["qoderEncodeBody"],"fullName":"qoderEncodeBody only emits characters from the custom alphabet","status":"passed","title":"only emits characters from the custom alphabet","duration":2.312707999999475,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["qoderEncodeBody"],"fullName":"qoderEncodeBody is deterministic for identical input","status":"passed","title":"is deterministic for identical input","duration":0.5214580000001661,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["qoderEncodeBody"],"fullName":"qoderEncodeBody produces different output for different input","status":"passed","title":"produces different output for different input","duration":12.91137499999968,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["generatePkcePair"],"fullName":"generatePkcePair produces base64url-safe verifier and challenge of the right length","status":"passed","title":"produces base64url-safe verifier and challenge of the right length","duration":2.072624999999789,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["generatePkcePair"],"fullName":"generatePkcePair verifier and challenge are different (challenge is sha256 of verifier)","status":"passed","title":"verifier and challenge are different (challenge is sha256 of verifier)","duration":1.0197499999994761,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["generatePkcePair"],"fullName":"generatePkcePair returns codeVerifier (not verifier) on the higher-level helper","status":"passed","title":"returns codeVerifier (not verifier) on the higher-level helper","duration":0.6865840000000389,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["initiateDeviceFlow"],"fullName":"initiateDeviceFlow produces a verification URL pointing at qoder.com/device/selectAccounts","status":"passed","title":"produces a verification URL pointing at qoder.com/device/selectAccounts","duration":0.3892920000007507,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["initiateDeviceFlow"],"fullName":"initiateDeviceFlow returns nonce and machineId as UUIDs","status":"passed","title":"returns nonce and machineId as UUIDs","duration":0.3280830000003334,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["buildCosyHeaders"],"fullName":"buildCosyHeaders produces all required Cosy-* headers","status":"passed","title":"produces all required Cosy-* headers","duration":2.85412499999984,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["buildCosyHeaders"],"fullName":"buildCosyHeaders Authorization is a Bearer COSY token with payload+sig","status":"passed","title":"Authorization is a Bearer COSY token with payload+sig","duration":0.9548329999997804,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["buildCosyHeaders"],"fullName":"buildCosyHeaders Cosy-Sigpath strips the leading /algo prefix","status":"passed","title":"Cosy-Sigpath strips the leading /algo prefix","duration":0.42941700000028504,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["buildCosyHeaders"],"fullName":"buildCosyHeaders Cosy-Sigpath also handles the encoded chat URL","status":"passed","title":"Cosy-Sigpath also handles the encoded chat URL","duration":0.49441700000079436,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["buildCosyHeaders"],"fullName":"buildCosyHeaders Cosy-Bodyhash is the MD5 of the request body, Cosy-Bodylength is the length","status":"passed","title":"Cosy-Bodyhash is the MD5 of the request body, Cosy-Bodylength is the length","duration":0.4782500000001164,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["buildCosyHeaders"],"fullName":"buildCosyHeaders empty body produces the canonical empty-MD5 hash","status":"passed","title":"empty body produces the canonical empty-MD5 hash","duration":0.4852499999997235,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["buildCosyHeaders"],"fullName":"buildCosyHeaders Cosy-Machineid + Cosy-Machinetoken match the supplied machineId","status":"passed","title":"Cosy-Machineid + Cosy-Machinetoken match the supplied machineId","duration":0.8946670000004815,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["buildCosyHeaders"],"fullName":"buildCosyHeaders auto-generates a machineId when none is supplied","status":"passed","title":"auto-generates a machineId when none is supplied","duration":0.4605840000003809,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["buildCosyHeaders"],"fullName":"buildCosyHeaders throws when userId is missing","status":"passed","title":"throws when userId is missing","duration":1.6323339999999007,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["buildCosyHeaders"],"fullName":"buildCosyHeaders throws when authToken is missing","status":"passed","title":"throws when authToken is missing","duration":0.25404100000014296,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["buildCosyHeaders"],"fullName":"buildCosyHeaders Cosy-User reflects the supplied userId verbatim","status":"passed","title":"Cosy-User reflects the supplied userId verbatim","duration":1.1525000000001455,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["buildCosyHeaders"],"fullName":"buildCosyHeaders two calls with identical inputs differ only in fields that include fresh randomness","status":"passed","title":"two calls with identical inputs differ only in fields that include fresh randomness","duration":1.1484999999993306,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["parseExpiry"],"fullName":"parseExpiry accepts ms-epoch as a JSON number","status":"passed","title":"accepts ms-epoch as a JSON number","duration":0.1986669999996593,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["parseExpiry"],"fullName":"parseExpiry accepts ms-epoch as a numeric string","status":"passed","title":"accepts ms-epoch as a numeric string","duration":0.1380410000001575,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["parseExpiry"],"fullName":"parseExpiry accepts RFC3339 strings","status":"passed","title":"accepts RFC3339 strings","duration":0.12987499999962893,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["parseExpiry"],"fullName":"parseExpiry does not interpret short numeric strings as a year","status":"passed","title":"does not interpret short numeric strings as a year","duration":0.08429199999955017,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["parseExpiry"],"fullName":"parseExpiry falls back to expiresInSeconds when expiresAt is missing","status":"passed","title":"falls back to expiresInSeconds when expiresAt is missing","duration":0.19099999999980355,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["parseExpiry"],"fullName":"parseExpiry treats expires_in: 0 as already expired (now), not 30-day fallback","status":"passed","title":"treats expires_in: 0 as already expired (now), not 30-day fallback","duration":0.11133400000016991,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["parseExpiry"],"fullName":"parseExpiry falls back to ~30 days when both inputs are missing","status":"passed","title":"falls back to ~30 days when both inputs are missing","duration":0.11395799999991141,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["parseExpiry"],"fullName":"parseExpiry falls back to ~30 days when both inputs are unparseable","status":"passed","title":"falls back to ~30 days when both inputs are unparseable","duration":0.12254200000006676,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["normalizeMessages"],"fullName":"normalizeMessages hoists role:system out of messages into systemText","status":"passed","title":"hoists role:system out of messages into systemText","duration":0.8817920000001322,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["normalizeMessages"],"fullName":"normalizeMessages flattens multipart text content into a string","status":"passed","title":"flattens multipart text content into a string","duration":0.11658299999999144,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["normalizeMessages"],"fullName":"normalizeMessages joins multiple system messages with a blank line","status":"passed","title":"joins multiple system messages with a blank line","duration":0.09787500000038563,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["normalizeMessages"],"fullName":"normalizeMessages returns empty results for empty input","status":"passed","title":"returns empty results for empty input","duration":0.22066700000050332,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["wrapQoderSSE"],"fullName":"wrapQoderSSE forwards an OpenAI envelope chunk and emits [DONE] in flush","status":"passed","title":"forwards an OpenAI envelope chunk and emits [DONE] in flush","duration":294.3993339999997,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["wrapQoderSSE"],"fullName":"wrapQoderSSE drains a trailing partial line without a newline in flush()","status":"passed","title":"drains a trailing partial line without a newline in flush()","duration":0.9862919999995938,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["wrapQoderSSE"],"fullName":"wrapQoderSSE does not forward chunks after [DONE] has been emitted","status":"passed","title":"does not forward chunks after [DONE] has been emitted","duration":14.659166999999798,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["wrapQoderSSE"],"fullName":"wrapQoderSSE strips embedded newlines from inner body before forwarding","status":"passed","title":"strips embedded newlines from inner body before forwarding","duration":1.0720000000001164,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["wrapQoderSSE"],"fullName":"wrapQoderSSE upstream error envelope produces an error chunk + [DONE]","status":"passed","title":"upstream error envelope produces an error chunk + [DONE]","duration":1.4125420000000304,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["wrapQoderSSE"],"fullName":"wrapQoderSSE non-ok responses are returned unchanged (no transform)","status":"passed","title":"non-ok responses are returned unchanged (no transform)","duration":11.414333000000624,"failureMessages":[],"meta":{},"tags":[]}],"startTime":1781440246019,"endTime":1781440246383.4143,"status":"passed","message":"","name":"/Users/Working/router4/app/tests/unit/qoder.test.js"},{"assertionResults":[{"ancestorTitles":["injectReasoningContent — DeepSeek thinking round-trip"],"fullName":"injectReasoningContent — DeepSeek thinking round-trip injects reasoning_content on a deepseek- assistant message that lacks it","status":"passed","title":"injects reasoning_content on a deepseek- assistant message that lacks it","duration":2.0983750000000327,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["injectReasoningContent — DeepSeek thinking round-trip"],"fullName":"injectReasoningContent — DeepSeek thinking round-trip preserves an existing reasoning_content instead of overwriting it","status":"passed","title":"preserves an existing reasoning_content instead of overwriting it","duration":0.37945799999988594,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["injectReasoningContent — DeepSeek thinking round-trip"],"fullName":"injectReasoningContent — DeepSeek thinking round-trip applies provider-level rule for provider 'deepseek' (scope all)","status":"passed","title":"applies provider-level rule for provider 'deepseek' (scope all)","duration":0.18604099999993196,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["injectReasoningContent — DeepSeek thinking round-trip"],"fullName":"injectReasoningContent — DeepSeek thinking round-trip matches deepseek model id case-insensitively for custom providers (#1543)","status":"passed","title":"matches deepseek model id case-insensitively for custom providers (#1543)","duration":0.24400000000014188,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["injectReasoningContent — DeepSeek thinking round-trip"],"fullName":"injectReasoningContent — DeepSeek thinking round-trip does not touch non-deepseek providers/models","status":"passed","title":"does not touch non-deepseek providers/models","duration":0.17437500000005457,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["injectReasoningContent — DeepSeek thinking round-trip"],"fullName":"injectReasoningContent — DeepSeek thinking round-trip maps deepseek-v4-pro-none alias to disabled thinking and strips reasoning_effort","status":"passed","title":"maps deepseek-v4-pro-none alias to disabled thinking and strips reasoning_effort","duration":0.3132909999999356,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["injectReasoningContent — MiniMax thinking round-trip"],"fullName":"injectReasoningContent — MiniMax thinking round-trip injects reasoning_content on a minimax assistant message that lacks it","status":"passed","title":"injects reasoning_content on a minimax assistant message that lacks it","duration":0.28062499999987267,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["injectReasoningContent — MiniMax thinking round-trip"],"fullName":"injectReasoningContent — MiniMax thinking round-trip injects reasoning_content on minimax assistant message with tool_calls but no reasoning_content","status":"passed","title":"injects reasoning_content on minimax assistant message with tool_calls but no reasoning_content","duration":0.28945900000007896,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["injectReasoningContent — MiniMax thinking round-trip"],"fullName":"injectReasoningContent — MiniMax thinking round-trip applies provider-level rule for provider 'minimax-cn' (scope all)","status":"passed","title":"applies provider-level rule for provider 'minimax-cn' (scope all)","duration":0.7662500000001273,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["injectReasoningContent — MiniMax thinking round-trip"],"fullName":"injectReasoningContent — MiniMax thinking round-trip preserves an existing reasoning_content on minimax instead of overwriting","status":"passed","title":"preserves an existing reasoning_content on minimax instead of overwriting","duration":0.2883750000000873,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["injectReasoningContent — MiniMax thinking round-trip"],"fullName":"injectReasoningContent — MiniMax thinking round-trip DefaultExecutor transformRequest runs the injector for minimax","status":"passed","title":"DefaultExecutor transformRequest runs the injector for minimax","duration":194.07916699999987,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["OpenCodeExecutor — issue #1543 regression"],"fullName":"OpenCodeExecutor — issue #1543 regression runs the injector so deepseek-v4-flash-free round-trips reasoning_content","status":"passed","title":"runs the injector so deepseek-v4-flash-free round-trips reasoning_content","duration":0.27129199999990306,"failureMessages":[],"meta":{},"tags":[]}],"startTime":1781440247733,"endTime":1781440247933.2712,"status":"passed","message":"","name":"/Users/Working/router4/app/tests/unit/reasoningContentInjector.test.js"},{"assertionResults":[{"ancestorTitles":["Responses abort terminal synthesis"],"fullName":"Responses abort terminal synthesis emits response.failed + [DONE] when upstream errors (abort/stall)","status":"passed","title":"emits response.failed + [DONE] when upstream errors (abort/stall)","duration":4.727708000000007,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["Responses abort terminal synthesis"],"fullName":"Responses abort terminal synthesis does not synthesize terminal for non-Responses streams (callback null)","status":"passed","title":"does not synthesize terminal for non-Responses streams (callback null)","duration":0.6887499999999989,"failureMessages":[],"meta":{},"tags":[]}],"startTime":1781440251239,"endTime":1781440251243.7278,"status":"passed","message":"","name":"/Users/Working/router4/app/tests/unit/responses-abort-terminal.test.js"},{"assertionResults":[{"ancestorTitles":["RTK end-to-end"],"fullName":"RTK end-to-end server is reachable","status":"skipped","title":"server is reachable","failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["RTK end-to-end"],"fullName":"RTK end-to-end rtkEnabled flag is true (user must enable via dashboard)","status":"skipped","title":"rtkEnabled flag is true (user must enable via dashboard)","failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["RTK end-to-end"],"fullName":"RTK end-to-end compresses git diff tool_result and writes [RTK] savings to log","status":"skipped","title":"compresses git diff tool_result and writes [RTK] savings to log","failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["RTK end-to-end"],"fullName":"RTK end-to-end compresses grep-style tool_result","status":"skipped","title":"compresses grep-style tool_result","failureMessages":[],"meta":{},"tags":[]}],"startTime":1781440226639,"endTime":1781440226639,"status":"passed","message":"","name":"/Users/Working/router4/app/tests/unit/rtk.e2e.test.js"},{"assertionResults":[{"ancestorTitles":["RTK multi-provider E2E"],"fullName":"RTK multi-provider E2E server reachable and rtkEnabled=true","status":"skipped","title":"server reachable and rtkEnabled=true","failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["RTK multi-provider E2E"],"fullName":"RTK multi-provider E2E compresses git diff for claude (cc/* → openai→claude)","status":"skipped","title":"compresses git diff for claude (cc/* → openai→claude)","failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["RTK multi-provider E2E"],"fullName":"RTK multi-provider E2E compresses git diff for codex (cx/* → openai→openai-responses)","status":"skipped","title":"compresses git diff for codex (cx/* → openai→openai-responses)","failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["RTK multi-provider E2E"],"fullName":"RTK multi-provider E2E compresses git diff for antigravity (ag/* → openai→antigravity)","status":"skipped","title":"compresses git diff for antigravity (ag/* → openai→antigravity)","failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["RTK multi-provider E2E"],"fullName":"RTK multi-provider E2E compresses git diff for cursor (cu/* → openai→cursor)","status":"skipped","title":"compresses git diff for cursor (cu/* → openai→cursor)","failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["RTK multi-provider E2E"],"fullName":"RTK multi-provider E2E compresses git diff for kiro (kr/* → openai→kiro)","status":"skipped","title":"compresses git diff for kiro (kr/* → openai→kiro)","failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["RTK multi-provider E2E"],"fullName":"RTK multi-provider E2E compresses git diff for gemini (gemini/* → openai→gemini)","status":"skipped","title":"compresses git diff for gemini (gemini/* → openai→gemini)","failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["RTK multi-provider E2E"],"fullName":"RTK multi-provider E2E compresses git diff for deepseek (deepseek/* → openai, passthrough)","status":"skipped","title":"compresses git diff for deepseek (deepseek/* → openai, passthrough)","failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["RTK multi-provider E2E"],"fullName":"RTK multi-provider E2E compresses git diff for ollama (ollama/* → openai→ollama)","status":"skipped","title":"compresses git diff for ollama (ollama/* → openai→ollama)","failureMessages":[],"meta":{},"tags":[]}],"startTime":1781440226639,"endTime":1781440226639,"status":"passed","message":"","name":"/Users/Working/router4/app/tests/unit/rtk.multi-provider.e2e.test.js"},{"assertionResults":[{"ancestorTitles":["RTK flag"],"fullName":"RTK flag default off, toggle works","status":"failed","title":"default off, toggle works","duration":5.7654999999999745,"failureMessages":["TypeError: (0 , __vite_ssr_import_1__.setRtkEnabled) is not a function\n at /Users/Working/router4/app/tests/unit/rtk.test.js:58:18\n at file:///Users/hoanganh/.npm/_npx/69c381f8ad94b576/node_modules/@vitest/runner/dist/chunk-artifact.js:302:11\n at file:///Users/hoanganh/.npm/_npx/69c381f8ad94b576/node_modules/@vitest/runner/dist/chunk-artifact.js:1903:26\n at file:///Users/hoanganh/.npm/_npx/69c381f8ad94b576/node_modules/@vitest/runner/dist/chunk-artifact.js:2326:20\n at new Promise ()\n at runWithCancel (file:///Users/hoanganh/.npm/_npx/69c381f8ad94b576/node_modules/@vitest/runner/dist/chunk-artifact.js:2323:10)\n at file:///Users/hoanganh/.npm/_npx/69c381f8ad94b576/node_modules/@vitest/runner/dist/chunk-artifact.js:2305:20\n at new Promise ()\n at runWithTimeout (file:///Users/hoanganh/.npm/_npx/69c381f8ad94b576/node_modules/@vitest/runner/dist/chunk-artifact.js:2272:10)\n at file:///Users/hoanganh/.npm/_npx/69c381f8ad94b576/node_modules/@vitest/runner/dist/chunk-artifact.js:2955:64"],"meta":{},"tags":[]},{"ancestorTitles":["RTK filters"],"fullName":"RTK filters gitDiff truncates hunks beyond 100 lines and preserves file header","status":"passed","title":"gitDiff truncates hunks beyond 100 lines and preserves file header","duration":1.4268329999999878,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["RTK filters"],"fullName":"RTK filters gitStatus groups by kind and produces compact output (Rust format)","status":"passed","title":"gitStatus groups by kind and produces compact output (Rust format)","duration":0.5959159999999883,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["RTK filters"],"fullName":"RTK filters grep groups matches by file and caps per-file lines (Rust format)","status":"passed","title":"grep groups matches by file and caps per-file lines (Rust format)","duration":0.6997089999999844,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["RTK filters"],"fullName":"RTK filters find groups paths by parent dir, shows basenames (Rust format)","status":"passed","title":"find groups paths by parent dir, shows basenames (Rust format)","duration":0.4078339999999798,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["RTK filters"],"fullName":"RTK filters dedupLog collapses consecutive duplicates","status":"passed","title":"dedupLog collapses consecutive duplicates","duration":0.2909159999999815,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["autoDetectFilter"],"fullName":"autoDetectFilter detects git diff","status":"passed","title":"detects git diff","duration":0.6351660000000265,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["autoDetectFilter"],"fullName":"autoDetectFilter detects git status","status":"passed","title":"detects git status","duration":0.3332919999999717,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["autoDetectFilter"],"fullName":"autoDetectFilter detects grep","status":"passed","title":"detects grep","duration":1.7557090000000244,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["autoDetectFilter"],"fullName":"autoDetectFilter detects find","status":"passed","title":"detects find","duration":0.4312500000000341,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["autoDetectFilter"],"fullName":"autoDetectFilter falls back to dedupLog for generic text","status":"passed","title":"falls back to dedupLog for generic text","duration":0.30604099999999335,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["RTK filters (extras)"],"fullName":"RTK filters (extras) ls: compact_ls strips perms/owner, keeps name + size","status":"passed","title":"ls: compact_ls strips perms/owner, keeps name + size","duration":0.6052090000000021,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["RTK filters (extras)"],"fullName":"RTK filters (extras) ls: filters noise dirs","status":"passed","title":"ls: filters noise dirs","duration":0.19362499999999727,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["RTK filters (extras)"],"fullName":"RTK filters (extras) tree: removes summary, keeps structure","status":"passed","title":"tree: removes summary, keeps structure","duration":0.211166999999989,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["RTK filters (extras)"],"fullName":"RTK filters (extras) smartTruncate: keeps head+tail, drops middle","status":"passed","title":"smartTruncate: keeps head+tail, drops middle","duration":0.25,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["RTK filters (extras)"],"fullName":"RTK filters (extras) smartTruncate: passes through small input","status":"passed","title":"smartTruncate: passes through small input","duration":0.06837500000000318,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["RTK filters (extras)"],"fullName":"RTK filters (extras) readNumbered: compacts very long line-numbered dump","status":"passed","title":"readNumbered: compacts very long line-numbered dump","duration":0.2566669999999931,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["RTK filters (extras)"],"fullName":"RTK filters (extras) searchList: groups Cursor Glob output by parent dir","status":"passed","title":"searchList: groups Cursor Glob output by parent dir","duration":0.42933299999998553,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["autoDetectFilter (extras)"],"fullName":"autoDetectFilter (extras) detects tree via box-drawing glyphs","status":"passed","title":"detects tree via box-drawing glyphs","duration":0.5113749999999868,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["autoDetectFilter (extras)"],"fullName":"autoDetectFilter (extras) detects ls via total + perms rows","status":"passed","title":"detects ls via total + perms rows","duration":0.16141699999997172,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["autoDetectFilter (extras)"],"fullName":"autoDetectFilter (extras) detects Cursor search list","status":"passed","title":"detects Cursor search list","duration":0.4044579999999769,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["safeApply"],"fullName":"safeApply returns input if filter throws","status":"passed","title":"returns input if filter throws","duration":1.1444169999999758,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["safeApply"],"fullName":"safeApply returns input if filter returns non-string","status":"passed","title":"returns input if filter returns non-string","duration":0.22116599999998243,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["compressMessages (disabled)"],"fullName":"compressMessages (disabled) returns null when disabled","status":"failed","title":"returns null when disabled","duration":1.031000000000006,"failureMessages":["TypeError: (0 , __vite_ssr_import_1__.setRtkEnabled) is not a function\n at /Users/Working/router4/app/tests/unit/rtk.test.js:248:33\n at file:///Users/hoanganh/.npm/_npx/69c381f8ad94b576/node_modules/@vitest/runner/dist/chunk-artifact.js:302:11\n at wrapper (file:///Users/hoanganh/.npm/_npx/69c381f8ad94b576/node_modules/@vitest/runner/dist/chunk-artifact.js:722:10)\n at file:///Users/hoanganh/.npm/_npx/69c381f8ad94b576/node_modules/@vitest/runner/dist/chunk-artifact.js:2305:20\n at new Promise ()\n at runWithTimeout (file:///Users/hoanganh/.npm/_npx/69c381f8ad94b576/node_modules/@vitest/runner/dist/chunk-artifact.js:2272:10)\n at file:///Users/hoanganh/.npm/_npx/69c381f8ad94b576/node_modules/@vitest/runner/dist/chunk-artifact.js:2621:52\n at run (file:///Users/hoanganh/.npm/_npx/69c381f8ad94b576/node_modules/@vitest/runner/dist/chunk-artifact.js:1150:20)\n at limiterFn (file:///Users/hoanganh/.npm/_npx/69c381f8ad94b576/node_modules/@vitest/runner/dist/chunk-artifact.js:1162:59)\n at runHook (file:///Users/hoanganh/.npm/_npx/69c381f8ad94b576/node_modules/@vitest/runner/dist/chunk-artifact.js:2620:10)"],"meta":{},"tags":[]},{"ancestorTitles":["compressMessages (enabled)"],"fullName":"compressMessages (enabled) compresses OpenAI tool message (string content)","status":"failed","title":"compresses OpenAI tool message (string content)","duration":0.20345900000000938,"failureMessages":["TypeError: (0 , __vite_ssr_import_1__.setRtkEnabled) is not a function\n at /Users/Working/router4/app/tests/unit/rtk.test.js:256:33\n at file:///Users/hoanganh/.npm/_npx/69c381f8ad94b576/node_modules/@vitest/runner/dist/chunk-artifact.js:302:11\n at wrapper (file:///Users/hoanganh/.npm/_npx/69c381f8ad94b576/node_modules/@vitest/runner/dist/chunk-artifact.js:722:10)\n at file:///Users/hoanganh/.npm/_npx/69c381f8ad94b576/node_modules/@vitest/runner/dist/chunk-artifact.js:2305:20\n at new Promise ()\n at runWithTimeout (file:///Users/hoanganh/.npm/_npx/69c381f8ad94b576/node_modules/@vitest/runner/dist/chunk-artifact.js:2272:10)\n at file:///Users/hoanganh/.npm/_npx/69c381f8ad94b576/node_modules/@vitest/runner/dist/chunk-artifact.js:2621:52\n at run (file:///Users/hoanganh/.npm/_npx/69c381f8ad94b576/node_modules/@vitest/runner/dist/chunk-artifact.js:1150:20)\n at limiterFn (file:///Users/hoanganh/.npm/_npx/69c381f8ad94b576/node_modules/@vitest/runner/dist/chunk-artifact.js:1162:59)\n at runHook (file:///Users/hoanganh/.npm/_npx/69c381f8ad94b576/node_modules/@vitest/runner/dist/chunk-artifact.js:2620:10)"],"meta":{},"tags":[]},{"ancestorTitles":["compressMessages (enabled)"],"fullName":"compressMessages (enabled) compresses Claude string-form tool_result","status":"failed","title":"compresses Claude string-form tool_result","duration":0.31324999999998226,"failureMessages":["TypeError: (0 , __vite_ssr_import_1__.setRtkEnabled) is not a function\n at /Users/Working/router4/app/tests/unit/rtk.test.js:256:33\n at file:///Users/hoanganh/.npm/_npx/69c381f8ad94b576/node_modules/@vitest/runner/dist/chunk-artifact.js:302:11\n at wrapper (file:///Users/hoanganh/.npm/_npx/69c381f8ad94b576/node_modules/@vitest/runner/dist/chunk-artifact.js:722:10)\n at file:///Users/hoanganh/.npm/_npx/69c381f8ad94b576/node_modules/@vitest/runner/dist/chunk-artifact.js:2305:20\n at new Promise ()\n at runWithTimeout (file:///Users/hoanganh/.npm/_npx/69c381f8ad94b576/node_modules/@vitest/runner/dist/chunk-artifact.js:2272:10)\n at file:///Users/hoanganh/.npm/_npx/69c381f8ad94b576/node_modules/@vitest/runner/dist/chunk-artifact.js:2621:52\n at run (file:///Users/hoanganh/.npm/_npx/69c381f8ad94b576/node_modules/@vitest/runner/dist/chunk-artifact.js:1150:20)\n at limiterFn (file:///Users/hoanganh/.npm/_npx/69c381f8ad94b576/node_modules/@vitest/runner/dist/chunk-artifact.js:1162:59)\n at runHook (file:///Users/hoanganh/.npm/_npx/69c381f8ad94b576/node_modules/@vitest/runner/dist/chunk-artifact.js:2620:10)"],"meta":{},"tags":[]},{"ancestorTitles":["compressMessages (enabled)"],"fullName":"compressMessages (enabled) compresses Claude array-form tool_result text parts","status":"failed","title":"compresses Claude array-form tool_result text parts","duration":0.7970419999999763,"failureMessages":["TypeError: (0 , __vite_ssr_import_1__.setRtkEnabled) is not a function\n at /Users/Working/router4/app/tests/unit/rtk.test.js:256:33\n at file:///Users/hoanganh/.npm/_npx/69c381f8ad94b576/node_modules/@vitest/runner/dist/chunk-artifact.js:302:11\n at wrapper (file:///Users/hoanganh/.npm/_npx/69c381f8ad94b576/node_modules/@vitest/runner/dist/chunk-artifact.js:722:10)\n at file:///Users/hoanganh/.npm/_npx/69c381f8ad94b576/node_modules/@vitest/runner/dist/chunk-artifact.js:2305:20\n at new Promise ()\n at runWithTimeout (file:///Users/hoanganh/.npm/_npx/69c381f8ad94b576/node_modules/@vitest/runner/dist/chunk-artifact.js:2272:10)\n at file:///Users/hoanganh/.npm/_npx/69c381f8ad94b576/node_modules/@vitest/runner/dist/chunk-artifact.js:2621:52\n at run (file:///Users/hoanganh/.npm/_npx/69c381f8ad94b576/node_modules/@vitest/runner/dist/chunk-artifact.js:1150:20)\n at limiterFn (file:///Users/hoanganh/.npm/_npx/69c381f8ad94b576/node_modules/@vitest/runner/dist/chunk-artifact.js:1162:59)\n at runHook (file:///Users/hoanganh/.npm/_npx/69c381f8ad94b576/node_modules/@vitest/runner/dist/chunk-artifact.js:2620:10)"],"meta":{},"tags":[]},{"ancestorTitles":["compressMessages (enabled)"],"fullName":"compressMessages (enabled) skips is_error tool_result","status":"failed","title":"skips is_error tool_result","duration":0.41258300000004056,"failureMessages":["TypeError: (0 , __vite_ssr_import_1__.setRtkEnabled) is not a function\n at /Users/Working/router4/app/tests/unit/rtk.test.js:256:33\n at file:///Users/hoanganh/.npm/_npx/69c381f8ad94b576/node_modules/@vitest/runner/dist/chunk-artifact.js:302:11\n at wrapper (file:///Users/hoanganh/.npm/_npx/69c381f8ad94b576/node_modules/@vitest/runner/dist/chunk-artifact.js:722:10)\n at file:///Users/hoanganh/.npm/_npx/69c381f8ad94b576/node_modules/@vitest/runner/dist/chunk-artifact.js:2305:20\n at new Promise ()\n at runWithTimeout (file:///Users/hoanganh/.npm/_npx/69c381f8ad94b576/node_modules/@vitest/runner/dist/chunk-artifact.js:2272:10)\n at file:///Users/hoanganh/.npm/_npx/69c381f8ad94b576/node_modules/@vitest/runner/dist/chunk-artifact.js:2621:52\n at run (file:///Users/hoanganh/.npm/_npx/69c381f8ad94b576/node_modules/@vitest/runner/dist/chunk-artifact.js:1150:20)\n at limiterFn (file:///Users/hoanganh/.npm/_npx/69c381f8ad94b576/node_modules/@vitest/runner/dist/chunk-artifact.js:1162:59)\n at runHook (file:///Users/hoanganh/.npm/_npx/69c381f8ad94b576/node_modules/@vitest/runner/dist/chunk-artifact.js:2620:10)"],"meta":{},"tags":[]},{"ancestorTitles":["compressMessages (enabled)"],"fullName":"compressMessages (enabled) skips below MIN_COMPRESS_SIZE (<500 bytes)","status":"failed","title":"skips below MIN_COMPRESS_SIZE (<500 bytes)","duration":0.3387089999999944,"failureMessages":["TypeError: (0 , __vite_ssr_import_1__.setRtkEnabled) is not a function\n at /Users/Working/router4/app/tests/unit/rtk.test.js:256:33\n at file:///Users/hoanganh/.npm/_npx/69c381f8ad94b576/node_modules/@vitest/runner/dist/chunk-artifact.js:302:11\n at wrapper (file:///Users/hoanganh/.npm/_npx/69c381f8ad94b576/node_modules/@vitest/runner/dist/chunk-artifact.js:722:10)\n at file:///Users/hoanganh/.npm/_npx/69c381f8ad94b576/node_modules/@vitest/runner/dist/chunk-artifact.js:2305:20\n at new Promise ()\n at runWithTimeout (file:///Users/hoanganh/.npm/_npx/69c381f8ad94b576/node_modules/@vitest/runner/dist/chunk-artifact.js:2272:10)\n at file:///Users/hoanganh/.npm/_npx/69c381f8ad94b576/node_modules/@vitest/runner/dist/chunk-artifact.js:2621:52\n at run (file:///Users/hoanganh/.npm/_npx/69c381f8ad94b576/node_modules/@vitest/runner/dist/chunk-artifact.js:1150:20)\n at limiterFn (file:///Users/hoanganh/.npm/_npx/69c381f8ad94b576/node_modules/@vitest/runner/dist/chunk-artifact.js:1162:59)\n at runHook (file:///Users/hoanganh/.npm/_npx/69c381f8ad94b576/node_modules/@vitest/runner/dist/chunk-artifact.js:2620:10)"],"meta":{},"tags":[]},{"ancestorTitles":["compressMessages (enabled)"],"fullName":"compressMessages (enabled) never produces empty content (R14 guard)","status":"failed","title":"never produces empty content (R14 guard)","duration":0.3785419999999817,"failureMessages":["TypeError: (0 , __vite_ssr_import_1__.setRtkEnabled) is not a function\n at /Users/Working/router4/app/tests/unit/rtk.test.js:256:33\n at file:///Users/hoanganh/.npm/_npx/69c381f8ad94b576/node_modules/@vitest/runner/dist/chunk-artifact.js:302:11\n at wrapper (file:///Users/hoanganh/.npm/_npx/69c381f8ad94b576/node_modules/@vitest/runner/dist/chunk-artifact.js:722:10)\n at file:///Users/hoanganh/.npm/_npx/69c381f8ad94b576/node_modules/@vitest/runner/dist/chunk-artifact.js:2305:20\n at new Promise ()\n at runWithTimeout (file:///Users/hoanganh/.npm/_npx/69c381f8ad94b576/node_modules/@vitest/runner/dist/chunk-artifact.js:2272:10)\n at file:///Users/hoanganh/.npm/_npx/69c381f8ad94b576/node_modules/@vitest/runner/dist/chunk-artifact.js:2621:52\n at run (file:///Users/hoanganh/.npm/_npx/69c381f8ad94b576/node_modules/@vitest/runner/dist/chunk-artifact.js:1150:20)\n at limiterFn (file:///Users/hoanganh/.npm/_npx/69c381f8ad94b576/node_modules/@vitest/runner/dist/chunk-artifact.js:1162:59)\n at runHook (file:///Users/hoanganh/.npm/_npx/69c381f8ad94b576/node_modules/@vitest/runner/dist/chunk-artifact.js:2620:10)"],"meta":{},"tags":[]},{"ancestorTitles":["compressMessages (enabled)"],"fullName":"compressMessages (enabled) skips when body has no messages","status":"failed","title":"skips when body has no messages","duration":0.23508299999997462,"failureMessages":["TypeError: (0 , __vite_ssr_import_1__.setRtkEnabled) is not a function\n at /Users/Working/router4/app/tests/unit/rtk.test.js:256:33\n at file:///Users/hoanganh/.npm/_npx/69c381f8ad94b576/node_modules/@vitest/runner/dist/chunk-artifact.js:302:11\n at wrapper (file:///Users/hoanganh/.npm/_npx/69c381f8ad94b576/node_modules/@vitest/runner/dist/chunk-artifact.js:722:10)\n at file:///Users/hoanganh/.npm/_npx/69c381f8ad94b576/node_modules/@vitest/runner/dist/chunk-artifact.js:2305:20\n at new Promise ()\n at runWithTimeout (file:///Users/hoanganh/.npm/_npx/69c381f8ad94b576/node_modules/@vitest/runner/dist/chunk-artifact.js:2272:10)\n at file:///Users/hoanganh/.npm/_npx/69c381f8ad94b576/node_modules/@vitest/runner/dist/chunk-artifact.js:2621:52\n at run (file:///Users/hoanganh/.npm/_npx/69c381f8ad94b576/node_modules/@vitest/runner/dist/chunk-artifact.js:1150:20)\n at limiterFn (file:///Users/hoanganh/.npm/_npx/69c381f8ad94b576/node_modules/@vitest/runner/dist/chunk-artifact.js:1162:59)\n at runHook (file:///Users/hoanganh/.npm/_npx/69c381f8ad94b576/node_modules/@vitest/runner/dist/chunk-artifact.js:2620:10)"],"meta":{},"tags":[]},{"ancestorTitles":["compressMessages (enabled)"],"fullName":"compressMessages (enabled) handles mix of messages without crashing","status":"failed","title":"handles mix of messages without crashing","duration":0.20674999999999955,"failureMessages":["TypeError: (0 , __vite_ssr_import_1__.setRtkEnabled) is not a function\n at /Users/Working/router4/app/tests/unit/rtk.test.js:256:33\n at file:///Users/hoanganh/.npm/_npx/69c381f8ad94b576/node_modules/@vitest/runner/dist/chunk-artifact.js:302:11\n at wrapper (file:///Users/hoanganh/.npm/_npx/69c381f8ad94b576/node_modules/@vitest/runner/dist/chunk-artifact.js:722:10)\n at file:///Users/hoanganh/.npm/_npx/69c381f8ad94b576/node_modules/@vitest/runner/dist/chunk-artifact.js:2305:20\n at new Promise ()\n at runWithTimeout (file:///Users/hoanganh/.npm/_npx/69c381f8ad94b576/node_modules/@vitest/runner/dist/chunk-artifact.js:2272:10)\n at file:///Users/hoanganh/.npm/_npx/69c381f8ad94b576/node_modules/@vitest/runner/dist/chunk-artifact.js:2621:52\n at run (file:///Users/hoanganh/.npm/_npx/69c381f8ad94b576/node_modules/@vitest/runner/dist/chunk-artifact.js:1150:20)\n at limiterFn (file:///Users/hoanganh/.npm/_npx/69c381f8ad94b576/node_modules/@vitest/runner/dist/chunk-artifact.js:1162:59)\n at runHook (file:///Users/hoanganh/.npm/_npx/69c381f8ad94b576/node_modules/@vitest/runner/dist/chunk-artifact.js:2620:10)"],"meta":{},"tags":[]},{"ancestorTitles":["formatRtkLog"],"fullName":"formatRtkLog returns null when no hits","status":"passed","title":"returns null when no hits","duration":0.15108300000002828,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["formatRtkLog"],"fullName":"formatRtkLog formats savings line with percentage","status":"passed","title":"formats savings line with percentage","duration":0.10408300000000281,"failureMessages":[],"meta":{},"tags":[]}],"startTime":1781440227160,"endTime":1781440227184.1511,"status":"failed","message":"","name":"/Users/Working/router4/app/tests/unit/rtk.test.js"},{"assertionResults":[{"ancestorTitles":["Kiro format RTK support"],"fullName":"Kiro format RTK support compresses tool results in Kiro conversationState.currentMessage","status":"passed","title":"compresses tool results in Kiro conversationState.currentMessage","duration":6.276417000000009,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["Kiro format RTK support"],"fullName":"Kiro format RTK support compresses tool results in Kiro conversationState.history","status":"passed","title":"compresses tool results in Kiro conversationState.history","duration":1.8280410000000131,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["Kiro format RTK support"],"fullName":"Kiro format RTK support handles multiple tool results across history and currentMessage","status":"passed","title":"handles multiple tool results across history and currentMessage","duration":0.6024590000000103,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["Kiro format RTK support"],"fullName":"Kiro format RTK support preserves error tool results without compression","status":"passed","title":"preserves error tool results without compression","duration":1.308415999999994,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["Kiro format RTK support"],"fullName":"Kiro format RTK support returns null when RTK is disabled","status":"passed","title":"returns null when RTK is disabled","duration":0.2513330000000167,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["Kiro format RTK support"],"fullName":"Kiro format RTK support handles Kiro body with no tool results gracefully","status":"passed","title":"handles Kiro body with no tool results gracefully","duration":0.25404100000000085,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["Kiro format RTK support"],"fullName":"Kiro format RTK support handles malformed Kiro body without crashing","status":"passed","title":"handles malformed Kiro body without crashing","duration":0.33712500000001455,"failureMessages":[],"meta":{},"tags":[]}],"startTime":1781440251171,"endTime":1781440251182.3372,"status":"passed","message":"","name":"/Users/Working/router4/app/tests/unit/rtkKiro.test.js"},{"assertionResults":[{"ancestorTitles":["tokenRefresh dispatch"],"fullName":"tokenRefresh dispatch getAccessToken returns null for missing/invalid refreshToken","status":"passed","title":"getAccessToken returns null for missing/invalid refreshToken","duration":123.53450000000001,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["tokenRefresh dispatch"],"fullName":"tokenRefresh dispatch getAccessToken default: unsupported provider → null","status":"passed","title":"getAccessToken default: unsupported provider → null","duration":0.7868750000000091,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["tokenRefresh dispatch"],"fullName":"tokenRefresh dispatch refreshTokenByProvider returns null without refreshToken","status":"passed","title":"refreshTokenByProvider returns null without refreshToken","duration":0.2071250000000191,"failureMessages":[],"meta":{},"tags":[]}],"startTime":1781440229057,"endTime":1781440229182.207,"status":"passed","message":"","name":"/Users/Working/router4/app/tests/unit/token-refresh-dispatch.test.js"},{"assertionResults":[{"ancestorTitles":["normalizeClaudePassthrough — haiku adaptive thinking (docs 11 §1)"],"fullName":"normalizeClaudePassthrough — haiku adaptive thinking (docs 11 §1) downgrades adaptive thinking to enabled+budget for haiku models","status":"passed","title":"downgrades adaptive thinking to enabled+budget for haiku models","duration":2.80600000000004,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["normalizeClaudePassthrough — haiku adaptive thinking (docs 11 §1)"],"fullName":"normalizeClaudePassthrough — haiku adaptive thinking (docs 11 §1) keeps adaptive thinking for sonnet/opus","status":"passed","title":"keeps adaptive thinking for sonnet/opus","duration":0.6051249999999868,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["normalizeClaudePassthrough — haiku adaptive thinking (docs 11 §1)"],"fullName":"normalizeClaudePassthrough — haiku adaptive thinking (docs 11 §1) hoists mid-conversation system messages into top-level system","status":"passed","title":"hoists mid-conversation system messages into top-level system","duration":0.49212499999998727,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["parseDataUri / encodeDataUri (docs 11 §4)"],"fullName":"parseDataUri / encodeDataUri (docs 11 §4) parses a base64 data uri","status":"passed","title":"parses a base64 data uri","duration":0.4147500000000264,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["parseDataUri / encodeDataUri (docs 11 §4)"],"fullName":"parseDataUri / encodeDataUri (docs 11 §4) tolerates newlines inside base64 payload","status":"passed","title":"tolerates newlines inside base64 payload","duration":0.27804200000002766,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["parseDataUri / encodeDataUri (docs 11 §4)"],"fullName":"parseDataUri / encodeDataUri (docs 11 §4) returns null for http urls and non-strings","status":"passed","title":"returns null for http urls and non-strings","duration":0.3623749999999859,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["parseDataUri / encodeDataUri (docs 11 §4)"],"fullName":"parseDataUri / encodeDataUri (docs 11 §4) encode/parse roundtrip","status":"passed","title":"encode/parse roundtrip","duration":0.4633339999999748,"failureMessages":[],"meta":{},"tags":[]}],"startTime":1781440251181,"endTime":1781440251187.4634,"status":"passed","message":"","name":"/Users/Working/router4/app/tests/unit/translator-helpers-edge.test.js"},{"assertionResults":[{"ancestorTitles":["request normalization"],"fullName":"request normalization claudeToOpenAIRequest flattens text-only content arrays into string","status":"failed","title":"claudeToOpenAIRequest flattens text-only content arrays into string","duration":9.11545799999999,"failureMessages":["AssertionError: expected [ { type: 'text', text: 'hi' }, …(1) ] to be 'hi\\nthere' // Object.is equality\n at /Users/Working/router4/app/tests/unit/translator-request-normalization.test.js:24:40\n at file:///Users/hoanganh/.npm/_npx/69c381f8ad94b576/node_modules/@vitest/runner/dist/chunk-artifact.js:302:11\n at file:///Users/hoanganh/.npm/_npx/69c381f8ad94b576/node_modules/@vitest/runner/dist/chunk-artifact.js:1903:26\n at file:///Users/hoanganh/.npm/_npx/69c381f8ad94b576/node_modules/@vitest/runner/dist/chunk-artifact.js:2326:20\n at new Promise ()\n at runWithCancel (file:///Users/hoanganh/.npm/_npx/69c381f8ad94b576/node_modules/@vitest/runner/dist/chunk-artifact.js:2323:10)\n at file:///Users/hoanganh/.npm/_npx/69c381f8ad94b576/node_modules/@vitest/runner/dist/chunk-artifact.js:2305:20\n at new Promise ()\n at runWithTimeout (file:///Users/hoanganh/.npm/_npx/69c381f8ad94b576/node_modules/@vitest/runner/dist/chunk-artifact.js:2272:10)\n at file:///Users/hoanganh/.npm/_npx/69c381f8ad94b576/node_modules/@vitest/runner/dist/chunk-artifact.js:2955:64"],"meta":{},"tags":[]},{"ancestorTitles":["request normalization"],"fullName":"request normalization claudeToOpenAIRequest preserves multimodal arrays","status":"passed","title":"claudeToOpenAIRequest preserves multimodal arrays","duration":0.3564999999999827,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["request normalization"],"fullName":"request normalization filterToOpenAIFormat flattens text-only arrays to string","status":"failed","title":"filterToOpenAIFormat flattens text-only arrays to string","duration":1.1120829999999842,"failureMessages":["AssertionError: expected [ { type: 'text', text: 'a' }, …(1) ] to be 'a\\nb' // Object.is equality\n at /Users/Working/router4/app/tests/unit/translator-request-normalization.test.js:65:40\n at file:///Users/hoanganh/.npm/_npx/69c381f8ad94b576/node_modules/@vitest/runner/dist/chunk-artifact.js:302:11\n at file:///Users/hoanganh/.npm/_npx/69c381f8ad94b576/node_modules/@vitest/runner/dist/chunk-artifact.js:1903:26\n at file:///Users/hoanganh/.npm/_npx/69c381f8ad94b576/node_modules/@vitest/runner/dist/chunk-artifact.js:2326:20\n at new Promise ()\n at runWithCancel (file:///Users/hoanganh/.npm/_npx/69c381f8ad94b576/node_modules/@vitest/runner/dist/chunk-artifact.js:2323:10)\n at file:///Users/hoanganh/.npm/_npx/69c381f8ad94b576/node_modules/@vitest/runner/dist/chunk-artifact.js:2305:20\n at new Promise ()\n at runWithTimeout (file:///Users/hoanganh/.npm/_npx/69c381f8ad94b576/node_modules/@vitest/runner/dist/chunk-artifact.js:2272:10)\n at file:///Users/hoanganh/.npm/_npx/69c381f8ad94b576/node_modules/@vitest/runner/dist/chunk-artifact.js:2955:64"],"meta":{},"tags":[]},{"ancestorTitles":["request normalization"],"fullName":"request normalization translateRequest keeps /v1/messages Claude->OpenAI text payloads string-safe","status":"failed","title":"translateRequest keeps /v1/messages Claude->OpenAI text payloads string-safe","duration":82.45733300000006,"failureMessages":["AssertionError: expected 'object' to be 'string' // Object.is equality\n at /Users/Working/router4/app/tests/unit/translator-request-normalization.test.js:95:40\n at file:///Users/hoanganh/.npm/_npx/69c381f8ad94b576/node_modules/@vitest/runner/dist/chunk-artifact.js:302:11\n at file:///Users/hoanganh/.npm/_npx/69c381f8ad94b576/node_modules/@vitest/runner/dist/chunk-artifact.js:1903:26\n at file:///Users/hoanganh/.npm/_npx/69c381f8ad94b576/node_modules/@vitest/runner/dist/chunk-artifact.js:2326:20\n at new Promise ()\n at runWithCancel (file:///Users/hoanganh/.npm/_npx/69c381f8ad94b576/node_modules/@vitest/runner/dist/chunk-artifact.js:2323:10)\n at file:///Users/hoanganh/.npm/_npx/69c381f8ad94b576/node_modules/@vitest/runner/dist/chunk-artifact.js:2305:20\n at new Promise ()\n at runWithTimeout (file:///Users/hoanganh/.npm/_npx/69c381f8ad94b576/node_modules/@vitest/runner/dist/chunk-artifact.js:2272:10)\n at file:///Users/hoanganh/.npm/_npx/69c381f8ad94b576/node_modules/@vitest/runner/dist/chunk-artifact.js:2955:64"],"meta":{},"tags":[]},{"ancestorTitles":["request normalization"],"fullName":"request normalization translateRequest strips unsupported Anthropic output_config for MiniMax Claude-compatible endpoints","status":"passed","title":"translateRequest strips unsupported Anthropic output_config for MiniMax Claude-compatible endpoints","duration":0.6045420000000377,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["request normalization"],"fullName":"request normalization translateRequest preserves output_config for Anthropic Claude","status":"passed","title":"translateRequest preserves output_config for Anthropic Claude","duration":0.4295829999999796,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["request normalization"],"fullName":"request normalization parseSSELine supports provider raw NDJSON stream lines","status":"failed","title":"parseSSELine supports provider raw NDJSON stream lines","duration":1.1019999999999754,"failureMessages":["AssertionError: expected null to deeply equal { model: 'gpt-oss:120b', …(2) }\n at /Users/Working/router4/app/tests/unit/translator-request-normalization.test.js:175:20\n at file:///Users/hoanganh/.npm/_npx/69c381f8ad94b576/node_modules/@vitest/runner/dist/chunk-artifact.js:302:11\n at file:///Users/hoanganh/.npm/_npx/69c381f8ad94b576/node_modules/@vitest/runner/dist/chunk-artifact.js:1903:26\n at file:///Users/hoanganh/.npm/_npx/69c381f8ad94b576/node_modules/@vitest/runner/dist/chunk-artifact.js:2326:20\n at new Promise ()\n at runWithCancel (file:///Users/hoanganh/.npm/_npx/69c381f8ad94b576/node_modules/@vitest/runner/dist/chunk-artifact.js:2323:10)\n at file:///Users/hoanganh/.npm/_npx/69c381f8ad94b576/node_modules/@vitest/runner/dist/chunk-artifact.js:2305:20\n at new Promise ()\n at runWithTimeout (file:///Users/hoanganh/.npm/_npx/69c381f8ad94b576/node_modules/@vitest/runner/dist/chunk-artifact.js:2272:10)\n at file:///Users/hoanganh/.npm/_npx/69c381f8ad94b576/node_modules/@vitest/runner/dist/chunk-artifact.js:2955:64"],"meta":{},"tags":[]},{"ancestorTitles":["request normalization"],"fullName":"request normalization parseSSELine still supports SSE data lines","status":"passed","title":"parseSSELine still supports SSE data lines","duration":0.21241699999995944,"failureMessages":[],"meta":{},"tags":[]}],"startTime":1781440227610,"endTime":1781440227705.2124,"status":"failed","message":"","name":"/Users/Working/router4/app/tests/unit/translator-request-normalization.test.js"},{"assertionResults":[{"ancestorTitles":["usage dispatch"],"fullName":"usage dispatch unsupported provider → not-implemented message","status":"passed","title":"unsupported provider → not-implemented message","duration":483.549583,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["usage dispatch"],"fullName":"usage dispatch every supported provider routes to its handler (no fallback message)","status":"passed","title":"every supported provider routes to its handler (no fallback message)","duration":4.657124999999951,"failureMessages":[],"meta":{},"tags":[]}],"startTime":1781440227971,"endTime":1781440228458.6572,"status":"passed","message":"","name":"/Users/Working/router4/app/tests/unit/usage-dispatch.test.js"},{"assertionResults":[{"ancestorTitles":["grok-web validation"],"fullName":"grok-web validation should return valid:true when response is 200","status":"passed","title":"should return valid:true when response is 200","duration":6.615584000000126,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["grok-web validation"],"fullName":"grok-web validation should return valid:true when response is 400 (auth accepted but bad body)","status":"passed","title":"should return valid:true when response is 400 (auth accepted but bad body)","duration":0.7760419999999613,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["grok-web validation"],"fullName":"grok-web validation should return valid:true when response is 429 (rate limited but auth ok)","status":"passed","title":"should return valid:true when response is 429 (rate limited but auth ok)","duration":1.0237499999998363,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["grok-web validation"],"fullName":"grok-web validation should return valid:false with error when response is 401","status":"passed","title":"should return valid:false with error when response is 401","duration":0.5887920000000122,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["grok-web validation"],"fullName":"grok-web validation should return valid:false with error when response is 403","status":"passed","title":"should return valid:false with error when response is 403","duration":0.6776250000000346,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["grok-web validation"],"fullName":"grok-web validation should strip sso= prefix from apiKey","status":"passed","title":"should strip sso= prefix from apiKey","duration":0.4680840000000899,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["grok-web validation"],"fullName":"grok-web validation should accept raw token without sso= prefix","status":"passed","title":"should accept raw token without sso= prefix","duration":0.4289169999999558,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["grok-web validation"],"fullName":"grok-web validation should POST to /rest/app-chat/conversations/new","status":"passed","title":"should POST to /rest/app-chat/conversations/new","duration":2.6224580000000515,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["grok-web validation"],"fullName":"grok-web validation should send Cloudflare-bypass headers","status":"passed","title":"should send Cloudflare-bypass headers","duration":1.7336249999998472,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["perplexity-web validation"],"fullName":"perplexity-web validation should return valid:true when response is 200","status":"passed","title":"should return valid:true when response is 200","duration":0.44954200000006495,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["perplexity-web validation"],"fullName":"perplexity-web validation should return valid:false when response is 401","status":"passed","title":"should return valid:false when response is 401","duration":0.38066600000001927,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["perplexity-web validation"],"fullName":"perplexity-web validation should return valid:false when response is 403","status":"passed","title":"should return valid:false when response is 403","duration":0.16137499999990723,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["perplexity-web validation"],"fullName":"perplexity-web validation should strip __Secure-next-auth.session-token= prefix","status":"passed","title":"should strip __Secure-next-auth.session-token= prefix","duration":0.15383399999996072,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["perplexity-web validation"],"fullName":"perplexity-web validation should accept raw token without prefix","status":"passed","title":"should accept raw token without prefix","duration":0.141208000000006,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["perplexity-web validation"],"fullName":"perplexity-web validation should POST to /rest/sse/perplexity_ask","status":"passed","title":"should POST to /rest/sse/perplexity_ask","duration":0.5736250000002201,"failureMessages":[],"meta":{},"tags":[]}],"startTime":1781440250645,"endTime":1781440250662.5737,"status":"passed","message":"","name":"/Users/Working/router4/app/tests/unit/web-cookie-validation.test.js"},{"assertionResults":[{"ancestorTitles":["xai/oauth service"],"fullName":"xai/oauth service validates discovered endpoints are https x.ai URLs","status":"passed","title":"validates discovered endpoints are https x.ai URLs","duration":232.925833,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["xai/oauth service"],"fullName":"xai/oauth service discovers endpoints without custom user-agent headers","status":"passed","title":"discovers endpoints without custom user-agent headers","duration":17.018583999999976,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["xai/oauth service"],"fullName":"xai/oauth service builds authorize URLs with CLIProxyAPI query extras","status":"passed","title":"builds authorize URLs with CLIProxyAPI query extras","duration":11.618208999999979,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["xai/oauth service"],"fullName":"xai/oauth service generates dashboard auth data with CLIProxyAPI PKCE size and discovered endpoints","status":"passed","title":"generates dashboard auth data with CLIProxyAPI PKCE size and discovered endpoints","duration":1139.999917,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["xai/oauth service"],"fullName":"xai/oauth service exchanges dashboard codes against the discovered xAI token endpoint","status":"passed","title":"exchanges dashboard codes against the discovered xAI token endpoint","duration":72.91116699999998,"failureMessages":[],"meta":{},"tags":[]}],"startTime":1781440227386,"endTime":1781440228860.9111,"status":"passed","message":"","name":"/Users/Working/router4/app/tests/unit/xai-oauth-service.test.js"},{"assertionResults":[{"ancestorTitles":["xai/token-refresh wrapper"],"fullName":"xai/token-refresh wrapper refreshXaiToken module loads without throwing","status":"passed","title":"refreshXaiToken module loads without throwing","duration":101.22454199999999,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["xai/token-refresh wrapper"],"fullName":"xai/token-refresh wrapper formatProviderCredentials returns Bearer-shape for xai","status":"passed","title":"formatProviderCredentials returns Bearer-shape for xai","duration":1.1181659999999738,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["xai/token-refresh wrapper"],"fullName":"xai/token-refresh wrapper refreshTokenByProvider returns null when refreshToken missing","status":"passed","title":"refreshTokenByProvider returns null when refreshToken missing","duration":0.23620800000003328,"failureMessages":[],"meta":{},"tags":[]},{"ancestorTitles":["xai/token-refresh wrapper"],"fullName":"xai/token-refresh wrapper refreshTokenByProvider returns expiresIn for refreshed xai tokens","status":"passed","title":"refreshTokenByProvider returns expiresIn for refreshed xai tokens","duration":14.37462499999998,"failureMessages":[],"meta":{},"tags":[]}],"startTime":1781440228712,"endTime":1781440228829.3745,"status":"passed","message":"","name":"/Users/Working/router4/app/tests/unit/xai-tokenRefresh.test.js"},{"assertionResults":[{"ancestorTitles":["REAL provider smoke"],"fullName":"REAL provider smoke has active providers in DB","status":"skipped","title":"has active providers in DB","failureMessages":[],"meta":{},"tags":[]}],"startTime":1781440226639,"endTime":1781440226639,"status":"passed","message":"","name":"/Users/Working/router4/app/tests/translator/real/smoke-providers.real.test.js"}]}