stella budget — Command Guide

The budget commands read release risk budgets, check proposed releases and record consumption through Policy Engine. They require a reachable backend and an authenticated tenant. Configure STELLAOPS_BACKEND_URL and the Authority credentials described in the CLI architecture.

Budget inventory contract verified against source commit 6a8e9f038d on 2026-10-07. Reason and atomic consumption contract verified against d2a4147aee on 2026-10-07. Owner-path and CLI verification are recorded in docs/implplan/_evidence/20261007-policy-budget-owner/pcd-451.json and pcd-452.json. Re-verify the command tree in src/Cli/StellaOps.Cli/Commands/Budget/RiskBudgetCommandGroup.cs, its registration in src/Cli/StellaOps.Cli/Program.cs, and the owner contract in src/Policy/StellaOps.Policy.Engine/Endpoints/RiskBudgetEndpoints.cs. Re-run PolicyEngineRiskBudgetInventoryTests, PostgresBudgetStoreTests and PolicyEngineRiskBudgetReasonTests, plus the CLI RiskBudgetRouteContractTests. Acceptance used an isolated Policy host with real PostgreSQL; shared-estate deployment is outside that receipt.

Commands and authorization

CommandOwner requestScope
statusGET /api/v1/policy/budget/status/{serviceId}; optional windowpolicy:read
consumePOST /api/v1/policy/budget/consumepolicy:operate
checkPOST /api/v1/policy/budget/checkpolicy:read
historyGET /api/v1/policy/budget/history/{serviceId}; optional windowpolicy:read
listGET /api/v1/policy/budget/list; optional status, window, limitpolicy:read

Every command accepts --output text|json (default text). The budget group’s --tenant selects the request tenant through the CLI tenant rule and takes precedence over the configured tenant. For example:

stella budget --tenant acme status --service my-service --output json

Tenant authorization remains enforced by the owner. The Budget.Read and Budget.Consume clients use the backend URL and air-gap egress guard. Authentication requests the operation’s scope before the command applies its effective tenant header. These commands have no offline budget ledger.

Status

stella budget status --service my-service --window 2026-10 --output json

--service is required; omitting --window asks the owner for the active window. The result preserves budgetId, serviceId, the named string tier, window, allocated, consumed, remaining, percentageUsed, status and updatedAt. There is no lastConsumedAt field in this contract.

Consume

stella budget consume --service my-service --points 25 --release-id v1.2.3 --output json

--service, positive --points and --release-id are required. This command records consumption: it sends serviceId, riskPoints, releaseId and optional reason. Service and release identifiers must be nonblank and at most 128 UTF-16 code units each. Policy preserves supplied reason text unchanged in the tenant’s consumption history; omission records no reason. --reason accepts at most 512 UTF-16 code units. Reasons support operator text, including Unicode, stored in PostgreSQL and exported as UTF-8 JSON.

A successful request atomically deducts its risk points and appends a history entry. Repeating a release ID creates another entry and deducts its points again. Release IDs do not deduplicate requests. A refused request adds neither a debit nor an entry.

The result contains isSuccess, entryId, remaining, percentageUsed, status and any error. A response with isSuccess=false fails even if its HTTP status is 200. The owner does not return a pointsConsumed field.

Check a proposed release

stella budget check --service my-service --tier CustomerFacingNonCritical --diff-category ApiBackwardCompatible --feature-flag --canary-percentage 10 --rollback-plan --output json

--service, --tier and --diff-category are required. Policy computes the risk points from the release category and context; this command has no --points option and does not record consumption.

Accepted tiers are Internal, CustomerFacingNonCritical, CustomerFacingCritical and SafetyCritical. Accepted diff categories are DocsOnly, UiNonCore, ApiBackwardCompatible, ApiBreaking, DatabaseMigration, AuthPermission, InfraNetworking, CryptoPayment and Other.

Optional inputOwner fieldDefault
--change-freezechangeFreezefalse
--incident-activeincidentActivefalse
--deployment-window <bool>deploymentWindowtrue
--feature-flaghasFeatureFlagfalse
--canary-percentage <n>canaryPercentage0
--rollback-planhasRollbackPlanfalse
--non-productionisNonProductionfalse

The result preserves canProceed, requiredGate, riskPoints, budgetRemainingBefore, budgetRemainingAfter, statusBefore, statusAfter, blockReason, requirements and recommendations. Operational context can block a release even when points remain. --fail-on-block defaults to true, so a blocked check exits nonzero. Set --fail-on-block false to inspect a valid blocked decision without making that decision a command failure; transport and response errors still fail.

History

stella budget history --service my-service --window 2026-10 --limit 20
stella budget history --service my-service --window 2026-10 --limit 20 --output json

--service is required. The owner returns the requested or active window in a serviceId, window, entries response. Each entry has entryId, releaseId, riskPoints, consumedAt and optional reason; there is no server total count. JSON retains recorded reasons. Text output shows a supplied reason below its entry.

--limit limits the text display after the full window has been received. It is never sent to the owner. JSON retains the complete owner response, including all returned entries, regardless of this display limit. This is a window read with no server paging contract.

List

stella budget list --status yellow --window 2026-10 --limit 50 --output json

--status accepts one state (green, yellow, red or exhausted); --window and --limit are owner query parameters. The command has no --tier filter. Budget rows use the full status contract, including the named string tier and update timestamp.

The owner queries persisted budgets for the admitted tenant. Omitted --window lists all persisted windows; an explicit window must be yyyy-MM. The limit defaults to 50 and must be between 1 and 1000. totalCount counts matching budgets before applying the limit. Results are ordered by update time descending, then service, window and budget ID.

A successful empty response (budgets: [], totalCount: 0) is an authoritative empty inventory and exits zero. Unavailable persistence returns HTTP 503 and exits nonzero without emitting a budget result. Invalid query parameters return HTTP 400.

Failures

HTTP failures, transport errors and malformed success responses exit nonzero without fabricated budget results. Missing required options and withdrawn options fail command parsing. For CI, check the exit code and the owner’s decision fields together.

The shipped stellaops-cli Authority client is permitted and granted policy:operate from Authority migrations S066 and 035 (2026-10-09). An Authority that predates them refuses the consume token request, so the command fails before it reaches Policy Engine.

See also budget attestation and Policy API.