From cc23cc522750f539f2b50230f9b206213a6623d0 Mon Sep 17 00:00:00 2001 From: "Dina Berry (She/her)" Date: Tue, 31 Mar 2026 13:01:23 -0700 Subject: [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 (header + '\n' + entries.join('\n') + '\n'). This caused the final recentContent to exceed DECISION_THRESHOLD even after archival, so the size limitation kept being reapplied on subsequent nap runs. Fix: add reassemblyOverhead (2 bytes for header/trailing newlines) and +1 byte per entry for join separators to the budget calculation. Closes #123 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .changeset/fix-nap-archival-budget.md | 12 ++++++++++++ CHANGELOG.md | 3 +++ packages/squad-cli/src/cli/core/nap.ts | 13 +++++++++---- 3 files changed, 24 insertions(+), 4 deletions(-) create mode 100644 .changeset/fix-nap-archival-budget.md diff --git a/.changeset/fix-nap-archival-budget.md b/.changeset/fix-nap-archival-budget.md new file mode 100644 index 000000000..95461886a --- /dev/null +++ b/.changeset/fix-nap-archival-budget.md @@ -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 \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 5dab04371..7d9972765 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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 diff --git a/packages/squad-cli/src/cli/core/nap.ts b/packages/squad-cli/src/cli/core/nap.ts index 8f26c43f7..95775aa6b 100644 --- a/packages/squad-cli/src/cli/core/nap.ts +++ b/packages/squad-cli/src/cli/core/nap.ts @@ -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);