Conversation
…of PR feedback Analysis of all 111 findings the check posted on apify-core and apify-web PRs since mid-May (74 fixed, 13 consciously declined, 12 ignored, 3 disproven with explain plans, plus 14 duplicate threads) surfaced recurring failure modes. This tunes the review prompt accordingly: - One-off migrations get their own policy: operational advice (hint, batching, replica reads, accepted scan) instead of new indexes; a reasoned author accept settles the finding; content-based dedup across timestamp renames. Migrations carried 27 findings incl. 11 criticals. - Collection scans over multi-million-doc collections are always critical (severity triage correction requested by mtrunkat on apify-core#28597). - Dedup by substance instead of (path, line): outdated/resolved threads count, no verbatim or severity-escalated re-posts, no residual-advice re-posts after a fix. Duplicates were the most common failure mode. - Reasoned human replies settle findings and stop counting toward the check result, so a declined finding no longer keeps the check red. - $expr equality $lookup no longer claimed as a collscan (disproven with explain on apify-core#29506); downgraded to medium as a robustness suggestion. - Planner-behavior claims must be phrased as testable hypotheses; all three disputed findings were confident planner claims an explain() refuted. - Recommended indexes must use fields that exist on the document type; partialFilterExpression suggestions must be provably selectable. - Suggested actions must be complete and atomic (regex anchor lesson), respect offset/limit API contracts, and call out $ne→equality missing-field semantics. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QGiLipa4LSVzsdXUWKA4RW
There was a problem hiding this comment.
🟡 Changes recommended
Unresolved critical, moderate, and nit findings remain.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Pull request overview
This PR tunes the MongoDB query-index review prompt using historical feedback.
Changes:
- Adds migration-specific guidance and severity rules.
- Refines planner and recommendation guardrails.
- Updates deduplication and settled-finding handling.
File summaries
| File | Summary |
|---|---|
mongodb-query-index-check/README.md |
Updates behavior and migration documentation; two nit findings remain. |
mongodb-query-index-check/prompts/review.md |
Adds revised review and deduplication rules; two critical and three moderate findings remain. |
Review details
Suppressed comments (7)
mongodb-query-index-check/README.md:105
- This migration summary advertises “replica reads” without limiting them to read-only migrations, although the prompt also covers
updateManyscans. A secondary cannot execute the write or offload its scan; qualify this advice for read-only operations and document primary-side batching/timing for writes.
One-off migration scripts get operational advice (a `hint`, batching, replica reads, a timing window, or an explicitly accepted scan) instead of new-index recommendations; an unbatched scan of a multi-million-document collection is still critical even there.
mongodb-query-index-check/README.md:103
- The README's top-level behavior summary still says the action fails whenever a finding is reported, while this new exception means settled findings no longer fail the result. Update that earlier summary as well so users are not given contradictory behavior guarantees.
Any finding turns the check red unless `request-changes` is set to `false` — except findings a human already settled with a reasoned reply on an earlier run's thread (an explain plan, "one-off migration, bounded set", an API constraint), which stop counting toward the result.
mongodb-query-index-check/prompts/review.md:64
- Because this migration section also covers
updateManyand other writes, “reading from a replica / secondary” is not a valid mitigation for those cases: MongoDB writes must target the primary, soreadPreferencecannot move the scan off the primary. Restrict replica-read advice to read-only migrations and use batching, hints, or a traffic window for writes.
- **Never recommend adding an index for a one-off migration.** Suggest, in order: a `hint` on an existing index, batching with a bounded batch size, reading from a replica / secondary, running in a low-traffic window, or explicitly accepting the scan with a short comment in the code.
mongodb-query-index-check/prompts/review.md:201
- The first sentence correctly says plan choice is a hypothesis, but the final sentence tells the model that one obvious index "will" be chosen and to skip a hint. A single candidate can still lose to a collection scan or another cost-based plan, so this can suppress real plan-choice issues; avoid prescribing a hint solely from candidate count, but still require an
explain()when plan selection is material.
- **State planner behavior as a testable hypothesis, not a certainty.** Every disputed finding in this check's history was a confident planner claim that an `explain()` disproved (partial-filter subsumption of `$ne: null`, `$expr` join index use, plan selection without a `hint`). When your finding hinges on what the planner will choose — rather than on an index that plainly doesn't exist — say so and ask for an `explain()` to confirm. Suggest a `hint` only when the collection genuinely has many overlapping candidate indexes for this filter shape; when one index is the obvious single choice, the planner will pick it — skip the hint.
mongodb-query-index-check/prompts/review.md:213
- This matching rule is still too coarse for deduplication: two different queries on the same collection can have the same problem class (for example, two
Users.findcalls both missing a shard-key predicate), so the first thread would suppress the second finding. Require query identity—filter/sort/projection or equivalent query content—in addition to collection and problem class; migration renames can still use that content key.
3. **Deduplicate by substance, not by `(path, line)`.** A finding is a duplicate when an existing thread describes the same underlying issue on the same query — same collection, same problem class (e.g. "sort not covered by index", "filter without shard key") — even if the line shifted, the thread is outdated, or the file was renamed (migration files get renamed on rebase; match them by content). Post a finding on a previously-flagged query only when the new commits introduce a genuinely different problem. Never re-post an existing finding with a changed severity, and never follow a fix up with a downgraded "residual advice" version of the same finding — if the fix landed, the thread is done.
mongodb-query-index-check/prompts/review.md:212
- GitHub's default workflow bot login is
github-actions[bot](and a customgithub-tokenmay use yet another identity), not the literalgithub-actionsvalue. This predicate can therefore collect none of the prior bot threads, so reruns will repost duplicates and cannot honor settled replies.
2. Collect ALL threads — **outdated and resolved ones included** — whose first comment's `author` is `github-actions` and whose `body` starts with the template prefix defined in step 4 (any of the four severity emojis followed by ` **MongoDB index check`). Read the human replies in each.
mongodb-query-index-check/prompts/review.md:211
get_review_commentsis cursor-paginated, but this step only describes one call. On a PR with more than one page of review threads, older/outdated/settled comments will be omitted and the check can still repost them; iterate untilhasNextPageis false and pass the next page's cursor.
1. Call `mcp__github__pull_request_read` with `method: get_review_comments` and `pullNumber: $PR_NUMBER`. The response is a list of review threads; each has `is_outdated` and a `comments` array (every comment has `author`, `body`, `path`, `line`).
- Files reviewed: 2/2 changed files
- Comments generated: 2
- Review effort level: Lite
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Analysis of every finding the check posted on
apify/apify-coreandapify/apify-webPRs since it shipped in mid-May: 111 unique findings on 83 PRs (plus 14 duplicate threads and 19 findings on the two DO-NOT-MERGE stress-test PRs). Outcomes: 74 fixed (67%), 13 consciously declined with reasoning, 12 ignored, 3 disproven with explain plans, 9 on open/abandoned PRs. This PR folds the recurring failure modes back intoprompts/review.md.What the data showed → what changed
Duplicates are the check's most common failure mode (14 duplicate threads): the same finding posted three times in five minutes (apify-core#27675), verbatim re-posts two days later (apify-core#28250), a re-post with severity escalated medium→high (apify-core#27941), and re-posts after migration-file renames (apify-core#30151).
→ Dedup step rewritten: match by substance (same query, same problem class) instead of
(path, line); outdated and resolved threads now count; never re-post with changed severity; never follow a landed fix with a downgraded "residual advice" version of the same finding.One-off migrations carried 27 findings — a quarter of the total, including 11 of the 15 criticals — and engineers accept the scan ("It is migration, so it is fine") as often as they fix it. mtrunkat suggested a migrations policy on apify-core#28597.
→ New "One-off migrations" section: operational advice (hint, batching, replica reads, timing window, explicitly accepted scan) instead of new indexes; a reasoned author accept settles the finding; content-based matching across timestamp renames. An unbatched scan of a multi-million-doc collection stays critical.
All 3 false positives were confident planner claims an
explain()refuted: partial-index subsumption of$ne: null(apify-core#28260, "Clanker is not clanking"),$expr$lookupusing the index (apify-core#29506), and the planner picking the right index without ahint(apify-core#28395).→ Planner behavior must be phrased as a testable hypothesis with an invitation to
explain(); the$exprequality-join rule no longer claims a collscan and drops to 🟡 medium;hintonly when the plan choice is genuinely ambiguous; explain-plan evidence in a reply settles the finding.Severity triage correction from the check's owner (apify-core#28597): "the severity shall be critical in a case of collection scan with millions of items".
→ Codified in the 🔴 critical rubric — no downgrading because the code path is a daemon or infrequent.
Reasoned declines used to keep the check red forever, which trains people to ignore it (12 findings were merged over silently).
→ Findings settled by a substantive human reply (explain plan, field-presence check, one-off-migration reasoning, API contract) stop counting toward the check result. Behavioral change: a re-run after a reasoned decline now goes green.
The bot's concrete recommendations were occasionally wrong: a suggested index on four fields that don't exist on the type (apify-core#29248), a
partialFilterExpressionMongo wouldn't select (apify-core#27675), a keyset-pagination suggestion against an offset/limit API contract (apify-core#30289), and a regex finding "fixed" by dropping theiflag while staying unanchored (apify-core#30484).→ New guardrails: verify recommended fields exist on the document type; propose partial filters only when provably selectable; check API contracts before suggesting keyset pagination; call out
$ne→equality missing-field semantics; make suggested actions complete and atomic (name the load-bearing part).README updated to reflect the settled-findings and migrations behavior.
Not changed
Full per-PR data and the weekly/per-engineer breakdown are in the HTML scorecard report generated alongside this PR.
🤖 Generated with Claude Code
https://claude.ai/code/session_01QGiLipa4LSVzsdXUWKA4RW
Generated by Claude Code