From d2a5d27c94aa1089ba52847393f12c3ef6a22562 Mon Sep 17 00:00:00 2001 From: Richard McDaniel <1130888+rmcdaniel@users.noreply.github.com> Date: Sun, 25 Oct 2026 01:19:40 +0000 Subject: [PATCH 1/9] Server parity: Waterline v1 projection import fixture, recorded from published 2.11.1 POST /api/workflows/import/waterline-v1 (LegacyV1ProjectionController and LegacyV1Projection) from v1 flow-detail templates, in the probe's own namespaces: - The request gates, Laravel validation, and each normalization refusal, alone and together. - operator_id precedence over id, and a dry run that writes nothing. - The projection with idempotent, trimmed, changed and cross-namespace repeats. - Every v1 status, timestamp offsets and unparseable times, unusable rows, signal-name fallbacks, and the fewest accepted fields. - A native identity collision from another namespace. - The projected runs through describe, run, runs, history, history export and list. - The read-only refusal of signal, query, update, cancel, terminate, repair, archive, redrive and cooperative cancellation, on running and completed projections. Projected identities are hashes of the source id, which carries the recording prefix, so the probe computes them as mappedIdentity does and records them, their event ids, dedupe keys, export checksums and import-time sort keys as labels. Import and export times are placeholders. Status projections get distinct source times, so the list order does not depend on hashed ids. Two export details are made target- and prefix-independent: - The summary's history size is recorded without the bytes the prefix contributes. - The probe recomputes each export's checksum over PHP's canonical JSON of the bundle and records whether it matches. Timeline, wait and projection-source reporting belong to the general history export and are left out. Recorded three times under prefixes of 2, 7 and 9 characters, identical. Stream items and close are left out until native serves those routes. Co-Authored-By: Claude Opus 5.5 --- .github/workflows/server-parity.yml | 4 +- .../conformance/server-parity/contract.mjs | 3 + scripts/conformance/server-parity/probe.php | 6 + .../waterline-import-contract.mjs | 25 + .../server-parity/waterline-import-probe.php | 324 + .../ServerParity/waterline-import.json | 10752 ++++++++++++++++ .../waterline-import-observation.json | 10634 +++++++++++++++ ...erverParityWaterlineImportContractTest.mjs | 100 + 8 files changed, 21847 insertions(+), 1 deletion(-) create mode 100644 scripts/conformance/server-parity/waterline-import-contract.mjs create mode 100644 scripts/conformance/server-parity/waterline-import-probe.php create mode 100644 tests/Fixtures/ServerParity/waterline-import.json create mode 100644 tests/Fixtures/ServerParityExpected/waterline-import-observation.json create mode 100644 tests/Unit/ServerParityWaterlineImportContractTest.mjs diff --git a/.github/workflows/server-parity.yml b/.github/workflows/server-parity.yml index ac9285b2b..0be764cc3 100644 --- a/.github/workflows/server-parity.yml +++ b/.github/workflows/server-parity.yml @@ -37,6 +37,7 @@ on: - tests/Unit/ServerParityActivityLeaseRenewalContractTest.mjs - tests/Unit/ServerParityServiceCatalogContractTest.mjs - tests/Unit/ServerParityWorkflowImportContractTest.mjs + - tests/Unit/ServerParityWaterlineImportContractTest.mjs - tests/Unit/ServerParitySystemMetricsContractTest.mjs - tests/Unit/ServerParityOperatorDashboardTypesContractTest.mjs - tests/Unit/ServerParityPrometheusMetricsContractTest.mjs @@ -94,6 +95,7 @@ on: - tests/Unit/ServerParityActivityLeaseRenewalContractTest.mjs - tests/Unit/ServerParityServiceCatalogContractTest.mjs - tests/Unit/ServerParityWorkflowImportContractTest.mjs + - tests/Unit/ServerParityWaterlineImportContractTest.mjs - tests/Unit/ServerParitySystemMetricsContractTest.mjs - tests/Unit/ServerParityOperatorDashboardTypesContractTest.mjs - tests/Unit/ServerParityPrometheusMetricsContractTest.mjs @@ -1531,7 +1533,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/ServerParitySearchAttributeContractTest.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 tests/Unit/ServerParityLateWorkflowCompletionContractTest.mjs tests/Unit/ServerParityStorageTestContractTest.mjs tests/Unit/ServerParitySchedulePoliciesContractTest.mjs tests/Unit/ServerParitySignalsBeforeWorkerContractTest.mjs tests/Unit/ServerParityScheduleCatalogContractTest.mjs tests/Unit/ServerParityOperatorMetricsContractTest.mjs tests/Unit/ServerParityActivityLeaseRenewalContractTest.mjs tests/Unit/ServerParityServiceCatalogContractTest.mjs tests/Unit/ServerParityWorkflowImportContractTest.mjs tests/Unit/ServerParitySystemMetricsContractTest.mjs tests/Unit/ServerParityOperatorDashboardTypesContractTest.mjs tests/Unit/ServerParityPrometheusMetricsContractTest.mjs tests/Unit/ServerParityPayloadCleanupContractTest.mjs tests/Unit/ServerParityRepairPassContractTest.mjs tests/Unit/ServerParityClusterInfoContractTest.mjs tests/Unit/ServerParityNamespaceDeleteContractTest.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/ServerParitySearchAttributeContractTest.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 tests/Unit/ServerParityLateWorkflowCompletionContractTest.mjs tests/Unit/ServerParityStorageTestContractTest.mjs tests/Unit/ServerParitySchedulePoliciesContractTest.mjs tests/Unit/ServerParitySignalsBeforeWorkerContractTest.mjs tests/Unit/ServerParityScheduleCatalogContractTest.mjs tests/Unit/ServerParityOperatorMetricsContractTest.mjs tests/Unit/ServerParityActivityLeaseRenewalContractTest.mjs tests/Unit/ServerParityServiceCatalogContractTest.mjs tests/Unit/ServerParityWorkflowImportContractTest.mjs tests/Unit/ServerParityWaterlineImportContractTest.mjs tests/Unit/ServerParitySystemMetricsContractTest.mjs tests/Unit/ServerParityOperatorDashboardTypesContractTest.mjs tests/Unit/ServerParityPrometheusMetricsContractTest.mjs tests/Unit/ServerParityPayloadCleanupContractTest.mjs tests/Unit/ServerParityRepairPassContractTest.mjs tests/Unit/ServerParityClusterInfoContractTest.mjs tests/Unit/ServerParityNamespaceDeleteContractTest.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 diff --git a/scripts/conformance/server-parity/contract.mjs b/scripts/conformance/server-parity/contract.mjs index 0d3bc1be4..bb4d51a63 100644 --- a/scripts/conformance/server-parity/contract.mjs +++ b/scripts/conformance/server-parity/contract.mjs @@ -15,6 +15,7 @@ import {checkStorageTest} from './storage-test-contract.mjs'; import {checkActivityLeaseRenewal} from './activity-lease-renewal-contract.mjs'; import {checkServiceCatalog} from './service-catalog-contract.mjs'; import {checkWorkflowImport} from './workflow-import-contract.mjs'; +import {checkWaterlineImport} from './waterline-import-contract.mjs'; import {checkSystemMetrics} from './system-metrics-contract.mjs'; import {checkOperatorDashboardTypes} from './operator-dashboard-types-contract.mjs'; import {checkPrometheusMetrics} from './prometheus-metrics-contract.mjs'; @@ -154,6 +155,7 @@ export function checkObservation(fixture, observation, workflowId, artifacts) { const activityLeaseRenewal = fixture.activity_lease_renewal ? checkActivityLeaseRenewal(fixture, observation, workflowId) : null; const serviceCatalog = fixture.service_catalog ? checkServiceCatalog(fixture, observation, workflowId) : null; const workflowImport = fixture.workflow_import ? checkWorkflowImport(fixture, observation, workflowId) : null; + const waterlineImport = fixture.waterline_import ? checkWaterlineImport(fixture, observation, workflowId) : null; const systemMetrics = fixture.system_metrics ? checkSystemMetrics(fixture, observation, workflowId) : null; const operatorDashboardTypes = fixture.operator_dashboard_types ? checkOperatorDashboardTypes(fixture, observation, workflowId) : null; const prometheusMetrics = fixture.prometheus_metrics ? checkPrometheusMetrics(fixture, observation, workflowId) : null; @@ -710,6 +712,7 @@ export function checkObservation(fixture, observation, workflowId, artifacts) { ...(activityLeaseRenewal ? {activity_lease_renewal: activityLeaseRenewal} : {}), ...(serviceCatalog ? {service_catalog: serviceCatalog} : {}), ...(workflowImport ? {workflow_import: workflowImport} : {}), + ...(waterlineImport ? {waterline_import: waterlineImport} : {}), ...(systemMetrics ? {system_metrics: systemMetrics} : {}), ...(operatorDashboardTypes ? {operator_dashboard_types: operatorDashboardTypes} : {}), ...(prometheusMetrics ? {prometheus_metrics: prometheusMetrics} : {}), diff --git a/scripts/conformance/server-parity/probe.php b/scripts/conformance/server-parity/probe.php index e8da666f4..409f3b6d5 100644 --- a/scripts/conformance/server-parity/probe.php +++ b/scripts/conformance/server-parity/probe.php @@ -433,6 +433,7 @@ function httpObservation(array $fixture, string $workflowId, string $namespace, $activityLeaseRenewal = isset($fixture['activity_lease_renewal']) ? finishHttpActivityLeaseRenewal($client, $fixture, $workflowId, $url) : null; $serviceCatalog = isset($fixture['service_catalog']) ? finishHttpServiceCatalog($client, $fixture, $workflowId, $url) : null; $workflowImport = isset($fixture['workflow_import']) ? finishHttpWorkflowImport($client, $fixture, $workflowId, $url) : null; + $waterlineImport = isset($fixture['waterline_import']) ? finishHttpWaterlineImport($client, $fixture, $workflowId, $url) : null; $systemMetrics = isset($fixture['system_metrics']) ? finishHttpSystemMetrics($client, $fixture, $workflowId, $url) : null; $operatorDashboardTypes = isset($fixture['operator_dashboard_types']) ? finishHttpOperatorDashboardTypes($client, $fixture, $workflowId, $url) : null; $prometheusMetrics = isset($fixture['prometheus_metrics']) ? finishHttpPrometheusMetrics($client, $fixture, $workflowId, $url) : null; @@ -542,6 +543,7 @@ function httpObservation(array $fixture, string $workflowId, string $namespace, 'activity_lease_renewal' => $activityLeaseRenewal, 'service_catalog' => $serviceCatalog, 'workflow_import' => $workflowImport, + 'waterline_import' => $waterlineImport, 'system_metrics' => $systemMetrics, 'operator_dashboard_types' => $operatorDashboardTypes, 'prometheus_metrics' => $prometheusMetrics, @@ -855,6 +857,7 @@ function embeddedObservation(array $fixture, string $workflowId, string $namespa require __DIR__.'/activity-lease-renewal-probe.php'; require __DIR__.'/service-catalog-probe.php'; require __DIR__.'/workflow-import-probe.php'; + require __DIR__.'/waterline-import-probe.php'; require __DIR__.'/system-metrics-probe.php'; require __DIR__.'/operator-dashboard-types-probe.php'; require __DIR__.'/prometheus-metrics-probe.php'; @@ -1029,6 +1032,9 @@ function embeddedObservation(array $fixture, string $workflowId, string $namespa if ($mode === 'embedded' && isset($fixture['workflow_import'])) { $observation['workflow_import'] = ['applicable' => false, 'reason' => 'embedded_has_no_http_workflow_import']; } + if ($mode === 'embedded' && isset($fixture['waterline_import'])) { + $observation['waterline_import'] = ['applicable' => false, 'reason' => 'embedded_has_no_http_waterline_import']; + } if ($mode === 'embedded' && isset($fixture['system_metrics'])) { $observation['system_metrics'] = ['applicable' => false, 'reason' => 'embedded_has_no_http_metrics']; } diff --git a/scripts/conformance/server-parity/waterline-import-contract.mjs b/scripts/conformance/server-parity/waterline-import-contract.mjs new file mode 100644 index 000000000..4f9bf6255 --- /dev/null +++ b/scripts/conformance/server-parity/waterline-import-contract.mjs @@ -0,0 +1,25 @@ +import assert from 'node:assert/strict'; + +// Waterline v1 projection import (LegacyV1ProjectionController), recorded +// against published Server 2.11.1. The fixture's `expected` holds the whole +// normalized observation, with the probe's workflow prefix as `{id}`, +// projected identities, event ids, dedupe keys and export checksums as +// `{