Skip to content

Land asto18089's queue as itself: #6736, #6737, #6738, #6740, #6742, #6743, #6744 - #6799

Open
Hmbown wants to merge 26 commits into
mainfrom
integration/asto-queue-20260930
Open

Hmbown wants to merge 26 commits into
mainfrom
integration/asto-queue-20260930

Conversation

@Hmbown

@Hmbown Hmbown commented Sep 30, 2026 •

Copy link
Copy Markdown
Owner

Lands seven of @asto18089's open PRs as themselves.

  • The fork's branches refuse maintainer pushes: HTTP 403, even though "allow edits" is on. Per cw-land, the fixes their hosted checks needed are resolved here on an integration branch instead of on their branches.
  • Each original PR head is merged unmodified, so every original commit keeps its author and lands as-is. GitHub marks each PR merged once its head is reachable from main. Nothing is harvested or rewritten.
Original PR Head merged What it does
#6736 8dad739155 Actionable error when every search backend is unavailable
#6737 6cf3732a88 Basename source labels for project instructions and constitution (author qiuYliangM)
#6738 ec246ab063 Stopship scout routes through tool_search → deferred grep_files
#6740 00db31a62b The idle watchdog stays patient while a tool call is in flight
#6742 0823390658 Vision requests are bounded by one 30-minute envelope with a separate connect deadline
#6744 bf7df01a9 TurnStarted echoes the host's submission id (additive, default-absent; every self-started turn carries none)
#6743 6372cbc3f js_execution gets a 600-second budget, and a timed-out interpreter is killed with everything it started

Maintainer fixes on top. Each one is a hosted failure from the original PRs:

Evidence (local, exact branch head, macOS arm64, governed build slots)

  • check-contributor-credit.py: 12 contributors, each credited on all three surfaces.
  • Credit consumers (vitest public-copy + public-surface-contract): 18 passed; 0 failed.
  • Focused TUI (tools::web::backend, project_context, context_report, task_manager::, vision::tools, the stopship/scout tests): 204 passed; 0 failed; 1 ignored.
  • Workflow crate js_authoring: 10 passed; 0 failed.
  • Causal control: the old nonexistent scope path was restored in workflows/stopship.workflow.js. The acceptance test then failed with explore-runtime scopes a file that does not exist: crates/tui/src/tools/workflow.rs. The file was restored byte-exact, and the restored run passed.
  • Workspace CI-policy Clippy: see the commit receipt.
  • fix(tools): kill the js execution child when its timeout fires and raise the cap #6743 at c1957a839 (Node v26.10.0): tools::js_execution:: 11 passed; 0 failed.
    • Causal control: contained_output was replaced by a bare cmd.output(). The run gave 9 passed; 2 failed: fix(tools): shell job retention, output deltas, and child process lifetimes #6759's dropped_js_execution_kills_the_interpreter_tree and the contributor's timeout_kills_the_node_child_instead_of_orphaning_it. Byte-exact restore, then 11 passed; 0 failed.
    • Workspace CI-policy Clippy passes, and so do cargo fmt --check, git diff --check and the blocking-call budget (754 sites, within budget).
    • The earlier attempts are kept as receipts: the blocking poll (10 passed; 1 failed), then two eprintln! skips that clippy::print_stderr rejects.

Not in this PR:

Those PRs stay open as themselves.

No-Issue: contributor queue integration for #6736, #6737, #6738, #6740 and #6742; each PR carries its own motivation.

  • feat(engine): echo host submission id on TurnStarted #6744 at e129f2975 (merged unmodified, then test(runtime): a runtime_threads fixture that reached main after feat(engine): echo host submission id on TurnStarted #6744's base built TurnStarted without the new field (E0063). It carries None like every runtime start.)
    • Focused engine, parity, submission and turn-start tests, remote control, pet watch, exec and context report: 783 passed; 0 failed; 4 ignored. Protocol crate: 1 passed; 0 failed.
    • The launch-card PTY suite on the merged head: 10 passed; 0 failed; 6 ignored. The scenario that failed on feat(engine): echo host submission id on TurnStarted #6744's old hosted Linux run passed 3/3 on main and 3/3 on main+feat(engine): echo host submission id on TurnStarted #6744 locally (macOS). This PR's exact-head Linux run is the arbiter.
    • Causal control: TurnStarted stopped echoing the token. turn_started_echoes_submission_id_and_self_starts_stay_none failed (0 passed; 1 failed). Byte-exact restore, then 1 passed; 0 failed.
    • Workspace CI-policy Clippy passes. cargo fmt --check, git diff --check, the changelog mirror, the blocking-call budget (754 sites) and the runtime-contract budget (55 metrics exact) all pass.

🤖 Generated with Claude Code

asto18089 and others added 18 commits September 29, 2026 14:35
When every configured search backend fails, the tool surfaced only the
bare backend id list, leaving no path back to a working configuration.
Append a configuration hint that names the keyed providers and their
environment-variable aliases, the SearXNG base_url requirement, and the
keyless firecrawl/bing routes. The hint is static text, so the existing
no-private-details guarantee of the message is preserved and now pinned
explicitly.

Adapted from the Pinvou fork (Pinvou/CodeWhale 1fafee7), extended for
the serply and tavily providers.

Signed-off-by: asto18089 <asto18089@126.com>
…labels

The <project_instructions source="..."> label carried the absolute path
of the loaded AGENTS.md. The label sits inside the pinned system prompt,
so loading an unchanged file from a moved or recased directory rewrote
the label and emitted a spurious <context_update> history append, and it
leaked the absolute project path into a provider-bound prompt label.

The label now reports the file name only, via a shared
project_instructions_source_label helper used by both
ProjectContext::as_system_block and the /context report's rendered
block (the report entry keeps the absolute path for operators). The
repo-constitution block, which sits in the same pinned region and always
resolves a fixed relative path, gets the same file-name convention; its
locator stays available via constitution_source_path and /constitution.

Directory identity is discoverable at runtime via the shell; the label
is an origin tag, not a locator. Regression tests pin byte-identity of
the instructions block for identical content loaded from two different
directories and forbid absolute paths in both provider-bound labels.

Adapted from the Pinvou fork (Pinvou/CodeWhale 102da17, PR #59) onto
the current project_context layout.

Co-authored-by: qiuYliangM <185303122+qiuYliangM@users.noreply.github.com>
Signed-off-by: asto18089 <asto18089@126.com>
…_files

The read-only scout brief commanded a `File` call with `action`
`search_content`, but `File` is a hidden replay-only alias
(`model_visible=false`): it never reaches a model-visible catalog, and
the child step loop fails any call outside the child's policy-filtered
catalog outright. The release-acceptance explore gate's first step
therefore could not succeed; dispatch-by-alias only worked below the
catalog gate (replay tests calling `registry.resolve` directly).

Route the scout through the live surface instead: response 1 activates
the deferred `grep_files` with one `tool_search` call, response 2 runs
the same alternation search through `grep_files`, and response 3
returns the verdict. The step and token caps are unchanged; the
evidence turn grows one small activation response. The leaf's explicit
`allowed_tools: ["File"]` is dropped — the read-only lowering already
scopes the leaf, and its alias-family intersection is what keeps
`grep_files` discoverable.

Guard both halves so neither side silently drifts again: a surface test
pins the scout catalog to an active `tool_search` plus a deferred,
searchable `grep_files` with no `File`; a behavioral test drives the
activation through the real dispatch gate; and the fixture guard now
pins the three-response contract and denies catalog-invisible tool
names in the brief.

Adapted from the Pinvou fork (Pinvou/CodeWhale 92427bd, PR #61).

Signed-off-by: asto18089 <asto18089@126.com>
A host submitting a turn through the in-process engine
(Op::SendMessage / Op::EditLastTurn) can attach an optional
process-local correlation token, submission_id, and the engine echoes
it verbatim on that turn's TurnStarted event. An embedder that defers
submit-window actions (e.g. a stop replay) binds them to the turn
that actually started instead of the first TurnStarted to arrive:
every engine self-started turn (idle sub-agent continuation,
background shell wake, goal continuation) and the composer shell
command turn emit None, so their start can never be mistaken for the
host's pending submission even when it overtakes it in the event
stream.

The change is additive and wire-compatible both ways:
EventMsg::TurnStarted gains submission_id: Option<String> with
serde(default) + skip_serializing_if, so old consumers parse new
events and vice versa. The token stays on the internal TurnSpec only:
the wire Op projection deliberately drops it and the durable-runtime
submission path carries none, matching the in-process handle scope.
The protocol-parity guard now asserts a stamped token crosses the
Event -> wire projection verbatim; engine tests pin the echo
contract, the edit replay's own token, and a real self-start
staying None.

Signed-off-by: asto18089 <asto18089@126.com>
…ight

The journal records a tool call only at start and completion — nothing
in between — so the background task's idle-progress deadline ran
unopposed during any silent build, test suite, or MCP call and killed
healthy work at the idle limit (120s by default).

Track in-flight tool items by their journal id across the
started/completed edges. While at least one tool is running, the turn
loop refreshes the idle clock and publishes a supervisor-side
ToolHeartbeat on the task-event channel, because the worker
supervisor's own guard feeds from that channel and cannot see the
journal-derived set. The heartbeat is liveness-only: it is excluded
from persistence (it would rewrite the whole task record ~5x/s during a
silent build) and from the visible timeline.

The wall-time budget remains the backstop for a genuinely hung tool,
and a turn with no in-flight tool still trips the idle deadline exactly
as before. Disclosed gap: a background task mid-context-compaction is
still invisible to the set (compaction emits no tool item and has no
heartbeat of its own).

Adapted from the Pinvou fork's timeout audit (Pinvou/CodeWhale
d349f25, PR #63 review series).

Signed-off-by: asto18089 <asto18089@126.com>
…iant

Signed-off-by: asto18089 <asto18089@126.com>
…lope

The image_analyze tool built its reqwest client with a single
client-level 120-second timeout covering the whole call: connect, the
multi-MB base64 upload, the full non-streaming vision generation, and
the body read. A slow-but-healthy provider doing legitimate incremental
work was killed at 120s with no distinction between "stalled" and
"still working".

reqwest's read_timeout is not a per-read idle bound for the request
phase — its timer starts at send() and never resets until the response
headers arrive — so an idle-read split cannot express this. Instead:

- the client now bounds only the connect handshake (10s);
- one tokio::time::timeout envelope (30 minutes, the same wall clock as
  engine streaming, STREAM_MAX_DURATION_SECS) wraps the request, all
  retry attempts, and the body decode as the sole total bound;
- the timeout surfaces as ToolError::Timeout, which drives the existing
  TimedOut classification instead of a generic failure;
- the envelope is scaled to 2s under cfg(test) so the new wiremock
  tests pin it without real time.

Tests: a stalled provider hits the envelope and reports a timeout; a
timely answer is returned intact. Full vision suite 59/0.

Adapted from the Pinvou fork's timeout audit (Pinvou/CodeWhale
d349f25 and its vision follow-ups, PR #63 review series).

Signed-off-by: asto18089 <asto18089@126.com>
…ise the cap

`execute_js_execution_tool` ran the interpreter as `timeout(120s,
cmd.output())`: when the 120 seconds elapsed, tokio dropped the wait
future WITHOUT killing the spawned child, so Node kept running detached
— holding CPU, files, and pipe write-ends — while the tool reported a
timeout. The 120s cap itself was also short for legitimate scripts
(builds, report generation).

Spawn the child under our ownership instead: it leads its own process
group on Unix so the timeout kill reaches scripts that spawned their
own children, `kill_on_drop` remains the backstop when the whole tool
future is dropped (turn interrupt), and stdout/stderr are drained
concurrently with the wait so a script blocked on a full pipe buffer
still exits. On timeout the process group is SIGKILLed, the child is
reaped, and the drain tasks are aborted. The cap is raised 120s → 600s.

Tests pin the kill itself: a Node child that reports its pid and sleeps
is verifiably dead after the timeout error, and a grandchild holding
the pipes cannot make the call hang past the budget.

Adapted from the Pinvou fork's timeout audit (Pinvou/CodeWhale
d349f25, PR #63 review series).

Signed-off-by: asto18089 <asto18089@126.com>
Hosted Lint failed only on this array formatting (backend.rs:852).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: CodeWhale Bot <bot@codewhale.net>
…dits

Signed-off-by: CodeWhale Bot <bot@codewhale.net>
The Version drift job failed `scripts/check-contributor-credit.py`:
@asto18089's commits need all three credit surfaces. CONTRIBUTORS.md and
CHANGELOG.md already name them; web/lib/release-credits.ts did not.
Local: credit check "11 contributor(s) ... credited on all three surfaces";
vitest public-copy + public-surface-contract 18 passed / 0 failed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: CodeWhale Bot <bot@codewhale.net>
Original authorship preserved; lands as its own commits.

Signed-off-by: CodeWhale Bot <bot@codewhale.net>
Original authorship preserved; lands as its own commits.

Signed-off-by: CodeWhale Bot <bot@codewhale.net>
Original authorship preserved; lands as its own commits.

Signed-off-by: CodeWhale Bot <bot@codewhale.net>
Original authorship preserved; lands as its own commits.

Signed-off-by: CodeWhale Bot <bot@codewhale.net>
Hosted Lint on #6737 failed only this import order (project_context.rs:27).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: CodeWhale Bot <bot@codewhale.net>
#6738 failed all three OS test jobs at tools/workflow/mod.rs:11084: the
acceptance test still required an explicit non-empty scout allowlist, which
#6738 deliberately removed so the read-only catalog (tool_search -> deferred
grep_files) scopes the scout. Assert that shape instead (`None`, pinned by
scout_surface_keeps_tool_search_grep_files_activation_path).

The scout's grep include and every role's file_scope named
crates/tui/src/tools/workflow.rs, which does not exist (the module is
tools/workflow/mod.rs), so the search could never see the owner it cites.
Correct the path in the workflow, its js_authoring assertions and the parity
doc, and assert every scoped file exists so the path cannot rot silently.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: CodeWhale Bot <bot@codewhale.net>
…edits

check-contributor-credit.py: every contributor credited on all three surfaces.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: CodeWhale Bot <bot@codewhale.net>
Copilot AI balanced review requested due to automatic review settings September 30, 2026 14:30

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

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

…ntity

Hosted Lint on #6799 failed check-runtime-contract-budget.py: the representative
project-authority stage identity changed. That is #6737's intended change:
project-instruction and constitution source labels become repository-relative
instead of absolute paths. The stage also shrank 7617 -> 7605 bytes. Recorded
with the script's documented `--update --allow-increase` from its own
measurement; no other metric moved.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: CodeWhale Bot <bot@codewhale.net>
CodeWhale Bot and others added 4 commits September 30, 2026 09:48
#6759 already runs js_execution through process_tree::contained_output, so
the PR's hand-rolled spawn, pipe drains and process-group kill resolve to
that shared primitive (which also gives Windows its Job Object). Kept from
the contributor: the 600 s budget (5 s under test) and both regression
tests — the timed-out Node child is killed, not orphaned, and the timeout
returns promptly while a grandchild holds the pipes.

The contributor's commit 6372cbc is an unmodified parent, so #6743 lands
as itself.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: CodeWhale Bot <bot@codewhale.net>
Brings in main through #6759 and 9507c4c, where #6743's unmodified head
6372cbc resolves onto main's contained js_execution with the
contributor's 600 s budget and both regression tests. With this, #6743
lands as itself alongside #6736/#6737/#6738/#6740/#6742; @asto18089 is
already on the unreleased credit line of this branch.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: CodeWhale Bot <bot@codewhale.net>
#6743's kill test polled with std::thread::sleep inside a current-thread
tokio test. On main's contained_output path the timed-out child is
SIGKILLed with its process group and reaped by tokio's orphan queue when
the driver parks; the blocking poll never let it park, so the dead child
stayed a zombie that kill(pid, 0) still reports (asto2 run: 10 passed,
1 failed). The poll now awaits, which also follows the blocking-call
convention (#6149).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: CodeWhale Bot <bot@codewhale.net>
…s do

The two #6743 tests printed their skip with eprintln!, which the tools
module denies (clippy::print_stderr) and failed workspace Clippy. The
module's existing Node-gated tests return silently.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: CodeWhale Bot <bot@codewhale.net>
@Hmbown Hmbown changed the title Land asto18089's queue as itself: #6736, #6737, #6738, #6740, #6742 Land asto18089's queue as itself: #6736, #6737, #6738, #6740, #6742, #6743 Sep 30, 2026
CodeWhale Bot and others added 2 commits September 30, 2026 10:39
The unmodified contributor head bf7df01 lands as itself. Its hosted
Version drift failure was the credit check this branch already fixes; its
hosted Linux PTY failure (launch_recent_click_then_enter_resumes...) is not
reproduced locally (macOS: main 3/3, main+#6744 3/3), so this branch's
exact-head Linux run is the arbiter.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: CodeWhale Bot <bot@codewhale.net>
…ted field

A runtime_threads test that reached main after #6744's base builds
EngineEvent::TurnStarted without the new submission_id field (E0063 on
the merged lib test build). A runtime turn is not a host submission, so the
fixture carries None like every other runtime start.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: CodeWhale Bot <bot@codewhale.net>
@Hmbown Hmbown changed the title Land asto18089's queue as itself: #6736, #6737, #6738, #6740, #6742, #6743 Land asto18089's queue as itself: #6736, #6737, #6738, #6740, #6742, #6743, #6744 Sep 30, 2026
#6740's worker_supervisor_honors_tool_heartbeats_during_silent_tools failed
once on hosted Windows (#6799 run 36756608424: Failed instead of Completed,
0.955 s for a 360 ms script) after passing there on the previous head: a
30 ms heartbeat against the 150 ms short-test idle deadline starves on a
loaded runner. The test now uses a 500 ms idle deadline and a 1.2 s silent
window (40 x 30 ms), with a 5 s wall budget: the window still outlasts the
deadline, so it fails if heartbeats stop counting as progress (see the
controller receipt), but a stall must reach half a second to starve it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: CodeWhale Bot <bot@codewhale.net>

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants