1
0

cap-decompressed-project-size.md 3.1 KB

Cap decompressed project size

Branch: limit-decompression → main

PR 2 of the review fixes plan (docs/review-fixes-plan.md). Part of 0.5.2; the version does not change in this PR.

What changed

Projects over 256 MB decompressed are refused (S2). xpj.Read used to read the whole gzip stream into memory, however large it was. In the review, a 1 MB file padded with spaces used 3.1 GB and took 10 seconds. Read now reads through io.LimitReader and stops one byte past the new xpj.MaxDecompressed, 256 MB. Past that, it returns xpj: project is larger than 256 MB when decompressed. A comment on the constant gives the reason.

The limit is 256 MB, not the plan's 512 MB (bajdev, 2026-11-12, during this PR). The limit counts only the project file once it is unpacked: the pads, the pool's list of file names and the sequences with their events. WAV files are separate files in the data folder and are not read through xpj.

  • A blank project is about 3 MB, almost all of it the 128 empty pad definitions.
  • Each recorded event takes about 480 bytes, and an empty sequence about 12 KB.
  • So 256 MB holds about half a million events, around 4,000 for each of 128 sequences. DemoFile has 225 events in total.

The Decisions table and PR 2's tasks in docs/review-fixes-plan.md now say 256 MB.

Test. TestDecompressionLimit builds its gzip streams in memory with gzip.NewWriter; nothing new is committed:

  • A minimal project padded with spaces to one byte over the limit is refused with that exact error.
  • The same project padded to exactly the limit still decodes.
  • Against the old Read, the over-limit case loads without error, so the test fails.
  • It takes about 3 seconds, and go test -short skips it.

Notes

Memory near the limit, as measured on the server:

  • A file padded to 3.1 GB (6 MB compressed) is now refused after 0.3 seconds, at a peak of about 600 MB. The buffer io.ReadAll grows can pass the limit before the check runs.
  • A file exactly at the limit still loads, at a peak of about 925 MB, because the JSON decoder keeps its own copy of the padding.
  • At 512 MB, these were about 1.3 GB and 2.3 GB.

The test needs memory: about 860 MB while it runs. go test -short ./... skips it.

Testing

On the server:

  • go test ./... passes, including the round-trip tests, unchanged.
  • go vet ./... and staticcheck ./... are clean.
  • govulncheck ./... reports only GO-2026-6859 in net/http, which waits for Go 1.27.4 in PR 4.
  • npm install, npm run check (0 errors, 0 warnings) and npm run build pass. The lockfile npm install wrote was not committed.
  • wails3 build builds, and timeout 15 xvfb-run -a bin/mpckit starts and runs. The log holds only the usual headless GTK warnings.

On the laptop (PowerShell, in the repo):

  1. git fetch; git checkout limit-decompression
  2. go test -run TestDecompressionLimit -v ./internal/xpj: PASS, in a few seconds. It uses about 900 MB of memory.
  3. go test ./...: all ok.
  4. wails3 dev: load testdata\device\DemoFile.xpj and testdata\accepted\MpckitT1.xpj. Both open as before.