[PR #1749] [MERGED] fix(mcp): keep advertised inputs within client reference budgets #4791

Closed
opened 2026-10-31 00:55:06 +00:00 by bsakaguchi · 0 comments
Owner

📋 Pull Request Information

Original PR: https://github.com/morluto/rea/pull/1749
Author: @akushonkamen
Created: 10/11/2026
Status: ✅ Merged
Merged: 10/13/2026
Merged by: @morluto

Base: main ← Head: fix/1632-pi-codemode-selector-unknown


📝 Commits (3)

  • c384339 fix(mcp): keep advertised inputs within client reference budgets (#1632)
  • 37ba319 docs(mcp): count the reduced presentation set as five (#1632)
  • 712ee9f fix: reconcile main and review findings for PR #1749

📊 Changes

5 files changed (+259 additions, -8 deletions)

View changed files

📝 docs/mcp-contracts.md (+8 -5)
📝 src/contracts/inputSchemaPresentation.ts (+74 -0)
📝 src/contracts/toolInputReferences.test.ts (+105 -1)
📝 src/contracts/toolSchemaMetadata.ts (+24 -2)
📝 tests/boundary/mcp/toolSchemaValidity.test.ts (+48 -0)

📄 Description

Pi 1.1.0 code-mode renders an advertised input through a 32 shared-reference-expansion budget spanning the whole schema, degrading every reference past the limit to unknown. The input projection (src/contracts/toolSchemaMetadata.ts:65) unconditionally requested libraryOptions: { reused: "ref" }, advertising trace_application_feature as 22 $defs/26 $ref; its leading Evidence-typed field alone consumed 22 expansions (46 measured total), 17 of 170 tools exceeded the budget, and the seed selector arrived as unknown in Pi's generated declaration while the wire schema itself stayed valid.

The projection now counts conservative reference expansions — countLocalReferenceExpansions walks every schema position with a cycle guard, skipping literals and $defs; per-tool counts matched Pi's exact traversal, never under — and inputSchemaWithinReferenceExpansionBudget keeps the shared form whenever it fits the 32-expansion budget, re-projecting over-budget tools with the zod-native inline form, which carries no references for the nonrecursive schemas REA advertises, so every field renders with complete structure. 153/170 tools keep a byte-identical shared form; only the 17 tools that budget actually breaks change projection. Two measured alternatives were rejected as worse: inlining at every position (414 KB across the 17 tools vs 340 KB for the inline projection) and full inlining everywhere (the ticket's 24.9 KB figure did not reproduce; trace_application_feature measured 9,718 B). Canonical validation, output schemas and the compact mechanism are untouched. project_managed_application_graph moves out of the reduced presentation set because its full-profile inline form now fits the compact byte budget — a gain; the pinning test and docs/mcp-contracts.md are updated to match.

Divergence, stated plainly: collaborator N0zoM1z0 holds that this should be fixed on the client side, and #1162 — the shared-schema design this budget trips over — is theirs, merged two days ago. This change keeps the shared form for the 153 tools inside the budget and re-projects only the 17 that budget verifiably breaks; the numbers above are the basis for that arbitration.

Fixes #1632.

Validation (all re-run on the rebased branch after git fetch origin + rebase onto current main):

  • timeout 300 npx vitest run --project mcp-boundary tests/boundary/mcp/toolSchemaValidity.test.ts — RED on pre-fix code (new budget test + fixtures applied to the base): 1 failed / 7 passed, failing on compare_managed_members exhausts the shared reference-expansion budget: expected 42 to be less than or equal to 32. GREEN post-fix: 8/8 passed. Note: the ticket command said --project boundary, but tests/boundary/mcp/** belongs to the mcp-boundary project (vitest.config.ts:84-85), so that project was used.
  • Pi 1.1.0 schemaToType on the fixed wire captured from the compiled stdio server: cd /tmp/pi-codemode-repro && timeout 60 node repro-fixed.mjs → seed: { structured selector. Red control on the pre-fix wire (timeout 60 node repro.mjs) still renders seed: unknown;.
  • Expansion counter (countLocalReferenceExpansions) over all 170 advertised tools: 0 over 32, max 32 (was 17 over / max 543); trace_application_feature 46 → 0.
  • npx vitest run --project domain — 1713 passed / 3 skipped, 130 files (the moved base adds 3 tests vs the 1710 recorded pre-rebase).
  • npm run test:boundary — 3011 passed / 166 skipped / 4 failed: 3 pre-existing nativeDmgArtifactReader failures (real hdiutil environment: verify refusal, target access, checksum mismatch) plus 1 intermittent flake in processCaptureProgress.test.ts > reports timeout and cancellation cleanup through MCP progress — a 1 s default poll for the post-abort disposition=cancelled notification. The flake fails on this branch in isolated re-runs (3 of 9) and also on clean main (1 of 6, interleaved), and passes on immediate re-run on both; this diff (contracts projection, MCP boundary tests, docs) does not touch the process-capture path.
  • npx vitest run --project mcp-boundary — 350 passed / 2 skipped.
  • npx vitest run --project composition — 183 passed / 183.
  • npx tsc --noEmit — clean.
  • npm run lint (oxlint + module boundaries), npx knip, npx oxfmt --check . — clean.
  • npm run mcp-catalog:check — exit 0.

Disclosure: investigation and fix produced with AI assistance (a Claude Code agent operated by akushonkamen), consistent with the disclosure in the issue's claiming comment.


🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.

## 📋 Pull Request Information **Original PR:** https://github.com/morluto/rea/pull/1749 **Author:** [@akushonkamen](https://github.com/akushonkamen) **Created:** 10/11/2026 **Status:** ✅ Merged **Merged:** 10/13/2026 **Merged by:** [@morluto](https://github.com/morluto) **Base:** `main` ← **Head:** `fix/1632-pi-codemode-selector-unknown` --- ### 📝 Commits (3) - [`c384339`](https://github.com/morluto/rea/commit/c384339f3243db106887acb050c88a3ce4109d43) fix(mcp): keep advertised inputs within client reference budgets (#1632) - [`37ba319`](https://github.com/morluto/rea/commit/37ba319c8301ff0e6c25cd9459a76ce5c2a558c2) docs(mcp): count the reduced presentation set as five (#1632) - [`712ee9f`](https://github.com/morluto/rea/commit/712ee9feccd94118898d2d8b1679ac01f2405aa5) fix: reconcile main and review findings for PR #1749 ### 📊 Changes **5 files changed** (+259 additions, -8 deletions) <details> <summary>View changed files</summary> 📝 `docs/mcp-contracts.md` (+8 -5) 📝 `src/contracts/inputSchemaPresentation.ts` (+74 -0) 📝 `src/contracts/toolInputReferences.test.ts` (+105 -1) 📝 `src/contracts/toolSchemaMetadata.ts` (+24 -2) 📝 `tests/boundary/mcp/toolSchemaValidity.test.ts` (+48 -0) </details> ### 📄 Description Pi 1.1.0 code-mode renders an advertised input through a 32 shared-reference-expansion budget spanning the whole schema, degrading every reference past the limit to `unknown`. The input projection (`src/contracts/toolSchemaMetadata.ts:65`) unconditionally requested `libraryOptions: { reused: "ref" }`, advertising `trace_application_feature` as 22 `$defs`/26 `$ref`; its leading Evidence-typed field alone consumed 22 expansions (46 measured total), 17 of 170 tools exceeded the budget, and the `seed` selector arrived as `unknown` in Pi's generated declaration while the wire schema itself stayed valid. The projection now counts conservative reference expansions — `countLocalReferenceExpansions` walks every schema position with a cycle guard, skipping literals and `$defs`; per-tool counts matched Pi's exact traversal, never under — and `inputSchemaWithinReferenceExpansionBudget` keeps the shared form whenever it fits the 32-expansion budget, re-projecting over-budget tools with the zod-native inline form, which carries no references for the nonrecursive schemas REA advertises, so every field renders with complete structure. 153/170 tools keep a byte-identical shared form; only the 17 tools that budget actually breaks change projection. Two measured alternatives were rejected as worse: inlining at every position (414 KB across the 17 tools vs 340 KB for the inline projection) and full inlining everywhere (the ticket's 24.9 KB figure did not reproduce; `trace_application_feature` measured 9,718 B). Canonical validation, output schemas and the compact mechanism are untouched. `project_managed_application_graph` moves out of the reduced presentation set because its full-profile inline form now fits the compact byte budget — a gain; the pinning test and `docs/mcp-contracts.md` are updated to match. Divergence, stated plainly: collaborator N0zoM1z0 holds that this should be fixed on the client side, and #1162 — the shared-schema design this budget trips over — is theirs, merged two days ago. This change keeps the shared form for the 153 tools inside the budget and re-projects only the 17 that budget verifiably breaks; the numbers above are the basis for that arbitration. Fixes #1632. Validation (all re-run on the rebased branch after `git fetch origin` + rebase onto current `main`): - `timeout 300 npx vitest run --project mcp-boundary tests/boundary/mcp/toolSchemaValidity.test.ts` — RED on pre-fix code (new budget test + fixtures applied to the base): 1 failed / 7 passed, failing on `compare_managed_members exhausts the shared reference-expansion budget: expected 42 to be less than or equal to 32`. GREEN post-fix: 8/8 passed. Note: the ticket command said `--project boundary`, but `tests/boundary/mcp/**` belongs to the `mcp-boundary` project (`vitest.config.ts:84-85`), so that project was used. - Pi 1.1.0 `schemaToType` on the fixed wire captured from the compiled stdio server: `cd /tmp/pi-codemode-repro && timeout 60 node repro-fixed.mjs` → `seed: {` structured selector. Red control on the pre-fix wire (`timeout 60 node repro.mjs`) still renders `seed: unknown;`. - Expansion counter (`countLocalReferenceExpansions`) over all 170 advertised tools: 0 over 32, max 32 (was 17 over / max 543); `trace_application_feature` 46 → 0. - `npx vitest run --project domain` — 1713 passed / 3 skipped, 130 files (the moved base adds 3 tests vs the 1710 recorded pre-rebase). - `npm run test:boundary` — 3011 passed / 166 skipped / 4 failed: 3 pre-existing `nativeDmgArtifactReader` failures (real `hdiutil` environment: verify refusal, target access, checksum mismatch) plus 1 intermittent flake in `processCaptureProgress.test.ts > reports timeout and cancellation cleanup through MCP progress` — a 1 s default poll for the post-abort `disposition=cancelled` notification. The flake fails on this branch in isolated re-runs (3 of 9) and also on clean `main` (1 of 6, interleaved), and passes on immediate re-run on both; this diff (contracts projection, MCP boundary tests, docs) does not touch the process-capture path. - `npx vitest run --project mcp-boundary` — 350 passed / 2 skipped. - `npx vitest run --project composition` — 183 passed / 183. - `npx tsc --noEmit` — clean. - `npm run lint` (oxlint + module boundaries), `npx knip`, `npx oxfmt --check .` — clean. - `npm run mcp-catalog:check` — exit 0. Disclosure: investigation and fix produced with AI assistance (a Claude Code agent operated by akushonkamen), consistent with the disclosure in the issue's claiming comment. --- <sub>🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.</sub>
bsakaguchi 2026-10-31 00:55:06 +00:00
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
morluto/rea#4791
No description provided.