Skip to content

chore(release): prepare v0.9.5 - #5292

Merged
Hmbown merged 126 commits into
mainfrom
codex/v095-release-contract-fix
Aug 8, 2026
Merged

chore(release): prepare v0.9.5#5292
Hmbown merged 126 commits into
mainfrom
codex/v095-release-contract-fix

Conversation

@Hmbown

@Hmbown Hmbown commented Aug 8, 2026

Copy link
Copy Markdown
Owner

Summary

Codewhale v0.9.5 consolidates the terminal app into one compiled runtime while keeping the codewhale and codew commands, removes default turn ceilings that interrupted long work, and aligns the updater, installers, release assets, website, and package surfaces around that contract.

This branch also records the exact current heads of community PRs #5255, #5256, #5257, and #5258 as merge ancestry. Each ancestry merge was proven tree-identical, so the contributor commits and GitHub provenance are retained without replaying stale/conflicting patches over their already-integrated behavior.

Release changes

  • ship one compiled runtime under codewhale and codew, with v0.9.5-only byte-identical codewhale-tui-* asset filenames as an update bridge for installed v0.9.4 clients
  • update aliases from one verified download and advertise complete releases on a one-hour cache
  • leave headless turns and persistent goals unlimited by default while preserving explicit opt-in limits and Fleet worker budgets
  • remove every legacy hidden 20-resume ceiling from tool, steering, child-completion, REPL-feedback, and goal-continuation paths
  • give Scout/Reviewer agents a bounded direct-command evidence shell, read-only Git/GitHub inspection, and private To-do notes with matching normal/headless catalog and dispatch authority
  • make full errors inspectable, keep localized navigation interactive, restore the canonical brand-first identity, and deploy one exact OpenNext/Cloudflare bundle
  • migrate stale single-runtime tests, release contracts, updater paths, nightlies, and package smoke coverage

Security boundary

The Scout evidence shell executes only a positive, direct-argv read profile. It resolves external executables canonically, validates effective-workspace operands and symlink containment, rejects Windows drive-relative paths, suppresses inherited shell hooks and Git/GitHub helper redirects, intersects parent shell/network ceilings, and keeps bounded Verifier Run authority typed and separate from Scout Bash.

Contributors

Verification

  • cargo fmt --all -- --check
  • Scout authority focused matrix: read-only 77 unit + 13 integration + 1 PTY; Scout 11; Verifier 28 unit + 2 integration; headless 16 unit + 4 integration; Todo/authority/shell-ceiling and exact transport regressions
  • cargo clippy -p codewhale-tui --all-targets --locked -- -D warnings
  • hidden-continuation marker regression plus the 20-tool-round provider-continuation regression
  • source-structure gate: 20 packages, 2 binaries, 179 large modules, 684,975 owned Rust lines
  • runtime-contract gate: all 55 metrics exactly at budget
  • version and OpenHarmony dependency/linker gates
  • ./scripts/release/publish-crates.sh dry-run
  • exact release build and clean npm pack/install smoke for codewhale + codew

The full exact-head multi-platform CI and seven-target/34-asset release-candidate workflows will be dispatched from the merged main SHA before the tag is created. Android execution remains cross-build evidence only; real Termux device execution is not claimed.

No-Issue: v0.9.5 release integration; the constituent fixes and community PRs are linked above, and unfinished milestone work was moved to v0.9.6.

Paulo Aboim Pinto and others added 30 commits August 7, 2026 02:52
…t gate

- structcopy.rs: simplify nonminimal boolean in next_absolute_path_start (no behavior change)
- latex_render.rs: remove always-true '|| true' last-row guard in parse_rows, which emitted a spurious empty row after a trailing row separator; add regression test

Boy Scout repairs of pre-existing issues on origin/main so the configured strict lint gate is green.
- New crates/tui/src/commands/discovery.rs: user_command_shadows_builtin_canonical,
  user_command_shadows_builtin_alias, unshadowed_builtin_aliases (order-preserving)
- Semantics ported from slash-completion predicates (widgets/mod.rs) which are the
  explicit alias-aware reference; palette consumes them in Phase 3
- 13 unit tests: canonical claims, accepted-alias claims, hidden ownership,
  rejected-alias omission, alias projection order, registry-lookup agreement guard
- Registered pub mod discovery in commands/mod.rs
- Temporary #[allow(dead_code)] on the three predicates until Phase 3/4 consumers
  land (recorded in planning-analysis-report.md); MUST be removed there

Generated with Claude Code
- command_palette.rs: canonical-shadow check now uses
  commands::discovery::user_command_shadows_builtin_canonical over a
  collected metadata slice instead of user_registry.get(command.name)
- palette_description_for_unshadowed_aliases now consumes
  discovery::unshadowed_builtin_aliases (order-preserving projection)
- Removed temporary #[allow(dead_code)] markers from discovery.rs (all three
  predicates now have consumers); module doc note removed
- New palette tests: visible canonical shadow (exactly one user-owned /help
  row with user metadata/action), accepted-alias suppression of built-in
  canonical row, hidden canonical shadow (no discovery row), alias-only
  shadow preserving canonical row without the claimed alias
- Palette suite: 34 passed (30 existing + 4 new); shared 13/13; completion
  23/23 guard green; strict clippy 0 warnings

Generated with Claude Code
- widgets/mod.rs: builtin_visible_for_completion_match and push_command_entry
  now consume commands::discovery predicates; local duplicate
  user_command_shadows_builtin_canonical/_alias definitions deleted
- New completion test: slash_completion_accepted_user_alias_claims_builtin_canonical_token
  (user alias claiming a built-in canonical token suppresses the built-in
  suggestion and surfaces the user command)
- Completion suite: 24 passed (23 existing + 1 new); discovery 13/13 and
  palette 34/34 guards green; strict clippy 0 warnings; no ranking/dedup/
  file-move changes; slash_completion_hints stays in widgets/mod.rs

Generated with Claude Code
- New tests/features/feat-012-discovery-filtering.feature: 7 scenarios
  (AC1-AC6 + AT-010 alias-aware unification) covering all six FEAT-012
  acceptance criteria and EPIC AT-008/009/010
- New commands/epic_discovery_acceptance.rs: scenario-level cucumber worlds
  bound to live palette builder, live slash completion, and live dispatch;
  fail_on_skipped + non-zero passed-step assertions per scenario
- Registered module in commands/mod.rs
- docs/architecture/command-dispatch.md: module map row for shared
  discovery.rs owner
- feat012 selector: 7/7 scenarios pass, zero skipped, non-zero steps each
- Guards: discovery 13/13, palette 34/34, completion 24/24; strict clippy
  0 warnings

Generated with Claude Code
- git_repo_root_reports_attempted_paths_when_no_repo_found created its
  harness in the checkout's parent dir; when the checkout is nested inside
  another git repo (e.g. a workspace repo with sibling checkouts), the
  harness itself resolved to that parent repo and the no-repository path
  was never exercised
- Use the system temp dir with deep nesting beyond the parent-search limit,
  mirroring the sibling create_isolated_worktree no-repo test

Boy Scout repair found by the FEAT-012 Phase 8 full workspace gate; test-only,
no behavior change to git_repo_root itself.
…eptance harness

FEAT-012 adds the shared discovery-shadowing contract (discovery.rs, 235
lines) and the Gherkin acceptance harness (epic_discovery_acceptance.rs,
750 lines) mirroring the accepted FEAT-011 pattern. Aggregate owned Rust
source 673375 -> 674554 (+1179 lines). No new 1000-line modules.

Pay down in v0.9.5 per the existing budget TODO notes.
registry_sync now returns instantly from the local snapshot and
refreshes it in the background: incremental via updated_since, with a
full pagination only when the snapshot is missing or older than a
month, and atomic cache replacement.
Fixes an upstream Windows-lane test failure introduced by #5212
(commit f0a6898, "fix(tui): honest large-output truncation + recovery
path").

#5212 flipped the adaptive-evidence contract so the model-facing
truncation footer MUST name the on-disk artifact path, but the footer
kept building that path with absolute_path.display().to_string(), which
on Windows emits backslashes (\artifacts\) while the acceptance test
asserts the POSIX form (/artifacts/).

- truncate.rs: the truncated_preview recovery_path (both the adaptive
  evidence path and the legacy spillover fallback) now goes through
  crate::artifacts::format_artifact_relative_path, which normalizes
  separators to '/' — the same normalization the artifact_relative_path
  metadata field already used.
- Consumers that read the footer path back (tool_routing, retrieval,
  UI preview) construct PathBuf from the string, and PathBuf::from
  accepts forward slashes on Windows, so no behavior change beyond the
  model-facing text being platform-independent.

The failing test (headless_bash_success_and_failure_are_distinct_
bounded_exact_evidence) fails identically on upstream main without this
PR's changes; this commit lands the repair inside the Layer 5.3 PR to
unblock the Windows lane.

Paulo Aboim Pinto
…-3-palette-completion-and-discovery-filte

# Conflicts:
#	scripts/source-structure-budget.json
Upstream commit b6585ea (WIP: 0.9.4 fence, turn liveness, model picker,
budget, and contributor credit, merged 2026-08-06) added three
#[allow(dead_code)] attributes without bumping the dead-code budget,
leaving both origin/main and this branch 3 over the 451 ceiling:

- stuck_guard.rs: StepFingerprint::waiting_for_subagents (test-only ctor)
- turn_loop.rs: should_hold_turn_for_subagents (test-only, #3216)
- behavioral_tips.rs: enum BehavioralTip (3 of 6 variants unconstructed)

None are removable without deleting test-only constructors or enum
variants, so re-baseline 451 -> 454 per the gate's own guidance. Our
FEAT-012 code contributes 0 net allows (Phase 2 added 3, Phase 3 removed
them). Pay down in the #4785 sweep.
…ename

Upstream ec5747f ("fix: todo_write sole progress surface + §3d/4a test
alignment", 0.9.4) renamed work_update -> todo_write in the tool catalog,
and the 0.9.4 WIP prompt tightening (b6585ea) grew the system prompt and
representative-stage identities. Neither re-baselined
scripts/runtime-contract-budget.json, leaving origin/main itself red on
this gate.

Sync all 49 drifted contract metrics to the measured receipt:
- tool_catalog tool_names/identity digests/bytes/tokens for plan, act,
  operate x active/full (work_update -> todo_write; +125 bytes per surface)
- system_prompt bytes/tokens for all modes (prompt tightening)
- representative_context stage identities and byte counts

The contract budget is a snapshot of the code; this locks the new identity
per the gate's own "explicit maintainer decision" rule. No FEAT-012
changes contribute to the drift.
8f2b622 normalized the model-facing artifact footer to forward slashes
(platform-independent). Two unit tests still asserted the raw OS path
against that footer, failing on the Windows lane:

- truncate::adaptive_evidence_footer_names_artifact_path_and_recovery
- subagent::subagent_tool_results_spill_to_disk_and_stay_bounded_inline
  (upstream fa7c4b0)

Assert the normalized form via format_artifact_relative_path, matching
what the footer actually emits.
The rustfmt pass on the footer-path test assertions (093186a) added 4
lines to production truncate.rs, pushing the aggregate to 677475, 4 over
the 677471 ceiling. Tighten ceiling 677471 -> 677475 (measured).
…-3-palette-completion-and-discovery-filte

# Conflicts:
#	scripts/dead-code-budget.json
Upstream 21ed173 renamed work_update -> todo_write (canonical; old names
stay hidden replay-only aliases) and updated docs/public-surface-facts.json,
docs/TOOL_SURFACE.md, and docs/RUNTIME_SIMPLIFICATION_DESIGN.md — but left
web/lib/public-surface-contract.test.ts expecting work_update, breaking the
Lint & Type Check gate on every branch:

- defaultActive array: work_update -> todo_write (matches facts file)
- RUNTIME_SIMPLIFICATION_DESIGN expectation: same rename
- web docs tools page: user-visible copy now names todo_write

Full web suite: 250/250 passing.
build_session_snapshot restored the title from the in-memory cache before
the disk lifecycle merge, and the cache is only refreshed at the end of
the function. A snapshot taken before the first user message therefore
pinned the placeholder title forever: every later snapshot overwrote
the conversation-derived title with the stale cached copy.

Title now resolves in priority order:
1. disk record, when the session already exists (user renames survive
   autosave, #2934/#4397);
2. in-memory cache, when no disk record exists for the session yet;
3. the title computed from the conversation (first user message).

A placeholder that survived from an earlier snapshot yields to the
computed title once a user message exists, healing both fresh and
pre-existing sessions. The placeholder string is centralized in
DEFAULT_SESSION_TITLE so the healing rule cannot drift from the
generator.

Regression tests: stale cached placeholder no longer overrides the
generated title; a persisted placeholder record yields to the computed
title. Existing picker-rename tests (rename survives autosave) still
pass. Full codewhale-tui suite: 9708 passed; 10 failures all verified
pre-existing on main (6) or parallel-flaky (4, pass in isolation).

Reviewed by a sub-agent reviewer: no Critical/Major findings; Minor
findings addressed (comments corrected, placeholder centralized, cache
assertions completed); one documented edge (a session deliberately
renamed to the literal placeholder title yields to the computed title).
- runtime-contract: regenerate tool_catalog for todo_write sole surface (plan/act/operate full/active now list todo_write, not work_update); bumps bytes/sha + prompt stages (agent plugins work)
- web: public-surface-contract expects todo_write (matches docs/RUNTIME_SIMPLIFICATION_DESIGN already)
- source-structure: 676325 -> 676652 (+327) — 321 for bf69e7f session-title fix plus 6 for stall/UI tweaks; durable test asset
- engine: raise no_user_input_continues 12 -> 20 (6 sites) to stop false 'hit (12)' stops on long todo_write loops; preserves anti-runaway
- subagent: GENERAL/PLAN intros now say todo_write, not work_update (child priming fix)
- palette: WHALE_TEXT_HINT #8491AA -> #8A99B3 (+0.4 contrast)
- tui: add BehavioralTipTodoWrite + 15 locale keys (hint: track with todo_write)
- subagent tests: fmt fixes for isolated_fleet_roster_with + assert! expansion

Refs: efcf47a, 21ed173, ec5747f, #5258
build_session_snapshot restored the title from the in-memory cache before
the disk lifecycle merge, and the cache is only refreshed at the end of
the function. A snapshot taken before the first user message therefore
pinned the placeholder title forever: every later snapshot overwrote
the conversation-derived title with the stale cached copy.

Title now resolves in priority order:
1. disk record, when the session already exists (user renames survive
   autosave, #2934/#4397);
2. in-memory cache, when no disk record exists for the session yet;
3. the title computed from the conversation (first user message).

A placeholder that survived from an earlier snapshot yields to the
computed title once a user message exists, healing both fresh and
pre-existing sessions. The placeholder string is centralized in
DEFAULT_SESSION_TITLE so the healing rule cannot drift from the
generator.

Regression tests: stale cached placeholder no longer overrides the
generated title; a persisted placeholder record yields to the computed
title. Existing picker-rename tests (rename survives autosave) still
pass. Full codewhale-tui suite: 9708 passed; 10 failures all verified
pre-existing on main (6) or parallel-flaky (4, pass in isolation).

Reviewed by a sub-agent reviewer: no Critical/Major findings; Minor
findings addressed (comments corrected, placeholder centralized, cache
assertions completed); one documented edge (a session deliberately
renamed to the literal placeholder title yields to the computed title).
- runtime-contract: regenerate tool_catalog for todo_write sole surface (plan/act/operate full/active now list todo_write, not work_update); bumps bytes/sha + prompt stages (agent plugins work)
- web: public-surface-contract expects todo_write (matches docs/RUNTIME_SIMPLIFICATION_DESIGN already)
- source-structure: 676325 -> 676652 (+327) — 321 for bf69e7f session-title fix plus 6 for stall/UI tweaks; durable test asset
- engine: raise no_user_input_continues 12 -> 20 (6 sites) to stop false 'hit (12)' stops on long todo_write loops; preserves anti-runaway
- subagent: GENERAL/PLAN intros now say todo_write, not work_update (child priming fix)
- palette: WHALE_TEXT_HINT #8491AA -> #8A99B3 (+0.4 contrast)
- tui: add BehavioralTipTodoWrite + 15 locale keys (hint: track with todo_write)
- subagent tests: fmt fixes for isolated_fleet_roster_with + assert! expansion

Refs: efcf47a, 21ed173, ec5747f, #5258
registry_sync now returns instantly from the local snapshot and
refreshes it in the background: incremental via updated_since, with a
full pagination only when the snapshot is missing or older than a
month, and atomic cache replacement.
When model = auto, dispatcher analyses prompt and selects pro vs flash.
- New crates/tui/src/commands/discovery.rs: user_command_shadows_builtin_canonical,
  user_command_shadows_builtin_alias, unshadowed_builtin_aliases (order-preserving)
- Semantics ported from slash-completion predicates (widgets/mod.rs) which are the
  explicit alias-aware reference; palette consumes them in Phase 3
- 13 unit tests: canonical claims, accepted-alias claims, hidden ownership,
  rejected-alias omission, alias projection order, registry-lookup agreement guard
- Registered pub mod discovery in commands/mod.rs
- Temporary #[allow(dead_code)] on the three predicates until Phase 3/4 consumers
  land (recorded in planning-analysis-report.md); MUST be removed there

Generated with Claude Code
- command_palette.rs: canonical-shadow check now uses
  commands::discovery::user_command_shadows_builtin_canonical over a
  collected metadata slice instead of user_registry.get(command.name)
- palette_description_for_unshadowed_aliases now consumes
  discovery::unshadowed_builtin_aliases (order-preserving projection)
- Removed temporary #[allow(dead_code)] markers from discovery.rs (all three
  predicates now have consumers); module doc note removed
- New palette tests: visible canonical shadow (exactly one user-owned /help
  row with user metadata/action), accepted-alias suppression of built-in
  canonical row, hidden canonical shadow (no discovery row), alias-only
  shadow preserving canonical row without the claimed alias
- Palette suite: 34 passed (30 existing + 4 new); shared 13/13; completion
  23/23 guard green; strict clippy 0 warnings

Generated with Claude Code
@claude

claude Bot commented Aug 8, 2026

Copy link
Copy Markdown
Contributor

Reviewing PR #5292 (chore(release): prepare v0.9.5)

Todo list:

  • Gather context (PR body, changed files, custom instructions)
  • Fetch diff against origin/main
  • Review correctness (logic errors, panics, unwraps, races, exhaustive matches)
  • Review provider/model/route safety invariant (EPIC v0.8.65 EPIC: Separate provider facts, model facts, offerings, and route resolution #2608)
  • Review reuse/simplification/dead code
  • Review test coverage
  • Review security (secrets, shell/exec policy, input validation)
  • Post final review summary

View job run

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: a701490dde

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread crates/cli/src/lib.rs Outdated
Comment thread crates/tui/locales/en.json Outdated
Comment thread .cnb.yml
Comment thread crates/tui/locales/ca.json Outdated
Comment thread crates/cli/src/lib.rs Outdated
Comment thread crates/tui/src/mcp/oauth.rs
Comment thread web/public/install.sh
Comment thread crates/tui/src/runtime_api.rs Outdated
Comment thread crates/tui/src/runtime_api.rs
Comment thread crates/cli/src/cloud.rs Outdated
Bring the dead-code ledger back to its existing ceiling by deleting helpers that were added for unfinished follow-up slices and by modeling the OAuth callback listener as intentional RAII state. The core Engine keeps its public constructor shape but no longer stores fields that are not yet part of the runtime.

Verified with the dead-code and source-structure gates, the runtime-contract gate, focused core/TUI unit tests, rustfmt, and strict Clippy for codewhale-core and codewhale-tui.
@claude

claude Bot commented Aug 8, 2026

Copy link
Copy Markdown
Contributor

Claude finished @Hmbown's task in 2m 37s —— View job


Reviewing PR #5292 (chore(release): prepare v0.9.5)

Todo list:

  • Gather context (PR body, changed files, custom instructions)
  • Fetch diff against origin/main
  • Review correctness (logic errors, panics, unwraps, races, exhaustive matches)
  • Review provider/model/route safety invariant (EPIC v0.8.65 EPIC: Separate provider facts, model facts, offerings, and route resolution #2608)
  • Review reuse/simplification/dead code
  • Review test coverage
  • Review security (secrets, shell/exec policy, input validation)
  • Cross-check existing Codex review comments
  • Post final review summary

This is a very large PR (277 files, +34806/-23020). Running parallel deep-dives across: auto-model routing safety, runtime_api.rs route/goal/PATCH bugs, new crates/core/crates/protocol engine modules, MCP OAuth/cloud/lib.rs findings, the Scout evidence-shell security boundary, release/install/CI plumbing, and fleet/session command additions — including verification of the existing Codex bot findings.

CodeWhale Bot added 15 commits August 8, 2026 01:52
Axum rejects duplicate method/path registrations while constructing the runtime router. Keep skill toggle plus uninstall and MCP list plus create on their respective single route definitions.

Add an explicit mobile router-start regression so future overlaps fail in the focused runtime API unit lane.

Verified with the mobile, MCP management, skill lifecycle, and skill-state tests; codewhale-tui all-targets clippy; and the runtime-contract budget gate.
Run the ignored persistence backlog receipt test from the TUI library after the integration target move. Pin the exact Cargo command in a hermetic harness test and reject successful zero-test or missing-receipt runs so future test relocations fail clearly.
Keep only the journal-backed active history in queued snapshots, then materialize the legacy messages projection in a temporary copy at the disk boundary. This removes the near-2x paused-channel retention introduced by the session journal while preserving 0.9.4 readers and checkpoint recovery.

When load-time tool-history repair changes the active projection, append the repaired suffix as a sibling branch instead of letting the stale journal overwrite it or rewriting prior evidence.

Verified with the paused measurement, all persistence-actor and session-manager tests, focused append-only repair regressions, rustfmt, and strict all-target codewhale-tui Clippy. The residual 0.46% journal schema overhead and aggregate source ledger are reconciled separately after the active release lanes land.
Register the tree, branch, and resume descriptions in the complete-locale contract and provide native copy in every shipped language. Keep the todo command name code-owned through a placeholder, and remove internal issue wording from the fork description.\n\nVerified with the localization and behavioral-tip test suites plus JSON parsing for every locale pack.
Keep provider-neutral auto selection in the provider-aware TUI and launch workflow lanes from the exact running executable. Repair CNB and installer alias contracts, refresh legacy website-installed TUI bytes during upgrades, and make account pull reject an unimplemented local import truthfully.\n\nVerified with focused CLI/config tests, strict Clippy, workflow contracts, shell syntax checks, and hermetic web installer tests.
Own and abort the MCP OAuth callback task so cancelled flows release fixed ports. Preserve omitted-versus-null semantics for nullable MCP PATCH fields while rejecting a server with no endpoint, and make replacement thread goals begin a fresh lifecycle instead of inheriting usage.

Agent-assisted implementation; primary review restored the existing create-validation test and added persisted-state coverage for an invalid final-endpoint clear. Verified with focused OAuth, MCP management, and thread-goal tests, rustfmt, and strict all-target TUI Clippy.
Rebaseline the paused persistence receipt after eliminating duplicate queued history: retained payload drops from 16,924,032 bytes in the broken candidate to roughly 8,528,000 bytes. The ceiling is under 0.5% above the pre-journal schema and includes 0.015% headroom over the largest of repeated clean samples.

Record the final net source delta at 86 lines above the prior review ceiling with no new package, binary, or thousand-line module. Verified with both budget checker suites, repeated clean measurements, JSON validation, and the source-structure gate.
Remove the stale /sessions resume alias now that /resume is a first-class command. At the persistence disk boundary, reconcile a non-empty compatibility projection back into the append-only journal before serialization so direct SavedSession callers cannot save a newer transcript that the next load silently replaces with an older journal branch.

Verified with both command registry invariants, stale-checkpoint recovery, long-history save/load, and checkpoint round-trip tests.
Keep canonical Bash.run available to Scout and Reviewer through the hardened read-only executor without reviving the retired exec_shell alias. Restore nested agent visibility below the configured depth ceiling, and align roster/setup assertions with the seeded worker, planner, and custom members.

Verified with 420 subagent tests, 16 Fleet roster tests, and the focused setup override regression.
Budget the pinned background-work row only from space left after the Work strip and measured composer growth. Compact terminals now hide the redundant chip before it steals rows from chat or the idle ocean.

Verified with all nine work-surface rail, resize, paint, and ambient-floor regressions.
Scope both config-path environment variables through the shared guard, and run the xAI API-key confirmation against a canonical temporary Codewhale home with the file secret backend. This removes ambient config/keychain coupling and the macOS /var symlink failure from the full parallel suite.

Verified with the focused xAI provider confirmation test.
Resolve relative anchor destinations against the fetched HTTP(S) page through htmd parsed elements before Markdown conversion. Absolute, fragment, non-HTTP, and malformed destinations retain the converter existing behavior.

Verified with all 19 extraction tests, including readable page chrome removal and relative-link preservation.
Reconcile the aggregate Rust ledger at 685165 lines after the release-gate repairs for session persistence, Scout authority, compact layout, provider-test isolation, and fetched relative links. Package, binary, large-module count, and largest-module ceilings do not grow.

Verified with the source-structure checker and JSON parsing through the checker.
The single-binary library conversion made the private command-safety module visible to rustdoc while its examples still imported it as a public API. Render those examples as behavior tables instead of publishing an internal policy module solely for doctests.\n\nVerified with cargo fmt and the codewhale-tui all-features doctest target.
Record GitHub v0.9.4 as the latest published release while keeping the workspace and website source candidate at v0.9.5. Regenerate the build-time facts fallback so the manual Cloudflare deploy receipt compares against the same published tag already served from KV.

Verified with the focused facts and deploy contracts, the complete 256-test web suite, ESLint, TypeScript, facts/docs drift checks, and a 288-page production build.
@claude

claude Bot commented Aug 8, 2026

Copy link
Copy Markdown
Contributor

Claude finished @Hmbown's task in 10m 26s —— View job


Reviewing PR #5292 (chore(release): prepare v0.9.5)

Todo list:

  • Gather context (PR body, changed files, custom instructions)
  • Fetch diff against origin/main
  • Review correctness (logic errors, panics, unwraps, races, exhaustive matches)
  • Review provider/model/route safety invariant (EPIC v0.8.65 EPIC: Separate provider facts, model facts, offerings, and route resolution #2608)
  • Review reuse/simplification/dead code
  • Review test coverage
  • Review security (Scout evidence shell, secrets, shell/exec policy)
  • Cross-check existing Codex review comments
  • Post final review summary

Summary

Re-reviewed after the latest fixup commits (through 9a30158). All 12 items previously flagged by the Codex bot (P1: auto-routing prefix bug, missing locale registration/translations, .cnb.yml preflight codew copy, Catalan copy-paste; P2: bare-codewhale lane command, install.sh crate-name fallback, duplicate runtime_api.rs routes, OAuth listener leak, stale codewhale-tui on upgrade, goal-replace usage reset, MCP PATCH tri-state, account pull no-op) are verified fixed in current code — checked directly, not inferred from commit messages. Good work closing those out.

Fresh findings from this round, plus two areas I verified are sound:

1. crates/core/{engine,ids,journal,request,session}.rs + crates/protocol/{op,event_msg,journal}.rs are ~1,800 lines of unwired scaffolding (medium-high, worth a decision before release)

Grep across crates/tui, crates/app-server, crates/cli finds zero callers of codewhale_core::engine::{Engine, EngineHandle, spawn_engine, spawn_headless_thread} or of crates/protocol's new Op/EventMsg/journal types. The module docs admit this themselves (e.g. crates/core/src/engine/thread/store.rs:8-9: "Until then it documents the contract"; thread/mod.rs:17: "behaviour stays in the TUI until the move completes"). These new types are also parallel duplicates, not shared implementations, of live production code: protocol::op::Op shadows crates/tui/src/core/ops.rs::Op (missing ResolvedRuntimeRoute, CompactionConfig, hooks, goal state); protocol::event_msg::EventMsg duplicates crates/tui/src/core/events.rs::Event; core::session::{Thread, Session} duplicates crates/tui/src/core/session.rs::Session; core::fragments duplicates crates/tui/src/model_context/fragment.rs (only 4 constants were actually deduplicated, despite the doc-comment claiming core is now "the single owner"). Only fragments.rs has any real caller (prompts.rs:1236, model_context/fragment.rs:14). Landing this much inert/duplicated scaffolding in a release-prep branch is a scope question worth a maintainer call: land it as explicitly-labeled in-progress migration work, or hold it for the branch where it's actually wired up.

Minor same-family nit: crates/core/src/engine/mod.rs:197-221 matches env.op with _ => {} for ContinueGoal/RunShellCommand/SetGoalStatus/PreviewOutboundRequest — harmless today since nothing drives the loop, but it won't force a compile error when new Op variants are added later, once this is wired up.

2. crates/config/src/auto_model.rs (new, 364 lines) is dead code — and self-admittedly unsafe if ever wired up

Its own doc comment says the CLI dispatcher "must not use it to resolve provider-neutral model = auto: doing so fabricates DeepSeek model ids for every active provider." Confirmed zero call sites outside its own tests. Not a live bug, but worth deleting or gating harder so it can't accidentally get wired in later — its classify/score logic is exactly the prefix-as-provider-proof pattern the EPIC #2608 invariant forbids.

3. web/public/install.sh:216-222 — sudo preflight doesn't cover the new legacy-binary refresh path

The write-permission check that decides whether to invoke sudo only tests install_dir, install_dir/codewhale, and install_dir/codew. But lines 231-259 now also conditionally cp/mv onto install_dir/codewhale-tui when refreshing a v0.9.4-era install. If that file is root-owned in a directory whose own writability check otherwise passes, the script proceeds without sudo and then fails under set -eu on the codewhale-tui write instead of falling back to sudo like it does for the other two binaries.
Fix this →

4. .winget/Hmbown.CodeWhale.yaml mirror claim is false on introduction (low)

Its header says it's "a mirror of packaging/winget/Hmbown.CodeWhale.yaml... Keep both in sync," but the new file is missing the InstallationNotes:/Documentations:/FileExtensions: blocks present in packaging/winget/Hmbown.CodeWhale.yaml. generate-winget-manifest.sh only patches version/URL/SHA/date by position in both files, never structural content, so this drift won't self-heal — either make the files structurally identical now or drop the "mirror" wording.

Verified sound — no action needed

  • Provider/model routing safety (EPIC v0.8.65 EPIC: Separate provider facts, model facts, offerings, and route resolution #2608): the live auto routing path (crates/tui/src/model_routing.rs, unchanged by this PR) filters candidates by candidate.provider == provider from the real ModelInventory before building routing pairs — it does not infer provider from a model-string prefix or freeform prompt text. crates/cli/src/lib.rs's DeepSeek-default fallback is correctly gated behind provider == ProviderKind::Deepseek. Good discipline maintained here.
  • Scout evidence shell: the described boundary (crates/tui/src/command_safety.rs + shell.rs) holds up under adversarial reading — true positive allowlist (not denylist) on both command prefix and per-flag basis, direct-argv execution (no shell), symlink-safe canonicalize-then-contain checks for both operands and the resolved executable, byte-level Windows drive-relative rejection, and forced safe flags (--no-ext-diff, etc.) plus a hardened env block backed by an extensive adversarial test suite (command_safety.rs:1364-1454). No exploitable gap found.

Not re-reviewed in depth

update.rs's new update-bridge logic, CI/workflow YAML, and Dockerfile/homebrew scripts were spot-checked and look internally consistent (asset counts, codewhale/codew/bridge-asset references line up); no further issues found there beyond items 3–4 above.

Reject rooted current-drive operands at the read-only Scout boundary, render absolute artifact footer paths with canonical forward slashes, and make the Scout cwd proof use Git-for-Windows pwd output without weakening its semantic path comparison.

Verified with the four Windows-failing TUI unit regressions, the related artifact test, the strict all-target TUI Clippy gate, formatting, source-structure budget, and diff checks.
@claude

claude Bot commented Aug 8, 2026

Copy link
Copy Markdown
Contributor

Claude finished @Hmbown's task in 1m 36s —— View job


Reviewing PR #5292 (chore(release): prepare v0.9.5)

Todo list:

  • Gather context (PR body, prior review history, custom instructions)
  • Identify what's new since the last review (through 9a30158)
  • Review the new commit 131bf52 (Windows evidence-path fix) for correctness
  • Re-verify Scout evidence-shell security boundary against the new change
  • Post final review summary

Summary

Only one commit landed since the last full review (which covered everything through 9a30158): 131bf52 — "fix(tui): normalize Windows evidence paths" (5 files, +12/-12). Reviewed it in full against origin/main. No new issues found — this is a targeted, correct fix to the read-only Scout evidence-shell boundary previously verified sound.

What the commit does, and why it's correct

  • crates/tui/src/tools/shell.rs:2938 — replaces candidate.is_absolute() with candidate.has_root() in enforce_readonly_workspace_operands. This closes a real Windows-only gap: Rust's Path::is_absolute() on Windows requires both a drive prefix and a root, so a "rooted current-drive" operand like \secret.txt (root, no drive letter) previously slipped past this check unrejected. has_root() catches it correctly while remaining equivalent to the old behavior on Unix (where root implies absolute). The companion test at crates/tui/src/tools/shell/tests.rs:551 (cat /rooted-current-drive.txt) exercises exactly this case.
  • crates/tui/src/command_safety.rs:526-529 — allows a Windows-only -W flag for pwd, gated by cfg!(windows), needed because the Scout cwd-proof now shells out to Git-for-Windows' pwd, which requires -W to print the native (non-MSYS) path. Correctly scoped to the allowlist's per-flag mechanism, doesn't loosen it on other platforms.
  • crates/tui/src/tools/subagent/tests.rs:6136-6150 — updates the Scout pwd integration test to canonicalize both sides and compare case-insensitively with normalized separators, matching the -W-driven native path output instead of assuming Unix-style output. Reasonable adaptation, doesn't weaken the assertion's intent (still proving the returned cwd matches the real workspace path).
  • crates/tui/src/tools/truncate.rs:585,855 — swaps raw absolute_path.display().to_string() for crate::artifacts::format_artifact_relative_path(&absolute_path) in two footer-path call sites, which just normalizes \ to / for consistent cross-platform display in artifact/spillover output. Pre-existing helper (artifacts.rs:307, not new in this commit), purely cosmetic, no information-exposure change from before.

Consistency check against the rest of the boundary

Checked whether has_root() should have replaced is_absolute() elsewhere in the same file for consistency:

  • shell.rs:2971 (readonly_sanitized_path_from, filtering PATH entries) — uses is_absolute() to keep only absolute entries; a rooted-but-not-absolute entry here gets dropped, which is the safe direction, so no fix needed.
  • shell.rs:3024 (resolve_readonly_program_from_path) — same reasoning; this only affects the allowlisted trusted-binary path used to build the safe PATH, not user-supplied operands, so it's outside the threat model this commit patches.

No inconsistency introduced by the fix.

Correctness / provider-routing / dead-code / test-coverage

No changes touch model routing, provider selection, or any of the previously-flagged files (runtime_api.rs, oauth.rs, cli/lib.rs, auto_model.rs, install scripts, .cnb.yml, locales). Those items from the earlier review round were already reported as fixed and remain untouched by this commit. No new dead code, no new panics/unwraps introduced, and the new/changed test coverage (shell/tests.rs, subagent/tests.rs) matches the new behavior.

Not independently re-run

I read the diff and cross-checked the surrounding logic directly rather than re-running the full cargo test/clippy matrix (this environment doesn't have that set up for a workspace this size within the review turn) — the PR body's verification list (Windows-failing TUI unit regressions, Clippy -D warnings, formatting, source-structure/diff gates) covers this commit per its message.

Keep pwd as a separately admitted read, but prove the ordinary Scout dispatch workspace by reading unique sentinel bytes through a bounded relative cat operand. This avoids comparing platform-specific pwd renderings and removes the temporary Windows-only pwd flag expansion.

Verified with the focused Scout test, strict all-target/all-feature TUI Clippy, formatting, source-structure budget, and diff checks.
@claude

claude Bot commented Aug 8, 2026

Copy link
Copy Markdown
Contributor

Claude finished @Hmbown's task in 1m 10s —— View job


Reviewing PR #5292 (chore(release): prepare v0.9.5)

Todo list:

  • Gather context (PR body, prior review history, custom instructions)
  • Identify what's new since the last review (through 131bf52)
  • Review new commit 8d4a9f0 (Scout cwd proof determinism) for correctness
  • Cross-check Codex bot findings remain fixed
  • Post final review summary

Summary

Only one commit landed since the last full review: 8d4a9f0 — "test(tui): make Scout cwd proof deterministic" (2 files, +5/-8). Reviewed in full against origin/main. No issues found — this is a clean, correct simplification of the previous commit's Windows-specific pwd -W workaround.

What changed and why it's correct

  • crates/tui/src/command_safety.rs:526-529 — removes the cfg!(windows)-gated -W flag from pwd's allowed-options list, reverting to a single cross-platform allowlist (-L -P --logical --physical). Confirmed via grep that no other call site in crates/tui/src still references a pwd -W invocation, so nothing is left dangling.
  • crates/tui/src/tools/subagent/tests.rs:6139-6149 — replaces the pwd-based cwd assertion (which needed the -W flag plus canonicalize/case-fold/separator-normalize gymnastics to compare against a Windows-rendered path) with a cat-based proof: it writes a unique sentinel file into tmp.path() (confirmed at line 6062 this is the exact path passed into ToolContext::new as the Scout's workspace root) and then dispatches cat scout-cwd-sentinel.txt through the same Scout Bash surface, asserting the sentinel bytes come back unmodified. This still proves Scout dispatch executes rooted at the correct workspace — a relative-path read only succeeds if the process cwd is tmp.path() — while sidestepping platform-specific path-string rendering entirely. Genuinely simpler and more robust than the path it replaces, not just a workaround shuffle.
  • cat and relative-path reads were already part of the allowed evidence profile exercised earlier in this same test (line 6117's admitted-commands list includes readonly reads), so no new allowlist surface is introduced.

Consistency / regressions

No other tests, docs, or code reference the removed Windows pwd -W allowance or the old canonicalize/case-insensitive comparison this replaces. No changes touch model routing, provider selection, runtime_api.rs, OAuth, install scripts, or locales — all previously-flagged and previously-fixed items from earlier review rounds are untouched by this commit.

Not independently re-run

As in the last round, I read the diff and traced the test/workspace wiring directly rather than re-running the full cargo test/clippy matrix (not available in this review environment for a workspace this size) — the commit message states the focused Scout test, strict all-target/all-feature TUI Clippy, formatting, and source-structure/diff gates were run locally.

Run the isolated Skills Manager scenario through the pty integration-test binary and use its module-qualified name so --exact executes one test instead of zero. Lock the command into the workflow contract and update the durable TUI verification examples.

Verified with the exact ignored PTY command, the workflow contract test, actionlint YAML/expression checks, and git diff --check.
@claude

claude Bot commented Aug 8, 2026

Copy link
Copy Markdown
Contributor

Claude finished @Hmbown's task in 2m 3s —— View job


Reviewing PR #5292 (chore(release): prepare v0.9.5)

Todo list:

  • Gather context (PR body, prior review history, custom instructions)
  • Identify what's new since the last review (through 8d4a9f0)
  • Review new commit cd4bf73 (CI: target consolidated PTY acceptance) for correctness
  • Check for regressions relative to previously-verified items
  • Post final review summary

Summary

Only one commit landed since the last review: cd4bf73 — "fix(ci): target consolidated PTY acceptance" (3 files, +13/-6). The core change is correct, but it leaves three stale references to the old test-target name that it should have updated at the same time.

What the commit does, and why the core change is correct

crates/tui/tests/pty/ was previously consolidated from separate qa_pty, release_runtime_qa, and terminal_matrix_qa integration-test binaries into one binary (tests/pty/main.rs declaring mod qa_pty; mod release_runtime_qa; mod terminal_matrix_qa;). This commit catches up .github/workflows/ci.yml:465 to invoke it correctly:

cargo test -p codewhale-tui --test pty qa_pty::skills_opens_manager_owned_then_compatible -- --ignored --exact

I verified this is valid: Cargo's target auto-discovery treats tests/<name>/main.rs as an integration-test target named <name> (no explicit [[test]] entry needed, and none exists in crates/tui/Cargo.toml), so --test pty resolves to tests/pty/main.rs. The function skills_opens_manager_owned_then_compatible does exist in crates/tui/tests/pty/qa_pty.rs:2195, and the module-qualified filter qa_pty::skills_opens_manager_owned_then_compatible is the correct way to select one test by name from a multi-module binary. The paired regression added to .github/scripts/release-workflows.test.js:45-50 (assert the new invocation is present, assert --test qa_pty is absent) is well-targeted at exactly this drift. crates/tui/AGENTS.md's three example commands were updated consistently (--test pty qa_pty, --test pty release_runtime_qa, --test pty terminal_matrix_qa).

Missed: stale target-name references elsewhere in the repo (same drift, not caught here)

Grepping repo-wide for the old single-binary invocations turns up three more spots still using the pre-consolidation command form, which now names a test target that no longer exists and will fail if copy-pasted:

  • CONTRIBUTING.md:91cargo test -p codewhale-tui --test qa_pty --locked
  • docs/skills/codew-release-qa-sweep/SKILL.md:41cargo test -p codewhale-tui --test release_runtime_qa --locked -- --test-threads=1
  • crates/tui/tests/pty/release_runtime_qa.rs:1325-1326 (doc comment) — `cargo test -p codewhale-tui --test release_runtime_qa --locked -- --ignored bench_thirty_two --nocapture --test-threads=1`

All three should become --test pty <module> form (e.g. --test pty qa_pty --locked, --test pty release_runtime_qa --locked -- --test-threads=1), matching the pattern this commit already applied to crates/tui/AGENTS.md. Low severity (docs/comments, not CI-executed), but worth a follow-up fixup so a contributor following CONTRIBUTING.md or the release-QA-sweep skill doesn't hit an immediate "no test target named release_runtime_qa" error.
Fix this →

Consistency / regressions

No changes touch model routing, provider selection, runtime_api.rs, OAuth, install scripts, or locales — all previously-flagged items from earlier review rounds (auto-routing prefix bug, locale registration, .cnb.yml codew copy, duplicate routes, OAuth listener leak, install.sh sudo preflight, MCP PATCH tri-state, goal-replace reset, account pull, etc.) remain untouched by this commit and were already verified fixed.

Not independently re-run

As in prior rounds, this environment isn't set up to run the full cargo test/clippy workspace matrix within the review turn (attempts to shell out to cargo required interactive approval not available here), so I verified the target-name/module-path claims by reading Cargo.toml, the tests/pty/ module tree, and grepping for the referenced function/target names directly rather than executing the build.

@Hmbown
Hmbown merged commit fdac09b into main Aug 8, 2026
29 checks passed
@Hmbown
Hmbown deleted the codex/v095-release-contract-fix branch August 8, 2026 12:31
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.

5 participants