fix(followups): F3 - .mam.env BOM, repeated keys and a missing MAM_ENV_FILE

PR #43 review (grok):
(a) A UTF-8 byte-order mark at the start of the file made the first line an
    "invalid key", so its setting was dropped. The one parser (envfile.py,
    used by the wrapper and mqtt_common) now reads with utf-8-sig.
(b) A key given twice keeps its first value (a later line does not replace
    it). The behaviour is unchanged; .mam.env.example's FORMAT section and
    envfile.py's docstring now say so.
(c) MESSAGING.md said a MAM_ENV_FILE naming no file logs an error and makes
    connections fail closed. Both loaders skip it silently and refuse the
    ambient search; a file that exists but cannot be read is the error
    (EnvFileError, one ERROR line and rc 1). The text now says that.

Tests A7: BOM in both loaders, first-value-wins in both loaders plus the
FORMAT text, and a missing explicit file loading neither it nor the ambient
.mam.env without an error plus the MESSAGING text (all three fail at 0051fd6).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HCGpJXhSZasJLU38ksDghe
This commit is contained in:
GodopuandClaude Opus 5.5 committed 2026-10-02 08:10:42 +09:00
1 parent 5edf913d22
commit 71ea8095c5
4 files changed
+52 -3

No files matched your search

+5 -2
View File
@@ -7,7 +7,9 @@ must match ``^[A-Za-z_][A-Za-z0-9_]*$`` and not be one of bash's own variables
(RESERVED); a line that breaks either, or that has no `=`, is skipped with a
warning naming the line (never the value — the file holds secrets). A line
holding a NUL byte is skipped the same way (no environment can carry it).
Variables already in the environment win over the file. A file that exists
A UTF-8 byte-order mark at the start of the file is dropped. Variables
already in the environment win over the file, and a key given twice keeps its
first value. A file that exists
but cannot be read or decoded as a whole is an error (EnvFileError; the
``--shell`` command exits 1), not an empty configuration.
@@ -55,7 +57,8 @@ def parse(path: str) -> Tuple[List[Tuple[str, str]], List[str]]:
pairs: List[Tuple[str, str]] = []
warnings: List[str] = []
try:
with open(path, "r", encoding="utf-8") as f:
# utf-8-sig: a byte-order mark at the start is not part of the first key
with open(path, "r", encoding="utf-8-sig") as f:
lines = f.read().splitlines()
except (OSError, UnicodeDecodeError) as e:
raise EnvFileError(f"{path}: cannot read ({type(e).__name__})") from None