Skip to content

fix(admin): the cost fold prorates on the requested window, and three what-if honesty fixes (issue #175) - #176

Merged
edgehero merged 1 commit into
mainfrom
fix/cost-fold-window-honesty
Aug 12, 2026
Merged

fix(admin): the cost fold prorates on the requested window, and three what-if honesty fixes (issue #175)#176
edgehero merged 1 commit into
mainfrom
fix/cost-fold-window-honesty

Conversation

@edgehero

Copy link
Copy Markdown
Owner

First slice of #175: the cost fold's four correctness defects, fixed before anything new is built on top of it.

What

  • Proration denominates on the requested window. foldCosts gains sinceMs (the same instant the caller cut the scan at) and derives window.days from it; the old first-observed-run derivation shrank the denominator on any sparse window, prorated a $99 plan to pocket change, and flipped verdicts to SAVING. The new pinned test folds the same records twice: SAVING under the old derivation (kept for window-less callers, sinceMs: null), LOSING under the honest one. COSTS_WINDOWS/costsSinceMs move INTO costs.mjs beside the fold so the scan cutoff and the denominator come from one function; the twins in dashboard.ts and index.ts are deleted. window.firstRunMs rides along, and daily buckets deliberately keep the first-run origin so the sparkline never opens with a month of leading zero cells.
  • The what-if filters by machine key. byFlow[] rows carry flowKey (null for the no-flow bucket) beside the display flow; the w layer stores both and hands the key to whatIfFlow. Before this, the "(no flow)" display label went into the (r.flow ?? null) filter, matched no record, and a fully ledgered bucket rendered the seeded band with "no ledgered run to measure from".
  • other/other leaves the what-if shortlist. The meter's 8-row overflow bucket is an aggregation artifact, not a model: getPricedModel("other","other") is null, so cycling onto it silently degraded the estimate to the seeded band.
  • Truncated ledgers are counted. usage.truncated was persisted per INT-RUN-HISTORY-FILE-CONTRACT and read by nothing; buildProvenance now counts runs whose ledger folded rows into other, and both provenance renderers say so, only when nonzero (the rates-drift pattern).

Specs

  • REQ-COST-ANALYTICS AMENDED, acceptance rows only; the lettered labeling rules (a)-(g) stand untouched.
  • DES-COST-FOLD-BY-SCAN AMENDED: the requested-window rule in the Decision, the refuted derivation on the Rejected list.
  • REQ-TOKEN-ACCOUNTING-AND-CAPS UNCHANGED, checked: usage.truncated was always in the contract; only the reader changed.
  • INT-RUN-HISTORY-FILE-CONTRACT UNCHANGED, checked. DES-SUBSCRIPTIONS-ARE-COUNTERFACTUAL-ONLY UNCHANGED, checked.
  • docs/costs.md: the frame example recomputed under the honest denominator, the proration sentence, and the truncated-ledger honest limit.

Tests

Suite green in the CI posture (2182 tests, 0 skipped, live Valkey). New pins: the SAVING→LOSING flip under sinceMs, costsSinceMs window edges including the future-edge clamp, flowKey on the no-flow bucket, the seam receiving flow: null from a no-flow what-if, other/other never offered across a full w cycle, and the truncated counter rendering only when it happened. The two amended window pins gained the new firstRunMs field; every other existing assertion passes unmodified.

… what-if honesty fixes (issue #175)

Four corrections to the cost analytics, the first insights slice:

- foldCosts gains sinceMs and prorates on the REQUESTED window, never
  the span the records happen to cover: a sparse window shrank the
  denominator and flipped plan verdicts to SAVING. COSTS_WINDOWS and
  costsSinceMs move into costs.mjs beside the fold so the scan cutoff
  and the denominator cannot drift; window.firstRunMs rides along for
  renderers that want the observed left edge, and daily buckets still
  start at the first observed run so the sparkline keeps its density.
- byFlow rows carry flowKey (null for the no-flow bucket) and the
  what-if filters by it: the "(no flow)" display label matched no
  record, so a fully ledgered bucket rendered the seeded band.
- The ledger's other/other overflow row leaves the what-if shortlist:
  it is unpriceable, so offering it silently degraded the estimate to
  the seeded band.
- buildProvenance counts truncated ledgers (usage.truncated was
  persisted by the record contract and read by nothing); the TUI and
  text provenance lines render the count only when nonzero.

Specs in the same PR: REQ-COST-ANALYTICS amended, acceptance rows only,
the lettered labeling rules (a)-(g) untouched; DES-COST-FOLD-BY-SCAN
amended with the first-run derivation moved to Rejected as a refuted
correction. REQ-TOKEN-ACCOUNTING-AND-CAPS UNCHANGED, checked (the
truncated field was always in the contract; only the reader changed).
INT-RUN-HISTORY-FILE-CONTRACT UNCHANGED, checked. docs/costs.md example
arithmetic recomputed under the honest denominator.

Suite green in the CI posture: 2182 tests, 0 skipped, live Valkey.

Signed-off-by: Rob Boerman <robboerman@live.nl>
@edgehero
edgehero merged commit 8f98a97 into main Aug 12, 2026
12 checks passed
edgehero added a commit that referenced this pull request Aug 12, 2026
Ships the insights consolidation: issues #175 and #181, PRs #176-#180
and #182-#184.

- admin 0.8.0: insights is the ONE analytics surface. Bare /dispatch
  insights (and the panel's i key) writes and opens the self-contained
  page: budget dials with used-vs-cap facts and the worker's own
  states, plan verdicts, daily + cumulative + per-flow spend charts,
  the four breakdowns, and the trigger/flow topology with schedule
  tips and spend badges. insights whatif is the estimator. The COSTS
  and GRAPH views and the costs/graph subcommands are REMOVED; the
  cost-fold correctness fixes (requested-window proration, flowKey,
  other/other, truncated-ledger counter) and the byTrigger/byRepo/
  dailyByFlow folds ride along. dispatch_costs is unchanged.
- worker 0.3.0 and receiver 0.2.1 are unchanged since v0.10.0 and
  their publishes skip.
- Image ?v= tags normalized to this release's version.

Suite green in the CI posture: 2192 tests, 0 skipped, live Valkey.

Signed-off-by: Rob Boerman <robboerman@live.nl>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant