You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: docs/architecture/platform-conformance-suite.md
+37-10Lines changed: 37 additions & 10 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -17,7 +17,7 @@ The machine-readable mirror of this document is
17
17
`Workflow\V2\Support\PlatformConformanceSuite`, exported by the
18
18
standalone `workflow-server` from `GET /api/cluster/info` under
19
19
`platform_conformance_suite`. Schema:
20
-
`durable-workflow.v2.platform-conformance.suite`, version `2`.
20
+
`durable-workflow.v2.platform-conformance.suite`, version `3`.
21
21
22
22
## Why one suite
23
23
@@ -73,7 +73,7 @@ them from the declared locations.
73
73
|`control_plane_request_response`|`cli`, `sdk-python`|`tests/fixtures/control-plane/`| Frozen request bodies and response shapes for `workflow.start`, `signal`, `query`, `update`, `cancel`, `task-history`, namespace storage. |
74
74
|`worker_task_lifecycle`|`cli`, `sdk-python`, `server`|`tests/fixtures/external-task-input/`, `tests/fixtures/external-task-result/`| Task input envelopes (poll → claim → run) and task result envelopes (complete, fail, cancel, heartbeat) used by every conforming worker. |
75
75
|`signal_query_runtime_contract`|`workflow`, `server`, `cli`, `sdk-python`, `waterline`|`docs/architecture/platform-conformance-suite.md`, `docs/architecture/query-and-live-debug.md`, `src/V2/Client/ControlPlaneClient.php`, `tests/Unit/V2/ControlPlaneClientTest.php`, `tests/Feature/SignalReplayTest.php`, `tests/Feature/V2/V2QueryWorkflowTest.php`, `tests/Feature/WorkflowControlPlaneTest.php`, `tests/Feature/WorkflowQueryTaskBrokerTest.php`, `tests/Commands/`, `tests/test_signals.py`, `tests/test_queries.py`, `tests/test_worker.py`, `CONFORMANCE.md`| Live published-artifact scenarios for signal delivery and query consistency across PHP and Python workers, CLI and SDK clients, replay timing, terminal runs, malformed payloads, and operator visibility. |
76
-
|`history_replay_bundles`|`workflow`, `sdk-python`|`tests/Fixtures/V2/GoldenHistory/`, `tests/fixtures/golden_history/`|Frozen history event bundles. A conforming SDK must replay each bundle and reproduce the documented final command sequence. |
76
+
|`history_replay_bundles`|`durable-workflow.github.io`, `workflow`, `sdk-python`|`static/platform-conformance/replay-runtime-scenarios.json`, `tests/Fixtures/V2/GoldenHistory/`, `tests/fixtures/golden_history/`|Deterministic replay coverage for frozen history bundles, worker restart replay, adversarial refusal, and in-flight signal timing across the official PHP and Python runtimes. |
77
77
|`failure_repair_actionability`|`server`, `workflow`|`docs/contracts/external-task-result.md`, `docs/contracts/replay-verification.md`, fixture pointers therein | Failure objects and repair / actionability shapes for stuck tasks, deterministic failure, and replay-mismatch surfaces. |
78
78
|`cli_json_envelopes`|`cli`|`tests/fixtures/control-plane/`, `schemas/`| The `--output=json` and `--output=jsonl` envelopes that automation depends on. Diagnostic-only fields are listed and excluded from the contract diff. |
79
79
|`waterline_observer_envelopes`|`waterline`| (TBD: `tests/fixtures/observer/`) | The `/waterline/api/v2/*` shapes and operator dashboard JSON envelopes. Status: provisional — fixtures land alongside the next Waterline contract slice. |
@@ -127,6 +127,31 @@ Required scenarios:
127
127
stable reason when live query values are intentionally not materialized
128
128
in read-only detail responses.
129
129
130
+
### History replay runtime contract
131
+
132
+
The `history_replay_bundles` category is also stable and load-bearing.
133
+
It must run against published install channels only, pin the resolved
134
+
artifact versions in the result, and name every required replay scenario
135
+
as passed, failed, or unsupported with a linked finding. A smoke-only
136
+
run is nonconforming even when the smoke path passes.
137
+
138
+
Required scenarios are published in the public replay scenario manifest
139
+
at `static/platform-conformance/replay-runtime-scenarios.json` and
140
+
include:
141
+
142
+
- published-artifact install-only evidence for server, CLI, PHP runtime,
143
+
and Python SDK;
144
+
- PHP and Python completed-history replay for activity, signal/update,
145
+
wait-condition, version-marker, and saga-compensation families;
146
+
- PHP and Python worker-restart replay for completed-query, activity,
147
+
signal/update, wait-condition, version-marker, and saga-compensation
148
+
state;
149
+
- PHP and Python divergent-code refusal with actionable
150
+
non-determinism diagnostics;
151
+
- server history mutation and malformed-history refusal through the
152
+
documented replay verification surface;
153
+
- PHP and Python in-flight signal restart timing.
154
+
130
155
## Pass / fail rules
131
156
132
157
The harness runs each fixture against the implementation under test and
@@ -154,10 +179,11 @@ emits a structured result. The rules below are normative.
154
179
release does not conform.
155
180
156
181
5.**Stable runtime scenario coverage.** A stable runtime category such
157
-
as `signal_query_runtime_contract` passes only when every scenario it
158
-
declares records a pass, fail, or unsupported result with resolved
159
-
artifact versions and linked findings. A smoke-only subset or omitted
160
-
scenario is nonconforming, not provisional.
182
+
as `signal_query_runtime_contract` or `history_replay_bundles` passes
183
+
only when every scenario it declares records a pass, fail, or
184
+
unsupported result with resolved artifact versions and linked
185
+
findings. A smoke-only subset or omitted scenario is nonconforming,
186
+
not provisional.
161
187
162
188
6.**Provisional categories warn but do not fail.** A failed fixture in
163
189
a provisional category emits a warning in the harness output. A
@@ -276,10 +302,11 @@ docs. It indexes them under one normative declaration so a single
276
302
`sdk-python/tests/fixtures/control-plane/` are the existing parity
277
303
fixtures. The suite cites them as the
278
304
`control_plane_request_response` source-of-truth.
279
-
-`tests/Fixtures/V2/GoldenHistory/` (this repo) and
280
-
`sdk-python/tests/fixtures/golden_history/` are the existing replay
281
-
bundles. The suite cites them as the `history_replay_bundles`
Copy file name to clipboardExpand all lines: src/V2/Exceptions/HistoryEventShapeMismatchException.php
+7-1Lines changed: 7 additions & 1 deletion
Original file line number
Diff line number
Diff line change
@@ -15,12 +15,18 @@ public function __construct(
15
15
publicreadonlyint$workflowSequence,
16
16
publicreadonlystring$expectedHistoryShape,
17
17
publicreadonlyarray$recordedEventTypes,
18
+
?string$detail = null,
18
19
) {
20
+
$detail = is_string($detail) && $detail !== ''
21
+
? "{$detail}"
22
+
: '';
23
+
19
24
parent::__construct(sprintf(
20
-
'Workflow history at workflow sequence %d recorded [%s], but the current workflow yielded %s. Keep yielded workflow steps stable across deployments or run this workflow on a compatible build.',
25
+
'Workflow history at workflow sequence %d recorded [%s], but the current workflow yielded %s.%s Keep yielded workflow steps stable across deployments or run this workflow on a compatible build.',
@@ -302,8 +302,12 @@ private static function fixtureCatalog(): array
302
302
],
303
303
'history_replay_bundles' => [
304
304
'status' => self::CATEGORY_STATUS_STABLE,
305
-
'description' => 'Frozen history event bundles. A conforming SDK must replay each bundle and reproduce the documented final command sequence.',
305
+
'description' => 'Deterministic replay coverage for frozen history bundles, worker restart replay, adversarial refusal, and in-flight signal timing across the official PHP and Python runtimes.',
@@ -400,7 +405,10 @@ private static function passFailRules(): array
400
405
],
401
406
'stable_runtime_scenario_coverage' => [
402
407
'rule' => 'A stable runtime fixture category passes only when every required scenario it declares records a pass, fail, or unsupported result with artifact versions and linked findings. A smoke-only subset or omitted scenario is nonconforming, not provisional.',
'rule' => 'A failed fixture in a provisional category emits a warning in the harness output and does not block the release. The category becomes load-bearing when promoted to stable in a later suite version.',
@@ -411,6 +419,44 @@ private static function passFailRules(): array
0 commit comments