Skip to content

[Detail Bug] S2 CLI Trim/Fence commands print incorrect stream tail position #693

Description

@detail-app

Detail Bug Report

https://app.detail.dev/org_89d327b3-b883-4365-b6a3-46b6701342a9/bugs/bug_0b819e13-abcf-4013-a11b-8c633c22ff07

Introduced in #103 by @infiniteregrets on Jan 28, 2026

Summary

  • Context: The Trim and Fence commands in the S2 CLI append command records to a stream and display the resulting tail position.
  • Bug: Both commands incorrectly use out.start (position of the appended command record) instead of out.tail (the actual stream tail position) in their output messages.
  • Actual vs. expected: The output label says "tail:" but displays the sequence number of the command record itself, not the sequence number that will be assigned to the next record on the stream.
  • Impact: Users receive misleading output showing an incorrect tail position, which could cause confusion when verifying stream state or debugging concurrent operations.

Code with Bug

// `cli/src/main.rs`
Command::Trim(args) => {
    let trim_point = args.trim_point;
    let out = ops::trim(&s2, args).await?;
    eprintln!(
        "{}",
        format!(
            "✓ [APPENDED] trim to {} // tail: {}",
            trim_point,
            format_position(out.start.seq_num, out.start.timestamp)  // <-- BUG 🔴 prints start (record position), not stream tail
        )
        .green()
        .bold()
    );
}

Command::Fence(args) => {
    let fencing_token = args.new_fencing_token.clone();
    let out = ops::fence(&s2, args).await?;
    eprintln!(
        "{}",
        format!(
            "✓ [APPENDED] new fencing token \"{}\" // tail: {}",
            fencing_token,
            format_position(out.start.seq_num, out.start.timestamp)  // <-- BUG 🔴 prints start (record position), not stream tail
        )
        .green()
        .bold()
    );
}

Explanation

  • AppendAck.tail is defined as “sequence number that will be assigned to the next record on the stream” (same concept returned by check_tail()). The CLI’s Append command already follows this contract by printing ack.batch.tail under the "tail:" label.
  • Trim and Fence also append records and receive an AppendAck, but they print out.start while still labeling it as "tail:". This is incorrect and becomes clearly observable under concurrency where out.tail.seq_num can be greater than out.start.seq_num + 1.

Codebase Inconsistency

The Append command output establishes the intended meaning of "tail:" as AppendAck.tail:

// `cli/src/main.rs`
eprintln!(
    "{}",
    format!(
        "✓ [APPENDED] {}..{} // tail: {}",
        ack.batch.start.seq_num,
        ack.batch.end.seq_num,
        format_position(ack.batch.tail.seq_num, ack.batch.tail.timestamp)
    )
    .green()
    .bold()
);

Recommended Fix

Update Trim and Fence output to use out.tail:

  • Replace format_position(out.start.seq_num, out.start.timestamp) with format_position(out.tail.seq_num, out.tail.timestamp) in both command handlers.

History

This bug was introduced in commit dc3bd4e when s2-cli was initially added: Trim/Fence printed out.start while labeling it "tail:", while Append printed ack.batch.tail.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions