/jobs?status=open API, and /health.0 open, while live API reports 120 rows marked open.contract_job_id=0 and payout_status=none, while /health reported treasury 0.396733 USDC and 39 failed payouts at the audit instant.API_STATUS_OPEN != ESCROW_FUNDED_OPEN; API rows are not promoted to executable revenue targets without funding/escrow proof.bountybook_watch in Turso and only emits a MONITOR_CHANGE action receipt when material state changes; repeated identical runs do not duplicate change receipts.FETCH_FAIL != ZERO_OPEN.payana/.REV-000001 = USD 0.01 with USER_CONFIRMED_RECEIPT_UNVERIFIED instead of fabricating missing provenance.receipt-gap-REV-000001 to track missing platform/task/transaction/timestamp evidence.vault_bridge.ts to bridge version 0.6.0 with six PayAna actions and snapshot retrieval.Frontend files are now served at version-addressed URLs
(/__immutable/45/frontend/index.tsx) with
Cache-Control: public, max-age=31536000, immutable, so repeat visits load the
whole client graph from the browser cache — roughly 3× faster (~665ms → ~157ms
measured). Publishing your val bumps its version, which changes every URL, so
caches invalidate automatically. Old-version URLs return 404 after a publish
(like Next.js build assets); a reload picks up the new version.
What changed in the template:
frontend/index.html → frontend/root.tsx: the HTML
shell is now JSX and stamps asset URLs with immutableFileUrl()index.ts: serves Root() at /, and one
app.get("/__immutable/*", (c) => serveImmutableFile(c.req.path)) route
serves all frontend filesYour copy of this template doesn't update automatically. Two options:
Minimal (most of the benefit): point both routes at serveImmutableFile —
your existing bare URLs redirect into versioned space, the new route serves
them, and the whole module graph gets cached (costs one redirect per page view):
import { serveImmutableFile } from "https://esm.town/v/std/utils/index.ts";
app.get("/__immutable/*", (c) => serveImmutableFile(c.req.path));
app.get("/frontend/**/*", (c) => serveImmutableFile(c.req.path)); // was serveFile
Full upgrade (also removes the redirect): three self-contained steps —
no other files needed. Adjust the <title>, favicon, and body of Root() to
match your app's existing index.html, and stamp anything else your shell
references directly (images, css) with immutableFileUrl().
frontend/root.tsx:/** @jsxImportSource npm:hono@4/jsx */
import { raw } from "npm:hono@4/html";
import { immutableFileUrl } from "https://esm.town/v/std/utils/index.ts";
// The HTML shell for the app. It is never cached, so immutableFileUrl can stamp
// the current val version into each asset URL — the browser caches those
// immutably, and publishing the val changes the URLs, refetching exactly once.
export function Root() {
return (
<>
{raw("<!DOCTYPE html>")}
<html lang="en">
<head>
<meta charSet="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>React Hono Val Town Starter</title>
<script src="https://cdn.twind.style" crossOrigin="" />
<link rel="icon" href={immutableFileUrl("/frontend/favicon.svg")} type="image/svg+xml" />
</head>
<body className="font-sans text-gray-800 p-6">
<main>
<div id="root" />
</main>
<script src="https://esm.town/v/std/catch" />
<script src={immutableFileUrl("/frontend/index.tsx")} type="module" />
</body>
</html>
</>
);
}
Root and serveImmutableFile, and replace
your / and frontend file routes with:import { serveImmutableFile } from "https://esm.town/v/std/utils/index.ts";
import { Root } from "./frontend/root.tsx";
// Serve the (never-cached) HTML shell at the root /
app.get("/", (c) => c.html(Root()));
// Serve frontend files at the version-addressed URLs Root() stamps, cached immutably
app.get("/__immutable/*", (c) => serveImmutableFile(c.req.path));
frontend/index.html (and any now-unused serveFile import).guh-vault skill.conversations*.json.vault_import_runs).v06_selftest.ts and v06_release_audit.ts.UNKNOWN_EXTERNAL_STATE fail-safe instead of blind retry after ambiguous network failures.accept filtering from the hidden file input because iOS Files/Safari exposed only JSON in the picker.