feat(ui): add vampire coder index metric (fixes #44)#281
Conversation
|
Tip 👋 Hey @Diwakar-odds — Miku's on it. Here are the most useful commands for this PR:
Note 🎓 This repo is part of ECSOC26. Run Note ⭐ Star this repo to unlock all commands. Say 📖 All commands🤖 AI-powered — 14 commands
🔧 Issue & PR management — 18 commands
🎉 Community & utility — 9 commands
|
PR Analysis & Label RequestThis PR introduces the Vampire Coder Index (Issue #44) to the TUI dashboards. It calculates the user's tendency for late-night coding sessions and seamlessly integrates this visual metric across all three main dashboard components. ECSoC26 Label Justification:
Please review when you have a moment. Thank you! |
|
| Filename | Overview |
|---|---|
| termstory/insights.py | Adds calculate_vampire_index, using the same local timestamp convention as nearby insight helpers. |
| termstory/tui.py | Displays the new metric in three header renderers, but the added Rich markup has unmatched close tags. |
Reviews (1): Last reviewed commit: "feat(ui): add vampire coder index metric..." | Re-trigger Greptile
| @@ -929,7 +931,7 @@ def render_time_summary( | |||
| header_lines.append(f"[bold cyan]{avatar_lines[6]}[/] [bold cyan]ACTIVE REPOS:[/] [bold]{active_projects_count} Workspaces[/]") | |||
| @@ -1160,7 +1164,7 @@ def _render_wrapped_view_ui( | |||
| header_lines.append(f"[bold cyan]{avatar_lines[6]}[/] [bold cyan]ACTIVE REPOS:[/] [bold]{active_projects_count} Workspaces[/]") | |||
| @@ -1357,7 +1363,7 @@ def render_daily_chronicle_view(self, date_str: str, sessions: List[Session], pr | |||
| header_lines.append(f"[bold cyan]{avatar_lines[6]}[/] [bold cyan]ACTIVE SESSIONS:[/] [bold]{len(sessions)}[/]") | |||
bitflicker64
left a comment
There was a problem hiding this comment.
Hey @Diwakar-odds, this is the third PR in the trio (with #282 and #280) and it shares two of the same blockers plus a new one. Needs another pass before merge.
What's blocking
-
CI is red on all four Python versions (
MarkupError: auto closing tag ('[/]') has nothing to closeintest_tui_landing_page_after_onboarding). Same root cause as PR #280: the f-string attermstory/tui.py:934ends with...[/dim][/]— extra trailing[/]because the wrapping pattern from the DAILY CLASS header in #282 was reused without adjusting. Compare to the line it replaces (PROJECTS:row) which balances cleanly with one[/]at the end. Three sites have the bug (934, 1167, 1366); Greptile flagged all three as P1s. Fix is the same in all three places. -
Duplicate logic with
calculate_vampire_coder_index. Acalculate_vampire_coder_index(sessions) -> floatalready exists onmainattermstory/insights.py:446, plus a richerget_vampire_metrics(sessions)that powersformat_vampire_indexinformatter.pyand the vampire rendering incli.py. Same situation as PR #280's necromancer duplicate. -
The two implementations disagree on what's being measured. This is worse than the necromancer duplicate. The new
calculate_vampire_indexcounts whole sessions whosestart_timefalls in[00:00, 05:00). The existingcalculate_vampire_coder_indexcounts each command and commit individually in that window, deduplicating commits by hash. These produce different numbers for the same data — e.g. a 6-hour session starting at 4 AM contributes 1 to the new one but could contribute hundreds of commands to the existing one. The issue text says "percentage and intensity of your coding sessions" which is closer to the new helper's definition, but the formatter/cli path renders the existing one. Two metrics with the same name will confuse users and split the codebase.
Suggested fix shape
- Pick one definition. If sessions-by-start-time matches the issue intent, replace the existing
calculate_vampire_coder_indexwith this new helper, migrateformatter.pyandcli.py, and delete the old one. If commands-and-commits is the canonical metric (which is what the codebase already has wired), delete the new helper and callget_vampire_metrics(sessions).get("vampire_index", 0.0)in the three header sites. - Fix the trailing
[/]in all three header lines (drop the[/]after[/dim]). - Add at minimum a unit test that constructs sessions with known start times and asserts the percentage.
Smaller notes
- No
is_legacyfilter, same drift as the existing implementations. - Empty-session returns
0.0(float), so the header will render0.0% late night. Slightly cleaner if youreturn 0for empty, or format as{vampire_index:g}%to drop trailing.0. VAMPIRE INDEX:is 14 chars while most other labels in the column are 9 (PROJECTS:,COMMITS:). The extra spaces compensate but the row drifts if you ever shorten the label. Minor.- Wrapped header at
tui.py:1167replacesCOMMITS:withVAMPIRE INDEX:, so monthly wrapped summaries lose the commit-volume metric.total_commitsis still computed above but no longer rendered. Same regression as PR #282 and #280. Add a row, don't replace.
Happy to approve once one of the two helpers is removed, the markup is fixed, and CI is green.
| header_lines.append(f"[bold cyan]{avatar_lines[7]}[/] [bold cyan]FOCUS SCORE:[/] [bold green]{fs:.1f}/10.0[/]") | ||
| header_lines.append(f"[bold cyan]{avatar_lines[8]}[/] [bold cyan]PEAK VELOCITY:[/] [dim]{peak_velocity}[/]") | ||
| header_lines.append(f"[bold cyan]{avatar_lines[9]}[/] [bold cyan]PROJECTS:[/] [dim]{active_projects_count}[/]") | ||
| header_lines.append(f"[bold cyan]{avatar_lines[9]}[/] [bold cyan]VAMPIRE INDEX:[/] [dim]{vampire_index}% late night[/dim][/]") |
There was a problem hiding this comment.
Root cause of the CI failure on all 4 Python versions. The f-string ends with ...[/dim][/] — extra trailing [/]. Fix: drop the [/] after [/dim], leaving [dim]{vampire_index}% late night[/dim]. Compare to the line it replaces (PROJECTS:[/] ... [dim]{active_projects_count}[/]) which balances cleanly.
| header_lines.append(f"[bold cyan]{avatar_lines[7]}[/] [bold cyan]FOCUS SCORE:[/] [bold green]{fs:.1f}/10.0[/]") | ||
| header_lines.append(f"[bold cyan]{avatar_lines[8]}[/] [bold cyan]PEAK VELOCITY:[/] [dim]{peak_velocity}[/]") | ||
| header_lines.append(f"[bold cyan]{avatar_lines[9]}[/] [bold cyan]COMMITS:[/] [dim]{total_commits}[/]") | ||
| header_lines.append(f"[bold cyan]{avatar_lines[9]}[/] [bold cyan]VAMPIRE INDEX:[/] [dim]{vampire_index}% late night[/dim][/]") |
There was a problem hiding this comment.
Same extra [/] markup bug as line 934. Fix mirrors that line.
| header_lines.append(f"[bold cyan]{avatar_lines[7]}[/] [bold cyan]FOCUS SCORE:[/] [bold green]{fs:.1f}/10.0[/]") | ||
| header_lines.append(f"[bold cyan]{avatar_lines[8]}[/] [bold cyan]PEAK TIME:[/] [dim]{peak_velocity}[/]") | ||
| header_lines.append(f"[bold cyan]{avatar_lines[9]}[/] [bold cyan]PROJECTS:[/] [dim]{len(projects)}[/]") | ||
| header_lines.append(f"[bold cyan]{avatar_lines[9]}[/] [bold cyan]VAMPIRE INDEX:[/] [dim]{vampire_index}% late night[/dim][/]") |
There was a problem hiding this comment.
Same extra [/] markup bug as line 934. Fix mirrors that line.
| header_lines.append(f"[bold cyan]{avatar_lines[7]}[/] [bold cyan]FOCUS SCORE:[/] [bold green]{fs:.1f}/10.0[/]") | ||
| header_lines.append(f"[bold cyan]{avatar_lines[8]}[/] [bold cyan]PEAK VELOCITY:[/] [dim]{peak_velocity}[/]") | ||
| header_lines.append(f"[bold cyan]{avatar_lines[9]}[/] [bold cyan]COMMITS:[/] [dim]{total_commits}[/]") | ||
| header_lines.append(f"[bold cyan]{avatar_lines[9]}[/] [bold cyan]VAMPIRE INDEX:[/] [dim]{vampire_index}% late night[/dim][/]") |
bitflicker64
left a comment
There was a problem hiding this comment.
Code Review Summary
Verdict: Request changes — CI red on all Python versions; also duplicates an existing vampire metric API.
Intent
Show a “Vampire Index” (% late-night work) in TUI headers (issue #44).
Critical
-
Broken Rich markup (CI failure) — every header line ends with
[/dim][/]:[dim]{vampire_index}% late night[/dim][/]
The trailing
[/]has nothing to close →MarkupErrorintest_tui_landing_page_after_onboardingon 3.9–3.12.Fix:
[dim]{vampire_index}% late night[/dim]
-
Duplicate metric —
mainalready hascalculate_vampire_coder_index/get_vampire_metricswith a richer definition (commands + commits). This PR adds a simpler session-start-hour-onlycalculate_vampire_index. Prefer reusing the existing helper so CLI/TUI/analyze_all stay consistent.
Warnings
- Replacing the PROJECTS / COMMITS header row drops useful info in those views; add a row instead of overwriting.
- No unit tests for the calculation edge cases (empty list, exactly midnight, hour==5 boundary).
- Local timezone via
datetime.fromtimestamp— fine if intentional; document that it’s local wall clock.
Verdict
Request changes — fix markup first (one-character class fix), then align with existing vampire APIs.
| header_lines.append(f"[bold cyan]{avatar_lines[7]}[/] [bold cyan]FOCUS SCORE:[/] [bold green]{fs:.1f}/10.0[/]") | ||
| header_lines.append(f"[bold cyan]{avatar_lines[8]}[/] [bold cyan]PEAK VELOCITY:[/] [dim]{peak_velocity}[/]") | ||
| header_lines.append(f"[bold cyan]{avatar_lines[9]}[/] [bold cyan]PROJECTS:[/] [dim]{active_projects_count}[/]") | ||
| header_lines.append(f"[bold cyan]{avatar_lines[9]}[/] [bold cyan]VAMPIRE INDEX:[/] [dim]{vampire_index}% late night[/dim][/]") |
There was a problem hiding this comment.
Critical / CI red: Extra closing tag.
| header_lines.append(f"[bold cyan]{avatar_lines[9]}[/] [bold cyan]VAMPIRE INDEX:[/] [dim]{vampire_index}% late night[/dim][/]") | |
| header_lines.append(f"[bold cyan]{avatar_lines[9]}[/] [bold cyan]VAMPIRE INDEX:[/] [dim]{vampire_index}% late night[/dim]") |
Apply the same one-line fix at the wrapped-view and daily-chronicle sites.
| break | ||
| return streak | ||
|
|
||
| def calculate_vampire_index(sessions: List[Session]) -> float: |
There was a problem hiding this comment.
Main already ships calculate_vampire_coder_index / get_vampire_metrics. A second, simpler definition will drift. Prefer:
from termstory.insights import calculate_vampire_coder_index
vampire_index = calculate_vampire_coder_index(sessions)…or explicitly justify why the TUI needs a different formula, and share one implementation.
|
/triage |
|
miku ✅ Marked as triaged ( |
|
:miku /check-star |
|
miku @Diwakar-odds still hasn't starred this repo. Applied Star this repo first, then run |
|
@gemini review |
|
Caution The consumer version of Gemini Code Assist on GitHub has been sunset. All code review activity has officially ceased. |
Summary
Introduces the Vampire Coder Index metric for user behavior analysis.
Motivation
Closes #44.
Changes
termstory/insights.py:calculate_vampire_indexto compute the ratio of late-night (00:00-05:00) sessions.termstory/tui.py:Acceptance Criteria
Impact & Side Effects
No breaking changes. Adds visual metrics to the TUI.
How to Test
termstory guiand open any dashboard timeframe view to verify the headers.VAMPIRE INDEXmetric correctly.Quality Checklist