Release 0.8.67 — Fleet/Workflow usability, goal-timer fix, whaleflow→workflow rename#4047
Conversation
…ning' into codex/0867-finish-local-candidate
…ements' into codex/0867-finish-local-candidate
Safety checkpoint of multi-agent cutover work (fleet roster core, whaleflow-js runtime, /fleet roster view, audit fix lanes). Tree may not compile: the agent-tool profile edit in tools/subagent/mod.rs was interrupted mid-edit (credit exhaustion). Checkpoint precedes repair.
Revert two interrupted files (shell.rs, todo.rs) to last-good; workspace compiles, whaleflow-js 36 tests pass, fleet roster 7 pass. Half-finished shell ring-buffer and todo blocked_on features deferred for clean redo.
The per-worker token-budget tests (e.g. `per_worker_token_budget_does_not_double_count_scope_accounting`) intermittently timed out at their 5s `tokio::time::timeout` when the full `subagent::` suite ran in parallel. Root cause: `rate_limit_pause_blocks_subagent_spawn` opens a 30s process-wide rate-limit window (`retry_status::note_rate_limit`) and clears it milliseconds later. But `client::send_with_retry` read the remaining window once and committed to `tokio::time::sleep` for the FULL duration without re-checking. A budget worker in a concurrent test whose model request entered that loop during the open window was stranded for up to 30s — long past the test's 5s deadline. The pause is global state, so one test's window leaked into unrelated tests. Fix: - Sleep the rate-limit pause in bounded 250ms slices so an already-cleared (or shortened) window releases waiting requests promptly, instead of honoring a stale full-window deadline. - Add `ClearRateLimitOnDrop` RAII guard to `rate_limit_pause_blocks_subagent_spawn` so a panicking assertion can't leak the 30s window into the rest of the suite. - Add `worker_is_not_stranded_by_transient_global_rate_limit_window` regression test reproducing the strand-and-release sequence. Verified with 13 consecutive clean runs of the full parallel `subagent::` suite (192 tests) plus the `retry_status` and `client::` suites.
config_override_requires_explicit_opt_in drains the process-global PROMPT_OVERRIDE_NOTICES queue but didn't hold test_support::lock_test_env(), while its sibling (tui::ui::tests::prompt_override_notice_surfaces_in_transcript_and_toast) does. With only one side locking, the two could interleave their take_prompt_override_notices() calls under the multi-threaded test binary and intermittently see an empty vec. Take the lock so both serialize. Signed-off-by: Hmbown <101357273+Hmbown@users.noreply.github.com> (cherry picked from commit d3c2d933dca4593d5808341a328f89e4c48d7aab)
discover_from_directories already warns when two roots yield the same normalized command name, but discover_recursive pushed every SKILL.md unconditionally. With aggressive slugging, two sibling dirs under one root (e.g. `My Skill/` and `my_skill/` → `my-skill`) could both land in the registry with identical names; get() only ever resolves the first, leaving the other silently unreachable. Mirror the cross-root behavior: keep the first and emit a "shadowed by" warning. Adds a same-root regression test. Signed-off-by: Hmbown <101357273+Hmbown@users.noreply.github.com> (cherry picked from commit baf0ec414a2ba9ff2982f2e7d48014cb0cdb0806)
Trusting a workspace is a security boundary. The Trust step bound Enter — the "advance" key on every other onboarding screen — to complete trust, so a reflexive Enter granted execution trust, and the behavior was inconsistent with the footer (which lists only 1/Y to trust, 2/N to exit). Enter now surfaces a guidance hint pointing at the explicit keys instead of trusting; it is neither an accidental-trust path nor a silent dead key. The explicit Y/1 and N/2 handlers are unchanged. Signed-off-by: Hmbown <101357273+Hmbown@users.noreply.github.com> (cherry picked from commit b12a7374b9778b19aa3d6dc0043840a25bb4ee97)
The field doc claimed None "in tests / when no home directory is available," but discovery always sets the store and default_user_plugins_dir falls back to /tmp. Reword to the real invariant: set by discovery; None only when a registry is built without a store (e.g. a direct PluginRegistry::new()). Signed-off-by: Hmbown <101357273+Hmbown@users.noreply.github.com> (cherry picked from commit a8e5a01813cea677b58279963b95c6183447e197)
Adds LongCat (Meituan's LongCat API platform) as a built-in OpenAI-compatible Chat Completions provider, mirroring the existing Sakana provider wiring: - ProviderKind::LongCat / ApiProvider::LongCat with aliases (long-cat, meituan-longcat, meituan) and LONGCAT_API_KEY / LONGCAT_BASE_URL / LONGCAT_MODEL env overrides. - Defaults: model LongCat-2.0, base https://api.longcat.chat/openai/v1, credential page https://longcat.chat/platform. - Registered in the provider registry + ModelRegistry (LongCat-2.0), and wired through every provider match (config accessors, defaults, reasoning-effort, base-url persistence, env overrides, merge, header badge). - API-key based like Sakana — deliberately NOT routed through the OpenAI Codex OAuth "missing credentials" message. - Docs (PROVIDERS.md) and config.example.toml updated. Verified: cargo check --workspace --all-features, the CI clippy gate (-D warnings), codewhale-config tests (347), and tui provider tests (366) all pass. Signed-off-by: Hmbown <101357273+Hmbown@users.noreply.github.com> (cherry picked from commit 242ef6d)
Adding the LongCat ApiProvider variant tripped the web `check:facts` gate
("unmapped ApiProvider variant(s): LongCat"). Add LongCat to
PROVIDER_LABEL_MAP (web/scripts/facts-lib.mjs) and labelMap
(web/lib/facts-drift.ts), mirroring the Sakana entry, and regenerate
web/lib/facts.generated.ts. `node scripts/check-facts.mjs` now passes
(providers=30, version=0.8.67).
Signed-off-by: Hmbown <101357273+Hmbown@users.noreply.github.com>
(cherry picked from commit a54a8dec2e74e2293f95d8904efba3464fade119)
Resolve the private 0.9.0 cutover base against origin/main and repair stale merged expectations. Receipts: cargo build -p codewhale-tui --locked; cargo test -p codewhale-tui --locked.
Two call sites used let config instead of let mut config, causing borrow errors after apply_loaded_session was changed to require &mut Config.
The operator slot was added to the built-in roster. Update three tests that assert exact member order to include the new entry.
The operator slot shifted member indices: scout moved from [1] to [2], synthesizer from [5] to [6]. Update the slot/loadout assertions in built_in_party_is_complete_with_floor_permissions to match.
Goal mode text in the To-do sidebar is a feature, not a leak. Keep the full objective visible but prefix it with 'Goal:' so the compact row is clearly identified as a goal-mode objective rather than raw prompt text. Also update hover text for consistency. Remove the 50-char truncation and SIDEBAR_GOAL_MAX_CHARS constant.
Completed and blocked goals now freeze the sidebar elapsed timer instead of ticking forever. Added finished_at to HuntState, propagated through apply_goal_snapshot_to_app / close_hunt / resume_hunt / clear and both sidebar render paths; the engine snapshot() clamps elapsed at finished_at. Runaway/continuation guards preserved (they short-circuit on !is_active()). Adds regression tests for freeze-on-complete, freeze-on-close, and resume-clears-frozen-timer.
Completes the whaleflow -> workflow rename workspace-wide:
- crates/whaleflow{,-js} -> crates/workflow{,-js}; codewhale-whaleflow -> codewhale-workflow
- WhaleflowVm -> WorkflowVm, WhaleflowJsError -> WorkflowJsError,
WHALEFLOW_LIFETIME_CAP -> WORKFLOW_LIFETIME_CAP, codewhale_whaleflow(_js) paths
- __whaleflow_* -> __workflow_* JS bridge symbols; CODEWHALE_WHALEFLOW_JS_* ->
CODEWHALE_WORKFLOW_JS_* env vars; whaleflow-js-vm thread; fleet_whaleflow_ledger
-> fleet_workflow_ledger durable owner tag
- CI: output key, bash var, path filter crates/workflow/*, job id
workflow-rlm-cache, cargo -p codewhale-workflow
- docs renamed WHALEFLOW_AUTHORING -> WORKFLOW_AUTHORING and
rfcs/WHALEFLOW_EXTERNAL_MEMORY -> WORKFLOW_EXTERNAL_MEMORY; inbound links,
active doc prose, and web/lib/facts.generated.ts updated
- README zh-CN/ja-JP/vi 'current lane' section reframed to 0.8.67
- Cargo.lock updated. CHANGELOG and retro ledgers left as historical record.
Adds the 0.8.67 changelog entries for the goal elapsed-timer freeze fix (Fixed) and the whaleflow -> workflow workspace rename (Changed). Fixes a stale 'v0.9.0 Track' cross-reference in README.vi.md to match the reframed 'Track tiep theo' heading (other locales already point to the generic next-track heading).
…variant) The RunCreated(FleetRun) and ReceiptRecorded(FleetReceipt) variants dwarfed the rest (688/256 bytes), failing the CI clippy gate. Box both payloads; Box<T> is serde-transparent so the on-disk JSONL ledger format is unchanged. This was a pre-existing lint that blocked CI, unrelated to model selection.
|
Claude finished @Hmbown's task in 11m 48s —— View job Review completeTodo list
This is a large PR (~187 files, +19,935/-5,636 across the diff vs Correctness — confirmed issues
Provider/model/route safety invariant (EPIC #2608)Checked closely across the Fleet roster/loadout feature ( Reuse / simplification (lower severity)
Tests
SecurityNo issues found. Secret handling looks improved ( Given the scale of this PR, I'd treat findings #1–#4 above as worth resolving or explicitly acknowledging before merge — #1 and #2 affect the release build/publish process directly, and #3/#4 are real regressions in behavior this PR itself is trying to fix or ship. |
docs/rfcs/1364-hooks-lifecycle.md exists on main but was deleted by the 0.8.67 wip checkpoint (000c041). web/lib/docs-map.ts still points its hooks topic at the file, so the Web Frontend check-docs gate fails on the release PR. Restore the file verbatim from origin/main.
The CI clippy gate (-D warnings) fails on two new sites: the retained thinking-block truncation collapses into a match-arm guard, and the fleet roster extras sort becomes sort_by_key. No behavior change.
The release profile added panic=abort alongside lto/strip/codegen-units, but the TUI's panic supervision (catch_unwind/spawn_supervised across utils, engine, runtime_threads, tools, automation_manager, ...) depends on unwinding: with abort, one panicking tool call takes down the whole session in exactly the builds users run. Keep the size/perf flags, drop the abort.
codewhale-tui and codewhale-cli depend on codewhale-build-support as a path+version build-dependency, and codewhale-tui depends on codewhale-workflow-js the same way. Neither crate was in release_crates, so cargo publish would fail on the dependents at release time. Add both in dependency order.
…queue scheduler_tick_shared enqueues the run's task without holding the manager lock, then calls finish_scheduled_run to persist. If the automation was deleted during the enqueue await, finish_scheduled_run returned Ok(()) without saving the run record, leaving the already-created task running untracked (collect_pending_runs walks automations and could never find it). Save the run unconditionally, matching run_now_with; only the schedule advance is skipped when the automation is gone.
apply_goal_snapshot_to_app cleared finished_at for every non-terminal verdict, including Wounded (paused). Usage keeps accruing while paused (record_goal_usage_for_turn runs each turn), so the next GoalUpdated snapshot silently re-armed a timer the user just paused — conflicting with close_hunt, which records the pause instant. Freeze on Hunted/Escaped/Wounded; only an explicit resume to Hunting re-arms.
The /fleet roster UI already pins the operator row to the live session route, but dispatch passed a hardcoded "auto" run model, so workers without a task/profile model pin never actually inherited the session selection. Adopt the active route as the run-level model: - FleetManager::with_session_model() stores the session route (empty and "auto" ignored); run_model() feeds worker-spec resolution at both dispatch call sites instead of "auto" - resolve_fleet_route() takes the session model so route receipts agree with dispatch and record model_source="run.model" when it applies - the runtime API and headless fleet CLI adopt config.default_model() - task.model and agent_profile.model pins still win; headless callers with no session keep the legacy auto sentinel The model picked in /model is now the model that runs the fleet, which is the seam Operate mode builds on.
The workflow engine and model-facing tool are wired, but a user had no way to invoke them: no /workflow command existed and discoverability was zero. Add /workflow (aliases /workflows, /wf) as the user-side opt-in: - bare /workflow authorizes orchestrating the CURRENT work — the model synthesizes the objective from the conversation context instead of demanding a restatement (the same context-dependence /goal mode uses) - /workflow <objective> narrows the run to an explicit objective - /workflow status [run_id] and /workflow cancel <run_id> relay typed run receipts through the workflow tool without starting new runs - agent-mode prompt documents the opt-in contract: the invocation is the authorization, fan-out scales to the ask, pipeline over barriers, responseSchema for structured child output, receipts close the loop CmdWorkflowDescription is localized across en/es-419/ja/pt-BR/vi/zh-Hans (zh-Hant falls back, matching the other command descriptions).
/goal with no argument and no active goal used to print usage. Now it is context-dependent, like bare /workflow: the model synthesizes the objective from the conversation and sets it with the create_goal tool, which the end-of-turn GoalUpdated snapshot syncs into the sidebar. With an active goal, bare /goal remains the status readout; explicit /goal <objective> is unchanged.
…re /goal Adds 0.8.67 entries for the session-model-as-operator fleet inheritance, the /workflow orchestration opt-in command, and context-dependent bare /goal, plus Fixed entries for the paused-goal timer freeze, the scheduled-automation orphan race, and the release-profile panic=abort removal. Regenerates the embedded crates/tui CHANGELOG slice.
|
Claude finished @Hmbown's task in 3m 7s —— View job Re-review after new commits (synchronize event)Todo list
Prior findings — all four resolved
New commits since last reviewThree feature commits landed (
No new correctness, safety, or security issues found in this round. The previously-noted lower-severity items (ledger Note: I was unable to run SummaryAll four blocking findings from the previous review are resolved with targeted fixes and regression tests. The three new feature commits are clean, respect the provider/model routing invariant, and are adequately tested. I have no further blocking concerns for this PR. |
The 20->64 max_subagents default (admission 200->1024) is a real cost/rate-limit-affecting change for metered plans; record it under Changed with the config override, per review feedback.
|
Claude finished @Hmbown's task in 25s —— View job Re-review after new commit (synchronize event)Todo list
What changedOnly one new commit since the last review ( It adds the release-note callout for the SummaryNo new code to review — this commit only adds documentation. All four previously-identified blocking findings ( |
…dead vocabulary Role model cleanup per maintainer direction: - Operator vs manager hierarchy made explicit: the operator (the session's /model selection) runs the operation and assigns managers to workflows; a manager is the middle manager of exactly one workflow. Built-in descriptions rewritten and both roles now carry real role instructions that flow into worker prompts on the Fleet task-spec path and the agent/workflow profile spawn path (the wiring existed; built-ins never used it). fleet_role_to_agent_type maps 'operator' to General by an explicit arm instead of the unknown-role fall-through, with a test. - Reviewer is adversarial: the built-in member assumes the change is broken and tries to refute it (instructions shipped), and REVIEW_AGENT_INTRO adopts the same framing while staying read-only and severity-scored. - Removed vocabulary that never routed differently: FleetSlot::ToolHeavy and the strong/balanced/deep-reasoning/code/review/tool-heavy loadout tiers. inherit (operator's route) and fast (provider's faster class) remain. Retired names in existing configs parse as Custom with the identical auto routing, covered by tests. The /fleet setup model-class step now offers only the two real choices. - Tutorial example and changelog updated.
|
Claude finished @Hmbown's task in 1m 21s —— View job Re-review after new commit (synchronize event)Todo list
What changedOne new commit since the last review ( Summary of the change: makes the operator/manager coordination hierarchy explicit (both now carry real Verified:
No correctness, provider-safety, or test-coverage issues found in this commit. All four blocking findings from the original review round ( |
CodeWhale 0.8.67 — Fleet/Workflow usability release
Merges the 0.8.67 release candidate to
main. Branch name (work/v0.9.0-cutover) is legacy; the content targets 0.8.67 (the 0.9.0 Operation/Operate-mode architecture remains deferred).Fast-forward clean against
main(candidate is 78 ahead, 0 behind at open time).Highlights
/setupwizard,/fleet roster, provider-agnostic rosters/loadouts,operatorbuilt-in roster member.WorkflowTool; the product-ready/workflow runcommand + TUI run view stay tracked for 0.8.68 (v0.8.68 Workflow: wire the model-facing workflow tool and run driver #2974, v0.8.68 Workflow: product-readiness tracker #4038)./goal resumeclears the freeze.whaleflow→workflowrename across the workspace (crates, identifiers, JS bridge symbols, env vars, docs). Historical changelog/retro ledgers keep the old name as record.clippy::large_enum_variantfix infleet/ledger.rs(pre-existing lint that blocked the CI clippy gate;Box<T>is serde-transparent so the on-disk ledger format is unchanged).Verification (local, this candidate)
cargo build --release -p codewhale-tui— OKcargo testacross fleet / workflow / setup / goal suites — greenscripts/v0867-setup-qa.sh— 33 passed, 0 failed (confirmsplan_limit_probed == false)--all-featureswith the repo's-Aset) — passescargo fmt --all --check,check-versions.sh(workspace = npm = 0.8.67),verify-workspace-version.sh 0.8.67— OKExplicitly NOT in this PR (still gated)
v0.8.67, no crates.io/npm publish, no GitHub Release — those remain separate manual steps after this merge.work/fleet-model-selection, 0.8.68 scope) and is not included here.Review follow-up (pushed 2026-07-06)
docs/rfcs/1364-hooks-lifecycle.md(deleted by the wip checkpoint; webcheck-docsrequires it) and fixed the two clippy errors (collapsible_matchin compaction,unnecessary_sort_byin the fleet roster).panic = "abort"from the release profile (restorescatch_unwindpanic supervision); addedcodewhale-build-supportandcodewhale-workflow-jsto the crate publish order;finish_scheduled_runnow persists the run record even when its automation was deleted mid-enqueue; paused goals keep their sidebar timer frozen across usage snapshots (regression tests added for both)./modelselection is now the operator: fleet workers with no task/profile model pin inherit the active session route instead of a hardcodedauto(route receipts recordmodel_source = "run.model"); headless callers with no session keep the legacy default./workflowcommand (aliases/workflows,/wf): context-dependent orchestration opt-in — bare/workfloworchestrates the current work (the model derives the objective from the conversation),/workflow <objective>narrows it,status/cancelrelay typed run receipts./goalnow declares a goal from the conversation context viacreate_goalinstead of printing usage.Note: the four workflow-tool integration tests can flake under full-suite parallelism (child
failedvscompleted); verified pre-existing at4a92b44ddbefore this follow-up — filtered runs pass deterministically. Tracked for a deflake pass.🤖 Generated with Claude Code