Mirror the Node-side changes from recost-dev/middleware-node#17 and recost-dev/middleware-node#20 in the Python SDK.
Why
Both SDKs serialize WindowSummary (Python: dict equivalent) onto the wire. After the Node PR, Node no longer emits projectId in the body and pins the timestamp wire format to ISO 8601 ms-precision UTC Z. Python should match so any cross-SDK analysis on the API side sees a single stable shape.
Tasks
-
Drop project_id from the dict that _aggregator.py produces on flush. The transport already has it for the URL path; the body field is dead weight (the API ignores it).
-
Normalize timestamps. Replace datetime.now(timezone.utc).isoformat() (microsecond precision, +00:00 suffix) with a helper:
def _iso_now() -> str:
return datetime.now(timezone.utc).isoformat(timespec="milliseconds").replace("+00:00", "Z")
Call this from every site that currently produces a WindowSummary timestamp.
-
Add a tests/test_contract.py assertion mirroring the Node side: window_start / window_end match ^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z$, and the serialized payload does not contain project_id.
Reference
Node-side spec / discussion lives in the PR for #17 + #20 (URL pending).
Closes the cross-SDK parity item in the wire-format-cleanup wave.
Mirror the Node-side changes from recost-dev/middleware-node#17 and recost-dev/middleware-node#20 in the Python SDK.
Why
Both SDKs serialize
WindowSummary(Python: dict equivalent) onto the wire. After the Node PR, Node no longer emitsprojectIdin the body and pins the timestamp wire format to ISO 8601 ms-precision UTCZ. Python should match so any cross-SDK analysis on the API side sees a single stable shape.Tasks
Drop
project_idfrom the dict that_aggregator.pyproduces on flush. The transport already has it for the URL path; the body field is dead weight (the API ignores it).Normalize timestamps. Replace
datetime.now(timezone.utc).isoformat()(microsecond precision,+00:00suffix) with a helper:Call this from every site that currently produces a
WindowSummarytimestamp.Add a
tests/test_contract.pyassertion mirroring the Node side:window_start/window_endmatch^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z$, and the serialized payload does not containproject_id.Reference
Node-side spec / discussion lives in the PR for #17 + #20 (URL pending).
Closes the cross-SDK parity item in the wire-format-cleanup wave.