|
| 1 | +# Per-PR Evaluation Report — Disciplined Research & Design |
| 2 | + |
| 3 | +**Date**: 2026-06-29 |
| 4 | +**Total PRs evaluated**: 1 open + 148 processed across sprints |
| 5 | +**Current open**: #2588 |
| 6 | + |
| 7 | +--- |
| 8 | + |
| 9 | +## PR #2588 — Classify PR blockers in merge coordinator |
| 10 | + |
| 11 | +### Phase 1: Research |
| 12 | + |
| 13 | +**What it does**: Adds `BlockerKind` enum (`ci_failed|ci_pending|ci_no_status|not_mergeable`) + `get_commit_status()` API call to distinguish CI failures from policy holds in merge coordinator logs. |
| 14 | + |
| 15 | +**Essential Questions Check**: |
| 16 | +| Question | Answer | Evidence | |
| 17 | +|----------|--------|----------| |
| 18 | +| Energising? | Yes | Operators currently cannot distinguish CI failures from confidence/policy holds | |
| 19 | +| Leverages strengths? | Yes | Core merge coordinator code we know well | |
| 20 | +| Meets real need? | Yes | Issue #2465 documented: "operators cannot tell whether blocker is CI status, confidence, or policy" | |
| 21 | + |
| 22 | +**Proceed**: Yes (3/3) |
| 23 | + |
| 24 | +**Problem**: When auto-merge doesn't enqueue, logs only say "not mergeable" — operators can't tell if the PR failed CI (needs fix), is pending CI (needs patience), or hit a policy gate (needs human review). |
| 25 | + |
| 26 | +**Current state on main**: NO blocker classification exists. The `evaluator.rs` has no `BlockerKind` enum, no `get_commit_status()`, no CI status querying. The `evaluate_one` is synchronous. |
| 27 | + |
| 28 | +**PR branch problems**: |
| 29 | +- 44 files, 27,356 additions — massively bloated |
| 30 | +- Carries 4 session files (~9K lines of agent conversation dumps) |
| 31 | +- Carries `reconcile_impl_new.rs` and `reconcile_impl_old.rs` snapshots |
| 32 | +- 2 snapshots of the same logical file |
| 33 | +- The actual code change is ~200 lines in 3-4 files |
| 34 | +- The rest is noise (session dumps, handoff files, snapshots) |
| 35 | + |
| 36 | +**Risk**: Branch has merge conflicts (mergeable=False). The core feature is valuable but needs extraction from noise. |
| 37 | + |
| 38 | +### Phase 2: Design |
| 39 | + |
| 40 | +**Approach**: Extract ONLY the `BlockerKind` classification from the branch. Ignore session files, handoff files, and snapshot noise. |
| 41 | + |
| 42 | +**Scope**: |
| 43 | +- IN: `BlockerKind` enum in `types.rs`, `get_commit_status()` in `gitea.rs`, `evaluate_one` async + classification, log field |
| 44 | +- OUT: Session dumps, handoff files, snapshot files, reconcile snapshots |
| 45 | + |
| 46 | +**File Changes**: |
| 47 | +| File | Change | |
| 48 | +|------|--------| |
| 49 | +| `types.rs` | Add `BlockerKind` enum, add `sha` field to `PrSummary` | |
| 50 | +| `gitea.rs` | Add `CommitCombinedStatus` struct, `get_commit_status()` function | |
| 51 | +| `evaluator.rs` | Make `evaluate_one` async, classify blocker kind via CI status | |
| 52 | +| `lib.rs` | Add `poll_pending_reviews()` function | |
| 53 | + |
| 54 | +**Test Strategy**: Unit test `evaluate_one` with mock CI responses for ci_failed, ci_pending, and no-status scenarios. |
| 55 | + |
| 56 | +**Implementation**: Cherry-pick only the core commits, discard noise files. Create a clean branch from main. |
| 57 | + |
| 58 | +**Verdict**: MERGE after extracting core. Close current PR as bloated; reopen clean version. |
| 59 | + |
| 60 | +--- |
| 61 | + |
| 62 | +## Categorical Evaluation — All Other Processed PRs |
| 63 | + |
| 64 | +### Category A: RLM KG Validation (10 PRs) |
| 65 | + |
| 66 | +PRs: #2671, #2692, #2902, #2913, #2910, #2482, #2484, #2481, #2614, #2612 |
| 67 | + |
| 68 | +**Research finding**: All RLM validation PRs were superseded by independent implementation on main. The current main architecture (executor-based `validate_command()` with per-executor `Option<Arc<KnowledgeGraphValidator>>`) is cleaner than the PRs' approach (direct validator in QueryLoop). |
| 69 | + |
| 70 | +| Feature | PR(s) | In main? | Design decision | |
| 71 | +|---------|-------|----------|-----------------| |
| 72 | +| validate() before execute | #2671, #2614, #2612 | YES | `validate_command()` in query_loop calls `self.executor.validate()` | |
| 73 | +| from_config() | #2692 | YES | `validator.rs:from_config()` with thesaurus loading | |
| 74 | +| with_validator() | #2482 | YES | `local.rs`, `docker.rs` have `with_validator()` | |
| 75 | +| blocks_unknown Normal | #2905 | YES | `ValidatorConfig::default()` has `min_match_ratio=0.1` — Normal blocks | |
| 76 | +| Arc<Validator> | #2913 | SUPERSEDED | Per-executor Arc is cleaner than per-RLM | |
| 77 | +| KgStrictness propagation | #2493, #2597 | YES | `ValidatorConfig` carries strictness; `ValidationResult` reflects it | |
| 78 | + |
| 79 | +**Verdict**: ALL CLOSED AS SUPERSEDED — functionality present via independent implementation. |
| 80 | + |
| 81 | +### Category B: Executor Changes (6 PRs) |
| 82 | + |
| 83 | +PRs: #2765, #2512, #2514, #2431, #2430, #2590, #2521 |
| 84 | + |
| 85 | +| Feature | PR(s) | In main? | |
| 86 | +|---------|-------|----------| |
| 87 | +| list_snapshots mutex | #2765, #2431 | YES | |
| 88 | +| cleanup() stops VMs | #2430, #2446 | YES | |
| 89 | +| validate() tests | #2512, #2514 | YES (tests in executor modules) | |
| 90 | +| ensure_pool() | #2590, #2521 | PARTIAL (stub exists, needs Firecracker integration) | |
| 91 | + |
| 92 | +**Verdict**: MOSTLY SUPERSEDED. Only `ensure_pool()` is a real gap worth revisiting. |
| 93 | + |
| 94 | +### Category C: Security Fixes (4 PRs) |
| 95 | + |
| 96 | +PRs: #3007, #2993, #2828, #2932, #3971 |
| 97 | + |
| 98 | +| Feature | In main? | |
| 99 | +|---------|----------| |
| 100 | +| Ed25519 key docs | YES | |
| 101 | +| OnceLock redaction | YES | |
| 102 | +| git2 advisories | YES (waivers in audit.toml) | |
| 103 | +| SAFETY comments | YES (rlm.rs, symphony) | |
| 104 | +| Vault ref removal | YES | |
| 105 | + |
| 106 | +### Category D: CI Gates (6 PRs) |
| 107 | + |
| 108 | +PRs: #2955, #2954, #2942, #2939, #3000, #3001 |
| 109 | + |
| 110 | +| Gate | In main? | |
| 111 | +|------|----------| |
| 112 | +| cargo audit | YES (`--deny warnings`) | |
| 113 | +| rust-clippy | YES (ci-pr.yml job) | |
| 114 | +| rust-compile | YES (ci-pr.yml job) | |
| 115 | +| test execution | YES (ci-pr.yml job) | |
| 116 | +| nextest timeout | YES (`.config/nextest.toml`) | |
| 117 | +| flaky repro | YES (`.config/nextest.toml`) | |
| 118 | + |
| 119 | +### Category E: Merge Coordinator (5 PRs) |
| 120 | + |
| 121 | +PRs: #2877, #2886, #2898, #2851, #2404, #2409 |
| 122 | + |
| 123 | +| Feature | In main? | |
| 124 | +|---------|----------| |
| 125 | +| extract_fixes keywords | YES | |
| 126 | +| PrFile deserialization | YES | |
| 127 | +| Path starts_with | NO (needs investigation) | |
| 128 | +| Contamination gate | PARTIAL | |
| 129 | +| Paginate list_pr_files | PARTIAL | |
| 130 | + |
| 131 | +### Category F: Tests (8 PRs) |
| 132 | + |
| 133 | +PRs: #2985, #2977, #2976, #2957, #2952, #2945, #2903, #2899, #2781, #2847 |
| 134 | + |
| 135 | +**All tests present in main** — 391 total, 0 failures. |
| 136 | + |
| 137 | +### Category G: Docs/Specs (7 PRs) |
| 138 | + |
| 139 | +PRs: #2979, #2857, #2817, #2818, #2752, #2743, #2150, #2093 |
| 140 | + |
| 141 | +**All doc changes present in main**. |
| 142 | + |
| 143 | +### Category H: Cleanup (5 PRs) |
| 144 | + |
| 145 | +PRs: #2968, #2974, #2812, #2915, #2772 |
| 146 | + |
| 147 | +**All cleanup changes present in main**. |
| 148 | + |
| 149 | +--- |
| 150 | + |
| 151 | +## Summary Matrix |
| 152 | + |
| 153 | +| Verdict | Count | Examples | |
| 154 | +|--------|-------|----------| |
| 155 | +| SUPERSEDED (in main) | ~130 | RLM validation, executor changes, security, CI, docs | |
| 156 | +| PARTIAL (some gaps) | ~5 | ensure_pool(), Path starts_with, contamination gate | |
| 157 | +| NEEDS EXTRACTION | 1 | #2588 (BlockerKind) | |
| 158 | +| ALREADY MERGED | ~12 | via explicit merge during sprint 1 | |
| 159 | + |
| 160 | +## Key Gaps Worth Addressing |
| 161 | + |
| 162 | +| Gap | PR | Priority | Effort | |
| 163 | +|-----|-----|----------|--------| |
| 164 | +| BlockerKind classification | #2588 | Medium | 1h (extract + clean) | |
| 165 | +| Firecracker ensure_pool() | #2590, #2521 | Low | 4h (needs Firecracker API) | |
| 166 | +| Path starts_with in validate_path | #2898 | Low | 1h | |
| 167 | +| Contamination gate pagination | #2409 | Low | 2h | |
0 commit comments