Skip to content

CI: SDK direction profiles in parallel lanes; deadline-health build off the critical path - #741

Merged
rmcdaniel merged 6 commits into
mainfrom
rust-325-ci-sdk-lanes
Oct 24, 2026
Merged

rmcdaniel merged 6 commits into
mainfrom
rust-325-ci-sdk-lanes

Conversation

@rmcdaniel

@rmcdaniel rmcdaniel commented Oct 24, 2026 •

Copy link
Copy Markdown
Member

Part of #325. Security class: R0 (CI efficiency).

Why

Each database job of Shared Server fixtures takes 64-72 minutes. About 22 of those minutes are the nine published-SDK direction profiles, run one after another. On train #729's PostgreSQL 17 job 120866907013 they ran from 12:19:50 to 12:41:36. The fixture corpus itself takes about 5.5 minutes.

Change

sdk-direction-lanes.sh runs the nine profiles in three concurrent lanes, balanced by those durations, in order within each lane. The profiles were already isolated from each other: each has its own containers, PHP and embedded databases, evidence and state directory, and its own workflow-ID prefix on the shared native server. Two of them already overlapped in the old step.

Every profile runs even after another fails. The step fails if any did, and prints each profile's log in its own group. Cleanup is unchanged.

Expected saving: about 14 minutes per database job, which is the run's critical path. The run on this PR measures it.

Order

This merges after #729, so #729 does not need main again.

Also: the activity lease flake fix (from #735)

activity_deadlines::heartbeat_renews_only_progress_deadline_and_cannot_resurrect_elapsed_authority compared two lease_expires_at strings. A lease on a whole second is written without a fraction (...:26Z), which sorts after ...:26.045Z, so the test failed about one run in a thousand (train #729, PostgreSQL 17 job 120852521096). The test now compares parsed instants and prints both values. Test only.

Also: the deadline-health build moves off the critical path

Every database job waited for published-sdk-adapters, about 15 minutes. Ten of those minutes built the optimized native binary that only the codec-deadline-health cells use. That build now runs in its own codec-native-build job beside the adapters, and the database jobs start about 10 minutes sooner. Together with the lanes, a run's critical path should drop from about 85 minutes to about 60.

In each database job of Shared Server fixtures, the nine published-SDK
direction profiles ran one after another (two pairs already overlapped),
about 22 of the job's 64-72 minutes (train #729, PostgreSQL 17 job
120866907013: 12:19:50 to 12:41:36). Each profile already has its own
containers, PHP and embedded databases, evidence and state directory,
and its own workflow-ID prefix on the shared native server.

sdk-direction-lanes.sh now runs them in three lanes balanced by those
durations, in order within a lane. Every profile runs even after another
fails; the step fails if any did, after printing each profile's log in
its own group. The job's existing cleanup steps still stop and remove
every profile's containers. Expected saving: about 14 minutes per
database job.
heartbeat_renews_only_progress_deadline_and_cannot_resurrect_elapsed_authority
compared two lease_expires_at strings. Native times are whole
milliseconds and serialize without a fraction on a whole second, so a
claim lease of ...:26Z sorted after a renewal of ...:26.045Z and the
assertion failed about one run in a thousand (train #729, PostgreSQL 17
job 120852521096). The test now parses both and reports the values.
Every database job waited for published-sdk-adapters (about 15 minutes),
but 10 of those minutes built the optimized native binary only the
codec-deadline-health cells use (train #729: "Build one bounded optimized
native artifact for deadline health", 10.0 minutes). The build, its
upload and its container cleanup now run in a codec-native-build job
beside the adapters; codec-deadline-health needs both, and the database
jobs still need only the adapters, so they start about 10 minutes
sooner. The build script and its bounded resources are unchanged.
@rmcdaniel rmcdaniel changed the title CI: run the SDK direction profiles in three concurrent lanes CI: SDK direction profiles in parallel lanes; deadline-health build off the critical path Oct 24, 2026
@rmcdaniel

Copy link
Copy Markdown
Member Author

Security/reliability correction for current head 337fe8de1658888cc9ab1bf133d22b16eb27e30f:

sdk-direction-lanes.sh does not stop a profile's persistent PHP server after that profile completes. sdk-direction-profile.sh starts "$RESOURCE_SCOPE-$tag-server" detached with a 512 MiB limit and never stops it. The previous serial workflow stopped each profile server before proceeding. With the new lanes, completed servers therefore accumulate from three toward all nine until the final job cleanup, alongside the database, native servers and active profile containers. That weakens the claimed bounded-resource/throughput improvement and can introduce avoidable runner pressure or flakiness.

Please retire "$RESOURCE_SCOPE-$tag-server" after each profile attempt in run_lane, without masking the profile's retained exit status and while preserving the final cleanup as the removal/logging backstop. Add a shell-level counterfactual proving all nine profiles run, every corresponding server is stopped, and one profile failure still runs later entries and makes the wrapper fail only after collecting all statuses/logs.

Integration note for the next PR: after #741 merges, #742 must explicitly account for the new independent codec-native-build root job in its change gating, terminal aggregate needs, and structure tests. The current pre-#741 #742 tree assumes published-sdk-adapters is the only root and cannot be merged unchanged after this PR.

@rmcdaniel

Copy link
Copy Markdown
Member Author

Sonar reconciliation for current #741 head: the quality gate passes, but the branch has four open findings, all in the new lane wrapper.

  • shelldre:S7688 at lines 13 and 43: use Bash [[ ... ]] rather than test / [ ... ] (reliability impact HIGH).
  • shelldre:S7679 at line 24: assign the lane positional parameter to a local before iterating.
  • shelldre:S7677 at line 44: send the ::error:: diagnostic to stderr.

These are narrow corrections and fit naturally with the requested per-profile server retirement/test. I do not recommend accepting four new findings as debt for this CI-efficiency change; please resolve them on the final head or record a specific contrary rationale. The GitHub workflow command remains recognized when emitted on stderr.

…est the lane wrapper

Each lane stops its profile's PHP server as soon as the profile ends, so at
most three run at once, and a failed stop only warns. The profile's status
is kept either way. A shell-level test runs the wrapper with stub profiles
and docker: all nine profiles run, every server is stopped after its profile,
a failed profile does not stop its lane, and the wrapper fails only after
printing every status and log. Also resolves the wrapper's Sonar findings.
rmcdaniel added a commit that referenced this pull request Oct 24, 2026
…and wait for it

codec-native-build is a second root fixture job. It runs only through the
change classifier, and the result needs it like every other fixture job.
@rmcdaniel

Copy link
Copy Markdown
Member Author

Corrections for Security's two findings, at head c834849c8b0e0de1f630f9090a0a842e95c0a8c5:

  • Server retirement. run_lane stops "$RESOURCE_SCOPE-$tag-server" right after each profile attempt, so at most three PHP servers run at once. The profile's status is written before the stop. A failed stop only emits ::warning::, and the final cleanup steps stay as the backstop. The isolation policy passes. My earlier attempt was refused only because the policy reads > /dev/null (with a space) as a container name.

  • Sonar. [[ ]] replaces test and [ ]; the lane is assigned to a local; ::error:: goes to stderr.

  • Counterfactual test. New tests/Unit/ServerParitySdkDirectionLanesTest.mjs runs the wrapper with stub profiles and a stub docker, in the comparator step's image. It proves:

    • all nine profiles run once with the given backend and URL;
    • every server is stopped once, after its profile ends and before the lane's next profile;
    • at most three servers run at once;
    • a failed profile (timer, exit 7) still runs the rest of its lane, and the wrapper exits 1 only after printing every status and log;
    • a failed stop keeps every status;
    • a missing scope refuses to run.

    5/5 pass on this head. Against the previous wrapper (337fe8de1), all 5 fail.

Also in this head, from earlier: the codec-native-build split. The database jobs no longer wait on the optimized build.

@rmcdaniel

Copy link
Copy Markdown
Member Author

Security exact-head correction review for c834849c8b0e0de1f630f9090a0a842e95c0a8c5:

  • The lane wrapper now retains each profile status, attempts docker stop --time 30 for that profile's exact server before starting the next entry in its lane, warns without masking the profile result if retirement fails, and preserves the job's final cleanup as backstop.
  • The new shell counterfactual covers all nine profiles, the three-server peak, per-profile stop ordering, continuation after a profile failure, stop failure, combined profile/stop failure, logs/statuses and missing resource scope.
  • Independent Node 24, network-disabled execution passes 5/5. My first hardened-container run used a non-executable scratch mount, so its generated docker stub could not run and correctly produced warnings; rerunning with normal executable ephemeral /tmp passed 5/5. No product/source defect is attributed to that harness-only result.
  • The four prior Sonar findings are corrected. The exact-head Sonar result now reports zero new/accepted issues, and the JavaScript/actions/Python CodeQL analyses and repository contracts are green. Long Rust/PHP/fixture jobs remain in progress at this checkpoint.

The Security lifecycle/quality corrections are accepted at this immutable head. This does not waive the remaining hosted checks or authorize merging while they are unsettled.

… the native server

The namespace and selected-run signal profiles ran beside the plain signal
profile, and on PostgreSQL 17 one's worker showed in another's routing
diagnostics (server-parity-sdk-signals). The old serial workflow never
overlapped them. A test now reads each profile's queues from its fixtures and
refuses any two profiles that share one in different lanes.
@rmcdaniel

Copy link
Copy Markdown
Member Author

Head e5d2186e64d6a563e35b4c15772daf36a917e481 fixes a lane defect found by the previous run (postgres-17, job 120893523629).

The namespace-signal and selected-run-signal profiles ran in different lanes, but all three signal profiles use the task queue server-parity-sdk-signals on the shared native server. A peer worker from one profile appeared in the other's routing diagnostics:

  • eligible_worker_count was 1 where 0 was expected;
  • status was worker_definition_missing where no_eligible_worker was expected.

The old serial workflow never overlapped these profiles.

Lanes are now:

  1. update, update-failure, child
  2. signal, namespace-signal, selected-run-signal (serial)
  3. timer, activity, query

A new test reads each profile's queue names from its fixtures and refuses any two profiles that share a queue in different lanes. It fails against the previous layout; the lanes test now passes 6/6.

This change is merged into #742 (261a557561eafb44e87862196241ca4cae17ef89) and #746 (2271b0b66b63b620e18157200526919a6ffa9641). To relieve runner queueing, only #746's fixture run is kept, because it qualifies this change together with the rest of the stack.

@sonarqubecloud

Copy link
Copy Markdown

@rmcdaniel
rmcdaniel merged commit 261a557 into main Oct 24, 2026
14 checks passed
@rmcdaniel
rmcdaniel deleted the rust-325-ci-sdk-lanes branch October 24, 2026 16:08
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