gabriel / musehub public
Closed #16
filed by gabriel human · 47 days ago

feat(intel): Velocity subpage — module growth rates, acceleration, dual-window comparison

0 Anchors
Blast radius
Churn 30d
0 Proposals

Overview

Full-featured velocity intelligence subpage surfacing muse code velocity data. Matches CLI output exactly, then supercharges it with filterable tables, acceleration badges, dual-window bar comparisons, and a sparkline commit timeline — all in the Spectral theme.

Closes the velocity gap on issue #8.


CLI Output Shape (ground truth)

muse -C ~/ecosystem/musehub code velocity --json
{
  "mode": "velocity",
  "ref": "dev",
  "window_size": 20,
  "commits_analysed": 593,
  "truncated": false,
  "filters": { "top": 20, "since": null, "predict": 0, "max_commits": 10000 },
  "modules": [
    {
      "module": "tests/",
      "current":  { "added": 150, "removed": 0, "net": 150, "modified": 3,  "active_commits": 4  },
      "prior":    { "added": 324, "removed": 21, "net": 303, "modified": 26, "active_commits": 12 },
      "acceleration": -153,
      "stagnant_commits": 3
    }
  ]
}

Key semantics:

  • current = last window_size commits; prior = the preceding window_size commits
  • acceleration = current.net − prior.net (positive = speeding up, negative = slowing)
  • stagnant_commits = commits that touched the module with net symbol delta = 0

DB table (musehub_intel_velocity) already exists but only stores partial prior-window data (prior_added, prior_net). Phase 0 expands this to the full prior shape.


Web UX — ASCII Wireframes

Page: /{owner}/{repo}/intel/velocity

┌──────────────────────────────────────────────────────────────────────────────┐
│  ← intel   ⚡ Velocity — gabriel/musehub                                     │
│  Module growth rates, dual-window comparison, acceleration signal.           │
├──────────────────────────────────────────────────────────────────────────────┤
│  ┌──────────────────┐  ┌──────────────────┐  ┌──────────────────┐           │
│  │ COMMITS ANALYSED │  │   WINDOW SIZE    │  │      REF         │           │
│  │      593         │  │       20         │  │  dev (HEAD)      │           │
│  └──────────────────┘  └──────────────────┘  └──────────────────┘           │
├──────────────────────────────────────────────────────────────────────────────┤
│  SORT BY [active_commits ▾]   TOP [25 ▾]   FILTER MODULE [______]  [Apply]  │
├──────────────────────────────────────────────────────────────────────────────┤
│                                                                              │
│  MODULE                      CURRENT WINDOW       PRIOR WINDOW    ACCEL     │
│  ─────────────────────────────────────────────────────────────── ─────────  │
│                                                                              │
│  ▌ tests/                    +150  4 commits      +303  12 commits  -153 ▼  │
│    current ████████░░░░░░░░  prior ████████████████████████████░░           │
│                                                                              │
│  ▌ alembic/versions/          +18  3 commits       +18   3 commits    0 ─   │
│    current ████░░░░░░░░░░░░  prior ████░░░░░░░░░░░░░░░░░░░░░░░░░░           │
│                                                                              │
│  ▌ musehub/api/routes/        +11  8 commits       +11   5 commits    0 ─   │
│    current ██████████████░░  prior ██████████░░░░░░░░░░░░░░░░░░░░           │
│                                                                              │
│  ▌ musehub/services/           +0  5 commits       +12   6 commits  -12 ▼   │
│    current ░░░░░░░░░░░░░░░░  prior ████████░░░░░░░░░░░░░░░░░░░░░░           │
│                                                                              │
│  ▌ musehub/db/                  +0  3 commits        +0   3 commits    0 ─  │
│    stagnant ●●●●●●● (7)                                                     │
└──────────────────────────────────────────────────────────────────────────────┘

Acceleration badge legend

  +N ▲  color: --color-success   (accelerating — net positive vs prior)
   0 ─  color: --text-muted      (steady state)
  -N ▼  color: --color-warning   (decelerating — net negative vs prior)

Module row detail (expanded concept)

┌─────────────────────────────────────────────────────────────────┐
│ ▌  musehub/api/routes/musehub/                                  │  ← left accent bar:
│                                                                 │     green=accel, warn=decel
│   CURRENT WINDOW (last 20 commits)     PRIOR WINDOW            │
│   +11 added  0 removed  +11 net        +11 added  0 removed    │
│   ████████████████████░░░░░░░░░░       ████████████████░░░░    │
│   8 active commits                     5 active commits        │
│                                                                 │
│   ACCELERATION  0 ─     STAGNANT  2 commits                    │
└─────────────────────────────────────────────────────────────────┘

Dashboard sparkline (existing, already wired)

  VELOCITY (12 weeks)                                  View all →
  ┌──────────────────────────────────────────────────────────────┐
  │                                                              │
  │         ▐▌  ▐▌  ▐▌                                          │
  │   ▐▌    ▐▌  ▐▌  ▐▌  ▐▌                                      │
  │   ▐▌    ▐▌  ▐▌  ▐▌  ▐▌  ▐▌  ▐▌  ▐▌  ▐▌  ▐▌  ▐▌  ▐▌        │
  │  week12 ...                                       week1 now  │
  └──────────────────────────────────────────────────────────────┘
  (bars = commits that week; newest on right)

Spectral Theme Tokens Used

Element Token
Module row background --bg-surface
Row hover --bg-hover
Left accent — accelerating --color-success
Left accent — decelerating --color-warning
Left accent — steady --border-default
Current-window bar fill --color-accent
Prior-window bar fill --border-strong
Acceleration +N badge --color-success
Acceleration −N badge --color-warning
Stagnant dot --color-warning
Meta pill border --border-subtle
Card/surface --bg-surface / --border-default
Font mono --font-mono

Implementation Plan

Phase 0 — VelocityProvider rewrite (pure-SQL, no subprocess)

Problem: Current VelocityProvider calls _run_muse subprocess (exits 2 in worker environment — same bug as the old CouplingProvider). DB table is empty.

Fix: Rewrite as pure-SQL BFS, mirroring CouplingProvider pattern:

  1. Fetch all commits + parent_ids for the repo.
  2. BFS-walk from HEAD, cap at _MAX_WALK = 10_000.
  3. Bulk-fetch musehub_symbol_history_entries for the repo.
  4. Derive module from address.split('::')[0].split('/')[0] + optional second segment.
  5. Build two commit-ordered windows (current = 0..window_size-1, prior = window_size..2*window_size-1).
  6. Per-module: count added/removed/net/modified/active_commits for each window.
  7. Compute acceleration = current.net − prior.net.
  8. Count stagnant: commits in current window touching module with net = 0.
  9. DELETE stale rows; upsert fresh set.
  10. Also store full prior window stats (migration required — see Phase 1).

Docstring contract:

CouplingProvider → file pairs
VelocityProvider → module windows
EntangleProvider → symbol pairs

Constants:

_MAX_WALK   = 10_000   # BFS depth cap
_WINDOW     = 20       # commits per window (matches CLI default)
_TOP        = 20       # stored leaderboard size

Phase 1 — Migration: expand prior-window columns

Add missing columns to musehub_intel_velocity so all prior-window stats are stored:

revision = "0012"
down_revision = "0011"

Adds:
  prior_modified      INTEGER NOT NULL DEFAULT 0
  prior_active_commits INTEGER NOT NULL DEFAULT 0
  window_size         INTEGER NOT NULL DEFAULT 20
  commits_analysed    INTEGER NOT NULL DEFAULT 0
  ix_intel_velocity_repo_active  (repo_id, active_commits DESC)

Also update MusehubIntelVelocity model in musehub_db/musehub_models.py.


Phase 2 — SCSS (Spectral theme)

Two files following the established two-file split:

src/scss/components/_velocity.scss — visual only

.vl-row            // module row: bg-surface, border-top, hover
.vl-row-accent     // left 3px accent bar: success/warning/muted
.vl-module-path    // font-mono, accent-link, truncated
.vl-bar-track      // base track (bg-elevated, h:4px)
.vl-bar-fill       // fill (--color-accent)
.vl-bar-fill--prior // prior fill (--border-strong)
.vl-accel-badge    // acceleration number + arrow
.vl-accel-badge--up   // color-success
.vl-accel-badge--down // color-warning
.vl-accel-badge--flat // text-muted
.vl-stagnant-dots  // dot row for stagnant commits
.vl-meta-pill      // stat pill: border-subtle bg
.vl-filter-bar     // filter row layout

src/scss/pages/_velocity.scss — structural layout only

.vl-wrap           // page container
.vl-summary-row    // 3-col meta stat grid
.vl-filter-bar     // form layout
.vl-module-list    // flex-column gap-0
.vl-row            // grid: path / current / prior / accel
.vl-bar-row        // dual bar row

Wire into src/scss/app.scss.


Phase 3 — Route + Template

Route: GET /{owner}/{repo_slug}/intel/velocity

Query params:

  • sort: active_commits (default) | net | acceleration | stagnant
  • top: 25 | 50 | 100 | 0 (all)
  • module: prefix filter string

Context built from musehub_intel_velocity query:

{
  "modules": [{
    "module", "added", "removed", "net", "modified", "active_commits",
    "prior_added", "prior_net", "prior_modified", "prior_active_commits",
    "acceleration", "stagnant_commits", "window_size", "commits_analysed",
    "bar_pct": int,          # current.active_commits / max_active * 100
    "prior_bar_pct": int,    # prior.active_commits / max_active * 100
    "accel_class": str,      # "up" | "down" | "flat"
    "accel_label": str,      # "+153" | "−153" | "0"
    "net_label": str,        # "+150" | "−12" | "0"
  }],
  "total_count", "commits_analysed", "window_size", "ref",
  "sort", "top", "module_filter", "valid_tops", "valid_sorts",
}

Template: musehub/templates/musehub/pages/intel_velocity.html

  • Extends base; breadcrumb: intel / velocity
  • intel-page-header with trending-up icon + description
  • intel-meta-bar: commits analysed, window size, ref
  • Filter form (sort + top + module prefix)
  • Module list: each row shows dual-bar + acceleration badge + stagnant dots

Phase 4 — Dashboard integration

  • Add "View all →" link to the existing velocity sparkline section
  • Update dashboard sparkline title to link: <a href="{base_url}/intel/velocity"\>VELOCITY</a>
  • No additional DB queries needed (sparkline data already in intel.velocity.weeks)

Phase 5 — Test suite (TDD, 7 tiers, 50+ cases)

File: tests/test_velocity_provider.py

Docstring contract for every test:

Each test carries: what it verifies, why it matters (invariant or failure mode), and the expected observable — following the same pattern as test_coupling_provider.py.

Tier 1  Unit            VL_01–VL_08   module derivation, acceleration formula,
                                      window split, accel_class helper, bar_pct helper
Tier 2  Integration     VL_09–VL_18   provider upserts, re-runs, window correctness,
                                      stagnant count, prior vs current symmetry
Tier 3  E2E             VL_19–VL_26   full seeded scenarios, sort params, top-N limit,
                                      module prefix filter
Tier 4  Performance     VL_27–VL_33   50-module dataset < 2s, 500-commit BFS < 3s,
                                      re-run idempotent timing
Tier 5  Data Integrity  VL_34–VL_39   acceleration = current.net − prior.net exactly,
                                      stagnant count precise, no double-counting
                                      across windows, bar_pct bounded [0,100]
Tier 6  Security        VL_40–VL_45   injection strings in module paths, repo isolation
                                      (two repos never share rows), unicode paths
Tier 7  Stress          VL_46–VL_50   10k-commit BFS cap, 500-module repo,
                                      empty repo returns [], single-commit repo

Total: 50 cases across 7 tiers.


Acceptance Criteria

  • /gabriel/musehub/intel/velocity returns 200 with data matching CLI output
  • Module rows match muse code velocity --json modules list exactly
  • Acceleration badges colored correctly (success/warning/muted)
  • Dual current/prior bars render proportionally
  • Sort by active_commits, net, acceleration, stagnant all work
  • Module prefix filter narrows list
  • Dashboard sparkline has working "View all →" link
  • All 50 tests pass
  • VelocityProvider stores data without subprocess (worker-safe)
  • Migration 0012 applies cleanly forward and back
Activity1
gabriel opened this issue 47 days ago
gabriel 47 days ago

Velocity feature — all 5 phases complete ✓

Deployed to staging as commit 10e6267a (image tag 10e6267a-20260503083857).

What shipped

Phase Description Status
0 Rewrote VelocityProvider as pure-SQL BFS (no subprocess)
1 Migration 0012 — 4 new columns: prior_modified, prior_active_commits, window_size, commits_analysed
2 SCSS — components/_velocity.scss + pages/_velocity.scss, wired into app.scss
3 Routes + templates — /intel/velocity list page + /intel/velocity/detail per-module page
4 Dashboard sparkline "View all →" link wired to /intel/velocity
5 50-case TDD test suite tests/test_velocity_provider.py (VL_01–VL_50, 7 tiers) — all pass

Test tiers

  • VL_01–08: unit — module derivation + accel helpers
  • VL_09–18: integration — op counting, net, active_commits, new columns, result key
  • VL_19–25: e2e — ranking, two modules, stagnant, prior window, acceleration
  • VL_26–32: performance — timing bounds (20-commit window < 5 s)
  • VL_33–38: state — idempotency, purge, incremental, no duplicates
  • VL_39–44: security — injection, XSS, repo isolation, unicode
  • VL_45–50: stress — TOP cap, truncated flag, 500 commits, count match, BFS cap

Algorithm

Two-window BFS from HEAD over musehub_commits + musehub_symbol_history_entries:

  • current_window = first 20 commits in BFS order
  • prior_window = commits 20–39
  • acceleration = current net − prior net
  • stagnant commits = commits where net additions == 0 for that module