Repository navigation
Fix eleven session-analysis defects in run, path refusals, Bedrock, colour codes and docs - #4247
Merged
Merged
Conversation
…0 seconds and kills it with what it started The generic-mode opener test ran for 16 and 48 minutes in two runs because handler_run_by and the child it starts waited for xdg-open with no bound, and the run ended only when the child was killed by hand. A program that has not ended at the deadline now fails the test with the variable under test in the message, on every host, and is not skipped. The program runs in a process group of its own and the whole group is killed, so xprop, xdg-mime and a handler that xdg-open started do not outlive the test. One helper pair in crate::testutil, status_within and output_within, does the wait. The opener tests use it for the child of handler_run_by (20 seconds, settable by the test through BRAVEBOT_TEST_BROWSER_DEADLINE_MS), for every run of this test binary that starts the installed opener (60 seconds, which covers the child's 20 and its start), for the installed xdg-open and gio runs in the stand-in, KDE and HOME tests, and for the kde-open run in the KDE marker test, which kept its own 30 second loop that killed only the direct child. xdg-open ends in well under a second where it works, so 20 seconds is a failure only on a host that cannot run the test. The waits that are left are the ones in tests that run only on Windows, which the Unix process-group helper cannot serve, and the runs of a compiler, a shell syntax check or a script that the tests write themselves. The cause of the hang is not observed on this host: no host with xdg-open and a desktop was available. an_opener_that_does_not_end_fails_the_test_and_is_killed_with_what_it_started and a_command_that_does_not_end_is_killed_at_the_deadline_and_one_that_ends_is_not run the deadline against a stand-in that never ends. Each waits on a thread for at most 30 seconds, so a run with no deadline fails and does not hang. docs/specs/sandboxing.md SANDBOX-30 states the deadline and lists both tests under verified-by. Part of brave#4230
…stopped by a signal A stage on macOS, and an unconfined stage on Linux, led a process group of its own and kept the controlling terminal. A program that opened or configured the terminal was stopped by SIGTTIN or SIGTTOU, and a background job has no deadline, so job_output reported it as running for as long as it was asked. Every stage on unix is now started as a session leader through one helper in bravebot-sandbox, called by the Seatbelt backend and by the unconfined start. A program that opens /dev/tty gets an error instead of a stop. A stage is started with a session or a group and never both, since setsid fails in a process that already leads a group. A stage whose leader is found stopped by waitid, without collecting its exit, is ended with SIGTERM then SIGCONT and reported as stopped by the signal, by the foreground wait and by job_output, once, and the turn's look between rounds does not report it again. The check reads the kernel's state for a child the driver started and nothing the job printed. RUN-11, RUN-15 and RUN-17, the known costs and the security page say so. Closes brave#4169
The longest wait_seconds is now 270 seconds where promptCacheTtl is 5m or unset and 600 seconds where it is 1h. A longer value is still refused rather than shortened, and the refusal names the bound and the reason. A request sent after the cached prefix expired writes the whole conversation again and reads none of it. Waits of 370 to 595 seconds made each following request do that, which the previous bound of 600 allowed and the description encouraged by saying a long wait costs nothing. Deadlines carries the bound as wait_ceiling, resolved from the settings by the caller that read them (Deadlines::from_settings), so the tool compares only the argument the planner typed against a figure the person set. The descriptions of wait_seconds, deadline_seconds and job_output quote the bound in force and state the cache cost. A foreground run deadline is not bounded, and its description points at background runs watched in shorter waits. RUN-17, BACKEND-27, the Known costs entry for cache expiry, terminal-input and the website pages state the new bound. Closes brave#4233
A step a signal ended was told as "step N was killed", so a planner could not tell a program the kernel killed for memory (SIGKILL) from one asked to end (SIGTERM) or one that crashed (SIGSEGV), and restarted a long gate without knowing which. The exec layer already records the signal of each stage beside its code. failed_steps and how_it_ended now take that list and say "step N was ended by signal 9 (SIGKILL)". The name is looked up from rustix's per-platform Signal values, so Linux and macOS numbers both resolve, and a signal with no name here is told by its number alone. A stage with neither a code nor a signal, which is one whose status could not be read, is told as "step N ended without an exit code", since no signal was read. A command substitution a signal ended is refused with the same words. The words are fixed and the number is the one the system reported, so no byte a program printed reaches the sentence. RUN-13, WATCH-17 and the two website pages say the signal is named. Closes brave#4235
A read, list, search, write or edit of a path outside the workspace was refused with a remedy naming /add-dir, --add-dir or a file drop in every run, including a one-shot command or a pipeline where nobody is there to type or drop. Only a run line's redirection was worded for that case. Policy now records that nobody can be asked, set by the turn from the permission mode. The wording moves from the redirection path into the shared refusal wording used by every file tool and by deferred reads, so each of them gives a remedy that opens a directory or drops a file as the remedy that names none, says nobody can be asked in this run and asks the planner to say which path the work needs. The trail records the remedy the planner was told. A credential location keeps its meaning and loses only the drop. The redirection-only helper is removed. TRUST-10, TRACE-1, CMDLINE-5, PATHREQ-7 and the website pages for tools, trust and the audit trail say the same, and TRUST-10 lists the new tests that verify it. The harm is a planner told to use a route that does not exist. A unit test cannot measure that, because it would need a planner that follows the sentence. The tests assert the sentence instead: what a refusal says in a run nobody can be asked in, for each file tool, for a run redirection, and for one unattended turn that makes an outside read_file and then an outside redirection. Each asserts that no refusal names /add-dir, --add-dir, a file drop, a checkout route or request_path, and that each says nobody can be asked and asks for the path. The attended controls still name /add-dir. Closes brave#4231
…le has Under bypass, vet_content, spawn_processor, read_output, run with stdin_ref and write_file with contents_ref open a file a listing or a search found through tools::materialise. The reach held for the call did not cover that opening, so a file in a directory beside the workspace was refused as outside the workspace and the refusal named /add-dir, where read_file on the same path was shown. In every other mode the refusal is unchanged. TOOLS_READING_A_REFERENCE gives vet_content, spawn_processor and read_output a read reach under bypass. materialise judges the deferred read as a read through Workspace::reading_under_the_reach, then gives the call its own reach back. Where no reach is held it adds none. The slot keeps its label. PATHREQ-7 and MODE-4 describe the rule and the new tests are listed as verified-by. The issue's alternative, a quarantined-listing sentence that names read_file with the path under bypass, is not taken: the reference opens directly, so the listing sentence is unchanged. read_output does not open a file slot: it refuses one as it does in every mode and names vet_content, and a turn test asserts that under bypass. The reads of a round that run together are given the reach of the live mode, and a turn test asserts that for bypass and for the mode that asks. Closes brave#4236
The mode is armed at an idle prompt only, so a ! typed while a turn runs is a character in the line. Enter on such a line went through the generic queueing arm, which put the text into the planner's interjection buffer at once. A line written as a command, and a !! line meant to stay private, reached the model as a sentence once for each press, and the model ran the command itself with its own tool. Enter and Ctrl-Enter on a line whose first character after leading white space is ! now queue nothing and hurry nothing. The line stays in the box and a note says shell mode is available at an idle prompt only. The check sits after the arms for the handoff brief and the enhanced line, so it reads only what the person typed or pasted. The line is not queued as a command because a typed bang and a pasted one are the same characters in the box, and only a keystroke may arm the mode (SHELL-4). SHELL-8 states the case, INPUT-9 names what the key does mid-turn, and the website page describes it. The note is in the en-US and fr catalogs. Closes brave#4240
A run result, a job_output look, the account of an ended job and a read_output page or search gave the planner every colour code a program wrote, while the screen already counted them and left them out (VIEW-30). Each complete code is now taken out of the text of that output once the cap has cut it, and a sentence says how many were, only where there were any. Every other escape is left as it is. The removal moves to bravebot_core::colour_codes so the agent and the terminal client use one definition. Policy::present_output makes it from the label alone, so output nobody vouched for is neither changed nor counted. The slot keeps the raw bytes, so the offsets in a cut marker, a page trailer and a matching line still name the slot. Part of brave#4238
…ce page The /mcp row, heading and section of the commands reference listed only list, reconnect and disable, so the bundled help page the model reads from reference/commands gave no sign that /mcp remove exists. An answer from it said the command may not exist. The row and heading now list remove <alias>. The section says remove is the permanent form (runs bravebot mcp disable then bravebot mcp remove, stops the server in this session, refused in an incognito session or with no state directory) and that disable and remove take a pattern with a *, as SERVERS-19 and the usage string say. The * pattern is built at this base (e9ef845) and is documented here. A test reads the /mcp section of the bundled commands page and checks the heading forms and the remove and pattern sentences. It fails on the previous page text. The slash-menu argument hint of /mcp in command_table.rs omitted list. It is now [list | reconnect | disable | remove], which names each subcommand in the order the usage message and the commands page give them and keeps the short form the other hints use, without the alias placeholders. A test in command_table.rs pins the hint and its order against the mcp-command-usage message, and CMD-6 lists it. It fails on the previous hint. Closes brave#4234
…, for thirty minutes, and says so The status that refuses the breakpoints is also the one an expired credential or a burst of requests gets. The first answered probe recorded the model for the life of the process, so one transient 403 removed the breakpoints from every later request with nothing on screen saying so, and a prefix was read at the full rate each turn. A first refusal is now held as a doubt, and the model is recorded only when a request that began after it is refused too. Requests that began together count once. The record lapses after thirty minutes, and a request that carries the breakpoints and the lifetime and is answered clears the doubt. The status report and the info panel say that the cache is off for the model while it is recorded, from a fixed catalog sentence, since no cache figure is drawn for it. The gateway and anthropic clients keep remembering on the answer; the specs say so. Closes brave#4237
…d to split the task A delegate whose requests went quiet, did not get through, or stopped part way ended with the planner told only that it did not finish. The planner read that as bad luck and started the same delegate again on the same task, which met the same ending. The rate-limited and unavailable endings already had a sentence for this. unfinished_account now writes a fixed sentence for transport and one for incomplete, chosen by comparing the closed category name the trail records, so nothing the service sent reaches the planner. Each says the service sent no refusal, that starting the same delegate again on the same task may meet the same ending, and that the task should be split so each delegate makes smaller replies or writes. Both compose with the spent-bound sentence. Every other category, a stop and a lost thread are told as before. DELEGATE-26, BACKEND-37, TRACE-8 and the audit trail page name the four categories. BACKEND-37 says which endings are transport and incomplete, and that a Bedrock reply that never began is not sent again and is told as transport. The integration test stand-in can now hang up or send a stream with no end. The Bedrock test for the doubt cleared by an answered request now also checks that a later single refusal is not counted with the cleared one. Replacing the clearing with nothing left the old test passing. The session test for a rate limit past the longest wait now covers an account reached through the tier variables too; removing the ceiling guard on that arm left the old test passing. Not built: a setting for the idle gap and retries on the tier-variable path, and handing back the work a failed delegate had done. DELEGATE-9 says nothing but the report crosses back, and a delegate that failed has no report, so handing back that work needs DELEGATE-9 amended first. Part of brave#4239
netzenbot-reviewer
requested changes
Nov 15, 2026
…ndex is a char boundary The lint-increase check counts clippy::string_slice sites in core. The slices in colour_codes::without start at an ESC found by find, end at a run of ASCII parameters, or sit one byte past an ASCII m, so each is a char boundary. Part of brave#4238
netzenbot-reviewer
requested changes
Nov 15, 2026
…d file read_output refuses a reference to a file and opens none (OUTPUT-2), so it is removed from TOOLS_READING_A_REFERENCE and from the lists of tools that open a reference in request-path.md and permission-modes.md. The reach test now asserts that reach_for returns None for read_output under bypass. Part of brave#4236
code_end reads only offsets inside the bytes it is given, and any offset it returns is the m that ends a colour code, at least two bytes in and no more than the parameter limit past them. The slices in without cut the text at the start of an escape or one byte after that m. Part of brave#4238
…ile tool's refusal does The sentence states what the refusal names and points at TRUST-10 for the case where it names none, instead of comparing with an earlier version. Part of brave#4236
bbondy
approved these changes
Nov 15, 2026
bbondy
enabled auto-merge
November 15, 2026 21:06
netzenbot-reviewer
approved these changes
Nov 15, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #4169
Closes #4231
Closes #4233
Closes #4234
Closes #4235
Closes #4236
Closes #4237
Closes #4240
Part of #4230
Part of #4238
Part of #4239
User impact: a background program that opens the terminal now fails instead of hanging,
job_outputwaits stay under the prompt cache lifetime, step failures name the signal, file refusals in an unattended run stop pointing at/add-dir, colour codes are taken out of what the planner reads, and Bedrock tells a person when it stopped sending cache breakpoints.Decisions to confirm
crates/tui/src/opener.rs.setsid, including an unconfined stage on Linux. A stage found stopped by a signal ends as a newOutcome::StoppedBySignal, and only the stage leader is checked. Theunsafepre_execis incrates/sandbox. Instead: macOS only; reuseStopped; read the whole group; putpre_execincrates/agent. Why: the same hang applies on Linux, and a stopped non-leader is not a stopped stage. Commit: Start every unix stage in a session of its own and end a stage found stopped by a signal. To reverse: start non-macOS stages as a group only and drop the variant. The placement of theunsafeis still open for the maintainer.job_outputwait is 270 s withpromptCacheTtlunset or5m, and 600 s with1h. A longer value is refused with a message naming the bound and the cache reason. A foregroundrundeadline has no bound. Instead: shorten silently, or bound the deadline. Why: RUN-17 forbids silent shortening, and thedeadline_secondsdescription now states the cache cost. Commit: Hold one job_output wait under the prompt cache lifetime in force. To reverse: changeWAIT_CACHE_MARGINorDeadlines::waiting_underincrates/agent/src/exec.rs.step N was ended by signal 9 (SIGKILL), and an unreadable status readsended without an exit code. Instead: keep "was killed". Why: "killed" named no cause and was also said when no signal was recorded. Commit: Name the signal that ended a step in the sentence about how a run ended. To reverse: change one arm offailed_stepsincrates/agent/src/tools.rs.runwording is kept and names no--add-dir. Instead: the wording in the issue's Fix text. Why: therunrefusal and its test already name no route. Commit: File tools name no route to a person where nobody can be asked. To reverse: changeNOBODY_TO_ASKincrates/agent/src/tools.rsand TRUST-10.read_outputspec (it opens no file slot, OUTPUT-2) and not changed in code. R5 is recorded as not taken, since opening the reference was chosen. R20 rests on manifest validation already refusing outsidedirectorypaths forlist_filesandsearch, and a new core test records it. Instead: a reach forread_output, a new listing sentence, a reach around the manifest calls. Commit: Open a reference to a listed file under bypass with the reach read_file has. To reverse: each needs a code change plus its spec sentence.!line keeps the line in the box with a note, and queues nothing. Instead: queue it as a shell line. Why: a pasted!cannot be told from a typed one (SHELL-4). Commit: Enter mid-turn on a line that begins with ! holds the line in the box. To reverse: replace the new arm incrates/tui/src/app/keys.rs. The other choices are in the A !! shell line typed while a turn runs is sent to the model as a prompt, twice, with no note that shell mode is off #4240 reproduction block.bravebot-core. Instead: removal before the cut, a loop to a fixed point, the sentence in the agent. Why: offsets and trailers keep naming the raw slot, and LOCALE-1 keeps planner text out of the catalogue. Commit: Take colour codes out of the output the planner reads and say how many. To reverse: move the call beforebounded, or moveplanner_note.*pattern is built and documented, contrary to the brief. Instead: leave the pattern out. Why: SERVERS-19 already describes it, so omitting it would leave the page behind the code. Commit: Name remove, the permanent form and the * pattern in the /mcp reference page. To reverse: delete the pattern paragraph incommands.mdand its test assertions.driveand the gateway and Anthropic clients are unchanged (BACKEND-57). Instead: a second send before recording, or a change indrive. Why: the issue allows either, and a count needs no extra request. Commit: Bedrock records refused cache breakpoints only after a second refusal, for thirty minutes, and says so. To reverse: changeremember_atandREFUSAL_LASTSincrates/bedrock/src/lib.rs.BRAVEBOT_BEDROCK_MAX_RETRIES(at most 7) andBRAVEBOT_BEDROCK_IDLE_TIMEOUT_MS(at most 600000) give the tier-variable Bedrock account the retry count and idle gap a provider entry has. R21 is left blocked. Instead: no settings, or building the hand-back. Why: the bounds match a provider entry, and the hand-back needs a design decision. Commit: The planner is told when a delegate ended transport or incomplete, and to split the task. To reverse: removeBEDROCK_PATIENCEfromperson_only()incrates/config/src/env_var.rs.The problem
#4230 An opener test that runs the installed
xdg-opencan hang the test run. Nothing bounded the wait. Left: the cause of the hang is not found, because macOS has noxdg-openand the cause needs a Linux host.#4169 A background run on macOS that opens
/dev/ttystops for good, andjob_outputsays it is running. The state staysTand every look reports "still running". The hang through the terminal client was not reproduced. A pty harness reproduced the stop only (SIGTTOU as stateT, andErrno 6on/dev/ttyonce the stage had its own session).#4233 A
job_outputwait of up to 600 s outlasts the 5-minute prompt cache. The next request writes the whole prefix again, and the tool description said a long wait costs nothing.#4235 A step ended by a signal is reported as "was killed" with no signal named. The planner cannot tell an out-of-memory kill from a crash.
#4231 File tool refusals outside the workspace name
/add-dirand a file drop in a run where nobody can be asked. Only therunredirection refusal was worded for that case.#4236
vet_contentrefuses a file that a listing found beside the workspace under bypass, whereread_fileshows it. The refusal also offered/add-dir.#4240 Enter mid-turn on a line that begins with
!sent the line to the model as words. Shell mode cannot be entered during a turn.#4238 A run result sent to the planner keeps terminal colour codes that the person's own view strips. Left: the Verus contract row cannot run because
verusis not installed on the host, andmake check-verusmust run in CI.#4234 The
/mcpreference page does not mentionremove, the permanent form or the*pattern. An answer from the bundled help said the command may not exist.#4237 One refused Bedrock request switches cache breakpoints off for the model for the rest of the session, with no notice. Every later request pays full price for the prefix.
#4239 A delegate that ends as a transport failure is reported with no cause, so the planner starts the same task again. Left: handing back a failed delegate's work (R21) needs a design decision under DELEGATE-9, which lets only a report cross back. The decision is whether a failed delegate leaves a partial account that crosses with the label its context earned.
Reproduce
#4230 opener test that waits on the installed xdg-open
Nothing a person sees changes, so the test is the reproduction.
BRAVEBOT_ALLOW_UNCONFIGURED_BUILD=1 cargo test -p bravebot-tui --lib opener:: --locked.an_opener_that_does_not_end_fails_the_test_and_is_killed_with_what_it_startedpasses a stand-inxdg-opentohandler_run_by_within. The stand-in starts(sleep 3; : > survived)in the background and then runsexec sleep 600.Before the change the call waits until the
sleepends. After it, with a 1 second deadline, the call panics in about 1 second namingXDG_DATA_HOME, andsurvivedis never written.Not reproducible locally: the hang itself needs a Linux host with
xdg-openand a desktop session. This host is macOS, and the tests that run the realxdg-openprintskipped.#4169 stage stopped by the terminal
HOME=<scratch dir> bravebot.runofpython3 -c "import os,termios; fd=os.open('/dev/tty', os.O_RDWR); termios.tcsetattr(fd, termios.TCSADRAIN, termios.tcgetattr(fd)); print('done')".job_outputwithwait_seconds10, and again later. In another terminal runps -o pid,stat,command.Today the program never prints
done, every look says it is still running, and the state isT. After the change opening/dev/ttyfails, the program exits non-zero, andjob_outputsays so. A stage stopped some other way (kill -STOP $$) is reported as stopped by the signal and ended.Not reproduced: the hang through the terminal client. The pty harness started a Python stage that opens
/dev/ttyand callstcsetattr. Started as a process group only, it was stopped by SIGTTOU andpsshowedT. Started in a session of its own, it exited with code 1 andOSError: [Errno 6] Device not configured: '/dev/tty'.#4233 job_output wait longer than the cache lifetime
A live backend that reports cache figures is needed to see the cost, so the tests are the reproduction.
promptCacheTtlunset and ask the planner for a backgroundrunofsleep 600.job_outputwithuntil_exit: trueandwait_seconds: 600.Today the call is accepted, and the next request writes the whole prefix again and reads none. After the change it is refused with a message naming 270 and the cache reason, and
wait_seconds: 270is accepted. WithpromptCacheTtlset to1hthe bound is 600.tools::the_longest_wait_follows_the_cache_lifetime_chosencovers it.Not reproducible locally: the recorded session behind the issue (25 waits over 300 s) is not in the repository, and no live backend run was made.
#4235 step ended by a signal
HOMEredirected, against a stand-in model server (contrib/README.md).runwithbackground: trueonsh killme.sh, wherekillme.shholdskill -9 $$, then callsjob_output. Repeat withkill -15 $$andkill -11 $$.Today each result reads
It failed: step 1 was killed.After the change they readstep 1 was ended by signal 9 (SIGKILL),signal 15 (SIGTERM)andsignal 11 (SIGSEGV). A foregroundrunof the same line says the same.a_job_output_call_names_the_signal_that_ended_a_finished_jobincrates/agent/tests/turn.rscovers the three.Not run: Linux and Windows. The signal names on Linux are reasoned from
rustix, and the Windows build is reasoned only.#4231 refusal outside the workspace in an unattended run
HOME=$(mktemp -d). Makeproj/andoutside/todo.txtbeside it.proj/runbravebot "read ../outside/todo.txt"(a one-shot, so nobody can be asked), with the model scripted by the turn-test server to callread_fileon the absolute path andlist_filesonoutside/.Today the refusal says the person can open the directory with
/add-diror--add-dir, or drop the file. After the change it says nobody can be asked in this run and to say in the reply which path the work needs and what for, and the trail recordsremedy offered: none. In an attended session the wording is unchanged.a_read_outside_the_workspace_nobody_can_be_asked_in_names_no_persons_routeandan_unattended_turn_refused_outside_by_read_file_and_by_run_is_given_one_answercover it.The three new tests fail on
upstream/maincode, and the old wording put back fails the turn test.#4236 reference to a listed file under bypass
$TMP/wsand a sibling$TMP/side/notes.txt. Startbravebot --dangerously-skip-permissionsin$TMP/wswithHOMEredirected.list_fileson$TMP/side, thenvet_contenton the reference it returns.Today
vet_contentis refused withref:1 could not be read: 'ref:1' resolves outside the workspaceand the/add-diradvice, whileread_fileon the same path is shown. After the change the reference opens. In Ask, AcceptEdits and Plan modes the listing itself is refused as before, and a reference made under bypass is refused once the mode leaves bypass.under_bypass_a_reference_to_a_listed_file_beside_the_session_is_openedfailed with the refusal above on the unmodified tree.#4240 a ! line mid-turn
!!pwdand press Enter, or Ctrl-Enter.Today the line leaves the box and is queued or interjected to the model. After the change the line stays in the box with a note that shell mode is for when the turn is idle, and nothing is queued. A line with
!after its first character is still queued.a_bang_line_pressed_mid_turn_is_held_and_never_interjectedandctrl_enter_on_a_bang_line_mid_turn_neither_queues_it_nor_stops_the_turncover it.Other choices: a pasted
!line is held the same way, leading white space counts, the note is a transcript note and not a hint line, the French text is a new translation, and a!line while an enhancement is pending is still queued as an enhanced prompt (INPUT-48).Not run live:
drive_tui.pyneeds a stand-in server that keeps a turn open, and none was available.#4238 colour codes in a run result sent to the planner
HOMEand a trusted throwaway directory.contrib/README.md). Its first reply callsrunwith{"command":"printf '\\033[0m\\033[36mok\\033[0m done\\n'","read":true}and its second reply isdone.toolmessage for the run in the second request the stand-in receives.Today the text holds
ESC [ 0 m ESC [ 3 6 m ok ESC [ 0 m donebyte for byte. After the change it holdsok donefollowed by3 colour codes were taken out of this output.A result with no colour code gets no sentence, and other escape sequences are left alone.cargo test -p bravebot-agent --test turn --locked -- colourcovers each route.Not run live: the
drive_tui.pyform. The in-tree stand-in server incrates/agent/tests/turn.rswas the reproduction, and the tests were not run against the parent commit.#4234 /mcp reference page
reference/commands) whether/mcp removeexists, or read the/mcprow and section ofdocs/website/docs/reference/commands.md.Today the row and heading list
list,reconnectanddisableonly. After the change they listremove <alias>, the section describes the permanent form and the*pattern, and the slash-menu hint reads[list | reconnect | disable | remove].help::tests::the_mcp_section_of_the_commands_page_names_every_form_of_the_commandfails on the previous page, andcommand_table::tests::the_mcp_hint_names_every_subcommand_the_usage_message_namesfailed on the previous hint.#4237 one refused Bedrock request switches breakpoints off
/statusand the info panel.Today the second request is answered without breakpoints, the model is recorded as refusing them, and every later request carries none, with no notice. After the change breakpoints are recorded as refused only after a second refusal on a request that began later, the record lapses after 30 minutes, and
/statusand the info panel say when breakpoints were given up.one_refused_request_does_not_stop_later_requests_carrying_the_breakpointscovers it.Not run live: the tests use scripted responses in
crates/bedrock/src/lib.rs.#4239 delegate ended transport or incomplete
The failure needs a model service that goes quiet, so the tests are the reproduction.
HOMEagainst a stand-in server that answers the planner with aspawn_agentcall.Today the planner message is
The delegate d1 did not finish. It ran N commands and made N writes.After the change it also says the service sent no refusal, that starting the same task again may meet the same silence or stop the same way, and to split the task. No text from the service is carried.a_delegate_that_ended_on_a_limit_an_outage_a_silence_or_a_stopped_reply_is_told_to_the_plannercovers both.The fix
#4230. The opener tests wait for the installed
xdg-openorgioat most 20 seconds, then kill it with everything it started and fail naming the variable. One helper incrates/tui/src/testutil.rsdoes the wait.#4169. Every unix stage starts in a session of its own, so it has no controlling terminal and opening one fails. A stage still found stopped is sent TERM then CONT, killed after a grace period, and reported once as stopped by the signal. RUN-11, RUN-15 and RUN-17 say so.
#4233.
Deadlinescarries the longest wait for the cache lifetime in force,wait_fromrefuses a longer value naming the bound, and the tool descriptions state the cache cost.#4235.
failed_stepsandhow_it_endedtake the signal list recorded for each stage and name the signal, with a name table that resolves per platform throughrustix.#4231.
Policyrecords that nobody can be asked, and the shared wording for every file tool maps each open and drop remedy to no route and says to name the path in the reply. TRUST-10, TRACE-1, CMDLINE-5 and PATHREQ-7 say the same.#4236. A second table lists the tools that open a reference (
vet_content,spawn_processor,read_output), andmaterialiseholds a read reach for them under bypass only.#4240. A new arm in
handle_key_while_workingholds a!line in the box with a note in English and French. SHELL-8 is new.#4238.
Policy::present_outputtakes complete colour codes out of the text of a trustedrun,job_outputorread_outputresult and says how many, on every route.withoutmoved frombravebot-tuitobravebot-core.#4234. The row, heading and section list
remove <alias>and the pattern, the slash-menu hint names every subcommand, and CMD-6 lists the new test.#4237. Bedrock holds a first refusal as a doubt, records it only when a later request is refused too, lets it lapse after 30 minutes, and draws a notice in
/statusand the info panel.#4239.
unfinished_accountnames the transport and incomplete endings with the advice to split the task, and a Bedrock account reached through the tier variables can state its retry count and idle gap.Test plan
BRAVEBOT_ALLOW_UNCONFIGURED_BUILD=1 make check-affectedcargo check --workspace --all-targets --locked: exit 0 on the combined treecargo clippywith-D warningson nine packages: exit 0make check-spec check-locales check-docs check-narration: exit 0 on the combined treean_opener_that_does_not_end_fails_the_test_and_is_killed_with_what_it_started: rejects no process-group kill, no deadline and a message without the variable; demonstrated by each fault. A deadline that skips instead of failing is reasoned only.a_stage_cannot_open_the_controlling_terminal: rejects a start as a process group only; demonstrated.a_stopped_stage_is_continued_so_the_request_to_end_reaches_itanda_stage_stopped_by_a_signal_is_reported_as_stopped_and_ended_before_the_limit: reject TERM without CONT and a wait with no stop detection; demonstrated. The stop-by-signal tests use SIGSTOP, not SIGTTOU, and Linux was not run.the_longest_wait_follows_the_cache_lifetime_chosen: rejects a bound of 600 under5mor unset and1hignored; demonstrated.a_job_output_wait_outside_the_bounds_is_refused_rather_than_shortenedrejects clamping; reasoned only.each_failed_step_is_named_by_its_place_and_how_it_ended: rejects a sentence that drops the signal; demonstrated.a_signal_with_no_name_is_told_by_its_number_alone: reasoned only.file_tools_with_nobody_to_ask_name_no_route_and_record_noneanda_read_outside_the_workspace_nobody_can_be_asked_in_names_no_persons_route: reject wording from the remedy alone and a turn that never sets the flag; demonstrated.under_bypass_a_reference_to_a_listed_file_beside_the_session_is_opened: rejects a reference opened with no reach; demonstrated.a_reference_made_under_bypass_is_refused_once_the_mode_leaves_bypassandthe_refusals_hold_for_a_file_a_reference_stands_for: reject a reach that outlives bypass and a deferred read without the refusals; demonstrated.under_bypass_with_read_only_a_reference_to_a_listed_file_is_opened: reasoned only. Noveruson this host and no gate or label code changed.a_bang_line_pressed_mid_turn_is_held_and_never_interjected: rejects leaving the line to the generic queue arm; demonstrated.a_line_with_a_bang_after_its_first_character_is_still_queued: reasoned only.colourturn tests, one per route: reject a route that usespresentand notpresent_output; demonstrated. The core test for output nobody vouched for: demonstrated./mcppage test and the hint test: reject the previous page and hint; demonstrated for the heading assertion and the hint, reasoned only for the sentence assertions.one_refused_request_does_not_stop_later_requests_carrying_the_breakpoints,a_model_that_refuses_on_a_second_request_is_sent_no_breakpoints_after_itand the lapse tests: reject recording on one answered probe, no record, and a record that never lapses; demonstrated by mutation.the_planner_is_told_the_category_only_where_a_repeat_ends_the_same_wayand the settings tests: reject a prefix match on the category and a project layer changing the retry count; demonstrated. Removing thepast_the_ceilingguard on theVariablearm fails thea_rate_limittests.a_redirection_writing_into_the_stores_is_refused_when_it_is_openedis flaky in a fulltools::run and passes when run alone.Failures that also occur on upstream/main
render::tests::todos::a_cancelled_task_is_struck_without_the_finished_colourandrender::sessions_screen::tests::a_calm_header_says_so_and_only_the_waiting_count_has_a_colourfail intermittently inbravebot-tuionupstream/maintoo, because neither takestheme::exclusive(). No issue or pull request is cited yet:gh issue listandgh pr list --repo brave/bravebot --search "theme exclusive colour test flaky" --state allfound none.