Skip to content

feat(nap): measure charter/skill context and add --dry-run --json - #1987

Closed
bradygaster wants to merge 1 commit into
devfrom
bradygaster-nap-reskill-context-improvements
Closed

feat(nap): measure charter/skill context and add --dry-run --json#1987
bradygaster wants to merge 1 commit into
devfrom
bradygaster-nap-reskill-context-improvements

Conversation

@bradygaster

Copy link
Copy Markdown
Owner

Problem

squad nap is a real 730-line engine with metrics, dry-run, and tests. reskill is a 92-line prompt with no code, no measurement, and no test.

reskill/SKILL.md asked agents to fill in a savings table — but no tool in the repository produced those numbers. Every reskill savings figure ever reported was a hand-estimate.

Separately, nap's NapMetrics measured history/log/decision bytes but not charter or skill bytes — the two things reskill exists to shrink. So the tool that could measure didn't measure the right thing, and the tool that needed numbers had no tool.

Flight's ruling: don't build a second engine. Extend nap's measurement so squad nap --dry-run --json becomes the primitive reskill was missing. Ship the primitive; defer the engine.

Baseline vs improved measurement

Everything below is asserted with exact equality in test/nap-reskill-measurement.test.ts against mkdtemp fixtures.

Metric Before this PR After this PR
charterBytes ❌ not measured 9036
charterReducibleBytes ❌ not measured 3928
skillBytes ❌ not measured 3072
historyBytes 51000 51000
historyReducibleBytes ❌ not measured 21424

Reskill opportunity surfaced: 25,352 bytes (24.8 KB) per spawn — previously unmeasurable.

reducible = Σ max(0, size − TARGET), where CHARTER_TARGET = 1536 and HISTORY_TARGET = 8192 come from the targets already written in reskill/SKILL.md (lines 31 and 39) and are commented with that provenance, so they're traceable rather than magic.

Real-world datapoint

Run against this repo's own live .squad/ (220 files, 1.7 MB):

charterBytes            34,605   (reducible  8,598)
skillBytes             200,745
historyReducibleBytes           22,457
decisionBytes          120,697 →  20,311
totalBytes           1,699,041 → 1,566,550   (129 KB reclaimable by nap)

~30 KB of reskill headroom that no tool could previously report.

Safety guarantees

  1. The added code contains zero write operations. git diff | grep -E 'writeFileSync|rmSync|unlinkSync|renameSync|mkdirSync|truncate' over the added lines returns nothing. All new code is measurement and formatting.
  2. Nap measures charters and skills but never modifies them. Automated charter rewriting is an explicit non-goal — charters are agent identity. Locked in by a byte-exact assertion that after.charterBytes === before.charterBytes and after.skillBytes === before.skillBytes after a real (non-dry-run) nap.
  3. estimateAfterMetrics passes charter/skill fields through unchanged rather than fabricating deltas for work nap doesn't do — a fabricated delta would be a lie the caller couldn't distinguish from truth.
  4. Verified live: nap --dry-run --json ran against the real 220-file .squad/ above and modified zero files (confirmed by find -newermt).
  5. Archival-safety invariants untouched. The append-first → verify-by-entry-count → then-trim ordering, the refuse-on-empty guard, and isCommittableDestination (Scribe's decisions archive step deletes entries without appending them to decisions-archive.md #1774 / Archival can silently destroy state: writes to untracked destinations are deletions #1783) were declared off-limits and are unchanged.
  6. No behavior change without a flag. --json is opt-in; the dry-run banner is presentation-only. formatNapReport(result, noColor?) keeps its signature — dryRun is read off result.

Limitations (stated honestly)

  • historyReducibleBytes passes through in dry-run. The aggregate can't be exactly decomposed from per-file historyBytes deltas, so dry-run reports the pre-nap value. Honest over clever.
  • Action descriptions inside --json stay past-tense. Conditional verbs (CompressedWould compress) are applied at format time via dryRunifyDescription(). JSON consumers key on result.dryRun, not on prose. Deliberate — prose in a machine payload shouldn't be the source of truth.
  • before.totalBytes − after.totalBytes === Σ bytesSaved holds exactly in dry-run only. In a real run, compress/archive/merge move content into sibling files still under .squad/; only prune is a pure deletion. The real-run test asserts savings > 0 with the reason inline.
  • No squad reskill engine. Deliberately deferred to its own PR now that the measurement primitive exists.

Tests

test/nap-reskill-measurement.test.ts24 new tests in 7 groups (881 lines), including boundary math at 1535/1536/1537 and 8191/8192/8193, non-.md filtering in skills traversal, and dry-run vs real-run pass-through semantics.

npx vitest run test/nap.test.ts test/nap-reskill-measurement.test.ts \
  test/cli/nap-archival-safety.test.ts test/cli/nap-subprocess.test.ts \
  test/cli/command-help.test.ts test/shell-polish.test.ts
→ 121/121 passing

npm run lint   → clean
npm run build  → clean

All fixtures use mkdtempSync(join(tmpdir(), ...)) — no test touches a real .squad/.

Team

Agent Role
Flight Architecture — confirmed the four gaps with file:line evidence, rejected the parallel-engine approach, set scope and non-goals
EECOM Runtime implementation in nap.ts + all call sites (CLI, REPL, help)
Procedures Rewrote reskill/SKILL.md from estimate-based to measurement-based; verified SDK mirror parity
PAO Docs — context-hygiene.md, cli.md
Surgeon Changeset; independently confirmed NapMetrics is not publicly exported → patch
FIDO The evidentiary test suite; found no bugs (no Reviewer Rejection triggered)

⚠️ Requested specialist review: CONTROL on the NapMetrics type-surface change. Flight flagged it. NapMetrics is not re-exported from the CLI barrel nor listed in the package exports map, so adding required fields is not a public API break — hence patch. Independently verified by Flight and Surgeon, but it's a type-surface change and CONTROL owns the type system.

Notes for reviewers

  • runNap and runNapSync are near-duplicate implementations; every change landed in both or the CLI and REPL (/nap, /compact) would silently drift.
  • packages/squad-sdk/templates/skills/reskill/SKILL.md mirrors the CLI copy via scripts/sync-skill-templates.mjs (runs on prebuild). Parity verified with diff — identical.
  • Build/sync-generated churn (version bumps to -build.1, CRLF↔LF on 9 workflow-wiring-* templates) was reverted so the diff stays scoped to the 11 intended files.

Co-authored-by: Copilot App 223556219+Copilot@users.noreply.github.com

Squad's `reskill` skill asked agents to hand-write a savings table, but no
tool produced those numbers — every reskill figure was an estimate. This
makes `squad nap --dry-run --json` the measurement primitive reskill was
missing, rather than building a second engine.

- NapMetrics gains charterBytes, skillBytes, charterReducibleBytes and
  historyReducibleBytes. Reducible = sum(max(0, size - TARGET)) against the
  targets already documented in reskill/SKILL.md (1536 charter, 8192 history).
- NapResult gains `dryRun`; the report gets a dry-run banner and conditional
  verbs applied at format time, so a preview can no longer be misread as a
  completed run.
- New `--json` flag on both the CLI and the REPL `/nap` path, following the
  existing health.ts JSON precedent.
- reskill/SKILL.md now starts its audit from measured output and forbids
  invented savings figures. Mirrored to the SDK template copy.

Nap measures charters and skills but never modifies them — automated charter
rewriting stays an explicit non-goal, and estimateAfterMetrics passes those
fields through unchanged rather than fabricating deltas. The added code
introduces zero write operations.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot AI lite review requested due to automatic review settings September 2, 2026 20:59
@github-actions

github-actions Bot commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

🟠 Impact Analysis — PR #1987

Risk tier: 🟠 HIGH

📊 Summary

Metric Count
Files changed 11
Files added 2
Files modified 9
Files deleted 0
Modules touched 5

🎯 Risk Factors

  • 11 files changed (6-20 → MEDIUM)
  • 5 modules touched (5-8 → HIGH)

📦 Modules Affected

docs (2 files)
  • docs/src/content/docs/features/context-hygiene.md
  • docs/src/content/docs/reference/cli.md
root (1 file)
  • .changeset/nap-context-json-safety.md
squad-cli (5 files)
  • packages/squad-cli/src/cli-entry.ts
  • packages/squad-cli/src/cli/core/command-help.ts
  • packages/squad-cli/src/cli/core/nap.ts
  • packages/squad-cli/src/cli/shell/commands.ts
  • packages/squad-cli/templates/skills/reskill/SKILL.md
squad-sdk (1 file)
  • packages/squad-sdk/templates/skills/reskill/SKILL.md
tests (2 files)
  • test/nap-reskill-measurement.test.ts
  • test/nap.test.ts

This report is generated automatically for every PR. See #733 for details.

@github-actions

github-actions Bot commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

🏗️ Architectural Review

⚠️ Architectural review: 1 warning(s), 1 info.

Severity Category Finding Files
🟡 warning bootstrap-area 2 file(s) in the bootstrap area (packages/squad-cli/src/cli/core/) were modified. These files must maintain zero external dependencies. Review carefully. packages/squad-cli/src/cli/core/command-help.ts, packages/squad-cli/src/cli/core/nap.ts
ℹ️ info template-sync Template files changed in packages/squad-cli/templates/ but not in other template locations. If these templates should stay in sync, consider updating the others too. Changed: packages/squad-cli/templates/, Unchanged: templates/, .squad-templates/, .github/workflows/

Automated architectural review — informational only.

@github-actions

github-actions Bot commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

🛫 PR Readiness Check

ℹ️ This comment updates on each push. Last checked: commit be1d9c4

PR Scope: 📦🔧 Mixed (product + infrastructure)

⚠️ 3 item(s) to address before review

Status Check Details
Single commit 1 commit — clean history
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 4 unresolved Copilot thread(s) — fix and resolve before merging
CI passing 1 check(s) failing: test

Files Changed (11 files, +1123 −30)

File +/−
.changeset/nap-context-json-safety.md +5 −0
docs/src/content/docs/features/context-hygiene.md +15 −7
docs/src/content/docs/reference/cli.md +1 −0
packages/squad-cli/src/cli-entry.ts +11 −3
packages/squad-cli/src/cli/core/command-help.ts +3 −2
packages/squad-cli/src/cli/core/nap.ts +164 −10
packages/squad-cli/src/cli/shell/commands.ts +4 −0
packages/squad-cli/templates/skills/reskill/SKILL.md +15 −4
packages/squad-sdk/templates/skills/reskill/SKILL.md +15 −4
test/nap-reskill-measurement.test.ts +881 −0
test/nap.test.ts +9 −0

Total: +1123 −30


This check runs automatically on every push. Fix any ❌ items and push again.
See CONTRIBUTING.md and PR Requirements for details.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot review overview

🟡 Changes recommended

formatNapReport can misreport “saved” in real runs when totalBytes grows, and the new test helper doesn’t actually create an empty .squad/ directory.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Review tier: Lite
Findings: 3 Medium severity · 1 Low severity

New issues introduced by this change (4)
Severity Finding
Medium severity packages/​squad-cli/​src/​cli/​core/​nap.tstokensSaved clamps negative deltas to 0 via Math.max(0, saved), but after.totalBytes can be…
Medium severity packages/​squad-cli/​src/​cli/​core/​nap.ts — The overall summary line always says “saved/would save”, but saved can be negative in real runs…
Medium severity test/​nap-reskill-measurement.test.tscreateTestSquadDir claims to create an isolated .squad/ directory, but when structure is…
Low severity test/​nap-reskill-measurement.test.ts — PR description safety guarantee #1 says a diff grep for write/remove operations over added lines…
What changed in this PR

This PR extends the existing squad nap engine to measure the charter/skill context that “reskill” is intended to reduce, and adds a --dry-run --json output mode so reskill-style savings can be based on deterministic, tool-produced numbers rather than estimates.

Changes:

  • Add new NapMetrics fields for charterBytes, skillBytes, charterReducibleBytes, and historyReducibleBytes, plus a top-level dryRun flag on NapResult.
  • Add --json output for squad nap in both CLI and interactive shell, and improve dry-run report labeling/wording.
  • Add an evidentiary test suite for exact byte accounting + update reskill skill/docs to reference measured nap --dry-run --json values.
File Description
test/​nap.test.ts Updates report-formatting fixture to include the expanded metrics shape and dryRun.
test/​nap-reskill-measurement.test.ts New byte-exact fixture-based tests for charter/skill/reducible metrics, dry-run safety, and JSON shape.
packages/​squad-sdk/​templates/​skills/​reskill/​SKILL.md Switches reskill guidance from estimates to measured nap --dry-run --json baselines and savings.
packages/​squad-cli/​templates/​skills/​reskill/​SKILL.md Mirrors the same reskill prompt update in the CLI templates.
packages/​squad-cli/​src/​cli/​shell/​commands.ts Adds --json support for /nap in the interactive shell (sync path).
packages/​squad-cli/​src/​cli/​core/​nap.ts Implements new measurements, adds dryRun to result, dry-run banner/conditional verbs, and reducibility reporting.
packages/​squad-cli/​src/​cli/​core/​command-help.ts Updates nap help text to document --json and the dry-run labeling behavior.
packages/​squad-cli/​src/​cli-entry.ts Adds --json support to the primary CLI nap command output.
docs/​src/​content/​docs/​reference/​cli.md Documents squad nap --json in the CLI reference table.
docs/​src/​content/​docs/​features/​context-hygiene.md Expands context-hygiene docs to recommend --dry-run --json for measured reclaimable context and reskill audit.
.changeset/​nap-context-json-safety.md Patch changeset describing the new metrics, JSON output, and dry-run UX changes.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

const { before, after, actions } = result;
const { before, after, actions, dryRun } = result;
const saved = before.totalBytes - after.totalBytes;
const tokensSaved = humanTokens(Math.max(0, saved));
Comment on lines +766 to 768
const arrow = dryRun ? `${D}(would become)${R}` : `${D}->${R}`;
lines.push(` ${humanBytes(before.totalBytes)} ${arrow} ${G}${humanBytes(after.totalBytes)}${R} ${D}(${dryRun ? 'would save' : 'saved'} ~${tokensSaved} tokens)${R}`);
lines.push('');
Comment on lines +66 to +70
const tmpDir = mkdtempSync(join(tmpdir(), 'squad-nap-reskill-'));
tmpDirs.push(tmpDir);
const squadDir = join(tmpDir, '.squad');
for (const [filePath, content] of Object.entries(structure)) {
const fullPath = join(squadDir, filePath);
Comment on lines +31 to +37
import {
mkdtempSync,
writeFileSync,
readFileSync,
readdirSync,
mkdirSync,
rmSync,
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants