Co-Authored-By: Claude Fable 5.1 <[email protected]> Claude-Session: https://claude.ai/code/session_01EmM1j46qgKMh3zqD1QMwEo
7.3 KiB
Requirements Document
Introduction
The plane moves from this laptop's kind cluster to a Kubernetes cluster of the maintainer's choosing without
changing what runs: the same ax manifests, runner image, memory store and credential path. Every host-bound
piece becomes a cluster resource or a configuration value, each change is proven on kind first, and the
production entry point (a delta Run for a push) is added. Context: brief.md, docs/deployment.md.
Boundary Context
- In scope: the reconciler as an in-cluster workload; receiver and router addressed as Services; configurable cluster context, registry and image pins; our own snapshot and memory buckets; the Joern engine as a plane task on a larger worker pool; worker pool sizing and autoscaling; a delta Run command and Workspaces from URL + commit; a deployment runbook with a proof on kind and a checklist for the target cluster.
- Out of scope: provisioning or operating the target cluster; modifying Agent Substrate or ax; any change to
detection, scoring, populations or the decision engine; replacing the
axCLI with a bespoke client beyond what in-cluster addressing needs. - Adjacent expectations:
ai-service-planerequirements (one Model + budget per task, attribution, credentials only in the start request, egress policies, verify-at-startup memory store) keep holding;harnessx-removalReq 6 (memory on the S3 store) keeps holding; nothing is deleted before its replacement passes its test (theharnessx-removalsequencing rule).
Target Environment (maintainer, 2026-10-02)
- Cluster: k3s. Consequences: containerd (no Docker socket; the engine's host-Docker path does not exist there),
gVisor needs
runscand aRuntimeClassinstalled on the nodes Substrate's workers run on, k3s ships Traefik and local-path storage, and single-node k3s is close enough to kind that the kind proof transfers. - Images and source: GitHub. Images are published to GitHub Container Registry (
ghcr.io/norandom/...), built by GitHub Actions from tagged commits, digest-pinned in the manifests; private packages need animagePullSecreton the worker and reconciler ServiceAccounts. Substrate's and ax's own images are built withkofrom their checkouts and pushed to the same registry.
Requirements
Requirement 1: Nothing assumes this host
User Story: As the maintainer, I want every host-bound assumption replaced by a cluster resource or a configuration value, so the plane runs the same on kind and on the target cluster.
Acceptance Criteria
- The kube context, the registry (GHCR in production), the ax-server address, the router address, the receiver address and the
snapshot and memory buckets are configuration (environment or one config file), with the kind values as the
documented defaults for development; no module names
kind-ousast,localhost:5001or172.19.0.1. ousast plane doctorchecks the configured cluster, not kind by name, and reports each configured address.- A test enumerates the source tree for host-only literals and fails on any.
Requirement 2: The reconciler runs in the cluster
User Story: As the maintainer, I want runs submitted to a reconciler that lives in the cluster, so that a push from CI, not a laptop session, drives the plane.
Acceptance Criteria
- The reconciler runs as a Kubernetes workload (a Deployment serving a submit API, or a Job per Run; the design decides) from the runner image, with a ServiceAccount whose RBAC allows what it does and nothing more.
- It talks to ax-server and
atenet-routerthrough their Services, not port-forwards; theaxCLI, if kept, is in the image. - Provider and store credentials come from Kubernetes Secrets into the reconciler's environment, never into a manifest, an ActorTemplate or a log; the start-request path is unchanged.
ousast plane runfrom a laptop still works against the kind cluster for development (it is the same code with the development defaults).
Requirement 3: Receiver and artifacts without a host
User Story: As the maintainer, I want task artifacts to land in the cluster or the store, not on a laptop.
Acceptance Criteria
- The receiver is a Service of the in-cluster reconciler, or tasks deliver through presigned URLs to the S3 store (the design chooses one and states why); the kind gateway EndpointSlice is removed.
- Egress policies grant each task exactly the hosts it needs (receiver or store, git hosts, the bound Model's host) and nothing else; a test renders the policy for every committed Task.
Requirement 4: The engine is a plane task
User Story: As the maintainer, I want Joern to run where the other tasks run, on a worker sized for it.
Acceptance Criteria
- A second WorkerPool sized for the engine (memory and CPU from a measured run) exists alongside the default
pool; an
enginetask module wraps today's host engine run and emits the samealerts.jsonlrows and coverage asalerts-engine. - The engine image is digest-pinned in the registry like the runner image; its size and pull time are recorded.
alerts-engineon the host remains available for development and is marked as such.
Requirement 5: Sizing and autoscaling
User Story: As the maintainer, I want the pool to follow the load of pushes without manual resizing.
Acceptance Criteria
- Worker pool replicas, limits and the autoscaling rule (Substrate's assigned-worker signal) are manifests under
ops/k8s/with the kind values as a small profile and a documented production profile. - The runbook records the measured footprint per task type and the queueing consequence of one actor per worker.
Requirement 6: A delta Run for a push
User Story: As a user with a repository the project has never seen, I want a push checked by the plane.
Acceptance Criteria
ousast plane scan <repo-url> --base <commit> --head <commit>generates Workspaces from the URL and commits, derives candidates from the changed functions (quick rules, inferred roles, repository facts), and submits a Run of facts, verify a/b, tie-break and agree with per-task budgets; a whole-repository mode is secondary.- Results are written to the memory store under the repository and head commit and reported with the attribution table; the decision engine's verdict is reported only when a model is adopted, else the plane's agreement (ai-service-plane Req 6 and learned-decision-engine Req 6 unchanged).
- The latency split is explicit: a blocking pre-push carries quick rules and the delta engine within its deadline; plane verdicts arrive asynchronously.
Requirement 7: Proven on kind, then documented for the target
User Story: As the maintainer, I want each step shown working on kind before I touch the real cluster.
Acceptance Criteria
- Every requirement above is exercised end to end on the kind cluster (the in-cluster reconciler included), with
a recorded run under
benchmarks/measurements/. docs/deployment.mdbecomes the runbook: prerequisites for the target cluster (Substrate, ax, registry, buckets, Secrets, node requirements for gVisor workers), the profile switch, and a checklist whose every item maps to a requirement here; planned items are labelled planned until their run is recorded.