Skip to content

M1-73 Compose smoke test

No Date Ruling Reason
M1-73/1 2026-10-19 The task names the branch and the base: feat/M1-73-compose-smoke from int/m1-wave46; the work is not merged locally (the brief's Definition of done says so), the launcher integrates it. No contract commit is brought in: every operation, schema and gateway op the brief names is on the base already. The task overrides the brief where both name a branch or a merge.
M1-73/2 2026-10-19 Design note D1: the probe runs with network_mode: service:api and dials 127.0.0.1:8080; api listens on 127.0.0.1:8080 and publishes no port; server.trusted_proxies keeps the installation's loopback default. Through a published port the server sees the bridge gateway, which SEC-TLS-1 rejects for plaintext; widening the trusted proxies would weaken the rule under test (P-10, 16 4.1).
M1-73/3 2026-10-19 Design note D2: the overlay drops only BOTHY_FILE__SCAN__CLAMD_ADDRESS (file.scan.clamd_address, planned for M3) from x-server-env. bothy config check of the M1 image with the installation values reports only this key as unknown; the other BOTHY_FILE__* keys (file.storage.driver, file.fs.root, file.s3.*) are active and stay. No other value is changed. The brief expected every BOTHY_FILE__* key; the server is the authority, and D2 allows removals of rejected keys only.
M1-73/4 2026-10-19 Design note D4: the collector overlay file lives in infra/compose/test/otel/ with tail_sampling.decision_wait and batch.timeout of 1 s and flush_interval 1 s; BOTHY_TRACE_SAMPLE_PERCENT=100. The collector keeps the image's user; the one-shot otel-out-init (the pinned PostgreSQL image, root, no network) makes the export volume writable. tools/opscheck validates the overlay with the base alone and reads it in collector-allowlist and the provider rule. Every trace of the run must be exported and the wait after the flush must stay short; running the collector as root could hide a permission defect of its secrets.
M1-73/5 2026-10-19 Design note D6: the scan first finds the run canary in a built-in control text (positive control) and fails afterwards unless the export holds a span with http.route /api/v1/threads/{thread_id}/messages, a log record and a metric data point of service.name bothy-server; SMOKE_TELEMETRY_SETTLE_S defaults to 5 s, at least the 3 s of decision_wait + batch.timeout + flush_interval (test_settle_covers_collector_waits). The enrollment code is scanned in its display and its canonical form. A passing scan must prove something: a broken scanner or an empty export cannot pass.
M1-73/6 2026-10-19 Design note D7: the probe image is the target smoke of services/server/Dockerfile (stage smoke-build from the builder stage, stage smoke on the same distroless reference as production, user 65532); the production stage is unchanged and last. The build context of smoke-probe is the repository root with dockerfile: services/server/Dockerfile, not ../../services/server as the brief writes, and smoke.sh passes the build argument VERSION from services/server/VERSION. Dockerfile.dockerignore re-includes only services/server/test/smoke/ (its _test.go files stay out). The Dockerfile copies services/server/... paths from the root context, and the builder stage refuses a build without VERSION; reusing it keeps one pin.
M1-73/7 2026-10-19 GatewayHTU and RESTHTU follow the server (M1-33): the gateway htu is https://<host of server.public_url>/api/v1/gateway, http on port 80 loses the port, a path of the public URL does not count; the REST htu is scheme and host of the public URL plus the request path. The server checks the proof against exactly this form; the brief asks to follow the documented rule.
M1-73/8 2026-10-19 The probe command reads SMOKE_PUBLIC_URL and SMOKE_CANARY with os.Getenv under a nolint:forbidigo with its reason; the lint configuration is unchanged. The rule keeps server modules on platform/config; the probe is a separate test binary whose only inputs from Compose are these two values, as the brief prescribes.
M1-73/9 2026-10-19 smoke.sh creates its workspace with mktemp -d "${TMPDIR:-/tmp}/bothy-smoke.XXXXXXXX" and removes only that directory; TMPDIR must be shared with the Docker VM (documented in infra/compose/test/README.md). The probe and the scanner use bind mounts below it; colima shares only the home directory by default.
M1-73/10 2026-10-21 Port to main: the ticket's own commits as one change on main, with the English text of main kept where both sides changed a document. On the integration line the smoke stages followed the console stage of M6-02, which main does not have yet; on main they follow the builder stage, and Dockerfile.dockerignore re-includes only the probe sources. Only the ticket's own change lands; the smoke stages do not depend on the console stage.
M1-73/11 2026-10-21 TestBlackBoxImports allows the own dependencies of the generated client api/rest; the probe's direct imports stay limited to api/rest and github.com/coder/websocket. On main the generated client carries convert.go with the value type internal/kernel/ids (M1-56), so the probe reaches it only through api/rest; no server logic enters the probe.
M1-73/12 2026-10-21 test_server_readme_names_the_pinned_base_images counts the distinct pinned images of services/server/Dockerfile, not its pinned FROM lines. The stage smoke reuses the distroless reference of the production stage, so two images stand in three lines; the README still has to name both.