WindowSummary body carries redundant projectId
Severity: Medium
Affected repos: middleware-node, middleware-python, api
Component boundary: middleware → API telemetry route
Symptom
Both SDKs serialize WindowSummary with a top-level projectId field. The API route POST /projects/:id/telemetry extracts the project ID from the URL path and ignores the body field. If the two ever disagree (URL says proj_A, body says proj_B), the validator on the API side does not catch it — the body field is silently dropped.
Evidence
middleware-node/src/core/aggregator.ts — flush() includes projectId in the returned object.
middleware-node/src/core/transport.ts — POSTs to /projects/${projectId}/telemetry while also sending projectId in the JSON body.
api/src/routes/telemetry.ts — handler reads c.req.param("id") and uses that.
Impact
- Redundant wire data (small).
- Confusing for anyone reading the SDK code or the API contract — two sources of truth for the same value.
- A future API change that starts trusting the body field could silently route data to the wrong project for misconfigured clients.
Fix recommendation
Stop emitting projectId from the SDKs' aggregators. The transport already has it for the URL. Document the contract: project ID lives in the path, never the body.
If the field needs to stay for backward compatibility, add a server-side validator: if body.projectId exists and differs from the URL param, return 400.
Verification
- Strip
projectId from WindowSummary types in both SDKs; rebuild; confirm JSON.stringify(summary) no longer contains the field.
- API still accepts the trimmed payload.
Related
Parity with recost-dev/middleware-node#17. Drop the projectId field from the Python WindowSummary dataclass / to_dict().
WindowSummary body carries redundant
projectIdSeverity: Medium
Affected repos:
middleware-node,middleware-python,apiComponent boundary: middleware → API telemetry route
Symptom
Both SDKs serialize
WindowSummarywith a top-levelprojectIdfield. The API routePOST /projects/:id/telemetryextracts the project ID from the URL path and ignores the body field. If the two ever disagree (URL saysproj_A, body saysproj_B), the validator on the API side does not catch it — the body field is silently dropped.Evidence
middleware-node/src/core/aggregator.ts—flush()includesprojectIdin the returned object.middleware-node/src/core/transport.ts— POSTs to/projects/${projectId}/telemetrywhile also sendingprojectIdin the JSON body.api/src/routes/telemetry.ts— handler readsc.req.param("id")and uses that.Impact
Fix recommendation
Stop emitting
projectIdfrom the SDKs' aggregators. The transport already has it for the URL. Document the contract: project ID lives in the path, never the body.If the field needs to stay for backward compatibility, add a server-side validator: if
body.projectIdexists and differs from the URL param, return 400.Verification
projectIdfromWindowSummarytypes in both SDKs; rebuild; confirmJSON.stringify(summary)no longer contains the field.Related
Parity with recost-dev/middleware-node#17. Drop the projectId field from the Python WindowSummary dataclass / to_dict().