Skip to content

feat: public status page on GitHub Pages, and a cost alert - #5

Merged
dhamsey3 merged 1 commit into
mainfrom
feat/status-page
Oct 16, 2026
Merged

dhamsey3 merged 1 commit into
mainfrom
feat/status-page

Conversation

@dhamsey3

Copy link
Copy Markdown
Owner

Second half of roadmap phase 2: a public page showing what voltcast promised, what happened, and what it cost. With this, phase 2 is done.

The page

python -m voltcast status reads the live record into status.json and renders one self-contained index.html:

  • Promise tiles: whether tomorrow's forecast is published, due or missing against the 10:15 deadline; the latest day's error; the length of the live record; the AWS bill this month against the budget.
  • The last scored day: published forecast against the cleared price, all 96 quarter-hours, with every model's MAE, RMSE and bias.
  • The next forecast once it's published, then the track record: rolling error per model (7 days, 30 days, since going live) and a daily-error chart.
  • What's running: the model and version, challengers in shadow, the code commit, and the input lineage.
  • The bill: month to date and past months.

It has inline CSS and SVG and no external assets. Every chart has a table view, a hover and keyboard read-out, and a direct label at each line end. Dark mode uses its own validated palette, and the layout holds at 375px wide. Only live forecasts appear; the backfill replay stays in voltcast report.

I checked it with headless Chrome in light, dark and phone width, against the real S3 data and a 30-day sample.

Hosting and access

  • GitHub Pages, deployed by .github/workflows/status.yml after the 10:15 deadline check and after 14:30 scoring, and on changes to the page code. Pages is already enabled with Actions as the source, and only main may deploy to it.
  • github-actions-voltcast-status (already applied in aws-oidc-bootstrap) is read-only and trusted from main only. It reads published/, scores/ and curated/, decrypting through S3 only, and views the budget. It can't read raw snapshots or unpublished challenger forecasts, and it can't write anything. I checked this with the IAM policy simulator (14 allow/deny cases) and Access Analyzer.

Cost alert

The new aws_budgets_budget.monthly (voltcast-monthly, 5 USD, account-wide) emails the alert address on actual or forecast spend above 100%. The status page reads the same budget through the free Budgets API; Cost Explorer would add 0.30–0.60 USD/month. The plan and apply roles have the matching budget permissions. ADR 6 records the decisions.

Expected plan on this PR

  • aws_budgets_budget.monthly: created. The notification blocks show as sensitive because of the email.
  • aws_lambda_function.pipeline: new code hash, because the package now includes status.py and page.py. The pipeline's behaviour doesn't change.

After merge

The deploy run creates the budget, and the status run publishes the page at https://dhamsey3.github.io/voltcast/. The bill tile shows "–" until AWS's next daily billing update fills the budget's spend.

`python -m voltcast status` reads the live record into status.json and
renders one self-contained page: whether tomorrow's forecast is out, the
latest scored day against the cleared price, the next forecast, rolling
error per model, what's deployed, and the AWS bill. It uses inline CSS and
SVG, a table behind every chart, and dark mode. Only live forecasts appear.

A scheduled workflow rebuilds it after the deadline check and after scoring,
using a read-only role that sees only published results.

The bill comes from a new account-wide AWS Budget, voltcast-monthly. Its
API is free, unlike Cost Explorer's. The budget also emails on-call when
actual or forecast spend passes 5 USD, so the cost line in the promise
table is now enforced. ADR 6 records the choices.
@dhamsey3
dhamsey3 merged commit b768bac into main Oct 16, 2026
4 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