-
Notifications
You must be signed in to change notification settings - Fork 0
chore(wp7): hygiene, stubs, test/CI/tooling, doc gaps, boundary patterns doc #1926
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
ed1e649
740b69c
b5adeac
bfd0582
0fe0749
e69885d
5d4feb1
11e6edc
9646e4e
0e6306b
c80ae98
fb018a6
d29e48c
6de9487
d9cc512
d02429a
d201bfb
3802c9c
175b2d7
fc4c090
69540af
d21d9e7
c8f2f03
c2fa188
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -129,6 +129,13 @@ All significant design and architecture decisions in force today, organized by d | |
|
|
||
| **Mitigation plan:** (1) File upstream PR against `nats-io/nats.py` with the one-line `inspect.iscoroutinefunction` fix; upstream PR status is tracked in the project issue queue (search `nats-py` label); the scoped `filterwarnings` entry in `pyproject.toml` remains the active workaround until a fixed upstream release is available. (2) If upstream is unresponsive by **2026-06-10** (60 days from the 2026-04-11 review), maintain a local monkey-patch in `bus/_nats_compat.py`. (3) Monitor `nats-core` for future JetStream support. | ||
|
|
||
| **Verification checkpoint (2026-06-10):** on this date run the checklist below and update this section with the outcome (mark each item Done / Not done / Outcome). | ||
|
|
||
| 1. Inspect `nats-io/nats.py` open PRs and recent releases on GitHub for the `inspect.iscoroutinefunction` fix. | ||
| 2. If a fixed release is available: bump the `nats-py` pin in `pyproject.toml`, drop the matching `filterwarnings` entry, run `uv run python -m pytest tests/ -m integration -k nats` to confirm warnings are gone, and replace this checkpoint section with the resolution outcome. | ||
| 3. If no fixed release exists: implement the local monkey-patch in `src/synthorg/communication/bus/_nats_compat.py` (one-line `nats.aio.client.iscoroutinefunction = inspect.iscoroutinefunction`), import it at bus initialisation, and extend this section with the patch landing date. | ||
| 4. Re-evaluate `nats-core` JetStream support: a maintained alternative removes the entire mitigation requirement. | ||
|
Comment on lines
+132
to
+137
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Checkpoint numerics should follow docs numeric-sourcing policy. The newly added dated checklist contains hardcoded numerics/date values without As per coding guidelines, “Numerics in README and public docs must be sourced from 🤖 Prompt for AI Agents |
||
|
|
||
| ## Overarching Pattern | ||
|
|
||
| Nearly every decision follows the same architecture: a pluggable protocol interface with one initial implementation shipped, and alternative strategies documented for future extension. This is consistent with the project's protocol-driven design philosophy. | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -32,6 +32,26 @@ uv sync | |
|
|
||
| `uv sync` creates a virtual environment in `.venv/` and installs all development dependencies (linters, type checker, test runner, pre-commit, etc.). | ||
|
|
||
| ## Install external CLI tools (one-time per machine) | ||
|
|
||
| Some gates and the docs build rely on external binaries that are not Python packages: `golangci-lint` (Go linter, used by the CLI) and `d2` (architecture diagram renderer). | ||
|
|
||
| Install `golangci-lint` once per machine: | ||
|
|
||
| ```bash | ||
| bash scripts/install_cli_tools.sh | ||
| ``` | ||
|
|
||
| The script downloads the pinned `golangci-lint` version that matches CI (`.github/workflows/cli.yml`). Re-run only after bumping the pinned version; subsequent `uv sync` invocations do NOT re-run the script. CI uses its own action-based install step, so this is strictly a local-developer convenience. | ||
|
|
||
| Install `d2` separately (the docs job pins `v0.7.1`). The fastest path is the upstream installer: | ||
|
|
||
| ```bash | ||
| curl -fsSL https://d2lang.com/install.sh | sh -s -- --version v0.7.1 | ||
| ``` | ||
|
|
||
| On Windows, install via `winget install Terrastruct.d2` or download the release archive from `https://github.com/terrastruct/d2/releases`. Either way, ensure the resulting `d2` binary is on `PATH`; the docs build invokes it directly. | ||
|
Comment on lines
+35
to
+53
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. New numeric doc content needs This section introduces hardcoded numeric values (including version numerics) without runtime-stats markers. Please source numeric literals via As per coding guidelines, “Numerics in README and public docs must be sourced from 🧰 Tools🪛 LanguageTool[uncategorized] ~45-~45: The official name of this software platform is spelled with a capital “H”. (GITHUB) 🤖 Prompt for AI Agents |
||
|
|
||
| ## Verify Installation | ||
|
|
||
| Run the smoke tests to confirm everything is working: | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,112 @@ | ||
| --- | ||
| title: A2A Federation | ||
| description: Register a peer SynthOrg deployment, expose JSON-RPC methods, route tasks across the federation. | ||
| --- | ||
|
|
||
| # A2A Federation | ||
|
|
||
| The Agent-to-Agent (A2A) bridge lets one SynthOrg deployment delegate tasks to a peer over JSON-RPC. Each side authenticates with a shared JWT credential and the typed boundary at `synthorg.a2a.rpc_params.parse_rpc_params` validates every inbound `params` block. This guide walks through registering a peer, enabling specific RPC methods, and observing a federation round-trip. | ||
|
|
||
| ## Concepts | ||
|
|
||
| - **Peer**: a SynthOrg deployment reachable at an HTTPS URL with a JSON-RPC endpoint mounted at `/a2a`. | ||
| - **Method**: a JSON-RPC operation the gateway exposes. The current method set is `message/send`, `tasks/get`, and `tasks/cancel`. | ||
| - **Envelope precedence**: the JSON-RPC `method` field on the envelope always wins; a `method` key smuggled inside `params` is rejected at `parse_rpc_params` time. | ||
|
|
||
| ## Configuration surface | ||
|
|
||
| Settings live under the `a2a` namespace. Resolve them via `SettingsService` or set them in the company-template YAML. | ||
|
|
||
| | Key | Type | Default | Purpose | | ||
| |---|---|---|---| | ||
| | `a2a.enabled` | bool | `false` | Master switch for the federation gateway. | | ||
| | `a2a.peer_url` | URL | (unset) | Outbound peer endpoint. | | ||
| | `a2a.peer_jwt_secret` | secret | (unset) | HMAC key for outbound JWT. | | ||
| | `a2a.methods_enabled` | list[str] | `[]` | Allowlist of inbound methods. | | ||
| | `a2a.timeout_seconds` | float | `30` | Per-request wall-clock budget. | | ||
|
|
||
|
Comment on lines
+20
to
+27
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Replace hard-coded numerics in this public guide with runtime-stat markers. This guide includes literal numeric values (defaults, ports, status codes) instead of As per coding guidelines: “Numerics in README and public docs must be sourced from Also applies to: 30-31, 85-87 🤖 Prompt for AI Agents |
||
| ## Worked example: two-node round-trip | ||
|
|
||
| The example uses two local processes on ports `8000` (node A) and `8001` (node B); each side has the other registered as its peer. | ||
|
|
||
| ### Node B (callee) | ||
|
|
||
| ```bash | ||
| SYNTHORG_DATA_DIR=/tmp/synthorg-b \ | ||
| SYNTHORG_BACKEND_PORT=8001 \ | ||
| uv run python -m synthorg.api | ||
| ``` | ||
|
|
||
| ```yaml | ||
| # /tmp/synthorg-b/config.yaml | ||
| a2a: | ||
| enabled: true | ||
| methods_enabled: | ||
| - tasks/get | ||
| peer_jwt_secret: "shared-secret-do-not-commit" | ||
| ``` | ||
|
|
||
| ### Node A (caller) | ||
|
|
||
| ```yaml | ||
| # /tmp/synthorg-a/config.yaml | ||
| a2a: | ||
| enabled: true | ||
| peer_url: http://localhost:8001/a2a | ||
| peer_jwt_secret: "shared-secret-do-not-commit" | ||
| methods_enabled: [] | ||
| ``` | ||
|
|
||
| Call `tasks/get` from node A: | ||
|
|
||
| ```python | ||
| import httpx | ||
| import jwt | ||
| import uuid | ||
|
|
||
| token = jwt.encode({"sub": "synthorg-a", "aud": "synthorg-b"}, "shared-secret-do-not-commit", algorithm="HS256") | ||
|
|
||
| payload = { | ||
| "jsonrpc": "2.0", | ||
| "id": str(uuid.uuid4()), | ||
| "method": "tasks/get", | ||
| "params": {"task_id": "task-12345"}, | ||
| } | ||
| resp = httpx.post( | ||
| "http://localhost:8001/a2a", | ||
| json=payload, | ||
| headers={"Authorization": f"Bearer {token}"}, | ||
| ) | ||
| print(resp.json()) | ||
| ``` | ||
|
|
||
| Expected outcomes: | ||
|
|
||
| - `200` with a `result` block when the task exists. | ||
| - `404` (mapped to JSON-RPC error `-32602` with `data.code: "task_not_found"`) when the task is unknown. | ||
| - `403` when the bearer JWT does not validate (peer secret mismatch or `aud` claim incorrect). | ||
|
|
||
| ## Observability | ||
|
|
||
| Every inbound JSON-RPC call emits these events: | ||
|
|
||
| - `a2a.jsonrpc.received`: at envelope decode; carries `peer`, `method`, `id`. | ||
| - `api.boundary.validation_failed`: when `parse_rpc_params` rejects a malformed `params` block. | ||
| - `a2a.jsonrpc.dispatched`: at successful method dispatch. | ||
| - `a2a.jsonrpc.error`: at error path (with `code` and `message`). | ||
|
|
||
| The `a2a.dispatch_latency_seconds` histogram has a `method` label so per-RPC latency is easy to chart. | ||
|
|
||
| ## Threat model + extension | ||
|
|
||
| The boundary check is the only validation gate; downstream handlers MUST treat their typed `params` as already-validated. | ||
|
|
||
| To add a new method: | ||
|
|
||
| 1. Define an `A2A<Method>Params` Pydantic model under `src/synthorg/a2a/rpc_params.py`. | ||
| 2. Add it to the `A2ARpcParams` discriminated union. | ||
| 3. Register the handler in the gateway registry. | ||
| 4. Add the method name to the per-peer `a2a.methods_enabled` allowlist. | ||
| 5. Cover the wire shape in `tests/unit/a2a/test_<method>.py`. | ||
|
|
||
| See [docs/reference/typed-boundaries.md](../reference/typed-boundaries.md) for the boundary contract and [docs/design/a2a.md](../design/a2a.md) for the full protocol design. | ||
Uh oh!
There was an error while loading. Please reload this page.