Skip to content

[api] boot a start's or resume's runtime upgrade in its pod and read its outcome from the node - #1708

Draft
the-gigi-pplx wants to merge 1 commit into
gigi/pla-7133-stay-stopped-runtime-upgrade-1from
gigi/pla-7133-stay-stopped-runtime-upgrade-2
Draft

the-gigi-pplx wants to merge 1 commit into
gigi/pla-7133-stay-stopped-runtime-upgrade-1from
gigi/pla-7133-stay-stopped-runtime-upgrade-2

Conversation

@the-gigi-pplx

@the-gigi-pplx the-gigi-pplx commented Nov 7, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

With SPACE_RUNTIME_UPGRADE_AT_ACTIVATION_ENABLED on, a Kubernetes start or resume that decides a runtime upgrade boots that upgrade in the sandbox's pod and reads its outcome from the node before the Wake, instead of failing. With the flag off, which is the default, start and resume behave as before.

Api paths below are under crates/l40_api/api/src/controllers/substrate/. "Booting an upgrade in its pod" and "Upgrading at resume and start" in docs/execution-environments.md are the long form.

Terms

  • Runtime upgrade: moving a stopped or suspended sandbox from the execution environment it last ran under to a certified target environment, decided at start or resume by activation_runtime_upgrade (kubernetes/runtime_upgrade.rs) and carried out by sandbox-manager's UpgradeRuntime.
  • Operation: one upgrade, named by an operation id derived from the sandbox, the move, its cause and the checkpoint or execution being moved, so every retry names the same upgrade under the same authorization.
  • runtime-upgrade pod mode: a restore pod whose space.pplx.net/checkpoint is runtime-upgrade and whose space.pplx.net/runtime-upgrade-* annotations carry the operation (PR [sbx-mgr] boot a Kubernetes runtime upgrade in its pod's shim through a runtime-upgrade checkpoint #1380). The pod's shim calls UpgradeRuntime from its container create.
  • Execution: the active row in sandbox_k8s_executions for a sandbox. It records the pod name (which fixes the generation), the pod UID once a materialization persists it, and the activation attempt holding its claim.
  • Activation attempt and joiner: the start or resume holding the execution's claim, and a concurrent start or resume that joined that claim instead of taking its own.
  • Settled: the wait has an outcome it can act on: reached the target, rolled back, refused, or not started. Anything else waits until the activation's readiness deadline.
  • Kept pod: an upgrade pod a restoring sandbox keeps whatever a later resume decides, since its upgrade may have retired the checkpoint the resume read.
  • Stranded: a sandbox whose environment may no longer execute and that has no certified edge to leave it; its activation is refused with FailedPrecondition (412).

The problem

PR #1015 decides a runtime upgrade at start and resume and sends it on the activation's Wake as WakeRequest.runtime_upgrade. On Kubernetes a sandbox boots in its pod's containerd shim at container create, never from the Wake, so an upgrade sent there can't take effect. PR #1380 made sandbox-manager refuse that field for a Kubernetes route identity, and added the runtime-upgrade pod mode for the shim to boot it instead. Nothing renders that mode yet, so with the flag on, every Kubernetes start or resume that decides an upgrade fails.

Moving the upgrade onto the pod raises questions the Wake path never had to answer:

  1. The pod's create is the upgrade, and kubelet retries a failed create from the same pod. The control plane learns the outcome only by asking the node, and the node's report can still be an earlier pod's.
  2. A pod carrying an upgrade may be booting it even when the activation that placed it failed afterwards, so that failure isn't clean, and deleting the pod or reverting a resume to suspended could interrupt a boot or lose a checkpoint the upgrade retired.
  3. Pods that existing materialization paths would adopt or replace now carry an operation, and adopting a pod carrying another operation, or replacing one that's booting, starts or loses the wrong upgrade.

How this fixes it

  • Render the mode for start and resume. PodCreateContext::upgrading_runtime (kubernetes/pod_ops.rs, kubernetes/pod_ops/create_request.rs) attaches the decided upgrade, with target state started, to the user-restore context a start or resume creates. A cross-node re-drive of an unschedulable source-pinned pod carries the same upgrade (kubernetes/pod_ops/redrive.rs). Every other pod kind is built without one. EnvironmentMove::wake_upgrade is gone (runtime_upgrade.rs), so no Kubernetes Wake carries runtime_upgrade.

  • Read the outcome before the Wake. await_pod_runtime_upgrade (kubernetes/pod_runtime_upgrade.rs) polls GetRuntimeUpgrade on the pod's node by node name, through node_worker_client (kubernetes/pod_ops/worker_clients.rs, which teardown's retire-by-node route now shares), since a pod whose create failed has no address. Each read names the pod's attempt (GetRuntimeUpgradeRequest.attempt_id, which on Kubernetes is the pod UID the shim names its attempt by: the pod at the name or, once it's gone, the one the wait knew), so a node from this release answers that attempt's own outcome, and absent in place of another attempt's; an older node answers the operation's latest, and the table below still settles only on a report naming the pod. In the table, "names this pod" means the report's attempt_id or refused_attempt_id is the pod's UID. Each report is read with the pod at the execution's name:

    Report started target
    Upgraded or already on target refused_attempt_id names this pod: refused (retryable 503), and the pod is deleted. Otherwise it's reached once the pod's container runs, refused (503) once the container has ended or the pod is gone, and it waits until then
    Rolled back or refused attempt_id names this pod: settled whatever its containers show (a rollback 503, a refusal 412), and the pod is deleted under its UID. Pod gone: settled only when attempt_id names the UID the wait last saw, or the one the execution recorded. A report naming another pod or none waits, unless the node the pod is bound to (or, with the pod gone, the node a look saw it bound to) reports the operation abandoned since, which settles as not started
    Absent Carrying a refused create the node kept for this pod after the sandbox's row went (refused_attempt_id): settled as that refusal (retryable 503), and the pod is deleted. Otherwise not started (503) once the pod's container has terminated, since the shim's call has returned by then. A failed pod phase, or a pod that's gone, proves nothing and waits. Absent and abandoned settles as not started
    In progress, unspecified, node unreadable Waits

    The Wake then carries no upgrade and only acknowledges the route the pod's execution runs under.

  • Settle only on this pod's own outcome, and fail closed. On every look the wait reads the execution that owns the pod's name. A pod being deleted, or one that isn't the pod the execution recorded, settles nothing, and a settled rollback or refusal deletes its pod under its UID, settling only once that delete lands or fails. A joiner reads the pod from the API on every look and doesn't settle on a missing pod while the execution records none (MissingPod::NotCreatedYet). A report naming no pod, from a sandbox-manager that predates the field, runs to the deadline and keeps the pod and its claim. Each observation runs under max(wait deadline, now + 1 s) (NODE_READ_FLOOR).

  • Answer a settled outcome before any Wake. settle_pod_runtime_upgrade_for_attempt gives up the activation's own attempt, so the retry gets a new pod. A rollback, or a pod the node refused after the target was reached, answers a retryable 503. A refusal the node recorded answers 412, as a stranded sandbox does: the node records only a refusal no retry changes, and a retry decides the same operation from the same inputs.

  • Keep the restore when the upgrade may have retired its checkpoint. A resume whose upgrade reached the target before its pod failed (PodUpgradeFailure::LeftOnTarget) stays restoring on its node rather than reverting to suspended. The node's runtime-exit cleanup stops the sandbox and keeps its disk, and its publication converges the row to stopped. A resume the node rolled back or refused reverts to suspended first and gives its attempt up only afterwards, since the revert retires the restore's execution only while it still carries the attempt (revert_restore_claim_to_suspended).

  • Treat a pod that may run as node work (kubernetes/pod_ops.rs, kubernetes/execution.rs, kubernetes/pod_ops/ensure_pod.rs). A materialization that fails after it created or kept a pod carrying its upgrade isn't a clean failure: a restore stays restoring and keeps its pod, and a start keeps its attempt's claim until the lease ends. The same holds for a create whose answer was lost and whose pod a confirming read doesn't find yet. The attempt holding a creating execution's claim creates a missing upgrade pod at the claim's name (create_missing_upgrade_pod). A pod already there carrying the operation is hydrated from an uncached read, since an interrupted re-drive leaves a successor at the same name and a reflector can still hold the deleted predecessor.

  • One stale-pod rule for upgrade pods (runtime_upgrade_stale_reason, kubernetes/pod_ops/ensure_pod.rs). On every path that could adopt an existing pod:

    • a pod that doesn't carry the operation a materialization renders is replaced under a new generation;
    • a stopped-target placeholder is stale to anything that doesn't render its operation;
    • a pod carrying an upgrade the materialization doesn't render is stale only while the sandbox is still stopped. A restoring sandbox keeps it, and a resume that takes over such a restore settles on the upgrade the pod carries (carried_runtime_upgrade, kept_runtime_upgrade), even when its own decision now strands the sandbox. A kept pod the reflector doesn't hold as the execution records it is confirmed from the API, both when the takeover looks for it and before the materialization refuses to replace it, so a replica that hasn't seen the pod still settles it. That covers a pod whose activation created it and failed to persist it: the execution is still creating with no UID, and the pod at its name counts while its annotations name the execution's generation and it isn't being deleted. The node doesn't read the control plane's policy, so kubelet's retries of that pod can boot the upgrade whatever a later decision says. The takeover reads the kept pod's upgrade before it materializes anything, and settles it first unless its own decision renders that same operation, whether the decision refused, renders no upgrade or renders another. The kept upgrade only settles its pod (PodMaterializationOwnership::runtime_upgrade_kept): the pod is kept whatever its phase, failed or being deleted included, it isn't re-driven, and no new pod is created for it, since the node takes a new pod as a new attempt and a plain replacement could restore from a checkpoint the upgrade retired. A resume that finds the kept pod gone answers retryably and keeps the restore restoring.
  • Stable operation ids and runtime names (runtime_upgrade.rs, kubernetes/runtime_upgrade.rs, kubernetes/store/runtime_upgrade.rs). A started target derives its operation id from its inputs, and every runtime name read into the decision's evidence passes through canonical_runtime, so the node's legacy fc columns match the catalog's firecracker.

A start still falls back to a plain start only when its decision changes, and when the upgrade didn't take effect the published environment stays the old one. The flag applies only to Kubernetes, so Direct activations are unchanged. The wait already reads a stopped target, which nothing here renders yet; that's the next pull request's.

Validation

At this head, on a Linux build box:

  • cargo clippy --workspace --locked --all-targets --all-features -- -D warnings and cargo fmt --all --check: clean.
  • CI's own entry points, ci/scripts/run-rust-checks.sh tests-unprivileged and, as root under ci/scripts/with-nocow-test-filesystem.sh, tests-privileged: 13027 unprivileged tests passed, plus doctests and the feature checks. The privileged lane had 6 failures, all from the build box rather than this change: three fs-verity tests (node-runtime-core verity and artifact_store::execution_cache, whose kernel has no fs-verity), two node-runtime-supervisor contained_launcher::linux tests (unsafe ancestors of the mirrored path), and spaced-guest-worker::embedding (needs a private cgroup namespace). CI's privileged lane covers them.
  • New and rewritten tests:
    • kubernetes::pod_runtime_upgrade::tests: the outcome table above, row by row.
    • kubernetes::tests::runtime_upgrade_dispatch: start and resume against a scripted node and Kubernetes API. The pod carries the decided upgrade and the Wake carries none; a rollback and a refused create answer a retryable 503, and a recorded refusal a 412, each deleting the pod; a retry gets a new pod; a joined claim doesn't settle on a missing pod, and a start's joiner settles once the owner's pod it saw is gone; a resume left on its target stays restoring; a rolled-back resume gives its attempt up after the revert.
    • kubernetes::tests::runtime_upgrade_dispatch::api_faults: a settled pod is never a later attempt's owner pod; a settled pod on a legacy route-less execution keeps it claimable; a settled pod settles only on its own delete; a pod read that never answers holds the wait at most NODE_READ_FLOOR past its deadline; a lost upgrade create keeps its claim; a stale upgrade pod that can't be deleted keeps the claim; a kept restore pod settles on the upgrade it carries, even once its own decision strands the sandbox, including one whose execution records no UID, cached or not; a stranded resume never settles on a pod at the name its execution doesn't own (another generation, one being deleted, or a recovering execution's); a resume hydrates a re-drive's successor, not a cached predecessor carrying the same operation; a takeover never places a new pod for its kept upgrade, whether its decision strands the sandbox or, with the flag off, renders no upgrade, and whether the kept pod failed, is being deleted, is unschedulable, is gone from the API, or is missing from this replica's reflector, with a rollback or the upgrade still in progress; a joiner never takes a cached earlier pod for its owner's; the wait asks the node for the pod it reads; a refused create the node kept after the sandbox's row went settles a start or a resume as it would with the report standing. Each guard on carried_runtime_upgrade's path for an execution with no recorded UID (the creating state, the generation match, the deleting check, the read on a cache miss), the uncached hydrate read, the kept upgrade's keep-the-pod and no-create guards, settling the kept upgrade on a decision that succeeds, the API reads that confirm a kept pod the reflector misses, and the kept refusal an absent report carries, was mutated away in turn, and a test fails for each. The kept upgrade's no-re-drive guard isn't reached by the scripted fixture, so no test fails without it.
    • kubernetes::store::k8s_store_postgres_tests::runtime_upgrade_evidence_tests: the legacy fc runtime spelling matches the catalog.

Not validated: a Kind run. The end-to-end Kind scenario for the start arm (space_smoke) is in a later pull request in the stack, with the trigger it needs.

Not covered

None of these loses a sandbox's disk or checkpoint, and every path that reverts a restore to suspended still needs the node's recorded outcome for that exact pod.

  • A stranded sandbox whose kept pod can't settle stays restoring. A kept pod that's unschedulable, or being deleted with no outcome the node names for it, keeps every stranded takeover waiting out its readiness budget until the pod goes or an operator allows the environment.
  • Marking a pod as possibly running. note_upgrade_pod marks a pod only when it carries the rendered operation. A start that finds an earlier start's pod carrying another operation, and can't delete it, gives up its attempt instead of keeping it until the lease ends.
  • The re-drive mark. The re-drive of an unschedulable source-pinned pod marks the upgrade pod as possibly running before its successor's create is sent, so a re-drive that fails earlier keeps the restore restoring until its lease expires.
  • A fresh resume or a joiner meeting a kept pod. Only a resume that takes over a restoring row settles on a kept pod's upgrade. A fresh resume, or a joiner, that finds one answers retryably, and the next takeover settles it. That includes a pod a settled rollback couldn't delete, which a revert to suspended leaves in place with abandoned-restore retirement off: a fresh resume that then renders no upgrade waits out its readiness budget and leases on it.
  • Transient read errors. A Kubernetes API or Postgres error on a look ends the wait as a failure that may still run, keeping the pod and the attempt until the lease ends, rather than polling again.
  • Where the give-up policy lives. Giving up or keeping the activation attempt on a settled upgrade is decided in the Kubernetes adapter (settle_pod_runtime_upgrade_for_attempt, the restore path in execution.rs), alongside the restore leases controllers/substrate/AGENTS.md already lists as adapter debt.

Dependencies

This is stacked on PR #1707, its base branch, and merges after it. PR #1707 is the top of an eight-PR chain that merges in order: PR #1750 → PR #1751 → PR #1752 → PR #1753 → PR #1754 → PR #1755 → PR #1756 → PR #1707. Together they make sandbox-manager's report name the pod each outcome is for, make a rollback or refusal final for its pod, and add AbandonRuntimeUpgrade, all of which the wait here relies on.

Deploy that chain first. This pull request adds no migrations or stored state, so it rolls out with any api release after it. Turn the flag on only once every worker's shim and sandbox-manager know the runtime-upgrade checkpoint (PR #1380) and run the chain above. An older shim fails the pod without booting anything. Against an older sandbox-manager, whose report names no pod, the wait never settles a rollback: it runs to the activation's deadline and keeps the pod and its claim. Set the flag the same on every api and cluster-controller replica, and give both node-api's policy-mutation trust, which GetRuntimeUpgrade needs (docs/configuration.md).

PR #1714 is stacked on this one, and the rest of the stay-stopped upgrade builds on it.

Severity and risk

Severity: medium. With SPACE_RUNTIME_UPGRADE_AT_ACTIVATION_ENABLED on, every Kubernetes start or resume that decides an upgrade fails today.

Risk: low with the flag off, which is the default. activation_runtime_upgrade then decides nothing, no pod carries an upgrade, and start and resume run as before. Two changes apply regardless of the flag:

  • teardown's retire-by-node dialing through the shared node_worker_client, under the same connect budget;
  • the stale-pod rule and a resume's settle on the upgrade its kept pod carries, which act only on pods carrying runtime-upgrade annotations, and no pod carries them unless the flag was on when it was created.

Roll back by reverting this pull request: it adds no migrations or stored state.

Docs

  • docs/execution-environments.md: "Booting an upgrade in its pod" and "Upgrading at resume and start" now describe the pod dispatch for start and resume, the outcome read and how it settles, the kept-pod and stale-pod rules, and the restore that stays restoring when its upgrade left it on the target.
  • docs/configuration.md: the flag's entry now says a decided upgrade boots in the activation's pod, that the flag waits on every worker's shim and sandbox-manager knowing the runtime-upgrade checkpoint, that node-api's policy-mutation trust is for GetRuntimeUpgrade, and that with the flag off a resume taking over an unsettled restore still settles its kept pod's upgrade first.

AI assistance: Claude Code split this pull request out of a larger change, wrote the code and tests with review, and drafted this description.

@coderabbitai

coderabbitai Bot commented Nov 7, 2026 •

Copy link
Copy Markdown

Caution

Pre-merge checks failed

Please resolve all errors before merging. Addressing warnings is optional.

  • Ignore (reviewers only)

Failed Failed checks: 1 error · 1 inconclusive

Check name Status Explanation Resolution
Weakened Safeguards Are Justified Error (previously flagged, unaddressed) crates/l40_api/api/src/controllers/substrate/kubernetes/pod_ops/redrive.rs:364 adds #[allow(clippy::too_many_arguments)] to non-test code without a specific reason. The previous failure remains un… Remove the suppression, or give a specific reason in the PR description, an adjacent comment, or the attribute.
Title check Pending This assessment has not completed. The check will be retried on the next pre-merge check run.
Passed Passed checks: 4 passed

Check name Status Explanation
Description Follows The Pr Template Passed The check tests only whether the PR description contains four items with real content. All four are present in the contributor's description for PR #1708, so no tool evidence was needed. 1. **"## Summ…
Bug Fixes Name A Regression Test Passed The check applies only to a bug fix under crates/, shim/, or ui/. This PR (#1708, author the-gigi-pplx) completes a feature. It renders the runtime-upgrade pod mode for Kubernetes start and resume b…
Agent Tooling Runs No New Commands Passed No agent-tooling content that runs commands or starts servers was found in the PR's agent plugin manifests, skills, or guideline files. Evidence: - The PR description scopes changes to Rust under `cra…
Public-Safe Content Passed The PR title and description contain no credentials, tokens, private keys, internal hostnames or URLs, tracker or chat links, cloud account IDs, real ARNs, cluster or environment names, personal works…
Full details: Description Follows The Pr Template

Explanation

The check tests only whether the PR description contains four items with real content. All four are present in the contributor's description for PR #1708, so no tool evidence was needed. 1. "## Summary": Present with content. It states that with SPACE_RUNTIME_UPGRADE_AT_ACTIVATION_ENABLED on, a Kubernetes start or resume boots a decided runtime upgrade in the sandbox's pod and reads the outcome from the node before the Wake. 2. "## Validation": Present. It names the commands run (cargo clippy, cargo fmt --all --check, ci/scripts/run-rust-checks.sh tests-unprivileged and tests-privileged) and their results (clean; 13027 unprivileged tests passed; 6 privileged failures attributed to the build box). It also lists the new and rewritten tests. 3. "## Severity and risk": Present. It gives "Severity: medium" and a risk statement ("Risk: low with the flag off, which is the default", with the flag-independent changes listed). 4. "AI assistance:" line: Present as its own line: "AI assistance: Claude Code split this pull request out of a larger change, wrote the code and tests with review, and drafted this description." This names the tool and the parts it drafted or changed. Per the check, presence is judged, not quality or length.

Full details: Bug Fixes Name A Regression Test

Explanation

The check applies only to a bug fix under crates/, shim/, or ui/. This PR (#1708, author the-gigi-pplx) completes a feature. It renders the runtime-upgrade pod mode for Kubernetes start and resume behind the new, default-off flag SPACE_RUNTIME_UPGRADE_AT_ACTIVATION_ENABLED. The description says "Nothing renders that mode yet," so the change is mostly new behavior, not a fix to shipped behavior. Even if it were treated as a bug fix, the Validation section names concrete regression tests. These are kubernetes::tests::runtime_upgrade_dispatch and runtime_upgrade_dispatch::api_faults, and kubernetes::pod_runtime_upgrade::tests. It says the dispatch tests cover the pod carrying the upgrade and the Wake carrying none, which would fail on the pre-change code. It also reports mutation runs in which a test failed for each guard removed. I confirmed the runtime_upgrade_dispatch test module exists in crates/l40_api/api/src/controllers/substrate/kubernetes/tests.rs. The check passes on either reading.

Full details: Agent Tooling Runs No New Commands

Explanation

No agent-tooling content that runs commands or starts servers was found in the PR's agent plugin manifests, skills, or guideline files. Evidence: - The PR description scopes changes to Rust under crates/l40_api/api/src/controllers/substrate/ and to docs/execution-environments.md and docs/configuration.md. None of these is an agent manifest, skill, or command file. - The local checkout has no merge base with origin/main. HEAD is a single root commit, so the exact PR diff could not be computed. The check therefore used a content scan of every agent-related file in HEAD (93 files under .agents/, .claude/, .claude-plugin/, and the AGENTS.md/CLAUDE.md guideline files, plus the two docs/ files the PR names). - Inline shell substitution (! followed by a backtick-quoted command): no matches in any scanned file. - SKILL.md frontmatter: every skill contains only name and description. No hooks or allowed-tools keys. - Plugin manifests (plugin.json, plugin.yaml, marketplace.json): no hook, MCP, LSP, command, or server entries. - No hooks, MCP, or LSP config files exist in the agent trees. - Diffs against origin/main in the agent files that differ are prose and version or path edits only, such as version strings, a reference path in test-economy.md, and a pod-rendering sentence in the substrate AGENTS.md. None adds an executable entry. Limitation: the diff base for this PR is not present in the checkout, so the scan covered whole-file content rather than the PR's own hunks. Because no violating pattern exists in any scanned file at HEAD, the PR cannot have introduced one in those files.

Full details: Public-Safe Content

Explanation

The PR title and description contain no credentials, tokens, private keys, internal hostnames or URLs, tracker or chat links, cloud account IDs, real ARNs, cluster or environment names, personal workstation paths, production logs, or unfixed vulnerability details. The description cites only public PR numbers, repo-relative doc and source paths, and component names. Diff evidence was limited. The local repository is a single root commit (d99f199), and HEAD~1 does not exist, so the PR-only patch could not be isolated. I therefore scanned the whole committed tree, which is a superset of the PR's added lines, for the sensitive classes the check names: - Private key headers, AWS access key IDs, GitHub and Slack tokens, and personal /Users/ or /home/ paths returned no real values. - The ARN-like hits in infra/space/aws/reference/README.md, infra/space/kind/README.md and the credmgr test files use masked 12-digit account placeholders (############) or fake role and secret names. These are placeholders, not real resource ARNs. - The -----BEGIN PRIVATE KEY----- hit in ed25519.rs is a parser string literal. - /home/user/data in a test comment is a fake path. - The /home/dev path in a workflow is a generic CI runner path, not a personal workstation path. - The PR-touched areas (crates/l40_api/api/src/controllers/substrate and docs/execution-environments.md / docs/configuration.md) returned no hits for the ARN, AKIA or private-key patterns. No sensitive content was found in the title, description, or tree-wide scan. Quoted values are omitted by design.

Full details: Weakened Safeguards Are Justified

Explanation

crates/l40_api/api/src/controllers/substrate/kubernetes/pod_ops/redrive.rs:364 adds #[allow(clippy::too_many_arguments)] to non-test code without a specific reason. The previous failure remains unresolved.

Resolution

Remove the suppression, or give a specific reason in the PR description, an adjacent comment, or the attribute.

Latest assessment: Weakened Safeguards Are Justified

Latest assessment: The latest assessment was inconclusive; the previous failure remains unresolved.

Latest explanation: Summary: The prior FAIL is refuted. The PR's full diff cannot be established, so the check cannot PASS. Prior claim (refuted). redrive.rs:366 carries #[allow(clippy::too_many_arguments)]. The main branch in this checkout (e97cc21) has the same attribute on the same function, at line 369. In main, the function has seven parameters plus self, and no runtime_upgrade parameter. This PR adds only that parameter. The suppression was therefore not added by this PR. Why INCONCLUSIVE. The checkout cannot show what this PR changed: - HEAD (d99f199) is a root commit. It holds the whole tree (5,027 files), so git diff against a parent is not possible. - main is a child of HEAD and differs by 1,423 files, so it is not the PR base either. - The PR base is PR #1707 (stacked chain), which is not in the checkout. Without the diff, the check cannot confirm that no test, assertion, lint, CI step, allowlist entry, or rule was removed or loosened. The check defines no FAIL condition for a missing diff, so the missing evidence cannot establish PASS. Partial evidence (no violation found): - No #[allow], #[expect], #![allow], or #[ignore] in the PR-named substrate files, other than the pre-existing redrive.rs attribute above. - .coderabbit.yaml contains merge-risk and approval text. The check's review-guidance clause covers only AGENTS.md, CLAUDE.md, skills under .agents/, CONTRIBUTING.md, and docs/rust/. No text in those files about review or merge-risk treatment was found in the grep. Needed to decide: the diff of this PR against its base (PR #1707 head, or the merge base of the stack). Check that diff for removed or loosened tests and assertions, new continue-on-error, SPACE_TEST_DEPS_OPTIONAL, or allowlist entries, and new lint suppressions in non-test Rust code. Also check changes to the CI workflows, .config/nextest.toml, deny.toml, clippy.toml, ARCHITECTURE.toml, and the covered rule files.

Latest resolution: Provide the PR's full diff against its base (PR #1707 head, or the merge base of the stacked chain) in a checkout that contains that base. Re-run this check on that diff. Confirm that no listed safeguard was removed, loosened, or newly suppressed without a reason. The #[allow(clippy::too_many_arguments)] at redrive.rs:366 predates this PR. It is not a finding.

@the-gigi-pplx
the-gigi-pplx force-pushed the gigi/pla-7133-stay-stopped-runtime-upgrade-2 branch from 6c0968a to 762ec97 Compare November 7, 2026 23:38
@the-gigi-pplx
the-gigi-pplx force-pushed the gigi/pla-7133-stay-stopped-runtime-upgrade-2 branch 2 times, most recently from a1819ed to 8556b10 Compare November 8, 2026 01:12
@the-gigi-pplx
the-gigi-pplx force-pushed the gigi/pla-7133-stay-stopped-runtime-upgrade-1 branch from 83f1ca8 to 8781a20 Compare November 8, 2026 01:45
@the-gigi-pplx
the-gigi-pplx force-pushed the gigi/pla-7133-stay-stopped-runtime-upgrade-2 branch from 8556b10 to 77e1fcc Compare November 8, 2026 01:54
@the-gigi-pplx
the-gigi-pplx force-pushed the gigi/pla-7133-stay-stopped-runtime-upgrade-1 branch 3 times, most recently from 7d37cef to 8451efa Compare November 8, 2026 02:28
@the-gigi-pplx
the-gigi-pplx force-pushed the gigi/pla-7133-stay-stopped-runtime-upgrade-2 branch 8 times, most recently from 1c43156 to 5ad7ee2 Compare November 8, 2026 05:16
@the-gigi-pplx
the-gigi-pplx force-pushed the gigi/pla-7133-stay-stopped-runtime-upgrade-1 branch from 8451efa to 6d843e7 Compare November 10, 2026 06:43
@the-gigi-pplx
the-gigi-pplx force-pushed the gigi/pla-7133-stay-stopped-runtime-upgrade-2 branch 2 times, most recently from f00949e to 825bb34 Compare November 10, 2026 08:54
@the-gigi-pplx
the-gigi-pplx force-pushed the gigi/pla-7133-stay-stopped-runtime-upgrade-1 branch from 6d843e7 to 5e9cc27 Compare November 10, 2026 21:49
@the-gigi-pplx
the-gigi-pplx force-pushed the gigi/pla-7133-stay-stopped-runtime-upgrade-2 branch from 825bb34 to 1410439 Compare November 10, 2026 21:57
@the-gigi-pplx
the-gigi-pplx force-pushed the gigi/pla-7133-stay-stopped-runtime-upgrade-1 branch from 5e9cc27 to e49aafc Compare November 10, 2026 22:03
@the-gigi-pplx
the-gigi-pplx force-pushed the gigi/pla-7133-stay-stopped-runtime-upgrade-2 branch from 1410439 to de4fb94 Compare November 10, 2026 22:16
@the-gigi-pplx
the-gigi-pplx force-pushed the gigi/pla-7133-stay-stopped-runtime-upgrade-1 branch from e49aafc to 913b4c7 Compare November 10, 2026 22:49
@the-gigi-pplx
the-gigi-pplx force-pushed the gigi/pla-7133-stay-stopped-runtime-upgrade-2 branch from de4fb94 to 6697735 Compare November 10, 2026 22:53
@the-gigi-pplx
the-gigi-pplx force-pushed the gigi/pla-7133-stay-stopped-runtime-upgrade-1 branch from 913b4c7 to ccbd14c Compare November 10, 2026 23:46
@the-gigi-pplx
the-gigi-pplx force-pushed the gigi/pla-7133-stay-stopped-runtime-upgrade-2 branch from 6697735 to 2660b4f Compare November 10, 2026 23:50
@the-gigi-pplx
the-gigi-pplx force-pushed the gigi/pla-7133-stay-stopped-runtime-upgrade-1 branch from ccbd14c to 1a3116a Compare November 11, 2026 00:21
@the-gigi-pplx
the-gigi-pplx force-pushed the gigi/pla-7133-stay-stopped-runtime-upgrade-2 branch from 2660b4f to 87822d1 Compare November 11, 2026 00:26
@the-gigi-pplx
the-gigi-pplx force-pushed the gigi/pla-7133-stay-stopped-runtime-upgrade-1 branch from 1a3116a to 1fc4517 Compare November 11, 2026 01:37
@the-gigi-pplx
the-gigi-pplx force-pushed the gigi/pla-7133-stay-stopped-runtime-upgrade-2 branch from 87822d1 to 7c91758 Compare November 11, 2026 01:37
@the-gigi-pplx
the-gigi-pplx force-pushed the gigi/pla-7133-stay-stopped-runtime-upgrade-1 branch from 1fc4517 to 4a2b483 Compare November 11, 2026 02:28
@the-gigi-pplx
the-gigi-pplx force-pushed the gigi/pla-7133-stay-stopped-runtime-upgrade-2 branch 2 times, most recently from 3bbfe7e to 66f2fe8 Compare November 11, 2026 02:54
@the-gigi-pplx
the-gigi-pplx force-pushed the gigi/pla-7133-stay-stopped-runtime-upgrade-1 branch from 4a2b483 to 4fe67bc Compare November 11, 2026 04:12
@the-gigi-pplx
the-gigi-pplx force-pushed the gigi/pla-7133-stay-stopped-runtime-upgrade-2 branch 2 times, most recently from 6e11a12 to 9248cdf Compare November 11, 2026 06:56
@the-gigi-pplx
the-gigi-pplx force-pushed the gigi/pla-7133-stay-stopped-runtime-upgrade-1 branch from 4fe67bc to 0371077 Compare November 11, 2026 09:49
@the-gigi-pplx
the-gigi-pplx force-pushed the gigi/pla-7133-stay-stopped-runtime-upgrade-2 branch from 9248cdf to aef571a Compare November 11, 2026 09:56
@the-gigi-pplx
the-gigi-pplx force-pushed the gigi/pla-7133-stay-stopped-runtime-upgrade-1 branch 2 times, most recently from 5c6f945 to 7d398d3 Compare November 11, 2026 15:17
@the-gigi-pplx
the-gigi-pplx force-pushed the gigi/pla-7133-stay-stopped-runtime-upgrade-2 branch from aef571a to 9eedd3e Compare November 11, 2026 15:27
@the-gigi-pplx
the-gigi-pplx force-pushed the gigi/pla-7133-stay-stopped-runtime-upgrade-1 branch from 7d398d3 to 3c3b124 Compare November 11, 2026 17:51
@the-gigi-pplx
the-gigi-pplx force-pushed the gigi/pla-7133-stay-stopped-runtime-upgrade-2 branch from 9eedd3e to 9cedcd5 Compare November 11, 2026 18:00
@the-gigi-pplx
the-gigi-pplx force-pushed the gigi/pla-7133-stay-stopped-runtime-upgrade-1 branch from 3c3b124 to 2366fc0 Compare November 11, 2026 19:23
@the-gigi-pplx
the-gigi-pplx force-pushed the gigi/pla-7133-stay-stopped-runtime-upgrade-2 branch from 9cedcd5 to 7a564dc Compare November 11, 2026 19:45
@the-gigi-pplx
the-gigi-pplx force-pushed the gigi/pla-7133-stay-stopped-runtime-upgrade-1 branch from 2366fc0 to ddc8ba1 Compare November 13, 2026 12:15
@the-gigi-pplx
the-gigi-pplx force-pushed the gigi/pla-7133-stay-stopped-runtime-upgrade-2 branch from 7a564dc to d99f199 Compare November 13, 2026 12:59

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant