Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions .changeset/fix-nap-archival-budget.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
---
"@bradygaster/squad-cli": patch
---

fix(nap): account for separator newlines in decision archival budget

The budget calculation in archiveDecisions() did not account for the newline
separators added during content reassembly. This caused the final recentContent
to exceed DECISION_THRESHOLD even after archival. Fix adds reassemblyOverhead
and per-entry separator bytes to the budget calculation.

Closes #123
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ All notable changes to this project will be documented in this file.

## [Unreleased]

### Fixed
- **Nap archival budget** (#123) — account for separator newlines in decision archival budget calculation

### Added — Full Work Monitor for squad watch (#708)
- `--execute` flag spawns Copilot sessions to work on actionable issues autonomously
- Multi-platform support — auto-detects GitHub vs Azure DevOps from git remote URL
Expand Down
13 changes: 9 additions & 4 deletions packages/squad-cli/src/cli/core/nap.ts
Original file line number Diff line number Diff line change
Expand Up @@ -386,17 +386,22 @@ function archiveDecisions(squadDir: string, dryRun: boolean): NapAction | null {
dated.sort((a, b) => a.daysAgo! - b.daysAgo!);

// Keep the most recent dated entries that fit under the threshold
// along with all undated entries and the header
// along with all undated entries and the header.
// Account for separator newlines added during reassembly:
// recentContent = header + '\n' + entries.join('\n') + '\n'
// Each entry contributes +1 byte for its join separator (overestimates
// by 1 byte for the last entry, which is a safe margin).
const headerEnd = entries.length > 0 ? entries[0]!.start : lines.length;
const headerSize = Buffer.byteLength(lines.slice(0, headerEnd).join('\n'), 'utf8');
const reassemblyOverhead = 2; // '\n' after header + trailing '\n'
const undatedSize = undated.reduce(
(sum, e) => sum + Buffer.byteLength(lines.slice(e.start, e.end).join('\n'), 'utf8'), 0,
(sum, e) => sum + Buffer.byteLength(lines.slice(e.start, e.end).join('\n'), 'utf8') + 1, 0,
);
let budget = DECISION_THRESHOLD - headerSize - undatedSize;
let budget = DECISION_THRESHOLD - headerSize - reassemblyOverhead - undatedSize;

const keptDated: typeof entries = [];
for (const e of dated) {
const entrySize = Buffer.byteLength(lines.slice(e.start, e.end).join('\n'), 'utf8');
const entrySize = Buffer.byteLength(lines.slice(e.start, e.end).join('\n'), 'utf8') + 1;
if (budget >= entrySize) {
budget -= entrySize;
keptDated.push(e);
Expand Down
Loading