Change:
Allows helpers to reject reports from too far in the future, matching the leader check detailed in "Upload Requests". We add for this case, and allow the leader to try the report again later. Requires helpers to mark undecodable decrypted input shares as invalid with ().
The DAP specification defines a number of error modes, which ultimately end up mapped to error codes defined in section 3.1. Currently, the specified behavior does not describe how to treat message-deserialization failures, in any of client-aggregator, aggregator-aggregator, or collector-aggregator communications. We should consider specifying this. Initial thoughts: Moving to (with a new error code?) or makes sense to me, for deserialization errors during the aggregation process. It'd be very nice if one "bad" client report didn't fail the entire aggregation job, e.g. we should probably specify behavior that limits the "blast radius" of a badly-serialized message. We could leave this unspecified; I suppose the risk is that different implementations might treat this error mode with different semantics (e.g. some will fail a single report, some will fail the entirety of the aggregation job).
(This fell out of discussion on URL; FWIW, Janus will currently transition a report aggregation to if it fails to decode a message, though of course that's just one implementation's choice.)

Discussion:
Before beginning the preparation step, Aggregators are required to perform the following generic checks. <ins> Check that the decrypted input share can be decoded.  If not, the input share MUST be marked as invalid with the error "unrecognized_message". </ins> Check if the report has already been aggregated with this aggregation parameter.  If this check fails, the input share MUST be marked as invalid with the error "report_replayed".  This is

collect sub-protocol.  (See batch-validation.)  If both checks succeed, the input share is not marked as invalid. <ins> Check if the report is too far into the future.  Implementors can provide for some small leeway, usually no more than a few minutes, to account for clock skew.  If a report is rejected for this reason, the Aggregator SHOULD mark the input share as invalid with the error "report_too_early". </ins> Check if the report's timestamp has passed its task's "task_expiration" time, if so the Aggregator MAY mark the input share as invalid with the error "task_expired".

The leader begins each round of continuation for a report share based on its locally computed prepare message and the previous PrepareStep from the helper.  If PrepareStep is of type "failed", then the leader <del> marks the report as failed and removes it from the candidate report set and does not process it further.  If the type is "finished", then the leader aborts with "unrecognizedMessage".  [[OPEN ISSUE: This behavior is not specified.]] If the type is "continued", then the leader proceeds as follows. </del> <ins> acts based on the value of the "ReportShareError": If the error is "ReportShareError.report_too_early", then the leader MAY try to re-send the report in a later "AggregateInitializeReq". For any other error, the leader marks the report as failed, removes it from the candidate report set and does not process it further. If the type is "finished", then the leader aborts with "unrecognizedMessage".  If the type is "continued", then the leader proceeds as follows. </ins> Let "leader_outbound" denote the leader's prepare message and "helper_outbound" denote the helper's.  The leader computes the next