Skip to content

Integration: website wave 1 + 0.10.1 CI/automation slices - #6407

Open
Hmbown wants to merge 128 commits into
mainfrom
integration/2026-09-22-web-ci
Open

Hmbown wants to merge 128 commits into
mainfrom
integration/2026-09-22-web-ci

Conversation

@Hmbown

@Hmbown Hmbown commented Sep 22, 2026

Copy link
Copy Markdown
Owner

Integration branch for today's reviewed slices. It lands through CI instead of direct pushes, so main only moves when checks are green.

Website (codewhale.net plan, wave 1)

  • Design foundation:
    • globals.css split into per-surface partials; built CSS is byte-identical
    • GPUI role tokens from set_theme
    • OS-following theme
    • Shannon Sans everywhere
    • GPUI radius, state and motion grammar
  • Docs corrections: subagent clamp, Work mode, Auto-Review, credentials, log targets, the Auto section
  • README hygiene and a docs index
  • Route hops: /download, /desktop and /pricing go to install in one hop
  • A robots option in buildPageMetadata
  • The MCP hook matcher glob now matches on the owning server

0.10.1 CI and repo automation

  • Budget ratchets block same-repo PRs, with same-PR --update receipts
  • Intake bots are label-only; a negated closing keyword fails the link check
  • After every publish, the release workflow proposes the release record

0.10.1 product

  • git spawns never prompt, and git_fetch is bounded by a timeout

Each slice was reviewed by a second agent, and follow-up fixes are separate commits. Every commit message lists the local checks it ran with their counts. The full suite runs here in CI.

This branch also carries 3aaf47306 (runtime-api computer display, from a parallel session), because it was already on local main.

No deploy happens from this merge. The site changes need an approved production deploy to go live.

Refs #6397
Refs #6310
Refs #6184

🤖 Generated with Claude Code

CodeWhale Bot and others added 23 commits September 22, 2026 11:28
Pages that must stay out of search indexes (draft legal, auth, empty
digest, flag-gated pricing) can now pass robots directives through the
shared helper instead of hand-rolling metadata. Omitted by default, so
existing pages are unchanged. Plan slice S23 (DOCS-13).

Checks:
- npx vitest run page-meta: 1 file, 14/14 passed
- npx tsc --noEmit: exit 0, no errors

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…ost_saving

S9a (M1). The docs/CONFIGURATION.md Auto section still said Auto routes
between a strong and a cheap model with a local heuristic. Since #6290 the
local path is the declared default model; the only content-blind override is
[auto] cost_saving. Document the declared default, the optional
[auto.router] classifier (including timeout_secs: default 4, 0 = default,
capped at 300), [auto] cost_saving and [auto] cross_provider, citing
auto_route_declared_fallback / inventory_auto_router_system_prompt in
model_routing.rs, AutoConfig / AutoRouterConfig / auto_router_timeout_secs in
config.rs and ModelInventory::from_config in model_inventory.rs. Symbol
citations replace the stale config.rs:2392-2402 line range.

Checks: npm run check:docs PASS (23 topics, source files, version, install
snippets).

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
/download and /desktop 404'd (M2); /pricing took two 307 hops via
/en/pricing (UX-13). Middleware now sends all three, bare or localized
(miscased prefixes folded), straight to /<locale>/install with a 307.
Public pricing still does not render (section 0); the pricing page
redirect remains as a backstop. Dark /download hub waits on D11.

Checks:
- npx vitest run middleware public-billing-legal-routes: 2 files, 22 passed, 0 failed
- npx tsc --noEmit: pass
- npx eslint middleware.ts lib/middleware.test.ts: pass

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
- README.md + 18 localized READMEs: drop the private-repo reference (and its
  "codehwhale-gpui" typo) and the superseded "web app sunsets" wording; the
  hosted web app is rebuilt in the desktop app's image (2026-09-18 amendment).
  "All documentation" now links docs/README.md. Source stamps refreshed.
- docs/README.md: new index covering every top-level doc.
- /constitution is canonical: /docs/constitution permanently redirects there,
  drops out of the sitemap, and the docs-map topic resolves via sitePath.
  The constitution page no longer links to the redirecting docs URL.
- docs-computers (en): resolve "provider brands stay internal" contradicting
  the Daytona naming on the same page.

Checks run:
- python3 scripts/check-readme-translations.py: OK, 18 translations in sync
- scripts/check-readme-locales.sh: PASS
- npm run check:docs: PASS (23 topics)
- npx vitest run docs-ia: 1 file, 18 passed, 0 failed
- npx vitest run public-copy dictionaries llms-txt: 3 files, 33 passed, 0 failed
- npx tsc --noEmit: 0 errors

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…s, log targets

S14 docs correctness batch (DOCS-01/02/03/05/09), en and zh:
- docs-configuration: project-overlay max_subagents clamps to 1..=128
  (lib.rs project overlay -> config::MAX_SUBAGENTS, subagent_limits.rs).
  Credential order is the six lookups of resolve_runtime_options_with_secrets
  (route auth contract, --api-key, config api_key, api_key_env, secret store,
  provider env var); the secret store is file-backed under
  ~/.codewhale/secrets/ unless CODEWHALE_SECRET_BACKEND=system
  (secret_backend_selection in crates/secrets).
- docs-modes + docs/modes page + docs/GUIDE.md: "Act" -> "Work"
  (AppModeAgent in en/zh-Hans locales; AppMode::parse accepts "work", so the
  page shows /mode work). Auto-Review never asks the user
  (permission_posture_allows_questions, AutoDenyAutoReview in authority.rs).
- docs-troubleshooting + docs/OPERATIONS_RUNBOOK.md: log targets are
  codewhale_tui / codewhale_tui::client (crate lib name); checkpoints and
  offline queues are per session (<id>.json, <id>.offline_queue.json), with
  legacy latest.json read-only and offline_queue.json adopted once
  (session_manager.rs).

Checks: npm run check:docs PASS; npx vitest run public-copy docs-ia
2 files / 24 tests passed; npm run build succeeded (shared tree also held
other agents' uncommitted edits at the time).

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Finish the Act -> Work rename in slice-owned docs that S14 missed:
- docs/GUIDE.md:326 still showed '/mode act' in the direct-switch block
  (the page and dictionaries now show '/mode work').
- docs/CONFIGURATION.md:1856 still said 'Plan and Act are the everyday
  visible modes'.
AppMode::parse accepts 'work' (crates/config/src/app_mode.rs); en.json
AppModeAgent = "Work".

Checks: npm run check:docs PASS (23 topics, source files, version=0.10.0,
install snippets); npx vitest run public-copy docs-ia: 2 files, 24/24
passed. npm run build not re-run (markdown-only change; other agents
building in web/).

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
globals.css (3,828 lines) becomes an import hub over app/styles/*.css,
cut at existing section boundaries in the original order: tailwind,
tokens-roles, base, shell, utilities, portal, home, docs, states,
docs-help, changelog, overrides. Pure move; no rule edited.

Tailwind expands each CSS file separately and appends variant utilities
(hover:, md:, ...) at the end of whichever file holds `@tailwind
utilities`, which moved them ahead of every site rule. postcss.config
now runs postcss-import (already a tailwindcss@3 dependency, hoisted in
package-lock) for ./styles/ imports so Tailwind sees one stylesheet
again. tokens.css stays a separate module as before.

The contract tests and whale-tokens.ts read the stylesheet through a new
lib/site-css.ts, which inlines the partials in cascade order.

Checks:
- Built CSS, back-to-back A/B/A builds (original / split / original):
  split output byte-identical to original (same md5 and chunk hash).
- next build: exit 0
- npm run lint: 0 errors, 2 pre-existing warnings
- npx tsc --noEmit: exit 0
- vitest (docs-theme-contract, blue-stage-contract, docs-ia,
  nav-hit-target, public-surface-contract): 5 files, 43/43 passed
- npm run check:tokens: up to date (122 tokens)

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Add a separate GPUI_* / GPUI_LIGHT_* const set to crates/palette
(mirrored from codewhale-app set_theme; Shoreline and the TUI are
unchanged, per founder decision D2 = separate set), export it as
--gpui-dark-* / --gpui-light-* through scripts/export-design-tokens.py,
and regenerate web/app/tokens.css.

web/app/styles/tokens-roles.css:
- New role layer (--bg --surface --panel --text --muted --line --accent
  --on-accent --hover --selected --selection --ring) that follows the
  OS: dark under prefers-color-scheme guarded by
  :root:not([data-theme="light"]), repeated for [data-theme="dark"].
  Not yet consumed; S2 moves the site onto it.
- The folio's --gpui-* aliases and --c-* triples now resolve to the
  generated GPUI values instead of Shoreline, with no literal hexes in
  role positions: hover is primary @ 0.9 and selection primary @ 0.28,
  as set_theme derives them. Dark ink-mute moves from #7e7583 (3.70:1)
  to muted_foreground #b1b1ad (UX-05).
- Removed the false "same constants the GPUI client..." comments
  (tokens-roles.css, tokens.rs Shoreline header).
tailwind indigo-deep now reads --indigo-deep (the dropped literal
--c-indigo-deep hover triple).

Checks (web/):
- npm run check:tokens: OK (142 tokens)
- npm run lint: 0 errors, 2 pre-existing warnings
- npx tsc --noEmit: pass
- npx vitest run lib/gpui-role-tokens lib/blue-stage-contract
  lib/docs-theme-contract: 3 files, 11/11 passed
- npm run build: pass
- cargo test -p codewhale-palette: 81 passed, 0 failed

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Stop repo automation from commenting on issues and PRs, and stop the
PR-link gate from passing a negated closing keyword, which GitHub still
acts on (PR 6371 closed the P1 in Refs below that way).

- issue-gate, pr-gate: skip comments entirely; bots (user.type == 'Bot')
  get a `bot-authored` label, unapproved externals get `needs-triage` /
  `contribution-gate` labels whose descriptions carry the old guidance.
  Enforce mode still closes the PR (now silently; mode is dry-run).
- spam-lockdown: label + close, no comment; `spam` label description
  tells a false positive how to reopen.
- stale: empty stale/close messages, so actions/stale labels and closes
  without commenting (verified at the pinned SHA: skip when length 0).
- approve-contributor: answer /lgtm and /lgtmi with reactions on the
  maintainer's comment plus a run-log notice instead of replies.
- pr-issue-link: fail when a closing keyword follows not/never/without/
  n't within three words; accept `Refs #N` as the non-closing link
  alongside `No-Issue:`.
- AGENTS.md: write close/fix/resolve #N only when you mean it.

Remaining comment paths are only the disabled agent review workflows
(claude-review.yml, codewhale-review.yml), left for the founder.

Refs #6184

Checks run:
- actionlint on the 6 workflows: pass (0 findings)
- pr-issue-link run script vs 14 PR bodies, GNU grep 3.11 (ubuntu:24.04)
  and BSD grep: 14/14 expected; negated forms (does not / doesn't /
  never / won't + keyword + issue ref) fail; Closes/Fixes:/Refs/No-Issue pass
- github-script bodies: node --check 4/4 ok; mocked-API run 8/8 scenarios
  (bot issue -> labels, 0 comments; bot PR, human issue/PR dry+enforce,
  spam, /lgtm misuse, /lgtmi) with zero createComment calls
- grep createComment .github/workflows: 0 hits
- npm test / check:web not run (workflow YAML + one doc line only)

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Every release turned Web Frontend red: check:latest-release compares the
checked-in record with GitHub's latest release and nothing wrote it, so the
record was hand-committed after each publish (e7ee83f, 2b8e6e1, ...).

- release.yml: new final `sync-release-record` job (needs release). Checks out
  the default branch at full depth, runs sync-latest-release.mjs and
  derive-facts.mjs, re-proves the record with sync-latest-release --check,
  check-cloud-facts and check-facts, then commits the four record files as
  CodeWhale Bot on chore/release-record-<tag> and opens a PR. It never pushes
  to the default branch (the ruleset requires a PR there). GITHUB_TOKEN may
  not open PRs in this repo, so the PR uses RELEASE_TAG_PAT; without it the
  job pushes the branch and fails with the compare link.
- sync-latest-release.mjs: also writes docs/cloud-facts/stable.json
  release.latest/release_url (the third mirror the last manual chore commit
  had to edit by hand), and repairs it even when the other two are current.
  --check only warns while the record is exactly one published release behind
  a release under 24h old, so PRs and main stay green while the bot PR waits.
  Past 24h, or two releases behind, it fails as before.

Refs plan 0.10.1 item B.

Checks run:
- actionlint .github/workflows/release.yml: 0 findings
- sync-latest-release in a scratch tree against live GitHub releases:
  current --check exit 0; one behind (v0.9.13, v0.10.0 at 1h old) exit 0 with
  warning; two behind (v0.9.12) exit 1; one behind with clock +2d exit 1;
  write mode reproduces the checked-in three files byte-for-byte; stale-only
  stable.json repaired.
- Job steps replayed on a scratch clone at 6ee404b (the commit whose Web
  Frontend runs 35766445346/35766445218 failed): produced the same four-file
  diff as the manual 2b8e6e1 except facts.generated.ts generatedAt;
  check:latest-release, check-cloud-facts, check-facts all OK; commit landed
  on chore/release-record-v0.10.0 as CodeWhale Bot. Push/PR not exercised.
- Current tree: check-cloud-facts OK, check-facts OK.
- npm test && npm run check:web not run (no web app/test code changed).

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The negated-keyword check matched only `#N`, so "Refs #1. Does not close
https://github.com/<owner>/<repo>/issues/N" (or owner/repo#N) passed via the
Refs line while GitHub still closed the issue on merge. Match all three
reference forms GitHub closes on: #N, owner/repo#N, full issue URL.

Refs #6184

Checks run:
- actionlint on pr-issue-link.yml: pass (0 findings); on all 6 lane
  workflows before the fix: pass (0 findings)
- pr-issue-link run script vs 19 PR bodies with stub gh: 19/19 expected
  under BSD grep (macOS) and GNU grep 3.11 (ubuntu:24.04); before the fix
  2 of 17 mismatched (negated owner/repo#N with Refs passed; Closes <URL>
  failed)
- github-script bodies: node --check 4/4 ok
- grep createComment .github/workflows: 0 hits

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
S2 of codewhale-ops/plans/WEBSITE-20260922.md (DL-5, DL-14, UX-07).

- The whole site now follows prefers-color-scheme: light by default, the
  GPUI dark set under OS dark unless data-theme="light" is pinned, and dark
  whenever data-theme="dark" is pinned. The legacy folio tokens (--paper,
  --ink, --indigo, --c-* triples, state inks, --docs-*) are merged into the
  role layer's dark blocks, so one OS-dark block and one pinned-dark block
  (asserted identical) re-ink everything.
- Deleted the docs-only region dark (html[data-theme=dark] .docs-portal and
  html[data-theme=dark] .docs-theme); docs inks are declared beside :root in
  both schemes and the docs sheet follows the root theme.
- ThemeToggle renders on every page (docs-only return null removed), uses
  system|light|dark on the shared cw-theme key, reads a stored "auto" as
  system, and its header comment is corrected.
- Boot script comment corrected: with no pin, CSS resolves the OS before
  paint and tracks it live; only an explicit light/dark is pinned.

Deliberately kept: .ocean-column and .site-footer stay the fixed dark stage
in both schemes (they share the pinned-dark block), because the waterline
strata in components/strata.tsx paint the descent in fixed stage tokens and
that file is outside this slice.

Checks run (from web/):
- npx vitest run lib/public-surface-contract lib/docs-ia
  lib/i18n/nav-hit-target lib/docs-theme-contract lib/blue-stage-contract
  lib/gpui-role-tokens: 6 files, 49/49 passed
- npm run check:tokens: up to date (142 tokens)
- npm run lint: 0 errors, 2 pre-existing warnings (nav.tsx <img>)
- npx tsc --noEmit: exit 0
- npm run build: succeeded

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…DOCS-04)

The documented `mcp__*` tool_name glob never matched a real MCP tool: the
model calls server tools by `McpPool::mcp_model_tool_name`
(`mcp_<server>_<tool>`), so the double-underscore pattern missed them all,
and the single-underscore `mcp_*` a user might try instead also caught the
built-in helpers (`mcp_read_resource`, `mcp_get_prompt`).

tool_name conditions now treat any `mcp__…` pattern (translated to the
model spelling via `mcp_model_tool_name`) and any glob starting with `mcp_`
as scoped to server-owned tools; the helpers are reachable by exact name
only. Known limits are written beside the matcher.

Checks run:
- New test mcp_glob_matches_real_model_tool_names_by_owning_server failed
  against the old matcher ("mcp_github_create_issue must match mcp__*"):
  0 passed; 1 failed.
- cargo test -p codewhale-tui hooks:: after the fix: lib 154 passed;
  0 failed (other test binaries matched 0).
- rustfmt --check on executor.rs: clean.
Not run: reproduction against a live MCP server; docs (S15b) unchanged.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The sync-release-record job comment said check:latest-release only warns on
pull_request; the script warns on every event within the 24h one-behind
window. Make the comment match the code.

Refs plan 0.10.1 item B.

Checks run:
- actionlint .github/workflows/release.yml: exit 0, 0 findings
- sync-latest-release --check on current tree: exit 0 (already current v0.10.0)
- scratch tree, live releases: one behind (v0.9.13) exit 0 with warning; two
  behind (v0.9.12) exit 1; write mode reproduced all three checked-in files
  byte-for-byte
- check-cloud-facts: OK; check-facts: OK

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…eceipts

The four whole-repo ratchets (dead-code, blocking-calls, runtime-contract,
persistence-backlog) were advisory on every pull request and fatal on
push, so PRs looked green and main went red after merge (38 of 154
main-push ci.yml runs green, 2026-09-16..22). 0.10.1 plan item A.

- scripts/ratchet-gate.sh wraps each ratchet in ci.yml. A failing check
  on a PR is re-run on the PR's merge base (first parent of the merge
  commit) in a throwaway checkout: base also fails -> inherited debt,
  warning only; base passes -> the PR added the debt, error. No base
  (push/schedule/dispatch) or unresolvable base -> blocks. Fork PRs stay
  advisory via continue-on-error; same-repo PRs now block.
- Every failure prints the receipt command that lands the fix in the
  same PR. runtime-contract gains `--update --allow-increase` (accepts
  growth and identity changes, which 759a373 had to hand-edit around,
  and keeps `_` history notes on any update). persistence-backlog gains
  `--update`, raising only exceeded ceilings and never lowering one
  (ceilings carry noise headroom).
- scripts/preflight.sh: one pre-push/preflight for sync-changelog
  (writes, or --check), README translation + locale checks, dead-code and
  blocking-calls ratchets (--full adds the cargo-backed two), and the
  branch's own feature receipts. Usable as a pre-push symlink.
- Version drift job: new blocking PR-scoped feature receipt step
  (check-feature-release-notes.sh base.sha..HEAD); the previous-tag range
  audit stays advisory. Lint job now also runs the blocking-calls
  checker's own unit tests.

Checks run (local):
- python3 scripts/test_check_dead_code_budget.py: 6 passed
- python3 scripts/test_check_blocking_calls_budget.py: 11 passed
- python3 scripts/test_check_runtime_contract_budget.py: 22 passed (3 new)
- python3 scripts/test_check_persistence_backlog_budget.py: 18 passed (2 new)
- actionlint (CI's ignore set) on ci.yml: 0 findings; shellcheck on both
  new scripts: 0 findings
- Scratch-clone simulation with a real injected thread::sleep in
  crates/cli/src/cloud.rs: PR vs clean base -> rc 1 (error); no base ->
  rc 1; unresolvable base -> rc 1; unrelated PR on red base -> rc 0
  (inherited warning); same PR after --update -> rc 0; base worktree
  removed afterwards.
- PR-scoped receipt: feat commit citing an unrecorded #N -> rc 1; after
  adding the CHANGELOG receipt -> rc 0.
- scripts/preflight.sh --check on the shared checkout: runs all steps.
Not run: the cargo-backed runtime-contract/persistence measurements, and
the npm test && npm run check:web gate (no npm/web files touched).
Hosted proof pending: a test PR on GitHub failing then passing with
--update, and 7 days of main-push success rate
(gh run list -w ci.yml -b main -e push).

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Typography and fonts in one sweep, per WEBSITE-20260922 S3 (DL-3, DL-4,
DL-15, DL-16, UX-06):

- layout.tsx drops the Newsreader and IBM Plex Mono next/font/google
  loads. Shannon Sans is split by the new web/scripts/subset-shannon-sans.py
  into a Latin face (56 KB, the only preloaded font) and an extended face
  (latin-ext/Greek/Cyrillic/Devanagari, preload: false), each declared with
  its unicode-range. The pinned 531 KB source stays as the subset input.
- tokens-roles.css: --font-body/--font-display resolve to the two Shannon
  subsets; --font-mono is the system monospace stack; --font-cjk is a sans
  stack; --text-mono 13px and --text-prose/--leading-prose 15/23.
- styles/*: every Newsreader rule now uses the sans display role (headings
  600), every text-transform: uppercase and its wide tracking is gone,
  labels are 12px sentence case in the body face, header/connection
  buttons 13px; code blocks and the composer prompt use --text-mono; docs
  and legal prose use 15/23. .font-serif is removed (no callers); the
  .font-display serif override (DL-15) is now the sans display face.
- tailwind.config.ts: font families point at the role vars only (no serif,
  no JetBrains fallback); the letterSpacing scale drops wider/widest; the
  textTransform core plugin is off so `uppercase` cannot be generated.
- lib/typography-contract.test.ts pins the above.

Checks (run in web/):
- npx vitest run lib/typography-contract lib/docs-theme-contract
  lib/public-auth-routes lib/blue-stage-contract: 4 files, 18 passed, 0 failed
- npx tsc --noEmit: exit 0
- npm run lint: 0 errors, 2 warnings (pre-existing no-img-element)
- npm run check:tokens: up to date (142 tokens)
- npm run build: exit 0; built /en HTML has 1 font preload (was 7);
  built CSS has no Newsreader/IBM Plex/JetBrains/text-transform:uppercase
- grep -c 'Newsreader\|uppercase' web/app/styles/*.css: 0 in every file

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…system (S4)

- Radius tokens --radius-{control,surface,sheet,pill} = 6/10/14/999px
  (DESIGN.md); every border-radius in app/styles/ and the Tailwind
  borderRadius scale resolves through them (code blocks and plates 10px).
- One :focus-visible ring (2px var(--ring)); per-component outlines, the
  search-input glow and admin focus:outline-none removed. ::selection uses
  the set_theme selection role (primary @ 0.28).
- Primary fills rest at primary and hover at primary @ 0.9 (folio and
  install CTA were inverted); neutral hovers use the --hover role.
- --ease-spring fits PANEL_SPRING(420, 42, 1) (motion.rs) as one
  cubic-bezier (max error 1.3%), with --dur-state/--dur-spring; reduced
  motion zeroes both so the page is a still pose.
- New components/icon.tsx ported from web-next; nav GitHub mark uses it.
- Deleted unused components/presence.tsx and the dead whale caustic
  branch plus its keyframes.
- Deferred: ui/{button,chip,card} primitives. Their existing callers
  (portal-button in ~14 app pages, the digest/runtime cards) are outside
  this slice's files, and a primitive without its callers is not created.

Checks (from web/):
- npm run check:tokens: pass (142 tokens up to date)
- npm run lint: 0 errors, 2 pre-existing <img> warnings (footer, nav)
- npx tsc --noEmit: pass (0 errors)
- npx vitest run design-grammar-contract typography-contract
  blue-stage-contract docs-ia docs-theme-contract gpui-role-tokens:
  6 files, 39/39 passed
- npm run build: pass; built CSS radii only 6/10/14/999px via tokens

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…r-surface partials under web/app/styles/ (pure move)

Correct a stale comment in blue-stage-contract.test.ts that still said
globals.css holds the palette-token references; they now live in the
app/styles/ partials.

Checks:
- Reviewer PostCSS A/B compile (parent vs 28754c4, tailwind+autoprefixer
  via the repo postcss.config): output identical after stripping comments
  and whitespace (rule order preserved)
- vitest (5 slice contract files at HEAD): 5 files, 45/45 passed
- vitest blue-stage-contract after edit: passed
- npx tsc --noEmit: exit 0
- npm run lint: 0 errors, 2 pre-existing warnings
- npm run check:tokens: up to date (142 tokens)

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…tives, icons (design foundation chain, after S1a/S1/S2/S3)

- Stage surfaces (ocean-column, footer, folio-shot, portal quickstart/
  community, contribute dev loop, code blocks) take the dark scheme's ring.
  S4 removed the homepage's gold focus ring, leaving the light primary
  ring (#245bc7) on the sidebar-dark stage (#191a1c) at ~2.8:1, under the
  3:1 a focus indicator needs; #90b9ff there is ~8.8:1.
- Tailwind's DEFAULT transition duration/easing now resolve to
  --dur-state/--ease-spring, so `transition-colors` callers follow the
  spring curve and are stilled under reduced motion like app/styles.
- Contract test covers both.

Checks (from web/):
- npm run check:tokens: pass (142 tokens up to date)
- npm run lint: 0 errors, 2 pre-existing <img> warnings (footer, nav)
- npx tsc --noEmit: pass (0 errors)
- npx vitest run design-grammar-contract typography-contract
  blue-stage-contract docs-ia docs-theme-contract gpui-role-tokens:
  6 files, 39/39 passed
- npm run build: exit 0; built CSS radii only via the 4 radius tokens

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…foundation chain, after S1a 28754c4 and S1 3cd160e)

S2 turned the dark scheme on site-wide, but the nav wordmark
(public/brand/wordmark.svg) is fixed #142352 navy ink, about 1.2:1 on the
dark charcoal, so the brand name vanished from the nav in dark (OS or
pinned). Re-ink the logo to the light stage foreground under both dark
selectors in styles/shell.css (a file S2's plan section lists), and assert
both selectors in the docs theme contract test.

Checks run (from web/):
- npx vitest run lib/public-surface-contract lib/docs-ia
  lib/i18n/nav-hit-target lib/docs-theme-contract lib/blue-stage-contract
  lib/gpui-role-tokens: 6 files, 50/50 passed
- npm run check:tokens: up to date (142 tokens)
- npm run lint: 0 errors, 2 pre-existing warnings (nav.tsx <img>)
- npx tsc --noEmit: exit 0
- npm run build: succeeded (821 static pages)
- Headless Chrome against next start on :3057, light and dark
  prefers-color-scheme, /en /en/docs /en/faq plus stored light/dark/auto:
  body bg and color-scheme follow the OS, pins win, legacy "auto" follows
  the OS; wordmark visible in dark after the fix.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…okens (S2)

Engine side of the Sprite computer (research/computer ARCHITECTURE §3.3, §6 S2):

- GET /v1/computer/display: WebSocket carrying raw RFB 3.8. The Engine does
  the upstream handshake with Xvnc on its Unix socket
  (CODEWHALE_COMPUTER_DISPLAY_SOCKET, default /run/cw/vnc.sock, always
  shared ClientInit) and offers only security None downstream. Server bytes
  pass verbatim; client bytes go through a fail-closed, length-tracked
  parser in its own task (types 0,2,3,4,5,6,150,251 only; unknown type ->
  close 1008 + event; parser panic -> 1011, contained to that task).
  SetEncodings is filtered so Xvnc never starts Fence/xvp/QEMU/ext-clipboard.
  Input (4,5,6,251) is dropped unless the principal holds the lease.
- Lease: POST /v1/computer/control/{acquire,release}, GET /v1/computer,
  300 s idle expiry; events computer.display.{attached,detached,idle_closed},
  computer.control.{acquired,released,expired} via GET /v1/computer/events.
  Events carry spans and counts only, never keystrokes or frames.
- POST/GET /v1/auth/client-tokens, DELETE /v1/auth/client-tokens/{id}:
  master-token only, per device, <= 1 h, revocable; a client token carries
  /v1 authority (auth.rs) but cannot manage tokens. Revocation closes its
  display sockets and expires its lease.
- POST /v1/computer/display/tickets: single-use 30 s ticket for ?ticket=,
  redacted (with mobile_stream_ticket/token) by redact_query_secrets.
- Peer IP is never trusted (S0 Q3: /proxy peers arrive as 10.0.0.2).
- axum gains the `ws` feature; tokio-tungstenite 0.29 is a dev-dependency.

Evidence: NOT RUN. `cargo test -p codewhale-tui --lib computer_display`
built for 28 min under shared-target contention and then failed on two
errors in other agents' uncommitted files (context_report/
pressure_fixture_tests.rs unused import; commands/groups/debug/cache.rs:877
E0596). No errors or warnings were reported in files this commit touches,
but 0 tests have run. The gate (npm test && npm run check:web) was not run.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
A remote that wanted credentials, a passphrase or a host-key confirmation
could prompt on /dev/tty inside the raw-mode TUI while a blocking
cmd.output() held a spawn_blocking thread forever, so the turn looked
frozen (a contributor to #6184-shaped reports).

- dependencies.rs: one helper, apply_git_noninteractive_env, is the single
  definition site for GIT_TERMINAL_PROMPT=0, GIT_PAGER='' and BatchMode ssh
  (skipped when the user pinned GIT_SSH_COMMAND or GIT_SSH). Git::command
  applies it, and Git::tokio_command now builds from Git::command so async
  spawns carry the same lock and prompt guards.
- runtime_api/git.rs, review_pr.rs, Git::review_command: drop their private
  copies of the env; review_pr applies the helper to its gh command too.
- git_history.rs: git_fetch runs under tokio::process with kill_on_drop and
  a 300s deadline, and reports a clear timed-out error. The "Known
  limitation" note is replaced.

Checks (run on an isolated HEAD+patch snapshot, because the shared
checkout's lib test build currently fails in other lanes' in-flight files
such as runtime_api/computer_display.rs and debug/cache.rs):
- cargo test -p codewhale-tui --lib -- git_fetch git_command
  dependencies::tests runtime_api::git review_pr tools::git_history
  tools::git:: : 89 passed, 0 failed. New tests are
  git_fetch_fails_fast_when_remote_requires_credentials (a loopback HTTP
  remote answering 401: clear error, no prompt),
  git_fetch_runner_kills_a_remote_that_never_answers (2s deadline) and
  git_commands_are_non_interactive.
- grep GIT_TERMINAL_PROMPT crates: one set site (dependencies.rs), plus
  doc comments and a test assertion.
- cargo clippy -p codewhale-tui --lib --tests: no findings in touched
  files. It reported 17 existing too_many_arguments errors in other files.
- Not run: npm test && npm run check:web (lane scope; not run here).

Refs #6184

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Move the new is_mcp_server_tool helper above tool_category_for's doc
comment. 091f052 inserted the helper between that doc block and its
function, so rustdoc attached the tool_category classification docs to
is_mcp_server_tool, and tool_category_for lost its own docs. The change
only moves code.

Checks run:
- rustfmt --edition 2024 --check executor.rs: clean.
- cargo test -p codewhale-tui --lib hooks:: (HEAD export + this file, in
  an isolated target dir, because the shared tree has an unrelated
  uncommitted compile error in commands/groups/debug/cache.rs:877):
  154 passed; 0 failed.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Copilot AI lite review requested due to automatic review settings September 22, 2026 20:21
@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.
To continue using code reviews, add credits to your account and enable them for code reviews in your settings.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

Comment thread crates/tui/src/runtime_api/computer_display.rs Fixed
CodeWhale Bot and others added 3 commits September 22, 2026 13:49
…urst window

The `[↵]` chip read `composer_enter_would_submit`, which also consults the
paste-burst window. That window is re-extended on every fast keystroke, so on
terminals outside the bracketed-paste allowlist (tmux, VS Code, kitty,
Alacritty, GNOME Terminal, SSH) the chip strobed `[↵]`/`[·]` while typing.

Add `App::composer_draft_is_submittable` (time-independent, trimmed-empty
check) and paint the chip from it. Enter routing, mouse submit and hover
registration stay on the timing predicate. Lands the preserved patch from the
fix/issue-sweep-0.10.0 worktree, with its placement corrected so
`composer_enter_would_submit` keeps its own doc comment and `#[must_use]`.
The pinned test at ui/tests.rs:6641 now asserts a steady `[↵]` while the
burst window is open and Enter routing still waits.

Refs #6397

Checks (run from a HEAD snapshot + these three files, because the shared
checkout's lib-test build was broken by other lanes' in-flight edits in
git_history.rs, context_report/, core/engine/tests.rs and debug/cache.rs):
- cargo test -p codewhale-tui --lib -- paste_safety composer_submit
  composer_enter submit_cue composer_draft: 6 passed, 0 failed
- rustfmt --check composer.rs: clean
Not run: manual tmux / VS Code terminal check.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
A provider response that ends with a clean terminal stop (e.g. `stop`)
and carries no text, no reasoning and no tool call used to fall straight
into the fatal "no answer or tool call" branch. Treat it like the
no-content stream death it is: one exact-prefix re-request, then one
re-request with the request-scoped continue nudge, then fail visibly
with the retry count in the message.

- turn_loop.rs: shared `plan_empty_stop_retry` / `EMPTY_STOP_MAX_RETRIES`
  (2); the engine records attempts in the new
  `stop_diagnostics.empty_stop_retries`. Output-limit stops, stream
  errors, reasoning-only replies (own reprompt path) and pending steers
  are excluded.
- acp_server.rs: `run_agentic_prompt_turn` used to report an empty
  completion as a silent success; it now uses the same budget, nudge
  and visible failure.
- tool_inspection.rs: `TurnStopDiagnostics::empty_stop_retries`.

Checks (built on a HEAD snapshot plus these four files, because the
shared checkout had other lanes' in-flight compile errors):
- cargo test -p codewhale-tui --lib -- empty_clean_stop agentic_turn
  tool_result_followed_by_terminal_empty reasoning_only: 19 passed, 0 failed
- cargo test -p codewhale-tui --lib -- acp_server
  core::engine::tests::sse_turn_recovery terminal_diagnostics
  stream_resume no_content empty: 382 passed, 0 failed
- cargo test -p codewhale-tui --lib -- core::engine runtime_threads:
  780 passed, 0 failed, 6 ignored
- `npm test && npm run check:web` gate was not run (Rust-only slice)

Refs #6310

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
git_fetch's deadline killed only the git process. Git hands the network
to a transport child (git-remote-http, ssh) which survived the SIGKILL
and kept the stalled connection open with no bound. Reproduced by hand:
after killing `git fetch` against a silent loopback remote,
git-remote-http was still running.

- run_git_command_bounded spawns git in its own process group on unix
  and, at the deadline, SIGKILLs the whole group. kill_on_drop still
  covers the leader.
- git_fetch_runner_kills_a_remote_that_never_answers now also asserts
  that the fake remote's connection closes after the deadline. It fails
  against the previous runner with "transport child outlived the
  deadline" (15 passed, 1 failed in tools::git_history) and passes with
  this change.
- spawn_fake_http_remote no longer needs its never-answer mode.

Checks, run on an isolated snapshot of 6b75b4f plus this file (the
shared checkout carries other lanes' uncommitted work):
- cargo test -p codewhale-tui --lib -- git_fetch git_command
  dependencies::tests runtime_api::git review_pr tools::git_history
  tools::git:: : 89 passed, 0 failed
- git_fetch_runner_kills_a_remote_that_never_answers alone, 3 runs:
  1 passed, 0 failed each time
- rustfmt --check on the file: clean. cargo clippy -p codewhale-tui
  --lib --tests: no findings in git_history.rs

Refs #6184

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
CodeWhale Bot and others added 28 commits September 22, 2026 20:29
/help used to append pinyin aliases to English rows ("/clear  (aliases:
/qingping)", /tuichu, /bangzhu, ...). Romanized and Han-script aliases
still dispatch and still match the filter in every locale, but the row
lists them only in the Chinese packs.

The fourteen English command summaries longer than 60 columns are
rewritten as one short sentence, so the list no longer sheds them into
fragments such as "Manage durable scheduled". The help title's subtitle
and /help's own summary stop promising a Concepts section that does not
exist yet: "Commands, skills, and keys".

Checks: cargo test -p codewhale-tui --lib tui::views::help +
tui::provider_picker: 186 passed, 0 failed (same run as two unrelated
failures in footer/frame files other lanes are editing).

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TvKGZz4LrKfrQiAXip48JS
…line

In a terminal without Kitty graphics and no pet companion, /pet painted
an empty tank captioned " · unobserved · Sound off", starting with an
orphan separator, and pet mode still took over the screen for a running
turn.

- With no companion frame the tank paints the launch screen's braille
  whale (largest rung that fits) above its caption. Once the companion
  has said it cannot be reached, the caption is "offline — codewhale pet
  serve wakes it"; before that the whale rests.
- The caption joins only non-empty parts, so no leading " · ".
- "unobserved" reads "resting" (presence vocabulary), in the habitat and
  in the cameo widget; the reconnect notice drops the word.
- Pet mode does not auto-enter for a turn while the companion is
  unavailable, and if the companion drops while a turn is running the
  habitat closes so the transcript stays in view.

New message PetOffline in every locale pack (translated), keeping parity.

Checks: cargo test -p codewhale-tui --lib tui::pet_watch tui::ambient_life
(within the 2551-pass targeted run; no pet or ambient failures), including
the new unavailable_companion_paints_the_resting_whale_and_keeps_the_turn_
visible; cargo test -p codewhale-localization 50 passed; staged locale
key parity checked across all 15 packs.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TvKGZz4LrKfrQiAXip48JS
In the all-providers view every unconfigured row read "missing key · N
bundled", fifty times down an alphabetical list. A row that needs a key
now says "needs key" (or "needs sign-in") and nothing else; the Details
pane beside the list still carries the catalog count. Configured
providers keep leading the list.

Checks: cargo test -p codewhale-tui --lib tui::provider_picker (in a
186-pass run with tui::views::help; the run's two failures are footer and
frame rows in files another lane is editing).

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TvKGZz4LrKfrQiAXip48JS
"Access now: {posture}" names a substitution slot, not a word anyone
reads. The lint now strips {name} slots before matching, and allowlists
the /fleet workers command name in its quick-start row.

Checks: python3 scripts/check-lexicon.py --summary -> 73 findings, rc 0.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TvKGZz4LrKfrQiAXip48JS
The slash menu described /setup as "Open constitution-first setup", an
engineering name. It now reads "Set up providers and preferences"
(experience mark 5). English value only; no test pins the old text.

Checks: git grep finds no Rust assertion on the old string;
check-tui-locale-parity unaffected (value-only change).

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TvKGZz4LrKfrQiAXip48JS
Typing "hello" with no key used to do nothing visible: the dispatch
failure set only a sticky footer status, and the engine's
"Auto-compaction enabled" acknowledgement (sent on every model/route
sync) classified as a success and cleared it.

- A missing-credential dispatch failure adds one transcript line ("No
  model connected, so this message was not sent. Choose a provider, then
  send it again.") and opens the provider picker, as a rejected
  environment key already does. The user's echo stays in the transcript.
- The engine acknowledges an unchanged SetCompaction silently; only a
  real change still reports "Auto-compaction enabled/disabled".
- While no model is connected, a routine success status no longer clears
  the error sticky; connecting a provider is the only thing that resolves
  it.

Checks: cargo test -p codewhale-tui --lib -- keyless_submit
unchanged_compaction_config sticky legacy_status missing_credential
dispatch_error -> 19 passed, 0 failed; -- onboarding keyless
compaction_config status_toast -> 77 passed, 0 failed. The PTY/golden
acceptance (keyless submit shows the cell and opens the picker in a real
terminal) is not added here.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TvKGZz4LrKfrQiAXip48JS
Follow-up to b9a3f14: format_stash_line was inserted between
preview_first_line and its doc comment, so rustdoc merged both
descriptions onto format_stash_line. Move the comment back. Update the
/cache doc comment, which still said any arg is a count override,
to say unknown args are now a usage error.

Checks: cargo test -p codewhale-tui --lib (stash, debug, config unknown,
session prune filters) -> 134 passed, 0 failed. rustfmt --check clean on
both files. Full npm test && npm run check:web gate not run.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TvKGZz4LrKfrQiAXip48JS
…its values; flag roster-dropped pins

0.10.1 lane B (experience marks 4 and 8, U3, #6035).

Approval card (E6, mark 4):
- ApprovalRequest carries the engine's model-independent `summary`
  (tools/approval_summary.rs) and its workspace. The English card heading
  is that sentence ("Run `cargo test`", "Write src/main.rs"); other packs
  keep the tool name until the summary is localized. File/Path/Dir detail
  rows show workspace-relative paths.
- Badges name the effect, not a tier: Reads only / Changes files / Runs a
  command / Uses the network / Uses a connected app / Starts an agent /
  Unclassified tool, and "Can't be undone" for destructive or publishing
  calls. REVIEW/APPROVAL badge ids are renamed; five ids are added.
- Categories: Command, Connected app (server), Agent. Choices: Allow for
  this conversation, Always allow in this repo, Don't allow, Stop this
  turn; Esc reads "stop". Critical-card prose drops policy/abort/Bash/MCP.
  All 15 packs translated.

Footer (mark 8, U3):
- The route's effort field is labeled ("thinking: max") and the context
  reading reads "context 12%" instead of "ctx".
- A keyless launch paints "model not connected" on the route chip instead
  of naming a default route that cannot answer, and the chip is not a
  route control until a model is connected. Tests whose fixtures carry no
  key but are about a connected route now set that explicitly; new
  keyless_launch_route_chip_says_not_connected pins the chip.

Fleet (#6035): the Fleet overview and the route picker (where a pin is
edited) flag a route whose fresh live roster no longer lists the model,
even when a bundled catalog row still offers it. Warning only; the pin
is never rewritten.

Checks:
- cargo test -p codewhale-localization: 50 passed, 0 failed
- cargo test -p codewhale-tui --lib -- approval widgets tui::ui:: infoline
  phase_strip fleet_detail underwater golden
  commands::groups::config::status provider_catalog_live: 1545 passed,
  1 failed (task_manager pending_approval_suspends_idle_... timing test;
  alone: 1 passed, 0 failed)
- cargo test -p codewhale-tui --lib -- approval (after the prose pass):
  295 passed, 1 failed (same timing test)
- scripts/check-lexicon.py: no findings left in approval or info-line keys
- not run: PTY suites, live providers

Refs #6035

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TvKGZz4LrKfrQiAXip48JS
…-default once

Review follow-up to afa53c8 and 4c6f180.

- Every pet notice used to mark the companion offline and, during a
  running turn, close the habitat. A refused select or export ("Save the
  terminal session before exporting") or a failed browser/window open
  came from a reachable companion, yet still closed pet mode. Only the
  new Notice::Unreachable (the view thread stopped, or a frame fetch
  failed and it is reconnecting) now marks it offline and hands the turn
  back; other messages stay a warning toast.
- The model-switch line read "Model is now X for this session (was Y).
  /model save-default keeps it. (session only — ... /model save-default
  remembers the default)": the caller already appends the session-only
  suffix, so the English value is now "Model is now {new} (was {old})."

Checks: cargo test -p codewhale-tui --lib -- tui::pet_watch
tui::ambient_life: 59 passed, 0 failed; the new regression test failed
(1 failed) with the old Message handling restored and passes with the
fix. tui::pet_watch + tui::ambient_life + commands::groups::core::core:
107 passed, 0 failed. cargo test -p codewhale-localization: 50 passed.
scripts/check-tui-locale-parity.py: PASS. rustfmt on the two pet files
only.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TvKGZz4LrKfrQiAXip48JS
Review follow-up on the A-engine lane (E2, mark 2).

- The posture-change status read "Policy: Full Access / ACT". Both words
  are in the CURRENT_DECISIONS section 19 "Not" column. It now reads
  "Permissions: Full Access · Work" (Plan / Work / Operate). The payload
  stays first, so a shed notice keeps the permission.
- The does-not-fit error claimed "there is no earlier conversation to
  summarize". It is used whenever history is below the summarizer's
  minimum (up to five messages), so a short exchange got a false claim.
  It now says "there is not enough earlier conversation to summarize".

Checks: cargo test -p codewhale-tui --lib --
posture_change_status broader_posture narrower_posture
a_request_that_cannot_fit -> 4 passed, 0 failed (new
posture_change_status_uses_permissions_and_work included). Lane filters
(live_runtime_authority posture_patch_during_approval_wait runtime_authority
change_mode deferred hydrat emergency context_does_not_fit keyless_submit
unchanged_compaction_config runtime_handoff sync_session ...) -> 69 passed,
0 failed. Broad filters approval_ compaction restore preflight onboarding
status_toast -> 556 passed, 2 failed. The failures are
task_manager pending_approval_suspends_idle_... and
tui::context_inspector inspector_rows_name_compaction_and_anchors. The first
is timing-sensitive under load and passed 3 of 3 runs alone. The second
renders en.json, which has peer edits. rustfmt --check was clean on the
touched files. The npm gate was not run.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TvKGZz4LrKfrQiAXip48JS
Review of c52a5c4 (lane B, experience mark 4). The approval card's
repo-rule variant still read "REPO LAW" and "Repository law requires
confirmation in approval-gated postures", both in the section 19 Not
column. The lexicon lint missed the plural, so the lane's no-findings
claim did not cover it.

- ApprovalRepoLawBadge: "Repo rule" (sentence case, like the new effect
  badges); ApprovalRepoLawWarning: "This repo's constitution asks you
  to confirm this change." Updated in the 10 packs that said law or
  posture (ja, ko, zh-Hans and zh-Hant already say constitution or rules).
- repo_law_approval_has_distinct_authority_grammar asserts the new copy
  and that REPO LAW, Repository law and posture never render.
- check-lexicon.py matches "postures" as well as "posture".

Checks:
- cargo test -p codewhale-localization: 50 passed, 0 failed
- cargo test -p codewhale-tui --lib -- approval repo_law: 311 passed,
  1 failed (task_manager pending_approval_suspends_idle_... timing test,
  file untouched here; alone: 1 passed, 0 failed, 3 runs)
- scripts/check-lexicon.py: 72 warn-only findings; none left in approval
  keys (the plural rule adds two in web docs-modes.ts)

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…2-web-ci

# Conflicts:
#	web/app/[locale]/docs/work/page.tsx
…real install state

- clap bin_name is `codewhale`, so usage/errors say `codewhale doctor`, not
  the retired `codewhale-tui`; tools README template and sample script too.
- doctor version block prints `codewhale: <ver>` and `host rustc:`; a missing
  rustc reads "not installed (only needed to build from source)".
- doctor update advice uses InstallMethod::detect(current_exe).update_command()
  so npm/Homebrew/cargo/Omarchy installs are not told to `codewhale update`.
- ExternalTool not-found errors name the binary (`git`), not the Rust type path.
- install.sh glibc failure matches preflight-glibc.js musl wording; drops the
  stale Ubuntu 22.04 and "Release follow-up" lines.
- install.bat checks all three source files before copying; PATH advice says
  PowerShell (no admin needed).
- npm shims share reportStartFailure, which prints installFailureHint; the hint
  links an absolute GitHub docs URL. The --version fallback prints
  `binary: not installed (expected vX)` with the error and hint on stderr
  instead of claiming an installed binary version.

Tests: cargo test -p codewhale-tui --lib (doctor::tests, dependencies::tests,
usage/companion name tests) 61 passed, 0 failed; new
dependencies missing_tool test passed; node --test npm/codewhale/test/*.test.js
67 passed, 0 failed.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TvKGZz4LrKfrQiAXip48JS
…, unignore streamable MCP

- subagent gpt55 route, web_search Baidu missing-key and client
  from_candidate tests now hold lock_test_env and use EnvVarGuard instead
  of unlocked unsafe set/restore; the false SAFETY comments are gone.
- external_editor tests drop their private ENV_LOCK/EnvGuard for the
  process-wide lock_test_env + EnvVarGuard (the editor helpers under test
  never take the lock, so the non-reentrant mutex is safe here).
- task_manager gains a wait_for_running deadline helper in place of the
  fixed 10ms/5ms sleeps; cancel_running_task_marks_canceled runs on
  CooperativeIdleCancelExecutor so the task cannot finish before cancel.
  Assertions unchanged.
- mcp streamable-HTTP event-stream test is no longer #[ignore]d (it
  already serializes on lock_mcp_loopback_tests); connect_timeout 2s->5s.

Checks (local, targeted): touched env tests 1/1/1 pass; external_editor
13 passed; mcp::tests --include-ignored 241 passed 0 failed 0 ignored;
task_manager cancel/shutdown pair 10x runs 2/2 each; streamable MCP 5x
pass; task_manager:: 65 passed 1 ignored. clippy -D warnings: no findings
in touched files (pre-existing too_many_arguments errors elsewhere).

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TvKGZz4LrKfrQiAXip48JS
The doctor update block re-implemented codewhale_release's
current_install_method() (current_exe + detect, Binary fallback). Call the
existing helper instead so there is one owner of that resolution.

Tests: cargo test -p codewhale-tui --lib (usage/companion name tests,
doctor::tests, dependencies::tests) 61 passed, 0 failed; node --test
npm/codewhale/test/*.test.js 67 passed, 0 failed.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TvKGZz4LrKfrQiAXip48JS
New catalogs expose lowercase `read` and `bash`; `File` and `Bash` are
model_visible=false compatibility names for saved transcripts. Several
model-facing strings still steered toward them:

- handle_read, the syntax-check edit refusal, and the skill companion-files
  note now say `read` (path=...) / `bash`.
- task_shell_wait's task_id no longer claims `Bash` returns task ids; the
  visible `bash` is foreground-only, so only task_shell_start does.
- pandoc_convert says `bash`.
- zh-Hans, ja, pt-BR and vi locale preambles use `read`/`bash` as the
  immutable tool-name examples.
- Bundled help and pdf skills name the `read` tool / `bash`. The pdf skill
  no longer claims the read tool extracts PDF text: the visible `read`
  lossy-decodes bytes and has no PDF path. Generation 15; exact
  generation-14 bodies are retained in SUPERSEDED_BODIES so untouched
  installs upgrade and edited ones do not.

Left alone: WriteFileTool/EditFileTool descriptions (and the test pinning
"`Bash`"/"File `read`" in them) belong to hidden handler tools whose
descriptions never enter a new catalog.

Tests: zh preamble test now asserts `read`/`bash` with `File`/`Bash` as
negatives; new tests cover all four preambles, the handle_read/pandoc/
task_shell_wait descriptions+schemas, a generation-14 -> 15 upgrade for help
and pdf, and negatives in the syntax-check and companion-files tests.

cargo test -p codewhale-tui --lib -- prompts:: tools::skill:: skills::system
tools::syntax_check tools::handle tools::pandoc: 185 passed, 0 failed.
cargo test -p codewhale-tui --lib -- tools::tasks: 12 passed, 0 failed.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TvKGZz4LrKfrQiAXip48JS
…rsor

- voice: the recording status uses MessageId::VoiceRecording for both the
  initial and the interim line (interim transcript kept), dropping the
  hardcoded English "(⌥V to finish)" hint.
- glyphs: hollow ○/☐ now fall back to `o` while ●/•/· stay `.`, so
  CURRENT and AVAILABLE remain distinguishable on ASCII terminals; the
  charter test asserts CURRENT != AVAILABLE. The tideline ASCII test
  expectation moves with it.
- cursor_accent: the OSC 12 accent is suppressed when ColorDepth::detect()
  is Monochrome (NO_COLOR), via a no_color flag on the pure predicate.

Tests: cargo test -p codewhale-tui --lib filtered to session_picker,
glyphs, cursor_accent, live_transcript, pager, session_boot, voice:
123 passed, 0 failed. Glyph-consumer sweep (ascii, color_compat,
notifications, whales, infoline, markdown_render, phase_strip,
focus_texture, tideline, underwater): 301 passed, 2 failed before the
tideline expectation update; after it the tideline test passes and the
remaining failure, views::tests::focus_texture_modes_keep_inline_modal_usable
("approval prompt must survive the texture"), comes from in-flight
approval/widgets work and is untouched here.

Refs #5846

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TvKGZz4LrKfrQiAXip48JS
Selecting a session read and parsed its whole transcript synchronously
in refresh_preview. Inside a runtime the load now runs on
spawn_blocking_supervised, tagged by session id and a per-refresh
generation, and tick() applies it only if it still matches the
selection; a stale result is cached but never shown. While loading, the
pane shows the ID and title lines plus an ellipsis, built from existing
localized strings (no new English-only text). Outside a runtime the load
stays inline. The preview cache is now an LRU bounded at 16 entries.

Tests: preview_cache_is_a_bounded_lru and
preview_loads_off_the_event_loop_and_drops_stale_results added; the
session_picker suite passes inside the 123-passed / 0-failed filtered run
(cargo test -p codewhale-tui --lib).

Refs #6014

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TvKGZz4LrKfrQiAXip48JS
- live_transcript: borrow the cached slice and clone each line and its
  links once (previously to_vec() then a second per-line clone); the miss
  path moves the rendered lines into the cache instead of cloning them.
- pager: search highlight uses binary_search on the ascending
  search_matches instead of a linear contains per visible line.
- markdown_render: prewarm_syntax_highlighting() loads the syntect syntax
  and theme sets; session_boot spawns it once (std::sync::Once, named
  thread) from SessionBootSurface::from_app, which only the live TUI
  footer reads, so headless paths never pay for it.

Tests: filtered cargo test -p codewhale-tui --lib (live_transcript,
pager, session_boot and the others in this lane): 123 passed, 0 failed;
markdown_render passes in the 301-test glyph-consumer sweep.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TvKGZz4LrKfrQiAXip48JS
Group the user-visible 0.10.1 work on this branch under Fixed, Experience,
Fleet and agents, Plugins and CI, keeping the existing Computer Use notes.
Adds release-note receipts for #6230, #6310 and #6303 (the three feature
commits the Version drift job flagged) plus #6184, #6035, #6277, #5529,
#6033, #6014, #6397, #5846, #3866, #6406, #6407. Regenerates
crates/tui/CHANGELOG.md (scripts/sync-changelog.sh) and
web/lib/changelog.generated.ts (npm --prefix web run prebuild).

Checks (local):
- scripts/release/check-feature-release-notes.sh origin/main HEAD: OK, 6 refs
- scripts/release/check-versions.sh --range-audit-advisory: OK, 62 refs in
  v0.9.13..HEAD; version state OK
- scripts/sync-changelog.sh --check: up to date
- vitest lib/changelog.test.ts: 6 passed, 0 failed

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TvKGZz4LrKfrQiAXip48JS
While the repository is on CodeQL default setup, GitHub rejects this
workflow's SARIF ("Code Scanning could not process the submitted SARIF").
The analyze job now requires vars.CODEQL_ADVANCED_SETUP == 'true'; the
header says the founder flips it after switching to advanced setup.

Checks: actionlint .github/workflows/codeql.yml: clean.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TvKGZz4LrKfrQiAXip48JS
CURRENT_DECISIONS §19 names Agent (not sub-agent) and Permissions (not
posture) across the TUI, app, site and docs. The Unreleased section said
sub-agent four times and posture three times, while also claiming the
TUI copy says agent and Permissions. Reworded those lines; no claims or
issue receipts changed. Regenerated crates/tui/CHANGELOG.md
(scripts/sync-changelog.sh) and web/lib/changelog.generated.ts
(npm --prefix web run prebuild).

Checks (local):
- scripts/sync-changelog.sh --check: up to date
- scripts/release/check-feature-release-notes.sh origin/main HEAD: OK, 6 refs
- vitest web lib/changelog.test.ts: 6 passed, 0 failed

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TvKGZz4LrKfrQiAXip48JS
… fmt, surface ceiling

CI on the integration branch (run 35816153928) failed Lint, Test on
ubuntu/macos, and Test on windows. Each failure traced to one cause:

- Intended copy change (4c6f180, c52a5c4; CURRENT_DECISIONS §19
  "Settings" not "Config", "Making room" not "compaction", mark 8/U3):
  - launch_card/search_text/contextual_tips PTY tests waited for the old
    "Config" title; the screen is titled "Settings".
  - core_command_surfaces.feature expected "Operator model changed:"; the
    model switch reads "Model is now ...".
  - context_inspector test expected the "compaction" row; it is "making room".
  - active_composer_pointer PTY expected the keyless launch to name
    deepseek-flash in the metrics row; a keyless launch now paints
    "model not connected" on the route chip by design.
- Windows compile (-D warnings): Inner.socket_path, read_reason and
  upstream_handshake are only reached through the Unix display socket;
  allow dead_code off Unix. diagnostics tests import StatusCode only for
  the cfg(unix) symlink/fifo tests.
- Lint: cargo fmt on two assert_eq! blocks in tui/ui/tests.rs.
- parent_agent_surface ceiling: deliberate growth of +73B (88,642 ->
  88,715 on Linux; 88,702 on macOS) from the E4 progress-narration prompt
  rule and the workflow Fleet origin list, net of read/bash trims.
  Re-measured and raised with the receipt in the comment.

Checks (macOS, targeted):
- cargo test -p codewhale-tui --features long-running-tests --lib
  --test cucumber -- <7 lane tests + core acceptance>: lib 6 passed,
  0 failed; cucumber 4 passed, 0 failed.
- cargo test -p codewhale-tui --lib -- runtime_api::diagnostics: 3 passed.
- rustfmt --check on touched files: clean.
- Not run: Windows build (local cross-check blocked by ring's C build);
  full suite (CI).

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TvKGZz4LrKfrQiAXip48JS
… to stop

- session picker: a background preview load finishing in `tick` returned
  ViewAction::None, so ViewStack::tick emitted nothing and the event loop
  never repainted; the placeholder stayed up until the next key. Views can
  now return ViewAction::Redraw from `tick`; ViewStack::tick returns a
  ViewTick { events, redraw } and the event loop sets needs_redraw from it.
  poll_preview reports whether the visible preview changed (stale loads
  are cached but do not repaint).
- voice: the recording status regained a stop cue, now localized
  (VoiceRecordingStopHint, all 15 packs). The old "(⌥V to finish)" was
  never true — the capture is awaited on the UI loop and ends after a
  second of silence — so the cue says "pause to finish".

Tests: cargo test -p codewhale-localization --lib: 50 passed, 0 failed.
cargo test -p codewhale-tui --lib -- session_picker voice views::
383 passed, 1 failed; the failure is the pre-existing
views::tests::focus_texture_modes_keep_inline_modal_usable (approval
prompt texture, noted in d771281), not touched here. New:
landed_preview_requests_a_redraw_through_the_view_stack; updated:
recording_status_is_localized_and_keeps_the_interim.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TvKGZz4LrKfrQiAXip48JS
Review of the 0.10.1 Unreleased notes against the commits they cite:

- The macOS heap line cited #6033 (lazy MCP connect). Its commit
  791b775 mentions #6033 only in passing and says no tracking issue
  exists; the receipt is removed.
- The CI line linked PR #6406, which is @gaord's resume/fork thread
  fix, not the CI change (479db05 only references it as context).
  The link moves to a new Fixed entry for that merged contributor fix,
  which the notes omitted, with credit.
- "the compaction gate" becomes "the point where Codewhale makes room"
  (CURRENT_DECISIONS §19: Making room, not compaction).

Regenerated crates/tui/CHANGELOG.md and web/lib/changelog.generated.ts.

Checks (local):
- scripts/sync-changelog.sh --check: up to date
- scripts/release/check-feature-release-notes.sh origin/main HEAD: OK, 6 refs
- vitest web lib/changelog.test.ts: 6 passed, 0 failed

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TvKGZz4LrKfrQiAXip48JS
Both failures on CI run 35816153928 trace to c52a5c4 (0.10.1 lane B,
experience marks 4 and 8), which changed copy intentionally; the tests
were not updated with it. No product code changes.

- one_owner_tests::idle_frame_keeps_two_chrome_rows_and_last_turn_metrics:
  mark 8 labels the footer readings ("thinking: max", "context 0%" instead
  of "max", "ctx 0%"). The wider row no longer fits "↓ 1.2K" at 100
  columns, and the info line's shed pass drops OutputTokens (priority 7,
  ahead of the help hint) by design. Draw at 120 columns, where the last
  turn's metrics fit; every other assertion is unchanged.
- views::tests::focus_texture_modes_keep_inline_modal_usable: mark 4 (E6)
  makes the approval card heading the plain summary of the call
  ("Read src/main.rs") instead of the raw tool name "read_file". Assert
  the summary.

Checks:
- cargo test -p codewhale-tui --lib -- <the two tests>: 2 passed, 0 failed
- cargo test -p codewhale-tui --lib -- tui::ui::frame::one_owner_tests
  tui::views::tests: 127 passed, 0 failed
- rustfmt --check on both files: clean
- not run: full suite, npm gate (TUI-only test change)

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TvKGZz4LrKfrQiAXip48JS
…e launch

Repair the observed integration failures without dropping or ignoring tests:
- Register approval grant events in the runtime web client so stream cursors
  remain continuous; retain the full emitted-vocabulary assertion.
- Use the shared TLS constructor in four computer display tests.
- Parse Unix display socket settings consistently on Windows; retain strict
  component rejection. Render rooted workspace approval paths relatively.
- Keep the executable Fleet tutorial fixture LF on Windows.
- Restore the reviewed generation-15 skills fixture and 18 first-run README
  translations from the unreviewed WIP, without importing its other changes.
- Gate Unix-only handshake helpers by platform rather than suppress dead code.
- Use async socket metadata and move named Fleet loading onto spawn_blocking.
  The two synchronous Fleet-loader sites are budgeted only after moving their
  sole production caller off Tokio; tests remain synchronous.
- Rebase the runtime contract on the intentional 400-byte E4 prompt addition
  in 5cf9db3 and the existing tool-catalog copy changes: 55 metrics, 21
  identities measured, no caps disabled.
- Reuse task cwd validation at plan lowering, so invalid paths fail before a
  background run is registered. Absolute, traversal, UNC and drive forms are
  covered, as is valid normalization.
- Preserve a producer's sequence across a scheduling delay inside its 2s lease.
  Observation coverage still resets; lease expiry and stale-source rejection
  are unchanged. A forced 400ms pause reproduced the CI HTTP 409 before the
  fix; the rebuilt owner passes the expanded black-box contract.

Verification:
- cargo fmt --all -- --check: PASS.
- cargo clippy --workspace --all-targets --all-features --locked with CI's
  -D warnings and three documented -A flags: PASS; the TUI gate was repeated
  after the recorder change and passed.
- Targeted TUI nextest: 35 passed, 0 failed (13207 not selected).
- Workflow VM path/dispatch contracts: 2 passed, 0 failed.
- Runtime web Node suite: 36 passed, 0 failed.
- Rebuilt recorder black-box: 11 checks passed, 0 failed. The first added
  assertion expected an absent optional duplicate field; corrected to the
  actual response contract and reran without rebuilding unchanged code.
- reqwest, dead-code, blocking-call, README/locale, contributor-credit,
  bundled-plugin, version and feature-note checks: PASS.
- Runtime-contract gate: all 55 measured metrics pass the updated budget.
- npm test: packaging 67 + SDK 14 passed; initial web 489 passed/1 failed due
  concurrent 404 catalog drift. After catalog regeneration web Vitest: 490
  passed/0 failed. npm run check:web: PASS. The separate 404 work is not in
  this patch.
- Persistence-backlog measurement ran but refuses a dirty source tree;
  clean-tree hosted validation remains required. No result is claimed.
- Windows/Linux execution and hosted CI remain pending. CodeQL unchanged.

Refs #6407
#[cfg(unix)]
{
use std::os::unix::fs::FileTypeExt;
tokio::fs::metadata(&computer.inner.socket_path)

This branch has not been deployed

No deployments
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.

3 participants