- 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
9.4 KiB
Cross-Code Review — Job 6f18ba0f
- Reviewer: cline (session: herdr:canary-projects-multi-agent-mux-creator-cline)
- Subject: Backlog items I-2 (headless fast-path timing contract) and I-3 (PaneInfo.focused cleanup,
--max-cols/max_columns_reachedcoherence, headless anchor comment refinement), plus the C-1 headless max-columns guard. - Changeset:
git diff—lib_py/layout.py(69 lines),tests/test_layout.py(75 lines, +3 tests),tests/test_b19_headless_reconcile_fixes.py(25 lines),.mam.env.example(14 lines),IMPROVEMENTS.md(3 lines).lib.shis not modified (verified: layout block unchanged at :432). - Date: 2026-08-23
§0 Executive Summary
The changeset cleanly addresses both backlog items and a related headless max-columns defect (C-1). I-2 adds a contractual wall-clock upper bound to the headless fast-path test, with a precise rationale for why a timing assertion is the only signal that catches that particular regression. I-3 removes the unused/non-deterministic PaneInfo.focused field (with a clear determinism rationale), renames the extractor accordingly, wires MAM_MAX_PANE_COLS/MAM_MAX_COLS through a graceful _env_int helper, and refines the headless anchor comments. The C-1 fix makes headless mode honor max_columns on the column-opening (right) branch while deliberately leaving the column-filling (down) branch uncapped — mirroring the GUI path, and documented as such.
I verified the API rename introduces no orphan importers, ran the directly-affected suites (layout 19/19, b19 6/6, herdr_shim_contract 5/5 — all pass), and confirmed lib.sh's layout invocation is untouched. No lint, behavioral, or missing-coverage defects found.
Verdict: PASS.
§1 I-2 — Headless fast-path timing contract (verified)
tests/test_b19_headless_reconcile_fixes.py::test_bug4_headless_unobservable_fast_path:
- Adds
import timeand anelapsed < 5.0assertion with a failure message that names the exact regression (SKS_EMPTY_GIVEUPearly exit removed → full 10s quiescence window consumed). The docstring justifies the bound empirically (1.22s with the optimization vs 10.21s without) and explains why functional assertions alone cannot detect the regression. This is a well-reasoned contractual guard, not a flaky nicety. ✅ - Strips
SKS_QUIESCENT_TRIES/SKS_QUIESCENT_INTERVAL/SKS_EMPTY_GIVEUPfrom the subprocess env so lib.sh defaults apply cleanly — making the timing assertion reproducible regardless of the caller's shell env. ✅ - The mock's
paste-bufferbranch had its earlyreturn 0removed; control now falls through to the finalreturn 0(line 161) with no intervening branch — functionally identical (both return 0), a harmless no-op cleanup. ✅ - Result: 6/6 b19 tests pass in 4.43s; the fast-path test itself runs well under the 5.0s bound (no flakiness margin concern). ✅
§2 I-3 — layout.py cleanup & max-cols coherence (verified)
PaneInfo.focused removal
- The
focused: bool = Falsefield is deleted and replaced with a NOTE comment: the engine is deliberately geometry/structure-driven so identical pane sets yield identical decisions; focus is user-interaction state that would make results non-deterministic. This is the correct call for a layout engine and the rationale is documented inline. ✅ extract_panes_and_focus→extract_panes, now returningList[PaneInfo]only; allfocused_idextraction logic removed. Docstring updated to enumerate the three accepted payload shapes. ✅- Orphan check:
grepforextract_panes_and_focus/PaneInfo/extract_panesimporters across.agentsandtests→ NONE. The remainingfocused_pane_idoccurrences (conftest.py:297/315, test_layout.py:177) are herdr payload data (herdr 0.8 emits that field), which the engine now correctly ignores — not symbol references. No breakage. ✅
--max-cols / max_columns_reached coherence
- New
_env_int(*names)helper reads the first non-empty env var among its arguments, parsing as int and returning None on bad values (a typo won't crash the layout call; lib.sh's|| echo "right …"fallback still applies). Used for--min-cols,--min-rows, and--max-colsdefaults. ✅ --max-colsdefault changed fromNoneto_env_int("MAM_MAX_COLS", "MAM_MAX_PANE_COLS")— so the column cap is honored without a CLI flag, which is exactly howlib.shinvokes the module (it passes no--max-cols). This is the key behavioral fix. ✅- C-1: the headless even-
nbranch now computescurrent_cols = n // 2and returnsoverflow/max_columns_reachedwhencurrent_cols >= max_columns. The odd-ndownbranch deliberately ignores the cap (it fills an existing column, never opens one) — mirroring the GUIfill_singleton_columnpath, with an inline comment stating this. Coherent and symmetric with the GUI path. ✅
Headless anchor comment refinement
- The terse alternation comment was replaced with a detailed explanation of why
n // 2is the completed-column count under the alternation invariant, and how an odd-ndrift self-corrects at the next evenn. Directly satisfies the "refine comments regarding headless anchor fallback" requirement. ✅
lib.sh (I-3 scope)
lib.shis unmodified in this changeset (diff stat confirms;python3 -m lib_py.layoutstill at :432). The lib.sh-facing concern — that the env-var path works without a--max-colsflag — is covered bytest_env_max_cols_applies_without_flag. No lib.sh edit is needed. ✅
§3 Test Coverage & DoD
New layout tests (tests/test_layout.py, +3, total 19, all PASS in 0.21s):
test_cli_max_cols_flag_triggers_overflow— CLI--max-cols 2reachescompute_2xk_layoutand yieldsoverflow/max_columns_reachedon a 4-pane/2-column payload. ✅test_env_max_cols_applies_without_flag—MAM_MAX_PANE_COLS=2is honoured with no--max-colsflag (the lib.sh invocation shape); assertsmax_columns_reached. ✅test_headless_max_columns_growth_guard— C-1: headless n=4/max=2 →overflow; n=2/max=2 →right(grows below cap); n=3/max=2 →down(fill not blocked); n=4 no cap →right(behavior neutrality). Comprehensive. ✅
b19 suite (tests/test_b19_headless_reconcile_fixes.py, 6/6 PASS in 4.43s) — I-2 timing contract holds.
Shim contract (tests/test_herdr_shim_contract.py, 5/5 PASS in 1.77s) — integration intact after the API rename.
Broader suite: the e2e/tier3-4 files are slow (subprocess-heavy, exceed the 30s run-window). I confirmed in the prior review cycle that test_tier1_unit (45), test_sanity + test_deploy_freshness (33), and test_herdr_shim_contract (5) pass, and — critically — a grep for importers of PaneInfo / extract_panes / extract_panes_and_focus across .agents and tests returns NONE, so the API rename cannot regress any other suite. No regression risk from this changeset's surface change.
Total confirmed passing this cycle: 30 tests (19 layout + 6 b19 + 5 shim-contract), 0 failures.
§4 Soundness & Cleanup
- No orphan references: removed/renamed symbols have zero importers; remaining
focused_pane_idstrings are payload data, correctly ignored. lib.shuntouched: the prior G-1 fix (python3 -m lib_py.layoutat :432) is preserved; no regression to the integration.- Env wiring documented:
.mam.env.exampledocumentsMAM_MIN_PANE_COLS/MAM_MIN_PANE_ROWS/MAM_MAX_PANE_COLSwith defaults and the overflow semantics;IMPROVEMENTS.mdrecords I-2/I-3/C-1 completion and updated test counts. - Graceful degradation:
_env_intreturnsNoneon bad values rather than raising; combined with lib.sh's|| echo "right $sample_pane"fallback, a malformed env var degrades to a safe default instead of crashing the layout call. Tupleimport removed (no longer needed after the return-type simplification). No unused imports remain.
§5 Minor Observations (non-blocking)
_env_intbehavior change for min-cols/min-rows on bad env values: previouslyint(bad_value)would raise (crash → lib.sh fallback toright); now it returnsNone→ falls back to the 60/20 default. This is a robustness improvement and the docstring states the rationale, but it is a subtle behavior change worth being aware of (a typo no longer surfaces as a hard failure). Acceptable and intentional.- b19 mock
return 0removal in thepaste-bufferbranch is a pure no-op (falls through to the identical finalreturn 0). Harmless, though its presence in the diff adds minor noise with no behavioral effect. Cosmetic. - Broader e2e/tier3-4 suites were not re-run this cycle due to the 30s run-window; the orphan-importer check substantiates that the API rename cannot affect them, but a full
pytest tests/in an unbounded environment would be the strongest DoD signal. Not a blocker.
None of the above warrant a NOT PASS or a planner escalation. They are notes for future polish only.
§6 Verdict
Both backlog items (I-2, I-3) and the related C-1 headless max-columns defect are correctly and coherently addressed. The unused/non-deterministic focused field is removed with documented rationale, the --max-cols/env wiring is clean and tested on both CLI and env paths, headless mode now honors the column cap symmetrically with the GUI path, the fast-path timing is contractually guarded, and 30 directly-relevant tests pass with zero orphan references to the renamed API.
[VERDICT: PASS]