Change:
known HPKE configuration.  When clients receive an 'outdatedConfig' error, they SHOULD invalidate any cached aggregator "HpkeConfigList" and retry with a freshly generated Report.  If this retried report <del> does not succeed, clients MUST abort and discontinue retrying. </del> <ins> does not succeed, clients SHOULD abort and discontinue retrying. If a report's ID matches that of a previously uploaded report, the leader MUST ignore it and the leader MAY alert the client with error "reportRejected".  See the implementation note in input-share- validation. </ins> The Leader MUST ignore any report pertaining to a batch that has <del> already been collected.  (See input-share-validation for details.) </del> <ins> already been collected (see input-share-validation for details). </ins> Otherwise, comparing the aggregate result to the previous aggregate <del> result may result in a privacy violation.  (Note that the Helpers enforce this as well.)  The Leader MAY ignore any reports whose timestamp is past the task's "task_expiration".  When it does so, the leader SHOULD abort the upload protocol and alert the client with error "reportTooLate".  Client MAY choose to opt out of the task if its own clock has passed "task_expiration". </del> <ins> result may result in a privacy violation.  Note that this is enforced by all Aggegators, not just the leader.  In addition, the leader MAY abort the upload protocol and alert the client with error "reportRejected". The Leader MAY ignore any reports whose timestamp is past the task's "task_expiration".  When it does so, the leader SHOULD abort the upload protocol and alert the client with error "reportRejected". Client MAY choose to opt out of the task if its own clock has passed "task_expiration". </ins> Leaders can buffer reports while waiting to aggregate them.  The leader SHOULD NOT accept reports whose timestamps are too far in the future.  Implementors MAY provide for some small leeway, usually no more than a few minutes, to account for clock skew.  If the leader rejects a report for this reason, it SHOULD abort the upload protocol <del> and alert the client with error "reportTooEarly". </del> <ins> and alert the client with error "reportTooEarly".  In this situation, clients MAY re-upload the report later on. </ins> If the Report contains an unrecognized extension, or of two extensions have the same ExtensionType, then the Leader MAY abort the

Discussion:
We didn't have any text that actually instructed leaders to reject uploads deemed to be replays based on their nonce. The text in {{anti-replay}} says leaders should do this, but then refers to the uploads section, which doesn't contain any text about checking nonces or what the leader should do. We now define a new problem document type "reportRejected", which replaces the previous "reportTooLate", previously used in the case where the leader detects a report pertaining to an already-collected batch. The rationale for using a less specific error type for these two cases is twofold: In these cases, we don't expect the client to do anything but give up on the report, so nothing more specific than a generic rejection is needed; If we did provide more specific error codes, we'd be giving attackers an oracle for what nonces have already been uploaded or what reports have already been collected. While I was in this text, I also: resolved . clarified that the client should do if it gets "reportTooEarly". If the client shouldn't do anything special in that situation, then I argue the error should be the generic "reportRejected". downgraded a MUST to a SHOULD in the case where the client gets "outdatedConfig" twice. There's no way the protocol can meaningfully enforce that MUST, and if the client continues to upload reports referencing an outdated or non-existent HPKE config, the leader can just continue to ignore the reports.
I don't think we should hold up draft-02 for this, unless it takes long enough for the fixed-task stuff to land anyway.
Responding to David-- I see your point, and maybe we need to invent some new terms to clearly distinguish between anti-replay as in "you tried to use the same report ID with different timestamps or content" and anti-replay as in "you tried to aggregate a single report too many times". But I do think the helper needs to defend against the former, not just the latter, and so the {{anti-replay}} section does seem pertinent to it. In my latest commit I added text to this effect. I agree. The API changes proposed in would mean that multiple PUT requests for the same report will all yield 200 OK (or 201 Created, I guess). So if you send the same multiple times, that's OK.

But I do think we want to enable (though not require, to Chris' point about allowing implementations to defer checking anti-replay to the aggregation sub-protocol) leaders alert clients if it's detected that they've tried to use an existing report ID with a new timestamp or input share.
NAME can you please rebase this?
I've updated this change. The section on handling uploads no longer references {{input-share-validation}}, per NAME argument that leader checks during upload and aggregator checks during aggregation are not the same thing. Instead we plainly state in the text of "Upload Requests" that leaders MUST ignore replays and MAY alert the client.
Section 4.2.2: "Clients SHOULD NOT upload the same measurement value in more than one report if the leader responds with status 200 and an empty body.”" Is a non-empty body understood to signal an error condition based on some other context? What if the client got status 200 from the leader but a non-empty body? Should the client retry as this text suggests? I don't know enough about HTTP semantics to know for sure, but it seems like specifying an empty body here is unnecessary. It seems fine to specify that the leader should send an empty body for 200, but maybe be less strict on the consumption side and drop the empty body requirement?