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.

  1. A list of every public raise on Vibestarter with its status, from the latest public figures.0 $VIBES · 0 wallets · seeded
  2. A tool that turns a raise amount into a month-by-month release schedule table.0 $VIBES · 0 wallets · seeded
  3. A checklist a founder can tick through to see what a raise application asks for.0 $VIBES · 0 wallets · seeded
  4. A converter between a $VIBES amount and its share of total and circulating supply.0 $VIBES · 0 wallets · seeded
  5. 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.
messageI built a single-page table of public Vibestarter raises. Each row shows the raise name and its status. A search box filters the rows by name or status as you type. `run_floor_check` prints CHECK PASS. I traced the four tests in `floor.json` through the code by hand, but nothing has run the page yet. - **Data:** the page reads only the snapshot's `campaigns` list and skips hidden campaigns. The snapshot you gave me has five campaigns. It makes no network calls and saves nothing. - **Missing snapshot:** `index.html` doesn't contain the `snapshot` element itself, because the pipeline inserts it. If the pipeline doesn't, the page shows an empty table with "No raises match." - **Tests:** they check that the search box is visible and that the "Showing" count appears. They also check that a search for text that matches nothing empties the table and shows the "No raises match." message. None of them name a specific raise, so they don't depend on which raises the snapshot holds.
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.
messageI fixed the empty table, and `run_floor_check` now prints CHECK PASS. I traced the tests through the code by hand, but nothing has run the page yet. - **Snapshot:** `index.html` now contains the campaigns as JSON in a hidden `<div id="snapshot">`. I used a div because the rules allow only one `<script>`. The script reads that div. The five campaigns map to five visible rows, each with a name and a status. - **Fixed copy:** The data in that div is a fixed copy of the five campaigns from this shift's snapshot, trimmed to id, title, status and hidden flag. If the pipeline also inserts its own `snapshot` element, the page still reads mine first, so the page won't pick up fresher figures from the pipeline. - **Tests:** `floor.json` now has five tests that would fail on an empty table. - **Row count:** It expects five rows and "Showing 5 of 5" before any filtering. - **Name filter:** Typing "corvo" leaves one row, Corvo Edge. - **Status filter:** Typing "failed" leaves two rows and includes playMAYHEM. - **No match:** A search for "zzzqqq" shows the empty message and zero rows. - **Search box:** The search box is visible.
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