economics: spec and CLI docs record the #288 landing; backhaul meters never count as usage (#288 round 2)
The spec's 'ships dormant' paragraph and docs/site/cli.md now state what shipped. PriceAccount's one generic meter walk (anyUsage, and its JS twin) skips the backhaul meters, so the identity test can pin the real invariant with an all-zero base. Zero-rate hint on the model row, one sumMeter for the row, usage text reflowed, printer param named w.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
7 files changed,
+54
−16
docs/site/cli.md+9 −0docs/superpowers/specs/2026-08-20-multi-region-ingress-design.md+11 −0economics.go+10 −9internal/console/economicsbackhaul_test.go+7 −0internal/console/templates/economics.html+7 −4internal/economics/compute.go+7 −1internal/usage/usage.go+3 −2
diff --git a/docs/site/cli.md b/docs/site/cli.md| index ee9a45caf..eb1fac4f1 100644 |
| --- a/docs/site/cli.md |
| +++ b/docs/site/cli.md |
| @@ -617,6 +617,15 @@ Operator only, and the console answers everyone else with the same bare 404 |
| it gives an unknown route. A "not found" here almost always means your |
| account lacks the fleet-operator bit, not that you typed the path wrong. |
| +`carlos economics backhaul` shows what serving through region edges costs |
| +the platform this period: the part of each account's egress that was |
| +backhauled from its home box, priced at the rate card's inter-region |
| +$/GB and absorbed — it appears in nobody's bill. |
| + |
| +```sh |
| +carlos economics backhaul -period mtd |
| +``` |
| + |
| ### carlos status |
| `-live` prints what every box in the fleet last reported about itself: |
diff --git a/docs/superpowers/specs/2026-08-20-multi-region-ingress-design.md b/docs/superpowers/specs/2026-08-20-multi-region-ingress-design.md| index e4d111856..70efa2bd9 100644 |
| --- a/docs/superpowers/specs/2026-08-20-multi-region-ingress-design.md |
| +++ b/docs/superpowers/specs/2026-08-20-multi-region-ingress-design.md |
| @@ -391,6 +391,17 @@ decision (price backhauled bytes, or absorb them as a platform cost of |
| any-edge serving) can be made later on real data. Default taken tonight: |
| **absorbed**. |
| +*Amendment 2026-08-26 (#284 ruled, #288 built).* Paul's ruling: absorb, |
| +keep the data on what it costs us. The counters are no longer dormant: |
| +the usage sweep folds the hop subset into `backhaul_gb` and |
| +`backhaul_requests_1k`, which ride in every account statement as data; |
| +`RateCard.InterRegionGBUSD` prices the extra home→edge leg (the home |
| +box's metered bytes are already egress) as a model line on the |
| +economics page, in the model total and in NO account's cost, revenue or |
| +bill — `PriceAccount` ignores both meters, pinned by test. Read via the |
| +economics pages, `GET /api/economics/backhaul` and `carlos economics |
| +backhaul`. |
| + |
| *Rollout.* Must be rolled to every box of a deployment BEFORE that |
| deployment arms a second edge — the home box needs the new binary to |
| annotate hops, the senders need the cap. It slots ahead of the steering |
diff --git a/economics.go b/economics.go| index 982362921..9c99ecb61 100644 |
| --- a/economics.go |
| +++ b/economics.go |
| @@ -146,8 +146,9 @@ Shows what serving through region edges costs the platform this period: |
| the part of every account's egress that was backhauled from its home box |
| (usage.EdgeRow's hop subset — inside the egress totals, never on top), |
| priced at the rate card's inter-region $/GB (the extra leg; the home box's |
| -bytes are already egress) and ABSORBED — it is in nobody's bill (#284). Operator only; a non-operator's token gets the same bare 404 |
| -an unknown route gets. |
| +bytes are already egress) and ABSORBED — it is in nobody's bill (#284). |
| +Operator only; a non-operator's token gets the same bare 404 an unknown |
| +route gets. |
| ` |
| type backhaulReport struct { |
| @@ -218,19 +219,19 @@ func runEconomicsBackhaul(args []string) { |
| printBackhaulReport(stdout, rep) |
| } |
| -func printBackhaulReport(stdout io.Writer, rep backhaulReport) { |
| - fmt.Fprintf(stdout, "backhaul %s (%d/%d days covered): %.2f GB of %.2f GB egress (%.1f%%), %.1fk requests — inter-region leg ≈ $%.2f at $%.3f/GB, absorbed\n", |
| +func printBackhaulReport(w io.Writer, rep backhaulReport) { |
| + fmt.Fprintf(w, "backhaul %s (%d/%d days covered): %.2f GB of %.2f GB egress (%.1f%%), %.1fk requests — inter-region leg ≈ $%.2f at $%.3f/GB, absorbed\n", |
| rep.Period, rep.CoveredDays, rep.PeriodDays, rep.BackhaulGB, rep.EgressGB, rep.ShareOfEgress*100, rep.BackhaulReq1k, rep.AbsorbedUSD, rep.InterRegionGBUSD) |
| if len(rep.Accounts) == 0 { |
| - fmt.Fprintln(stdout, "no account backhauled anything this period") |
| + fmt.Fprintln(w, "no account backhauled anything this period") |
| return |
| } |
| - w := newTable(stdout) |
| - fmt.Fprintln(w, "ACCOUNT\tNAME\tEGRESS GB\tBACKHAUL GB\tSHARE\tREQ (k)\tABSORBED") |
| + tw := newTable(w) |
| + fmt.Fprintln(tw, "ACCOUNT\tNAME\tEGRESS GB\tBACKHAUL GB\tSHARE\tREQ (k)\tABSORBED") |
| for _, a := range rep.Accounts { |
| - fmt.Fprintf(w, "%s\t%s\t%.2f\t%.2f\t%.1f%%\t%.1f\t$%.2f\n", a.Account, a.Name, a.EgressGB, a.BackhaulGB, a.ShareOfEgress*100, a.BackhaulReq1k, a.AbsorbedUSD) |
| + fmt.Fprintf(tw, "%s\t%s\t%.2f\t%.2f\t%.1f%%\t%.1f\t$%.2f\n", a.Account, a.Name, a.EgressGB, a.BackhaulGB, a.ShareOfEgress*100, a.BackhaulReq1k, a.AbsorbedUSD) |
| } |
| - w.Flush() |
| + tw.Flush() |
| } |
| // economicsBillResult mirrors handleAPIEconomicsBill's success shape: the |
diff --git a/internal/console/economicsbackhaul_test.go b/internal/console/economicsbackhaul_test.go| index e158d5a11..1f54633ff 100644 |
| --- a/internal/console/economicsbackhaul_test.go |
| +++ b/internal/console/economicsbackhaul_test.go |
| @@ -106,4 +106,11 @@ func TestBackhaulMetersNeverPriceAnAccount(t *testing.T) { |
| if a != b { |
| t.Fatalf("backhaul meters changed an account's price:\n%+v\n%+v", a, b) |
| } |
| + // And with nothing else metered: the meters must not even count as |
| + // usage (FreeTierPos), the one generic meter walk PriceAccount has. |
| + none := economics.PriceAccount(sc, "bab", map[string]float64{}, 0) |
| + only := economics.PriceAccount(sc, "bab", map[string]float64{usage.MeterBackhaulGB: 25, usage.MeterBackhaulRequests1k: 500}, 0) |
| + if none != only { |
| + t.Fatalf("backhaul-only meters changed an otherwise idle account:\n%+v\n%+v", none, only) |
| + } |
| } |
diff --git a/internal/console/templates/economics.html b/internal/console/templates/economics.html| index 3cc92bd3c..ff3107a94 100644 |
| --- a/internal/console/templates/economics.html |
| +++ b/internal/console/templates/economics.html |
| @@ -164,7 +164,8 @@ |
| {{$s3storage := mul (sumMeter .Economics.Meters "storage_gb_month") .Economics.Scenario.RateCard.StorageGBMonthUSD}} |
| {{$s3requests := mul (sumMeter .Economics.Meters "requests_1k") .Economics.Scenario.RateCard.RequestsPer1kUSD}} |
| {{$egress := mul (sumMeter .Economics.Meters "egress_gb") .Economics.Scenario.RateCard.EgressGBUSD}} |
| -{{$backhaul := mul (sumMeter .Economics.Meters "backhaul_gb") .Economics.Scenario.RateCard.InterRegionGBUSD}} |
| +{{$backhaulGB := sumMeter .Economics.Meters "backhaul_gb"}} |
| +{{$backhaul := mul $backhaulGB .Economics.Scenario.RateCard.InterRegionGBUSD}} |
| {{$overheads := overheadUSD .Economics.Scenario .Economics.PeriodDays}} |
| {{$modelTotal := add $ec2 $ebs $s3storage $s3requests $egress $backhaul $overheads}} |
| <h2>Model vs. bill</h2> |
| @@ -176,8 +177,7 @@ |
| <tr><td>S3 storage</td><td id="model-s3-storage">{{usd $s3storage}}</td></tr> |
| <tr><td>S3 requests</td><td id="model-s3-requests">{{usd $s3requests}}</td></tr> |
| <tr><td>Egress</td><td id="model-egress">{{usd $egress}}</td></tr> |
| - {{$backhaulGB := sumMeter .Economics.Meters "backhaul_gb"}} |
| - <tr><td>Backhaul (inter-region leg) <span class="small">{{printf "%.2f" $backhaulGB}} GB{{with sumMeter .Economics.Meters "egress_gb"}}{{if gt . 0.0}} · {{printf "%.1f" (mul (div $backhaulGB .) 100.0)}}% of egress{{end}}{{end}} · absorbed, in no account's bill</span></td><td id="model-backhaul">{{usd $backhaul}}</td></tr> |
| + <tr><td>Backhaul (inter-region leg) <span class="small">{{printf "%.2f" $backhaulGB}} GB{{with sumMeter .Economics.Meters "egress_gb"}}{{if gt . 0.0}} · {{printf "%.1f" (mul (div $backhaulGB .) 100.0)}}% of egress{{end}}{{end}} · absorbed, in no account's bill{{if and (gt $backhaulGB 0.0) (eq .Economics.Scenario.RateCard.InterRegionGBUSD 0.0)}} · <strong>rate unset</strong> — set "Inter-region $/GB" in the knobs{{end}}</span></td><td id="model-backhaul">{{usd $backhaul}}</td></tr> |
| <tr><td>Overheads</td><td id="model-overheads">{{usd $overheads}}</td></tr> |
| <tr><th>Model total</th><th id="model-total">{{usd $modelTotal}}</th></tr> |
| </table> |
| @@ -711,7 +711,10 @@ |
| if (revenue > 0) { margin = (revenue - cost) / revenue; } |
| var anyUsage = false; |
| - Object.keys(meters).forEach(function (k) { if (meters[k] > 0) { anyUsage = true; } }); |
| + Object.keys(meters).forEach(function (k) { |
| + if (k === "backhaul_gb" || k === "backhaul_requests_1k") { return; } // data, not usage (#288) |
| + if (meters[k] > 0) { anyUsage = true; } |
| + }); |
| var clipped = bEgress < (meters.egress_gb || 0) || |
| bStorage < (meters.storage_gb_month || 0) || |
| bApps < (meters.app_months || 0) || |
diff --git a/internal/economics/compute.go b/internal/economics/compute.go| index cf98f26a0..7ab9a1108 100644 |
| --- a/internal/economics/compute.go |
| +++ b/internal/economics/compute.go |
| @@ -144,7 +144,13 @@ func PriceAccount(sc Scenario, account string, meters map[string]float64, alloca |
| } |
| anyUsage := false |
| - for _, v := range meters { |
| + for k, v := range meters { |
| + // The backhaul meters are data, not usage: a subset of egress, |
| + // priced nowhere (#288). Skipped so that an account cannot look |
| + // "inside the free tier" on their account alone. |
| + if k == usage.MeterBackhaulGB || k == usage.MeterBackhaulRequests1k { |
| + continue |
| + } |
| if v > 0 { |
| anyUsage = true |
| break |
diff --git a/internal/usage/usage.go b/internal/usage/usage.go| index 7a981a110..dd0ee44a9 100644 |
| --- a/internal/usage/usage.go |
| +++ b/internal/usage/usage.go |
| @@ -28,8 +28,9 @@ const ( |
| // reaching the client. It rides in statements and the economics sweep |
| // as data (#288) and is priced in NO account's cost, revenue or bill — |
| // #284's ruling is absorb. A billing engine iterating meters generically |
| - // must skip it; PriceAccount names its meters and does. The platform's |
| - // own cost for it is the inter-region leg, RateCard.InterRegionGBUSD. |
| + // must skip it, as economics.PriceAccount's usage check does; its priced |
| + // terms name their meters. The platform's own cost for it is the |
| + // inter-region leg, RateCard.InterRegionGBUSD. |
| MeterBackhaulGB = "backhaul_gb" |
| // MeterBackhaulRequests1k is the request-count twin of MeterBackhaulGB: |
| // requests that crossed a region before being served. Informational, |