Skip to content

feat(a2a): the peer wire says project - #489

Merged
Jacksondr5 merged 7 commits into
j5/mainfrom
fold/peer-wire-says-project
Oct 8, 2026
Merged

Jacksondr5 merged 7 commits into
j5/mainfrom
fold/peer-wire-says-project

Conversation

@Jacksondr5

@Jacksondr5 Jacksondr5 commented Oct 8, 2026 •

Copy link
Copy Markdown
Owner

Problem

After #484 the only place a project is still called a Squadron in running code is the wire between two peered J5 servers: originSquadronId on a delivery, squadronId in a dropped Exchange's cause, and squadronId and squadronName on a roster entry. Jackson decided to rename them now, while nobody runs peer servers. Part of #412. Stacked on #484.

What changed

  • The peer wire fields say project: originProjectId, terminal.cause.projectId, and a roster entry's projectId and projectTitle.
  • The peer protocol version is 2. The fields are required, so this is a breaking change to the wire, and feat(a2a): peer servers negotiate a peer protocol version #401's version check is what handles it. A server that states no version still counts as version 1, which is now an older version.
  • The "update" message, when the other server is the older one, ends "Update J5 there". That branch could not be reached before, and it repeated the other server's name mid-sentence, which read badly where a caller names it with a phrase ("The server at https://…").
  • The translation at the boundary is gone. peerDeliveryBody.ts, peerRoster.ts, PeerDirectory.ts and PeerInboundService.ts pass the fields through under one name.
  • Migration 032 renames the two fields inside each stored roster snapshot. A storing server keeps a polling peer's last roster as the JSON it was sent. Renaming the fields keeps that peer's agents listed from the upgrade until it next sends its roster, which a restarted poller does on its first poll.

Release note: two connected J5 servers must be updated together

A server on this version and a server on the previous one stop exchanging messages until both are updated. A message queued for the other server is not dropped and its Exchange stays open. Where this server sends to the other one, the delivery is retried, and if the other server stays on the older version it ends as an alarm, like any delivery that keeps failing. Where this server stores for a polling peer, the message waits to be handed out, with no retry and no alarm.

Where this server connects to the other one (direct mode, and the polling side of poll mode):

  • A person sees the peer's row under Settings → Connections → Peer servers in red: "Work VM runs peer protocol 1 and this server runs 2. Update J5 there, then try again." On the older server the row says "Update J5 on this server".
  • An agent sees list_participants leave that server's agents out and count it in unread_peer_count.

On a server that stores messages for a polling peer, it looks different, because this server never connects to that peer:

  • A mismatched poll is refused before anything is recorded, so the peer's row shows it going offline, not a red mismatch. The poller's own row is where the update message appears.
  • list_participants keeps listing the poller's agents from the roster it last sent, and does not count it in unread_peer_count.
  • Messages for it stay stored until a poll on the same version arrives.

An older peer is refused by the version check before its request body is read, in both directions and in both link modes, so it never fails as a schema error.

Stored data

  • Remote ids already stored are untouched. A peer's ids in deliveries, Exchanges and events stay exactly as they are.
  • Queued peer-bound messages need nothing. A delivery row stores no wire field names; the body is built from the row each time it is sent, so a message queued before the upgrade goes out in the new shape.
  • The stored roster snapshot is the one place the old field names were stored. Migration 032 renames them; the stored hash is left alone.
  • Events and inbox rows were already renamed by migration 031.

Unchanged

The j5Squadrons capability key stays, reported as false. It is what makes an older client show its J5 views as unsupported.

Upstream impact

None. Every file is J5-owned. FORK.md case 48 (peering) is updated for migration 32 and protocol 2.

How it was checked

  • vp run typecheck in contracts, client-runtime, web, mobile, desktop and server: 0 errors each.
  • New to new, direct mode: PeerRoundTrip.test.ts runs two real servers' peer layers against each other. Poll mode: PeerPollRoundTrip.test.ts does the same with one side polling.
  • Old to new: PeerHttp.test.ts sends hello, roster, deliver and poll requests on another version, and a delivery that states none; each gets 409 with the update message and nothing is recorded. PeerRegistryService.test.ts refuses an unversioned hello when a peer is added.
  • New to old: PeerOutbound.test.ts gets a protocol-1 server's answer to a delivery; the row is retried, the Exchange stays open, and the peer's record names it as the one to update. PeerPoller.test.ts does the same for a poll. PeerDirectory.test.ts covers a roster read from a server on another version, using a newer one (3 against 2); the compare is the same function for both.
  • A message queued before the upgrade: PeerOutbound.test.ts builds the request body from the stored delivery row and asserts originProjectId; no stored row carries a wire field name.
  • Migration 032: 032_PeerRosterSaysProject.test.ts renames a protocol-1 snapshot, keeps its agents in order and its hash, leaves a peer with no snapshot alone, and the result decodes with the wire schema.
  • CI on 6c808dd (the head before it was restacked with refactor(a2a): internal names say project #484; the restack brought in only j5/main's marketing change): the required job "Format, lint, typecheck, and unit tests" passed, with the whole server suite in three shards, the client tests, and format, lint and typecheck. The first head failed CI typecheck on one line of the new migration test, which is fixed.
  • The crew's tester ran two isolated servers with real agents, previous version 13a6480 against b58e32c (this head differs from that one only in a test's encoding and a comment):
    • New to new, direct and poll mode: an ask and a reply crossed each way, both Exchanges closed on both servers, and each roster listed the other's agent with its project title.
    • New with old, direct mode: each peer row showed its update message as written above; both servers left the other's agents out with unread_peer_count 1; a deliver request each way got 409 peer_protocol_mismatch, not a schema error; nothing crossed.
    • New with old, poll mode, both arrangements: the poller showed the mismatch; the storing server kept the cached agent listed and its outbound ask pending.
    • A message queued before the upgrade was delivered and answered once both sides were upgraded.
    • Migration 032 rewrote a stored roster, kept its hash, and the snapshot was listed and accepted a hash-only poll without a resend.
    • Adding an old server as a peer from a new one showed the update message and recorded nothing.
  • Not captured: screenshots of the peer rows. The tester's browser snapshot tool failed on the Connections page; the row and dialog text were read from the live page.

Checklist

  • One concern: the description has no "also"
  • Tests cover the changed behavior (backend changes ship with focused tests)
  • UI changes: before/after screenshots above, and a video for motion or interaction — no UI code changes; the peer row shows existing text with a new reason, verified live but not captured as an image
  • Upstream-owned files: each one is recorded in FORK.md (case text and file-table row) in this PR — none touched
  • Upstream product: any change to what upstream's product does has a human decision linked above and a register entry in docs/j5/product/upstream.md — none
  • Surfaces: entry points, clients, providers, contracts, reverse states, connection modes (see AGENTS.md) — contracts: the peer wire; connection modes: direct and poll peering both covered
  • Docs: definitions under docs/j5/product/ and user docs rewritten where this changes them — left for the docs PR; this PR edits FORK.md case 48 only

Claude Opus 5.5 (1M context), Claude Code in J5 Code.

🤖 Generated with Claude Code

Jacksondr5 and others added 3 commits October 8, 2026 00:24
The welcome wizard loses its Squadron stage and imports into projects as
upstream does. Branding and the Providers label stay.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Squadrons are retired (#412). The agent-to-agent ledger is keyed by
project id, every thread except a provider Subagent is a participant in
its own project, and everything an agent or a person reads says project.

Migration 031 re-keys and renames the ledger in place: the Squadron table
is never dropped, so nothing cascades, and no row is added, removed or
renumbered. It refuses by name a project that several Squadrons share,
keeps a record of the old ids and names, leaves a peer server's ids alone,
and aborts if any table's row count changes or any row is left without a
project.

Registration moves off the launch path to the stored thread.created
event, which every creation writes, including the two importers that
bypass the thread.create command. A server that upgrades registers the
threads it already has, and a caller without a home registers on its
first agent-to-agent call.

list_squadrons, join_squadron and the Squadron routes are removed. Tools,
routes and contracts carry project ids and titles. A client refuses a
server whose ledger is not keyed by project.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…n-start

Implementing a proposed plan in a new thread used J5's single launch so
the new thread could inherit its plan parent's Squadron. A thread's home
is now its project, so there is nothing to inherit.

ChatView's function is upstream's again: create the thread, start the turn
with the plan reference, and delete the thread if the start fails. The
launch request and its contract lose sourcePlanRef. J5's launch never
passed the reference to the first message, so the plan was not marked
completed; upstream's message dispatch does.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@vercel

vercel Bot commented Oct 8, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
j5-code Ready Ready Preview Oct 8, 2026 7:02am UTC

Request Review

@github-actions github-actions Bot added vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. size:M 30-99 effective changed lines (test files excluded in mixed PRs). labels Oct 8, 2026
@Jacksondr5 Jacksondr5 mentioned this pull request Oct 8, 2026
5 of 7 tasks
@Jacksondr5
Jacksondr5 force-pushed the fold/peer-wire-says-project branch 2 times, most recently from 33125f0 to 6c808dd Compare October 8, 2026 06:26
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@Jacksondr5
Jacksondr5 marked this pull request as ready for review October 8, 2026 06:45
Jacksondr5 and others added 2 commits October 8, 2026 02:45
The ledger has been keyed by project since the re-key, but the code still called
its key a Squadron. This renames the leftover internal names: squadronId becomes
projectId, the SquadronId type becomes LedgerProjectId, and the functions,
services, errors, test helpers and comments follow. No table, column, route,
tool or JSON key changes, and no migration is added.

Three error tags that agents read in tool errors change with their classes:
ProjectLedgerNotFoundError, PlacementProjectNotFoundError and
ArchiveCrewProjectMismatchError. The peer wire fields and the j5Squadrons
capability key keep their names.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Two peered J5 servers named a project a Squadron on the wire between them:
originSquadronId on a delivery, squadronId in a dropped Exchange's cause, and
squadronId and squadronName on a roster entry. They are now originProjectId,
projectId and projectTitle, and the translation at the boundary is gone.

The fields are required, so the peer protocol version becomes 2. Two connected
servers have to be updated together: an older one is refused by the version
check before its request is read, in both directions, and is named as the one
to update. Messages queued for it are retried, not dropped.

Migration 032 renames the fields inside a stored roster snapshot, so a
polling peer's agents stay listed until it next sends its roster.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@Jacksondr5
Jacksondr5 force-pushed the j5/fold-internal-names-say-project branch from 13a6480 to edc79a1 Compare October 8, 2026 06:45
@Jacksondr5
Jacksondr5 force-pushed the fold/peer-wire-says-project branch from 6c808dd to 1b12862 Compare October 8, 2026 06:45
@github-actions github-actions Bot added size:XXL 1,000+ effective changed lines (test files excluded in mixed PRs). and removed size:M 30-99 effective changed lines (test files excluded in mixed PRs). labels Oct 8, 2026
@github-actions github-actions Bot added size:M 30-99 effective changed lines (test files excluded in mixed PRs). and removed size:XXL 1,000+ effective changed lines (test files excluded in mixed PRs). labels Oct 8, 2026
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@Jacksondr5
Jacksondr5 changed the base branch from j5/fold-internal-names-say-project to j5/main October 8, 2026 07:01
@coderabbitai

coderabbitai Bot commented Oct 8, 2026

Copy link
Copy Markdown

Review in Change Stack →

✨ Finishing Touches
📝 Generate docstrings
  • Commit to this branch
  • Create a new PR
🧪 Generate unit tests (beta)
  • Commit to this branch
  • Create a new PR
  • Autopilot · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Comment @coderabbitai help to get the list of available commands.

@Jacksondr5
Jacksondr5 merged commit 937c6b1 into j5/main Oct 8, 2026
27 of 28 checks passed
@Jacksondr5
Jacksondr5 deleted the fold/peer-wire-says-project branch October 8, 2026 07:09

This branch was successfully deployed

1 active deployment
Preview — 279bcc87 Deployed Oct 8, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:M 30-99 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