Skip to main content

substrate

How AX depends on Agent Substrate (modules, address contract, mocks, version bumps, E2E pin). Load when touching internal/substrate, bumping Substrate, or triaging make test-e2e.

Quellinformationen

Repository
google/ax
Letzte Quellaktivität
2. November 2026 um 23:16
Erkannte Sprache von SKILL.md
Englisch
Sterne
14.575
Forks
784

Installationsoptionen

Standardmäßig ist der Prompt ausgewählt, der zuerst die Quelle prüft. Sie können zu einem direkten Befehl wechseln oder eine lokale Kopie herunterladen.

Quelldateien prüfen

Lesen Sie SKILL.md und alle von SkillsMP angezeigten Begleitdateien, bevor Sie sich für eine Installation entscheiden.

SKILL.md wird angezeigt

SKILL.md
Quellanweisungen · Schreibgeschützte Vorschau
name
substrate
description
How AX depends on Agent Substrate (modules, address contract, mocks, version bumps, E2E pin). Load when touching internal/substrate, bumping Substrate, or triaging make test-e2e.
# Agent Substrate in AX AX schedules every `Task` as a sandboxed **actor** on [Agent Substrate](https://github.com/agent-substrate/substrate). AX owns the declarative layer (Task/Workspace/Model, reconciler, CLI); Substrate owns isolation, checkpoint/restore, worker placement and in-cluster routing. Facts below were verified against `main` on 2026-10-28 — re-check `go.mod` and `hack/setup-e2e-kind.sh` if they look stale. ## 1. Module map | Module | Pinned | Provides | Imported by | |---|---|---|---| | `go.ate.dev/substrate` | `v1.0.0-rc.1` | Control API protos `api/ateapi/v1` (atespaces, actor templates, actors, suspend/resume) | `internal/substrate`, `internal/server`, `internal/controller`, `test/e2e` | | `github.com/agent-substrate/env` | `v0.0.11-0.20260912052224-4468a200b170` (pseudo-version) | Guest services served inside the sandbox (process exec + file system gRPC) and `proto/ateenv/v1alpha` | `internal/guest`, `internal/metadata` | There is no `replace` directive for either module. Local hacking against a Substrate checkout goes through `SUBSTRATE_DIR` in E2E (section 5). ## 2. The Control API wrapper: `internal/substrate.Client` All Control API traffic goes through this package. It encapsulates: - **Endpoint defaults** — `api.ate-system.svc.cluster.local:443`; authority and TLS `ServerName` default to `api.ate-system.svc` when the target contains that string. - **Auth** — bearer token from `SUBSTRATE_TOKEN_FILE` (in-cluster: projected SA token with audience `api.ate-system.svc`, see `deploy/ax-server.yaml`), CA from `SUBSTRATE_CA_FILE`. - **Retry** — `IsTransientError` + `retryOnCodes` for `Unavailable`-class errors. - **Helpers** the reconciler relies on — `EnsureAtespace`, `EnsureActorTemplateWithImage`, `EnsureActor`, `SuspendActor`, `ResumeActor`, `DeleteActor`, `WorkerIP`, `ResourceLimits`, `BuildActorTemplate`. ### Where a new Control API call lives today - `internal/substrate/client.go` is the only non-test file that calls `ateapipb.NewControlClient`; every existing RPC is a method on `*Client`, wrapped in `retryOnCodes(..., codes.Unavailable)` where idempotent. - Each method has a table-driven case in `client_test.go` (`mockControlClient`). - Callers in `internal/controller` exercise it through `mockControlServer`; `internal/server` and `cmd/ax` tests use `internal/substrate/substratetest` (section 4). ## 3. Address contract | Value | Occurrences | |---|---| | `api.ate-system.svc.cluster.local:443` + authority `api.ate-system.svc` | `cmd/ax-server/main.go` (`--substrate-endpoint` / `--substrate-authority` flag defaults), `internal/substrate/client.go` (3×), `deploy/ax-server.yaml`, `test/e2e/manifests/ax-server.yaml`, `test/e2e/harness_test.go` | | `atenet-router.ate-system.svc[.cluster.local]` | `internal/controller/reconciler.go` (`defaultRouterServerName`), `internal/tunnel/router_tls.go` (`routerServerName`), `cmd/ax/main.go` (ssh port-forward path), `internal/guest/client.go` (doc comment), `deploy/ax-server.yaml`, `test/e2e/manifests/ax-server.yaml`, `docs/networking.md` | | namespace `ate-system` | all of the above + `test/e2e/harness_test.go` (`ateSystemNamespace`) | Why it matters: tasks never get a Service/Ingress. Every request to a task is proxied by the **atenet router**, which picks the target from the `ate-target-actor` header and resumes a suspended actor on demand (`docs/networking.md`). `ax ssh` port-forwards to `svc/atenet-router` on 443 (mTLS) and falls back to 80. ## 4. Testing against Substrate ### Unit tests: in-process mock, no cluster ```go type mockControlServer struct { ateapipb.UnimplementedControlServer // record calls / inject failures here } grpcServer := grpc.NewServer() ateapipb.RegisterControlServer(grpcServer, mockSrv) // serve on a listener, point substrate.NewClient at it ``` Canonical examples: `internal/controller/reconciler_test.go` (reconciler state transitions; the largest test file in the repo). `internal/server/server_test.go` and `cmd/ax/main_test.go` run a real `TaskReconciler` against `internal/substrate/substratetest`, an in-memory fake of the same API. `internal/substrate/client_test.go` uses a client-side `mockControlClient` instead. No mocking library is in `go.mod`. ### Substrate behaviour the code already depends on - Actor template images must be digest-pinned (`@sha256:…`); a tag-only `spec.image` fails at ActorTemplate creation with reason `TemplateCreationFailed` (`docs/manifests.md`). `make images` writes `bin/ax-server.digest` / `bin/ax-task-runner.digest` for this reason. - After `ResumeActor` the actor may be on a different worker, so AX never stores a worker IP: the server reads it from the actor on every get and list (`substrate.WorkerIP` in `internal/server/server.go`), and the reconciler uses the IP `ResumeActor` returns only for its readiness probe (`internal/controller/reconciler.go`). - Guest services (process + fs) are mounted by `internal/metadata/server.go` only when `task.Spec.Debug` is true; `ax ssh` (`cmd/ax/main.go`) refuses to connect otherwise. - Readiness: Substrate and the reconciler probe the runner on port 80 (`/healthz`, `/readyz?check=workspace`, served by `internal/metadata`); `/readyz` is 503 until all workspaces are materialized (`docs/sandbox.md`). - Snapshot storage: Actor templates created by AX leave `SnapshotConfig.StorageLocation` empty by default so Substrate uses its cluster-wide `--snapshot-location`. Specifying a custom snapshot bucket (`snapshotsBucket` in `BuildActorTemplate`) can only be used when the Substrate cluster has the `PerTemplateSnapshotLocation` preview feature gate enabled; otherwise Substrate rejects template creation with `actor_template.snapshot_config.storage_location: Forbidden`. ## 5. E2E and the Substrate version pin `test/e2e` is compiled by `go test ./...` but **self-skips** unless `AX_E2E=true` or `-args --e2e`. The real runs go through `make`: | Target | Substrate version | When | |---|---|---| | `make test-e2e` | exactly `go list -m -f '{{.Version}}' go.ate.dev/substrate` (pseudo-versions reduced to the 12-char commit) | PR CI (`e2e.yml`) | | `make test-e2e SUBSTRATE_REF=<branch\|tag\|sha>` | override | local, or `workflow_dispatch` input `substrate_ref` in `e2e.yml` | | `make test-e2e-head` | Substrate `main` | nightly schedule in `e2e.yml` | | `make e2e-setup` / `e2e-run` / `e2e-cleanup` | same as above | iterate without re-provisioning | Useful env (full list in `test/e2e/README.md`): `SUBSTRATE_DIR` (local checkout; a detached worktree is created under `.tmp/` if HEAD ≠ ref), `SUBSTRATE_REPO`, `SUBSTRATE_IMAGE_CACHE_DIR` (CI caches built Substrate images keyed by the Substrate version, so a version change is a cache miss), `E2E_ARGS='-test.run TestE2E_ModelCRUD'`. ## 6. Bumping Substrate What the repo mechanically requires when `go.ate.dev/substrate` or `github.com/agent-substrate/env` changes in `go.mod`: ```bash go get go.ate.dev/substrate@vX.Y.Z # and/or github.com/agent-substrate/env@<sha> go mod tidy # CI diffs go.mod/go.sum go build ./... && go test ./... # unit tests compile against the new ateapipb make test-e2e # hack/setup-e2e-kind.sh installs the go.mod version ``` `e2e.yml` keys its Substrate image cache on the module version, so the first E2E run after a bump rebuilds Substrate.
Auf GitHub ansehen