Repository navigation
docs: localized AGENTS.md for sbx-mgr, node-mgr and the api crate - #275
Conversation
07744e5 to
e89d061
Compare
Review — 7 findingsMedium
Low
I checked the other mechanism, file and function claims in the three AGENTS.md files and the conventions section against the source at this head, and they hold. Examples: Verified against |
the-gigi-pplx
left a comment
There was a problem hiding this comment.
Approved. 7 non-blocking findings in the review comment above.
e89d061 to
ff7c8be
Compare
|
Thanks, all seven are addressed in ff7c8be (one commit, docs only):
The socket and test-default rules are now worded so they stay accurate whichever of the seam PRs (#296/#299, #298) lands first. |
Agents changing the sandbox-lifecycle crates kept missing crate-local constraints. Add short AGENTS.md files (with CLAUDE.md symlinks) for crates/libs/sbx/mgr/server, crates/libs/node/mgr/server and crates/libs/api. Each states contracts for new changes, and names an existing exception only where one or two keep the rule true: - sbx-mgr: sandboxes.state goes through compare-and-set writers in src/db. Child tables are registered in the manual delete cascade. New node-manager RPC fields carry domain identifiers; existing path fields are validated by node-manager. Tests must not dial node-manager's fixed socket (connect(), connect_once(), lazy()), and the service's Default options read host state. - node-mgr: new RPCs take domain identifiers and existing path fields are validated. Privileged inputs are pinned, pinned subvolumes change only through the pinned-descriptor helpers, and host tools and nft mutations have named owners. Supervisor replay is limited to untransmitted failures (a get_or_connect dial error and the two predicates), and is_client_connect_failure is shared by every gRPC client. Unit-test services inject test-owned replacements for host-reading defaults. - api: new Kubernetes substrate SQL goes in store/ with db_context error mapping. PerSandboxSetup covers cold and pooled setup, and the route manifest and M1 baseline hold the public contract. Generic guidance lives once in docs/rust/space-conventions.md, and each file points to it: - "Tests run as root on the CI host": the Rust job is privileged, uses host networking and includes ignored tests, so tests leave alone host state they do not own. Fixtures fail closed, and host mutation needs an environment opt-in. Env-dependent tests give parsers explicit inputs (TestEnv), as docs/rust/unsafe.md says; only real startup-environment behavior runs in a child process through enter_test_process. - "Log targets": bare tracing targets follow module_path!(), so a moved module breaks exact-value @target filters. - The SQL section adds that caller SQL must not go through a wrapper that applies sql! for it, naming the migrator's bootstrap_roles.rs execute helper as the known exception. The largest instruction chain stays root + infra/space/kind (12,475 bytes), well under Codex's 32 KiB budget.
ff7c8be to
17272b0
Compare
Summary
Agents changing the sandbox-lifecycle crates kept missing crate-local constraints. This adds short
AGENTS.mdfiles, each with aCLAUDE.mdsymlink, for:crates/libs/sbx/mgr/servercrates/libs/node/mgr/servercrates/libs/api(crate level; it points tosrc/controllers/substrate/AGENTS.md)The files state rules for new changes, and name an existing exception only where one or two keep the rule true. Every sentence was checked against code at this head. The files don't name helpers or fixtures that open PRs (#278, #296, #298, #299) add or change, so they stay accurate whichever of those lands first.
The generic guidance appears once, in
docs/rust/space-conventions.md, and each file points to it:--privileged --network host. Fixtures must fail closed, and host mutation needs an environment opt-in.tracingtargets followmodule_path!(), so a module move breaks exact-value@targetfilters. Pin those targets with a literaltarget: "…";const LOG_TARGET = module_path!()survives a child-module extraction but not a file move.Rules
sbx-mgr
sandboxes.stateis written only throughsrc/dbwriters.src/db; no generic writer compares against the caller's observed state.delete_sandbox_child_rows.service/adapter.rsdelegates mostly to thegrpc_*modules.dest_dir,artifact_dir) are validated by node-manager.connect(),connect_once(),lazy()); give the code under test a test-served node-manager.shutdown_tokenfirst protects only code paths that check it before dialing.SandboxManagerServiceOptions::default()reads host state.db::open().node-mgr
btrfs.rs,clone_cleanup.rs). Where the CLI is unavoidable, it is bound to the pinned descriptor in a private mount namespace (service/artifact_fs/receive.rs).host_command.rsandnftmutations throughfirewall.rs. Exceptions: the startup supervisor activator inrun.rsand the non-Linuxnet/fallback.rs.get_or_connectdial error,is_client_connect_failureandis_request_refused_before_transmission.is_client_connect_failurelives incrates/libs/common/grpc/src/retry.rs, so changing it changes every gRPC client.NetworkPool::open.api
store/withDbContext::db_context. Warm-pool slot rows belong toWarmPoolStore.PerSandboxSetup, so per-sandbox setup goes there./v1operations, and the M1 baseline is a compatibility floor, not a snapshot to refresh.routes/e2b/.AppState::from_pooland thefrom_envconstructors read env. Test a parser through its explicit-input form (from_environment, withTestEnv) where one exists; useenter_test_processonly for tests that need the process-env constructors.Shared guidance in
docs/rust/space-conventions.mddocs/rust/unsafe.md: give parsers explicit inputs (TestEnv) first. Only real startup-environment behavior runs in a child process throughenter_test_process. Neverstd::env::set_var.module_path!()constants do not survive moving or renaming their defining module.sql!for it. Theexecutehelper incrates/libs/db/migrator/src/bootstrap_roles.rsis named as the known exception, not a precedent.The api post-result lifecycle write rules are left out on purpose.
Size and budget
crates/libs/sbx/mgr/server/AGENTS.mdcrates/libs/node/mgr/server/AGENTS.mdcrates/libs/api/AGENTS.mdThe largest instruction chain is unchanged: root
AGENTS.md(5,745) +infra/space/kind/AGENTS.md(6,730) = 12,475 bytes. The deepest new chain, root +crates/libs/api+substrate, is 9,088 bytes. Both are under the 32 KiB budget.Validation
CLAUDE.mdsymlinks are mode 120000 and resolve to their siblingAGENTS.md.Follow-ups
These test-safety gaps are outside this docs-only PR:
loop_devicesignored test and api e2btest_state()default Postgres URL: fixed in tests: keep three tests off host state they don't own #278 (open).enter_sim_worker_processhost token read: it unsets the token-path variables, sobearer_token.rsfalls back to/var/run/space-auth/*.tokenon the host before the synthetic env token. tests: pin publication convergence and other lifecycle behavior from #272 #290 adds an owned-token-files variant for its own tests. The ~60 existing callers still use the old helper.runtime_liveness_optionsandSandboxManagerService::newdefaults: not owned by an open PR. LOW in CI, because CI runners have no production sockets; the exposure is on hosts running SPACE node services.service_for_unit_testshost-reading defaults: test seams in node-mgr: let tests inject the runtime supervisor and host-reading defaults #298 (open).🤖 Generated with Claude Code