Skip to content

Changed Python workflow definitions silently strand in-flight runs #518

Closed

Description

@rmcdaniel

Problem

A Python worker redeployed with any change to a workflow class cannot continue runs that started before the change, and nothing tells the operator why.

Reproduction

Published durableworkflow/server:2.9.7 via docker-compose.published.yml, PyPI durable-workflow==2.6.1, no build id:

  1. Worker v1 starts a run that waits on a condition. WorkflowStarted records v1's fingerprint with source worker.
  2. Stop v1. Start v2, whose only change is yield ctx.get_version("change", -1, 1) after the wait. Send the signal.
  3. The run stays waiting, with one ready, unleased workflow task, for 90 s. v2's polls return empty, and nothing is logged.
  4. Restarting the Server with DW_V2_PIN_TO_RECORDED_FINGERPRINT=false (confirmed in config) changes nothing.
  5. Restarting v1 claims the task within a second and completes the run. Fresh v2 runs complete normally.

While the run was stalled, the operator surfaces said nothing was wrong:

  • Describe showed compatibility_status: compatible with no recovery kind.
  • POST /workflows/{id}/repair returned repair_not_needed.
  • Task queue repair reported needs_attention: false.
  • The only hint was workflow_definition_fingerprint_conflicts on the build-ids view, and it appeared only while the stale v1 registration was still counted.

Acceptance criteria

  • With no active worker advertising a run's recorded fingerprint, run detail, describe, task queue diagnostics and repair all report a specific blocked reason that names the workflow type and the missing fingerprint, instead of compatible or repair_not_needed.
  • DW_V2_PIN_TO_RECORDED_FINGERPRINT=false lets a worker with the same type and compatibility claim those runs, as the docs already describe.
  • The Python versioning path works for in-flight runs: a worker whose only change adds a get_version branch continues runs started under the previous definition, with the default setting. Requiring old workers to keep running until those runs finish is not an acceptable resolution.
  • A regression test against published artifacts covers this scenario.

Activity

  1. added
    bugSomething isn't working
    kind:defectA public product behavior is incorrect
    priority:P1High-priority product or release risk
    on Oct 20, 2026
  2. rmcdaniel commented on Oct 20, 2026

    @rmcdaniel
    MemberAuthor

    Independent published-artifact reproduction

    Confirmed on the published Server 2.9.7 amd64 image sha256:40e969d0b6b240b835dcdb2fc531507266216ec34a83f59f561674f41e35f461 (Server source 150f3fbcbf3911a2a20abb53b4a714081ee53dd7, bundled Core 2.7.2 / 64efa176e4c37e5d6ae80e767ba3b41464024e53) and normally pip-installed Python SDK 2.6.1. All 46 hashed SDK distribution files match installed RECORD entries. No product source was edited.

    The API started with DW_V2_PIN_TO_RECORDED_FINGERPRINT=false; a bootstrapped read of its effective cached configuration returned boolean false before workflow admission.

    Actual original and replacement

    • Namespace default, queue general518, workflow type general518.wait, module/class definition.WaitingWorkflow, no build id, original compatibility null.
    • Original workflow general518-original, run 01m5c69qpq7b1n04pxd3a2sv61, execution budget 180 seconds and run budget 120 seconds, fixed at original admission. Each registration/terminal observer has a 30-second maximum; the actual replacement observation below lasted 25.02 seconds.
    • The old SDK worker registered HTTP 201, claimed the original workflow task, and committed a genuine condition wait. It then handled explicit SIGTERM, deregistered with HTTP 200 / deregistered, and exited 0. The old registration was verified absent before the replacement started.
    • The replacement's only class-source difference is yield ctx.get_version("change", -1, 1) immediately after the unchanged condition wait. Module/class, workflow/signal contract, queue, namespace and build/compatibility selection are unchanged.
    • Old fingerprint: sha256:bffe2533baf27d16a79ff01f19bf58a7cf27f4a71c14c1b15946d1daccc4a8a4.
    • New fingerprint: sha256:a9078a4e8ddea5afd30b93352c7680ac448d3d96523f7e9bcba71761f87b8e0c.
    • WorkflowStarted records the old fingerprint with source worker. The new worker registered HTTP 201. Across its lifetime, 22 observed workflow polls returned HTTP 200 / poll_status=empty / no task. The run remained stalled for the 25.02-second observation after the real ready signal; the worker made no workflow claim. The poll count is for the whole replacement process, not a separately filtered post-signal count.
    • The original remained waiting, with exactly one ready workflow task: no lease owner/timestamps, attempt 0, repair 0, no recorded claim error. Only the new registration was present.

    The first four committed history rows remained byte-identical through the stall. The diagnostic repair request below appended its expected RepairRequested audit event; it did not advance business execution. The original namespace/queue/compatibility, run id and stored deadlines remained exact, including UTC microseconds:

    • execution deadline 2026-10-20 08:22:28.086815
    • run deadline 2026-10-20 08:21:28.086815

    Diagnostics and old-code control

    • Describe: HTTP 200, compatibility_status=compatible, recovery_kind=null, waiting on the condition.
    • Repair: HTTP 200 / repair_not_needed.
    • Build-id view: workflow_definition_fingerprint_conflicts=[] after the old worker was removed.
    • Difference from the initial report: task queue repair.needs_attention=true at this observation. It indicates generic overdue task attention, without identifying the missing recorded fingerprint. This reproduction does not support claiming that field was false.

    The new worker stopped/deregistered and exited 0. A separate fresh old-code process then claimed the same original task and completed the same run in 2.09 seconds. Normal SDK decoding returned the exact signed-int64/null/Unicode result. Both actual task completion submissions returned HTTP 200 / completed / recorded=true; the replacement submitted no workflow completion. The final pre-shutdown read-only SQL capture confirms one completed run, two completed first-attempt workflow tasks, nine events, zero repairs and zero remaining registrations. Original history prefix and both original deadlines are unchanged. The API exited 0/no OOM/no restart on explicit SIGTERM.

    Correction retained: the first post-stop reader could not open the WAL-mode database through the read-only mount; that observer is unsuccessful. A separate corrected stopped reader then verified the same facts using mode=ro&immutable=1, only after the clean API exit and explicit confirmation that no WAL or SHM existed. Its database SHA-256 stayed a224e72c564c8304625a19babec87a7f21bc0ece6fb33bd0b0349ac1a4536fc9 before/after inspection. The original four-row prefix and both UTC6 deadlines also match in that stopped read.

    Source triage and correction boundary

    At the published Server source, WorkflowTaskPoller calls matchesRecordedWorkflowDefinition() around line 1043. Its worker-sourced fingerprint equality check around lines 2359–2386 does not consult the pinning configuration. Core's WorkflowDefinitionFingerprint::resolveClassForRun() does read that configuration, but it is the embedded class resolver, not this service-worker claim path. Python SDK 2.6.1 hashes the actual class source, so this one-line version-branch addition changes the advertised fingerprint as expected.

    Default strict fingerprint fencing is an existing documented policy, not itself disproved by this test. The confirmed defects are the ineffective documented opt-out on this path and incomplete operator explanations for the resulting blocked work. No earlier-version counterfactual establishes which release introduced them.

    The smallest useful correction to review is to make service claim eligibility and its operator diagnostics use the same fingerprint decision: preserve default strict fencing, honor the existing explicit opt-out without bypassing namespace/queue/type/build/compatibility or lease/capability guards, and report the missing recorded fingerprint when fencing is active. That proposal is not a safety qualification; it still requires contract review and regression coverage for original histories, get_version replay, false/true configurations and all affected diagnostics before adoption.

    Preserved setup/observer limits

    An initial preadmission fixture mistakenly used a nonexistent @workflow.run decorator and never registered a worker or created a workflow. A config-reader command initially omitted the autoloader. Both setup errors are corrected only in the later separate passing reads/original. An initial post-read auditor incorrectly expected no additional history despite intentionally issuing repair; the accurate assertion is an unchanged four-event prefix plus the one expected repair audit event. No product outcome was relabelled or repaired by those observer corrections.

    SQLite/source reproduction only: no MySQL/PostgreSQL, default-true runtime comparison, edited Server binary, native rewrite, or proposed-fix acceptance is claimed. Raw task data, SDK dependencies and all task resources are being retired immediately; the borrowed image is preserved for its owner.

  3. rmcdaniel commented on Oct 20, 2026

    @rmcdaniel
    MemberAuthor

    Actual cleanup verified at 08:24:31 UTC, before the 09:00 bound: all task application/worker containers, private network, SQLite data, installed SDK/dependencies, caches, fixtures and raw captures are removed (36 MiB). The borrowed published image remains intact for its owner. The exact published-artifact evidence and preserved setup/observer limits are in comment 6286711779. No product source was edited or proposed fix adopted.

  4. rmcdaniel commented on Oct 20, 2026

    @rmcdaniel
    MemberAuthor

    Accepted as a P1 product correction. The independent published reproduction in comment 6286711779 confirms the ineffective opt-out and missing routing explanation, but its proposed opt-out-only correction is not the complete acceptance contract.

    The fix must also support a replay-compatible Python code upgrade that adds get_version for an already-started run under the default configuration. Keeping old workers indefinitely or rewriting the guide is not the resolution. Default strict selection, compatible evolution and explicit opt-out need a coherent routing policy, with original recorded fingerprints/history left intact and real incompatible replay still refused.

    Next implementation work is the PHP matcher/diagnostics contract plus affected SDK replay compatibility controls: prove the unchanged-source failures first, retain namespace/queue/type/build/compatibility/capability and lease fences, then qualify normally installed old/new workers against the exact candidate and published artifacts. Coordination is on Server #325; no native/shared/frozen adoption or claim of a shipped fix follows from this triage.

  5. rmcdaniel commented on Oct 20, 2026

    @rmcdaniel
    MemberAuthor

    PHP correction is in draft #525 at 57de9ec39b4107f32d2a7bcb6b070a4158cf3dc1, whole tree 7f734fb91d81e5ba39579f21145eb9cbaab0fce5.

    The default now prefers a fresh eligible recorded-definition peer, then lets a replacement undergo strict replay when no eligible matching peer remains. The published opt-out removes that preference. Build pins, namespace/queue/type, capability and actual wire-version eligibility, registration identity and claim/lease fences remain. Original history, fingerprint and deadlines are not rewritten. Run detail/debug, queue detail and repair expose the same routing policy; repair preserves its stored command decision.

    Qualification:

    • Tests first: two new actual HTTP regressions fail on unchanged source; matching-live-peer control and all 19 old pinning tests pass.
    • Parent implementation e03bd5fc3: 189 focused and surrounding PHP tests / 2,155 assertions pass. Final canonical selected/current-run enrichment correction: 95 focused tests / 1,279 assertions pass.
    • Four fresh originals on final 57de9ec39, normally installed Python SDK 2.6.1 (33 Python distribution files independently match RECORD): default replacement completes the original after an actual get_version edit; a live gated matching peer keeps preference and completes when released; effective pinning=false permits replacement despite that peer; an incompatible condition key is leased but reports NonDeterministicReplayError/condition_key_changed, with zero business completion.
    • Eight actual application Worker processes exit 0. Three independent cold Client processes return exact signed-int64 maximum/null/Unicode results. Eight first-attempt workflow tasks, zero repairs, 30 retained events. All original history prefixes/fingerprints remain equal. Stopped query-only SQLite audits verify the unchanged original 60-second run and 120-second execution deadlines at stored microsecond precision, typed durable replay refusal and unchanged database/WAL hashes.

    Earlier probe/setup and audit mistakes remain unsuccessful, including the first observer's incorrect history URL. That preliminary original is separate and retains one stale setup registration; final-cohort registrations are zero. No rows were deleted to manufacture an audit pass. The development PHP API launcher needed forced shutdown (137/no OOM), so graceful API shutdown is not qualified here.

    Normal CI and Sonar for the exact new head are queued. No merge, release, installed Server image or native/shared/frozen adoption claim. The original published-image failure remains failed. The next gate is normal exact-head CI/Sonar, followed by publication and genuine installed-image acceptance. Native/shared/runner/OpenAPI/Composer/version paths remain unchanged.

  6. rmcdaniel commented on Oct 20, 2026

    @rmcdaniel
    MemberAuthor

    Source follow-through is now e692df2196a3e973903e10ea2fec22487ba1707b / whole b4280b968732e0a84f0599033525845c2c040ea3. It integrates current main 1638681911a473b86484a1782b4654bab80ed209 without changing its native benchmark additions. Fresh normal gates are qualifying this combined tree; no prior whole-tree pass transfers.

    The four actionable maintainability findings on prior 57de9ec3 were addressed in source, without threshold changes or suppression. A new actual HTTP regression also preserves the existing distinction between omitted client metrics and explicit process_metrics: null: omission retains them, explicit null clears them, and neither can overwrite the authenticated server-owned worker protocol. The old implementation failed that null regression; final routing/pinning/debug/queue/control-plane selection passes 114 tests / 1,746 assertions. Fresh analyzer resolution remains pending.

    There is now a separate release-safety dependency: shared221 tracks source-verified service SDK entry-binding errors that can become terminal workflow failures before application versioning code runs. Core866 independently reproduces the embedded counterpart, including silently substituted DTO input. Current518 evidence proves command-history incompatibility refusal, not safe handling of every entry-signature/input-schema change. I will qualify that SDK boundary before publishing518's routing fallback; keeping old workers forever is not the product resolution. The independent PgBouncer524 fix can proceed through its own exact source/image gates.

    No source-hash policy can prove arbitrary application code compatible. Original run/input/history/claim/deadline authority and the real SDK refusal decision remain required. This is an owned implementation/qualification dependency, with no operator action needed.

  7. rmcdaniel commented on Oct 20, 2026

    @rmcdaniel
    MemberAuthor

    Python's counterpart is now independently reproduced with normally installedSDK2.6.1, whose replayer/Worker/errors bytes match published150c6f6b. Against candidate-qualified Server525 e692, adding a required entry argument terminally fails a genuine original both before first execution and after a committed condition wait. Genuine body-error and compatible optional-entry controls remain distinct. These are source-Server/published-SDK observations, not a released Server fallback qualification.

    Draft SDK Python170 now holds correction 6dcd59280af4fff4b7764f6f1b0f4f22a3f8693b / whole 297d2fc623dec961ee266b4961d975f4ceee3c69. It pre-binds the call outside application failure handling and uses the existing typed task refusal with reason workflow_entry_arguments_mismatch. Python annotations remain annotations. Final style/strict typing and674 focused tests pass, two explicit skips. The retained official fixture fails unchanged source by observing the unsafe terminal command.

    Two final actual source originals expose replay-blocked API diagnostics and recover through supported run-scoped repair with compatible code, same input/history prefix/microsecond deadlines and one completion each. An earlier source component separately covers genuine body failures and optional arguments. Across12 originals the stopped read-only audit verifies17 tasks/65 events/four repairs/zero registrations/28 Worker exits0; six cold readers preserve typed results. Failed published originals and the broad local failed qualification remain explicit in the PR. No full hosted or published fixed-SDK claim.

    PHP/Rust reproduction and correction remain next, together with published artifact/UI acceptance. Server518's release-safety dependency is still open; no human action is needed. No native/shared/frozen adoption or competing Server implementation is requested.

  8. rmcdaniel commented on Oct 20, 2026

    @rmcdaniel
    MemberAuthor

    Problem

    Service-SDK counterpart of durable-workflow/.github#221 and Workflow#866. Normally installed PHP SDK 2.5.3 reproduces terminal failure when a redeployment adds a required entry argument before the first task or after a committed condition wait, and when the recorded integer is no longer accepted by a string parameter. A genuine body TypeError still fails, and a compatible optional addition completes with exact typed output.

    The isolated target is the already candidate-qualified PHP Server525 source, not a published routing fix or native runtime. The five published-SDK business originals and the two unsuccessful fixture setup attempts remain separate.

    Source correction

    Candidate aa53d791cc93c81b13e51ff8f12f6a321b07bfce, whole tree d7afc1017cd2f9a0ca7b3d2c10a6d8d192a63b60, validates the real discovered callable's entry inputs before entering application code. It reports a typed nonterminal workflow-task replay refusal with safe binding metadata, preserving claim/input/history/deadlines. Genuine body failures retain business failure semantics, including a body that deliberately throws the new internal exception. PHP's compatible optional, nullable, union, variadic, integer-to-float and trailing-argument rules remain explicit controls. The first variadic context parameter is also checked against recorded input.

    Verification and remaining delivery

    • Tests-first 802072bc has nine actual failures and seven passing controls. Its first mock omitted a later activity poll; that unsuccessful fixture attempt remains distinct from the corrected counterfactual.
    • Full local PHP 8.3 suite: 2,516 tests, 12,471 assertions, 56 skips, no failures. Final focused entry/corpus selection: 23 tests, 66 assertions. Five changed PHP source/test files pass PHPStan with its existing level 6. An earlier 128 MiB analysis ran out of memory; the explicit 768 MiB process succeeds. Missing generic/array annotations were corrected without suppressions.
    • The minimized actual post-wait input history is retained in the official replay corpus. All 41 PHP fixtures pass through the official Worker consumer. The new fixture fails against the normally installed published producer with expected.type does not match, rather than passing because the test runner cannot load.
    • Five published originals, five initial source originals and six final-runtime originals remain separate. Final originals prove three typed nonterminal refusals followed by compatible cold code and supported repair of those exact runs, a genuine body TypeError, a deliberately thrown internal exception remaining a business failure, and a compatible optional addition. Every business worker exits 0. Nine separate normally installed cold clients preserve integer maximum/null/Unicode results.
    • Stopped read-only SQL verifies 16 business runs, 26 tasks, 104 events, six intentional repairs, 38 worker exits 0 and zero registrations. Original microsecond starts plus 30-second run / 60-second execution deadlines, exact history prefixes and database/WAL hashes are preserved. One earlier selected-run observer setup admitted a separate waiting run; it is not counted as a passing original. The earlier registration observer missed the actual /worker/register route before any business admission. Neither fixture mistake is called a product defect.
    • API shutdown required 137 with no OOM after the business controls finished. Graceful API shutdown is not qualified.

    Exact normal CI/Sonar/policy, source merge/fresh main, stable publication and installed artifact/API/Waterline acceptance remain pending. No SDK major, protocol floor, Server runtime, dependency or frozen actor change. The independently reproduced Python counterpart remains SDK Python #170; Rust's typed-input adapter is still open in .github#221. Server#518 release remains held until the relevant client safety is qualified.

  9. rmcdaniel commented on Oct 20, 2026

    @rmcdaniel
    MemberAuthor

    Rust entry-safety: genuine published-backend counterfactual and remaining runtime boundary

    Source: SDK Rust draft #106, exact ecd2a7155a99a16ada0ff40d05b74fbf028e083f. This compatible refinement preserves the existing public Error::HandlerType variant shape; its five focused controls and sixteen official replay fixtures pass. The preceding implementation passed all 562 library tests. Normal final-head CI is still required.

    Three genuine originals ran against immutable Server 2.9.8 / Core 2.7.2, amd64 child 76c5b6b7cc78aeb02dd1ff9f87016662991c11f9af7dba4aaae7748bc87a1ad1, PostgreSQL 16.15. The published counterfactual uses normally resolved crates.io 3.5.5. Both consumers use byte-identical application source and identical recorded workflow fingerprint; a controlled custom input deserializer changes its schema requirement before handler entry. This qualifies entry-error classification, not the separate changed-fingerprint routing fix in Server #518.

    • Published 3.5.5, rust221-published-before / 01m5cvwxm0f4satz58nwb1qhmv: an incompatible input terminally fails the business run before any body or activity invocation. Exact history is StartAccepted, WorkflowStarted, WorkflowFailed.
    • Published 3.5.5 cold replay, rust221-published-cold / 01m5cvwzhh8qjjnb6k4gvh24m3: one genuine activity completes first; the incompatible cold worker invokes neither body nor activity. The run remains waiting and the failed continuation is replay-blocked. Five committed events survive. This differs from the pre-history terminal failure.
    • SDK source, rust221-source-before / 01m5cvx2hahs8bjtpjdcyk6amz: zero body/activity invocations; the SDK submits task failure with reason workflow_entry_arguments_mismatch and type WorkflowEntryArgumentsMismatch. The business run remains pending with its two original events. Published Server 2.9.8 does not replay-block this reason: it persists a failed task and creates a ready retry task. Only one incompatible attempt ran; an endless retry loop was not reproduced. Source inspection confirms the held Allow replay-compatible workflow definition upgrades and explain routing #525 classifier also needs the new structured reason before its release.

    Stopped SELECT-only SQL confirms the three original inputs are byte-identical; original start+30-second run and start+60-second execution deadlines retain exact stored precision. The source original starts 2026-10-20T14:37:01.866168, with deadlines 14:37:31.866168 and 14:38:01.866168. No deadline was extended. Pending/waiting are the observed stopped states after wall-clock expiry; no later timeout transition is inferred.

    The aggregate recovery recipe is unsuccessful: its repair request omitted the required control-plane-version header and received canonical HTTP 400. Recovery and the later source-cold/body cases were therefore unexecuted. A first audit used a nonexistent registration table and failed; a separate corrected read-only run/event/task audit completed. No zero-registration claim follows from that audit. The API required stop 137/no OOM; PostgreSQL exited 0/no OOM. No graceful API-shutdown claim.

    All owned runtime, database, compiler/dependency/target/formatter, downloaded image and raw evidence resources were removed at 14:43:40 UTC, before the 14:45 cleanup checkpoint. Only clean pushed product source, a small reproduction recipe and this bounded receipt remain. Borrowed and other-agent resources are preserved.

    Next acceptance gate is coordinated SDK + Server handling: explicitly replay-block this typed pre-entry failure, preserve the original task/history/input/deadlines, and verify supported compatible recovery on a fresh original. SDK publication must not imply that current Server 2.9.8 supplies that missing fence. Existing failed originals remain failed; no runtime, native/shared/frozen change is inferred or requested here.

  10. rmcdaniel commented on Oct 20, 2026

    @rmcdaniel
    MemberAuthor

    The current-source Server regression now independently reproduces the missing entry-refusal fence for all three SDK failure types: each creates an unwanted retry task. Explicitly recognizing the structured workflow_entry_arguments_mismatch reason makes the full 24-case worker-evolution selection pass, including original-task supported repair and unchanged admission/deadline bytes. Ordinary application failures keep their existing semantics.

    Review exposed a second release requirement: default changed-fingerprint fallback must not silently route an original to an older SDK that can still terminally fail it during entry binding. The coordinated fix will use an additive worker capability, workflow_entry_arguments_validation, advertised only by the corrected first-party worker implementations. Matching recorded definitions retain their existing routing, as do the explicit pinning opt-out semantics. Default replacement fallback requires this safety declaration; diagnostics must identify a missing declaration and the worker upgrade action. A raw caller's registration remains its declaration of implementation, not independent proof of safe code.

    This adds no protocol floor and does not rewrite a stored fingerprint, build pin, namespace/queue/type, input, history or deadline. Existing/native/frozen workers do not acquire the capability by assumption. SDK source, runtime, normal CI and fresh genuine artifact acceptance remain separately required before release or issue closure.

  11. rmcdaniel commented on Oct 20, 2026

    @rmcdaniel
    MemberAuthor

    Published Rust entry-safety acceptance

    The protected 3.5.6 publisher 39469465008 passes. Independent crates.io sparse-index and downloaded-archive verification match checksum 3e933f0d775c25c2002f154829b31232089dc65f8f9d4c43e893128ed06a5215 and embedded Git source 01be5a0bb175a5371f69e1cf9d6104448d94eb39.

    A fresh normal Cargo registry installation (no SDK path/source overlay) passes three actual SQLite originals against immutable Server 2.9.9, index sha256:d45d197e9556292ec096531030717e43d69ea4ea9ab197170971492f14cc0869, amd64 image/config 040a104ad6614dd5eca59d49d1a365b3d068f7bcdf0a507fdf2585c112611146, Core 2.7.2. The consumer binary is c80aef21ed80ebae748322f3b6bffb7c0bfc1abacb04790bd6003f304aded054.

    • Pre-entry refusal, run 01m5d7we5sdpf9mn74380mjb88: incompatible decoding invokes zero body/activity callbacks and leaves the original task replay-blocked. Supported repair and compatible code complete the same run once in 3.70 seconds.
    • Cold refusal, run 01m5d7wkptfvszxbhqbbv92q88: a genuine activity commits before incompatible cold replay. The refusing worker invokes zero callbacks and preserves that complete prefix; repair and compatible replay finish the same run in 3.60 seconds without another activity invocation.
    • Genuine body failure, run 01m5d7ws32j6swn6ey09psx88n: an application error remains an ordinary terminal failure, with no entry-mismatch classification.

    Both successful runs retain the exact original int64-maximum/null/Unicode output, input/history prefixes, and microsecond start+30-second run / start+60-second execution deadlines. Separate cold clients decode the original result. Seven business Worker processes, both supported repairs and both cold readers exit 0. Stopped, kernel-read-only SQL independently proves two completed runs, one intentional failed run; seven tasks (six completed/one intentional failure), 17 events, two deliberate repairs and zero registrations. The database SHA-256 is unchanged before/after the corrected read-only audit.

    The first aggregate audit used an incorrect registration table name and failed before producing counts; its corrected separate reader uses the actual table. The first build invocation also refused a missing new consumer lockfile before compilation; normal resolution followed by the locked build succeeds. Neither setup failure is a product defect. API teardown required exit 137/no OOM; the idle consumer container exited 143/no OOM, so no graceful API shutdown is claimed.

    This completes the Rust 3.5.6 installed entry-safety slice. The PHP/Python installed consumers, broader changed-definition routing, operator/Waterline diagnostics and held all-locale documentation remain separate requirements of shared #221 / Server #518. No cross-SDK, native, catalog, Cloud or stopped-qualification adoption is inferred.

  12. rmcdaniel commented on Oct 20, 2026

    @rmcdaniel
    MemberAuthor

    Normally installed PHP 2.5.4 acceptance

    Fresh Composer installation resolves durable-workflow/sdk 2.5.4 from Packagist, exact source/dist cd8834aea01331912e6e9854ae0174f9fb7ba8fa, with no SDK source overlay. The immutable backend is Server 2.9.9, index sha256:d45d197e9556292ec096531030717e43d69ea4ea9ab197170971492f14cc0869, amd64 image 040a104ad6614dd5eca59d49d1a365b3d068f7bcdf0a507fdf2585c112611146, locked Core 2.7.2.

    All six actual originals pass the existing entry-binding recipe:

    Control Original run Observed result
    Added required argument before entry 01m5d8g1vcxr2qaa6hbk9ve4dx Typed nonterminal refusal, same-original supported repair and one completion
    Added required argument after a committed wait 01m5d8gb33wb29r6c1kzzspvdk Typed cold refusal, retained wait/history, same-original repair and one completion
    Recorded integer incompatible with new string parameter 01m5d8gpvt0py6sry5jda1hd14 Typed cold refusal and same-original repair
    Compatible optional argument 01m5d8h1et9q80pq8nnzefptzn Completes normally
    Genuine body TypeError 01m5d8h6nj4fbat8qkne9qkxkz Ordinary terminal business failure
    Body deliberately throws the internal entry exception 01m5d8heqxvqybv7nm4zgwwtm0 Ordinary terminal business failure

    The three incompatible workers submit exactly one entry-mismatch refusal each and no terminal workflow command. The public per-run debug route reports replay-blocked state. Restoring compatible code and the supported run-scoped repair complete the original runs. Exact original input/history prefixes and microsecond start+30-second run / start+60-second execution deadlines survive. Four separate normally installed cold clients decode exact integer-maximum/null/Unicode results.

    All 15 business Worker processes exit 0. Independent stopped SQL verifies six runs (four completed/two intentional failures), ten tasks, 41 events, three deliberate repairs, zero registrations and no extra setup original. Database SHA-256 202e18a0688c5828ed0cce61b2b78709fdd9dd625eba6f2dd5426605f8f93bf4 is unchanged.

    The first kernel-read-only aggregate auditor cannot open this WAL-mode file without sidecars. The corrected separate auditor first refuses any existing WAL, then reads the stopped WAL-free file with SQLite's immutable/read-only option on a kernel-read-only mount, as allowed by SQLite's read-only WAL rules. No source bytes or journal mode are changed. The first audit stays unsuccessful. API teardown requires 137/no OOM; the idle client exits 143/no OOM. Graceful API shutdown remains unqualified.

    This completes PHP 2.5.4's published entry-safety acceptance. Rust 3.5.6 has its separate published acceptance at shared #221. Python 2.6.2, Waterline/operator presentation, held all-locale Website #333 and PHP portal #195 follow-through remain pending; shared #221 / Server #518 remain open. No native/catalog/frozen or Cloud adoption is inferred.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingkind:defectA public product behavior is incorrectpriority:P1High-priority product or release risk

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions