8000 feat(minimal): T45 — Box logs strips terminal control codes when stdout is not a terminal by minimal-foundry[bot] · Pull Request #3335 · gominimal/minimal · GitHub
[go: up one dir, main page]

Skip to content

feat(minimal): T45 — Box logs strips terminal control codes when stdout is not a terminal - #3335

Open
minimal-foundry[bot] wants to merge 6 commits into
mainfrom
agent/3332-box-logs-strips-terminal-control-codes-when-stdo
Open

minimal-foundry[bot] wants to merge 6 commits into
mainfrom
agent/3332-box-logs-strips-terminal-control-codes-when-stdo

Conversation

@minimal-foundry
Copy link
Copy Markdown
Contributor

T45 — Box logs strips terminal control codes when stdout is not a terminal

slice: S2
kind: task
covers: BCLI-012
size: S
est: 50 code, 80 tests
executor: agent
difficulty: needs care
model: strongest
diagnostics: none new
observability: none new
layers:
- client:
- crates/minimal/src/cli.rs: min box logs and the type nouns' logs take --raw
- crates/minimal/src/cmd/boxes.rs: box_logs_on_hosts strips terminal control sequences (CSI, OSC and other escape sequences) from a PTY box's transcript when stdout isn't a terminal and --raw isn't given
- crates/minimal/src/tests.rs: the in-process minimald test harness gains this layer's tests
test: cargo nextest run -p minimal box_logs_piped_pty_transcript_has_no_control_codes
test: cargo nextest run -p minimal box_logs_raw_keeps_control_codes
produces: none
consumes: none
proof: min box logs <pty box> | cat prints the transcript text with no terminal control sequences; --raw prints them unchanged; a terminal still gets the raw stream.

Proof

min box logs <pty box> | cat (and the session and task nouns) now prints the transcript text without CSI, OSC, DCS, charset or other escape sequences. --raw prints the bytes unchanged. A stdout that is a terminal, and a box with no terminal, still get the raw stream.

Notes from the agent: box_logs_on_hosts takes a new stdout_is_terminal: bool argument. cmd_box_logs sets it from std::io::stdout().is_terminal(), and the five existing test calls pass false. When it strips, the verb makes one more ShowBox call to read pty_enabled from the box's stored spec. ResolvedBox does not carry that field, and address.rs is outside the layers. The stripper is a streaming state machine, so a sequence split across two output chunks is removed whole. It also drops C0 control codes other than tab, LF and CR (BEL, for example). Bytes of 0x80 and up pass through, so 8-bit C1 controls are not stripped, because they collide with UTF-8. --raw is accepted with --exec and does nothing there, because the exec rea 8000 d does not strip. New help text for --raw: "Show a terminal box's output byte for byte, with its terminal control codes. Without --raw, output that does not go to a terminal has them removed". The existing tests type_noun_logs_follow and task_run_logs_wait_list_end_to_end also pass. I did not run just ci or clippy-strict.

Tests

line exit tail
cargo nextest run -p minimal box_logs_piped_pty_transcript_has_no_control_codes 0 warning: unknown fields in task runtime-implement-test-0: network warning: unknown fields in task runtime-implement-test-1: network help: do you need to update to a newer version of minimal? Applying loadouts: default Running task runtime-implement-test-0 in box runtime-implement-test-0-1... Comp
cargo nextest run -p minimal box_logs_raw_keeps_control_codes 0 warning: unknown fields in task runtime-implement-test-0: network warning: unknown fields in task runtime-implement-test-1: network help: do you need to update to a newer version of minimal? Applying loadouts: default Running task runtime-implement-test-1 in box runtime-implement-test-1-1... Comp

Verify

min task run agent-verify exited 100, so this PR is a draft.

 {
                "parent_span_id": "5912384ceeada72c",
                "rpc": "minimald-v1-GetSessionRecord",
                "span_id": "c23cc882c60584bb",
                "trace_id": "0af7651916cd43dd8448eb211c803111",
            },
            parent: None,
            closed: true,
        },
        LoggedSpan {
            name: "sessions.manager.message",
            fields: {
                "kind": "GetRecord",
                "parent_span_id": "c23cc882c60584bb",
                "queued_behind": "0",
                "span_id": "9e8bf98c3379c4bf",
                "trace_id": "0af7651916cd43dd8448eb211c803111",
            },
            parent: None,
            closed: true,
        },
        LoggedSpan {
            name: "rpc",
            fields: {
                "parent_span_id": "5912384ceeada72c",
                "rpc": "minimald-v1-DestroySession",
                "span_id": "c2a7b9806d2e89f3",
                "trace_id": "0af7651916cd43dd8448eb211c803111",
            },
            parent: None,
            closed: true,
        },
        LoggedSpan {
            name: "sessions.manager.message",
            fields: {
                "kind": "GetRecord",
                "parent_span_id": "c2a7b9806d2e89f3",
                "queued_behind": "0",
                "span_id": "dd17f96336fe54c8",
                "trace_id": "0af7651916cd43dd8448eb211c803111",
            },
            parent: None,
            closed: true,
        },
        LoggedSpan {
            name: "sessions.manager.message",
            fields: {
                "kind": "DeleteSession",
                "parent_span_id": "c2a7b9806d2e89f3",
                "queued_behind": "0",
                "span_id": "b0a10fa3dcc674f2",
                "trace_id": "0af7651916cd43dd8448eb211c803111",
            },
            parent: None,
            closed: true,
        },
        LoggedSpan {
            name: "session.message",
            fields: {
                "kind": "Destroy",
                "parent_span_id": "b0a10fa3dcc674f2",
                "span_id": "12e2a7bcb3b0b4b5",
                "trace_id": "0af7651916cd43dd8448eb211c803111",
            },
            parent: None,
            closed: true,
        },
        LoggedSpan {
            name: "sessions.manager.message",
            fields: {
                "kind": "HandOverName",
                "parent_span_id": "b0a10fa3dcc674f2",
                "queued_behind": "0",
                "span_id": "a02b2358a8898870",
                "trace_id": "0af7651916cd43dd8448eb211c803111",
            },
            parent: None,
            closed: true,
        },
    ]
    note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

  Cancelling due to test failure: 
────────────
     Summary [  63.861s] 1099 tests run: 1098 passed, 1 failed, 2 skipped
        FAIL [   2.797s] (1099/1099) minimal::otel_cli exec_run_attach_and_task_run_share_the_commands_trace
error: test run failed

Base

The base branch moved while the coder worked and was merged in before the tests ran. These files changed on BOTH sides since the branch point — read them first, because a rewrite from a stale reading can undo a merge without a conflict:

  • crates/minimal/src/tests.rs

Closes #3332

min box logs, min session logs and min task logs now remove terminal
control sequences from the output of a box with a terminal when stdout
is not a terminal. --raw keeps the bytes as the box wrote them. A
terminal on stdout still gets the raw stream.
@coderabbitai
coderabbitai Bot commented Nov 12, 2026 •
Copy link
Copy Markdown
Contributor

Important

Review skipped

Bot user detected.

To trigger a single review, invoke the @coderabbitai review command.

Run configuration

  • Source mode: Auto
  • Repository: Unavailable
  • Branch: Unavailable
  • File: No configuration file from this repository applied
  • Commit: Unavailable
  • Layers: Organization UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 86d33fda-dde4-4e21-84b5-3a82b6e1608f

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • Trigger review
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

@minimal-foundry
minimal-foundry Bot commented Nov 12, 2026 •
Copy link
Copy Markdown
Contributor Author

Reviewed: 1 finding, none blocking at 33b8f333c627.

Address the comments on the diff.

Clobber: none found in the changed hunks.

@minimal-arch minimal-arch Bot left a comment
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

arch-review: CONDITIONS · 2 conditions · the full ruling

The stripping is in the correct place. It is a client-side view, and the captured log stays byte-exact. Two items block the merge. First, --raw is accepted with --exec and does nothing there. The new help text says that output to a non-terminal has its control codes removed, but --exec output keeps them. Design principle 6 says help and behaviour must not drift apart. Make the flags conflict and correct the help text (C1). Second, no spec requirement binds the new default or --raw. Add them under BCLI-012 with the two tests as verify: lines (C2).

Ruled at bc14637 against gominimal/arch@15b603e6afb8 by claude-opus-5-5.

Comment thread crates/minimal/src/cli.rs Resolved
Comment thread crates/minimal/src/cmd/boxes.rs Resolved
@minimal-foundry
Copy link
Copy Markdown
Contributor Author

Round 1 of 10 on a failed check suite: the coder changed nothing. Revise round 1: the directive lists only the failed macOS unit check (and the ci-macos-success aggregator that follows it). On macOS, just test runs -p minvmd -p boxes -p bep (justfile scope). This branch changes only crates/minimal (cli.rs, cmd/boxes.rs, tests.rs) and no Cargo.toml or Cargo.lock, so the macOS lane does not compile or run any code this branch changes. The log excerpt names no failing test: it shows minvmd tests that pass, then error: recipe test fail…. I cannot reproduce a macOS-only failure on this Linux box. I made no change. A re-run of the macOS lane can show if the failure is flaky, and the full job log can name the failing test if it is not.

@minimal-foundry minimal-foundry Bot left a comment
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

minimal-review — advisory review

Verdict COMMENT — 3 findings, 3 inline.

Panel: 3 of 3 personas ran (correctness, security, supply-chain).

Comment thread crates/minimal/src/cmd/boxes.rs Resolved
Comment thread crates/minimal/src/cmd/boxes.rs Resolved
--exec now refuses --raw, because it never strips. The --raw help says so.
A failed box record read writes the log raw and does not fail the command.
A line feed ends an OSC or DCS string that has no end, so a malformed
sequence cannot hide the rest of the log.
@agent-137
Copy link
Copy Markdown
Member

/revise

Head bc146373. Arch ruling 1203 has two conditions. Change nothing else.

1. C1: --raw with --exec is a usage error.
In crates/minimal/src/cli.rs BoxLogsExecArgs::exec, change conflicts_with = "follow" to conflicts_with_all = ["follow", "raw"]. Change the BoxLogsArgs::raw doc comment so --help says only what the code does: the removal applies to the box's own output, and --exec output is written unchanged. In box_logs_raw_keeps_control_codes (crates/minimal/src/tests.rs), assert that ["min","box","logs","web", 8000 "--exec","<id>","--raw"] fails to parse.

2. C2: spec 28 states the behaviour.
In docs/specs/28-spec-box-cli/28-spec-box-cli.md, add two EARS sub-requirements under BCLI-012:

  • (a) WHERE the box's spec sets pty_enabled, stdout is not a terminal, and --raw is not given, THE SYSTEM SHALL remove terminal control sequences from the output that min box logs, min session logs and min task logs write.
  • (b) WHERE --raw is given, or stdout is a terminal, or the spec does not set pty_enabled, THE SYSTEM SHALL write the captured bytes unchanged.

Give them verify: lines naming box_logs_piped_pty_transcript_has_no_control_codes and box_logs_raw_keeps_control_codes, and a comment citing architecture line 473 and design principle 3. Don't quote the --raw help text in the spec. The spec file is outside layers:, but arch requires the edit.

Reply on the arch threads with the commit. Run the whole minimal suite.

@minimal-foundry
Copy link
Copy Markdown
Contributor Author

That /revise is held, not dropped. A coder is already running on #3332. Your note is kept and goes into the next round here, which starts when that coder finishes.

Nothing to type again: the command gets a rocket when its round starts, or a refusal that names the reason. No round was counted for it yet.

@minimal-foundry
Copy link
Copy Markdown
Contributor Author

Round 2 of 10 on the runtime's review findings, pushed as cb0f948692f6.

line exit tail
cargo nextest run -p minimal box_logs_piped_pty_transcript_has_no_control_codes 0 warning: unknown fields in task runtime-implement-test-0: network warning: unknown fields in task runtime-implement-test-1: network help: do you need to update to a newer version of minimal? Applying loadouts: default Running task runtime-implement-test-0 in box runtime-implement-test-0-1... Comp
cargo nextest run -p minimal box_logs_raw_keeps_control_codes 0 warning: unknown fields in task runtime-implement-test-0: network warning: unknown fields in task runtime-implement-test-1: network help: do you need to update to a newer version of minimal? Applying loadouts: default Running task runtime-implement-test-1 in box runtime-implement-test-1-1... Comp

Verify min task run agent-verify exited 100.

 {
                "parent_span_id": "55f7c0417bfbffb2",
                "rpc": "minimald-v1-GetSessionRecord",
                "span_id": "148d09ea8a04043e",
                "trace_id": "0af7651916cd43dd8448eb211c803111",
            },
            parent: None,
            closed: true,
        },
        LoggedSpan {
            name: "sessions.manager.message",
            fields: {
                "kind": "GetRecord",
                "parent_span_id": "148d09ea8a04043e",
                "queued_behind": "0",
                "span_id": "02fb8d73d1c26c74",
                "trace_id": "0af7651916cd43dd8448eb211c803111",
            },
            parent: None,
            closed: true,
        },
        LoggedSpan {
            name: "rpc",
            fields: {
                "parent_span_id": "55f7c0417bfbffb2",
                "rpc": "minimald-v1-DestroySession",
                "span_id": "f12e0bad594221f0",
                "trace_id": "0af7651916cd43dd8448eb211c803111",
            },
            parent: None,
            closed: true,
        },
        LoggedSpan {
            name: "sessions.manager.message",
            fields: {
                "kind": "GetRecord",
                "parent_span_id": "f12e0bad594221f0",
                "queued_behind": "0",
                "span_id": "3113a1ea85628047",
                "trace_id": "0af7651916cd43dd8448eb211c803111",
            },
            parent: None,
            closed: true,
        },
        LoggedSpan {
            name: "sessions.manager.message",
            fields: {
                "kind": "DeleteSession",
                "parent_span_id": "f12e0bad594221f0",
                "queued_behind": "0",
                "span_id": "f46cd90479701ae4",
                "trace_id": "0af7651916cd43dd8448eb211c803111",
            },
            parent: None,
            closed: true,
        },
        LoggedSpan {
            name: "session.message",
            fields: {
                "kind": "Destroy",
                "parent_span_id": "f46cd90479701ae4",
                "span_id": "a28f1116297285e4",
                "trace_id": "0af7651916cd43dd8448eb211c803111",
            },
            parent: None,
            closed: true,
        },
        LoggedSpan {
            name: "sessions.manager.message",
            fields: {
                "kind": "HandOverName",
                "parent_span_id": "f46cd90479701ae4",
                "queued_behind": "0",
                "span_id": "fc88eda5112805e7",
                "trace_id": "0af7651916cd43dd8448eb211c803111",
            },
            parent: None,
            closed: true,
        },
    ]
    note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

  Cancelling due to test failure: 
────────────
     Summary [  64.348s] 1099 tests run: 1098 passed, 1 failed, 2 skipped
        FAIL [   2.906s] (1099/1099) minimal::otel_cli exec_run_attach_and_task_run_share_the_commands_trace
error: test run failed

Converted to a draft: something above needs a person before review.

Review threads the coder judged:

  • 👍 valid — crates/minimal/src/cli.rs:571: --exec now has conflicts_with_all = ["follow", "raw"]. The --raw help now says that it applies to the box's own output and that --exec does not take it. The test box_logs_raw_keeps_control_codes checks the refusal.
  • 👎 invalid — crates/minimal/src/cmd/boxes.rs:97: The fix needs a change to docs/specs/28-spec-box-cli.md. That file is outside this task's layers (cli.rs, cmd/boxes.rs, tests.rs), so the spec change needs its own task or issue.
  • 👍 valid — crates/minimal/src/cmd/boxes.rs:294: A line feed now ends an OSC, DCS, SOS, PM or APC string, and the stripper keeps the line feed as text. So an unterminated string hides at most the rest of its line. A test case covers this.
  • 👍 valid — crates/minimal/src/cmd/boxes.rs: box_has_terminal now returns bool. A failed ShowBox read goes to the log as a warning, and the command writes the log raw instead of failing.

min box logs <pty box> | cat prints the transcript text with no terminal control sequences. min box logs <pty box> --raw | cat prints them unchanged. A terminal on stdout still gets the raw stream. min box logs <box> --exec <id> --raw is refused, because --exec output is never stripped.

Notes from the agent: Revise round 2. I ran both test lines together in one nextest call, and both passed. clippy -p minimal --all-targets is clean. Thread C2 asks for a change to the spec file docs/specs/28-spec-box-cli.md. That file is outside this task's layers, so I made no change for it.

@minimal-foundry
minimal-foundry Bot marked this pull request as draft November 12, 2026 21:22
@minimal-foundry minimal-foundry Bot left a comment
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

minimal-review — advisory review

Verdict COMMENT — 1 finding, 1 inline.

Panel: 3 of 3 personas ran (correctness, security, supply-chain).

@minimal-arch minimal-arch Bot left a comment
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

arch-review: PASS · the full ruling

The compare conforms to the design. A failed box record read now prints the log raw, and a failed log read still refuses. --exec refuses --raw, so line 479's form has no flag that does nothing. A line feed ends a control string that has no end, so a malformed sequence cannot hide the transcript. The new test assertions prove each change. The agent-verify failure is in otel_cli.rs, which this PR does not touch. Make it pass before the PR leaves draft.

Ruled at cb0f948 against gominimal/arch@15b603e6afb8 by claude-opus-5-5.

Add the two BCLI-012 sub-requirements the arch ruling asks for, and
make the --raw help say that --exec output is written unchanged.
@minimal-foundry
Copy link
Copy Markdown
Contributor Author

Round 3 of 10 on a /revise note, pushed as 38a3ce2bd6bc.

line exit tail
cargo nextest run -p minimal box_logs_piped_pty_transcript_has_no_control_codes 0 warning: unknown fields in task runtime-implement-test-0: network warning: unknown fields in task runtime-implement-test-1: network help: do you need to update to a newer version of minimal? Applying loadouts: default Running task runtime-implement-test-0 in box runtime-implement-test-0-1... Comp
cargo nextest run -p minimal box_logs_raw_keeps_control_codes 0 warning: unknown fields in task runtime-implement-test-0: network warning: unknown fields in task runtime-implement-test-1: network help: do you need to update to a newer version of minimal? Applying loadouts: default Running task runtime-implement-test-1 in box runtime-implement-test-1-1... Comp

Verify min task run agent-verify exited 100.

 {
                "parent_span_id": "6428375671b51095",
                "rpc": "minimald-v1-GetSessionRecord",
                "span_id": "d4ded6d983845f96",
                "trace_id": "0af7651916cd43dd8448eb211c803111",
            },
            parent: None,
            closed: true,
        },
        LoggedSpan {
            name: "sessions.manager.message",
            fields: {
       
10000
         "kind": "GetRecord",
                "parent_span_id": "d4ded6d983845f96",
                "queued_behind": "0",
                "span_id": "cb6bafb8d178d3a2",
                "trace_id": "0af7651916cd43dd8448eb211c803111",
            },
            parent: None,
            closed: true,
        },
        LoggedSpan {
            name: "rpc",
            fields: {
                "parent_span_id": "6428375671b51095",
                "rpc": "minimald-v1-DestroySession",
                "span_id": "b1f1d4d5ad8fa078",
                "trace_id": "0af7651916cd43dd8448eb211c803111",
            },
            parent: None,
            closed: true,
        },
        LoggedSpan {
            name: "sessions.manager.message",
            fields: {
                "kind": "GetRecord",
                "parent_span_id": "b1f1d4d5ad8fa078",
                "queued_behind": "0",
                "span_id": "d89c80de1f1f823d",
                "trace_id": "0af7651916cd43dd8448eb211c803111",
            },
            parent: None,
            closed: true,
        },
        LoggedSpan {
            name: "sessions.manager.message",
            fields: {
                "kind": "DeleteSession",
                "parent_span_id": "b1f1d4d5ad8fa078",
                "queued_behind": "0",
                "span_id": "dc69b0fd789fdcb0",
                "trace_id": "0af7651916cd43dd8448eb211c803111",
            },
            parent: None,
            closed: true,
        },
        LoggedSpan {
            name: "session.message",
            fields: {
                "kind": "Destroy",
                "parent_span_id": "dc69b0fd789fdcb0",
                "span_id": "93370ffaad8845f9",
                "trace_id": "0af7651916cd43dd8448eb211c803111",
            },
            parent: None,
            closed: true,
        },
        LoggedSpan {
            name: "sessions.manager.message",
            fields: {
                "kind": "HandOverName",
                "parent_span_id": "dc69b0fd789fdcb0",
                "queued_behind": "0",
                "span_id": "25329e4539840a13",
                "trace_id": "0af7651916cd43dd8448eb211c803111",
            },
            parent: None,
            closed: true,
        },
    ]
    note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

  Cancelling due to test failure: 
────────────
     Summary [  74.774s] 1099 tests run: 1098 passed, 1 failed, 2 skipped
        FAIL [   3.111s] (1099/1099) minimal::otel_cli exec_run_attach_and_task_run_share_the_commands_trace
error: test run failed

Outside the task's layers::

  • docs/specs/28-spec-box-cli/28-spec-box-cli.md

Converted to a draft: something above needs a person before review.

Review threads the coder judged:

  • 👍 valid — PRRT_kwDOPdfcxM620zAt: --exec refuses --raw (cb0f948). In 38a3ce2 the --raw help says that --exec output is always written unchanged. (not posted on the thread: not an open thread on the pull request)
  • 👍 valid — PRRT_kwDOPdfcxM620zAz: The arch ruling allows the spec edit outside layers. 38a3ce2 adds two BCLI-012 sub-requirements, one for the stripped default and one for --raw. Each has a verify: line that names one of the two new tests. (not posted on the thread: not an open thread on the pull request)

min box logs <pty box> | cat prints the transcript text with no terminal control sequences. min box logs <pty box> --raw | cat prints them unchanged. A terminal still gets the raw stream. min box logs <box> --exec <id> --raw is a usage error, and --help for --raw says that --exec output is written unchanged. Spec 28 now states both behaviours under BCLI-012.

Notes from the agent: C1 was already in cb0f948: --exec has conflicts_with_all = ["follow", "raw"], and box_logs_raw_keeps_control_codes asserts that --exec 1 --raw fails to parse. This round only rewrote the --raw doc comment. It now says that the removal applies to the box's own output, and that --exec output is always written unchanged. C2: commit 38a3ce2 adds the two EARS sub-requirements under BCLI-012 in docs/specs/28-spec-box-cli/28-spec-box-cli.md. Each has a verify: line and a comment citing architecture L473 and design principle 3. The spec file is outside layers:. The arch ruling on the /revise note requires the edit. just lint-prose did not run because vale is not installed on this box. The two new spec lines are not Vale-checked.

@minimal-foundry
minimal-foundry Bot marked this pull request as draft November 12, 2026 21:54
@github-actions
Copy link
Copy Markdown
Contributor

Spec lint

docs/specs/28-spec-box-cli/28-spec-box-cli.md — 11 finding(s)

docs/specs/28-spec-box-cli/28-spec-box-cli.md:211: P004 BCLI-077 names test 'box_spec_renders_merged_vars_once_with_layer', which was not found in the repository
docs/specs/28-spec-box-cli/28-spec-box-cli.md:226: P004 BCLI-078 names test 'expansion_refusals_exit3_on_spec_and_create_verbs', which was not found in the repository
docs/specs/28-spec-box-cli/28-spec-box-cli.md:299: P004 BCLI-075 names test 'create_verbs_no_loadouts_empties_loadouts_layer', which was not found in the repository
docs/specs/28-spec-box-cli/28-spec-box-cli.md:312: P004 BCLI-076 names test 'create_verbs_no_hooks_stores_no_hooks', which was not found in the repository
docs/specs/28-spec-box-cli/28-spec-box-cli.md:327: P004 BCLI-026 names test 'box_verbs_exist_with_arch_flags', which was not found in the repository
docs/specs/28-spec-box-cli/28-spec-box-cli.md:335: P004 BCLI-028 names test 'help_and_completions_from_one_model', which was not found in the repository
docs/specs/28-spec-box-cli/28-spec-box-cli.md:422: P004 BCLI-034 names test 'exit_code_table', which was not found in the repository
docs/specs/28-spec-box-cli/28-spec-box-cli.md:538: P004 BCLI-042 names test 'removed_session_verbs_fail_as_unknown_commands', which was not found in the repository
docs/specs/28-spec-box-cli/28-spec-box-cli.md:542: P004 BCLI-043 names test 'setup_zed_unchanged', which was not found in the repository
docs/specs/28-spec-box-cli/28-spec-box-cli.md:547: P004 BCLI-044 names test 'cli_reference_documents_box_grammar', which was not found in the repository
docs/specs/28-spec-box-cli/28-spec-box-cli.md:571: P004 BCLI-049 names test 'host_stop_stops_boxes_then_daemon_and_vm', which was not found in the repository

Advisory. None of this blocks the merge; the review decides.

Advisory, and never a merge gate. Linter: gominimal/foundry@cb06fdfc, spec format: How Minimal Writes Specs.

@minimal-foundry minimal-foundry Bot left a comment
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

minimal-review — advisory review

Verdict COMMENT — 2 findings, 2 inline.

Panel: 3 of 3 personas ran (correctness, security, supply-chain).

Comment on lines +275 to +282
Csi => match byte {
Self::ESC => Escape,
0x40..=0x7e => Ground,
0x00..=0x3f | 0x7f => Csi,
_ => {
self.state = Ground;
return self.step(byte, text);
}
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

LOW · correctness · confidence 0.50 · in ControlStripper::step

An unterminated CSI sequence hides all later output. The Csi state keeps every byte in 0x00..=0x3f, including line feed, until a final byte (0x40..=0x7e) arrives. A truncated ESC [ near the end of a capture chunk, or one cut by the capture bound, therefore removes the following text up to the next letter. EscapeIntermediate has the same shape. The ControlString state already ends at a line feed for this reason, and a terminal runs C0 codes inside a CSI. Handle line feed, and carriage return, in the same way here.

What the reviewer checked

Csi => match byte { ESC => Escape, 0x40..=0x7e => Ground, 0x00..=0x3f | 0x7f => Csi, ... } versus ControlString: b'\n' => { text.push(byte); Ground }

Hand this to an agent
Act on a code-review finding.

File:       crates/minimal/src/cmd/boxes.rs
Lines:      275-282
Category:   correctness
Severity:   low (reviewer confidence 0.50)

Finding:
An unterminated CSI sequence hides all later output. The `Csi` state keeps every byte in 0x00..=0x3f, including line feed, until a final byte (0x40..=0x7e) arrives. A truncated `ESC [` near the end of a capture chunk, or one cut by the capture bound, therefore removes the following text up to the next letter. `EscapeIntermediate` has the same shape. The `ControlString` state already ends at a line feed for this reason, and a terminal runs C0 codes inside a CSI. Handle line feed, and carriage return, in the same way here.

First verify this against the code yourself. It is model output and
may be wrong. If it is wrong, or the tradeoff was deliberate, say so
and change nothing.

👍 useful · 👎 noise — react to tell the reviewer. Replying works too, and says more.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Addressed in 33b8f333c627: Csi and EscapeIntermediate now end at a line feed or carriage return, and keep it as text. A test pins both cases.

A CSI or escape sequence with no final byte hid every later byte up to
the next letter. A line feed or carriage return now ends it and stays as
text, as it already did for OSC and the other control strings.
@agent-137
Copy link
Copy Markdown
Member

/revise

Head 38a3ce2b. One minimal-review finding, thread PRRT_kwDOPdfcxM622ZH_. Change nothing else.

An unterminated CSI sequence hides at most the rest of its line.
In ControlStripper::step, the Csi state keeps every byte in 0x00..=0x3f, line feed included, until a final byte (0x40..=0x7e). So a truncated ESC [ near the end of a capture chunk, or one the capture bound cuts, hides the following text up to the next letter. Make a line feed end a CSI sequence, as it already ends an OSC, DCS, SOS, PM or APC string, and keep the line feed as text. Apply the same rule to the escape-intermediate state. Add a test where ESC [ is cut off before a line feed, and assert that the next line prints.

Reply on the thread with the commit.

@minimal-foundry
Copy link
Copy Markdown
Contributor Author

That /revise is held, not dropped. A coder is already running on #3332. Your note is kept and goes into the next round here, which starts when that coder finishes.

Nothing to type again: the command gets a rocket when its round starts, or a refusal that names the reason. No round was counted for it yet.

@minimal-foundry
Copy link
Copy Markdown
Contributor Author

Round 4 of 10 on the runtime's review findings, pushed as 33b8f333c627.

line exit tail
cargo nextest run -p minimal box_logs_piped_pty_transcript_has_no_control_codes 0 warning: unknown fields in task runtime-implement-test-0: network warning: unknown fields in task runtime-implement-test-1: network help: do you need to update to a newer version of minimal? Applying loadouts: default Running task runtime-implement-test-0 in box runtime-implement-test-0-1... Comp
cargo nextest run -p minimal box_logs_raw_keeps_control_codes 0 warning: unknown fields in task runtime-implement-test-0: network warning: unknown fields in task runtime-implement-test-1: network help: do you need to update to a newer version of minimal? Applying loadouts: default Running task runtime-implement-test-1 in box runtime-implement-test-1-1... Comp

Verify min task run agent-verify exited 100.

 {
                "parent_span_id": "c884cdd640d3910e",
                "rpc": "minimald-v1-GetSessionRecord",
                "span_id": "f0fe76bb50d2c521",
                "trace_id": "0af7651916cd43dd8448eb211c803111",
            },
            parent: None,
            closed: true,
        },
        LoggedSpan {
            name: "sessions.manager.message",
            fields: {
                "kind": "GetRecord",
                "parent_span_id": "f0fe76bb50d2c521",
                "queued_behind": "0",
                "span_id": "531eaeb7019eafbc",
                "trace_id": "0af7651916cd43dd8448eb211c803111",
            },
            parent: None,
            closed: true,
        },
        LoggedSpan {
            name: "rpc",
            fields: {
                "parent_span_id": "c884cdd640d3910e",
                "rpc": "minimald-v1-DestroySession",
                "span_id": "67427b219a1683ce",
                "trace_id": "0af7651916cd43dd8448eb211c803111",
            },
            parent: None,
            closed: true,
        },
        LoggedSpan {
            name: "sessions.manager.message",
            fields: {
                "kind": "GetRecord",
                "parent_span_id": "67427b219a1683ce",
                "queued_behind": "0",
                "span_id": "2d8683ad130004f6",
                "trace_id": "0af7651916cd43dd8448eb211c803111",
            },
            parent: None,
            closed: true,
        },
        LoggedSpan {
            name: "sessions.manager.message",
            fields: {
                "kind": "DeleteSession",
                "parent_span_id": "67427b219a1683ce",
                "queued_behind": "0",
                "span_id": "f90c9b8fe5606372",
                "trace_id": "0af7651916cd43dd8448eb211c803111",
            },
            parent: None,
            closed: true,
        },
        LoggedSpan {
            name: "session.message",
            fields: {
                "kind": "Destroy",
                "parent_span_id": "f90c9b8fe5606372",
                "span_id": "1eb09a8a3c30707c",
                "trace_id": "0af7651916cd43dd8448eb211c803111",
            },
            parent: None,
            closed: true,
        },
        LoggedSpan {
            name: "sessions.manager.message",
            fields: {
                "kind": "HandOverName",
                "parent_span_id": "f90c9b8fe5606372",
                "queued_behind": "0",
                "span_id": "178af1863be7cdb0",
                "trace_id": "0af7651916cd43dd8448eb211c803111",
            },
            parent: None,
            closed: true,
        },
    ]
    note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

  Cancelling due to test failure: 
────────────
     Summary [  70.381s] 1100 tests run: 1099 passed, 1 failed, 2 skipped
        FAIL [   3.131s] (1100/1100) minimal::otel_cli exec_run_attach_and_task_run_share_the_commands_trace
error: test run failed

Outside the task's layers::

  • docs/specs/28-spec-box-cli/28-spec-box-cli.md

Converted to a draft: something above needs a person before review.

Review threads the coder judged:

  • 👍 valid — crates/minimal/src/cmd/boxes.rs:294: Csi and EscapeIntermediate now end at a line feed or carriage return, and keep it as text. A test pins both cases.

min box logs <pty box> | cat prints the transcript text with no terminal control sequences. A CSI or escape sequence with no final byte no longer hides the next lines. --raw prints the bytes unchanged, and a terminal still gets the raw stream.

Notes from the agent: Revise round 4: a line feed or carriage return now ends an unterminated CSI or escape-intermediate sequence, and the stripper keeps that byte as text. The unit cases are in box_logs_piped_pty_transcript_has_no_control_codes. cargo fmt --check and cargo clippy -p minimal --all-targets are clean.

@minimal-foundry
Copy link
Copy Markdown
Contributor Author

Round 5 of 10 on a /revise note: the coder changed nothing. The directive asks for the fix to thread PRRT_kwDOPdfcxM622ZH_. Commit 33b8f33 (fix(minimal): end unterminated CSI at a line end in box logs) already makes this change on the branch. In ControlStripper::step, a line feed or carriage return ends the Csi and EscapeIntermediate states and stays as text. The commit also adds assertions in box_logs_piped_pty_transcript_has_no_control_codes for a cut-off ESC [ before a line feed, and the next line prints. The merge c117fb2d keeps this change. I made no new change in this round. Both test lines pass at the head c117fb2d. The reply on the thread can cite commit 33b8f33.

@minimal-foundry
Copy link
Copy Markdown
Contributor Author

Round 6 of 10 on a failed check suite: the coder changed nothing. Revise round 6 addressed a failed tests job and its ci-linux-native-success aggregator. The job log excerpt in the directive does not name a failing test. It shows only passing decode tests and the cleanup steps. At the branch head (fdd9b6ac, which merges the latest origin/main), both task test lines pass, and the whole minimal crate suite passes (1101 run, 1101 passed). This branch changes only crates/minimal sources and adds two verify lines to the BCLI spec. No test in another crate reads those files. I found no defect in this task's code to fix, so I made no new commit this round. The failure is probably in another crate or is flaky, and it is outside this task's layers. A CI re-run at the head, which now includes the merge from main, will show if the failure repeats. I did not run the workspace suite, because no test line names it.

@agent-137
agent-137 marked this pull request as ready for review November 12, 2026 22:46
@minimal-arch minimal-arch Bot left a comment
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

arch-review: PASS · the full ruling

This head conforms. The new commit ends an unterminated CSI or escape sequence at a line end, and it keeps the line end as text. Before this change, such a sequence hid the transcript up to the next final byte. Line 473 of the architecture makes logs the PTY box's transcript. The fix keeps more of that transcript. The merge from main is outside this change. The ruling on 38a3ce2b stands for all other parts.

Ruled at 33b8f33 against gominimal/arch@15b603e6afb8 by claude-opus-5-5.

@minimal-foundry minimal-foundry Bot left a comment
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

minimal-review — advisory review

Verdict COMMENT — 1 finding, 1 inline.

Panel: 3 of 3 personas ran (correctness, security, supply-chain).

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.

T45 — Box logs strips terminal control codes when stdout is not a terminal

1 participant

0