Skip to content

feat(factory): wire per-role reasoning_effort from LlmConfig through spawn pipeline#4

Merged
pippenz merged 3 commits into
mainfrom
factory/fast-hawk-76
May 2, 2026
Merged

feat(factory): wire per-role reasoning_effort from LlmConfig through spawn pipeline#4
pippenz merged 3 commits into
mainfrom
factory/fast-hawk-76

Conversation

@pippenz
Copy link
Copy Markdown
Owner

@pippenz pippenz commented May 2, 2026

Summary

  • Threads reasoning_effort config per-role (supervisor/worker) through the full factory spawn pipeline, mirroring the existing model pattern
  • Both spawn paths covered: Mux::factory() (static init) and FactoryCore::spawn_supervisor/spawn_worker() (dynamic)
  • Role-based defaults updated to match origin/main: xhigh for supervisor, high for worker when no config set
  • Autofix applied: FactoryCore::new now also calls mux.set_worker_model() for symmetry with set_worker_effort()
  • Rebased onto af5358a (v2.11.0); all new test call sites from origin/main updated for new 9-arg PtyConfig::claude/codex signatures

Files changed

  • crates/cas-pty/src/pty.rs — added effort: Option<&str> param; unwrap_or defaults to xhigh/high; 10 new test call sites updated
  • crates/cas-mux/src/pane/mod.rs — forwarded effort through Pane::supervisor() and Pane::worker()
  • crates/cas-mux/src/mux.rs — added supervisor_effort/worker_effort to MuxConfig; stored worker_effort in Mux for dynamic spawn
  • crates/cas-factory/src/config.rs — added supervisor_effort/worker_effort to FactoryConfig
  • crates/cas-factory/src/core.rs — wired worker_effort and worker_model through FactoryCore::new()
  • cas-cli/src/cli/factory/mod.rs, daemon.rs — reads from LlmConfig::reasoning_effort_for_role()
  • cas-cli/src/ui/factory/app/init.rs, daemon/fork_first.rs — forwarded through MuxConfig

Test plan

  • 3 new unit tests in pty.rs: custom effort, supervisor default (xhigh), worker default (high)
  • All 37 cas-pty tests pass
  • cas-mux and cas-factory packages compile and test clean
  • Full cas crate compiles (warnings only, pre-existing)
  • Verifier approved (confidence 0.95)
  • Code review: no P0 findings; 1 P2 safe_auto autofix applied; follow-up tasks created

Closes: cas-63d9

🤖 Generated with Claude Code

pippenz and others added 3 commits May 2, 2026 16:18
…ugh PtyConfig::claude

test-first gate: new tests verify that:
- custom effort value (e.g. "low") is used when provided
- supervisor defaults to "high" when effort=None
- worker defaults to "medium" when effort=None

These tests require the new `effort: Option<&str>` parameter on
PtyConfig::claude which does not exist yet — compilation failure
is the expected failing state.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
… factory spawn

Reads `llm.supervisor.reasoning_effort` / `llm.worker.reasoning_effort`
from `.cas/config.yaml` and threads the value all the way to the `--effort`
flag passed to Claude CLI at spawn time.

Changes:
- cas-pty: add `effort: Option<&str>` to PtyConfig::claude and PtyConfig::codex;
  replace hardcoded high/medium with role-based fallback that respects the config
  value when set (backward-compatible: None → "high" for supervisor, "medium" for worker)
- cas-mux: add `effort` param to Pane::worker() and Pane::supervisor();
  add supervisor_effort/worker_effort to MuxConfig and Mux, wire through
  factory() and add_worker()
- cas-factory: add supervisor_effort/worker_effort fields to FactoryConfig;
  wire into FactoryCore::new() (set_worker_effort) and spawn_supervisor()
- cas-cli: populate the new FactoryConfig fields via
  llm.reasoning_effort_for_role() in both factory entry points (mod.rs + daemon.rs)
  and propagate through the two MuxConfig construction sites (init.rs + fork_first.rs)

Also fixes pre-existing incorrect test assertion in test_pty_config_claude_with_teams
which claimed workers should NOT have --session-id (they always do).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
FactoryCore::new was calling set_worker_cli and set_worker_effort but
missing set_worker_model, leaving worker model config silently ignored
when using the dynamic-spawn path.

Detected and applied by cas-code-review autofix loop (round 1).
Refs: cas-63d9

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@pippenz pippenz merged commit a47dc84 into main May 2, 2026
@pippenz pippenz deleted the factory/fast-hawk-76 branch May 2, 2026 20:23
pippenz added a commit that referenced this pull request May 12, 2026
P2 #4 — show_help was missing from alt_screen_scroll_input guard. When
the help overlay is open and the focused pane is in alt-screen, wheel
events were incorrectly forwarded to the inner PTY. Fix: add
`|| self.show_help` to the suppression guard and update the doc comment
to enumerate all overlay conditions.

P2 #5 — PgUp (ESC [ 5 ~) and PgDn (ESC [ 6 ~) were not forwarded in
alt-screen mode; the generic ESC handler only consumed the first byte
(bare 0x1b) and left the remaining [5~ as stray ASCII. Fix: add a
dedicated 4-byte sequence check in client_input.rs before the arrow-key
check. In alt-screen mode, the full native sequence is forwarded via
mux.send_input; outside alt-screen, handle_scroll_up/down is called
(same behavior as mouse wheel). Satisfies AC #1 ("same on PgUp").

Added FactoryApp::for_test() — #[cfg(test)] minimal constructor that
builds a FactoryApp without spawning PTYs or opening files, enabling
unit tests for guard logic at the FactoryApp layer.

Tests added:
- sidecar_and_selection::tests (11 new unit tests):
  - Baseline: returns Some when guard clear + pane in alt-screen
  - show_help guard blocks forwarding (P2 #4)
  - MC + mc_focus==None guard blocks forwarding (P1 #1 regression)
  - MC + mc_focus==Workers guard blocks forwarding
  - PgUp/PgDn dispatch fires when alt-screen active (P2 #5)
  - PgUp/PgDn fall through to handle_scroll when NOT in alt-screen
  - Wheel scroll no-regress when not in alt-screen (AC #3)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
pippenz added a commit that referenced this pull request May 13, 2026
The `FactoryApp::for_test()` constructor itself was already shipped in
commit 53a7bf4 (cas-d5fa P2 fix) on 2026-05-07 — the same day cas-11b0
was opened. The structural AC bullets (cfg(test)-gated, Mux::new vs
Mux::factory, in-memory stubs, DirectorStores=None, all dialogs=false,
sidecar_focus=None, factory_view_mode default) are all satisfied; 8
tests in `sidecar_and_selection` already exercise the constructor and
pass on main.

The one remaining AC bullet — "document which fields need special
handling (Notifier, PaneGrid, DirectorEventDetector, etc.)" — was the
only meaningful unfinished work. Expand the docstring from 3 lines to
a structured field-handling note covering the ~10 fields with
non-obvious construction reasoning: `mux` (new vs factory), the
DirectorEventDetector `.initialize` sequence, `director_stores=None`
contract, the empty DirectorData literal, theme/notifier inert
defaults, the cas_dir/project_dir placeholder warning, and the
"keep terminal_cols/rows in sync with the Mux dimensions" pitfall.

Also adds the canary clause: "If you add a field to FactoryApp, you
must also add it here — the test constructor will fail to compile
otherwise, which is the intended canary." This makes the rolling cost
of `FactoryApp::for_test` legible to anyone adding new fields.

No code changes; docs-only. All 25 ui::factory::app tests still pass.

This is commit #4 on factory/daring-swan-93 (dc95458 cas-f645 +
16f5ba8 cas-ec8f main + b48706c cas-ec8f amendment + this), per
supervisor instruction not to rebase. Cherry-pick split at merge time
still works.
pippenz added a commit that referenced this pull request May 13, 2026
…screen

cas-72c3 was the deferred test rider for cas-d5fa, blocked on cas-11b0
(FactoryApp::for_test constructor). Per cas-11b0's close note, the
for_test() constructor + 8 unit tests at the FactoryApp layer already
shipped in 53a7bf4 (same day cas-d5fa landed), covering:

  - AC #1 (MC + mc_focus==None + alt-screen → no forward):
      scroll_blocked_by_mc_focus_none
  - AC #2 (show_help + alt-screen → no forward):
      scroll_blocked_by_show_help
  - AC #4 (non-alt-screen no-regress):
      wheel_scroll_no_regress_when_not_in_alt_screen

The genuinely uncovered slice was AC #3 — the daemon-dispatch path in
`client_input.rs` lines 157-187 that maps `MouseScrollUp` to either
`diff_scroll_up()`, `mux.send_input(SCROLL_UP_ARROWS)`, or a no-op,
depending on `show_changes_dialog` and `handle_scroll_up()`'s return.
That branch lives inside a deep `tokio::select!` and can't be exercised
directly from a unit test without spinning up the full client loop, so
this commit pins the three contracts the daemon relies on instead:

1. scroll_arrow_consts_have_exact_byte_shape_cas_72c3
   Asserts SCROLL_UP_ARROWS == `ESC[A` × SCROLL_LINES and
   SCROLL_DOWN_ARROWS == `ESC[B` × SCROLL_LINES. Pre-cas-72c3 the
   only structural assertion (line ~37) checked length, not bytes; a
   typo could silently break wheel forwarding without firing any
   guard.

2. scroll_changes_dialog_blocks_alt_screen_forwarding_cas_72c3
   With both show_changes_dialog AND alt-screen active, `handle_scroll_up`
   must return `Done` (not `AltScreen`). That's the post-condition the
   daemon's outer `if self.app.show_changes_dialog` branch relies on
   to early-return without forwarding arrows to the PTY. Pins both
   up and down directions.

3. daemon_dispatch_table_for_mouse_scroll_up_cas_72c3
   Table-driven mirror of the daemon's three-way decision (`diff`,
   `alt`, `noop`), asserted against five FactoryApp state shapes. Any
   future drift in either the daemon dispatch or `handle_scroll_up`'s
   return contract fails the test row that no longer maps correctly.

All 11 sidecar_and_selection tests (8 pre-existing + 3 new) pass.
Test-only diff; no production code touched.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
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