Skip to content

refactor(acp): split oversized service into focused modules - #67

Open
yan-ad wants to merge 5 commits into
Blankeos:mainfrom
yan-ad:refactor/acp-service-modules
Open

yan-ad wants to merge 5 commits into
Blankeos:mainfrom
yan-ad:refactor/acp-service-modules

Conversation

@yan-ad

@yan-ad yan-ad commented Oct 13, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Split src/acp/service.rs into a private service/ module tree without changing behavior. The original file is 5,549 lines at the updated #64 head; service/mod.rs is now 190 lines and every extracted file is now at most 374 lines, including adjacent test files.

Depends on #64. This branch starts from #64's current head, including the compaction-mode tooltip follow-up. Please merge #64 first; until then GitHub's diff against main also includes that prerequisite. The refactor commits are above #64; the latest follow-up further narrows module responsibilities.

Closes #65.

Module boundaries

  • mod.rs: service/session state, capabilities, shared cancellation and error helpers.
  • sessions.rs: new/load/resume/fork/list/close/delete/cancel and persisted attachment handling.
  • prompt.rs and stream.rs: prompt preparation, execution, stream events, transcript recording, and turn finalization.
  • compaction.rs: explicit/automatic compaction, summary generation, transcript replacement, and notifications.
  • usage.rs: provider context measurements, live usage, cumulative billing, and ACP usage updates.
  • config.rs: MCP config, modes, model/reasoning selection, limits, and picker descriptions.
  • commands.rs: command advertisement, expansion, and side questions.
  • attachments.rs: input conversion, image/audio storage, and rollback guard.
  • permissions.rs, questions.rs, and terminals.rs: permission previews/grants, elicitation, and client-terminal bridging/cleanup.
  • notifications.rs: text/tool projections, locations/diffs/media, and transcript replay.
  • test_support.rs: shared test fixtures, compiled only under cfg(test).

Tests move alongside their owners; stdio integration tests stay in tests/acp_stdio.rs. Production imports are explicit, child modules remain private, sibling-used helpers use pub(super), and the server-facing service::AcpService API is unchanged.

Behavior preservation

No changes to function bodies, public signatures, lock scopes, persistence ordering, cancellation handling, compaction thresholds, context-versus-billing semantics, or terminal cleanup. Compared all 202 functions/methods/types/fixtures/tests against #64 using Rust syntax parsing: production function and method bodies are token-identical; moved test bodies differ only in formatting-only trailing commas. Only internal type/field visibility and import/module placement change.

Validation

  • cargo test acp:: --bin crabcode: 76 passed.
  • cargo test session::compaction:: --bin crabcode: 21 passed.
  • cargo test --test acp_stdio: 8 passed, including automatic compaction and serialized mode descriptions.
  • cargo fmt --all -- --check and git diff --check: passed.
  • Serial full-unit run before the tooltip follow-up: 1,850 passed, 3 ignored, one existing unrelated failure in ui::components::chat::tests::test_edit_tool_renders_codex_style_diff_summary. It embeds /Users/carlo/Desktop/Projects/crabcode and expects a basename on other checkouts; the same failure is documented in fix(acp): trigger automatic compaction from provider context usage #64.

Synced to yan-ad/crabcode:yan-flavor (refactor commit ac52d96, latest smaller-module sync head ca801fe), preserving that branch's older lifecycle implementation and concurrent install/upgrade changes. Flavor validation: 61 ACP tests, 21 compaction tests, and 4 stdio tests pass. Five consecutive parallel stdio runs pass after test-only fixtures eliminated models.dev and Ollama discovery dependencies. All 181 flavor functions/types/fixtures/tests are preserved, with function and test bodies token-identical to the flavor baseline.

Follow-up: smaller source chunks

The smaller-module follow-up (3189129) separates models, modes, and MCP config; tool content, tool locations, and replay; attachment storage; command expansion; permission previews; context accounting; transcript recording; and compaction summary construction. Long lifecycle tests are in adjacent service/tests/ files, still compiled as child modules of their owners.

This is source organization, not Rust minification or a change to model context size. Related execution flows remain intact rather than splitting functions to satisfy an arbitrary line count. Upstream's largest file is now 374 lines (previously 622); the shared core remains 202 lines. The adapted flavor retains its existing 521-line prompt flow, with all other files at most 349 lines.

Validation after this follow-up: upstream 76 ACP tests, 21 compaction tests, and 8 stdio tests; flavor 61 ACP tests, 21 compaction tests, and 4 stdio tests. Both stdio suites pass in three consecutive complete runs. Formatting and whitespace checks pass. A separate upstream test-only follow-up (bbea752) isolates mock compaction from runtime-provider discovery without altering authentication tests.

yan-ad added a commit to yan-ad/crabcode that referenced this pull request Oct 13, 2026
Adapt PR Blankeos#67 to yan-flavor without changing its session storage, cancellation, or stream finalization behavior.
yan-ad added a commit to yan-ad/crabcode that referenced this pull request Oct 13, 2026
Sync PR Blankeos#67 follow-up while preserving yan-flavor prompt and cancellation behavior.
@Blankeos

Blankeos commented Nov 7, 2026

Copy link
Copy Markdown
Owner

refactor/acp-service-modules → main
Model: claude-sonnet-5-5, effort unknown

Confidence: 4/5

Pure file split of src/acp/service.rs into a private service/ tree. I could not find any behaviour change, and build, fmt and the ACP tests are green. Held at 4 because it is stacked on open #64 and will collide with three other open PRs.
Checks run:

  • cargo fmt --check: clean.
  • cargo build: ok, 0 warnings.
  • cargo test --bin crabcode acp::: 76 passed (3 runs).
  • cargo test --test acp_stdio: 8 passed (2 runs). One run under heavy parallel load failed login_with_piped_stdin_fails_promptly..., a timing test this PR does not touch. It passed on rerun.
  • Whole cargo test --bin crabcode, serial (--test-threads=1): 1851 passed, 1 failed, 3 ignored. The one failure is ui::components::chat::tests::test_edit_tool_renders_codex_style_diff_summary, a hard-coded /Users/carlo/... path that fails on any other checkout. It is not caused by this PR and the PR notes it.
  • Whole cargo test in parallel: 3 to 6 flaky failures per run, varying run to run. They are model::discovery, model::catalog, command::handlers and ui::chat finalize-TPS tests, all in files this PR does not touch, and they look like shared global state or timing. One run also failed acp::service::stream::...cancelled_permission..., which passed alone and in 3 later acp:: runs. This was on a loaded machine, so I am not calling it a regression, but the new service/tests/stream.rs is timing-sensitive.
  • Behaviour-preservation check of my own: I compared the old service.rs (at fix(acp): trigger automatic compaction from provider context usage #64 head 4a4f25a) against the concatenated new files, ignoring whitespace, pub(super)/pub visibility and trailing commas. Differences are use/mod lines and re-indentation of test code. No production logic change found.
  • Ran the built binary for real: crabcode acp over stdio with a temp XDG_* and CRABCODE_TEST_MODE=1. initialize returned the same capabilities (loadSession, list/delete/fork/resume/close), session/new returned modes, config options and available_commands_update, and session/list returned [].
  • Clippy: 9 findings fall in src/acp/service/*, all in moved code (sort_by_key, MutexGuard across await, collapsible if, 9 args, assert_eq! with a literal bool). None are new logic. The repo-wide 176 errors are the known pre-existing set.
  • No UI or TUI change, so no screenshots.
    Confidence bumps: none left that I can do. Re-checking after fix(acp): trigger automatic compaction from provider context usage #64 lands would be cheap, because the diff against main then shrinks to the real refactor (no score change expected).

Summary

Splits the 5.5k-line src/acp/service.rs into 25 private modules plus 3 test files, with the largest file at 374 lines. The public service::AcpService API is unchanged. The commits on top of #64 only move code, narrow visibility to pub(super), and add test fixtures (test_support.rs, a mock auth.json in tests/acp_stdio.rs).

Notes:

Map

flowchart TD
  M[service/mod.rs: AcpService, AcpSessions] --> S[sessions.rs]
  M --> P[prompt.rs] --> ST[stream.rs] --> T[transcript.rs]
  P --> A[attachments.rs + attachment_storage.rs]
  M --> C[compaction.rs + compaction_summary.rs] --> U[usage.rs + context.rs]
  M --> CF[config.rs + models.rs + modes.rs + mcp_config.rs]
  M --> CM[commands.rs + command_expansion.rs]
  M --> PQ[permissions.rs + permission_preview.rs + questions.rs + terminals.rs]
  M --> N[notifications.rs + tool_content.rs + tool_locations.rs + replay.rs]
  M --> TS[test_support.rs + tests/*]
Loading

Start at service/mod.rs, then prompt.rs and stream.rs.

Regressions

Migrations

None. No schema, config or wire change.

Before merging

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.

refactor(acp): split oversized service.rs into focused modules

2 participants