Expand description
The placement cost model — §3.4’s node costs, edge costs and byte estimates.
docs/03-type-and-effect-system.md §3.4:
Node costs: ∞ for forbidden tiers; tier-specific compute cost otherwise (client CPU is expensive and untrusted; fold-engine compute is cheap and adjacent to state). Edge costs: for each signal edge or call that crosses tiers,
latency + bytes × unit, bytes estimated from row types.
Everything here is an integer. Not for speed — the graphs are tiny — but because §3.4’s
first guardrail is determinism, and a cost model in floating point makes “these two placements
cost the same” a question about rounding. Costs are in hundredths of a notional millisecond, so
a latency of 25 ms is 2_500.
§The numbers, and where they come from
They are not measured; they are ordered, and the ordering is what a placement decision reads. Every one is a ratio the design already states, so the model can be argued with rather than tuned in the dark:
| quantity | value | from |
|---|---|---|
| compute weight, data | 1 | “fold-engine compute is cheap and adjacent to state” (§3.4) |
| compute weight, server | 2 | the middle |
| compute weight, client | 8 | “client CPU is expensive and untrusted” (§3.4) |
| latency, data ↔ server | 1 ms | same pod network |
| latency, server ↔ client | 25 ms | Phase 0’s realistic RTT (18) |
| latency, data ↔ client | 26 ms | it goes through the server |
| bytes → cost | ×5 per byte | so a 2 KB crossing (~100 ms) outweighs an RTT, which is the |
| trade a placement decision is actually making |
There is no constant for “a fold that is not at the data tier”. node_cost charges such a
fold an edge to the log, sized from the accumulator, because that is what it physically pays:
the log is at the data tier, and an accumulator kept elsewhere crosses to it on every event. A
constant would have been a number to tune; an edge is a number to derive.
§The one rule worth arguing with
A crossing is charged the smaller of its two endpoints’ values, and that is not a
simplification — it is §5.1’s Mode A/B question, expressed as a cost instead of as a mode.
Between a Signal[State] at the data tier and a Signal[Html] at the browser, the compiler may
either send the state and render in the browser (Mode B: 2 KB of data patches) or render first
and send the document (Mode A: 1 KB of DOM patches). It will pick the cheaper, so the cheaper is
what the boundary costs. Phase 2 only implements Mode A, so today the minimum is a prediction
rather than a choice — and it is the right prediction to be making when Phase 3 makes the choice
real.
Constants§
- ASSUMED_
CARDINALITY - How many elements a collection is assumed to hold when nothing says otherwise.
- BYTE_
UNIT - The cost of moving one byte across a tier boundary.
- FORBIDDEN
- A placement that cannot be, kept finite so that sums never overflow and comparisons stay total.
Functions§
- compute_
weight - §3.4: “client CPU is expensive and untrusted; fold-engine compute is cheap and adjacent to state”.
- edge_
cost - The cost of an edge between two placed nodes.
- estimate_
bytes - Estimate the wire size of a value of this type — §3.4’s “bytes estimated from row types”.
- latency
- Round-trip latency between two tiers, in hundredths of a millisecond.
- node_
cost - The node cost of putting
rowontier, given how much work the node does and — for a durable fold — what its accumulator looks like.
Type Aliases§
- Cost
- Costs are in hundredths of a millisecond.