DATEADD and DATEPART with milliseconds yields strange results
This is due to a strange limitation1 in the accuracy of the datetime data type, as documented:

Accuracy | Rounded to increments of .000, .003, or .007 seconds

The solution would be to use datetime2, which provides better accuracy, as you can see in this dbfiddle demo:

The return type of the DATEADD is dynamic based on what you send into it.  So the important thing is to make sure you are passing datetime2 to the step where you add the milliseconds on.

1 Randolph West has a great blog series on how SQL Server data types are stored, including one on dates and times (How SQL Server stores data types: dates and times).  That post has a useful comment from Data Platform MVP Jeff Moden:

The time portion of DATETIME is actually an integer count of the number of 1/300’s of a second that have passed since midnight. That translates to a 3.3 millisecond resolution but that level of resolution isn’t possible for the way the data is stored so 0.0 and 3.3 ms are rounded down to 0ms and 3ms and 6.6 milliseconds is rounded up to 7 milliseconds.