Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
88dabb2
Terminate a workflow natively, as published PHP does
durable-workflow-ops Oct 20, 2026
1270e24
Merge remote-tracking branch 'origin/main' into rust-325-terminate
durable-workflow-ops Oct 20, 2026
69e77a8
Record the undiagnosed Python query worker shutdown failure
durable-workflow-ops Oct 20, 2026
a313004
List and describe workers natively, as published PHP does
durable-workflow-ops Oct 20, 2026
6d1ef0a
Merge remote-tracking branch 'origin/rust-325-terminate' into rust-32…
durable-workflow-ops Oct 20, 2026
0cba292
Release a replaced worker's activity leases at once, as PHP does
durable-workflow-ops Oct 20, 2026
afef428
Record current PHP's workflow definition evolution as a gap to follow
durable-workflow-ops Oct 20, 2026
05c5fc4
Bring the port log's current state and missing API surface up to date
durable-workflow-ops Oct 20, 2026
82f14f8
Merge remote-tracking branch 'origin/main' into rust-325-terminate
durable-workflow-ops Oct 20, 2026
b373962
Merge branch 'rust-325-terminate' into rust-325-worker-listing
durable-workflow-ops Oct 20, 2026
3c11224
Note #515 as merged in the port log
durable-workflow-ops Oct 20, 2026
aa35115
Record the agreed native boundary for Workflow trace context
durable-workflow-ops Oct 20, 2026
5f25492
Merge pull request #544 from durable-workflow/rust-325-worker-listing
rmcdaniel Oct 20, 2026
2d6b1e9
Merge remote-tracking branch 'origin/main' into rust-325-terminate
durable-workflow-ops Oct 20, 2026
5a84466
Merge remote-tracking branch 'origin/main' into rust-325-terminate
durable-workflow-ops Oct 20, 2026
e7b8dfb
Merge remote-tracking branch 'origin/main' into rust-325-terminate
durable-workflow-ops Oct 20, 2026
09d249c
Merge remote-tracking branch 'origin/main' into rust-325-terminate
durable-workflow-ops Oct 20, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion .github/workflows/server-parity.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ on:
- tests/Unit/ServerParityAdmissionContractTest.mjs
- tests/Unit/ServerParityRoleTokenContractTest.mjs
- tests/Unit/ServerParityWorkerDeregistrationContractTest.mjs
- tests/Unit/ServerParityWorkerListingContractTest.mjs
- tests/Unit/ServerParityWorkerReplacementContractTest.mjs
- tests/Unit/ServerParityWaitingHistoryContractTest.mjs
- tests/Unit/ServerParityTaskRetryContractTest.mjs
- tests/Unit/ServerParityPublishedPatchContractTest.mjs
Expand Down Expand Up @@ -61,6 +63,8 @@ on:
- tests/Unit/ServerParityAdmissionContractTest.mjs
- tests/Unit/ServerParityRoleTokenContractTest.mjs
- tests/Unit/ServerParityWorkerDeregistrationContractTest.mjs
- tests/Unit/ServerParityWorkerListingContractTest.mjs
- tests/Unit/ServerParityWorkerReplacementContractTest.mjs
- tests/Unit/ServerParityWaitingHistoryContractTest.mjs
- tests/Unit/ServerParityTaskRetryContractTest.mjs
- tests/Unit/ServerParityPublishedPatchContractTest.mjs
Expand Down Expand Up @@ -1420,7 +1424,7 @@ jobs:
-e COMPOSER_HOME=/tmp/composer -v "$PWD:/source" -w /source "$image" \
install --working-dir=scripts/conformance/server-parity --no-interaction --no-progress
docker run --rm --user=1000:1000 --entrypoint node -v "$PWD:/source:ro" -w /source \
"$image" --test tests/Unit/ServerParityRunnerTest.mjs tests/Unit/ServerParityCooperativeContractTest.mjs tests/Unit/ServerParityChildCancellationContractTest.mjs tests/Unit/ServerParityScheduleContractTest.mjs tests/Unit/ServerParityVisibilityContractTest.mjs tests/Unit/ServerParityAdmissionContractTest.mjs tests/Unit/ServerParityRoleTokenContractTest.mjs tests/Unit/ServerParityWorkerDeregistrationContractTest.mjs tests/Unit/ServerParityPatchDeploymentContractTest.mjs tests/Unit/ServerParityWaitingHistoryContractTest.mjs tests/Unit/ServerParityTaskRetryContractTest.mjs tests/Unit/ServerParityPublishedPatchContractTest.mjs tests/Unit/ServerParityPublishedPatchTransportTest.mjs tests/Unit/ServerParityRecordFileTest.mjs > parity-evidence/comparator-tests.txt
"$image" --test tests/Unit/ServerParityRunnerTest.mjs tests/Unit/ServerParityCooperativeContractTest.mjs tests/Unit/ServerParityChildCancellationContractTest.mjs tests/Unit/ServerParityScheduleContractTest.mjs tests/Unit/ServerParityVisibilityContractTest.mjs tests/Unit/ServerParityAdmissionContractTest.mjs tests/Unit/ServerParityRoleTokenContractTest.mjs tests/Unit/ServerParityWorkerDeregistrationContractTest.mjs tests/Unit/ServerParityWorkerListingContractTest.mjs tests/Unit/ServerParityWorkerReplacementContractTest.mjs tests/Unit/ServerParityPatchDeploymentContractTest.mjs tests/Unit/ServerParityWaitingHistoryContractTest.mjs tests/Unit/ServerParityTaskRetryContractTest.mjs tests/Unit/ServerParityPublishedPatchContractTest.mjs tests/Unit/ServerParityPublishedPatchTransportTest.mjs tests/Unit/ServerParityRecordFileTest.mjs > parity-evidence/comparator-tests.txt
docker run --rm --user=1000:1000 --cpus=1 --memory=256m --memory-swap=256m \
--network=none --entrypoint node -v "$PWD:/source:ro" -w /source \
"$image" --test tests/Unit/ServerParityCodecDeadlineLoadTest.mjs > parity-evidence/codec-load-tests.txt
Expand Down
201 changes: 178 additions & 23 deletions docs/rust-server-port.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,29 +14,75 @@ qualify a later tree.

## Current state

Updated October 19, 2026, after merging #460.

- **Merged native slices.** [#478](https://github.com/durable-workflow/server/pull/478)
(run observation, timed waits, `all` barriers, terminal update closure and
cooperative cancellation with abandoned and independently cancelled
children), [#476](https://github.com/durable-workflow/server/pull/476)
(run activity metadata listing), [#494](https://github.com/durable-workflow/server/pull/494)
(CPU deadline-health observer timing) and [#460](https://github.com/durable-workflow/server/pull/460)
(read-only inspection of an existing PHP database). No native PR is open.
- **Shared-suite reliability.** Each 13-job run still tends to show one
intermittent failure in a step its change does not touch, and qualification
records classify each one. Diagnosed and corrected: published PHP SQLite
reference lock pressure, CPU observer client timing, and native replay of a
live query lease to a fresh poll, which published PHP never does without a
matching poll request id.
Not yet diagnosed: one native-test failure in `execution-and-codec` step 8 on
main's post-#478 run, which four local repetitions under the CI limits did
not reproduce.
- **Next action.** Correct native timer dispatch under CPU load with a
deadline-health control. Then continue the remaining parity families, the
backup-first in-place takeover and the performance baseline on disposable
hosts.

Updated October 20, 2026.

- **Merged on October 20.**
- [#507](https://github.com/durable-workflow/server/pull/507) gives codec work under the transition lock its own permit.
- [#508](https://github.com/durable-workflow/server/pull/508) keeps explicit worker command declarations.
- [#509](https://github.com/durable-workflow/server/pull/509) reports poll statuses as the worker protocol does.
- [#515](https://github.com/durable-workflow/server/pull/515) retries the PHP reference's lock-pressure refusals in the probes.
- [#516](https://github.com/durable-workflow/server/pull/516) lets held long polls wait without the transition lock.
- [#517](https://github.com/durable-workflow/server/pull/517) designs the backup-first takeover.
- [#499](https://github.com/durable-workflow/server/pull/499) and [#510](https://github.com/durable-workflow/server/pull/510) replay a live query lease only to its own poll request and remember query poll answers per request.
- [#542](https://github.com/durable-workflow/server/pull/542) records repeated matched PHP/native performance pairs.
- This branch: [#543](https://github.com/durable-workflow/server/pull/543) (immediate termination) with [#544](https://github.com/durable-workflow/server/pull/544) (worker listing and registration facts).
- **Open.**
- The backup-first takeover stack: [#523](https://github.com/durable-workflow/server/pull/523)
(fingerprint), [#529](https://github.com/durable-workflow/server/pull/529)
(layouts) and [#532](https://github.com/durable-workflow/server/pull/532),
[#533](https://github.com/durable-workflow/server/pull/533) and
[#536](https://github.com/durable-workflow/server/pull/536) (SQLite,
PostgreSQL and MySQL/MariaDB takeover). Then
[#538](https://github.com/durable-workflow/server/pull/538) (SQLite WAL
preparation) and [#539](https://github.com/durable-workflow/server/pull/539)
(a PHP-accepted signal and an expired PHP lease resumed under native, plus
refusal of unsupported features). Its top passed all 13 parity jobs.
- [#548](https://github.com/durable-workflow/server/pull/548): PHP's
ownership guard refusals for a lost workflow task claim.
- [#549](https://github.com/durable-workflow/server/pull/549): the
multi-node kill and restart qualification and its results.
- [#550](https://github.com/durable-workflow/server/pull/550): the search
attribute registry. [#551](https://github.com/durable-workflow/server/pull/551):
namespace update.
- **Parity surface.** With this branch, native serves 63 of published PHP's 173 API
routes. The missing families are listed below under "API surface still
missing".
- **Next action.** Merge the open PRs as their checks pass. Then port history
export, a large bundle the CLI and both SDKs use for replay. Packaging the
native binary into the server image remains an open gate.

## API surface still missing

These published PHP 2.9.8 routes have no native handler yet, by family. The
CLI and Waterline use the first group.

- **Used by the CLI or Waterline.**
- Schedule listing, update and backfill.
- Task queues and their build IDs.
- Namespace update, delete and external storage.
- Search attributes.
- `system` repair, retention and activity-timeout passes, metrics and
operator dashboards.
- Storage test.
- Activities (standalone).
- **Worker protocol features.**
- Worker sessions.
- Update validation tasks.
- Prepared local activities.
- Cancellation scopes.
- Activity cancellation acknowledgement.
- **Run operations.**
- History export.
- Archive.
- Redrive.
- Imports from embedded v2 and Waterline v1.
- **Other families.**
- Message streams.
- Service catalogs and endpoints.
- Nexus operations.
- Runtime credentials.
- Deployments.
- Bridge adapters.
## Known gaps found in review

These are confirmed differences from the published PHP reference and open
Expand Down Expand Up @@ -75,6 +121,41 @@ contract fixture before its correction.
above the request timeout, still inside the 9-second load wave, needs its own
reviewed profile change.

- **History retention.** Published PHP's worker heartbeat runs an inline
history retention pass, and the default namespace retention is bounded at
30 days, so PHP prunes old closed runs. Native has no retention yet. Its
heartbeat omits PHP's `retention` report rather than claim a pass. The
`system/retention` endpoints are absent too.
- **Python worker shutdown after a late synchronous query handler (not yet
diagnosed).** In the SQLite query-authority cohort on #515's run
39431491496, the published Python SDK 2.5.15 client in `late-handler-sync`
mode failed against native. Its 6-second handler returned and was fenced
with `query_execution_budget_expired` after one claim. The SDK's query thread
then did not stop within the 5-second shutdown budget. Forty local
repetitions of that case alone passed. Find what holds the query thread
after the fence before changing either side.
- **Workflow definition evolution (PHP main after #525, not yet released).**
Current PHP routes a run whose recorded workflow definition is gone to a
replacement definition that passes strict replay. It then reports
`definition_routing` on task queues and run diagnostics. It also records
each worker's protocol version under `_worker_protocol_version` in its
stored process metrics. That entry shows up in the worker listing. Native
follows the frozen published reference, which has none of this. Port it
with its own fixture once it is published.
- **Trace context (Workflow #773 / workflow#788, not yet published).** A
Workflow minor will add nullable `observability_context` columns on runs,
commands and tasks, plus an entry in schedule metadata. Native-owned
databases are unaffected. A Server release carrying the columns is a new
takeover source layout, which native refuses with
`upgrade_source_catalog_unqualified` until its recipe lands. The recipe must
also refuse rows that carry trace context until native implements the
contract. The boundary is agreed on #325.
- **Terminating a child run.** Published Workflow resolves the parent with
`ChildRunTerminated` and the `terminated` child call status. Native refuses
this with `422 termination_propagation_not_available` until the parent-side
wait, child summary and failure projections for `ChildRunTerminated` have a
fixture.

## Contract and verification inventory

The status column summarizes bounded native source and its recorded component
Expand Down Expand Up @@ -142,6 +223,80 @@ support is not evidence of multi-node safety.
Newest checkpoints first. Each entry is exact to the source, tree and runs it
names, including unsuccessful observations.

October 20, worker listing:

- **Source.** Native serves `GET /api/workers` and `GET /api/workers/{id}`,
as published PHP's WorkerManagementController does:
- the summary fields;
- the `task_queue` and `status` filters, with stale workers hidden unless
asked for;
- the stale window;
- `404 worker_not_found`.

Operators may read these; only `DELETE` needs an admin. Named namespaces may
read them.
- **Registration facts.** Registration and heartbeat now keep what PHP keeps:
- capacities, defaulting to 100, 100 and 10;
- task slots, bounded by those capacities;
- normalized process metrics;
- the heartbeat cadence;
- workflow definition fingerprints.

Re-registering an active worker with a changed fingerprint is refused with
`409 workflow_definition_changed`. Omitting an advertised one is refused with
`409 workflow_definition_fingerprint_missing`, and neither refusal changes
the registration. Omitting the fingerprints keeps the advertised one. A
heartbeat changes only what it reports. Its acknowledgement carries the
configured cadence and stale window.
- **A replaced worker's activity leases.** A new process registering a
worker_id that holds activity leases now releases them at once, as PHP
does. Its running attempts close as `expired`, and the tasks return to
ready, so the next claim is attempt 2 of the same task. This holds even under
a one-attempt retry policy, since PHP checks no policy at claim time. Before
this, native left the task leased for the five-minute activity lease. The
expired attempt's completion now gets PHP's whole stale receipt:
`409 stale_attempt`, `recorded: false`, and the activity, attempt and task
statuses.
- **Fixtures.**
- `worker-listing` registers two workers through the unchanged published
SDK. It then lists, filters, describes and refuses them, and
re-registers and deregisters them.
- `worker-replacement-activity-lease` replaces a worker holding an activity
lease, then completes the original and the replacement attempts.

The contracts check each HTTP target against the reviewed facts. Embedded
mode is explicitly inapplicable.
- **Local evidence.** A local copy of the SQLite parity step recorded
published PHP 2.5.14, embedded PHP and native for both fixtures and
`namespace-isolation`. All three targets passed and the comparison passed.
Before the release, native failed the replacement fixture: its second claim
found no task. Native integration tests pass on SQLite, PostgreSQL, MySQL
and MariaDB.

October 20, immediate termination:

- **Source.** Native serves `POST /api/workflows/{id}/terminate` and its
selected-run form. Published Workflow runs cancel and terminate through one
`attemptTerminalCommand`, so native now does the same. Terminate records
`TerminateRequested` and `WorkflowTerminated`, the `terminated` status,
closed reason, failure category and propagation kind, and
`WorkflowTerminatedException`. It cancels open tasks, activities and timers
exactly as cancel does. A late activity outcome is refused with
`run_terminated`. The response carries the `terminate` control-plane
contract, which matches cancel's.
- **Refused.** Terminating a child run returns
`422 termination_propagation_not_available` and changes nothing (see known
gaps). The other propagation refusals are cancel's.
- **Fixtures.** `terminate-before-claim`, `terminate-pending-timer` and
`terminate-leased-activity` reuse the cancellation workflows with
`immediate_cancellation.command = "terminate"`. The shared contract and its
runner unit tests check the termination identity in place of cancellation's.
- **Local evidence.** A local copy of the SQLite parity step recorded published
PHP 2.5.14 over HTTP, embedded PHP and native for the three cancel and three
terminate fixtures. All six passed on each target, and the comparison passed.
Native integration tests for both commands pass on SQLite, PostgreSQL and
MySQL.

October 20, namespace update:

- **Source.** Native serves `PUT /api/namespaces/{name}`, as published PHP's
Expand Down
Loading
Loading