From 7dc81372ae264d94a78a911674c74491e9699375 Mon Sep 17 00:00:00 2001 From: Bo Wu Date: Mon, 31 Aug 2026 18:58:54 -0700 Subject: [PATCH] Refactor repository into component directories --- .github/workflows/container.yml | 1 + Cargo.toml | 19 +++-------- README.md | 17 +++++++++- audit-log/README.md | 9 ++++++ {bin => control-server/bin}/hash-password.mjs | 2 +- .../bin}/prepare-repository.mjs | 0 .../test/prepare-repository.test.mjs | 2 +- docker/README.md | 14 ++++++++ Dockerfile => docker/runtime/Dockerfile | 6 ++-- .../runtime/Dockerfile.dockerignore | 0 .../runtime}/container-entrypoint.sh | 0 docs/architecture/system-architecture.md | 32 ++++++++++++++++--- docs/technical-note.md | 5 +-- evaluation/README.md | 2 +- evaluation/adapters/ops_trace.py | 3 +- evaluation/swe_bench_pro_on_demand.py | 6 ++-- gitops/README.md | 13 ++++++++ launch.sh | 2 +- runtime/Cargo.toml | 15 +++++++++ runtime/README.md | 16 ++++++++++ {src => runtime/src}/agent.rs | 0 {src => runtime/src}/authority.rs | 0 {src => runtime/src}/config.rs | 0 {src => runtime/src}/dag.rs | 0 {src => runtime/src}/decision.rs | 0 {src => runtime/src}/linux_privilege.rs | 0 {src => runtime/src}/main.rs | 0 {src => runtime/src}/policy.rs | 0 {src => runtime/src}/prod_ops.rs | 7 ++-- {src => runtime/src}/prompt_bundle.rs | 0 {src => runtime/src}/role_sandbox.rs | 0 {src => runtime/src}/runtime.rs | 8 +++-- {src => runtime/src}/session_control.rs | 2 +- {src => runtime/src}/snapshot.rs | 0 {src => runtime/src}/state.rs | 0 {src => runtime/src}/subagent.rs | 0 {src => runtime/src}/supervisor.rs | 0 {src => runtime/src}/workflow.rs | 0 tests/run.sh | 4 +-- tests/test_container_runtime_contract.py | 4 +-- tests/test_migration_contracts.py | 7 ++-- tests/test_native_solver_import_model.py | 5 ++- 42 files changed, 157 insertions(+), 44 deletions(-) create mode 100644 audit-log/README.md rename {bin => control-server/bin}/hash-password.mjs (96%) rename {bin => control-server/bin}/prepare-repository.mjs (100%) create mode 100644 docker/README.md rename Dockerfile => docker/runtime/Dockerfile (89%) rename .dockerignore => docker/runtime/Dockerfile.dockerignore (100%) rename {bin => docker/runtime}/container-entrypoint.sh (100%) create mode 100644 gitops/README.md create mode 100644 runtime/Cargo.toml create mode 100644 runtime/README.md rename {src => runtime/src}/agent.rs (100%) rename {src => runtime/src}/authority.rs (100%) rename {src => runtime/src}/config.rs (100%) rename {src => runtime/src}/dag.rs (100%) rename {src => runtime/src}/decision.rs (100%) rename {src => runtime/src}/linux_privilege.rs (100%) rename {src => runtime/src}/main.rs (100%) rename {src => runtime/src}/policy.rs (100%) rename {src => runtime/src}/prod_ops.rs (99%) rename {src => runtime/src}/prompt_bundle.rs (100%) rename {src => runtime/src}/role_sandbox.rs (100%) rename {src => runtime/src}/runtime.rs (99%) rename {src => runtime/src}/session_control.rs (98%) rename {src => runtime/src}/snapshot.rs (100%) rename {src => runtime/src}/state.rs (100%) rename {src => runtime/src}/subagent.rs (100%) rename {src => runtime/src}/supervisor.rs (100%) rename {src => runtime/src}/workflow.rs (100%) diff --git a/.github/workflows/container.yml b/.github/workflows/container.yml index 8b85392..1b816f9 100644 --- a/.github/workflows/container.yml +++ b/.github/workflows/container.yml @@ -31,6 +31,7 @@ jobs: - uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 # v6 with: context: . + file: docker/runtime/Dockerfile push: true tags: ${{ steps.metadata.outputs.tags }} labels: ${{ steps.metadata.outputs.labels }} diff --git a/Cargo.toml b/Cargo.toml index 9075ea7..cd47ed9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,15 +1,4 @@ -[package] -name = "multiagent" -version = "0.1.0" -edition = "2021" -rust-version = "1.98" -description = "Typed control plane for the Multiagent orchestration framework" -license = "MIT" - -[dependencies] -chrono = { version = "0.4.45", default-features = false, features = ["clock"] } -fs2 = "0.4.3" -libc = "0.2.189" -serde = { version = "1.0.228", features = ["derive"] } -serde_json = "1.0.138" -sha2 = "0.10.9" +[workspace] +members = ["runtime"] +default-members = ["runtime"] +resolver = "2" diff --git a/README.md b/README.md index 363439c..fe48e2a 100644 --- a/README.md +++ b/README.md @@ -20,7 +20,7 @@ Production operations are driven by authoritative Markdown runbooks rather than Users are configured in a mounted JSON file. Passwords must be scrypt hashes, never plaintext: ```bash -node bin/hash-password.mjs operator +node control-server/bin/hash-password.mjs operator ``` The mounted file has this shape: @@ -91,6 +91,21 @@ and authenticate at least one supported coding-agent CLI. Python 3.8+ is used only by evaluation and evidence-analysis tools, not the production control plane. +## Repository layout + +- `client/` contains the independently distributed terminal client. +- `control-server/` contains the authenticated thread gateway. +- `runtime/` contains the Rust session runtime and supervisor package. +- `audit-log/` reserves the independent audit-service boundary for the next + implementation phase; phase 1 contains no audit-service behavior. +- `docker/` contains component image definitions and container entrypoints. +- `gitops/` documents the deployment integration boundary. Production GitOps + resources remain owned by the separate `InternalServices` repository. + +Portable prompts, contracts, and runbook examples remain at the repository root +because they are shared framework artifacts rather than executable component +source. + ## Quick Start Run: diff --git a/audit-log/README.md b/audit-log/README.md new file mode 100644 index 0000000..d12f9b0 --- /dev/null +++ b/audit-log/README.md @@ -0,0 +1,9 @@ +# Audit log service + +This directory reserves an independent component boundary for the audit log +service planned for phase 2. + +Phase 1 contains no audit-service executable, storage implementation, network +API, identity, signing authority, or image pipeline. Those behaviors require a +separate architecture decision and will be implemented only after the +repository-layout pull request is merged. diff --git a/bin/hash-password.mjs b/control-server/bin/hash-password.mjs similarity index 96% rename from bin/hash-password.mjs rename to control-server/bin/hash-password.mjs index 9b0f068..be6c711 100644 --- a/bin/hash-password.mjs +++ b/control-server/bin/hash-password.mjs @@ -3,7 +3,7 @@ import crypto from "node:crypto"; const username = process.argv[2]; if (!username || !/^[a-zA-Z0-9._-]{1,64}$/.test(username)) { - console.error("usage: bin/hash-password.mjs USERNAME"); + console.error("usage: control-server/bin/hash-password.mjs USERNAME"); process.exit(2); } diff --git a/bin/prepare-repository.mjs b/control-server/bin/prepare-repository.mjs similarity index 100% rename from bin/prepare-repository.mjs rename to control-server/bin/prepare-repository.mjs diff --git a/control-server/test/prepare-repository.test.mjs b/control-server/test/prepare-repository.test.mjs index a91b239..5a2ecac 100644 --- a/control-server/test/prepare-repository.test.mjs +++ b/control-server/test/prepare-repository.test.mjs @@ -4,7 +4,7 @@ import fs from "node:fs"; import os from "node:os"; import path from "node:path"; import test from "node:test"; -import { githubRepositoryFromUrl, issueAppJwt, issueInstallationToken, prepareRepository } from "../../bin/prepare-repository.mjs"; +import { githubRepositoryFromUrl, issueAppJwt, issueInstallationToken, prepareRepository } from "../bin/prepare-repository.mjs"; test("GitHub repository URLs are parsed without accepting credentials or extra paths", () => { assert.deepEqual(githubRepositoryFromUrl("https://github.com/MoveIndustries/sdk.git"), { owner: "MoveIndustries", repository: "sdk" }); diff --git a/docker/README.md b/docker/README.md new file mode 100644 index 0000000..8ba6124 --- /dev/null +++ b/docker/README.md @@ -0,0 +1,14 @@ +# Container images + +Component image definitions and their container-specific entrypoints live in +this directory. Build the current session-runtime/control-gateway image from the +repository root with: + +```bash +docker build -f docker/runtime/Dockerfile -t multiagent:local . +``` + +The repository root remains the build context so the image can consume the +runtime package, control server, portable framework assets, and shared +contracts. Environment-specific deployment configuration is intentionally not +part of these image definitions. diff --git a/Dockerfile b/docker/runtime/Dockerfile similarity index 89% rename from Dockerfile rename to docker/runtime/Dockerfile index d481d2d..fbdebc4 100644 --- a/Dockerfile +++ b/docker/runtime/Dockerfile @@ -2,7 +2,7 @@ FROM rust:1.98-bookworm AS multiagent-builder WORKDIR /src COPY . . -RUN cargo build --release --locked +RUN cargo build --release --locked --package multiagent FROM node:22-bookworm-slim @@ -19,7 +19,9 @@ COPY control-server/package*.json control-server/ RUN cd control-server && npm ci --omit=dev COPY . . COPY --from=multiagent-builder /src/target/release/multiagent /opt/multiagent/bin/multiagent -RUN chmod +x launch.sh bin/*.sh bin/*.mjs \ +RUN install -m 0755 docker/runtime/container-entrypoint.sh /opt/multiagent/bin/container-entrypoint.sh \ + && install -m 0755 control-server/bin/prepare-repository.mjs /opt/multiagent/bin/prepare-repository.mjs \ + && chmod +x launch.sh control-server/bin/*.mjs \ && groupadd --gid 10000 multiagent-control \ && groupadd --gid 10001 multiagent-role \ && groupadd --gid 10004 multiagent-credentials \ diff --git a/.dockerignore b/docker/runtime/Dockerfile.dockerignore similarity index 100% rename from .dockerignore rename to docker/runtime/Dockerfile.dockerignore diff --git a/bin/container-entrypoint.sh b/docker/runtime/container-entrypoint.sh similarity index 100% rename from bin/container-entrypoint.sh rename to docker/runtime/container-entrypoint.sh diff --git a/docs/architecture/system-architecture.md b/docs/architecture/system-architecture.md index 2ca7dc2..dfbc85e 100644 --- a/docs/architecture/system-architecture.md +++ b/docs/architecture/system-architecture.md @@ -87,6 +87,29 @@ The deployment may also place a trusted repository-preparation init container in front of a session runtime. That init container is not an agent and is not part of the orchestrator's production-operation path. +## Repository component layout + +Executable components and deployment integration surfaces have explicit +top-level ownership boundaries: + +- `client/` owns the terminal client package. +- `control-server/` owns the authenticated control gateway package. +- `runtime/` owns the Rust session runtime, supervisor, and role-confinement + package. +- `audit-log/` is reserved for the independent audit service planned for a + later architecture and implementation phase. Its presence in the phase-one + layout grants it no authority and changes no trace behavior. +- `docker/` owns component image definitions and container entrypoints, but not + deployment secrets or environment-specific configuration. +- `gitops/` documents the application-to-deployment contract. Concrete GitOps + resources, identities, endpoints, storage, and secrets remain owned by the + separate `InternalServices` repository. + +Portable prompts, contracts, and runbook examples remain shared framework +artifacts at the repository root. Directory placement must not be interpreted +as authority: the component ownership table and accepted architecture decisions +remain controlling. + ## Accepted architecture decisions ### AD-001: The authenticated client user is the authorizing user @@ -120,10 +143,11 @@ preventing client-only ID or lifecycle behavior from drifting from the server contract. The terminal-client implementation lives in the top-level `client/` package. -The `control-server/` package contains no client source or executable, and the -control-server container image excludes `client/`. This filesystem and package -boundary prevents the independently distributed caller from importing trusted -server internals; the public HTTP API is their only integration surface. +The `control-server/` package contains no client source or executable, the +session runtime implementation lives in the top-level `runtime/` package, and +the control-server container image excludes `client/`. These filesystem and +package boundaries prevent the independently distributed caller from importing +trusted server internals; the public HTTP API is its only integration surface. ### AD-002: There is one supervisor per execution session diff --git a/docs/technical-note.md b/docs/technical-note.md index 5f89002..58aef82 100644 --- a/docs/technical-note.md +++ b/docs/technical-note.md @@ -121,8 +121,9 @@ no shared mutable state except declared artifacts. scorer-only metadata outside every agent context. This repository implements the snapshot primitive in -[`../src/snapshot.rs`](../src/snapshot.rs) and durable hash-bound finding/TODO -gate integration in [`../src/subagent.rs`](../src/subagent.rs). Benchmark +[`../runtime/src/snapshot.rs`](../runtime/src/snapshot.rs) and durable hash-bound +finding/TODO gate integration in +[`../runtime/src/subagent.rs`](../runtime/src/subagent.rs). Benchmark adapters do not repeat these checks before submitting a workspace. ## Improvements over a single unconstrained agent loop diff --git a/evaluation/README.md b/evaluation/README.md index 7389816..25a6aa7 100644 --- a/evaluation/README.md +++ b/evaluation/README.md @@ -167,7 +167,7 @@ authority reviewers, workers, verifiers, and final reviews. Build the exact checkout before a live multiagent comparison: ```bash -docker build -t multiagent:ops-trace-current . +docker build -f docker/runtime/Dockerfile -t multiagent:ops-trace-current . ``` Override that image with `MULTIAGENT_OPS_TRACE_IMAGE`. The optional diff --git a/evaluation/adapters/ops_trace.py b/evaluation/adapters/ops_trace.py index 75b69b7..3e48e78 100644 --- a/evaluation/adapters/ops_trace.py +++ b/evaluation/adapters/ops_trace.py @@ -191,7 +191,8 @@ def _run_production_multiagent( if inspected.returncode != 0: raise RuntimeError( f"production multiagent image is unavailable: {image}; " - "build it with `docker build -t multiagent:ops-trace-current .`" + "build it with `docker build -f docker/runtime/Dockerfile " + "-t multiagent:ops-trace-current .`" ) runtime_root = Path(os.environ.get("MULTIAGENT_OPS_TRACE_RUNTIME_ROOT", "/tmp")) diff --git a/evaluation/swe_bench_pro_on_demand.py b/evaluation/swe_bench_pro_on_demand.py index 16c519b..f3e201f 100644 --- a/evaluation/swe_bench_pro_on_demand.py +++ b/evaluation/swe_bench_pro_on_demand.py @@ -245,8 +245,10 @@ def _rust_builder_lines() -> list[str]: "RUN apk add --no-cache musl-dev", "WORKDIR /build", "COPY multiagent/Cargo.toml multiagent/Cargo.lock ./", - "COPY multiagent/src ./src", - "RUN cargo build --release --locked", + "COPY multiagent/runtime/Cargo.toml runtime/Cargo.toml", + "COPY multiagent/runtime/src runtime/src", + "COPY multiagent/contracts contracts", + "RUN cargo build --release --locked --package multiagent", ] @staticmethod diff --git a/gitops/README.md b/gitops/README.md new file mode 100644 index 0000000..435553c --- /dev/null +++ b/gitops/README.md @@ -0,0 +1,13 @@ +# GitOps integration boundary + +This directory documents application-owned deployment contracts. It does not +contain the production GitOps source of truth. + +The separate `InternalServices` repository owns Kubernetes resources, workload +identities, IAM, KMS, secrets, endpoints, storage, ingress, and concrete +runbook artifacts. Application code may define configuration interfaces and +image contracts here, but must not duplicate environment-specific deployment +configuration. + +Phase 2 will update that external GitOps source together with the independent +audit-log image and service deployment. diff --git a/launch.sh b/launch.sh index 151fb3b..9afab1f 100755 --- a/launch.sh +++ b/launch.sh @@ -23,4 +23,4 @@ command -v cargo >/dev/null 2>&1 || { exit 1 } -exec cargo run --quiet --manifest-path "$SCRIPT_DIR/Cargo.toml" -- launch "$@" +exec cargo run --quiet --manifest-path "$SCRIPT_DIR/Cargo.toml" --package multiagent -- launch "$@" diff --git a/runtime/Cargo.toml b/runtime/Cargo.toml new file mode 100644 index 0000000..9075ea7 --- /dev/null +++ b/runtime/Cargo.toml @@ -0,0 +1,15 @@ +[package] +name = "multiagent" +version = "0.1.0" +edition = "2021" +rust-version = "1.98" +description = "Typed control plane for the Multiagent orchestration framework" +license = "MIT" + +[dependencies] +chrono = { version = "0.4.45", default-features = false, features = ["clock"] } +fs2 = "0.4.3" +libc = "0.2.189" +serde = { version = "1.0.228", features = ["derive"] } +serde_json = "1.0.138" +sha2 = "0.10.9" diff --git a/runtime/README.md b/runtime/README.md new file mode 100644 index 0000000..eb2d0bb --- /dev/null +++ b/runtime/README.md @@ -0,0 +1,16 @@ +# Session runtime + +This package contains the Rust `multiagent` binary, including the session +runtime, supervisor, role confinement, workflow state, and coding-agent backend +adapters. + +Build and test it from the repository root through the Cargo workspace: + +```bash +cargo build --locked --package multiagent +cargo test --locked --package multiagent +``` + +The runtime intentionally consumes portable framework assets from the +repository-level `prompts/`, `contracts/`, and `runbooks/` directories. Concrete +deployment configuration and credentials remain outside this package. diff --git a/src/agent.rs b/runtime/src/agent.rs similarity index 100% rename from src/agent.rs rename to runtime/src/agent.rs diff --git a/src/authority.rs b/runtime/src/authority.rs similarity index 100% rename from src/authority.rs rename to runtime/src/authority.rs diff --git a/src/config.rs b/runtime/src/config.rs similarity index 100% rename from src/config.rs rename to runtime/src/config.rs diff --git a/src/dag.rs b/runtime/src/dag.rs similarity index 100% rename from src/dag.rs rename to runtime/src/dag.rs diff --git a/src/decision.rs b/runtime/src/decision.rs similarity index 100% rename from src/decision.rs rename to runtime/src/decision.rs diff --git a/src/linux_privilege.rs b/runtime/src/linux_privilege.rs similarity index 100% rename from src/linux_privilege.rs rename to runtime/src/linux_privilege.rs diff --git a/src/main.rs b/runtime/src/main.rs similarity index 100% rename from src/main.rs rename to runtime/src/main.rs diff --git a/src/policy.rs b/runtime/src/policy.rs similarity index 100% rename from src/policy.rs rename to runtime/src/policy.rs diff --git a/src/prod_ops.rs b/runtime/src/prod_ops.rs similarity index 99% rename from src/prod_ops.rs rename to runtime/src/prod_ops.rs index 3875d17..b367fe7 100644 --- a/src/prod_ops.rs +++ b/runtime/src/prod_ops.rs @@ -1773,9 +1773,10 @@ mod tests { #[test] fn shared_action_permit_fixture_matches_the_rust_contract() { - let fixture: serde_json::Value = - serde_json::from_str(include_str!("../contracts/prod-mcp-action-permit-v1.json")) - .unwrap(); + let fixture: serde_json::Value = serde_json::from_str(include_str!( + "../../contracts/prod-mcp-action-permit-v1.json" + )) + .unwrap(); let request = fixture.get("request").unwrap(); assert_eq!( diff --git a/src/prompt_bundle.rs b/runtime/src/prompt_bundle.rs similarity index 100% rename from src/prompt_bundle.rs rename to runtime/src/prompt_bundle.rs diff --git a/src/role_sandbox.rs b/runtime/src/role_sandbox.rs similarity index 100% rename from src/role_sandbox.rs rename to runtime/src/role_sandbox.rs diff --git a/src/runtime.rs b/runtime/src/runtime.rs similarity index 99% rename from src/runtime.rs rename to runtime/src/runtime.rs index acaefeb..1ffcbd1 100644 --- a/src/runtime.rs +++ b/runtime/src/runtime.rs @@ -5179,8 +5179,12 @@ fn is_executable(path: &Path) -> bool { } fn framework_root() -> PathBuf { - env_path("MULTIAGENT_FRAMEWORK_ROOT") - .unwrap_or_else(|| PathBuf::from(env!("CARGO_MANIFEST_DIR"))) + env_path("MULTIAGENT_FRAMEWORK_ROOT").unwrap_or_else(|| { + PathBuf::from(env!("CARGO_MANIFEST_DIR")) + .parent() + .expect("runtime package must live below the framework root") + .to_path_buf() + }) } fn env_nonempty(key: &str) -> Option { diff --git a/src/session_control.rs b/runtime/src/session_control.rs similarity index 98% rename from src/session_control.rs rename to runtime/src/session_control.rs index 2e9be5c..7a6b605 100644 --- a/src/session_control.rs +++ b/runtime/src/session_control.rs @@ -216,7 +216,7 @@ mod tests { #[test] fn session_ids_match_the_shared_control_plane_contract() { let vectors: serde_json::Value = - serde_json::from_str(include_str!("../contracts/session-id-vectors.json")).unwrap(); + serde_json::from_str(include_str!("../../contracts/session-id-vectors.json")).unwrap(); for value in vectors["valid"].as_array().unwrap() { assert!(validate_session_id(value.as_str().unwrap()).is_ok()); } diff --git a/src/snapshot.rs b/runtime/src/snapshot.rs similarity index 100% rename from src/snapshot.rs rename to runtime/src/snapshot.rs diff --git a/src/state.rs b/runtime/src/state.rs similarity index 100% rename from src/state.rs rename to runtime/src/state.rs diff --git a/src/subagent.rs b/runtime/src/subagent.rs similarity index 100% rename from src/subagent.rs rename to runtime/src/subagent.rs diff --git a/src/supervisor.rs b/runtime/src/supervisor.rs similarity index 100% rename from src/supervisor.rs rename to runtime/src/supervisor.rs diff --git a/src/workflow.rs b/runtime/src/workflow.rs similarity index 100% rename from src/workflow.rs rename to runtime/src/workflow.rs diff --git a/tests/run.sh b/tests/run.sh index 59b5025..078a76c 100755 --- a/tests/run.sh +++ b/tests/run.sh @@ -1083,7 +1083,7 @@ assert_file_contains "$ROOT/runbooks/github-repository-work.md" "explicitly auth assert_file_contains "$ROOT/evaluation/README.md" "large-update-300" assert_file_contains "$ROOT/evaluation/README.md" "Low-signal orchestration cases" assert_file_contains "$ROOT/orchestrator_prompt.md" "MULTIAGENT_PROMPT_MODULE_ROOT" -assert_file_contains "$ROOT/src/runtime.rs" "MULTIAGENT_PROMPT_MODULE_ROOT" +assert_file_contains "$ROOT/runtime/src/runtime.rs" "MULTIAGENT_PROMPT_MODULE_ROOT" assert_file_not_contains "$ROOT/launch.sh" "python" assert_file_contains "$ROOT/prompts/verifier.md" "state-space partition audit" assert_file_contains "$ROOT/prompts/verifier.md" "mixed-category, unknown/forward-compatible variant" @@ -1170,7 +1170,7 @@ assert_file_contains "$ROOT/prompts/contracts/orchestration-invariants.md" "prom assert_file_contains "$ROOT/prompts/contracts/orchestration-invariants.md" "build-verification-passed:" assert_file_contains "$ROOT/prompts/playbooks/finding-todo-loop.md" "Do not create or reopen a todo from command evidence bound" assert_file_contains "$MULTIAGENT" subagent '--own|--owned-path)' -assert_file_contains "$ROOT/src/runtime.rs" 'crate::snapshot::canonical_diff(&cfg.root, "HEAD")' +assert_file_contains "$ROOT/runtime/src/runtime.rs" 'crate::snapshot::canonical_diff(&cfg.root, "HEAD")' assert_file_contains "$MULTIAGENT" subagent '--source-finding-id|--finding)' assert_file_contains "$MULTIAGENT" subagent '--role)' assert_file_contains "$ROOT/prompts/roles/acceptance-scout.md" "declared-type ownership risk" diff --git a/tests/test_container_runtime_contract.py b/tests/test_container_runtime_contract.py index 4235c70..aabf1d6 100644 --- a/tests/test_container_runtime_contract.py +++ b/tests/test_container_runtime_contract.py @@ -7,12 +7,12 @@ class ContainerRuntimeContractTests(unittest.TestCase): def test_session_bootstrap_does_not_read_trace_archive(self): - entrypoint = (ROOT / "bin/container-entrypoint.sh").read_text() + entrypoint = (ROOT / "docker/runtime/container-entrypoint.sh").read_text() self.assertNotIn("MULTIAGENT_STATE_S3_URI", entrypoint) self.assertNotIn("aws s3 sync", entrypoint) def test_state_parent_is_traversable_by_isolated_roles_but_not_writable(self): - runtime = (ROOT / "src/runtime.rs").read_text() + runtime = (ROOT / "runtime/src/runtime.rs").read_text() state_entry = runtime.split('base.join("state")', 1)[1].split("),", 1)[0] self.assertIn("config::ROLE_GID", state_entry) self.assertIn("0o2750", state_entry) diff --git a/tests/test_migration_contracts.py b/tests/test_migration_contracts.py index 40fc745..365bd5e 100644 --- a/tests/test_migration_contracts.py +++ b/tests/test_migration_contracts.py @@ -74,8 +74,11 @@ class MigrationCliContractTest(unittest.TestCase): def test_launch_is_the_only_production_shell_bootstrap(self): self.assertTrue((PROJECT_ROOT / "launch.sh").is_file()) self.assertEqual( - list((PROJECT_ROOT / "bin").glob("*.sh")), - [PROJECT_ROOT / "bin" / "container-entrypoint.sh"], + list(PROJECT_ROOT.glob("*.sh")), + [PROJECT_ROOT / "launch.sh"], + ) + self.assertTrue( + (PROJECT_ROOT / "docker" / "runtime" / "container-entrypoint.sh").is_file() ) launch = (PROJECT_ROOT / "launch.sh").read_text(encoding="utf-8") self.assertIn('exec "$MULTIAGENT_BIN" launch "$@"', launch) diff --git a/tests/test_native_solver_import_model.py b/tests/test_native_solver_import_model.py index 72a4865..701004c 100644 --- a/tests/test_native_solver_import_model.py +++ b/tests/test_native_solver_import_model.py @@ -108,7 +108,10 @@ def test_bake_copies_package_initializers(self) -> None: manager._rust_builder_lines()[0], "FROM rust:1.85-alpine AS multiagent-builder", ) - self.assertIn("RUN cargo build --release --locked", manager._rust_builder_lines()) + self.assertIn( + "RUN cargo build --release --locked --package multiagent", + manager._rust_builder_lines(), + ) def test_native_modules_have_strict_relative_imports(self) -> None: failures = []