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
Merge-workspace review of PR #43 (codex R1-R4, claude R1/R2).
- R1: envfile.parse raises EnvFileError when the file exists but cannot be
read or decoded as a whole; `--shell` prints the cause and exits 1, so the
wrapper stops (rc 1, as before #26) instead of running on defaults, and
mqtt_common's entry points stop on the same error. A bad single line is
still a warning. The wrapper's message no longer claims a read failure
when the cause is elsewhere ("cannot load ... see the line above").
- R2: lib.sh mam_int spells out the ASCII blanks and digits instead of
[[:space:]]/[0-9], which follow the locale: U+2003 30 U+2003 was 30 in the
wrapper and invalid in the runner under en_US.UTF-8. The test oracle
_expected uses the same ASCII rule.
- R3: an integer flag given explicitly with an empty value is refused like
any other invalid value; only an absent flag keeps its default.
- R4: a line holding a NUL byte is skipped with a warning by both loaders;
before, the wrapper read "leftright" and the Python loader died.
- .mam.env.example states the format: no expansion, `export` and bash's own
variables skipped, a trailing `# ...` is part of the value, the environment
wins, an unreadable file is an error.
Tests: unreadable (0000) and invalid-UTF-8 files stop the wrapper and the
Python loader; a NUL line is skipped by both; Unicode blanks/digits are
invalid for mam_int, _positive_int, the wrapper and the runner under C and
en_US.UTF-8; explicit empty values for the five integer flags are refused.
All of them fail on b58edac.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VCgu9Fa9iT7TbJUSzdq4Ff
- lib_py/delegation/envfile.py (stdlib only) holds the one set of rules:
comments and blank lines skipped, key and value stripped, one matching
quote pair removed, no shell interpretation, keys must match
^[A-Za-z_][A-Za-z0-9_]*$ (bad or `=`-less lines warn with the line
number, never the value).
- mqtt_common._parse_env_file delegates to envfile.apply.
- The delegate-job wrapper runs envfile.py --shell by path and evals the
shlex-quoted exports; values never reach a command line. The environment
now wins over the file in both loaders.
- .mam.env.example: commented assignments no longer use $HOME, which the
parser keeps literally.
The shell parsed the env file in one place only (wrapper :38), not three.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Implement CodexAdapter in lib_py/agents/adapters/codex.py with safe flags and TUI readiness
- Extend create_session, resume_session, stop_session, and reconcile for codex CLI
- Support codex agent delegation and loop integration across all multi-agent skills
- Add unit, component, and contract test suites for codex integration
- Verify all 462 tests passing cleanly
- Define immutable MAM_VERSION="3.1.0" runtime constant in lib.sh
- Bump YAML frontmatter version to 3.1.0 across all 8 skill packages
- Document v3.1.0 changelog, 2-tier TUI readiness architecture, and migration guide in VERSIONS.md
- Document new tuning knobs (MAM_KILL_ON_READY_TIMEOUT, MAM_DIALOG_TAIL_LINES, MAM_READY_EMPTY_GIVEUP) in .mam.env.example
- Add 3-way lockstep and immutability test suite in tests/test_version_consistency.py
- Change N=1->2 split policy from down to right to establish 2 full-height columns
- Share single decision table across GUI and headless modes
- Add _full_height_pane guard to prevent half-height column splits
- Quadruple-wire default max_columns=2 and max_rows=2 across layout.py, lib.sh, and .mam.env.example
- Update unit and integration tests to enforce deterministic 2x2 grid trajectory
- I-2: add 5.0s upper-bound execution time assertion in test_bug4_headless_unobservable_fast_path to contractually guard SKS_EMPTY_GIVEUP early-exit latency
- I-3: clean up PaneInfo.focused, wire MAM_MAX_PANE_COLS/MAM_MAX_COLS environment variables and CLI --max-cols flag
- C-1: apply max_columns growth guard to headless 0x0 layouts, mirroring GUI behavior
- Promoted Planner consensus plan Rev.2 (plan-fea5f1b2.md) and unanimous PASS reports from Reviewers Claude (report-55d1a1d9.md) and Cline (report-6f18ba0f.md)
- Verified all 333 test cases pass with exit code 0