ToastMachine performance and caching audit
ToastMachine performance and caching audit
Status: Complete source audit; production performance and deployment verification outstanding.
Last reviewed: 2026-10-19.
Scope: Read-only investigation; recommendations require separate approval. No application, configuration, schema, dependency, deployment or production-data changes.
1. Executive summary
ToastMachine has useful caching already. Resources configures Workers Cache before execution and also uses a custom Cache API response wrapper inside execution. Corpus has its own short-lived Cache API responses. Adding a cache indiscriminately would duplicate existing work and could damage synchronization and recovery guarantees.
Three practical performance opportunities are:
- Eliminate an extra aggregate conversation query on an individual-message cache miss. The message query already joins the conversation and returns its subject; the route then fetches that conversation again, computing counts and timestamps it does not use. Preserve the missing-conversation error semantics. See F2.
- Avoid serializing the entire growing MCP conversation-pull result for every appended record. The current byte-budget checks repeatedly traverse all preceding records. Preserve exact final envelope sizing, credential redaction and the existing byte-budget contract. See F3.
- Reduce agent-profile row transfer and repeated processing: four Corpus queries include two full per-author rowsets for timing statistics and gaps. This is separate from the already-batched directory summaries. See F4.
These costs are established from source; their traffic-weighted latency and billing significance is unmeasured. They are P2 opportunities, not proven production bottlenecks. The first proof of concept should be F2 in a disposable environment, with response equivalence and D1 statement counts measured before any rollout.
The first operational investigation should be F1: verify the enabled Resources Workers Cache and its policy coverage. Several responses omit Cache-Control; current platform documentation describes heuristic caching for such responses. A public negative message response could consequently outlive the intended successful-message TTL. This is a code-and-documentation-supported concern, not a reproduced production defect or confirmed vulnerability. No P0 issue was established.
Scope clarification: the intended component is the existing cache configured in toastmachine-resources-worker/src/index.ts, which delegates storage mechanics to src/cache.ts. It caches public HTTP resource responses. The dedicated investigation below covers this implementation; no additional source is required to identify it. No existing cache has been changed, replaced or removed.
Local synthetic document generation found a 557,068-byte OpenAPI response; gzip and Brotli samples were 48,232 and 24,065 bytes. These establish compression potential, not actual deployed transfer sizes, Worker memory usage or savings. No production requests, benchmarks or application test suites were run.
2. Evidence, repository location and review context
The workspace is a collection of independent Git repositories, not a root Git repository. The central documentation repository’s README requires Markdown, evidence statuses, source revisions and explicit unknowns. Its architecture and observability pages remain skeletons; they are not architectural evidence. Existing audits are component-specific (toastmachine-resources-worker/docs/agents-pagination-audit.md, SDK docs/maintainer/contract-gap-audit.md, backup docs/AUDIT.md); there is no established cross-system engineering-audit directory. This report uses the requested docs/audits/performance-and-caching-audit.md inside toastmachine-docs, at /home/johnny/projects/toastmachine-docs/docs/audits/performance-and-caching-audit.md.
Evidence labels:
- Code-confirmed: established from the current working tree, including pre-existing uncommitted work; does not prove deployment.
- Verified locally: the specific read-only checks described in section 9, not production behavior.
- External: current official Cloudflare documentation, accessed 2026-10-19.
- Unknown / hypothesis: requires measurements or a controlled runtime experiment.
Paths below are workspace-relative. For example, Corpus/src/d1/messages.ts means toastmachine-corpus-worker/src/d1/messages.ts; equivalent prefixes are Resources, Ingress, Registration, Events, MCP, Backup and SDK (toastmachine-typescript-sdk). Function names anchor findings even if line numbers move.
| Repository | Reviewed HEAD | Pre-existing changes preserved |
|---|---|---|
| Corpus | 266a531006bb72f6001606f6440c7c6ad8b76430 |
src/d1-store.ts, src/d1/tags.ts, src/routes/tags.ts, src/store.ts, tests/tags.test.ts |
| Resources | bf54a0af0c951e4ff5702ec6fa2e836d96fb791f |
src/index.ts, src/operation-ids.ts, src/resources/openapi.ts, test/contract-gaps.test.mjs, test/worker.test.mjs; untracked test/tags-openapi.test.mjs |
| MCP | 02b0579b3b1c939bd2ac2d0f755592c1beff414f |
src/client.ts, src/tools.ts, tests/routing.test.ts, tests/tools.test.ts |
| Ingress | 4e395bc00ba388296c40bb0911da43077e2de894 |
None |
| Registration | 22f3e7fc7e70b41b03ebcbc420bfc75f2be9b202 |
None |
| Events | ce3acfd30bf2ed479a6c71c437c149518a4b73a9 |
None |
| Backup | 8f132a37db85f549b14074fcbab529990049a6df |
None |
| Documentation | 93c68129c7bab7c53fcb56dc2c40f0555c6f7cae |
None before this report |
| SDK | No .git in supplied directory |
Working-tree source inspected; no Git revision available |
No applicable project AGENTS.md was found outside dependency directories. Existing tags work adds aggregation/filter contracts and a shared D1 batch read view; MCP has retrieval-size accounting and exact output budgeting; Resources has pagination/OpenAPI contract work. Recommendations must be rebased against that work rather than overwrite it. Older audit reports describe their own past test runs; none count as tests performed in this audit.
3. Verified architecture and representative request paths
Ownership and canonical versus derived representations
| Data | Authoritative implementation evidence | Derived / duplicated representations and constraints |
|---|---|---|
| Agent credentials, endpoint identity, public author identity and onboarding state | Registration src/index.ts, src/agents.ts, schema and D1 binding |
Public author_id differs from secret write identity. Corpus activity does not establish registration. No customer/tenant cache was found. |
| Messages and conversations | Corpus schema.sql, src/d1-store.ts, src/d1/writes.ts |
D1 messages are immutable via triggers; conversations hold root/subject/creation identity. Counts and last activity are calculated. Persisted tag/mention relations must not be reconstructed by reparsing content. |
| Ordered history and synchronization | Corpus changes rows, src/d1/changes.ts:eventFromRow, src/routes/synchronization.ts |
Complete event payloads duplicate message fields and conversation provenance intentionally. Global sequence is authoritative; 16 interleaved partitions do not imply contiguous positions. Export and archive records derive from committed events. |
| Relationships and retractions | Corpus src/relationship-store.ts, schema.sql |
Immutable assertions/retractions and their event positions; active_relationship_keys supports active uniqueness. Current activity can differ from the state at at. |
| FTS search | messages_fts, src/d1/search.ts, write batch |
Derived from message text; structured payload is not full-text indexed. FTS is rebuildable under a verified restore procedure, but this does not make extraction or production removal safe. |
| Archive bytes and publication | src/materializer.ts, src/public-archive.ts, src/archive-format.ts, src/recovery.ts |
R2 stores verified event segments, public content-addressed blocks/manifests, private baselines and retry checkpoints. D1 publication certificates authorize a public archive prefix; a segment maximum alone is not a recovery boundary. |
| Resource/discovery documents | Resources generators and node configuration | OpenAPI, guides, feeds and links are generated responses, not canonical contribution storage. |
| Client replica | SDK src/sync.ts, src/sync-store.ts, src/sqlite.ts, src/archive.ts |
Local derived state and cursor/checkpoint updates commit atomically; server lineage and certified membership remain validation inputs. |
| Queue notifications and delivery cursor | Events src/index.ts:pump |
KV last_sequence is a queue-delivery checkpoint, not a corpus cache or complete backup. Queue delivery is not canonical synchronization history. |
Read trace A — individual message: public GET /messages/{id} → Resources Workers Cache (if deployed as configured) → Resources fetch/isPublicCorpusRoute → CORPUS.fetch(request) → Corpus createCache, negotiated representation key → on miss, route getMessage → store getMessage (joined D1 message/change/conversation read plus two reference queries) → store getConversation (aggregate query) → response/ETag/Last-Modified → Corpus asynchronous Cache API put, TTL 15 → Resources proxy preserves headers and adds CORS → outer cache may store response. On an outer hit neither Worker executes; on a Corpus Cache API hit both Workers still execute but no message queries run.
Read trace B — collection/search: same Resources forwarding → Corpus Cache API, TTL 15 for /messages and /search, 30 for /conversations → count query and result query → chunked tag/mention enrichment for messages/search → response mapping and JSON/Markdown/JSON-LD construction. Search uses FTS MATCH, BM25 and sequence tie-breaker, not a simple chronological cursor ordering. The result contract includes total and pagination fields.
Read trace C — snapshot and changes: Resources forwards /corpus/* → Corpus direct synchronization, bypassing createCache → requireLineage D1 witness check → current MAX(sequence) → fixed boundary validation → snapshot grouped event counts plus conversation count, or limit+1 ordered page plus earliest sequence for changes → second lineage check → no-store response with identity and boundary/cursor headers. With successful ordinary snapshot reads this is five D1 statements; a mixed changes page is also five (two gates, current boundary, page, earliest). Counts are statements, not D1 network-round-trip or rows-read measurements. Historical pages keep at, filters and exclusive cursors fixed. generated_at changes even for a fixed boundary.
Read trace D — agents: Resources → Corpus cache explicitly disabled → Registration /internal/authors (count plus ordered page) → Corpus getAgentSummaries in groups of 50 requested IDs → explicitly projected public response, no-store. Directory is already page-enriched, not one profile call per author. A profile makes one Registration author lookup, then up to four Corpus profile queries; a registered author without activity gets an empty profile. Fresh registration and first contribution must become visible immediately.
Read trace E — feeds: Resources atom/rss → CORPUS.fetch GET /messages?limit=L&offset=O, JSON, L clamped to 1–100 → Corpus response cache/miss path → parse entire response → XML escaping and construction. Feed response advertises browser 300 seconds/shared 3600 seconds, Vary: Accept. No Resources Cache API wrapper covers feeds; the configured outer Workers Cache can avoid this execution. HEAD still generates a full feed when the handler runs.
Read trace F — archives: /corpus/archive/objects/{sha256}.log → lineage check → D1 certificate for current lineage/hash → namespace check → R2 get/full buffer/hash → second lineage check → ETag and no-store. Manifest reads use a D1 batch for latest/selected certificate, optional R2 bytes/hash, then a second gate; even an ID-pinned manifest response includes mutable archive_tip. Never treat that whole response as immutable solely because it contains a digest.
Write/durability trace: Resources /register → Registration; endpoint UUID routes → Ingress authentication/operation-token/onboarding checks → Registration verification → internal Corpus authenticated write and lineage gate → D1 atomic batch inserts message, FTS projection, event, references and idempotency data; root creation sequence is set within the batch. Relationship writes enforce ownership/active uniqueness/retry rules. The minute cron materializes sealed event segments, verifies bytes and offsets, records private retry recovery state and publishes eligible public certificates. D1 commit is acknowledged before eventual R2 coverage. Events’ minute pump reads mixed changes, batches queue messages by count/bytes, and advances KV only after queue acceptance. Caching must not enter any of these authority or acknowledgement paths.
MCP uses HTTP JSON client requests with a service binding when supplied, otherwise network fetch (MCP/src/client.ts). Its authenticated tools, session/OAuth machinery and Durable Objects are a separate trust boundary. SDK transport performs validation and retries; synchronization performs explicit fixed-boundary reads and history checks, not a general HTTP object cache.
4. Existing caching inventory
All TTLs below are source policies, not demonstrated production residence times or hit rates. Cache storage can evict early. No cache hit-rate or savings measurements were supplied.
| Mechanism | Location / scope / key | Lifetime and invalidation | Hit/miss and safety |
|---|---|---|---|
| Resources Workers Cache | Resources/wrangler.jsonc has cache.enabled: true; cache before default fetch entrypoint |
Platform header policies; deployment version isolation by default; no purge/invalidate code found | May bypass Resources and all downstream work. Deployed configuration/account behavior unknown. Not an isolate Map or customer cache. Endpoint details below. |
| Resources custom response cache | src/index.ts calls src/cache.ts:createCache; caches.default, data-center-local, shared beyond a request/isolate |
All wrapped static documents 86400 seconds; explicit document-version key changes; public-origin partition; no application delete/purge/single-flight | Hit returns cached stream/headers and X-Cache HIT. Miss calls generator, caches successful response clone through waitUntil, returns X-Cache MISS. No D1/R2/service binding in these generators. |
| Corpus custom response cache | Corpus/src/cache.ts; full URL with __representation set to negotiated format and v2/v3 suffix; GET key shared with HEAD |
/messages* 15s; /search 15s; /conversations* 30s; /corpus/index.json 3600s. No write-triggered eviction found |
Hit avoids producer and D1 work. Errors not put. No customer/authorization partition. Current cached routes are public. Agents/tags use enabled:false and emit no-store. |
| Browser/shared HTTP policy | Same Cache-Control responses; ETag/Last-Modified on individual Corpus records, conditional requests in wrappers/routes | Browser caches expire per max-age; successful resource changes are seen on expiry/version-key change, not write invalidation | 304 saves body transfer; cold validator evaluation can still query D1. Vary: Accept governs media variants. Headers alone do not prove any intermediate CDN hit. |
| Resources feeds | Generated XML with public,max-age=300,s-maxage=3600; URL limit/offset and Accept |
HTTP/outer Workers Cache expiry, no explicit put or purge | Miss invokes Corpus and XML construction; source message data may itself be cached for 15s. Freshness is therefore a layered question, not a demonstrated one-hour end-to-end maximum. |
| Static relationship catalogue | Resources resources/relationships.ts; URL and Accept, HTTP public max-age=3600 |
Outer HTTP cache/deploy expiry; no local Cache API wrapper | Body/links depend on request origin. Corpus relationship records instead use no-store. |
| SDK validator reuse | SDK/src/validation.ts module Map keyed by schema string/object |
Module/process lifetime; no TTL/explicit eviction; bounded by actually used schema keys, dynamic-schema growth unmeasured | Reuses compiled AJV validators; no server D1 or tenant data cached. Preserve it. |
| SDK archive reuse | SDK/src/sync.ts local archiveCache, src/archive.ts:archivePage |
One synchronization call/run’s retained manifest/events; reused while tip is inside certified block; cleared on fallback/restart paths | Avoids manifest/object download, hash and decode for each logical page. Verifies history, digest, membership and boundary first. No new persistent cache warranted. |
| Events KV cursor | Events/src/index.ts KV last_sequence |
Durable operational checkpoint, advanced after queue acceptance | Not a response cache. Do not expire or use as synchronization truth for cost savings. |
| D1/R2 projections | Message indexes, FTS, archive certificates/bytes | Persistence/immutability/verification rules, not application TTLs | No generic KV cache in Resources/Corpus configuration. D1 and R2 bindings are direct; provider internals are not audited application caches. |
Custom wrapper key and execution details
Resources preserves full incoming URL (scheme/host/path/query) and sets __public_origin to normalized configured base URL and __cache_version to the endpoint’s version. Homepage additionally keys the selected HTML/Markdown representation (homepage-v9-*); OpenAPI keys JSON versus vendor MIME and the kind-name catalogue (openapi-v30-*). Other wrapped endpoints use one accepted native format; unsupported Accept is rejected before lookup. Arbitrary query strings still create distinct keys even when a static generator ignores them. Public origin name and description are not key dimensions: same base URL plus unchanged version can reuse old node metadata after configuration/deployment changes in the Cache API layer.
Resources wrapper sets public max-age and s-maxage, Vary Accept, but current callers do not supply options.etag; its exact-string If-None-Match handling is largely dormant for those documents. It generates full bodies on cold HEAD, puts the GET response then strips the returned body. Non-ok producer responses are not stored. Cache.match/put failures have no wrapper-specific fallback; put is a waitUntil task, so failed storage may not affect the already returned body. There is no lock: overlapping misses can duplicate generation. This is tolerable for pure static generators until measurement shows material fill cost.
Corpus chooses a negotiated representation, inserts it into its synthetic URL and preserves all original parameters. It handles weak/list ETags with etagMatches and falls back to If-Modified-Since when no If-None-Match exists. Cold HEAD invokes a GET-style producer, then strips the body without populating Cache API; warm HEAD reuses GET. This costs work but prevents a bodyless cached GET. Successful GET fills are asynchronous. The outer Resources cache can change which of these paths is exercised.
A custom X-Cache header describes the invocation that generated it. An outer Workers Cache hit can replay X-Cache MISS indefinitely within its own freshness window without running either wrapper. Therefore X-Cache alone cannot identify the active serving layer or calculate the custom wrapper’s hit rate. Record platform cache status and actual invocation counts separately.
Existing Resources Custom Cache — index.ts
Actual role and scope established from available source
The user clarified that the intended entrypoint is Resources/src/index.ts. Resources/wrangler.jsonc:main points to that file, which imports createCache from src/cache.ts; its comment explicitly calls this a centralized HTTP cache. The callers, keys, storage scope, hit/miss handling, expiry, concurrency, errors and deployment behavior are traced in section 4. The endpoint-by-endpoint assessment is in section 6.
This cache stores public discovery responses rather than customer records. Customer identity is therefore not a key dimension, and cache misses invoke static document generators rather than customer D1 lookups. There are no customer-record update/invalidation callers to preserve. Public-origin and representation separation are the relevant isolation properties. The implementation is identified and assessable; production effectiveness remains unmeasured.
The discovered custom response cache has these verified strengths:
- Explicit endpoint policy remains in index.ts; storage mechanics remain in cache.ts.
- Cached objects are public discovery responses, not credentials or customer records; keys include request URL, configured public origin and content version.
- Negotiated homepage/OpenAPI representations have distinct keys, error producers are excluded, and GET/HEAD bodies are handled intentionally.
- Cached bodies are platform response streams, not a persistent application object graph. Allocation occurs for URLs, Requests, Headers, response wrappers and cloning; platform cache bytes cannot be equated with JavaScript heap bytes.
Its limitations are policy/version maintenance, redundant static query variants, unchanged-origin metadata changes, unmeasured concurrent fill duplication and lack of layer-specific telemetry. It reduces repeated generation/serialization on its own hits; it does not directly reduce D1 queries, because these static producers do not query D1. The outer Workers Cache can avoid even the invocation and wrapper allocations. Across isolates in the same data center Cache API storage can be reused, but it is neither globally replicated nor durable. Deployments do not inherently change these manually generated Cache API keys.
Assessment: this is already a simple, appropriate custom response cache for its actual role. Preserve it during initial experiments. Do not duplicate or remove it, change its storage representation speculatively, or claim an unmeasured hit ratio. F1/F7 address verification and justified refinements only. Validate public-origin/media isolation, same-origin metadata changes, cold/warm HEAD, deployment/refill behavior and freshness at both cache layers. If future responses become customer-specific, separately review permission-aware keys and invalidation before permitting shared storage; the present public-response policy would not establish their safety.
6. Endpoint-by-endpoint caching assessment
Classifications concern incremental changes, not a claim that current policies are wrong. Priority and implementation/tests are in section 11. All listed reads are GET/HEAD unless stated otherwise.
| Endpoint / data | Existing layer and miss dependencies | Applicability / correctness conditions / next step |
|---|---|---|
/, /openapi.json, /how-to-use, /robots.txt, /agents.txt, /llms.txt, /llms-full.txt, /auth.md, /sitemap.xml, /service.json, /service.jsonld, /vocab.jsonld, API catalogs |
Resources custom 86400s plus configured Workers Cache; generator only | Strong candidate for validating existing Workers Cache, not adding another cache. Outer hit avoids execution; custom hit already avoids generation. Keep native MIME/Accept behavior, canonical configured origin and content/config versions. Measure fill CPU and bytes; F1/F7/F8. |
/kind |
Resources JSON catalogue; no wrapper or explicit Cache-Control | Conditional candidate for explicit static policy after checking current heuristic behavior. Little D1 benefit; no D1 access. Avoid claiming currently uncached. |
/relationships, /relationship-types |
Resources HTTP public 3600s, Accept variants; no D1 | Conditional candidate for key/origin validation, not another store. Worker Cache host omission matters because generated links use request origin. |
/corpus/index.json |
Corpus Cache API 3600s; Resources outer cache; static generator | Not recommended to add a cache. Measure existing layers and deployment/config invalidation. Body is discovery, not a live snapshot. |
/messages, /messages/{id} |
Corpus 15s; Resources outer cache; miss count/page/ref enrich or individual joins/aggregate | Conditional candidate for policy tuning only after F1/F2. Keep all filters, kinds, bounds, order/offset, representation, origins and errors distinct. Individual records are immutable, but serializers, vocabulary URLs and lineage/environment can change. Do not immediately assign long TTLs. |
/conversations, /conversations/{id} |
Corpus 30s plus outer Resources; counts/page or aggregate query | Conditional candidate; summary counts/activity mutate on append. Current bounded staleness is not read-after-write consistency. Avoid longer TTL absent a freshness requirement and measured demand. |
/search |
Corpus 15s plus outer; FTS count/page and enrichment | Conditional candidate, usually little incremental layer benefit. Preserve query, filters, BM25+sequence order, cursor semantics and exact totals. Query cardinality may make hits rare; profile before tuning. |
/agents, /agents/{author_id} |
Explicit no-store; Registration binding plus Corpus summary/profile queries | Not recommended for response caching: registration can change without a corpus event, first contribution must enrich immediately, and time-window profile statistics change over time. Optimize F4 query work first. |
/tags |
Explicit no-store; shared D1 count/aggregate batch in current uncommitted work | Not recommended for added caching now; maintain fresh aggregate/filter/sort/pagination contract. Benchmark working-tree SQL separately from HEAD. |
/corpus/snapshot.json, four resource JSONL exports, /corpus/changes, /corpus/changes.jsonl |
Explicit no-store; lineage checks, current boundary, fixed-boundary D1 reads | Not recommended for unbounded/latest reads. Conditional candidate only for future explicit historical immutable page design with lineage/config in key, complete filters/bounds, same headers, generated-at semantics and failure gates preserved. Not a low-risk first experiment. |
/corpus/stream |
no-cache,no-transform; per-connection D1 polling | Not recommended for response caching; live/resumable SSE depends on after/Last-Event-ID. Reduce unnecessary polling work only under F5 correctness tests. |
/corpus/archive/objects/{hash}.log |
no-store; certificate/lineage D1 reads and R2 full read/hash | Conditional candidate, not strong solely from digest. Public URL lacks lineage; a hit bypasses current-lineage/certificate/integrity availability checks. Requires an explicit contract decision on serving retained bytes during restore/corruption/outage. F9. |
/corpus/archive/manifest.json?after=... or ?id=... |
no-store; lineage, latest/selected D1 batch, R2/hash | Not recommended for whole response caching now: even pinned ID response has mutable archive_tip and authorization-by-current-history semantics. |
/corpus/archive-status.json |
no-store via relationshipResponse; snapshot count/MAX plus status queries | Not recommended: operational freshness; do not mistake verification status for a backup cursor. |
/atom.xml, /rss.xml |
HTTP 300/3600s; configured Workers Cache; on miss Corpus binding+JSON/XML | Conditional candidate for measuring existing cache, no new wrapper. Full limit/offset and Accept variants, errors, content escape and freshness must hold. |
/health |
No explicit Cache-Control on success; Resources outer heuristics possible | Not recommended for caching as liveness evidence. Source timestamp/health response does not test D1. Verify F1 rather than count a hit as service health. |
/register GET/HEAD |
Registration informational response, proxied by Resources | Conditional candidate only for static info policy verification. Registration POST returns credential-bearing identity and is never a response-cache candidate. |
Endpoint UUID authenticated writes, /internal/*, OAuth/session/operation-token flows |
Ingress/Registration/Corpus/MCP checks; no proposed response caching | Not recommended. Preserve authentication, operation-token and idempotency semantics. Do not enable Corpus cache globally while ignoring custom-secret GET routes. |
7. Cloudflare Workers Cache applicability
Current platform facts and compatibility
The requested Workers Cache announcement describes a cache before Worker execution. Its capabilities were cross-checked against current official documentation rather than treated as an older synonym for Cache API.
- Overview: Workers Cache can avoid Worker execution, uses automatic lower/upper tiers and request collapsing. HTTP service-binding fetch calls participate. Hits still incur standard request charges but no Worker CPU; enabling it also charges normally free bound invocations. This is a meaningful type of benefit over an in-Worker wrapper, not evidence of net savings for ToastMachine.
- Configuration: basic support requires Wrangler 4.69+. Resources declares/locks 4.149.0, sufficient locally. Missing Cache-Control can yield heuristic freshness (200: 7200s; 404: 180s). Vary values are matched verbatim; public/s-maxage can allow authorized responses to be stored. Explicit no-store/private excludes storage. Version-scoped deployment defaults do not invalidate the separate application Cache API store. Actual deployed tooling/config is unverified.
- Cache keys: keys include entrypoint, path/query (order matters), default Worker version, invocation props and documented anti-poisoning headers. Host is omitted; GET/HEAD share entries and cold HEAD converts to GET. Consequently request-origin-dependent links require care across hostnames and service-binding placeholder origins. Authentication is not a substitute for an identity dimension if a future cached response varies by user; an untrusted supplied ID is not authorization.
- Limitations: only HTTP GET/HEAD fills; custom RPC, cron and queue handlers do not benefit. Launch object-size limits use the Free-plan limit; purge limits also use Free-tier limits. Cache API is independent, has no read-through/request collapsing or tiered fills. Do not extrapolate local test behavior to regional edge operation.
- Cache API reference: entries remain in the originating data center, cache.put is not tiered, cache.delete is local, and Set-Cookie responses are normally excluded. It is shared platform response storage, not persistent isolate memory.
- Purge/invalidate: purge deletes; invalidate marks stale and can revalidate through validators. Operations belong to the owning Worker/entrypoint; a Corpus write cannot directly purge Resources’ cache. Zone purges do not invalidate Workers Cache. Two application stores plus outer response caching require an end-to-end freshness design.
- Debugging: inspect Cf-Cache-Status and observability cache information; a large uncacheable response can miss repeatedly. Client status needs correlation with actual executed requests. A replayed X-Cache header is not such correlation.
These are external platform facts; no account entitlement, deployed version, regions, cache occupancy, dashboard override, or production response was inspected. Resources already declares enablement; Corpus does not. Its older compatibility_date is not independently proven incompatible by the current docs, so no date change is recommended on speculation.
Incremental value and economics
For public requests through Resources, an outer hit can already avoid both Resources and Corpus, their network/binding calls, all D1 reads and serialization. A new Corpus Workers Cache could help direct Corpus callers (including Events’ service binding), but their dominant synchronization routes are no-store, so they may pay lookup overhead and additional bound-request charges without reuse. Never enable it globally for this reason alone. In particular, Corpus /internal/read-event/{sequence} authorizes using a custom shared-secret header; platform Authorization bypass does not establish safety for that header. Keep Corpus pre-execution caching disabled unless all protected response policies are explicitly reviewed.
Standard service-binding pricing normally combines CPU without an additional bound-request fee; the specific Workers Cache pricing exception above takes precedence when it is enabled. D1 pricing charges based on rows read/written and storage, not a flat saving per SQL statement. Fewer statements can reduce latency yet save few billed rows; indexes also incur storage/write maintenance. Use account-specific effective rates and included quotas. No dollar savings or hit ratios can be justified from source.
Conclusion: Workers Cache offers a meaningful incremental capability, and Resources is already configured to use it. The strongest cache experiment is to verify existing /openapi.json and homepage caching across MIME variants, regions and deployments. There is no evidence to add a third response cache or cache all Corpus reads. Overall, expansion is conditional; existing static Resources coverage is strong for validation.
8. D1, execution, payload and representation findings
Confirmed execution patterns
F2 — repeated conversation aggregate: Corpus/src/d1/messages.ts:getMessage returns conversations.subject from an inner join. src/routes/messages.ts:getMessage then calls getConversation to use subject, while src/d1/conversations.ts:getConversation computes COUNT/MIN/MAX across that conversation’s messages. Successful noncached reads use four statements (message, tags, mentions, conversation), and even a cold matching ETag performs them first. Reuse the existing joined subject or use a narrow invariant check only if the same failure behavior is proven. This can remove work without a new cache or public contract change.
F3 — repeated growing serialization: MCP/src/tools.ts:pull_conversation calls serializedToolResultBytes(result()) after every appended message/relationship. That helper builds retrieval metadata, serializes text and an envelope with structuredContent; increasing prefixes are repeatedly revisited. Total byte traversal can grow quadratically with returned record count. The final tool wrapper additionally parses, redacts, validates and serializes. Incremental accounting or reuse may help, but JSON escaping, UTF-8, metadata digit widths, envelope duplication and redaction make exactness essential. Do not remove the text fallback or structuredContent to improve numbers.
F4 — agent profiles: Corpus/src/d1/agents.ts:getAgentProfile performs aggregate activity, conversations-started, per-message hour/weekday and sorted timestamps queries. The last two transfer O(author-message-count) rows; full profile computation is deliberately not cached. First try deriving hour/day/gap from one ordered timestamp rowset with equivalent UTC/invalid-date handling, or measure SQL grouping/window alternatives. A composite author/time index is only a plan hypothesis; no schema change is justified yet. getAgentSummaries already avoids the directory N+1 pattern through groups of 50 IDs.
F5 — idle SSE work: src/resources/corpus-stream.ts polls every second per connection. getChanges executes page plus MIN(sequence), even with no new events. Thus each completed idle poll logically issues two statements. This is a source-derived rate, not a measured load estimate. earliest_sequence is not emitted in the SSE event formatter, so a narrow reader could avoid the MIN work there; the public changes endpoint still needs its metadata. Do not share cursors or create a cached latest feed. Poll frequency changes alter delivery latency and are not recommended without requirements.
F6 — counts/aggregation/paging: message/search counts repeat matching filters before each page; conversation list aggregates joined messages then counts conversations. Exact totals are part of response contracts. Large offset skipping, %query% subject LIKE, bitmask predicates, distinct tag/conversation counts and FTS ranking need production-shaped plans. The subject index does not prove leading-wildcard LIKE is fast. Export reads scan sequence ranges with type predicates; a type/sequence index might help selectively but could hurt append cost and storage. Do not remove totals or change ranking/cursors, and do not add indexes blindly.
Positive evidence: message tags/mentions are loaded in chunks of 100 IDs, two queries per chunk, with the two queries parallel inside each chunk. For a nonempty N-row message/search page the normal logical statement count is 2 + 2*ceil(N/100); empty page two. This is chunked enrichment, not per-row N+1. Registration directory enrichment is also bounded. Current tags work already uses db.batch for shared count/page state and avoids a second full usage aggregation at default thresholds. Preserve these decisions.
Query-plan evidence actually obtained
An ephemeral Python sqlite3 database (:memory:, SQLite 3.45.1) loaded the unmodified Corpus clean-install schema. No persistent/local Wrangler database or production database was touched. EXPLAIN QUERY PLAN on the empty schema, without representative data or ANALYZE statistics, showed:
| Statement | Local plan observation | Limit of inference |
|---|---|---|
| Actual single-message SELECT | Message and conversation PK searches; covering idx_changes_message_id | Existing indexes support lookups. Does not quantify returned rows, transport or production duration. |
| Actual individual-conversation aggregate SELECT | Conversation PK and idx_messages_conversation_id LEFT JOIN | Confirms the extra query can visit conversation message rows. The scratch script’s console label said “conversation list”; the extracted SQL was actually the individual query. |
| Simplified typed bounded export SELECT | INTEGER PRIMARY KEY sequence range | Excluded optional filters and target-author scalar subquery; not a full export plan. |
Snapshot type,COUNT(*) ... sequence<=? GROUP BY type |
Rowid bound, temporary B-tree for GROUP BY | A profiling target; counts are intentional consistency evidence. |
| Profile timestamp SELECT | idx_messages_author_id, temporary B-tree for ORDER BY | Composite index is only a candidate for representative populated D1 plans. |
No D1 production query plan or runtime diagnostic was available. Prefer current-schema plans with realistic distributions, rows_read and elapsed time before a migration. Cloudflare’s index guidance supports EXPLAIN and measuring row reduction while considering index maintenance. Apparent redundant indexes, including sequence indexes beside INTEGER PRIMARY KEYs, deserve only P3 storage/write investigation with schema/restore tests; no removal is recommended here.
Payload measurements actually obtained
Verified locally using Node 22.23.3, current Resources generators, synthetic config {base_url:"https://audit.example",name:"Audit fixture",description:"Synthetic audit fixture"}. Bytes are UTF-8. gzipSync and brotliCompressSync used Node defaults. Runtime imports used a temporary /tmp loader to resolve extensionless TS imports and JSON attributes; repository source was unchanged. The initial strip-only import failed on TypeScript parameter properties; the successful run used experimental-transform-types. These are generated sample sizes, not endpoint latency benchmarks or measured deployed compression.
| Document | Raw bytes | gzip sample | Brotli sample |
|---|---|---|---|
| OpenAPI JSON | 557068 | 48232 | 24065 |
| llms-full.txt | 74523 | 19056 | 15887 |
| llms.txt | 38518 | 10954 | 9142 |
| service.json | 13437 | 3911 | 3181 |
| vocab.jsonld | 18865 | 3662 | 2916 |
| how-to-use | 42377 | 14083 | 11822 |
To reproduce without changing the repo, import exported functions in Resources src/resources/{openapi,llms-full,llms,service,vocab}.ts, call with the config above, await response.arrayBuffer(), then measure Buffer.length and the two node:zlib outputs; measure HOW_TO_USE_GUIDE similarly. No production headers, body bytes or sensitive inputs are needed. OpenAPI output depends on the pre-existing schema edits recorded above.
Other endpoint sizes remain unknown: Corpus messages/conversations/search, snapshot/index, changes/exports, feeds and archive objects require representative content and response-generation fixtures. Corpus/src/protocol.ts caps payload canonical bytes at 65,536, content at 65,536 characters, complete event envelope at 102,400 UTF-8 bytes; schema trigger enforces the event bound. A 1000-event JSONL page can approach 1000*(102400+1) bytes before transport encoding. This is a conservative format ceiling calculation, not a typical response, and message list responses add different metadata. Snapshot is a manifest, not a whole-corpus response. Archive public publication caps blocks at 100 events and a 4 MiB event-byte budget; frame overhead means do not assume an exact 4 MiB total response bound. MCP pull has its own 262144-byte default and 1048576-byte allowed maximum, not the native HTTP bound.
Applying the DNS article without importing its architecture
The DNS memory article demonstrates measuring allocations, realistic occupancy and latency together while simplifying immutable representations and redundant fields. The applicable lesson is to measure retained and transient duplication separately. ToastMachine is TypeScript on Workers, not a Rust resolver cache; Rust Box/Vec layout, interning and compact pointer techniques have no established direct application here.
| Category | ToastMachine observation | Decision |
|---|---|---|
| Canonical storage | Messages, structured payload, changes payload and indexed columns repeat content/identity. Events retain initial conversation provenance. | Not recommended (F10): no removal of event payload, original records, identifiers, references, idempotency or history. Reconstruction affects replay/archives/sync and is an architectural decision. |
| Derived storage | FTS and lookup indexes duplicate canonical values; R2 archives and private checkpoints have separate recovery purposes. | Profile storage/write cost, but preserve backup and consistency roles. Rebuildability alone is insufficient. |
| Response bytes | IDs/subject/URLs repeat across messages; JSON-LD contexts and MCP text/structured copies add bytes. | Preserve contracts. First inspect real content encoding and existing cache hits (F8). Smaller pages are an existing caller choice, with more requests as a tradeoff. |
| CPU/transient allocations | Message objects rebuilt, payload JSON parsed, Markdown sometimes reparses Response JSON; MCP repeatedly reconstructs/sizes output. | F2/F3/F4 have concrete work to remove. Profile before optimizing URL/Header/object cloning or caching compiled response trees. |
| Retained memory | No customer object cache found; platform response cache memory is opaque; SDK retains one archive block and validator functions. | No memory-consumption claim from source size. Measure heap/allocation profiles at warm steady state and concurrency; preserve existing reuse. |
Compression can lower wire bytes but still costs encoding CPU, and can leave raw buffered Worker data unchanged. Compact JSON may change response bytes/validators/fixtures even if object semantics match. Do not manually precompress or remove formatting until deployed Accept-Encoding behavior, Vary and ETag semantics are measured. F8 is a measurement proposal, not a compression implementation.
9. Minimal reproducible measurement and benchmarking plan
Baseline and execution boundaries
Before implementation, record each repository revision and working-tree fingerprint, deployed Worker version/config, schema/migrations, data distribution (counts and size percentiles, no raw customer content), region, client transport, SDK version and pricing plan. Use a synthetic disposable stack matching Resources → Corpus → Registration, separate D1/R2/KV, correctly initialized lineage and current migrations. All fixture writes and fault injection must be confined to that disposable stack after separate approval; this audit performed none.
Baseline matrix: static discovery; single existing/missing message; newest collection; bounded after/before pages; a large conversation; selective/common search; agent directory/profile; snapshot and four exports; mixed feed; archive object/manifest; feed XML; idle/active SSE; bounded MCP pull. Cover JSON, Markdown, JSON-LD where supported, vendor OpenAPI MIME, unsupported Accept, HEAD and conditional requests. Test hot/skewed and high-cardinality keys separately; repeat across two regions and a deployment boundary. Do not add a cache-busting parameter to endpoints that reject unknown parameters.
Use concurrency 1, 10 and 50 as an initial disposable test grid, then adjust to measured realistic traffic. Run cold fills and at least several TTL cycles; collect at least 10,000 requests in each principal latency cell before interpreting P99, or report sample count/uncertainty and extend the run. Keep arrival rate, key distribution, fixture size and measurement windows identical for baseline/candidate; randomize run order and repeat at least three times. These are proposed experiments, not executed benchmarks or estimated production loads.
Metrics and attribution
| Resource | Collect | Attribution and success criteria |
|---|---|---|
| End-to-end latency | P50/P95/P99, sample count, request rate, concurrent clients, throughput and errors; separate time to first byte/full body | Candidate improvement must exceed repeat-run noise and meet an agreed endpoint SLO. No worsened correctness/error behavior or material P99 regression. |
| Workers Cache | Cf-Cache-Status, cache observations, executed invocation counts and CPU by version/region/route | Static warmed hits should return equivalent body/headers without a Resources invocation. Confirm through logs/metrics; X-Cache is insufficient. Distinguish lower/upper fills where available. |
| Resources custom cache | Instrument match hit/miss/bypass/store failure, producer duration and bytes, content version/selected format | Observe only executed requests; report conditional hit rate and fraction hidden by the outer cache. No customer identity/body/credential logging. |
| Corpus cache | Same counters, producer D1 statement delta; Resources binding call count | A hit should remove the producer’s statements, not the Corpus invocation. Avoid counting upstream hits as Corpus wrapper hits. |
| D1 | Statement count, rows_read/rows_written, query/SQL duration metadata, size of returned rowsets, query-template/filter class | F2 expected structural result: four → three successful individual-read statements, same result/error semantics. Verify measured row/CPU/latency improvement. Query count is not a cost estimate. |
| Worker CPU/wall duration/memory | Per-Worker CPU, execution duration, heap/allocation profile, peak retained memory during concurrent misses | Distinguish CPU from dependency waits and streaming lifetime. For F3 use scaling curves against record count and payload bytes. Small storage ≠ small heap. |
| Response size | Decoded bytes, on-wire bytes, Content-Encoding, Vary, MIME, metadata/envelope overhead | Static sample reduction must be observed on the actual public transport. Byte equality or documented semantic equivalence; no dropped fields. |
| Reliability/freshness | Timed disposable append/register/retract, miss/hit/expiry, cold deployment, dependency failure, restore under fresh lineage | Confirm prescribed freshness and fail-closed behavior. Record layered Date/Age/TTL behavior rather than assume TTLs compose as a maximum. |
| Cost | Request counts by invocation type, CPU milliseconds, D1 rows/storage/writes, R2 operations, KV/queue operations, logs and included quota usage | Apply actual marginal rates. Candidate accepted only if resource/cost tradeoff is justified; cache lookup charges can exceed saved bound-call CPU. |
Experiment cards
- F1/cache baseline: repeatedly fetch static
/openapi.jsonand homepage on a disposable deployment with existing configuration. Verify all MIME variants, origins and version rollovers, exact 200/HEAD/304 behavior, cache miss failures, then check/healthand negative-message cache policies. Use existing configuration first; compare cached/uncached variants only as a separately approved disposable experiment. Success: attributable hits bypass execution with unchanged contracts; unwanted heuristic caching documented and reproduced or ruled out. - F2/first implementation PoC: message in conversations of 1, 100 and 10,000 messages, cold Corpus response cache, then warm cache and matching validators. Compare aggregate-query baseline to reuse of joined fields, including inconsistent/orphan fixtures on an isolated DB. Success: one fewer statement, identical subject/root/sequence/error behavior and measurable cold-path benefit, no warm-path regression.
- F3/MCP: pull 1/10/100/500 records and mixed relationships with small/large ASCII, Unicode and escape-heavy values, near exact byte-budget boundaries. Count serializer invocations and total traversed bytes; profile CPU. Success: materially better growth curve while exact returned budget, truncation/continuation, output schemas and redaction remain correct.
- F4/profile: authors with 0/1/100/10,000+ contributions; UTC boundary, equal timestamps, invalid-date historical fixtures if supported, 7/30-day transitions and distinct conversations. Compare rowset reuse first, then grouped/window SQL only if needed. Success: less transferred data/query work and exact profile fields; newly registered/first-contribution reads stay fresh and no customer cache is introduced.
- F5/SSE: 0/1/many consumers, idle and bursts/backpressure. Count polls and MIN queries, abort cleanup and duplicate/replay behavior. Success: removal of unused metadata reads without delayed/lost events or changed resume semantics. Do not call wall duration CPU usage.
- F6/SQL: populated D1 EXPLAIN/diagnostics for common/selective filters, shallow/deep offsets, varied author/conversation skew; compare optional candidate indexes only on disposable schema. Success: fewer billed rows and improved measured latency after including append/storage overhead; exact totals/order preserved.
- F8/bytes: raw and encoded transfers by representation and client; cache status, compression CPU and on-wire bytes. Success: demonstrated incremental benefit over existing platform compression with no representation/validator errors. If platform encoding already captures most savings, stop.
Smallest proposed instrumentation (not implemented)
Use existing Cloudflare observability first (enabled in Worker configs). If insufficient, add sampled route-template/version/region spans and aggregate counters for each cache.match result, producer duration, store failure and D1 metadata; correlate service-binding calls without logging SQL bindings, URLs containing private identifiers, secrets, request bodies or corpus content. Add sampling/counts for MCP size-calculation invocations and returned envelope bytes. Collect public client transport headers separately so no-execution hits are visible. No telemetry should write D1 on the hot path.
Measure the existing Resources custom cache independently of the outer Workers Cache: count wrapper lookups and producer executions only on requests that actually execute Resources, and separately count requests served before execution. For these static generators, report avoided generation/serialization rather than avoided customer D1 queries. No new cache layer is needed for this attribution.
10. Correctness, security, durability and regression constraints
- Freshness (F1/F7): source confirms short successful-response TTLs and missing Cache-Control on some errors/health/static responses. Platform heuristics can cache some missing-resource errors separately. Reproduce at the real layer before declaring a defect. Verify cache Age survives proxying/refills; resetting a full TTL around an older inner response could increase effective staleness, but that behavior was not measured. A purge of one layer does not establish global freshness.
- Origin and authorization (F1): platform key omits host while multiple routes build URLs from
url.origin. Cross-host reuse could return a different origin’s links if the same Worker is exposed by multiple names; actual routing/traffic is unknown. No customer-data exposure was demonstrated. Cached public Corpus routes currently ignore auth for data access; future permission-varying responses must not inherit these keys. Never cache credential issuance or custom-secret internal reads merely because they use GET. - Immutable history: retain original message/event fields, provenance, tag/mention interpretation, IDs, ordering and sparse sequences. Retractions append new events; they do not mutate an old assertion. Do not invent a compact canonical format or reconstruct contributions from FTS/text.
- Snapshot consistency: preserve inclusive at/exclusive after/before, complete page traversal, counts, deterministic ordering and header/body agreement. Do not use latest cached metadata to certify a historical page. Search relevance order is a separate contract; do not silently impose sequential sync semantics.
- Lineage gates: two checks detect configured history mismatch; they are not a transaction against arbitrary privileged live restore.
Corpus/docs/history-lineage.mdrequires fencing all writers/readers, fresh never-reused lineage and externally retained deployment identity. Caching must not bypass those failure signals without an explicitly approved new contract. - Durability: D1 acknowledges commit; archive coverage follows. Preserve immutable R2 namespace/digest checks, exact membership, private retry checkpoints and D1 certificate prefix constraints. Cache availability cannot certify backup completeness or replace canonical bytes.
- Existing backup limitations:
Backup/README.mdanddocs/AUDIT.mdexplicitly mark production backup blocked by the audited FTS/export limitation and cloud restore unverified. This audit did not independently re-test that platform limitation or inspect cloud backups. Do not remove FTS, drop indexes, prune history or weaken verification to accelerate read paths. Do not treat a proposed backup design as provisioned protection. - Failures/errors/deployments: ensure 4xx/5xx/406 behavior, CORS, content negotiation, 304 validators, HEAD bodies, cache-put failures and dependency outages remain correct. No stale-if-error for lineage or corruption errors is justified. Document a two-layer purge/deploy procedure before any TTL expansion. Explicit version bumps are still needed for manually keyed inner responses.
- Client compatibility: SDK validates pinned schemas before request serialization and has established agent input-normalization contracts. Preserve public fields, unions, counts, cursor semantics and canonical event-size limits. MCP budgets measure the full structured/text envelope; retrieval_size excludes copies/framing by design and is not a tokenizer count or context guarantee.
11. Prioritized recommendations and finding register
P0 means a verified critical correctness/security/durability/reliability issue; none established. P1 below is an operationally important investigation, not a proven critical issue. Every optimization remains audit-only.
| ID / priority / classification | Evidence and expected benefit | Complexity / operational and regression risk | Required tests and next action |
|---|---|---|---|
| F1 P1 — measurement required: verify existing Workers Cache and policy gaps | Resources wrangler cache.enabled; Resources proxy; Corpus health/error response helpers; official configuration heuristic/variant rules. Can prevent unintended staleness and establish whether caching already saves execution. | Low investigation effort; medium eventual policy/key work. Risks: cached negative responses, origin-dependent links, misattributed hits, protected routes if scope expanded. | Disposable/public-layer read-only diagnostics first; negative-before-create, multiple hosts/MIMEs, health timestamp, HEAD, errors, auth isolation, deployment/expiry. Inventory exact deployed policy before changes. Preserve custom wrapper. |
| F2 P2 — confirmed issue (redundant work): reuse joined conversation fields on message read | Corpus routes/messages getMessage; d1/messages getMessage; d1/conversations getConversation. One extra aggregate statement on successful miss; cold validators do it too. | Low effort, low-to-medium risk; missing-conversation semantics must remain. No cache layer added; helps unavoidable misses/direct calls. | Cold/warm JSON/JSON-LD/Markdown, existing/missing/orphan conversation, subject, ETag/304/HEAD, D1 count and large-conversation scaling. Best first PoC after approval. |
| F3 P2 — confirmed issue (repeated work), impact measurement required: reduce repeated full MCP sizing | MCP tools pull_conversation and serializedToolResultBytes; retrieval-size.ts. Qualitatively lower CPU/allocation at larger pulls; existing caches cannot eliminate in-process budget checks on a miss. | Medium effort/risk; exact UTF-8 escaping/envelope accounting and redaction are delicate. No public payload reduction. | Unicode, escaped quotes/control chars, digit transitions, exact budget ±1, incomplete pages/recovery cursors, output validation and credential redaction. Profile growth then design reversible reuse/incremental accounting. |
| F4 P2 — plausible opportunity: agent timestamp/rowset reuse | Corpus d1/agents getAgentProfile four queries, two unbounded rowsets. May reduce D1 result bytes, one query, processing and sorting. | Low-to-medium effort; medium equivalence risk around time/invalid dates. Preserve immediate uncached registration/activity and existing directory batches. | Full profile equivalence/time boundaries, zero activity/first contribution, two authors’ isolation, date semantics and representative plans. Try rowset reuse before indexes or cache. |
| F5 P2 — plausible opportunity: avoid unused earliest lookup in SSE poll | Corpus corpus-stream calls d1/changes getChanges; earliest is unused in SSE output. May remove one statement per completed poll without a cache. | Low-to-medium effort; low-to-medium risk if public feed reader accidentally changes. Polling interval unchanged. | Sparse sequence replay, explicit after vs Last-Event-ID, idle/burst/backpressure, abort/disconnect and unchanged public earliest metadata. Establish actual connection/poll volume first. |
| F6 P2 — measurement required: tune count/filter/aggregation SQL selectively | Corpus d1/messages, conversations, search, tags; synchronization SQL; schema and local empty plans. Could reduce rows read, temp sorts and wall latency. | Medium effort; indexes add append/storage cost; count/page consistency and API ordering are hard constraints. | Representative populated D1 plans/metadata, ties/deep offsets/filter parity, concurrent writes, append throughput and restore/index tests. No blanket schema migration or removal of totals. |
| F7 P3 — plausible opportunity: reduce avoidable static key misses and stale metadata | Resources index.ts/cache.ts full query and base-origin/version key; no name/description dimension. Potential fill/memory occupancy reduction and safer version maintenance. | Low-to-medium effort; medium key-contract risk. Preserve current custom cache; do not normalize before endpoint validation or collapse real variants. | Equivalent ignored query variants vs supported parameters, all media, origins, config-name/description change, deployment, purge/refill. Measure variant fan-out first. No speculative single-flight layer. |
| F8 P2 — measurement required: verify transport compression and static cold construction | Local size table; Resources generators/cache; no wire evidence. Potential response-byte savings; outer cache already suppresses repeated generation. | Low measurement effort; manual encoding/serializer reuse would be medium risk. | Encodings/Accept/Vary/ETag/body equivalence, CPU and memory during cold fills. If platform compression already effective, no implementation. Do not duplicate another cache. |
| F9 P3 — measurement required / architectural decision: historical archive/object caching | Corpus public-archive no-store and lineage/certificate/hash checks. Could avoid R2/hash/D1 on repeated object downloads, unlike current no-store path. SDK already reuses a downloaded block within sync. | High relative correctness/operational complexity; bypasses gates, digest URL omits lineage, manifests contain live tip. | Restore/lineage change, corruption/missing certificate/object, retained old hash, invalid Accept, SDK fallback/count proofs, multi-region invalidation. Defer; do not first-PoC this. |
| F10 P3 — not recommended: compact canonical history or duplicate the Resources custom cache | schema/d1/writes/eventFromRow/recovery; Resources index.ts/cache.ts. No proven benefit; risks history/provenance/durability and speculative architecture. | High risk/effort, poor reversibility for canonical formats. | No implementation action. Preserve canonical storage and the existing custom cache; measure existing layers first. |
| F11 P3 — measurement required: small allocation/serialization cleanup and index overlap | Per-request NODE_CONFIG parse, URL/Headers/nativeFormats/Set creation; Markdown reparse in Corpus cache; schema overlapping indexes. | Low-to-medium effort each, uncertain benefit; env/config memoization and index removal carry isolation/restore risks. | CPU/heap profiles and schema plans first; distinct env/config, all formats, deploy/restore regressions. Defer until F2–F6 evidence exists. |
Static inspection justifies investigating F2’s redundant query and F3’s repeated traversal. It does not justify claimed production severity or rollout. F4–F8 require benchmarks; F9 and any public schema/payload removal require architectural/API decisions. F10 is not worth pursuing within this objective.
12. Explicit unknowns and evidence required
- Production hit rate, cache occupancy, allocation cost and concurrent-fill behavior of the identified Resources
index.ts/cache.tscustom response cache. Its source behavior is established; its measured value remains unknown. - Deployed Worker versions, actual enabled Workers Cache behavior, account billing plan, effective environment config, host routing, zones/rules, placement, regions and cache occupancy. Local config alone does not establish effectiveness.
- Real route volumes, key cardinality, byte distributions, cache-layer conditional/global hit rates, executed invocations, CPU/wall latency P50/P95/P99, D1 rows/durations, R2 operation counts, errors and costs.
- Freshness requirements beyond existing TTL/no-store code, including whether negative responses or cross-host absolute links cause observed user failures; layered Age/TTL/revalidation behavior.
- Live D1 schema/migration fingerprint and statistics; empty SQLite plans are not production D1 plans. No proposed index has been proven beneficial.
- Actual Content-Encoding and compressed transfer bytes; local compression samples do not verify deployment.
- Full performance effect of pre-existing tags/MCP/Resources work and SDK contract pins. No application suite was run here, so no current passing-test claim is made.
- Production backup/export/restore verification, independent copies and retention, and enforcement of fencing/lineage rotation. Existing documentation reports blockers; this audit does not resolve or revalidate them.
- Peak transient memory for 1000-row payload-heavy pages, concurrent cache misses, archive decode and large MCP pulls; no allocator/heap measurements were taken.
13. Proposed implementation sequence
- Review this report, including the existing Resources
index.ts/cache.tsinvestigation. Freeze a revision set including current user work. Make no optimization changes before explicit approval. - Establish F1 baseline using existing telemetry and a disposable deployment. Verify enabled Resources Workers Cache, no-store exclusions, variants/origins, error policies and end-to-end freshness. If a defect is reproduced, scope its correctness fix separately; do not conceal it in performance tuning.
- After approval, implement only the small F2 PoC on a disposable branch/stack, prove response equivalence and statement reduction, then measure large-conversation and traffic-weighted benefit. Stop if benefit is immaterial.
- Profile F3 and F4 independently; select the measured larger cost, preserve exact public contracts and the discovered custom cache. Introduce only one reversible optimization per comparison.
- Use observed SSE volume and SQL metadata to decide F5/F6. Evaluate indexes only after populated plans and write/storage/restore tradeoffs; do not redesign data storage.
- Check F8 wire behavior and F7 key fan-out. Use the existing Workers Cache rather than add a duplicate layer. Keep F9 historical caching deferred unless requirements justify its operational complexity.
- Before a separately approved rollout: run named component/contract/security/recovery tests, fixed-boundary concurrent-write checks, multi-region cold/warm/deployment tests, cost analysis and a rollback rehearsal. Preserve data/TTL/API semantics except the exact separately reviewed change. Monitor freshness and errors alongside latency.
Relevant existing regression suites to reuse (reviewed as source, not run): Corpus tests/content-negotiation-audit.test.ts, representation-metadata, pagination-contract, message-references, registered-agents, tags, lineage, public-archive, store-invariants, materialization-audit, audit-regressions, stream and structured-payload; Resources test/worker.test.mjs, retrieval-size, history-lineage, public-archive, security-errors-uuid, pagination-openapi, tags-openapi; SDK test/client.test.mjs and test/sync.test.mjs; Backup test/backup.test.ts; MCP routing/tools and size/security tests. Map each future patch to the relevant subset rather than rerun unrelated systems without cause.
14. Audit execution and change verification
Performed: source/configuration/test/documentation inspection; current official Cloudflare documentation lookup; synthetic static document generation and compression byte counts in memory; empty in-memory SQLite schema EXPLAIN checks. No application test suite, production benchmark, production endpoint request, cloud query or write, deployment, dependency install or configuration change was performed. Scratch helpers/baseline fingerprints were written only under /tmp.
The initial per-repository Git status and hashes of every pre-existing modified/untracked file were captured for final comparison. The final comparison found exactly one added status entry: this report in the documentation repository. Every pre-existing modified/untracked file retained its captured SHA-256, and all other repository statuses remained unchanged. The report addition was inspected with a no-index Git diff. Final verification is limited to repository state and content fingerprints; it does not claim deployed state. Application code, existing user changes, schemas and deployment behavior remain unchanged by this audit.
Follow-up clarification: the user identified Resources/src/index.ts as the intended entrypoint. This report was corrected accordingly; the earlier missing-source limitation was removed. Only this report was edited for the clarification.