Skip to content

sandbox-store: move the publish path's stopped, activity, absent-delete and rollback writes - #1333

Merged
ac-pplx merged 1 commit into
ac/lifecycle-move-api-restfrom
ac/lifecycle-move-internal-api
Nov 3, 2026
Merged

ac-pplx merged 1 commit into
ac/lifecycle-move-api-restfrom
ac/lifecycle-move-internal-api

Conversation

@ac-pplx

@ac-pplx ac-pplx commented Nov 2, 2026 •

Copy link
Copy Markdown
Contributor

Mechanical move, no functional change. The sandboxes row writes listed below move into pplx-space-sandbox-store with their SQL byte-for-byte; callers keep their locks, transactions and error handling. Everything else is doc comments. Part of the wave-2 stack (7 of 10, on #1347); it lands with the stack.

Summary

PublishNodeState wrote the sandboxes row inline in four internal-API places. Each statement moves into pplx-space-sandbox-store with its SQL text byte-for-byte; only the binds change. Each new function's doc names the fact it writes and any unusual guards. Callers keep the publication transaction, candidate locks (FOR UPDATE), recordset serialization and error mapping.

  • published_state::converge_stopped_sandboxes (statement) → ingest::converge_published_stopped (observed projection; has no evacuation exemption)
  • published_state::update_activity_timestamps (statement) → ingest::advance_published_activity (observed projection; checks only active_node_id)
  • published_state::DELETE_ABSENT_STOPPED_SANDBOXES → ingest::delete_published_absent_stopped (inference; its FOR UPDATE OF s stays inside the statement)
  • sandbox_quarantine_store::apply_activation_rollback_candidates (UPDATE sandboxes) → new quarantine::converge_activation_rollback (observed projection). It returns bool, where the caller previously checked rows_affected() != 1; id is the primary key, so the two are equivalent.

architecture-baseline.toml: both files' pattern_ratchet.sandbox_writes entries are removed (3 and 1). The file_size cap for published_state.rs drops from 3658 to 3504; the old cap was already stale at 3632. The internal-api AGENTS.md now points the stopped projection at pplx_space_sandbox_store::ingest. No test files change (git diff --stat $(git merge-base origin/main HEAD) HEAD -- '*test*' '*/tests/*' is empty).

sql! locators change: these four statements now report pplx_space_sandbox_store::ingest / ::quarantine in pg_stat_activity and query monitoring, instead of the internal-api modules.

Validation

  • cargo nextest run -p pplx-space-sandbox-store -p pplx-space-internal-api-server -p pplx-space-internal-api-svc: 431 passed, 0 skipped. Postgres ran in a container.
  • cargo nextest run -p pplx-space-api -p pplx-space-template-mgr: 1865 passed, 1 failed, 1 skipped (an opt-in #[ignore] benchmark). The failure, routes::e2b::tests::detail_reports_authoritative_federated_ownership_not_metadata, is a JSON key-order snapshot mismatch. Under this package selection it fails the same way on origin/main, and it passes in CI's full workspace test run.
  • cargo clippy -p pplx-space-sandbox-store -p pplx-space-internal-api-server --all-targets -- -D warnings: clean.
  • cargo arch, plus --base-baseline/--base-architecture from main: 0 required findings.
  • Mutation proof (each one local only, then reverted):
    • Dropping 'started' from the stopped convergence fails node_publication_converges_only_from_its_source_lifecycles.
    • Dropping s.lifecycle = 'stopped' from the absent delete fails absent_report_deletes_only_a_stopped_direct_row and absent_stopped_delete_decides_on_the_row_committed_while_it_waits.
    • Dropping the node check from the activity advance fails publish_sandbox_state_updates_activity_clocks_without_touching_updated_at.
    • Always clearing placement_changed_at in the rollback fails activation_rollback_receipts_converge_stable_targets_with_attempt_fence.
  • Fresh Kind from this change before its review fixes, which edit only doc comments (install-fc-vendor.sh, up.sh): up in 628 s.
  • scripts/tests/smoke-kind-typed.sh all: ECW 85 passed, 0 failed, 3 inconclusive; native 35 passed, 0 failed; wall 3126 s.
    • ecw.cold_create_environment and ecw.warm_pool_environment passed on rerun once SPACE_SMOKE_KIND_COLD_RECEIPTS and a token file were set.
    • local.restarted_btrfs_send_is_rejected_and_retried needs otel telemetry and was not run.

Severity and risk

Severity: does not apply (refactor). Risk is low: same SQL text and binds, same transaction. Roll back by reverting the commit.

Rollout

No migration. Old and new pods issue identical statements; only the locator comment differs.

Open PRs that will need to rebase

Not covered

  • The rollback's active_node_id = $2 guard has no test: weakening it fails nothing. The candidate selection already requires s.active_node_id = $1 under FOR UPDATE in the same transaction, so no test through the publication can observe it.
  • The Kind run doesn't show which moved statements it reached. The absent-stopped delete matches only Direct-substrate rows, and the rollback convergence runs only on a node's activation-rollback receipt. The Postgres-backed tests named under Validation cover both.

AI assistance: Claude Code (an AI agent) wrote the code change, ran the validation and drafted this description.

After the wave-2 restack

This PR is one layer of a 10-PR stack, restacked onto main c5fdf0c7 (which includes #826) and then rebased mechanically onto 42a99002, which changed only baseline context lines, in order #1329 → #1336 → #1338 → #1339 → #1342 → #1347 → #1333 → #1335 → #1328 → #1332. The validation earlier in this description ran at pre-restack heads; this layer's head is 042daad2.

@github-actions github-actions Bot added the triage:pending Waiting for a maintainer to triage label Nov 2, 2026
@github-actions

github-actions Bot commented Nov 2, 2026

Copy link
Copy Markdown

Thanks for opening this pull request! A SPACE maintainer will take a look.

CONTRIBUTING.md explains how we review outside contributions.

@ac-pplx
ac-pplx force-pushed the ac/lifecycle-move-internal-api branch from 3505eb3 to 71a927d Compare November 2, 2026 21:04
@ac-pplx
ac-pplx force-pushed the ac/lifecycle-move-internal-api branch from 71a927d to 9f272b7 Compare November 2, 2026 23:25
@ac-pplx
ac-pplx changed the base branch from main to ac/lifecycle-move-api-rest November 3, 2026 03:50
@ac-pplx
ac-pplx added this pull request to stack #1382 November 3, 2026 03:50
@ac-pplx
ac-pplx marked this pull request as ready for review November 3, 2026 03:51
@ac-pplx
ac-pplx marked this pull request as draft November 3, 2026 03:52
@ac-pplx
ac-pplx force-pushed the ac/lifecycle-move-internal-api branch from 9f272b7 to 973fc96 Compare November 3, 2026 06:00
@ac-pplx
ac-pplx marked this pull request as ready for review November 3, 2026 06:29
…te and rollback writes

PublishNodeState still wrote the `sandboxes` row inline in four places in
the internal API: the stopped convergence, the activity-clock advance, the
delete of stopped Direct rows a node reports absent, and the
activation-rollback convergence. Move each statement, byte for byte apart
from its binds, into pplx-space-sandbox-store:

- published_state::converge_stopped_sandboxes (statement)
  -> ingest::converge_published_stopped
- published_state::update_activity_timestamps (statement)
  -> ingest::advance_published_activity
- published_state::DELETE_ABSENT_STOPPED_SANDBOXES
  -> ingest::delete_published_absent_stopped
- sandbox_quarantine_store::apply_activation_rollback_candidates (sandboxes
  update) -> quarantine::converge_activation_rollback

The callers keep the publication transaction, its candidate locks, the
recordset serialization and their error mapping. The statements' sql!
locators now name the store modules. Neither file has a sandbox_writes
baseline entry left.
@ac-pplx
ac-pplx force-pushed the ac/lifecycle-move-internal-api branch from 973fc96 to 042daad Compare November 3, 2026 21:24
@ac-pplx
ac-pplx added this pull request to the merge queue Nov 3, 2026
Merged via the queue into main with commit be17989 Nov 3, 2026
27 checks passed
@ac-pplx
ac-pplx deleted the ac/lifecycle-move-internal-api branch November 3, 2026 22:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

triage:pending Waiting for a maintainer to triage

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants