qa(evidence): live production verification report
build-and-publish / test (pull_request) Has been cancelled
build-and-publish / image (pull_request) Has been cancelled

Captured against https://canvas.flow-master.ai with browser-style
probes + Playwright dogfood + raw fetches:

- Every /api/* through canvas's nginx returns 502 (proxy broken).
- demo.flow-master.ai upstream is alive (200/401 direct).
- Frontend calls auth routes that return 404 even direct on demo:
  /api/v1/auth/dev-login-config, /api/v1/auth/microsoft/login.
- User's 'GETs all 200' hypothesis was wrong — they're 502s.
- Zero EA2 traffic reaches the backend.

Repros in qa/evidence/_*.mjs. Screenshots + JSON dumps + full
report in qa/evidence/.
This commit is contained in:
canvas-bot
2026-06-15 01:21:19 +04:00
parent 32bf8260e3
commit 14ae238cbb
10 changed files with 369 additions and 0 deletions
+48
View File
@@ -0,0 +1,48 @@
// Browser-style trace: visit live canvas, capture every network request, and
// classify whether EA2 endpoints are actually being hit with real responses.
import { chromium } from "playwright";
const URL = "https://canvas.flow-master.ai/";
const calls = [];
const b = await chromium.launch({ headless: true });
const ctx = await b.newContext({ viewport: { width: 1440, height: 900 } });
const p = await ctx.newPage();
p.on("response", async (res) => {
const u = res.url();
if (!u.includes("/api/")) return;
calls.push({
url: u,
status: res.status(),
ts: Date.now(),
});
});
await p.goto(URL, { waitUntil: "domcontentloaded" });
await p.waitForTimeout(8000);
const total = calls.length;
const byStatus = {};
const byEndpoint = {};
for (const c of calls) {
byStatus[c.status] = (byStatus[c.status] || 0) + 1;
const path = c.url.replace(/https?:\/\/[^/]+/, "").split("?")[0];
const bucket = path.split("/").slice(0, 5).join("/");
byEndpoint[bucket] = (byEndpoint[bucket] || 0) + 1;
}
console.log("\n=== EA2 wiring trace ===");
console.log("total /api/ calls in 8s:", total);
console.log("by status:", JSON.stringify(byStatus));
console.log("by endpoint:");
for (const [ep, n] of Object.entries(byEndpoint).sort((a, b) => b[1] - a[1])) {
console.log(` ${n}\t${ep}`);
}
const ea2 = calls.filter((c) => c.url.includes("/api/ea2/"));
const auth = calls.filter((c) => c.url.includes("/api/v1/auth/"));
console.log(`\nEA2 calls: ${ea2.length} (${ea2.filter((c) => c.status === 200).length} 200)`);
console.log(`auth calls: ${auth.length} (${auth.filter((c) => c.status === 200).length} 200)`);
await b.close();