soma.cell

W0016: budget_advisory

W0016 budget_advisory — a memory budget whose proof is incomplete.

A warning of soma check, the checker of the Soma programming language (soma explain W0016).

The rule

When a cell declares a memory budget (scale { memory: "128Mi" }), soma check tries to prove the cell's peak memory stays under it; W0016 is the advisory it prints when a handler allocates something with no static bound, so the proof is incomplete. It names each such call site, here http_get, whose response size is not bounded. Bound the allocation, here with the max_bytes option (http_get(url, map("max_bytes", 65536))), and check then reports that the budget holds.

A program that triggers it

wrong.cell

cell RateFeed {
    memory {
        fetched: Map<String, Int> [persistent, capacity(200)]
    }
    on refresh(currency: String) {
        let reply = http_get("https://api.example.com/rates/{currency}")
        fetched.set(currency, now())
        return reply
    }
    scale {
        replicas: 1
        memory: "128Mi"
    }
}

What soma check prints:

$ soma check wrong.cell
advisory: cell 'RateFeed' declares budget 128.00 MiB; bounded portion is 16.84 MiB, but these handler allocations have no bound, so the proof is incomplete:
      → http_get at call site — HTTP response size is not statically bounded
✓ 1 warning(s), no errors.

The fix field of soma check --json: Review and address the reported warning.

On line 6, let reply = http_get("https://api.example.com/rates/{currency}") becomes let reply = http_get("https://api.example.com/rates/{currency}", map("max_bytes", 65536)).

wrong.cell → right.cell

--- wrong.cell
+++ right.cell
@@ -4,5 +4,5 @@
     }
     on refresh(currency: String) {
-        let reply = http_get("https://api.example.com/rates/{currency}")
+        let reply = http_get("https://api.example.com/rates/{currency}", map("max_bytes", 65536))
         fetched.set(currency, now())
         return reply

With the fix, soma check accepts the program:

$ soma check right.cell
✓ budget holds for cell 'RateFeed' while its slots stay within their assumed sizes: peak ≤ 24.91 MiB ≤ declared 128.00 MiB
    breakdown: slots 862.50 KiB + max-handler 8.06 MiB + state 0 B + runtime 16.00 MiB
    assumed: each slot within [capacity(N)] / [max_key_bytes(N)] / [max_value_bytes(N)] (else 10 000 entries of 256-byte keys and 4 KiB values) — not enforced at run time
✓ All checks passed (1 note above).