carlos / platform Public
Round 5 review of feef9a5c.
| Previous finding | Disposition | Evidence from revision 5 | |---|---|---| | R3-1. Expiry/install races | Resolved | §5.3 retains expiry checks before download and installation, with genMu serializing installation, expiry and cleanup. | | R3-2. Unprotected console Locate | Resolved | §5.4 retains locked Swappable.Locate and puts the wrapper in Config.GeoIP. | | R3-3. Coordinate-only results | Resolved | §8.1a accepts coordinate-only hits; §9 counts their country as _unknown. | | R3-4. Heartbeat freshness | Resolved | §5.5 retains status.BoxStale and the jittered-heartbeat test. | | R1-4, carried forward: orphan destruction | Resolved | §3 retains startup and daily orphan sweeps, followed by §15’s noncurrent-version expiration. | | R1-16, carried forward: rollout verification | Partly resolved | §5.5 adds expected-box reconciliation through control/edges/, but fleet boxes explicitly skip that publisher: edgesfile.go:698. Missing fleet heartbeats remain invisible, and those older than seven days are still discarded. Also, systemBoxes’s strict mode still uses LoadBoxes, which silently skips individual unreadable records: apisystemupdate.go:258. Reconcile active registered fleet boxes through ListFleetBoxes, and use LoadBoxesComplete for every heartbeat prefix. | | R4-1. Duplicate tunnel analytics | Partly resolved | §9 correctly suppresses the remote observer through viaTunnelKey, but §8.4 still requires a test that counts the country in the remote box’s analytics. Change that assertion to zero remote observations and exactly one aggregate observation at the hub. | | R4-2. Publication deadline across backhaul | Resolved | §4.2 stages the upload, returns 202, and moves verification and publication into a polled job, with a backhaul timeout regression test. |
- P2 — §§4.1–4.2: the upload-and-job split leaves staging concurrency unspecified. The revised protocol places the job under the publication mutex and refuses another upload while a job holds it. It does not reserve the slot while the first request is still uploading. Multiple slow uploads can therefore start before any job exists, each staging up to 1 GiB on the console’s disk. Serializing the subsequent jobs does not bound that disk consumption.
Evidence: the staging and job-lock rules are at design.md:305. The existing job registry reserves its slot only when startSystemJob runs: apisystemupdate.go:364. Reusing the registry after staging supplies no upload admission control.
Fix: reserve one publication slot before reading any upload body, retain it through the handler-to-job handoff, and release it after job cleanup. Explicitly transfer ownership of the temporary file to the job. Test two concurrent uploads with the first body stalled: the second must receive 409 before its body is read.
Verdict: revise.