@resolveio/server-lib 22.3.227 → 22.3.229
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json
CHANGED
|
@@ -1,4 +1,33 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __makeTemplateObject = (this && this.__makeTemplateObject) || function (cooked, raw) {
|
|
3
|
+
if (Object.defineProperty) { Object.defineProperty(cooked, "raw", { value: raw }); } else { cooked.raw = raw; }
|
|
4
|
+
return cooked;
|
|
5
|
+
};
|
|
6
|
+
var __read = (this && this.__read) || function (o, n) {
|
|
7
|
+
var m = typeof Symbol === "function" && o[Symbol.iterator];
|
|
8
|
+
if (!m) return o;
|
|
9
|
+
var i = m.call(o), r, ar = [], e;
|
|
10
|
+
try {
|
|
11
|
+
while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value);
|
|
12
|
+
}
|
|
13
|
+
catch (error) { e = { error: error }; }
|
|
14
|
+
finally {
|
|
15
|
+
try {
|
|
16
|
+
if (r && !r.done && (m = i["return"])) m.call(i);
|
|
17
|
+
}
|
|
18
|
+
finally { if (e) throw e.error; }
|
|
19
|
+
}
|
|
20
|
+
return ar;
|
|
21
|
+
};
|
|
22
|
+
var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
|
|
23
|
+
if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
|
|
24
|
+
if (ar || !(i in from)) {
|
|
25
|
+
if (!ar) ar = Array.prototype.slice.call(from, 0, i);
|
|
26
|
+
ar[i] = from[i];
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
return to.concat(ar || Array.prototype.slice.call(from));
|
|
30
|
+
};
|
|
2
31
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
32
|
exports.buildResolveIORunnerQaEnvScript = buildResolveIORunnerQaEnvScript;
|
|
4
33
|
exports.buildResolveIORunnerQaPreflightScript = buildResolveIORunnerQaPreflightScript;
|
|
@@ -1841,10 +1870,10 @@ function buildResolveIORunnerQaLiveDataSeederScript() {
|
|
|
1841
1870
|
' const explicit = process.env.RESOLVEIO_QA_INCLUDE_BILLING_FIXTURES || process.env.RESOLVEIO_SUPPORT_QA_INCLUDE_BILLING_FIXTURES || process.env.RESOLVEIO_RUNNER_QA_INCLUDE_BILLING_FIXTURES || "";',
|
|
1842
1871
|
' if (/^(true|1|yes|on)$/i.test(explicit)) return true;',
|
|
1843
1872
|
' if (/^(false|0|no|off)$/i.test(explicit)) return false;',
|
|
1873
|
+
' if (shouldSeedPartInventorySnapshotContext()) return false;',
|
|
1844
1874
|
' const text = readSeedHintText();',
|
|
1845
1875
|
' const billingSurface = /\\b(invoice|invoicing|billing|billable|tax|taxes|surcharge|checkout|check\\s*out|pick\\s*ticket)\\b/i.test(text);',
|
|
1846
1876
|
' if (billingSurface) return true;',
|
|
1847
|
-
' if (shouldSeedPartInventorySnapshotContext()) return false;',
|
|
1848
1877
|
' return /\\binventory\\b/i.test(text);',
|
|
1849
1878
|
'}',
|
|
1850
1879
|
'',
|
|
@@ -2388,25 +2417,25 @@ function buildResolveIORunnerQaLiveDataSeederScript() {
|
|
|
2388
2417
|
' const hintedQuery = identifierQuery(identifiers);',
|
|
2389
2418
|
' let hintedProductionDeliveries = [];',
|
|
2390
2419
|
' let hintedTruckTreatingDeliveries = [];',
|
|
2391
|
-
' if (hintedQuery) {',
|
|
2420
|
+
' if (includeBillingFixtures && hintedQuery) {',
|
|
2392
2421
|
' hintedProductionDeliveries = await copyByIds(sourceDb, targetDb, "production-deliveries", await selectDashboardReadyProductionDeliveryIds(sourceDb, { $and: [billableDeliveryQuery, hintedQuery] }, 3), summary, 3);',
|
|
2393
2422
|
' hintedTruckTreatingDeliveries = await copyByIds(sourceDb, targetDb, "production-deliveries", await selectTruckTreatDashboardReadyProductionDeliveryIds(sourceDb, { $and: [billableTruckTreatQuery, hintedQuery] }, 3), summary, 3);',
|
|
2394
2423
|
' if (hintedProductionDeliveries.length || hintedTruckTreatingDeliveries.length) summary.notes.push(`Preferred live records matching ticket identifiers: ${identifiers.join(", ")}`);',
|
|
2395
2424
|
' else summary.notes.push(`No billable live records matched ticket identifiers: ${identifiers.join(", ")}`);',
|
|
2396
2425
|
' }',
|
|
2397
2426
|
'',
|
|
2398
|
-
' let fallbackProductionDeliveries = hintedProductionDeliveries.length ? [] : await copyByIds(sourceDb, targetDb, "production-deliveries", await selectDashboardReadyProductionDeliveryIds(sourceDb, billableDeliveryQuery, 3), summary, 3);',
|
|
2399
|
-
' if (!hintedProductionDeliveries.length && !fallbackProductionDeliveries.length) {',
|
|
2427
|
+
' let fallbackProductionDeliveries = includeBillingFixtures && hintedProductionDeliveries.length ? [] : includeBillingFixtures ? await copyByIds(sourceDb, targetDb, "production-deliveries", await selectDashboardReadyProductionDeliveryIds(sourceDb, billableDeliveryQuery, 3), summary, 3) : [];',
|
|
2428
|
+
' if (includeBillingFixtures && !hintedProductionDeliveries.length && !fallbackProductionDeliveries.length) {',
|
|
2400
2429
|
' fallbackProductionDeliveries = await copyByIds(sourceDb, targetDb, "production-deliveries", await selectLocalhostDeliveryFixtureIds(sourceDb, billableDeliveryQuery, 3), summary, 3);',
|
|
2401
2430
|
' if (fallbackProductionDeliveries.length) summary.notes.push("Created localhost-only delivery invoice fixture from live delivery data by normalizing copied BOL status to Delivered in local Mongo.");',
|
|
2402
2431
|
' }',
|
|
2403
|
-
' const fallbackTruckTreatingDeliveries = hintedTruckTreatingDeliveries.length ? [] : await copyByIds(sourceDb, targetDb, "production-deliveries", await selectTruckTreatDashboardReadyProductionDeliveryIds(sourceDb, billableTruckTreatQuery, 3), summary, 3);',
|
|
2432
|
+
' const fallbackTruckTreatingDeliveries = includeBillingFixtures && hintedTruckTreatingDeliveries.length ? [] : includeBillingFixtures ? await copyByIds(sourceDb, targetDb, "production-deliveries", await selectTruckTreatDashboardReadyProductionDeliveryIds(sourceDb, billableTruckTreatQuery, 3), summary, 3) : [];',
|
|
2404
2433
|
' const productionDeliveries = [...hintedProductionDeliveries, ...fallbackProductionDeliveries];',
|
|
2405
2434
|
' const truckTreatingDeliveries = [...hintedTruckTreatingDeliveries, ...fallbackTruckTreatingDeliveries];',
|
|
2406
2435
|
' summary.selected.production_deliveries = productionDeliveries.map((doc) => doc._id);',
|
|
2407
2436
|
' summary.selected.truck_treating_deliveries = truckTreatingDeliveries.map((doc) => doc._id);',
|
|
2408
2437
|
' if (!productionDeliveries.length && !truckTreatingDeliveries.length) {',
|
|
2409
|
-
' summary.notes.push("No live billable delivery or truck-treatment records matched the Billing Dashboard awaiting-invoice filters.");',
|
|
2438
|
+
' summary.notes.push(includeBillingFixtures ? "No live billable delivery or truck-treatment records matched the Billing Dashboard awaiting-invoice filters." : "Skipped billable delivery/truck-treatment discovery because billing fixtures are disabled for this QA scope.");',
|
|
2410
2439
|
' }',
|
|
2411
2440
|
'',
|
|
2412
2441
|
' const sourceDocs = [...qaIdentityUsers, ...truckTreatingBolContextDocs, ...ticketAssetContextDocs, ...productionInterchangeablesContextDocs, ...partInventorySnapshotContextDocs, ...pricingImportWorkbookContextDocs, ...productionDeliveries, ...truckTreatingDeliveries];',
|
|
@@ -2674,8 +2703,11 @@ function buildResolveIORunnerBugfixComparisonQaScript() {
|
|
|
2674
2703
|
''
|
|
2675
2704
|
].join('\n');
|
|
2676
2705
|
}
|
|
2706
|
+
function buildResolveIOPartInventorySnapshotProofScriptLines() {
|
|
2707
|
+
return String.raw(templateObject_1 || (templateObject_1 = __makeTemplateObject(["\nfunction activeMatrixRow() {\n\tconst matrix = readJson(matrixPath) || {};\n\tconst rows = matrixRows(matrix);\n\treturn rows.find((candidate) => !/^(pass|passed)$/i.test(String(candidate && candidate.status || \"\"))) || rows[0] || {};\n}\nfunction readSeedPartInventorySnapshotContext() {\n\tconst seed = readJson(path.join(artifactDir, \"qa-live-data-seed-result.json\")) || {};\n\tconst selected = seed && seed.selected || {};\n\tconst context = selected.part_inventory_snapshot_context || selected.partInventorySnapshotContext || null;\n\tif (!context || typeof context !== \"object\") return null;\n\tconst partIds = uniqueStrings(context.part_ids || context.partIds || []);\n\tconst dayKeys = uniqueStrings(context.day_keys || context.dayKeys || []);\n\tif (!partIds.length && !dayKeys.length && !Number(context.snapshot_count || context.snapshotCount || 0)) return null;\n\treturn { ...context, part_ids: partIds, day_keys: dayKeys };\n}\nfunction shouldRunPartInventorySnapshotProof() {\n\tconst context = readSeedPartInventorySnapshotContext();\n\tif (!context) return false;\n\tconst text = [activeRowText(), targetRoute].join(\"\n\");\n\treturn /\b(reportDailyInventorySnapshot|inventory-daily-snapshots|dailys+inventorys+snapshot|parts+inventorys+snapshot|warehouse_location|Parts)\b/i.test(text);\n}\nfunction normalizePartSnapshotDayKey(value) {\n\tconst text = String(value || \"\").trim();\n\tconst match = /d{4}-d{2}-d{2}/.exec(text);\n\tif (match) return match[0];\n\tconst date = new Date(text);\n\treturn Number.isFinite(date.getTime()) ? date.toISOString().slice(0, 10) : \"\";\n}\nfunction partSnapshotRowPartId(row) {\n\tconst metadata = row && typeof row.metadata === \"object\" ? row.metadata : {};\n\treturn String(metadata.id_part || row.id_part || row.id_item || row.id_source || \"\").trim();\n}\nfunction partSnapshotRowYardId(row) {\n\tconst metadata = row && typeof row.metadata === \"object\" ? row.metadata : {};\n\tconst explicit = String(metadata.id_yard || row.id_yard || row.id_warehouse_location || \"\").trim();\n\tif (explicit) return explicit;\n\tconst source = String(row && row.id_source || \"\");\n\tconst sourceMatch = /^yard:([A-Za-z0-9_-]+)/i.exec(source);\n\treturn sourceMatch ? sourceMatch[1] : \"\";\n}\nfunction normalizeWarehouseName(value) {\n\treturn String(value || \"\").trim().toLowerCase().replace(/s+/g, \" \");\n}\nfunction methodDateFromDayKey(dayKey) {\n\treturn new Date(dayKey + \"T12:00:00.000Z\");\n}\nfunction resolveWsUrl() {\n\tif (/^https:/i.test(serverUrl)) return serverUrl.replace(/^https:/i, \"wss:\");\n\tif (/^http:/i.test(serverUrl)) return serverUrl.replace(/^http:/i, \"ws:\");\n\treturn serverUrl;\n}\nfunction callResolveIOMethodViaWs(auth, route, methodName, args) {\n\treturn new Promise((resolve, reject) => {\n\t\tconst token = auth && auth.accessToken;\n\t\tif (!token) {\n\t\t\treject(new Error(\"Missing access token for websocket method proof.\"));\n\t\t\treturn;\n\t\t}\n\t\tconst WebSocket = requireQaModule(\"ws\");\n\t\tconst ws = new WebSocket(resolveWsUrl(), [token], { origin: clientUrl });\n\t\tconst messageId = Date.now() + Math.floor(Math.random() * 100000);\n\t\tconst timeout = setTimeout(() => {\n\t\t\ttry { ws.close(); } catch (error) {}\n\t\t\treject(new Error(\"Timed out waiting for \" + methodName + \" websocket response.\"));\n\t\t}, Number(process.env.RESOLVEIO_SUPPORT_QA_METHOD_PROOF_TIMEOUT_MS || 120000));\n\t\tlet settled = false;\n\t\tconst finish = (error, value) => {\n\t\t\tif (settled) return;\n\t\t\tsettled = true;\n\t\t\tclearTimeout(timeout);\n\t\t\ttry { ws.close(); } catch (closeError) {}\n\t\t\tif (error) reject(error);\n\t\t\telse resolve(value);\n\t\t};\n\t\tws.on(\"open\", () => {\n\t\t\tconst payload = [[route || \"/\", new Date().toISOString(), messageId, \"method\", methodName, ...(args || [])]];\n\t\t\tws.send(JSON.stringify(payload));\n\t\t});\n\t\tws.on(\"message\", (raw) => {\n\t\t\tlet payload;\n\t\t\ttry { payload = JSON.parse(Buffer.isBuffer(raw) ? raw.toString(\"utf8\") : String(raw)); }\n\t\t\tcatch (error) { return; }\n\t\t\tif (!payload || payload.messageId !== messageId) return;\n\t\t\tif (payload.data === \"ACK\" && payload.hasError === false) return;\n\t\t\tif (payload.hasError) finish(new Error(typeof payload.data === \"string\" ? payload.data : JSON.stringify(payload.data || {})));\n\t\t\telse finish(null, payload.data);\n\t\t});\n\t\tws.on(\"error\", (error) => finish(error));\n\t});\n}\nasync function readPartInventorySnapshotProofData(context, dayKey) {\n\tconst { MongoClient } = mongoRequire();\n\tconst client = new MongoClient(safeLocalMongoUrl());\n\tawait client.connect();\n\ttry {\n\t\tconst db = client.db();\n\t\tconst query = { section: \"Parts\" };\n\t\tif (dayKey) query.day_key = dayKey;\n\t\tconst partIds = uniqueStrings(context.part_ids || []);\n\t\tif (partIds.length) query.$or = [{ \"metadata.id_part\": { $in: partIds } }, { id_part: { $in: partIds } }];\n\t\tconst snapshots = await db.collection(\"inventory-daily-snapshots\").find(query).sort({ day_key: -1, item_name: 1, location: 1 }).limit(120).toArray();\n\t\tconst yardIds = uniqueStrings(snapshots.map(partSnapshotRowYardId));\n\t\tconst yards = yardIds.length ? await db.collection(\"yards\").find({ _id: { $in: yardIds } }).project({ _id: 1, name: 1 }).toArray() : [];\n\t\tconst yardById = new Map(yards.map((yard) => [String(yard._id), yard]));\n\t\treturn { snapshots, yards, yardById };\n\t} finally {\n\t\tawait client.close().catch(() => undefined);\n\t}\n}\nasync function renderPartInventorySnapshotProofScreenshot(page, payload, rowRoute, screenshotPath) {\n\tconst escapeHtml = (value) => String(value === undefined || value === null ? \"\" : value).replace(/[&<>\"']/g, (char) => ({ \"&\": \"&\", \"<\": \"<\", \">\": \">\", \"\"\": \""\", \"'\": \"'\" }[char]));\n\tconst comparisons = (payload.comparisons || []).slice(0, 12).map((entry) => \"<tr><td>\" + escapeHtml(entry.partId || entry.itemName || \"part\") + \"</td><td>\" + escapeHtml(entry.beforeWarehouse || \"\") + \"</td><td>\" + escapeHtml(entry.expectedYardName || \"\") + \"</td><td>\" + escapeHtml(entry.afterWarehouse || \"\") + \"</td><td>\" + (entry.pass ? \"<span class=\"ok\">PASS</span>\" : \"<span class=\"bad\">FAIL</span>\") + \"</td></tr>\").join(\"\");\n\tconst html = \"<!doctype html><html><head><meta charset=\"utf-8\"><style>body{margin:0;background:#f5f7fb;color:#111827;font-family:Arial,Helvetica,sans-serif}.wrap{padding:42px 52px}.eyebrow{font-size:16px;text-transform:uppercase;color:#475569;font-weight:700}.title{font-size:34px;font-weight:800;margin:10px 0}.caption{font-size:20px;line-height:1.35;color:#1f2937;margin:0 0 22px}.grid{display:grid;grid-template-columns:1fr 1fr 1fr;gap:16px;margin:22px 0}.card{background:white;border:2px solid #d7dde8;border-radius:8px;padding:18px}.label{font-size:14px;color:#64748b;font-weight:700;text-transform:uppercase}.value{font-size:28px;font-weight:800;margin-top:8px}.ok{color:#047857;font-weight:800}.bad{color:#b91c1c;font-weight:800}table{width:100%;border-collapse:collapse;background:white;border:2px solid #d7dde8;border-radius:8px;overflow:hidden;font-size:17px}th{background:#111827;color:white;text-align:left;padding:12px}td{border-top:1px solid #e5e7eb;padding:12px}.footer{margin-top:20px;font-size:16px;color:#475569}.path{font-family:Menlo,Consolas,monospace;font-size:14px;color:#334155}</style></head><body><main class=\"wrap\"><div class=\"eyebrow\">ResolveIO Support QA Business Proof</div><div class=\"title\">Part Inventory Snapshot Warehouse Attribution</div><p class=\"caption\">\" + escapeHtml(payload.caption || \"\") + \"</p><section class=\"grid\"><div class=\"card\"><div class=\"label\">Report Method</div><div class=\"value\">reportDailyInventorySnapshot</div></div><div class=\"card\"><div class=\"label\">Snapshot Date</div><div class=\"value\">\" + escapeHtml(payload.dayKey || \"\") + \"</div></div><div class=\"card\"><div class=\"label\">Stale Rows Corrected</div><div class=\"value \" + (payload.pass ? \"ok\" : \"bad\") + \"\">\" + Number(payload.correctedStaleRows || 0) + \"/\" + Number(payload.staleRows || 0) + \"</div></div></section><table><thead><tr><th>Part</th><th>Before Saved Warehouse</th><th>Expected Yard</th><th>Method Response Warehouse</th><th>Result</th></tr></thead><tbody>\" + comparisons + \"</tbody></table><div class=\"footer\">Before: saved historical Parts snapshot rows contained stale warehouse_location values. Action: called reportDailyInventorySnapshot(date, [\"Parts\"]) on the local QA server. After: the method response used the authoritative yard lineage for the affected part rows.</div><div class=\"footer path\">Route: \" + escapeHtml(rowRoute || targetRoute) + \" | Artifacts: qa-part-inventory-snapshot-proof.json, aiqa-business-assertion.json, qa-coverage-matrix.json</div></main></body></html>\";\n\tawait page.setViewport({ width: Math.max(viewportWidth, 1600), height: Math.max(viewportHeight, 900) }).catch(() => undefined);\n\tawait page.setContent(html, { waitUntil: \"domcontentloaded\", timeout: 30000 });\n\tawait page.screenshot({ path: screenshotPath, type: \"png\", fullPage: false });\n}\nasync function runPartInventorySnapshotMethodProof(page, routeSummary, auth) {\n\tif (!shouldRunPartInventorySnapshotProof()) return null;\n\tconst context = readSeedPartInventorySnapshotContext();\n\tconst row = activeMatrixRow();\n\tconst rowRoute = String(row.route || row.screen || \"/print\").trim() || \"/print\";\n\tconst rowWorkflow = String(row.workflow || row.action_under_test || \"Invoke reportDailyInventorySnapshot(date, [\"Parts\"]) and verify Part warehouse_location uses authoritative yard lineage.\").trim();\n\tconst proofPath = path.join(artifactDir, \"qa-part-inventory-snapshot-proof.json\");\n\tconst businessAssertionPath = path.join(artifactDir, \"aiqa-business-assertion.json\");\n\tconst beforeAfterScreenshotPath = path.join(artifactDir, \"support-business-proof-before-after.png\");\n\tconst requestedDayKeys = uniqueStrings(context.day_keys || []).map(normalizePartSnapshotDayKey).filter(Boolean);\n\tconst dayKey = requestedDayKeys[0] || normalizePartSnapshotDayKey(new Date(Date.now() - 86400000).toISOString());\n\tconst writeFailed = async (message, extra) => {\n\t\tconst payload = { status: \"failed\", targetRoute: rowRoute, dayKey, context, error: message, ...(extra || {}), updated_at: new Date().toISOString() };\n\t\twriteJson(proofPath, payload);\n\t\twriteJson(businessAssertionPath, { assertion: String(row.assertion || row.required_proof || \"Part inventory snapshot warehouse attribution proof\"), status: \"failed\", result: \"business_assertion_failed\", outcome: \"business_assertion_failed\", workflow: rowWorkflow, route: rowRoute, before: \"\", action: \"Attempted deterministic reportDailyInventorySnapshot websocket method proof.\", expected: \"Affected Part rows return the yard named by snapshot metadata.id_yard instead of stale saved warehouse_location.\", after: \"\", observed: message, dataProof: message, mongoDelta: {}, artifactPaths: [proofPath, matrixPath], metadata: { supportDiagnosisProof: false, proofType: \"part_inventory_snapshot_report_method\", generatedBy: \"resolveio_runner_part_inventory_snapshot_business_proof\", generatedAt: new Date().toISOString() } });\n\t\tconst matrix = readJson(matrixPath) || { status: \"started\", rows: [] };\n\t\tconst rows = matrixRows(matrix);\n\t\tconst activeIndex = Math.max(0, rows.indexOf(row));\n\t\tif (rows[activeIndex]) { rows[activeIndex].status = \"failed\"; rows[activeIndex].result = \"failed\"; rows[activeIndex].acceptance_blocked = true; rows[activeIndex].blocker = message; rows[activeIndex].artifact = proofPath; }\n\t\tmatrix.rows = rows;\n\t\tmatrix.status = \"failed\";\n\t\tmatrix.part_inventory_snapshot_proof = proofPath;\n\t\tmatrix.aiqa_business_assertion = businessAssertionPath;\n\t\tmatrix.updated_at = new Date().toISOString();\n\t\twriteJson(matrixPath, matrix);\n\t\treturn payload;\n\t};\n\ttry {\n\t\tconst data = await readPartInventorySnapshotProofData(context, dayKey);\n\t\tif (!data.snapshots.length) return await writeFailed(\"No seeded Part inventory daily snapshot rows were available for day_key \" + dayKey + \".\");\n\t\tconst methodResult = await callResolveIOMethodViaWs(auth, rowRoute, \"reportDailyInventorySnapshot\", [methodDateFromDayKey(dayKey), [\"Parts\"]]);\n\t\tconst responseRows = Array.isArray(methodResult && methodResult.rows) ? methodResult.rows : [];\n\t\tconst comparisons = data.snapshots.map((snapshot) => {\n\t\t\tconst partId = partSnapshotRowPartId(snapshot);\n\t\t\tconst yardId = partSnapshotRowYardId(snapshot);\n\t\t\tconst yard = yardId ? data.yardById.get(String(yardId)) : null;\n\t\t\tconst expectedYardName = String(yard && yard.name || \"\").trim();\n\t\t\tconst beforeWarehouse = String(snapshot.warehouse_location || snapshot.location || \"\").trim();\n\t\t\tconst responseCandidates = responseRows.filter((candidate) => !partId || partSnapshotRowPartId(candidate) === partId || String(candidate.item_name || candidate.name || \"\") === String(snapshot.item_name || snapshot.name || \"\"));\n\t\t\tconst afterRow = responseCandidates.find((candidate) => expectedYardName && normalizeWarehouseName(candidate.warehouse_location || candidate.location) === normalizeWarehouseName(expectedYardName)) || responseCandidates[0] || null;\n\t\t\tconst afterWarehouse = String(afterRow && (afterRow.warehouse_location || afterRow.location) || \"\").trim();\n\t\t\tconst staleBefore = !!expectedYardName && !!beforeWarehouse && normalizeWarehouseName(beforeWarehouse) !== normalizeWarehouseName(expectedYardName);\n\t\t\treturn { partId, itemName: String(snapshot.item_name || snapshot.name || \"\"), dayKey: String(snapshot.day_key || \"\"), beforeWarehouse, expectedYardName, afterWarehouse, staleBefore, pass: staleBefore && !!afterWarehouse && normalizeWarehouseName(afterWarehouse) === normalizeWarehouseName(expectedYardName) };\n\t\t}).filter((entry) => entry.expectedYardName);\n\t\tconst staleRows = comparisons.filter((entry) => entry.staleBefore);\n\t\tconst passedRows = staleRows.filter((entry) => entry.pass);\n\t\tconst pass = staleRows.length > 0 && passedRows.length === staleRows.length;\n\t\tconst caption = pass\n\t\t\t? \"Part inventory snapshot proof passed: \" + passedRows.length + \" stale saved row(s) returned the authoritative yard warehouse in reportDailyInventorySnapshot.\"\n\t\t\t: \"Part inventory snapshot proof failed: staleRows=\" + staleRows.length + \", corrected=\" + passedRows.length + \".\";\n\t\tconst payload = { status: pass ? \"pass\" : \"failed\", targetRoute: rowRoute, dayKey, methodName: \"reportDailyInventorySnapshot\", context, snapshotCount: data.snapshots.length, responseRowCount: responseRows.length, staleRows: staleRows.length, correctedStaleRows: passedRows.length, comparisons, caption, screenshot: beforeAfterScreenshotPath, page: routeSummary, updated_at: new Date().toISOString() };\n\t\tawait renderPartInventorySnapshotProofScreenshot(page, payload, rowRoute, beforeAfterScreenshotPath).catch(() => undefined);\n\t\twriteJson(proofPath, payload);\n\t\tconst businessAssertion = {\n\t\t\tassertion: String(row.assertion || row.required_proof || \"Affected Part warehouse_location maps to authoritative yard lineage in reportDailyInventorySnapshot response.\").trim(),\n\t\t\tstatus: pass ? \"pass\" : \"failed\",\n\t\t\tresult: pass ? \"business_assertion_passed\" : \"business_assertion_failed\",\n\t\t\toutcome: pass ? \"business_assertion_passed\" : \"business_assertion_failed\",\n\t\t\tworkflow: rowWorkflow,\n\t\t\troute: rowRoute,\n\t\t\tbefore: \"Saved non-today Parts snapshot rows for day_key \" + dayKey + \" included \" + staleRows.length + \" stale warehouse_location value(s): \" + staleRows.map((entry) => (entry.itemName || entry.partId) + \"=\" + entry.beforeWarehouse).join(\"; \"),\n\t\t\taction: \"Called reportDailyInventorySnapshot(\" + dayKey + \", [\"Parts\"]) through the local QA websocket method path.\",\n\t\t\texpected: \"Every affected stale Part row returns the yard named by metadata.id_yard in warehouse_location.\",\n\t\t\tafter: \"Method response corrected \" + passedRows.length + \" of \" + staleRows.length + \" stale row(s): \" + passedRows.map((entry) => (entry.itemName || entry.partId) + \"=\" + entry.afterWarehouse).join(\"; \"),\n\t\t\tobserved: caption,\n\t\t\tdataProof: comparisons.map((entry) => (entry.itemName || entry.partId || \"part\") + \": before=\" + entry.beforeWarehouse + \", expected=\" + entry.expectedYardName + \", after=\" + entry.afterWarehouse + \", pass=\" + entry.pass).join(\"\n\"),\n\t\t\tmongoDelta: { collection: \"inventory-daily-snapshots\", day_key: dayKey, staleRows: staleRows.length, correctedStaleRows: passedRows.length, responseRowCount: responseRows.length },\n\t\t\tartifactPaths: [proofPath, beforeAfterScreenshotPath, matrixPath],\n\t\t\tmetadata: { supportDiagnosisProof: pass, proofType: \"part_inventory_snapshot_report_method\", methodPath: \"server/src/methods/report.ts reportDailyInventorySnapshot\", generatedBy: \"resolveio_runner_part_inventory_snapshot_business_proof\", generatedAt: new Date().toISOString() }\n\t\t};\n\t\twriteJson(businessAssertionPath, businessAssertion);\n\t\tconst matrix = readJson(matrixPath) || { status: \"started\", rows: [] };\n\t\tconst rows = matrixRows(matrix);\n\t\tconst rowIndex = rows.findIndex((candidate) => String(candidate && candidate.workflow || \"\") === rowWorkflow) >= 0 ? rows.findIndex((candidate) => String(candidate && candidate.workflow || \"\") === rowWorkflow) : rows.findIndex((candidate) => !/^(pass|passed)$/i.test(String(candidate && candidate.status || \"\")));\n\t\tconst activeIndex = rowIndex >= 0 ? rowIndex : 0;\n\t\tif (rows[activeIndex]) {\n\t\t\trows[activeIndex].status = pass ? \"pass\" : \"failed\";\n\t\t\trows[activeIndex].result = pass ? \"pass\" : \"failed\";\n\t\t\trows[activeIndex].acceptance_blocked = !pass;\n\t\t\trows[activeIndex].screenshot = beforeAfterScreenshotPath;\n\t\t\trows[activeIndex].screenshots = [beforeAfterScreenshotPath, passScreenshotPath].filter(Boolean);\n\t\t\trows[activeIndex].caption = caption;\n\t\t\trows[activeIndex].artifact = proofPath;\n\t\t\trows[activeIndex].artifacts = [{ path: proofPath, caption: \"Part inventory snapshot method response proof.\" }, { screenshot: beforeAfterScreenshotPath, caption }, { path: businessAssertionPath, caption: \"AIQaBusinessAssertion for support diagnosis proof plan.\" }];\n\t\t\trows[activeIndex].persisted_assertion = businessAssertion.dataProof;\n\t\t\tif (!pass) rows[activeIndex].blocker = caption;\n\t\t}\n\t\tmatrix.rows = rows;\n\t\tmatrix.status = pass ? \"pass\" : \"failed\";\n\t\tmatrix.part_inventory_snapshot_proof = proofPath;\n\t\tmatrix.aiqa_business_assertion = businessAssertionPath;\n\t\tmatrix.updated_at = new Date().toISOString();\n\t\twriteJson(matrixPath, matrix);\n\t\treturn payload;\n\t} catch (error) {\n\t\treturn await writeFailed(error && (error.stack || error.message) || String(error));\n\t}\n}\n"], ["\nfunction activeMatrixRow() {\n\tconst matrix = readJson(matrixPath) || {};\n\tconst rows = matrixRows(matrix);\n\treturn rows.find((candidate) => !/^(pass|passed)$/i.test(String(candidate && candidate.status || \"\"))) || rows[0] || {};\n}\nfunction readSeedPartInventorySnapshotContext() {\n\tconst seed = readJson(path.join(artifactDir, \"qa-live-data-seed-result.json\")) || {};\n\tconst selected = seed && seed.selected || {};\n\tconst context = selected.part_inventory_snapshot_context || selected.partInventorySnapshotContext || null;\n\tif (!context || typeof context !== \"object\") return null;\n\tconst partIds = uniqueStrings(context.part_ids || context.partIds || []);\n\tconst dayKeys = uniqueStrings(context.day_keys || context.dayKeys || []);\n\tif (!partIds.length && !dayKeys.length && !Number(context.snapshot_count || context.snapshotCount || 0)) return null;\n\treturn { ...context, part_ids: partIds, day_keys: dayKeys };\n}\nfunction shouldRunPartInventorySnapshotProof() {\n\tconst context = readSeedPartInventorySnapshotContext();\n\tif (!context) return false;\n\tconst text = [activeRowText(), targetRoute].join(\"\\n\");\n\treturn /\\b(reportDailyInventorySnapshot|inventory-daily-snapshots|daily\\s+inventory\\s+snapshot|part\\s+inventory\\s+snapshot|warehouse_location|Parts)\\b/i.test(text);\n}\nfunction normalizePartSnapshotDayKey(value) {\n\tconst text = String(value || \"\").trim();\n\tconst match = /\\d{4}-\\d{2}-\\d{2}/.exec(text);\n\tif (match) return match[0];\n\tconst date = new Date(text);\n\treturn Number.isFinite(date.getTime()) ? date.toISOString().slice(0, 10) : \"\";\n}\nfunction partSnapshotRowPartId(row) {\n\tconst metadata = row && typeof row.metadata === \"object\" ? row.metadata : {};\n\treturn String(metadata.id_part || row.id_part || row.id_item || row.id_source || \"\").trim();\n}\nfunction partSnapshotRowYardId(row) {\n\tconst metadata = row && typeof row.metadata === \"object\" ? row.metadata : {};\n\tconst explicit = String(metadata.id_yard || row.id_yard || row.id_warehouse_location || \"\").trim();\n\tif (explicit) return explicit;\n\tconst source = String(row && row.id_source || \"\");\n\tconst sourceMatch = /^yard:([A-Za-z0-9_-]+)/i.exec(source);\n\treturn sourceMatch ? sourceMatch[1] : \"\";\n}\nfunction normalizeWarehouseName(value) {\n\treturn String(value || \"\").trim().toLowerCase().replace(/\\s+/g, \" \");\n}\nfunction methodDateFromDayKey(dayKey) {\n\treturn new Date(dayKey + \"T12:00:00.000Z\");\n}\nfunction resolveWsUrl() {\n\tif (/^https:/i.test(serverUrl)) return serverUrl.replace(/^https:/i, \"wss:\");\n\tif (/^http:/i.test(serverUrl)) return serverUrl.replace(/^http:/i, \"ws:\");\n\treturn serverUrl;\n}\nfunction callResolveIOMethodViaWs(auth, route, methodName, args) {\n\treturn new Promise((resolve, reject) => {\n\t\tconst token = auth && auth.accessToken;\n\t\tif (!token) {\n\t\t\treject(new Error(\"Missing access token for websocket method proof.\"));\n\t\t\treturn;\n\t\t}\n\t\tconst WebSocket = requireQaModule(\"ws\");\n\t\tconst ws = new WebSocket(resolveWsUrl(), [token], { origin: clientUrl });\n\t\tconst messageId = Date.now() + Math.floor(Math.random() * 100000);\n\t\tconst timeout = setTimeout(() => {\n\t\t\ttry { ws.close(); } catch (error) {}\n\t\t\treject(new Error(\"Timed out waiting for \" + methodName + \" websocket response.\"));\n\t\t}, Number(process.env.RESOLVEIO_SUPPORT_QA_METHOD_PROOF_TIMEOUT_MS || 120000));\n\t\tlet settled = false;\n\t\tconst finish = (error, value) => {\n\t\t\tif (settled) return;\n\t\t\tsettled = true;\n\t\t\tclearTimeout(timeout);\n\t\t\ttry { ws.close(); } catch (closeError) {}\n\t\t\tif (error) reject(error);\n\t\t\telse resolve(value);\n\t\t};\n\t\tws.on(\"open\", () => {\n\t\t\tconst payload = [[route || \"/\", new Date().toISOString(), messageId, \"method\", methodName, ...(args || [])]];\n\t\t\tws.send(JSON.stringify(payload));\n\t\t});\n\t\tws.on(\"message\", (raw) => {\n\t\t\tlet payload;\n\t\t\ttry { payload = JSON.parse(Buffer.isBuffer(raw) ? raw.toString(\"utf8\") : String(raw)); }\n\t\t\tcatch (error) { return; }\n\t\t\tif (!payload || payload.messageId !== messageId) return;\n\t\t\tif (payload.data === \"ACK\" && payload.hasError === false) return;\n\t\t\tif (payload.hasError) finish(new Error(typeof payload.data === \"string\" ? payload.data : JSON.stringify(payload.data || {})));\n\t\t\telse finish(null, payload.data);\n\t\t});\n\t\tws.on(\"error\", (error) => finish(error));\n\t});\n}\nasync function readPartInventorySnapshotProofData(context, dayKey) {\n\tconst { MongoClient } = mongoRequire();\n\tconst client = new MongoClient(safeLocalMongoUrl());\n\tawait client.connect();\n\ttry {\n\t\tconst db = client.db();\n\t\tconst query = { section: \"Parts\" };\n\t\tif (dayKey) query.day_key = dayKey;\n\t\tconst partIds = uniqueStrings(context.part_ids || []);\n\t\tif (partIds.length) query.$or = [{ \"metadata.id_part\": { $in: partIds } }, { id_part: { $in: partIds } }];\n\t\tconst snapshots = await db.collection(\"inventory-daily-snapshots\").find(query).sort({ day_key: -1, item_name: 1, location: 1 }).limit(120).toArray();\n\t\tconst yardIds = uniqueStrings(snapshots.map(partSnapshotRowYardId));\n\t\tconst yards = yardIds.length ? await db.collection(\"yards\").find({ _id: { $in: yardIds } }).project({ _id: 1, name: 1 }).toArray() : [];\n\t\tconst yardById = new Map(yards.map((yard) => [String(yard._id), yard]));\n\t\treturn { snapshots, yards, yardById };\n\t} finally {\n\t\tawait client.close().catch(() => undefined);\n\t}\n}\nasync function renderPartInventorySnapshotProofScreenshot(page, payload, rowRoute, screenshotPath) {\n\tconst escapeHtml = (value) => String(value === undefined || value === null ? \"\" : value).replace(/[&<>\"']/g, (char) => ({ \"&\": \"&\", \"<\": \"<\", \">\": \">\", \"\\\"\": \""\", \"'\": \"'\" }[char]));\n\tconst comparisons = (payload.comparisons || []).slice(0, 12).map((entry) => \"<tr><td>\" + escapeHtml(entry.partId || entry.itemName || \"part\") + \"</td><td>\" + escapeHtml(entry.beforeWarehouse || \"\") + \"</td><td>\" + escapeHtml(entry.expectedYardName || \"\") + \"</td><td>\" + escapeHtml(entry.afterWarehouse || \"\") + \"</td><td>\" + (entry.pass ? \"<span class=\\\"ok\\\">PASS</span>\" : \"<span class=\\\"bad\\\">FAIL</span>\") + \"</td></tr>\").join(\"\");\n\tconst html = \"<!doctype html><html><head><meta charset=\\\"utf-8\\\"><style>body{margin:0;background:#f5f7fb;color:#111827;font-family:Arial,Helvetica,sans-serif}.wrap{padding:42px 52px}.eyebrow{font-size:16px;text-transform:uppercase;color:#475569;font-weight:700}.title{font-size:34px;font-weight:800;margin:10px 0}.caption{font-size:20px;line-height:1.35;color:#1f2937;margin:0 0 22px}.grid{display:grid;grid-template-columns:1fr 1fr 1fr;gap:16px;margin:22px 0}.card{background:white;border:2px solid #d7dde8;border-radius:8px;padding:18px}.label{font-size:14px;color:#64748b;font-weight:700;text-transform:uppercase}.value{font-size:28px;font-weight:800;margin-top:8px}.ok{color:#047857;font-weight:800}.bad{color:#b91c1c;font-weight:800}table{width:100%;border-collapse:collapse;background:white;border:2px solid #d7dde8;border-radius:8px;overflow:hidden;font-size:17px}th{background:#111827;color:white;text-align:left;padding:12px}td{border-top:1px solid #e5e7eb;padding:12px}.footer{margin-top:20px;font-size:16px;color:#475569}.path{font-family:Menlo,Consolas,monospace;font-size:14px;color:#334155}</style></head><body><main class=\\\"wrap\\\"><div class=\\\"eyebrow\\\">ResolveIO Support QA Business Proof</div><div class=\\\"title\\\">Part Inventory Snapshot Warehouse Attribution</div><p class=\\\"caption\\\">\" + escapeHtml(payload.caption || \"\") + \"</p><section class=\\\"grid\\\"><div class=\\\"card\\\"><div class=\\\"label\\\">Report Method</div><div class=\\\"value\\\">reportDailyInventorySnapshot</div></div><div class=\\\"card\\\"><div class=\\\"label\\\">Snapshot Date</div><div class=\\\"value\\\">\" + escapeHtml(payload.dayKey || \"\") + \"</div></div><div class=\\\"card\\\"><div class=\\\"label\\\">Stale Rows Corrected</div><div class=\\\"value \" + (payload.pass ? \"ok\" : \"bad\") + \"\\\">\" + Number(payload.correctedStaleRows || 0) + \"/\" + Number(payload.staleRows || 0) + \"</div></div></section><table><thead><tr><th>Part</th><th>Before Saved Warehouse</th><th>Expected Yard</th><th>Method Response Warehouse</th><th>Result</th></tr></thead><tbody>\" + comparisons + \"</tbody></table><div class=\\\"footer\\\">Before: saved historical Parts snapshot rows contained stale warehouse_location values. Action: called reportDailyInventorySnapshot(date, [\\\"Parts\\\"]) on the local QA server. After: the method response used the authoritative yard lineage for the affected part rows.</div><div class=\\\"footer path\\\">Route: \" + escapeHtml(rowRoute || targetRoute) + \" | Artifacts: qa-part-inventory-snapshot-proof.json, aiqa-business-assertion.json, qa-coverage-matrix.json</div></main></body></html>\";\n\tawait page.setViewport({ width: Math.max(viewportWidth, 1600), height: Math.max(viewportHeight, 900) }).catch(() => undefined);\n\tawait page.setContent(html, { waitUntil: \"domcontentloaded\", timeout: 30000 });\n\tawait page.screenshot({ path: screenshotPath, type: \"png\", fullPage: false });\n}\nasync function runPartInventorySnapshotMethodProof(page, routeSummary, auth) {\n\tif (!shouldRunPartInventorySnapshotProof()) return null;\n\tconst context = readSeedPartInventorySnapshotContext();\n\tconst row = activeMatrixRow();\n\tconst rowRoute = String(row.route || row.screen || \"/print\").trim() || \"/print\";\n\tconst rowWorkflow = String(row.workflow || row.action_under_test || \"Invoke reportDailyInventorySnapshot(date, [\\\"Parts\\\"]) and verify Part warehouse_location uses authoritative yard lineage.\").trim();\n\tconst proofPath = path.join(artifactDir, \"qa-part-inventory-snapshot-proof.json\");\n\tconst businessAssertionPath = path.join(artifactDir, \"aiqa-business-assertion.json\");\n\tconst beforeAfterScreenshotPath = path.join(artifactDir, \"support-business-proof-before-after.png\");\n\tconst requestedDayKeys = uniqueStrings(context.day_keys || []).map(normalizePartSnapshotDayKey).filter(Boolean);\n\tconst dayKey = requestedDayKeys[0] || normalizePartSnapshotDayKey(new Date(Date.now() - 86400000).toISOString());\n\tconst writeFailed = async (message, extra) => {\n\t\tconst payload = { status: \"failed\", targetRoute: rowRoute, dayKey, context, error: message, ...(extra || {}), updated_at: new Date().toISOString() };\n\t\twriteJson(proofPath, payload);\n\t\twriteJson(businessAssertionPath, { assertion: String(row.assertion || row.required_proof || \"Part inventory snapshot warehouse attribution proof\"), status: \"failed\", result: \"business_assertion_failed\", outcome: \"business_assertion_failed\", workflow: rowWorkflow, route: rowRoute, before: \"\", action: \"Attempted deterministic reportDailyInventorySnapshot websocket method proof.\", expected: \"Affected Part rows return the yard named by snapshot metadata.id_yard instead of stale saved warehouse_location.\", after: \"\", observed: message, dataProof: message, mongoDelta: {}, artifactPaths: [proofPath, matrixPath], metadata: { supportDiagnosisProof: false, proofType: \"part_inventory_snapshot_report_method\", generatedBy: \"resolveio_runner_part_inventory_snapshot_business_proof\", generatedAt: new Date().toISOString() } });\n\t\tconst matrix = readJson(matrixPath) || { status: \"started\", rows: [] };\n\t\tconst rows = matrixRows(matrix);\n\t\tconst activeIndex = Math.max(0, rows.indexOf(row));\n\t\tif (rows[activeIndex]) { rows[activeIndex].status = \"failed\"; rows[activeIndex].result = \"failed\"; rows[activeIndex].acceptance_blocked = true; rows[activeIndex].blocker = message; rows[activeIndex].artifact = proofPath; }\n\t\tmatrix.rows = rows;\n\t\tmatrix.status = \"failed\";\n\t\tmatrix.part_inventory_snapshot_proof = proofPath;\n\t\tmatrix.aiqa_business_assertion = businessAssertionPath;\n\t\tmatrix.updated_at = new Date().toISOString();\n\t\twriteJson(matrixPath, matrix);\n\t\treturn payload;\n\t};\n\ttry {\n\t\tconst data = await readPartInventorySnapshotProofData(context, dayKey);\n\t\tif (!data.snapshots.length) return await writeFailed(\"No seeded Part inventory daily snapshot rows were available for day_key \" + dayKey + \".\");\n\t\tconst methodResult = await callResolveIOMethodViaWs(auth, rowRoute, \"reportDailyInventorySnapshot\", [methodDateFromDayKey(dayKey), [\"Parts\"]]);\n\t\tconst responseRows = Array.isArray(methodResult && methodResult.rows) ? methodResult.rows : [];\n\t\tconst comparisons = data.snapshots.map((snapshot) => {\n\t\t\tconst partId = partSnapshotRowPartId(snapshot);\n\t\t\tconst yardId = partSnapshotRowYardId(snapshot);\n\t\t\tconst yard = yardId ? data.yardById.get(String(yardId)) : null;\n\t\t\tconst expectedYardName = String(yard && yard.name || \"\").trim();\n\t\t\tconst beforeWarehouse = String(snapshot.warehouse_location || snapshot.location || \"\").trim();\n\t\t\tconst responseCandidates = responseRows.filter((candidate) => !partId || partSnapshotRowPartId(candidate) === partId || String(candidate.item_name || candidate.name || \"\") === String(snapshot.item_name || snapshot.name || \"\"));\n\t\t\tconst afterRow = responseCandidates.find((candidate) => expectedYardName && normalizeWarehouseName(candidate.warehouse_location || candidate.location) === normalizeWarehouseName(expectedYardName)) || responseCandidates[0] || null;\n\t\t\tconst afterWarehouse = String(afterRow && (afterRow.warehouse_location || afterRow.location) || \"\").trim();\n\t\t\tconst staleBefore = !!expectedYardName && !!beforeWarehouse && normalizeWarehouseName(beforeWarehouse) !== normalizeWarehouseName(expectedYardName);\n\t\t\treturn { partId, itemName: String(snapshot.item_name || snapshot.name || \"\"), dayKey: String(snapshot.day_key || \"\"), beforeWarehouse, expectedYardName, afterWarehouse, staleBefore, pass: staleBefore && !!afterWarehouse && normalizeWarehouseName(afterWarehouse) === normalizeWarehouseName(expectedYardName) };\n\t\t}).filter((entry) => entry.expectedYardName);\n\t\tconst staleRows = comparisons.filter((entry) => entry.staleBefore);\n\t\tconst passedRows = staleRows.filter((entry) => entry.pass);\n\t\tconst pass = staleRows.length > 0 && passedRows.length === staleRows.length;\n\t\tconst caption = pass\n\t\t\t? \"Part inventory snapshot proof passed: \" + passedRows.length + \" stale saved row(s) returned the authoritative yard warehouse in reportDailyInventorySnapshot.\"\n\t\t\t: \"Part inventory snapshot proof failed: staleRows=\" + staleRows.length + \", corrected=\" + passedRows.length + \".\";\n\t\tconst payload = { status: pass ? \"pass\" : \"failed\", targetRoute: rowRoute, dayKey, methodName: \"reportDailyInventorySnapshot\", context, snapshotCount: data.snapshots.length, responseRowCount: responseRows.length, staleRows: staleRows.length, correctedStaleRows: passedRows.length, comparisons, caption, screenshot: beforeAfterScreenshotPath, page: routeSummary, updated_at: new Date().toISOString() };\n\t\tawait renderPartInventorySnapshotProofScreenshot(page, payload, rowRoute, beforeAfterScreenshotPath).catch(() => undefined);\n\t\twriteJson(proofPath, payload);\n\t\tconst businessAssertion = {\n\t\t\tassertion: String(row.assertion || row.required_proof || \"Affected Part warehouse_location maps to authoritative yard lineage in reportDailyInventorySnapshot response.\").trim(),\n\t\t\tstatus: pass ? \"pass\" : \"failed\",\n\t\t\tresult: pass ? \"business_assertion_passed\" : \"business_assertion_failed\",\n\t\t\toutcome: pass ? \"business_assertion_passed\" : \"business_assertion_failed\",\n\t\t\tworkflow: rowWorkflow,\n\t\t\troute: rowRoute,\n\t\t\tbefore: \"Saved non-today Parts snapshot rows for day_key \" + dayKey + \" included \" + staleRows.length + \" stale warehouse_location value(s): \" + staleRows.map((entry) => (entry.itemName || entry.partId) + \"=\" + entry.beforeWarehouse).join(\"; \"),\n\t\t\taction: \"Called reportDailyInventorySnapshot(\" + dayKey + \", [\\\"Parts\\\"]) through the local QA websocket method path.\",\n\t\t\texpected: \"Every affected stale Part row returns the yard named by metadata.id_yard in warehouse_location.\",\n\t\t\tafter: \"Method response corrected \" + passedRows.length + \" of \" + staleRows.length + \" stale row(s): \" + passedRows.map((entry) => (entry.itemName || entry.partId) + \"=\" + entry.afterWarehouse).join(\"; \"),\n\t\t\tobserved: caption,\n\t\t\tdataProof: comparisons.map((entry) => (entry.itemName || entry.partId || \"part\") + \": before=\" + entry.beforeWarehouse + \", expected=\" + entry.expectedYardName + \", after=\" + entry.afterWarehouse + \", pass=\" + entry.pass).join(\"\\n\"),\n\t\t\tmongoDelta: { collection: \"inventory-daily-snapshots\", day_key: dayKey, staleRows: staleRows.length, correctedStaleRows: passedRows.length, responseRowCount: responseRows.length },\n\t\t\tartifactPaths: [proofPath, beforeAfterScreenshotPath, matrixPath],\n\t\t\tmetadata: { supportDiagnosisProof: pass, proofType: \"part_inventory_snapshot_report_method\", methodPath: \"server/src/methods/report.ts reportDailyInventorySnapshot\", generatedBy: \"resolveio_runner_part_inventory_snapshot_business_proof\", generatedAt: new Date().toISOString() }\n\t\t};\n\t\twriteJson(businessAssertionPath, businessAssertion);\n\t\tconst matrix = readJson(matrixPath) || { status: \"started\", rows: [] };\n\t\tconst rows = matrixRows(matrix);\n\t\tconst rowIndex = rows.findIndex((candidate) => String(candidate && candidate.workflow || \"\") === rowWorkflow) >= 0 ? rows.findIndex((candidate) => String(candidate && candidate.workflow || \"\") === rowWorkflow) : rows.findIndex((candidate) => !/^(pass|passed)$/i.test(String(candidate && candidate.status || \"\")));\n\t\tconst activeIndex = rowIndex >= 0 ? rowIndex : 0;\n\t\tif (rows[activeIndex]) {\n\t\t\trows[activeIndex].status = pass ? \"pass\" : \"failed\";\n\t\t\trows[activeIndex].result = pass ? \"pass\" : \"failed\";\n\t\t\trows[activeIndex].acceptance_blocked = !pass;\n\t\t\trows[activeIndex].screenshot = beforeAfterScreenshotPath;\n\t\t\trows[activeIndex].screenshots = [beforeAfterScreenshotPath, passScreenshotPath].filter(Boolean);\n\t\t\trows[activeIndex].caption = caption;\n\t\t\trows[activeIndex].artifact = proofPath;\n\t\t\trows[activeIndex].artifacts = [{ path: proofPath, caption: \"Part inventory snapshot method response proof.\" }, { screenshot: beforeAfterScreenshotPath, caption }, { path: businessAssertionPath, caption: \"AIQaBusinessAssertion for support diagnosis proof plan.\" }];\n\t\t\trows[activeIndex].persisted_assertion = businessAssertion.dataProof;\n\t\t\tif (!pass) rows[activeIndex].blocker = caption;\n\t\t}\n\t\tmatrix.rows = rows;\n\t\tmatrix.status = pass ? \"pass\" : \"failed\";\n\t\tmatrix.part_inventory_snapshot_proof = proofPath;\n\t\tmatrix.aiqa_business_assertion = businessAssertionPath;\n\t\tmatrix.updated_at = new Date().toISOString();\n\t\twriteJson(matrixPath, matrix);\n\t\treturn payload;\n\t} catch (error) {\n\t\treturn await writeFailed(error && (error.stack || error.message) || String(error));\n\t}\n}\n"]))).trim().split('\n');
|
|
2708
|
+
}
|
|
2677
2709
|
function buildResolveIORunnerQaWorkflowProbeScript() {
|
|
2678
|
-
return [
|
|
2710
|
+
return __spreadArray(__spreadArray([
|
|
2679
2711
|
'#!/usr/bin/env node',
|
|
2680
2712
|
"'use strict';",
|
|
2681
2713
|
'',
|
|
@@ -3457,7 +3489,8 @@ function buildResolveIORunnerQaWorkflowProbeScript() {
|
|
|
3457
3489
|
' matrix.updated_at = new Date().toISOString();',
|
|
3458
3490
|
' writeJson(matrixPath, matrix);',
|
|
3459
3491
|
' return payload;',
|
|
3460
|
-
'}'
|
|
3492
|
+
'}'
|
|
3493
|
+
], __read(buildResolveIOPartInventorySnapshotProofScriptLines()), false), [
|
|
3461
3494
|
'function updateMatrix(status, screenshotPath, caption, assertion) {',
|
|
3462
3495
|
' const matrix = readJson(matrixPath) || { status: "started", rows: [] };',
|
|
3463
3496
|
' const routeProbePassed = status === "route_probe_pass" || status === "pass";',
|
|
@@ -3500,6 +3533,11 @@ function buildResolveIORunnerQaWorkflowProbeScript() {
|
|
|
3500
3533
|
' let specializedProofPath = specializedProof ? path.join(artifactDir, "qa-pricing-import-proof.json") : "";',
|
|
3501
3534
|
' let specializedProofLabel = specializedProof ? "Pricing import workbook business proof" : "";',
|
|
3502
3535
|
' if (!specializedProof) {',
|
|
3536
|
+
' specializedProof = await runPartInventorySnapshotMethodProof(page, summary, auth);',
|
|
3537
|
+
' specializedProofPath = specializedProof ? path.join(artifactDir, "qa-part-inventory-snapshot-proof.json") : "";',
|
|
3538
|
+
' specializedProofLabel = specializedProof ? "Part inventory snapshot report method business proof" : "";',
|
|
3539
|
+
' }',
|
|
3540
|
+
' if (!specializedProof) {',
|
|
3503
3541
|
' specializedProof = await runAssetLocationRowProof(page, summary);',
|
|
3504
3542
|
' specializedProofPath = specializedProof ? path.join(artifactDir, "qa-asset-location-proof.json") : "";',
|
|
3505
3543
|
' specializedProofLabel = specializedProof ? "Asset location list/detail/edit business proof" : "";',
|
|
@@ -3549,7 +3587,7 @@ function buildResolveIORunnerQaWorkflowProbeScript() {
|
|
|
3549
3587
|
' }',
|
|
3550
3588
|
'})();',
|
|
3551
3589
|
''
|
|
3552
|
-
].join('\n');
|
|
3590
|
+
], false).join('\n');
|
|
3553
3591
|
}
|
|
3554
3592
|
function buildResolveIORunnerQaToolsReadme(options) {
|
|
3555
3593
|
if (options === void 0) { options = {}; }
|
|
@@ -3588,6 +3626,7 @@ function buildResolveIORunnerQaToolsReadme(options) {
|
|
|
3588
3626
|
'For From/To, source/target, dropdown, combobox, rio-select, filter, item, customer, yard, chemical, or treatment-plan selection workflows, capture pass screenshots only after the selected values are visible in the controls/chips/labels. The QA matrix data/assertion/caption must name the selected values; empty controls, placeholder text, or route-load screenshots are blocker evidence, not pass evidence.',
|
|
3589
3627
|
'For import/export/form-submit/data workflows, prove before/action/after with representative data and a concrete row/count/value assertion.',
|
|
3590
3628
|
'For pricing import/upload bugs, drive the actual Manage Pricing browser import for the attached/template variants and assert localhost Mongo pricing row/count/value changes. Validator-only proof must fail.',
|
|
3629
|
+
'For Part Inventory Snapshot / reportDailyInventorySnapshot warehouse bugs, use the deterministic method proof in `qa-workflow-probe.js`: it calls the local websocket method for the seeded day/Parts section, compares returned `warehouse_location` values against seeded yard lineage, and writes `aiqa-business-assertion.json` plus `support-business-proof-before-after.png` without launching another model or Angular build.',
|
|
3591
3630
|
'For asset location/current-yard bugs, prove the exact asset/unit on list, detail, and edit/save screens, with a joined/canonical yard assertion and stale yard name absence proof.',
|
|
3592
3631
|
'For Update Interchangeables/Mass Update chemical bugs, select the real source and target chemicals, run the update, and assert before/after treatment-plan/tank document counts or ids in localhost Mongo. Route-load or dropdown-only proof must fail.',
|
|
3593
3632
|
'For data-backed workflows, run `qa-live-data-seed.js` after the local app is ready and before browser clickthrough. It reads a bounded live-data slice from `RESOLVEIO_QA_LIVE_MONGO_URL` or staged mongo context, writes only to localhost QA Mongo, prefers ticket-mentioned invoice/BOL/order/ticket identifiers, and records `qa-artifacts/qa-live-data-seed-result.json`.',
|
|
@@ -3602,5 +3641,6 @@ function buildResolveIORunnerQaToolsReadme(options) {
|
|
|
3602
3641
|
''
|
|
3603
3642
|
].filter(function (line) { return line !== ''; }).join('\n');
|
|
3604
3643
|
}
|
|
3644
|
+
var templateObject_1;
|
|
3605
3645
|
|
|
3606
3646
|
//# sourceMappingURL=ai-runner-qa-tools.js.map
|