9.0 KiB
Cross-Code Review Report: B-8 send_keys_safe agy Path Bypass Removal
Job ID: d629619a
Reviewer: cline (session: herdr:canary-projects-multi-agent-mux-creator-cline)
Review Target: B-8 send_keys_safe agy unconditional return 0 bypass removal and verification integrity cross-check
Base Commit: f8bfa07 (clean tree except working changes)
Date: 2026-08-13
1. Executive Summary
This review verifies the removal of the agy early return 0 bypass in send_keys_safe() and the addition of supporting input-region infrastructure (adapter properties, CLI bridge, input_region.py module). The change set includes 5 modified files and 2 new files.
Verdict: PASS — The core B-8 fix is correct: the agy unconditional return 0 is removed, and agy sessions now go through the C-m submission verification loop with hardened checks. The test confirms returncode 4 on submission failure (not 0). However, the supporting input_region.py module has a missing base.py property declaration that causes AttributeError (instead of the intended ValueError) for the hermes adapter. This is a latent bug in infrastructure not yet wired into send_keys_safe, so it does not affect the B-8 fix itself.
2. Change Set
| File | Change | Lines |
|---|---|---|
.agents/skills/lib.sh |
Remove agy early return 0; add agy to skip-paste-check group | -6/+2 |
.agents/skills/lib_py/agents/__main__.py |
Add input-region CLI command + emit INPUT_* facts |
+15 |
.agents/skills/lib_py/agents/adapters/agy.py |
Add input_prompt/placeholder/rule_pattern | +12 |
.agents/skills/lib_py/agents/adapters/claude.py |
Add input_prompt/placeholder/rule_pattern | +12 |
.agents/skills/lib_py/agents/adapters/cline.py |
Add input_prompt/placeholder/rule_pattern | +12 |
.agents/skills/lib_py/agents/input_region.py |
NEW: rule-based input region extraction | +40 |
tests/test_b8_send_keys_verification.py |
NEW: bash mock test for agy submission failure | +29 |
3. Core B-8 Fix Analysis (lib.sh)
Before (lines 1587-1591, removed):
if [[ "$sess" =~ "agy" ]]; then
_sks_herdr send-keys -t "$sess" C-m
return 0
fi
This was the B-8 bug: agy sessions blindly returned 0 (success) after sending C-m, without verifying submission.
After (line 1588):
if [[ "$sess" =~ "cline" ]] || [[ "$sess" =~ "claude" ]] || [[ "$sess" =~ "agy" ]]; then
# Skip strict paste check due to scrollout false-positives, proceed to C-m submission loop
true
agy is now grouped with cline/claude: paste visibility check is skipped (due to scrollout false-positives), but the session goes through the full C-m submission verification loop (lines 1607-1626). If submission is not accepted after 3 tries, return 4 is executed instead of return 0.
Verification: The test test_send_keys_safe_b8_verification mocks _pane_capture to return static content (no execution token, no pane change) and confirms send_keys_safe returns 4 with "Enter not accepted after 3 tries" in stderr. ✅
4. Supporting Infrastructure Analysis
4.1 Adapter Properties (agy.py, claude.py, cline.py)
Each adapter now defines input_prompt, input_placeholder, and input_rule_pattern:
| Adapter | input_prompt | input_placeholder | input_rule_pattern |
|---|---|---|---|
| agy | > |
`` | ─{10,} |
| claude | ❯ |
`` | ─{10,} |
| cline | ❯ |
Ask anything... |
─{10,} |
These are correct and consistent with the agent TUI input area layouts. ✅
4.2 CLI Bridge (__main__.py)
New input-region command reads pane text from stdin and calls extract_input_region(). On success, prints region and exits 0. On exception, prints error to stderr and exits 5.
The facts command now also emits INPUT_PROMPT, INPUT_PLACEHOLDER, INPUT_RULE_PATTERN for shell evaluation. ✅
Manual verification:
input-region agywith rule-delimited pane → outputs "test prompt", RC=0 ✅input-region clinewith multi-line + placeholder → outputs "line 1\nline 2\nmarker-xyz", RC=0 ✅input-region hermes→ outputsAttributeErrormessage, RC=5 ⚠️ (see F-1)
4.3 input_region.py
Rule-based extraction: finds horizontal rule separators (─{10,}), extracts text between the last two rules (excluding rule lines themselves via lines[rule_indices[-2] + 1:rule_indices[-1]]), strips prompt tokens and placeholders.
Key design choices (correct):
- Excludes rule lines from region:
+1offset on start index ✅ - Falls back to full
lineswhen no rules found (supports mocks/unruled panes) ✅ - Checks
not adapter.input_promptfor unsupported agent detection ✅ - Uses
adapter.input_rule_pattern or r'─{10,}'fallback ✅
4.4 Test (test_b8_send_keys_verification.py)
Bash mock test that sources lib.sh, mocks _pane_quiescent, _pane_dialog_open, _sks_herdr, and _pane_capture, then runs send_keys_safe for an agy session. Expects returncode 4 and "Enter not accepted after 3 tries" in stderr.
Note: _pane_tail is NOT mocked — it calls _pane_capture internally (line 1508), which IS mocked, so this works correctly. ✅
5. Findings
F-1 (Medium) — Missing input_prompt/input_placeholder/input_rule_pattern in base.py
Location: .agents/skills/lib_py/agents/base.py (not modified)
Observation: BaseAgentAdapter does not define input_prompt, input_placeholder, or input_rule_pattern properties. Only agy, claude, and cline adapters override them. HermesAgentAdapter inherits from BaseAgentAdapter without override.
Impact: When input_region.py line 14 accesses adapter.input_prompt on a hermes adapter, it raises AttributeError: 'HermesAgentAdapter' object has no attribute 'input_prompt' instead of the intended ValueError("Agent 'hermes' has no input area facts"). The CLI bridge catches Exception broadly so it still exits with code 5, but the error message is unhelpful.
Verified: hasattr(get_adapter('hermes'), 'input_prompt') returns False.
Fix: Add to base.py:
@property
def input_prompt(self) -> Optional[str]:
return None
@property
def input_placeholder(self) -> Optional[str]:
return None
@property
def input_rule_pattern(self) -> Optional[str]:
return None
Severity assessment: Medium — latent bug in new infrastructure. Does not affect the B-8 fix itself (d629619a's lib.sh does not call input-region), but will surface when the infrastructure is wired in.
F-2 (Low) — Usage string in __main__.py doesn't mention input-region
Location: .agents/skills/lib_py/agents/__main__.py:8
Observation: Usage string says Usage: python -m lib_py.agents <facts|resolve> [args...] but input-region is now a supported command.
Fix: Update to Usage: python -m lib_py.agents <facts|resolve|input-region> [args...]
F-3 (Info) — input_region.py not wired into send_keys_safe
Observation: The input_region.py module and CLI bridge are added but not called from send_keys_safe(). The lib.sh change is purely the agy early-return removal. The infrastructure is prepared for future integration (as seen in the alternative 0d0147de implementation).
Assessment: Acceptable incremental approach. The B-8 fix is self-contained.
F-4 (Info) — [A-Za-z]+ing fast-path regex retained
Location: .agents/skills/lib.sh:1614
Observation: The submission loop still uses grep -Eq "● |✽ |[A-Za-z]+ing" as a fast-path to return 0. This pattern can match false positives (any English word ending in "ing": "Running", "string", "thing", etc.).
Assessment: Pre-existing issue, NOT introduced by this change. The 0d0147de alternative removes this fast-path. Non-blocking for d629619a.
6. Test Results
| Test | Result |
|---|---|
test_b8_send_keys_verification.py::test_send_keys_safe_b8_verification |
PASS |
test_a4_adapter_contract.py::test_resolve_home_contract |
PASS |
test_a4_adapter_contract.py::test_agent_adapter_registry |
PASS |
test_a4_adapter_contract.py::test_agent_of_row_priority |
PASS |
Static Analysis
| Check | Result |
|---|---|
bash -n .agents/skills/lib.sh |
PASS |
py_compile all 6 Python files |
PASS |
CLI input-region agy manual test |
PASS (RC=0, correct output) |
CLI input-region cline manual test |
PASS (RC=0, correct output) |
CLI input-region hermes manual test |
RC=5 but AttributeError (F-1) |
flake8 |
Not available (non-blocking) |
7. Conclusion
The B-8 fix correctly removes the agy unconditional return 0 bypass. agy sessions now go through the same C-m submission verification loop as cline and claude, with failure returning 4 instead of 0. The test validates this behavior.
The supporting input-region infrastructure (adapter properties, CLI bridge, input_region.py) is functionally correct for supported agents (agy, claude, cline) but has a missing base.py property declaration that causes AttributeError for hermes (F-1, Medium). This should be fixed before the infrastructure is wired into send_keys_safe.
No design-level rework or escalation is needed.
[VERDICT: PASS]