Skip to content

feat(tui): replace /retitle with local /rename - #826

Merged
anandh8x merged 2 commits into
mainfrom
fix/tui-session-rename
Jul 30, 2026
Merged

feat(tui): replace /retitle with local /rename#826
anandh8x merged 2 commits into
mainfrom
fix/tui-session-rename

Conversation

@anandh8x

@anandh8x anandh8x commented Jul 29, 2026

Copy link
Copy Markdown
Collaborator

Summary

  • Replace the bulk /retitle command with a local /rename [title] command.
  • Make bare /rename open a prefilled editor with Enter-to-save and Esc-to-cancel behavior.
  • Preserve names chosen before a fresh session's first prompt and prevent a late automatic-title response from overwriting a manual rename.
  • Polish /resume with aligned timestamp/title columns, hidden-but-searchable raw session IDs, and a visible position count.

Why

Renaming a session should be an immediate local metadata operation rather than a model-backed bulk action. The previous resume rows also gave raw IDs too much visual space, truncating the titles users actually scan for.

Impact

Users can rename the current session without a provider call or token usage, including before the first prompt. Resume rows are cleaner and easier to scan while session IDs remain available through search.

Validation

  • make fmt-check
  • go vet ./...
  • go test ./...
  • go run ./cmd/zero-release build
  • go run ./cmd/zero-release smoke
  • make lint-static
  • make vulncheck
  • git diff HEAD --check
  • Manual TUI verification of bare rename, inline rename, save, cancel, prefill, fresh-session naming, and the resume picker

Summary by CodeRabbit

  • New Features
    • Added /rename to rename the active session or set a title before the first prompt.
    • Added an interactive rename editor with save, cancel, validation, and paste support.
    • Session pickers now show cleaner titles, aligned timestamps, safer searchable entries, and “position / total” pagination.
  • Bug Fixes
    • Automatic titles no longer overwrite manual renames (even when an auto-title is in progress).
    • Empty rename pastes no longer trigger clipboard image handling.
    • /retitle is no longer available; rename editor state better blocks unrelated UI interactions.

BREAKING CHANGE: /retitle is removed; use /rename instead.

@github-actions

github-actions Bot commented Jul 29, 2026

Copy link
Copy Markdown
Contributor

Zero automated PR review

Verdict: No blockers found

Blockers

  • None found.

Validation

  • [pass] Diff hygiene: git diff --check
  • [pass] Tests: go test ./...
  • [pass] Build: go run ./cmd/zero-release build
  • [pass] Smoke build: go run ./cmd/zero-release smoke

Scope

Head: 36f16b7483c0
Changed files (16): internal/sessions/session_title_test.go, internal/sessions/store.go, internal/tui/btw.go, internal/tui/clipboard.go, internal/tui/commands.go, internal/tui/composer.go, internal/tui/model.go, internal/tui/model_test.go, internal/tui/session.go, internal/tui/session_rename.go, internal/tui/session_rename_test.go, internal/tui/session_title.go, and 4 more

This deterministic review checks validation status and basic diff hygiene. A human reviewer still owns product judgment and design quality.

@coderabbitai

coderabbitai Bot commented Jul 29, 2026

Copy link
Copy Markdown

Review Change Stack

Walkthrough

The TUI replaces /retitle with /rename, adds interactive and pending-session rename support, and conditionally persists automatic titles so stale generation cannot overwrite manual names. Session picker labels and overlay/sidebar behavior are also updated.

Changes

Session title flow

Layer / File(s) Summary
Conditional title storage
internal/sessions/store.go, internal/sessions/session_title_test.go
Adds locked UpdateTitleIfCurrent, applying trimmed non-empty titles only when the stored title matches the expected value, with matching and stale-update tests.
Manual rename command and editor
internal/tui/commands.go, internal/tui/model.go, internal/tui/session_rename.go, internal/tui/session.go, internal/tui/clipboard.go, internal/tui/composer.go, internal/tui/btw.go, internal/tui/session_rename_test.go
Adds /rename, interactive editing, pending titles, validation, persistence, paste handling, modal routing, and command-flow tests.
Automatic title consistency
internal/tui/session_title.go, internal/tui/session_title_test.go
Automatic title generation uses conditional updates and applies results only when the stored title remains unchanged.
Picker and overlay presentation
internal/tui/session.go, internal/tui/view.go, internal/tui/model_test.go, internal/tui/sidebar.go, internal/tui/transcript_selection.go
Session picker labels hide IDs while retaining searchability, add aligned timestamps and position counts, and suppress sidebar interactions for active MCP UI state.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant User
  participant TUIModel
  participant SessionStore
  participant AutoTitle
  User->>TUIModel: Enter /rename
  TUIModel->>SessionStore: Persist manual title
  SessionStore-->>TUIModel: Updated metadata
  AutoTitle->>SessionStore: UpdateTitleIfCurrent(original title, generated title)
  SessionStore-->>AutoTitle: applied=false when manual title changed
  AutoTitle-->>TUIModel: Report title result
Loading

Possibly related PRs

  • Gitlawb/zero#224: Extends the same session title persistence functionality with conditional title updates.
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 15.79% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely captures the main change: replacing /retitle with a local /rename command in the TUI.
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/tui-session-rename

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai 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.

Actionable comments posted: 2

🧹 Nitpick comments (1)
internal/tui/session_title_test.go (1)

275-312: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add the missing branch assertion: stale auto-title must keep the retry gate set.

handleSessionTitleGenerated has three outcomes (apply / stale-skip-keep-gate / failure-release-gate); this test proves the store-level CAS outcome but doesn't drive result through handleSessionTitleGenerated to confirm titledSessions[session.SessionID] stays true after a stale (applied:false, err:nil) result — the one combination not covered by TestAutoTitleFailureReleasesRetryGate.

 	got, err := store.Get(session.SessionID)
 	if err != nil || got == nil {
 		t.Fatalf("get session: %v", err)
 	}
 	if got.Title != "Manual Name" {
 		t.Fatalf("late automatic title overwrote manual name: %q", got.Title)
 	}
+
+	next, _ := m.handleSessionTitleGenerated(result)
+	if !next.titledSessions[session.SessionID] {
+		t.Fatal("a stale auto-title result must not release the retry gate (manual rename already won)")
+	}
 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@internal/tui/session_title_test.go` around lines 275 - 312, Extend
TestManualRenameWinsOverInFlightAutoTitle to pass the stale successful result
through handleSessionTitleGenerated after execCmd, then assert
titledSessions[session.SessionID] remains true. Preserve the existing
store-level assertions and verify the applied:false, err:nil branch keeps the
retry gate set.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@internal/tui/model_test.go`:
- Around line 942-949: Update TestSessionPickerLabelAlignsTitles to assert that
todayColumn and olderColumn are non-negative before comparing them, so missing
titles fail the test rather than matching at -1; retain the existing alignment
assertion for present titles.

In `@internal/tui/session_rename.go`:
- Around line 46-53: Update renameActiveSession to truncate the trimmed title to
tuiSessionTitleLimit before validating and storing it, preserving the existing
empty-title and unavailable-storage handling.

---

Nitpick comments:
In `@internal/tui/session_title_test.go`:
- Around line 275-312: Extend TestManualRenameWinsOverInFlightAutoTitle to pass
the stale successful result through handleSessionTitleGenerated after execCmd,
then assert titledSessions[session.SessionID] remains true. Preserve the
existing store-level assertions and verify the applied:false, err:nil branch
keeps the retry gate set.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: fab9a4d9-a0fa-42a8-a3e4-3632c1506cfc

📥 Commits

Reviewing files that changed from the base of the PR and between 097c265 and daee6c1.

📒 Files selected for processing (16)
  • internal/sessions/session_title_test.go
  • internal/sessions/store.go
  • internal/tui/btw.go
  • internal/tui/clipboard.go
  • internal/tui/commands.go
  • internal/tui/composer.go
  • internal/tui/model.go
  • internal/tui/model_test.go
  • internal/tui/session.go
  • internal/tui/session_rename.go
  • internal/tui/session_rename_test.go
  • internal/tui/session_title.go
  • internal/tui/session_title_test.go
  • internal/tui/sidebar.go
  • internal/tui/transcript_selection.go
  • internal/tui/view.go

Comment thread internal/tui/model_test.go
Comment thread internal/tui/session_rename.go

@gnanam1990 gnanam1990 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Verdict

Changes requested — for one thing that is not a code change. The engineering here is sound and I could not break it; the problem is that as titled, this PR will silently drop a user-facing breaking change from the changelog.

Reviewed at 36f16b7, base 097c265 (level with origin/main, zero commits behind). Author has write access, so this is the internal cycle rather than the issue-approved gate.

What I verified

  • The compare-and-swap actually does the work it claims. I gutted it — removed the session.Title != strings.TrimSpace(expected) guard at internal/sessions/store.go:775 so a late automatic title always overwrites — and two independent tests failed, one at each layer:

    --- FAIL: TestUpdateTitleIfCurrent
        stale update should preserve manual title: Title:"Late generated title" ... true
    --- FAIL: TestManualRenameWinsOverInFlightAutoTitle
        late automatic title should be skipped, got {title:"Generated Automatic Title", applied:true}
    
  • The pre-first-prompt path is guarded, and the guard is tested. Removing the m.titledSessions[session.SessionID] = true block at internal/tui/session.go:48-53 fails TestRenameNamesFreshSessionBeforeFirstPrompt ("a manually named fresh session must skip automatic naming"). Belt and braces here — sessionTitleIsAuto at session_title.go:213 would also refuse a manual title — but the explicit gate is the one under test.

  • "Hidden but searchable" holds. Dropping Meta: meta.SessionID from the picker item does not cost searchability: scorePickerItem builds its haystack from Group, Label, Value, Meta (internal/tui/picker.go:168) and Value is still the session ID.

  • The n / total footer is consistent with the filtered view. applyPickerFilter replaces p.items wholesale (picker.go:158) and resets selected to 0, so the counter and the visible list always agree. I went looking for an off-by-one against an unfiltered total and there isn't one.

  • /retitle is fully excised — no leftover retitleQueue/retitleActive/retitleTotal/retitleDone/retitleOK fields, no stale docs. The only surviving reference is the negative test at session_rename_test.go:182.

  • Gauntlet, darwin/arm64, non-/tmp checkout: make fmt-check clean, go vet ./... clean, go test ./... fully green, go test -race ./internal/tui/ ./internal/sessions/ -count=3 green, go run ./cmd/zero-release build and smoke both pass, git diff HEAD --check clean.

  • Passes executed: 0–5, 7–12. Pass 6 was run narrowly rather than in full — this diff has no auth, exec, parsing or network surface; I checked the two boundaries it does touch (the new store write path and the paste route) and nothing else applied.

Blocking

  1. The PR title is not a conventional commit, and this repo derives its changelog from the squash subject. — PR title / release-please-config.json

    The chain, each hop checked:

    • release-please-config.json and .github/workflows/release-please.yml mean versioning and CHANGELOG.md are generated from conventional-commit subjects.
    • gh api repos/Gitlawb/zero reports squash_merge_commit_title=COMMIT_OR_PR_TITLE. This PR has two commits (daee6c15, 36f16b74), so the squash subject will be the PR title, not a commit subject.
    • That title is Improve session naming and resume picker — no type, no scope. release-please parses no type, so the change contributes no changelog entry and no version bump.
    • Every recently merged PR does follow the convention: fix(sandbox):, test(tools):, fix(config):.

    That would be a minor annoyance on an ordinary change. It is not one here, because this PR removes /retitle, which shipped in #224 and has been present in every release from v0.3.0 through v0.6.0. A command that existed in the last release disappears, and under the current title the changelog will not say so.

    Retitle to something like feat(tui)!: replace /retitle with a local /rename and add a BREAKING CHANGE: /retitle is removed; use /rename footer. No code change required — this is the whole blocker.

Non-blocking

  • && msg.applied currently has no observable effect.internal/tui/session_title.go:255. I mutated it out and the entire internal/tui suite stayed green, so I traced why rather than reporting it as untested-and-therefore-broken. When the store rejects the update, UpdateTitleIfCurrent returns the freshly-read metadata (store.go:777), so msg.title is already the manual title — assigning it to m.activeSession.Title is a no-op, and the titledSessions gate is retained on both branches either way. The flag is correct defensive code that becomes load-bearing the moment UpdateTitleIfCurrent returns anything else on rejection. Worth a one-line comment saying that, so a future reader does not delete it as dead.
  • Four separable changes in one PR. — diffstat. The /retitle/rename swap, the rename editor, the pre-prompt naming plus compare-and-swap, and the /resume picker relayout (session.go:406-436, view.go:816-825) are independent; the picker work does not depend on any of the rename work. Team PR through the internal cycle, so I am not treating this as a scope close — but the picker change is the one a bisect would most want isolated.
  • Merge-conflict exposure with two long-lived branches. #643 and #570 both touch internal/tui/session.go, commands.go and model.go. Neither is close to merging, and this branch is current, so the right outcome is probably that they rebase onto this — worth saying so on those PRs rather than holding this one.
  • /rename is missing from the README command table.README.md:214. /resume, /rewind are listed as the session commands; /retitle never was, so nothing is stale, but a new user-facing command belongs on that line.
  • Blank submit closes the editor instead of holding it open.internal/tui/session_rename.go:32-37. m.renamePrompt = nil is set before validation, so Enter on whitespace closes the editor and prints an error. TestRenameEditorRejectsBlankAndEscCancels:157 asserts this deliberately, so I read it as intended rather than an oversight — flagging only because the user loses their editing context to recover from a typo.

Questions for the author

  • /retitle refused to run mid-turn (Cannot retitle sessions while a run is active); /rename has no m.pending guard. I believe that is correct — the old guard existed because /retitle made provider calls and /rename is pure local metadata, and the in-flight case is exactly what the compare-and-swap covers. Confirming that was deliberate rather than dropped with the surrounding code.

Not covered by this PR

  • A migration path for /retitle. It now resolves to nothing, so a user who typed it last week gets a generic unknown-command error. A one-release alias that prints "renamed to /rename" would be kinder than a changelog line alone, though the changelog line is the part I am blocking on.
  • Bulk retitling of old sessions is simply gone as a capability. That looks intentional given the "no provider call, no token usage" rationale, but nothing in the PR body says the bulk case was considered and dropped rather than overlooked.

Not verified

  • Windows and Linux — everything above is darwin/arm64 only. The diff is platform-neutral TUI and store code, and internal/sessions locking is unchanged by this PR, so I did not expect divergence and did not look for it.
  • The manual TUI walkthrough listed in the PR description. I exercised the rename paths through the model's Update loop and the store, not through a real terminal, so the editor's rendering and the picker's new column alignment are unconfirmed by eye.
  • Cross-process races. UpdateTitleIfCurrent takes the same per-session lock as UpdateTitle and AppendEvent, and I read that as correct, but I did not run two zero processes against one session to prove it.

@Vasanthdev2004 Vasanthdev2004 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Approving, with two small things you can take or leave.

renameActiveSession (session_rename.go:47) does TrimSpace then cutRunes, which strips the ends but keeps interior newlines. /rename foo<newline>bar persists a multi-line title into metadata, and the pickers and listings all assume one line. The other title paths collapse whitespace, so this one is the odd one out.

The empty-paste guard in routePaste (clipboard.go:79-81) looks unreachable: the right-click path already returns earlier, so nothing gets there with an empty payload. The clipboard change is also the one part of this PR with no test.

Neither is worth holding it for. The store change is backward compatible, sessions without the new fields still load, and I could not get the picker to point at a deleted session.

@anandh8x anandh8x changed the title Improve session naming and resume picker feat(tui)!: replace /retitle with local /rename Jul 29, 2026
@anandh8x

Copy link
Copy Markdown
Collaborator Author

@gnanam1990 Updated the PR title to the conventional breaking-change format and added the BREAKING CHANGE note. Could you please re-review and clear the changes-requested status if this resolves the blocker?

@anandh8x
anandh8x requested a review from gnanam1990 July 30, 2026 11:34
@Vasanthdev2004

Copy link
Copy Markdown
Collaborator

@gnanam1990 your blocker is done — the title is now feat(tui)!: replace /retitle with local /rename, two commits so the squash subject is the PR title, and release-please will see the !. Worth flipping your review when you get a minute; my approval on 36f16b7 still stands and the code hasn't moved.

Doing exactly what you asked did surface two things about the release mechanics that I don't think either of us looked at, and one of them is a real decision rather than a nit.

The ! is on track to cut 1.0.0, not 0.7.0. release-please-config.json doesn't set bump-minor-pre-major, and that's the flag whose entire job is "breaking changes only bump semver minor if version < 1.0.0". Without it a breaking change bumps major, so at 0.6.x that's 1.0.0. The open release PR #837 is currently proposing 0.6.1, so merging this would take that from a patch to a major in one step. @kevin-hnnh that's your call, not mine — this PR is correct either way, but 1.0.0 arriving as a side effect of a TUI command rename seems worth a deliberate yes. If the answer is "not yet", setting bump-minor-pre-major: true gets you 0.7.0 and keeps the breaking-change entry.

The BREAKING CHANGE: footer is in the wrong place to reach the commit. It's in the PR description, but this repo has squash_merge_commit_message=COMMIT_MESSAGES, so the squash body comes from the two commit messages — "Improve session naming and resume picker" and "Address session rename review feedback" — and the PR body is dropped. The ! still gets you the bump and the breaking flag, but the footer is what makes the changelog actually say why, which was gnanam's point in the first place. Putting the footer in a commit message fixes it.

Neither is a code change and I'm not re-blocking on either. Flagging because this would be the repo's first ! commit — nothing on main has ever carried one, so this is the first time the config gets exercised.

@gnanam1990 gnanam1990 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Verdict

Changes requested — but for a consequence my own previous review created, not for anything you did wrong. The title fix is exactly right; following it will, on current config, cut v1.0.0 instead of v0.7.0. That needs a decision before merge, and it is a one-line config change or a deliberate "yes, 1.0.0".

Re-reviewed at 36f16b7, base 097c265 — the same commit as my previous review. My freshness check missed this fix entirely, because the head SHA cannot move when the change is to PR metadata. Worth recording as a limitation of SHA-diffing when the blocker itself lives outside git.

Withdrawn — the changelog blocker is fixed

The title is now feat(tui)!: replace /retitle with local /rename, with the ! breaking marker. With two commits, squash_merge_commit_title=COMMIT_OR_PR_TITLE takes the PR title, so the squash subject will be conventional and breaking-marked. Resolved.

While confirming the mechanism I found much better evidence than I originally posted, which is worth leaving on the record because it shows this was not a theoretical concern. Five merged PRs whose squash subjects lacked a conventional type are absent from CHANGELOG.md entirely:

Commit on main In CHANGELOG
c00a473 Add Atlas Cloud provider preset (#784) no
ab2f9fb Add shell completion generation (#764) no
18cce35 Add deterministic completion policy (#719) no
9242b9e Add transcript-grounded structured task state (#761) no
0125e70 Fix pinned Go quality tools on Go 1.26 (#689) no

A whole provider preset and a new user-facing command shipped with no changelog record. That is the class, it predates this PR, and it deserves its own issue rather than anything from you here.

Blocking

  1. feat(tui)!: will bump 0.6.0 → 1.0.0, not 0.7.0.release-please-config.json

    The trace, each hop verified against origin/main:

    • .release-please-manifest.json is {".":"0.6.0"}, and CHANGELOG.md's newest heading is ## [0.6.0], so release-please's state is consistent and current at 0.6.0.
    • release-please-config.json sets release-type, include-component-in-tag, bootstrap-sha and package-name. It does not set bump-minor-pre-major.
    • release-please's default for bump-minor-pre-major is false, which means a breaking change on a 0.x version bumps to 1.0.0 rather than to 0.7.0.
    • The workflow is pinned to googleapis/release-please-action@a02a34c… (v4.2.0), so this is not version drift on my part.
    • Nothing has ever exercised this path here: no commit on main carries a BREAKING CHANGE footer, none uses the ! marker, and CHANGELOG.md has never contained a breaking-changes section. #826 would be the first.

    So the likely outcome of merging as-is is a v1.0.0 tag and a 1.0.0 publish of @gitlawb/zero, triggered by a TUI command rename. Tags and registry publishes are the awkward kind of thing to walk back.

    Two clean resolutions, and this is a maintainer call rather than a code fix:

    • Add "bump-minor-pre-major": true to release-please-config.json — then feat(tui)!: yields 0.7.0 and still records the breaking change. This looks like what the project actually wants, given it is deliberately pre-1.0 and CHANGELOG.md says versioning applies "once the first release is tagged".
    • Or accept 1.0.0 knowingly, in which case that decision belongs in the PR description so it is not a surprise in the release PR.

    I want to be precise about what I did and did not do: this is a configuration-reading proof, not an executed one. I did not run release-please against this branch, so I cannot show you the computed version. If you would rather not take the default on faith, the release PR that this merge opens will state the version before anything is tagged — that is a safe place to confirm.

Non-blocking

  • The BREAKING CHANGE: footer in the PR description will not reach the commit. — PR body. The footer is there and correctly worded (/retitle is removed; use /rename instead.), but squash_merge_commit_message=COMMIT_MESSAGES builds the squash body from the commit messages, which are Improve session naming and resume picker and Address session rename review feedback. Neither carries it. The ! in the subject is enough for release-please to classify the change as breaking, so the entry will appear — it will just appear without the sentence telling users what to do instead, which is the part users need. Either amend a commit to carry the footer, or paste it into the squash body in the merge dialog.

Carried forward from my previous review, unchanged

  • Four separable changes in one PR. The /retitle/rename swap, the rename editor, the pre-prompt naming plus compare-and-swap, and the /resume picker relayout (session.go:406-436, view.go:816-825) are independent. Team PR through the internal cycle, so not a scope close — but the picker change is the one a bisect would most want isolated.
  • Merge-conflict exposure with #643 and #570, which both touch internal/tui/session.go, commands.go and model.go.
  • /rename is missing from the README command table (README.md:214).
  • Blank submit closes the editor rather than holding it open (session_rename.go:32-37); the test asserts this deliberately, so I read it as intent.

Everything I verified about the code itself at 36f16b7 stands — the compare-and-swap is load-bearing under mutation, the pre-prompt gate is tested, /retitle is cleanly excised, and the full gauntlet was green. The only thing standing between this and a merge is which version number it cuts.

@anandh8x anandh8x changed the title feat(tui)!: replace /retitle with local /rename feat(tui): replace /retitle with local /rename Jul 30, 2026
@anandh8x

Copy link
Copy Markdown
Collaborator Author

@gnanam1990 removed the breaking marker so this remains a pre-1.0 minor release instead of triggering v1.0.0. Could you re-review and approve if everything looks good?

@gnanam1990 gnanam1990 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Verdict

Approve. Both of my blockers are resolved, and you picked the right resolution for the second one. Apologies for the two rounds of churn — the first ask created the second problem, and that is on me, not on the change.

Re-reviewed at 36f16b7, base 097c265. The code tree is byte-identical to my two previous reviews (git diff 36f16b7..refs/pull/826/head is empty); the entire delta since my last review is the PR title.

Withdrawn — both blockers

1. The changelog entry. The title is now feat(tui): replace /retitle with local /rename. With two commits, squash_merge_commit_title=COMMIT_OR_PR_TITLE takes the PR title, so the squash subject is conventional and release-please will record it under Features. The subject also states the removal in plain words, which is most of what a reader scanning the changelog needs.

2. The 1.0.0 bump. Dropping the ! avoids it. Traced to be sure rather than assumed:

  • Squash subject: feat(tui): replace /retitle with local /rename (#826) — no !.
  • Squash body comes from squash_merge_commit_message=COMMIT_MESSAGES, i.e. Improve session naming and resume picker and Address session rename review feedback. Neither carries a BREAKING CHANGE: footer.
  • With neither ! nor a footer, release-please classifies a plain featminor bump, 0.6.0 → 0.7.0.

That is the safe outcome and it needs no config change to get there.

Non-blocking — one thing to watch at merge time

The BREAKING CHANGE: footer is still in the PR description. — PR body

It is no longer reachable by the automation, because the squash body is assembled from commit messages rather than the description. But it is sitting right there in the description, which makes it a natural thing for whoever merges to paste into the squash message. If that happens, release-please sees a breaking change, and with bump-minor-pre-major still unset in release-please-config.json the bump becomes 1.0.0 after all.

So the 1.0.0 risk is now conditional on merge-time behaviour rather than eliminated. Either is fine:

  • Drop the footer from the description, so there is nothing to paste.
  • Or leave it and merge with the default squash body, taking care not to add it.

The better end state is neither of those, and it is not your job here. Removing a command that shipped in v0.3.0 through v0.6.0 genuinely is a breaking change, and the reason it cannot be marked as one is that release-please-config.json lacks "bump-minor-pre-major": true — so ! currently means "go to 1.0.0" instead of "minor bump, flagged breaking". Setting that flag would let this and every future breaking change be labelled honestly while the project stays pre-1.0. That is a one-line repo-config PR and it should not hold this one up.

For the record, since it is the thing a user upgrading would want and will not get: /retitle existed in v0.3.0, v0.4.0, v0.5.0 and v0.6.0, and after this it is gone with /rename as the replacement. It will appear in the changelog as a feature rather than under a breaking-changes heading.

Carried forward, unchanged and not blocking

  • Four separable changes in one PR — the /retitle/rename swap, the rename editor, the pre-prompt naming plus compare-and-swap, and the /resume picker relayout (session.go:406-436, view.go:816-825). Team PR through the internal cycle, so not a scope close, but the picker change is the one a bisect would most want isolated.
  • Merge-conflict exposure with #643 and #570, which both touch internal/tui/session.go, commands.go and model.go. This branch is current, so those should rebase onto it.
  • /rename is missing from the README command table (README.md:214).
  • Blank submit closes the editor rather than holding it open (session_rename.go:32-37) — asserted deliberately by the test, so read as intent.

Not re-verified

Nothing about the code needed re-running: the tree is unchanged from my first review, where the compare-and-swap held up under mutation at both layers, the pre-prompt titledSessions gate was mutation-tested, /retitle was confirmed cleanly excised, and the full gauntlet was green on darwin/arm64. Those results stand.

Separately, and not for this PR: five earlier merges with non-conventional subjects are missing from CHANGELOG.md entirely, including Add Atlas Cloud provider preset (#784) and Add shell completion generation (#764). That plus the bump-minor-pre-major gap are one issue about release hygiene, and this PR is a good illustration of why it is worth filing.

@anandh8x
anandh8x merged commit 5886354 into main Jul 30, 2026
9 checks passed
@Vasanthdev2004

Copy link
Copy Markdown
Collaborator

Correcting myself on the 1.0.0 warning above, since it didn't play out and I'd rather say why than leave it standing.

The release PR came out as 0.7.0, not 1.0.0. But not because my reading of bump-minor-pre-major was wrong — that never got tested. The ! didn't survive the squash. The merged subject is:

feat(tui): replace /retitle with local /rename (#826)

No !. So release-please saw a plain feat, bumped the minor, and filed it under Features. There's no BREAKING CHANGES section in #837.

Whether that was deliberate on merge or just the squash box being edited, I don't know. Either way the practical outcome is the thing gnanam originally raised: v0.7.0 removes /retitle, a command that shipped in every release from v0.3.0, and the changelog doesn't mark it breaking. The entry does say "replace /retitle with local /rename", so it's not invisible — someone reading the Features list can work it out. It just isn't flagged.

@kevin-hnnh #837 is still open if you want a BREAKING CHANGE: note in there before it goes out. Not blocking anything, and I have no strong view — flagging it because the window closes when that merges.

gnanam1990 added a commit to gnanam1990/zero that referenced this pull request Aug 1, 2026
ONE REAL CONFLICT, in the TUI model's fields. main replaced the /retitle
backfill with a local /rename (Gitlawb#826), so its side deletes retitleQueue and the
four counters beside it and adds renamePrompt; this branch's side carries the
orchestrate plan surface main has never seen. Both, not either: keeping our copy
of the retitle fields would have resurrected state whose only callers main
removed, leaving it compiling and unreachable.

THE POSTURE-OFF GOLDEN MOVED, and it was checked rather than assumed. Gitlawb#838
reworded four tool descriptions (glob, grep, list_directory, read_file), which
changes the definition bytes the fingerprint freezes. A moved golden is exactly
what a posture leak from this branch would look like, so the two were told apart
by measurement: a posture-off run's first request body, compared byte for byte
against a binary built from this same main, across --auto low/medium/high/member
and --use-spec. All five identical. The absolute sizes moved with main's new
wording (33549 -> 31851 on --auto low); the difference between the binaries
stayed zero, which is the property the guard exists for.

Everything else auto-merged.
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.

3 participants