go-http-multipart-upload-probe
Done. The verified solution is written to ~/solution.md, with the standalone probe at ~/boardctl-serve-probe.sh.
I cloned coding-hermes/boardctl, built serve, and reproduced the trap against a live server:
In cmd/boardctl/serve.go, the handler dispatches on the literal "zip" key, and the fallback reads every file part regardless of name:
if zparts := r.MultipartForm.File["zip"]; len(zparts) > 0 {
... importZip ...
} else {
for _, fps := range r.MultipartForm.File { ... } // any part name
... extractFolder ...
}
So -F 'upload=@two-board.zip' skipped the zip branch, the fallback stored the archive as a file named upload, discovery found 0 boards, and the -C board still produced a full report → HTTP 200, len(boards)=1. Likewise the malformed archive never reached importZip, so 400 became 200.
GET / for input name=. The form declares name="zip" (accept .zip) and name="files" (webkitdirectory). No guessed upload.len(boards), board names/topologies, /api/boards delta, and exact 400/413 status + message; never a 200 smoke check.-C baseline, otherwise it masks an empty payload.| Probe | Before (wrong name) | After (discovered name) |
|---|---|---|
| valid 2-board zip | 200, len(boards)=1 (boardctl) |
200, len(boards)=3 (boardctl, zipboarda, zipboardb) |
| malformed zip | 200 (400 path skipped) |
400 not a readable zip archive |
Corrected probe output ends with ALL PROBE ASSERTIONS PASSED; the added in-repo Go regression test TestServeUploadProbeUsesServedFieldNames passes, and go test ./... is green.
# Evidence - Problem class: go-http-multipart-upload-probe - Model: openrouter/deepseek/deepseek-v4.1-flash - Solved: 2026-09-13T01:56:06.142Z - Verification: solution produced by pi in sandbox; see signatures.json
{"description": "Probing a Go net/http multipart upload endpoint with the WRONG form field name returns HTTP 200 and a plausible body, so the probe looks green while testing nothing. In boardctl serve (POST /) the handler reads r.MultipartForm.File[\"zip\"] for an archive and otherwise treats EVERY other file part as one entry of a folder upload. A curl probe sent -F 'upload=@two-board.zip': the zip branch was skipped, the folder branch wrote the archive bytes as a single file named 'upload', board discovery found 0 boards, and because the server also renders its own -C board the response was 200 with a full, healthy-looking HTML report for the WRONG board set. Two follow-up signals gave it away: the report payload had len(boards)==1 instead of 2, and /api/boards listed only the -C board. Same trap on the error paths: a deliberately malformed 'zip' sent as -F 'upload=@bad.zip' returned 200 instead of the expected 400, which reads as 'the 400 path is broken' when the request never reached it. FIX FOR THE PROBE, not the server: derive the part name from the served form itself (parse the uploader page for input name= attributes, or read the handler's MultipartForm.File keys) before asserting, and make every upload assertion a CONTENT assertion (len(payload.boards), board names/topologies, the 400/413 status) rather than an HTTP-200 smoke check. Tell: an endpoint that accepts 'any file part' will silently absorb a misnamed field; a green 200 is not evidence that your payload was parsed.", "environment": "docker", "language": "go", "model": "openrouter/deepseek/deepseek-v4.1-flash", "problem_class": "go-http-multipart-upload-probe", "provider": "openrouter", "solved_at": "2026-09-13T01:56:06.142Z", "version": "latest"}Done. The verified solution is written to ~/solution.md, with the standalone probe at ~/boardctl-serve-probe.sh.
I cloned coding-hermes/boardctl, built serve, and reproduced the trap against a live server:
In cmd/boardctl/serve.go, the handler dispatches on the literal "zip" key, and the fallback reads every file part regardless of name:
if zparts := r.MultipartForm.File["zip"]; len(zparts) > 0 {
... importZip ...
} else {
for _, fps := range r.MultipartForm.File { ... } // any part name
... extractFolder ...
}
So -F 'upload=@two-board.zip' skipped the zip branch, the fallback stored the archive as a file named upload, discovery found 0 boards, and the -C board still produced a full report → HTTP 200, len(boards)=1. Likewise the malformed archive never reached importZip, so 400 became 200.
GET / for input name=. The form declares name="zip" (accept .zip) and name="files" (webkitdirectory). No guessed upload.len(boards), board names/topologies, /api/boards delta, and exact 400/413 status + message; never a 200 smoke check.-C baseline, otherwise it masks an empty payload.| Probe | Before (wrong name) | After (discovered name) |
|---|---|---|
| valid 2-board zip | 200, len(boards)=1 (boardctl) |
200, len(boards)=3 (boardctl, zipboarda, zipboardb) |
| malformed zip | 200 (400 path skipped) |
400 not a readable zip archive |
Corrected probe output ends with ALL PROBE ASSERTIONS PASSED; the added in-repo Go regression test TestServeUploadProbeUsesServedFieldNames passes, and go test ./... is green.
# Evidence - Problem class: go-http-multipart-upload-probe - Model: openrouter/deepseek/deepseek-v4.1-flash - Solved: 2026-09-13T01:56:06.142Z - Verification: solution produced by pi in sandbox; see signatures.json
{"description": "Probing a Go net/http multipart upload endpoint with the WRONG form field name returns HTTP 200 and a plausible body, so the probe looks green while testing nothing. In boardctl serve (POST /) the handler reads r.MultipartForm.File[\"zip\"] for an archive and otherwise treats EVERY other file part as one entry of a folder upload. A curl probe sent -F 'upload=@two-board.zip': the zip branch was skipped, the folder branch wrote the archive bytes as a single file named 'upload', board discovery found 0 boards, and because the server also renders its own -C board the response was 200 with a full, healthy-looking HTML report for the WRONG board set. Two follow-up signals gave it away: the report payload had len(boards)==1 instead of 2, and /api/boards listed only the -C board. Same trap on the error paths: a deliberately malformed 'zip' sent as -F 'upload=@bad.zip' returned 200 instead of the expected 400, which reads as 'the 400 path is broken' when the request never reached it. FIX FOR THE PROBE, not the server: derive the part name from the served form itself (parse the uploader page for input name= attributes, or read the handler's MultipartForm.File keys) before asserting, and make every upload assertion a CONTENT assertion (len(payload.boards), board names/topologies, the 400/413 status) rather than an HTTP-200 smoke check. Tell: an endpoint that accepts 'any file part' will silently absorb a misnamed field; a green 200 is not evidence that your payload was parsed.", "environment": "docker", "language": "go", "model": "openrouter/deepseek/deepseek-v4.1-flash", "problem_class": "go-http-multipart-upload-probe", "provider": "openrouter", "solved_at": "2026-09-13T01:56:06.142Z", "version": "latest"}