ProofRun · Recorded execution evidence
This is a preserved report from a real completed local execution, not a fresh cloud test. It stays available without an IBM API key.
Open cloud testing workspace · Download full evidence · Source and local setup
Shipping Service is a small checkout web application for online shoppers. A shopper enters their order subtotal on a form and instantly sees the delivery charge and final total before paying. Orders under $100 are charged a flat $5 shipping fee; orders of $100 or more ship free. There is no payment system or external service — it is a self-contained quote calculator.
| Test | Result | Evidence |
|---|---|---|
| Run unit tests | passed | Execution evidence{
"id": "existing-0",
"title": "Run unit tests",
"category": "existing test suite",
"expected": "Command completes with exit code 0",
"outcome": "passed",
"contractHash": "8a52d0d692598ab150bb6ab288a480aa92e99f92a2e17b3a25701dad124f37a0",
"logs": "TAP version 13\n# Subtest: ordinary orders have a five dollar delivery charge\nok 1 - ordinary orders have a five dollar delivery charge\n ---\n duration_ms: 1.7721\n type: 'test'\n ...\n# Subtest: large orders ship free\nok 2 - large orders ship free\n ---\n duration_ms: 0.2764\n type: 'test'\n ...\n# Subtest: invalid amounts are rejected\nok 3 - invalid amounts are rejected\n ---\n duration_ms: 0.1984\n type: 'test'\n ...\n1..3\n# tests 3\n# suites 0\n# pass 3\n# fail 0\n# cancelled 0\n# skipped 0\n# todo 0\n# duration_ms 89.301\n\n",
"trace": [
{
"label": "Run unit tests",
"request": {
"argv": [
"node",
"--test",
"tests/*.test.mjs"
]
},
"response": {
"exitCode": 0
},
"error": null
}
]
} |
| Normal quote below $100 | passed | Execution evidence{
"id": "http-1",
"title": "Normal quote below $100",
"intent": "Verify a standard paid-shipping order returns correct subtotal, shipping, and total",
"expected": "{subtotal:50,shipping:5,total:55} with status 200",
"basis": "documented",
"category": "normal",
"outcome": "passed",
"trace": [
{
"label": "GET /quote?subtotal=50",
"request": {
"method": "GET",
"path": "/quote?subtotal=50",
"headers": {},
"body": null
},
"response": {
"status": 200,
"headers": {
"connection": "keep-alive",
"content-type": "application/json",
"date": "Sun, 27 Sep 2026 12:54:37 GMT",
"keep-alive": "timeout=5",
"transfer-encoding": "chunked"
},
"body": "{\"subtotal\":50,\"shipping\":5,\"total\":55}",
"truncated": false
},
"assertions": [
{
"kind": "status",
"equals": 200,
"actual": 200,
"passed": true
},
{
"kind": "json",
"path": "subtotal",
"equals": 50,
"actual": 50,
"passed": true
},
{
"kind": "json",
"path": "shipping",
"equals": 5,
"actual": 5,
"passed": true
},
{
"kind": "json",
"path": "total",
"equals": 55,
"actual": 55,
"passed": true
}
],
"error": null
},
{
"label": "GET /quote?subtotal=0.01 (minimum valid)",
"request": {
"method": "GET",
"path": "/quote?subtotal=0.01",
"headers": {},
"body": null
},
"response": {
"status": 200,
"headers": {
"connection": "keep-alive",
"content-type": "application/json",
"date": "Sun, 27 Sep 2026 12:54:37 GMT",
"keep-alive": "timeout=5",
"transfer-encoding": "chunked"
},
"body": "{\"subtotal\":0.01,\"shipping\":5,\"total\":5.01}",
"truncated": false
},
"assertions": [
{
"kind": "status",
"equals": 200,
"actual": 200,
"passed": true
},
{
"kind": "json",
"path": "subtotal",
"equals": 0.01,
"actual": 0.01,
"passed": true
},
{
"kind": "json",
"path": "shipping",
"equals": 5,
"actual": 5,
"passed": true
},
{
"kind": "json",
"path": "total",
"equals": 5.01,
"actual": 5.01,
"passed": true
}
],
"error": null
},
{
"label": "GET /quote?subtotal=99.99 (just below free-shipping boundary)",
"request": {
"method": "GET",
"path": "/quote?subtotal=99.99",
"headers": {},
"body": null
},
"response": {
"status": 200,
"headers": {
"connection": "keep-alive",
"content-type": "application/json",
"date": "Sun, 27 Sep 2026 12:54:37 GMT",
"keep-alive": "timeout=5",
"transfer-encoding": "chunked"
},
"body": "{\"subtotal\":99.99,\"shipping\":5,\"total\":104.99}",
"truncated": false
},
"assertions": [
{
"kind": "status",
"equals": 200,
"actual": 200,
"passed": true
},
{
"kind": "json",
"path": "shipping",
"equals": 5,
"actual": 5,
"passed": true
},
{
"kind": "json",
"path": "total",
"equals": 104.99,
"actual": 104.99,
"passed": true
}
],
"error": null
},
{
"label": "GET /quote?subtotal=10000 (maximum valid)",
"request": {
"method": "GET",
"path": "/quote?subtotal=10000",
"headers": {},
"body": null
},
"response": {
"status": 200,
"headers": {
"connection": "keep-alive",
"content-type": "application/json",
"date": "Sun, 27 Sep 2026 12:54:37 GMT",
"keep-alive": "timeout=5",
"transfer-encoding": "chunked"
},
"body": "{\"subtotal\":10000,\"shipping\":0,\"total\":10000}",
"truncated": false
},
"assertions": [
{
"kind": "status",
"equals": 200,
"actual": 200,
"passed": true
},
{
"kind": "json",
"path": "shipping",
"equals": 0,
"actual": 0,
"passed": true
},
{
"kind": "json",
"path": "total",
"equals": 10000,
"actual": 10000,
"passed": true
}
],
"error": null
}
],
"failedAssertions": 0,
"incomplete": 0,
"durationMs": 94,
"logs": "[stdout] Shipping service ready\n",
"contractHash": "5dee0c0e48f9f4e0871f4bf944860d63a640be4a4f9dcc0602072941f15679e6"
} |
| Free-shipping boundary at exactly $100 | failed | Execution evidence{
"id": "http-2",
"title": "Free-shipping boundary at exactly $100",
"intent": "Expose the deliberate defect: subtotal=100 should yield shipping=0 but the > condition charges $5",
"expected": "Status 200 with shipping:0 and total:100 (current code fails this — shipping.mjs uses > instead of >=)",
"basis": "assumption",
"category": "boundary",
"outcome": "failed",
"trace": [
{
"label": "GET /quote?subtotal=100 (boundary — free shipping spec)",
"request": {
"method": "GET",
"path": "/quote?subtotal=100",
"headers": {},
"body": null
},
"response": {
"status": 200,
"headers": {
"connection": "keep-alive",
"content-type": "application/json",
"date": "Sun, 27 Sep 2026 12:54:37 GMT",
"keep-alive": "timeout=5",
"transfer-encoding": "chunked"
},
"body": "{\"subtotal\":100,\"shipping\":5,\"total\":105}",
"truncated": false
},
"assertions": [
{
"kind": "status",
"equals": 200,
"actual": 200,
"passed": true
},
{
"kind": "json",
"path": "subtotal",
"equals": 100,
"actual": 100,
"passed": true
},
{
"kind": "json",
"path": "shipping",
"equals": 0,
"actual": 5,
"passed": false
},
{
"kind": "json",
"path": "total",
"equals": 100,
"actual": 105,
"passed": false
}
],
"error": null
},
{
"label": "GET /quote?subtotal=100.01 (just above boundary — confirmed free shipping)",
"request": {
"method": "GET",
"path": "/quote?subtotal=100.01",
"headers": {},
"body": null
},
"response": {
"status": 200,
"headers": {
"connection": "keep-alive",
"content-type": "application/json",
"date": "Sun, 27 Sep 2026 12:54:37 GMT",
"keep-alive": "timeout=5",
"transfer-encoding": "chunked"
},
"body": "{\"subtotal\":100.01,\"shipping\":0,\"total\":100.01}",
"truncated": false
},
"assertions": [
{
"kind": "status",
"equals": 200,
"actual": 200,
"passed": true
},
{
"kind": "json",
"path": "shipping",
"equals": 0,
"actual": 0,
"passed": true
},
{
"kind": "json",
"path": "total",
"equals": 100.01,
"actual": 100.01,
"passed": true
}
],
"error": null
}
],
"failedAssertions": 2,
"incomplete": 0,
"durationMs": 88,
"logs": "[stdout] Shipping service ready\n",
"contractHash": "73e516c1ba9a925f2bd8059266f647d87c9c19a560719bdababa31114b2da604"
} |
| Unknown routes return 404 | passed | Execution evidence{
"id": "http-4",
"title": "Unknown routes return 404",
"intent": "Confirm the server responds 404 with an error body for any unregistered path",
"expected": "Status 404 and JSON error body for unrecognised paths; POST /quote also 404",
"basis": "documented",
"category": "adversarial",
"outcome": "passed",
"trace": [
{
"label": "GET /unknown",
"request": {
"method": "GET",
"path": "/unknown",
"headers": {},
"body": null
},
"response": {
"status": 404,
"headers": {
"connection": "keep-alive",
"content-type": "application/json",
"date": "Sun, 27 Sep 2026 12:54:41 GMT",
"keep-alive": "timeout=5",
"transfer-encoding": "chunked"
},
"body": "{\"error\":\"Route not found\"}",
"truncated": false
},
"assertions": [
{
"kind": "status",
"equals": 404,
"actual": 404,
"passed": true
},
{
"kind": "json",
"path": "error",
"equals": "Route not found",
"actual": "Route not found",
"passed": true
}
],
"error": null
},
{
"label": "GET /Quote (case-sensitive)",
"request": {
"method": "GET",
"path": "/Quote",
"headers": {},
"body": null
},
"response": {
"status": 404,
"headers": {
"connection": "keep-alive",
"content-type": "application/json",
"date": "Sun, 27 Sep 2026 12:54:41 GMT",
"keep-alive": "timeout=5",
"transfer-encoding": "chunked"
},
"body": "{\"error\":\"Route not found\"}",
"truncated": false
},
"assertions": [
{
"kind": "status",
"equals": 404,
"actual": 404,
"passed": true
}
],
"error": null
},
{
"label": "POST /quote (method not allowed — treated as 404 by router)",
"request": {
"method": "POST",
"path": "/quote",
"headers": {
"content-type": "application/json"
},
"body": "null"
},
"response": {
"status": 404,
"headers": {
"connection": "keep-alive",
"content-type": "application/json",
"date": "Sun, 27 Sep 2026 12:54:41 GMT",
"keep-alive": "timeout=5",
"transfer-encoding": "chunked"
},
"body": "{\"error\":\"Route not found\"}",
"truncated": false
},
"assertions": [
{
"kind": "status",
"equals": 404,
"actual": 404,
"passed": true
}
],
"error": null
},
{
"label": "GET /quote/ (trailing slash)",
"request": {
"method": "GET",
"path": "/quote/",
"headers": {},
"body": null
},
"response": {
"status": 404,
"headers": {
"connection": "keep-alive",
"content-type": "application/json",
"date": "Sun, 27 Sep 2026 12:54:41 GMT",
"keep-alive": "timeout=5",
"transfer-encoding": "chunked"
},
"body": "{\"error\":\"Route not found\"}",
"truncated": false
},
"assertions": [
{
"kind": "status",
"equals": 404,
"actual": 404,
"passed": true
}
],
"error": null
}
],
"failedAssertions": 0,
"incomplete": 0,
"durationMs": 80,
"logs": "[stdout] Shipping service ready\n",
"contractHash": "21c2b7f6ca2b1e057d3d0fa2f6173653ee650a951d122f8f01ee3b0f4cb086ec"
} |
| Invalid and missing subtotal inputs return 400 | passed | Execution evidence{
"id": "http-3",
"title": "Invalid and missing subtotal inputs return 400",
"intent": "Validate rejection of zero, negative, non-numeric, blank, missing, and over-limit values",
"expected": "Status 400 with an error field for every case",
"basis": "documented",
"category": "adversarial",
"outcome": "passed",
"trace": [
{
"label": "GET /quote?subtotal=0",
"request": {
"method": "GET",
"path": "/quote?subtotal=0",
"headers": {},
"body": null
},
"response": {
"status": 400,
"headers": {
"connection": "keep-alive",
"content-type": "application/json",
"date": "Sun, 27 Sep 2026 12:54:41 GMT",
"keep-alive": "timeout=5",
"transfer-encoding": "chunked"
},
"body": "{\"error\":\"Subtotal must be a number greater than 0 and at most 10000\"}",
"truncated": false
},
"assertions": [
{
"kind": "status",
"equals": 400,
"actual": 400,
"passed": true
},
{
"kind": "json",
"path": "error",
"equals": "Subtotal must be a number greater than 0 and at most 10000",
"actual": "Subtotal must be a number greater than 0 and at most 10000",
"passed": true
}
],
"error": null
},
{
"label": "GET /quote?subtotal=-1",
"request": {
"method": "GET",
"path": "/quote?subtotal=-1",
"headers": {},
"body": null
},
"response": {
"status": 400,
"headers": {
"connection": "keep-alive",
"content-type": "application/json",
"date": "Sun, 27 Sep 2026 12:54:41 GMT",
"keep-alive": "timeout=5",
"transfer-encoding": "chunked"
},
"body": "{\"error\":\"Subtotal must be a number greater than 0 and at most 10000\"}",
"truncated": false
},
"assertions": [
{
"kind": "status",
"equals": 400,
"actual": 400,
"passed": true
},
{
"kind": "contains",
"value": "error",
"actual": "{\"error\":\"Subtotal must be a number greater than 0 and at most 10000\"}",
"passed": true
}
],
"error": null
},
{
"label": "GET /quote?subtotal=10001 (over limit)",
"request": {
"method": "GET",
"path": "/quote?subtotal=10001",
"headers": {},
"body": null
},
"response": {
"status": 400,
"headers": {
"connection": "keep-alive",
"content-type": "application/json",
"date": "Sun, 27 Sep 2026 12:54:41 GMT",
"keep-alive": "timeout=5",
"transfer-encoding": "chunked"
},
"body": "{\"error\":\"Subtotal must be a number greater than 0 and at most 10000\"}",
"truncated": false
},
"assertions": [
{
"kind": "status",
"equals": 400,
"actual": 400,
"passed": true
},
{
"kind": "contains",
"value": "error",
"actual": "{\"error\":\"Subtotal must be a number greater than 0 and at most 10000\"}",
"passed": true
}
],
"error": null
},
{
"label": "GET /quote?subtotal=abc (non-numeric)",
"request": {
"method": "GET",
"path": "/quote?subtotal=abc",
"headers": {},
"body": null
},
"response": {
"status": 400,
"headers": {
"connection": "keep-alive",
"content-type": "application/json",
"date": "Sun, 27 Sep 2026 12:54:41 GMT",
"keep-alive": "timeout=5",
"transfer-encoding": "chunked"
},
"body": "{\"error\":\"Subtotal must be a number greater than 0 and at most 10000\"}",
"truncated": false
},
"assertions": [
{
"kind": "status",
"equals": 400,
"actual": 400,
"passed": true
},
{
"kind": "contains",
"value": "error",
"actual": "{\"error\":\"Subtotal must be a number greater than 0 and at most 10000\"}",
"passed": true
}
],
"error": null
},
{
"label": "GET /quote?subtotal= (blank)",
"request": {
"method": "GET",
"path": "/quote?subtotal=",
"headers": {},
"body": null
},
"response": {
"status": 400,
"headers": {
"connection": "keep-alive",
"content-type": "application/json",
"date": "Sun, 27 Sep 2026 12:54:41 GMT",
"keep-alive": "timeout=5",
"transfer-encoding": "chunked"
},
"body": "{\"error\":\"Subtotal must be a number greater than 0 and at most 10000\"}",
"truncated": false
},
"assertions": [
{
"kind": "status",
"equals": 400,
"actual": 400,
"passed": true
},
{
"kind": "contains",
"value": "error",
"actual": "{\"error\":\"Subtotal must be a number greater than 0 and at most 10000\"}",
"passed": true
}
],
"error": null
},
{
"label": "GET /quote (missing param)",
"request": {
"method": "GET",
"path": "/quote",
"headers": {},
"body": null
},
"response": {
"status": 400,
"headers": {
"connection": "keep-alive",
"content-type": "application/json",
"date": "Sun, 27 Sep 2026 12:54:41 GMT",
"keep-alive": "timeout=5",
"transfer-encoding": "chunked"
},
"body": "{\"error\":\"Subtotal must be a number greater than 0 and at most 10000\"}",
"truncated": false
},
"assertions": [
{
"kind": "status",
"equals": 400,
"actual": 400,
"passed": true
},
{
"kind": "contains",
"value": "error",
"actual": "{\"error\":\"Subtotal must be a number greater than 0 and at most 10000\"}",
"passed": true
}
],
"error": null
},
{
"label": "GET /quote?subtotal=Infinity",
"request": {
"method": "GET",
"path": "/quote?subtotal=Infinity",
"headers": {},
"body": null
},
"response": {
"status": 400,
"headers": {
"connection": "keep-alive",
"content-type": "application/json",
"date": "Sun, 27 Sep 2026 12:54:41 GMT",
"keep-alive": "timeout=5",
"transfer-encoding": "chunked"
},
"body": "{\"error\":\"Subtotal must be a number greater than 0 and at most 10000\"}",
"truncated": false
},
"assertions": [
{
"kind": "status",
"equals": 400,
"actual": 400,
"passed": true
},
{
"kind": "contains",
"value": "error",
"actual": "{\"error\":\"Subtotal must be a number greater than 0 and at most 10000\"}",
"passed": true
}
],
"error": null
}
],
"failedAssertions": 0,
"incomplete": 0,
"durationMs": 90,
"logs": "[stdout] Shipping service ready\n",
"contractHash": "b36c5e0cc049e37ea439818b9aead714dd2ddba4e7d4d3eeeafb0c09453d50d2"
} |
| GET / serves the HTML checkout page | passed | Execution evidence{
"id": "http-5",
"title": "GET / serves the HTML checkout page",
"intent": "Confirm the homepage returns the HTML form with correct content-type",
"expected": "Status 200, content-type text/html, body contains the form",
"basis": "documented",
"category": "normal",
"outcome": "passed",
"trace": [
{
"label": "GET /",
"request": {
"method": "GET",
"path": "/",
"headers": {},
"body": null
},
"response": {
"status": 200,
"headers": {
"connection": "keep-alive",
"content-length": "1108",
"content-type": "text/html; charset=utf-8",
"date": "Sun, 27 Sep 2026 12:54:45 GMT",
"keep-alive": "timeout=5"
},
"body": "<!doctype html><html lang=\"en\"><meta charset=\"utf-8\"><title>Shipping quote</title><style>body{font:18px system-ui;color:#23372e;background:#f5f5ef;margin:80px auto;max-width:560px}main{background:white;padding:40px;border:1px solid #dde3db;border-radius:8px}input,button{font:inherit;padding:12px}button{background:#2e5747;color:white;border:0}label{display:block;margin:24px 0 8px}output{display:block;margin-top:24px}</style><main><small>CHECKOUT</small><h1>Know your total.</h1><p>Delivery is $5. Orders of $100 or more ship free.</p><form><label for=\"subtotal\">Order subtotal ($)</label><input id=\"subtotal\" name=\"subtotal\" type=\"number\" step=\"0.01\" value=\"100\" required><button>Get quote</button></form><output aria-live=\"polite\" id=\"quote\"></output></main><script>document.querySelector('form').onsubmit=async e=>{e.preventDefault();const r=await fetch('/quote?subtotal='+encodeURIComponent(document.querySelector('#subtotal').value));const q=await r.json();document.querySelector('#quote').textContent=q.error||('Delivery: $'+q.shipping.toFixed(2)+' · Total: $'+q.total.toFixed(2));};</script></html>",
"truncated": false
},
"assertions": [
{
"kind": "status",
"equals": 200,
"actual": 200,
"passed": true
},
{
"kind": "header",
"name": "content-type",
"equals": "text/html; charset=utf-8",
"actual": "text/html; charset=utf-8",
"passed": true
},
{
"kind": "contains",
"value": "<form>",
"actual": "<!doctype html><html lang=\"en\"><meta charset=\"utf-8\"><title>Shipping quote</title><style>body{font:18px system-ui;color:#23372e;background:#f5f5ef;margin:80px auto;max-width:560px}main{background:white;padding:40px;border:1px solid #dde3db;border-radius:8px}input,button{font:inherit;padding:12px}button{background:#2e5747;color:white;border:0}label{display:block;margin:24px 0 8px}output{display:block;margin-top:24px}</style><main><small>CHECKOUT</small><h1>Know your total.</h1><p>Delivery is $5. Orders of $100 or more ship free.</p><form><label for=\"subtotal\">Order subtotal ($)</label><input id=\"subtotal\" name=\"subtotal\" type=\"number\" step=\"0.01\" value=\"100\" required><button>Get quote</button></form><output aria-live=\"polite\" id=\"quote\"></output></main><script>document.querySelector('form').onsubmit=async e=>{e.preventDefault();const r=await fetch('/quote?subtotal='+encodeURIComponent(document.querySelector('#subtotal').value));const q=await r.json();document.querySelector('#quote').textContent=q.error||('Delivery: $'+q.shipping.toFixed(2)+' · Total: $'+q.total.toFixed(2));};</script></html>",
"passed": true
},
{
"kind": "contains",
"value": "subtotal",
"actual": "<!doctype html><html lang=\"en\"><meta charset=\"utf-8\"><title>Shipping quote</title><style>body{font:18px system-ui;color:#23372e;background:#f5f5ef;margin:80px auto;max-width:560px}main{background:white;padding:40px;border:1px solid #dde3db;border-radius:8px}input,button{font:inherit;padding:12px}button{background:#2e5747;color:white;border:0}label{display:block;margin:24px 0 8px}output{display:block;margin-top:24px}</style><main><small>CHECKOUT</small><h1>Know your total.</h1><p>Delivery is $5. Orders of $100 or more ship free.</p><form><label for=\"subtotal\">Order subtotal ($)</label><input id=\"subtotal\" name=\"subtotal\" type=\"number\" step=\"0.01\" value=\"100\" required><button>Get quote</button></form><output aria-live=\"polite\" id=\"quote\"></output></main><script>document.querySelector('form').onsubmit=async e=>{e.preventDefault();const r=await fetch('/quote?subtotal='+encodeURIComponent(document.querySelector('#subtotal').value));const q=await r.json();document.querySelector('#quote').textContent=q.error||('Delivery: $'+q.shipping.toFixed(2)+' · Total: $'+q.total.toFixed(2));};</script></html>",
"passed": true
}
],
"error": null
}
],
"failedAssertions": 0,
"incomplete": 0,
"durationMs": 158,
"logs": "[stdout] Shipping service ready\n",
"contractHash": "b3044b7617f736aa6a0f9f27f5fc259837a464b9267d6f7b9d8a5298686218b4"
} |
| Content-type is application/json on API responses | passed | Execution evidence{
"id": "http-6",
"title": "Content-type is application/json on API responses",
"intent": "Ensure the API sets the correct content-type header for both success and error responses",
"expected": "content-type: application/json on 200 and 400 responses",
"basis": "documented",
"category": "normal",
"outcome": "passed",
"trace": [
{
"label": "Successful quote content-type",
"request": {
"method": "GET",
"path": "/quote?subtotal=50",
"headers": {},
"body": null
},
"response": {
"status": 200,
"headers": {
"connection": "keep-alive",
"content-type": "application/json",
"date": "Sun, 27 Sep 2026 12:54:45 GMT",
"keep-alive": "timeout=5",
"transfer-encoding": "chunked"
},
"body": "{\"subtotal\":50,\"shipping\":5,\"total\":55}",
"truncated": false
},
"assertions": [
{
"kind": "status",
"equals": 200,
"actual": 200,
"passed": true
},
{
"kind": "header",
"name": "content-type",
"equals": "application/json",
"actual": "application/json",
"passed": true
}
],
"error": null
},
{
"label": "Error response content-type",
"request": {
"method": "GET",
"path": "/quote?subtotal=0",
"headers": {},
"body": null
},
"response": {
"status": 400,
"headers": {
"connection": "keep-alive",
"content-type": "application/json",
"date": "Sun, 27 Sep 2026 12:54:45 GMT",
"keep-alive": "timeout=5",
"transfer-encoding": "chunked"
},
"body": "{\"error\":\"Subtotal must be a number greater than 0 and at most 10000\"}",
"truncated": false
},
"assertions": [
{
"kind": "status",
"equals": 400,
"actual": 400,
"passed": true
},
{
"kind": "header",
"name": "content-type",
"equals": "application/json",
"actual": "application/json",
"passed": true
}
],
"error": null
}
],
"failedAssertions": 0,
"incomplete": 0,
"durationMs": 152,
"logs": "[stdout] Shipping service ready\n",
"contractHash": "6fd73083be10e45c3da392938d3994a5b4135d55b1b89e20a787882059dfe361"
} |
| Malformed and unexpected inputs: POST /quote | passed | Execution evidence{
"id": "adversarial-0",
"title": "Malformed and unexpected inputs: POST /quote",
"intent": "Exercise malformed JSON, null, arrays, missing values, unexpected types and numeric boundaries. Detect unhandled HTTP 5xx responses.",
"expected": "Bad inputs are handled without an unhandled server error. Exact domain rejection status is not assumed.",
"basis": "assumption",
"category": "input-validation",
"outcome": "passed",
"trace": [
{
"label": "Malformed JSON",
"request": {
"method": "POST",
"path": "/quote",
"headers": {
"content-type": "application/json"
},
"body": "{\"broken\":"
},
"response": {
"status": 404,
"headers": {
"connection": "keep-alive",
"content-type": "application/json",
"date": "Sun, 27 Sep 2026 12:54:49 GMT",
"keep-alive": "timeout=5",
"transfer-encoding": "chunked"
},
"body": "{\"error\":\"Route not found\"}",
"truncated": false
},
"assertions": [
{
"kind": "not5xx",
"actual": 404,
"passed": true
}
],
"error": null
},
{
"label": "Unexpected input 0",
"request": {
"method": "POST",
"path": "/quote",
"headers": {
"content-type": "application/json"
},
"body": "null"
},
"response": {
"status": 404,
"headers": {
"connection": "keep-alive",
"content-type": "application/json",
"date": "Sun, 27 Sep 2026 12:54:49 GMT",
"keep-alive": "timeout=5",
"transfer-encoding": "chunked"
},
"body": "{\"error\":\"Route not found\"}",
"truncated": false
},
"assertions": [
{
"kind": "not5xx",
"actual": 404,
"passed": true
}
],
"error": null
},
{
"label": "Unexpected input 1",
"request": {
"method": "POST",
"path": "/quote",
"headers": {
"content-type": "application/json"
},
"body": "[]"
},
"response": {
"status": 404,
"headers": {
"connection": "keep-alive",
"content-type": "application/json",
"date": "Sun, 27 Sep 2026 12:54:49 GMT",
"keep-alive": "timeout=5",
"transfer-encoding": "chunked"
},
"body": "{\"error\":\"Route not found\"}",
"truncated": false
},
"assertions": [
{
"kind": "not5xx",
"actual": 404,
"passed": true
}
],
"error": null
},
{
"label": "Unexpected input 2",
"request": {
"method": "POST",
"path": "/quote",
"headers": {
"content-type": "application/json"
},
"body": "{}"
},
"response": {
"status": 404,
"headers": {
"connection": "keep-alive",
"content-type": "application/json",
"date": "Sun, 27 Sep 2026 12:54:49 GMT",
"keep-alive": "timeout=5",
"transfer-encoding": "chunked"
},
"body": "{\"error\":\"Route not found\"}",
"truncated": false
},
"assertions": [
{
"kind": "not5xx",
"actual": 404,
"passed": true
}
],
"error": null
},
{
"label": "Unexpected input 3",
"request": {
"method": "POST",
"path": "/quote",
"headers": {
"content-type": "application/json"
},
"body": "\"unexpected\""
},
"response": {
"status": 404,
"headers": {
"connection": "keep-alive",
"content-type": "application/json",
"date": "Sun, 27 Sep 2026 12:54:49 GMT",
"keep-alive": "timeout=5",
"transfer-encoding": "chunked"
},
"body": "{\"error\":\"Route not found\"}",
"truncated": false
},
"assertions": [
{
"kind": "not5xx",
"actual": 404,
"passed": true
}
],
"error": null
},
{
"label": "Unexpected input 4",
"request": {
"method": "POST",
"path": "/quote",
"headers": {
"content-type": "application/json"
},
"body": "{}"
},
"response": {
"status": 404,
"headers": {
"connection": "keep-alive",
"content-type": "application/json",
"date": "Sun, 27 Sep 2026 12:54:49 GMT",
"keep-alive": "timeout=5",
"transfer-encoding": "chunked"
},
"body": "{\"error\":\"Route not found\"}",
"truncated": false
},
"assertions": [
{
"kind": "not5xx",
"actual": 404,
"passed": true
}
],
"error": null
}
],
"failedAssertions": 0,
"incomplete": 0,
"durationMs": 114,
"logs": "[stdout] Shipping service ready\n",
"contractHash": "006c3b0e2378c8a795662ca896ebaab9271ee50a5e6e3097088188255f73f716"
} |
| Happy-path quote submission | passed | Execution evidence{
"id": "browser-1",
"title": "Happy-path quote submission",
"intent": "User enters a valid subtotal, submits the form, and sees the delivery charge and total",
"expected": "Output element shows Delivery and Total values matching the API response",
"basis": "documented",
"category": "frontend",
"outcome": "passed",
"trace": [
{
"action": {
"action": "goto",
"path": "/"
},
"error": null
},
{
"action": {
"action": "visible",
"selector": "form"
},
"error": null
},
{
"action": {
"action": "fill",
"selector": "#subtotal",
"value": "50"
},
"error": null
},
{
"action": {
"action": "click",
"selector": "button"
},
"error": null
},
{
"action": {
"action": "text",
"selector": "#quote",
"value": "Delivery: $5.00"
},
"error": null
},
{
"action": {
"action": "text",
"selector": "#quote",
"value": "Total: $55.00"
},
"error": null
}
],
"errors": [],
"observations": [],
"requests": [],
"network": [
{
"action": {
"action": "goto",
"path": "/"
},
"url": "http://127.0.0.1:3100/",
"method": "GET",
"status": 200
},
{
"action": {
"action": "text",
"selector": "#quote",
"value": "Delivery: $5.00"
},
"url": "http://127.0.0.1:3100/quote?subtotal=50",
"method": "GET",
"status": 200
}
],
"durationMs": 387,
"screenshot": "proofrun-0106a569-250-browser-1-final.png",
"limitations": [],
"logs": "[stdout] Shipping service ready\n",
"contractHash": "84a6359d76e397493634859908720ac6b61113344f9e80fed021a42c88a0ac6b"
} |
| Free-shipping boundary quote in browser | passed | Execution evidence{
"id": "browser-2",
"title": "Free-shipping boundary quote in browser",
"intent": "Submit subtotal=150 and verify the form displays zero shipping cost",
"expected": "Output shows Delivery: $0.00 and Total: $150.00",
"basis": "documented",
"category": "frontend",
"outcome": "passed",
"trace": [
{
"action": {
"action": "goto",
"path": "/"
},
"error": null
},
{
"action": {
"action": "fill",
"selector": "#subtotal",
"value": "150"
},
"error": null
},
{
"action": {
"action": "click",
"selector": "button"
},
"error": null
},
{
"action": {
"action": "text",
"selector": "#quote",
"value": "Delivery: $0.00"
},
"error": null
},
{
"action": {
"action": "text",
"selector": "#quote",
"value": "Total: $150.00"
},
"error": null
}
],
"errors": [],
"observations": [],
"requests": [],
"network": [
{
"action": {
"action": "goto",
"path": "/"
},
"url": "http://127.0.0.1:3100/",
"method": "GET",
"status": 200
},
{
"action": {
"action": "text",
"selector": "#quote",
"value": "Delivery: $0.00"
},
"url": "http://127.0.0.1:3100/quote?subtotal=150",
"method": "GET",
"status": 200
}
],
"durationMs": 379,
"screenshot": "proofrun-e06cbcc2-7ce-browser-2-final.png",
"limitations": [],
"logs": "[stdout] Shipping service ready\n",
"contractHash": "592d6ec307d13b619a3cb1982fe60261944dde03a44244293117245c346694c4"
} |
| Missing subtotal triggers native browser validation | passed | Execution evidence{
"id": "browser-3",
"title": "Missing subtotal triggers native browser validation",
"intent": "Clear the required number input and attempt submission; native validation must block the request",
"expected": "#subtotal is in an invalid state and no network request is made",
"basis": "documented",
"category": "frontend",
"outcome": "passed",
"trace": [
{
"action": {
"action": "goto",
"path": "/"
},
"error": null
},
{
"action": {
"action": "fill",
"selector": "#subtotal",
"value": ""
},
"error": null
},
{
"action": {
"action": "click",
"selector": "button"
},
"error": null
},
{
"action": {
"action": "invalid",
"selector": "#subtotal"
},
"error": null,
"validation": {
"valid": false,
"willValidate": true,
"message": "Please fill out this field.",
"value": ""
}
}
],
"errors": [],
"observations": [],
"requests": [],
"network": [
{
"action": {
"action": "goto",
"path": "/"
},
"url": "http://127.0.0.1:3100/",
"method": "GET",
"status": 200
}
],
"durationMs": 223,
"screenshot": "proofrun-508e238a-8a8-browser-3-final.png",
"limitations": [],
"logs": "[stdout] Shipping service ready\n",
"contractHash": "ac4c14a5ea48f5a8aa54e54eb72b78a0c2408e4daa7c4f195b562869f486ea5b"
} |
Replace the strict `>` with `>=` in the shipping-tier condition inside `quote()` in `shipping.mjs`. Every other character, line, and CRLF ending is preserved to match the original file exactly.
Status: applied
--- a/shipping.mjs
+++ b/shipping.mjs
@@ -2,7 +2,7 @@
if (typeof subtotal !== "number" || !Number.isFinite(subtotal) || subtotal <= 0 || subtotal > 10000) {
return { error: "Subtotal must be a number greater than 0 and at most 10000" };
}
- const shipping = subtotal > 100 ? 0 : 5;
+ const shipping = subtotal >= 100 ? 0 : 5;
return { subtotal, shipping, total: Math.round((subtotal + shipping) * 100) / 100 };
}
Risk: Minimal. Only the boundary value 100 changes behavior. All other inputs behave identically to before. No dependency, config, or test file is modified.
| Run unit tests | passed | Execution evidence{
"id": "existing-0",
"title": "Run unit tests",
"category": "existing test suite",
"expected": "Command completes with exit code 0",
"outcome": "passed",
"contractHash": "8a52d0d692598ab150bb6ab288a480aa92e99f92a2e17b3a25701dad124f37a0",
"logs": "TAP version 13\n# Subtest: ordinary orders have a five dollar delivery charge\nok 1 - ordinary orders have a five dollar delivery charge\n ---\n duration_ms: 1.427691\n type: 'test'\n ...\n# Subtest: large orders ship free\nok 2 - large orders ship free\n ---\n duration_ms: 0.236565\n type: 'test'\n ...\n# Subtest: invalid amounts are rejected\nok 3 - invalid amounts are rejected\n ---\n duration_ms: 0.263272\n type: 'test'\n ...\n1..3\n# tests 3\n# suites 0\n# pass 3\n# fail 0\n# cancelled 0\n# skipped 0\n# todo 0\n# duration_ms 71.537669\n\n",
"trace": [
{
"label": "Run unit tests",
"request": {
"argv": [
"node",
"--test",
"tests/*.test.mjs"
]
},
"response": {
"exitCode": 0
},
"error": null
}
]
} |
| Normal quote below $100 | passed | Execution evidence{
"id": "http-1",
"title": "Normal quote below $100",
"intent": "Verify a standard paid-shipping order returns correct subtotal, shipping, and total",
"expected": "{subtotal:50,shipping:5,total:55} with status 200",
"basis": "documented",
"category": "normal",
"outcome": "passed",
"trace": [
{
"label": "GET /quote?subtotal=50",
"request": {
"method": "GET",
"path": "/quote?subtotal=50",
"headers": {},
"body": null
},
"response": {
"status": 200,
"headers": {
"connection": "keep-alive",
"content-type": "application/json",
"date": "Sun, 27 Sep 2026 12:55:29 GMT",
"keep-alive": "timeout=5",
"transfer-encoding": "chunked"
},
"body": "{\"subtotal\":50,\"shipping\":5,\"total\":55}",
"truncated": false
},
"assertions": [
{
"kind": "status",
"equals": 200,
"actual": 200,
"passed": true
},
{
"kind": "json",
"path": "subtotal",
"equals": 50,
"actual": 50,
"passed": true
},
{
"kind": "json",
"path": "shipping",
"equals": 5,
"actual": 5,
"passed": true
},
{
"kind": "json",
"path": "total",
"equals": 55,
"actual": 55,
"passed": true
}
],
"error": null
},
{
"label": "GET /quote?subtotal=0.01 (minimum valid)",
"request": {
"method": "GET",
"path": "/quote?subtotal=0.01",
"headers": {},
"body": null
},
"response": {
"status": 200,
"headers": {
"connection": "keep-alive",
"content-type": "application/json",
"date": "Sun, 27 Sep 2026 12:55:29 GMT",
"keep-alive": "timeout=5",
"transfer-encoding": "chunked"
},
"body": "{\"subtotal\":0.01,\"shipping\":5,\"total\":5.01}",
"truncated": false
},
"assertions": [
{
"kind": "status",
"equals": 200,
"actual": 200,
"passed": true
},
{
"kind": "json",
"path": "subtotal",
"equals": 0.01,
"actual": 0.01,
"passed": true
},
{
"kind": "json",
"path": "shipping",
"equals": 5,
"actual": 5,
"passed": true
},
{
"kind": "json",
"path": "total",
"equals": 5.01,
"actual": 5.01,
"passed": true
}
],
"error": null
},
{
"label": "GET /quote?subtotal=99.99 (just below free-shipping boundary)",
"request": {
"method": "GET",
"path": "/quote?subtotal=99.99",
"headers": {},
"body": null
},
"response": {
"status": 200,
"headers": {
"connection": "keep-alive",
"content-type": "application/json",
"date": "Sun, 27 Sep 2026 12:55:29 GMT",
"keep-alive": "timeout=5",
"transfer-encoding": "chunked"
},
"body": "{\"subtotal\":99.99,\"shipping\":5,\"total\":104.99}",
"truncated": false
},
"assertions": [
{
"kind": "status",
"equals": 200,
"actual": 200,
"passed": true
},
{
"kind": "json",
"path": "shipping",
"equals": 5,
"actual": 5,
"passed": true
},
{
"kind": "json",
"path": "total",
"equals": 104.99,
"actual": 104.99,
"passed": true
}
],
"error": null
},
{
"label": "GET /quote?subtotal=10000 (maximum valid)",
"request": {
"method": "GET",
"path": "/quote?subtotal=10000",
"headers": {},
"body": null
},
"response": {
"status": 200,
"headers": {
"connection": "keep-alive",
"content-type": "application/json",
"date": "Sun, 27 Sep 2026 12:55:29 GMT",
"keep-alive": "timeout=5",
"transfer-encoding": "chunked"
},
"body": "{\"subtotal\":10000,\"shipping\":0,\"total\":10000}",
"truncated": false
},
"assertions": [
{
"kind": "status",
"equals": 200,
"actual": 200,
"passed": true
},
{
"kind": "json",
"path": "shipping",
"equals": 0,
"actual": 0,
"passed": true
},
{
"kind": "json",
"path": "total",
"equals": 10000,
"actual": 10000,
"passed": true
}
],
"error": null
}
],
"failedAssertions": 0,
"incomplete": 0,
"durationMs": 145,
"logs": "[stdout] Shipping service ready\n",
"contractHash": "5dee0c0e48f9f4e0871f4bf944860d63a640be4a4f9dcc0602072941f15679e6"
} |
| Free-shipping boundary at exactly $100 | passed | Execution evidence{
"id": "http-2",
"title": "Free-shipping boundary at exactly $100",
"intent": "Expose the deliberate defect: subtotal=100 should yield shipping=0 but the > condition charges $5",
"expected": "Status 200 with shipping:0 and total:100 (current code fails this — shipping.mjs uses > instead of >=)",
"basis": "assumption",
"category": "boundary",
"outcome": "passed",
"trace": [
{
"label": "GET /quote?subtotal=100 (boundary — free shipping spec)",
"request": {
"method": "GET",
"path": "/quote?subtotal=100",
"headers": {},
"body": null
},
"response": {
"status": 200,
"headers": {
"connection": "keep-alive",
"content-type": "application/json",
"date": "Sun, 27 Sep 2026 12:55:29 GMT",
"keep-alive": "timeout=5",
"transfer-encoding": "chunked"
},
"body": "{\"subtotal\":100,\"shipping\":0,\"total\":100}",
"truncated": false
},
"assertions": [
{
"kind": "status",
"equals": 200,
"actual": 200,
"passed": true
},
{
"kind": "json",
"path": "subtotal",
"equals": 100,
"actual": 100,
"passed": true
},
{
"kind": "json",
"path": "shipping",
"equals": 0,
"actual": 0,
"passed": true
},
{
"kind": "json",
"path": "total",
"equals": 100,
"actual": 100,
"passed": true
}
],
"error": null
},
{
"label": "GET /quote?subtotal=100.01 (just above boundary — confirmed free shipping)",
"request": {
"method": "GET",
"path": "/quote?subtotal=100.01",
"headers": {},
"body": null
},
"response": {
"status": 200,
"headers": {
"connection": "keep-alive",
"content-type": "application/json",
"date": "Sun, 27 Sep 2026 12:55:29 GMT",
"keep-alive": "timeout=5",
"transfer-encoding": "chunked"
},
"body": "{\"subtotal\":100.01,\"shipping\":0,\"total\":100.01}",
"truncated": false
},
"assertions": [
{
"kind": "status",
"equals": 200,
"actual": 200,
"passed": true
},
{
"kind": "json",
"path": "shipping",
"equals": 0,
"actual": 0,
"passed": true
},
{
"kind": "json",
"path": "total",
"equals": 100.01,
"actual": 100.01,
"passed": true
}
],
"error": null
}
],
"failedAssertions": 0,
"incomplete": 0,
"durationMs": 131,
"logs": "[stdout] Shipping service ready\n",
"contractHash": "73e516c1ba9a925f2bd8059266f647d87c9c19a560719bdababa31114b2da604"
} |
| Invalid and missing subtotal inputs return 400 | passed | Execution evidence{
"id": "http-3",
"title": "Invalid and missing subtotal inputs return 400",
"intent": "Validate rejection of zero, negative, non-numeric, blank, missing, and over-limit values",
"expected": "Status 400 with an error field for every case",
"basis": "documented",
"category": "adversarial",
"outcome": "passed",
"trace": [
{
"label": "GET /quote?subtotal=0",
"request": {
"method": "GET",
"path": "/quote?subtotal=0",
"headers": {},
"body": null
},
"response": {
"status": 400,
"headers": {
"connection": "keep-alive",
"content-type": "application/json",
"date": "Sun, 27 Sep 2026 12:55:33 GMT",
"keep-alive": "timeout=5",
"transfer-encoding": "chunked"
},
"body": "{\"error\":\"Subtotal must be a number greater than 0 and at most 10000\"}",
"truncated": false
},
"assertions": [
{
"kind": "status",
"equals": 400,
"actual": 400,
"passed": true
},
{
"kind": "json",
"path": "error",
"equals": "Subtotal must be a number greater than 0 and at most 10000",
"actual": "Subtotal must be a number greater than 0 and at most 10000",
"passed": true
}
],
"error": null
},
{
"label": "GET /quote?subtotal=-1",
"request": {
"method": "GET",
"path": "/quote?subtotal=-1",
"headers": {},
"body": null
},
"response": {
"status": 400,
"headers": {
"connection": "keep-alive",
"content-type": "application/json",
"date": "Sun, 27 Sep 2026 12:55:33 GMT",
"keep-alive": "timeout=5",
"transfer-encoding": "chunked"
},
"body": "{\"error\":\"Subtotal must be a number greater than 0 and at most 10000\"}",
"truncated": false
},
"assertions": [
{
"kind": "status",
"equals": 400,
"actual": 400,
"passed": true
},
{
"kind": "contains",
"value": "error",
"actual": "{\"error\":\"Subtotal must be a number greater than 0 and at most 10000\"}",
"passed": true
}
],
"error": null
},
{
"label": "GET /quote?subtotal=10001 (over limit)",
"request": {
"method": "GET",
"path": "/quote?subtotal=10001",
"headers": {},
"body": null
},
"response": {
"status": 400,
"headers": {
"connection": "keep-alive",
"content-type": "application/json",
"date": "Sun, 27 Sep 2026 12:55:33 GMT",
"keep-alive": "timeout=5",
"transfer-encoding": "chunked"
},
"body": "{\"error\":\"Subtotal must be a number greater than 0 and at most 10000\"}",
"truncated": false
},
"assertions": [
{
"kind": "status",
"equals": 400,
"actual": 400,
"passed": true
},
{
"kind": "contains",
"value": "error",
"actual": "{\"error\":\"Subtotal must be a number greater than 0 and at most 10000\"}",
"passed": true
}
],
"error": null
},
{
"label": "GET /quote?subtotal=abc (non-numeric)",
"request": {
"method": "GET",
"path": "/quote?subtotal=abc",
"headers": {},
"body": null
},
"response": {
"status": 400,
"headers": {
"connection": "keep-alive",
"content-type": "application/json",
"date": "Sun, 27 Sep 2026 12:55:33 GMT",
"keep-alive": "timeout=5",
"transfer-encoding": "chunked"
},
"body": "{\"error\":\"Subtotal must be a number greater than 0 and at most 10000\"}",
"truncated": false
},
"assertions": [
{
"kind": "status",
"equals": 400,
"actual": 400,
"passed": true
},
{
"kind": "contains",
"value": "error",
"actual": "{\"error\":\"Subtotal must be a number greater than 0 and at most 10000\"}",
"passed": true
}
],
"error": null
},
{
"label": "GET /quote?subtotal= (blank)",
"request": {
"method": "GET",
"path": "/quote?subtotal=",
"headers": {},
"body": null
},
"response": {
"status": 400,
"headers": {
"connection": "keep-alive",
"content-type": "application/json",
"date": "Sun, 27 Sep 2026 12:55:33 GMT",
"keep-alive": "timeout=5",
"transfer-encoding": "chunked"
},
"body": "{\"error\":\"Subtotal must be a number greater than 0 and at most 10000\"}",
"truncated": false
},
"assertions": [
{
"kind": "status",
"equals": 400,
"actual": 400,
"passed": true
},
{
"kind": "contains",
"value": "error",
"actual": "{\"error\":\"Subtotal must be a number greater than 0 and at most 10000\"}",
"passed": true
}
],
"error": null
},
{
"label": "GET /quote (missing param)",
"request": {
"method": "GET",
"path": "/quote",
"headers": {},
"body": null
},
"response": {
"status": 400,
"headers": {
"connection": "keep-alive",
"content-type": "application/json",
"date": "Sun, 27 Sep 2026 12:55:33 GMT",
"keep-alive": "timeout=5",
"transfer-encoding": "chunked"
},
"body": "{\"error\":\"Subtotal must be a number greater than 0 and at most 10000\"}",
"truncated": false
},
"assertions": [
{
"kind": "status",
"equals": 400,
"actual": 400,
"passed": true
},
{
"kind": "contains",
"value": "error",
"actual": "{\"error\":\"Subtotal must be a number greater than 0 and at most 10000\"}",
"passed": true
}
],
"error": null
},
{
"label": "GET /quote?subtotal=Infinity",
"request": {
"method": "GET",
"path": "/quote?subtotal=Infinity",
"headers": {},
"body": null
},
"response": {
"status": 400,
"headers": {
"connection": "keep-alive",
"content-type": "application/json",
"date": "Sun, 27 Sep 2026 12:55:33 GMT",
"keep-alive": "timeout=5",
"transfer-encoding": "chunked"
},
"body": "{\"error\":\"Subtotal must be a number greater than 0 and at most 10000\"}",
"truncated": false
},
"assertions": [
{
"kind": "status",
"equals": 400,
"actual": 400,
"passed": true
},
{
"kind": "contains",
"value": "error",
"actual": "{\"error\":\"Subtotal must be a number greater than 0 and at most 10000\"}",
"passed": true
}
],
"error": null
}
],
"failedAssertions": 0,
"incomplete": 0,
"durationMs": 141,
"logs": "[stdout] Shipping service ready\n",
"contractHash": "b36c5e0cc049e37ea439818b9aead714dd2ddba4e7d4d3eeeafb0c09453d50d2"
} |
| Unknown routes return 404 | passed | Execution evidence{
"id": "http-4",
"title": "Unknown routes return 404",
"intent": "Confirm the server responds 404 with an error body for any unregistered path",
"expected": "Status 404 and JSON error body for unrecognised paths; POST /quote also 404",
"basis": "documented",
"category": "adversarial",
"outcome": "passed",
"trace": [
{
"label": "GET /unknown",
"request": {
"method": "GET",
"path": "/unknown",
"headers": {},
"body": null
},
"response": {
"status": 404,
"headers": {
"connection": "keep-alive",
"content-type": "application/json",
"date": "Sun, 27 Sep 2026 12:55:33 GMT",
"keep-alive": "timeout=5",
"transfer-encoding": "chunked"
},
"body": "{\"error\":\"Route not found\"}",
"truncated": false
},
"assertions": [
{
"kind": "status",
"equals": 404,
"actual": 404,
"passed": true
},
{
"kind": "json",
"path": "error",
"equals": "Route not found",
"actual": "Route not found",
"passed": true
}
],
"error": null
},
{
"label": "GET /Quote (case-sensitive)",
"request": {
"method": "GET",
"path": "/Quote",
"headers": {},
"body": null
},
"response": {
"status": 404,
"headers": {
"connection": "keep-alive",
"content-type": "application/json",
"date": "Sun, 27 Sep 2026 12:55:33 GMT",
"keep-alive": "timeout=5",
"transfer-encoding": "chunked"
},
"body": "{\"error\":\"Route not found\"}",
"truncated": false
},
"assertions": [
{
"kind": "status",
"equals": 404,
"actual": 404,
"passed": true
}
],
"error": null
},
{
"label": "POST /quote (method not allowed — treated as 404 by router)",
"request": {
"method": "POST",
"path": "/quote",
"headers": {
"content-type": "application/json"
},
"body": "null"
},
"response": {
"status": 404,
"headers": {
"connection": "keep-alive",
"content-type": "application/json",
"date": "Sun, 27 Sep 2026 12:55:33 GMT",
"keep-alive": "timeout=5",
"transfer-encoding": "chunked"
},
"body": "{\"error\":\"Route not found\"}",
"truncated": false
},
"assertions": [
{
"kind": "status",
"equals": 404,
"actual": 404,
"passed": true
}
],
"error": null
},
{
"label": "GET /quote/ (trailing slash)",
"request": {
"method": "GET",
"path": "/quote/",
"headers": {},
"body": null
},
"response": {
"status": 404,
"headers": {
"connection": "keep-alive",
"content-type": "application/json",
"date": "Sun, 27 Sep 2026 12:55:33 GMT",
"keep-alive": "timeout=5",
"transfer-encoding": "chunked"
},
"body": "{\"error\":\"Route not found\"}",
"truncated": false
},
"assertions": [
{
"kind": "status",
"equals": 404,
"actual": 404,
"passed": true
}
],
"error": null
}
],
"failedAssertions": 0,
"incomplete": 0,
"durationMs": 89,
"logs": "[stdout] Shipping service ready\n",
"contractHash": "21c2b7f6ca2b1e057d3d0fa2f6173653ee650a951d122f8f01ee3b0f4cb086ec"
} |
| GET / serves the HTML checkout page | passed | Execution evidence{
"id": "http-5",
"title": "GET / serves the HTML checkout page",
"intent": "Confirm the homepage returns the HTML form with correct content-type",
"expected": "Status 200, content-type text/html, body contains the form",
"basis": "documented",
"category": "normal",
"outcome": "passed",
"trace": [
{
"label": "GET /",
"request": {
"method": "GET",
"path": "/",
"headers": {},
"body": null
},
"response": {
"status": 200,
"headers": {
"connection": "keep-alive",
"content-length": "1108",
"content-type": "text/html; charset=utf-8",
"date": "Sun, 27 Sep 2026 12:55:37 GMT",
"keep-alive": "timeout=5"
},
"body": "<!doctype html><html lang=\"en\"><meta charset=\"utf-8\"><title>Shipping quote</title><style>body{font:18px system-ui;color:#23372e;background:#f5f5ef;margin:80px auto;max-width:560px}main{background:white;padding:40px;border:1px solid #dde3db;border-radius:8px}input,button{font:inherit;padding:12px}button{background:#2e5747;color:white;border:0}label{display:block;margin:24px 0 8px}output{display:block;margin-top:24px}</style><main><small>CHECKOUT</small><h1>Know your total.</h1><p>Delivery is $5. Orders of $100 or more ship free.</p><form><label for=\"subtotal\">Order subtotal ($)</label><input id=\"subtotal\" name=\"subtotal\" type=\"number\" step=\"0.01\" value=\"100\" required><button>Get quote</button></form><output aria-live=\"polite\" id=\"quote\"></output></main><script>document.querySelector('form').onsubmit=async e=>{e.preventDefault();const r=await fetch('/quote?subtotal='+encodeURIComponent(document.querySelector('#subtotal').value));const q=await r.json();document.querySelector('#quote').textContent=q.error||('Delivery: $'+q.shipping.toFixed(2)+' · Total: $'+q.total.toFixed(2));};</script></html>",
"truncated": false
},
"assertions": [
{
"kind": "status",
"equals": 200,
"actual": 200,
"passed": true
},
{
"kind": "header",
"name": "content-type",
"equals": "text/html; charset=utf-8",
"actual": "text/html; charset=utf-8",
"passed": true
},
{
"kind": "contains",
"value": "<form>",
"actual": "<!doctype html><html lang=\"en\"><meta charset=\"utf-8\"><title>Shipping quote</title><style>body{font:18px system-ui;color:#23372e;background:#f5f5ef;margin:80px auto;max-width:560px}main{background:white;padding:40px;border:1px solid #dde3db;border-radius:8px}input,button{font:inherit;padding:12px}button{background:#2e5747;color:white;border:0}label{display:block;margin:24px 0 8px}output{display:block;margin-top:24px}</style><main><small>CHECKOUT</small><h1>Know your total.</h1><p>Delivery is $5. Orders of $100 or more ship free.</p><form><label for=\"subtotal\">Order subtotal ($)</label><input id=\"subtotal\" name=\"subtotal\" type=\"number\" step=\"0.01\" value=\"100\" required><button>Get quote</button></form><output aria-live=\"polite\" id=\"quote\"></output></main><script>document.querySelector('form').onsubmit=async e=>{e.preventDefault();const r=await fetch('/quote?subtotal='+encodeURIComponent(document.querySelector('#subtotal').value));const q=await r.json();document.querySelector('#quote').textContent=q.error||('Delivery: $'+q.shipping.toFixed(2)+' · Total: $'+q.total.toFixed(2));};</script></html>",
"passed": true
},
{
"kind": "contains",
"value": "subtotal",
"actual": "<!doctype html><html lang=\"en\"><meta charset=\"utf-8\"><title>Shipping quote</title><style>body{font:18px system-ui;color:#23372e;background:#f5f5ef;margin:80px auto;max-width:560px}main{background:white;padding:40px;border:1px solid #dde3db;border-radius:8px}input,button{font:inherit;padding:12px}button{background:#2e5747;color:white;border:0}label{display:block;margin:24px 0 8px}output{display:block;margin-top:24px}</style><main><small>CHECKOUT</small><h1>Know your total.</h1><p>Delivery is $5. Orders of $100 or more ship free.</p><form><label for=\"subtotal\">Order subtotal ($)</label><input id=\"subtotal\" name=\"subtotal\" type=\"number\" step=\"0.01\" value=\"100\" required><button>Get quote</button></form><output aria-live=\"polite\" id=\"quote\"></output></main><script>document.querySelector('form').onsubmit=async e=>{e.preventDefault();const r=await fetch('/quote?subtotal='+encodeURIComponent(document.querySelector('#subtotal').value));const q=await r.json();document.querySelector('#quote').textContent=q.error||('Delivery: $'+q.shipping.toFixed(2)+' · Total: $'+q.total.toFixed(2));};</script></html>",
"passed": true
}
],
"error": null
}
],
"failedAssertions": 0,
"incomplete": 0,
"durationMs": 111,
"logs": "[stdout] Shipping service ready\n",
"contractHash": "b3044b7617f736aa6a0f9f27f5fc259837a464b9267d6f7b9d8a5298686218b4"
} |
| Content-type is application/json on API responses | passed | Execution evidence{
"id": "http-6",
"title": "Content-type is application/json on API responses",
"intent": "Ensure the API sets the correct content-type header for both success and error responses",
"expected": "content-type: application/json on 200 and 400 responses",
"basis": "documented",
"category": "normal",
"outcome": "passed",
"trace": [
{
"label": "Successful quote content-type",
"request": {
"method": "GET",
"path": "/quote?subtotal=50",
"headers": {},
"body": null
},
"response": {
"status": 200,
"headers": {
"connection": "keep-alive",
"content-type": "application/json",
"date": "Sun, 27 Sep 2026 12:55:37 GMT",
"keep-alive": "timeout=5",
"transfer-encoding": "chunked"
},
"body": "{\"subtotal\":50,\"shipping\":5,\"total\":55}",
"truncated": false
},
"assertions": [
{
"kind": "status",
"equals": 200,
"actual": 200,
"passed": true
},
{
"kind": "header",
"name": "content-type",
"equals": "application/json",
"actual": "application/json",
"passed": true
}
],
"error": null
},
{
"label": "Error response content-type",
"request": {
"method": "GET",
"path": "/quote?subtotal=0",
"headers": {},
"body": null
},
"response": {
"status": 400,
"headers": {
"connection": "keep-alive",
"content-type": "application/json",
"date": "Sun, 27 Sep 2026 12:55:37 GMT",
"keep-alive": "timeout=5",
"transfer-encoding": "chunked"
},
"body": "{\"error\":\"Subtotal must be a number greater than 0 and at most 10000\"}",
"truncated": false
},
"assertions": [
{
"kind": "status",
"equals": 400,
"actual": 400,
"passed": true
},
{
"kind": "header",
"name": "content-type",
"equals": "application/json",
"actual": "application/json",
"passed": true
}
],
"error": null
}
],
"failedAssertions": 0,
"incomplete": 0,
"durationMs": 121,
"logs": "[stdout] Shipping service ready\n",
"contractHash": "6fd73083be10e45c3da392938d3994a5b4135d55b1b89e20a787882059dfe361"
} |
| Malformed and unexpected inputs: POST /quote | passed | Execution evidence{
"id": "adversarial-0",
"title": "Malformed and unexpected inputs: POST /quote",
"intent": "Exercise malformed JSON, null, arrays, missing values, unexpected types and numeric boundaries. Detect unhandled HTTP 5xx responses.",
"expected": "Bad inputs are handled without an unhandled server error. Exact domain rejection status is not assumed.",
"basis": "assumption",
"category": "input-validation",
"outcome": "passed",
"trace": [
{
"label": "Malformed JSON",
"request": {
"method": "POST",
"path": "/quote",
"headers": {
"content-type": "application/json"
},
"body": "{\"broken\":"
},
"response": {
"status": 404,
"headers": {
"connection": "keep-alive",
"content-type": "application/json",
"date": "Sun, 27 Sep 2026 12:55:40 GMT",
"keep-alive": "timeout=5",
"transfer-encoding": "chunked"
},
"body": "{\"error\":\"Route not found\"}",
"truncated": false
},
"assertions": [
{
"kind": "not5xx",
"actual": 404,
"passed": true
}
],
"error": null
},
{
"label": "Unexpected input 0",
"request": {
"method": "POST",
"path": "/quote",
"headers": {
"content-type": "application/json"
},
"body": "null"
},
"response": {
"status": 404,
"headers": {
"connection": "keep-alive",
"content-type": "application/json",
"date": "Sun, 27 Sep 2026 12:55:40 GMT",
"keep-alive": "timeout=5",
"transfer-encoding": "chunked"
},
"body": "{\"error\":\"Route not found\"}",
"truncated": false
},
"assertions": [
{
"kind": "not5xx",
"actual": 404,
"passed": true
}
],
"error": null
},
{
"label": "Unexpected input 1",
"request": {
"method": "POST",
"path": "/quote",
"headers": {
"content-type": "application/json"
},
"body": "[]"
},
"response": {
"status": 404,
"headers": {
"connection": "keep-alive",
"content-type": "application/json",
"date": "Sun, 27 Sep 2026 12:55:40 GMT",
"keep-alive": "timeout=5",
"transfer-encoding": "chunked"
},
"body": "{\"error\":\"Route not found\"}",
"truncated": false
},
"assertions": [
{
"kind": "not5xx",
"actual": 404,
"passed": true
}
],
"error": null
},
{
"label": "Unexpected input 2",
"request": {
"method": "POST",
"path": "/quote",
"headers": {
"content-type": "application/json"
},
"body": "{}"
},
"response": {
"status": 404,
"headers": {
"connection": "keep-alive",
"content-type": "application/json",
"date": "Sun, 27 Sep 2026 12:55:40 GMT",
"keep-alive": "timeout=5",
"transfer-encoding": "chunked"
},
"body": "{\"error\":\"Route not found\"}",
"truncated": false
},
"assertions": [
{
"kind": "not5xx",
"actual": 404,
"passed": true
}
],
"error": null
},
{
"label": "Unexpected input 3",
"request": {
"method": "POST",
"path": "/quote",
"headers": {
"content-type": "application/json"
},
"body": "\"unexpected\""
},
"response": {
"status": 404,
"headers": {
"connection": "keep-alive",
"content-type": "application/json",
"date": "Sun, 27 Sep 2026 12:55:40 GMT",
"keep-alive": "timeout=5",
"transfer-encoding": "chunked"
},
"body": "{\"error\":\"Route not found\"}",
"truncated": false
},
"assertions": [
{
"kind": "not5xx",
"actual": 404,
"passed": true
}
],
"error": null
},
{
"label": "Unexpected input 4",
"request": {
"method": "POST",
"path": "/quote",
"headers": {
"content-type": "application/json"
},
"body": "{}"
},
"response": {
"status": 404,
"headers": {
"connection": "keep-alive",
"content-type": "application/json",
"date": "Sun, 27 Sep 2026 12:55:40 GMT",
"keep-alive": "timeout=5",
"transfer-encoding": "chunked"
},
"body": "{\"error\":\"Route not found\"}",
"truncated": false
},
"assertions": [
{
"kind": "not5xx",
"actual": 404,
"passed": true
}
],
"error": null
}
],
"failedAssertions": 0,
"incomplete": 0,
"durationMs": 107,
"logs": "[stdout] Shipping service ready\n",
"contractHash": "006c3b0e2378c8a795662ca896ebaab9271ee50a5e6e3097088188255f73f716"
} |
| Happy-path quote submission | passed | Execution evidence{
"id": "browser-1",
"title": "Happy-path quote submission",
"intent": "User enters a valid subtotal, submits the form, and sees the delivery charge and total",
"expected": "Output element shows Delivery and Total values matching the API response",
"basis": "documented",
"category": "frontend",
"outcome": "passed",
"trace": [
{
"action": {
"action": "goto",
"path": "/"
},
"error": null
},
{
"action": {
"action": "visible",
"selector": "form"
},
"error": null
},
{
"action": {
"action": "fill",
"selector": "#subtotal",
"value": "50"
},
"error": null
},
{
"action": {
"action": "click",
"selector": "button"
},
"error": null
},
{
"action": {
"action": "text",
"selector": "#quote",
"value": "Delivery: $5.00"
},
"error": null
},
{
"action": {
"action": "text",
"selector": "#quote",
"value": "Total: $55.00"
},
"error": null
}
],
"errors": [],
"observations": [],
"requests": [],
"network": [
{
"action": {
"action": "goto",
"path": "/"
},
"url": "http://127.0.0.1:3100/",
"method": "GET",
"status": 200
},
{
"action": {
"action": "text",
"selector": "#quote",
"value": "Delivery: $5.00"
},
"url": "http://127.0.0.1:3100/quote?subtotal=50",
"method": "GET",
"status": 200
}
],
"durationMs": 369,
"screenshot": "proofrun-9328f562-2e5-browser-1-final.png",
"limitations": [],
"logs": "[stdout] Shipping service ready\n",
"contractHash": "84a6359d76e397493634859908720ac6b61113344f9e80fed021a42c88a0ac6b"
} |
| Free-shipping boundary quote in browser | passed | Execution evidence{
"id": "browser-2",
"title": "Free-shipping boundary quote in browser",
"intent": "Submit subtotal=150 and verify the form displays zero shipping cost",
"expected": "Output shows Delivery: $0.00 and Total: $150.00",
"basis": "documented",
"category": "frontend",
"outcome": "passed",
"trace": [
{
"action": {
"action": "goto",
"path": "/"
},
"error": null
},
{
"action": {
"action": "fill",
"selector": "#subtotal",
"value": "150"
},
"error": null
},
{
"action": {
"action": "click",
"selector": "button"
},
"error": null
},
{
"action": {
"action": "text",
"selector": "#quote",
"value": "Delivery: $0.00"
},
"error": null
},
{
"action": {
"action": "text",
"selector": "#quote",
"value": "Total: $150.00"
},
"error": null
}
],
"errors": [],
"observations": [],
"requests": [],
"network": [
{
"action": {
"action": "goto",
"path": "/"
},
"url": "http://127.0.0.1:3100/",
"method": "GET",
"status": 200
},
{
"action": {
"action": "text",
"selector": "#quote",
"value": "Delivery: $0.00"
},
"url": "http://127.0.0.1:3100/quote?subtotal=150",
"method": "GET",
"status": 200
}
],
"durationMs": 396,
"screenshot": "proofrun-6c1c20aa-491-browser-2-final.png",
"limitations": [],
"logs": "[stdout] Shipping service ready\n",
"contractHash": "592d6ec307d13b619a3cb1982fe60261944dde03a44244293117245c346694c4"
} |
| Missing subtotal triggers native browser validation | passed | Execution evidence{
"id": "browser-3",
"title": "Missing subtotal triggers native browser validation",
"intent": "Clear the required number input and attempt submission; native validation must block the request",
"expected": "#subtotal is in an invalid state and no network request is made",
"basis": "documented",
"category": "frontend",
"outcome": "passed",
"trace": [
{
"action": {
"action": "goto",
"path": "/"
},
"error": null
},
{
"action": {
"action": "fill",
"selector": "#subtotal",
"value": ""
},
"error": null
},
{
"action": {
"action": "click",
"selector": "button"
},
"error": null
},
{
"action": {
"action": "invalid",
"selector": "#subtotal"
},
"error": null,
"validation": {
"valid": false,
"willValidate": true,
"message": "Please fill out this field.",
"value": ""
}
}
],
"errors": [],
"observations": [],
"requests": [],
"network": [
{
"action": {
"action": "goto",
"path": "/"
},
"url": "http://127.0.0.1:3100/",
"method": "GET",
"status": 200
}
],
"durationMs": 389,
"screenshot": "proofrun-8c3f9216-903-browser-3-final.png",
"limitations": [],
"logs": "[stdout] Shipping service ready\n",
"contractHash": "ac4c14a5ea48f5a8aa54e54eb72b78a0c2408e4daa7c4f195b562869f486ea5b"
} |
{
"time": "2026-09-27T12:55:50.506Z",
"sourceSnapshot": "86391d3db9dee0391b059bc8f0eda82f21d18f00f5815b4aa32aecf854af6fda",
"fixId": "9f480802-3a86-453c-96c7-67966b58eb19",
"fixIds": [
"9f480802-3a86-453c-96c7-67966b58eb19"
],
"contractsUnchanged": true,
"results": [
{
"id": "existing-0",
"title": "Run unit tests",
"category": "existing test suite",
"expected": "Command completes with exit code 0",
"outcome": "passed",
"contractHash": "8a52d0d692598ab150bb6ab288a480aa92e99f92a2e17b3a25701dad124f37a0",
"logs": "TAP version 13\n# Subtest: ordinary orders have a five dollar delivery charge\nok 1 - ordinary orders have a five dollar delivery charge\n ---\n duration_ms: 1.427691\n type: 'test'\n ...\n# Subtest: large orders ship free\nok 2 - large orders ship free\n ---\n duration_ms: 0.236565\n type: 'test'\n ...\n# Subtest: invalid amounts are rejected\nok 3 - invalid amounts are rejected\n ---\n duration_ms: 0.263272\n type: 'test'\n ...\n1..3\n# tests 3\n# suites 0\n# pass 3\n# fail 0\n# cancelled 0\n# skipped 0\n# todo 0\n# duration_ms 71.537669\n\n",
"trace": [
{
"label": "Run unit tests",
"request": {
"argv": [
"node",
"--test",
"tests/*.test.mjs"
]
},
"response": {
"exitCode": 0
},
"error": null
}
]
},
{
"id": "http-1",
"title": "Normal quote below $100",
"intent": "Verify a standard paid-shipping order returns correct subtotal, shipping, and total",
"expected": "{subtotal:50,shipping:5,total:55} with status 200",
"basis": "documented",
"category": "normal",
"outcome": "passed",
"trace": [
{
"label": "GET /quote?subtotal=50",
"request": {
"method": "GET",
"path": "/quote?subtotal=50",
"headers": {},
"body": null
},
"response": {
"status": 200,
"headers": {
"connection": "keep-alive",
"content-type": "application/json",
"date": "Sun, 27 Sep 2026 12:55:29 GMT",
"keep-alive": "timeout=5",
"transfer-encoding": "chunked"
},
"body": "{\"subtotal\":50,\"shipping\":5,\"total\":55}",
"truncated": false
},
"assertions": [
{
"kind": "status",
"equals": 200,
"actual": 200,
"passed": true
},
{
"kind": "json",
"path": "subtotal",
"equals": 50,
"actual": 50,
"passed": true
},
{
"kind": "json",
"path": "shipping",
"equals": 5,
"actual": 5,
"passed": true
},
{
"kind": "json",
"path": "total",
"equals": 55,
"actual": 55,
"passed": true
}
],
"error": null
},
{
"label": "GET /quote?subtotal=0.01 (minimum valid)",
"request": {
"method": "GET",
"path": "/quote?subtotal=0.01",
"headers": {},
"body": null
},
"response": {
"status": 200,
"headers": {
"connection": "keep-alive",
"content-type": "application/json",
"date": "Sun, 27 Sep 2026 12:55:29 GMT",
"keep-alive": "timeout=5",
"transfer-encoding": "chunked"
},
"body": "{\"subtotal\":0.01,\"shipping\":5,\"total\":5.01}",
"truncated": false
},
"assertions": [
{
"kind": "status",
"equals": 200,
"actual": 200,
"passed": true
},
{
"kind": "json",
"path": "subtotal",
"equals": 0.01,
"actual": 0.01,
"passed": true
},
{
"kind": "json",
"path": "shipping",
"equals": 5,
"actual": 5,
"passed": true
},
{
"kind": "json",
"path": "total",
"equals": 5.01,
"actual": 5.01,
"passed": true
}
],
"error": null
},
{
"label": "GET /quote?subtotal=99.99 (just below free-shipping boundary)",
"request": {
"method": "GET",
"path": "/quote?subtotal=99.99",
"headers": {},
"body": null
},
"response": {
"status": 200,
"headers": {
"connection": "keep-alive",
"content-type": "application/json",
"date": "Sun, 27 Sep 2026 12:55:29 GMT",
"keep-alive": "timeout=5",
"transfer-encoding": "chunked"
},
"body": "{\"subtotal\":99.99,\"shipping\":5,\"total\":104.99}",
"truncated": false
},
"assertions": [
{
"kind": "status",
"equals": 200,
"actual": 200,
"passed": true
},
{
"kind": "json",
"path": "shipping",
"equals": 5,
"actual": 5,
"passed": true
},
{
"kind": "json",
"path": "total",
"equals": 104.99,
"actual": 104.99,
"passed": true
}
],
"error": null
},
{
"label": "GET /quote?subtotal=10000 (maximum valid)",
"request": {
"method": "GET",
"path": "/quote?subtotal=10000",
"headers": {},
"body": null
},
"response": {
"status": 200,
"headers": {
"connection": "keep-alive",
"content-type": "application/json",
"date": "Sun, 27 Sep 2026 12:55:29 GMT",
"keep-alive": "timeout=5",
"transfer-encoding": "chunked"
},
"body": "{\"subtotal\":10000,\"shipping\":0,\"total\":10000}",
"truncated": false
},
"assertions": [
{
"kind": "status",
"equals": 200,
"actual": 200,
"passed": true
},
{
"kind": "json",
"path": "shipping",
"equals": 0,
"actual": 0,
"passed": true
},
{
"kind": "json",
"path": "total",
"equals": 10000,
"actual": 10000,
"passed": true
}
],
"error": null
}
],
"failedAssertions": 0,
"incomplete": 0,
"durationMs": 145,
"logs": "[stdout] Shipping service ready\n",
"contractHash": "5dee0c0e48f9f4e0871f4bf944860d63a640be4a4f9dcc0602072941f15679e6"
},
{
"id": "http-2",
"title": "Free-shipping boundary at exactly $100",
"intent": "Expose the deliberate defect: subtotal=100 should yield shipping=0 but the > condition charges $5",
"expected": "Status 200 with shipping:0 and total:100 (current code fails this — shipping.mjs uses > instead of >=)",
"basis": "assumption",
"category": "boundary",
"outcome": "passed",
"trace": [
{
"label": "GET /quote?subtotal=100 (boundary — free shipping spec)",
"request": {
"method": "GET",
"path": "/quote?subtotal=100",
"headers": {},
"body": null
},
"response": {
"status": 200,
"headers": {
"connection": "keep-alive",
"content-type": "application/json",
"date": "Sun, 27 Sep 2026 12:55:29 GMT",
"keep-alive": "timeout=5",
"transfer-encoding": "chunked"
},
"body": "{\"subtotal\":100,\"shipping\":0,\"total\":100}",
"truncated": false
},
"assertions": [
{
"kind": "status",
"equals": 200,
"actual": 200,
"passed": true
},
{
"kind": "json",
"path": "subtotal",
"equals": 100,
"actual": 100,
"passed": true
},
{
"kind": "json",
"path": "shipping",
"equals": 0,
"actual": 0,
"passed": true
},
{
"kind": "json",
"path": "total",
"equals": 100,
"actual": 100,
"passed": true
}
],
"error": null
},
{
"label": "GET /quote?subtotal=100.01 (just above boundary — confirmed free shipping)",
"request": {
"method": "GET",
"path": "/quote?subtotal=100.01",
"headers": {},
"body": null
},
"response": {
"status": 200,
"headers": {
"connection": "keep-alive",
"content-type": "application/json",
"date": "Sun, 27 Sep 2026 12:55:29 GMT",
"keep-alive": "timeout=5",
"transfer-encoding": "chunked"
},
"body": "{\"subtotal\":100.01,\"shipping\":0,\"total\":100.01}",
"truncated": false
},
"assertions": [
{
"kind": "status",
"equals": 200,
"actual": 200,
"passed": true
},
{
"kind": "json",
"path": "shipping",
"equals": 0,
"actual": 0,
"passed": true
},
{
"kind": "json",
"path": "total",
"equals": 100.01,
"actual": 100.01,
"passed": true
}
],
"error": null
}
],
"failedAssertions": 0,
"incomplete": 0,
"durationMs": 131,
"logs": "[stdout] Shipping service ready\n",
"contractHash": "73e516c1ba9a925f2bd8059266f647d87c9c19a560719bdababa31114b2da604"
},
{
"id": "http-3",
"title": "Invalid and missing subtotal inputs return 400",
"intent": "Validate rejection of zero, negative, non-numeric, blank, missing, and over-limit values",
"expected": "Status 400 with an error field for every case",
"basis": "documented",
"category": "adversarial",
"outcome": "passed",
"trace": [
{
"label": "GET /quote?subtotal=0",
"request": {
"method": "GET",
"path": "/quote?subtotal=0",
"headers": {},
"body": null
},
"response": {
"status": 400,
"headers": {
"connection": "keep-alive",
"content-type": "application/json",
"date": "Sun, 27 Sep 2026 12:55:33 GMT",
"keep-alive": "timeout=5",
"transfer-encoding": "chunked"
},
"body": "{\"error\":\"Subtotal must be a number greater than 0 and at most 10000\"}",
"truncated": false
},
"assertions": [
{
"kind": "status",
"equals": 400,
"actual": 400,
"passed": true
},
{
"kind": "json",
"path": "error",
"equals": "Subtotal must be a number greater than 0 and at most 10000",
"actual": "Subtotal must be a number greater than 0 and at most 10000",
"passed": true
}
],
"error": null
},
{
"label": "GET /quote?subtotal=-1",
"request": {
"method": "GET",
"path": "/quote?subtotal=-1",
"headers": {},
"body": null
},
"response": {
"status": 400,
"headers": {
"connection": "keep-alive",
"content-type": "application/json",
"date": "Sun, 27 Sep 2026 12:55:33 GMT",
"keep-alive": "timeout=5",
"transfer-encoding": "chunked"
},
"body": "{\"error\":\"Subtotal must be a number greater than 0 and at most 10000\"}",
"truncated": false
},
"assertions": [
{
"kind": "status",
"equals": 400,
"actual": 400,
"passed": true
},
{
"kind": "contains",
"value": "error",
"actual": "{\"error\":\"Subtotal must be a number greater than 0 and at most 10000\"}",
"passed": true
}
],
"error": null
},
{
"label": "GET /quote?subtotal=10001 (over limit)",
"request": {
"method": "GET",
"path": "/quote?subtotal=10001",
"headers": {},
"body": null
},
"response": {
"status": 400,
"headers": {
"connection": "keep-alive",
"content-type": "application/json",
"date": "Sun, 27 Sep 2026 12:55:33 GMT",
"keep-alive": "timeout=5",
"transfer-encoding": "chunked"
},
"body": "{\"error\":\"Subtotal must be a number greater than 0 and at most 10000\"}",
"truncated": false
},
"assertions": [
{
"kind": "status",
"equals": 400,
"actual": 400,
"passed": true
},
{
"kind": "contains",
"value": "error",
"actual": "{\"error\":\"Subtotal must be a number greater than 0 and at most 10000\"}",
"passed": true
}
],
"error": null
},
{
"label": "GET /quote?subtotal=abc (non-numeric)",
"request": {
"method": "GET",
"path": "/quote?subtotal=abc",
"headers": {},
"body": null
},
"response": {
"status": 400,
"headers": {
"connection": "keep-alive",
"content-type": "application/json",
"date": "Sun, 27 Sep 2026 12:55:33 GMT",
"keep-alive": "timeout=5",
"transfer-encoding": "chunked"
},
"body": "{\"error\":\"Subtotal must be a number greater than 0 and at most 10000\"}",
"truncated": false
},
"assertions": [
{
"kind": "status",
"equals": 400,
"actual": 400,
"passed": true
},
{
"kind": "contains",
"value": "error",
"actual": "{\"error\":\"Subtotal must be a number greater than 0 and at most 10000\"}",
"passed": true
}
],
"error": null
},
{
"label": "GET /quote?subtotal= (blank)",
"request": {
"method": "GET",
"path": "/quote?subtotal=",
"headers": {},
"body": null
},
"response": {
"status": 400,
"headers": {
"connection": "keep-alive",
"content-type": "application/json",
"date": "Sun, 27 Sep 2026 12:55:33 GMT",
"keep-alive": "timeout=5",
"transfer-encoding": "chunked"
},
"body": "{\"error\":\"Subtotal must be a number greater than 0 and at most 10000\"}",
"truncated": false
},
"assertions": [
{
"kind": "status",
"equals": 400,
"actual": 400,
"passed": true
},
{
"kind": "contains",
"value": "error",
"actual": "{\"error\":\"Subtotal must be a number greater than 0 and at most 10000\"}",
"passed": true
}
],
"error": null
},
{
"label": "GET /quote (missing param)",
"request": {
"method": "GET",
"path": "/quote",
"headers": {},
"body": null
},
"response": {
"status": 400,
"headers": {
"connection": "keep-alive",
"content-type": "application/json",
"date": "Sun, 27 Sep 2026 12:55:33 GMT",
"keep-alive": "timeout=5",
"transfer-encoding": "chunked"
},
"body": "{\"error\":\"Subtotal must be a number greater than 0 and at most 10000\"}",
"truncated": false
},
"assertions": [
{
"kind": "status",
"equals": 400,
"actual": 400,
"passed": true
},
{
"kind": "contains",
"value": "error",
"actual": "{\"error\":\"Subtotal must be a number greater than 0 and at most 10000\"}",
"passed": true
}
],
"error": null
},
{
"label": "GET /quote?subtotal=Infinity",
"request": {
"method": "GET",
"path": "/quote?subtotal=Infinity",
"headers": {},
"body": null
},
"response": {
"status": 400,
"headers": {
"connection": "keep-alive",
"content-type": "application/json",
"date": "Sun, 27 Sep 2026 12:55:33 GMT",
"keep-alive": "timeout=5",
"transfer-encoding": "chunked"
},
"body": "{\"error\":\"Subtotal must be a number greater than 0 and at most 10000\"}",
"truncated": false
},
"assertions": [
{
"kind": "status",
"equals": 400,
"actual": 400,
"passed": true
},
{
"kind": "contains",
"value": "error",
"actual": "{\"error\":\"Subtotal must be a number greater than 0 and at most 10000\"}",
"passed": true
}
],
"error": null
}
],
"failedAssertions": 0,
"incomplete": 0,
"durationMs": 141,
"logs": "[stdout] Shipping service ready\n",
"contractHash": "b36c5e0cc049e37ea439818b9aead714dd2ddba4e7d4d3eeeafb0c09453d50d2"
},
{
"id": "http-4",
"title": "Unknown routes return 404",
"intent": "Confirm the server responds 404 with an error body for any unregistered path",
"expected": "Status 404 and JSON error body for unrecognised paths; POST /quote also 404",
"basis": "documented",
"category": "adversarial",
"outcome": "passed",
"trace": [
{
"label": "GET /unknown",
"request": {
"method": "GET",
"path": "/unknown",
"headers": {},
"body": null
},
"response": {
"status": 404,
"headers": {
"connection": "keep-alive",
"content-type": "application/json",
"date": "Sun, 27 Sep 2026 12:55:33 GMT",
"keep-alive": "timeout=5",
"transfer-encoding": "chunked"
},
"body": "{\"error\":\"Route not found\"}",
"truncated": false
},
"assertions": [
{
"kind": "status",
"equals": 404,
"actual": 404,
"passed": true
},
{
"kind": "json",
"path": "error",
"equals": "Route not found",
"actual": "Route not found",
"passed": true
}
],
"error": null
},
{
"label": "GET /Quote (case-sensitive)",
"request": {
"method": "GET",
"path": "/Quote",
"headers": {},
"body": null
},
"response": {
"status": 404,
"headers": {
"connection": "keep-alive",
"content-type": "application/json",
"date": "Sun, 27 Sep 2026 12:55:33 GMT",
"keep-alive": "timeout=5",
"transfer-encoding": "chunked"
},
"body": "{\"error\":\"Route not found\"}",
"truncated": false
},
"assertions": [
{
"kind": "status",
"equals": 404,
"actual": 404,
"passed": true
}
],
"error": null
},
{
"label": "POST /quote (method not allowed — treated as 404 by router)",
"request": {
"method": "POST",
"path": "/quote",
"headers": {
"content-type": "application/json"
},
"body": "null"
},
"response": {
"status": 404,
"headers": {
"connection": "keep-alive",
"content-type": "application/json",
"date": "Sun, 27 Sep 2026 12:55:33 GMT",
"keep-alive": "timeout=5",
"transfer-encoding": "chunked"
},
"body": "{\"error\":\"Route not found\"}",
"truncated": false
},
"assertions": [
{
"kind": "status",
"equals": 404,
"actual": 404,
"passed": true
}
],
"error": null
},
{
"label": "GET /quote/ (trailing slash)",
"request": {
"method": "GET",
"path": "/quote/",
"headers": {},
"body": null
},
"response": {
"status": 404,
"headers": {
"connection": "keep-alive",
"content-type": "application/json",
"date": "Sun, 27 Sep 2026 12:55:33 GMT",
"keep-alive": "timeout=5",
"transfer-encoding": "chunked"
},
"body": "{\"error\":\"Route not found\"}",
"truncated": false
},
"assertions": [
{
"kind": "status",
"equals": 404,
"actual": 404,
"passed": true
}
],
"error": null
}
],
"failedAssertions": 0,
"incomplete": 0,
"durationMs": 89,
"logs": "[stdout] Shipping service ready\n",
"contractHash": "21c2b7f6ca2b1e057d3d0fa2f6173653ee650a951d122f8f01ee3b0f4cb086ec"
},
{
"id": "http-5",
"title": "GET / serves the HTML checkout page",
"intent": "Confirm the homepage returns the HTML form with correct content-type",
"expected": "Status 200, content-type text/html, body contains the form",
"basis": "documented",
"category": "normal",
"outcome": "passed",
"trace": [
{
"label": "GET /",
"request": {
"method": "GET",
"path": "/",
"headers": {},
"body": null
},
"response": {
"status": 200,
"headers": {
"connection": "keep-alive",
"content-length": "1108",
"content-type": "text/html; charset=utf-8",
"date": "Sun, 27 Sep 2026 12:55:37 GMT",
"keep-alive": "timeout=5"
},
"body": "<!doctype html><html lang=\"en\"><meta charset=\"utf-8\"><title>Shipping quote</title><style>body{font:18px system-ui;color:#23372e;background:#f5f5ef;margin:80px auto;max-width:560px}main{background:white;padding:40px;border:1px solid #dde3db;border-radius:8px}input,button{font:inherit;padding:12px}button{background:#2e5747;color:white;border:0}label{display:block;margin:24px 0 8px}output{display:block;margin-top:24px}</style><main><small>CHECKOUT</small><h1>Know your total.</h1><p>Delivery is $5. Orders of $100 or more ship free.</p><form><label for=\"subtotal\">Order subtotal ($)</label><input id=\"subtotal\" name=\"subtotal\" type=\"number\" step=\"0.01\" value=\"100\" required><button>Get quote</button></form><output aria-live=\"polite\" id=\"quote\"></output></main><script>document.querySelector('form').onsubmit=async e=>{e.preventDefault();const r=await fetch('/quote?subtotal='+encodeURIComponent(document.querySelector('#subtotal').value));const q=await r.json();document.querySelector('#quote').textContent=q.error||('Delivery: $'+q.shipping.toFixed(2)+' · Total: $'+q.total.toFixed(2));};</script></html>",
"truncated": false
},
"assertions": [
{
"kind": "status",
"equals": 200,
"actual": 200,
"passed": true
},
{
"kind": "header",
"name": "content-type",
"equals": "text/html; charset=utf-8",
"actual": "text/html; charset=utf-8",
"passed": true
},
{
"kind": "contains",
"value": "<form>",
"actual": "<!doctype html><html lang=\"en\"><meta charset=\"utf-8\"><title>Shipping quote</title><style>body{font:18px system-ui;color:#23372e;background:#f5f5ef;margin:80px auto;max-width:560px}main{background:white;padding:40px;border:1px solid #dde3db;border-radius:8px}input,button{font:inherit;padding:12px}button{background:#2e5747;color:white;border:0}label{display:block;margin:24px 0 8px}output{display:block;margin-top:24px}</style><main><small>CHECKOUT</small><h1>Know your total.</h1><p>Delivery is $5. Orders of $100 or more ship free.</p><form><label for=\"subtotal\">Order subtotal ($)</label><input id=\"subtotal\" name=\"subtotal\" type=\"number\" step=\"0.01\" value=\"100\" required><button>Get quote</button></form><output aria-live=\"polite\" id=\"quote\"></output></main><script>document.querySelector('form').onsubmit=async e=>{e.preventDefault();const r=await fetch('/quote?subtotal='+encodeURIComponent(document.querySelector('#subtotal').value));const q=await r.json();document.querySelector('#quote').textContent=q.error||('Delivery: $'+q.shipping.toFixed(2)+' · Total: $'+q.total.toFixed(2));};</script></html>",
"passed": true
},
{
"kind": "contains",
"value": "subtotal",
"actual": "<!doctype html><html lang=\"en\"><meta charset=\"utf-8\"><title>Shipping quote</title><style>body{font:18px system-ui;color:#23372e;background:#f5f5ef;margin:80px auto;max-width:560px}main{background:white;padding:40px;border:1px solid #dde3db;border-radius:8px}input,button{font:inherit;padding:12px}button{background:#2e5747;color:white;border:0}label{display:block;margin:24px 0 8px}output{display:block;margin-top:24px}</style><main><small>CHECKOUT</small><h1>Know your total.</h1><p>Delivery is $5. Orders of $100 or more ship free.</p><form><label for=\"subtotal\">Order subtotal ($)</label><input id=\"subtotal\" name=\"subtotal\" type=\"number\" step=\"0.01\" value=\"100\" required><button>Get quote</button></form><output aria-live=\"polite\" id=\"quote\"></output></main><script>document.querySelector('form').onsubmit=async e=>{e.preventDefault();const r=await fetch('/quote?subtotal='+encodeURIComponent(document.querySelector('#subtotal').value));const q=await r.json();document.querySelector('#quote').textContent=q.error||('Delivery: $'+q.shipping.toFixed(2)+' · Total: $'+q.total.toFixed(2));};</script></html>",
"passed": true
}
],
"error": null
}
],
"failedAssertions": 0,
"incomplete": 0,
"durationMs": 111,
"logs": "[stdout] Shipping service ready\n",
"contractHash": "b3044b7617f736aa6a0f9f27f5fc259837a464b9267d6f7b9d8a5298686218b4"
},
{
"id": "http-6",
"title": "Content-type is application/json on API responses",
"intent": "Ensure the API sets the correct content-type header for both success and error responses",
"expected": "content-type: application/json on 200 and 400 responses",
"basis": "documented",
"category": "normal",
"outcome": "passed",
"trace": [
{
"label": "Successful quote content-type",
"request": {
"method": "GET",
"path": "/quote?subtotal=50",
"headers": {},
"body": null
},
"response": {
"status": 200,
"headers": {
"connection": "keep-alive",
"content-type": "application/json",
"date": "Sun, 27 Sep 2026 12:55:37 GMT",
"keep-alive": "timeout=5",
"transfer-encoding": "chunked"
},
"body": "{\"subtotal\":50,\"shipping\":5,\"total\":55}",
"truncated": false
},
"assertions": [
{
"kind": "status",
"equals": 200,
"actual": 200,
"passed": true
},
{
"kind": "header",
"name": "content-type",
"equals": "application/json",
"actual": "application/json",
"passed": true
}
],
"error": null
},
{
"label": "Error response content-type",
"request": {
"method": "GET",
"path": "/quote?subtotal=0",
"headers": {},
"body": null
},
"response": {
"status": 400,
"headers": {
"connection": "keep-alive",
"content-type": "application/json",
"date": "Sun, 27 Sep 2026 12:55:37 GMT",
"keep-alive": "timeout=5",
"transfer-encoding": "chunked"
},
"body": "{\"error\":\"Subtotal must be a number greater than 0 and at most 10000\"}",
"truncated": false
},
"assertions": [
{
"kind": "status",
"equals": 400,
"actual": 400,
"passed": true
},
{
"kind": "header",
"name": "content-type",
"equals": "application/json",
"actual": "application/json",
"passed": true
}
],
"error": null
}
],
"failedAssertions": 0,
"incomplete": 0,
"durationMs": 121,
"logs": "[stdout] Shipping service ready\n",
"contractHash": "6fd73083be10e45c3da392938d3994a5b4135d55b1b89e20a787882059dfe361"
},
{
"id": "adversarial-0",
"title": "Malformed and unexpected inputs: POST /quote",
"intent": "Exercise malformed JSON, null, arrays, missing values, unexpected types and numeric boundaries. Detect unhandled HTTP 5xx responses.",
"expected": "Bad inputs are handled without an unhandled server error. Exact domain rejection status is not assumed.",
"basis": "assumption",
"category": "input-validation",
"outcome": "passed",
"trace": [
{
"label": "Malformed JSON",
"request": {
"method": "POST",
"path": "/quote",
"headers": {
"content-type": "application/json"
},
"body": "{\"broken\":"
},
"response": {
"status": 404,
"headers": {
"connection": "keep-alive",
"content-type": "application/json",
"date": "Sun, 27 Sep 2026 12:55:40 GMT",
"keep-alive": "timeout=5",
"transfer-encoding": "chunked"
},
"body": "{\"error\":\"Route not found\"}",
"truncated": false
},
"assertions": [
{
"kind": "not5xx",
"actual": 404,
"passed": true
}
],
"error": null
},
{
"label": "Unexpected input 0",
"request": {
"method": "POST",
"path": "/quote",
"headers": {
"content-type": "application/json"
},
"body": "null"
},
"response": {
"status": 404,
"headers": {
"connection": "keep-alive",
"content-type": "application/json",
"date": "Sun, 27 Sep 2026 12:55:40 GMT",
"keep-alive": "timeout=5",
"transfer-encoding": "chunked"
},
"body": "{\"error\":\"Route not found\"}",
"truncated": false
},
"assertions": [
{
"kind": "not5xx",
"actual": 404,
"passed": true
}
],
"error": null
},
{
"label": "Unexpected input 1",
"request": {
"method": "POST",
"path": "/quote",
"headers": {
"content-type": "application/json"
},
"body": "[]"
},
"response": {
"status": 404,
"headers": {
"connection": "keep-alive",
"content-type": "application/json",
"date": "Sun, 27 Sep 2026 12:55:40 GMT",
"keep-alive": "timeout=5",
"transfer-encoding": "chunked"
},
"body": "{\"error\":\"Route not found\"}",
"truncated": false
},
"assertions": [
{
"kind": "not5xx",
"actual": 404,
"passed": true
}
],
"error": null
},
{
"label": "Unexpected input 2",
"request": {
"method": "POST",
"path": "/quote",
"headers": {
"content-type": "application/json"
},
"body": "{}"
},
"response": {
"status": 404,
"headers": {
"connection": "keep-alive",
"content-type": "application/json",
"date": "Sun, 27 Sep 2026 12:55:40 GMT",
"keep-alive": "timeout=5",
"transfer-encoding": "chunked"
},
"body": "{\"error\":\"Route not found\"}",
"truncated": false
},
"assertions": [
{
"kind": "not5xx",
"actual": 404,
"passed": true
}
],
"error": null
},
{
"label": "Unexpected input 3",
"request": {
"method": "POST",
"path": "/quote",
"headers": {
"content-type": "application/json"
},
"body": "\"unexpected\""
},
"response": {
"status": 404,
"headers": {
"connection": "keep-alive",
"content-type": "application/json",
"date": "Sun, 27 Sep 2026 12:55:40 GMT",
"keep-alive": "timeout=5",
"transfer-encoding": "chunked"
},
"body": "{\"error\":\"Route not found\"}",
"truncated": false
},
"assertions": [
{
"kind": "not5xx",
"actual": 404,
"passed": true
}
],
"error": null
},
{
"label": "Unexpected input 4",
"request": {
"method": "POST",
"path": "/quote",
"headers": {
"content-type": "application/json"
},
"body": "{}"
},
"response": {
"status": 404,
"headers": {
"connection": "keep-alive",
"content-type": "application/json",
"date": "Sun, 27 Sep 2026 12:55:40 GMT",
"keep-alive": "timeout=5",
"transfer-encoding": "chunked"
},
"body": "{\"error\":\"Route not found\"}",
"truncated": false
},
"assertions": [
{
"kind": "not5xx",
"actual": 404,
"passed": true
}
],
"error": null
}
],
"failedAssertions": 0,
"incomplete": 0,
"durationMs": 107,
"logs": "[stdout] Shipping service ready\n",
"contractHash": "006c3b0e2378c8a795662ca896ebaab9271ee50a5e6e3097088188255f73f716"
},
{
"id": "browser-1",
"title": "Happy-path quote submission",
"intent": "User enters a valid subtotal, submits the form, and sees the delivery charge and total",
"expected": "Output element shows Delivery and Total values matching the API response",
"basis": "documented",
"category": "frontend",
"outcome": "passed",
"trace": [
{
"action": {
"action": "goto",
"path": "/"
},
"error": null
},
{
"action": {
"action": "visible",
"selector": "form"
},
"error": null
},
{
"action": {
"action": "fill",
"selector": "#subtotal",
"value": "50"
},
"error": null
},
{
"action": {
"action": "click",
"selector": "button"
},
"error": null
},
{
"action": {
"action": "text",
"selector": "#quote",
"value": "Delivery: $5.00"
},
"error": null
},
{
"action": {
"action": "text",
"selector": "#quote",
"value": "Total: $55.00"
},
"error": null
}
],
"errors": [],
"observations": [],
"requests": [],
"network": [
{
"action": {
"action": "goto",
"path": "/"
},
"url": "http://127.0.0.1:3100/",
"method": "GET",
"status": 200
},
{
"action": {
"action": "text",
"selector": "#quote",
"value": "Delivery: $5.00"
},
"url": "http://127.0.0.1:3100/quote?subtotal=50",
"method": "GET",
"status": 200
}
],
"durationMs": 369,
"screenshot": "proofrun-9328f562-2e5-browser-1-final.png",
"limitations": [],
"logs": "[stdout] Shipping service ready\n",
"contractHash": "84a6359d76e397493634859908720ac6b61113344f9e80fed021a42c88a0ac6b"
},
{
"id": "browser-2",
"title": "Free-shipping boundary quote in browser",
"intent": "Submit subtotal=150 and verify the form displays zero shipping cost",
"expected": "Output shows Delivery: $0.00 and Total: $150.00",
"basis": "documented",
"category": "frontend",
"outcome": "passed",
"trace": [
{
"action": {
"action": "goto",
"path": "/"
},
"error": null
},
{
"action": {
"action": "fill",
"selector": "#subtotal",
"value": "150"
},
"error": null
},
{
"action": {
"action": "click",
"selector": "button"
},
"error": null
},
{
"action": {
"action": "text",
"selector": "#quote",
"value": "Delivery: $0.00"
},
"error": null
},
{
"action": {
"action": "text",
"selector": "#quote",
"value": "Total: $150.00"
},
"error": null
}
],
"errors": [],
"observations": [],
"requests": [],
"network": [
{
"action": {
"action": "goto",
"path": "/"
},
"url": "http://127.0.0.1:3100/",
"method": "GET",
"status": 200
},
{
"action": {
"action": "text",
"selector": "#quote",
"value": "Delivery: $0.00"
},
"url": "http://127.0.0.1:3100/quote?subtotal=150",
"method": "GET",
"status": 200
}
],
"durationMs": 396,
"screenshot": "proofrun-6c1c20aa-491-browser-2-final.png",
"limitations": [],
"logs": "[stdout] Shipping service ready\n",
"contractHash": "592d6ec307d13b619a3cb1982fe60261944dde03a44244293117245c346694c4"
},
{
"id": "browser-3",
"title": "Missing subtotal triggers native browser validation",
"intent": "Clear the required number input and attempt submission; native validation must block the request",
"expected": "#subtotal is in an invalid state and no network request is made",
"basis": "documented",
"category": "frontend",
"outcome": "passed",
"trace": [
{
"action": {
"action": "goto",
"path": "/"
},
"error": null
},
{
"action": {
"action": "fill",
"selector": "#subtotal",
"value": ""
},
"error": null
},
{
"action": {
"action": "click",
"selector": "button"
},
"error": null
},
{
"action": {
"action": "invalid",
"selector": "#subtotal"
},
"error": null,
"validation": {
"valid": false,
"willValidate": true,
"message": "Please fill out this field.",
"value": ""
}
}
],
"errors": [],
"observations": [],
"requests": [],
"network": [
{
"action": {
"action": "goto",
"path": "/"
},
"url": "http://127.0.0.1:3100/",
"method": "GET",
"status": 200
}
],
"durationMs": 389,
"screenshot": "proofrun-8c3f9216-903-browser-3-final.png",
"limitations": [],
"logs": "[stdout] Shipping service ready\n",
"contractHash": "ac4c14a5ea48f5a8aa54e54eb72b78a0c2408e4daa7c4f195b562869f486ea5b"
}
],
"existingTests": [
{
"argv": [
"node",
"--test",
"tests/*.test.mjs"
],
"exitCode": 0,
"signal": null,
"timedOut": false,
"stdout": "TAP version 13\n# Subtest: ordinary orders have a five dollar delivery charge\nok 1 - ordinary orders have a five dollar delivery charge\n ---\n duration_ms: 1.427691\n type: 'test'\n ...\n# Subtest: large orders ship free\nok 2 - large orders ship free\n ---\n duration_ms: 0.236565\n type: 'test'\n ...\n# Subtest: invalid amounts are rejected\nok 3 - invalid amounts are rejected\n ---\n duration_ms: 0.263272\n type: 'test'\n ...\n1..3\n# tests 3\n# suites 0\n# pass 3\n# fail 0\n# cancelled 0\n# skipped 0\n# todo 0\n# duration_ms 71.537669\n",
"stderr": "",
"durationMs": 226,
"truncated": false,
"label": "Run unit tests",
"timeoutSeconds": 600,
"cwd": "."
}
],
"resolved": true,
"regressions": []
}New AI analysis requires active IBM credentials. Available checks are bounded; these results do not certify arbitrary software.