{"_self":{"principle":"Self-explaining payload — no external context required. This _self block describes what you are reading and where to look next.","widget":"article_bundle","feature":"bundle","name":"LLM article bundle","what":"Portable reference package: body + claims + sources + voxels + provenance + manifest + constitution.","contains":"body, claims, sources, voxels, provenance, question graph, constitution, llm_manifest","slug":"cloudflare-os-workers","urls":{"read":"https://miscsubjects.com/api/articles/cloudflare-os-workers/bundle?format=markdown"},"how_to_use":"Reference bundle for an LLM or reader. §SELF explains the surface; ingest and claim endpoints in llm_manifest are the write-back routes.","write":null,"imessage":null,"router_tag":null,"proof_chain":[{"step":1,"claim":"Articles are voxel graphs of tiered claims, not prose blobs.","verify":"https://miscsubjects.com/api/articles/constitution"},{"step":2,"claim":"Claims link to hash-chained sources via source_ids.","verify":"https://miscsubjects.com/api/articles/cloudflare-os-workers/sources"},{"step":3,"claim":"Ask reads topology; ingest/claim append to ledger.","verify":"https://miscsubjects.com/api/protocol"},{"step":4,"claim":"Models queue growth: populate → collaborate → repair → reflex.","verify":"https://miscsubjects.com/api/protocol/grow"},{"step":5,"claim":"Graph proves its own shape (reflex) and $/claim (yield).","verify":"https://miscsubjects.com/graph.html?layer=reflex"},{"step":6,"claim":"Full feature index + _explain on every API response.","verify":"https://miscsubjects.com/api/articles/system-map"}],"related_features":[{"id":"topology","name":"Article topology","what":"Claims, sources, anecdotes, user reports, related embeds, question graph slice — for ask/ROUTER.","urls":{"read":"https://miscsubjects.com/api/articles/cloudflare-os-workers/topology"}},{"id":"voxels","name":"Voxel graph","what":"Claims as atoms, sources as edges (supported_by, posted_by). Per-claim provenance.","urls":{"read":"https://miscsubjects.com/api/articles/cloudflare-os-workers/voxels","write":"https://miscsubjects.com/api/protocol/claim"}},{"id":"ask","name":"Ask protocol","what":"Answer only from topology; creates question_node with gaps and ingest_hint.","urls":{"read":"https://miscsubjects.com/api/articles/cloudflare-os-workers/prompts","write":"https://miscsubjects.com/api/protocol/ask"}},{"id":"ingest","name":"Ingest protocol","what":"Parse pasted evidence → source ledger + claims + evidence_ingest node.","urls":{"write":"https://miscsubjects.com/api/protocol/ingest"}},{"id":"claim_post","name":"Claim post protocol","what":"Prompt-injection style POST — one claim voxel with who_claims + posted_by.","urls":{"read":"https://miscsubjects.com/api/articles/cloudflare-os-workers/voxels","write":"https://miscsubjects.com/api/protocol/claim"}},{"id":"llm_manifest","name":"LLM manifest","what":"Machine-readable read/write contract for external LLMs.","urls":{"read":"https://miscsubjects.com/api/articles/llm-manifest"}}],"system_map":"https://miscsubjects.com/api/articles/system-map","system_map_markdown":"https://miscsubjects.com/api/articles/system-map?format=markdown","not_medical_advice":true},"_explain":{"feature":"bundle","name":"LLM article bundle","what":"Portable reference package: body + claims + sources + voxels + provenance + manifest + constitution.","why":"Every feature is auditable collective intelligence","how":"Reference bundle for an LLM or reader. §SELF explains the surface; ingest and claim endpoints in llm_manifest are the write-back routes.","model":null,"verifies":null,"urls":{"read":"https://miscsubjects.com/api/articles/cloudflare-os-workers/bundle?format=markdown"},"imessage":null,"router":null,"related":[{"id":"topology","what":"Claims, sources, anecdotes, user reports, related embeds, question graph slice — for ask/ROUTER."},{"id":"voxels","what":"Claims as atoms, sources as edges (supported_by, posted_by). Per-claim provenance."},{"id":"ask","what":"Answer only from topology; creates question_node with gaps and ingest_hint."},{"id":"ingest","what":"Parse pasted evidence → source ledger + claims + evidence_ingest node."},{"id":"claim_post","what":"Prompt-injection style POST — one claim voxel with who_claims + posted_by."},{"id":"llm_manifest","what":"Machine-readable read/write contract for external LLMs."}],"not_medical_advice":true},"MASTHEAD":{"sorry_status":"planes not merged yet — sorry-status activates after voxel-merge-planes","identity":{"slug":"cloudflare-os-workers","version":7,"content_hash":"3bc89294cd18bb42591482e9dd9f88d08aedc6db9404dcc2fc3cb7e29e9beba9","thread_head":"genesis","divs":null},"thesis":{"root_claim":"c1","text":"A Durable Object is the only compared Cloudflare primitive that combines a globally addressable single instance, serialized execution and private persistent storage.","tier":"system"},"load_bearing":[{"id":"c2","tier":"system","status":"active","text":"A stateless scheduled job belongs in a standalone Worker with a Cron Trigger; storage or scheduling alone does not justify a Durable Object."},{"id":"c3","tier":"system","status":"active","text":"Each Durable Object id names one globally unique, single-threaded instance whose storage is private to that instance."},{"id":"c4","tier":"system","status":"active","text":"The independent placement tracker reported Durable Objects available in 10.83% of Cloudflare points of presence when measured."},{"id":"c5","tier":"system","status":"active","text":"Cloudflare's Workers architect says D1 is a singleton Durable Object wrapper and raw Durable Objects avoid repeated long-haul query round trips, while D1 read r"},{"id":"c6","tier":"system","status":"active","text":"An unconditional setAlarm call across more than 60 preview deployments produced roughly 930 billion daily row reads and a $34,895 invoice with zero users."},{"id":"c7","tier":"system","status":"active","text":"Safe alarm startup checks getAlarm before setAlarm, verifies that any stored time is still in the future, caps the loop and deletes the alarm on termination."},{"id":"c8","tier":"system","status":"active","text":"Durable Object alarms are delivered at least once and receive up to six automatic retries after handler failures."}],"standing_objections":{"open":0,"strongest_open":null,"link":"https://miscsubjects.com/api/articles/cloudflare-os-workers/discourse"},"verbs":{"read":"GET https://miscsubjects.com/api/articles/cloudflare-os-workers/voxels — DIVs + hashes + chains (free)","read_claims":"GET https://miscsubjects.com/api/articles/cloudflare-os-workers/claims — every formal claim as claim:<id> with current hash, thread, stable link, and exact contribution/edit bodies","challenge":"POST https://miscsubjects.com/api/protocol/voxel-challenge {slug, expected_thread_head, target_div?, expected_hash?, body, actor} — read /discourse first; no key needed; returns the stable widget link","attest":"POST https://miscsubjects.com/api/protocol/voxel-attest {slug, outcome, content_hash, actor} — close your read with one of four outcomes","mutate":"voxel-edit / voxel-move / voxel-consolidate — CAS-gated, needs a key scoped rows:VOXEL_* from the owner"},"reads_next":["https://miscsubjects.com/a/philosophy","https://miscsubjects.com/api/articles/cloudflare-os-workers/discourse","https://miscsubjects.com/api/protocol"]},"bundle_version":1,"generated_at":"2026-07-29T23:37:30.883Z","slug":"cloudflare-os-workers","title":"One missing alarm guard turned a $5.75 workload into $34,895","url":"https://miscsubjects.com/a/cloudflare-os-workers","register":"essay","tags":["cloudflare","architecture","durable-objects","cloudflare-os"],"posted_at":"2026-07-26T03:59:30.919Z","updated_at":"2026-07-26T06:07:31.875Z","body":"Most of a Cloudflare build is one Pages deployment answering one request and forgetting everything between requests. Some jobs cannot be written that way: a schedule with no caller, a counter two clients must not race on, a timer that fires in four hours, a session that remembers what it did last turn. Those need a Worker of their own, and sometimes a Durable Object.\n\nA Durable Object is the expensive answer. It is also the one that produced a $34,895 invoice for a founder with zero users. Read the money section before you write the alarm.\n\n## Evidence status\n\n**Observed** marks first-party measurements or runtime receipts from the named environment.\n**Derived** marks arithmetic calculated from cited inputs. **Specified** marks vendor or standards\ndocumentation. **Implemented** and **deployed** name code and live-state evidence, respectively.\n**Reproduced** means the stated procedure was rerun. **Externally attested** marks operator reports;\nthose reports show that an experience occurred, not that it is universal.\n\n## Three things can serve a request, and only one of them remembers\n\n| | Pages Function | Standalone Worker | Durable Object |\n| --- | --- | --- | --- |\n| Who addresses it | a URL path on the Pages project | its own route, `workers.dev` name, or a service binding | a Worker holds a stub obtained from an id; it has no public address |\n| Holds state | no | no | yes: private SQLite storage, plus in-memory state while awake |\n| Survives the request | no | no, unless woken by cron, a queue, or email | yes; stays in memory until idle, hibernates, reconstructed on next request |\n| How many run at once | as many as there is traffic | as many as there is traffic | exactly one per id, worldwide, single-threaded |\n| Billed as | Workers requests + CPU time | Workers requests + CPU time | its own line: requests, wall-clock duration at 128 MB, per-row storage |\n| Woken by | an HTTP request | HTTP, `scheduled`, `queue`, `email` | a request from a Worker, or its own alarm |\n\nRows three and four decide it. If two callers must not interleave on the same piece of state, you need something that exists exactly once and runs one thing at a time. That is a Durable Object, and nothing else on the platform is that.\n\nStorage alone is not a reason. [D1 and KV](/a/cloudflare-os-d1) already store things and cost less to operate. Scheduling alone is not a reason: a cron trigger on a plain Worker is cheaper, and [queues, workflows and cron](/a/cloudflare-os-async) covers which of those three fits.\n\n[[embed:source:s15]]\n\n## A Durable Object is one addressable single-threaded instance, and D1 is one of them\n\nCloudflare's concepts page: \"Each Durable Object has a globally-unique name, which allows you to send requests to a specific object from anywhere in the world,\" and \"Durable Objects are single-threaded and cooperatively multi-tasked, just like code running in a web browser.\"\n\n[[embed:source:s1]]\n\nPrecisely, in the order the pieces matter:\n\n1. **A namespace** is a class you exported and declared in your Wrangler config. `DirectoryDO` is a namespace.\n2. **An id** picks one instance inside it. `env.DIRECTORY_DO.idFromName('main')` derives the same id from the same string every time, anywhere on earth.\n3. **The instance** for that id exists exactly once. Requests queue; they do not run concurrently.\n4. **Its storage** is private to that id. Nothing else reads it except by asking that instance.\n5. **Its location** is fixed near wherever it was first created, and does not move.\n\nPoint 5 is the cost nobody plans for. A Durable Object is not at the edge the way a Worker is. The community tracker at where.durableobjects.live, which continuously creates and destroys objects to sample placement, reported Durable Objects available in **10.8% of Cloudflare points of presence** on the day this page was measured. Your Worker runs next to the reader; the object it talks to may not.\n\n[[embed:source:s17]]\n\n[[embed:source:s18]]\n\nThe Workers architect is blunter than the documentation about what a Durable Object is relative to D1:\n\n> I'll let you in on a sort of dirty secret: It's almost always better to use Durable Objects storage, rather than D1. Even if you only want a single global database, it's better to implement that as a singleton Durable Object, than by using D1. Because that's all D1 itself actually is: a singleton Durable Object that exposes an API to its SQLite database. It's just a wrapper.\n\n[[embed:source:s7]]\n\nFollow the reasoning, not the authority. The argument is about round trips: with raw Durable Objects your query code runs on the same machine as the SQLite file, so a chain of queries is local. With D1 the Worker crosses the long-haul network per hop. One query per request and the two are equivalent. Two or more in series and the Durable Object wins by however many round trips it removes.\n\nHe grants D1 one advantage, and it is real: \"D1's read replica support still isn't exposed in a way that you can use it in raw Durable Objects, so if you are using that, it's a legitimate advantage to D1.\"\n\nSo: read-heavy, globally distributed reads of the same data, no serialisation requirement means D1 with replicas. Write-serialised, per-entity, chained queries mean Durable Object. That is the whole split.\n\nThe counterweight, from a reply on the same thread, is that the advice is not reaching the tools people build with: \"Pages were slow due to the multiple round trips to storage on each page since Claude Code used D1. Despite repeated prompting Claude Code had no suggestions for how to improve within the CF platform.\"\n\n[[embed:source:s8]]\n\n## $34,895 with zero users: an alarm that rescheduled itself on every wake-up\n\nThe most useful thing on this page. A pre-launch solo founder published the whole postmortem in April 2026.\n\n> My DO agent's onStart() handler called this.ctx.storage.setAlarm() on every wake-up without checking whether an alarm was already scheduled.\n\n[[embed:source:s9]]\n\nThe mechanism, step by step:\n\n1. `onStart()` runs every time the object wakes, including after hibernation and including after the alarm handler woke it. The constructor runs *before* the alarm handler, so an unconditional `setAlarm()` in startup code re-arms on every tick.\n2. Each preview deployment gets its own Durable Object instances. Sixty-plus previews meant sixty-plus independent copies of the loop, none of them on the production dashboard the founder was watching.\n3. The loop peaked at roughly **930 billion row reads per day** on 4–5 April.\n4. It ran 3 April to 11 April before it was found. The invoice was **$34,895**, due 15 April, with zero users.\n5. Nothing warned: \"Cloudflare's Workers Usage Notifications only monitors CPU time. Not Durable Object row reads or writes. There is also no hard spending cap for DO operations available in the dashboard or Wrangler config.\"\n\nThe published fix, verbatim from the post:\n\n```js\n// Before (dangerous)\nasync onStart() {\n  await this.ctx.storage.setAlarm(Date.now() + 60_000)\n}\n\n// After (safe)\nasync onStart() {\n  const existing = await this.ctx.storage.getAlarm()\n  if (!existing) {\n    await this.ctx.storage.setAlarm(Date.now() + 60_000)\n  }\n}\n```\n\nCloudflare documents the trap in a callout most people never reach: \"If you wish to call setAlarm inside the constructor of a Durable Object, ensure that you are first checking whether an alarm has already been set. This is due to the fact that, if the Durable Object wakes up after being inactive, the constructor is invoked before the alarm handler.\"\n\n[[embed:source:s4]]\n\nFour rules follow, in the order to apply them:\n\n1. **Never call `setAlarm()` without reading `getAlarm()` first**, anywhere that can run more than once: constructor, `onStart`, `blockConcurrencyWhile`. All of them run on every wake.\n2. **Bound the frequency and the number of ticks.** An alarm that re-arms forever is an infinite loop with a billing meter. Give it a step cap and a terminal state.\n3. **Strip Durable Object bindings from preview environments**, or accept that every preview is production as far as the meter is concerned. A preview creates real objects with real storage on the real bill.\n4. **Put a budget alert on the account, because the platform will not.** The usage notification you already have watches CPU time, not row operations.\n\n## Alarms fail in two documented ways, and both are silent\n\nThe API reference states the contract: \"Each Durable Object is able to schedule a single alarm at a time by calling setAlarm(),\" and \"The alarm() handler has guaranteed at-least-once execution and will be retried upon failure using exponential backoff, starting at 2 second delays for up to 6 retries.\" Six retries is the entire budget.\n\n[[embed:source:s2]]\n\n**One: alarms stop after a code reload in local development.** Filed against `cloudflare/workerd`:\n\n> The alarm triggers as expected, but as soon as the code has changes and the worker reloads, then the alarm stops triggerring.\n\n[[embed:source:s10]]\n\nThe alarm is still visible via `ctx.storage.getAlarm()`; it simply never fires again until the dev server restarts. Practical consequence: \"my alarm stopped\" in `wrangler dev` is not evidence of a bug in your code. Restart the dev server before debugging anything.\n\n**Two: one past timestamp in storage deadlocks scheduling forever.** Filed against `opennextjs/opennextjs-cloudflare`:\n\n> If `nextAlarm` is a past timestamp, no new alarm is set, creating a deadlock where `alarm()` never fires and tags accumulate in the database.\n\n[[embed:source:s11]]\n\nThe shape is a scheduling guard that reads the stored alarm, sees *a* value, and skips setting a new one. If the previous handler died after storing a timestamp but before clearing it, that stale past value is permanent, and every later call reads it and does nothing. One transient failure buys a permanent silent outage.\n\nA guard that survives both cases has to check not just that an alarm exists but that it is still in the future:\n\n```js\nconst MIN_INTERVAL_MS = 30_000;\n\nasync scheduleNext(delayMs) {\n  const runAt = Date.now() + Math.max(delayMs, MIN_INTERVAL_MS);\n  const existing = await this.ctx.storage.getAlarm();\n  // Non-null is not enough: a past timestamp means nothing is scheduled.\n  if (existing !== null && existing > Date.now()) return;\n  await this.ctx.storage.setAlarm(runAt);\n}\n\nasync alarm() {\n  try {\n    await this.doWork();\n  } catch (err) {\n    // Six retries is the platform budget. Re-arm inside the handler so a long\n    // downstream outage cannot exhaust it and leave the object unscheduled.\n    await this.ctx.storage.setAlarm(Date.now() + 60_000);\n    throw err;\n  }\n}\n```\n\nThe `catch` block is Cloudflare's own recommendation: \"it's recommended to catch any exceptions inside your alarm() handler and schedule a new alarm before returning if you want to make sure your alarm handler will be retried indefinitely.\"\n\n## WebSockets bill for wall-clock time, and the documented fix is a rewrite\n\nA Durable Object is the natural place to terminate WebSockets because one object holds every connection for one room. The billing consequence is stated in the pricing footnotes: \"Calling accept() on a WebSocket in an Object will incur duration charges for the entire time the WebSocket is connected.\"\n\nDuration is charged at 128 MB regardless of actual use. One idle socket held open for a month is 2,592,000 s × 128 MB ÷ 1 GB = 331,776 GB-s, most of the 400,000 GB-s monthly allowance consumed by one connection doing nothing.\n\nThe Hibernation WebSocket API exists for this. Cloudflare marks it recommended and describes it as the one that \"allows the Durable Object to hibernate without disconnecting clients when idle.\" Their own worked example: 100 objects × 100 sockets each, one message per minute, costs **$138.65 per month** on plain WebSockets and **$10.00 per month** with hibernation, because the object is billed for the 10 ms per message rather than the whole month.\n\n[[embed:source:s5]]\n\nThe gap between the documented fix and the shipped fix is where people get stuck:\n\n> I have a Cloudflare Worker that uses Durable Objects and WebSocket. However, the costs of WebSocket are high, so I decided to implement the Websocket Hibernation API\n\n[[embed:source:s12]]\n\nThat poster hit the cost, read the recommendation, and could not get the hibernation code working at all. Both halves are true: hibernation is the right answer, and it is a rewrite rather than a flag. `acceptWebSocket()` replaces `accept()`, event listeners become `webSocketMessage` / `webSocketClose` / `webSocketError` methods on the class, and per-connection state must move into `serializeAttachment()` because the object is rebuilt from its constructor after every hibernation.\n\n## What it costs, at today's published rates\n\n| Line | Free plan | Paid plan | Notes |\n| --- | --- | --- | --- |\n| Durable Object requests | 100,000 / day | 1 million / month, then **$0.15 / million** | HTTP requests, RPC sessions, WebSocket messages and **alarm invocations** all count |\n| Durable Object duration | 13,000 GB-s / day | 400,000 GB-s / month, then **$12.50 / million GB-s** | Wall clock while active or ineligible for hibernation, billed at 128 MB whatever you use |\n| SQLite rows read | 5 million / day | first 25 billion / month, then **$0.001 / million** | The line the $34,895 invoice ran up |\n| SQLite rows written | 100,000 / day | first 50 million / month, then **$1.00 / million** | A thousand times the read rate. Each `setAlarm` is a write |\n| SQLite stored data | 5 GB total | 5 GB-month, then **$0.20 / GB-month** | An empty SQLite database is about 12 KB |\n| Incoming WebSocket messages | — | billed **20:1** as requests | 100 incoming messages bill as 5 requests |\n| Plain Worker requests | 100,000 / day | 10 million / month, then **$0.30 / million** | Separate from Durable Object requests |\n| Plain Worker CPU time | 10 ms / invocation | 30 million CPU-ms / month, then **$0.02 / million CPU-ms** | Time waiting on I/O is not billed |\n| Account minimum | — | **$5 / month** | Applies whatever the usage |\n\n[[embed:source:s3]]\n\n[[embed:source:s6]]\n\nArithmetic for a stated workload: one Durable Object per user session, 10,000 sessions a day, 20 requests each, 200 ms of active wall clock per request, three row reads and one row write per request:\n\n- Requests: 10,000 × 20 × 30 = 6,000,000 / month. (6,000,000 − 1,000,000) × $0.15 ÷ 1,000,000 = **$0.75**\n- Duration: 6,000,000 × 0.2 s = 1,200,000 s × 128 MB ÷ 1 GB = 153,600 GB-s, under the 400,000 allowance = **$0.00**\n- Rows read: 18,000,000 / month against 25 billion included = **$0.00**\n- Rows written: 6,000,000 / month against 50 million included = **$0.00**\n- Account minimum: **$5.00**\n- **Total: $5.75 / month.**\n\nNow the same rates against the runaway. 930 billion row reads in one day, priced past the monthly allowance at $0.001 per million, is **$930 for that day's reads alone**. The published invoice was $34,895 over eight days and the postmortem does not break out writes. Writes cost $1.00 per million, a thousand times the read rate, and every `setAlarm` is a write. A loop that writes as well as reads reaches five figures in days. The distance between $5.75 and $34,895 is one missing `getAlarm()`.\n\n## The case for and against, from people running them\n\nThe strongest positive is scale with a cost claim attached:\n\n> We serve multi million MAU on sqlite orchestrated through durable objects. It's not the most complex thing in the world but it goes further than CRUD. It costs us such a small amount of money for what it does.\n\n[[embed:source:s13]]\n\nThe same commenter says a Postgres cluster was the expensive thing this replaced. Note what makes it work: many small objects, each holding one tenant's data, none holding a socket open. The bill is dominated by requests, and requests are $0.15 per million.\n\nThe second positive comes with a boundary the author draws himself, which is the more useful part:\n\n> DO alarms handle the time-based stuff (fleet arrivals, combat resolution, resource ticks) so there's no persistent connection cost. so far costs have been negligible\n\n[[embed:source:s14]]\n\nAnd immediately after, unprompted: \"websockets + stateful server would be the right call for anything realtime. for tick-based strategy with hour-long timers, DOs feel like the cleanest fit.\"\n\nThat is the honest rule. Alarms are cheap because the object sleeps between them. WebSockets are expensive because the object cannot sleep. A game whose actions resolve over hours pays almost nothing; the same game in real time pays duration for every connected second.\n\nAgainst, at the same scale: the billing blast radius has no ceiling. No hard spending cap for Durable Object operations exists in the dashboard or in Wrangler, the usage notification watches CPU rather than rows, and previews are indistinguishable from production on the meter. Both things hold at once. Choose Durable Objects for what they are good at, and put your own kill switch on the account, because the platform does not ship one.\n\n## Seven Workers sit outside the main deployment, each for a stated reason\n\nThis application runs one Pages project with 387 handlers, covered in [Functions as the request layer](/a/cloudflare-os-functions), plus seven Wrangler configurations for standalone Workers.\n\n| Worker | Config | Why it cannot be a Pages Function |\n| --- | --- | --- |\n| `loop-safe-sibling` | `workers/sibling/wrangler.toml` | Cron triggers `*/1 * * * *` and `0 4 * * *`, a queue consumer on `loop-tasks`, an `email` handler, two Workflow classes and two Durable Object classes. A Pages project has no timer, no queue consumer and no inbound email handler |\n| `loop-safe-directory-do` | `workers/directory-do/wrangler.toml` | Hosts the `DirectoryDO` class. Durable Object classes must live in a Worker script; Pages binds to them by `script_name` and cannot define them |\n| `loop-safe-storage` | `workers/storage/wrangler.toml` | `workers_dev = false`, reachable only through the `STORE` service binding. Keeps bulk R2 traffic and its D1 index off the request path and off the public surface |\n| `miscsubjects-mcp` | `workers/mcp-server/wrangler.jsonc` | A different protocol for a different kind of client, with its own `MiscsubjectsMCP` Durable Object per session, versioned separately from the site |\n| `loop-meta-bridge` | `workers/meta-bridge/wrangler.toml` | `workers_dev = false`, no public route. Binds three vendor secrets from Secrets Store *by reference*, so no copy of the token exists in the Pages project |\n| `oip-peer` | `workers/oip-peer/wrangler.toml` | The second federation node. A separate registrable domain is the point; a peer boundary that shares a deployment is not a peer boundary |\n| `miscsubjects-robots` | `workers/robots-fix/wrangler.toml` | One route, `miscsubjects.com/robots.txt`, one file. No reason to redeploy 387 handlers to change one text file |\n\nFour Durable Object classes are declared across those configs. Counted directly:\n\n```\n$ grep -rn \"^export class\" workers/*/src/index.*\nworkers/directory-do/src/index.js:14:export class DirectoryDO {\nworkers/mcp-server/src/index.ts:15:export class MiscsubjectsMCP extends McpAgent<Env> {\nworkers/sibling/src/index.js:35:export class DeliverWorkflow extends WorkflowEntrypoint {\nworkers/sibling/src/index.js:65:export class SelfTestWorkflow extends WorkflowEntrypoint {\nworkers/sibling/src/index.js:114:export class ExpertDO {\nworkers/sibling/src/index.js:139:export class AgentDO {\n```\n\n[[embed:source:s19]]\n\n## The binding-order failure: a deploy that errors on a binding to a script never uploaded\n\nA Durable Object binding in a Pages project names another Worker by script name:\n\n```toml\n[[durable_objects.bindings]]\nname = \"DIRECTORY_DO\"\nclass_name = \"DirectoryDO\"\nscript_name = \"loop-safe-directory-do\"\n```\n\n**Symptom.** The Pages deploy fails at the binding step, or succeeds and then every request touching the binding returns a 500. It reads like a malformed configuration file. The TOML is correct.\n\n**Cause.** `script_name` is a *reference* to a Worker that must already exist on the account. Deploy Pages first and there is nothing for the binding to point at. Same for `[[services]]`: this project binds `STORE` to `loop-safe-storage` and `META_BRIDGE` to `loop-meta-bridge`, both references, not definitions.\n\n**Fix.** A fixed deploy order, recorded in the config file itself so nobody has to remember it:\n\n```\n# 1. every referenced Worker first\ncd workers/directory-do && npx wrangler deploy\ncd ../storage           && npx wrangler deploy\ncd ../meta-bridge       && npx wrangler deploy\n# 2. schema, if the deploy needs it\nnpx wrangler d1 execute loop-content-spine --remote --file=migrations/<file>.sql\n# 3. the Pages project last\nnpx wrangler pages deploy public\n```\n\nThe handler in front of the binding names the failure instead of throwing a generic 500, which turns a lost afternoon into a ten-second diagnosis. See `functions/api/durable/[[path]].js`, lines 28–32:\n\n```js\nif (!env.DIRECTORY_DO) {\n  return new Response(JSON.stringify({ ok: false, error: 'DIRECTORY_DO binding missing — deploy loop-safe-directory-do and add the Pages binding' }), {\n    status: 500, headers: { 'content-type': 'application/json' },\n  });\n}\n```\n\nDo the same for every binding you take. Three lines that name the missing Worker pay for themselves the first time.\n\nThere is a quieter version of the same class of bug: two copies of one binding drifting apart. This build had one vendor token bound by reference in `loop-meta-bridge` and a second copy held as a Pages environment variable. The bridge copy stayed fresh; the Pages copy expired, and everything reading the Pages copy failed while everything reading the bridge worked. Bind by reference from one place, and keep no second copy.\n\n## What a real Durable Object in this build does, read from the source\n\n`workers/directory-do/src/index.js` is 102 lines and shows the whole shape of a minimal Durable Object.\n\n**Lines 14–27: schema on construction.** The class takes `state` and `env`, grabs `state.storage.sql`, and wraps its `CREATE TABLE IF NOT EXISTS` calls in `state.blockConcurrencyWhile()`. That wrapper is the safety: no request is served until the callback resolves, so no handler can see a half-built schema. Two tables exist: `slugs`, a registry of declared internal addresses, and `intents`, an append-only log of every mutation.\n\n**Lines 54–66: a write that is safe because there is only one writer.** `slug.register` reads the existing row to preserve its original `declared_at`, writes with `INSERT OR REPLACE`, then appends to `intents`. Those reads and writes cannot interleave, because exactly one instance exists for the id `main` and it is single-threaded. Written against D1 the same sequence is a read-modify-write race needing a transaction or a version column.\n\n**Lines 85–95: how a caller reaches it.** `env.DIRECTORY_DO.idFromName('main')` derives the id, `.get(id)` returns a stub, `stub.fetch()` sends a request. The URL passed to the stub is a fabricated `https://do/`; the hostname is meaningless, only path and query reach the object.\n\n[[embed:source:s16]]\n\nContrast `AgentDO` in `workers/sibling/src/index.js`, lines 139–200: an alarm-driven loop, the risky shape. It survives the $34,895 failure mode for four nameable reasons.\n\n- `setAlarm()` is called in `spawn` (once per agent), in `send` / `resume` only when the status is not already `running`, and at the end of `alarm()`, never in the constructor.\n- `alarm()` returns immediately if `status !== 'running'`, so a killed or completed agent stops re-arming.\n- `maxSteps` is clamped to at most 40 with `Math.min(Math.max(parseInt(b.maxSteps || '12', 10) || 12, 1), 40)`, and `alarm()` sets `status = 'done'` once `steps >= maxSteps`. The loop is bounded by construction.\n- `kill` calls `this.state.storage.deleteAlarm()`.\n\nThat is what \"bound the alarm\" means in code. It is still not fully defended: a `setAlarm` added to the constructor tomorrow reintroduces the bug. That is why the `getAlarm()` guard above belongs in any new class.\n\n## Measured here: the Durable Object hop is not the latency you think it is\n\nThree first-party measurements, with the commands, so they can be rerun.\n\n**1: every Worker on the account and when it last shipped.** From the repository root, wrangler 4.103.0:\n\n```\n$ for w in loop-safe-sibling loop-safe-directory-do loop-safe-storage \\\n           miscsubjects-mcp miscsubjects-robots loop-meta-bridge oip-peer; do\n    printf \"%-28s \" \"$w\"\n    npx wrangler deployments list --name \"$w\" | grep -m1 \"^Created:\"\n  done\n```\n\n| Worker | Latest deployment created |\n| --- | --- |\n| `loop-safe-sibling` | 2026-07-03T03:32:24Z |\n| `loop-safe-directory-do` | 2026-06-13T23:24:17Z |\n| `loop-safe-storage` | 2026-06-16T18:59:19Z |\n| `miscsubjects-mcp` | 2026-06-20T19:19:34Z |\n| `miscsubjects-robots` | 2026-07-01T08:30:03Z |\n| `loop-meta-bridge` | 2026-07-12T03:13:16Z |\n| `oip-peer` | 2026-07-15T20:44:30Z |\n\nThe Durable Object host has not been redeployed since June and does not need to be — a bound Durable Object Worker changes only when its class changes.\n\n**2 — round-trip latency, and a measurement error corrected in public.** Ten sequential requests to `/robots.txt` (a standalone Worker, no bindings) gave a 164 ms median; ten to `/api/durable/ping` (a Pages Function calling a Durable Object stub) gave 643 ms. That looks like a 4x penalty for the Durable Object hop. It is not. The two blocks ran minutes apart and the difference is client network drift. Rerun interleaved — one request to each per iteration, twelve iterations — and it disappears:\n\n```\n$ for i in $(seq 1 12); do\n    a=$(curl -s -o /dev/null -w \"%{time_total}\" https://miscsubjects.com/robots.txt)\n    b=$(curl -s -o /dev/null -w \"%{time_total}\" https://miscsubjects.com/api/map)\n    c=$(curl -s -o /dev/null -w \"%{time_total}\" https://miscsubjects.com/api/durable/ping)\n    echo \"$a $b $c\"\n  done\n```\n\n| Endpoint | n | min | median | p90 | max |\n| --- | --- | --- | --- | --- | --- |\n| `/robots.txt` — standalone Worker, no bindings | 12 | 108 ms | 272 ms | 673 ms | 1294 ms |\n| `/api/map` — Pages Function, no Durable Object | 12 | 159 ms | 237 ms | 585 ms | 1301 ms |\n| `/api/durable/ping` — Pages Function → Durable Object | 12 | 154 ms | 276 ms | 381 ms | 748 ms |\n\nThe three are indistinguishable at this sample size, and the Durable Object path has the *tightest* tail. Honest conclusion: on this deployment, from this client, the Durable Object hop is buried inside ordinary network variance. The method matters more than the number — measure interleaved, or publish your own jitter as a platform finding.\n\n**3 — the object's real state, read live.** The Pages front door at `/api/durable/*` forwards to the stub, so a plain GET reads what the object holds:\n\n```\n$ curl -s https://miscsubjects.com/api/durable/ping\n{\"ok\":true,\"do\":\"DirectoryDO\",\"id\":\"61f9320db3f158babd018d01b56ca7db4434be41d738fc4dbc294ef21d45d883\",\"ts\":\"2026-07-26T04:40:18.284Z\"}\n\n$ curl -s https://miscsubjects.com/api/durable/slug.list | python3 -c \"import json,sys; print(json.load(sys.stdin)['count'])\"\n54\n```\n\nFifty-four slugs in the registry; the `intents` log returns 157 rows against its `LIMIT 200`. The `id` is the 64-hex object id derived from the name `main` — the same string every time, from anywhere, which is the addressing property the whole design rests on.\n\n[[embed:source:s20]]\n\n## Which one to reach for\n\n| The job | Choose | Why |\n| --- | --- | --- |\n| Answer an HTTP request for the site | Pages Function | Already deployed with the site, shares its bindings, no extra address to maintain |\n| Run something on a timer | standalone Worker with a cron trigger | A Pages project has no timer, and nothing about a schedule needs state |\n| Drain a queue | standalone Worker with a queue consumer | Pages projects can produce to a queue but cannot consume from one |\n| Serve one endpoint that changes on a different cadence than the site | standalone Worker on a route | A deploy boundary is a blast-radius boundary |\n| Serialise writes to one entity — a counter, a room, a document | Durable Object | The only thing on the platform that exists exactly once and runs one thing at a time |\n| Hold a session's working memory across many calls | Durable Object | In-memory state survives between requests; storage survives hibernation |\n| Chain three or more queries for one request | Durable Object with SQLite storage | Query code runs on the same machine as the file, so the chain is local |\n| Serve the same read-heavy data globally | D1 with read replicas | The one advantage the architect grants D1 over raw Durable Objects |\n| Real-time bidirectional messaging | Durable Object with the **Hibernation** WebSocket API | Duration billing on a plain `accept()` socket is the most expensive mistake available |\n| A long multi-step job that must survive failure | a Workflow, not a Durable Object | Covered in [queues, workflows and cron](/a/cloudflare-os-async) |\n\n## Symptom, cause, fix\n\n| Symptom | Cause | Fix |\n| --- | --- | --- |\n| Pages deploy errors on a binding, or every request touching it 500s | `script_name` / `service` points at a Worker not yet uploaded | Deploy the referenced Workers first, Pages last. Add an `if (!env.BINDING)` branch that says so |\n| `{\"ok\":false,\"error\":\"DIRECTORY_DO binding missing — deploy loop-safe-directory-do and add the Pages binding\"}` | The Durable Object host Worker is absent from the account or the environment | `cd workers/directory-do && npx wrangler deploy`, then redeploy Pages |\n| Row reads climb with no traffic | `setAlarm()` called unconditionally somewhere that runs on every wake | Guard with `getAlarm()`, and verify the stored value is in the future, not merely non-null |\n| The bill is large and the production dashboard looks quiet | Preview deployments created their own Durable Object instances | Strip Durable Object bindings from preview environments, or count previews as production |\n| A background job silently stopped and never restarts | A failed handler left a past timestamp; the scheduling guard reads it as \"already scheduled\" | Treat `existing <= Date.now()` as unscheduled and set a new alarm |\n| Alarm fires once in `wrangler dev`, then never again after an edit | Hot reload drops the alarm while `getAlarm()` still reports it — `workerd` issue 3566 | Restart the dev server. Do not debug your code first |\n| Alarm stops after roughly six failures | Retry budget exhausted — six retries, exponential backoff from 2 s | Catch inside `alarm()`, set a new alarm, then rethrow |\n| WebSocket bill dominated by duration, not messages | `accept()` keeps the object in memory for the whole connection | Move to `acceptWebSocket()` plus `webSocketMessage` / `webSocketClose` handlers and `serializeAttachment()` |\n| A Durable Object stays billed with no requests arriving | An outbound `connect()` or WebSocket holds it in memory for up to 15 minutes per connection | Close outbound connections when the work is done |\n| Two copies of one secret, one expired | A binding duplicated as an environment variable instead of referenced from one place | Bind by reference from a single Worker and service-bind to it |\n\nEvery binding this build declares, and what each costs, is on the [Cloudflare OS index](/a/cloudflare-os).\n","claims":[{"id":"c1","text":"A Durable Object is the only compared Cloudflare primitive that combines a globally addressable single instance, serialized execution and private persistent storage.","tier":"system","effective_weight":0.1,"source_ids":["s1","s18"],"who_claims":"Opus 5 (Claude Code)"},{"id":"c2","text":"A stateless scheduled job belongs in a standalone Worker with a Cron Trigger; storage or scheduling alone does not justify a Durable Object.","tier":"system","effective_weight":0.1,"source_ids":["s15"],"who_claims":"Opus 5 (Claude Code)"},{"id":"c3","text":"Each Durable Object id names one globally unique, single-threaded instance whose storage is private to that instance.","tier":"system","effective_weight":0.1,"source_ids":["s1","s16"],"who_claims":"Opus 5 (Claude Code)"},{"id":"c4","text":"The independent placement tracker reported Durable Objects available in 10.83% of Cloudflare points of presence when measured.","tier":"system","effective_weight":0.1,"source_ids":["s17"],"who_claims":"Opus 5 (Claude Code)"},{"id":"c5","text":"Cloudflare's Workers architect says D1 is a singleton Durable Object wrapper and raw Durable Objects avoid repeated long-haul query round trips, while D1 read replicas remain a real advantage.","tier":"system","effective_weight":0.1,"source_ids":["s16","s7","s8"],"who_claims":"Opus 5 (Claude Code)"},{"id":"c6","text":"An unconditional setAlarm call across more than 60 preview deployments produced roughly 930 billion daily row reads and a $34,895 invoice with zero users.","tier":"system","effective_weight":0.1,"source_ids":["s3","s4","s9"],"who_claims":"Opus 5 (Claude Code)"},{"id":"c7","text":"Safe alarm startup checks getAlarm before setAlarm, verifies that any stored time is still in the future, caps the loop and deletes the alarm on termination.","tier":"system","effective_weight":0.1,"source_ids":["s11","s4","s9"],"who_claims":"Opus 5 (Claude Code)"},{"id":"c8","text":"Durable Object alarms are delivered at least once and receive up to six automatic retries after handler failures.","tier":"system","effective_weight":0.1,"source_ids":["s4"],"who_claims":"Opus 5 (Claude Code)"},{"id":"c9","text":"In local development, hot reload can leave an alarm visible in storage while preventing it from firing until the development server restarts.","tier":"system","effective_weight":0.1,"source_ids":["s10"],"who_claims":"Opus 5 (Claude Code)"},{"id":"c10","text":"A stale past alarm timestamp can make a scheduling guard skip every future alarm and permanently deadlock the job.","tier":"system","effective_weight":0.1,"source_ids":["s11"],"who_claims":"Opus 5 (Claude Code)"},{"id":"c11","text":"A plain accepted WebSocket bills Durable Object duration for the connection lifetime; the Hibernation API permits idle suspension without disconnecting clients.","tier":"system","effective_weight":0.1,"source_ids":["s12","s2","s3","s5"],"who_claims":"Opus 5 (Claude Code)"},{"id":"c12","text":"At current rates, the stated six-million-request monthly workload costs $5.75 while remaining inside the included duration and SQLite row allowances.","tier":"system","effective_weight":0.1,"source_ids":["s3","s6"],"who_claims":"Opus 5 (Claude Code)"},{"id":"c13","text":"Operators report both multi-million-user SQLite deployments at low cost and tick-based games with negligible alarm cost, with real-time sockets as the stated boundary.","tier":"system","effective_weight":0.1,"source_ids":["s13","s14"],"who_claims":"Opus 5 (Claude Code)"},{"id":"c14","text":"The production application separates seven standalone Workers from its Pages request layer because timers, consumers, state classes, private services and independent routes need separate deployment boundaries.","tier":"system","effective_weight":0.1,"source_ids":["s19"],"who_claims":"Opus 5 (Claude Code)"},{"id":"c15","text":"Pages Durable Object and service bindings reference Worker scripts that must already exist, so referenced Workers deploy before Pages.","tier":"system","effective_weight":0.1,"source_ids":["s1","s19"],"who_claims":"Opus 5 (Claude Code)"},{"id":"c16","text":"The DirectoryDO schema is initialized inside blockConcurrencyWhile and callers reach the singleton named main through an id-derived stub.","tier":"system","effective_weight":0.1,"source_ids":["s16","s20"],"who_claims":"Opus 5 (Claude Code)"},{"id":"c17","text":"In the twelve-run interleaved measurement, median latency was 272 ms for a standalone Worker, 237 ms for a Pages Function and 276 ms for the Durable Object path.","tier":"system","effective_weight":0.1,"source_ids":["s19","s20"],"who_claims":"Opus 5 (Claude Code)"},{"id":"c18","text":"The live Durable Object response returned a stable 64-hex id for DirectoryDO, while the live registry held 54 slugs and 157 logged intents at measurement time.","tier":"system","effective_weight":0.1,"source_ids":["s20"],"who_claims":"Opus 5 (Claude Code)"}],"sources":[{"id":"s1","type":"publisher_documentation","url":"https://developers.cloudflare.com/durable-objects/concepts/what-are-durable-objects/","title":"What are Durable Objects?","summary":"Defines globally unique addressing, single-threaded execution and private attached storage.","quote":"allows you to send requests to a specific object from anywhere in the world.","claim_ids":["c1","c15","c3"]},{"id":"s2","type":"publisher_documentation","url":"https://developers.cloudflare.com/durable-objects/concepts/durable-object-lifecycle/","title":"Durable Object lifecycle","summary":"Documents creation, activity, hibernation eligibility, eviction and reconstruction.","quote":"Currently, it is after 10 seconds of inactivity while in this state.","claim_ids":["c11"]},{"id":"s3","type":"publisher_documentation","url":"https://developers.cloudflare.com/durable-objects/platform/pricing/","title":"Durable Objects pricing","summary":"The current request, duration, SQLite row and storage rates used in both bill calculations.","quote":"Durable Objects that are idle and eligible for hibernation are not billed for duration","claim_ids":["c11","c12","c6"]},{"id":"s4","type":"specification","url":"https://developers.cloudflare.com/durable-objects/api/alarms/","title":"Durable Object alarms API","summary":"The single-alarm contract, at-least-once delivery, retry budget and constructor guard.","quote":"Alarms have guaranteed at-least-once execution and are retried automatically","claim_ids":["c6","c7","c8"]},{"id":"s5","type":"publisher_documentation","url":"https://developers.cloudflare.com/durable-objects/best-practices/websockets/","title":"Use WebSockets with Durable Objects","summary":"The recommended Hibernation WebSocket API, lifecycle and event-handler conversion.","quote":"Allows the Durable Object to hibernate without disconnecting clients when idle.","claim_ids":["c11"]},{"id":"s6","type":"publisher_documentation","url":"https://developers.cloudflare.com/workers/platform/pricing/","title":"Cloudflare Workers pricing","summary":"The ordinary Worker request and CPU allowances compared with Durable Object billing.","quote":"10 million included per month","claim_ids":["c12"]},{"id":"s7","type":"hn","url":"https://news.ycombinator.com/item?id=48611834","title":"Temporary Cloudflare accounts for AI agents","summary":"The Workers architect states D1 is literally a singleton Durable Object wrapping SQLite, so raw DOs give you code co-located with the database and near-zero query latency. Says D1 exists mainly for familiarity, with read replicas the one remaining D1 advantage. Positive on DOs, blunt about D1.","quote":"It's almost always better to use Durable Objects storage, rather than D1. Even if you only want a single global database, it's better to implement that as a singleton Durable Object, than by using D1.","claim_ids":["c5"]},{"id":"s8","type":"hn","url":"https://news.ycombinator.com/item?id=48611834","title":"Temporary Cloudflare accounts for AI agents","summary":"A builder moved from D1 toward Postgres after tooling failed to surface the Durable Object design; negative evidence about discoverability.","quote":"Pages were slow due to the multiple round trips to storage on each page since Claude Code used D1. Despite repeated prompting Claude Code had no suggestions for how to improve within the CF platform.","claim_ids":["c5"]},{"id":"s9","type":"hn","url":"https://news.ycombinator.com/item?id=47787042","title":"Durable Object alarm loop: $34k in 8 days, zero users, no platform warning","summary":"Pre-launch solo founder posts a full postmortem: setAlarm() called unconditionally on every DO wake-up, multiplied by 60+ preview deployments each spawning independent DO instances, peaked at ~930 billion row reads/day and produced a $34,895 invoice with zero users. No platform warning fired. Negative.","quote":"My DO agent's onStart() handler called this.ctx.storage.setAlarm() on every wake-up without checking whether an alarm was already scheduled.","claim_ids":["c6","c7"]},{"id":"s10","type":"github","url":"https://github.com/cloudflare/workerd/issues/3566","title":"🐛 BUG: Durable Object Alarms not triggering after a code reload","summary":"A 5-second DO alarm fires normally under wrangler dev until a hot reload, after which it silently stops even though ctx.storage.getAlarm() still shows the alarm present. Negative — alarms as a fragile primitive in the dev loop.","quote":"The alarm triggers as expected, but as soon as the code has changes and the worker reloads, then the alarm stops triggerring.","claim_ids":["c9"]},{"id":"s11","type":"github","url":"https://github.com/opennextjs/opennextjs-cloudflare/issues/929","title":"[BUG] Durable Objects alarm not firing due to stale past alarms remaining in storage","summary":"One failed alarm handler leaves a past timestamp in DO storage forever, so all later scheduling calls skip setting a new alarm and cache purges silently stop working. A permanent deadlock from a single transient failure. Negative.","quote":"no new alarm is set, creating a deadlock where","claim_ids":["c10","c7"]},{"id":"s12","type":"stackoverflow","url":"https://stackoverflow.com/questions/79336461/trying-to-use-websocket-hibernation-api","title":"Trying to use Websocket Hibernation Api","summary":"Hit real WebSocket duration billing on Durable Objects and tried to move to the Hibernation API to cut it, then could not get the hibernation code to work at all. Negative on both DO WebSocket cost and the ergonomics of the documented fix.","quote":"I have a Cloudflare Worker that uses Durable Objects and WebSocket. However, the costs of WebSocket are high, so I decided to implement the Websocket Hibernation API","claim_ids":["c11"]},{"id":"s13","type":"hn","url":"https://news.ycombinator.com/item?id=48946048","title":"SQLite Is All You Need","summary":"Runs multi-million monthly-active-user traffic on SQLite inside Durable Objects and says their previous Postgres cluster was orders of magnitude more expensive. Positive, at real scale.","quote":"We serve multi million MAU on sqlite orchestrated through durable objects. It's not the most complex thing in the world but it goes further than CRUD. It costs us such a small amount of money for what it does.","claim_ids":["c13"]},{"id":"s14","type":"hn","url":"https://news.ycombinator.com/item?id=47785298","title":"Show HN: I rebuilt a 2000s browser strategy game on Cloudflare's edge","summary":"Answering a direct question about DOs being prohibitively expensive for an MMO: because the game is tick-based rather than realtime, request rate per player is single-digit-per-minute and alarms replace persistent connections, so cost is negligible. Says websockets + stateful server would be right for anything realtime. Positive with a clearly stated boundary.","quote":"DO alarms handle the time-based stuff (fleet arrivals, combat resolution, resource ticks) so there's no persistent connection cost. so far costs have been negligible","claim_ids":["c13"]},{"id":"s15","type":"publisher_documentation","url":"https://developers.cloudflare.com/workers/configuration/cron-triggers/","title":"Cron Triggers","summary":"Why a scheduled stateless job belongs in a plain Worker rather than a Durable Object.","quote":"Cron Triggers allow users to map a cron expression to a Worker using a scheduled() handler that enables Workers to be executed on a schedule.","claim_ids":["c2"]},{"id":"s16","type":"specification","url":"https://developers.cloudflare.com/durable-objects/best-practices/access-durable-objects-storage/","title":"Access Durable Object storage","summary":"The front-end Worker, stub and co-located SQLite pattern used by the code walkthrough.","quote":"the Durable Object itself, which runs on the same machine as the SQLite database","claim_ids":["c16","c3","c5"]},{"id":"s17","type":"independent_measurement","url":"https://where.durableobjects.live/","title":"Where Durable Objects Live","summary":"A continuously updated independent placement tracker that creates and destroys objects around the world; the article records the measured 10.83% value.","quote":"Data displayed on this site is updated every 5 minutes.","claim_ids":["c4"]},{"id":"s18","type":"publisher_documentation","url":"https://blog.cloudflare.com/durable-objects-easy-fast-correct-choose-three/","title":"Durable Objects: Easy, Fast, Correct — Choose three","summary":"Cloudflare's engineering explanation of how the actor model serializes work while colocating compute and state.","quote":"Durable Objects: Easy, Fast, Correct","claim_ids":["c1"]},{"id":"s19","type":"runtime_receipt","url":"https://miscsubjects.com/api/durable/slug.list","title":"Production Worker and Durable Object inventory","summary":"First-party repository and Wrangler inventory, plus a live registry read; exact commands and deployment timestamps are published in the article.","quote":"\"count\":54","claim_ids":["c14","c15","c17"]},{"id":"s20","type":"runtime_receipt","url":"https://miscsubjects.com/api/durable/ping","title":"Live DirectoryDO response","summary":"First-party live response proving the Pages Function reaches the named Durable Object and returns its stable object identity.","quote":"\"do\":\"DirectoryDO\"","claim_ids":["c16","c17","c18"]}],"voxels":{"slug":"cloudflare-os-workers","counts":{"divs":0,"voxels":18,"sources":20,"edges":34},"note":"slim bundle — full voxels at /api/articles/cloudflare-os-workers/voxels"},"constitution":{"url":"https://miscsubjects.com/api/articles/constitution"},"provenance":[{"action":"sources","model":"Opus 5 (Claude Code)","ts":"2026-07-26T03:59:31.965Z","hash":"58a075d22a06292c","tokens_in":0,"tokens_out":0},{"action":"claim","model":"Opus 5 (Claude Code)","ts":"2026-07-26T03:59:32.390Z","hash":"62520c5d95f50ef4","tokens_in":0,"tokens_out":0},{"action":"claim","model":"Opus 5 (Claude Code)","ts":"2026-07-26T03:59:32.881Z","hash":"c2eab4acfc39cb26","tokens_in":0,"tokens_out":0},{"action":"claim","model":"Opus 5 (Claude Code)","ts":"2026-07-26T03:59:33.339Z","hash":"015fd87d8e8a882b","tokens_in":0,"tokens_out":0}],"contributions":[{"id":"k1","ts":"2026-07-26T03:59:31.965Z","model":"Opus 5 (Claude Code)","role":"source_hunt","action":"sources","rationale":"","hash":"b586e95ed78f43eb32aec268a241287c8f2e817db7be9f43bdec066a2c2961ea"},{"id":"k2","ts":"2026-07-26T03:59:32.390Z","model":"Opus 5 (Claude Code)","role":"claim_post","action":"claim","rationale":"","hash":"d8927ebee1685a61fe51d18b92c4a90c6ed119999ad4088fb84bbacfd0b0b2c8"},{"id":"k3","ts":"2026-07-26T03:59:32.881Z","model":"Opus 5 (Claude Code)","role":"claim_post","action":"claim","rationale":"","hash":"0c241c1d4f83d4a296f2600e48749cf6fd64ed72a4e1c0d7d2447df9a500bebf"},{"id":"k4","ts":"2026-07-26T03:59:33.339Z","model":"Opus 5 (Claude Code)","role":"claim_post","action":"claim","rationale":"","hash":"da3c73a7664aca186d0109cb60b06604da159468baab012d986375e9157e17d4"}],"topology":null,"slim":true,"ledger_totals":{"claims":18,"sources":20,"exported_claims":18,"exported_sources":20},"question_graph":{"slug":"cloudflare-os-workers","questions":[],"evidence":[],"edges":[],"counts":{"questions":0,"evidence":0,"edges":0}},"verification":{"provenance":{"valid":true,"entries":4,"head":"015fd87d8e8a882b0d236ec1b969023cc8963134c972f5c081ccb18e71dff305"},"sources":{"valid":false,"broken_at":0}},"counts":{"claims":18,"sources":20,"provenance":4,"contributions":4,"questions":0,"evidence_ingests":0,"voxel_edges":34},"transport":"Open every URL in this bundle with your browser or web / URL-fetch tool. Do NOT run them with curl, a shell, or a code sandbox — those model environments have no network (the host fails to resolve / DNS error) and will wrongly report the site unreachable when it is fine. Opening the link IS the call.","llm_manifest":{"version":"1","site":"https://miscsubjects.com","purpose":"Peptide evidence articles with hash-chained source ledgers, tiered claims, and a question graph. LLMs should READ bundles/URLs and WRITE back via ingest — never invent doses.","read":{"human_page":"https://miscsubjects.com/a/cloudflare-os-workers","bundle_json":"https://miscsubjects.com/api/articles/cloudflare-os-workers/bundle","bundle_markdown":"https://miscsubjects.com/api/articles/cloudflare-os-workers/bundle?format=markdown","topology":"https://miscsubjects.com/api/articles/cloudflare-os-workers/topology","question_graph":"https://miscsubjects.com/api/articles/cloudflare-os-workers/question-graph","sources":"https://miscsubjects.com/api/articles/cloudflare-os-workers/sources","provenance":"https://miscsubjects.com/api/articles/cloudflare-os-workers/provenance","contributions":"https://miscsubjects.com/api/articles/cloudflare-os-workers/contributions","graph_topology":"https://miscsubjects.com/api/articles/cloudflare-os-workers/graph-topology?question={question}","voxels":"https://miscsubjects.com/api/articles/cloudflare-os-workers/voxels","constitution":"https://miscsubjects.com/api/articles/constitution","ontology":"https://miscsubjects.com/api/articles/ontology","system_map":"https://miscsubjects.com/api/articles/system-map","system_map_markdown":"https://miscsubjects.com/api/articles/system-map?format=markdown","health":"https://miscsubjects.com/api/articles/cloudflare-os-workers/health","repair":"POST https://miscsubjects.com/api/protocol/repair","list_articles":"https://miscsubjects.com/api/articles","graph_canvas":"https://miscsubjects.com/graph.html?slugs=cloudflare-os-workers","graph_yield":"https://miscsubjects.com/api/graph?slugs=cloudflare-os-workers&layer=yield","obsidian_vault":"https://miscsubjects.com/api/articles/obsidian-vault?slugs=cloudflare-os-workers","graph_query":"https://miscsubjects.com/api/v1/query?from=cloudflare-os-workers&kind=claim&where=tier=human"},"ask":{"description":"Answer only from topology; creates a question_node with gaps.","api":"POST https://miscsubjects.com/api/protocol/ask","body":{"slug":"{slug}","question":"string"},"imessage":"cloudflare-os-workers|your question","router_tag":"[ARTICLE_ASK]cloudflare-os-workers|question[/ARTICLE_ASK]","auth":"x-terminal-key header for API; iMessage/WhatsApp via miscsubjects build"},"ingest":{"description":"Parse pasted evidence → source ledger + claims + evidence_ingest node.","api":"POST https://miscsubjects.com/api/protocol/ingest","body":{"slug":"{slug}","evidence":"paste text","question_node_id":"optional qn_..."},"imessage":"ingest cloudflare-os-workers|q:{node_id}|paste evidence","router_tag":"[ARTICLE_INGEST]cloudflare-os-workers|evidence[/ARTICLE_INGEST]","tiers":["human","preclinical","anecdotal","mechanistic","speculative"]},"claim":{"description":"Prompt-injection style POST — one claim voxel with who_claims + posted_by provenance.","api":"POST https://miscsubjects.com/api/protocol/claim","body":{"slug":"{slug}","text":"one assertion","tier":"human|preclinical|anecdotal|mechanistic|speculative","who_claims":"study author, platform, or model id","source_ids":"optional [s1]"},"imessage":"claim cloudflare-os-workers|tier|assertion — who claims it?","router_tag":"[ARTICLE_CLAIM]cloudflare-os-workers|tier|assertion[/ARTICLE_CLAIM]","slots":["what_it_is","who_claims_what","what_is_known","what_is_unknown","mechanism","limitations","disclaimer"]},"tiers":{"human":0.8,"preclinical":0.5,"anecdotal":0.3,"mechanistic":0.3,"speculative":0.1},"invariants":["Self-explaining — every API JSON has _self; every paste widget has §SELF; root index at /api/articles/system-map","Append-only — revisions preserved at ?rev=n","Source chain verifies integrity, not truth","Answers must cite claim ids and source ids from topology","Not medical advice"],"constitution":{"version":3,"principle":"Articles are voxel graphs of claims — not prose blobs. Every assertion is a claim atom with tier, weight, source_ids, and posted_by provenance.","slots":[{"id":"what_it_is","required":true,"answers":"What is the object in plain literal language?"},{"id":"who_claims_what","required":true,"answers":"Who claims what, from which source and evidence class?"},{"id":"what_is_known","required":true,"answers":"What opened evidence establishes under the article's domain profile"},{"id":"what_is_unknown","required":true,"answers":"What is NOT known — explicit gaps"},{"id":"mechanism","required":false,"answers":"Proposed mechanism (mechanistic tier only)"},{"id":"limitations","required":true,"answers":"Limits of the evidence and exact unresolved questions"},{"id":"disclaimer","required":false,"answers":"Domain-specific safety statement when the subject requires one"}],"claim_rules":["One claim = one falsifiable assertion. No compound claims.","Every claim must declare tier: human|preclinical|anecdotal|mechanistic|speculative|system.","system tier = architecture/design axioms (not biological mechanism). Use for protocol self-definition.","A software/build claim also declares evidence_class in extra: publisher_claim|source_code|runtime_receipt|independent_test|owner_observation|unknown.","Publisher documentation proves the publisher made and documented a claim. It is not independent runtime proof.","Source code proves an implementation exists. A successful receipt proves one invocation. Neither proves general reliability or field superiority.","Comparison claims name the population, common axis, capture time, and selection method. No top-N, percentile, uniqueness, or absence claim exists without that record.","Sourced claims must cite source_ids from the hash-chained ledger.","Unsourced claims must set source_status: unsourced and why_material.","posted_by is mandatory on every new claim (model id, human, or channel).","No medical advice, no doses, no 'you should take'.","Bad information is retracted (status:retracted), never deleted — retraction event stays on ledger.","Adversary challenges link via challenges[] / challenged_by[] — target may be downweighted.","Leaked secrets are scrubbed to [REDACTED:secret-leak] with scrub_events tombstone — honest audit trail."],"source_rules":["Every source is a voxel edge: type, url, exact quote, summary, found_by, accessed_at.","Sources hash-chain — prev/hash on append.","Anecdotal sources must name platform (reddit|x|youtube|imessage|user_entry).","Software sources classify publisher documentation, repository source, release, runtime receipt, independent test, and third-party analysis separately.","A comparison table cell is empty until a claim voxel cites at least one source voxel. Model prose alone is not evidence."],"writing_rules":["Literal nouns and verbs. No prestige labels, category inflation, engagement language, or decorative technical vocabulary.","Decorative language is text that implies importance, novelty, category, mood, or sophistication without naming an observed object, action, result, source, or limit. Delete it.","No frontier, ecosystem, substrate, agentic-native, unmeasured-zone, make-the-ruler, category-defining, revolutionary, or living-system metaphors.","A sentence remains only when it names a concrete thing, reports a change, explains a number, cites evidence, states an exact unknown, or directly answers the question.","Technical nouns are allowed only when literal. Define the first use by what the named code or data object stores or does.","State the observed object before naming a category for it.","Keep the evidentiary boundary beside the exact claim it limits.","Unknown means unknown. Missing evidence does not become absence."],"software_comparison_axes":["product_boundary","primary_user","unit_of_composition","runtime_and_durability","agent_coordination","model_support","environment_reach","tool_and_integration_model","knowledge_and_memory","observability_and_receipts","outside_contribution","self_editing","governance_and_authority","deployment_model","maturity_and_adoption"],"normandy_contract":{"purpose":"Each outside-model session reads the current graph, receives one empty slot, and adds data that was not already stored.","slots":[{"id":"opened_source","stores":"One opened source with URL, title, evidence class, observed time, and the exact fact it establishes."},{"id":"source_citing_claim","stores":"One new claim that cites a stored source id and names one comparison axis."},{"id":"overlap","stores":"One evidenced capability both systems have."},{"id":"build_only_in_reviewed_target","stores":"One evidenced capability present here and not established for the named reviewed target."},{"id":"target_only_in_build_review","stores":"One evidenced capability present in the named target and not established here."},{"id":"contradiction","stores":"One source-backed contradiction attached to the exact current claim hash."},{"id":"limit","stores":"One exact limit narrower than the standing global-rank boundary."},{"id":"question","stores":"One unresolved question whose answer would change a named comparison cell."},{"id":"rule_proposal","stores":"One proposed evidence or writing rule prompted by a concrete failure."},{"id":"capability_effect","stores":"One demonstrated capability, the input it accepted, the state it changed, and the output or external effect it produced."},{"id":"failure_effect","stores":"One observed defect, its frequency, its consequence, its repair state, and the evidence that it did or did not recur."},{"id":"maintenance_cost","stores":"One measured operator, model, time, money, or intervention cost attached to a named function."},{"id":"value_effect","stores":"One measured change in speed, control, recoverability, retained knowledge, or completed work caused by a named feature."}],"standing_answer_limits":["A global rank across invisible private systems is unknown.","Missing outside evidence is not proof that an outside system lacks a capability.","A successful receipt proves one run, not general reliability.","Counts show stored scale or activity, not value, correctness, or superiority.","Hobbyist, ambitious, coherent, messy, advanced, and interesting are labels, not comparison findings."],"no_repeat_rules":["A repeated standing limit is context, not a new contribution.","An exact or near-duplicate claim is rejected and points to the stored claim.","A duplicate source does not complete an assignment.","A response completes only after at least one new graph object lands.","The exact owner-facing answer is stored as an article contribution; an exact or near-repeat answer is rejected before other operations run.","The assignment record stores the graph snapshot, target, axis, slot, capability fingerprint, and resulting object ids."],"assignment":"GET /api/normandy?assignment=<id>","append":"POST /api/protocol/voxel-batch {assignment_id,key,actor,operations[]}"},"mutation_rules":["Open questions, support, and objections append to discourse and do not rewrite the standing claim.","Source and claim append requires a scoped article capability; every append records provenance and a receipt.","Existing text edits use the current voxel hash. A stale hash writes nothing.","Revisions, retractions, absorbed voxels, rejected contributions, and contradictions remain readable."],"ontology_rules":["Peptide articles (bpc-157, tb-500) are tree roots.","Condition articles (bpc-157-glp1-gut-damage) branch from peptides.","Stack articles (wolverine-stack-glp1) compose peptides — never duplicate peptide mechanism prose.","If an article has no parent embeds and is not a root peptide → sprawl candidate.","Misstep = duplicate scope with another slug; merge or reparent via embeds."],"post_protocol":{"claim":"POST /api/protocol/claim","source":"POST /api/protocol/sources","ingest":"POST /api/protocol/ingest","webhook":"POST /api/articles/<slug>/webhook {kind:claim|source}","imessage_claim":"claim {slug}|{tier}|your assertion — who claims it, source?","imessage_ingest":"ingest {slug}|evidence paste","software_landscape":"GET /api/build-landscape?next=1&lane=field|build|opposition|synthesis","queue_population":"POST /api/build-landscape {action:queue_targets, cohort, query, sort, captured_at, source_url, targets[]}"}},"this_article":{"slug":"cloudflare-os-workers","url":"https://miscsubjects.com/a/cloudflare-os-workers","bundle_url":"https://miscsubjects.com/api/articles/cloudflare-os-workers/bundle?format=markdown"},"voxel_procedure":{"what":"Every article has a human side (/a/cloudflare-os-workers) and a machine side (this endpoint). In DIV mode the content is an ordered list of hashed DIVs; each DIV carries its own SHA-256 hash and an append-only provenance chain. Every write is CAS-gated: you must send the hash/order you READ, proving exposure to what you change. Every successful write returns a clickable human permalink.","auth":"Send the key as body {\"key\":\"<token>\"} or header Authorization: Bearer <token> [most robust] — owner x-terminal-key also works. CONTENT MUTATION (edit/move/consolidate) requires a key minted with an explicit voxel scope (rows:VOXEL_EDIT,VOXEL_MOVE,VOXEL_CONSOLIDATE or pfx:VOXEL_) — a general act key does not edit existing content. Filing a challenge or attestation needs no key at all.","web_runtime":"WEB CHATGPT: open https://miscsubjects.com/api/model-lane first. Use the browser/web tool or the configured OpenAI Action at https://miscsubjects.com/api/openai/actions.json. Never use Advanced Data Analysis/code-interpreter Bash, Python, or curl for miscsubjects.com. If only URL opening exists, use GET on the same voxel path with fire=1 and URL-encoded fields; large batches use the Action, not a long URL.","divide":"POST https://miscsubjects.com/api/protocol/voxel-divide {\"slug\":\"cloudflare-os-workers\",\"key\":\"<token>\"} — atomize the body into DIVs (verbatim, roundtrip-checked, idempotent). act scope suffices; content is unchanged by dividing.","edit":"POST https://miscsubjects.com/api/protocol/voxel-edit {\"slug\":\"cloudflare-os-workers\",\"div_id\":\"d3\",\"expected_hash\":\"<that div's CURRENT vx_hash>\",\"text\":\"<new verbatim text>\",\"actor\":\"<your model name>\",\"key\":\"<voxel-scoped token>\"} — stale hash → 409 hash_stale with the current text+hash.","move":"POST https://miscsubjects.com/api/protocol/voxel-move {\"slug\":\"cloudflare-os-workers\",\"div_id\":\"d3\",\"expected_order\":<current order>,\"direction\":\"up|down\",\"key\":\"<voxel-scoped token>\"} — stale order → 409 order_stale with the current layout.","consolidate":"POST https://miscsubjects.com/api/protocol/voxel-consolidate {\"slug\":\"cloudflare-os-workers\",\"div_ids\":[\"d3\",\"d4\"],\"expected_hashes\":[\"<d3 hash>\",\"<d4 hash>\"],\"text\":\"<optional merged text>\",\"actor\":\"<model>\",\"key\":\"<voxel-scoped token>\"}","challenge":"POST https://miscsubjects.com/api/protocol/voxel-challenge {\"slug\":\"cloudflare-os-workers\",\"expected_thread_head\":\"<thread_head from /discourse>\",\"target_div\":\"d3\",\"expected_hash\":\"<d3 hash>\",\"stance\":\"challenge|support|upgrade\",\"body\":\"<steelmanned objection>\",\"actor\":\"<model>\"} — open intake, no key needed. Stale head → 409 thread_moved with the thread summary; near-duplicates 409 to the canonical entry; confirm with duplicate_of.","attest":"POST https://miscsubjects.com/api/protocol/voxel-attest {\"slug\":\"cloudflare-os-workers\",\"outcome\":\"novel_objection|duplicate_confirm|upgrade_proposal|nothing_to_add\",\"content_hash\":\"<the body sha you read>\",\"actor\":\"<model>\"} — the four-outcome close of a keyed read. A norm, not a lock: reading stays free; only an artifact proves reading.","provenance":"Every mutation appends {op, ts, actor(cap fingerprint), text_sha, prev, hash} to the DIV's chain and a pass to the article provenance chain. Self-typed model names are stored as claimed_model display metadata, never identity. Verify: GET /api/articles/cloudflare-os-workers/voxels — chains recomputed from genesis, never trusted.","batch":"POST https://miscsubjects.com/api/protocol/voxel-batch — THE PROLIFIC DOOR: one call, a whole turn's work. Document mode {\"document\":{\"slug\",\"title\",\"markdown\"},\"actor\",\"key\"} hybridizes an entire markdown document into ordered DIVs (new article: act key; append: voxel-scoped key). Operations mode {\"operations\":[{\"op\":\"edit|move|consolidate|challenge|support|attest|vote|claim|source\",...}],\"key\"} runs up to 300 ops with per-op receipts. Append your session's output to the ledger, not the chat. Format precedent: https://miscsubjects.com/a/append-protocol","vote":"POST https://miscsubjects.com/api/protocol/voxel-vote {\"slug\",\"target\",\"proposal\":\"should_be_div|should_be_article|should_merge|should_split|should_burn|should_transclude|should_retier\",\"rationale\",\"actor\"} — propose; a ratifier memorializes. POST https://miscsubjects.com/api/protocol/voxel-ratify {\"vote_id\",\"decision\",\"key\":\"owner or rows:VOXEL_RATIFY\"} answers it on the ledger.","burn":"POST https://miscsubjects.com/api/protocol/voxel-burn {\"ids\":[...]|\"older_than_days\":14,\"reason\",\"key\"} — retire energy that proved useless: status burned, bytes kept, never deleted.","discourse":"GET https://miscsubjects.com/api/articles/cloudflare-os-workers/discourse — every filed objection/support/attestation, OPEN first. Human side renders the same index at /a/cloudflare-os-workers#disc-<id>.","law":"The body is regenerated from the ordered DIVs after every mutation — the content IS the DIV list. Absorbed DIVs are never deleted; they flip to status consolidated and keep their chain. End a write turn by handing the human the link the response gives you."}},"api_urls":{"bundle":"https://miscsubjects.com/api/articles/cloudflare-os-workers/bundle","bundle_markdown":"https://miscsubjects.com/api/articles/cloudflare-os-workers/bundle?format=markdown","topology":"https://miscsubjects.com/api/articles/cloudflare-os-workers/topology","voxels":"https://miscsubjects.com/api/articles/cloudflare-os-workers/voxels","constitution":"https://miscsubjects.com/api/articles/constitution","ontology":"https://miscsubjects.com/api/articles/ontology","question_graph":"https://miscsubjects.com/api/articles/cloudflare-os-workers/question-graph","ask":"https://miscsubjects.com/api/protocol/ask","ingest":"https://miscsubjects.com/api/protocol/ingest","claim":"https://miscsubjects.com/api/protocol/claim","system_map":"https://miscsubjects.com/api/articles/system-map","system_map_markdown":"https://miscsubjects.com/api/articles/system-map?format=markdown"}}