Skip to content

fix(linear): seed a ticket prompt only when the worktree is created - #259

Merged
hayke102 merged 2 commits into
masterfrom
fix/manual-session-no-ticket-prompt
Aug 20, 2026
Merged

fix(linear): seed a ticket prompt only when the worktree is created#259
hayke102 merged 2 commits into
masterfrom
fix/manual-session-no-ticket-prompt

Conversation

@hayke102

@hayke102 hayke102 commented Aug 20, 2026

Copy link
Copy Markdown
Collaborator

The bug

A session added by hand (a / n / A) to a checkout that once held a Linear ticket opened already working on that ticket — even when the checkout had since moved on to master.

handleSessionCreate ran ticketPromptFor on every session creation, seeding Session.InitialPrompt two ways:

  • Reuselinear.ExistingPrompt(path) read back the prompt.txt already sitting in .fleet/ticket/<ID>/. It never looked at the branch, so the prompt was re-asked on every session after the first, forever. This is the reported case.
  • Inference — a branch or worktree dir name matching <TEAM>-<N> fetched and materialized the ticket, then seeded from it.

The fix

A seeded first message is the gesture of starting a worktree from a ticket, not a property of the directory that worktree happens to be. Both branches are gone; handleSessionCreate now passes msg.prompt through untouched.

The worktree-creation path (app.go) already set prompt explicitly, and ticketPromptFor early-returned when it was non-empty — so nothing there changes.

before after
a / n / A in a ticket worktree prompt re-seeded empty
a / n / A on a ticket-named branch fetch + seed empty
w + a ticket prompt ✓ prompt ✓
fleet worktree --ticket / -p prompt ✓ prompt ✓

Also removed

The negative pin (NegativelyPinned / pinNoTicket / .no-ticket) existed only to stop the inference path re-asking Linear on every session start. With that path gone it would be a write-only file, so it goes too. pathTailAfterRepo stays — palette_tickets.go still uses it.

Guard

TestManualSessionCreationSeedsNoPrompt fails if handleSessionCreate reaches into internal/linear again, or if anything in app.go assigns to a .prompt field on the way to the launch. Verified it fires by temporarily reintroducing an assignment.

Known cost

A worktree created outside fleet on a ticket-named branch no longer materializes its ticket — that was the inference branch. Deliberate, per the scoping decision: manual session creation seeds nothing, ever.

Testing

make build passes. go test ./... is green except TestCredentialResolutionOrder, which fails identically on unmodified master on this machine (it asserts "nothing stored" while the local keychain holds a real Linear credential).

🤖 Generated with Claude Code

https://claude.ai/code/session_01WBQUYTfR7kzUjgozd58mr6

Summary by CodeRabbit

  • Bug Fixes

    • Improved Linear ticket error handling by clearly reporting when an issue cannot be found, while preserving disconnected-state behavior.
    • Prevented manually created sessions from inheriting ticket prompts or performing automatic ticket lookups.
    • Ensured ticket briefings are added only when creating a worktree explicitly from a ticket.
  • Documentation

    • Added release documentation describing the updated manual session behavior.

handleSessionCreate ran ticketPromptFor on every session creation, which
seeded the agent's first message from a Linear ticket in two ways:

  - reuse: linear.ExistingPrompt read back the prompt.txt already sitting
    in .fleet/ticket/<ID>/. It never looked at the branch, so a checkout
    that once held a ticket re-asked the original task on every session
    added afterwards -- forever, including long after the checkout had
    moved on to master.
  - inference: a branch or worktree dir name matching <TEAM>-<N> fetched
    and materialized the ticket, then seeded from it.

A seeded first message is the gesture of starting a worktree from a
ticket, not a property of the directory that worktree happens to be. So
both branches go, and handleSessionCreate now passes msg.prompt through
untouched. The worktree-creation path already set it explicitly (and
ticketPromptFor early-returned on it), so `w` + a ticket and
`fleet worktree --ticket` are unaffected; `a`/`n`/`A` always start empty.

The negative pin (NegativelyPinned/pinNoTicket) existed only to stop the
inference path re-asking Linear on every session start, so it goes with
it rather than staying as a write-only file. pathTailAfterRepo stays --
palette_tickets.go still uses it.

TestManualSessionCreationSeedsNoPrompt fails if handleSessionCreate
reaches into internal/linear again, or if anything in app.go assigns to a
.prompt field on the way to the launch.

Cost: a worktree created outside fleet on a ticket-named branch no longer
materializes its ticket.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WBQUYTfR7kzUjgozd58mr6
Copilot AI lite review requested due to automatic review settings August 20, 2026 08:07
@gitstream-cm

gitstream-cm Bot commented Aug 20, 2026

Copy link
Copy Markdown

🚨 gitStream Monthly Automation Limit Reached 🚨

Your organization has exceeded the number of pull requests allowed for automation with gitStream.
Monthly PRs automated: 250/250

To continue automating your PR workflows and unlock additional features, please contact LinearB.

Copilot AI 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.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@coderabbitai

coderabbitai Bot commented Aug 20, 2026

Copy link
Copy Markdown

Review Change Stack

Note

.coderabbit.yaml has unrecognized properties

CodeRabbit is using all valid settings from your configuration. Unrecognized properties (listed below) have been ignored and may indicate typos or deprecated fields that can be removed.

⚠️ Parsing warnings (1)
Validation error: Unrecognized key: "tools"
⚙️ Configuration instructions
  • Please see the configuration documentation for more information.
  • You can also validate your configuration using the online YAML validator.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 1a378754-88e8-40d4-8308-45724b710784

📥 Commits

Reviewing files that changed from the base of the PR and between 5a49bc9 and 21ca14e.

📒 Files selected for processing (3)
  • CLAUDE.md
  • internal/ui/ticket.go
  • internal/ui/worktree_ticket_routing_test.go

Included review availability: Your plan provides up to 1 included review per hour; 0 remain after this review.


📝 Walkthrough

Walkthrough

Manual session creation no longer infers Linear ticket prompts. Materialization no longer reuses prompts or creates negative pins. Worktree creation reports missing tickets explicitly, while disconnected Linear access remains silent.

Changes

Ticket prompt flow

Layer / File(s) Summary
Remove prompt reuse and negative pinning
internal/linear/materialize.go, internal/linear/linear_test.go
Materialization no longer reuses existing prompts or creates negative-ticket pins. Related tests were removed.
Keep manual session prompts unchanged
internal/ui/app.go, internal/ui/ticket.go, CLAUDE.md
Session creation preserves the caller-provided prompt and removes branch-based ticket inference. Worktree creation reports ErrNotFound with an explicit message.
Validate explicit prompt seeding
internal/ui/worktree_ticket_routing_test.go, changelog/unreleased/manual-session-no-ticket-prompt.md
Tests verify that manual session creation does not access Linear or assign prompts. The changelog records the behavior change.

Estimated code review effort: 2 (Simple) | ~10 minutes

Merge Risk: ⚪ Minimal · up to 21ca1

The change limits ticket prompt seeding to explicit worktree creation, with no actionable merge-blocking risk remaining after normal checks and review.

Possibly related PRs

  • brizzai/fleet#248: Introduced the ticket inference and materialization flow removed by this PR.
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the main change: ticket prompts are seeded only when a worktree is created.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
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.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/manual-session-no-ticket-prompt

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.

Comment thread internal/ui/ticket.go
Comment thread internal/linear/materialize.go
Comment thread internal/ui/worktree_ticket_routing_test.go
Two review findings on the inference removal.

ticketStatusLine swallowed ErrNotFound alongside ErrNotConnected, which
was right while inference guessed identifiers out of branch names -- "no
such issue" was the ordinary answer there. Removing inference left one
caller, worktree creation, where the user picked the ticket in the `w`
dialog and Materialize re-fetched it: "not found" now means the issue was
deleted, or their access to it changed, in the seconds since. Swallowing
it hands back a worktree and a session with no prompt and no message at
all. It gets its own line, worded rather than %v-formatted because the
sentinel reads "linear: issue not found" and would render "Linear:
linear: issue not found". ErrNotConnected stays swallowed -- it can
barely reach this caller, since the dialog's own fetch had to succeed for
there to be a ticket to materialize. The CLI path was never affected; it
prints the error to stderr itself.

TestManualSessionCreationSeedsNoPrompt walked all of app.go for any
AssignStmt assigning to a selector named `prompt`. sessionCreateMsg
already declares that field, so the name is live in the package and any
future `x.prompt = ...` -- a dialog, a form -- would fail with an error
message about Linear tickets inheriting into manual sessions. Scoped to
the handleSessionCreate FuncDecl, which is what the doc comment already
described. Nothing is lost: the other way to set a prompt is a composite
literal (sessionCreateMsg{prompt: ...}), which is how the worktree path
legitimately does it and is not an AssignStmt in any file. Verified both
directions -- an assignment inside the function fails, one elsewhere in
app.go passes.

CLAUDE.md carried the inference-era rationale for the swallow, in a line
this branch wrote.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WBQUYTfR7kzUjgozd58mr6
Copilot AI review requested due to automatic review settings August 20, 2026 11:03

Copilot AI 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.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@hayke102
hayke102 merged commit 891c38f into master Aug 20, 2026
6 checks passed
@hayke102
hayke102 deleted the fix/manual-session-no-ticket-prompt branch August 20, 2026 11:12
@hayke102

Copy link
Copy Markdown
Collaborator Author

/ship

@github-actions

Copy link
Copy Markdown
Contributor

🚀 Release PR opened: #260 (v2.30.1)
Merge to release.

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.

2 participants