Prepare CodeWhale v0.8.68 release candidate#4361
Conversation
Extract the Tasks, To-do, and worker ledger into an owned work-surface module with stable focus, scrolling, mouse actions, compact overflow, and safe cancellation. Keep Classic as the rollback shell while removing the migrated underwater strip from the legacy sidebar. Make route billing distinguish metered API usage from OAuth, token-plan, and local routes; align direct startup, mode truth, slash-model performance, modal stack safety, hermetic tests, PTY gates, and atomic dogfood receipts.
Add configurable top/left/right Ocean work-surface placement while preserving Classic and narrow-terminal fallbacks. Unify exact-route provider readiness across provider/model/Fleet/setup surfaces, keep saved private models visible, and prevent OAuth, endpoint, model, or custom-provider health leakage. Retire visible legacy mode vocabulary while retaining compatibility aliases and strengthen hermetic/product-language gates.
Integrate the underwater TUI renovation, coherent work surfaces, provider and settings flows, truthful runtime receipts, terminal session persistence, motion contracts, and release QA coverage. Verified with locked workspace clippy/tests, focused PTY/runtime suites, and a production release build before publication.
f3e3213 to
ed77493
Compare
Gate Unix-only terminal session code so Windows builds do not fail under -D warnings. Resolve the remaining candidate lint and diff hygiene failures without changing runtime behavior.
Classify project approval, sandbox, and shell provenance using the same non-escalation rules as startup. Carry persisted approval policy into the live Config and apply setup posture files transactionally with rollback before mutating runtime state.
Keep printable input owned by the composer, mask links beneath modal surfaces, route model settings through the real picker, and retain config search state across live rebuilds. Hide the unready Operate affordance while preserving parse compatibility. Separate terminal frame-rate constraints from reduced-motion semantics so underwater motion and stream delivery remain truthful.
Replace model-facing context-management UI tutorials and cache-price narration with a compact inspect-edit-verify-finish contract. Keep compaction and prompt accounting host-owned, preserve repository law and approval boundaries, and expose the lean layer in prompt inspection.
Prioritize every selectable option over secondary detail at the minimum supported terminal size, and keep catalog-backed model rows routed through the full picker. Isolate config and transcript fixtures from host settings so the full TUI suite remains deterministic under parallel execution.
Route configuration preview events through a small dispatcher path so debug TUI builds do not exhaust the macOS main-thread stack when a live theme changes. Make release PTY readiness semantic under ambient ocean motion and fail with process logs if palette preview exits.
Run the async Codewhale owner on an explicit 16 MiB stack after process hardening and panic-hook setup, preventing debug builds from overflowing on modal events. Strengthen real-PTY approval mouse coverage across resize and freeze decoration in state-transition scenarios.
|
Claude finished @Hmbown's task in 1m 31s —— View job Reviewing PR #4361 (v0.8.68 release candidate)
Todo list
|
Keep terminal-specific motion tests independent from the legacy Windows console heuristic, pin the cadence test to its authored motion inputs, and serialize managed config paths as valid TOML on Windows. Exercise settings migration through persisted values so runtime terminal overlays cannot mask the migration contract. Signed-off-by: Hunter B <hmbown@gmail.com>
|
Claude finished @Hmbown's task in 9m 19s —— View job Reviewing PR #4361 (v0.8.68 release candidate)Todo list
This is a 100-file, ~25.7k-line diff, so I fanned review out across three areas: provider/routing/billing safety, engine/runtime-contract correctness, and the TUI layer (config persistence, motion, mouse/keyboard). Inline comments are posted on the 5 most concrete findings; summary below. 1. Correctness bugs
2. Provider/model/route safety (EPIC #2608 invariant)No violations found. This is the area I scrutinized hardest given the two large new files (
One edge case worth a look: 3. Reuse / simplification
4. Tests
5. SecurityNothing new stood out — no secret-handling, shell/exec-policy, or input-validation regressions found in the reviewed subsystems. Good choices worth noting
|
| let control_allows_change = if persist { | ||
| control.editable_root() | ||
| } else { | ||
| matches!(control, crate::config::ApprovalPolicyControl::Unset) | ||
| }; |
There was a problem hiding this comment.
Correctness: approval_mode's session-only (persist == false) editability requires control to be exactly ApprovalPolicyControl::Unset (line 1517-1518), whereas the parallel allow_shell branch below (line 1586) calls control.editable_root() unconditionally, regardless of persist. That means a session-only toggle of allow_shell is permitted whenever editable_root() returns true (e.g. under RootConfig), but the equivalent session-only toggle of approval_mode is rejected in that same state. This is an unflagged behavioral inconsistency between two permission-posture controls added/touched in this PR, and no test in config/tests.rs exercises the RootConfig + session-only case for either key to confirm which behavior is intended.
| // tokens through the side-channel so the dashboard total | ||
| // matches the website (#526). | ||
| crate::cost_status::report(client.api_provider(), &response.model, &response.usage); | ||
| let api_provider = crate::config::ApiProvider::parse(client.provider_name()) |
There was a problem hiding this comment.
Minor: replacing the previous typed client.api_provider() with ApiProvider::parse(client.provider_name()) silently falls back to ApiProvider::Custom on any mismatch between a provider's provider_name() string and what ApiProvider::parse recognizes. A future rename/typo here would misattribute costs to "Custom" silently rather than failing loudly or falling back to the client's actual typed provider. No test covers this fallback path.
| pub mod authority; | ||
| pub mod engine; | ||
| pub mod events; | ||
| // The first production consumer of the staged runtime contract is the | ||
| // provider-neutral model boundary. Keep the remaining contract files staged | ||
| // until their own consumers land instead of compiling dead scaffolding. | ||
| #[path = "runtime_contract/model.rs"] | ||
| pub mod model_client; | ||
| pub mod ops; | ||
| #[path = "runtime_contract/termination.rs"] | ||
| pub mod termination; |
There was a problem hiding this comment.
Reuse/simplification note: per this comment, runtime_contract/budget.rs, context.rs, ledger.rs, manifest.rs, profile.rs, progress.rs, resources.rs, retry.rs, terminal.rs, work.rs (~1,576 lines total) are intentionally left uncompiled scaffolding — pub mod runtime_contract; is never declared, only model.rs and termination.rs are wired in via #[path]. That's a reasonable staged-rollout strategy per TUI-DOG-017, but it means this PR ships ~1,576 lines that get zero compiler checking and zero test execution (they don't even build under cfg(test)). Their cross-module references to each other (e.g. ledger.rs, manifest.rs, profile.rs importing super::RUNTIME_CONTRACT_SCHEMA_VERSION) could already be broken and CI would not catch it until a later PR wires them in. Worth a tracking issue/comment reference so this doesn't get lost.
| // The interactive runtime intentionally carries a large state machine: | ||
| // terminal rendering, modal dispatch, provider setup, and fleet/workflow | ||
| // events all share one async owner. Debug builds retain enough stack | ||
| // temporaries that nesting a modal event over the TUI loop can exceed the | ||
| // platform main-thread default (8 MiB on macOS). Give that owner an | ||
| // explicit stack while keeping process hardening and the global panic hook | ||
| // above this boundary, before Tokio or any worker thread exists. | ||
| let runtime_thread = std::thread::Builder::new() | ||
| .name("codewhale-main".to_string()) | ||
| .stack_size(CODEWHALE_MAIN_STACK_BYTES) | ||
| .spawn(run_async_main) |
There was a problem hiding this comment.
Correctness / claim mismatch: this gives the codewhale-main OS thread (which runs run_async_main, a #[tokio::main] fn) a 16 MiB stack. But run_async_main's #[tokio::main] macro builds its own multi-thread Tokio runtime with the default (un-overridden) worker stack size — there's no Builder::thread_stack_size call anywhere in the crate. Only code directly .awaited on this thread (i.e. tui::run_tui(...), main.rs:7339) benefits from the widened stack.
Engine::run() (crates/tui/src/core/engine.rs:3956 spawn_engine) is dispatched via spawn_supervised → plain tokio::spawn (utils.rs:356), so it runs on a different OS thread from Tokio's default worker pool — still the un-widened default stack. That's exactly the code this PR touches most (turn_loop.rs, dispatch.rs, new StuckGuard/subagent-coordination logic).
So the PR description's claim — "gives the TUI state machine an explicit 16 MiB async-owner stack, eliminating modal-event stack overflows on macOS" — only holds for the render/modal-dispatch loop, not the engine half of the state machine. If any of the stack-overflow reports motivating this change were actually inside engine/turn-loop code (not pure rendering), this change doesn't fix them.
| ("low_motion", bool_str(doc.settings.low_motion)), | ||
| ("fancy_animations", bool_str(doc.settings.fancy_animations)), | ||
| ("ocean_treatment", doc.settings.ocean_treatment.as_setting()), | ||
| ( |
There was a problem hiding this comment.
Correctness (plausible): this loop (starting at apply_document, line ~511) applies each (key, value) pair via set_config_value and bail!s on the first error (line 593). approval_mode is processed right after model, before work_surface_placement and most other settings below. This PR broadened approval_mode's error condition in set_config_value (commands/groups/config/config.rs:1520) to reject whenever ApprovalPolicyControl is Environment/Profile/ManagedConfig/ProjectConfig/Requirements (previously narrower). So a full settings-editor save while approval policy is externally controlled now aborts the whole apply after model (and any earlier key) has already been applied to live app state — with no rollback of keys already processed and no test covering this interaction. Consider validating all keys up front, or moving policy-gated keys to the end of the list, so an approval-mode rejection can't leave other edits (like theme/locale in this same call) half-applied.
Exercise the production settings load and migration logic with explicit candidate paths. Windows resolves roaming config through the Win32 known-folder API, so APPDATA and XDG overrides cannot safely isolate that location in a parallel test runner. Signed-off-by: Hunter B <hmbown@gmail.com>
|
Claude finished @Hmbown's task in 1m 36s —— View job Reviewing PR #4361 (v0.8.68 release candidate) — re-review after synchronizeTodo list
What changed since the last reviewThe last full review (02:09–02:10 UTC) was against
Together they touch only
No new correctness, provider-safety, or security issues in this incremental diff — it's test-quality-only, matching both commit messages. Status of the 5 previously-flagged findingsNone of the files involved in this synchronize were touched, so all 5 remain open as reported in the prior review pass (unchanged, re-verified against current
None of these block the test-isolation commits themselves, but they're still open items against the release-candidate claims in the PR description (particularly #1, which contradicts the "eliminates modal-event stack overflows" claim for engine-side stack overflows, and #2/#3, which have no test coverage either direction). |

Summary
Completes the Codewhale v0.8.68 release candidate on one reviewable branch.
OpenHands runtime parity
This is runtime simplification, not benchmark setup.
The default model-facing prompt now centers the execution loop on inspecting the repository, editing only what the task requires, verifying the result, and finishing with evidence. UI tutorials and cache-management narration are no longer the default instructions. That makes normal Codewhale behavior closer to the lean OpenHands execution contract, so benchmark behavior can improve as a consequence without a benchmark-only mode or manifest.
Verification
Release boundary
This PR does not tag a release, create a GitHub Release, or publish crates/npm artifacts. After merge, the merged commit will be rebuilt and installed only as local dogfood for final testing.