Add 'rootstock usage push': send aggregated rollups to the dashboard - #169
Merged
Conversation
The collector (#159) aggregates the usage spool; this adds the last hop from issue #47 — pushing the aggregated monthly rollup rows to the rootstock-admin backend's new usage endpoint (Garden-AI/rootstock-admin#6). - `rootstock usage push [--dry-run]` pushes the same aggregation `report` shows, filed under the manifest's cluster name. The backend stores rollups per month and replaces only the months present in a push, so repeated pushes (e.g. from the smoke-test cron) are idempotent. - Only derived counts are sent; the salted user hashes stay in the spool (summarize_spool already strips them). - The usage endpoint URL is derived from api_url by swapping the standard rootstock-admin function name (-manifest -> -usage); a new optional usage_api_url config field / ROOTSTOCK_USAGE_API_URL env var overrides it for non-standard deployments. - The success line names the endpoint it pushed to: dev-vs-prod mixups previously looked identical to success (the delta manifest incident). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
The final hop of the usage-stats design from #47: #156 writes per-session records, #159 aggregates them (
usage report/compact), and this PR pushes the aggregated monthly rollup rows to the dashboard backend. The receiving endpoint is Garden-AI/rootstock-admin#6.rootstock usage push [--root <path>] [--dry-run]— pushes the same aggregationreportshows (rollup files plus not-yet-compacted raw records), filed under the manifest's cluster name. Requires a manifest (manifest init) and the same Modal proxy-auth credentials asmanifest push. The backend stores rollups per cluster per month and replaces only the months present in a push, so running it repeatedly — e.g. from the nightly smoke-test cron alongsideusage compact— is idempotent and never erases previously pushed history.summarize_spoolalready strips the salted user hashes down tounique_userscounts, and the backend drops anyusersfield defensively on ingest.api_urlby swapping the standard rootstock-admin function name (-manifest→-usage). A new optionalusage_api_urlconfig field (ROOTSTOCK_USAGE_API_URLenv var) overrides it for deployments that don't follow that naming; if neither applies, the command says exactly what to set.--dry-runprints the resolved URL and full payload for the same reason.Test plan
usage_api_url(4), andusage pushcommand tests covering missing credentials, non-derivable URL, missing manifest, missing spool, empty spool,--dry-runpayload (counts only, no hashes), and a mocked-urlopen POST asserting URL, auth headers, and body (7).ruff checkclean; touched filesruff formated.--dry-runagainst a seeded temp root resolvesgarden-ai-dev--rootstock-admin-usage.modal.runfrom the standard manifest URL and emits the expected payload.usage push→GET /usagefrom a login node.🤖 Generated with Claude Code