Repository navigation
fix(agent): follow primitive streams and the bridges to them in a parallel pipeline (#1172) - #1225
Merged
Merged
Conversation
…allel pipeline (#1172) #1209 followed a reference Stream's map, filter and peek lambdas to the common pool's workers, but a primitive stream's were still unattributed, and so was any lambda behind mapToInt. list.parallelStream().mapToInt(...) .sum() is the usual way to total in parallel, and a plain counter inside its lambda was seen only on the caller's own elements. IntStream, LongStream and DoubleStream now get the Stream treatment: map, filter, peek and mapToObj wait in a slot, and the terminal operations (forEachOrdered, reduce, collect, the matches, sum, count, average, min, max, summaryStatistics, toArray, the finds) lend the run to every slot while they run. The pipeline map is keyed by BaseStream, so the slots follow a pipeline across Stream.mapToInt/mapToLong/mapToDouble, mapToObj and boxed. The three primitive forEach hooks now share parallelTerminal. Tests first: six new cases in AgentParallelStreamHooksTest failed to compile on the 59 missing hooks; all 19 pass. Disabling the mapToInt hook turns two of them red. The class now runs a telemetry drain per test: without one the ring filled and every later task event waited out the ring's one-second give-up, which hung the class for over 15 minutes. Corpus: four idioms, IntStream.map and Stream.mapToInt counters with and without a lock; idiom lane 86/86, every lane green. Library 3963 and agent 117 tests green, static gate chain green. Still not followed: a stage behind sorted, distinct, limit, skip or flatMap, a pipeline ended by iterator(), and a Collector's own functions. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Codecov Report❌ Patch coverage is
📢 Thoughts on this report? Let us know! |
7 of 8 tasks
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.
Partly addresses #1172. The forms still not followed stay there (narrowed in a comment on the issue).
Why
#1209 followed a reference
Stream'smap,filterandpeeklambdas to the common pool's workers. A primitive stream's were still unattributed, and so was any lambda behindmapToInt.list.parallelStream().mapToInt(...).sum()is the usual way to total in parallel, and a plain counter inside its lambda was seen only on the caller's own elements, so the race drew nothing reliable.What changed
IntStream,LongStreamandDoubleStreamget theStreamtreatment.map,filter,peekandmapToObjwait in a slot. The terminal operations (forEachOrdered,reduce,collect, the matches,sum,count,average,min,max,summaryStatistics,toArray, the finds) lend the run to every slot while they run. As before, areduceoperator and acollectcombiner run as combines.BaseStream, so the slots follow a pipeline acrossStream.mapToInt/mapToLong/mapToDouble, a primitive stream'smapToObjandboxed.boxedadds no slot of its own and only carries the slots behind it.forEachhooks now go through the sameparallelTerminal, so aforEachending a primitive pipeline lends the run to itsmaplambdas too.AgentConcurrencyUtilHooks, all additive and tagged@since 1.14.2, with 66 matching rows inCollectionAccessWeaver.How it was verified
AgentParallelStreamHooksTestfailed to compile on the 59 missing hooks. All 19 cases in the class pass now. Turning off themapToInthook made two of them fail (aLambdaStaysLentAcrossTheBridges,theCallerIsOrderedAfterAMapToIntLambda), and they passed again once it was restored.TelemetryEventBuffer.publish). With the drain it runs in about 17 s.parallelIntMap_plainCounterandparallelMapToInt_plainCounterareMUST_FIRE; their locked twins areMUST_STAY_SILENT. The idiom lane passed 86/86 and every other lane is green. The newMUST_FIRErows were not run against the old jar. Their red-before evidence is the unit test mutation above.-P fast, JDK 26). The static gate chain (mvn install -DskipTests -Djacoco.skip=true) is green.Docs
docs/CHANGELOG.md(extended the #1172 entry under Unreleased),docs/agent/limitations.mdanddocs/analysis/corpus-eval-future-improvements.md. All three named primitivemap/filterandmapToIntas unfollowed; they now list what is still unfollowed. No VibeTags guardrail was added. The hooks class already carries its contract-frozen rule, which covers the new hooks, and no new external contract or security boundary was introduced.Checklist
VIBETAGS-START/VIBETAGS-ENDmarkers@since 1.14.2Co-Authored-BytrailerStill not followed (tracked in #1172)
A stage behind
sorted,distinct,limit,skiporflatMap, a pipeline ended byiterator()or in unwoven code, and aCollector's own functions.🤖 Generated with Claude Code