diff --git a/UPSTREAM_SYNC.md b/UPSTREAM_SYNC.md index 94d4e56..0aea569 100644 --- a/UPSTREAM_SYNC.md +++ b/UPSTREAM_SYNC.md @@ -30,6 +30,51 @@ These upstream areas are excluded (TS/npm-specific): ## Sync Log +### 2026-10-22 - Post-merge local runtime acceptance + +- Owner: Codex, branch `codex/smoke-upstream-20261022`. +- Revision under test: merged main `422774fe3ba3d94c3e9be2e7082945ed54222770`. +- Outcome: verify the actual standalone CLI process over HTTP and a browser. +- Scope: DOSRouter test harness and evidence; isolated localhost gateway and + synthetic state only. No provider charge, credentials or remote rollout. +- Acceptance: binary revision/hash, startup catalog refresh, explicit model + and free aliases, fallback/outcomes, streaming, spend admission, local trust, + clean shutdown and browser readback with machine-readable evidence. +- Environment discovery: GitHub environments list is empty; the current + process has no DOSROUTER_UPSTREAM, DOSROUTER_PORT or DOSROUTER_API_KEY. + Historical npm/Docker plans do not describe this standalone Go runtime. +- Completed: clean-source Go 1.26.10 binary, SHA-256 + `5bd95979b1176002133def84734e3b98cd6d70cb107d58627ffb00cede9f7a27`; + all 18 process scenarios passed. The real refresh intervals were 300011 + and 300012 ms; invalid startup recovered and invalid updates retained the + last good catalog. MCP Playwright verified same-origin health, model list + and chat, plus cross-site HTTP 403. All three CLI processes exited and + their ports closed. Report rendering passed desktop and 390px checks. +- Driver correction: Node fetch ignored a forged Host override. The original + failed observation remains recorded; literal raw HTTP against the same + binary returned four HTTP 403 responses with zero gateway sends. The fixed + harness then passed a separate full 18-scenario run without corrections. +- Independent review found two harness gaps: late SIGINT registration and a + vacuously true reasoning assertion. Both were fixed. A focused final-source + probe passed 16 immediate scenarios, preserved the exact assistant message + and model, and confirmed owned-process shutdown on Ctrl+C during the timer + wait. It makes no claim for the interrupted refresh scenario. +- CodeRabbit's subsequent review added browser-proof correlation and cleanup + on a failed concurrency assertion. The finish endpoint now rejects missing + gateway-chat evidence or mismatched browser fields; the renderer checks the + correlation too. An injected unexpected concurrency response still releases + and settles the held request. A final-source process probe passed all 16 + immediate scenarios and interrupt shutdown. External MCP browser observations + remain operator attestations, with gateway chat independently correlated. +- Evidence: [Vietnamese report](docs/validation/2026-10-22/upstream-smoke.html), + [initial run and correction](docs/validation/2026-10-22/upstream-smoke.json), + [full rerun and final-source probes](docs/validation/2026-10-22/harness-recheck.json) + [failure-path and final delta probes](docs/validation/2026-10-22/harness-failure-probes.json) + and [report browser readback](docs/validation/2026-10-22/report-browser.json). +- Remaining boundary: remote staging, paid-provider behavior and deployment + remain unverified because no target environment is configured or authorized. + No product source change was needed for the process acceptance. + ### 2026-10-22 - Sync through 0.12.297 source Owner: Codex, branch `codex/sync-clawrouter-20261022`. Compared the previous diff --git a/docs/validation/2026-10-22/harness-failure-probes.json b/docs/validation/2026-10-22/harness-failure-probes.json new file mode 100644 index 0000000..58d315f --- /dev/null +++ b/docs/validation/2026-10-22/harness-failure-probes.json @@ -0,0 +1,388 @@ +{ + "recordedAt": "2026-10-22T14:55:40.794Z", + "browserWithoutGatewayChat": "rejected", + "browserWrongRevision": "rejected", + "rendererWithoutGatewayChat": "not passed", + "recordedBrowserChat": "accepted with gateway correlation", + "concurrencySecondUnexpected200": { + "heldReleasedOnce": true, + "firstSettled": true, + "assertionFailurePreserved": true + }, + "finalSourceProcessProbe": { + "recordedAt": "2026-10-22T14:56:38.234Z", + "revision": "422774fe3ba3d94c3e9be2e7082945ed54222770", + "binarySha256": "5bd95979b1176002133def84734e3b98cd6d70cb107d58627ffb00cede9f7a27", + "harnessSourceSha256": "0f12761cf69b952bd4de2012a096764add2d86fc20d7f33e87914f4e940a0a15", + "browserProofSourceSha256": "b325c2b5410ede738bec3df44a71013089043f6fb5ec556467fdd651350898aa", + "checks": [ + { + "id": "health", + "label": "Health và revision của tiến trình CLI", + "pass": true, + "durationMs": 1, + "details": { + "gateway": "http://127.0.0.1:63336", + "journalEntries": 0, + "journalSessions": 0, + "sessions": 0, + "spendControl": { + "perRequest": { + "limit": 0.05, + "spent": 0, + "remaining": 0.05 + }, + "session": { + "limit": 10, + "spent": 0, + "remaining": 10 + } + }, + "status": "ok", + "version": "422774f" + } + }, + { + "id": "startup-catalog", + "label": "Catalog mới tự nạp khi khởi động", + "pass": true, + "durationMs": 5, + "details": { + "reads": 1, + "modelVisible": true + } + }, + { + "id": "invalid-startup", + "label": "Catalog lỗi giữ bản đóng gói", + "pass": true, + "durationMs": 17, + "details": { + "bundledFallback": true + } + }, + { + "id": "reasoning", + "label": "Model reasoning mới chuyển tiếp đúng metadata", + "pass": true, + "durationMs": 17, + "details": { + "status": 200, + "trace": [ + { + "gateway": "stable", + "tag": "reasoning", + "model": "fixture/reasoner", + "sequence": 1, + "status": 200, + "assistantCount": 1, + "assistantContents": [ + "hello" + ], + "reasoningNormalized": true + } + ] + } + }, + { + "id": "free-alias", + "label": "Alias miễn phí không thành model trả phí", + "pass": true, + "durationMs": 12, + "details": [ + { + "gateway": "stable", + "tag": "free-alias", + "model": "free/nemotron-3.5-lightning", + "sequence": 1, + "status": 200, + "assistantCount": 0, + "assistantContents": [], + "reasoningNormalized": false + } + ] + }, + { + "id": "outcome-memory", + "label": "Model lỗi lặp lại được chuyển xuống cuối", + "pass": true, + "durationMs": 47, + "details": [ + { + "gateway": "stable", + "tag": "repeat-failure-0", + "model": "google/gemini-2.5-flash", + "sequence": 1, + "status": 502, + "assistantCount": 0, + "assistantContents": [], + "reasoningNormalized": false + }, + { + "gateway": "stable", + "tag": "repeat-failure-0", + "model": "google/gemini-3-flash-preview", + "sequence": 2, + "status": 200, + "assistantCount": 0, + "assistantContents": [], + "reasoningNormalized": false + }, + { + "gateway": "stable", + "tag": "repeat-failure-1", + "model": "google/gemini-2.5-flash", + "sequence": 1, + "status": 502, + "assistantCount": 0, + "assistantContents": [], + "reasoningNormalized": false + }, + { + "gateway": "stable", + "tag": "repeat-failure-1", + "model": "google/gemini-3-flash-preview", + "sequence": 2, + "status": 200, + "assistantCount": 0, + "assistantContents": [], + "reasoningNormalized": false + }, + { + "gateway": "stable", + "tag": "repeat-failure-2", + "model": "google/gemini-2.5-flash", + "sequence": 1, + "status": 502, + "assistantCount": 0, + "assistantContents": [], + "reasoningNormalized": false + }, + { + "gateway": "stable", + "tag": "repeat-failure-2", + "model": "google/gemini-3-flash-preview", + "sequence": 2, + "status": 200, + "assistantCount": 0, + "assistantContents": [], + "reasoningNormalized": false + }, + { + "gateway": "stable", + "tag": "repeat-failure-3", + "model": "google/gemini-3-flash-preview", + "sequence": 1, + "status": 200, + "assistantCount": 0, + "assistantContents": [], + "reasoningNormalized": false + } + ] + }, + { + "id": "empty-chain", + "label": "Phản hồi rỗng tiếp tục tới model có kết quả", + "pass": true, + "durationMs": 15, + "details": [ + { + "gateway": "stable", + "tag": "empty-chain", + "model": "google/gemini-3.5-flash", + "sequence": 1, + "status": 200, + "assistantCount": 0, + "assistantContents": [], + "reasoningNormalized": false + }, + { + "gateway": "stable", + "tag": "empty-chain", + "model": "google/gemini-3.6-flash", + "sequence": 2, + "status": 200, + "assistantCount": 0, + "assistantContents": [], + "reasoningNormalized": false + }, + { + "gateway": "stable", + "tag": "empty-chain", + "model": "anthropic/claude-haiku-4.5", + "sequence": 3, + "status": 200, + "assistantCount": 0, + "assistantContents": [], + "reasoningNormalized": false + } + ] + }, + { + "id": "attempt-cap", + "label": "Chuỗi lỗi dừng sau tối đa 5 model", + "pass": true, + "durationMs": 20, + "details": [ + { + "gateway": "stable", + "tag": "all-fail", + "model": "google/gemini-3.5-flash", + "sequence": 1, + "status": 502, + "assistantCount": 0, + "assistantContents": [], + "reasoningNormalized": false + }, + { + "gateway": "stable", + "tag": "all-fail", + "model": "google/gemini-3.6-flash", + "sequence": 2, + "status": 502, + "assistantCount": 0, + "assistantContents": [], + "reasoningNormalized": false + }, + { + "gateway": "stable", + "tag": "all-fail", + "model": "anthropic/claude-haiku-4.5", + "sequence": 3, + "status": 502, + "assistantCount": 0, + "assistantContents": [], + "reasoningNormalized": false + }, + { + "gateway": "stable", + "tag": "all-fail", + "model": "zai/glm-5.3", + "sequence": 4, + "status": 502, + "assistantCount": 0, + "assistantContents": [], + "reasoningNormalized": false + }, + { + "gateway": "stable", + "tag": "all-fail", + "model": "google/gemini-3.5-flash-lite", + "sequence": 5, + "status": 502, + "assistantCount": 0, + "assistantContents": [], + "reasoningNormalized": false + } + ] + }, + { + "id": "explicit-pin", + "label": "Model chỉ định không bị thay bằng fallback", + "pass": true, + "durationMs": 15, + "details": [ + { + "gateway": "stable", + "tag": "explicit-pin-fails", + "model": "openai/gpt-4o-mini", + "sequence": 1, + "status": 502, + "assistantCount": 0, + "assistantContents": [], + "reasoningNormalized": false + } + ] + }, + { + "id": "lost-send", + "label": "Mất phản hồi không làm gửi lại request", + "pass": true, + "durationMs": 14, + "details": [ + { + "gateway": "stable", + "tag": "lost-response", + "model": "google/gemini-3-flash-preview", + "sequence": 1, + "status": "socket-closed", + "assistantCount": 0, + "assistantContents": [], + "reasoningNormalized": false + } + ] + }, + { + "id": "stream", + "label": "SSE giữ nội dung và dấu kết thúc", + "pass": true, + "durationMs": 13, + "details": { + "status": 200, + "done": true + } + }, + { + "id": "expensive-admission", + "label": "Giá cao bị chặn trước khi gửi", + "pass": true, + "durationMs": 9, + "details": { + "status": 429, + "upstreamSends": 0 + } + }, + { + "id": "zero-flat", + "label": "Giá cố định bằng 0 không vượt spend limit", + "pass": true, + "durationMs": 13, + "details": { + "status": 429, + "upstreamSends": 0 + } + }, + { + "id": "local-trust", + "label": "Host và Origin không tin cậy bị từ chối", + "pass": true, + "durationMs": 6, + "details": { + "statuses": [ + 403, + 403, + 403, + 403 + ], + "upstreamSends": 0 + } + }, + { + "id": "cjk", + "label": "Prompt CJK dài được nâng tier theo số token", + "pass": true, + "durationMs": 22, + "details": { + "tier": "COMPLEX", + "reason": "Input exceeds 100000 tokens" + } + }, + { + "id": "concurrency", + "label": "Reservation đồng thời và settlement trả lại ngân sách", + "pass": true, + "durationMs": 46, + "details": { + "first": 200, + "whileInFlight": 429, + "afterSettlement": 200 + } + } + ], + "shutdown": { + "allOwnedProcessesExited": true, + "portsClosed": true + }, + "interruption": "Intentional Ctrl+C during refresh wait; terminal exit 1. Timer result not claimed." + } +} diff --git a/docs/validation/2026-10-22/harness-recheck.json b/docs/validation/2026-10-22/harness-recheck.json new file mode 100644 index 0000000..11c755c --- /dev/null +++ b/docs/validation/2026-10-22/harness-recheck.json @@ -0,0 +1,783 @@ +{ + "recordedAt": "2026-10-22T14:49:09.666Z", + "revision": "422774fe3ba3d94c3e9be2e7082945ed54222770", + "binarySha256": "5bd95979b1176002133def84734e3b98cd6d70cb107d58627ffb00cede9f7a27", + "fullSuite": { + "harnessCommit": "6eb201b05c29c37d9f50155e06f6285442ff1d7a", + "harnessSourceSha256": "c5a18ef8df443f753578bc556451c2991e122ba7d6f4b36300e0988922c4af29", + "startedAt": "2026-10-22T14:42:39.802Z", + "finishedAt": "2026-10-22T14:47:40.090Z", + "checks": [ + { + "id": "health", + "label": "Health và revision của tiến trình CLI", + "pass": true, + "durationMs": 3, + "details": { + "gateway": "http://127.0.0.1:59966", + "journalEntries": 0, + "journalSessions": 0, + "sessions": 0, + "spendControl": { + "perRequest": { + "limit": 0.05, + "spent": 0, + "remaining": 0.05 + }, + "session": { + "limit": 10, + "spent": 0, + "remaining": 10 + } + }, + "status": "ok", + "version": "422774f" + } + }, + { + "id": "startup-catalog", + "label": "Catalog mới tự nạp khi khởi động", + "pass": true, + "durationMs": 6, + "details": { + "reads": 1, + "modelVisible": true + } + }, + { + "id": "invalid-startup", + "label": "Catalog lỗi giữ bản đóng gói", + "pass": true, + "durationMs": 16, + "details": { + "bundledFallback": true + } + }, + { + "id": "reasoning", + "label": "Model reasoning mới chuyển tiếp đúng metadata", + "pass": true, + "durationMs": 8, + "details": { + "status": 200, + "trace": [ + { + "gateway": "stable", + "tag": "reasoning", + "model": "fixture/reasoner", + "sequence": 1, + "status": 200, + "reasoningNormalized": true + } + ] + } + }, + { + "id": "free-alias", + "label": "Alias miễn phí không thành model trả phí", + "pass": true, + "durationMs": 8, + "details": [ + { + "gateway": "stable", + "tag": "free-alias", + "model": "free/nemotron-3.5-lightning", + "sequence": 1, + "status": 200, + "reasoningNormalized": true + } + ] + }, + { + "id": "outcome-memory", + "label": "Model lỗi lặp lại được chuyển xuống cuối", + "pass": true, + "durationMs": 60, + "details": [ + { + "gateway": "stable", + "tag": "repeat-failure-0", + "model": "google/gemini-2.5-flash", + "sequence": 1, + "status": 502, + "reasoningNormalized": true + }, + { + "gateway": "stable", + "tag": "repeat-failure-0", + "model": "google/gemini-3-flash-preview", + "sequence": 2, + "status": 200, + "reasoningNormalized": true + }, + { + "gateway": "stable", + "tag": "repeat-failure-1", + "model": "google/gemini-2.5-flash", + "sequence": 1, + "status": 502, + "reasoningNormalized": true + }, + { + "gateway": "stable", + "tag": "repeat-failure-1", + "model": "google/gemini-3-flash-preview", + "sequence": 2, + "status": 200, + "reasoningNormalized": true + }, + { + "gateway": "stable", + "tag": "repeat-failure-2", + "model": "google/gemini-2.5-flash", + "sequence": 1, + "status": 502, + "reasoningNormalized": true + }, + { + "gateway": "stable", + "tag": "repeat-failure-2", + "model": "google/gemini-3-flash-preview", + "sequence": 2, + "status": 200, + "reasoningNormalized": true + }, + { + "gateway": "stable", + "tag": "repeat-failure-3", + "model": "google/gemini-3-flash-preview", + "sequence": 1, + "status": 200, + "reasoningNormalized": true + } + ] + }, + { + "id": "empty-chain", + "label": "Phản hồi rỗng tiếp tục tới model có kết quả", + "pass": true, + "durationMs": 20, + "details": [ + { + "gateway": "stable", + "tag": "empty-chain", + "model": "google/gemini-3.5-flash", + "sequence": 1, + "status": 200, + "reasoningNormalized": true + }, + { + "gateway": "stable", + "tag": "empty-chain", + "model": "google/gemini-3.6-flash", + "sequence": 2, + "status": 200, + "reasoningNormalized": true + }, + { + "gateway": "stable", + "tag": "empty-chain", + "model": "anthropic/claude-haiku-4.5", + "sequence": 3, + "status": 200, + "reasoningNormalized": true + } + ] + }, + { + "id": "attempt-cap", + "label": "Chuỗi lỗi dừng sau tối đa 5 model", + "pass": true, + "durationMs": 20, + "details": [ + { + "gateway": "stable", + "tag": "all-fail", + "model": "google/gemini-3.5-flash", + "sequence": 1, + "status": 502, + "reasoningNormalized": true + }, + { + "gateway": "stable", + "tag": "all-fail", + "model": "google/gemini-3.6-flash", + "sequence": 2, + "status": 502, + "reasoningNormalized": true + }, + { + "gateway": "stable", + "tag": "all-fail", + "model": "anthropic/claude-haiku-4.5", + "sequence": 3, + "status": 502, + "reasoningNormalized": true + }, + { + "gateway": "stable", + "tag": "all-fail", + "model": "zai/glm-5.3", + "sequence": 4, + "status": 502, + "reasoningNormalized": true + }, + { + "gateway": "stable", + "tag": "all-fail", + "model": "google/gemini-3.5-flash-lite", + "sequence": 5, + "status": 502, + "reasoningNormalized": true + } + ] + }, + { + "id": "explicit-pin", + "label": "Model chỉ định không bị thay bằng fallback", + "pass": true, + "durationMs": 17, + "details": [ + { + "gateway": "stable", + "tag": "explicit-pin-fails", + "model": "openai/gpt-4o-mini", + "sequence": 1, + "status": 502, + "reasoningNormalized": true + } + ] + }, + { + "id": "lost-send", + "label": "Mất phản hồi không làm gửi lại request", + "pass": true, + "durationMs": 15, + "details": [ + { + "gateway": "stable", + "tag": "lost-response", + "model": "google/gemini-3-flash-preview", + "sequence": 1, + "status": "socket-closed", + "reasoningNormalized": true + } + ] + }, + { + "id": "stream", + "label": "SSE giữ nội dung và dấu kết thúc", + "pass": true, + "durationMs": 15, + "details": { + "status": 200, + "done": true + } + }, + { + "id": "expensive-admission", + "label": "Giá cao bị chặn trước khi gửi", + "pass": true, + "durationMs": 10, + "details": { + "status": 429, + "upstreamSends": 0 + } + }, + { + "id": "zero-flat", + "label": "Giá cố định bằng 0 không vượt spend limit", + "pass": true, + "durationMs": 14, + "details": { + "status": 429, + "upstreamSends": 0 + } + }, + { + "id": "local-trust", + "label": "Host và Origin không tin cậy bị từ chối", + "pass": true, + "durationMs": 5, + "details": { + "statuses": [ + 403, + 403, + 403, + 403 + ], + "upstreamSends": 0 + } + }, + { + "id": "cjk", + "label": "Prompt CJK dài được nâng tier theo số token", + "pass": true, + "durationMs": 28, + "details": { + "tier": "COMPLEX", + "reason": "Input exceeds 100000 tokens" + } + }, + { + "id": "concurrency", + "label": "Reservation đồng thời và settlement trả lại ngân sách", + "pass": true, + "durationMs": 43, + "details": { + "first": 200, + "whileInFlight": 429, + "afterSettlement": 200 + } + }, + { + "id": "scheduled-refresh", + "label": "Refresh 5 phút và phục hồi catalog", + "pass": true, + "durationMs": 299512, + "details": { + "intervals": [ + { + "gateway": "stable", + "intervalMs": 300023 + }, + { + "gateway": "recovery", + "intervalMs": 300023 + } + ], + "lastGoodRetained": true, + "recoveredFromInvalidStartup": true + } + }, + { + "id": "isolated-state", + "label": "Accounting chỉ ghi vào thư mục thử nghiệm", + "pass": true, + "durationMs": 1, + "details": { + "isolatedProfiles": 3, + "historyCounts": [ + 20, + 0, + 2 + ], + "syntheticOnly": true + } + } + ], + "catalogReads": [ + { + "gateway": "stable", + "count": 1, + "at": "2026-10-22T14:42:39.877Z", + "mode": "valid" + }, + { + "gateway": "recovery", + "count": 1, + "at": "2026-10-22T14:42:40.026Z", + "mode": "invalid" + }, + { + "gateway": "concurrency", + "count": 1, + "at": "2026-10-22T14:42:40.153Z", + "mode": "valid" + }, + { + "gateway": "stable", + "count": 2, + "at": "2026-10-22T14:47:39.900Z", + "mode": "invalid" + }, + { + "gateway": "recovery", + "count": 2, + "at": "2026-10-22T14:47:40.049Z", + "mode": "valid" + } + ], + "shutdown": { + "allOwnedProcessesExited": true, + "portsClosed": true + } + }, + "focusedDelta": { + "harnessSourceSha256": "bc234550786661cb32a1f03b2fb443822761de9a68f6d4bbd833a3e5500c71ba", + "startedAt": "2026-10-22T14:47:44.995Z", + "checks": [ + { + "id": "health", + "label": "Health và revision của tiến trình CLI", + "pass": true, + "durationMs": 2, + "details": { + "gateway": "http://127.0.0.1:64752", + "journalEntries": 0, + "journalSessions": 0, + "sessions": 0, + "spendControl": { + "perRequest": { + "limit": 0.05, + "spent": 0, + "remaining": 0.05 + }, + "session": { + "limit": 10, + "spent": 0, + "remaining": 10 + } + }, + "status": "ok", + "version": "422774f" + } + }, + { + "id": "startup-catalog", + "label": "Catalog mới tự nạp khi khởi động", + "pass": true, + "durationMs": 6, + "details": { + "reads": 1, + "modelVisible": true + } + }, + { + "id": "invalid-startup", + "label": "Catalog lỗi giữ bản đóng gói", + "pass": true, + "durationMs": 17, + "details": { + "bundledFallback": true + } + }, + { + "id": "reasoning", + "label": "Model reasoning mới chuyển tiếp đúng metadata", + "pass": true, + "durationMs": 18, + "details": { + "status": 200, + "trace": [ + { + "gateway": "stable", + "tag": "reasoning", + "model": "fixture/reasoner", + "sequence": 1, + "status": 200, + "assistantCount": 1, + "assistantContents": [ + "hello" + ], + "reasoningNormalized": true + } + ] + } + }, + { + "id": "free-alias", + "label": "Alias miễn phí không thành model trả phí", + "pass": true, + "durationMs": 8, + "details": [ + { + "gateway": "stable", + "tag": "free-alias", + "model": "free/nemotron-3.5-lightning", + "sequence": 1, + "status": 200, + "assistantCount": 0, + "assistantContents": [], + "reasoningNormalized": false + } + ] + }, + { + "id": "outcome-memory", + "label": "Model lỗi lặp lại được chuyển xuống cuối", + "pass": true, + "durationMs": 60, + "details": [ + { + "gateway": "stable", + "tag": "repeat-failure-0", + "model": "google/gemini-2.5-flash", + "sequence": 1, + "status": 502, + "assistantCount": 0, + "assistantContents": [], + "reasoningNormalized": false + }, + { + "gateway": "stable", + "tag": "repeat-failure-0", + "model": "google/gemini-3-flash-preview", + "sequence": 2, + "status": 200, + "assistantCount": 0, + "assistantContents": [], + "reasoningNormalized": false + }, + { + "gateway": "stable", + "tag": "repeat-failure-1", + "model": "google/gemini-2.5-flash", + "sequence": 1, + "status": 502, + "assistantCount": 0, + "assistantContents": [], + "reasoningNormalized": false + }, + { + "gateway": "stable", + "tag": "repeat-failure-1", + "model": "google/gemini-3-flash-preview", + "sequence": 2, + "status": 200, + "assistantCount": 0, + "assistantContents": [], + "reasoningNormalized": false + }, + { + "gateway": "stable", + "tag": "repeat-failure-2", + "model": "google/gemini-2.5-flash", + "sequence": 1, + "status": 502, + "assistantCount": 0, + "assistantContents": [], + "reasoningNormalized": false + }, + { + "gateway": "stable", + "tag": "repeat-failure-2", + "model": "google/gemini-3-flash-preview", + "sequence": 2, + "status": 200, + "assistantCount": 0, + "assistantContents": [], + "reasoningNormalized": false + }, + { + "gateway": "stable", + "tag": "repeat-failure-3", + "model": "google/gemini-3-flash-preview", + "sequence": 1, + "status": 200, + "assistantCount": 0, + "assistantContents": [], + "reasoningNormalized": false + } + ] + }, + { + "id": "empty-chain", + "label": "Phản hồi rỗng tiếp tục tới model có kết quả", + "pass": true, + "durationMs": 11, + "details": [ + { + "gateway": "stable", + "tag": "empty-chain", + "model": "google/gemini-3.5-flash", + "sequence": 1, + "status": 200, + "assistantCount": 0, + "assistantContents": [], + "reasoningNormalized": false + }, + { + "gateway": "stable", + "tag": "empty-chain", + "model": "google/gemini-3.6-flash", + "sequence": 2, + "status": 200, + "assistantCount": 0, + "assistantContents": [], + "reasoningNormalized": false + }, + { + "gateway": "stable", + "tag": "empty-chain", + "model": "anthropic/claude-haiku-4.5", + "sequence": 3, + "status": 200, + "assistantCount": 0, + "assistantContents": [], + "reasoningNormalized": false + } + ] + }, + { + "id": "attempt-cap", + "label": "Chuỗi lỗi dừng sau tối đa 5 model", + "pass": true, + "durationMs": 29, + "details": [ + { + "gateway": "stable", + "tag": "all-fail", + "model": "google/gemini-3.5-flash", + "sequence": 1, + "status": 502, + "assistantCount": 0, + "assistantContents": [], + "reasoningNormalized": false + }, + { + "gateway": "stable", + "tag": "all-fail", + "model": "google/gemini-3.6-flash", + "sequence": 2, + "status": 502, + "assistantCount": 0, + "assistantContents": [], + "reasoningNormalized": false + }, + { + "gateway": "stable", + "tag": "all-fail", + "model": "anthropic/claude-haiku-4.5", + "sequence": 3, + "status": 502, + "assistantCount": 0, + "assistantContents": [], + "reasoningNormalized": false + }, + { + "gateway": "stable", + "tag": "all-fail", + "model": "zai/glm-5.3", + "sequence": 4, + "status": 502, + "assistantCount": 0, + "assistantContents": [], + "reasoningNormalized": false + }, + { + "gateway": "stable", + "tag": "all-fail", + "model": "google/gemini-3.5-flash-lite", + "sequence": 5, + "status": 502, + "assistantCount": 0, + "assistantContents": [], + "reasoningNormalized": false + } + ] + }, + { + "id": "explicit-pin", + "label": "Model chỉ định không bị thay bằng fallback", + "pass": true, + "durationMs": 16, + "details": [ + { + "gateway": "stable", + "tag": "explicit-pin-fails", + "model": "openai/gpt-4o-mini", + "sequence": 1, + "status": 502, + "assistantCount": 0, + "assistantContents": [], + "reasoningNormalized": false + } + ] + }, + { + "id": "lost-send", + "label": "Mất phản hồi không làm gửi lại request", + "pass": true, + "durationMs": 15, + "details": [ + { + "gateway": "stable", + "tag": "lost-response", + "model": "google/gemini-3-flash-preview", + "sequence": 1, + "status": "socket-closed", + "assistantCount": 0, + "assistantContents": [], + "reasoningNormalized": false + } + ] + }, + { + "id": "stream", + "label": "SSE giữ nội dung và dấu kết thúc", + "pass": true, + "durationMs": 14, + "details": { + "status": 200, + "done": true + } + }, + { + "id": "expensive-admission", + "label": "Giá cao bị chặn trước khi gửi", + "pass": true, + "durationMs": 9, + "details": { + "status": 429, + "upstreamSends": 0 + } + }, + { + "id": "zero-flat", + "label": "Giá cố định bằng 0 không vượt spend limit", + "pass": true, + "durationMs": 14, + "details": { + "status": 429, + "upstreamSends": 0 + } + }, + { + "id": "local-trust", + "label": "Host và Origin không tin cậy bị từ chối", + "pass": true, + "durationMs": 5, + "details": { + "statuses": [ + 403, + 403, + 403, + 403 + ], + "upstreamSends": 0 + } + }, + { + "id": "cjk", + "label": "Prompt CJK dài được nâng tier theo số token", + "pass": true, + "durationMs": 21, + "details": { + "tier": "COMPLEX", + "reason": "Input exceeds 100000 tokens" + } + }, + { + "id": "concurrency", + "label": "Reservation đồng thời và settlement trả lại ngân sách", + "pass": true, + "durationMs": 48, + "details": { + "first": 200, + "whileInFlight": 429, + "afterSettlement": 200 + } + } + ], + "shutdown": { + "allOwnedProcessesExited": true, + "portsClosed": true + }, + "interruption": { + "method": "Ctrl+C sent to owned PTY while waiting for the first scheduled refresh", + "terminalExitCode": 1, + "note": "PowerShell PTY reported exit 1 after interruption; successful cleanup is established separately by saved process and port evidence. No scheduled-refresh result is claimed for this interrupted probe." + } + } +} diff --git a/docs/validation/2026-10-22/host-origin-probe.json b/docs/validation/2026-10-22/host-origin-probe.json new file mode 100644 index 0000000..17ef5d0 --- /dev/null +++ b/docs/validation/2026-10-22/host-origin-probe.json @@ -0,0 +1,34 @@ +{ + "checkedAt": "2026-10-22T14:32:04.813Z", + "revision": "422774fe3ba3d94c3e9be2e7082945ed54222770", + "binarySha256": "5bd95979b1176002133def84734e3b98cd6d70cb107d58627ffb00cede9f7a27", + "transport": "node:http sends the literal Host header", + "originalDriverIssue": "Node fetch ignored the overridden Host header and sent the loopback host; its 429 was a driver error, not a guard failure.", + "results": [ + { + "headers": { + "Origin": "https://attacker.invalid" + }, + "status": 403 + }, + { + "headers": { + "Origin": "null" + }, + "status": 403 + }, + { + "headers": { + "Host": "attacker.invalid" + }, + "status": 403 + }, + { + "headers": { + "Sec-Fetch-Site": "cross-site" + }, + "status": 403 + } + ], + "upstreamSends": 0 +} diff --git a/docs/validation/2026-10-22/report-browser.json b/docs/validation/2026-10-22/report-browser.json new file mode 100644 index 0000000..528fcae --- /dev/null +++ b/docs/validation/2026-10-22/report-browser.json @@ -0,0 +1,22 @@ +{ + "driver": "MCP Playwright", + "desktop": { + "language": "vi", + "passCount": "18/18", + "rows": 18, + "failures": 0, + "background": "rgb(16, 16, 20)", + "red": "rgb(255, 76, 87)", + "jsonStatus": 200, + "jsonChecks": 18, + "jsonAllPass": true, + "overflow": false + }, + "mobile": { + "width": 390, + "scrollWidth": 375, + "overflow": false + }, + "note": "Report and linked JSON inspected through temporary localhost HTTP. Link checked using browser fetch after native click timed out.", + "recordedAt": "2026-10-22T14:45:15.397Z" +} diff --git a/docs/validation/2026-10-22/upstream-smoke.html b/docs/validation/2026-10-22/upstream-smoke.html new file mode 100644 index 0000000..edd188d --- /dev/null +++ b/docs/validation/2026-10-22/upstream-smoke.html @@ -0,0 +1,288 @@ +
Binary CLI thật, giao tiếp HTTP với gateway mô phỏng. Đây là kết quả cục bộ, chưa xác nhận provider live hoặc triển khai từ xa.
+Commit: 422774fe3ba3d94c3e9be2e7082945ed54222770
SHA-256 binary: 5bd95979b1176002133def84734e3b98cd6d70cb107d58627ffb00cede9f7a27
VCS revision khớp commit và vcs.modified=false. Mỗi tiến trình dùng thư mục người dùng riêng, không dùng API key thật.
| Kịch bản | Kết quả | Bằng chứng |
|---|---|---|
| Health và revision của tiến trình CLI | Đạt | Chi tiết{
+ "gateway": "http://127.0.0.1:57085",
+ "journalEntries": 0,
+ "journalSessions": 0,
+ "sessions": 0,
+ "spendControl": {
+ "perRequest": {
+ "limit": 0.05,
+ "spent": 0,
+ "remaining": 0.05
+ },
+ "session": {
+ "limit": 10,
+ "spent": 0,
+ "remaining": 10
+ }
+ },
+ "status": "ok",
+ "version": "422774f"
+} |
| Catalog mới tự nạp khi khởi động | Đạt | Chi tiết{
+ "reads": 1,
+ "modelVisible": true
+} |
| Catalog lỗi giữ bản đóng gói | Đạt | Chi tiết{
+ "bundledFallback": true
+} |
| Model reasoning mới chuyển tiếp đúng metadata | Đạt | Chi tiết{
+ "status": 200,
+ "trace": [
+ {
+ "gateway": "stable",
+ "tag": "reasoning",
+ "model": "fixture/reasoner",
+ "sequence": 1,
+ "status": 200,
+ "reasoningNormalized": true
+ }
+ ]
+} |
| Alias miễn phí không thành model trả phí | Đạt | Chi tiết[
+ {
+ "gateway": "stable",
+ "tag": "free-alias",
+ "model": "free/nemotron-3.5-lightning",
+ "sequence": 1,
+ "status": 200,
+ "reasoningNormalized": true
+ }
+] |
| Model lỗi lặp lại được chuyển xuống cuối | Đạt | Chi tiết[
+ {
+ "gateway": "stable",
+ "tag": "repeat-failure-0",
+ "model": "google/gemini-2.5-flash",
+ "sequence": 1,
+ "status": 502,
+ "reasoningNormalized": true
+ },
+ {
+ "gateway": "stable",
+ "tag": "repeat-failure-0",
+ "model": "google/gemini-3-flash-preview",
+ "sequence": 2,
+ "status": 200,
+ "reasoningNormalized": true
+ },
+ {
+ "gateway": "stable",
+ "tag": "repeat-failure-1",
+ "model": "google/gemini-2.5-flash",
+ "sequence": 1,
+ "status": 502,
+ "reasoningNormalized": true
+ },
+ {
+ "gateway": "stable",
+ "tag": "repeat-failure-1",
+ "model": "google/gemini-3-flash-preview",
+ "sequence": 2,
+ "status": 200,
+ "reasoningNormalized": true
+ },
+ {
+ "gateway": "stable",
+ "tag": "repeat-failure-2",
+ "model": "google/gemini-2.5-flash",
+ "sequence": 1,
+ "status": 502,
+ "reasoningNormalized": true
+ },
+ {
+ "gateway": "stable",
+ "tag": "repeat-failure-2",
+ "model": "google/gemini-3-flash-preview",
+ "sequence": 2,
+ "status": 200,
+ "reasoningNormalized": true
+ },
+ {
+ "gateway": "stable",
+ "tag": "repeat-failure-3",
+ "model": "google/gemini-3-flash-preview",
+ "sequence": 1,
+ "status": 200,
+ "reasoningNormalized": true
+ }
+] |
| Phản hồi rỗng tiếp tục tới model có kết quả | Đạt | Chi tiết[
+ {
+ "gateway": "stable",
+ "tag": "empty-chain",
+ "model": "google/gemini-3.5-flash",
+ "sequence": 1,
+ "status": 200,
+ "reasoningNormalized": true
+ },
+ {
+ "gateway": "stable",
+ "tag": "empty-chain",
+ "model": "google/gemini-3.6-flash",
+ "sequence": 2,
+ "status": 200,
+ "reasoningNormalized": true
+ },
+ {
+ "gateway": "stable",
+ "tag": "empty-chain",
+ "model": "anthropic/claude-haiku-4.5",
+ "sequence": 3,
+ "status": 200,
+ "reasoningNormalized": true
+ }
+] |
| Chuỗi lỗi dừng sau tối đa 5 model | Đạt | Chi tiết[
+ {
+ "gateway": "stable",
+ "tag": "all-fail",
+ "model": "google/gemini-3.5-flash",
+ "sequence": 1,
+ "status": 502,
+ "reasoningNormalized": true
+ },
+ {
+ "gateway": "stable",
+ "tag": "all-fail",
+ "model": "google/gemini-3.6-flash",
+ "sequence": 2,
+ "status": 502,
+ "reasoningNormalized": true
+ },
+ {
+ "gateway": "stable",
+ "tag": "all-fail",
+ "model": "anthropic/claude-haiku-4.5",
+ "sequence": 3,
+ "status": 502,
+ "reasoningNormalized": true
+ },
+ {
+ "gateway": "stable",
+ "tag": "all-fail",
+ "model": "zai/glm-5.3",
+ "sequence": 4,
+ "status": 502,
+ "reasoningNormalized": true
+ },
+ {
+ "gateway": "stable",
+ "tag": "all-fail",
+ "model": "google/gemini-3.5-flash-lite",
+ "sequence": 5,
+ "status": 502,
+ "reasoningNormalized": true
+ }
+] |
| Model chỉ định không bị thay bằng fallback | Đạt | Chi tiết[
+ {
+ "gateway": "stable",
+ "tag": "explicit-pin-fails",
+ "model": "openai/gpt-4o-mini",
+ "sequence": 1,
+ "status": 502,
+ "reasoningNormalized": true
+ }
+] |
| Mất phản hồi không làm gửi lại request | Đạt | Chi tiết[
+ {
+ "gateway": "stable",
+ "tag": "lost-response",
+ "model": "google/gemini-3-flash-preview",
+ "sequence": 1,
+ "status": "socket-closed",
+ "reasoningNormalized": true
+ }
+] |
| SSE giữ nội dung và dấu kết thúc | Đạt | Chi tiết{
+ "status": 200,
+ "done": true
+} |
| Giá cao bị chặn trước khi gửi | Đạt | Chi tiết{
+ "status": 429,
+ "upstreamSends": 0
+} |
| Giá cố định bằng 0 không vượt spend limit | Đạt | Chi tiết{
+ "status": 429,
+ "upstreamSends": 0
+} |
| Host và Origin không tin cậy bị từ chối | Đạt | Chi tiết{
+ "initialDriverFailure": {
+ "error": "Expected values to be strictly equal:\n\n429 !== 403\n"
+ },
+ "recheck": {
+ "checkedAt": "2026-10-22T14:32:04.813Z",
+ "revision": "422774fe3ba3d94c3e9be2e7082945ed54222770",
+ "binarySha256": "5bd95979b1176002133def84734e3b98cd6d70cb107d58627ffb00cede9f7a27",
+ "transport": "node:http sends the literal Host header",
+ "originalDriverIssue": "Node fetch ignored the overridden Host header and sent the loopback host; its 429 was a driver error, not a guard failure.",
+ "results": [
+ {
+ "headers": {
+ "Origin": "https://attacker.invalid"
+ },
+ "status": 403
+ },
+ {
+ "headers": {
+ "Origin": "null"
+ },
+ "status": 403
+ },
+ {
+ "headers": {
+ "Host": "attacker.invalid"
+ },
+ "status": 403
+ },
+ {
+ "headers": {
+ "Sec-Fetch-Site": "cross-site"
+ },
+ "status": 403
+ }
+ ],
+ "upstreamSends": 0
+ },
+ "evidenceFile": "host-origin-probe.json"
+} |
| Prompt CJK dài được nâng tier theo số token | Đạt | Chi tiết{
+ "tier": "COMPLEX",
+ "reason": "Input exceeds 100000 tokens"
+} |
| Reservation đồng thời và settlement trả lại ngân sách | Đạt | Chi tiết{
+ "first": 200,
+ "whileInFlight": 429,
+ "afterSettlement": 200
+} |
| Refresh 5 phút và phục hồi catalog | Đạt | Chi tiết{
+ "intervals": [
+ {
+ "gateway": "stable",
+ "intervalMs": 300011
+ },
+ {
+ "gateway": "recovery",
+ "intervalMs": 300012
+ }
+ ],
+ "lastGoodRetained": true,
+ "recoveredFromInvalidStartup": true
+} |
| Accounting chỉ ghi vào thư mục thử nghiệm | Đạt | Chi tiết{
+ "isolatedProfiles": 3,
+ "historyCounts": [
+ 20,
+ 0,
+ 2
+ ],
+ "syntheticOnly": true
+} |
Playwright xác minh health, catalog và chat từ cùng origin; điều hướng cross-site nhận HTTP 403. Các tiến trình CLI thử nghiệm đã thoát và các cổng của chúng không còn truy cập được.
{
+ "browser": {
+ "chatStatus": 200,
+ "sameOriginHealthStatus": "ok",
+ "chatModel": "fixture/reasoner",
+ "requestFetchSite": "same-origin",
+ "driver": "MCP Playwright",
+ "catalogDiscovered": true,
+ "healthVersion": "422774f",
+ "crossSiteNavigationStatusObserved": 403,
+ "gatewayCorrelationVerified": true,
+ "evidenceKind": "External MCP browser attestation, correlated with the local gateway trace"
+ },
+ "shutdown": {
+ "allOwnedProcessesExited": true,
+ "portsClosed": true
+ }
+}Lần đầu, Node fetch bỏ qua Host giả mạo nên phép thử nhận 429. Gửi lại bằng HTTP trực tiếp giữ nguyên Host cho kết quả 403 ở cả bốn tình huống, không gửi request tới gateway. Bằng chứng lỗi ban đầu và lần kiểm tra lại đều được giữ trong JSON.
Repo chưa có môi trường staging từ xa được cấu hình. Không gọi model live, không có giao dịch thanh toán và không thay đổi dịch vụ đang phục vụ. Phí trong fixture là dữ liệu giả để kiểm tra accounting.
Binary CLI thật, giao tiếp HTTP với gateway mô phỏng. Đây là kết quả cục bộ, chưa xác nhận provider live hoặc triển khai từ xa.
+Commit: ${escape(evidence.revision)}
SHA-256 binary: ${escape(evidence.binarySha256)}
VCS revision khớp commit và vcs.modified=false. Mỗi tiến trình dùng thư mục người dùng riêng, không dùng API key thật.
| Kịch bản | Kết quả | Bằng chứng |
|---|---|---|
| ${escape(c.label)} | ${c.pass ? 'Đạt':'Chưa đạt'} | Chi tiết${escape(JSON.stringify(c.details,null,2))} |
${browserPassed ? 'Playwright xác minh health, catalog và chat từ cùng origin; điều hướng cross-site nhận HTTP 403.' : 'Browser chưa có đủ bằng chứng đạt.'} ${shutdownPassed ? 'Các tiến trình CLI thử nghiệm đã thoát và các cổng của chúng không còn truy cập được.' : 'Chưa xác nhận các tiến trình thử nghiệm đã đóng hoàn toàn.'}
${escape(JSON.stringify({browser:evidence.browser,shutdown:evidence.shutdown},null,2))}Lần đầu, Node fetch bỏ qua Host giả mạo nên phép thử nhận 429. Gửi lại bằng HTTP trực tiếp giữ nguyên Host cho kết quả 403 ở cả bốn tình huống, không gửi request tới gateway. Bằng chứng lỗi ban đầu và lần kiểm tra lại đều được giữ trong JSON.
Repo chưa có môi trường staging từ xa được cấu hình. Không gọi model live, không có giao dịch thanh toán và không thay đổi dịch vụ đang phục vụ. Phí trong fixture là dữ liệu giả để kiểm tra accounting.