Skip to content

feat(roadmap-planner): W2 — fold bot contributions into synthetic bot member#190

Merged
danielfbm merged 1 commit into
mainfrom
feat/metrics-w2-bot-consolidation
May 19, 2026
Merged

feat(roadmap-planner): W2 — fold bot contributions into synthetic bot member#190
danielfbm merged 1 commit into
mainfrom
feat/metrics-w2-bot-consolidation

Conversation

@danielfbm

Copy link
Copy Markdown
Contributor

Second workstream of the 2026-05-19 metrics audit follow-up — resolves B4 (56% of pr_reviews rows are bots, dragging team-wide first-review p50 to ~0.1h).

Summary

  • Two new columns (migration 0005_first_human_review.sql):
    • pr_reviews.is_bot — tagged when reviewer_login matches team_analytics.bot_logins.
    • pull_requests.first_human_review_atMIN(submitted_at) over non-bot reviews.
  • New team_analytics.bot_logins []string config + contributions.BotSet predicate. Exact + case-folded match, no suffix magic (confirmed by maintainer).
  • GitHub + GitLab syncers reassign bot author_id / reviewer_id"bot" and set is_bot / first_human_review_at live during sync.
  • contributions.ConsolidateBots runs once on every startup as a retroactive backfill (idempotent) so pre-W2 rows get the same treatment without a re-sync.
  • NetworkDensity reads from first_human_review_at and joins with rv.is_bot = 0.

Activation rules

  • bot_logins: [] → no behaviour change. Predicate is a no-op; backfill returns immediately.
  • Populated list → live ingest reclassifies + one-shot backfill on next boot.

Visible effects when enabled

  • A bot row appears in the team table with the volume of automated work (renovate alone is hundreds of PRs in any 6-month window). Already in the W1 allowlist.
  • First-review p50 jumps from sub-1h to the real human value (typically several hours).

Rollback

  • Empty bot_logins: [] and restart → predicate disables; new rows ingest under raw login. Schema additions stay (no destructive migration).
  • Retroactive author/reviewer rewrites are sticky. If a full undo is required, manual SQL.

Test plan

  • go test ./... + go vet ./... — green
  • TestBotSet — empty / exact / case-fold / whitespace
  • TestConsolidateBots — human PR with mixed bot+human reviews, bot-authored PR, idempotency on rerun
  • Dev deploy with bot_logins: [alaudabot, alaudaa-renovate, edge-katanomi-app2[bot], copilot-pull-request-reviewer[bot], kilo-code-bot[bot], copilot] — verify backfill counts + first-review p50 climbs
  • Operator smoke: bot member shows up in /team with non-trivial prs_merged and prs_reviewed
  • Network density panel: first_review_latency_p50_hours reflects human review time

Depends on

Independent of W1 (#189). W1's allowlist already includes the synthetic bot member, so this PR's volume row stays visible when both ship.

Unlocks

  • W8review_latency_p50_hours (per-reviewer week p50 of first_human_review_at - created_at).

🤖 Generated with Claude Code

if bots.Size() > 0 {
res, err := contributions.ConsolidateBots(ctx, store, bots)
if err != nil {
logger.Warn("bot consolidation backfill failed", zap.Error(err))

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Warning (style/error-handling): ConsolidateBots errors are logged as warnings rather than returning a fatal error. If backfill fails, the server continues with potentially inconsistent state. Consider whether this should be fatal for production deployments, or add a startup health check to verify the backfill succeeded.

placeholders := strings.Repeat("?, ", len(logins))
placeholders = strings.TrimSuffix(placeholders, ", ")

rebind := func(q string) string {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggestion (docs/readability): The rebind function uses dialect.Placeholder(n) assuming 1-based indexing. Consider adding a brief comment explaining this assumption to improve maintainability.

@alaudabot

alaudabot commented May 19, 2026

Copy link
Copy Markdown
Contributor

🤖 AI Code Review

Property Value
Model opencode/minimax-m2.5-free
Style strict
Issues Found 1
Config Source centralized
Profile ❌ Not Found
Personalized Prompt ❌ No
Prompt Path .github/review/profiles/alaudadevops/toolbox/pr-review.md
Alauda Skills ✅ base-acp-operator-list, base-acp-operator-release, base-authoring, base-m365, base-ocp-operator-list, base-skill-setup, builders-alauda-component-e2e-release, builders-alauda-component-upgrade, builders-alauda-pipeline, builders-claudetask-submit, builders-component-knowledge, builders-confluence, builders-dev-mesh-qa, builders-edge-ci-trace, builders-gitlab-ops, builders-helm-operator-generator, builders-install-cluster-plugin, builders-jira, builders-notify-wecom, builders-olm-operator-lifecycle, builders-prd-to-testcase, builders-publish-errata, builders-roadmap-studio, builders-story-split, builders-violet, builders-webapp-testing, cross-repo-add-mirror, cross-repo-publish, devops-add-bug-release-notes, devops-autodns, devops-bundle-csv-baseline-diff, devops-candidate-version-supervisor, devops-connectors-acceptance-test, devops-connectors-explore, devops-connectors-poc-case, devops-connectors-review, devops-connectors-unit-test, devops-connectors-upgrade-test, devops-connectors-write-user-docs, devops-creating-tekton-pipelines, devops-fix-go-vulns, devops-fork-alauda-binary-release, devops-gen-advanced-form-descriptors, devops-jira-rfd-acceptance, devops-knowledge-adoption, devops-pr-review, devops-refresh-containerfile-digests, devops-refresh-containerfile-tags, devops-replace-strings, devops-scan-docker-keywords, devops-sync-alauda-github-releases, devops-tekton-dynamic-form-optimizer, devops-tekton-operator-task-e2e, devops-tekton-pipeline-delivery, devops-tekton-refresh-results-tag, devops-tekton-task-delivery, devops-tekton-task-overview-template, devops-tekton-task-version-upgrade, devops-tekton-upgrade-notes, devops-tool-report-troubleshoot, devops-ui-e2e-code-audit, devops-ui-e2e-fix-base-on-report, devops-ui-e2e-regression-and-fix, devops-ui-generate-e2e-from-feature, devops-ui-pre-setup, devops-upgrade-go, devops-upstream-backport-cve, devops-upstream-upgrade
Reviewed at 2026-05-19 22:29:23 UTC

Summary

This PR implements W2 of the roadmap-planner metrics audit follow-up: consolidating bot contributions (renovate, copilot, etc.) into a synthetic "bot" member to prevent bot activity from skewing human-first-review latency metrics. The implementation adds is_bot and first_human_review_at columns, config-based bot login allowlist, live syncer integration, and an idempotent startup backfill. However, there is a critical unresolved merge conflict in config.example.yaml that would cause build failures.

Review Statistics

Category Count
Critical Issues 1
Warnings 0
Suggestions 2
Files Reviewed 12

Critical Issues

Issues that MUST be addressed before merging (security, bugs, breaking changes)

  • [config.example.yaml:125] CRITICAL (bug/merge-conflict): Unresolved merge conflict markers (<<<<<<< HEAD, =======, >>>>>>> ee78c5b) present in the config file. This will cause YAML parsing failures and prevent the server from starting. The conflict must be resolved before deployment.

Warnings

Issues that SHOULD be addressed but are not blocking

  • None identified

Suggestions

Recommendations for improvement (nice to have)

  • [bot.go:107] (style/code-structure): The rebind function is complex and handles dialect-specific placeholder translation. Consider extracting this into a dedicated helper package or adding more explicit documentation about which dialects require this transformation.

  • [main.go:230] (style/error-handling): ConsolidateBots errors are logged as warnings rather than returned, meaning startup continues even if the backfill fails. This may hide data inconsistency issues in production. Consider either returning the error or adding a startup health check that verifies the backfill completed.

Positive Feedback

The implementation is well thought out:

  • Idempotent backfill: ConsolidateBots safely runs on every startup without re-processing already-consolidated rows
  • Clean separation: Bot detection logic is isolated in BotSet with clear Contains() and Size() interfaces
  • Comprehensive tests: TestBotSet covers empty/exact/case-fold/whitespace scenarios; TestConsolidateBots verifies all four side effects plus idempotency
  • Proper SQL dialect handling: The rebind helper handles both ? (SQLite) and $N (PostgreSQL) placeholders
  • Good documentation: CHANGES.md clearly explains W2 changes with audit cross-references

Note: Since this PR is already merged, these comments serve as documentation for future reference. The merge conflict in config.example.yaml should have been caught before merge and requires immediate remediation.


ℹ️ About this review

This review was automatically generated using the run-actions workflow.

  • Shared prompt: .github/prompts/code-review.md
  • Config source: centralized
  • Profile path: Not Found
  • Profile ref: e75e733e9aa1b417a8b3c6441e53495dbcb418ad
  • No repository-specific prompt configured
  • Alauda skills: base-acp-operator-list, base-acp-operator-release, base-authoring, base-m365, base-ocp-operator-list, base-skill-setup, builders-alauda-component-e2e-release, builders-alauda-component-upgrade, builders-alauda-pipeline, builders-claudetask-submit, builders-component-knowledge, builders-confluence, builders-dev-mesh-qa, builders-edge-ci-trace, builders-gitlab-ops, builders-helm-operator-generator, builders-install-cluster-plugin, builders-jira, builders-notify-wecom, builders-olm-operator-lifecycle, builders-prd-to-testcase, builders-publish-errata, builders-roadmap-studio, builders-story-split, builders-violet, builders-webapp-testing, cross-repo-add-mirror, cross-repo-publish, devops-add-bug-release-notes, devops-autodns, devops-bundle-csv-baseline-diff, devops-candidate-version-supervisor, devops-connectors-acceptance-test, devops-connectors-explore, devops-connectors-poc-case, devops-connectors-review, devops-connectors-unit-test, devops-connectors-upgrade-test, devops-connectors-write-user-docs, devops-creating-tekton-pipelines, devops-fix-go-vulns, devops-fork-alauda-binary-release, devops-gen-advanced-form-descriptors, devops-jira-rfd-acceptance, devops-knowledge-adoption, devops-pr-review, devops-refresh-containerfile-digests, devops-refresh-containerfile-tags, devops-replace-strings, devops-scan-docker-keywords, devops-sync-alauda-github-releases, devops-tekton-dynamic-form-optimizer, devops-tekton-operator-task-e2e, devops-tekton-pipeline-delivery, devops-tekton-refresh-results-tag, devops-tekton-task-delivery, devops-tekton-task-overview-template, devops-tekton-task-version-upgrade, devops-tekton-upgrade-notes, devops-tool-report-troubleshoot, devops-ui-e2e-code-audit, devops-ui-e2e-fix-base-on-report, devops-ui-e2e-regression-and-fix, devops-ui-generate-e2e-from-feature, devops-ui-pre-setup, devops-upgrade-go, devops-upstream-backport-cve, devops-upstream-upgrade

… member

Second workstream of the 2026-05-19 metrics audit follow-up. Resolves
finding B4 (56% of pr_reviews rows are automated, dragging the
team-wide first-review p50 to ~0.1h).

Adds two new schema columns (migration 0005), an explicit
team_analytics.bot_logins config knob, and the contributions/bot.go
package that owns both the live predicate (BotSet) and the one-shot
retroactive consolidation pass (ConsolidateBots).

Live ingest changes:
- github.Syncer.IsBotLogin / gitlab.Syncer.IsBotLogin predicates.
  When a PR's author_login matches, author_id becomes "bot". Same
  for review rows: reviewer_id="bot" and is_bot=1.
- pull_requests.first_human_review_at is computed live as
  MIN(submitted_at) over non-bot reviews.

Retroactive backfill at startup (idempotent):
- pr_reviews: tag is_bot=1, rewrite reviewer_id to "bot" where login matches.
- pull_requests: rewrite author_id to "bot" where login matches; populate
  first_human_review_at from non-bot reviews on each PR.

NetworkDensity now:
- Reads first-review latency from first_human_review_at (so renovate's
  instant comments stop collapsing p50 to ~0.1h).
- Joins with rv.is_bot=0 in the cross-pillar review query.

Activation:
- Empty bot_logins -> no behaviour change (BotSet.Size()==0 is a no-op).
- Populated list -> live ingest reclassifies + startup pass updates
  historical rows.

Tests:
- BotSet truth table (empty, exact, case-fold).
- ConsolidateBots: human PR with bot+human reviews -> is_bot tagged,
  reviewer_id rewritten, first_human_review_at = human's review time
  (not the earlier bot review). Bot-authored PR -> author_id="bot".
  Idempotency: re-running consolidates nothing.

Doc: CHANGES.md gets the W2 block describing config, visible effects,
and rollback path.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@danielfbm danielfbm force-pushed the feat/metrics-w2-bot-consolidation branch from ee78c5b to df4d8bf Compare May 19, 2026 22:28
@danielfbm danielfbm merged commit c25b699 into main May 19, 2026
6 of 8 checks passed
@danielfbm danielfbm deleted the feat/metrics-w2-bot-consolidation branch May 19, 2026 22:28
@@ -125,6 +125,7 @@ github:
private_key_path: "" # path to the PEM file (mount via Secret)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CRITICAL (bug/merge-conflict): Unresolved merge conflict markers (<<<<<<< HEAD, =======, >>>>>>> ee78c5b) present in this file. This will cause YAML parsing failures when the config is loaded. The conflict must be resolved before this PR can be deployed.

placeholders := strings.Repeat("?, ", len(logins))
placeholders = strings.TrimSuffix(placeholders, ", ")

rebind := func(q string) string {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggestion (style/code-structure): The rebind function is complex and handles dialect-specific placeholder translation. Consider extracting this into a dedicated helper or adding more documentation about which dialects require this transformation.

if bots.Size() > 0 {
res, err := contributions.ConsolidateBots(ctx, store, bots)
if err != nil {
logger.Warn("bot consolidation backfill failed", zap.Error(err))

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Warning (style/error-handling): ConsolidateBots errors are logged as warnings rather than returned, meaning startup continues even if the backfill fails. This may hide data inconsistency issues in production. Consider adding a startup health check or returning the error.

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.

2 participants