carlos / platform Public

docs: scanner-host README after the review fixes (copy approved by Paul); spec synced

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Paul Campbell pushed by claude agent, operated by paul@keymail.dev f0edf8743310493b8edd4693bd1603e10fa30188 parent 6828110
2 files changed, +9 −5
  • docs/superpowers/specs/2026-10-04-scanner-host-rollout-design.md +6 −2
  • infra/modules/scanner-host/README.md +3 −3

CI passed — run details

diff --git a/docs/superpowers/specs/2026-10-04-scanner-host-rollout-design.md b/docs/superpowers/specs/2026-10-04-scanner-host-rollout-design.md
index 5a2df4cf9..0739dc3fd 100644
--- a/docs/superpowers/specs/2026-10-04-scanner-host-rollout-design.md
+++ b/docs/superpowers/specs/2026-10-04-scanner-host-rollout-design.md
@@ -126,7 +126,11 @@ So clamd itself never listens on TCP. Three units:
`clamd.conf` keys, each rewritten idempotently (clamd has no include
directory):
- - `StreamMaxLength <stream_max_bytes>`.
+ - `StreamMaxLength <stream_max_bytes / 1 MiB>M`. Written in whole MiB, not
+ bytes: Debian's debconf round trip strips an `M` and appends one, so a bare
+ byte count would become a 25 TiB limit on the first configure (final
+ review I1). `clamav-daemon/debconf` is also set false after install, so
+ later upgrades leave `clamd.conf` alone.
- `AlertExceedsMax yes`. With the default `no`, an archive that expands past
`MaxScanSize`, `MaxFileSize`, `MaxFiles` or `MaxRecursion` is partly
scanned and answered `OK`. With `yes` clamd answers
@@ -245,7 +249,7 @@ engine wherever it runs.
| `ami_id` | — | Debian arm64, from `region-host` |
| `client_security_group_id` | — | The console box's group |
| `instance_type` | `t4g.medium` | `t4g.small` only with `concurrent_database_reload = false` |
-| `stream_max_bytes` | `26214400` | Must equal the console's `CARLOS_CLAMD_MAX_BYTES`. Validation: between 8 MiB and 100 MiB, so the self-test's fixtures (about 5 MB compressed) always fit the stream and a whole stream always fits the scan budget **(codex 11)** |
+| `stream_max_bytes` | `26214400` | Must equal the console's `CARLOS_CLAMD_MAX_BYTES`. Validation: a whole number of MiB, between 8 MiB and 100 MiB, so the self-test's fixtures (about 5 MB compressed) always fit the stream and a whole stream always fits the scan budget **(codex 11)** |
| `memory_max` | `"3G"` | clamd's cgroup ceiling |
| `concurrent_database_reload` | `true` | |
| `subnet_id` | `null` | |
diff --git a/infra/modules/scanner-host/README.md b/infra/modules/scanner-host/README.md
index 708b6b094..803fd079f 100644
--- a/infra/modules/scanner-host/README.md
+++ b/infra/modules/scanner-host/README.md
@@ -59,7 +59,7 @@ clamd runs with `MaxFileSize 100M`, `MaxScanSize 100M` and `AlertExceedsMax yes`
That is not enough on its own. ClamAV 1.4.3 trims a zip member that expands past `MaxFileSize`, scans the trimmed copy, and raises no limit. With the two limits equal, the trimmed copy is as large as the whole scan budget, so scanning it always trips `MaxScanSize`, which does alert. The fixtures and expected answers in the self-test are sized for 100 MiB, so changing the limit means deriving both from it.
-Measured on 2026-10-05 against Debian trixie's clamd (ClamAV 1.4.3), with `StreamMaxLength` at 25M and every fixture streamed with `clamdscan --stream`. Each member is a repeating 16 KiB random block, distinct per member, so clamd's clean cache cannot short-circuit it. "Limit" means a `Heuristics.Limits.Exceeded.*` reply.
+Measured on 2026-10-05 against Debian trixie's clamd (ClamAV 1.4.3), with `StreamMaxLength` at 25M and every fixture streamed with `clamdscan --stream`. Each member is a repeating 16 KiB random block, distinct per member, so clamd's clean cache cannot short-circuit it. "Limit" means a `Heuristics.Limits.Exceeded.*` reply. The self-test does not count `Heuristics.Limits.Exceeded.MaxScanTime` as one. That reply is a timeout, not a limit, and it fails the test.
| Fixture | `MaxFileSize 25M`, `MaxScanSize 100M` | Both 100M (this module) | Self-test requires |
|---|---|---|---|
@@ -77,7 +77,7 @@ Measured on 2026-10-05 against Debian trixie's clamd (ClamAV 1.4.3), with `Strea
The first column is what an unequal pair does: three fixtures were signed clean over content nobody read.
-`stream_max_bytes` is the one limit you can change. It is clamd's `StreamMaxLength`, the largest object it accepts on a stream. It defaults to 26214400 (25 MiB) and must be between 8 MiB and 100 MiB. The floor keeps the self-test's fixtures, about 5 MB each, inside the stream. The ceiling keeps a whole stream inside the scan budget. The console's `CARLOS_CLAMD_MAX_BYTES` must equal it. Use the `stream_max_bytes` output rather than typing the number twice.
+`stream_max_bytes` is the one limit you can change. It is clamd's `StreamMaxLength`, the largest object it accepts on a stream. It defaults to 26214400 (25 MiB). It must be a whole number of MiB, between 8 MiB and 100 MiB. The floor keeps the self-test's fixtures, about 5 MB each, inside the stream. The ceiling keeps a whole stream inside the scan budget. The console's `CARLOS_CLAMD_MAX_BYTES` must equal it. Use the `stream_max_bytes` output rather than typing the number twice.
## What a clean verdict does not cover
@@ -94,7 +94,7 @@ systemctl is-active scanner-selftest.service scanner-tcp.socket
journalctl -u scanner-selftest.service --no-pager | tail -14
```
-You should see `status: done`, a ClamAV version line, `active` twice, and then ten `pass` lines and `scanner-selftest: PASS`. The init script also writes each step to the serial console, ending in `SCANNER-HOST READY <version>` or `SCANNER-HOST FAILED: <reason>`. To read it without a session:
+You should see `status: done`, a ClamAV version line, `active` twice, and then ten `pass` lines and `scanner-selftest: PASS`. The init script writes each step to `/var/log/cloud-init-output.log`, and copies it to the serial console when it can, ending in `SCANNER-HOST READY <version>` or `SCANNER-HOST FAILED: <reason>`. To read the console copy without a session:
```sh
aws ec2 get-console-output --instance-id <scanner-instance-id> --latest --output text | grep 'SCANNER-HOST'