Add burn claude-md: CLAUDE.md hot-path cost attribution#51
Add burn claude-md: CLAUDE.md hot-path cost attribution#51willwashburn wants to merge 1 commit intomainfrom
Conversation
CLAUDE.md rides in every turn's cached context, so a bloated CLAUDE.md
silently taxes every session in the repo. Burn already carries real
per-turn cacheRead values, so we can attribute its cost honestly:
per-turn cost = claude_md_tokens × cacheRead_price (when cacheRead
is large enough to actually contain it)
The "in cache" check (turn.cacheRead >= claude_md_tokens) is a
conservative eviction signal: it skips the first turn (where CLAUDE.md
lives in cacheCreate, not cacheRead) and any turn where the file has
been compacted away. Cost-per-section is proportional to that section's
token share.
Section parsing groups by H2 if any exist (matching the standard
CLAUDE.md shape where the H1 is a doc title and H2s are the meaningful
sections), falls back to H1, and treats a heading-less file as a single
preamble. Code fences are skipped so example markdown inside them
isn't parsed as a real heading.
`burn claude-md advise` emits unified-diff TRIM hunks for the most
expensive sections — line ranges match the user's current file so the
diffs hand-apply cleanly. There is no --apply flag: burn never mutates
CLAUDE.md.
Closes #10
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
| if (!inFence) { | ||
| inFence = true; | ||
| fenceMarker = marker; | ||
| } else if (trimmed.startsWith(fenceMarker.charAt(0).repeat(fenceMarker.length))) { |
There was a problem hiding this comment.
🟡 Fence closing check matches lines with trailing content, incorrectly exiting code blocks
The closing fence check at line 176 uses trimmed.startsWith(fenceMarker.charAt(0).repeat(fenceMarker.length)), which matches any line that begins with enough backticks/tildes — even if the line has trailing content (e.g. ````python). Per the CommonMark spec, a closing fence must contain only fence characters and optional whitespace. When a line like ````python appears inside a 3-backtick code block, this code incorrectly closes the fence, causing subsequent headings that are still inside the code block to be detected as real sections. Meanwhile, the actual closing ``` line is misinterpreted as opening a new fence, swallowing headings after the real code block.
Reproduction
Input:
inside block
## should-be-inside
```
## should-be-outside
```
Expected headings: only `## should-be-outside`.
Actual headings: only `## should-be-inside` (wrong one).
</details>
```suggestion
} else if (new RegExp(`^${fenceMarker.charAt(0) === '`' ? '`' : '~'}{${fenceMarker.length},}\\s*$`).test(trimmed)) {
```
<!-- devin-review-badge-begin -->
<a href="https://app.devin.ai/review/agentworkforce/burn/pull/51" target="_blank">
<picture>
<source media="(prefers-color-scheme: dark)" srcset="https://static.devin.ai/assets/gh-open-in-devin-review-dark.svg?v=1">
<img src="https://static.devin.ai/assets/gh-open-in-devin-review-light.svg?v=1" alt="Open in Devin Review">
</picture>
</a>
<!-- devin-review-badge-end -->
---
*Was this helpful? React with 👍 or 👎 to provide feedback.*
Summary
burn claude-mdcommand: per-section cost attribution for the project's CLAUDE.md, with cross-session aggregation and a per-session cost breakdownburn claude-md advisesubcommand: emits unified-diff TRIM hunks for the most expensive sections (read-only — burn never mutates CLAUDE.md)Closes #10.
Output shape
```
CLAUDE.md at /Users/will/Projects/foo/CLAUDE.md (412 lines, ~3.1k tokens)
Cost per session: avg $0.18, p95 $0.34
Cost over 7d: $4.12 across 23 sessions
Sections ranked by cost:
lines heading tokens cost/session %file
12- 47 ## Architecture 1.8k $0.11 59.0%
48- 89 ## Testing conventions 890 $0.05 28.7%
90- 148 ## Tone and personality 410 $0.02 13.2%
```
Attribution math
Each turn's CLAUDE.md cost is computed directly: `claude_md_tokens × cacheReadPrice / 1M` per turn where `cacheRead >= claude_md_tokens`. This simplification of the issue's share-based formula falls out cleanly because CLAUDE.md size is constant across the session — the share-vs-direct difference vanishes. The `cacheRead < claude_md_tokens` check skips:
Section attribution is proportional: `section_cost = total_cost × (section_tokens / total_tokens)`.
Section parsing
Test plan
Notes / follow-ups
🤖 Generated with Claude Code