# How Commit-Scoped Commenting Works in Tuicr: A Technical Deep Dive

> Discover how Tuicr's commit-scoped commenting works. Learn how commit SHA and user selection filters comments for a streamlined review process.

- Repository: [Almog Gavra/tuicr](https://github.com/agavra/tuicr)
- Tags: deep-dive
- Published: 2026-08-01

---

**Tuicr implements commit-scoped commenting by storing an optional commit SHA in each comment's `commit_id` field, then filtering visibility based on the user's current commit selection in the review interface.**

When reviewing pull requests that span multiple commits, context is everything. Commit-scoped commenting in Tuicr allows reviewers to attach feedback to specific commits rather than the cumulative diff, ensuring comments remain relevant even as the PR evolves. This feature is built into the Rust-based TUI code review tool through a three-component architecture that handles data storage, user selection, and visibility filtering.

## The Core Architecture

Tuicr's commit-scoped commenting system relies on three integrated components working together across the application layer and data model.

### The Data Model: `Comment::commit_id`

At the heart of the system is an optional `String` field on the `Comment` struct. Located in [`src/model/comment.rs`](https://github.com/agavra/tuicr/blob/main/src/model/comment.rs) at lines 86-94, this field stores the SHA of the commit against which the comment was created.

- When `commit_id` is `Some(sha)`, the comment is bound to that specific commit.
- When `commit_id` is `None`, the comment is considered unbound (either a legacy comment or one targeting the cumulative diff).

This optional binding allows the system to support both granular, commit-specific feedback and general PR-level comments within the same data structure.

### The Commit Selector

The user interface provides a commit selector that determines the current viewing context. Implemented in [`src/app/commits.rs`](https://github.com/agavra/tuicr/blob/main/src/app/commits.rs) at lines 36-45, this component tracks the user's selection through `App::commit_selection_range`.

When the selector resolves to exactly one commit—meaning `commit_selection_range` equals `Some((i, i))`—the application knows to scope new comments to that specific SHA. If the selector shows multiple commits or the full range, the system treats the view as cumulative.

### The Visibility Predicate

To determine whether a comment should appear in the current view, Tuicr uses the `App::comment_visible()` method and its zero-allocation counterpart `comment_visible_with()`, defined in [`src/app/commits.rs`](https://github.com/agavra/tuicr/blob/main/src/app/commits.rs) at lines 4-30.

This predicate checks if a comment's `commit_id` exists within the currently selected commit set:

- Comments with `commit_id: None` are always visible.
- Comments with a specific SHA are visible only when that commit is selected.
- When viewing all commits, all commit-scoped comments become visible.

## The Comment Lifecycle

Understanding how a comment flows through the system clarifies how commit-scoping is applied in practice.

### 1. Commit Selection

When a user presses `)` to cycle the inline commit selector, the application updates `commit_selection_range`. If the selection resolves to a single commit, `App::commit_id_for_new_comment()` returns that commit's SHA; otherwise, it returns `None`.

### 2. Comment Creation

During the comment creation flow in [`src/app/comments.rs`](https://github.com/agavra/tuicr/blob/main/src/app/comments.rs), the system consults `commit_id_for_new_comment()` to determine the scope:

```rust
let commit_id = self.commit_id_for_new_comment();   // may be Some(sha) or None
let mut comment = Comment::new(content, comment_type, side);
comment.commit_id = commit_id;

```

This stamps the current commit SHA onto the comment before persistence.

### 3. Persistence and Rendering

Once saved, the comment carries its commit binding in the session JSON. During rendering—handled in both [`src/ui/diff_unified.rs`](https://github.com/agavra/tuicr/blob/main/src/ui/diff_unified.rs) and [`src/ui/diff_side_by_side.rs`](https://github.com/agavra/tuicr/blob/main/src/ui/diff_side_by_side.rs)—the diff view calls `app.comment_visible(&comment)` for every frame.

The visibility check compares the comment's stored SHA against `selected_commit_set()`. If the user switches to a different commit, the comment disappears from view but remains in the session data, ready to reappear when the original commit is selected again.

## Practical Implementation Examples

### Creating a Commit-Scoped Comment Interactively

When working within the TUI, the application handles scoping automatically based on the current selector state:

```rust
// Inside the TUI comment-creation path
let commit_id = app.commit_id_for_new_comment(); // e.g. Some("b1e2c3d")
let mut comment = Comment::new(
    "Fix the off-by-one bug".to_string(),
    CommentType::from_id("issue"),
    Some(LineSide::New),
);
comment.commit_id = commit_id; // stamps the current commit SHA
app.save_comment(comment);

```

### Adding a Comment via the Library API

For programmatic access, you can explicitly specify the commit SHA when creating comments:

```rust
use tuicr::{review_store::{AddCommentRequest, CommentTarget}, model::CommentType};

let req = AddCommentRequest {
    session_slug: "myrepo".into(),
    path: "src/main.rs".into(),
    target: CommentTarget::Line {
        line: 42,
        side: LineSide::New,
    },
    content: "Consider using `Result` instead of panicking".into(),
    comment_type: CommentType::from_id("suggestion"),
    // Explicitly bind the comment to a specific commit SHA
    commit_id: Some("d4e5f6a".to_string()),
};
add_comment_to_session(&repo_path, req).unwrap();

```

### Filtering Comments Manually

You can leverage the visibility predicate directly when processing comments outside the standard UI flow:

```rust
use std::collections::HashSet;
use tuicr::app::App;

// Assume `app` is already built and the selector currently selects commits "abc" and "def"
let commit_set: HashSet<String> = ["abc".to_string(), "def".to_string()]
    .iter().cloned().collect();

for comment in app.session.comments_iter() {
    if App::comment_visible_with(&comment, Some(&commit_set)) {
        println!("Visible comment: {}", comment.content);
    }
}

```

## Edge Cases and Legacy Support

The system includes specific handling for various viewing scenarios and backward compatibility.

### Legacy Comments

Comments created before the `commit_id` field was introduced carry `commit_id: None`. According to the visibility rules in [`src/app/commits.rs`](https://github.com/agavra/tuicr/blob/main/src/app/commits.rs), these comments are always displayed regardless of the current commit selection, ensuring backward compatibility with existing review sessions.

### Full-Range and Multi-Commit Views

When `commit_selection_range` is set to `Some((0, n-1))` (the full range) or any subset where `start != end`, the system treats the view as cumulative. In these cases:

- `commit_id_for_new_comment()` returns `None`, preventing ambiguous scoping.
- All commit-scoped comments become visible because the selected set contains every relevant SHA.

This design choice ensures that comments are only bound to commits when the user is viewing a single, unambiguous commit context.

### Testing Coverage

The visibility logic is verified by the unit test suite in [`src/app/tests/commit_scoped_comment_tests.rs`](https://github.com/agavra/tuicr/blob/main/src/app/tests/commit_scoped_comment_tests.rs), which covers legacy comment visibility, single-commit selection behavior, full-range selection, and inactive selector states.

## Summary

Commit-scoped commenting in Tuicr enables precise feedback attribution through a lightweight but robust mechanism:

- **Optional binding**: The `commit_id` field in [`src/model/comment.rs`](https://github.com/agavra/tuicr/blob/main/src/model/comment.rs) stores an optional SHA, allowing both scoped and unscoped comments.
- **Context-aware creation**: The `commit_id_for_new_comment()` method in [`src/app/commits.rs`](https://github.com/agavra/tuicr/blob/main/src/app/commits.rs) only stamps commit IDs when viewing a single commit.
- **Dynamic filtering**: The `comment_visible()` predicate ensures comments appear only when their associated commit is selected, or always if unscoped.
- **Backward compatibility**: Legacy comments with `None` commit IDs remain visible in all contexts.

## Frequently Asked Questions

### How do I view comments from all commits at once?

When you select the full commit range or disable the commit selector, Tuicr treats the view as cumulative. In this mode, all commit-scoped comments become visible simultaneously, regardless of which specific commit they target, because the selected set contains every SHA in the range.

### What happens to commit-scoped comments when I switch to a different commit?

The comments remain stored in your review session but are filtered from the display. The `comment_visible()` predicate in [`src/app/commits.rs`](https://github.com/agavra/tuicr/blob/main/src/app/commits.rs) checks the current `selected_commit_set()` against each comment's `commit_id`. When you navigate back to the original commit, the comments reappear automatically.

### Can I create a commit-scoped comment when viewing multiple commits?

No. When the commit selector shows a range or multiple commits (`start != end`), the `commit_id_for_new_comment()` method returns `None`. This prevents ambiguous scoping—comments are only bound to specific commits when you are viewing exactly one commit in the TUI.

### Where is the commit-scoped commenting logic tested?

The unit tests reside in [`src/app/tests/commit_scoped_comment_tests.rs`](https://github.com/agavra/tuicr/blob/main/src/app/tests/commit_scoped_comment_tests.rs). These tests verify visibility behavior for legacy comments without commit IDs, single-commit selection filtering, full-range cumulative views, and scenarios where the selector is inactive.