limn-review 0.1.123
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +110 -0
- package/README.md +133 -0
- package/dist/ai/runtime.js +535 -0
- package/dist/api/plugins/auth.js +169 -0
- package/dist/api/plugins/error-handler.js +114 -0
- package/dist/api/plugins/rate-limit.js +855 -0
- package/dist/api/plugins/security.js +321 -0
- package/dist/api/routes/activity.js +103 -0
- package/dist/api/routes/ai-runtime.js +67 -0
- package/dist/api/routes/auth.js +194 -0
- package/dist/api/routes/billing.js +209 -0
- package/dist/api/routes/bot-triage.js +1289 -0
- package/dist/api/routes/conflicts.js +730 -0
- package/dist/api/routes/contact.js +318 -0
- package/dist/api/routes/daily-brief.js +58 -0
- package/dist/api/routes/flow.js +71 -0
- package/dist/api/routes/health.js +7 -0
- package/dist/api/routes/insights.js +200 -0
- package/dist/api/routes/me.js +458 -0
- package/dist/api/routes/mentions.js +22 -0
- package/dist/api/routes/mergers.js +8 -0
- package/dist/api/routes/ml-labels.js +109 -0
- package/dist/api/routes/open-prs.js +35 -0
- package/dist/api/routes/prs.js +1633 -0
- package/dist/api/routes/reactions.js +217 -0
- package/dist/api/routes/repos.js +563 -0
- package/dist/api/routes/search.js +41 -0
- package/dist/api/routes/threads.js +118 -0
- package/dist/api/routes/timeline.js +150 -0
- package/dist/api/routes/users.js +67 -0
- package/dist/api/routes/webhooks.js +181 -0
- package/dist/api/routes/workspaces.js +322 -0
- package/dist/app.js +274 -0
- package/dist/ascii.js +19 -0
- package/dist/auth/account.js +482 -0
- package/dist/auth/crypto.js +46 -0
- package/dist/bot-triage/resolve.js +59 -0
- package/dist/cli.js +388 -0
- package/dist/coding/activity.js +80 -0
- package/dist/coding/agent.js +288 -0
- package/dist/coding/ai-fix/auto-fix.js +212 -0
- package/dist/coding/ai-fix/manager.js +370 -0
- package/dist/coding/ai-fix/persist.js +213 -0
- package/dist/coding/ai-fix/pr-context.js +58 -0
- package/dist/coding/ai-fix/prompts.js +138 -0
- package/dist/coding/ai-fix/review-seed.js +357 -0
- package/dist/coding/ai-fix/routes.js +425 -0
- package/dist/coding/git-ops.js +321 -0
- package/dist/coding/git.js +184 -0
- package/dist/coding/merge.js +262 -0
- package/dist/coding/safe-path.js +75 -0
- package/dist/coding/schema.js +43 -0
- package/dist/config.js +648 -0
- package/dist/conflict/diff.js +304 -0
- package/dist/conflict/git.js +118 -0
- package/dist/conflict/hash.js +73 -0
- package/dist/conflict/janitor.js +218 -0
- package/dist/conflict/land.js +675 -0
- package/dist/conflict/model-types.js +2 -0
- package/dist/conflict/model.js +1081 -0
- package/dist/conflict/parse.js +142 -0
- package/dist/conflict/seam.js +136 -0
- package/dist/conflict/session.js +532 -0
- package/dist/conflict/suggestion.js +398 -0
- package/dist/conflict/tokens.js +72 -0
- package/dist/data-dir.js +112 -0
- package/dist/db/actor-lanes.js +213 -0
- package/dist/db/automation-ids.js +97 -0
- package/dist/db/automation-output.js +349 -0
- package/dist/db/blast-radius-query.js +36 -0
- package/dist/db/blast-radius.js +226 -0
- package/dist/db/bot-dormancy.js +115 -0
- package/dist/db/bot-overlap.js +579 -0
- package/dist/db/bot-volume.js +722 -0
- package/dist/db/bot-window.js +35 -0
- package/dist/db/branch-queries.js +310 -0
- package/dist/db/change-shape.js +243 -0
- package/dist/db/changepoint.js +75 -0
- package/dist/db/cleanup.js +36 -0
- package/dist/db/client.js +102 -0
- package/dist/db/code-loc.js +388 -0
- package/dist/db/credits.js +79 -0
- package/dist/db/daily-brief.js +406 -0
- package/dist/db/dependency-cards.js +145 -0
- package/dist/db/erase-account.js +255 -0
- package/dist/db/export-account.js +189 -0
- package/dist/db/failing-checks.js +124 -0
- package/dist/db/file-coupling.js +197 -0
- package/dist/db/flow-detail.js +661 -0
- package/dist/db/flow-pointers.js +197 -0
- package/dist/db/flow-settings.js +67 -0
- package/dist/db/forecast.js +114 -0
- package/dist/db/line-overlap.js +81 -0
- package/dist/db/merge-queue.js +189 -0
- package/dist/db/migrate.js +17 -0
- package/dist/db/migrations/0000_purple_ben_grimm.sql +155 -0
- package/dist/db/migrations/0001_colorful_ozymandias.sql +31 -0
- package/dist/db/migrations/0002_famous_sersi.sql +9 -0
- package/dist/db/migrations/0003_clever_shinobi_shaw.sql +3 -0
- package/dist/db/migrations/0004_pale_scalphunter.sql +1 -0
- package/dist/db/migrations/0005_daffy_guardian.sql +2 -0
- package/dist/db/migrations/0006_cute_violations.sql +45 -0
- package/dist/db/migrations/0007_dark_anthem.sql +2 -0
- package/dist/db/migrations/0008_multitenant_accounts.sql +44 -0
- package/dist/db/migrations/0009_lean_bodies.sql +13 -0
- package/dist/db/migrations/0010_lean_bodies_nullable.sql +56 -0
- package/dist/db/migrations/0011_pr_diff_size.sql +10 -0
- package/dist/db/migrations/0012_findings_included_default.sql +7 -0
- package/dist/db/migrations/0013_review_routing.sql +9 -0
- package/dist/db/migrations/0014_account_last_active.sql +6 -0
- package/dist/db/migrations/0015_repos_inbox_watch.sql +9 -0
- package/dist/db/migrations/0016_repo_viewer_permission.sql +7 -0
- package/dist/db/migrations/0017_account_display_name.sql +7 -0
- package/dist/db/migrations/0018_finding_comment_kind.sql +7 -0
- package/dist/db/migrations/0019_finding_file_in_diff.sql +7 -0
- package/dist/db/migrations/0020_claude_review_cost_telemetry.sql +11 -0
- package/dist/db/migrations/0021_account_feed_last_seen.sql +7 -0
- package/dist/db/migrations/0022_ci_status_events.sql +21 -0
- package/dist/db/migrations/0023_ai_usage.sql +21 -0
- package/dist/db/migrations/0024_pr_head_ref_name.sql +6 -0
- package/dist/db/migrations/0025_account_billing.sql +7 -0
- package/dist/db/migrations/0026_ai_credit_allowance.sql +5 -0
- package/dist/db/migrations/0027_user_github_type.sql +6 -0
- package/dist/db/migrations/0028_bot_review_classification.sql +21 -0
- package/dist/db/migrations/0029_bot_mute_rules.sql +19 -0
- package/dist/db/migrations/0030_teams.sql +32 -0
- package/dist/db/migrations/0031_events_pr_idx.sql +7 -0
- package/dist/db/migrations/0032_benchmark_contributions.sql +29 -0
- package/dist/db/migrations/0033_thread_addressed_confidence.sql +9 -0
- package/dist/db/migrations/0034_thread_resolved_at.sql +6 -0
- package/dist/db/migrations/0035_pr_first_review_requested_at.sql +5 -0
- package/dist/db/migrations/0036_search_index.sql +25 -0
- package/dist/db/migrations/0037_author_indexes.sql +15 -0
- package/dist/db/migrations/0038_auto_merge_requests.sql +37 -0
- package/dist/db/migrations/0039_branch_status.sql +44 -0
- package/dist/db/migrations/0040_pr_review_decision.sql +10 -0
- package/dist/db/migrations/0041_branch_commit_detail.sql +38 -0
- package/dist/db/migrations/0042_repo_reviewers.sql +176 -0
- package/dist/db/migrations/0043_account_reviewers.sql +131 -0
- package/dist/db/migrations/0044_workspaces.sql +138 -0
- package/dist/db/migrations/0045_workspace_reviewers.sql +180 -0
- package/dist/db/migrations/0046_drop_inbox_watch.sql +25 -0
- package/dist/db/migrations/0047_ml_comment_labels.sql +40 -0
- package/dist/db/migrations/0048_ml_vendor_severity.sql +31 -0
- package/dist/db/migrations/0049_seat_pricing_repo_description.sql +21 -0
- package/dist/db/migrations/0050_users_app_slug.sql +12 -0
- package/dist/db/migrations/0051_auto_merge_queue.sql +17 -0
- package/dist/db/migrations/0052_trunk_ci_status_events.sql +43 -0
- package/dist/db/migrations/0053_automation_roles.sql +79 -0
- package/dist/db/migrations/0054_automation_vendor_kinds.sql +514 -0
- package/dist/db/migrations/0055_auto_merge_phase.sql +12 -0
- package/dist/db/migrations/0056_pr_mentions.sql +22 -0
- package/dist/db/migrations/0057_large_pr_threshold.sql +14 -0
- package/dist/db/migrations/0058_pending_mute.sql +53 -0
- package/dist/db/migrations/0059_merge_queue_state.sql +33 -0
- package/dist/db/migrations/0060_drop_my_turn_dismissals.sql +33 -0
- package/dist/db/migrations/0061_auto_merge_durable_anchors.sql +27 -0
- package/dist/db/migrations/0062_blast_radius_config.sql +21 -0
- package/dist/db/migrations/0063_repo_file_coupling.sql +33 -0
- package/dist/db/migrations/0064_pr_content_kind.sql +21 -0
- package/dist/db/migrations/0065_workspace_flow_settings.sql +13 -0
- package/dist/db/migrations/0066_review_request_events.sql +31 -0
- package/dist/db/migrations/0067_pr_security_signals.sql +86 -0
- package/dist/db/migrations/0068_my_turn_settings.sql +18 -0
- package/dist/db/migrations/0069_my_turn_dismissals.sql +41 -0
- package/dist/db/migrations/0070_claude_review_follow_up_ticket.sql +22 -0
- package/dist/db/migrations/0071_claude_review_trigger.sql +11 -0
- package/dist/db/migrations/0072_commit_message_headline.sql +13 -0
- package/dist/db/migrations/0073_claude_review_chat.sql +31 -0
- package/dist/db/migrations/0074_adopt_agentic_tables.sql +98 -0
- package/dist/db/migrations/0075_review_lens_drop_learnings.sql +15 -0
- package/dist/db/migrations/0076_claude_review_threads.sql +17 -0
- package/dist/db/migrations/0077_claude_review_ci_failures.sql +10 -0
- package/dist/db/migrations/0078_ai_fix_change_report.sql +17 -0
- package/dist/db/migrations/0079_claude_finding_story.sql +16 -0
- package/dist/db/migrations/meta/0000_snapshot.json +1116 -0
- package/dist/db/migrations/meta/0001_snapshot.json +1321 -0
- package/dist/db/migrations/meta/0002_snapshot.json +1375 -0
- package/dist/db/migrations/meta/0003_snapshot.json +1396 -0
- package/dist/db/migrations/meta/0004_snapshot.json +1416 -0
- package/dist/db/migrations/meta/0005_snapshot.json +1430 -0
- package/dist/db/migrations/meta/0006_snapshot.json +1745 -0
- package/dist/db/migrations/meta/0007_snapshot.json +1759 -0
- package/dist/db/migrations/meta/_journal.json +566 -0
- package/dist/db/migrations-pg/0000_tired_alex_power.sql +268 -0
- package/dist/db/migrations-pg/0001_dizzy_mockingbird.sql +3 -0
- package/dist/db/migrations-pg/0002_glorious_ikaris.sql +4 -0
- package/dist/db/migrations-pg/0003_melted_secret_warriors.sql +2 -0
- package/dist/db/migrations-pg/0004_numerous_triton.sql +1 -0
- package/dist/db/migrations-pg/0005_thick_blockbuster.sql +2 -0
- package/dist/db/migrations-pg/0006_majestic_dracula.sql +1 -0
- package/dist/db/migrations-pg/0007_same_human_torch.sql +2 -0
- package/dist/db/migrations-pg/0008_slimy_toxin.sql +1 -0
- package/dist/db/migrations-pg/0009_fuzzy_jubilee.sql +4 -0
- package/dist/db/migrations-pg/0010_late_hammerhead.sql +1 -0
- package/dist/db/migrations-pg/0011_happy_leech.sql +16 -0
- package/dist/db/migrations-pg/0012_woozy_captain_midlands.sql +16 -0
- package/dist/db/migrations-pg/0013_yielding_nicolaos.sql +1 -0
- package/dist/db/migrations-pg/0014_wakeful_bill_hollister.sql +2 -0
- package/dist/db/migrations-pg/0015_aspiring_black_tom.sql +1 -0
- package/dist/db/migrations-pg/0016_cute_ghost_rider.sql +30 -0
- package/dist/db/migrations-pg/0017_far_changeling.sql +24 -0
- package/dist/db/migrations-pg/0018_fancy_miss_america.sql +1 -0
- package/dist/db/migrations-pg/0019_benchmark_contributions.sql +22 -0
- package/dist/db/migrations-pg/0020_majestic_edwin_jarvis.sql +3 -0
- package/dist/db/migrations-pg/0021_green_salo.sql +1 -0
- package/dist/db/migrations-pg/0022_wise_baron_strucker.sql +1 -0
- package/dist/db/migrations-pg/0023_search_index.sql +19 -0
- package/dist/db/migrations-pg/0024_author_indexes.sql +9 -0
- package/dist/db/migrations-pg/0025_auto_merge_requests.sql +26 -0
- package/dist/db/migrations-pg/0026_branch_status.sql +32 -0
- package/dist/db/migrations-pg/0027_pr_review_decision.sql +5 -0
- package/dist/db/migrations-pg/0028_branch_commit_detail.sql +9 -0
- package/dist/db/migrations-pg/0029_repo_reviewers.sql +127 -0
- package/dist/db/migrations-pg/0030_account_reviewers.sql +77 -0
- package/dist/db/migrations-pg/0031_workspaces.sql +131 -0
- package/dist/db/migrations-pg/0032_workspace_reviewers.sql +165 -0
- package/dist/db/migrations-pg/0033_drop_inbox_watch.sql +14 -0
- package/dist/db/migrations-pg/0034_ml_comment_labels.sql +33 -0
- package/dist/db/migrations-pg/0035_ml_vendor_severity.sql +16 -0
- package/dist/db/migrations-pg/0036_seat_pricing_repo_description.sql +12 -0
- package/dist/db/migrations-pg/0037_users_app_slug.sql +9 -0
- package/dist/db/migrations-pg/0038_auto_merge_queue.sql +10 -0
- package/dist/db/migrations-pg/0039_trunk_ci_status_events.sql +27 -0
- package/dist/db/migrations-pg/0040_automation_roles.sql +63 -0
- package/dist/db/migrations-pg/0041_automation_vendor_kinds.sql +488 -0
- package/dist/db/migrations-pg/0042_auto_merge_phase.sql +8 -0
- package/dist/db/migrations-pg/0043_pr_mentions.sql +19 -0
- package/dist/db/migrations-pg/0044_large_pr_threshold.sql +6 -0
- package/dist/db/migrations-pg/0045_pending_mute.sql +26 -0
- package/dist/db/migrations-pg/0046_merge_queue_state.sql +18 -0
- package/dist/db/migrations-pg/0047_drop_my_turn_dismissals.sql +21 -0
- package/dist/db/migrations-pg/0048_auto_merge_durable_anchors.sql +27 -0
- package/dist/db/migrations-pg/0049_blast_radius_config.sql +8 -0
- package/dist/db/migrations-pg/0050_repo_file_coupling.sql +13 -0
- package/dist/db/migrations-pg/0051_pr_content_kind.sql +6 -0
- package/dist/db/migrations-pg/0052_workspace_flow_settings.sql +4 -0
- package/dist/db/migrations-pg/0053_review_request_events.sql +18 -0
- package/dist/db/migrations-pg/0054_pr_security_signals.sql +59 -0
- package/dist/db/migrations-pg/0055_my_turn_settings.sql +6 -0
- package/dist/db/migrations-pg/0056_my_turn_dismissals.sql +21 -0
- package/dist/db/migrations-pg/0057_claude_review_follow_up_ticket.sql +8 -0
- package/dist/db/migrations-pg/0058_claude_review_trigger.sql +4 -0
- package/dist/db/migrations-pg/0059_commit_message_headline.sql +3 -0
- package/dist/db/migrations-pg/0060_claude_review_chat.sql +24 -0
- package/dist/db/migrations-pg/0061_adopt_agentic_tables.sql +79 -0
- package/dist/db/migrations-pg/0062_review_lens_drop_learnings.sql +5 -0
- package/dist/db/migrations-pg/0063_claude_review_threads.sql +7 -0
- package/dist/db/migrations-pg/0064_claude_review_ci_failures.sql +4 -0
- package/dist/db/migrations-pg/0065_ai_fix_change_report.sql +9 -0
- package/dist/db/migrations-pg/0066_claude_finding_story.sql +7 -0
- package/dist/db/migrations-pg/meta/0000_snapshot.json +2137 -0
- package/dist/db/migrations-pg/meta/0001_snapshot.json +2143 -0
- package/dist/db/migrations-pg/meta/0002_snapshot.json +2170 -0
- package/dist/db/migrations-pg/meta/0003_snapshot.json +2182 -0
- package/dist/db/migrations-pg/meta/0004_snapshot.json +2188 -0
- package/dist/db/migrations-pg/meta/0005_snapshot.json +2201 -0
- package/dist/db/migrations-pg/meta/0006_snapshot.json +2207 -0
- package/dist/db/migrations-pg/meta/0007_snapshot.json +2219 -0
- package/dist/db/migrations-pg/meta/0008_snapshot.json +2226 -0
- package/dist/db/migrations-pg/meta/0009_snapshot.json +2250 -0
- package/dist/db/migrations-pg/meta/0010_snapshot.json +2256 -0
- package/dist/db/migrations-pg/meta/0011_snapshot.json +2412 -0
- package/dist/db/migrations-pg/meta/0012_snapshot.json +2528 -0
- package/dist/db/migrations-pg/meta/0013_snapshot.json +2534 -0
- package/dist/db/migrations-pg/meta/0014_snapshot.json +2547 -0
- package/dist/db/migrations-pg/meta/0015_snapshot.json +2553 -0
- package/dist/db/migrations-pg/meta/0016_snapshot.json +2774 -0
- package/dist/db/migrations-pg/meta/0017_snapshot.json +2999 -0
- package/dist/db/migrations-pg/meta/0018_snapshot.json +3020 -0
- package/dist/db/migrations-pg/meta/0020_snapshot.json +3228 -0
- package/dist/db/migrations-pg/meta/0021_snapshot.json +3234 -0
- package/dist/db/migrations-pg/meta/0022_snapshot.json +3240 -0
- package/dist/db/migrations-pg/meta/_journal.json +475 -0
- package/dist/db/ml-labels.js +1666 -0
- package/dist/db/my-turn-dismissals.js +343 -0
- package/dist/db/my-turn-settings.js +34 -0
- package/dist/db/pending-classify.js +46 -0
- package/dist/db/pending-mute.js +171 -0
- package/dist/db/pending-tabs.js +238 -0
- package/dist/db/period-metrics.js +820 -0
- package/dist/db/person-period.js +763 -0
- package/dist/db/pr-intervals.js +930 -0
- package/dist/db/pr-liveness.js +240 -0
- package/dist/db/pr-mentions.js +279 -0
- package/dist/db/pr-merge-queue-stamp.js +91 -0
- package/dist/db/queries.js +14631 -0
- package/dist/db/reaction-targets.js +94 -0
- package/dist/db/repo-activity.js +171 -0
- package/dist/db/retention.js +138 -0
- package/dist/db/review-threads-for-review.js +240 -0
- package/dist/db/run-migrations.js +24 -0
- package/dist/db/schema.pg.js +1220 -0
- package/dist/db/schema.sqlite.js +1801 -0
- package/dist/db/search.js +317 -0
- package/dist/db/security-alerts.js +218 -0
- package/dist/db/synthesis-input.js +565 -0
- package/dist/db/triage.js +320 -0
- package/dist/db/usage.js +63 -0
- package/dist/db/work-plan.js +1086 -0
- package/dist/db/working-hours.js +161 -0
- package/dist/feed/my-turn.js +122 -0
- package/dist/github/actions-logs.js +397 -0
- package/dist/github/auth.js +86 -0
- package/dist/github/branch-queries.js +229 -0
- package/dist/github/client.js +454 -0
- package/dist/github/codeowners.js +221 -0
- package/dist/github/commit-checks.js +105 -0
- package/dist/github/compare.js +110 -0
- package/dist/github/diff-anchor.js +227 -0
- package/dist/github/mutations.js +706 -0
- package/dist/github/pr-file-content.js +254 -0
- package/dist/github/pr-liveness.js +161 -0
- package/dist/github/queries.js +875 -0
- package/dist/github/rate-budget.js +129 -0
- package/dist/github/reactions.js +161 -0
- package/dist/github/reviewer-suggest.js +104 -0
- package/dist/github/team-reviewers.js +96 -0
- package/dist/index.js +184 -0
- package/dist/merge/auto-merge-runner.js +960 -0
- package/dist/ml/severity-client.js +218 -0
- package/dist/pr/detail-enricher.js +26 -0
- package/dist/pro/bind.js +302 -0
- package/dist/pro/contract.js +37 -0
- package/dist/pro/migrate.js +64 -0
- package/dist/review/agent-context.js +127 -0
- package/dist/review/agent.js +385 -0
- package/dist/review/agentic.js +59 -0
- package/dist/review/auth.js +94 -0
- package/dist/review/chat-agent.js +179 -0
- package/dist/review/claude-review/ai-ready.js +16 -0
- package/dist/review/claude-review/auto-settings.js +139 -0
- package/dist/review/claude-review/auto.js +244 -0
- package/dist/review/claude-review/chat.js +489 -0
- package/dist/review/claude-review/ci-failures.js +350 -0
- package/dist/review/claude-review/follow-up.js +310 -0
- package/dist/review/claude-review/manager.js +686 -0
- package/dist/review/claude-review/persist.js +996 -0
- package/dist/review/claude-review/prompts.js +357 -0
- package/dist/review/claude-review/routes.js +518 -0
- package/dist/review/claude-review/routing.js +61 -0
- package/dist/review/claude-review/specialists.js +190 -0
- package/dist/review/claude-review/threads.js +265 -0
- package/dist/review/claude-review/ticket.js +282 -0
- package/dist/review/clone-hygiene.js +380 -0
- package/dist/review/clone-manager.js +367 -0
- package/dist/review/llm.js +113 -0
- package/dist/review/model-options.js +48 -0
- package/dist/review/plugin-providers.js +12 -0
- package/dist/review/post-review.js +216 -0
- package/dist/review/post-seam.js +161 -0
- package/dist/review/prepare.js +168 -0
- package/dist/review/pricing.js +17 -0
- package/dist/review/schema.js +156 -0
- package/dist/review/submit-map.js +41 -0
- package/dist/review/usage.js +90 -0
- package/dist/shared/claude-review.js +335 -0
- package/dist/shared/conflict-fold.js +151 -0
- package/dist/shared/conflicts.js +30 -0
- package/dist/shared/flow-settings.js +191 -0
- package/dist/shared/index.js +8 -0
- package/dist/shared/my-turn-settings.js +238 -0
- package/dist/shared/pending-rules.js +281 -0
- package/dist/shared/product.js +54 -0
- package/dist/shared/types.js +896 -0
- package/dist/status.js +386 -0
- package/dist/sync/adaptive.js +185 -0
- package/dist/sync/app-attribution.js +66 -0
- package/dist/sync/auth-notices.js +36 -0
- package/dist/sync/backfill-ci-history.js +315 -0
- package/dist/sync/backfill-commit-headlines.js +136 -0
- package/dist/sync/backfill-pr-security.js +175 -0
- package/dist/sync/backfill-review-requests.js +97 -0
- package/dist/sync/benchmark-rollup.js +50 -0
- package/dist/sync/bot-detection.js +309 -0
- package/dist/sync/bot-resolution-markers.js +30 -0
- package/dist/sync/branch-status.js +634 -0
- package/dist/sync/classify-change-shape.js +150 -0
- package/dist/sync/commit-files.js +74 -0
- package/dist/sync/derive-thread-state.js +99 -0
- package/dist/sync/drain-review-threads.js +212 -0
- package/dist/sync/hydrate-detail.js +482 -0
- package/dist/sync/mention-scan.js +89 -0
- package/dist/sync/ml-enrichment.js +478 -0
- package/dist/sync/pr-change-signal.js +96 -0
- package/dist/sync/pr-liveness-sweep.js +139 -0
- package/dist/sync/pr-settle.js +381 -0
- package/dist/sync/refresh-pr.js +163 -0
- package/dist/sync/reparse-vendor-badges.js +495 -0
- package/dist/sync/resync-after-write.js +280 -0
- package/dist/sync/review-fingerprint.js +117 -0
- package/dist/sync/reviewer-behavior.js +103 -0
- package/dist/sync/reviewer-classify.js +503 -0
- package/dist/sync/routing-files.js +97 -0
- package/dist/sync/scheduled-jobs.js +12 -0
- package/dist/sync/scheduler.js +159 -0
- package/dist/sync/security-detect.js +521 -0
- package/dist/sync/sync-manager.js +750 -0
- package/dist/sync/sync-one-pr.js +205 -0
- package/dist/sync/sync-repo.js +400 -0
- package/dist/sync/unsettled-prs.js +506 -0
- package/dist/sync/upsert.js +1190 -0
- package/package.json +56 -0
- package/public/apple-touch-icon.png +0 -0
- package/public/assets/AiFixTab-CQP6PT5u.js +2 -0
- package/public/assets/ClaudeReviewTab-DQJ-58ZA.js +8 -0
- package/public/assets/PrBotBehaviourTab-CCnFrWbC.js +1 -0
- package/public/assets/archivo-latin-600-BN-JkNrl.woff2 +0 -0
- package/public/assets/highlight-BEHUn5zE.css +10 -0
- package/public/assets/highlight-CIIZLa6Z.js +12 -0
- package/public/assets/index-BDnYs6zg.js +73 -0
- package/public/assets/index-mCuI--RC.css +1 -0
- package/public/assets/markdown-I_JLLVAZ.js +32 -0
- package/public/assets/perfProbe-Da13EhTE.js +1 -0
- package/public/assets/tanstack-5qsxxaLe.js +17 -0
- package/public/assets/vis-C3BCkP5U.js +1280 -0
- package/public/assets/vis-ziCVehMy.css +1 -0
- package/public/favicon-16.png +0 -0
- package/public/favicon-32.png +0 -0
- package/public/favicon-48.png +0 -0
- package/public/favicon.svg +5 -0
- package/public/index.html +41 -0
- package/public-landing/apple-touch-icon.png +0 -0
- package/public-landing/assets/archivo-latin-500-BWmvx2Mg.woff2 +0 -0
- package/public-landing/assets/archivo-latin-600-BN-JkNrl.woff2 +0 -0
- package/public-landing/assets/index-CA3eEGXO.js +40 -0
- package/public-landing/assets/index-naQrQ6Fe.css +1 -0
- package/public-landing/assets/jetbrains-mono-latin-400-RruCX7RW.woff2 +0 -0
- package/public-landing/assets/newsreader-latin-400-DExrRRrN.woff2 +0 -0
- package/public-landing/assets/newsreader-latin-400-italic-b0I-AwbV.woff2 +0 -0
- package/public-landing/bots/index.html +156 -0
- package/public-landing/contact/index.html +156 -0
- package/public-landing/cookies/index.html +156 -0
- package/public-landing/demo/limn-walkthrough-poster.jpg +0 -0
- package/public-landing/demo/limn-walkthrough.cues.json +44 -0
- package/public-landing/demo/limn-walkthrough.mp4 +0 -0
- package/public-landing/favicon-16.png +0 -0
- package/public-landing/favicon-32.png +0 -0
- package/public-landing/favicon-48.png +0 -0
- package/public-landing/favicon.svg +5 -0
- package/public-landing/features/index.html +156 -0
- package/public-landing/for-developers/index.html +156 -0
- package/public-landing/for-managers/index.html +156 -0
- package/public-landing/how-it-works/index.html +156 -0
- package/public-landing/how-we-measure/index.html +156 -0
- package/public-landing/icon-192.png +0 -0
- package/public-landing/icon-512.png +0 -0
- package/public-landing/index.html +156 -0
- package/public-landing/insights/index.html +156 -0
- package/public-landing/og-image.png +0 -0
- package/public-landing/pricing/index.html +156 -0
- package/public-landing/privacy/index.html +156 -0
- package/public-landing/pro/index.html +156 -0
- package/public-landing/reviews/index.html +156 -0
- package/public-landing/robots.txt +8 -0
- package/public-landing/shots/benchmark.png +0 -0
- package/public-landing/shots/bot-roi.png +0 -0
- package/public-landing/shots/bot-settings.png +0 -0
- package/public-landing/shots/chronology.png +0 -0
- package/public-landing/shots/feed.png +0 -0
- package/public-landing/shots/flow-metrics.png +0 -0
- package/public-landing/shots/free-reports.png +0 -0
- package/public-landing/shots/pending-board.png +0 -0
- package/public-landing/shots/pending-card.png +0 -0
- package/public-landing/shots/period-report.png +0 -0
- package/public-landing/shots/pr-detail.png +0 -0
- package/public-landing/shots/pr-threads.png +0 -0
- package/public-landing/shots/reach.png +0 -0
- package/public-landing/shots/repo-rows.png +0 -0
- package/public-landing/shots/severity-findings.png +0 -0
- package/public-landing/shots/severity-strip.png +0 -0
- package/public-landing/site.webmanifest +14 -0
- package/public-landing/sitemap.xml +51 -0
- package/public-landing/terms/index.html +156 -0
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
-- TEAMS BECOME WORKSPACES, AND A REPO GETS EXACTLY ONE. SQLite / local mode; Postgres twin:
|
|
2
|
+
-- migrations-pg/0031_workspaces.sql. Migration 0045 then collapses the two bot tables onto the
|
|
3
|
+
-- workspace key — read them together, they are one change in two steps:
|
|
4
|
+
--
|
|
5
|
+
-- 0044 RE-HOME repo grouping: teams (m2m) → workspaces (1:N), + a Default per account
|
|
6
|
+
-- 0045 COLLAPSE the bot object: repo_reviewers + account_reviewers → workspace_reviewers
|
|
7
|
+
--
|
|
8
|
+
-- WHY A WORKSPACE. `teams` was a many-to-many bag of repos alongside four scope sentinels
|
|
9
|
+
-- ('all' / 'none' / 'teams' / a set), which made "which repos am I looking at" a five-branch
|
|
10
|
+
-- question with three independent parsers. A workspace is the ONE scope: a repo belongs to
|
|
11
|
+
-- EXACTLY ONE of them, so there is nothing to canonicalise and no "in no team" bucket.
|
|
12
|
+
--
|
|
13
|
+
-- WORKSPACE IDS ARE THE OLD TEAM IDS. Preserved deliberately: a URL, a bookmark, a persisted
|
|
14
|
+
-- filter and (after the plugin's own 0020) a cache row all carry the number, and renumbering
|
|
15
|
+
-- would silently repoint them at a different repo set.
|
|
16
|
+
--
|
|
17
|
+
-- ⚠ THE ONE THING THAT DIFFERS BETWEEN THE DIALECTS IS THE SEQUENCE. SQLite AUTOINCREMENT tracks
|
|
18
|
+
-- max(rowid) ever seen, so an explicit-id INSERT advances it and the Default rows below get fresh
|
|
19
|
+
-- ids for free. Postgres `serial` does NOT advance on an explicit-id INSERT, so the twin must
|
|
20
|
+
-- setval() between the two inserts or the very next workspace collides with a preserved team id.
|
|
21
|
+
--
|
|
22
|
+
-- ── ON RE-RUNNING THIS FILE ─────────────────────────────────────────────────────────────────
|
|
23
|
+
-- Every statement is IF NOT EXISTS / ON CONFLICT DO NOTHING down to the two DROPs, and the legacy
|
|
24
|
+
-- source tables are STUBBED below, so the backfill is still a legal, empty statement on a database
|
|
25
|
+
-- where they have already gone. That is the SQLite answer to the pg twin's `to_regclass` guard,
|
|
26
|
+
-- which exists for the same reason: this file ends by dropping the tables its own backfill reads.
|
|
27
|
+
|
|
28
|
+
-- THE LEGACY SOURCES, STUBBED — no-ops on every database this migration is meant for.
|
|
29
|
+
CREATE TABLE IF NOT EXISTS `teams` (
|
|
30
|
+
`id` integer, `account_id` integer, `name` text, `created_at` integer
|
|
31
|
+
);--> statement-breakpoint
|
|
32
|
+
CREATE TABLE IF NOT EXISTS `team_repos` (
|
|
33
|
+
`id` integer, `account_id` integer, `team_id` integer, `repo_id` integer, `created_at` integer
|
|
34
|
+
);--> statement-breakpoint
|
|
35
|
+
|
|
36
|
+
CREATE TABLE IF NOT EXISTS `workspaces` (
|
|
37
|
+
`id` integer PRIMARY KEY AUTOINCREMENT NOT NULL,
|
|
38
|
+
`account_id` integer NOT NULL,
|
|
39
|
+
`name` text NOT NULL,
|
|
40
|
+
`is_default` integer DEFAULT 0 NOT NULL,
|
|
41
|
+
`created_at` integer DEFAULT (unixepoch()) NOT NULL,
|
|
42
|
+
FOREIGN KEY (`account_id`) REFERENCES `accounts`(`id`) ON UPDATE no action ON DELETE cascade
|
|
43
|
+
);--> statement-breakpoint
|
|
44
|
+
CREATE UNIQUE INDEX IF NOT EXISTS `workspaces_account_name` ON `workspaces` (`account_id`,`name`);--> statement-breakpoint
|
|
45
|
+
CREATE INDEX IF NOT EXISTS `workspaces_account_idx` ON `workspaces` (`account_id`);--> statement-breakpoint
|
|
46
|
+
-- The parent key for the composite FKs on workspace_repos + workspace_reviewers. NOT a lookup
|
|
47
|
+
-- index — `id` is already the PK — and both dialects require a unique index over the parent-key
|
|
48
|
+
-- columns before such an FK is legal. Drop it and both composite FKs become unexpressible.
|
|
49
|
+
CREATE UNIQUE INDEX IF NOT EXISTS `workspaces_id_account` ON `workspaces` (`id`,`account_id`);--> statement-breakpoint
|
|
50
|
+
|
|
51
|
+
-- 1. One workspace per existing team, IDS PRESERVED.
|
|
52
|
+
INSERT INTO `workspaces` (`id`, `account_id`, `name`, `is_default`, `created_at`)
|
|
53
|
+
SELECT `id`, `account_id`, `name`, 0, `created_at` FROM `teams`
|
|
54
|
+
WHERE true
|
|
55
|
+
ON CONFLICT (`id`) DO NOTHING;--> statement-breakpoint
|
|
56
|
+
|
|
57
|
+
-- 2. A Default workspace for EVERY account, including accounts that never had a team.
|
|
58
|
+
-- The three-level name CASE exists because `workspaces_account_name` is unique and a user may
|
|
59
|
+
-- already own a team called "Default". The third form embeds the account id, so it cannot
|
|
60
|
+
-- collide with the first two for the same account.
|
|
61
|
+
INSERT INTO `workspaces` (`account_id`, `name`, `is_default`, `created_at`)
|
|
62
|
+
SELECT a.`id`,
|
|
63
|
+
CASE
|
|
64
|
+
WHEN NOT EXISTS (SELECT 1 FROM `workspaces` w WHERE w.`account_id` = a.`id` AND w.`name` = 'Default')
|
|
65
|
+
THEN 'Default'
|
|
66
|
+
WHEN NOT EXISTS (SELECT 1 FROM `workspaces` w WHERE w.`account_id` = a.`id` AND w.`name` = 'Default workspace')
|
|
67
|
+
THEN 'Default workspace'
|
|
68
|
+
ELSE 'Default (workspace ' || a.`id` || ')'
|
|
69
|
+
END,
|
|
70
|
+
1, unixepoch()
|
|
71
|
+
FROM `accounts` a
|
|
72
|
+
WHERE NOT EXISTS (SELECT 1 FROM `workspaces` w WHERE w.`account_id` = a.`id` AND w.`is_default` = 1);--> statement-breakpoint
|
|
73
|
+
|
|
74
|
+
-- 2b. ONE DEFAULT PER ACCOUNT, AS A DATABASE FACT. Created after the backfill so a hand-corrupted
|
|
75
|
+
-- database fails on a statement whose meaning is obvious. This is what makes
|
|
76
|
+
-- ensureDefaultWorkspace's "INSERT … ON CONFLICT DO NOTHING then re-SELECT" race-safe: it runs
|
|
77
|
+
-- on effectively every request, and two concurrent calls for an account with no default would
|
|
78
|
+
-- otherwise both SELECT nothing and both INSERT.
|
|
79
|
+
CREATE UNIQUE INDEX IF NOT EXISTS `workspaces_one_default` ON `workspaces` (`account_id`) WHERE `is_default` = 1;--> statement-breakpoint
|
|
80
|
+
|
|
81
|
+
-- EXACTLY ONE WORKSPACE PER REPO, AS A DATABASE FACT: the unique on (account_id, repo_id) is what
|
|
82
|
+
-- makes assigning a repo elsewhere an UPSERT, i.e. a MOVE, with no code path able to produce a
|
|
83
|
+
-- second membership row. `repo_id` alone would do (repos.id is a global PK) — account_id rides in
|
|
84
|
+
-- the key so the isolation predicate and the conflict target are the same columns, the same
|
|
85
|
+
-- discipline `repo_reviewers` used.
|
|
86
|
+
--
|
|
87
|
+
-- WHY A TABLE AND NOT A `repos.workspace_id` COLUMN. SQLite cannot ADD a CONSTRAINT to an existing
|
|
88
|
+
-- table and cannot cheaply make an existing column NOT NULL; a NOT NULL FK column on `repos` means
|
|
89
|
+
-- rebuilding `repos` (create-copy-drop-rename) under `foreign_keys=ON` with every child FK in the
|
|
90
|
+
-- schema pointing at it mid-flight. A join table arrives fully constrained on day one.
|
|
91
|
+
--
|
|
92
|
+
-- TENANCY IS STRUCTURAL. `workspace_id` arrives in a REQUEST BODY, so a plain
|
|
93
|
+
-- `REFERENCES workspaces(id)` would accept (account 2, workspace 10) where workspace 10 belongs to
|
|
94
|
+
-- account 1 — both halves individually valid. The FK is COMPOSITE and NAMED, so Postgres quotes the
|
|
95
|
+
-- name in the violation message and a grep for it finds a live constraint.
|
|
96
|
+
CREATE TABLE IF NOT EXISTS `workspace_repos` (
|
|
97
|
+
`id` integer PRIMARY KEY AUTOINCREMENT NOT NULL,
|
|
98
|
+
`account_id` integer NOT NULL,
|
|
99
|
+
`workspace_id` integer NOT NULL,
|
|
100
|
+
`repo_id` integer NOT NULL,
|
|
101
|
+
`created_at` integer DEFAULT (unixepoch()) NOT NULL,
|
|
102
|
+
FOREIGN KEY (`account_id`) REFERENCES `accounts`(`id`) ON UPDATE no action ON DELETE cascade,
|
|
103
|
+
CONSTRAINT `workspace_repos_workspace_account_fk` FOREIGN KEY (`workspace_id`,`account_id`) REFERENCES `workspaces`(`id`,`account_id`) ON UPDATE no action ON DELETE cascade,
|
|
104
|
+
CONSTRAINT `workspace_repos_repo_account_fk` FOREIGN KEY (`repo_id`,`account_id`) REFERENCES `repos`(`id`,`account_id`) ON UPDATE no action ON DELETE cascade
|
|
105
|
+
);--> statement-breakpoint
|
|
106
|
+
CREATE UNIQUE INDEX IF NOT EXISTS `workspace_repos_account_repo` ON `workspace_repos` (`account_id`,`repo_id`);--> statement-breakpoint
|
|
107
|
+
CREATE INDEX IF NOT EXISTS `workspace_repos_account_workspace_idx` ON `workspace_repos` (`account_id`,`workspace_id`);--> statement-breakpoint
|
|
108
|
+
CREATE INDEX IF NOT EXISTS `workspace_repos_repo_idx` ON `workspace_repos` (`repo_id`);--> statement-breakpoint
|
|
109
|
+
|
|
110
|
+
-- 3. THE TIE-BREAK: a repo in 2+ teams keeps its EARLIEST assignment (lowest team_repos.id).
|
|
111
|
+
-- Written as a correlated MIN() rather than DISTINCT ON, which SQLite does not have and which
|
|
112
|
+
-- would therefore make the two dialects' files structurally different for no reason. The
|
|
113
|
+
-- account predicate in the subquery is redundant (repos.id is a global PK, so repo_id already
|
|
114
|
+
-- implies the account) and is spelled anyway so tenancy is visible in the statement.
|
|
115
|
+
INSERT INTO `workspace_repos` (`account_id`, `workspace_id`, `repo_id`, `created_at`)
|
|
116
|
+
SELECT tr.`account_id`, tr.`team_id`, tr.`repo_id`, tr.`created_at`
|
|
117
|
+
FROM `team_repos` tr
|
|
118
|
+
WHERE tr.`id` = (
|
|
119
|
+
SELECT MIN(tr2.`id`) FROM `team_repos` tr2
|
|
120
|
+
WHERE tr2.`repo_id` = tr.`repo_id` AND tr2.`account_id` = tr.`account_id`)
|
|
121
|
+
ON CONFLICT (`account_id`, `repo_id`) DO NOTHING;--> statement-breakpoint
|
|
122
|
+
|
|
123
|
+
-- 4. Every repo with no resulting row → that account's Default. Covers repos that were in no team
|
|
124
|
+
-- at all AND (on a replay) anything step 3 could not place. A repo with NO membership row is
|
|
125
|
+
-- invisible to every workspace-scoped read, which is why this statement exists and why the
|
|
126
|
+
-- runtime keeps a repair (`ensureRepoMemberships`) on the same rule.
|
|
127
|
+
INSERT INTO `workspace_repos` (`account_id`, `workspace_id`, `repo_id`, `created_at`)
|
|
128
|
+
SELECT r.`account_id`, w.`id`, r.`id`, unixepoch()
|
|
129
|
+
FROM `repos` r
|
|
130
|
+
JOIN `workspaces` w ON w.`account_id` = r.`account_id` AND w.`is_default` = 1
|
|
131
|
+
WHERE NOT EXISTS (SELECT 1 FROM `workspace_repos` wr WHERE wr.`repo_id` = r.`id`)
|
|
132
|
+
ON CONFLICT (`account_id`, `repo_id`) DO NOTHING;--> statement-breakpoint
|
|
133
|
+
|
|
134
|
+
-- 5. Child first (team_repos FKs teams), then the parent. Leaving either behind would leave a
|
|
135
|
+
-- second, differently-keyed answer to "which repos are grouped together" in every database —
|
|
136
|
+
-- the exact failure `bot_review_classification` was dropped to avoid.
|
|
137
|
+
DROP TABLE IF EXISTS `team_repos`;--> statement-breakpoint
|
|
138
|
+
DROP TABLE IF EXISTS `teams`;
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
-- THE BOT OBJECT COLLAPSES ONTO THE WORKSPACE KEY. SQLite / local mode; Postgres twin:
|
|
2
|
+
-- migrations-pg/0032_workspace_reviewers.sql. Second half of the change 0044 starts:
|
|
3
|
+
--
|
|
4
|
+
-- 0044 RE-HOME repo grouping: teams (m2m) → workspaces (1:N), + a Default per account
|
|
5
|
+
-- 0045 COLLAPSE the bot object: repo_reviewers + account_reviewers → workspace_reviewers
|
|
6
|
+
--
|
|
7
|
+
-- `repo_reviewers` answered "is this login a bot" once per (account, repo). `account_reviewers`
|
|
8
|
+
-- answered "who is it and what does it cost" once per (account, actor). With one workspace as the
|
|
9
|
+
-- only scope, both questions have the same key, so both tables become one row per
|
|
10
|
+
-- (account, workspace, actor) — and the fold that reads six repo rows into one metric answer
|
|
11
|
+
-- disappears with them.
|
|
12
|
+
--
|
|
13
|
+
-- ⚠ WHAT MUST NOT BE LOST WITH THE MERGE: the two PROVENANCE FLAGS stay separate columns and are
|
|
14
|
+
-- honoured INDEPENDENTLY. `source` owns automated/role/confidence/reasons; `identity_source` owns
|
|
15
|
+
-- kind/label. Inside one row that separation is code discipline (a narrowed `set:` object) rather
|
|
16
|
+
-- than a table boundary — a classification pass that respects only one of them either reverts a
|
|
17
|
+
-- human's vendor correction or freezes auto-detection.
|
|
18
|
+
--
|
|
19
|
+
-- ⚠ `monthly_cents` IS NEVER IN ANY DERIVED UPDATE. It is the one column no classifier can
|
|
20
|
+
-- regenerate. From here on the price is a per-WORKSPACE fact like every other attribute on this
|
|
21
|
+
-- row: `setReviewerCost` writes ONE row, nothing fans out, nothing seeds a later row.
|
|
22
|
+
-- NULL = no price set, 0 = "recorded as free". Nothing inherits; there is no chain behind a `??`.
|
|
23
|
+
--
|
|
24
|
+
-- ── THE FOLD RULE ────────────────────────────────────────────────────────────────────────────
|
|
25
|
+
-- For each (account, workspace, actor) with at least one repo_reviewers row on a repo now in
|
|
26
|
+
-- that workspace:
|
|
27
|
+
-- automated = TRUE if ANY contributing row is automated (union — this half DOES
|
|
28
|
+
-- role = 'review' if ANY contributing row roles it 'review' reproduce resolveJudgements
|
|
29
|
+
-- else 'quality_check' exactly, for READS)
|
|
30
|
+
-- confidence = the highest confidence among the rows that carried the WINNING `automated` value
|
|
31
|
+
-- (folding the max across all rows lets an automated=false row hand `high` to an
|
|
32
|
+
-- automated=true verdict it disagreed with)
|
|
33
|
+
-- updated_at = MAX of the contributing rows
|
|
34
|
+
--
|
|
35
|
+
-- source = 'manual' if ANY contributing row is manual, regardless of which side won.
|
|
36
|
+
-- ⚠ THIS IS DELIBERATELY *NOT* THE READ-TIME UNION RULE, and the difference is the
|
|
37
|
+
-- whole point. For reads, `manualHuman` is only consulted when nothing in scope
|
|
38
|
+
-- calls the actor automated — so a manual "this is a human" on repo B losing to an
|
|
39
|
+
-- auto-automated repo A is faithful. But `source` is not only a read input: it is
|
|
40
|
+
-- the WRITE GATE in persist() and the flag behind the "Reset classification"
|
|
41
|
+
-- affordance. Folding it to 'auto' would let the next classification pass silently
|
|
42
|
+
-- overwrite a human's opinion, with no control offered to undo it and no trace in
|
|
43
|
+
-- reasons_json. A visible, resettable pin the user can see is strictly better than
|
|
44
|
+
-- a judgement that vanishes. (Same for a manual role='quality_check' that loses to
|
|
45
|
+
-- an auto 'review': the role is wrong AND pinned — so the fold FLAGS it, below.)
|
|
46
|
+
-- ELSE the source of the winning evidence — carried, not invented: the highest
|
|
47
|
+
-- confidence row on the winning side of `automated`, ties broken by updated_at DESC
|
|
48
|
+
-- then repo_id ASC so both dialects pick the same row. ⚠ NEVER the literal 'auto':
|
|
49
|
+
-- that is the `identity_source` vocabulary. `ClassificationSource` is
|
|
50
|
+
-- 'manual'|'vendor_login'|'github_type'|'app_attribution'|'fingerprint'|
|
|
51
|
+
-- 'behavioral'|'ai_tiebreak' and an out-of-union value would never self-heal —
|
|
52
|
+
-- persist() only revisits rows it derives, and the listing's lazy trigger is a
|
|
53
|
+
-- MISSING row, which after this migration no actor has. `'fingerprint'` is the
|
|
54
|
+
-- fallback if the subquery somehow finds nothing (it matches persistHumanJudgement's
|
|
55
|
+
-- choice for a derived, fully re-derivable row).
|
|
56
|
+
--
|
|
57
|
+
-- reasons_json = SYNTHESISED, not carried. One repo row's reason text does not describe a
|
|
58
|
+
-- workspace verdict, the field is advisory display evidence, and the next
|
|
59
|
+
-- classification pass overwrites it for every non-manual row. Carrying it would
|
|
60
|
+
-- need a per-dialect "pick one row" statement (sqlite bare-columns vs pg
|
|
61
|
+
-- DISTINCT ON) for text nobody reads twice. ⚠ A fold where a manual row LOST gets
|
|
62
|
+
-- an explicit conflict string ("⚠ conflicting per-repo judgements were merged —
|
|
63
|
+
-- review this"), so the one case where a human's judgement was superseded is
|
|
64
|
+
-- visible on the card rather than inferred from a mismatched provenance flag.
|
|
65
|
+
--
|
|
66
|
+
-- kind, label, identity_source = copied from the actor's account_reviewers row. Account-grain
|
|
67
|
+
-- today, so they REPLICATE into each workspace the actor appears in. That
|
|
68
|
+
-- replication is the accepted consequence of the merge: from here on they are
|
|
69
|
+
-- per-workspace facts and may legitimately diverge.
|
|
70
|
+
-- monthly_cents = copied into every workspace row of that actor, on exactly the same footing.
|
|
71
|
+
-- This is the faithful carry-over of a value that WAS account-wide — a ONE-TIME
|
|
72
|
+
-- SEED, not an invariant. From here on price is a per-workspace fact like kind and
|
|
73
|
+
-- label: `setReviewerCost` writes ONE row, nothing fans out, nothing seeds a later
|
|
74
|
+
-- row, and the copies diverge freely as the user edits them.
|
|
75
|
+
--
|
|
76
|
+
-- Actors with an account_reviewers row but NO repo_reviewers row anywhere are DROPPED — the
|
|
77
|
+
-- listing has always been row-driven, and such an identity could never be displayed, edited or
|
|
78
|
+
-- cleared (the same rule the 404 on the old identity route enforced).
|
|
79
|
+
--
|
|
80
|
+
-- ── ON RE-RUNNING THIS FILE ─────────────────────────────────────────────────────────────────
|
|
81
|
+
-- The legacy sources are STUBBED, exactly as 0044 stubs `teams`, so the backfill is a legal empty
|
|
82
|
+
-- statement on a database where they have already gone. `repo_reviewers` and `account_reviewers`
|
|
83
|
+
-- are DROPPED at the bottom: leaving either would leave a second, differently-keyed answer to the
|
|
84
|
+
-- same question sitting in every database.
|
|
85
|
+
|
|
86
|
+
CREATE TABLE IF NOT EXISTS `repo_reviewers` (
|
|
87
|
+
`account_id` integer, `repo_id` integer, `author_user_id` integer, `automated` integer,
|
|
88
|
+
`role` text, `confidence` text, `source` text, `reasons_json` text, `updated_at` integer
|
|
89
|
+
);--> statement-breakpoint
|
|
90
|
+
CREATE TABLE IF NOT EXISTS `account_reviewers` (
|
|
91
|
+
`account_id` integer, `author_user_id` integer, `kind` text, `label` text,
|
|
92
|
+
`identity_source` text, `monthly_cents` integer
|
|
93
|
+
);--> statement-breakpoint
|
|
94
|
+
|
|
95
|
+
CREATE TABLE IF NOT EXISTS `workspace_reviewers` (
|
|
96
|
+
`id` integer PRIMARY KEY AUTOINCREMENT NOT NULL,
|
|
97
|
+
`account_id` integer NOT NULL,
|
|
98
|
+
`workspace_id` integer NOT NULL,
|
|
99
|
+
`author_user_id` integer NOT NULL,
|
|
100
|
+
`automated` integer NOT NULL,
|
|
101
|
+
`role` text DEFAULT 'review' NOT NULL,
|
|
102
|
+
`confidence` text NOT NULL,
|
|
103
|
+
`source` text NOT NULL,
|
|
104
|
+
`reasons_json` text,
|
|
105
|
+
`kind` text,
|
|
106
|
+
`label` text,
|
|
107
|
+
`identity_source` text DEFAULT 'auto' NOT NULL,
|
|
108
|
+
`monthly_cents` integer,
|
|
109
|
+
`updated_at` integer DEFAULT (unixepoch()) NOT NULL,
|
|
110
|
+
FOREIGN KEY (`account_id`) REFERENCES `accounts`(`id`) ON UPDATE no action ON DELETE cascade,
|
|
111
|
+
CONSTRAINT `workspace_reviewers_workspace_account_fk` FOREIGN KEY (`workspace_id`,`account_id`) REFERENCES `workspaces`(`id`,`account_id`) ON UPDATE no action ON DELETE cascade,
|
|
112
|
+
FOREIGN KEY (`author_user_id`) REFERENCES `users`(`id`) ON UPDATE no action ON DELETE no action
|
|
113
|
+
);--> statement-breakpoint
|
|
114
|
+
CREATE UNIQUE INDEX IF NOT EXISTS `workspace_reviewers_account_workspace_author` ON `workspace_reviewers` (`account_id`,`workspace_id`,`author_user_id`);--> statement-breakpoint
|
|
115
|
+
CREATE INDEX IF NOT EXISTS `workspace_reviewers_account_workspace_idx` ON `workspace_reviewers` (`account_id`,`workspace_id`);--> statement-breakpoint
|
|
116
|
+
CREATE INDEX IF NOT EXISTS `workspace_reviewers_account_author_idx` ON `workspace_reviewers` (`account_id`,`author_user_id`);--> statement-breakpoint
|
|
117
|
+
|
|
118
|
+
INSERT INTO `workspace_reviewers`
|
|
119
|
+
(`account_id`, `workspace_id`, `author_user_id`, `automated`, `role`, `confidence`, `source`,
|
|
120
|
+
`reasons_json`, `kind`, `label`, `identity_source`, `monthly_cents`, `updated_at`)
|
|
121
|
+
SELECT f.`account_id`, f.`workspace_id`, f.`author_user_id`,
|
|
122
|
+
f.`aut`,
|
|
123
|
+
CASE WHEN f.`any_review` = 1 THEN 'review' ELSE 'quality_check' END,
|
|
124
|
+
CASE WHEN f.`aut` = 1 THEN
|
|
125
|
+
CASE f.`conf_aut` WHEN 3 THEN 'high' WHEN 2 THEN 'medium' ELSE 'low' END
|
|
126
|
+
ELSE
|
|
127
|
+
CASE f.`conf_any` WHEN 3 THEN 'high' WHEN 2 THEN 'medium' ELSE 'low' END
|
|
128
|
+
END,
|
|
129
|
+
-- source: 'manual' if ANY contributing row was manual (the pin survives, visibly);
|
|
130
|
+
-- otherwise the winning row's OWN source — a real ClassificationSource member, never 'auto'.
|
|
131
|
+
CASE WHEN f.`manual_any` = 1 THEN 'manual' ELSE COALESCE((
|
|
132
|
+
SELECT rr2.`source`
|
|
133
|
+
FROM `repo_reviewers` rr2
|
|
134
|
+
JOIN `workspace_repos` wr2
|
|
135
|
+
ON wr2.`repo_id` = rr2.`repo_id` AND wr2.`account_id` = rr2.`account_id`
|
|
136
|
+
WHERE rr2.`account_id` = f.`account_id`
|
|
137
|
+
AND wr2.`workspace_id` = f.`workspace_id`
|
|
138
|
+
AND rr2.`author_user_id` = f.`author_user_id`
|
|
139
|
+
AND rr2.`automated` = f.`aut`
|
|
140
|
+
ORDER BY CASE rr2.`confidence` WHEN 'high' THEN 3 WHEN 'medium' THEN 2 ELSE 1 END DESC,
|
|
141
|
+
rr2.`updated_at` DESC, rr2.`repo_id` ASC
|
|
142
|
+
LIMIT 1), 'fingerprint') END,
|
|
143
|
+
CASE WHEN f.`aut` = 1 AND f.`manual_aut` = 1
|
|
144
|
+
THEN '["manually tagged as an automated reviewer"]'
|
|
145
|
+
WHEN f.`aut` = 0 AND f.`manual_any` = 1
|
|
146
|
+
THEN '["manually confirmed as a human"]'
|
|
147
|
+
-- The one lossy case, named out loud on the card rather than left to be inferred.
|
|
148
|
+
WHEN f.`manual_any` = 1
|
|
149
|
+
THEN '["migrated from the per-repo classification","⚠ conflicting per-repo judgements were merged — review this"]'
|
|
150
|
+
ELSE '["migrated from the per-repo classification"]' END,
|
|
151
|
+
ar.`kind`, ar.`label`, COALESCE(ar.`identity_source`, 'auto'), ar.`monthly_cents`,
|
|
152
|
+
f.`upd`
|
|
153
|
+
FROM (
|
|
154
|
+
SELECT rr.`account_id` AS `account_id`,
|
|
155
|
+
wr.`workspace_id` AS `workspace_id`,
|
|
156
|
+
rr.`author_user_id` AS `author_user_id`,
|
|
157
|
+
MAX(rr.`automated`) AS `aut`,
|
|
158
|
+
-- COALESCE: the live column is NOT NULL DEFAULT 'review', but the legacy-source STUB
|
|
159
|
+
-- above declares `role text` NULLABLE, and SQL three-valued logic sends a NULL role to
|
|
160
|
+
-- ELSE 0 — i.e. every reviewer folds to 'quality_check' on a stub replay.
|
|
161
|
+
MAX(CASE WHEN COALESCE(rr.`role`,'review') <> 'quality_check' THEN 1 ELSE 0 END) AS `any_review`,
|
|
162
|
+
MAX(CASE WHEN rr.`automated` = 1
|
|
163
|
+
THEN CASE rr.`confidence` WHEN 'high' THEN 3 WHEN 'medium' THEN 2 ELSE 1 END
|
|
164
|
+
ELSE 0 END) AS `conf_aut`,
|
|
165
|
+
MAX(CASE rr.`confidence` WHEN 'high' THEN 3 WHEN 'medium' THEN 2 ELSE 1 END) AS `conf_any`,
|
|
166
|
+
MAX(CASE WHEN rr.`source` = 'manual' AND rr.`automated` = 1 THEN 1 ELSE 0 END) AS `manual_aut`,
|
|
167
|
+
MAX(CASE WHEN rr.`source` = 'manual' THEN 1 ELSE 0 END) AS `manual_any`,
|
|
168
|
+
MAX(rr.`updated_at`) AS `upd`
|
|
169
|
+
FROM `repo_reviewers` rr
|
|
170
|
+
JOIN `workspace_repos` wr
|
|
171
|
+
ON wr.`repo_id` = rr.`repo_id` AND wr.`account_id` = rr.`account_id`
|
|
172
|
+
GROUP BY rr.`account_id`, wr.`workspace_id`, rr.`author_user_id`
|
|
173
|
+
) f
|
|
174
|
+
LEFT JOIN `account_reviewers` ar
|
|
175
|
+
ON ar.`account_id` = f.`account_id` AND ar.`author_user_id` = f.`author_user_id`
|
|
176
|
+
WHERE true
|
|
177
|
+
ON CONFLICT (`account_id`, `workspace_id`, `author_user_id`) DO NOTHING;--> statement-breakpoint
|
|
178
|
+
|
|
179
|
+
DROP TABLE IF EXISTS `repo_reviewers`;--> statement-breakpoint
|
|
180
|
+
DROP TABLE IF EXISTS `account_reviewers`;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
-- Drop the "watched" concept, SQLite / local mode.
|
|
2
|
+
--
|
|
3
|
+
-- `repos.inbox_watch` / `repos.inbox_watch_started_at` were a SECOND visibility axis on top of
|
|
4
|
+
-- "is this repo added to the account": a repo could be added-but-not-in-my-inbox, and the Feed,
|
|
5
|
+
-- recent activity, My Turn and the Pro digest collection all quietly narrowed to the watched
|
|
6
|
+
-- subset. With Workspaces the Workspace IS the scope, so that second axis only made it
|
|
7
|
+
-- ambiguous which of the two a screen was obeying. Every repo in a Workspace is now fully live.
|
|
8
|
+
--
|
|
9
|
+
-- The one property the watch window actually bought — adding a repo with 400 open PRs must not
|
|
10
|
+
-- dump them all into My Turn on day one — is preserved by keying the "New PRs" section on
|
|
11
|
+
-- `repos.created_at` (when the repo was ADDED) instead of `inbox_watch_started_at`. That column
|
|
12
|
+
-- already exists, is NOT NULL, and is set on insert, so there is no backfill and no window to
|
|
13
|
+
-- reconstruct: an existing repo keeps the cutoff it was added at.
|
|
14
|
+
--
|
|
15
|
+
-- Neither column is a PK, UNIQUE, indexed, or named in any partial index / CHECK / FK /
|
|
16
|
+
-- generated column (verified against the real dev DB: the four indexes on `repos` are
|
|
17
|
+
-- repos_account_owner_name, repos_account_node, repos_account_idx, repos_id_account, and none
|
|
18
|
+
-- mentions either column), so SQLite's plain ALTER TABLE ... DROP COLUMN is legal here and no
|
|
19
|
+
-- 12-step table rebuild is needed.
|
|
20
|
+
--
|
|
21
|
+
-- NOT re-runnable: SQLite has no `DROP COLUMN IF EXISTS` (the pg twin uses one). drizzle's
|
|
22
|
+
-- migrator records each file once, so that is fine — but do not hand-replay this one.
|
|
23
|
+
-- Postgres twin: migrations-pg/0033_drop_inbox_watch.sql.
|
|
24
|
+
ALTER TABLE `repos` DROP COLUMN `inbox_watch`;--> statement-breakpoint
|
|
25
|
+
ALTER TABLE `repos` DROP COLUMN `inbox_watch_started_at`;
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
-- ML severity/category labels for BOT-authored text (CORE, free tier, no LLM). One row per
|
|
2
|
+
-- classified target — a review-thread comment, a PR comment, or a review BODY. Written only by
|
|
3
|
+
-- the background enrichment worker (sync/ml-enrichment.ts), which batches text to the
|
|
4
|
+
-- `severity-api` microservice from the sibling `pierre-ml` repo; read by the per-PR badge index
|
|
5
|
+
-- and the Bots severity rollup. Contract: docs/ML-SEVERITY.md.
|
|
6
|
+
--
|
|
7
|
+
-- `target_id` is NOT a foreign key: it lives in three different id spaces (review_comments.id /
|
|
8
|
+
-- pr_comments.id / reviews.id), so `target_kind` is part of the unique. Cleanup rides the
|
|
9
|
+
-- cascading `pr_id` FK — deleting a PR takes its labels with it — which is why this table is
|
|
10
|
+
-- deliberately absent from deleteRepo and deletePrSubtree (the `search_index` precedent).
|
|
11
|
+
-- The Postgres twin is migrations-pg/0034_ml_comment_labels.sql.
|
|
12
|
+
CREATE TABLE IF NOT EXISTS `ml_comment_labels` (
|
|
13
|
+
`id` integer PRIMARY KEY AUTOINCREMENT NOT NULL,
|
|
14
|
+
`account_id` integer NOT NULL,
|
|
15
|
+
`repo_id` integer NOT NULL,
|
|
16
|
+
`pr_id` integer NOT NULL,
|
|
17
|
+
`target_kind` text NOT NULL,
|
|
18
|
+
`target_id` integer NOT NULL,
|
|
19
|
+
`author_user_id` integer NOT NULL,
|
|
20
|
+
`severity` text NOT NULL,
|
|
21
|
+
`severity_ord` integer NOT NULL,
|
|
22
|
+
`severity_prob` real NOT NULL,
|
|
23
|
+
`categories` text NOT NULL,
|
|
24
|
+
`category_probs` text NOT NULL,
|
|
25
|
+
`is_summary` integer NOT NULL,
|
|
26
|
+
`backend` text NOT NULL,
|
|
27
|
+
`model_version` text NOT NULL,
|
|
28
|
+
`body_hash` text NOT NULL,
|
|
29
|
+
`target_created_at` integer NOT NULL,
|
|
30
|
+
`created_at` integer DEFAULT (unixepoch()) NOT NULL,
|
|
31
|
+
`updated_at` integer DEFAULT (unixepoch()) NOT NULL,
|
|
32
|
+
FOREIGN KEY (`account_id`) REFERENCES `accounts`(`id`) ON UPDATE no action ON DELETE cascade,
|
|
33
|
+
FOREIGN KEY (`repo_id`) REFERENCES `repos`(`id`) ON UPDATE no action ON DELETE cascade,
|
|
34
|
+
FOREIGN KEY (`pr_id`) REFERENCES `pull_requests`(`id`) ON UPDATE no action ON DELETE cascade,
|
|
35
|
+
FOREIGN KEY (`author_user_id`) REFERENCES `users`(`id`) ON UPDATE no action ON DELETE no action
|
|
36
|
+
);
|
|
37
|
+
--> statement-breakpoint
|
|
38
|
+
CREATE UNIQUE INDEX IF NOT EXISTS `mcl_account_target` ON `ml_comment_labels` (`account_id`,`target_kind`,`target_id`);--> statement-breakpoint
|
|
39
|
+
CREATE INDEX IF NOT EXISTS `mcl_account_pr_idx` ON `ml_comment_labels` (`account_id`,`pr_id`);--> statement-breakpoint
|
|
40
|
+
CREATE INDEX IF NOT EXISTS `mcl_account_repo_author_idx` ON `ml_comment_labels` (`account_id`,`repo_id`,`author_user_id`);
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
-- The REVIEW BOT'S OWN declared severity, stored beside ours. SQLite / local mode; Postgres
|
|
2
|
+
-- twin: migrations-pg/0035_ml_vendor_severity.sql. Two additive nullable columns on
|
|
3
|
+
-- `ml_comment_labels`, no index, no backfill.
|
|
4
|
+
--
|
|
5
|
+
-- WHAT THESE ARE. CodeRabbit et al. stamp their own severity into their comment markup
|
|
6
|
+
-- ("**Major**", a badge, a table cell). The severity-api's deterministic marker reader already
|
|
7
|
+
-- extracts it and we were discarding it. `vendor_severity` is that claim verbatim (the four
|
|
8
|
+
-- values our own scale uses, lowercased at the wire boundary); `vendor_severity_confidence`
|
|
9
|
+
-- is how sure the reader is that it read a real declared badge rather than inferring one from
|
|
10
|
+
-- prose.
|
|
11
|
+
--
|
|
12
|
+
-- WHAT THEY ARE NOT: an input to our own label. Measured on `gold_v2_sample` (300 comments,
|
|
13
|
+
-- fresh label-free adjudication, marker-stratified, held out properly) our model scores 0.700
|
|
14
|
+
-- exact / 0.303 ordinal MAE while the vendor's own badge scores 0.474 / 0.697 — the bot's
|
|
15
|
+
-- self-assessment is materially WORSE than the model sitting next to it. So nothing derives,
|
|
16
|
+
-- corrects or falls back to these columns. They exist to be DISPLAYED alongside ours
|
|
17
|
+
-- ("CodeRabbit: Major · Pierre: Minor"), because the disagreement is the product.
|
|
18
|
+
--
|
|
19
|
+
-- BOTH ARE NULLABLE, for two independent reasons that must not be conflated:
|
|
20
|
+
-- 1. most comments simply carry no vendor badge — null is the ordinary case, not a gap;
|
|
21
|
+
-- 2. an OLDER severity-api build omits the response fields entirely, and that has to degrade
|
|
22
|
+
-- to null silently rather than throw (the client reads them defensively).
|
|
23
|
+
-- Neither is distinguishable from the other after the fact, and neither needs to be: a null
|
|
24
|
+
-- renders nothing.
|
|
25
|
+
--
|
|
26
|
+
-- No index: the values are read out of an already-fetched label row (the per-PR badge index),
|
|
27
|
+
-- never used as a predicate. No backfill either — an existing label is never re-scored (see
|
|
28
|
+
-- docs/ML-SEVERITY.md § known gaps), so historical rows keep NULL until `pnpm ml:enrich --reset`
|
|
29
|
+
-- refills them. Until then a badge with no vendor claim renders exactly as it does today.
|
|
30
|
+
ALTER TABLE `ml_comment_labels` ADD `vendor_severity` text;--> statement-breakpoint
|
|
31
|
+
ALTER TABLE `ml_comment_labels` ADD `vendor_severity_confidence` text;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
-- Per-seat bot pricing + repo descriptions. SQLite / local mode; Postgres twin:
|
|
2
|
+
-- migrations-pg/0036_seat_pricing_repo_description.sql. Two additive columns, no index,
|
|
3
|
+
-- no backfill.
|
|
4
|
+
--
|
|
5
|
+
-- `workspace_reviewers.cost_model` — how `monthly_cents` is READ, never a second price.
|
|
6
|
+
-- 'flat' (the default, preserving every existing row's meaning) = the whole workspace
|
|
7
|
+
-- subscription, exactly as before. 'per_seat' = `monthly_cents` is a per-seat UNIT price
|
|
8
|
+
-- (e.g. CodeRabbit's $29/user/month) multiplied on read by the workspace's derived human
|
|
9
|
+
-- seat count (distinct human PR authors in the workspace's repos over a trailing window).
|
|
10
|
+
-- The product is NEVER stored: seats × cents can exceed int4 and would go stale the moment
|
|
11
|
+
-- a new contributor opens a PR. Ownership is identical to `monthly_cents`: one writer
|
|
12
|
+
-- (`setReviewerCost`), one standalone cost route, never in any derived UPDATE, never in the
|
|
13
|
+
-- combined PATCH body.
|
|
14
|
+
--
|
|
15
|
+
-- `repos.description` — the repo's GitHub "About" text, captured by the activity sync like
|
|
16
|
+
-- `default_branch` / `viewer_permission`. It exists as grounding for the workspace-purpose
|
|
17
|
+
-- sprint-chat preset ("what does this workspace do?"): the app persists no other repo-purpose
|
|
18
|
+
-- text (READMEs are never fetched, PR bodies are lean). Nullable — null until a sync
|
|
19
|
+
-- populates it, or when the repo has no description on GitHub.
|
|
20
|
+
ALTER TABLE `repos` ADD `description` text;--> statement-breakpoint
|
|
21
|
+
ALTER TABLE `workspace_reviewers` ADD `cost_model` text DEFAULT 'flat' NOT NULL;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
-- Bot Tuning Advisor discovery: capture the GitHub App slug behind a bot's comments.
|
|
2
|
+
-- SQLite / local mode; Postgres twin: migrations-pg/0037_users_app_slug.sql. One additive
|
|
3
|
+
-- nullable column, no index, no backfill.
|
|
4
|
+
--
|
|
5
|
+
-- `users.app_slug` — the `performed_via_github_app.slug` the app-attribution probe
|
|
6
|
+
-- (sync/app-attribution.ts) has always RECEIVED and, until now, discarded down to a
|
|
7
|
+
-- PR-level boolean. A bot's App identity is a global fact about the actor (like
|
|
8
|
+
-- `github_type`), so it lives on the global `users` table. The advisor's discovery tier
|
|
9
|
+
-- reads it to split App-authored from Actions-authored comments. Null = never observed
|
|
10
|
+
-- (PAT/OAuth posters have no app); an observed slug is never cleared by a later app-less
|
|
11
|
+
-- comment — the write path only fills nulls or updates to a NEW slug, never nulls out.
|
|
12
|
+
ALTER TABLE `users` ADD `app_slug` text;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
-- Auto-merge ("merge when ready") learns GitHub's native merge queue. SQLite / local mode;
|
|
2
|
+
-- Postgres twin: migrations-pg/0038_auto_merge_queue.sql. Two additive columns, no index,
|
|
3
|
+
-- no backfill (existing intents are direct-merge intents — via_merge_queue defaults false).
|
|
4
|
+
--
|
|
5
|
+
-- `via_merge_queue` — stamped at arm time when the PR's base branch had a merge queue: the
|
|
6
|
+
-- watcher's terminal action is then "add to the queue" (GraphQL enqueuePullRequest, pinned
|
|
7
|
+
-- to the consented head) instead of a direct merge, which GitHub refuses on a
|
|
8
|
+
-- queue-protected branch. The runner re-checks the queue live each tick, so a queue
|
|
9
|
+
-- disabled after arming degrades to the direct merge rather than stranding the intent.
|
|
10
|
+
--
|
|
11
|
+
-- `enqueued_at` — when the WATCHER enqueued the PR; null until then. This is the
|
|
12
|
+
-- attribution record: a PR that merges while it is set resolves 'merged' (the watcher's
|
|
13
|
+
-- doing — the landed toast fires), one a human queued resolves 'disarmed_blocked' like any
|
|
14
|
+
-- outside merge, and a disarm with it set also dequeues the entry the watcher created.
|
|
15
|
+
ALTER TABLE `auto_merge_requests` ADD `via_merge_queue` integer DEFAULT 0 NOT NULL;
|
|
16
|
+
--> statement-breakpoint
|
|
17
|
+
ALTER TABLE `auto_merge_requests` ADD `enqueued_at` integer;
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
-- Default-branch ("trunk") CI TRANSITION log. SQLite / local mode; Postgres twin:
|
|
2
|
+
-- migrations-pg/0039_trunk_ci_status_events.sql. One additive table, no backfill.
|
|
3
|
+
--
|
|
4
|
+
-- WHY IT HAS TO EXIST. `branch_commits.ci_status` is updated IN PLACE by the branch snapshot's
|
|
5
|
+
-- idempotent upsert, so a trunk commit that turns red hours after it landed carries no record of
|
|
6
|
+
-- WHEN it turned red: the only timestamps on that row are `committed_at` (git commit time) and
|
|
7
|
+
-- `created_at` (first insertion). Presenting either as "trunk CI failed at" would be a quiet
|
|
8
|
+
-- lie, so the observation gets its own append-only row. This is the trunk twin of
|
|
9
|
+
-- `ci_status_events`, which does exactly the same job for a PR head.
|
|
10
|
+
--
|
|
11
|
+
-- WRITE RULES (sync/branch-status.ts): a row is written only on a TRANSITION (status / head sha
|
|
12
|
+
-- / failing-check name set differs from this repo's last row) AND only on a POSITIVE statement
|
|
13
|
+
-- from GitHub — an `unknown` rollup, which is also what `graphqlTolerant` produces when a
|
|
14
|
+
-- partial response NULLs the selection, records nothing at all. `observed_at` is OUR observation
|
|
15
|
+
-- time (the branch query selects no `completedAt`), so UI wording says "detected".
|
|
16
|
+
--
|
|
17
|
+
-- `failing_checks` carries the FULL BranchCheckRun[] render payload, matching
|
|
18
|
+
-- `branch_commits.failing_checks` — deliberately NOT `ci_status_events.failing_checks`, which is
|
|
19
|
+
-- a bare string[] of names for the CI metrics log. Same column name, different shape, on purpose.
|
|
20
|
+
--
|
|
21
|
+
-- Retention: bounded by its own per-repo trim in the writer, because the time-based sweep anchors
|
|
22
|
+
-- everything to a parent PR's `updated_at` and a trunk row has no PR. That trim is HYBRID — the
|
|
23
|
+
-- newest TRUNK_CI_EVENT_WINDOW rows UNION everything still inside FEED_WINDOW_DAYS
|
|
24
|
+
-- (`staleTrunkCiEventIds`) — exactly like `branch_commits`, and for opposite reasons in each
|
|
25
|
+
-- direction: a pure COUNT bound evicted the failure rows the Feed reads on repos that sync faster
|
|
26
|
+
-- than the read window elapses, and a pure AGE bound would delete a dormant repo's entire log.
|
|
27
|
+
-- FKs CASCADE so a repo delete / account erasure cleans up regardless; both are ALSO done
|
|
28
|
+
-- explicitly (deleteRepo / eraseAccountData) so the guarantee doesn't depend on `foreign_keys=ON`.
|
|
29
|
+
CREATE TABLE IF NOT EXISTS `trunk_ci_status_events` (
|
|
30
|
+
`id` integer PRIMARY KEY AUTOINCREMENT NOT NULL,
|
|
31
|
+
`account_id` integer NOT NULL REFERENCES `accounts`(`id`) ON DELETE cascade,
|
|
32
|
+
`repo_id` integer NOT NULL REFERENCES `repos`(`id`) ON DELETE cascade,
|
|
33
|
+
`branch_name` text,
|
|
34
|
+
`head_sha` text NOT NULL,
|
|
35
|
+
`status` text NOT NULL,
|
|
36
|
+
`failing_checks` text,
|
|
37
|
+
`observed_at` integer NOT NULL
|
|
38
|
+
);
|
|
39
|
+
--> statement-breakpoint
|
|
40
|
+
-- The read (the Feed builder) and the per-repo trim: one repo's log, newest first.
|
|
41
|
+
CREATE INDEX IF NOT EXISTS `tcse_account_repo_observed` ON `trunk_ci_status_events` (`account_id`,`repo_id`,`observed_at`);
|
|
42
|
+
--> statement-breakpoint
|
|
43
|
+
CREATE INDEX IF NOT EXISTS `tcse_account_idx` ON `trunk_ci_status_events` (`account_id`);
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
-- Re-derive `workspace_reviewers.role` against the five automation vocabularies.
|
|
2
|
+
--
|
|
3
|
+
-- WHY A MIGRATION IS REQUIRED AND NOT JUST A LONGER LIST IN CODE.
|
|
4
|
+
--
|
|
5
|
+
-- `reviewerRoleForUser` applies the login seed FIRST and then lets a stored `workspace_reviewers`
|
|
6
|
+
-- row overwrite it. That ordering is correct — an explicit row must beat a default — but it means
|
|
7
|
+
-- adding a login to `QUALITY_CHECK_BOTS` (or to any of the four new lists) has NO EFFECT on an
|
|
8
|
+
-- actor that has already been classified, and the lazy classifier stamps a row the first time
|
|
9
|
+
-- anyone opens the Bots tab. So on any install that has used the product, `github-actions` keeps
|
|
10
|
+
-- the `role: 'review'` it was given when 'review' was the only fallback, and stays in the
|
|
11
|
+
-- AI-reviewer ROI cohort no matter what the code says.
|
|
12
|
+
--
|
|
13
|
+
-- Measured on the dev corpus before this ran: `github-actions` + `github-actions[bot]` held 385
|
|
14
|
+
-- submitted reviews and 3,116 comments between them while roled 'review' — the single largest
|
|
15
|
+
-- "AI reviewer" in the account was a CI runner. `dependabot`/`dependabot[bot]` (738 authored PRs)
|
|
16
|
+
-- were roled 'review' as well, an actor that has never reviewed anything.
|
|
17
|
+
--
|
|
18
|
+
-- `source <> 'manual'` is the whole safety condition: a role a PERSON chose is never re-derived,
|
|
19
|
+
-- exactly as migration 0042's backfill had it. The judgement half is owned by `source`.
|
|
20
|
+
--
|
|
21
|
+
-- The `[bot]` suffix is stripped rather than each login being listed twice, because the SAME
|
|
22
|
+
-- ACTOR exists as two `users` rows on real accounts (`dependabot` and `dependabot[bot]` have
|
|
23
|
+
-- different GitHub node ids) and a list that covers one spelling and not the other splits an
|
|
24
|
+
-- actor across two roles. `replace()` is safe here: no GitHub login may contain `[` or `]`, so
|
|
25
|
+
-- the substring can only ever appear as the suffix. The Postgres twin uses `regexp_replace(…,
|
|
26
|
+
-- '\[bot\]$', '')`, which is the same operation spelled in that dialect's idiom.
|
|
27
|
+
UPDATE `workspace_reviewers`
|
|
28
|
+
SET `role` = 'dependency'
|
|
29
|
+
WHERE `source` <> 'manual'
|
|
30
|
+
AND `author_user_id` IN (
|
|
31
|
+
SELECT `id` FROM `users` WHERE replace(lower(`github_login`), '[bot]', '') IN (
|
|
32
|
+
'dependabot', 'dependabot-preview', 'renovate', 'renovate-bot',
|
|
33
|
+
'snyk-bot', 'pyup-bot', 'greenkeeper', 'depfu'
|
|
34
|
+
)
|
|
35
|
+
);--> statement-breakpoint
|
|
36
|
+
UPDATE `workspace_reviewers`
|
|
37
|
+
SET `role` = 'code_agent'
|
|
38
|
+
WHERE `source` <> 'manual'
|
|
39
|
+
AND `author_user_id` IN (
|
|
40
|
+
SELECT `id` FROM `users` WHERE replace(lower(`github_login`), '[bot]', '') IN (
|
|
41
|
+
'devin-ai-integration', 'sweep-ai', 'codegen-sh', 'deepsource-autofix',
|
|
42
|
+
'pre-commit-ci', 'restyled-io', 'imgbot', 'imgbotapp',
|
|
43
|
+
'transifex-integration', 'crowdin-bot', 'mintlify', 'allstar'
|
|
44
|
+
)
|
|
45
|
+
);--> statement-breakpoint
|
|
46
|
+
UPDATE `workspace_reviewers`
|
|
47
|
+
SET `role` = 'release'
|
|
48
|
+
WHERE `source` <> 'manual'
|
|
49
|
+
AND `author_user_id` IN (
|
|
50
|
+
SELECT `id` FROM `users` WHERE replace(lower(`github_login`), '[bot]', '') IN (
|
|
51
|
+
'mergify', 'kodiak', 'kodiakhq', 'bulldozer', 'release-please', 'releaser',
|
|
52
|
+
'semantic-release', 'semantic-release-bot', 'release-drafter', 'changeset-bot',
|
|
53
|
+
'changesets', 'autorelease', 'lumberbot-app', 'meeseeksdev', 'backport'
|
|
54
|
+
)
|
|
55
|
+
);--> statement-breakpoint
|
|
56
|
+
UPDATE `workspace_reviewers`
|
|
57
|
+
SET `role` = 'housekeeping'
|
|
58
|
+
WHERE `source` <> 'manual'
|
|
59
|
+
AND `author_user_id` IN (
|
|
60
|
+
SELECT `id` FROM `users` WHERE replace(lower(`github_login`), '[bot]', '') IN (
|
|
61
|
+
'cla-bot', 'cla-assistant', 'claassistant', 'google-cla', 'googlebot',
|
|
62
|
+
'facebook-github-bot', 'dco', 'stale', 'welcome', 'lock', 'allcontributors',
|
|
63
|
+
'semantic-pull-request', 'sizebot', 'react-sizebot', 'diffray-bot',
|
|
64
|
+
'codesandbox-ci', 'netlify', 'vercel', 'gitpod-io'
|
|
65
|
+
)
|
|
66
|
+
);--> statement-breakpoint
|
|
67
|
+
-- Last, and it supersedes 0042's narrower list rather than repeating it: the eight original
|
|
68
|
+
-- static-analysis logins plus the CI runners and security scanners added alongside the new roles.
|
|
69
|
+
UPDATE `workspace_reviewers`
|
|
70
|
+
SET `role` = 'quality_check'
|
|
71
|
+
WHERE `source` <> 'manual'
|
|
72
|
+
AND `author_user_id` IN (
|
|
73
|
+
SELECT `id` FROM `users` WHERE replace(lower(`github_login`), '[bot]', '') IN (
|
|
74
|
+
'sonarqubecloud', 'sonarcloud', 'codecov', 'codeclimate', 'codefactor-io',
|
|
75
|
+
'houndci-bot', 'coveralls', 'codacy-bot',
|
|
76
|
+
'github-actions', 'jit-ci', 'socket-security', 'gitguardian',
|
|
77
|
+
'semgrep-app', 'trunk-io'
|
|
78
|
+
)
|
|
79
|
+
);
|