Repository navigation
0.10.2 readiness: green main again, then release-blocking fixes - #6957
Conversation
…/disconnect 0ff4ffd added /connect and /disconnect to the config command group but left the two tests that pin that group's registry on the old 17 commands. Hosted CI has been red on Windows since then (run 38129356685, job 114440346849: "18309 tests run: 18307 passed, 2 failed"): - config_policy_keeps_host_registry_order_metadata_and_exact_capabilities expected no connect/disconnect after login; - command_ownership_contract_is_enforced expected exactly 17 commands, got 19. The green run on ed3fbec (38129634138) skipped every Rust test as a light change, so it is not evidence for this code. Both tests now name the two commands in their registered position, and the count is 19. The neighbouring comment that claimed the production groups hold exactly 96 commands was already false and no longer states a number. Checks (Ubuntu 24.04 container): nextest -p codewhale-tui --lib -E 'test(/^commands::/)': 1192 tests run: 1177 passed, 15 failed. Both guard tests passed. The 15 failures are all snapshot restore/undo tests that fail on git 2.43's `checkout --end-of-options` (fixed separately; hosted CI runs git 2.55 and is unaffected). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BsXVvReYca2UxzimQtj7Mj
Snapshot restore ran `git checkout --end-of-options <id> -- <paths>`. git 2.43, which Ubuntu 24.04 ships, rejects that form with "fatal: only one reference expected, 2 given", so /undo and restore failed there. That form shipped in v0.10.1 (593be41). Hosted CI runs git 2.55, so it never saw the failure. Both checkout call sites drop `--end-of-options`. The id passed there is a SnapshotId, which is validated as 40 or 64 hex characters. It can never start with '-', so the option guard protected nothing that reaches it. The `--` separator before the paths stays. Evidence: on this Ubuntu 24.04 container (git 2.43), `nextest run -p codewhale-tui --lib -E 'test(/^commands::/)'` on db29e64 gave `1192 tests run: 1177 passed, 15 failed`. All 15 failures were snapshot restore and undo tests failing with "only one reference expected". The re-run with this change is pending a local test build and hosted CI on #6957. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BsXVvReYca2UxzimQtj7Mj
… its exit
Two session-export defects in the background-shell cancel path:
- Cancelling your own background job also queued its completion
notification. The session then got a "finished" event for a job it had
just killed, and a new model turn could start from it.
`ShellManager::kill` now marks a job it killed as
`completion_reported`, so the completion drain skips it.
- A job that exited between the user's look and the cancel was still
killed and reported as "Killed" with exit 0.
`BackgroundShell::kill` now polls first and returns without signalling
when the process has already finished. The cancel receipt then reports
the real status and exit ("... Nothing was killed.") instead of "Canceled
background command".
Evidence: cargo fmt --all -- --check is clean. The compile and the
tools::shell / tool_cancellation tests are pending a local test build and
hosted CI on #6957.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BsXVvReYca2UxzimQtj7Mj
…lainly
When a foreground bash call outlived its wait and moved to the background,
the card copied the model's receipt ("Background task started: shell-42
... use task_shell_wait ...") into its live output. That told the user how
the model should poll, not what happened. Ctrl+B already showed a user
notice for the same transition.
- A running Exec result no longer seeds `live_output` with the model's
receipt. The card keeps its live task identity, and output arrives from
the job as before.
- The auto-background case pushes the same `ShellWaitReleased` toast as
Ctrl+B ("... keep running in /jobs"), at Info level for 6 s. A call the
model started with background:true gets no toast, because nothing moved.
- canonical_background_bash_keeps_live_task_identity_for_follow_up_actions
now asserts the card has no copied receipt.
Evidence: cargo fmt --all -- --check is clean. The compile and the ui test
are pending a local test build and hosted CI on
#6957.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BsXVvReYca2UxzimQtj7Mj
Every todo_write call returned the whole checklist to the model. A
long-running session paid for the full list again on each update, although
the model had just written that list in its own call. That was a
session-export finding.
The structured-result compactor now handles a todo_write result:
- it keeps the "Todo list updated (...)" header with its counts;
- it adds the item in progress ("In progress: #3 ...") or "No item in
progress".
- The full list stays in the tool result's metadata, and the TUI's todo
panel still renders from it.
Model-visible means logged: the receipt is a deterministic projection of
the logged tool result and metadata, so the session log reconstructs it.
KV-cache: tool results are append-only history; the cached prefix is
unchanged.
The todo_snapshot doc comment, docs/TOOL_LIFECYCLE.md, docs/SUBAGENTS.md
(and their zh_hans copies) and the test_cases_13 comment now say the
model learns its list from its own todo_write call, confirmed by the
receipt.
Evidence: cargo fmt --all -- --check is clean. The compile and the
core::engine::context tests are pending a local test build and hosted CI
on #6957.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BsXVvReYca2UxzimQtj7Mj
… goal A session-export review found that goal usage never moved: `tokens_used` stayed at 0 against 1,309,909 tokens actually spent, and `time_used_seconds` was always 0. Usage was recorded after the turn ended, but only while the goal was still active. A turn that completed, yielded or blocked the goal had already left it inactive by then, and the usual goal turn ends exactly that way. So the turns that did the work were never counted. - `GoalState::record_usage` takes the turn's start `Instant`. It also counts when the goal has an objective and finished at or after that start, so the turn that finished the goal is charged. Earlier turns are not. - `record_goal_usage_for_turn` takes the turn's start (`turn.started_at` or the compaction start) and derives elapsed seconds from it. The now unused `TurnContext::elapsed` is removed. - The existing goal, turn_loop, test_cases_04/15 and preview tests pass `Instant::now()` for the new argument. Evidence: cargo fmt --all -- --check is clean. The compile and the goal tests are pending a local test build and hosted CI on #6957. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BsXVvReYca2UxzimQtj7Mj
The pet read only `app.agent_roster`, which AgentList refreshes between turns. A sub-agent therefore appeared only after it finished. A finished one stayed "working" until the next refresh. `pet_watch::full::live_rows` overlays live state onto that roster when the pet renders: - `app.subagent_cache` supplies each agent's status (its worker status or the terminal-projection mapping), parked state, model, usage and steps. An agent the roster has not listed yet is added from the cache. - `app.agent_progress` supplies the current activity line, and adds a row for an agent known only by progress. - Elapsed time ticks from `started_at` only while the agent runs. A finished agent keeps its recorded duration. It reads the cache and progress maps directly, so the history is not walked on every animation frame. `subagent_routing::worker_status_for_terminal_projection` becomes pub(crate) for this reader. Evidence: cargo fmt --all -- --check is clean. The compile and the pet_watch tests are pending a local test build and hosted CI on #6957. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BsXVvReYca2UxzimQtj7Mj
The pet looked blurred in the terminal. Upstream 387562b had replaced Sprite's nearest-neighbour lookup with an alpha-weighted box filter, which smears avatar tiles at every scale except 1:1. The whale cove was also rasterized with 4x4 supersampling (2x2 above 64 px), so every edge became a fractional-alpha pixel that Sprite then blended toward the background. Re-vendored from upstream 8f51c6bccadeb11278cda1e2481a116573e5d233 (codewhale-hq/codewhale-ratatui#27): - `Sprite::sample` takes the source pixel under the target pixel's centre. - `whale_motion/pixels.rs` rasterizes one sample per pixel. The cove's deliberate layer opacities keep their translucency; only the anti-aliased rim goes. Upstream, with this change: `cargo test --locked`, 787 passed, 0 failed (46 test binaries). The vendored crate goes to 0.1.2. It is the crates.io publish source, and it gained DotWhale after 0.1.1 was published, so the packaged codewhale-tui cannot compile against crates.io 0.1.1. Also changed: - crates/tui and pet/tui depend on 0.1.2, and both lockfiles are updated (cargo metadata --locked passes for the workspace and for pet/tui); - UPSTREAM.json records the upstream commit and the file hashes; - the vendored CHANGELOG has a 0.1.2 entry; - scripts/release/check-versions.sh allows 0.1.2; - the deconstruction roadmap names 0.1.2. Publishing codewhale-ratatui 0.1.2 to crates.io is a founder step and comes before the codewhale-tui publish. Evidence: cargo fmt --all -- --check is clean. The engine compile and the pet_watch tests are pending a local test build and hosted CI on #6957. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BsXVvReYca2UxzimQtj7Mj
Refs #6931. The issue's headline case was a running recursive search shown as "run running · stale · no output 2m 07s". After 60 s without output, `job_snapshot` flagged a live, non-PTY job `stale`. The inspector, the /jobs list, the work dock and the Runtime API all read `stale` as "process gone": - the Stop action disappeared (shell_job_routing `live = Running && !stale`, work_surface `shell_inspector_body`); - the detail said "stale after restart; the process is no longer running"; - "(no output yet)" was suppressed; - the API refused resize as "no longer running" and reported no tty. - A live process is never `stale`. `job_snapshot` sets `stale: false`; only `remember_stale_job` (a restart snapshot, status Killed) sets it, which is the "known-stale" job docs/RUNTIME_API.md describes. The 60 s threshold becomes `QUIET_NO_OUTPUT_AFTER` and only drives presentation. - The exec card reads "running · no output for 2m 07s" instead of "running · stale · no output …". Silence is not shown as hung, which acceptance 2 requires. - `/jobs poll` and `/jobs stdin` no longer consume the model's unread output. Both called `poll_delta_for_session`, which advances the model's stdout cursor (acceptance 4). - `poll` opens the inspector from `inspect_job_for_session`. - `/jobs wait` uses the new `wait_job_for_session`, which waits through the same `wait_while_running` loop `get_output_delta` uses, then inspects. - `stdin` shows the job's one-line status and tail. - `poll_delta_for_session` has no callers left and is removed. - Alt+V with no selection prefers the newest running shell only when it is visible in the transcript viewport. It no longer takes over the completed card the user is looking at (acceptance 1). A click or selection still targets that exact card. - shell_job_routing.rs records its known limitations. The inspector is a snapshot with no follow mode; `/jobs poll` re-reads it. Named PTY sessions live in the terminal dock (#6912), not /jobs. - Tests updated where this change made them wrong: - running_job_snapshot_keeps_silent_live_job_live asserts a silent live job is not stale and still exposes its quiet time; - the stale-running fixture in ui/tests.rs is `stale: false`, and its header assertion uses the new label; - QUIET_NO_OUTPUT_AFTER replaces the old constant name. Still open in #6931: - a follow-mode or auto-refreshing inspector; - listing delegated agents' shells in the agent detail; - the PTY journeys on the installed candidate at normal and narrow widths. Evidence: cargo fmt --all -- --check is clean. The compile and the tools::shell / tui tests are pending a local test build and hosted CI on #6957. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BsXVvReYca2UxzimQtj7Mj
…ng say what happens Session-export review of /constitution. Each item was read on both sides before changing it. - ratify promised it would be "refused if the base changed after you reviewed it", but it re-read the live file and handed that same digest back, so the guard could never fire. `/constitution suggestions` now records the digest the user reviewed on `App`, and ratify passes that to `UserConstitution::ratify`. Ratify without a review says to review first. A ratify after the file moved is refused as StaleBase. The existing ratify test now reviews before it ratifies, and checks the unreviewed refusal. - `preview` claimed to show "the exact block that would be injected", but rendered `source="<absolute home path>"`, while the engine injects `render_block(None)` (`source="user-global"`). It now renders the same block. - ratify and migrate said the prompt-cache prefix "moved" or "survives". The constitution reaches the model as a session message appended at turn admission (`record_current_constitution`), outside the cached prefix, as prompts.rs's `user_global_constitution_is_captured_outside_the_stable_prefix` asserts. The messages now say so, and so does the user_constitution module doc. The migrate test checks the new wording. - The setup wizard printed the assembly order (bundled → user-global → repo → AGENTS → memory → current request) under "HIERARCHY OF AUTHORITY". That reverses the base prompt's ranking, which says it "is stated here and nowhere else". The line is removed from all 15 locale templates, and so is the now-unused SetupCheckpointLayerOrder message. "Your direct requests always outrank this document" stays. - The wizard capped the user's own note at 4000 characters, then appended it to a ~300-character template. save_to then trimmed the total to 4000, silently cutting off the end of the user's own text. The note is now capped at MAX_NOTES_LEN - 1000 while typing, so the saved file keeps all of it. The longest template is 335 characters before labels. - zh-Hans used 协作准则 in the /constitution manager and 宪章 (the docs/zh_hans/GLOSSARY.md term) elsewhere, sometimes on the same screen. It now uses 宪章 throughout, including the model-draft status line. - The help usage line and docs/CONFIGURATION.md now list base, suggestions, ratify, migrate and rollback. The step is named "Working agreement" as the wizard shows it. docs/GUIDE.md no longer calls /constitution a way to customize the bundled layer. Not changed here: - A signed-in user still sees the local file as "active", although the account profile is what the model gets. The fix needs an async account check, because the credential store must not be read on the UI loop. - The Runtime API's GET and preview `modelGuidance` shapes differ. - `doctor` reports autonomy from an inactive file. - The context inspector lists the personal constitution as a system-prompt layer. Evidence: cargo fmt --all -- --check is clean, and every edited locale file parses as JSON. The compile and the commands::core::constitution tests are pending a local test build and hosted CI on #6957. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BsXVvReYca2UxzimQtj7Mj
…isconnect - The CHANGELOG 0.10.2 section gains Added (`/connect` and `/disconnect`, #6950) and Fixed lines for the slices on this branch: - git 2.43 /undo, shell cancel, the 30 s background notice and the todo_write receipt; - goal usage, pet live rows and crisp sprites, #6931 and /constitution; - the fixes that already landed on main for #6953, #6954, #6955, #6923, #6947 and #6945, plus the Auto-Review guardian budget, skills, MCP reconnect, the pet owner idle exit, tool headers, /jobs and the one-row gap. - Contributors: @LIghtJUNction for #6950, #6947 added to @SparkofSpike, and #6952 added to @Lstarsky0. - crates/tui/CHANGELOG.md was regenerated with scripts/sync-changelog.sh; the tui crate include_str!s it. - docs/features.toml: the plugin-oauth-providers summary names /disconnect next to /connect (111 characters, under the 120 limit). Evidence: ./scripts/release/check-versions.sh --require-dated-release prints "Version state OK: workspace=0.10.2, npm=0.10.2, npm-binary=0.10.2, lockfile in sync" and "Feature release-note receipts OK: 8 linked issue reference(s) checked in v0.10.1..HEAD". Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BsXVvReYca2UxzimQtj7Mj
…ibutor page CI on 054b122 failed "Lint & Type Check": web/lib/public-copy.test.ts:167 compares the 0.10.2 CHANGELOG contributor handles with the website credit arrays and the docs/CONTRIBUTORS.md band. The previous commit (49bd217) added @LIghtJUNction (#6950) to the CHANGELOG. The website still listed them under UNRELEASED_CONTRIBUTORS, which RELEASE_CONTRIBUTORS does not include. - web/lib/release-credits.ts moves @LIghtJUNction from UNRELEASED_CONTRIBUTORS to RELEASE_CONTRIBUTORS, as its own comment describes for the release that carries the work. UNRELEASED_CONTRIBUTORS is now empty. - The docs/CONTRIBUTORS.md v0.10.2 band gains the #6950 line, and adds #6947 to SparkofSpike's entry and #6952 to Lstarsky0's, matching the CHANGELOG. Evidence: a python3 re-implementation of the test's three handle extractions gives the same 8 sorted handles for the CHANGELOG, the website arrays and the doc band (@BX166 @LIghtJUNction @Lstarsky0 @SparkofSpike @asto18089 @dajiaohuang @gaord @jayanthvee). `python3 scripts/check-contributor-credit.py`: "Every contributor in the window is credited on all three surfaces." The vitest run itself is CI's job on this PR. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BsXVvReYca2UxzimQtj7Mj
…ips exited jobs Follow-up to 8eb23ad, from an adversarial review of that slice. - 8eb23ad marked a killed job's completion as reported inside `ShellManager::kill`, which /jobs, the Runtime API and the model's cancel all share. When a person stopped a job the model had started, the model was therefore never told. `kill` is neutral again. The model's own cancel marks the jobs it actually killed through the new `mark_cancel_reported`. A person's cancel still reaches the model as a Killed completion. - Cancel-all picked jobs by their cached status. A job that had exited since the last poll was "canceled": the model's receipt said "Canceled 1 background command" with status Killed, and its real Completed event followed. `/jobs cancel all` said the same. `kill_running_for_session` now polls each of the session's jobs before selecting the running ones, and returns only the jobs it actually killed. Evidence: cargo fmt --all -- --check is clean. Compile and tests are pending: the running local test build predates this edit, and hosted CI on #6957 runs them on this push. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BsXVvReYca2UxzimQtj7Mj
Follow-up to d33dc38, from an adversarial review of that slice. The moved-to-jobs toast is meant only for a foreground wait that ran out, so a call started in the background gets none. The check looked only at `background`, but `tty:true` also starts in the background (the schema says "implies background"). A tty call therefore came back Running at once and showed "... keep running in /jobs" although nothing had moved. `tty:true` now counts as an explicit background start. `exec_is_background` itself is unchanged, because the start-path wait dedupe also uses it. Evidence: cargo fmt --all -- --check is clean. Compile and the tool_routing and ui tests are pending a local build and hosted CI on #6957. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BsXVvReYca2UxzimQtj7Mj
Follow-up to e71255e, from an adversarial review of that slice. Ratify now checks the digest reviewed in `/constitution suggestions`, but that digest stayed at its pre-ratify value. The next `/constitution ratify <id>` was therefore refused as StaleBase, although the only change since the review was the user's own ratification. A repeated `ratify c1` also said StaleBase instead of "already ratified". `ratify_text` now returns the saved file's digest (`ratification.after_digest`) on success, and the command stores it as the reviewed digest. An edit made outside the session is still refused as stale. Evidence: cargo fmt --all -- --check is clean. Compile and the commands::core::constitution tests are pending a local build and hosted CI on #6957. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BsXVvReYca2UxzimQtj7Mj
"Pet conformance / recorder (macos-latest)" failed on #6957 (run 38141362016, job 114475791414) at pet/scripts/check-shared.py:97: styled=frame_when(d,lambda f:f['appearance']==appearance) AssertionError: Accepted state did not reach the frame projection Cause: main's b0f9cbc ("/pet style and language, pixel whale body", committed unbuilt) added `body_style` and `text_language` to `Appearance` (pet_watch/appearance.rs:56-59). Both use `#[serde(default)]` and are always serialized. The owner stores the parsed appearance and echoes it whole (owner.rs:665), so the frame carries 10 keys while the fixture sent 8. The strict equality at :97, and again after the crash restart at :107, could never hold. The owner kept answering /v1/frame for the full 5 s, so this is not a stall. The failure is deterministic; Windows runs that step only on macOS (`if: runner.os == 'macOS'`), so it never saw it. Pet conformance runs only on PRs that touch pet paths, so this PR is the first run since b0f9cbc. The product's full echo is intended. shared.html builds and reads both fields, and the persisted and live appearance must agree. So the fixture moves to the current schema instead of the owner hiding defaults. It sends non-default values ('bodyStyle':'pixel', 'textLanguage':'ja'), so the round trip and the restart now also prove the new fields persist. With eventColors False, owner.rs:619-623 still writes `particle` into style.r/g/b for any body style, so the colour assertion at :98 holds. Evidence: `python3 -I -m py_compile pet/scripts/check-shared.py` passes. The script drives the owner binary, so the run itself is the macOS recorder job on this push. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BsXVvReYca2UxzimQtj7Mj
…age report shows
A session-export review found update_goal rejected `progress` sent with
`status: "yield"` ("progress is only accepted with status not_achieved or
advisory"). Yield means a finished stage handed back to the user, which is
exactly when a progress estimate is most useful.
- update_goal accepts `progress` with yield, and stores it on the yielded
goal after `mark_yielded`. `record_progress` only records on an active
goal, so it would have dropped it. The refusal text names yield. The
schema description says "Optional with not_achieved, advisory or yield".
- The TUI shows the progress receipt for a yield too (ui/apply.rs). Paused
and complete goals keep their last report silent; a yield is the stage
report the user is handed back with. The schema promises the estimate is
"shown to the user as reported progress". An adversarial review flagged
that without this, a yield's estimate reached only the model.
- The existing progress-rejection test expects the new refusal text.
- CHANGELOG notes it, and crates/tui/CHANGELOG.md is re-synced.
Model-visible and KV-cache: one sentence of update_goal's schema
description changes, 7 bytes longer. That changes the session-pinned tool
catalog for new sessions only; a running session keeps its pinned prefix.
The 12 conformance goldens that pin the catalog were re-recorded with
CODEWHALE_CONFORMANCE_UPDATE=1 (CI unset). Normalized, their diff moves
only:
- the description text, and a fixed-width preview shifted 7 characters;
- the sha256 values and the short "frozen: <digest>" label;
- tools_bytes and payload_json_bytes, each +7;
- a `.codewhale/state/.gitignore` entry in the event goldens'
workspace_after. That entry comes from main's 491d3df, which writes
that file and was committed with its tests left to CI, so main's
golden_turn_events_match was already stale.
Evidence, on a local lib test binary (Ubuntu 24.04) built from this
branch with the goal.rs change:
- `conformance::`: test result: ok. 33 passed; 0 failed.
- `tools::goal`: test result: ok. 36 passed; 0 failed.
The ui/apply.rs condition was added after that build. cargo fmt --check
is clean, and hosted CI compiles and runs it.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BsXVvReYca2UxzimQtj7Mj
Refs #6957 Lint. 407cb8e made update_goal accept a progress estimate with yield and named yield in the progress description. The runtime-contract ratchet measured that on hosted Linux (run 38144890574, Lint job 114486327862) as +7 bytes on every Plan, Act and Operate surface: - full and active, Plan: 55163 -> 55170 and 36173 -> 36180; - full and active, Act/Operate: 84384 -> 84391 and 37703 -> 37710; - +1 to +2 estimated tokens on each. The ratchet confirmed base b1e39f4 passes, so this commit adds the debt; it is intended. No tool enters or leaves a surface, and every identity is unchanged. The twelve ceilings take the exact CI values, with a dated _codex_20261011_goal_yield_remeasure note, as d54a098 did. scripts/test_check_runtime_contract_budget.py: Ran 22 tests, OK. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BsXVvReYca2UxzimQtj7Mj
…clicked card Refs #6931. Acceptance 4 (follow mode; refresh without the model's cursor) and acceptance 1 (a new card never takes over the target). Follow mode: - When the Bash Job pager opens on a running job, it records the job id. - On its 2.5 s tick, the event loop re-reads that job through `inspect_job_for_session`. This is a bounded read, under try_lock as `refresh_shell_exec_live_output` does, and never touches the model's output cursor. The event loop then swaps the text into the open pager. - A view at the bottom stays pinned to the newest row. Scrolling up, Home, `gg` or a search jump stops following; End, `G` or scrolling back to the bottom resumes it. - When the job ends or leaves the session, refresh stops and Stop is removed, because it no longer applies (acceptance 5: inapplicable controls are disabled). - The Status line reads "running · no output for 2m 05s" once a live job has been quiet for QUIET_NO_OUTPUT_AFTER. It uses the label the exec card already uses. - `ViewStack::top_pager_mut` is the downcast, next to `refresh_extensions`. Alt+V target: - 674dcc3 sent Alt+V with no selection to the newest running shell on screen before anything else. That bypassed `detail_cell_index_for_viewport`, which the footer hint also uses. So a running card that scrolled into view took over the completed card the user was reading, and the hint and the key disagreed. Alt+V now resolves only through `detail_target_cell_index`. `newest_visible_running_shell_cell` is deleted. A running shell stays reachable by click, by the work dock and by /jobs. - A selection stored only its rendered line. When a run of successful tool cards collapsed above it, or cells were appended while an active cell was open, that line pointed at another card. A click now also records its owner cell as the existing `TranscriptActionOwner` (cell index plus transcript identity epoch). Space-fold already uses it. `rebase_active_cell_bindings` shifts the owner with the other bindings. Any other identity change (folds, rollback) invalidates it, and the target falls back to the line. Alt+V, the detail target and Ctrl+O prefer the owner. - CHANGELOG lines that advertised the old Alt+V rule are corrected. Known limits, stated in shell_job_routing.rs: - new output reaches the pager up to 2.5 s late; - the work dock's inspector is still a snapshot; - delegated agents' shells appear in /jobs and the dock with their Owner, not in the agent's detail; - named PTYs live in the terminal dock (#6912). Focused tests: the issue asks for them in acceptance 7. - pager: follow, unfollow and resume, and dropping Stop when the job ends; - shell_job_routing: a silent running job reads quiet, not stale, with "(no output yet)"; - the existing stale-list test now shares the snapshot fixture. Evidence: cargo fmt --all clean. clippy -p codewhale-tui --lib --tests (-D warnings) is running locally on this exact tree; the focused tests run in hosted CI on #6957. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BsXVvReYca2UxzimQtj7Mj
…rvived Refs #6944, acceptance 1 and 2 for what the model and the person read. - `ShellManager::running_progress` polls a live job and reads its bounded 1,200-byte tails (`job_snapshot`). It returns "Progress: last output Ns ago; output phase: …" using the existing `output_phase_hint`. - A running single-task `wait` puts that line ahead of the delta result. - A multi-task `wait` adds it to each running id's line. - Silence plus phase separates "still compiling" from a stall without another poll. - Metadata and `build_shell_delta_tool_result` are unchanged. - The /jobs cancel receipt (`format_shell_poll`) and the shell completion handoff the model receives after a person's cancel now name whether compile artifacts survive. They use the `kill_outcome_note` the model's own cancel path already shows. The handoff adds a `kill_note` key on Killed events only. It is an append-only user-role message that is already in the session log, so the KV-cache prefix is unchanged. - `tools::shell_output` becomes pub(crate) so the TUI receipt can reuse the note. - Two comments that 34bf656 made false no longer claim that Full Access cannot bypass the background floor (turn_loop.rs, auto_review.rs). Known limit: cargo prints no "crate N of M" or "k/N tests" to a non-TTY pipe, so the phase stays coarse (compiling / build finished / running / unrecognized). Not here: - (a) unpolled mid-run progress events; - (b) deleting `Run(action=tests)`; - (c) the measured side-by-side. These are founder questions. Evidence: cargo fmt --all clean; clippy pending locally on this tree. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BsXVvReYca2UxzimQtj7Mj
Refs #6925. Since the sign-in repair, every `OAuthProviderParams` sets `originator: None`. The authorize-URL branch that appended it could not run, and its doc comment described a ChatGPT requirement that no longer holds. - The field, its five `None` initializers and the dead branch are removed. - `OwnedAuthEntry.originator` stays, so credential files written by older builds still parse. A new ChatGPT login stores `None` there. - `authorize_url_uses_documented_chatgpt_parameters_and_pkce` already asserts that the URL has no `originator=`. - The `oauth` module is private to the crate, so no published API changes. Evidence: cargo fmt --all clean; clippy pending locally on this tree. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BsXVvReYca2UxzimQtj7Mj
Refs #6939 (RS-12). The test `default_max_turns_does_not_add_a_hidden_worker_cap` parsed the worker argv with `crate::Cli` from inside fleet/executor.rs. That was the remaining `test fleet|lib.rs 3` edge. - The test moves unchanged in substance into lib/terminal_mode_test_cases_03.rs. That is where 0f48161 put its sibling. - The task is built from JSON, and the launch spec comes from the public `fleet_task_to_worker_spec_with_profiles`. No visibility changes. - The runtime-boundary baseline drops from test 35 to test 32 (`module_graph.py --update`, then --check PASS 11/32/1/1 over 117 closure modules). - DECONSTRUCTION_ROADMAP.md's gates and the 0.10.5 edge list follow the new baseline. - TUI_DECONSTRUCTION.md records RS-12 as landed. Evidence: python3 scripts/split/module_graph.py --check: [runtime-boundary] PASS: {prod 11, test 32, late 1, uilib 1, doc 0} (117 closure modules). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BsXVvReYca2UxzimQtj7Mj
… progress Refs #6931, #6944. - The inspector bullet says it follows output, drops Stop when the command ends, and that Alt+V keeps the clicked card. - The silent-shell bullet loses the clause that advertised the removed 'running shell first' Alt+V rule. - A new bullet covers wait progress and the kill note. - crates/tui/CHANGELOG.md is regenerated by scripts/sync-changelog.sh. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BsXVvReYca2UxzimQtj7Mj
…nspector Refs #6931 (acceptance 4 and 5, "inspectable and stoppable"). Found by the 0.10.2 UX audit's live-work lens; each finding was checked against the code before this change. - `/jobs wait <id>` called `wait_job_for_session(…, 5_000)` on the UI event loop. It held the ShellManager std Mutex and slept in 100 ms steps, so the screen and the model's shell tools stalled for up to 5 s, against the #6149 blocking-call rule. `poll` and `wait` now parse to the same action as `show`: the live-following pager from f7264f7. The `ShellJobAction::Poll` variant, its handler arm and `wait_job_for_session`, which had no other caller, are deleted. - Work-dock shell rows, live and finished, ran `shell_inspector_body` in every projection. That is several passes per frame, on every dock tab: a `try_lock`, then `inspect_job_for_session`, which polls the child and copies the full retained stdout and stderr (up to 16 MiB each). The pager it opened was a frozen snapshot that said "Open this row to watch live output". Shell rows now run `/jobs show <id>`, and `shell_inspector_body` is deleted, so projection never touches ShellManager. - The right-click menu keeps "Stop work" for a running shell (`/jobs cancel <id>` behind the same in-menu confirm). The pager has its confirmed `s` Stop. - Durable task rows ran `/jobs show task_…` against the shell manager, which printed "Command lookup failed: Job task_… not found". They now run `/task show <id>`, and RLM pseudo-rows (`rlm-N`) have no action. - Tests updated where this made them wrong: the live shell row's primary action, and the shell-prefixed task rows' `/task show`. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BsXVvReYca2UxzimQtj7Mj
…ip settings I/O Found by the 0.10.2 UX audit (first-run and chrome lenses); each was checked against the code before this change. - `/setup` mapped `u` (bundled) and `d` (defer) with no step guard. Pressing either on the Provider, Permissions, Remote or Ready step closed the wizard. `prompts.rs` treats Bundled and Deferred as "user constitution disabled", so a ratified working agreement silently stopped applying. Both arms now carry the `selected_step() == SetupStep::Constitution` guard their g/a/f/k neighbours already have. - `note_footer_hint_used` ran a locked `settings.toml` transaction (process mutex, fd lock, read and parse) on the UI thread for every Tab, Shift+Tab, Ctrl+], Esc interrupt and agent arrow, forever. It now returns early once the in-memory count is retired. That count is seeded from settings at startup, so a hint retired in another instance still counts. Its doc comment claimed it never blocks the input path; it now says what really happens. - CHANGELOG: the #6931 bullet adds `/jobs wait`, dock shell rows and task rows; a new bullet covers the `/setup` keys. crates/tui/CHANGELOG.md is regenerated. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BsXVvReYca2UxzimQtj7Mj
Refs #6931. 8fa735e pointed work-dock shell rows at the live-following Bash Job pager, so the known-limitations note's 'the work dock's inspector is still a snapshot' became false. The note now names the three ways the pager opens; the remaining limits (2.5 s latency, delegated-agent shells outside the agent detail, PTYs in the terminal dock) are unchanged. Comment-only; no code change. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BsXVvReYca2UxzimQtj7Mj
From the 0.10.2 UX audit. Each was checked against the code first.
- ko ChipPermissionNever said '묻지 않음' ("doesn't ask"), which reads as
auto-run on the deny-all Never chip. It is now '허용 안 함', the word
/status already uses for the same posture.
- OnboardLanguageBlurb, in all 15 packs, told a new user to change
language with `/settings set locale <tag>`, which answers
"Usage: /settings [text]". The command is now
`/config locale <tag> --save`, which persists the locale. The
translated prose and placeholder words are unchanged.
- en ElevationOptionAbortDesc said "Cancel this run", but the handler
denies only the tool call and the turn continues. It now says "Skip
only this tool call", as the other packs do. The test-only English
mirror in approval/elevation.rs and its assertion follow.
All 15 packs still parse, and `rg '/settings set locale' crates/localization`
finds nothing.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BsXVvReYca2UxzimQtj7Mj
… table
From the 0.10.2 UX audit (transcript-cards lens), checked against the
code before the change.
- The most common card, a file edit, used the generic "• tool" verb
because PatchSummaryCell passes the title "File", which
tool_family_for_title did not map. "File" now maps to the Patch family.
The card's header carries the receipt's change summary, and the bold
first body row that repeated it is gone. With inline diffs off, the
header keeps the calm outcome label. The pager, inspect text and exact
diff are unchanged.
- One transcript said "run Done", "tool done", "run issue" (failed) and
"✓ tool tool loaded - retry required".
- en ToolReceiptDone is lowercase like every other pack.
- tool_status_label says "failed" for Failed (Warning stays "issue")
and "loaded, not run" for Hydrated.
- A hydrated tool gets the neutral glyph, not the done check.
- activity_detail's duplicate table is deleted and its four call sites
use tool_status_label.
- The exploring card's per-entry prefix also says "failed", so a
failed read card no longer says "failed" in its header and "issue" on
its row.
- Tests whose copy changed are updated. The behavioural asserts are
kept: hydrated is still not reported done, and failed is still not
reported hydrated.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BsXVvReYca2UxzimQtj7Mj
From the 0.10.2 UX audit (errors-toasts and localization lenses, merged), checked against the code first. On the most safety-critical surface, 13 of 15 locales showed translated options next to English field labels (Command, Dir, File, Preview…) and an English "About" sentence. localize_detail_label and description_for_locale gated existing ApprovalLabel*/ApprovalDesc* MessageIds to zh-Hans only. The packs already carry them, and the pager already used tr(ApprovalLabelPreview) for every locale. - The MessageId-backed label arms apply to every locale. The hard-coded Chinese arms stay zh-only. - The category description comes from tr(locale, ApprovalDesc*) for every non-English locale. - ApprovalDetail gains a typed `is_preview`, set where the Preview detail is built. The live card and the legacy band read it instead of matching the English label "Preview", so the 3/5-row preview bound holds in every locale. - impacts_for_locale is unchanged: its zh builder carries literal Chinese. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BsXVvReYca2UxzimQtj7Mj
From the 0.10.2 UX audit (first-run and errors-toasts lenses). Each item was checked against the code first. Ollama adoption. When a local Ollama model was adopted during first run, the picker was popped and onboarding set to None. That skipped the trust question and the ready screen, and mark_onboarded never ran, so the next launch restarted onboarding. It now calls advance_onboarding_after_provider. The adoption test expects TrustDirectory or Ready. Retry receipts stay in the transcript. They also wrote status_message, which the legacy classifier turned into an 8-second red Error toast that hid the later "recovered" line. A receipt now adds its System cell and nothing else. A turn that ended in failure reads as Error, live and on resume. - present_turn_failure and the resume replay of saved outcomes used Warning, which goes against the pinned a_failure_that_ended_the_work_is_never_a_warning rule. - The terminal stream-open branch in model_step promotes a Warning envelope to Error before sending it. `recoverable`, `category` and `code` are untouched, so provider fallback is unchanged. - When an earlier Warning error cell (a stream stall) already showed the failure, present_turn_failure upgrades that cell to Error. The live view then matches the record that resume replays. /setup honesty. - The final step no longer says "You're ready." without a working provider. It reuses the Provider step's title and blurb and leads its action bar with P (provider). C (customize) is listed because it was already handled. - The key-entry modal puts the rejection reason first, so the 6-row cap drops guidance rather than the reason. - Its continue/back footers use SetupActionContinue/SetupActionBack. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BsXVvReYca2UxzimQtj7Mj
…ants
From the 0.10.2 UX audit (commands-help and localization lenses, merged),
checked against the code first.
The picker, chip, hotbar and settings say "Work", but several places
still said "Act":
- `/mode work` replied "Switched to Act mode.";
- /overview printed "Mode: ACT";
- /setup showed "Work intent: Act";
- the startup-default notice spliced in "Act".
All four now use AppModeUi::display_name_localized.
/zidong and `/mode yolo` switch to Full Access, with shell and trust on,
but replied only "Switched to Act mode.". They now reply "Switched to
Full Access (Work)." (tr(HotbarActionModeYoloName)).
The /mode usage is now "/mode [work|plan|operate|1|2|3]", and the usage
error prints MODE_INFO.usage instead of a hand copy that also listed
"agent". The English hints that still said "Act" ("Act + Full Access",
"applies in Act and Operate", "Act mode will expose shell") now say
Work.
Unchanged: AppMode::display_name, label() and the hotbar short_label.
Session export and the hotbar metadata cross-check depend on them.
Tests that pinned "Act" are updated: config yolo, the allow_shell
messages, the app permission-cycle toast, and the help filters
"mode [act" → "mode [work".
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BsXVvReYca2UxzimQtj7Mj
…<call id>"
From the 0.10.2 UX audit (transcript-cards and live-work lenses), checked
against the code first.
drive_child_actor sent `format!("Core tool {id}")` to the parent mailbox
on ToolExecutionStarted, and recorded "Core tool {id} settled" on
completion, so every delegated card read "Core tool call_7f3a9c2e
running". Event::ToolCallStarted, which carries the name, fell through
to `_ => {}`.
A local map from call id to the tool's model-facing name is filled on
ToolCallStarted. The card now reads "read running" and then "read done"
or "read failed", falling back to "tool". It uses the raw name, the one
the progress meta's `.with_tool(name)` already records, rather than the
retired policy alias (read_file), so both surfaces agree.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BsXVvReYca2UxzimQtj7Mj
…s lose per-row rules From the 0.10.2 UX audit (transcript-cards lens), checked against the code before the change. - parse_heading accepted '#' with no following space, so a reply line like '#6235 fixed the race' became an H1 with a 40-column rule. It now follows CommonMark: 1-6 '#' then whitespace or end of line. - Headings rendered through the plain wrapper, so '## Changes to `x`' showed literal backticks and asterisks. They now use the inline path paragraphs use, with the heading style. render_wrapped_line_tagged, and wrap_code_line and wrap_text which only it reached, are deleted with their four direct unit tests. Two comments that named wrap_text are corrected. - Tables pushed a rule after every row, nearly doubling their height. A rule now marks only the header separator, the header row is bold, and ragged rows are padded to the column count so they line up with the borders. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BsXVvReYca2UxzimQtj7Mj
From the 0.10.2 Rust optimization audit (memory lens, judged safe-now). The cost. apply_engine_session_projection cleared the UI's per-message token cache on every engine projection, and the engine sends one per tool result. The next frame's estimated_context_tokens then re-estimated every message on the UI thread. That includes serializing every ToolUse input to a String, so a write_file carrying a whole file was serialized again for each later tool result. The change. - set_api_messages already counted the leading messages that are unchanged and then dropped that number. It now returns it, and the projection truncates the cache to that prefix instead of clearing it. The estimates kept are for messages equal to the ones they were computed from, so every value matches what a full clear produces. - In-place edits go through api_messages_mut, for example replace_matching_assistant_text, and a prefix compare cannot see them. So api_messages_mut now clears the cache, and the edit shows sooner than before. - push_api_message appends through Arc::make_mut directly, so appends keep the cache. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BsXVvReYca2UxzimQtj7Mj
…once an hour From the 0.10.2 Rust optimization audit (blocking lens, judged safe-now). The cost. Every private single write_atomic, and every write_atomic_batch parent, ran is_codewhale_owned_state_dir (up to 4 canonicalize calls) and then a full read_dir of the directory looking for stale temp files. Those temps only become stale after STALE_AFTER (1 h). A fork that clones hundreds of items paid one directory scan per item, measured at 22 ms each. The change. A process-wide map from directory to last sweep, using the same OnceLock<Mutex<…>> pattern as settings_transaction_mutex, lets sweep_owned_dir_if_due skip both the owned check and the read_dir when the directory was swept less than STALE_AFTER ago. Expired entries are dropped, so the map holds only directories touched in the last hour. The owned check and the sweep themselves are unchanged. A cached entry can only skip a sweep; it can never cause one in a directory that is not owned. Comments the change made false are corrected: the AtomicWriteScope::Single and write_atomic_batch docs, the call site, and the two runtime_threads.rs comments that described a per-item sweep. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BsXVvReYca2UxzimQtj7Mj
…r thread From the 0.10.2 Rust optimization audit (io lens, judged safe-now). The cost. aggregate_usage called list_turns_for_thread for every thread. Each call is list_all_turns, which reads and parses every turn file, plus a retain. So one GET /v1/usage cost T x N file reads, inline on a Tokio worker. The change follows the pattern thread_list_facts and running_threads already use (#3757). One spawn_blocking on a cloned store lists the threads and reads all turns once, grouped by thread id. The async side accumulates in the same thread order and still validates each thread id. A join error reads 'Runtime usage aggregation task failed', matching aggregate_usage_for_thread. Totals and ordering are unchanged. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BsXVvReYca2UxzimQtj7Mj
…opying it From the 0.10.2 Rust optimization audit (memory lens, judged safe-now). The cost. SessionObjectSnapshot.messages was Vec<Message>, and build_tool_context_for_turn filled it with self.session.messages.clone().into(). AppendLog::into_inner deep-copies whenever the Arc is shared, and the engine always shares it. ToolContext derives Clone, and live_tool_context clones the registry context per call. So about 8 full copies of the history stayed resident per turn, plus 2-3 per tool call. The change. The field is Arc<Vec<Message>> and is filled from the existing AppendLog::snapshot(). SessionObjectSnapshot::new takes impl Into<Arc<Vec<Message>>>, so the existing vec![] callers compile unchanged. Every reader only iterates, indexes or borrows as &[Message]. The snapshot is immutable: AppendLog mutates only through Arc::make_mut, so tools still see exactly the turn-start view. Debug output is identical. Nothing model-visible, persisted or serialized changes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BsXVvReYca2UxzimQtj7Mj
… without allocating From the 0.10.2 Rust optimization audit (turn-loop lens, judged safe-now). The redundant walk. - run_auto_compaction first computes live = turn.live_input_tokens_for_compaction(messages, system, …), which is already max(E, billed + growth). E is estimate_input_tokens_for_pressure over the same messages and system prompt. - It then gated on compaction_pressure_reached_with_billed(messages, system, config, live). Below the threshold, which is most steps, that recomputed the same E with a second full-history walk before returning max(E, live) >= threshold. - Since live >= E, that equals live >= threshold. The gate now compares live with the threshold directly. - When live is None, E is 0 and both forms are 0 >= threshold. - compaction_pressure_reached_with_billed keeps its other callers, and the sentence in its doc that described the double pass is removed. JSON sizing. estimate_tokens_for_message serialized each ToolUse, ServerToolUse, ToolSearchToolResult and CodeExecutionToolResult value to a String only to take its length. compact_json_len now counts the bytes through serde_json::to_writer into the existing utils::CountingWriter. That gives the same compact-formatter count with no allocation. ToolUse keeps its 100-token fallback. Every estimate and every compaction decision is unchanged. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BsXVvReYca2UxzimQtj7Mj
From the 0.10.2 Rust optimization audit (ui-hot-path lens, judged safe-now). The default theme is underwater, so this runs on every frame. The underwater shell block painted the full frame with the surface_bg ground and then repainted four sub-rects (strip, side work, work chat, preview) with the same ground. Why the four repaints changed nothing: - Nothing is drawn between the full-frame pass and those four. - Each pass uses the same column, theme, ground and ocean semantic-surface slice. - The frame area is the buffer area, so the first pass already visits every cell. - Water depends only on the absolute row: paint_native pins the viewport to y, and paint_matching_native passes no samples. The four passes are removed. The composer, plugin-CTA, footer and workbar passes, which use different grounds, stay. The comment above the full-frame pass no longer implies more surface_bg passes follow. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BsXVvReYca2UxzimQtj7Mj
…ole child history twice From the 0.10.2 Rust optimization audit (memory lens, judged safe-now). The cost. - insert_subagent_full_transcript_handle and build_subagent_checkpoint each ran safe_tool_result_message_projection over the whole child history, which is a to_vec copy, only to keep a 256 KiB / 1 MiB tail. - Sizing each message took a serde_json::to_string allocation. - On the Core path, the transcript writer's projected sync found its cursor already advanced by the raw sync, so the copy bought nothing. The change. - bounded_tail_messages walks newest-first and projects one message at a time until the budget, keeping the always-keep-final rule. - approximate_message_bytes counts serialized bytes with CountingWriter. The count is identical and still falls back to 1024. - The writer projects only its unsynced suffix. - Callers pass the raw history. The doc comment says it returns projected messages, because re-projecting is lossy. The persisted checkpoint and transcript bytes are unchanged. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BsXVvReYca2UxzimQtj7Mj
…erlay From the 0.10.2 Rust optimization audit (io lens, judged safe-now). Every save ends with cleanup_old_sessions, which called list_session_records. That applied apply_late_usage_to_metadata to every saved session: a lock-file open, a blocking fd_lock read, a tombstone read and a ledger parse per record. Retention only orders and archives by metadata it never reads costs from, so all of that was wasted on every save. The overlay moves into list_sessions, the only other caller, which applies it to each record after listing. Retention gets the raw metadata, and the session list a person sees is unchanged. The list_session_records doc says it is list_sessions without the overlay. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BsXVvReYca2UxzimQtj7Mj
…t runs From the 0.10.2 Rust optimization audit (ui-hot-path lens, judged safe-now). The cost. pet_watch::tick runs on every event-loop iteration. Every 30 ms it called crossterm window_size(), which on unix opens /dev/tty, does an ioctl and closes it. It also read CODEWHALE_PET_GRAPHICS, allocated the locale, ran ShellPhase::from_app and built a live::View. All of that happened even when no pet worker existed, and the view was then dropped unread. The change. last_tick still advances unconditionally inside the 30 ms gate, so timing is unchanged. The phase, probe, env read, locale and View build all move inside 'if let Some(worker)'. The notices drain reads app.pet_watch.worker, which ends the mutable borrow before ShellPhase::from_app. A running pet sees exactly the same view. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BsXVvReYca2UxzimQtj7Mj
… dev-dependencies From the 0.10.2 Rust optimization audit (build-size lens, judged safe-now). Doctests. codewhale-tui has no runnable doc example: its fences are 7 ignore, 1 rust,ignore, and text/json/sh blocks. Yet 'cargo test --doc' still built a rustdoc test harness for the crate on every run. Its [lib] now sets doctest = false. BUILD_PERFORMANCE.md says why. The workspace doctest inventory (3 passing / 8 ignored across 21 crates, all 8 ignored in codewhale-tui) is marked as not re-measured. Dependencies. schemars and rusqlite are used only under cfg(test): the schemars derive is cfg_attr(test, …), and rusqlite appears only in test modules. Both move to [dev-dependencies] with the same versions and features. rusqlite stays in the workspace's normal build through codewhale-memory, codewhale-state and codewhale-app-server, so its features are unchanged. Cargo.lock is unchanged, and --locked still resolves. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BsXVvReYca2UxzimQtj7Mj
User-facing bullets for d40be2b through 79735df: setup honesty, the Ollama first run, failure severity and retry notices, file-edit cards and status words, delegated-agent cards, markdown headings and tables, approval labels in every locale, the Work mode name, the three locale strings, and the UI-thread and memory work. crates/tui/CHANGELOG.md is regenerated by scripts/sync-changelog.sh. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BsXVvReYca2UxzimQtj7Mj
Refs #6915, #6728, #6396, #6931. The 0.10.2 notes had no known-limits block, so four limits of the current candidate went unstated: - the Windows dead-owner start refusal ('Windows stale-owner recovery is not qualified', app-server/src/lib.rs); - idle CPU not measured on FreeBSD or Linux; - base-rate pricing above a Models.dev context tier, which can only happen after a live refresh because the bundled catalog has 0 tiered rows (checked); - delegated agents' shells shown in /jobs and the dock, not in the agent's detail. Any of these that the founder fixes before the tag comes out of this block. crates/tui/CHANGELOG.md is regenerated. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BsXVvReYca2UxzimQtj7Mj
…on't repeat themselves
The 0.10.2 UX audit's second slice. The judge marked it as needing no
product decision; it was held back only by the 12-item cap. Every
sub-item was re-checked against the tree before the change, and an
adversarial review's three findings are fixed here.
First run, chrome and errors:
- Provider readiness says "endpoint reachable · model not checked"
instead of "models endpoint 2xx". It deliberately does not say "key
works": providers with a public /models answer 2xx to a bad key.
- remote_control::Status is reachable through one typed accessor.
'/rc failed' paints in Failure ink, not Info, and /setup reads the
enum. It used to match English status-line prefixes, so a failed
remote showed as "not available".
- An error cell offers "Alt+V:full error" only when the error wraps past
4 rows. Alt+V still opens every error.
- Clipboard: native copy and cut say "Copied to the clipboard" through a
typed toast, and a failure says "Clipboard copy failed: {error}". That
is the new MessageId ClipboardCopyFailed, translated in all 15 packs.
The duplicate Cmd+C composer path calls copy_active_selection.
- NotificationProviderFallback leads with the switch and puts the reason
after a clause joint in every pack, so the toast survives at 80-100
columns instead of vanishing below about 146.
- notice_budget also respects the permission chip's floor, so the kit
never clips a notice with '...'.
- The effort field reads "auto→high", not "auto: high".
- The elevation card drops its duplicate in-body heading and the
"Tool: exec_shell" row when a command is shown.
ElevationTitleSandboxDenied had no other use and is removed from the
enum and all packs.
Transcript cards:
- The checklist card drops its "checklist: <tool>" row. The legacy
change card maps raw statuses through TodoStatus to four new
translated MessageIds ("in progress", not "in_progress").
- A failed read or search entry carries its reason: ExploringEntry.error
is set from the tool result on failure.
- A single-entry card shows up to 6 rows and Alt+V when rows are hidden.
- A multi-entry card shows only the first line, because the cell holds
one detail record and Alt+V there could open a sibling's record.
- Body rows no longer repeat what the header already shows in full:
- exploring done/live, web-search query and image path;
- a generic card's name, and its args when the header carries them.
That compares the value alone or a " · value" suffix, not a raw
suffix.
- No double space, and the parallel strip lists only non-zero counts.
- Every affordance row joins with " · ". "Output shortened" gets the
transcript rail like its siblings.
- MCP calls no longer collapse into a run summary (their side effects
cannot be known). Run summaries show "read file", not "read_file".
Tests whose pinned copy changed are updated: clipboard receipts, the
effort label, elevation titles in en/zh-Hans/ja/zh-Hant, the checklist
status, the collapsed-run summaries, readiness, and two ExploringEntry
literals.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BsXVvReYca2UxzimQtj7Mj
There was a problem hiding this comment.
If your organization's extra usage balance is empty, an organization admin can add extra usage credits at claude.ai/admin-settings/usage. If its monthly spend limit was reached, an admin can raise it on the same page. If neither applies, contact Anthropic support.
Once extra usage is available, someone with write access to this repository can comment @claude review on this pull request to trigger a review.
There was a problem hiding this comment.
🔵 Needs a closer look
The cross-cutting 136-file release branch includes runtime, authentication, execution, and UI changes whose remaining installed-candidate and PTY validation requires final human review.
0 open findings
What changed in this PR
Prepares Codewhale 0.10.2 by consolidating release-blocking correctness, observability, UX, localization, performance, and release-documentation work.
Changes:
- Improves shell-job inspection, cancellation, background execution, goal handling, and sub-agent presentation.
- Corrects OAuth, snapshots, constitution workflows, approval UI, localization, and markdown rendering.
- Updates performance paths, conformance fixtures, release metadata, documentation, and vendored ratatui assets.
| File | Description |
|---|---|
CHANGELOG.md |
Documents 0.10.2 changes and limits. |
Cargo.lock |
Updates resolved dependencies. |
crates/config/src/user_constitution.rs |
Corrects constitution projection and ratification. |
crates/localization/locales/ca.json |
Updates Catalan UI copy. |
crates/localization/locales/de.json |
Updates German UI copy. |
crates/localization/locales/en.json |
Updates English UI copy. |
crates/localization/locales/es-419.json |
Updates Latin American Spanish copy. |
crates/localization/locales/fr.json |
Updates French UI copy. |
crates/localization/locales/hi.json |
Updates Hindi UI copy. |
crates/localization/locales/id.json |
Updates Indonesian UI copy. |
crates/localization/locales/ja.json |
Updates Japanese UI copy. |
crates/localization/locales/ko.json |
Updates Korean UI copy. |
crates/localization/locales/pt-BR.json |
Updates Brazilian Portuguese copy. |
crates/localization/locales/ru.json |
Updates Russian UI copy. |
crates/localization/locales/uk.json |
Updates Ukrainian UI copy. |
crates/localization/locales/vi.json |
Updates Vietnamese UI copy. |
crates/localization/locales/zh-Hans.json |
Updates Simplified Chinese copy. |
crates/localization/locales/zh-Hant.json |
Updates Traditional Chinese copy. |
crates/localization/src/lib.rs |
Extends localized message definitions. |
crates/tui/CHANGELOG.md |
Synchronizes TUI release notes. |
crates/tui/Cargo.toml |
Adjusts TUI dependencies and doctests. |
crates/tui/src/commands/groups/config/config.rs |
Updates configuration command behavior. |
crates/tui/src/commands/groups/config/mod.rs |
Adjusts config command registration. |
crates/tui/src/commands/groups/core/constitution.rs |
Fixes constitution review and ratification. |
crates/tui/src/commands/groups/core/core.rs |
Updates mode command copy and usage. |
crates/tui/src/commands/groups/utility/jobs.rs |
Routes job inspection through the live pager. |
crates/tui/src/commands/mod.rs |
Updates command dispatch. |
crates/tui/src/commands/traits.rs |
Adjusts command contracts. |
crates/tui/src/compaction.rs |
Reduces compaction work. |
crates/tui/src/core/authority/auto_review.rs |
Refines approval behavior. |
crates/tui/src/core/engine.rs |
Updates engine lifecycle handling. |
crates/tui/src/core/engine/compaction.rs |
Consolidates compaction-pressure calculation. |
crates/tui/src/core/engine/context.rs |
Shares turn-start context history. |
crates/tui/src/core/engine/preview/tests.rs |
Updates preview expectations. |
crates/tui/src/core/engine/tests/test_cases_04.rs |
Updates engine regressions. |
crates/tui/src/core/engine/tests/test_cases_13.rs |
Updates engine regressions. |
crates/tui/src/core/engine/tests/test_cases_15.rs |
Updates engine regressions. |
crates/tui/src/core/engine/turn_loop.rs |
Corrects turn completion accounting. |
crates/tui/src/core/engine/turn_loop/model_step.rs |
Refines model-step lifecycle handling. |
crates/tui/src/core/turn.rs |
Improves context estimation. |
crates/tui/src/fleet/executor.rs |
Relocates CLI parsing coverage. |
crates/tui/src/lib/terminal_mode_test_cases_03.rs |
Updates terminal-mode coverage. |
crates/tui/src/oauth.rs |
Removes the unsupported OAuth parameter. |
crates/tui/src/provider_readiness.rs |
Clarifies provider readiness states. |
crates/tui/src/remote_control.rs |
Updates remote-control status handling. |
crates/tui/src/rlm/session.rs |
Refines session context sharing. |
crates/tui/src/runtime_handoff.rs |
Updates runtime handoff behavior. |
crates/tui/src/runtime_threads.rs |
Adjusts runtime initialization boundaries. |
crates/tui/src/session_manager.rs |
Updates session restoration state. |
crates/tui/src/snapshot/repo.rs |
Restores snapshots on Git 2.43. |
crates/tui/src/todo_snapshot.rs |
Shortens todo tool receipts. |
crates/tui/src/tools/goal.rs |
Adds yield progress and usage accounting. |
crates/tui/src/tools/mod.rs |
Updates tool registration and status handling. |
crates/tui/src/tools/shell.rs |
Fixes job cancellation, polling, and inspection. |
crates/tui/src/tools/shell/tests.rs |
Updates shell-job coverage. |
crates/tui/src/tools/subagent/engine.rs |
Refines delegated-agent execution. |
crates/tui/src/tools/subagent/mod.rs |
Bounds checkpoint projection and lifecycle state. |
crates/tui/src/tui/active_cell.rs |
Updates active-cell rendering state. |
crates/tui/src/tui/app.rs |
Integrates new UI and job state. |
crates/tui/src/tui/app/init.rs |
Adjusts application initialization. |
crates/tui/src/tui/app/tests.rs |
Updates application behavior coverage. |
crates/tui/src/tui/app/types.rs |
Extends typed application state. |
crates/tui/src/tui/approval.rs |
Localizes approval presentation. |
crates/tui/src/tui/approval/elevation.rs |
Simplifies elevation cards. |
crates/tui/src/tui/approval/previews.rs |
Adds typed preview state. |
crates/tui/src/tui/approval/tests.rs |
Updates approval coverage. |
crates/tui/src/tui/footer_hints.rs |
Corrects footer controls and clipping. |
crates/tui/src/tui/history.rs |
Refines history-cell presentation. |
crates/tui/src/tui/history/checklist.rs |
Removes redundant checklist labels. |
crates/tui/src/tui/history/file_mutation.rs |
Uses patch-oriented edit presentation. |
crates/tui/src/tui/history/tests.rs |
Updates history rendering coverage. |
crates/tui/src/tui/history/tool_output.rs |
Improves tool output status rendering. |
crates/tui/src/tui/history/tool_run.rs |
Humanizes tool-run presentation. |
crates/tui/src/tui/markdown_render.rs |
Fixes headings and table rendering. |
crates/tui/src/tui/mouse_ui.rs |
Pins clicked transcript operations. |
crates/tui/src/tui/mouse_ui/primary_tests.rs |
Updates mouse interaction coverage. |
crates/tui/src/tui/pager.rs |
Adds live, followable job inspection. |
crates/tui/src/tui/pet_watch/full.rs |
Shows delegated agents in the pet view. |
crates/tui/src/tui/pet_watch/mod.rs |
Reduces idle pet work. |
crates/tui/src/tui/phase_strip.rs |
Updates phase and failure presentation. |
crates/tui/src/tui/provider_picker.rs |
Refines provider onboarding states. |
crates/tui/src/tui/selection.rs |
Tracks stable transcript selection ownership. |
crates/tui/src/tui/setup/mod.rs |
Fixes setup navigation and status copy. |
crates/tui/src/tui/shell_job_routing.rs |
Formats and refreshes job inspectors. |
crates/tui/src/tui/subagent_routing.rs |
Improves delegated-agent labels and state. |
crates/tui/src/tui/tool_routing.rs |
Centralizes tool status presentation. |
crates/tui/src/tui/ui/activity_detail.rs |
Opens the selected operation’s details. |
crates/tui/src/tui/ui/apply.rs |
Applies updated goal and error states. |
crates/tui/src/tui/ui/event_loop.rs |
Refreshes live job inspectors. |
crates/tui/src/tui/ui/frame.rs |
Updates UI framing and fallback layout. |
crates/tui/src/tui/ui/handlers.rs |
Routes job and task actions. |
crates/tui/src/tui/ui/task_projection.rs |
Avoids repeatedly copying shell output. |
crates/tui/src/tui/ui/tests.rs |
Updates integrated UI coverage. |
crates/tui/src/tui/views/help.rs |
Updates help presentation. |
crates/tui/src/tui/views/mod.rs |
Registers revised views. |
crates/tui/src/tui/widgets/approval_band_legacy.rs |
Uses translated approval metadata. |
crates/tui/src/tui/widgets/mod.rs |
Updates widget exports. |
crates/tui/src/tui/widgets/tool_card.rs |
Refines tool-card statuses and affordances. |
crates/tui/src/tui/work_surface/model.rs |
Updates job, task, and agent projections. |
crates/tui/src/utils.rs |
Throttles stale atomic-temp cleanup. |
crates/tui/tests/fixtures/conformance/events/approval_denied.golden.jsonl |
Re-records approval-denied events. |
crates/tui/tests/fixtures/conformance/events/cancel_midstream.golden.jsonl |
Re-records cancellation events. |
crates/tui/tests/fixtures/conformance/events/one_tool_call.golden.jsonl |
Re-records single-tool events. |
crates/tui/tests/fixtures/conformance/events/parallel_tool_calls.golden.jsonl |
Re-records parallel-tool events. |
crates/tui/tests/fixtures/conformance/events/plain_answer.golden.jsonl |
Re-records plain-answer events. |
crates/tui/tests/fixtures/conformance/events/provider_error_after_tool_call.golden.jsonl |
Re-records provider-error events. |
crates/tui/tests/fixtures/conformance/prompt/agent_suggest.golden.json |
Updates agent prompt golden. |
crates/tui/tests/fixtures/conformance/prompt/agent_suggest.tools.golden.json |
Updates agent tool-catalog golden. |
crates/tui/tests/fixtures/conformance/prompt/plan_mode.golden.json |
Updates plan-mode prompt golden. |
crates/tui/tests/fixtures/conformance/prompt/plan_mode.tools.golden.json |
Updates plan-mode tools golden. |
crates/tui/tests/fixtures/conformance/prompt/trusted_project_instructions.golden.json |
Updates trusted-project prompt golden. |
crates/tui/tests/fixtures/conformance/prompt/trusted_project_instructions.tools.golden.json |
Updates trusted-project tools golden. |
docs/BUILD_PERFORMANCE.md |
Documents build-performance changes. |
docs/CONFIGURATION.md |
Updates configuration guidance. |
docs/CONTRIBUTORS.md |
Synchronizes contributor credits. |
docs/GUIDE.md |
Updates user-facing command guidance. |
docs/SUBAGENTS.md |
Documents delegated-agent behavior. |
docs/TOOL_LIFECYCLE.md |
Documents revised tool lifecycle. |
docs/design/DECONSTRUCTION_ROADMAP.md |
Updates runtime-split progress. |
docs/design/TUI_DECONSTRUCTION.md |
Updates TUI boundary metrics. |
docs/features.toml |
Registers the user-visible feature changes. |
docs/zh_hans/SUBAGENTS.md |
Updates Chinese sub-agent documentation. |
docs/zh_hans/TOOL_LIFECYCLE.md |
Updates Chinese lifecycle documentation. |
pet/scripts/check-shared.py |
Sends the current appearance schema. |
pet/tui/Cargo.lock |
Updates pet TUI dependency resolution. |
pet/tui/Cargo.toml |
Updates the pet TUI dependency. |
scripts/release/check-versions.sh |
Updates release-version validation. |
scripts/runtime-boundary-baseline.json |
Lowers runtime-boundary counts. |
scripts/runtime-contract-budget.json |
Updates the measured contract ceiling. |
vendor/codewhale-ratatui/CHANGELOG.md |
Records vendored rendering changes. |
vendor/codewhale-ratatui/Cargo.lock |
Updates vendored dependency resolution. |
vendor/codewhale-ratatui/Cargo.toml |
Versions the vendored crate. |
vendor/codewhale-ratatui/UPSTREAM.json |
Records upstream provenance. |
vendor/codewhale-ratatui/src/avatar_sprite.rs |
Adds crisp half-block sprites. |
vendor/codewhale-ratatui/src/whale_motion/pixels.rs |
Updates pixel rendering. |
web/lib/release-credits.ts |
Adds 0.10.2 contributor credit. |
🧠 Review effort: Balanced
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
What and why
This is the 0.10.2 release-readiness branch from the cloud session. The founder chose one draft PR per repo. Every commit is a self-contained slice on top of
main, which has been merged in as it moved./connectand/disconnect.maincarries the same fix as 7be1f48, and the two merged cleanly./undowork on git 2.43 (Ubuntu 24.04). That version rejectscheckout --end-of-options <id> -- <paths>./jobsnotice instead of the model-facing receipt.tty:truedoes not count as moved.todo_writeanswers the model with a short receipt.update_goalaccepts progress withyield, and the TUI shows that stage report. Covers the schema text, 12 re-recorded conformance goldens, and the measured +7 B runtime-contract ceiling./jobs pollandstdinno longer consume the model's output cursor./jobs waitand/jobs pollopen the live inspector instead of blocking the UI loop for up to 5 s on the ShellManager mutex. Dock shell rows open that inspector too: projection stops copying full stdout and stderr on every pass, and right-click keeps Stop. Dock task rows run/task showinstead of failing with "Job task_… not found".waiton a running job adds "Progress: last output Ns ago; output phase: …". The/jobscancel receipt and the completion the model receives after a person's cancel say whether build artifacts survive. Two comments that 34bf656 made false are fixed./setupu/dact only on the working-agreement step; elsewhere they no longer close the wizard and turn a ratified agreement off. Retired footer hints no longer run a lockedsettings.tomltransaction on every Tab/Shift+Tab/Esc.originatorauthorize parameter and its dead branch are gone. Stored credentials keep the field so old files still parse.crate::Cli) moves to the CLI tests. The runtime-boundary ratchet goes from test 35 to 32, and the roadmap numbers follow./settings set locale(now/config locale <tag> --save, in all 15 packs), and the English elevation Abort ("Skip only this tool call").done,failed,loaded, not run), and a hydrated tool loses the done check.is_previewreplaces the English label match./setupstops saying "You're ready." without a model, and a rejected key's reason survives the 6-row cap./zidongnames the Full Access it grants./modeusage is[work|plan|operate|1|2|3].#and render inline markup. Tables draw one header rule and pad ragged rows.auto→high; a cleaner elevation card. Cards: no checklist tool-name row and translated statuses; failed read/search entries show their reason; body rows stop repeating the header;·affordances; MCP calls never collapse; humanized run names./constitutionfixes from the session-export review. Ratify checks the reviewed digest, and ratifying one at a time works. Preview matches the injected block. Cache wording is honest, the wizard's authority order is fixed, notes are no longer silently truncated, and zh-Hans uses 宪章.pet/scripts/check-shared.pysends the current appearance schema. Main's b0f9cbc added two always-serialized fields, which broke the macOS Pet conformance check.KV-cache
update_goal'sprogressdescription, +7 B measured. That changes the session-pinned prefix for new sessions only.kill_noteon Killed shell-completion handoffs, a user-role runtime message already in the session log.Issue
Refs #6931
Refs #6944
Refs #6925
Refs #6939
Refs #6915
Refs #6728
Refs #6396
The other slices are session-export and release-readiness fixes with no issue of their own. None of the commits closes an issue on merge.
How I tested it
Local
codewhale-tuilib test binary (Ubuntu 24.04, git 2.43), built from the branch through d220add plus the goal change:commands:: snapshot:: tools::shell tool_cancellation pet_watch core::engine tools::goal tools::todo tool_routing shell_job_routing task_projection work_surface setup:: tui::history:test result: FAILED. 2764 passed; 1 failed; 5 ignored.tui::views::fleet_setup::tests::model_step_detail_shows_capability_badges_for_known_models_only. It depends on process-shared registry state in that single-process libtest run.1 passed; 0 failed), and so does its module (54 passed; 0 failed).conformance:::33 passed; 0 failed.tools::goal:36 passed; 0 failed.Compile and static checks
cargo check -p codewhale-tui --lib --tests --locked: exit 0, 0 warnings, at d220add plus the goal change.cargo fmt --all -- --check: clean at e107caf.scripts/release/check-versions.sh: OK.check-contributor-credit.py: passes.module_graph.py --check: PASS {prod 11, test 32, late 1, uilib 1} over 117 modules;test_check_runtime_contract_budget.py: 22 OK;Hosted CI on e99934a (run 38149284218):
19036 tests run: 19036 passed (4 slow), 34 skipped. This includeslive_shell_job_pager_follows_new_output_until_scrolled_back,ending_a_live_shell_job_drops_stop,silent_running_job_detail_reads_quiet_not_staleand the moveddefault_max_turns_does_not_add_a_hidden_worker_cap.Hosted CI on 2f82993 (run 38156029258), covering everything through the performance commits and the merged main:
19032 tests run: 19032 passed (4 slow), 34 skipped. That is 4 fewer than before because four markdown helper tests were removed with the code they tested.Slice 2 (e107caf) locally: clippy (tui + localization) 0 warnings;
cargo test -p codewhale-localization:54 passed; 0 failed.Hosted CI on e107caf (run 38160307827), the current head and the release candidate SHA:
19032 tests run: 19032 passed (4 slow), 34 skipped.git merge-treeexit 0), so the release cut from main after this PR merges carries both.Not covered by the local binary
ui/apply.rsline, and f7264f7 through e107caf.cargo clippy -p codewhale-tui --lib --tests --locked -- -D warnings(CI's allow-list): 0 warnings on e2ee2d2 (Finishedin 19m 54s), 28ea342 (3m 51s) and the tree at 2f82993 (15m 53s).Not done here (founder or follow-up)
/jobsand the dock with their Owner, not in the agent's detail;Run(action=tests);/constitution:modelGuidanceshape;doctorautonomy;description(session-export finding): held for a design call, so that a model-written description never hides the real command on auto-approved runs.🤖 Generated with Claude Code
https://claude.ai/code/session_01BsXVvReYca2UxzimQtj7Mj