Skip to content

feat(scripts): pr-env.sh --peer serves one build twice and peers the two servers - #255

Merged
Jacksondr5 merged 2 commits into
j5/mainfrom
j5/pr-env-peer
Sep 23, 2026
Merged

Jacksondr5 merged 2 commits into
j5/mainfrom
j5/pr-env-peer

Conversation

@Jacksondr5

Copy link
Copy Markdown
Owner

Standalone against j5/main; not part of the peering stack. --peer needs a PR build that contains the j5 a2a peer CLI (#173 or later), which every stack PR from #173 up does.

Problem

Testing cross-server A2A means two servers on one host, peered, every time. Doing it by hand takes two terminals, a second pairing URL, and four CLI calls in the right order with the right ids.

What this does

scripts/j5/pr-env.sh <pr> --peer serves the PR's build twice from one worktree:

  • Local on the ordinary PR port with the usual state dir, so a single-server rerun of the same PR reuses it.
  • Remote on port+100 (J5_ENV_PEER_PORT) with its own state-remote dir.
  • Waits for both descriptors with a bounded probe, reads each environment id, then peers them headlessly: Remote issues a credential for Local and Local records Remote at its loopback origin, then the mirror image. Each direction retries a few times because both servers are seconds old.
  • Startup pairing tokens are untouched. The peer CLI mints and revokes a temporary local admin session against each state dir; the startup pairing grant is a separate record. Verified below by exchanging Local's startup token after peering.
  • Interleaved logs. Both servers stream to the terminal, each line prefixed [Local] or [Remote] (coloured on a tty), and each is also kept in local.log / remote.log under the env root. The summary reprints both pairing URLs so nobody has to scroll for them.
  • Ctrl-C stops both servers by the PIDs the script captured, never by pattern. Rerunning re-peers idempotently, since re-issuing rotates the credential and re-adding rotates the record.

Single-server mode is unchanged.

Traps found while proving it

Eight scratch runs on a host that itself runs the J5 background service surfaced three real defects, all fixed:

  1. A shell under the J5 service inherits T3_SERVICE_LAUNCHER_CONTEXT, and serve refuses the version mismatch. A PR-env server is never a launcher child, so the script unsets it.
  2. The readiness curl needed a timeout: the server binds its port before it can answer, so an unbounded request sat on the listen backlog for twenty minutes instead of retrying.
  3. Capturing the credential with a prefixed stderr process substitution inside $(...) put the prefixed warning lines into the captured value, so Local presented a multi-line bearer token and the hello failed at the transport layer. The credential is now captured from stdout alone, with stderr shown only on failure.

The third one also showed the server's unreachable reason was unhelpful; #198 gained a small commit that joins the cause chain into the message.

Verification

Scratch run against j5/peering-7-names on this host with pr-env.sh 998 --branch … --peer:

  • Both servers up, peered in both directions on the first attempt; the direction a previous run had recorded took the "Updated peer" path.
  • j5 a2a peer list on each state dir shows the other server under its Local / Remote label.
  • Local's startup pairing token exchanged after peering: HTTP 200 with the administrative scope set including access:write.
  • Ctrl-C equivalent (TERM to the script) stopped both servers and cleared both ports.
  • The final signal-trap tidy (exit after cleanup instead of falling through to the "a server exited" line) is syntax-checked but was applied after the last full run.

Built by Claude Fable 5.1 in Claude Code.

🤖 Generated with Claude Code

…two servers

Testing cross-server A2A needs two servers on one host, peered, every time.
--peer serves the PR's build as "Local" (the ordinary port and state dir) and
"Remote" (port+100, its own state dir), waits for both descriptors with a
bounded probe, then peers them headlessly with `j5 a2a peer` against each
state dir. That mints and revokes a temporary local admin session and never
touches the startup pairing grants, so both pairing URLs stay valid; the
summary reprints them. Both logs stream interleaved, each line prefixed
[Local] or [Remote]. Rerunning re-peers idempotently. Ctrl-C stops both by
the PIDs the script captured.

Three traps found while proving it on a host that runs the J5 service: the
inherited T3_SERVICE_LAUNCHER_CONTEXT must be unset or serve refuses the
version mismatch; the readiness probe needs a timeout because the server
binds its port before it can answer; and the credential must be captured
from stdout alone, since a prefixed stderr inside $(...) ends up in the
captured value.

Built by Claude Fable 5.1 in Claude Code.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@github-actions github-actions Bot added vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. size:L 100-499 effective changed lines (test files excluded in mixed PRs). labels Sep 23, 2026
Built by Claude Fable 5.1 in Claude Code.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:L 100-499 effective changed lines (test files excluded in mixed PRs). vouch:trusted PR author is trusted by repo permissions or the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant