* docs(#3025): MCP tool schema as a context-budget concern
Adds documentation covering the largest GSD cost lever that GSD
itself does not own: MCP tool schema injection. Every enabled MCP
server adds its schema to every turn (often 20k+ tokens for
heavyweight servers like browser/playwright, mac-tools, etc.),
which can dwarf whatever `model_profile` tuning saves.
Two doc surfaces (per the bundle-docs-with-code skill depth gradient):
1. get-shit-done/references/context-budget.md
- New "MCP Tool Schema Cost (Harness Concern)" section.
- Explains schemas-per-turn cost framing.
- Names enabledMcpjsonServers / disabledMcpjsonServers and
.claude/settings.json explicitly.
- Pre-phase audit checklist: browser/playwright, platform-specific,
cross-project/stale, duplicate/shadow.
- Explicit "GSD does not manage MCP enablement — harness concern"
statement so users don't hunt for a GSD setting.
- Links to Anthropic Claude Code MCP docs as canonical reference.
- Notes compounding interaction with model_profile (additive levers).
2. docs/USER-GUIDE.md
- New task-oriented "Trim MCP servers to reduce per-turn cost"
section above "Using Non-Claude Runtimes".
- Same checklist condensed.
- Cross-link to context-budget.md for the full reference.
Tests:
- tests/feat-3025-mcp-token-budget-docs.test.cjs (12 cases) parses
both docs into typed semantic-flag records and asserts behavioral
invariants (mentions key, includes audit, names harness, etc.)
rather than substring-matching prose. Adheres to CONTRIBUTING.md
no-source-grep — section can be reworded freely as long as the
required semantics survive.
- Markdownlint pre-flight tests (MD040 fence language, MD056 table
column count) per the bundle-docs-with-code skill so CR can't
ratchet on prose nitpicks across multiple review rounds.
Verification:
- 12/12 pass on regression test
- 6857/6857 full suite (12 net new)
- lint-no-source-grep clean (377 test files)
Companion to #3023 (per-phase-type model map) and #3024 (dynamic
routing). Together they cover the three biggest cost levers users
ask about; this issue covers the one GSD does not own.
Closes#3025
* docs(#3025): batch 3 CR fixes — pr id, relative link, named flag
CodeRabbit on PR #3032 (3 minor — 2 inline + 1 nitpick), all in one
push per the bundle-docs-with-code skill (avoid per-round nitpick
ratchet):
1. Inline (Minor) — .changeset/mcp-token-budget-docs.md:3
`pr: TBD` → `pr: 3032` so changeset tooling can link the entry.
2. Inline (Minor) — docs/USER-GUIDE.md:1101
Used a hardcoded `https://github.com/.../blob/main/...` URL for the
cross-link to `context-budget.md`. Rest of USER-GUIDE.md uses
relative links. Switched to `../get-shit-done/references/context-
budget.md#mcp-tool-schema-cost-harness-concern` so feature-branch
work shows the right content and rename-resilience is preserved.
3. Nitpick — tests/feat-3025-mcp-token-budget-docs.test.cjs:234
The cross-link assertion used an inline `/context-budget/i.test(...)`
while every other invariant in the file lived as a named flag in
`parseMcpBudgetSection`. Per CONTRIBUTING.md no-source-grep, added
`crossLinksContextBudget` to the parser and asserted on
`parsed.crossLinksContextBudget` so the cross-link rule sits next
to its siblings.
Verification:
- 12/12 pass on regression test (no count change; refactor only)
- No source code changes, only docs + tests
* test(#3025): strip inline markdown before phrase-match (CR nitpick)
CodeRabbit caught that the `explainsHarnessNotGsd` primary regex
branch couldn't match "GSD does **not** manage" in
context-budget.md because the markdown bold markers (`**`) sit
between contiguous words. The test passed today only via the
fallback `harness (concern|setting|controlled)` branch — the
primary branch was effectively dead code.
Fix: strip inline markdown emphasis (`**`, `*`, `~~`) and inline-
code backticks before any phrase-matching in `parseMcpBudgetSection`.
All seven flag computations now run against the stripped text so
markdown formatting can't silently invalidate any invariant.
Underscores are intentionally NOT stripped — `model_profile` and
other snake_case identifiers must survive intact for the
mentionsModelProfileInteraction check to find them.
Verification: 12/12 still pass; primary branches now fire on
real markdown content rather than relying on fallbacks.
* test(#3025): guard markdownlint tests against null section (CR nitpick)
CodeRabbit caught that the MD040 and MD056 markdownlint pre-flight
tests called `section.match(...)` and `section.split('\n')`
directly on the value returned by `extractSection`, which returns
null when no matching header is found. If the MCP section is ever
removed (regression), both tests would throw `TypeError: Cannot
read properties of null` instead of producing a clean assertion
failure naming the actual problem.
The semantic tests above are protected because parseMcpBudgetSection
short-circuits to a typed-falsy record on null input. The
markdownlint tests bypassed that guard since they need raw section
text, not parsed flags. Added `assert.ok(section, ...)` preconditions
to both so a missing section produces a meaningful failure message.
No content changes; defensive programming only.
Verification: 12/12 still pass.