[2/6] fix(pg): persist deferred reusable callers' subtree and splice matrix parents

BN
5d ago
+601-1

Stacked on #480, merge in order. Stack: 2/6, splitting #479.

Summary

Deferred reusable callers never folded on Postgres. A uses: whose subtree materializes at runtime (fromJSON matrix inside a reusable workflow) starts with inner_job_ids empty; the PG apply of its expansion never wrote them, so the fold read an empty list and the caller never folded, with or without a matrix. SQLite already did this. main and lite were not affected before #378.

What changed

  • write_reusable_meta persists the callee metadata on the callee spec rows and sets the caller's inner_job_ids to the registered subtree (lite's write_reusable_meta).
  • splice_matrix_parent replaces an expanded matrix parent's id with its legs in every caller's list, so the fold waits for the legs instead of the placeholder (lite's splice_matrix_parents).
  • Shared-suite scenarios (run on PG and lite): deferred callee, deferred matrix callee, pre-seeded matrix placeholder, and a pre-populated control. The PG ones failed before the fix (caller InProgress, InProgress, Pending) and pass after. The test commit comes first and is red on PG by design.
  • Docs: internal/settle-redesign.md (deferred-caller expansion contract, shared-suite scenarios) and the CHANGELOG entry.

The change is confined to the expansion apply path (dispatch.rs). It applies on top of main without #1's code, but it is stacked on #480 so the stack stays a single chain.

Not included

The other PRs in the stack (see #480 for the list): dead-code removal (#3), groundwork (#4), job-scoped admission (#5), dependent and waiter promotion (#6).

Test plan

On this PR's tip, against a disposable Postgres 17 (max_connections=2000, PRELOOP_PG_WRITERS=3 PRELOOP_PG_READERS=3, PRELOOP_TEST_POSTGRES_URL set):

  • cargo fmt --all --check: clean
  • cargo clippy --workspace --all-targets -- -D warnings: clean
  • cargo test --locked -p preloop-runner-server --lib -- control::: 351 passed (343 + the 4 new scenarios on each backend), 0 failed, 0 skipping: lines

just test-ci and the local engine CI run were not run on this PR's tip: the laptop engine's runner pool does not advertise the preloop-cpane label that ci.yml requires, so jobs fail at enqueue. The checks on this PR are the first full CI run for these commits.

Stack

  1. #480 fix(pg): max-parallel stall, cohort waiter retry, nested-caller fold, non-terminal guard
  2. #481 fix(pg): deferred reusable callers
  3. #482 refactor(pg): remove the in-memory completion path
  4. #483 refactor(pg): row-based enqueue target, needs view, settle hand-off (no behaviour change)
  5. #484 perf(control/pg): max-parallel admission over rows
  6. #485 perf(control/pg): dependents and job waiters over rows

Each PR's base is the previous PR's branch, so each shows only its own diff. Supersedes #479 (closed).