Skip to content

composition detail=true: soft-cap co-occurrence, spill the full dump to full_result_path - #140

Merged
cafzal merged 1 commit into
mainfrom
claude/composition-detail-path
Aug 4, 2026
Merged

composition detail=true: soft-cap co-occurrence, spill the full dump to full_result_path#140
cafzal merged 1 commit into
mainfrom
claude/composition-detail-path

Conversation

@cafzal

@cafzal cafzal commented Aug 4, 2026

Copy link
Copy Markdown
Owner

Defect

explore composition detail=true on a large frontier blows past the MCP tool-result ceiling — the payload is truncated by the transport or unusable. Measured engine-direct on the bundled examples: capital_project_selection_300 returns 5,253 co-occurrence pairs, 413 KB (~100k tokens); research_cohort_selection 2,346 pairs / 193 KB.

Root cause

detail=true's only effect on composition is lifting the co-occurrence top-N from a summary handful (8) to every sometimes-but-not-always option pair — O(options²) — and the server returned that list inline with no cap, unlike its siblings (solutions detail=true and, since #129, marginal_analysis detail=true), which soft-cap and spill to disk.

Fix

The exact treatment #129 gave marginal_analysis, same conventions throughout:

  • mcp_server/server.py: new _cap_composition_detail beside _cap_marginal_detail — past EXPLORE_DETAIL_CAP pairs, the full payload is written via store.write_run_result(problem_id, f"{run_id}-composition", result) (same path scheme as {run_id}-marginal), the response carries full_result_path, and an unwritable data dir degrades best-effort to the full inline payload. Wired into the composition case exactly as the marginal_analysis case is.
  • engine/explorer.py: new cap_composition_detail beside cap_marginal_detail — keeps the top-max_rows pairs (the list is already ranked by departure from independence, so the head is the summary view scaled up; the ASCII visualization never reads the pair list, so no re-render is needed) and echoes truncated: {total_pairs, shown}, mirroring marginal's truncated block. Nothing mutated — the caller keeps the full payload for the on-disk dump.
  • Surface prose: the explore docstring's full_result_path paragraph and the composition action entry, architecture.md's composition row, and solution_interpreter's co_occurrence field row all name the behavior.

Result on the showcase: 413 KB → ~35 KB inline plus full_result_path.

Tests

Written failing against main's behavior first, in tests/test_server.py::TestComposition mirroring TestMarginalAnalysis's inline/spill pair:

  • test_small_frontier_detail_stays_inline — no cap, no path on a small frontier.
  • test_large_frontier_detail_writes_full_result_path — on capital_project_selection_300: inline list == EXPLORE_DETAIL_CAP, truncated totals, inline JSON < 100 KB, the on-disk file parses, carries the full pair list with no truncated marker, and the inline pairs are the head of the ranked full list.

Full suite: 1049 passed, 2 skipped.

…to full_result_path

On a large frontier the detail=true co-occurrence list is every
sometimes-but-not-always option pair — O(options^2), 413 KB on the
300-option showcase — which blows past the MCP tool-result ceiling.
Mirror marginal_analysis detail=true (PR #129): past EXPLORE_DETAIL_CAP
pairs the response keeps the top-ranked head of the list (already ranked
by departure from independence, so the head IS the summary view scaled
up), echoes truncated {total_pairs, shown}, and writes the full payload
beside the run's own result file, pointed at by full_result_path — same
field, same <run_id>-composition path scheme, same cap, same best-effort
degradation on an unwritable data dir. Explore docstring, architecture.md
composition row, and the solution_interpreter field table say so.
@cafzal
cafzal force-pushed the claude/composition-detail-path branch from 34ccbb3 to a2e3803 Compare August 4, 2026 02:18
@cafzal
cafzal merged commit 2faab88 into main Aug 4, 2026
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