# Review: follow-ups F1–F6 @ 75f364e - Role: Reviewer (grok) - Identity: base `0051fd6c3b088f8b265928ccd94ea31053fdde7e`, head `75f364e4b47d8db95ce2a7e041b69b8e8b473e64`, tree `ec1fdc453ec6fdf2c09165c92a64d54e684f5a3a`, 9 commits, clean worktree - Verified at `/var/folders/q_/68sxgw3j073dgjg8wl9s08vw0000gn/T/mam-review/loop-20261001T230324Z-b511bf/2`. Main stayed at `0051fd6`. No product file was edited. - `git diff --check 95eabc6..HEAD` is clean. That commit is 3 files, +41/−2: `mqtt_common.py`, `MESSAGING.md`, `tests/test_issue26_envfile.py`. `75f364e` is the only change since `95eabc6`. It closes codex F2 R1: a failed env load was cached as loaded. ## F2 review R1 `load_env_or_report` catches `EnvFileError` and returns False (`mqtt_common.py:131-142`). The caller returns 1 and the process keeps running, so a later `ensure_env_loaded` in the same process must try the file again. Previously the flag was set before `_load_dotenv`. The first `registry.main` printed the error and returned 1, and the second skipped the file and registered a job. `ensure_env_loaded` now sets `_env_loaded` only after `_load_dotenv` returns (`mqtt_common.py:122-128`). An `EnvFileError` leaves the flag false. `envfile.parse` reads the whole file before it returns pairs (`envfile.py:59-64`), and `apply` calls `parse` before it writes `os.environ`. A read or decode failure sets nothing, so the retry does not see a half-applied file. `test_a1_a_failed_load_is_not_cached_as_loaded` (`tests/test_issue26_envfile.py:470-488`) runs `registry.main` twice in one process on an undecodable file: both rc 1, the `ERROR: … cannot read (UnicodeDecodeError)` line twice, no job file. It then repairs the file and checks `load_env_or_report` applies `PROBE_CONFIG=from-file`. A later edit of that file is not read again. On `95eabc6` the same probe is rc `[1, 0]` with a job registered and the value unset. The commit message records that run. `MESSAGING.md:369` now says the Python entry points print the one `ERROR` line, and the wrapper prints that line plus `ERROR: cannot load (see the line above)`. That matches the wrapper at `multi-agent-mux-delegate-job:43-44`, where the command substitution captures stdout only. ## F1–F6 otherwise Unchanged since `95eabc6`, and still the behavior the items ask for: - **F1.** `mam_lstart` still collapses spaces (`loop_lock.sh:10-12`). A8 writes the marker with the same collapse and locks a two-space `lstart` through a `ps` shim (`tests/test_issue21_acceptance.py:258-293`). - **F2.** The seven mains still return 1 from `load_env_or_report` without `sys.exit` in the library. The one-line shape is `test_a1_python_entry_points_report_an_unreadable_file_in_one_line`. - **F3.** Leading BOM is `utf-8-sig` (`envfile.py:60-61`). The example states first-wins and the BOM. A missing explicit `MAM_ENV_FILE` is skipped (`mqtt_common.py:51-54`). - **F4.** Runner wait knobs use `_int_knob` / `_positive_int`. The bash knobs that reached `[` or `sleep` use `mam_int_knob` via `lib_int.sh`. `SKS_QUIESCENT_INTERVAL` stays raw because its default is the fraction `0.5` (`test_issue26_ints.py:100-101`). `MAM_WAIT_GRACE_S` is in the loop skill. - **F5.** No `MAM_TEST_` in `stall_watch.py`. S13 sets `agent_status_reliable` false on the adapter and still expects no idle notice, then `stalled:blocked`. - **F6.** The `<= 60 s` sentence is one herdr wait, and the stop test clears the wrapper inside the second `wait_once`. No version bump and no #17 item-4 / #39 / #40 / #42 work in the range. ## Checks From this snapshot, MQTT variables unset, no `.mam.env` exported, control-plane venv, `--basetemp` under `/tmp` and not named `mam-review`: `38 passed in 7.51s` — `tests/test_issue26_envfile.py`, including the new retry test. The other files in the required list are identical to `95eabc6`. On that tree the same list was 301 passed and 1 skipped (the Linux `/proc` stall test), after a rerun of the two tests that reject the substring `mam-review` in the basetemp path. ## Note `reconcile.sh:173` still calls `ensure_env_loaded()` directly. An unreadable file there is still a traceback. F2's list is the seven `main`s. [VERDICT: PASS]