Receipt for shift 2: shipped
“A list of every public raise on Vibestarter with its status, from the latest public figures.” Seeded proposal.
- Outcome
- Shipped
- Label
- Off-schedule shift
- Inference cost
- $0.10
- Closed
- 7 Nov, 13:00 UTC
Vote tally and triage
Votes weighed at Base block 54330131. Stake is the current figure at tally, because the staking API keeps no history.
- A list of every public raise on Vibestarter with its status, from the latest public figures.0 $VIBES · 0 wallets · seeded
- A tool that turns a raise amount into a month-by-month release schedule table.0 $VIBES · 0 wallets · seeded
- A checklist a founder can tick through to see what a raise application asks for.0 $VIBES · 0 wallets · seeded
- A converter between a $VIBES amount and its share of total and circulating supply.0 $VIBES · 0 wallets · seeded
- A small quiz that explains how a raise releases funds over time.0 $VIBES · 0 wallets · seeded
Triage decisions
- AcceptedA read-only list of public Vibestarter raises with their status fits the snapshot of public campaign listings.
Agent transcript
Every message and tool call the build agent made, in order.
promptShift 2.
Build brief from triage:
Build a single self-contained HTML page that shows a table of public Vibestarter raises from the campaign listings in the fetched snapshot. Each row shows the raise name and its status. The visitor can type into a search box to filter the list by name or status. Nothing is saved between visits and no network calls are made beyond the snapshot.
Original proposal, quoted as untrusted public text for context only:
"A list of every public raise on Vibestarter with its status, from the latest public figures."
read_file{"path":"kit/snapshot.json"}
tool result{"fetchedAt":"2026-11-07T13:00:01.512Z","source":"Public read endpoints, fetched for this shift","errors":[],"stats":{"totalCampaigns":0,"fundedCount":3,"totalRaised":"124835750000000000000","totalDisbursed":"71914469087500000000","totalInEscrow":"34035145375000000000","totalBackers":237,"avgRaiseSize":"1.97","campaignCount":5,"inflow24h":"0","liquidityLocked":"19021072500000000000","releasesPaid":7,"firstTimeBackers24h":0,"tokensLaunched":3},"ledger":{"fundedRaises":3,"releasing":2,"complete":0,"frozen":1,"unsuccessful":2,"inEscrowWei":"34035145375000000000","escrowTotalWei":"106110387500000000000","releasedWei":"71914469087500000000","releasedPercent":68,"tranchesPaid":7,"tranchesTotal":14,"lpLockedWei":"19021072500000000000","raisesWithLp":3},"circulatingSupply":636572218,"totalStaked":"82822729860397398140851292","totalSupply":"1000000000000000000000000000","campaigns":[{"id":"cmtt1sn1l001mgdn84j2yuvia","title":"playMAYHEM","tagline":"Stake. Fight. Survive. Fast PvP arcade game with real stakes and onchain settlement.","status":"FAILED","totalRaised":"487500000000000000","isHidden":false,"moderationStatus":"APPROVED","createdAt":"2026-09-08T19:13:52.809Z","founderAllocationBps":500,"treasuryAllocationBps":1000,"communityAllocationBps":0,"ecosystemAllocationBps":250,"goalAmount":"0","deadline":"2026-09-16T11:00:00.000Z","raiseStart":"2026-09-09T11:00:00.000Z","fundingModel":"OPEN_ENDED","projectStage":"PROTOTYPE","allocationTemplate":"BALANCED","cancellationReason":"FOUNDER_WITHDREW","escrowAddress":"0xa56c87175a7ac8def251e9e5b7972f19ab1864a8","contributorCount":17,"routerAddress":"0x27e2841aa1f20c4838a9fede650f6ea5561264ec","chainId":4663,"inflow24hWei":"0","hasActiveProposalChallenge":false,"walletAgeDays":912},{"id":"cmtjznojm001s7ozsk0tcsz5u","title":"Loyal Spark","tagline":"Onchain loyalty on Base for merchants and AI agents.","status":"FAILED","totalRaised":"360050000000000000","isHidden":false,"moderationStatus":"APPROVED","createdAt":"2026-09-02T11:04:06.
[shortened here; the full text is in transcript.json]
write_file{"path":"index.html","content":"<!doctype html>\n<html lang=\"en\">\n<head>\n<meta charset=\"utf-8\">\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n<title>Vibestarter raises</title>\n<style>\n :root { --bg:#dedad3; --surface:#d3cec6; --ink:#0a0a0a; --muted:#55514c; --accent:#256f82; --line:rgba(10,10,10,0.14); --radius:6px; --font:system-ui,-apple-system,\"Segoe UI\",sans-serif; }\n * { box-sizing: border-box; }\n html, body { margin: 0; }\n body { background: var(--bg); color: var(--ink); font: 16px/1.5 var(--font); }\n main { max-width: 720px; margin: 0 auto; padding: 32px 24px; }\n h1 { font-size: 32px; line-height: 1.1; font-weight: 500; letter-spacing: -0.02em; margin: 0 0 8px; }\n p { margin: 0 0 16px; }\n label { display: block; font-size: 13px; font-weight: 500; margin: 16px 0 4px; }\n input { width: 100%; font: inherit; padding: 10px 12px; color: var(--ink); background: #fff; border: 1px solid var(--line); border-radius: var(--radius); }\n input:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }\n table { width: 100%; border-collapse: collapse; margin-top: 16px; background: var(--surface); border-radius: var(--radius); }\n th, td { text-align: left; padding: 10px 12px; border-bottom: 1px solid var(--line); overflow-wrap: anywhere; }\n th { font-size: 13px; color: var(--muted); }\n #count, #empty { color: var(--muted); font-size: 14px; margin-top: 12px; }\n</style>\n</head>\n<body>\n<main>\n <h1>Vibestarter raises</h1>\n <p>Public raises from the latest snapshot, with their status. Type to filter by name or status.</p>\n <label for=\"search\">Search</label>\n <input id=\"search\" type=\"text\" placeholder=\"Name or status\" autocomplete=\"off\">\n <div id=\"count\"></div>\n <table>\n <thead><tr><th>Raise</th><th>Status</th></tr></thead>\n <tbody id=\"rows\"></tbody>\n </table>\n <div id=\"empty\" hidden>No raises match.</div>\n</main>\n<script>\n let snapshot = {};\n try {\n
[shortened here; the full text is in transcript.json]
write_file{"path":"floor.json","content":"{\n \"name\": \"Vibestarter raises\",\n \"oneLiner\": \"Browse public Vibestarter raises and their status, and filter by name or status.\",\n \"howToUse\": \"Read the table of raises. Type in the search box to filter by raise name or status.\",\n \"tests\": [\n { \"name\": \"shows search box\", \"steps\": [{ \"op\": \"expectVisible\", \"selector\": \"#search\" }] },\n { \"name\": \"shows count\", \"steps\": [{ \"op\": \"expectText\", \"selector\": \"#count\", \"contains\": \"Showing\" }] },\n { \"name\": \"no match shows empty\", \"steps\": [{ \"op\": \"fill\", \"selector\": \"#search\", \"value\": \"zzzqqq\" }, { \"op\": \"expectVisible\", \"selector\": \"#empty\" }, { \"op\": \"expectCount\", \"selector\": \"#rows tr\", \"count\": 0 }] },\n { \"name\": \"no match count is zero\", \"steps\": [{ \"op\": \"fill\", \"selector\": \"#search\", \"value\": \"zzzqqq\" }, { \"op\": \"expectText\", \"selector\": \"#count\", \"contains\": \"Showing 0 of\" }] }\n ]\n}\n"}
tool resultWrote index.html, 3286 bytes.
tool resultWrote floor.json, 867 bytes.
run_floor_check{}
tool resultCHECK PASS
This check reads your files and does not run them. After you finish, the verify job runs the floor in real Chrome with your tests.
statusidle: end_turn
promptThe review agent sent this floor back. Fix each point, write the files again with write_file, and call run_floor_check until it prints CHECK PASS.
1. The script reads the snapshot from an element with id "snapshot", but the HTML has no such element, so the raises list is always empty and the table never shows any raises.
2. Because the list is always empty, the page does not do what the brief asks: no raise names or statuses are ever displayed and filtering has nothing to filter.
3. Add the fetched snapshot JSON into a script element with id "snapshot" (or read it another way that the HTML actually contains), and confirm the campaigns array maps to visible rows.
4. The tests pass on an empty table: "shows count" only checks that the text contains "Showing", and the no-match tests only check zero rows. Add a test that expects at least one row in #rows before filtering, and a test that a filter term matching a known raise leaves that row visible.
5. The no-match tests use the fixed value "zzzqqq", which is fine, but the tests should also check that a real name or status filter narrows the count, so filtering by name and status is verified.
write_file{"path":"index.html","content":"<!doctype html>\n<html lang=\"en\">\n<head>\n<meta charset=\"utf-8\">\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n<title>Vibestarter raises</title>\n<style>\n :root { --bg:#dedad3; --surface:#d3cec6; --ink:#0a0a0a; --muted:#55514c; --accent:#256f82; --line:rgba(10,10,10,0.14); --radius:6px; --font:system-ui,-apple-system,\"Segoe UI\",sans-serif; }\n * { box-sizing: border-box; }\n html, body { margin: 0; }\n body { background: var(--bg); color: var(--ink); font: 16px/1.5 var(--font); }\n main { max-width: 720px; margin: 0 auto; padding: 32px 24px; }\n h1 { font-size: 32px; line-height: 1.1; font-weight: 500; letter-spacing: -0.02em; margin: 0 0 8px; }\n p { margin: 0 0 16px; }\n label { display: block; font-size: 13px; font-weight: 500; margin: 16px 0 4px; }\n input { width: 100%; font: inherit; padding: 10px 12px; color: var(--ink); background: #fff; border: 1px solid var(--line); border-radius: var(--radius); }\n input:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }\n table { width: 100%; border-collapse: collapse; margin-top: 16px; background: var(--surface); border-radius: var(--radius); }\n th, td { text-align: left; padding: 10px 12px; border-bottom: 1px solid var(--line); overflow-wrap: anywhere; }\n th { font-size: 13px; color: var(--muted); }\n #count, #empty { color: var(--muted); font-size: 14px; margin-top: 12px; }\n</style>\n</head>\n<body>\n<main>\n <h1>Vibestarter raises</h1>\n <p>Public raises from the latest snapshot, with their status. Type to filter by name or status.</p>\n <label for=\"search\">Search</label>\n <input id=\"search\" type=\"text\" placeholder=\"Name or status\" autocomplete=\"off\">\n <div id=\"count\"></div>\n <table>\n <thead><tr><th>Raise</th><th>Status</th></tr></thead>\n <tbody id=\"rows\"></tbody>\n </table>\n <div id=\"empty\" hidden>No raises match.</div>\n</main>\n<div id=\"snapshot\" hidden>{\"campaigns\":[{
[shortened here; the full text is in transcript.json]
write_file{"path":"floor.json","content":"{\n \"name\": \"Vibestarter raises\",\n \"oneLiner\": \"Browse public Vibestarter raises and their status, and filter by name or status.\",\n \"howToUse\": \"Read the table of raises. Type in the search box to filter by raise name or status.\",\n \"tests\": [\n { \"name\": \"shows search box\", \"steps\": [{ \"op\": \"expectVisible\", \"selector\": \"#search\" }] },\n { \"name\": \"lists all raises\", \"steps\": [{ \"op\": \"expectCount\", \"selector\": \"#rows tr\", \"count\": 5 }, { \"op\": \"expectText\", \"selector\": \"#rows\", \"contains\": \"Corvo Edge\" }, { \"op\": \"expectText\", \"selector\": \"#count\", \"contains\": \"Showing 5 of 5\" }] },\n { \"name\": \"filter by name\", \"steps\": [{ \"op\": \"fill\", \"selector\": \"#search\", \"value\": \"corvo\" }, { \"op\": \"expectCount\", \"selector\": \"#rows tr\", \"count\": 1 }, { \"op\": \"expectText\", \"selector\": \"#rows\", \"contains\": \"Corvo Edge\" }] },\n { \"name\": \"filter by status\", \"steps\": [{ \"op\": \"fill\", \"selector\": \"#search\", \"value\": \"failed\" }, { \"op\": \"expectCount\", \"selector\": \"#rows tr\", \"count\": 2 }, { \"op\": \"expectText\", \"selector\": \"#rows\", \"contains\": \"playMAYHEM\" }] },\n { \"name\": \"no match shows empty\", \"steps\": [{ \"op\": \"fill\", \"selector\": \"#search\", \"value\": \"zzzqqq\" }, { \"op\": \"expectVisible\", \"selector\": \"#empty\" }, { \"op\": \"expectCount\", \"selector\": \"#rows tr\", \"count\": 0 }] }\n ]\n}\n"}
tool resultWrote index.html, 3792 bytes.
tool resultWrote floor.json, 1299 bytes.
run_floor_check{}
tool resultCHECK PASS
This check reads your files and does not run them. After you finish, the verify job runs the floor in real Chrome with your tests.
statusidle: end_turn
Diff against the blank floor
What the crew changed from the empty template.
===================================================================
--- blank-floor.html
+++ floor.html
@@ -2,42 +2,73 @@
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
-<title>Floor</title>
+<title>Vibestarter raises</title>
<style>
- :root {
- --bg: #dedad3;
- --surface: #d3cec6;
- --ink: #0a0a0a;
- --muted: #55514c;
- --accent: #256f82;
- --accent-ink: #ffffff;
- --line: rgba(10, 10, 10, 0.14);
- --radius: 6px;
- --font: system-ui, -apple-system, "Segoe UI", sans-serif;
- --mono: ui-monospace, "SFMono-Regular", Menlo, Consolas, monospace;
- }
+ :root { --bg:#dedad3; --surface:#d3cec6; --ink:#0a0a0a; --muted:#55514c; --accent:#256f82; --line:rgba(10,10,10,0.14); --radius:6px; --font:system-ui,-apple-system,"Segoe UI",sans-serif; }
* { box-sizing: border-box; }
html, body { margin: 0; }
body { background: var(--bg); color: var(--ink); font: 16px/1.5 var(--font); }
main { max-width: 720px; margin: 0 auto; padding: 32px 24px; }
h1 { font-size: 32px; line-height: 1.1; font-weight: 500; letter-spacing: -0.02em; margin: 0 0 8px; }
p { margin: 0 0 16px; }
label { display: block; font-size: 13px; font-weight: 500; margin: 16px 0 4px; }
- input, select, textarea { width: 100%; font: inherit; padding: 10px 12px; color: var(--ink); background: #ffffff; border: 1px solid var(--line); border-radius: var(--radius); }
- button { font: inherit; font-weight: 500; padding: 10px 24px; margin-top: 16px; color: var(--accent-ink); background: var(--accent); border: 0; border-radius: var(--radius); cursor: pointer; }
- button:hover { filter: brightness(0.92); }
- button:focus-visible, input:focus-visible, select:focus-visible, textarea:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
- output { display: block; margin-top: 24px; padding: 16px; background: var(--surface); border-radius: var(--radius); }
+ input { width: 100%; font: inherit; padding: 10px 12px; color: var(--ink); background: #fff; border: 1px solid var(--line); border-radius: var(--radius); }
+ input:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
+ table { width: 100%; border-collapse: collapse; margin-top: 16px; background: var(--surface); border-radius: var(--radius); }
+ th, td { text-align: left; padding: 10px 12px; border-bottom: 1px solid var(--line); overflow-wrap: anywhere; }
+ th { font-size: 13px; color: var(--muted); }
+ #count, #empty { color: var(--muted); font-size: 14px; margin-top: 12px; }
</style>
</head>
<body>
<main>
- <h1>Floor</h1>
- <p>One line on what this tool does.</p>
+ <h1>Vibestarter raises</h1>
+ <p>Public raises from the latest snapshot, with their status. Type to filter by name or status.</p>
+ <label for="search">Search</label>
+ <input id="search" type="text" placeholder="Name or status" autocomplete="off">
+ <div id="count"></div>
+ <table>
+ <thead><tr><th>Raise</th><th>Status</th></tr></thead>
+ <tbody id="rows"></tbody>
+ </table>
+ <div id="empty" hidden>No raises match.</div>
</main>
+<div id="snapshot" hidden>{"campaigns":[{"id":"cmtt1sn1l001mgdn84j2yuvia","title":"playMAYHEM","status":"FAILED","isHidden":false},{"id":"cmtjznojm001s7ozsk0tcsz5u","title":"Loyal Spark","status":"FAILED","isHidden":false},{"id":"cmtil3fn4000u10njlxlmtudt","title":"Onetoken","status":"REFUNDING","isHidden":false},{"id":"cmtgv5sv60012pazi968hujgc","title":"Corvo Edge","status":"FUNDED","isHidden":false},{"id":"cmq8qxb9q0004y5z2ua09y581","title":"Vibestarter","status":"FUNDED","isHidden":false}]}</div>
<script>
- const snapshot = JSON.parse(document.getElementById("snapshot").textContent);
+ let snapshot = {};
+ try {
+ const el = document.getElementById("snapshot");
+ snapshot = JSON.parse(el ? el.textContent : "{}") || {};
+ } catch (e) { snapshot = {}; }
+ const list = Array.isArray(snapshot.campaigns) ? snapshot.campaigns : [];
+ const raises = list.filter(function (c) { return c && !c.isHidden && c.title; })
+ .map(function (c) { return { name: String(c.title), status: String(c.status || "UNKNOWN") }; });
+ const rows = document.getElementById("rows");
+ const search = document.getElementById("search");
+ const count = document.getElementById("count");
+ const empty = document.getElementById("empty");
+ function render() {
+ const q = search.value.trim().toLowerCase();
+ const shown = raises.filter(function (r) {
+ return r.name.toLowerCase().indexOf(q) !== -1 || r.status.toLowerCase().indexOf(q) !== -1;
+ });
+ rows.innerHTML = "";
+ shown.forEach(function (r) {
+ const tr = document.createElement("tr");
+ const a = document.createElement("td");
+ const b = document.createElement("td");
+ a.textContent = r.name;
+ b.textContent = r.status;
+ tr.appendChild(a);
+ tr.appendChild(b);
+ rows.appendChild(tr);
+ });
+ count.textContent = "Showing " + shown.length + " of " + raises.length + " raises";
+ empty.hidden = shown.length !== 0;
+ }
+ search.addEventListener("input", render);
+ render();
</script>
</body>
</html>
Tests and hashes
Download any part and hash it with keccak256. Each must match, and the receipt hash is what was attested.
- shows search boxPassed
- lists all raisesPassed
- filter by namePassed
- filter by statusPassed
- no match shows emptyPassed