Skip to content

Commit 7e69e80

Browse files
committed
refactor: structure github conversation analytics
1 parent a6d6075 commit 7e69e80

File tree

7 files changed

+1057
-58
lines changed

7 files changed

+1057
-58
lines changed

README.md

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,8 @@ Copy `.env.example` to `.env` and adjust values locally if you prefer dotenv-sty
9898
- The JSON results are mapped back to the originating changed lines so findings retain repo/PR/file/line attribution.
9999
- Extend the rule pack or point the detector at your organization-wide Semgrep registry by updating `SemgrepDetector` in `app/services/detection.py`.
100100
- Register additional detectors by providing module paths in `PROVENANCE_DETECTOR_MODULE_PATHS`; each module should expose `register_detectors()` returning `BaseDetector` instances.
101-
- When GitHub credentials are configured, the service automatically inspects commit trailers, PR labels, review comments, and reviewer identities to fill missing agent attribution (see `app/provenance/github_resolver.py`).
101+
- When GitHub credentials are configured, the service automatically inspects commit trailers, PR labels, review comments, reviewer identities, and PR timelines to fill missing agent attribution and capture structured evidence (see `app/provenance/github_resolver.py`).
102+
- The resolver also persists PR conversations (thread counts, classification breakdowns, agent response latency), CI outcomes (time-to-green, failed checks), and commit/timeline summaries (force pushes, human follow-ups, rewrite loops) so analytics can surface behavioral signals without re-calling the GitHub API.
102103
- Built-in heuristics now include a Python import detector that flags risky modules (e.g., `subprocess`, `pickle`); extend this pattern with your own detectors via modular hooks.
103104

104105
## API Surface
@@ -146,9 +147,9 @@ Example ingestion payload:
146147

147148
## Agent Insights & Analytics
148149

149-
- `/v1/analytics/summary` now supports additional metrics: `code_volume`, `code_churn_rate`, and `avg_line_complexity` in addition to `risk_rate` and `provenance_coverage`.
150-
- `/v1/analytics/agents/behavior` returns composite snapshots (volume, churn rate, heuristic complexity, and top vulnerability categories per agent) to power comparison dashboards.
151-
- Review-focused metrics (`review_comments`, `unique_reviewers`) leverage GitHub PR data when credentials are supplied.
150+
- `/v1/analytics/summary` now surfaces GitHub-aware metrics alongside the existing risk/volume suite: `code_volume`, `code_churn_rate`, `avg_line_complexity`, `agent_response_rate`, `agent_response_p50_hours`, `agent_response_p90_hours`, `reopened_threads`, `force_push_events`, `rewrite_loops`, `human_followup_commits`, `ci_time_to_green_hours`, `ci_failed_checks`, `agent_commit_ratio`, `commit_lead_time_hours`, and `classification_<label>_count` (e.g., `classification_security_count`).
151+
- `/v1/analytics/agents/behavior` returns composite snapshots that now blend code/finding metrics with review conversation health (thread counts, response latency, classification breakdowns), CI friction (failures, time-to-green), commit dynamics (force pushes, rewrite loops, human follow-ups), and attention heatmaps (top paths + hot files) per agent.
152+
- Review-focused metrics (`review_comments`, `unique_reviewers`, `review_events`, `agent_comment_mentions`) continue to leverage GitHub PR data when credentials are supplied; classification metrics reflect the resolver's heuristic labeling of each conversation snippet.
152153
- Use `PROVENANCE_ANALYTICS_DEFAULT_WINDOW` or query parameters such as `?time_window=14d` to track longer horizons and compare agents.
153154

154155
## Telemetry Export

app/models/analytics.py

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,34 @@ class AgentBehaviorSnapshot(BaseModel):
5454
unique_reviewers: int = Field(0, description="Unique reviewer count across associated PRs.")
5555
review_events: int = Field(0, description="Total review submissions across associated PRs.")
5656
agent_comment_mentions: int = Field(0, description="Count of agent markers found in review comments.")
57+
comment_threads: int = Field(0, description="Distinct review discussion threads observed.")
58+
reopened_threads: int = Field(0, description="Threads where reviewers re-engaged after an agent response.")
59+
agent_response_rate: float = Field(0.0, description="Share of threads with an agent response.")
60+
agent_response_p50_hours: Optional[float] = Field(
61+
None, description="Median response time (hours) between reviewer comment and agent reply."
62+
)
63+
agent_response_p90_hours: Optional[float] = Field(
64+
None, description="P90 response time (hours) between reviewer comment and agent reply."
65+
)
66+
classification_breakdown: dict[str, int] = Field(
67+
default_factory=dict, description="Aggregate comment/review classifications (security, nit, etc.)."
68+
)
69+
ci_run_count: int = Field(0, description="Number of CI runs/checks evaluated.")
70+
ci_failure_count: int = Field(0, description="Number of failing CI runs/checks.")
71+
ci_failed_checks: int = Field(0, description="Unique failing CI checks in the window.")
72+
ci_time_to_green_hours: Optional[float] = Field(None, description="Median time-to-green across CI runs.")
73+
ci_latest_status: Optional[str] = Field(None, description="Most recent CI rollup status observed.")
74+
force_push_events: int = Field(0, description="Force-push events recorded on associated PRs.")
75+
rewrite_loops: int = Field(0, description="Follow-up human commits arriving within 48h of agent commits.")
76+
human_followup_commits: int = Field(0, description="Count of human commits landing immediately after agent commits.")
77+
agent_commit_ratio: float = Field(0.0, description="Share of commits authored by the agent.")
78+
commit_lead_time_hours: Optional[float] = Field(None, description="Lead time between earliest and latest commits.")
79+
top_paths: dict[str, int] = Field(
80+
default_factory=dict, description="Most frequently modified top-level paths for the agent."
81+
)
82+
hot_files: list[str] = Field(
83+
default_factory=list, description="Files touched repeatedly (>=3 times) signalling attention hot-spots."
84+
)
5785

5886

5987
class AgentBehaviorReport(BaseModel):

0 commit comments

Comments
 (0)