Repository navigation
Link Issues to threads and start a thread from an Issue #28
Copy link
Copy link
Closed
Description
Activity
Handoff: PR #34 (not merged)
- PR: feat(server): link GitHub Issues to threads (#28) #34 into
feat/25-issues - Head:
4cd64ab46384b96407e4c11bcc44f9a6987b0319onfeat/28-issue-links
Commands run and results
apps/server:vp test run src/issueLinks src/mcp/McpHttpServer.test.ts src/auth/RpcAuthorization.test.ts src/server.test.ts: 233 passed, 2 skipped (the live suite, opt-in).apps/server:T3_LIVE_GITHUB=1 vp test run src/issueLinks/IssueLinks.live.test.tswith realghagainst real GitHub (PR feat(server): add project-scoped thread supervision #16 closes Threads toolkit: read and message any thread in the project (scope: children | project) #15): 2 passed.packages/contracts:vp test run src/issueLinks.test.ts: 5 passed.apps/web:vp test run src/components/issues: 9 passed.tsc --noEmitin apps/server, apps/web, packages/contracts, packages/client-runtime: 0 errors.vp linton changed files: no new findings (ChatView's 74 warnings exist before and after).vp fmtapplied.knip --include files,exportson server, web, contracts, client-runtime: clean.scripts/fork-check.sh: OK. Stack is 14 commits, 10 features.
Deviations and notes
- Closing references are not stored in
projection_thread_pull_requests: snapshots carry no PR body. They are read from GitHub (gh api graphql,closingIssuesReferences/closedByPullRequestsReferences) at read time and cached. A failed read drops only those derived links. - Server push covers stored-link changes only. For derived changes, clients reread when the thread shell's branch or PR links change. A server-side domain-event forwarder would have broken upstream tests whose mocked engines lack
subscribeDomainEvents. - Unlink writes a
dismissedtombstone, so a removed branch or closing-reference link stays removed until it is linked again. - The links tab (the PR panel) is now also available for server threads when the environment answers Issue-link reads. This makes manual linking reachable when a thread has no PRs.
- Start thread: Computed Issue status, status grouping and filters #29 uses
useStartThreadFromIssue(), which prefills title, URL and body. The trigger here is "Start another thread" on each linked-Issue row, which knows only the URL. - Issue rows show number and repository but no title (no GitHub read for titles here).
- Merge overlap with feat(web): browse GitHub Issues next to PRs (#27) #32 (Browse Issues: list, filters, parent tree and side panel #27): both add insertions at the same spots in
rpc.ts,ws.ts,server.ts,RpcAuthorization.ts,contracts/index.ts, the allowlist and the feature map. Whichever lands second must rebase, and move shared paths tosharedFilesso each keeps exactly one primary owner.
Unverified
- No real-client or browser pass, and no screenshots (no dev server or browser started, per the brief).
- No independent review of the head yet.
- No user docs added.
- PR: feat(server): link GitHub Issues to threads (#28) #34 into
Handoff update: review fixes on PR #34 (not merged)
- PR: feat(server): link GitHub Issues to threads (#28) #34 into
feat/25-issues - Head:
7fd4e6dab4d6f1b3f91a652e931f02ac7564bf96(supersedes4cd64ab)
Review items
- The links tab opens for threads without PRs:
addPullRequestsSurfaceand both tab props gate onlinksSurfaceAvailable. The label is now "Linked PRs and Issues". threadsForIssueis replaced by batchedthreadsForIssues({ issues: [{host, repository, number, closingPullRequests}] }), capped at 100 and returned in input order. It makes no GitHub call. Change pushes carry{threadId, issues}, and client refresh signals fire only for the matching thread or Issue keys.- A
capabilities.issueLinksserver flag decides tab availability. Only the links panel callsuseThreadIssueLinks. - The branch rule requires a conventional-commit type and a slug starting with a letter.
linkreturnsalreadyLinked=truefor any existing source (branch and closing reference included) and writes nothing.- Lazy prune on read, at most every 10 minutes: links of deleted threads, and drafts unsent after 7 days. A reused draft drops its previous
startedrow. - An explicit unlink always writes the tombstone.
- The stubbed closing-references service is removed. CI tests use stored and branch links only; closing references are covered only by the live real-
ghsuite.
Commands and results
apps/server:vp test run src/issueLinks src/mcp/McpHttpServer.test.ts src/auth/RpcAuthorization.test.ts src/server.test.ts src/environment: 277 passed, 2 skipped.T3_LIVE_GITHUB=1 vp test run src/issueLinks/IssueLinks.live.test.ts: 2 passed (realgh, real GitHub).- Contracts
issueLinks.test.ts: 5 passed. Webcomponents/issuesandRightPanelTabs: 29 passed. tsc --noEmitin apps/server, apps/web, packages/contracts, packages/client-runtime: 0 errors.vp linton changed files: no errors and no new warnings.vp fmt --checkon changed files: clean.vp run knip:check: passes.scripts/fork-check.sh: OK (stack 15/20).
New upstream edits (allowlisted, owner
issues-links)packages/contracts/src/environment.tsandapps/server/src/environment/ServerEnvironment.ts(capability), andapps/web/src/components/RightPanelTabs.tsx(label).Pending and unverified
- Rebase onto
origin/feat/25-issuesafter feat(web): browse GitHub Issues next to PRs (#27) #32 merges, resolving shared insert points and moving shared paths tosharedFiles. Waiting for the go-ahead. - No browser or real-client pass. No re-review of this head yet.
- Derived-link changes on other threads (a branch rename) reach Issue rows only through the 30 s staleness, not a push.
- PR: feat(server): link GitHub Issues to threads (#28) #34 into
- added a commit that references this issue
on Sep 25, 2026 Handoff update: rebase onto #27 and re-review fixes (PR #34, not merged)
- PR: feat(server): link GitHub Issues to threads (#28) #34 into
feat/25-issues, mergeable - Head:
43988f2615a37695be2816dcbca3d323b3a420b7(supersedes7fd4e6d). Two commits on335312e4:e7221b06d: the feature squashed to one commit before rebasing.43988f261: the re-review fixes.
Rebase
- Conflicts resolved in
rpc.ts,ws.ts,server.ts,RpcAuthorization.ts,contracts/index.ts, the allowlist and the feature map. Both features are intact (...IssueRpcsplus.merge(IssueLinksRpcGroup), and both handler spreads, scopes and layers). - Ownership:
issues-browsestays primary forRpcAuthorization.ts,server.ts,ws.ts,CommandPalette.tsxandrpc.ts.issues-linkslists those, plusMcpHttpServer.tsandcontracts/index.ts, insharedFiles.issues-linksis primary owner ofServerEnvironment.ts,ChatView.tsx,RightPanelTabs.tsx,client-runtime/rpc/client.tsandcontracts/environment.ts.
Re-review fixes
- Pruning removes a deleted thread's links only when
deleted_atis more than 7 days old. Tests cover delete then re-create, a recent deletion, and an existing thread's link older than 7 days. - The client subscription applies
Stream.chunks, so each delivered batch is one value, and a batch matches when any of its changes names the target (issueLinkChangesMatch, tested with two changes delivered together). ThreadLinksPanelrenders the Issues section only whencapabilities.issueLinksis true.- A CI test drives
threadsForIssuesclosing references from real DB rows and caller data. It covers stack-dismissed exclusion, a tombstone suppressing a closing reference, mixed-case repositories, and a cross-repo closing PR. - The command palette entry reads "Show linked PRs and Issues" and is enabled when the thread has PRs or the server advertises
issueLinks. The file is allowlisted by Browse Issues: list, filters, parent tree and side panel #27 and shared in the map. // Fork: … (#28)marker added on the RightPanelTabs label.
Commands and results
apps/server:vp test run src/issueLinks src/issues src/mcp/McpHttpServer.test.ts src/auth/RpcAuthorization.test.ts src/server.test.ts src/environment: 291 passed, 8 skipped (live suites).T3_LIVE_GITHUB=1 vp test run src/issueLinks/IssueLinks.live.test.ts: 2 passed.- Web
components/issues,RightPanelTabs,CommandPalette,state/pullRequests.test.ts: 79 passed. ContractsissueLinks.test.ts: 5 passed. tsc --noEmitin server, web, contracts, client-runtime: 0 errors.vp linton changed files: no errors and no new warnings.vp fmt --checkon changed files: clean.vp run knip:check: passes.scripts/fork-check.sh: OK (stack 16/20, 12 features).
Process note
An intermediate push (
76d1c15) went up before fork-check passed: the rebase had cut the end of theissues-browseJSON block. It was fixed and replaced with a lease-guarded push; the current head passes fork-check.Unverified
- No browser or real-client pass. No re-review of this head yet.
- The Browse Issues: list, filters, parent tree and side panel #27 live suite (
IssueService.live.test.ts) was not run with a token; it was skipped.
- PR: feat(server): link GitHub Issues to threads (#28) #34 into
Metadata
Metadata
Assignees
Labels
No labels
Parent
#25
Outcome
Threads and Issues are linked, the user sees a thread's Issues next to its PRs, and can start a linked thread from an Issue.
Acceptance criteria
link_issue/unlink_issueMCP tool mirroringlink_pull_request, task branch name<type>/<number>-<slug>in the project's repository, and closing references (Closes #N) of the thread's linked PRs.fork_thread_issue_linkscreated by the fork in the existing database, outside upstream migrations and the event log. Derived links are computed when read. Stored links survive a server restart.scripts/fork-upstream-edits.txtanddocs/fork-features.md.Non-goals
Blocked by
None
Required proof
ghwhere GitHub is read (no fake CLI).scripts/fork-check.sh; independent review of the exact head.