Skip to content

[FIX] Rectify: Fix #4399 — Envelope Truncation and Tool Registry Loss - #4401

Merged
Trecek merged 6 commits into
developfrom
claude-code-full-open-kitchen-returns-no-recipe-body-and-clo/4399
Jul 28, 2026
Merged

[FIX] Rectify: Fix #4399 — Envelope Truncation and Tool Registry Loss#4401
Trecek merged 6 commits into
developfrom
claude-code-full-open-kitchen-returns-no-recipe-body-and-clo/4399

Conversation

@Trecek

@Trecek Trecek commented Jul 28, 2026

Copy link
Copy Markdown
Collaborator

Summary

Issue #4399 has two independent root causes:

  1. Envelope truncation: finalize_recipe_delivery() delegates to resolve_recipe_delivery_decision(), which returns ENVELOPE mode for recipes exceeding ~46.5K tokens on Claude Code backends (protected_recipe_delivery_capable=False). The 195KB response exemption registered for open_kitchen is only consulted AFTER the delivery decision, at a different layer (enforce_response_budget), and only prevents a different downgrade (ORDINARY_INLINE→ENVELOPE for non-exempt oversized responses). The PostToolUse formatter _fmt_open_kitchen only reads ORDINARY_INLINE-shape keys (content, summary, diagram) and has zero knowledge of ENVELOPE-shape keys (step_flow_skeleton, recipe_pull), producing a degenerate ## open_kitchen ✓ v{version} with no recipe body.

  2. Tool registry loss: close_kitchen() appends permanent global mcp.disable(tags={"kitchen"}) and mcp.disable(tags={"plan-review"}) to FastMCP's append-only Provider._transforms list. The next open_kitchen() has _skip_notify=True for Claude Code backends (supports_tool_list_changed=False), so it skips ctx.enable_components() — the session-scoped enable that would override the global disable. The 41 kitchen-tagged tools permanently vanish.

Both defects share a pattern — lifecycle assumptions that hold on first use but are violated by subsequent state changes. The fix restores alignment between exemption scope and delivery decision, and tightens the visibility lifecycle so close/reopen cycles preserve the kitchen-tagged tool registry.

Requirements

  • A full open_kitchen(name="remediation") on Claude Code returns the recipe body — step flow, ingredients table and orchestration rules — not ## open_kitchen ✓ v.
  • close_kitchen() followed by open_kitchen() leaves all 41 kitchen-tagged tools callable; run_skill in particular resolves and executes.
  • A regression test asserts tool-registry survival across a close_kitchenopen_kitchen lifecycle. The existing suite passes while the registry is empty, which is why this shipped.
  • A regression test asserts the formatter renders real content for an exempt surface, rather than asserting only that it does not crash.
  • Catalog breadth is not reduced to achieve any of the above (see [Tracking] Raise Codex skills metadata budget for AutoSkillit sessions #4363, which states breadth is intentional). Bound the delivery, never the catalog.

Closes #4399

Implementation Plan

Plan file: /home/talon/projects/autoskillit-runs/fix-4362-20260727-154546-650120/.autoskillit/temp/rectify/rectify_fix_4362_envelope_truncation_and_registry_loss_2026-07-27_170000.md

🤖 Generated with Claude Code via AutoSkillit

Trecek and others added 6 commits July 27, 2026 17:53
…registry loss

- Test 1A: Verify finalize_recipe_delivery() returns ORDINARY_INLINE for exempt
  surfaces whose ordinary-rendered payload fits within the 195KB exemption
  ceiling. Boundary cases: payload exceeding ceiling → ENVELOPE; non-exempt
  surface (get_recipe) → ENVELOPE.
- Test 1B: Strengthen test_rendered_open_kitchen_payload_under_budget to
  assert the rendered output contains recipe content (not just byte-size
  compliance) for recipes whose ordinary-rendered payload fits within the
  ceiling.
- Test 1C: After close_kitchen() hides pre-revealed kitchen tools, verify
  that a subsequent open_kitchen() with _skip_notify=True (Claude Code
  backend) restores all kitchen-tagged tools to visible.

These tests fail before the fix in Steps 2A/2B and pass after.
When an exempt surface's ordinary-rendered payload fits within the
registered exemption ceiling, upgrade ENVELOPE back to ORDINARY_INLINE
so the full recipe body survives. Placed after ALL ENVELOPE-producing
branches (initial resolve, response-budget downgrade, receipt-store-
missing downgrade, reservation-failure downgrade) so the override
catches every path.

Without this, exempt surfaces like open_kitchen on Claude Code
(protected_recipe_delivery_capable=False) get ENVELOPE for any payload
exceeding the 46.5K ordinary_limit, producing a degenerate formatter
output with no recipe body.

Co-Authored-By: Claude <noreply@anthropic.com>
When the backend can't process tool/list_changed notifications
(Claude Code), the _skip_notify branch in open_kitchen only logged a
debug message without re-enabling kitchen and plan-review tags. After
close_kitchen() appends global mcp.disable() for these tags, the
skipped re-enable left tools invisible.

Replace the log-only branch with explicit global mcp.enable() calls
for both tags, using FastMCP's last-match-wins semantics to override
the prior disables. _redisable_subsets() runs immediately after to
re-apply config-disabled subsets as session-scoped disables, so
dual-tagged tools don't leak.

Co-Authored-By: Claude <noreply@anthropic.com>
- _recipe_delivery.py: scope ENVELOPE→ORDINARY override to backends without
  recipe_delivery_budget (Claude Code) only; Codex keeps bounded envelope
  semantics. Inject success=True into candidate_payload once so ORDINARY_INLINE
  always carries the wire-shape success indicator.
- test_subpackage_isolation.py: bump tools_kitchen.py line-limit exemption to
  1700 for the +2-line global-enables refresh; extend reason with #4399 note.
- test_schema_version_convention.py: shift legacy JSON write line 1453→1460
  to match the post-fix tools_kitchen.py file shape.
- test_tools_kitchen_visibility.py: patch _get_ctx inside close_kitchen call so
  _close_kitchen_handler operates on the mocked ctx (it reads from _get_ctx,
  not the ctx parameter).
- test_tools_recipe_pull.py: clamp oversized payload to ceiling - 1000 to
  keep the test below the open_kitchen exemption ceiling irrespective of
  downstream ceiling changes.

Co-Authored-By: Claude <noreply@anthropic.com>
…rojection

- tests/arch/test_subpackage_isolation.py: bump _LINE_LIMIT_EXEMPTIONS for
  server/_recipe_delivery.py from 1100 to 1150. The #4399 ENVELOPE→ORDINARY
  override (scope check + byte budget + decision.replace; ~18 net lines) and
  success=True injection on candidate_payload (~8 net lines) brought the file
  to 1129 lines. Add a per-line rationale citing both #4399 code paths.
- tests/infra/test_pretty_output_recipe.py: the test_rendered_open_kitchen_payload_under_budget
  content gate (#4399 Test 1B) compared the raw YAML against the rendered
  output, but _fmt_recipe_body applies compact_recipe_display (strips
  top-level name/description/summary/recipe_version and step descriptions,
  halves structural indentation) AND additionally strips the YAML
  ingredients: block when ingredients_table is present. Mirror both
  projections inline before substring-matching:
    1. Inline a localized _strip_yaml_ingredients_block (production helper
       uses bare relative imports, not directly importable from the test
       harness which uses autoskillit.* imports).
    2. Strip ingredients when ingredients_table is present, then run
       compact_recipe_display, then substring-check the rendered output.
  This catches both #4399's original failure mode (formatter receives
  envelope → no recipe body) and the order-of-operations correctness of the
  formatter chain.

Co-Authored-By: Claude <noreply@anthropic.com>
@Trecek
Trecek added this pull request to the merge queue Jul 28, 2026
Merged via the queue into develop with commit 92873e7 Jul 28, 2026
3 checks passed
@Trecek
Trecek deleted the claude-code-full-open-kitchen-returns-no-recipe-body-and-clo/4399 branch July 28, 2026 02:13
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.

1 participant