Files
multi-agent-mux/.agents/reports/canary-projects-multi-agent-mux-creator-cline/report-93a74271.md
T

13 KiB

Cross-Code Review Report — Job 93a74271

Job ID: 93a74271 Reviewer: cline Date: 2026-08-23 Scope: Track 1R — Docker deployment assets for nats-server on a remote server Changeset: 5 new files (docker/ directory + requirements.txt) + 3 modified files (PRIVATE_SERVER.md, implementation_plan.md, tests/test_deploy_freshness.py)


1. Executive Summary

This review covers the creation of production-ready Docker deployment assets in the docker/ directory (docker-compose.yaml, nats.conf, .env.example, README.md) and the addition of 9 regression guards (D-22 ~ D-30) in tests/test_deploy_freshness.py, along with documentation updates to PRIVATE_SERVER.md and implementation_plan.md.

Verdict: PASS. All 5 task objectives are met. The Docker assets are correct, internally consistent, and match the canonical documentation. All 306 tests collect; the 29 deploy-freshness guards (including 9 new) pass, and the fast subset (sanity + tier1_unit, 47 tests) shows no regressions. Findings are limited to documentation consistency issues that do not affect the functionality or security of the deployment assets.


2. Task Objective Verification

2.1 docker/docker-compose.yaml — PASS

Requirement Status Evidence
nats:2.12-alpine service PASS Line 9: image: nats:2.12-alpine
MQTT 1883 PASS Line 22: "${MQTT_BIND:-127.0.0.1}:1883:1883"
NATS 4222 PASS Line 23: "${NATS_BIND:-127.0.0.1}:4222:4222"
WS 8080 PASS Line 25: "${WS_BIND:-127.0.0.1}:8080:8080"
HTTP monitor 8222 (loopback only) PASS Line 24: "127.0.0.1:8222:8222" (hardcoded)
JetStream volume /data PASS Line 28: nats-data:/data
Healthcheck PASS Lines 29-34: wget to /healthz on 127.0.0.1:8222
Fail-closed secrets PASS Lines 15-18: ${VAR:?error} syntax for all 4 secrets
Log rotation PASS Lines 35-37: json-file, 10m max-size, 3 max-file

Note: The previous review (job e1c4e9c3) flagged M-1 (Medium): compose omitted NATS 4222 port. This is now fixed${NATS_BIND:-127.0.0.1}:4222:4222 is present in both docker/docker-compose.yaml and the PRIVATE_SERVER.md code fence.

2.2 docker/nats.conf — PASS

Requirement Status Evidence
MQTT block PASS Lines 23-27: port: 1883, ack_wait: 60s, max_ack_pending: 1024
JetStream block PASS Lines 15-19: store_dir: "/data", max_file: 10G, max_mem: 256M
Multi-tenant accounts (MAM with mam/observer) PASS Lines 55-70: MAM account with mam_agent + mam_observer (sub-only, pub denied)
HOME account PASS Line 72: HOME: { jetstream: enabled, users: [...] }
SYS account PASS Line 73: SYS: { users: [...] }
system_account: SYS PASS Line 75
WebSocket block PASS Lines 29-52: port: 8080, no_tls: true, origin policy, /mqtt path docs
No hardcoded secrets PASS All passwords are $VAR references; D-25 guard verifies

2.3 docker/.env.example — PASS

Requirement Status Evidence
Fail-closed security PASS All 4 secrets have empty values (lines 22, 25, 28, 31)
Variable definitions PASS Each secret has a comment explaining purpose and generation method
Bind address variables PASS Lines 37-47: MQTT_BIND, NATS_BIND, WS_BIND (commented, default 127.0.0.1)
8222 not variable-ized PASS Line 47: explicit note that HTTP monitor is loopback-fixed
Git tracking PASS .gitignore line 23 !.env.example exempts it; D-29 guard verifies

2.4 docker/README.md — PASS (with findings — see section 3)

Requirement Status Evidence
Step-by-step deployment PASS Section 3: 5-step quick deploy guide
Verification instructions PASS Section 5: R-3 port scan; Section 7: R-1~R-10 playbook
Network/firewall guidance PASS Section 4: UFW rules with Docker bypass warning
Client connection guide PASS Section 6: MAM .mam.env config + MQTT.js dashboard recipe
Operations/maintenance PASS Section 8: logs, backup, upgrade, monitoring
Troubleshooting PASS Section 9: 10-row troubleshooting table

2.5 tests/test_deploy_freshness.py — PASS

9 new guards added (D-22 ~ D-30), all passing:

Guard What it checks Result
D-22 docker/ assets exist and are populated PASS
D-23 compose image matches doc and is alpine PASS
D-24 compose port exposure contract (4 ports, 8222 loopback) PASS
D-25 secrets are fail-closed (${VAR:?} syntax, empty .env.example, $VAR in nats.conf) PASS
D-26 nats.conf jetstream/mqtt contract (store_dir /data, max_file/max_mem, mqtt 1883, MAM jetstream) PASS
D-27 observer permissions match mqtt_common.DEFAULT_TOPIC_ROOT (python.mqtt.jobs) PASS
D-28 healthcheck contract (wget, /healthz, 127.0.0.1:8222) and alpine coupling PASS
D-29 env secrets never tracked (.env ignored, .env.example not ignored) PASS
D-30 websocket origin policy startable (no_tls: true, no *, /mqtt documented) PASS

D-16 guard change: Assertion tightened from "-alpine" in tag or tag.startswith("2.") to "alpine" in tag. Correct — healthcheck requires wget only in alpine. All nats: references in PRIVATE_SERVER.md use nats:2.12-alpine; no breakage.

Test count: 306 collected (was 297), matching implementation_plan.md claim "297 to 306".


3. Findings

M-1 (Medium) — R-1R-10 ID collision between PRIVATE_SERVER.md section 9.4 and docker/README.md section 7; R-11R-13 undefined

Category: Documentation consistency / Loss

The R-1~R-10 verification playbook IDs have different meanings in PRIVATE_SERVER.md section 9.4 and docker/README.md section 7. Key collisions:

R-ID PRIVATE_SERVER.md section 9.4 docker/README.md section 7
R-2 Listener + TLS identity External monitoring blocked
R-4 Round-trip pub/sub + JetStream WAN latency
R-5 Retained terminal event (MQTT) Auth rejection (unauthorized)
R-6 Broker identity assertion Auth success (normal)
R-7 Freeze regression (H-1/H-4) Retained event delivery
R-8 Full regression suite Broker identity verification

Only R-1 (health), R-3 (port exposure), R-9 (tenant isolation), and R-10 (retained boundary) share the same concept.

Additionally, implementation_plan.md (lines 122, 182) references "R-1 ~ R-13" with "R-5(retained) / R-9(account boundary) / R-13(MQTT-over-WS)" as final gates. However:

  • R-11, R-12, R-13 are never defined in either PRIVATE_SERVER.md section 9.4 or docker/README.md section 7.
  • The "R-5(retained)" reference matches PRIVATE_SERVER.md's R-5, but not docker/README.md's R-5 (auth rejection).
  • PRIVATE_SERVER.md section 9.5 cutover procedure still says "R-1 ~ R-10" (not R-1~R-13).

Impact: An operator following docker/README.md who is told to verify "R-5(retained)" would check auth rejection instead of retained event delivery. The undefined R-11~R-13 create ambiguity about what constitutes the final acceptance gate.

Fix: Either (a) align the README's R-IDs with PRIVATE_SERVER.md section 9.4 (use different ID ranges like RR-1RR-10 for the README's deployment-focused checks), or (b) define R-11R-13 in both documents and update section 9.5 to reference R-1~R-13.

L-1 (Low) — docker/README.md section 7 R-4 references non-existent latency_check.py

Category: Operability / Loss

docker/README.md section 7 R-4 states: python latency_check.py with expected result "RTT P95 < 150ms". No such file exists in the repository. PRIVATE_SERVER.md section 9.4 defines the latency probe as an inline Python heredoc (not a standalone script). An operator following the README would get a "file not found" error.

Fix: Either (a) replace python latency_check.py with the inline heredoc from PRIVATE_SERVER.md section 9.4, or (b) create docker/latency_check.py as a standalone script, or (c) reference the PRIVATE_SERVER.md section 9.4 latency probe section.

L-2 (Low) — docker/README.md section 4 UFW rules more permissive than PRIVATE_SERVER.md section 9.3

Category: Documentation consistency

docker/README.md section 4 uses sudo ufw allow in on tailscale0 to any (allows all ports on the tailnet interface), while PRIVATE_SERVER.md section 9.3 uses granular per-port rules (port 1883, port 4222, port 8080). Both are valid for a trusted tailnet, but the README's approach is less defense-in-depth. The README also omits the 4222 UFW rule that PRIVATE_SERVER.md section 9.3 includes.

Fix: Align the README's UFW rules with PRIVATE_SERVER.md section 9.3's per-port approach, or add a note explaining the intentional difference.

V-1 (Very Low) — implementation_plan.md P0.5 step indentation

Category: Cosmetic

The new P0.5 step in the roadmap diagram uses slightly different indentation alignment than the surrounding steps. Purely cosmetic; does not affect readability of the plan.


4. Cross-Reference Verification

4.1 docker/ files vs PRIVATE_SERVER.md code fences

File Method Result
docker/nats.conf vs PRIVATE_SERVER.md section 9.1 code fence Programmatic byte-level comparison EXACT MATCH
docker/docker-compose.yaml vs PRIVATE_SERVER.md section 9.2 code fence Programmatic byte-level comparison EXACT MATCH

The D-22~D-30 guards provide structural verification but not a full byte-level diff. The manual programmatic comparison confirms zero drift between the canonical files and the documentation code fences.

4.2 Topic root consistency

mqtt_common.DEFAULT_TOPIC_ROOT = "python/mqtt/jobs" -> dotted form = "python.mqtt.jobs". docker/nats.conf observer subscribe: { allow: ["python.mqtt.jobs.>"] } — matches. D-27 guard verifies this programmatically.

4.3 .gitignore verification

  • docker/.env -> ignored by .gitignore line 21 (.env pattern). D-29 guard passes.
  • docker/.env.example -> not ignored (.gitignore line 23 !.env.example overrides line 22 .env.*). D-29 guard passes.
  • .env.example lines 4-5 reference .gitignore:23 and .gitignore:21 — line numbers verified correct.

4.4 Previous review findings (job e1c4e9c3) — resolution status

Previous Finding Status Evidence
M-1: section 9.2 compose omits NATS 4222 port FIXED Both docker/docker-compose.yaml and PRIVATE_SERVER.md section 9.2 include ${NATS_BIND:-127.0.0.1}:4222:4222
V-2: Unchecked M2b guard checkbox FIXED implementation_plan.md line 180: - [x] for guards G-D5~G-D9, G-R1, G-R2 (290 to 297)
L-1/L-2 (lib.sh latency, handle_startup_dialogs timeout) Out of scope Not part of this changeset
L-3 (D-19 regex scans full markdown) Still present D-19 unchanged; not part of this changeset

5. Test Results

Suite Tests Result
tests/test_deploy_freshness.py (full) 29 29 passed (12.16s)
tests/test_sanity.py + tests/test_tier1_unit.py 47 47 passed (16.99s)
Full collection 306 306 collected (0.04s) — matches implementation_plan.md "297 to 306"
Full suite (tests/) 306 Not completed (integration/e2e tests with MQTT exceed 30s timeout; not affected by this changeset)

No regressions detected in the fast subset. The D-16 guard tightening is validated by all 29 deploy-freshness tests passing.


6. Security Review

Check Status
No hardcoded secrets in any file PASS — All passwords are $VAR references; D-25 guard verifies
Fail-closed on missing secrets PASS — ${VAR:?error} compose syntax; empty .env.example values
8222 (HTTP monitor) loopback-only PASS — Hardcoded 127.0.0.1:8222:8222, not variable-ized
Default bind addresses are loopback PASS — ${MQTT_BIND:-127.0.0.1}, ${NATS_BIND:-127.0.0.1}, ${WS_BIND:-127.0.0.1}
.env never tracked in git PASS — .gitignore + D-29 guard
WebSocket no_tls: true explicit PASS — Prevents startup failure from implicit TLS requirement
No * in allowed_origins PASS — D-30 guard verifies; comment explains NATS rejects *
Observer publish denied PASS — publish: { deny: [">"] } in nats.conf; D-27 guard verifies

7. Conclusion

The implementation fully satisfies all 5 task objectives. The Docker deployment assets are production-ready, internally consistent, and match the canonical documentation byte-for-byte. The 9 new regression guards (D-22~D-30) provide comprehensive structural verification of the deployment contract. The previous review's M-1 finding (missing 4222 port) is resolved.

The findings (1 Medium, 2 Low, 1 Very Low) are all documentation consistency issues that do not affect the functionality or security of the deployment assets. They can be addressed with minor documentation edits without rework.

[VERDICT: PASS]