From 6eb201b05c29c37d9f50155e06f6285442ff1d7a Mon Sep 17 00:00:00 2001 From: JOY <5027251+JOY@users.noreply.github.com> Date: Thu, 22 Oct 2026 21:43:23 +0700 Subject: [PATCH 1/3] test: verify merged upstream with isolated CLI process smoke --- UPSTREAM_SYNC.md | 16 + .../2026-10-22/host-origin-probe.json | 34 + .../validation/2026-10-22/report-browser.json | 22 + .../validation/2026-10-22/upstream-smoke.html | 286 ++++++++ .../validation/2026-10-22/upstream-smoke.json | 664 ++++++++++++++++++ tools/README.md | 34 + tools/smoke-cli.mjs | 138 ++++ tools/smoke-report.mjs | 15 + 8 files changed, 1209 insertions(+) create mode 100644 docs/validation/2026-10-22/host-origin-probe.json create mode 100644 docs/validation/2026-10-22/report-browser.json create mode 100644 docs/validation/2026-10-22/upstream-smoke.html create mode 100644 docs/validation/2026-10-22/upstream-smoke.json create mode 100644 tools/README.md create mode 100644 tools/smoke-cli.mjs create mode 100644 tools/smoke-report.mjs diff --git a/UPSTREAM_SYNC.md b/UPSTREAM_SYNC.md index 94d4e56..aacc13e 100644 --- a/UPSTREAM_SYNC.md +++ b/UPSTREAM_SYNC.md @@ -30,6 +30,22 @@ These upstream areas are excluded (TS/npm-specific): ## Sync Log +### 2026-10-22 - Post-merge runtime acceptance (in progress) + +- 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. +- Next: build the clean merged revision, run process-level smoke scenarios, + preserve results and close any reproduced acceptance failure within scope. + ### 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/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..779c9b0 --- /dev/null +++ b/docs/validation/2026-10-22/report-browser.json @@ -0,0 +1,22 @@ +{ + "driver": "MCP Playwright", + "checkedAt": "2026-10-22T14:41:27Z", + "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." +} 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..8939b36 --- /dev/null +++ b/docs/validation/2026-10-22/upstream-smoke.html @@ -0,0 +1,286 @@ +
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
+ },
+ "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.