Skip to content

feat(cli): add mallcop balance subcommand (mallcoppro-718) - #53

Open
baron-3dl wants to merge 3 commits into
mainfrom
work/mallcoppro-718
Open

baron-3dl wants to merge 3 commits into
mainfrom
work/mallcoppro-718

Conversation

@baron-3dl

Copy link
Copy Markdown
Collaborator

Summary

  • Adds mallcop balance CLI subcommand that calls GET /v1/balance on mallcop.app
  • Closes gap 1 from the Wk4 balance display surfaces audit (mallcoppro-718)
  • Reads MALLCOP_APP_URL and MALLCOP_SERVICE_TOKEN from env; both consistent with existing chart naming conventions

What this does

The endpoint GET /v1/balance was already built and tested on mallcop.app (mallcop-pro). This PR adds the customer-facing CLI surface that calls it.

mallcop balance [--url <url>] [--key <token>] [--json]

Output example:

Donut balance: 42 🍩
  credits:         7
  subscription:    35

Test plan

  • TestBalance_MissingToken — error when no token
  • TestBalance_Unauthorized — error on 401
  • TestBalance_HumanReadable — pool breakdown in human output
  • TestBalance_JSONOutput--json flag produces parseable JSON
  • TestBalance_NoPools — total-only response
  • TestBalance_EnvVars — MALLCOP_APP_URL + MALLCOP_SERVICE_TOKEN env vars
  • TestBalance_LiveForge — live integration test against forge.3dl.dev (returned 70000 donuts, confirmed passing)

All 7 tests pass. Run: go test ./cmd/mallcop/... -run TestBalance

Audit context

Full audit at mallcop-pro/docs/audit/2026-05-06-balance-display-surfaces.md:

  • 1 gap closed (this PR): mallcop balance CLI subcommand
  • 3 operator-decision-blocked gaps listed: web dashboard balance page, balance response metadata, mallcop init --pro key storage

🤖 Generated with Claude Code

baron-3dl and others added 2 commits May 12, 2026 19:26
Closes gap 1 from the Wk4 balance display surfaces audit.
GET /v1/balance is already built and tested on mallcop.app; this
adds the customer-facing `mallcop balance` CLI command that calls it.

- balance.go: runBalance() — calls <MALLCOP_APP_URL>/v1/balance,
  converts JSON to human-readable donut output; --json for machine use.
  Reads MALLCOP_APP_URL and MALLCOP_SERVICE_TOKEN from env (consistent
  with charts/vertical-slice.toml naming).
- balance_test.go: 7 tests — missing token, 401, human readable,
  JSON output, no pools, env vars, live Forge integration smoke.
  Live Forge test runs when FORGE_API_KEY + FORGE_BASE_URL are set;
  confirmed 70000 donuts returned from forge.3dl.dev.
- main.go: wire balance case + update usage string.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…llcoppro-718)

Veracity rework addressing findings 1 and 2:

Finding 1 — all 5 unit tests (Unauthorized, HumanReadable, JSONOutput, NoPools,
EnvVars) now use testutil.FakeForge + testutil.NewServer from mallcop-pro/testutil.
Mock boundary is at Forge's HTTP API (GET /v1/keys, GET /v1/accounts/{id}/balance),
not at the mallcop.app surface. Real handleBalance, real pricing.MicroToDonuts, and
real config-driven costPerDonutMicro run in every unit test.

Finding 2 — TestBalance_LiveForge rewritten to use testutil.NewServerWithForgeURL.
No handler logic reimplemented. Real forge.Client + real pricing.MicroToDonuts
route through the actual server.handleBalance. costPerDonutMicro is a parameter,
not a hardcoded constant.

Finding 3 — test still t.Skips when env unset. Runs unconditionally when
FORGE_API_KEY + FORGE_BASE_URL are set. CI secret prereq filed as mallcoppro-fd3.

Added github.com/thirdiv/mallcop-pro as a go.mod dependency (replace directive
pointing to local path) to import the new testutil package.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@baron-3dl

Copy link
Copy Markdown
Collaborator Author

Veracity rework (mallcoppro-718 findings 1+2)

This push addresses the veracity adversary's HIGH findings:

Finding 1 resolved — All 5 unit tests (TestBalance_Unauthorized, TestBalance_HumanReadable, TestBalance_JSONOutput, TestBalance_NoPools, TestBalance_EnvVars) now use testutil.FakeForge + testutil.NewServer. Mock boundary is at Forge's HTTP API, not at the mallcop.app surface. Real handleBalance, real pricing.MicroToDonuts, and config-driven costPerDonutMicro run in every test.

Finding 2 resolvedTestBalance_LiveForge rewritten to use testutil.NewServerWithForgeURL. No handler logic reimplemented. Real forge.Client + real pricing.MicroToDonuts route through the actual server.handleBalance.

Finding 3 (MEDIUM) — Test still t.Skips when env unset. CI secret prereq filed as mallcoppro-fd3.

New dependency — Added github.com/thirdiv/mallcop-pro (local replace directive) to go.mod to import the new testutil package. The testutil package was added to mallcop-pro in PR #94 (commit 835fd1f).

All 7 tests green: 6 unit (including live Forge at 70000 🍩) + TestBalance_MissingToken.

…1 (mallcoppro-718)

Update go.mod to use the corrected module path github.com/3dl-dev/mallcop-pro@v0.1.1
instead of the dead github.com/thirdiv/mallcop-pro path. Update the testutil import
in balance_test.go accordingly. Removes need for local replace directive.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
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