docs: remove stray Unreleased heading, note removed --no-cache flag

Also adds a regression test for the midnight-straddle bucketing invariant
that was flagged by the pre-push review: if someone reverts the assistant-
timestamp bucketing back to user-timestamp, this test will catch it.
This commit is contained in:
iamtoruk 2026-04-21 04:54:50 -07:00
parent 07d2fb07aa
commit 5a4e14f0f6
2 changed files with 47 additions and 2 deletions

View file

@ -1,7 +1,5 @@
# Changelog
## Unreleased
## 0.8.5 - 2026-04-21
### Fixed
@ -9,6 +7,9 @@
- **Menubar and terminal status disagreed on Today.** A turn that straddled midnight (user message in one day, response in the next) was bucketed by user timestamp in one code path and by assistant timestamp in another, producing different Today values in the two surfaces. Both paths now count a turn on the day its first assistant call ran.
- **Kept from 0.8.2-0.8.4:** subscription plan tracking, pricing accuracy and CSV injection hardening, cursor-agent provider, menubar prefetch and timezone alignment. Only the cache rewrite and its follow-up patches were reverted.
### Removed
- `--no-cache` flag on `report`, `today`, `month`, `status`, `export`, `optimize`, and `compare`. The flag existed to bypass the persistent source cache which no longer exists. If your scripts pass `--no-cache`, drop it; the parse runs fresh every time now.
### Notes
- 0.8.2, 0.8.3, and 0.8.4 on npm contain the buggy cache. Upgrade with `npm i -g codeburn@latest` or `npm i -g codeburn@0.8.5`.
- This release uses a full reparse on every invocation, matching v0.8.1 behavior. On large corpora (5,000+ session files) expect 3 to 10 seconds per invocation. An incremental refresh design that preserves correctness is planned for a follow-up release.

View file

@ -255,4 +255,48 @@ describe('buildPeriodDataFromDays', () => {
expect(pd.categories).toEqual([])
expect(pd.models).toEqual([])
})
it('attributes a midnight-straddling turn to the first assistant call date, not the user message date', () => {
// Regression for the bug that shipped in 0.8.2-0.8.4: when a user message
// sat on one side of midnight and the assistant response landed on the other,
// day-aggregator.ts bucketed by assistant time but renderStatusBar bucketed
// by user time, so the menubar and `codeburn status` disagreed on Today.
// The invariant for both surfaces: a turn is counted on the day its first
// assistant call actually ran.
const userTs = '2026-04-20T23:58:00Z'
const assistantTs = '2026-04-21T00:30:00Z'
const assistantLocal = new Date(assistantTs)
const expectedDate = `${assistantLocal.getFullYear()}-${String(assistantLocal.getMonth() + 1).padStart(2, '0')}-${String(assistantLocal.getDate()).padStart(2, '0')}`
const projects: ProjectSummary[] = [
makeProject({
sessions: [{
sessionId: 's1',
project: 'p',
firstTimestamp: userTs,
lastTimestamp: assistantTs,
totalCostUSD: 5,
totalInputTokens: 0, totalOutputTokens: 0, totalCacheReadTokens: 0, totalCacheWriteTokens: 0,
apiCalls: 1,
turns: [{
userMessage: 'ask',
timestamp: userTs,
sessionId: 's1',
category: 'coding',
retries: 0,
hasEdits: false,
assistantCalls: [makeCall(assistantTs, 5)],
}],
modelBreakdown: {}, toolBreakdown: {}, mcpBreakdown: {}, bashBreakdown: {},
categoryBreakdown: {} as never,
}],
}),
]
const days = aggregateProjectsIntoDays(projects)
const costDay = days.find(d => d.cost === 5)
expect(costDay, 'turn cost must be bucketed somewhere').toBeDefined()
expect(costDay!.date).toBe(expectedDate)
expect(costDay!.calls).toBe(1)
})
})