Repository navigation
fix(cli): scope squad cost to the shell's Squad session - #2348
Merged
Merged
Conversation
Plain `squad cost` read usage from the ledger, which only the interactive shell writes, but took the session start from the newest Scribe session log in .squad/log/, which the shell never writes. With no log it reported every session; a log written by another host during a shell run hid that run's earlier turns. - the ledger records get an optional squadSessionId; the shell stamps turn starts and usage with its persisted session id (the one /resume restores); - squad cost scopes to the Squad session of the newest ledger row, and falls back to the session-log cutoff when that row has no id; - the summary counts Squad sessions instead of SDK sessions; - cost-tracking.md describes the ledger and shows the real output. USAGE_LEDGER_VERSION stays 1; older readers ignore the new field. Closes github#2347
Contributor
🟠 Impact Analysis — PR #2348Risk tier: 🟠 HIGH 📊 Summary
🎯 Risk Factors
📦 Modules Affecteddocs (1 file)
root (1 file)
squad-cli (2 files)
squad-sdk (1 file)
tests (2 files)
|
Contributor
🛫 PR Readiness Check
PR Scope: 📦🔧 Mixed (product + infrastructure)
|
| Status | Check | Details |
|---|---|---|
| ❌ | Single commit | 2 commits — consider squashing before review |
| ✅ | Not in draft | Ready for review |
| ✅ | Branch up to date | Up to date with dev |
| ❌ | Copilot review | No Copilot review yet — it may still be processing |
| ✅ | Changeset present | Changeset file found |
| ✅ | Scope clean | No .squad/ or docs/proposals/ files |
| ✅ | No merge conflicts | No merge conflicts |
| ✅ | Copilot threads resolved | No Copilot review threads |
| ❌ | CI passing | 14 check(s) still running |
Files Changed (7 files, +240 −38)
| File | +/− |
|---|---|
.changeset/cost-squad-session.md |
+6 −0 |
docs/src/content/docs/features/cost-tracking.md |
+27 −22 |
packages/squad-cli/src/cli/commands/cost.ts |
+42 −12 |
packages/squad-cli/src/cli/shell/index.ts |
+3 −1 |
packages/squad-sdk/src/runtime/usage-ledger.ts |
+24 −3 |
test/cli/cost.test.ts |
+91 −0 |
test/usage-ledger.test.ts |
+47 −0 |
Total: +240 −38
This check runs automatically on every push. Fix any ❌ items and push again.
See CONTRIBUTING.md and PR Requirements for details.
12 of 13 tasks
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.
What
Plain
squad costnow scopes the current session with a session id the shell writes into the usage ledger, instead of Scribe's session logs. The summary counts Squad sessions instead of SDK sessions, and the cost-tracking docs describe how it works today.Why
Closes #2347
The usage comes from the ledger, which only the interactive shell writes. The session start came from the newest
.squad/log/*.mdfile, a Scribe session log that the shell never writes. With no log, plainsquad costreports every session ever recorded. A log written by a Copilot session during a shell run hides the first part of that run. Once #2322 lands, nothing asks for session logs at all, so this needs to go in first (Tamir's comment on #2322).How
runtime/usage-ledger.ts.UsageLedgerRecord,UsageLedgerTurnStartandUsageTurnStartget an optionalsquadSessionId.append()takes an optional second argument,UsageRecordContext, because the runtimeUsageEventdoesn't know about Squad sessions.USAGE_LEDGER_VERSIONstays 1.shell/index.ts. The three ledger writes passsquadSessionId: persistedSession.id, the shell session that/resumerestores. It's read at write time, so a/resumeapplies from the next turn.commands/cost.ts.squadSessionIdof the newest ledger row, and plainsquad costkeeps only rows with that id. Session logs are ignored then.log/*.mdcutoff applies unchanged. The legacy markdown fallback also keeps that cutoff.--allis unchanged.squadSessionId ?? sessionId.features/cost-tracking.md. The page said usage lives in orchestration-log Token usage rows (the template has no such row any more) and showed an output format that no longer exists. It now covers the ledger, which hosts write it, how the current session is picked, and real output.Compatibility
dev'sUsageLedger.read()on stamped rows: 0 invalid.Known limits
squad costfollows whichever wrote last. A--session <id>flag could be a follow-up./resumecalls a session.Testing
New tests:
test/usage-ledger.test.ts: the id is stamped on turn starts and usage; an empty id is rejected before anything is written.test/cli/cost.test.ts, with ledgers shaped like the shell's writes (coordinator plus one SDK session per agent):squad costpicks the newest Squad session even with a session log in the middle of it;--allreports 2 sessions for two shell runs, not 5;--agentdoesn't reach into older sessions.Results:
usage-ledger,cli/costand the tests that load the shell (signal-handling,ghost-response,init-autocast,regression-368,repl-streaming,sdk-failure-scenarios,stress): 212 passed, and the tracked-file guard from Guard tests against tracked file changes #2308 stays quiet.npm run lint(after building the SDK): clean. ESLint on the changed files: 0 errors..changeset/cost-squad-session.md, cli and sdk patch)PR Readiness Checklist
Branch & Commit
dev(notmain)dev(938e56b)Build & Test
npm run lintpassesDocs
features/cost-tracking.mdupdatedBreaking Changes
None. The new field is optional, and
USAGE_LEDGER_VERSIONis unchanged.UsageLedger.append()gains an optional second parameter. Plainsquad costreports a different (correct) range once the shell has written stamped records.Waivers
None.