Skip to content

feat(admin): schedule and spend on the graph, and the HTML honesty carry-through (issue #175) - #178

Merged
edgehero merged 1 commit into
mainfrom
feat/graph-spend-schedule-badges
Aug 12, 2026
Merged

feat(admin): schedule and spend on the graph, and the HTML honesty carry-through (issue #175)#178
edgehero merged 1 commit into
mainfrom
feat/graph-spend-schedule-badges

Conversation

@edgehero

Copy link
Copy Markdown
Owner

Third slice of #175, stacked on #177: the facts the graph computed and never said, plus the honesty counters the HTML page dropped. The diff collapses to this slice once #177 merges.

What

  • Spend on trigger nodes. buildGraphModel gains triggerCosts (the foldTriggerCosts map from feat(admin): spend per trigger and per repo, and the COSTS table cycle (issue #175) #177, keyed by this module's own node ids) and trigger nodes carry cost — a node FACT beside runs/lastOutcome. No new edge kind, no new flag: the closed vocabularies are pinned unchanged by a new test. Both assemblers wire it with one extra file read (subscriptions) and two pure folds over the scan they already paid for, so the GRAPH view's entry-plus-r-only refresh policy is untouched — the real-10ms-poll pin proves it.
  • Schedule on cron rows. next/overdueMs were computed by the model's first slice and rendered by nothing (the design-to-data gap class the Show triggers and flows as a graph on the admin panel #54 delivery lesson names). TUI rows and /dispatch graph text now say next 4h — a countdown against the model's own generatedAt, never a live clock, so a stale model shows its stale countdown honestly — or overdue 2h in the error color, the money backstop's own signal.
  • Money discipline holds on the graph: spend renders only through fmtCost/styler.fmtCost, so a plan-covered trigger reads plan:<id>, never $0.00 (pinned).
  • graph.html honesty carry-through: normalizeModel gains meta.chainRefusals (sorted, clipped), meta.injectedUnreachable (sorted, capped) and observed-edge lastEndedAt; the legend states the two counters the text and TUI surfaces always stated, and an observed wire's label carries recency beside its count ((3× · 2d ago)) via the injected-now relTime, so byte-determinism holds. Node cost is deliberately NOT allowlisted into graph.html: the page may not use the from clause, and a hand-copied money formatter pinned by parity test is a liability the insights artifact (next slice) avoids by taking the real shared formatter.
  • No new glyphs: the plan considered /¤ twins, but plain words plus fmtCost's own shapes carry the facts with zero ambiguous-width risk, and the ASCII-purity pin stays as it was.

Specs

  • REQ-TOPOLOGY-GRAPH AMENDED with (h): schedule and typed spend as node facts, fmtCost-rendered, vocabularies closed.
  • REQ-GRAPH-HTML-EXPORT AMENDED: the artifact states the same honesty counters as the other two surfaces; observed-edge recency.
  • DES-GRAPH-EDGE-DERIVATION and DES-ADMIN-VIA-PI-EXTENSION AMENDED (one clause each, rationale recorded).
  • REQ-COST-ANALYTICS UNCHANGED, checked (foldTriggerCosts gained consumers, not semantics). DES-COST-FOLD-BY-SCAN UNCHANGED, checked.
  • docs/graph.md: the trigger-line example and the schedule/spend reading guide.

Tests

Suite green in the CI posture (2197 tests, 0 skipped, live Valkey). New pins: triggerCosts pass-through with vocabularies unchanged, TUI rows saying next/overdue/plan:kimi (and never $0.00), no-claim-when-no-scheduler, text renderer twins, the page carrying refusals/unreadable-dirs, and the observed label's recency grammar (the one amended pin — the old (N×) regex predates the suffix and the amendment keeps its "a potential wire never carries a count" claim).

Stacked on #177.

@edgehero
edgehero changed the base branch from feat/cost-trigger-repo-folds to main August 12, 2026 07:48
…rry-through (issue #175)

The third insights slice: the facts the graph computed and never said.

- Trigger nodes gain cost (the typed spend foldTriggerCosts maps onto
  the node id) -- a node FACT beside runs/lastOutcome, no new edge kind,
  no new flag, the closed vocabularies pinned unchanged. The assemblers
  wire it with one extra file read and two pure folds over the scan
  they already paid for; the GRAPH view's entry-plus-r-only refresh
  policy is untouched and the real-poll pin proves it.
- Cron rows finally render next/overdue: next as a countdown against
  the model's own generatedAt (never a live clock; a stale model shows
  its stale countdown honestly), overdue in the error color. Both in
  the TUI and in /dispatch graph text.
- Spend renders only through fmtCost/styler.fmtCost, so a plan-covered
  trigger reads plan:<id> on the graph too, never $0.00.
- graph.html: normalizeModel carries meta.chainRefusals,
  meta.injectedUnreachable and observed-edge lastEndedAt; the legend
  states the two counters the text and TUI always stated; an observed
  wire's label says how fresh it is beside its count. Node cost is
  deliberately NOT allowlisted there: the page cannot use the from
  clause, and a hand-copied money formatter is a parity liability the
  insights artifact avoids by taking the real formatter.

Specs in the same PR: REQ-TOPOLOGY-GRAPH gains (h);
REQ-GRAPH-HTML-EXPORT amended (honesty counters, edge recency);
DES-GRAPH-EDGE-DERIVATION and DES-ADMIN-VIA-PI-EXTENSION amended;
REQ-COST-ANALYTICS UNCHANGED, checked; DES-COST-FOLD-BY-SCAN
UNCHANGED, checked. docs/graph.md updated.

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

Signed-off-by: Rob Boerman <robboerman@live.nl>
@edgehero
edgehero force-pushed the feat/graph-spend-schedule-badges branch from 41691eb to f224260 Compare August 12, 2026 07:49
@edgehero
edgehero merged commit 2de0208 into main Aug 12, 2026
12 checks passed
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