`.github/scripts/release-workflows.test.js:105` asserts
`doesNotMatch(nightly, /codewhale-tui/)`. The surrounding assertions show why:
nightly must build `-p codewhale-cli` and stage `codewhale`/`codew` artifacts,
never the legacy `codewhale-tui` binary. It is a textual guard, so prose trips
it as readily as a build argument would.
The stack-size comment I added named the crate being compiled. Reworded to
`crates/tui`, which says the same thing without the guarded token. The
underscored `codewhale_tui` in the quoted rustc error is untouched — the guard
matches the hyphenated binary name, and the quoted diagnostic is the evidence
that makes the comment worth having.
Weakening the guard to accommodate a comment would have been the wrong trade:
it protects a real invariant about what nightly builds.
Verified: the full ci.yml `versions` job run locally — check-versions.sh plus
all thirteen release-helper contract tests — passes end to end, and
actionlint 1.7.12 is clean.
Signed-off-by: Hunter Bown <hmbown@gmail.com>
`check-versions.sh` requires `crates/tui/CHANGELOG.md` to mirror its slice of
the root `CHANGELOG.md`. The nightly codegen-thread-stack entry went into the
root file only — I judged a workflow change to be outside the tui crate's
changelog — but the gate compares the files, not the subject matter, so main
went red on Version drift while every test job passed.
Generated with ./scripts/sync-changelog.sh, as the failure message instructs.
Verified: ./scripts/release/check-versions.sh exits 0 locally
("Version state OK: workspace=0.9.10, npm=0.9.10, lockfile in sync").
Signed-off-by: Hunter Bown <hmbown@gmail.com>
Every nightly since 2026-08-16 failed the windows-arm64 leg while compiling
codewhale-tui, with `thread 'optimize module codewhale_tui.551c4fd52ebe22df
-cgu.13' has overflowed its stack` — the same codegen unit on all three build
attempts, so this was never flaky.
The stack belongs to the LLVM worker threads rustc spawns to run per-codegen-
unit optimization, not to rustc's main thread. `lto=off` is why that work runs
while the *library* is compiled instead of being deferred to the ThinLTO stage,
but it is not the root cause: removing the override would only relocate the
optimization and hide the failure.
Evidence (local, aarch64-apple-darwin, crate and every flag held fixed, only
RUST_MIN_STACK varied, CARGO_PROFILE_RELEASE_LTO=off):
default (2 MiB) -> builds, 2m53s
1 MiB -> rustc dies, SIGBUS
2 MiB -> builds
4 MiB -> builds
So the requirement sits between 1 and 2 MiB. Unix std defaults to 2 MiB and
passes; the Windows ARM64 runner sat under it.
That requirement follows from the size of the crate — crates/tui is 788k lines
and the regression window added 24.7k of them — not from the operating system,
so RUST_MIN_STACK is set for the whole matrix rather than special-cased. The
value is reserved address space, not committed memory. Splitting the crate's
largest modules is the durable fix and is tracked separately.
Also drops CARGO_PROFILE_RELEASE_CODEGEN_UNITS: [profile.release] already sets
codegen-units = 16, so the override restated the existing value and never
provoked anything. Believing it did is what pointed the first diagnosis at the
wrong flag.
Shipped binaries were never affected: release-artifacts.yml builds
--profile dist with fat LTO and codegen-units = 1.
Verified locally: actionlint 1.7.12 clean, YAML parses, Build step env asserted.
The windows-arm64 nightly turning green is CI-only and is not proven here.
Diagnosis and patch produced with agent assistance.
Signed-off-by: Hunter Bown <hmbown@gmail.com>
Skipping Welcome to land on the local-runtime picker was an over-correction.
New users never saw a start screen or the calm "pick where your model runs"
explanation, so the first API-key setup had no way in except Esc-from-a-list
they did not ask for.
First run now always opens Welcome. Enter routes to language, the provider
explanation, trust, or ready depending on what this run actually needs; a
second Enter on the provider screen opens the picker. Returning missing-key
recovery still opens the picker on launch so a persisted route cannot be
silently replaced.
Evidence: cargo nextest -p codewhale-tui --lib -E 'test(/first_run_|launch_onboarding_|welcome_routes|provider_back_walks|tui::onboarding::/)' 31/31 pass.
Signed-off-by: Hunter Bown <hmbown@gmail.com>
CI's clippy step ran without `--all-targets`, so it never linted a single
test target. That is why the v0.9.10 release gate opened with four clippy
failures sitting on a green main: every one of them was in test code, and
two of the four were additionally allowed outright by
`-A clippy::collapsible_if -A clippy::assertions_on_constants`. The gate
crates/tui/AGENTS.md points contributors at is the all-targets one, so CI
was enforcing a weaker rule than the repo documents.
This is not a hypothetical gap. While fixing the timeout bug in the parent
commit I wrote a fresh `assertions_on_constants` violation in a new test;
the local all-targets gate caught it immediately, and CI as configured
would have merged it.
Widen the step to `--all-targets` and drop those two allowances. The three
that remain — uninlined_format_args, too_many_arguments, unnecessary_map_or
— are deliberate project style rather than oversights, so they stay. The
Lint job's budget goes to 45 minutes because the ubuntu Test job is skipped
on push, which means this runner has no warm cache for test targets.
Signed-off-by: Hunter Bown <hmbown@gmail.com>
A community report sat on one tool call for 9,522 seconds. The model had
already run the CLI once, seen it print "Not authenticated", and then
invoked it again; that second call blocked, and the turn stayed pinned with
the tool row simply counting seconds.
The hang is ours, not the CLI's. `BashTool::contract_delegate` sets
`optional_timeout`, so an omitted `timeout_ms` stayed `None` and fell
through `timeout_ms.unwrap_or(BASH_MAX_TIMEOUT_MS)` to `i32::MAX`
milliseconds — about 24.8 days. The tool's own input schema already
promises "action=run 120000", and its description already says foreground
mode is for bounded commands, so the implementation was contradicting the
contract it advertises to the model. We also already had the right
recovery: `FOREGROUND_TIMEOUT_RECOVERY_HINT` kills the process and tells
the model to rerun with `background=true` and poll with `action="wait"`.
It could never fire, because it is gated on a timeout that was never set.
Resolve the lifetime in one place, `contract_bash_timeout_ms`, and only for
foreground runs. Background and interactive runs are meant to outlive the
call, so bounding them here would kill long-lived jobs the model
deliberately detached — they keep `None`. An explicit `timeout_ms` still
wins at any value, including well above the default, so genuinely long
foreground work stays possible by asking for it.
The shared schema text now scopes the 600000 cap to the standalone Bash
tool, which is the only variant that clamps to it, and says what an omitted
foreground timeout does.
Evidence: `contract_bash_foreground_without_a_timeout_is_bounded_not_endless`
covers the omitted, explicit-long, explicit-short, background, interactive,
and non-contract cases; the shell and timeout suites pass 85/85; the exact
all-target all-feature clippy gate exits 0.
Signed-off-by: Hunter Bown <hmbown@gmail.com>
Three onboarding tests build their app with `App::new`, which derives the
first-run decision from the ambient box — whether a locale can be inferred,
whether `settings.toml` exists, whether a provider key is in the
environment. Each test then overrode only the flags it named and inherited
the rest, so the same commit asserted different things on different
machines. That is why main is red in two directions at once:
- Windows CI (clean box, no locale, no key) fails
`welcome_routes_to_the_first_decision_this_run_needs` and
`progress_counts_only_required_decisions`: `App::new` had already set
`onboarding_had_language_step`, so welcome routed to Language instead of
Provider and the counter saw two required steps instead of one.
- A configured developer box fails
`provider_back_walks_to_the_last_decision_this_run_asked`: `App::new` set
`onboarding_missing_key_recovery`, whose branch exits to the offline
composer instead of walking back.
Neither is a product defect — `advance_onboarding_from_welcome`,
`required_progress`, and `back_from_provider_onboarding` are all correct.
The fixtures were under-specified. Reset the onboarding decision fields to
"nothing asked yet" in `test_app_with_locale` and name the recovery flag in
the walk-back test, so each test opts in to the steps it is actually about.
No assertion is weakened or removed; the missing-key-recovery branch keeps
its own case.
Evidence: `cargo nextest run -p codewhale-tui -E 'test(tui::onboarding::)'`
25/25 pass, and the walk-back test passes under both nextest and libtest.
Signed-off-by: Hunter Bown <hmbown@gmail.com>
Lstarsky0's receipt landed in `[Unreleased]`, but v0.9.10 is not tagged
yet, so everything on main ships in it. generate-release-body.sh extracts
only the `[<version>]` section, which means an `[Unreleased]` entry would
be dropped from the 0.9.10 release body — the exact disappearance that
check-feature-release-notes.sh was written to catch.
Move the entry beside its sibling phase in 0.9.10 `### Added` and adopt
that section's established shape, so #5504 and #5517 now read alike. The
wording, the epic framing, and the contributor's own commit are kept; only
the placement changes. main already carries the matching Contributors
credit line.
crates/tui/CHANGELOG.md regenerated with ./scripts/sync-changelog.sh.
Signed-off-by: Hunter Bown <hmbown@gmail.com>
PR #5517 shipped docs/constitution and docs/runtime-api onto the typed
dictionary spine and merged into this release, but the 0.9.10 Contributors
section never named it. The new feature-release-note gate catches this on
any branch whose commits reference #5517 — including Lstarsky0's follow-up
PR #5520, where the honest fix is to record the receipt rather than delete
the contributor's reference to their own earlier work.
The entry states what actually landed: 28 inline `isZh` branches replaced
by typed English and Chinese dictionaries held to key and token parity,
with the other sixteen locales keeping the English fallback.
crates/tui/CHANGELOG.md regenerated with ./scripts/sync-changelog.sh.
Signed-off-by: Hunter Bown <hmbown@gmail.com>
The getting-started contract corroborated the site's keyless-launch claim
by requiring docs/GUIDE.md to contain one exact sentence, "On first launch,
Codewhale opens with a recommended working agreement". The honest first-run
work replaced that flow, so the sentence is gone and the assertion pinned
obsolete copy rather than product truth. The web suite fails identically on
main and on any branch built from it.
Assert what the docs actually owe this step: inside the First Launch
section, that the first launch asks only for the decisions the install
still needs, and that the provider step keeps an explicit offline route.
Together those are what make "starts without any API key" true, and they
survive rewording. The section slice matches heading-level hashes only, so
the `# npm` comments inside the fenced install snippets cannot end it.
Evidence: `npm test` 311/311 pass (was 310/311), `npm run lint` clean,
`npx tsc --noEmit` clean, `npm run check:facts` and `check:docs` pass.
Signed-off-by: Hunter Bown <hmbown@gmail.com>
`cargo clippy --workspace --all-targets --all-features --locked -D warnings`
failed on four mechanical lints, which kept the release gate red while the
code itself was correct. Each fix is narrow and behavior-preserving:
- `qa_harness::watchdog::progress` collapses its nested `if` into the
edition-2024 let-chain clippy suggested; the label is still only taken
when the lock is free and only rewritten when it actually changed.
- The raw-stream ceiling invariants move into `const { assert!(..) }`
blocks. These compare two constants, so the check now fails the build
rather than a test run — strictly stronger evidence, same guarantee.
- The 80-column language-picker test drops a redundant closure.
- The copy-answer projection fixture is only iterated, so it is an array
rather than a `Vec`.
Evidence on this tree: `cargo fmt --all`; the exact all-target clippy
command exits 0; the four owning tests pass
(`raw_stream_ceiling_clears_every_downstream_bound`,
`bounded_output_keeps_last_two_thousand_complete_lines`,
`every_option_is_visible_at_80_columns`,
`completed_assistant_answer_projection_excludes_reasoning_tools_and_status`).
Signed-off-by: Hunter Bown <hmbown@gmail.com>
#5517 merged after v0.9.10 was cut and left no changelog entry, so
check-feature-release-notes.sh fails on any feature commit whose message
mentions it, including this branch's. crates/tui/CHANGELOG.md is the
sync-changelog.sh slice of the same entry.
Signed-off-by: Lstarsky0 <59827030+Lstarsky0@users.noreply.github.com>
Both pages carried 14 and 15 isZh branches; both are now zero. Same
shape as #5504 and #5517: an en and a zh dictionary per page, wired
through types.ts and index.ts, and both files added to
check-locales.mjs's OPTIONAL_FILES so zh is held to key and token
parity while the other sixteen locales fall back to English.
The config values the policies paragraph typesets as inline code, and
the commands and flags on the browser-client page, stay code-owned in
the page and reach the dictionaries as {token}s, per docs/VOICE.md.
Rendered output is unchanged across all 36 pages (18 locales x 2).
Move route identity to the phase rail, remove obsolete orchestration advertising, and replace the launch lecture with one localized invitation.
Signed-off-by: Hunter Bown <hmbown@gmail.com>
Describe Codewhale as a coding agent throughout the public landing copy while retaining DeepSeek Harness only as the external integration proper name.
Signed-off-by: Hunter Bown <hmbown@gmail.com>
Show the typed provider decision and offline action before opening the detailed provider picker on fresh installs.
Signed-off-by: Hunter Bown <hmbown@gmail.com>
Stop invoking deleted brittle harnesses, drop the retired PTY nextest target, and preserve Agent Mail error and redaction behavior without duplicate branches.
Signed-off-by: Hunter Bown <hmbown@gmail.com>
Ask only required decisions, preserve real CLI prompts, keep offline state visible, seed the first task, and route optional web continuation through /rc.
Signed-off-by: Hunter Bown <hmbown@gmail.com>