Repository navigation
substrate: make Kubernetes and Direct first-class in the substrate contract - #1153
Conversation
|
Thanks for opening this pull request! A SPACE maintainer will take a look. CONTRIBUTING.md explains how we review outside contributions. |
d74a5e5 to
67a713e
Compare
…ntract The substrate AGENTS.md told contributors to implement new lifecycle operations for Kubernetes only, return SubstrateError::Unsupported on Direct unless examples/first_sandbox.py used the call, and add a required SubstrateAdapter method for each new operation. Both substrates are supported, so that text left Direct further behind with each feature, grew the trait, and invited Kubernetes-only repair loops that give Direct no failure exit. Replace "Direct Substrate Contract" with "Substrate contract": - both substrates are supported, and regressing either is a regression; Direct is the planned base for pod-less hosting on Kubernetes nodes; - an adapter should answer node and execution questions only. Placement, admission, warm-pool policy, lifecycle transitions, leases, generations, retries, repair, drain and evacuation are core logic that belongs once in shared code (the sandbox controller, pplx-space-sandbox-store). The core logic still in the adapters (Direct's worker and restore-candidate retries and restore lease, Kubernetes' restore leases, started recovery and redrive, the Kubernetes-only pplx-space-placement machine) is named as debt; - an adapter method is added only for an infrastructure action and lands for both substrates; every Unsupported needs a gap-table row, a change to Direct updates the direct.rs module doc, and closing a gap deletes its row. The old rule that a Direct change belongs in its own PR is dropped, since new operations now land on both substrates in one PR; - new sandbox and node state reconcilers run for both substrates; the existing Kubernetes-only ones are debt; - capabilities state infrastructure facts, not disabled features; supports_node_drain is named as debt. The archcheck-backed rules are kept, condensed, and say where their ratchets stop. The required-method rule keeps its reason (a forgotten forwarding arm gives both substrates the trait default) and holds until dispatch is generated. The tests section asks for both substrates only where the path differs by substrate, names the shared Direct test helper (test_support::direct_substrate with a SimWorkerHarness worker), and states that only the try_pg_test_db fixtures skip under SPACE_TEST_DEPS_OPTIONAL. The direct.rs module doc's list of what Direct does not do becomes a gap table (refused or missing / effect today / removed by) with the same gaps. The resolves_cold_create_shape doc comment in mod.rs no longer says Direct refuses a one-shot create with custom vCPU or memory; Direct sends them on its separate start call. Links to the renamed heading are updated. No code changes.
67a713e to
4f5b14f
Compare
A gap row now names who owns closing it as well as the change that removes it, and a row without an owner and a removal plan fails review the same way an Unsupported without a row does. The direct.rs gap table gains an Owner column; the workstream owner holds every existing row until it is reassigned.
|
Heads-up for open work that cites the substrate contract this PR replaces.
|
Review — 2 findingsLow
Checked and holds:
Not checked: I didn't run the doc build or Verified against |
the-gigi-pplx
left a comment
There was a problem hiding this comment.
Approved. 2 non-blocking findings in the review comment above.
|
The new contract is clear. I have one suggestion about how the gap table can be checked.
|
Summary
The substrate
AGENTS.mdtold contributors to implement new lifecycle operations for Kubernetes only, and to returnSubstrateError::Unsupportedon Direct unlessexamples/first_sandbox.pyused the call. It also asked for a requiredSubstrateAdaptermethod for each new operation. Both substrates are supported, so that text left Direct further behind with each feature, grew the trait, and invited Kubernetes-only repair loops that give Direct no failure exit.This replaces "Direct Substrate Contract" with "Substrate contract" in
crates/libs/api/src/controllers/substrate/AGENTS.md:controllers/sandbox/andpplx-space-sandbox-store. The section names the core logic still in the adapters as debt:pplx-space-placementmachine.Unsupportedneeds a row in the gap table that names an owner and the change that removes it.direct.rsmodule doc, and the PR that closes a gap deletes its row.Unsupportedtrait defaults andsupports_node_drain, a capability for a missing feature, are debt, not precedent.The archcheck-backed rules are kept, condensed, and say where their ratchets stop:
kubernetes_accesscannot tell a presence test from a use,substrate_literalscatches only the common forms, anddirect_tablesis advisory. The required-method rule keeps its reason: a forgotten forwarding arm gives both substrates the trait default. It holds until dispatch is generated.The tests section:
crate::test_support::direct_substratewith aSimWorkerHarnessworker);try_pg_test_db*fixtures skip, and only whenSPACE_TEST_DEPS_OPTIONALis set.The
direct.rsmodule doc's list of what Direct does not do becomes a gap table (refused or missing / effect today / owner / removed by) with the same gaps; each existing row's owner is the PR author until it is reassigned.The
resolves_cold_create_shapedoc comment inmod.rsno longer says Direct refuses a one-shot create with custom vCPU or memory. That refusal is gone; Direct sends custom vCPU or memory on its separate start call.Links to the renamed heading are updated in
crates/libs/api/AGENTS.md,crates/libs/cluster/controller/server/AGENTS.mdandcrates/libs/internal/api/server/AGENTS.md.No Rust behavior changes: only doc comments change in
direct.rsandmod.rs.Validation
All at this head:
.mdfiles: 2 links, 0 broken. The#substrate-contractanchor resolves.rg -n "direct-substrate-contract|Direct Substrate Contract|Direct substrate contract"finds no matches.cargo fmt -p pplx-space-api --checkpasses.RUSTDOCFLAGS="-D rustdoc::broken_intra_doc_links" cargo doc -p pplx-space-api --no-deps --document-private-itemsreports only errors already on main: 10 unresolved links and onerunfunction/module ambiguity inlib.rs. None are indirect.rsor in the editedmod.rslines.cargo archexits 0 with 113 advisory findings and 0 required. It ran without base baselines, so theno_new_entriesandno_raised_capschecks were skipped.Instruction-chain budget (bytes; root
AGENTS.mdplus each chain, against a 32,768 B limit):AGENTS.mdcrates/libs/api+…/controllers/substratecrates/libs/apicrates/libs/cluster/controller/servercrates/libs/internal/api/serverThe contract section is 6,220 B, against 5,450 B for the old "Direct Substrate Contract" section. It grew on purpose: it now says where core logic lives, what each archcheck ratchet does not catch, and the upkeep rule for the
direct.rsmodule doc. The largest chain is still well under the limit.No tests were run because there is no behavior change.
Severity and risk
Severity: moderate. These are agent and contributor instructions, and the old text steered new work away from Direct.
Risk: documentation only; nothing at runtime changes. Open PRs and an RFC that cite the old heading or the old own-PR rule will need to rebase their references. If this conflicts with #1157 on the
as_kubernetes()sentence, whichever lands second rebases. To roll back, revert the commit.Not covered
Tracked as follow-ups:
run_reconcilersinto sandbox/node-state loops or Kubernetes-object loops, and naming them in the gap row.space-rust-developmentskill (a plugin change that needs a version bump).supports_node_pool_placementandresolves_cold_create_shapeare feature-off capabilities.pplx-space-placement.Unsupportedwith a gap row, once the Direct lane runs as a required check. For now a row must name an owner and the change that removes it.AI assistance: An AI agent (Claude Code) drafted all of the documentation and doc-comment changes and this description.