Fan the three human state-loads' per-candidate fetches out through map_bounded - #236
Conversation
`next_design_fetch`, `next_close_candidate_fetch` and `leak_scan_with` each hand-rolled a serial per-candidate `gh` loop on a "the population is small" assumption nothing enforces. `map_bounded` — bounded to `QUEUE_FETCH_CONCURRENCY` scoped threads, input-order results, work-stolen off one atomic counter — already existed with one production caller. All three now go through it. The reads fan out; the COUNTING does not. Each function folds the outcomes serially in candidate order, so `counts`, the withheld/stranded list and the error list are exactly what the same GitHub state produced one call at a time, and both documents' "raw is the sum of its parts" arithmetic still holds. A failed fetch stays an outcome: the `continue`-plus-counter-bump arms became named variants folded into the same buckets, with the same reason strings. Measured on `next_design` at `aiDesign: 22` against the live API: 17.5s -> 3.9s. Closes #235 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
Warning Review limit reached
Next review available in: 12 minutes You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: Organization UI Review profile: ASSERTIVE Plan: Pro Plus Run ID: 📒 Files selected for processing (1)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
The scan names the item the gate decision is made in (`ncc_outcome`) and the item the fetch classifies through (`ncc_classify`). One hop between them was unpinned: an `ncc_classify` that stopped calling `ncc_outcome` and hand-rolled its own gate satisfied both assertions while BEING the divergence they exist to forbid. Both links are now asserted. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Adversarial pass over this diffI tried to construct an ordering or failure interleaving where a converted function returns rows in the wrong order, loses a candidate, double-counts one, or reports a failed read as a clean result. What I found: No hole in the ordering or the accounting. The one construct that could have hidden a loss is Everything running on a worker thread is pure. One residual hazard, named rather than fixed hereThese three still read through It is unchanged by this PR (they used |
…sify Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
Reviewed ff77beb: approve Read the conversion sites and the constraint surface myself rather than grading the summary. The three folds are correct, and correct in the way that matters. Each fans its per-candidate read through The seam widening is right. The Constraints checked individually, not taken on trust. The conformance pin was the hunk I most wanted to see, and the widening is the right call. The The claim is measured, not asserted: Known residual, unchanged by this PR and stated on it: these three still read through CI 20/20 green, Rulings-conformance: graded against the repo's CLAUDE.md north star and every ruling the human stated for this work, each named with how the artifact obeys it.
|
Closes #235
What
Three human-facing state-loads fetched their candidates serially, one blocking
gh pr view/gh issue viewsubprocess at a time, on an assumption the codestated and nothing enforced ("the population is small").
map_bounded— boundedto
QUEUE_FETCH_CONCURRENCY = 8scoped threads, input-order results, work-stolenoff one atomic counter, already tested — sat in the same file with exactly one
production caller. These three now go through it:
next_design_fetch→nd_classifynext_close_candidate_fetch→ncc_classifyleak_scan_withunvetted_fetchis deliberately untouched: #233 is rewriting it and, after #233,it WRITES to GitHub in a guaranteed order. The issue records it as a follow-up.
The two constraints the shape exists to hold
The fetches parallelise; the counting does not. Each converted function fans
the reads out through
map_bounded, which hands back one outcome per candidatein candidate order, then folds those outcomes serially into
counts, thewithheld/stranded list and the error list. That is the split
presentable_queuealready models, and it is what keeps
aiDesign/flaggedprovably the sum oftheir parts and both human-read lists in the order the queue enumerated them. A
fold in completion order changes no count and silently reshuffles two of the
three lists on every run.
A failed fetch is an outcome, never a skip. The
continue-plus-counter-bumparms became named variants —
NdOutcome::FetchFailed,NccOutcome::FetchFailed/
Unaddressable, andleak_scan_with's existingunreadable— folded into thesame buckets, in the same order, with the same
whystrings. Nothing new iscounted and nothing is dropped.
Output shape
Unchanged. No document key added, removed or renamed; no list reordered; no cap
touched.
nd_pr_detail/ncc_issue_detailask for byte-identical--jsonfieldsets to the inline calls they replace. This is a latency fix and the diff is one.
The one test edit outside the new tests is the
cc_gatesource-scan pin: thehuman inbox's classification moved from
next_close_candidate_fetchintoncc_outcome, so the pin namesncc_outcome, and a new assertion was addedbeside it so the chain is closed at the far end (
next_close_candidate_fetchmust reach
ncc_classify) — naming the classifier alone would let an item thatclassifies correctly and is called by nothing satisfy the rule.
Measured
next_designend to end against the real GitHub API,aiDesign: 22, releasebuild, same box, same token, driven through the MCP server on stdin:
3.3x, 17.6s → 5.3s. The residue is the one org-wide search plus the slowest
of the eight in-flight reads. The 22 candidate reads went from ~14s of sequential
round trips to ~2s.
The two documents were compared key by key and are identical — same counts,
same
withheldlist in the same order, samenextrow.next_close_candidate(flagged: 0) andnext_leak(1 leak candidate) have nopopulation to fan out today, so neither shows a change (4.09s → 4.11s and 6.21s →
6.33s, both inside the noise); both were re-run and their documents are identical
too. The design lane is the one with a population, which is what #235 measured.
QA
next_design_tests::the_design_reads_fan_out_and_every_list_stays_in_candidate_order,next_close_candidate_tests::the_flag_reads_fan_out_and_every_list_stays_in_hit_order,next_leak_tests::the_leak_reads_fan_out_and_the_unknowns_stay_in_candidate_order,next_design_tests::a_design_read_that_failed_is_an_error_row_not_a_missing_one,next_close_candidate_tests::a_flag_read_that_failed_is_an_error_row_not_a_missing_one,next_design_tests::the_design_counts_partition_the_whole_population_after_the_fan_out,next_close_candidate_tests::the_flag_counts_partition_the_whole_population_after_the_fan_out— the three order tests inject a fetch whose candidate 0 blocks until some other candidate has finished, so completion order provably differs from candidate order, then assert every emitted list is still in candidate order. The functions under test do not exist on base, so "fails on base" was verified by mutating the merged code back to base's implementation (map_bounded(…)→ a serial.iter().map(…).collect()): all three then fail on the inversion assertion, which is the serial behaviour they are written to discriminate.nd_classifymap_bounded→ serial.iter().map()→the_design_reads_fan_out_and_every_list_stays_in_candidate_order;ncc_classifysame →the_flag_reads_fan_out_and_every_list_stays_in_hit_order;leak_scan_withsame →the_leak_reads_fan_out_and_the_unknowns_stay_in_candidate_order;nd_classifyfoldfor out in outcomes→outcomes.into_iter().rev()(completion-order proxy) →the_design_reads_fan_out_and_every_list_stays_in_candidate_order;nd_apply_outcomeNdOutcome::FetchFailedarm → no-op skip →a_design_read_that_failed_is_an_error_row_not_a_missing_one;ncc_apply_outcomeNccOutcome::FetchFailedarm → no-op skip →a_flag_read_that_failed_is_an_error_row_not_a_missing_one;leak_scan_withunreadable.push(...)→ barecontinue→a_failed_comment_read_is_unknown_and_never_a_clean_bill(existing) andthe_leak_reads_fan_out_and_the_unknowns_stay_in_candidate_order;nd_classifyraw: live.len() + frozen→live.len()→the_design_counts_partition_the_whole_population_after_the_fan_out;ncc_apply_outcomeCcGate::Unvetted => counts.unvetted += 1→counts.no_flag += 1→the_flag_counts_partition_the_whole_population_after_the_fan_out.whyconstants (ND_WHY_NO_QUESTION/ND_WHY_FETCH_FAILED,"unparseable issue ref","gh issue view failed — not classified this run"), and the partition arithmetic the two count structs' doc comments state (aiDesign == draft + unaddressable + presentable + noQuestion + fetchErrors + archivedRepo;flagged == presentable + vetterCloseVerdict + tornHumanClose + unvetted + noProducerFlag + humanRuled + vetterRejectedStillFlagged + fetchErrors). Expected sequences are computed from the candidate index in the test, never read back out of the value under test. The latency claim's oracle is the wall clock against the live API, both binaries built release from the same tree.next_design_fetch,next_close_candidate_fetchandleak_scan_withrouted throughmap_bounded; ordering preserved by folding serially in input order; failures surviving the fan-out into the same buckets; the cap and the output shape untouched;unvetted_fetchleft alone. Covered — all three converted, all three carry an order test driven by an injected out-of-order fetch, both error paths carry their own test, both partitions are asserted after the fan-out,QUEUE_FETCH_CONCURRENCYand every document key are unchanged, andunvetted_fetchis not in the diff.