Skip to content

feat(projects): add in-flight PRs + branches to Current Projects cards (GLOOK-19)#52

Merged
msogin merged 8 commits into
mainfrom
feat/glook-19-inflight-projects
Jun 10, 2026
Merged

feat(projects): add in-flight PRs + branches to Current Projects cards (GLOOK-19)#52
msogin merged 8 commits into
mainfrom
feat/glook-19-inflight-projects

Conversation

@msogin

@msogin msogin commented Jun 10, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Adds open PRs and bare-branch commits to the per-team Current Projects card (team page) so the LLM clusters both shipped and in-progress work
  • Same treatment for the org-wide project insights card (home page)
  • Both cards now show a fuller picture of what the team is working on, not just what has already merged

How it works

Team page: extractTeamProjectsData now fetches up to 30 open PRs + top 10 bare branches for the team. These are formatted as a compact pipe-delimited IN-FLIGHT WORK block and injected into the prompt via {{IN_FLIGHT_BLOCK}}. The LLM merges them into existing project clusters or creates new ones. Draft PRs are included. PROMPT_VERSION bumped to v4-inflight to invalidate cached rows.

Home page: Same data shape added inline to project-insights/route.ts. Cache versioned with _v: 2 — stale v1 rows regenerate automatically.

Bug fixed

SUM(...) AS lines in the bare-branches SQL caused a MySQL reserved-word parse error (LINES is reserved). Renamed to AS total_lines.

Test plan

  • All 740 unit tests pass
  • Team Current Projects card includes in-flight PRs mixed into clusters
  • Home page project insights incorporates in-flight work
  • Teams with no in-flight data work normally (empty block omitted from prompt)

🤖 Generated with Claude Code

msogin and others added 7 commits June 9, 2026 17:31
…ueries

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
…mpt call

Adds renderInflightBlock (module-private) that formats open PRs and bare
branches into a plain-text IN-FLIGHT WORK section. Updates generateTeamProjects
to extend the short-circuit check with the new in-flight fields, call
renderInflightBlock, and pass IN_FLIGHT_BLOCK to loadPrompt. Updates tests:
baseInput() includes in_flight_prs/in_flight_branches, short-circuit test
includes the new required fields, and two new tests cover the inflight block
(one expected-fail pending Task 3 template update).

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
…k, bump PROMPT_VERSION

- Add IN-FLIGHT WORK rule to prompt template describing how to mix open PRs/branches into clusters
- Add {{IN_FLIGHT_BLOCK}} placeholder at end of template for injected in-flight data
- Bump PROMPT_VERSION from v3-projects to v4-inflight to invalidate old cache
- Update prompts.test.ts to pass IN_FLIGHT_BLOCK parameter
- Update team-projects-generator tests to check for in-flight data block content instead of template rule

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
…e, cache v2

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
@msogin

msogin commented Jun 10, 2026

Copy link
Copy Markdown
Contributor Author

Code Review — automated (claude-pr-review-local + review-loop)

🟡 Worth discussing before merge

Prompt injection via unescaped GitHub-sourced strings (src/lib/team-pulse/projects.ts, src/app/api/project-insights/route.ts)
PR titles and branch names are interpolated verbatim into the LLM prompt with no length cap or escaping. For a purely internal tool (trusted org employees only) the risk is self-contained. If external contributors or forked repos ever feed the pipeline, a crafted branch name could manipulate the LLM's JSON output. Recommend confirming the trust model and adding a character-limit trim (e.g. 100 chars on title/branch) as a cheap defence.


🔵 Suggestions

Separator spacing in userMessage (src/app/api/project-insights/route.ts ~L181)
renderInsightsInflightBlock starts with '\n', so ${noJiraData}${inflightBlock} puts only one newline between the commits section and the IN-FLIGHT header — sections run together without a blank separator, unlike the team-page surface. Change the leading '\n' to '\n\n'.

b.commit_count / b.total_lines not null-coerced (src/app/api/project-insights/route.ts inside renderInsightsInflightBlock)
The PR-row fields pr_additions/pr_deletions use Number(pr.X ?? 0), but b.commit_count and b.total_lines are interpolated raw. COUNT(*) won't return NULL, but the asymmetry is a latent footgun. Add Number(b.commit_count ?? 0) and Number(b.total_lines ?? 0) for consistency.

Trailing double blank line when IN_FLIGHT_BLOCK is empty (prompts/team-pulse-projects.txt)
When there is no in-flight data, loadPrompt substitutes '' and leaves two blank lines at the end of every prompt. Cosmetic / harmless to the LLM, but captured in the snapshot. Fixable by having renderInflightBlock prepend '\n' to the non-empty block and removing the extra blank line before {{IN_FLIGHT_BLOCK}} in the template.

Duplicated render logic (src/app/api/project-insights/route.ts vs src/lib/team-pulse/projects.ts)
renderInsightsInflightBlock and renderInflightBlock produce the same format via different internal idioms. If the pipe-delimited layout ever changes, both need updating independently. Consider extracting to a shared utility (e.g. src/lib/team-pulse/render.ts) so there is one function to test and maintain.

No test for short-circuit with only in-flight data (src/lib/__tests__/unit/team-projects-generator.test.ts)
The short-circuit gate now checks all four fields. The existing test covers the all-empty case. A test where in_flight_prs is non-empty but commits and jira_issues are both empty would confirm the LLM is still called in that scenario.

renderInsightsInflightBlock and _v: 2 cache guard are untested
Both branches are straightforward to unit-test in isolation. The spec accepts this gap ("consistent with existing coverage posture") but they are non-trivial enough to be worth adding later.


🟣 Questions

Rule vs data in different message roles (src/app/api/project-insights/route.ts ~L168-178)
On the home-page surface the "Use IN-FLIGHT WORK..." instruction is appended to the end of systemPrompt, while the in-flight data is in userMessage. On the team-page surface both live in the same system prompt template. Is the split intentional? Most providers handle it fine, just flagging the inconsistency.

_v: 2 cache guard lifetime
This is a one-time migration shim — once all self-keyed report_comparisons rows for active orgs have been overwritten with _v: 2 entries, the guard is pure overhead. A short comment in the code noting when it can be removed would help future readers.

@msogin msogin merged commit f0e6fb1 into main Jun 10, 2026
1 check passed
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.

1 participant