Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -541,7 +541,7 @@ jobs:
source_mode: embedded_v2
php: '8.3'
laravel: '^12.0'
workflow: '^2.0@RC'
workflow: '^2.0'
steps:
- uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6
- uses: shivammathur/setup-php@f3e473d116dcccaddc5834248c87452386958240 # v2
Expand Down
13 changes: 7 additions & 6 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ project follows [Semantic Versioning](https://semver.org/).

## [Unreleased]

## [2.0.0] - 2026-09-01

### Added

- Service workers can execute deterministically recorded local activities,
Expand Down Expand Up @@ -89,16 +91,15 @@ project follows [Semantic Versioning](https://semver.org/).
straight-line execution. Durable operations now return recorded values or
throw recorded failures directly at their call sites, while replay retains
strict command-order, history-shape, and command-detail validation.
- Advanced the PHP SDK source to `2.0.0-rc.54` and qualified it with Server
`2.0.0-rc.68`. Worker registration now explicitly advertises memo upserts and
- Published the stable PHP SDK `2.0.0`, qualified with Server `2.0.0`.
Worker registration explicitly advertises memo upserts and
typed search attributes, with worker protocol `1.19` and explicit floors for
portable worker affinity (`1.18`) and durable selection (`1.19`). During the
worker-session lifecycle, session identifiers are canonicalized once so
create, routing, renewal, explicit close, and shutdown target one identity.
During the active 2.0 prerelease train, package
metadata names the exact SDK artifact and exact qualified Server artifact
rather than a compatibility range; other prereleases remain historical and
receive no compatibility shim. Avro is the sole public
Package metadata names the exact SDK artifact and exact qualified Server
artifact. The prereleases remain historical and receive no compatibility
shim. Avro is the sole public
Durable Workflow 2.0 payload codec, and non-Avro configuration fails before
transmission. Managed registration emits an explicit empty validator list,
while low-level registration documents and preserves that declaration and
Expand Down
20 changes: 9 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,13 +31,12 @@ Create an empty Composer project and install the current published package:
mkdir durable-php-quickstart
cd durable-php-quickstart
composer init --name=acme/durable-php-quickstart --no-interaction
composer require 'durable-workflow/sdk:^2.0@RC'
composer require 'durable-workflow/sdk:^2.0'
```

The current 2.0 RC declares its verified Server baseline in package metadata;
using another Server prerelease requires separate conformance evidence. Earlier
2.0 prereleases and pre-1.0 SDK releases remain historical rather than
alternate supported baselines.
The stable 2.0 package declares its verified Server baseline in package
metadata. Earlier 2.0 prereleases and pre-1.0 SDK releases remain historical
rather than alternate supported baselines.

To install directly from the source repository before a tagged release:

Expand Down Expand Up @@ -262,11 +261,10 @@ Release metadata and the machine-readable
package and Server compatibility line, runtime URL forms, role-specific
environment variables, package-resolvable executable sources, expected result,
and public published-artifact qualification identity that keep this path in sync.
During the active 2.0 prerelease train, `product-train` names the exact SDK
artifact being qualified and `supported-server-versions` names the exact
standalone Server artifact qualified with it. The latter is not a version range
or a promise of compatibility with other prereleases; earlier prereleases remain
historical and do not activate compatibility shims.
For the stable 2.0 release, `product-train` names the exact SDK artifact and
`supported-server-versions` names the exact standalone Server artifact
qualified with it. Earlier prereleases remain historical and do not activate
compatibility shims.

`npm run qualify:quickstart-contract-deployment` verifies that deployed contract
and its public workflow evidence. Local runs may omit `GITHUB_TOKEN` and use
Expand Down Expand Up @@ -501,7 +499,7 @@ Publish the environment-backed configuration, add attributed handler services,
and start the supervised Artisan command:

```bash
composer require 'durable-workflow/sdk:^2.0@RC'
composer require 'durable-workflow/sdk:^2.0'
php artisan vendor:publish --tag=durable-workflow-config
php artisan config:cache
php artisan durable-workflow:worker
Expand Down
4 changes: 2 additions & 2 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -74,8 +74,8 @@
}
},
"durable-workflow": {
"product-train": "2.0.0-rc.54",
"supported-server-versions": "2.0.0-rc.68",
"product-train": "2.0.0",
"supported-server-versions": "2.0.0",
"worker-protocol-version": "1.19",
"control-plane-version": "2",
"durable-selection": true,
Expand Down
4 changes: 2 additions & 2 deletions docs/laravel-adoption-contract.json
Original file line number Diff line number Diff line change
Expand Up @@ -38,12 +38,12 @@
},
"embedded_v2": {
"package": "durable-workflow/workflow",
"channel": "^2.0@RC",
"channel": "^2.0",
"state_owner": "laravel_application"
},
"service_v2": {
"package": "durable-workflow/sdk",
"channel": "^2.0@RC",
"channel": "^2.0",
"state_owner": "server_or_cloud"
}
},
Expand Down
2 changes: 1 addition & 1 deletion docs/laravel-adoption-contract.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -271,7 +271,7 @@
"required": ["package", "channel", "state_owner"],
"properties": {
"package": {"enum": ["durable-workflow/workflow", "durable-workflow/sdk"]},
"channel": {"enum": ["^1.0", "^2.0@RC"]},
"channel": {"enum": ["^1.0", "^2.0"]},
"state_owner": {"enum": ["laravel_application", "server_or_cloud"]}
}
}
Expand Down
4 changes: 2 additions & 2 deletions docs/portal/frameworks/laravel.md
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ This path keeps state ownership in Laravel.
1. Install the v2 channel in the existing application and run its migrations:

```bash
composer require 'durable-workflow/workflow:^2.0@RC' --with-all-dependencies
composer require 'durable-workflow/workflow:^2.0' --with-all-dependencies
php artisan migrate --force
```

Expand Down Expand Up @@ -117,7 +117,7 @@ The SDK can be installed while v1 remains present and draining.
1. Install the service-mode channel and publish configuration:

```bash
composer require 'durable-workflow/sdk:^2.0@RC'
composer require 'durable-workflow/sdk:^2.0'
php artisan vendor:publish --tag=durable-workflow-config
```

Expand Down
2 changes: 1 addition & 1 deletion docs/portal/getting-started/client-setup.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ next:
---
## Install and construct

Install from the supported 2.0 prerelease channel shown throughout this portal:
Install from the supported stable 2.0 line shown throughout this portal:

```bash
{{ release.composerCommand }}
Expand Down
2 changes: 1 addition & 1 deletion docs/portal/operate/deployment.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ A minimal production image should:
4. expose no HTTP port unless the container also owns a separate health process;
5. identify the application release through `buildId`.

Do not use the SDK repository's `main` branch as a production Composer source. Install `{{ release.composerPackage }}` to follow the supported 2.0 prerelease channel, then commit the resolved version in `composer.lock`.
Do not use the SDK repository's `main` branch as a production Composer source. Install `{{ release.composerPackage }}` to follow the supported stable 2.0 line, then commit the resolved version in `composer.lock`.

## Roll out compatible workers

Expand Down
8 changes: 4 additions & 4 deletions docs/quickstart-contract.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,17 @@
"schema_version": 2,
"package": {
"name": "durable-workflow/sdk",
"published_version": "2.0.0-rc.54",
"composer_requirement": "2.0.0-rc.54@RC",
"onboarding_requirement": "^2.0@RC"
"published_version": "2.0.0",
"composer_requirement": "2.0.0",
"onboarding_requirement": "^2.0"
},
"runtime_targets": {
"server": {
"client_input": "http://localhost:8080",
"namespace_input": "default",
"input_kind": "server_origin",
"example_request": "http://localhost:8080/api/workflows",
"image": "durableworkflow/server:2.0.0-rc.68"
"image": "durableworkflow/server:2.0.0"
},
"cloud": {
"client_input": "https://cloud.example/api/runtime/v1/namespaces/<runtime-id>",
Expand Down
2 changes: 1 addition & 1 deletion docs/quickstart-contract.schema.v2.json
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@
"composer_requirement": {"type": "string", "minLength": 1},
"onboarding_requirement": {
"type": "string",
"pattern": "^\\^[0-9]+\\.[0-9]+@RC$"
"pattern": "^\\^[0-9]+\\.[0-9]+(?:@RC)?$"
}
},
"additionalProperties": false
Expand Down
8 changes: 4 additions & 4 deletions scripts/check-docs-examples.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -123,12 +123,12 @@ assert(
'quickstart published version must match the Composer product train',
);
assert(
quickstart.package?.composer_requirement === `${quickstart.package.published_version}@RC`,
'quickstart Composer requirement must select the published release candidate',
quickstart.package?.composer_requirement === quickstart.package.published_version,
'quickstart Composer requirement must select the published stable release',
);
assert(
/^\^\d+\.\d+@RC$/.test(quickstart.package?.onboarding_requirement || ''),
'quickstart onboarding requirement must select a prerelease release channel',
/^\^\d+\.\d+$/.test(quickstart.package?.onboarding_requirement || ''),
'quickstart onboarding requirement must select a stable release series',
);
assert(
quickstart.workflow_authoring?.execution_model === 'fiber'
Expand Down
6 changes: 4 additions & 2 deletions scripts/check-docs-portal.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ const release = composer.extra['durable-workflow'];
const sdkVersion = release['product-train'];
const composerCommand = `composer require ${quickstartContract.package.name}:${quickstartContract.package.onboarding_requirement}`;
const sdkSeries = sdkVersion.split('.').slice(0, 2).join('.');
const sdkChannel = sdkVersion.includes('-') ? `${sdkSeries} prerelease` : sdkSeries;
const onboardingRequirement = sdkVersion.includes('-') ? `^${sdkSeries}@RC` : `^${sdkSeries}`;

function filesUnder(directory, extension) {
return fs.readdirSync(directory, {withFileTypes: true}).flatMap((entry) => {
Expand Down Expand Up @@ -178,7 +180,7 @@ assert.equal(
release.frameworks.laravel,
'Laravel adoption and Composer framework compatibility must stay aligned.',
);
assert(home.includes(`PHP SDK ${sdkSeries} prerelease`), 'Home release badge must identify the SDK prerelease channel.');
assert(home.includes(`PHP SDK ${sdkChannel}`), 'Home release badge must identify the SDK release channel.');
assert(
home.includes('<a class="button primary" href="/frameworks/laravel/">'),
'Home must keep a primary entry to the Laravel ownership guide.',
Expand All @@ -187,7 +189,7 @@ assert.equal(quickstartContract.schema_version, 2, 'Quickstart contract must use
assert.equal(quickstartContract.$schema, quickstartSchema.$id, 'Quickstart contract must identify its deployed schema.');
assert.equal(quickstartContract.package.name, composer.name, 'Quickstart package must match Composer metadata.');
assert.equal(quickstartContract.package.published_version, sdkVersion, 'Quickstart version must match Composer metadata.');
assert.equal(quickstartContract.package.onboarding_requirement, `^${sdkSeries}@RC`);
assert.equal(quickstartContract.package.onboarding_requirement, onboardingRequirement);
assert.equal(
quickstartContract.integrations.embedded_laravel,
'https://php.durable-workflow.com/frameworks/laravel/',
Expand Down
2 changes: 1 addition & 1 deletion scripts/ci/test-ci-qualification.py
Original file line number Diff line number Diff line change
Expand Up @@ -293,7 +293,7 @@ def test_established_laravel_transitions_are_executable(self) -> None:
self.assertIn("source_mode: embedded_v1", transition_job)
self.assertIn("workflow: '^1.0'", transition_job)
self.assertIn("source_mode: embedded_v2", transition_job)
self.assertIn("workflow: '^2.0@RC'", transition_job)
self.assertIn("workflow: '^2.0'", transition_job)
self.assertEqual(
1,
transition_job.count(
Expand Down
2 changes: 1 addition & 1 deletion scripts/qualify-quickstart-contract-deployment.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -220,7 +220,7 @@ function validateContract(contract, schema) {
'deployed contract must select an exact published package version',
);
assert(
contract.package?.composer_requirement === `${contract.package.published_version}@RC`,
contract.package?.composer_requirement === contract.package.published_version,
'deployed contract must derive its Composer requirement from the published version',
);
assert(!('published_smoke' in contract), 'deployed contract exposes a repository-local smoke path');
Expand Down
9 changes: 5 additions & 4 deletions tests/DependencyBoundaryTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -39,20 +39,21 @@ public function testProductionManifestHasNoEmbeddedFrameworkDependencies(): void
}
}

public function testPrereleaseMetadataDeclaresExactQualifiedArtifacts(): void
public function testStableMetadataDeclaresExactQualifiedArtifacts(): void
{
$metadata = $this->manifest()['extra']['durable-workflow'];
$quickstart = $this->quickstartContract();

self::assertMatchesRegularExpression('/^2\.0\.0-rc\.(?:0|[1-9][0-9]*)$/D', $metadata['product-train']);
self::assertSame('2.0.0-rc.68', $metadata['supported-server-versions']);
self::assertSame('2.0.0', $metadata['product-train']);
self::assertSame('2.0.0', $metadata['supported-server-versions']);
self::assertSame('1.19', $metadata['worker-protocol-version']);
self::assertTrue($metadata['durable-selection']);
self::assertSame('1.19', $metadata['durable-selection-minimum-worker-protocol-version']);
self::assertTrue($metadata['message-streams']);
self::assertSame('1.15', $metadata['message-streams-minimum-worker-protocol-version']);
self::assertSame($metadata['product-train'], $quickstart['package']['published_version']);
self::assertSame($metadata['product-train'].'@RC', $quickstart['package']['composer_requirement']);
self::assertSame($metadata['product-train'], $quickstart['package']['composer_requirement']);
self::assertSame('^2.0', $quickstart['package']['onboarding_requirement']);
self::assertSame(
'durableworkflow/server:'.$metadata['supported-server-versions'],
$quickstart['runtime_targets']['server']['image'],
Expand Down