Program: 112507
Project: 112507
Buggy source:
private static ScenarioDefinition buildHistoricalScenarios(Map<LocalDate,Map<RateCurveId,Curve>> historicalCurves,List<LocalDate> scenarioDates){
  CurveGroupName curveGroup=CurveGroupName.of("String_Node_Str");
  DiscountCurveId discountCurveId=DiscountCurveId.of(Currency.USD,curveGroup);
  RateIndexCurveId libor3mCurveId=RateIndexCurveId.of(IborIndices.USD_LIBOR_3M,curveGroup);
  RateIndexCurveId libor6mCurveId=RateIndexCurveId.of(IborIndices.USD_LIBOR_6M,curveGroup);
  Set<RateCurveId> curveIds=ImmutableSet.of(discountCurveId,libor3mCurveId,libor6mCurveId);
  LocalDate firstScenarioDate=scenarioDates.get(0);
  Map<RateCurveId,Curve> previousCurves=historicalCurves.get(firstScenarioDate);
  List<Perturbation<Curve>> baseScenario=ImmutableList.of(Perturbation.none());
  Map<RateCurveId,List<Perturbation<Curve>>> curvePerturbations=previousCurves.keySet().stream().collect(toImmutableMap(id -> id,k -> Lists.newArrayList(baseScenario)));
  for (int i=1; i < scenarioDates.size(); i++) {
    LocalDate scenarioDate=scenarioDates.get(i);
    Map<RateCurveId,Curve> curves=historicalCurves.get(scenarioDate);
    for (    RateCurveId curveId : curveIds) {
      NodalCurve curve=(NodalCurve)curves.get(curveId);
      NodalCurve previousCurve=(NodalCurve)previousCurves.get(curveId);
      List<CurveParameterMetadata> curveNodeMetadata=curve.getMetadata().getParameters().get();
      CurvePointShiftBuilder shiftBuilder=CurvePointShift.builder(ShiftType.ABSOLUTE);
      for (int curveNodeIdx=0; curveNodeIdx < curve.getParameterCount(); curveNodeIdx++) {
        double zeroRate=curve.getYValues()[curveNodeIdx];
        double previousZeroRate=previousCurve.getYValues()[curveNodeIdx];
        double shift=(zeroRate - previousZeroRate);
        shiftBuilder.addShift(curveNodeMetadata.get(curveNodeIdx).getIdentifier(),shift);
      }
      curvePerturbations.get(curveId).add(shiftBuilder.build());
    }
    previousCurves=curves;
  }
  PerturbationMapping<Curve> discountCurveMappings=PerturbationMapping.of(Curve.class,AnyDiscountCurveFilter.INSTANCE,curvePerturbations.get(discountCurveId));
  PerturbationMapping<Curve> libor3mMappings=PerturbationMapping.of(Curve.class,CurveRateIndexFilter.of(IborIndices.USD_LIBOR_3M),curvePerturbations.get(libor3mCurveId));
  PerturbationMapping<Curve> libor6mMappings=PerturbationMapping.of(Curve.class,CurveRateIndexFilter.of(IborIndices.USD_LIBOR_6M),curvePerturbations.get(libor3mCurveId));
  return ScenarioDefinition.ofMappings(discountCurveMappings,libor3mMappings,libor6mMappings);
}

Fixed version (ground truth):
private static ScenarioDefinition buildHistoricalScenarios(Map<LocalDate,Map<RateCurveId,Curve>> historicalCurves,List<LocalDate> scenarioDates){
  CurveGroupName curveGroup=CurveGroupName.of("String_Node_Str");
  DiscountCurveId discountCurveId=DiscountCurveId.of(Currency.USD,curveGroup);
  RateIndexCurveId libor3mCurveId=RateIndexCurveId.of(IborIndices.USD_LIBOR_3M,curveGroup);
  RateIndexCurveId libor6mCurveId=RateIndexCurveId.of(IborIndices.USD_LIBOR_6M,curveGroup);
  Set<RateCurveId> curveIds=ImmutableSet.of(discountCurveId,libor3mCurveId,libor6mCurveId);
  LocalDate firstScenarioDate=scenarioDates.get(0);
  Map<RateCurveId,Curve> previousCurves=historicalCurves.get(firstScenarioDate);
  List<Perturbation<Curve>> baseScenario=ImmutableList.of(Perturbation.none());
  Map<RateCurveId,List<Perturbation<Curve>>> curvePerturbations=previousCurves.keySet().stream().collect(toImmutableMap(id -> id,k -> Lists.newArrayList(baseScenario)));
  for (int i=1; i < scenarioDates.size(); i++) {
    LocalDate scenarioDate=scenarioDates.get(i);
    Map<RateCurveId,Curve> curves=historicalCurves.get(scenarioDate);
    for (    RateCurveId curveId : curveIds) {
      NodalCurve curve=(NodalCurve)curves.get(curveId);
      NodalCurve previousCurve=(NodalCurve)previousCurves.get(curveId);
      List<CurveParameterMetadata> curveNodeMetadata=curve.getMetadata().getParameters().get();
      CurvePointShiftBuilder shiftBuilder=CurvePointShift.builder(ShiftType.ABSOLUTE);
      for (int curveNodeIdx=0; curveNodeIdx < curve.getParameterCount(); curveNodeIdx++) {
        double zeroRate=curve.getYValues()[curveNodeIdx];
        double previousZeroRate=previousCurve.getYValues()[curveNodeIdx];
        double shift=(zeroRate - previousZeroRate);
        shiftBuilder.addShift(curveNodeMetadata.get(curveNodeIdx).getIdentifier(),shift);
      }
      curvePerturbations.get(curveId).add(shiftBuilder.build());
    }
    previousCurves=curves;
  }
  PerturbationMapping<Curve> discountCurveMappings=PerturbationMapping.of(Curve.class,AnyDiscountCurveFilter.INSTANCE,curvePerturbations.get(discountCurveId));
  PerturbationMapping<Curve> libor3mMappings=PerturbationMapping.of(Curve.class,CurveRateIndexFilter.of(IborIndices.USD_LIBOR_3M),curvePerturbations.get(libor3mCurveId));
  PerturbationMapping<Curve> libor6mMappings=PerturbationMapping.of(Curve.class,CurveRateIndexFilter.of(IborIndices.USD_LIBOR_6M),curvePerturbations.get(libor6mCurveId));
  return ScenarioDefinition.ofMappings(discountCurveMappings,libor3mMappings,libor6mMappings);
}