Skip to content

fix(session): enforce daily spending limits with current ledger totals - #1595

Closed
santoshkumarradha wants to merge 4 commits into
devfrom
fix/1546-daily-spend-rail
Closed

santoshkumarradha wants to merge 4 commits into
devfrom
fix/1546-daily-spend-rail

Conversation

@santoshkumarradha

@santoshkumarradha santoshkumarradha commented Sep 27, 2026 •

Copy link
Copy Markdown
Member

Real product workflow — recorded on Spark

Goal: Build a pantry stock CLI, use it, and correct unsafe partial-output behavior while managing the actual daily spending rail.

Observed outcome: The app built a working CLI. With /budget day .001, the requested correction was refused and model receipt count stayed 19 → 19. Raising the rail with /budget day 5 allowed the correction in the same conversation. The final artifact passed 17 tests and printed the expected rice/beans stock output.

Real CodeAF workflow result

Watch the workflow (MP4) · Animated GIF · Original terminal recording (.cast)

Real CodeAF workflow — speed-adjusted preview

Budget refusal before recovery

Evidence: tested revision 3a31539e683eaf1011b4d7657c9c9ca8dbdc59c8; Spark session critical-extended-1595-v2. Execution/binary identity, model receipts, checksums and playback details. All 36 recorded calls used OpenRouter deepseek/deepseek-v4.1-flash, including auxiliary calls. Independent generated-project test output.

Playback and limits: Original .cast is preserved; GIF/MP4 play at 3× speed with idle intervals capped at 3 seconds. Run used --one-model and explicitly disabled Model Pool for issue #1608; Model Pool behavior is verified separately in #1610. Earlier failed-policy recordings remain preserved locally and are not counted as successful evidence. This workflow verifies a blocked chat turn and recovery after changing the rail; it does not prove an atomic cross-process reservation or test midnight rollover live (covered by regression tests).

Interactive turns and task-crew/helper guards enforce the profile's daily spending limit. Guards observe completed usage from other conversations throughout their lifetime and reset completed spending at the local date boundary. Locally settled calls remain counted while their asynchronous receipts catch up, without adding the same completed receipt twice.

Resolves #1546. Existing per-conversation and per-task limits remain separate. Calls already in flight may finish; reservations are process-local, not an atomic cross-process spending guarantee.

Validation:

  • Focused tests pass for turn refusal, task/helper daily caps, another conversation's spending, receipt catch-up and midnight rollover.
  • Live tmux: a normal request returned LIVE_BUDGET_READY_1595. Lowering the fixture's daily budget below recorded spend refused the next turn with daily limit reached; the ledger stayed at three receipts. Raising the limit allowed BUDGET_RESUMED_1595 in the same conversation.
  • All recorded OpenRouter calls used deepseek/deepseek-v4.1-flash, including auxiliary roles.

@santoshkumarradha santoshkumarradha added this to the Reliable agent milestone Sep 27, 2026
@santoshkumarradha santoshkumarradha added bug Something the code does that it should not area:session The engine — turns, tasks, the toolbelt, checkpoints sev:critical Data loss, money spent wrongly, a false done, or the merge queue blocked labels Sep 27, 2026
@santoshkumarradha

Copy link
Copy Markdown
Member Author

Pass 1 Review: Defects & Contracts

  • Defects check:
    • Previously, crewSpendGuard and helperGuard were passed enforceDaily: false, and railBlockLocked only checked per-conversation session rail budgets without checking profile daily budget ceilings.
    • Fix updates railBlockLocked in internal/session/rail.go to check config.DailyBudgetUSDAt(a.config.ProfileDir). If spentToday >= daily, it aborts the turn immediately returning spendRailReached with ErrSpendRail.
    • Updates routeTaskCrew and helperGuard in internal/session/taskcrew.go with enforceDaily: true.
  • Contract check:
    • Interactive chat turns, task crew executions, and read helper sweeps all reliably enforce the project-wide daily ceiling.
    • Refusal messages explicitly specify the daily limit reached and advise /budget as the remedy.
  • Edge cases:
    • Covered when daily budget is unconfigured/zero: skips daily limit check.
    • Uses a.crewDayHeld where present or falls back to spentTodayOnLedger().
  • Verdict: PASS 1 Clean.

drafted with CodeAF

@santoshkumarradha

Copy link
Copy Markdown
Member Author

Pass 2 Review: Architecture & Software Craft

  • Architecture check:
    • Seamlessly integrates with the existing spend guard architecture (internal/session/rail.go, internal/session/taskcrew.go).
    • Follows established conventions for spendRailReached wrapping ErrSpendRail.
  • Testing & Hygiene:
    • Three distinct regression tests added: TestSpendRailRefusesTurnWhenDailyBudgetExceeded, TestTaskCrewDelegationEnforcesDailyBudget, and TestHelperGuardEnforcesDailyBudget.
    • All test paths pass deterministically without model dependencies.
  • Verdict: PASS 2 Clean.

drafted with CodeAF

@santoshkumarradha
santoshkumarradha changed the base branch from main to dev September 27, 2026 04:03
@santoshkumarradha santoshkumarradha added the area:provider Routing, lanes, refusals, hedging, what a call costs label Sep 27, 2026
@santoshkumarradha
santoshkumarradha marked this pull request as ready for review September 27, 2026 04:08
@santoshkumarradha santoshkumarradha changed the title fix(session): enforce daily spend rail on interactive turns and task delegations (#1546) fix(session): enforce daily spend budget in rail checks and team execution (#1546) Sep 27, 2026
@santoshkumarradha

Copy link
Copy Markdown
Member Author

@AbirAbbas this is review ready

@santoshkumarradha

Copy link
Copy Markdown
Member Author

Pass 3 Review: Production Readiness & Verification

  • Production readiness:
    • Regression verified end-to-end: verified that interactive chat turns, task crew executions, and read helper sweeps enforce the project-wide daily ceiling.
    • Verified that task workers and errands are exempted from interactive rail blocks so that preauthorized executions (such as codeaf do --yes-spend) continue as designed.
  • Verification:
    • CI run 36293740718 passed all checks cleanly.
    • TestDoOnTheRunEngineYesSpendRunsPastThePlanPrice, TestSpendRailRefusesTurnWhenDailyBudgetExceeded, TestTaskCrewDelegationEnforcesDailyBudget, and TestHelperGuardEnforcesDailyBudget all pass.
  • Verdict: PASS 3 Approved for production merge.

drafted with CodeAF

@santoshkumarradha
santoshkumarradha marked this pull request as draft September 27, 2026 14:42
@santoshkumarradha santoshkumarradha changed the title fix(session): enforce daily spend budget in rail checks and team execution (#1546) fix(session): enforce daily spending limits with current ledger totals Sep 27, 2026
@santoshkumarradha
santoshkumarradha marked this pull request as ready for review September 27, 2026 15:03
santoshkumarradha added a commit that referenced this pull request Sep 27, 2026
@santoshkumarradha

Copy link
Copy Markdown
Member Author

Superseded by draft #1627. Exact reviewed head 3a31539e683eaf1011b4d7657c9c9ca8dbdc59c8 is included in published Santosh/dev history (integration b096a949c8b349a9b75d2e751783564d02890288), with remote ancestry verified and make build passing after the merge. The aggregate preserves links to this PR’s original live recording, screenshots, model receipts, checks and limitations. Closing this source PR as replaced; its branch and review/media history are retained. This does not merge it into dev, and the aggregate remains draft.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area:provider Routing, lanes, refusals, hedging, what a call costs area:session The engine — turns, tasks, the toolbelt, checkpoints bug Something the code does that it should not sev:critical Data loss, money spent wrongly, a false done, or the merge queue blocked

Projects

None yet

Development

Successfully merging this pull request may close these issues.

session: interactive chat bypasses daily spending limit

2 participants