Skip to content

fix(wrappers): move per-side rebind after lib-auth source (INV-37/38)#159

Merged
zxkane merged 3 commits into
mainfrom
fix/inv37-rebind-order
May 27, 2026
Merged

fix(wrappers): move per-side rebind after lib-auth source (INV-37/38)#159
zxkane merged 3 commits into
mainfrom
fix/inv37-rebind-order

Conversation

@zxkane
Copy link
Copy Markdown
Owner

@zxkane zxkane commented May 27, 2026

Summary

Both wrappers (autonomous-dev.sh, autonomous-review.sh) used to rebind AGENT_CMD and AGENT_LAUNCHER_ARGV to per-side values between sourcing lib-agent.sh and lib-auth.sh. That order is broken: lib-auth.sh transitively re-sources autonomous.conf (via lib-config.sh::load_autonomous_conf), which silently reverts the per-side rebind because operator confs declare AGENT_CMD="claude" unconditionally.

Fix: move the rebind to after source lib-auth.sh (and the review-specific libs).

Bug shape

A downstream consumer's review wrapper kept invoking claude with model claude-sonnet-4.6 (a kiro model name) and failing 404. Operator had set AGENT_REVIEW_CMD=kiro. Two consecutive review-wrapper crashes triggered the dev agent's loop-break protection, which removed the autonomous label from the issue.

The bug was invisible whenever AGENT_DEV_CMD == AGENT_REVIEW_CMD == AGENT_CMD (the common case). It surfaced only on mixed-CLI deployments — exactly the deployment INV-37 was supposed to enable.

Root cause

autonomous-review.sh:22  source lib-agent.sh        # AGENT_CMD=claude (default), AGENT_REVIEW_CMD=kiro
autonomous-review.sh:27  AGENT_CMD="$AGENT_REVIEW_CMD"  # AGENT_CMD=kiro ✓
autonomous-review.sh:32  source lib-auth.sh
   lib-auth.sh:14            source lib-config.sh
   lib-auth.sh:15            load_autonomous_conf "${_LIB_AUTH_DIR}"
                                  source autonomous.conf
                                  # conf line: AGENT_CMD="claude" → overwrite!  ✗

Files changed

  • skills/autonomous-dispatcher/scripts/autonomous-dev.sh — move rebind below source lib-auth.sh + 5-line WHY comment.
  • skills/autonomous-dispatcher/scripts/autonomous-review.sh — same shape, after all four lib sources.
  • tests/unit/test-wrapper-rebind-order.shnew behavioral regression. Builds a sandbox conf with AGENT_DEV_CMD=claude + AGENT_REVIEW_CMD=kiro + AGENT_DEV_LAUNCHER=cc-bridge; sources each wrapper's source/rebind block; asserts post-rebind state. T2 reproduces the downstream consumer review misroute.
  • tests/unit/test-lib-agent-per-side-cmd.sh — PSC-S9/S10 rewritten: assert "rebind AFTER source lib-auth.sh" instead of "within ≤4/5 lines of source lib-agent.sh" (the old line-window assertion was the bug shape).
  • tests/unit/test-lib-agent-per-side-launcher.sh — PSL-S9/S10 same shape.
  • docs/pipeline/invariants.md — INV-37 description corrected with "Why after lib-auth.sh" rationale; INV-38 cross-ref.
  • docs/pipeline/per-side-agent-cmd.md — implementation step 2/3 corrected.
  • docs/pipeline/per-side-launcher.md — resolution-order block updated; PSL-S9/S10 test description updated.

Test plan

  • bash tests/unit/test-lib-agent-per-side-cmd.sh → 17/17 PASS
  • bash tests/unit/test-lib-agent-per-side-launcher.sh → 14/14 PASS
  • bash tests/unit/test-wrapper-rebind-order.sh → 4/4 PASS (T2 directly reproduces the downstream consumer misroute)
  • All other test-lib-agent-*.sh and test-autonomous-{dev,review}-*.sh → still PASS
  • CI checks pass
  • After merge: npx skills update -g -y autonomous-dispatcher to refresh user-scope skill on dev box; rerun review wrapper end-to-end against a real PR to confirm the misroute is gone.

Backwards compat

Pure structural reordering of three lines per wrapper. No public API change. No conf-format change. Default deployment (AGENT_DEV_CMD == AGENT_REVIEW_CMD == AGENT_CMD == claude) is byte-for-byte identical — the bug only manifested on mixed-CLI deployments where the rebind was load-bearing.

Both wrappers (autonomous-dev.sh, autonomous-review.sh) used to apply
their per-side AGENT_CMD / AGENT_LAUNCHER_ARGV rebind immediately after
sourcing lib-agent.sh — and crucially BEFORE sourcing lib-auth.sh.

That order is broken: lib-auth.sh transitively sources
lib-config.sh::load_autonomous_conf, which re-sources autonomous.conf.
Operator confs unconditionally declare AGENT_CMD="claude" (the default
CLI), so the re-source silently reverted any per-side rebind. The bug
was invisible whenever AGENT_DEV_CMD == AGENT_REVIEW_CMD == AGENT_CMD;
it surfaced only when an operator set a non-trivial AGENT_REVIEW_CMD
(e.g. kiro for cheaper review passes).

Discovered when a downstream consumer's review wrapper kept invoking
claude with model 'claude-sonnet-4.6' (a kiro model name) and failing
404 — operator had set AGENT_REVIEW_CMD=kiro and the rebind was being
undone seven seconds into every invocation. Two consecutive review-
wrapper crashes triggered the dev agent's loop-break protection,
removing the autonomous label from the issue.

Fix: move the rebind below `source lib-auth.sh` (and, for review,
below the review-specific libs too — none of them currently re-source
autonomous.conf, but keeping all rebind below all lib sources is the
robust contract). lib-auth.sh and friends do not read AGENT_CMD or
AGENT_LAUNCHER_ARGV, so deferring the rebind is safe.

Tests:
- tests/unit/test-wrapper-rebind-order.sh — new behavioral regression.
  Builds a sandbox conf with AGENT_DEV_CMD=claude, AGENT_REVIEW_CMD=kiro,
  AGENT_DEV_LAUNCHER=cc-bridge; sources each wrapper's source/rebind
  block and asserts post-rebind state. T2 directly reproduces the
  downstream consumer review misroute.
- tests/unit/test-lib-agent-per-side-cmd.sh — PSC-S9/S10 rewritten to
  assert "rebind AFTER source lib-auth.sh" instead of "rebind within
  ≤4/5 lines of source lib-agent.sh". The old line-window assertion
  was the bug shape.
- tests/unit/test-lib-agent-per-side-launcher.sh — PSL-S9/S10
  rewritten in the same shape.

Docs:
- invariants.md INV-37 description corrected (and INV-38 cross-ref).
- per-side-agent-cmd.md implementation step 2/3 corrected with a
  load-bearing-rationale paragraph naming the bug.
- per-side-launcher.md resolution-order block updated; PSL-S9/S10
  test description updated.
Copy link
Copy Markdown

@amazon-q-developer amazon-q-developer Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This PR correctly fixes INV-37/INV-38 rebind order by moving the per-side overrides after all library sources. The structural change ensures autonomous.conf re-sourcing via lib-auth.sh no longer silently reverts the rebind. Comprehensive test coverage (including behavioral regression) and clear documentation make this ready to merge.


You can now have the agent implement changes and create commits directly on your pull request's source branch. Simply comment with /q followed by your request in natural language to ask the agent to make changes.

agy review of #159 surfaced three issues:

P2 (test bug, now P1 in effect): test-wrapper-rebind-order.sh used a
hardcoded `sed -n '22,40p'` extraction range for the wrapper init
block. Review-side launcher rebind sits at line 41 of the post-fix
autonomous-review.sh, so the hardcoded range silently truncated the
launcher rebind out of the simulation. Default-empty
AGENT_REVIEW_LAUNCHER_ARGV made the count assertion pass vacuously.

Fix:
- Replace hardcoded range with content-anchored awk extraction (from
  `SCRIPT_DIR=` to before `: "${PROJECT_ID:?...}"`). Stays in
  lock-step with wrapper edits.
- Switch from `bash -c "..."` to writing the script to a tmpfile and
  feeding `bash <file>`. The extracted block contains markdown
  backticks (e.g. `AGENT_CMD="claude"` in WHY comments). bash -c
  treats backticks as command substitution under double-quoting,
  which would silently execute the comment payload.
- Add T3 — separate sandbox where AGENT_REVIEW_CMD=claude (so INV-38
  guard accepts) and AGENT_REVIEW_LAUNCHER is non-empty. Asserts
  both AGENT_CMD and the launcher rebind execute. Closes the
  vacuously-passing-T2 hole.

P3 (test gap): test-lib-agent-per-side-launcher.sh PSL-S9/S10 only
asserted "rebind lands AFTER lib-auth.sh", missing the symmetric
"rebind does NOT precede lib-auth.sh" check that PSC-S9/S10 has.
Added the matching pre-source assertions. Verified by mutating the
review wrapper to revert the bug shape: PSL-S10 now FAILs with
"REBIND_BEFORE_LIB_AUTH", catching what the AFTER-only check missed.

P2 (doc typo): per-side-agent-cmd.md test-summary table had a stale
duplicate row for PSC-S10 referencing the old "within 5 lines"
assertion. Removed.
@zxkane
Copy link
Copy Markdown
Owner Author

zxkane commented May 27, 2026

Addressed agy review findings (commit 6dfb7d0)

All 3 findings resolved. Key issue was that one of agy's "P2" was structurally a P1 — the test was vacuously passing.

Finding 1 (effectively P1) — test-wrapper-rebind-order.sh hardcoded range truncated launcher rebind:

sed -n '22,40p' cut off line 41 (review-side launcher rebind in post-fix autonomous-review.sh). Default-empty AGENT_REVIEW_LAUNCHER_ARGV made the count assertion pass without the rebind ever executing. Fix:

  • Content-anchored awk extraction (/^SCRIPT_DIR=//^: "\${PROJECT_ID:\?/)
  • Switched to tmpfile + bash <file> instead of bash -c "..." because the extracted block contains markdown backticks in WHY comments — bash -c would treat them as command substitution
  • Added T3: separate sandbox with AGENT_REVIEW_CMD=claude + non-empty AGENT_REVIEW_LAUNCHER so the launcher rebind is actually exercised on the review side (T2 left it default-empty)

Finding 2 (P3) — PSL-S9/S10 missing pre-source check:

PSC-S9/S10 had dual assertions ("rebind AFTER lib-auth" + "rebind does NOT precede lib-auth"); PSL was AFTER-only. Added the symmetric hit_pre checks. Verified by reverting the bug shape: PSC-S10 fails with REBIND_BEFORE_LIB_AUTH immediately — confirms the assertion catches the regression.

Finding 3 (P2) — duplicate doc table row:

Removed the stale PSC-S10 row in per-side-agent-cmd.md test summary that still referenced the pre-fix "within 5 lines" assertion.

Test results

  • test-lib-agent-per-side-cmd.sh: 17 PASS
  • test-lib-agent-per-side-launcher.sh: 16 PASS (was 14, +2 from new pre-source assertions)
  • test-wrapper-rebind-order.sh: 6 PASS (was 4, +2 from new T3)
  • All other related tests still PASS

Re-review please?

agy follow-up review on PR #159 noted that the awk end-anchor was
coupled to the specific variable name PROJECT_ID. If a future edit
reorders the validation block (e.g. validates REPO before PROJECT_ID)
or renames PROJECT_ID, the extraction would fail to terminate and
the test would silently capture wrapper code beyond the init block.

Generalize the regex to '\${[A-Z_]+:\\?' — matches any uppercase
variable name in the `: "${VAR:?...}"` validation idiom that
the wrappers use to gate startup on required config.
@zxkane zxkane merged commit 396b92c into main May 27, 2026
3 checks passed
@zxkane zxkane deleted the fix/inv37-rebind-order branch May 27, 2026 06:59
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant