Skip to content

[AAASM-3402] ✨ (python-sdk): Wire native gateway check/register into SDK lifecycle#146

Merged
Chisanan232 merged 6 commits into
masterfrom
v0.0.1/AAASM-3402/wire_gateway_check
Jun 19, 2026
Merged

[AAASM-3402] ✨ (python-sdk): Wire native gateway check/register into SDK lifecycle#146
Chisanan232 merged 6 commits into
masterfrom
v0.0.1/AAASM-3402/wire_gateway_check

Conversation

@Chisanan232

Copy link
Copy Markdown
Contributor

Description

Wires the SDK's pre-execution policy check and agent registration to the native aa-sdk-client path and retires the legacy raw-REST register/check, closing the unwired-enforcement gap (AAASM-3021 family).

What changed

  • init_assembly now connects a single native RuntimeClient, calls its register() (AAASM-3399) on startup so the agent registers with the gateway and the issued credential token is stored on the shared client, and reuses that same client for the RuntimeQueryInterceptor's query_policy checks (so every check authenticates).
  • A native deny decision now actually blocks the tool call before it runs, via the adapter check_tool_start contract.
  • Removed GatewayClient.register_agent() and GatewayClient.check_policy_compliance() — these issued raw HTTP to the core, which ADR 0004 forbids. report_edge()/dispatch_tool() (genuinely HTTP routes) are retained.
  • Corrected in-repo prose (README + docstrings) that claimed registration/policy checks go to core over HTTP; restated as SDK → aa-sdk-client → core over gRPC/UDS.

Why
Previously the public SDK never called the native register/query_policy; the in-process check was effectively a no-op, so a denied action was not blocked at the SDK layer even with a reachable core. This PR closes that gap.

How it works (enforcement semantics preserved)

  • enforce: register failure or an unreachable/erroring runtime → fail closed (init aborts on register failure; queries deny).
  • observe / disabled (or no mode): register failure is swallowed and queries proceed → fail open.
  • Native extension missing entirely: SDK fast path is simply not engaged (bare client, every mode) — unchanged.

Follow-up (documented, out of scope): the native register() signature does not yet carry the topology/lineage fields (parent_agent_id, team_id, delegation_reason, spawned_by_tool, depth) that the old REST register forwarded. Those fields are still stored on GatewayClient; forwarding them over the native register call is a tracked follow-up.

Type of Change

  • ✨ New feature
  • ♻️ Refactoring
  • 📚 Documentation update

Breaking Changes

  • No
  • Yes (please describe below)

GatewayClient.register_agent() and GatewayClient.check_policy_compliance() are removed. These were internal-facing helpers (not part of the supported init_assembly flow); the public entrypoint init_assembly is unchanged and now performs registration automatically over the native path.

Related Issues

  • Related JIRA ticket: AAASM-3402
  • Builds on AAASM-3399 (native register()/query_policy() shim)

Closes AAASM-3402

Testing

Describe the testing performed for this PR:

  • Unit tests added/updated
  • Integration tests added/updated
  • Manual testing performed

New regression tests (test/unit/core/test_init_registration.py + _fake_core.py fakes):

  • init_assembly calls native register on startup.
  • A native deny makes the adapter interceptor's check_tool_start block (the core of the fixed bug).
  • observe swallows a registration failure; enforce propagates it (fail closed).

Retired the REST register/check unit + integration tests; kept the topology-field-storage tests.

Local validation (native _core not built on this macOS host, so native-only suites skip as designed):

  • .venv/bin/python -m pytest test/565 passed, 13 skipped
  • .venv/bin/mypy (CI config, --ignore-missing-imports) → clean
  • pre-commit run (black / isort / autoflake / mypy) on changed files → clean

CI for python-sdk is minimal (mypy type-check workflow; no ruff gate in pre-commit). Validated locally as above.

Checklist

  • Code follows project style guidelines
  • Self-review completed
  • Comments added for complex logic
  • Documentation updated if needed
  • All tests passing

🤖 Generated with Claude Code

Chisanan232 and others added 6 commits June 19, 2026 12:21
Expose connect_runtime_client() and register_agent() over the native
RuntimeClient (AAASM-3399), and let build_governance_interceptor reuse a
pre-connected client so register and query_policy share one client (and thus
the issued credential token). native_available is threaded through so a missing
extension (fail open) stays distinct from an unreachable socket (fail closed
under enforce).

Refs AAASM-3402

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
init_assembly now connects one native runtime client, registers the agent on it
(storing the credential token), and reuses that client for the
RuntimeQueryInterceptor — so a deny actually blocks a tool. Registration
failure propagates under enforce (fail closed) and is swallowed under
observe/disabled (fail open), honoring the existing enforcement semantics.

Refs AAASM-3402

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
register_agent() and check_policy_compliance() issued raw HTTP to the core,
which ADR 0004 forbids — registration and the policy check now go through the
native gRPC path. Removes the methods plus the unit/integration tests that
asserted their REST wire shape; report_edge()/dispatch_tool() (genuinely HTTP)
and the GatewayClient topology-field storage tests are kept. Topology lineage
over the native register call is a tracked follow-up.

Refs AAASM-3402

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The Public API section advertised the removed REST register_agent/
check_policy_compliance and claimed registration + policy checks go over HTTP.
Restate per ADR 0004: those go SDK → aa-sdk-client → core over gRPC/UDS; only
topology edges and secret dispatch remain HTTP routes.

Refs AAASM-3402

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
FakeRuntimeClient records register calls and returns a canned query_policy
decision; install_fake_core swaps a fake agent_assembly._core into sys.modules
so init_assembly exercises the native register/query path without a built
extension or a running aa-runtime.

Refs AAASM-3402

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Closes the unwired-enforcement gap with four cases: init_assembly calls native
register; a native deny makes the adapter interceptor's check_tool_start block;
observe swallows a registration failure; enforce propagates it (fail closed).

Refs AAASM-3402

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

codecov Bot commented Jun 19, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 93.18182% with 3 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
agent_assembly/core/runtime_interceptor.py 90.00% 3 Missing ⚠️

📢 Thoughts on this report? Let us know!

@sonarqubecloud

Copy link
Copy Markdown

@Chisanan232 Chisanan232 left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Claude Code — PR review (AAASM-3402)

Verdict: ✅ ready to merge. CI all green (CI Success gate, unit + integration, SonarCloud, codecov, CodeQL; only e2e/deploy intentionally skipped). Scope clean: gateway.py, core/assembly.py, core/runtime_interceptor.py, README + 5 test files.

Scope reviewed

  • Root cause confirmed & fixed: the public SDK never called native register/query_policy (from AAASM-3399), so the pre-exec check was a no-op — a denied action was not blocked at the SDK layer. ✅ Now init_assembly connects one native RuntimeClient, registers on startup (token stored on the shared client), and the same client backs the RuntimeQueryInterceptor, so deny actually blocks the tool.
  • Legacy raw-REST GatewayClient.register_agent() / check_policy_compliance() (ADR-0004 violations) removed. ✅
  • Enforcement semantics preserved: enforce = fail-closed, observe/disabled = fail-open. ✅
  • README + docstrings corrected to native gRPC path. Regression tests: register-on-init + deny-blocks. 565 pass / 13 skip (native _core not built on macOS host — expected).

Follow-up filed (not a blocker)

The native register() does not yet forward the topology/lineage fields (parent_agent_id, team_id, …) the old REST register sent — they're still stored on GatewayClient but not carried over the native path. This matters because team_id drives team-budget attribution and the topology graph. Tracked as a separate ticket under Epic AAASM-3395 (likely needs the Register proto to carry these fields → affects all SDKs). Closing the unwired-enforcement gap here is correct and self-contained.

Good to merge.

@Chisanan232 Chisanan232 merged commit ee7ef1f into master Jun 19, 2026
21 checks passed
@Chisanan232 Chisanan232 deleted the v0.0.1/AAASM-3402/wire_gateway_check branch June 19, 2026 04:35
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