Skip to content

Fix cargo fmt formatting issues - #1

Merged
Hmbown merged 1 commit into
mainfrom
Hmbown/fix-cargo-fmt
Jan 20, 2026
Merged

Hmbown merged 1 commit into
mainfrom
Hmbown/fix-cargo-fmt

Conversation

@Hmbown

@Hmbown Hmbown commented Jan 20, 2026

Copy link
Copy Markdown
Collaborator

Summary

  • Fix cargo fmt CI failure in src/commands/note.rs and src/settings.rs

Test plan

  • cargo fmt --all -- --check passes

🤖 Generated with Claude Code

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@Hmbown
Hmbown merged commit f279531 into main Jan 20, 2026
1 check passed
@gemini-code-assist

Copy link
Copy Markdown
Contributor

Summary of Changes

Hello @Hmbown, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request addresses and resolves automated code formatting issues identified by cargo fmt in the CI pipeline. The changes ensure that the codebase adheres to the defined style guidelines, preventing future CI failures related to formatting and maintaining code consistency.

Highlights

  • CI Fix: Resolved cargo fmt CI failures in src/commands/note.rs and src/settings.rs.
  • Code Formatting: Applied consistent formatting by reordering use statements and adjusting format! macro calls in src/commands/note.rs.
  • Settings Formatting: Adjusted the formatting of the auto_rlm setting description in src/settings.rs for cargo fmt compliance.

🧠 New Feature in Public Preview: You can now enable Memory to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console.

Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution. ↩

@gemini-code-assist gemini-code-assist Bot 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.

Code Review

This pull request correctly applies cargo fmt to resolve formatting issues. The changes look good. I've added one suggestion in src/commands/note.rs to improve the consistency of the note formatting, which is a minor logic improvement related to the changed code.

I am having trouble creating individual review comments. Click here to see my feedback.

src/commands/note.rs (48-53)

medium

The current logic for writing notes can lead to inconsistent formatting. Specifically, it always prepends \n---\n, which results in an unnecessary leading newline and separator for the very first note in an empty file. A better approach is to check if the file is empty. If so, write the note content directly. Otherwise, prepend the separator. This ensures notes are always formatted consistently without leading whitespace in new files.

    // Write separator and note content
    let is_empty = match file.metadata() {
        Ok(md) => md.len() == 0,
        Err(e) => return CommandResult::error(format!("Failed to read file metadata: {e}")),
    };

    let format_string = if is_empty { "{}" } else { "\n---\n{}" };
    if let Err(e) = writeln!(file, format_string, note_content) {
        return CommandResult::error(format!("Failed to write note: {e}"));
    }

@Hmbown
Hmbown deleted the Hmbown/fix-cargo-fmt branch January 21, 2026 00:07
Hmbown added a commit that referenced this pull request Feb 19, 2026
Hmbown added a commit that referenced this pull request Apr 28, 2026
Sub-area #1 of the v0.6.6 UI redesign (issue #121).

User cells now lead with `▎` (solid bar, no animation — input is finished).
Assistant cells lead with `●`. While streaming, the bullet pulses on a
2-second cycle between 30%..100% brightness via `palette::pulse_brightness`;
once a turn completes the bullet sits at full DEEPSEEK_SKY so finished
history reads as solid.

Honors `low_motion`: the pulse is suppressed and the glyph holds full
brightness regardless of streaming state. Pager / clipboard exports
(`transcript_lines`) also skip the pulse so screenshots are stable.

Existing pager titles in `ui.rs` (`history_cell_to_text`) keep the literal
"You" / "Assistant" wording — those drive the modal title bar and read
better as words than as glyphs.

Tests: glyphs replace the literal labels in both User and Assistant cells;
streaming pulse demonstrably dips below source brightness; idle and
low_motion both pin to source.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
MMMarcinho pushed a commit to MMMarcinho/DeepSeek-TUI that referenced this pull request May 6, 2026
Sub-area codewhale-hq#1 of the v0.6.6 UI redesign (issue codewhale-hq#121).

User cells now lead with `▎` (solid bar, no animation — input is finished).
Assistant cells lead with `●`. While streaming, the bullet pulses on a
2-second cycle between 30%..100% brightness via `palette::pulse_brightness`;
once a turn completes the bullet sits at full DEEPSEEK_SKY so finished
history reads as solid.

Honors `low_motion`: the pulse is suppressed and the glyph holds full
brightness regardless of streaming state. Pager / clipboard exports
(`transcript_lines`) also skip the pulse so screenshots are stable.

Existing pager titles in `ui.rs` (`history_cell_to_text`) keep the literal
"You" / "Assistant" wording — those drive the modal title bar and read
better as words than as glyphs.

Tests: glyphs replace the literal labels in both User and Assistant cells;
streaming pulse demonstrably dips below source brightness; idle and
low_motion both pin to source.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
YaYII added a commit to YaYII/DeepSeek-TUI that referenced this pull request May 9, 2026
…whale-hq#4

🔴 Fix codewhale-hq#1 (Embedder blocks async runtime):
- Pre-warm embedder in init_vector_db() via warmup_embedder()
- Model downloaded during startup, not first retrieval
- Eliminates 5-10s UI freeze on first embed call

🔴 Fix codewhale-hq#2 (Compaction summary pollution):
- store_compaction_summary_to_vector_db() now extracts only
  the summary section from the SystemPrompt, stripping
  boilerplate headers and workflow context
- Uses regex extraction between ## Summary and ## Workflow markers

🔴 Fix codewhale-hq#3 (No vector index → full table scan):
- New ensure_vector_index() in LanceDbBackend
- Checks list_indices() for existing IVF-PQ index on embedding column
- Creates missing index via table.create_index(["embedding"], Index::Auto)
- Called from ensure_tables() for all three tables

🔴 Fix codewhale-hq#4 (Compaction threshold regression for non-vector users):
- Added MINIMUM_AUTO_COMPACTION_TOKENS_WITHOUT_VECTOR = 500K
- should_compact() now accepts vector_db_enabled: bool
- Non-vector users keep 500K floor; vector users use 50K floor
- auto_floor_tokens=0 (explicit disable by tests) bypasses both floors
- token_threshold default restored to 800K (fallback only;
  real values come from compaction_threshold_for_model_and_effort)

🟡 Fix codewhale-hq#7 (No score threshold → noise injection):
- search_memories() and search_summaries() now filter
  results where score < 0.4 before returning
- Prevents low-quality retrieval from polluting system prompt

Tests: 62/62 compaction ✓, 17/17 vector_db ✓
YaYII added a commit to YaYII/DeepSeek-TUI that referenced this pull request May 9, 2026
🔴 codewhale-hq#1 Embedder blocks async runtime:
  - Pre-warm embedder in init_vector_db() via warmup_embedder()
  - Model downloaded at startup, eliminating 5-10s UI freeze

🔴 codewhale-hq#2 Compaction summary boilerplate pollution:
  - store_compaction_summary_to_vector_db() now extracts only
    the actual summary section using regex, stripping headers
    and workflow context from embeddings

🔴 codewhale-hq#3 No vector index → full table scan:
  - New ensure_vector_index() checks list_indices() for IVF-PQ
  - Creates missing index via create_index(["embedding"], Auto)
  - Called from ensure_tables() for all 3 tables

🔴 codewhale-hq#4 Compaction threshold regression:
  - Added MINIMUM_AUTO_COMPACTION_TOKENS_WITHOUT_VECTOR = 500K
  - should_compact() accepts vector_db_enabled: bool
  - Non-vector users keep 500K floor; vector users get 50K
  - auto_floor_tokens=0 bypasses both (test compatibility)
  - token_threshold default restored to 800K

🟡 codewhale-hq#7 Score threshold filtering added:
  - search_memories() and search_summaries() filter score < 0.4

Tests: 62/62 compaction ✓, 17/17 vector_db ✓, 99/100 engine ✓
@Hmbown Hmbown mentioned this pull request May 10, 2026
8 tasks
Yourdaylight added a commit to Yourdaylight/DeepSeek-TUI that referenced this pull request May 15, 2026
… precision

- resolve_path: normalise .. components; reject workspace escapes (codewhale-hq#1,codewhale-hq#5)
- tool_read_file: clamp start_line >= 1 to prevent underflow panic (codewhale-hq#4)
- tool_edit_file: use replacen(.., 1) to avoid mass-replacement bugs (codewhale-hq#6,codewhale-hq#8)
Hmbown pushed a commit that referenced this pull request May 15, 2026
)

When an OpenAI-compatible backend (vLLM, Ollama, LM Studio, Together AI,
self-hosted vLLM/SGLang, etc.) streams an assistant message containing
multiple tool_calls in a single round, only the **last** tool's
`Event::ToolCallStarted` was firing. The preceding N-1 tool calls
executed and produced tool_result events, but never announced their
start to consumers (TUI / runtime API / embedder bridges), leaving them
with N orphan tool_result blocks and no matching tool_use blocks in the
assistant history.

## Reproduction

```text
backend dispatches:   7 × write_file + 1 × exec_shell
log shows:            7 × ApprovalRequired events ✓
listeners receive:    1 × chat:tool_start, 7 × chat:tool_end
session history:      1 tool_use + 7 tool_result (6 orphans)
```

Tested against vLLM 0.7 + Qwen3.6-35B-A3B with a "scaffold 7-file Tauri
template" prompt. Any model+backend combo that emits batch tool_calls
trips this — typical when a single LLM round asks for multiple parallel
file writes or edits.

## Root cause

`run_turn` tracked the currently-streaming tool block with a single
`current_tool_index: Option<usize>`. The Anthropic-style adapter
(non-streaming response → events at `chat.rs::L1807`) emits
Start/Stop pairs in lockstep so the slot never overlaps. But the
OpenAI streaming parser (`chat.rs::L1954-2064`) emits every
`ContentBlockStart::ToolUse` as soon as a tool_call delta lands, then
batches every `ContentBlockStop` at `finish_reason`:

```text
Start { index: 0 }       // tool #1
Delta { index: 0, .. }
Start { index: 1 }       // tool #2 — overwrites current_tool_index
Delta { index: 1, .. }
…
Start { index: 6 }       // current_tool_index = Some(6)
Delta { index: 6, .. }
Stop  { index: 0 }       // take() returns Some(6)  ← wrong tool!
Stop  { index: 1 }       // take() returns None
Stop  { index: 2 }       // take() returns None
…
```

The first `Stop` consumes the last index and emits `ToolCallStarted`
for the wrong `tool_uses` entry; every subsequent `Stop` finds the
slot already `None` and skips the entire `if let Some(index) = …`
branch, dropping the announcement.

## Fix

Replace the single slot with `HashMap<u32 block_index, usize
tool_uses_idx>`:

- `ContentBlockStart::ToolUse` and `::ServerToolUse` insert the
  `(event.index → tool_uses.len())` mapping.
- `InputJsonDelta` looks up by the `ContentBlockDelta` outer index.
- `ContentBlockStop` removes by the stop's index, so each Stop routes
  to its own `tool_uses` entry regardless of arrival order.

Routing no longer depends on `current_block_kind` (which has the same
single-slot overwrite problem); `current_tool_indices.remove(&index)`
returning `Some(_)` already proves the Stop belongs to a tool block.

## Tests

Added `batch_tool_calls_preserve_all_tool_use_indices` in
`core/engine/turn_loop.rs::tests` — feeds 7 Starts and 7 Stops through
the same `HashMap` API used by `run_turn`, asserts every index round-trips.

Manual end-to-end verification: vLLM + Qwen3.6-35B + 7-file Tauri
template prompt → frontend `messages` history now contains all 7
`write_file` tool_use blocks paired with their tool_result blocks.

Co-authored-by: hexin <he.xin@h3c.com>
encyc added a commit to encyc/DeepSeek-TUI that referenced this pull request May 31, 2026
…he_control, verify fast-path, naming

- combined_hash now hashes full tool JSON (name + description + schema),
  not just tool names, so schema/description changes are detected (codewhale-hq#1).
- build_messages preserves cache_control from SystemPrompt::Blocks so
  DeepSeek context-cache breakpoints are not lost (codewhale-hq#2).
- FrozenPrefix::verify() compares raw text before hashing to avoid
  redundant SHA-256 computation (codewhale-hq#3).
- build_messages uses self.message_count() for vector capacity (codewhale-hq#4).
- Strict-mode error message no longer references nonexistent
  /prefix-unfreeze command — suggests restart or config toggle (codewhale-hq#5).
Hmbown pushed a commit that referenced this pull request Sep 2, 2026
Buildkite 1535 on #5809: two cucumber PTY tests against the real binary
failed under the new Bottom default — at 40x12 a queued message had no
`Queued #1:` preview, and the plugin acceptance stage stayed blank.

Cause: the Bottom layout dropped the strip's leading slot and re-ordered
the constraint list, but the stage, workflow panel, pending-input preview
and background chip are addressed by fixed slot index (`body_chunks[1..4]`),
so under Bottom they drew into the wrong, zero-height slots.

Fix: one nine-slot layout in both placements. The strip owns a slot at
each end (above the stage for `top`, under the composer for `bottom`) and
only one has height, so every other slot keeps its index. The dual
constraint list is gone.

Test: `bottom_placement_keeps_the_stage_and_queued_preview_at_twelve_rows`
renders a 40x12 frame under Bottom with a transcript row and a queued
message and asserts both paint.

Evidence:
  cargo test -p codewhale-tui --all-features --locked --test cucumber -- \
    active_composer_pointer_submit_queues_without_provider \
    plugin_toml_binary_lifecycle_skill_and_stdio_mcp_acceptance
    test result: ok. 2 passed; 0 failed; 0 ignored
    (before the fix, the pointer test failed exactly as on Buildkite:
     "40x12: queued preview ... not visible after pointer submit")
  cargo test -p codewhale-tui --lib -- work_surface tui::ui::tests
    test result: ok. 808 passed; 0 failed; 0 ignored
  cargo test -p codewhale-tui --lib -- bottom_placement
    test result: ok. 3 passed; 0 failed; 0 ignored
  cargo clippy -p codewhale-tui --all-targets -D warnings (CI allows): clean
Signed-off-by: CodeWhale Bot <bot@codewhale.net>
Hmbown added a commit that referenced this pull request Sep 2, 2026
* feat(tui): the work surface sits under the composer by default

Round 3 of the shell design (codewhale-ops/design/SHELL-DESIGN-20260901.md
§2.0): the bar's information — posture, agent roster, to-do — lives UNDER
the composer, so scrolling up reads as intentional history and nothing
paints above the stage by default.

- `WorkSurfacePlacement::Bottom`: a strip placement that shares Top's
  auto-fit height math (`is_strip()`) and row machinery; only its slot in
  the frame differs (after the composer, before the footer). Its divider
  is the strip's top edge, so a drag on it inverts Top's delta; the body
  starts one row below the divider so row hitboxes stay honest.
- `bottom` is the default (`work_surface_placement`, `WorkSurfaceState`,
  `/rail on`, the rail hotbar toggle and Ctrl+Alt+0 all restore it) and
  the fallback for unknown values. Narrow terminals keep Bottom; only the
  side rails still fall back to Top below the side-rail width.
- `/config work_surface_placement bottom` is accepted; the error text
  lists the five placements.

Upgrade note: the default for `work_surface_placement` changes from
`left` to `bottom`. Users who set it explicitly are untouched.

Legacy ui/sidebar/mouse test fixtures pin `Top` because they assert the
old strip-above-transcript geometry; the Bottom default has its own
coverage (`bottom_placement_draws_the_work_strip_under_the_composer`,
`rail_panels_render_in_all_placements` now includes Bottom).

No goldens changed: the startup goldens carry no work rows, so the strip
is zero-height in both placements.

Evidence:
  scripts/dev-test.sh tui (cargo test -p codewhale-tui --lib):
    test result: FAILED. 11848 passed; 3 failed; 13 ignored
    (the 3 — runtime_api::omitted_runtime_models_use_the_active_provider_default,
    runtime_threads::approval_required_awaits_external_decision_allow,
    sandbox::seatbelt::file_provider_synthetic_operations_are_independent_under_seatbelt —
    are unrelated to this change and pass in isolation:
    test result: ok. 3 passed; 0 failed)
  focused rerun after the last edits:
    test result: ok. 11 passed; 0 failed; 0 ignored
  cargo clippy --workspace --all-targets -D warnings (CI allows): clean
Signed-off-by: CodeWhale Bot <bot@codewhale.net>

* fix(tui): the bottom strip keeps every other frame slot in place

Buildkite 1535 on #5809: two cucumber PTY tests against the real binary
failed under the new Bottom default — at 40x12 a queued message had no
`Queued #1:` preview, and the plugin acceptance stage stayed blank.

Cause: the Bottom layout dropped the strip's leading slot and re-ordered
the constraint list, but the stage, workflow panel, pending-input preview
and background chip are addressed by fixed slot index (`body_chunks[1..4]`),
so under Bottom they drew into the wrong, zero-height slots.

Fix: one nine-slot layout in both placements. The strip owns a slot at
each end (above the stage for `top`, under the composer for `bottom`) and
only one has height, so every other slot keeps its index. The dual
constraint list is gone.

Test: `bottom_placement_keeps_the_stage_and_queued_preview_at_twelve_rows`
renders a 40x12 frame under Bottom with a transcript row and a queued
message and asserts both paint.

Evidence:
  cargo test -p codewhale-tui --all-features --locked --test cucumber -- \
    active_composer_pointer_submit_queues_without_provider \
    plugin_toml_binary_lifecycle_skill_and_stdio_mcp_acceptance
    test result: ok. 2 passed; 0 failed; 0 ignored
    (before the fix, the pointer test failed exactly as on Buildkite:
     "40x12: queued preview ... not visible after pointer submit")
  cargo test -p codewhale-tui --lib -- work_surface tui::ui::tests
    test result: ok. 808 passed; 0 failed; 0 ignored
  cargo test -p codewhale-tui --lib -- bottom_placement
    test result: ok. 3 passed; 0 failed; 0 ignored
  cargo clippy -p codewhale-tui --all-targets -D warnings (CI allows): clean
Signed-off-by: CodeWhale Bot <bot@codewhale.net>

---------

Signed-off-by: CodeWhale Bot <bot@codewhale.net>
Co-authored-by: CodeWhale Bot <bot@codewhale.net>
Garfield1985 pushed a commit to Garfield1985/DeepSeek-TUI that referenced this pull request Sep 5, 2026
…umber hang, mobile smoke, release receipts)

- Windows warnings (§5.1): restructure link and error bindings in
  document.rs and runtime_api/tests.rs so variables exist only on targets
  that use them. Note: Windows CI cannot be run locally on this host.
- macOS PTY acceptance (§5.2): in plugin_e2e_acceptance, iterate over all
  marker match indices in review_confirmation_in_text rather than only the
  first, preventing false stalls on the composer's typed command echo.
  Full 31/31 cucumber tests passed.
- Mobile smoke (§5.3): update scripts/mobile-smoke.sh Test Group 3 to
  assert loopback security warning, matching the loopback-only hardening
  from e80be8c. 9/9 passed.
- Release-note receipts (§5.4): cite genuine issues (codewhale-hq#5533, codewhale-hq#5831, codewhale-hq#5825,
  codewhale-hq#5829, codewhale-hq#5801, codewhale-hq#5815, codewhale-hq#5826, codewhale-hq#5286, codewhale-hq#5809, codewhale-hq#5778, codewhale-hq#5725, codewhale-hq#5701, codewhale-hq#5712,
  codewhale-hq#5747, codewhale-hq#5782, codewhale-hq#4394) in CHANGELOG.md; filter commit-body scrape noise
  (#000, codewhale-hq#1, codewhale-hq#24, codewhale-hq#26, codewhale-hq#1834, #142352) in check-feature-release-notes.sh.
  check-versions passes in strict release mode (71 receipts checked).

Evidence:
- cargo nextest run --workspace --all-features --locked:
  14229 passed; 0 failed; 15 skipped
- cargo clippy --workspace --all-targets --all-features --locked -- -D warnings:
  clean (0 warnings)
- cargo test --workspace --all-features --doc --locked:
  3 passed; 0 failed; 8 ignored
- cargo test -p codewhale-tui --test cucumber --features long-running-tests --locked:
  31 passed; 0 failed; 0 ignored
- scripts/mobile-smoke.sh:
  9 passed; 0 failed
- scripts/release/check-versions.sh --require-dated-release:
  Feature release-note receipts OK (71 linked issues); Version state OK
- Python policy gates:
  check-provider-registry, check-command-crate-boundaries,
  check-dead-code-budget, check-runtime-contract-budget,
  check-readme-translations, check-tui-locale-parity all PASS
Garfield1985 pushed a commit to Garfield1985/DeepSeek-TUI that referenced this pull request Sep 5, 2026
…room, fleet roles

Launch / splash
- The launch stage now samples the ambient clock and asks for frames while
  the mark surfaces, the card dissolves, or the water is alive. Before, the
  only clock driver was the transcript widget, which the launch screen never
  builds: surface_progress stayed at 0 and the braille whale was painted in
  the field colour forever (codewhale-hq#1), and the ocean ramp / ambient life were never
  wired into the stage (codewhale-hq#2, codewhale-hq#3). The stage paints the same ramp and life the
  transcript does; the life field ends at the composer dock.
- Recent rows resume (codewhale-hq#4): AppAction::LoadSession never dismissed the launch
  stage, so a resumed session loaded under a still-visible card.
- Tab cycles the mode on the launch screen (codewhale-hq#5): ModeCycle is AnyShell. The
  card's rule now reads `model (effort) · mode · permission` so the cycle is
  legible and matches the posture bar (codewhale-hq#7).

Work bar
- One-time migration of a persisted `work_surface_placement = "top"` to
  `bottom` (codewhale-hq#9), recorded in `work_surface_bottom_migrated`.
- Idle scheduled automations no longer count as work that auto-opens the
  dock (codewhale-hq#10); live shells, tasks, or a running automation still do.
- ORDER / AUTO_ORDER lead with TODO, then AGENTS (codewhale-hq#11). The dismissed dock
  re-opens on new work in any auto view, and `← for agents` works from the
  TODO view. Golden dock_80x24 re-blessed for the order.
- The posture bar's live counts are click targets that open the dock view
  they count; with nothing live a dim `todo` chip is the bottom affordance.

/mcp, /plugin, Extensions
- /mcp and every MCP action open Extensions → MCP rebuilt from the live
  pool snapshot; the text pager and its formatter are deleted (codewhale-hq#17–codewhale-hq#19,
  codewhale-hq#25 — the `tools: 0` rows were the passive config snapshot).
- The markdown inline parser honours backslash escapes, so `computer\-use`
  renders as `computer-use` (codewhale-hq#21).
- Extensions keyboard follows grokbuild: Tab / Shift+Tab move across tabs,
  including mid-search with the query kept (codewhale-hq#22, codewhale-hq#23).

Automations
- New AutomationsView (`/automation`, `/automation show <id>`, the dock's
  background row): list + detail, p pause/resume, r run, x cancel the live
  run (via /task cancel), d delete (two-step confirm), Tab list↔detail.
  Every action is the typed command, so receipts match (codewhale-hq#14, codewhale-hq#16).
  `/automation list` and `print <id>` keep the text forms.

Fleet
- Roles are members. `add_fleet_model` requires a role (NeedsRole); the
  auto-enroll that turned every selected model into a role-less member is
  deleted with its 7 call sites; bare model pins are dropped on read so
  27 → 12 members (codewhale-hq#26). Picker ⇧F enrolls under `general`.
- Roster detail is role-first and compact (codewhale-hq#27, codewhale-hq#28); footer is
  ↑↓ · Enter · Tab workers · f · Esc (codewhale-hq#29). `m`, `s` and the model-picker
  shortcut event are removed.

Gates (run):
- cargo fmt --all -- --check: clean
- cargo clippy -p codewhale-tui -p codewhale-config --all-targets: clean
- scripts/dev-test.sh tui: 11658 tests run: 11658 passed, 13 skipped
- scripts/dev-test.sh tui-integration: 280 passed
- cargo test -p codewhale-config --lib: 634 passed; 0 failed; 1 ignored
- budget checks: dead-code 418/425, runtime-contract, provider-registry,
  command boundaries, migration manifest, locale parity (15 packs
  complete), product vocabulary: all PASS
- release build + tmux dogfood at 120x34: whale surfaces, ramp + fish on
  launch, Tab cycles mode, Enter on recent row resumes, dock closed at
  start and bottom/TODO-first when opened, /mcp opens Extensions with live
  tool counts, /automation opens the room, fleet shows 12 role members.
Not run: cargo nextest --workspace, tui-cucumber, web rung (no web change).

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Hmbown pushed a commit that referenced this pull request Sep 16, 2026
…or say what is actually wrong

`scripts/release/check-versions.sh` runs on **every** release path — release.yml:107,
auto-tag.yml:102, release-candidate.yml:73 — and outside the advisory set, so
these two failures blocked any 0.9.14 tag.

**crates/memory pinned its own version and MSRV.** Check #1 forbids a literal
`version = "..."` in any `crates/*/Cargo.toml` and check #2 requires
`rust-version.workspace = true`; the vendored crate did both wrong. It now
inherits. The MSRV change is a semantic no-op — the literal was `1.88` and the
workspace MSRV is `1.88`. The version moves 0.2.0 -> the workspace version,
which has no external meaning for a `publish = false` crate and is the
convention every other crate here follows. `check-versions.sh` now passes
everything except the changelog sync.

**The publish-order validator demanded an unpublishable crate.** `release_names`
collected every `codewhale-*` workspace package with no `publish = false`
filter, so it required `codewhale-memory` to appear in `crates.sh` — a
contradiction, since `crates.sh` drives `cargo publish`, which refuses a crate
marked unpublishable. `cargo metadata` renders `publish = false` as an empty
registry list, so the filter is exact.

That fix does not make the problem disappear; it makes the validator report the
real one. `validate-crate-publish-order.test.sh` now fails with
"codewhale-tui depends on workspace crate codewhale-memory [normal], which is
not in the codewhale-* release inventory" instead of the misleading "mixed
versions". That message is correct and the condition is genuine: `cargo publish
-p codewhale-tui` cannot succeed while a **normal** dependency is absent from
crates.io. Resolving it is a decision, not a cleanup — publish
`codewhale-memory`, feature-gate the dependency, or stop publishing
`codewhale-tui` — so it is filed rather than guessed at.

Tests: `bash scripts/release/validate-crate-publish-order.test.sh` — its
hermetic fixtures pass; its final live-workspace block now reports the real
dependency problem rather than the version one. `bash
scripts/release/check-versions.sh` — the only remaining error is
`crates/tui/CHANGELOG.md is out of date`, which is a separate commit.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Signed-off-by: CodeWhale Bot <bot@codewhale.net>
Hmbown pushed a commit that referenced this pull request Sep 16, 2026
`crates/memory` moved from a literal `version = "0.2.0"` to
`version.workspace = true` in the previous commit so it would satisfy
`check-versions.sh` check #1. Cargo.lock still recorded 0.2.0, which made every
`--locked` invocation refuse to proceed:

    error: cannot update the lock file ... because --locked was passed

That took out `scripts/release/check-ohos-deps.sh` (its `cargo tree` retried
three times and failed) and would have taken out CI's "Lockfile drift guard"
step, which is `git diff --exit-code -- Cargo.lock`.

Regenerated offline. One line changed: `codewhale-memory` 0.2.0 -> 0.9.13. No
dependency was added, removed or bumped.

`bash scripts/release/check-ohos-deps.sh` passes again.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Signed-off-by: CodeWhale Bot <bot@codewhale.net>
Hmbown pushed a commit that referenced this pull request Sep 17, 2026
…assification (determinism audit batch 2, #1)

The auto_reasoning keyword classifier (debug/error -> Max, search/lookup ->
Low, plus CJK/JP lists) made cost and answer quality depend on vocabulary.
auto now resolves the declared High default everywhere: turn loop,
route planner, CLI/exec paths, runtime threads, and subagent assignment.
The prompt plumbing through the spawn-route functions is deleted with it
(-375/+106); select() is the seam a model-declared escalation hint lands in.

Tests: auto_reasoning/resolve_auto_effort/cli_auto/model_routing filters
47 passed, 0 failed; tools::subagent 672 passed, 1 failed where the single
failure (issue_5305 untethered fail-closed) also fails on clean HEAD and is
unrelated to this change. clippy --all-targets clean, fmt clean.
mwl1023-byte pushed a commit to mwl1023-byte/AsBudy that referenced this pull request Sep 21, 2026
引擎早就会收图(POST /v1/threads/{id}/turns 的 images:[{mime,dataBase64}]、三种 wire 格式
都投影好了),官方 web 一个字没做 —— 属铁律 codewhale-hq#1 的「搬表」。

做法:只猴补 window.fetch,认 POST /turns 时把 images 拼进 body,官方发送逻辑一个字没改
(流式与乐观 UI 全照旧)。取图三处:按钮 / 粘贴 / 拖入。校验照引擎口径(PNG/JPEG/GIF/WebP、
单图 4MiB、总 5MiB、最多 10 张)。能力判定照引擎口径:只认明确 supported,auto 当不支持,
拿不到会话时是 unknown(不猜、不假装支持)。

只发图不打字会被引擎拒(prompt 不能为空),而输入框空时官方发送按钮本来就是灰的
—— 所以改成选完图就提示,不拦按钮点击(disabled 按钮根本不发 click 事件,实测)。
Lstarsky0 pushed a commit to Lstarsky0/CodeWhale that referenced this pull request Sep 23, 2026
The negated-keyword check matched only `#N`, so "Refs codewhale-hq#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 codewhale-hq#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>
Hmbown pushed a commit that referenced this pull request Oct 1, 2026
In a shared process the events golden drifted in parallel_tool_calls: its
operation_activity span ids read #11/#12 against the recorded #2/#3 (whole
codewhale-tui lib, three of three parallel runs; passes alone). Span ids end
in a process-wide sequence so a consumer can deduplicate spans, and the
goldens carry the numbers of one pass over the cases in an idle process
(one_tool_call #1, parallel_tool_calls #2 and #3). Every span another test
started in between shifted them. On the last hosted shared-process run this
was hidden behind the earlier registry-count drift.

The events replay now numbers spans from a thread-scoped sequence starting at
1 (test builds, unix only); production keeps the process-wide counter. No
golden changes.

Evidence: conformance:: 13 passed; 0 failed alone; whole codewhale-tui lib in
one process: test result: ok. 14479 passed; 0 failed; 22 ignored. Drift
captured in batch11/parallel-golden-drift.diff.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: CodeWhale Bot <bot@codewhale.net>
Hmbown pushed a commit that referenced this pull request Oct 16, 2026
… the user sends them

Refs #6978, CW-7427. @SergiuSSoluS reported that the same three old messages
were answered again at every launch. The cause, traced in the thread: a
session's parked queue file
(sessions/checkpoints/<id>.offline_queue.json) was restored at launch, and
its messages went out one by one after the user's next message. On their
Windows machine the file's clear never reached disk, so every launch
replayed them. The launch packet (codewhale-ops item 22) recommends not
auto-sending restored messages. This implements that conservative default.
It is reversible, and nothing ships until the next release; 0.10.2 is
frozen.

What
- App.held_restored_queue counts the restored messages at the front of
  queued_messages.
  - restore_matching_offline_queue_state sets it to the restored count. That
    covers launch, --continue, /resume and every other session transition
    that installs a parked queue.
  - pop_queued_message, the only auto-dispatch (after TurnComplete), now
    takes the first message after the held ones. Messages queued in this
    session still send in order, ahead of held ones.
  - remove_queued_message (/queue send <n>, edit <n>, drop <n>) decrements
    the count when it removes a held message.
  - restore_queued_message re-inserting inside the held range increments
    it.
  - ↑ (pop_last_queued_into_draft) clamps it.
  - The double-tap steer drain, /queue clear, the session transition clear
    and /new reset it to 0.
- The restore notice now says the messages are not sent automatically and
  names /queue send <n> and /queue clear. It is also written to the
  transcript: a resume's "Resumed session" status replaced the toast, which
  is why the reporter never saw it. All 15 locale packs are updated.
- docs/ARCHITECTURE.md and the zh_hans twin (offline queue, item 4), and a
  CHANGELOG [Unreleased] bullet with the known limit: ↑ then Esc on a held
  message puts it back as an ordinary queued one.

Verification
- Real TUI (isolated tmux socket and HOME, local mock gateway). One turn,
  /quit. A parked queue file for that session with "queued alpha" and
  "queued beta". Then `codewhale --continue`, "fresh message", /queue,
  /queue send 1, /queue.
  - Before (installed 0.10.2, 91dbd4f): the mock received "fresh
    message", then "queued alpha", then "queued beta", all in the same
    second, with no user action. The transcript shows all three.
  - After (this tree): transcript note "Restored 2 queued message(s) from
    an earlier session. They are not sent automatically: /queue send <n>
    sends one, /queue clear discards them." Only "fresh message" was sent.
    /queue listed both. /queue send 1 sent "queued alpha". Beta stayed
    queued after alpha's turn ("Queued #1: queued beta").
- scripts/dev-test.sh tui queue offline_queue session_state dispatch
  tui::app tui::ui commands::tests commands::groups::core: 2061 tests run:
  2061 passed (after the transcript-note edit; the earlier run of the same
  filters also passed). Localization: 54 passed.
- CI-form clippy (workspace, all targets, all features, -D warnings with
  the CI allows): exit 0, no warnings. cargo fmt --check: clean.
- npm test: root 101/101, runtime-sdk 19/19, extension-host 420 (413 pass,
  7 skipped), web 7/7, vitest 772/772. npm run check:web: exit 0. npm
  --prefix web run prebuild regenerated web/data/agent-docs.generated.json
  for the ARCHITECTURE line.
- sync-changelog --check: up to date. check-versions
  --require-dated-release: OK.

Not verified: Windows, and the reporter's 99 MB session. The probe wrote
the parked queue file itself, in the format the app writes; the reporter's
underlying "clear never reaches disk" write failure is not fixed here, only
made harmless. Seen while probing and not chased here: `codewhale --continue`
after a killed TUI printed "Recovered interrupted session" and then refused
with "session ... is open in an interactive Codewhale session"; the
process-local live registry treats its own recovered session as live.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NBKbhx19BRbZtvWK8rVKjz
Hmbown pushed a commit that referenced this pull request Oct 22, 2026
Review exists to stop bad changes from merging at the lowest cost in human
attention, and nothing measured either. #1 asks for a corpus built from our
own history and a replay that asks, of each pull request that introduced a
bug we later fixed, whether the reviewer would have caught it before merge.

scripts/review-eval.mjs, one command, no model spend in the corpus half:

- corpus: walks non-merge fix commits, blames each changed old line to the
  commit that introduced it, resolves that commit to its pull request, and
  keeps the case only when the replay is actually possible. Four checks do
  the filtering, and each drop is counted rather than skipped silently:
  the pull request head must be fetched from refs/pull/N/head; the
  introducing commit must be an ancestor of that head (a "(#1234)" subject
  can name another repository's pull request); the blamed line must exist at
  that head; and the line must be one the pull request itself added,
  compared against base..head, so a fix that touches pre-existing code is
  not scored as a missed defect. Oversized pull requests and non-code paths
  are excluded, both counted.
- replay: runs a named reviewer over the corpus. `hosted-floor` calls the
  control plane's deterministic reviewer in-process (free, no model);
  `cli` runs the released binary's `codewhale review --json` with an
  optional money cap that stops the run and says so; `skill` runs the
  `/review` instructions through `exec`. Each case is written as its own
  JSON record so a rerun resumes past finished work and a partial run is
  auditable.
- grade: recall at a line window and at same-file, claims and words per
  case (the attention-cost inputs), wall time, estimated cost from usage
  and an optional per-million rate, and a failure count. `report` diffs two
  grades so a later issue can state its delta on the same corpus.

Checks: node --check passes; the corpus was built over 3363 fix commits and
15774 hunks from 2026-07-01 and the free deterministic-floor baseline was
graded over it. The model-backed baselines for `cli` and `skill` are NOT run:
#1 requires a founder-approved route and budget, and there is no approved
eval budget, so this stops at the free baseline and asks rather than spending.

Refs CW-7503, codewhale-agent #1
Hmbown pushed a commit that referenced this pull request Oct 22, 2026
…s whether it applied

#7: a docs typo and a billing migration were reviewed with the same fixed
effort. `tools/review_triage.rs` now sets the budget from the diff alone,
before any model call:

- triage is a path and size read: sensitive paths (auth, billing, payment,
  migrations, crypto, secrets, permission/policy, sandbox, locking,
  deletion, schema) or a change of 400+ lines / 20+ files is high risk; API,
  route, server, config, database, storage and contract paths or 80+ lines /
  6+ files is medium; everything else is low. Every reason is kept, so a
  receipt can explain its own tier instead of asserting one.
- budget: low risk gets one step and no repository tools (the diff still
  gets reviewed), medium gets 4 steps and 6 tool calls, high gets 6 steps
  and 12 calls, with an output-token ceiling per tier.
- the money cap is `--money-cap-usd` with `--input-usd-per-mtok` and
  `--output-usd-per-mtok`. A cap without a price cannot be enforced, so
  `money_limit_supported` stays false and the receipt reports the cap as
  unsupported rather than implying it ran out. The core checks the cap
  before each model step and again at the end.
- a stop is named: money_cap, step_budget, tool_budget, output_limit or
  model_failure, and the summary carries a partial-review note naming the
  limit that stopped it and saying plainly that unreached files were not
  reviewed and are not thereby correct. It is never a silent truncation.

Triage, budget, stop and spend travel on the tool metadata and the CLI JSON,
so the same review can be audited after the fact.

Checks: scripts/dev-cargo.sh check -p codewhale-tui --lib clean;
scripts/dev-cargo.sh test -p codewhale-tui --lib tools::review = 80 passed,
0 failed (6 new triage tests: docs-low vs billing-migration-high, size and
sensitive paths raising the tier independently, a cap without a price
reported unsupported, cost over every billable counter, and the partial
note naming its limit).

Not claimed: cost per corpus pull request is not yet shown to fall with no
recall loss, because the model-backed baseline is blocked on an approved eval
route (see #1). The free deterministic-floor baseline is unaffected by this
slice, since it never calls the core.

Refs CW-7503, codewhale-agent #7
Hmbown pushed a commit that referenced this pull request Oct 22, 2026
…tracts and the summary shape

Four issues that share one schema change, because they are four questions
about the same claim: what did it mean to do, what did it break, how do we
know, and should you merge.

#5 — intent is checked, not obeyed. `ReviewIntent` (title, description,
commit messages, linked issue) travels as a named field of one untrusted
JSON document, never as prose. The old `commit_intent_preamble` that spliced
commit messages into the prompt body is deleted, and the PR prompt no longer
embeds the description when the core carries it, so the author's claims exist
once and in a field labelled as claims. The prompt asks for `kind: intent`
when what the code does differs from what it says, in either direction:
named and missing, or done and unannounced.

#4 — changed contracts. `kind: contract` claims carry `became` (what the
change made newly true or false) and `dependents_checked` (every dependent
the reviewer looked at, including the ones that turned out fine). The
dependents use the read-only tools the core already had; no index was built,
because the corpus has not shown search to be the recall bottleneck.

#6 — evidence tiers. Every claim carries `reproduced`, `traced` or
`suspected`. A `reproduced` or `traced` claim without a detail is demoted,
not trusted: the tier is a claim about evidence and an empty one is no
evidence. Suspected claims leave the posted findings entirely and become the
summary's "worth a human look" list, capped at three. A second model call
with the same read-only tools then tries to refute each remaining claim; it
can grade a claim `stands`, `refuted` or `unproven`, and it can add nothing,
so the pass can only shrink a review. It runs on high-risk changes, where the
budget already bought repository tools.

#9 — the summary shape, one renderer for every forge:
`render_review_summary` leads with merge risk and its reason, states what was
not reviewed before the findings, prints each finding with its evidence tier
and its changed contract, then what was verified, then the assessment. It does
not restate the diff. `ForgeMarkdown` carries the one capability that changes
the rendering: GitHub gets committable `suggestion` fences, a forge without
them gets a fenced diff, and the two bodies are byte-identical otherwise.
`render_review_markdown` now delegates to it, so the Engine has one renderer
rather than two.

Schema compatibility: every new field is optional with a default, so receipts
and model output written before this change still parse; `kind` reads as
`defect` and a missing tier reads as `suspected`.

Checks: scripts/dev-cargo.sh check -p codewhale-tui --lib clean;
cargo fmt -p codewhale-tui --check clean;
scripts/dev-cargo.sh test -p codewhale-tui --lib tools::review = 82 passed,
0 failed. Four new tests: the core moves a suspected claim out of the posted
findings into the summary; the summary's section order and evidence rendering;
GitHub vs no-suggestion-forge bodies identical except the suggestion block;
the severity scale. Updated the core tool-loop fixture to carry a traced and a
suspected claim rather than one bare one.

Not claimed, and why: #6's "calibration at least 90% for reproduced and
traced claims" and #4's "recall improves on the corpus" and #5's "precision
does not fall" are all measured quantities, and the model-backed corpus run is
blocked on an approved eval route and budget (#1). `refute = true` is the
high-risk path; whether it raises precision is the next number to measure, not
something this commit asserts.

Refs CW-7503, codewhale-agent #4 #5 #6 #9
Hmbown pushed a commit that referenced this pull request Oct 22, 2026
…author, and the tally is machine readable

Two mechanisms from the competitive research note
(docs/research/competitive-code-review-20261022.md), plus the negative result
that makes a review's silence meaningful.

**Authorship is decided mechanically, never by the model.** `introduced_lines`
computes the lines this change actually added from the diff, and
`apply_claim_limits` sets `authorship` on every claim from it. A model that
labels its own accusation "pre-existing" is overruled. Three cases:
- the anchor is an added line → `introduced`;
- the anchor is inside a hunk but not added (unchanged context) → `preexisting`,
  because the code was already there;
- no usable anchor → `preexisting`, because we cannot prove this change wrote
  it and an accusation we cannot support is worse than a label we can.

**A pre-existing defect cannot hold the merge risk up on its own.** If every
claim is pre-existing, the finding signal is zero and the level is set to low,
keeping the model's reason and prefixing why. Enforced inside
`apply_claim_limits`, the one place claims are adjudicated, so every caller
inherits it. Structural risk from triage is separate and untouched.

**Pre-existing claims are never inline comments.** `inline_issue_comments`
skips them, so the author is not handed an inline accusation for code they did
not write; the summary renderer gives them their own section, after the
findings this change introduced.

**`ruled_out`: the negative result.** What the reviewer checked and found
sound, one line each, capped at five, rendered under "Checked, nothing wrong".
Distinct from `verified` (what established a claim) and from `not_reviewed`
(what was not looked at). It never carries a claim and never affects merge risk.

**A machine-readable tally.** Every summary ends with
`<!-- codewhale-review: {"blocker":N,"concern":N,"nit":N,"introduced":N,"preexisting":N} -->`
— integers and closed enums only, asserted by a test that feeds paths and prose
through it and checks neither appears.

Also: `inline_anchorable` is recorded per claim, so a claim whose line is not in
the diff is marked rather than assumed — the publisher turns that into the body
fallback.

Schema compatibility: every new field is optional with a default; `ruled_out`
and `authorship` are absent from older receipts and read as empty and
`introduced`.

Checks: `scripts/dev-cargo.sh check -p codewhale-tui --lib` clean; rustfmt
clean on the changed files; `scripts/dev-cargo.sh test -p codewhale-tui --lib
tools::review` = 86 passed, 0 failed, including four new tests: authorship
decided from the diff while the model's own label is overruled; an unanchorable
claim kept and marked instead of dropped; pre-existing findings alone forcing
merge risk to low while the model's reason survives; and the summary's section
order plus a tally that parses as JSON and contains no path.

Not claimed: the corpus delta. #18's done-when includes behaviour on real pull
requests, and the model-backed corpus run is still blocked on an approved eval
route and budget (#1).

Refs CW-7503, codewhale-agent #18 #19
Hmbown pushed a commit that referenced this pull request Oct 22, 2026
…ar the release gates

The 0.10.2 CHANGELOG stopped at 8bb5cc0; eighteen commits landed after it
with no receipt, including a security fix and a breaking settings change.

- Latest fixes: tool-call argument redaction, same-host provider redirects
  and the wider IPv6 network guard, bounded MCP template cache and
  fail-closed prefix allow rules (d1fd6f1, 38d7a09); the non-Latin
  auto-review crash (26155e9, #7048, credited to @8sero on all three
  credit surfaces); Computer Use consent in Full Access (ad697b3); the
  16 MiB plugin state limit (1d44435).
- Added: the shared review core, risk-scaled budgets, money cap, evidence
  tiers, refutation pass and pre-existing labelling (CW-7503: 42b7d19,
  0ab0d4a, 1f40f4b, 5573bab).
- Changed: transcript_spacing is compact | spacious, spacious default
  (39621ff).
- The release date moves from 2026-10-19 to 2026-10-22; 0.10.2 is untagged.

Gates:
- check-feature-release-notes.sh: the CW-7503 commits cite issues in the
  private codewhale-agent repository as bare #4 #5 #6 #7 #9 #16 #18 #19 and
  quote "(#1234)" as an example. Codewhale's own #4-#19 are March/April
  roadmap items and #1234 an input-box request, none of them this work, so
  they join the existing false-positive skip list (which already holds that
  repo's #1).
- check-contributor-credit.py: "Codewhale Agent <agent@codewhale.dev>" is the
  project's automation identity (CW-7495), so it joins "codewhale bot" in the
  bot skip set.

Checks: scripts/release/prepare-release.sh 0.10.2 exit 0 (receipts OK, 17
linked references; Version state OK workspace=npm=npm-binary=0.10.2,
lockfile in sync; OHOS linker, graph and bindgen OK);
scripts/check-contributor-credit.py exit 0; scripts/sync-changelog.sh
regenerated crates/tui/CHANGELOG.md. No compile: docs and scripts only.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
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.

1 participant