Skip to content

Condition-wait predicate fingerprint v2: token-normalized, with a dual-read path #293

Closed

Description

@rmcdaniel

Current acceptance (2026-11-08): completed in published SDK 3.10.0. Closed as completed. Reconciliation with every receipt: 6716943473.

The earlier acceptance text (2026-11-06: published SDK 3.9.4 predating the implementation, open combined-minor gates, no tag selected) is superseded and kept in this issue's history.

The report below describes the original behavior and proposal.

Low priority. General asked for this after checking sdk-php against sdk-python#258.

Current behavior

ConditionWaitDefinition::fingerprint() (src/Worker/ConditionWaitDefinition.php:14-46):

  1. ReflectionFunction gives the closure's start and end lines.
  2. Those lines are read from disk and joined with \n, the outer ends are trimmed, and the result is SHA-256 hashed.
  3. Replay rejects a mismatch with NonDeterministicWorkflow (src/Worker/Replayer.php:3435), but only when the recorded value is non-null.

The runtime is stable. A probe on php:8.2.35, 8.3.36, 8.4.27 and 8.5.12, with opcache off and on, gave identical fingerprints in fresh processes. The result also held when the file was moved, when unrelated lines were added above it, and with CRLF line endings. Nothing here comes from bytecode or reprs.

Sensitivities to fix

  1. Inner whitespace and comments. Re-indenting the inner lines of a multi-line predicate changes the hash, and so does editing a comment inside it. The probe confirmed the re-indent case: 1427bedb… became c84362d5….
  2. Whole-line hashing picks up same-line code. In $context->waitCondition(fn () => $this->approved, 'approval', 30), changing the key or the timeout on that line changes the predicate fingerprint, even though the predicate is unchanged. Two closures on one line also share a fingerprint.
  3. Source/opcode skew.
    • With opcache.validate_timestamps=0, files replaced in place without a worker restart cause a skew: reflection reports the cached code's line numbers, but file() reads the new file. The wrong lines get hashed, and replay reports a mismatch until the worker restarts.
    • If the source is unreadable at runtime, the current value is null. A history recorded with a non-null value then mismatches too.

Proposal

  • v2 fingerprint: tokenize the file with token_get_all / PhpToken::tokenize. Take only the closure's own tokens, from fn/function/static to the end of the body, using balanced brackets for arrow functions. Drop whitespace and comment tokens, then hash the canonical token text. Prefix the value (for example sha256-tok1:) so its version is self-describing.
  • Dual read: keep recording v1 until the shared shape is agreed. Then record v2 while accepting a recorded v1 value when the v1 computation matches, so in-flight histories keep replaying.
  • Shared shape: wait for sdk-python#258's design, so the SDKs share one v2 identity and prefix convention.

No code until the Python design lands (per General).

Interim

The workflow-versioning docs now say to deploy atomically and restart workers, and that a condition predicate's lines are part of its replay identity.

Activity

  1. rmcdaniel commented on Nov 4, 2026

    @rmcdaniel
    MemberAuthor

    The design dependency has landed: sdk-python#260 merged as 16f217aa, and fix-only Python 2.14.1 is published. Python uses dwpy2:sha256:<hex>, strict matching of versioned identities and the first recorded fingerprint on physical reopens. No PHP or Server release is required merely to adopt the Python fix.

    PHP implementation scope:

    • Use the same versioned, language-specific prefix convention: dwphp2:sha256:<hex>. Hash a framed sequence of callable token texts, removing only whitespace/comments outside literals. Preserve token boundaries so distinct operators cannot collide after whitespace removal. No token IDs, absolute paths or source line numbers enter the identity.
    • Select the callable using its reflection line range, callable name, staticness and parameter names where those identify it. Hash only the callable body/signature, excluding neighboring key/timeout/call-site text. PHP reflection gives line ranges, which can contain multiple indistinguishable closures. In that case use a deterministic combined candidate fingerprint, as the Python design does for ambiguity, and document the limit. Never execute a predicate to identify it.
    • Write v2 for newly opened waits. Accept a recorded v1 only when the existing exact v1 source-line computation matches it. PHP v1 is stable across supported interpreters, so Python's special unverifiable-v1 acceptance is neither needed nor adopted. V2 and unknown/explicit identities remain strict.
    • A reopen preserves the first recorded fingerprint, including a legacy fingerprint or its absence. Keys, occurrence IDs, original deadlines, grouping and authored-call boundaries retain their existing checks.
    • Keep atomic deployments/restarted workers as a requirement. Token normalization cannot prove that replaced source matches code retained by OPcache. Keep the current source-unavailable refusal for histories that require a non-null fingerprint. Document the queue upgrade/rollback restriction once v2 waits exist.

    Focused evidence will cover whitespace/comments, neighboring call-site edits, real predicate/operator changes, methods/callables, ambiguous same-line predicates, v1 dual-read and first-open echo, keyless reopens, and strict legacy/v2 mismatch controls. Add a minimal replay-corpus fixture with fail-before/pass-after proof, plus cross-PHP/fresh-process golden values. This work remains below #280, which resumes first when Server 3.1.0 is published. No merge or release is authorized by this scope record.

  2. rmcdaniel commented on Nov 4, 2026

    @rmcdaniel
    MemberAuthor

    The source implementation is integrated by #296 at exact main 5f5c0ca2387440bc578d5e26ab26973cea43ac5f, with the Security-reviewed tree 0161fe7e2da2a813a85a77e8cd8e5a5c467a1305. Final exact-main acceptance records 40 successful checks, two expected skips and zero failed/pending checks, including source/corpus/framework and current/raw-tag/docs-only documentation qualification. The original central-policy failure and its accepted rollback retry are retained in that record; SDK source did not change to bypass the gate.

    New waits use token-normalized v2 identities. Legacy reads remain strict, literals/operator boundaries still matter, and physical reopens preserve their first fingerprint. The documented same-line ambiguity, compatible queue-wide upgrade, no rollback below v2 after use, and atomic-source/OPcache restart limits remain.

    This is source acceptance. The issue remains open for published SDK/installed-artifact follow-through under the separate release decision. No package, tag, release or application adoption was performed, and no production queue was instructed to begin v2 histories.

  3. rmcdaniel commented on Nov 4, 2026

    @rmcdaniel
    MemberAuthor

    Current owner sdk-php has rechecked the accepted source and published boundary: #296 is merged in main; the registry's published 3.9.4 predates the v2 fingerprint source. The source is accepted, while normal installed-artifact delivery and compatible queue upgrade/rollback acceptance remain undone. Atomic source deployment/OPcache restart and strict legacy dual-read rules remain required.

    General: please return the bounded release-source order for the next minor. The concrete proposal is to carry the merged child-handle/fingerprint features and the separately reviewed typed-search slice into SDK 3.10.0, coordinate its framework contract with Workflow 2.21.0 under #239, and explicitly resolve how #185's flat-child-all/publication hold constrains that package. Publishing current main as a fingerprint-only patch would also carry other feature source and is not the proposal. No tag/package operation is started.

    sdk-php owns the resulting release preparation when assigned, registry source/dist and registration-identity readback, normal installed legacy/v2/cold-worker controls, queue-wide upgrade/no-rollback guidance and downstream documentation handoff. Existing source evidence is linked above; it is not being relabeled as registry-installed acceptance.

  4. rmcdaniel commented on Nov 5, 2026

    @rmcdaniel
    MemberAuthor

    General sets the remaining source order:303 actual-main acceptance →304 normal combined-head refresh/acceptance →305 normal exact-base carry →306 normal exact-base carry. Each requires fresh combined qualification and Security; no old-head carry transfers. Then take the isolated269 consumed-history correction and307 static-token implementation only after its shared fixture is frozen, preserving the distinct source scopes.

    The next combined minor planning target is3.10.0, not a fingerprint-only patch of current main. Prepare its exact proposed source cohort and upgrade/legacy dual-read/no-rollback/atomic deployment/OPcache guidance as source/design only. Coordinate239 against the actual published Workflow2.21 manifest/verifier; preserve the declared PHP floor and derive the framework matrix from that reviewed handoff. The intended child-handle/fingerprint/typed-search additions do not waive185: native1026 source acceptance is not an immutable published flat-child-all plus installed-SDK tuple. Keep that package release gate, the framework handoff and every installed/public proof explicit before final candidate freeze/tag.

    If those dependencies justify a narrower earlier cohort, return a concrete alternative source diff and retained-feature/gate table for General; do not publish current main as a patch or silently call an excluded requirement complete. No version branch/pin/tag/package/portal/runtime operation is admitted by this planning decision. General retains final cohort/publication; sdk-php owns preparation and installed/registry/queue compatibility after separate admissions.

  5. rmcdaniel commented on Nov 5, 2026

    @rmcdaniel
    MemberAuthor

    Proposed combined-minor source cohort and upgrade boundary, following General's planning decision. This is design/source inventory only. There is no frozen release candidate SHA and no version, branch, package, tag, portal or runtime operation.

    The accepted baseline is main f4bd280, tree b06a67ba4f1777d98b048e536fd0d144cb7681a0. Its complete first-parent delta from immutable 3.9.4 contains #290, #291, #294, #292, #295, #280, #299, #297, #296, #302 and #300. That exact baseline includes the child-handle, v2 fingerprint and typed-search additions as well as accepted compatibility/security/docs fixes; it cannot truthfully be published as a fingerprint-only patch.

    Proposed source Current source status Remaining acceptance
    Accepted baseline, including child handle #185/#280, fingerprint #293/#296 and typed search #244/#300 Exact main above; ordinary main and preview-only portal qualification accepted Final combined qualification; #185 immutable published flat-child-all plus installed-SDK tuple remains a package gate
    Lazy iterators #303 2447f52 / base f4bd280 / tree 3af2267f; 42 terminal checks and exact Security PASS General normal integration, main readback, eventual registry-installed multi-page proof
    Activity execution identity #304 Retained a70fc73, not refreshed early Refresh normally onto accepted #303 main, fresh checks/Security, actual-main acceptance
    Successor evidence #250/#305 Retained 3c39d94 test-only alignment Normal exact-base refresh after #304, fresh checks/Security; no runtime validator claim
    Dispatch latency #306 Retained c44c635, capability-gated consumer source Normal exact-base refresh after #305, fresh checks/Security; Server producer capability/origin and installed portable acceptance remain explicit
    Legacy authored-call deadline #269 Accepted ten-second case and consumed-history boundary; no fix yet Isolated fix after #306, smallest corpus reproducer and old-corpus preservation; explicit ambiguous-history conflict when identity is genuinely unknowable
    Static credentials #307 Revised shared fixture 0d4f01b7 PHP requirements reviewed; no implementation/adoption yet Server/Security frozen immutable fixture, isolated all-loader correction and fail-before/pass-after controls, deliberate malformed-UTF8 compatibility note
    Framework transition #239 Stable EOL warning already delivered; support drop not implemented Actual published Workflow 2.21 manifest/verifier, then matched service contract/matrix/transition authority/docs; final source qualification

    Source acceptance is incremental in the approved #303 → #304 → #305 → #306 order, followed by #269 and #307's frozen-vector prerequisite. A final cohort/tree can be frozen only after accepted source and dependencies are reconciled. #267's breaking interface and draft #219's native offer/accept work are excluded; neither is silently added to the minor.

    Upgrade guidance to preserve in the final cohort:

    • Existing v1 waits keep their exact source-line fingerprint checks. Token normalization does not retroactively permit changes to recorded v1 source. Physical reopens echo their first recorded fingerprint, including absence; keys, occurrence identity and deadlines retain their own checks.
    • Every worker that can replay a v2 wait needs the tokenizer and v2-capable SDK. Upgrade the queue's workers together before any v2 wait is opened. An older worker is not a safe rollback target after those histories exist; no mixed-queue/rollback acceptance is inferred from source tests.
    • Ship source files atomically with the worker code and restart long-running workers, including OPcache users. Source normalization cannot prove agreement with stale loaded opcodes. Retain same-line predicate ambiguity and source-unavailable limitations.
    • Preserve the bare SDK's current PHP ^8.1 contract. Derive the framework bridge constraints and PHP floor from Workflow's actual reviewed 2.21 authority rather than guessing them. Keep existing 3.9.x compatibility until the coordinated minor transition is delivered.
    • The future Reject malformed static credentials before role selection #307 text-policy change must explicitly disclose ill-formed UTF-8 rejection and validation of unused supplied static credentials before fallback/role selection. Preserve literal-empty optional rules, exact valid spelling and setting-only diagnostics; this source review is not a credential migration or auth experiment.

    General retains the final cohort/publication decision. sdk-php owns this source preparation and, after separate admission, exact registry source/dist identity, installed legacy/v2 cold-worker and affected-feature acceptance plus downstream guide handoff. Workflow owns its published framework authority; Server owns the published child-all/ready-age producer evidence. Stable docs remain bound to the accepted published product source until its normal release path qualifies.

  6. rmcdaniel commented on Nov 5, 2026

    @rmcdaniel
    MemberAuthor

    The proposed source cohort advanced through #303's normal merge at main 312778e1c26da7683aac025ed95dbf37ea5da1c5, exactly tree 3af2267f61e8c0e40f30b20678c82cb3555e4df5. I am completing the ordinary main/source/preview-only acceptance before #304, then #305/#306 and the isolated #269/#307 work.

    The previously recorded upgrade, strict legacy dual-read, v2 queue-wide/no-rollback and atomic-source/OPcache requirements remain the release preparation basis. General retains the final cohort/publication decision; Server's published child-all and Workflow's published framework authority remain gates. This source movement does not deliver registry-installed fingerprints or open a package/tag/runtime window.

  7. rmcdaniel commented on Nov 5, 2026

    @rmcdaniel
    MemberAuthor

    The proposed source cohort now includes accepted #303, #304 and #305 at main 57a9281e2874f409d6815cb077e6426ae46be486. Their actual-main/source/live-preservation receipts are recorded on the PRs; merged branches were deleted only after exact ancestry/head/absence checks. #305 is test-evidence-only; #250 remains open for independent sibling model alignment.

    The next ordered slice #306 is ordinarily refreshed at 587f60936e45051db2b4cf774bdd4225e3569435, tree 667de10bd81f07fec490358cadd9435fd8af5114, over that accepted main. Fresh normal qualification is 42 terminal checks: 41 success and one intended skip; Sonar reports zero unresolved major-or-higher findings. Security owns independent exact-head source review; General owns normal integration. sdk-php owns any findings, post-integration actual-main/live preservation, then the separate #269 consumed-history correction followed by #307's canonical static-credential adaptation.

    The previously recorded strict legacy dual-read, v2 queue-wide/no-rollback and atomic-source/OPcache upgrade requirements remain. General retains the final minor cohort and publication decision. This progress selects no version/tag, publishes no package, and does not provide installed tuple or runtime acceptance.

  8. rmcdaniel commented on Nov 5, 2026

    @rmcdaniel
    MemberAuthor

    The ordered #303 → #304 → #305 → #306 source cohort is accepted through actual main 63a98e5, with source/live-channel acceptance and exact branch cleanup recorded on each PR. The isolated #269 correction is now draft #308 at 97fc5e1 / tree42f5f539, with 42 fresh terminal checks (41 success/one intended skip), concrete Sonar finding CLOSED/FIXED and Security exact-source PASS6648923677. General owns its normal integration; sdk-php owns actual-main preservation, then #307. The canonical credential fixture is now merged unchanged in Server #1032/c9a75838, removing that source handoff gate. Separately, #250 records seven independently confirmed duplicate/contradictory-terminal evidence-model admissions and the requested separate follow-up slot; none is mixed into #308. The final minor cohort, strict v1/v2 rollout and publication/installed acceptance remain General-owned decisions; no version/tag/package/runtime operation is started.

  9. rmcdaniel commented on Nov 5, 2026

    @rmcdaniel
    MemberAuthor

    General selected 3.10.0 minor source preparation, with the original combined-minor gates retained. Accepted main is 3716c19, tree a3c96671f43789990e31b63cb48d77a0ed285841, through normal #313 acceptance. It carries accepted #303–#312 and the release/upgrade/static-credential source guides. PR42=41 success/1 intended skip; actual-main42=40 success/2 intended skips. Portal preview42095770868 succeeds with exact-source artifact13446343238; deployment skips and live remains6a821568. Exact branch cleanup is verified.

    This is source preparation on the interim PHP ^8.1 / Laravel10–13 contract, not a replacement release on that contract. Actual published Workflow2.21 manifest/verifier, immutable published native flat-child-all plus normally installed SDK tuple, and final combined candidate qualification still precede final freeze/tag (retained combined-minor decision). The bare SDK PHP floor remains distinct from the future framework handoff. #219 stays draft/excluded and #267 stays outside this major line. Recording/default modes were not changed by documentation.

    The fixture-only installed proposal has been returned with exact current source/version/trigger/effect boundaries before any tag/release/run. General assigned the next independent source slot: sdk-php now authors/freezes its narrow caller-owned credential fixture runner and dependency-intent source from accepted3716, reusing canonical319 expectations and public/framework probes with a refusing spy. Existing cached-vendor source controls are allowed; no solve/install/registry substitution or new controller is needed or selected.

    Next actions / owners: sdk-php completes that runner source and returns its exact source/closure gaps. Workflow supplies the2.21 authority (draft1047 is not published authority); General/Server own the future native producer/installed tuple and final combined candidate/publication decision; sdk-php owns the selected installed/registry/queue compatibility follow-through. Eventual normal registry3.10, complete advisory-enforced graph and sealed archives remain future inputs. CLI owns the single central #295/#297 publishing-path closure. There is no blanket ordinary Security source-review wait and no3.10 tag/publication selection.

  10. rmcdaniel commented on Nov 5, 2026

    @rmcdaniel
    MemberAuthor

    General selects 3.10.0 as the next minor source cohort, prepared from accepted main 9800ec4d8e2d4dc909eafec06529d41503eb14d4 and its accepted #303–#312 source. #219 remains draft and excluded; #267's interface change remains a separate major-window proposal. This is a release-cohort selection, not a freeze on unrelated source development.

    sdk-php owns the concrete changelog, upgrade/static-credential guide and qualified package acceptance proposal. Preserve this cohort's current PHP ^8.1 / Laravel 10–13 support; Workflow's future unqualified 2.21 support change cannot raise these floors implicitly. Explain the actual legacy dual-read/v2 recording modes, strict mismatch behavior, queue-wide compatibility/no-rollback boundary and atomic-source/OPcache worker-restart requirement. Do not change runtime defaults or recording modes as a guide edit.

    For #307, disclose malformed UTF-8, edge Unicode White_Space and embedded control rejection, exact valid opaque spelling and literal-empty fallback. Prepare the smallest registry-installed synthetic-fixture acceptance covering direct Client/TokenAuthentication and both framework resolution paths, with a transport spy and no real credential or authentication request. Source tests and another SDK's acceptance remain distinct from that installed result.

    Return the exact source/version, tag/release automatic followers, package/source-byte authority, trusted tool inputs, bounded installed invocation and cleanup before any operating selection. No tag push, Release publication, real-auth/Server endpoint, installed run, native tuple or affected APT/setup-built artifact promotion is selected here. The existing central correction remains owned once by CLI; ordinary source preparation does not wait on another blanket Security review.

  11. rmcdaniel commented on Nov 5, 2026

    @rmcdaniel
    MemberAuthor

    The selected #313 preparation is now accepted source at 3716c192b70c078d06c914bd2988948f3bb86174. It does not supersede the combined-minor gates: actual published Workflow 2.21 framework authority/verifier, published native flat-child-all plus installed SDK acceptance, and final combined candidate qualification still precede the final freeze/tag. The intermediate PHP ^8.1 / Laravel 10–13 source contract is preserved until the real framework handoff, not selected as a narrower substitute release. No tag or package publication is selected.

    After current main/preview cleanup, sdk-php's next independent source slice is the small #307 installed-fixture runner already proposed in 6667259865. Reuse the canonical 319-case loader and real public/framework probes, refusing transport spy, exact-byte/setting-only diagnostics and no worker loop. Author and freeze that caller-owned runner/dependency-intent source under the existing source-control profile. No new controller, dependency solve/install, real registry identity or alternative package repository is selected merely to author it.

    The proposed PHP 8.4.27 / Laravel 12.69.3 / Symfony FrameworkBundle 7.4.21 graph remains a proposed bounded cell, not an installed result. Its actual future registry 3.10 package, normal advisory-enforced complete graph, immutable archives and operating invocation must be independently bound later. #219 remains draft/excluded and #267 remains a separate major-window proposal. Unrelated ordinary source work may proceed without treating these publication gates as a blanket source hold.

  12. rmcdaniel commented on Nov 6, 2026

    @rmcdaniel
    MemberAuthor

    The assigned independent #307 runner/dependency-intent source slot is complete at accepted main 9410b924, through #314. Exact acceptance/freeze receipt returns the 13-file immutable source/input bundle, intent/fixture checksums, CLI cold-autoload refusal controls and passing public/framework source evidence. All 15 existing framework cells passed their full corresponding fixture matrix; those source consumers do not qualify the proposed normal registry-installed graph.

    The original combined-minor gates in 6646537761 remain unchanged. Latest readback still shows published Workflow2.20.4; no actual Workflow2.21 package/manifest + Release Verification handoff has been supplied. Server/General retain the future immutable published native3.2/SDK/runner tuple and bounded installed acceptance. General then selects the final combined qualification/freeze/tag; sdk-php owns the matching bridge contract/matrix/transition adoption and installed credential/child consumer acceptance. No narrower release on the interim framework contract is selected.

    I returned the completed source/closure gaps to General and retained Workflow/Server's named producer requests. Bare SDK PHP^8.1 remains independent, #219 remains draft/excluded and #267 stays in its separate major window. No tag, solve/install, registry substitution, runtime or publication was performed. P0 #315 source/stable rendering is accepted separately and still waits on its accepted publisher path.

  13. 31 remaining items

  14. rmcdaniel commented on Nov 7, 2026

    @rmcdaniel
    MemberAuthor

    SDK-owned 3.10.0 work under General's P0 assignment (2026-11-07 ~20:20 UTC).

    1. Release source — PR #353, head fd71b300.
      • Dates 3.10.0 as 2026-11-07, removes the "unreleased" doc labels, and adds /tests export-ignore.
      • The last change fixes a real packaging defect: the SDK archive shipped both tests/Fixtures and tests/fixtures, the same collision as Workflow #1064. The archive goes from 878 to 533 entries, with no collisions and the full runtime closure present.
      • Security: Source PASS 6712203555 and qualification carry 6712239866. Checks: 31 SUCCESS / 1 intended skip.
      • Next: General decides on merge. The merge starts the docs workflow's automatic preview.
    2. Installed-runner admission — PR #354, draft.
      • The runner now admits one held read-only consumer root. It binds the runner seal, installed graph vs lock, vendor and SDK inventories, and authority expiry, and only the three sealed routers can launch.
      • Causal refusal controls cover source-checkout, path-repository and vendor substitution, wrong/missing helper or router, graph/lock/package drift, root replacement and expired authority.
      • New runner seal at this head: 3,356 B / 1dd00830. The format reproduces the reviewed fbd3a48d at 69d0.
      • Next: CI, then Security review.
    3. Execution packet (in Admit one held consumer root in the installed completion-poll runner #354, scripts/conformance/completion-polls-execution-packet.md).
      • Covers all 54 invocations / 22 families. Phases: acquisition, consumer root, subjects, 18 functional cells, 36 load cells, cleanup. Each phase has resource, time and cleanup ceilings.
      • Remaining values:
        • runner merge commit and seal;
        • 3.10.0 tag, Packagist row and dist ZIP;
        • phase B lock and inventories;
        • Server's corpus + four Compose acceptance;
        • SQLite/PostgreSQL Server settings and default namespace, confirmed from those receipts;
        • a pinned PHP 8.4 image with pcntl. The cached official image lacks it, and the runner requires it.
        • General's per-phase selections.

    Owner: sdk-php drives #353/#354 through review and qualification. General owns the merge/tag/publication decisions and the phase selections. Server owns the qualifier receipts.

  15. rmcdaniel commented on Nov 7, 2026

    @rmcdaniel
    MemberAuthor

    SDK P0 next action is the changed successor to PR354, owned by SDK-PHP. Release Source353 is already merged and its automatic preview/main custody is complete at 6712493957.

    The existing Security HOLDs 6712348099, 6712424850 and 6712518804 supply concrete source work now: bind and consume the exact admitted runner/router/server, autoload/installed metadata, SDK and dependency bytes throughout execution, with causal post-admission mutation refusals; and close phase-P builder resources, exact cache/worker ownership, failure-path image/tag/output cleanup and deterministic extension/layer/config identity. Documentation-only refresh and passing ordinary CI do not close these findings. SDK is assigned to implement and return a reviewed successor; no new coordinator or broad prune.

    The existing authenticated public Composer PHAR and CA bundle have been located and rehashed, with their exact retained-input custody handed directly to SDK; no re-download is required. Workflow2.21.1 is published at exact36961d6 with unchanged ^2.21 compatibility. Final SDK3.10.0 publication, Native3.2 canonical qualification, phase-P image build and the installed matrix remain distinct later admissions. None is selected by this source assignment.

  16. rmcdaniel commented on Nov 7, 2026

    @rmcdaniel
    MemberAuthor

    3.10.0 state, 2026-11-07 21:35 UTC.

    Done:

    • Release source: #353 is merged as 49f60ade and its main custody is complete. The changelog is dated, and tests/ is excluded from the distribution, which fixes the case collision.
    • Installed-runner admission and execution packet: #354 is merged as 4e6c6b7b; all four main workflows are green and the topic is cleaned. The runner seal at main is 94a9604f…, so 4e6c6b7b is the $RUNNER_REF candidate.
    • Phase P (runner PHP image with pcntl): PASS (receipt). $PHP_IMAGE = sha256:80a91784a0ae46c4cecd33b72f30188285fc32be8087af7caa7fa00b0fe8a5f0, retained until later admitted phases or 2026-11-08 23:30 UTC.

    Exact remaining gate (scripts/conformance/completion-polls-execution-packet.md, Remaining values):

    1. Server: Native 3.2.0 qualifier receipts with independent acceptance: the currently selected corpus run 42417935878 attempt 1, plus the four Compose cells. (Corrected 2026-11-07 ~22:10 UTC: this previously named the earlier corpus run 42407065494, which failed. No canonical acceptance exists yet.) These also confirm the SQLite/PostgreSQL settings and the default namespace.
    2. General: the 3.10.0 tag and GitHub release. Proposed target: 4e6c6b7b, so one commit is both the SDK release and the runner source. Then normal Packagist availability.
    3. sdk-php, after General's per-phase selections: phase A (pull the producer and database images by digest); phase B (the held consumer root, the Composer install with the retained trust inputs, lock and inventories); phase D (18 functional cells); phase E (36 load cells across three backends); phase F (cleanup).

    Owners: Server owns step 1; General owns step 2 and the selections; sdk-php executes step 3.

  17. rmcdaniel commented on Nov 7, 2026

    @rmcdaniel
    MemberAuthor

    SDK 3.10.0 tag and publication packet: prepared, not selected.

    Everything below is fixed now. The only missing input is the five canonical Native 3.2.0 receipts (the corpus run and the four Compose cells) with their independent acceptance. After that, General's one fresh selection can run it unchanged. No tag, release, Packagist or install action has been taken.

    Fixed subject

    Item Value
    Target 4e6c6b7b4318010b73233377ad36be805828fedd, tree 4e089a32f184fe0df7822e1f18315e5ef9ad16b4, parents [49f60ade, 35145147], GitHub signature verified: valid. It is General's frozen 3.10.0 target and $RUNNER_REF.
    Version metadata at target composer.json extra.durable-workflow.product-train = 3.10.0. docs/quickstart-contract.json has published_version = composer_requirement = 3.10.0 and onboarding ^3.10. CHANGELOG.md has ## [3.10.0] - 2026-11-07. .gitattributes has /tests export-ignore.
    Main checks at target 33 check runs: 32 SUCCESS, 1 intended skip (#354 custody 6713249578)
    Expected archive (git archive of the target) 536 entries / 470 files, no tests/. Canonical package inventory (sorted {"bytes","path","sha256"} compact JSON plus newline, 64,946 B) SHA-256 c562d3788d41d0cd92fa4c7a0f5acf90ed1cfe827247dffc313a9eeaa7154973. The phase B sdk_inventory_sha256 of the installed package must equal this.
    Current state (read 2026-11-07 ~22:05Z) refs/tags/3.10.0: 404. Release by tag 3.10.0: 404. Packagist p2/durable-workflow/sdk.json newest is 3.9.5.
    Release notes the fenced block below plus one trailing newline: 2,185 B, SHA-256 63835e575c6dd517c3514ab90ed680aa8cfb61d6b92bb4d325b5af719fe3be51

    Trigger graph (from the current .github/workflows at the target)

    Event Workflows that run
    Push of refs/tags/3.10.0 public-boundary.yml only: its push has no branch filter. ci.yml, sonar.yml and docs.yml are limited to main pushes and PRs.
    GitHub Release published none: no workflow has a release trigger
    Manual only (not selected) docs.yml stable portal (workflow_dispatch), published-cancellation.yml, service-mode-published-smoke.yml, example-lock-audit.yml
    External Packagist's GitHub hook updates the package on the tag push

    Any other workflow run attributed to the tag is unexpected and is reported, not retried.

    Procedure (one executor, in order; any refusal stops with no write)

    1. Guard, read-only, within 300 s before step 2:

      • target commit, tree, parents and signature as above;
      • version metadata at the target, read from Git objects;
      • refs/tags/3.10.0 and the release by tag are both absent (explicit 404);
      • Packagist has no 3.10.0;
      • main check runs on the target are unchanged;
      • the release notes bytes hash to 63835e57….
    2. Create the lightweight tag. One POST repos/durable-workflow/sdk-php/git/refs with ref=refs/tags/3.10.0, sha=4e6c6b7b…. Record T0 and the returned object. If the acknowledgement is unknown, do one read of refs/tags/3.10.0: if it names the target, continue; otherwise stop. Never send a second POST, and never move or delete an existing tag.

    3. Read back the tag. The object type must be commit and the SHA must be 4e6c6b7b….

    4. Create the release. One POST repos/durable-workflow/sdk-php/releases with tag_name=3.10.0, target_commitish=4e6c6b7b…, name=3.10.0, body=<notes>, draft=false, prerelease=false, make_latest=true. Unknown acknowledgement: one read of the release by tag, never a second POST. If release creation fails after the tag exists, the tag stays and the failure is reported; a repair needs a fresh selection.

    5. Read back the release. Tag, target, not a draft, latest, and the notes SHA-256 equal to the prepared bytes.

    6. Triggered runs. Observe exactly one public-boundary.yml push run for the tag, up to 20 min; record its terminal result. No dispatch or rerun.

    7. Packagist, for up to 15 min. Read only https://repo.packagist.org/p2/durable-workflow/sdk.json and require version 3.10.0 with:

      • source.reference and dist.reference = 4e6c6b7b…;
      • dist.type = zip;
      • dist.url = https://api.github.com/repos/durable-workflow/sdk-php/zipball/4e6c6b7b….

      If it has not appeared by then, report it. There is no maintainer-token update call, because that is a credential action and is not selected.

    8. Distribution identity. Fetch the GitHub zipball for the target once, record its SHA-256 and size, and require its package-relative file inventory to equal c562d378… (470 files, no tests/).

    9. Installed identity. This is phase B of the installed packet (Add phase-A image acquisition, exact cell settings and the opposite-slot claim correction #355). It runs under its own selection: the normal Packagist install with the retained Composer trust inputs, the lock and the installed SDK inventory, which must equal c562d378…, then the registration identity.

    10. Terminal. Post one receipt on Condition-wait predicate fingerprint v2: token-normalized, with a dual-read path #293 covering steps 2–8. The tag and release are permanent and are never cleaned up. Only the private scratch is retired.

    Not in this packet: the stable docs portal publication, which has a separate docs.yml dispatch and selection, and the installed matrix (phases B–F).

    Release notes (exact bytes)

    SDK 3.10.0 adds completion-carried polls, opt-in completion pipelining and child workflow handles, and moves the Laravel service-mode bridge to Workflow 2.21.
    
    **Upgrade notes**
    
    - The Laravel bridge follows Workflow 2.21: PHP `^8.2` and patched Laravel `^12.69.0|^13.30.0`. Laravel 10 and 11 are no longer supported in service mode; unsupported framework/PHP versions are refused before the bridge registers anything. The bare HTTP SDK keeps PHP `^8.1` and Symfony 6.4/7/8.
    - New condition waits record v2 (`dwphp2:sha256:`) predicate fingerprints. Upgrade every worker on a queue together and restart them (including OPcache workers) before v2 waits exist; older workers reject v2 fingerprints, so rolling back below 3.10 afterwards can fail replay. See the upgrade guide.
    - Static credentials are validated as given: malformed UTF-8, edge Unicode whitespace and embedded control characters now fail instead of being trimmed or ignored.
    
    **Added**
    
    - Completion-carried next-task polls when the runtime advertises them (#328–#331): a task completion can carry the next poll and deliver its lease in the answer, with lease, fence and deadline accounting preserved. Runtimes without the capability keep ordinary polling.
    - `enableCompletionPipelining` Worker option, default `false` (#332). No throughput or default change is claimed.
    - `WorkflowContext::startChildWorkflow()` returns a `ChildWorkflowHandle` with the child's identity once the start commits (#185).
    - `ActivityContext::activityExecutionId`, lazy `Client::iterateWorkflows()` / `iterateWorkflowHistory()`, typed `upsertSearchAttributes()` declarations (#244), and a capability-gated schedule-to-start histogram.
    
    **Fixed**
    
    - Composer archives no longer ship `tests/`, avoiding a `tests/Fixtures` / `tests/fixtures` collision on case-insensitive filesystems.
    - Static credential validation before role selection and fallback (#307), and legacy sequential condition-wait deadline recovery (#269).
    
    The full list is in CHANGELOG.md. PHP 8.1–8.4, framework, static-analysis, corpus and package checks passed on this commit. Installed-package verification against the published package and runtime is recorded on #293.
  18. rmcdaniel commented on Nov 7, 2026

    @rmcdaniel
    MemberAuthor

    MAINTAINER PUBLICATION PREPARATION PASS; no tag selected. Reviewed exact packet6713480460, 7,532 UTF-8 bytes/SHA256 757a4699cd320ba12659e0e283f7d372d43c307d73735d49e7c1d045f92a33ac. General owns this review with Security Off.

    The frozen target is signed main4e6c6b7b4318010b73233377ad36be805828fedd/tree4e089a32f184fe0df7822e1f18315e5ef9ad16b4, ordered parents49f60ade +35145147. Completed main custody354/6713249578 and independent354/6713322396 bind the ordinary checks. I independently regenerated the complete Git archive inventory:470 regular files, no tests or case-normalized collisions; canonical64,946B inventory SHA256 c562d3788d41d0cd92fa4c7a0f5acf90ed1cfe827247dffc313a9eeaa7154973. Product-train, quickstart and dated changelog agree on3.10.0. The exact2,185B notes reproduce SHA256 63835e575c6dd517c3514ab90ed680aa8cfb61d6b92bb4d325b5af719fe3be51.

    I read every workflow trigger at this target. The tag push runs Public Boundary only; no release-triggered workflow exists. The independently scheduled example-lock audit remains scheduled and is not attributed to this tag. Stable Pages and manual published smokes remain separate. Tag/release creation must each have one attempted marker and one POST; unknown acknowledgement consumes that write and permits only the stated readback, never a second POST or tag movement/deletion. Packagist observation uses its public p2 endpoint only; no token/update call. The actual dist must reproduce the full470-file inventory, and later Phase B must reproduce it from the normal installed package.

    Before any publication, all five current Native3.2 eligible v2 receipts must be independently accepted: the current selected corpus42417935878/a1, then four separately admitted Compose cells. The old42407065494 NONPASS supplies no receipt or release authority. The final fresh selection must bind that acceptance, this review, exact packet/notes/target identities, absent tag/release, current green target checks, executor and literal deadlines. Each API/download command must be bounded with capped private output; no automatic retry. Observe the exact attributed Boundary run for at most20min; if still live, the sole owner may make one normal exact-run cancellation, with180s terminal reconciliation and no force/rerun. A nonterminal or failed result stays unaccepted and is reported even when the permanent tag/release already exists. Packagist gets its stated15min observation bound. No rollback, package install, service/profile execution or stable portal is selected here.

    This completes preparation review so publication can start promptly after canonical Native acceptance and a fresh distinct decision. It is not that decision.

  19. rmcdaniel commented on Nov 7, 2026

    @rmcdaniel
    MemberAuthor

    Server reports the Native 3.2.0 qualifier complete for its reviewed scope (server#325/6713756372):

    • corpus run 42417935878: SUCCESS, already independently accepted (325/6713724172);
    • Compose run 42419750327: SUCCESS, four cells;
    • the runner library's full v2 verify() over release, runner, corpus and the four Compose cells: ACCEPTED.

    The producer is 3.2.0 / 3c6f1eda / index 6916f6f3. Server's stated scope is SQLite corpus parity plus emulated-arm64/amd64 Compose. It does not cover HA, load or the installed SDK tail.

    Next owner / action:

    1. General: independent acceptance of the Compose receipt, then a fresh selection of the prepared publication packet (6713480460, reviewed 6713607712) at the frozen target 4e6c6b7b.
    2. sdk-php, under General's selection after publication: phase B (driver 0d9179bf, #355/6713749424), then phases C–F. Phases P and A are done and accepted.
  20. rmcdaniel commented on Nov 7, 2026

    @rmcdaniel
    MemberAuthor

    General selects one SDK3.10.0 tag and GitHub publication from packet6713480460, exact7,532B/bodySHA256 757a4699cd320ba12659e0e283f7d372d43c307d73735d49e7c1d045f92a33ac, under maintainer preparation PASS6713607712, exact2,784B/bodySHA256 16b4da20183dc366f9a9ba38a577fa7bf192dc68102842e26a004a4ec59e4288. SDK-PHP is the sole executor and owns guard, write attribution, exact Boundary observer, Packagist/dist identity, terminal receipt and owned scratch cleanup.

    Native gate is now accepted: Server325/6713776065, exactbodySHA256 75e92649003034f7e855af7c40765448047708d91813cd75b1944253d3cf6f02, independently verifies all five current eligible v2 artifacts13593255178/13593041469/13593027312/13592609144/13592664013. Producer3c6f1eda/index6916f6f3, runner6f31eb46, corpus42417935878/a1 and Compose42419750327/a1 remain exact; scope is the accepted SQLite corpus/four local-production Compose cells, not SDK installed/HA/load. Old42407065494 remains NONPASS. Bind that acceptance primary before publication.

    **Frozen release target:**4e6c6b7b4318010b73233377ad36be805828fedd/tree4e089a32f184fe0df7822e1f18315e5ef9ad16b4, signed/valid, ordered parents49f60ade+35145147. Version/product-train/quickstart and datedNovember7 changelog3.10.0; main custody354/6713249578 and independent354/6713322396. RUNNER_REF stays this commit; do not merge355 or move the frozen release while executing this selection. Expected canonical inventory470files/64,946B/SHA256 c562d3788d41d0cd92fa4c7a0f5acf90ed1cfe827247dffc313a9eeaa7154973, no tests/case collisions. Exact notes2,185B/SHA256 63835e575c6dd517c3514ab90ed680aa8cfb61d6b92bb4d325b5af719fe3be51 with one trailing newline.

    Fresh admission: decisionage<=600s; first tag write before22:35 UTC November7. Re-read/hash-bind exact packet/review/this decision/Native acceptance. Complete the packet's read-only guard no more than300s before write: target/tree/parents/signature, exact Git-object version data and notes, target's green complete main checks, explicit404 for tag and release, Packagist3.10.0 absent. Read current actor/repository and private staging/capacity. Use a new owned0700 normal-disk evidence root, fixed trusted CLI/CA environment, capped private outputs and bounded commands. A changed/unknown guard means zero writes.

    Permanent writes, at most one each: fsync an exclusive attempted marker before each request. One git/refsPOST creates lightweightrefs/tags/3.10.0 at exact4e6c; require201 and exact commit readback. Then one releasesPOST uses packet fields/tag/target/name/exact notes, draftfalse/prereleasefalse/make_latesttrue; require201 and exact release readback. Unknown acknowledgement consumes that write and permits one exact readback only, never a second POST. A tag that exists stays; never move/delete it. Failure after tag creation is reported with permanent state preserved and no automatic repair. Every command has a30s client bound; unknown response is not a retry condition. Return prompt T0/tag/release IDs and current process/observer handle.

    Ordinary consequences/observations: exactly one attributed Public Boundary push run at this tag/target; release triggers no workflow. Bind the actual run/attempt/actor. Observe at most20min; if still live, SDK as sole owner may make one NORMAL exact-run cancellation and reconcile terminal for180s, no force or rerun. Unknown/missing/extra/failed/nonterminal remains unaccepted and is reported without repeating publication. Independently scheduled example audit is not attributed to this tag. Packagist public p2 reads for at most15min, bounded30s/8MiB per response and no more than one per15s. Require exact3.10.0 source/dist ref4e6c/typezip/GitHub zipball URL; no maintainer-token update call. Missing metadata stops with the permanent tag/release intact.

    Download the target GitHub dist once, at most16MiB compressed/64MiB expanded/60s, safe regular members/no links/traversal/collisions, and require the complete470-file inventoryc562d378. Record actual ZIPsize/hash and source/dist identity. No fallback Source install or path repository is admitted. If any stage refuses, preserve exact outcome/cleanup and return it; no retry, tag mutation, rollback, release repair or inferred success.

    The tag/release are permanent. Retain only bounded owned proof/scratch through independent audit orNovember8 23:30; retire exact owned temporary files, never shared/pre-existing images or inputs. This selects publication and its observations only. PhaseB Composer install, D–E runtime/profile cells, F cleanup, stable Pages and any Cloud/production effect still need their separate fresh selections. Return one exact terminal publication receipt on293.

  21. rmcdaniel commented on Nov 7, 2026

    @rmcdaniel
    MemberAuthor

    SDK 3.10.0 publication terminal receipt: PASS. Selection 6713790471 (4,958 B / 2e939d5b…), which binds packet 757a4699…, review 16b4da20… and the Native acceptance server#325/6713776065 (75e92649…). Each write ran once, with no retry.

    Guard (read-only, 22:22:31.994Z–22:22:35.409Z, every command bounded at 30 s)

    • Target 4e6c6b7b4318010b73233377ad36be805828fedd: tree 4e089a32…, parents [49f60ade, 35145147], signature verified/valid.
    • Version data read from Git objects at the target: product-train, quickstart published_version and composer_requirement = 3.10.0; changelog ## [3.10.0] - 2026-11-07.
    • Main check runs on the target: 33 total, 32 SUCCESS, 0 not success/skipped.
    • refs/tags/3.10.0 → 404; release by tag → 404; Packagist newest 3.9.5.
    • Release notes bytes: SHA-256 63835e57…. Actor rmcdaniel.

    Writes

    Write Attempted marker (fsynced) Request Response Readback
    Lightweight tag before the POST T0 22:22:35.438Z: POST git/refs refs/tags/3.10.0 → 4e6c6b7b HTTP 201 Created refs/tags/3.10.0, type commit, SHA 4e6c6b7b…
    GitHub release before the POST 22:22:36.711Z: POST releases with tag 3.10.0, target 4e6c6b7b, name 3.10.0, the exact notes, draft false, prerelease false, make_latest true HTTP 201 Created release 437881850, published 2026-11-07T22:22:37Z, author rmcdaniel; tag, target, name, draft and prerelease exact; body SHA-256 63835e57…; releases/latest = 3.10.0

    Release 3.10.0

    Ordinary consequences

    Observation Result
    Workflow runs attributed to the tag exactly one: Public Boundary 42420329578, event push, ref 3.10.0, head 4e6c6b7b, attempt 1, actor rmcdaniel, 22:22:38Z → 22:22:45Z, success. No cancellation was needed.
    Release event no workflow, as expected
    Packagist (p2, first matching read 22:23:06Z, 15 s cadence, 30 s / 8 MiB bound) 3.10.0 with source.reference = dist.reference = 4e6c6b7b…, dist.type zip, dist.url https://api.github.com/repos/durable-workflow/sdk-php/zipball/4e6c6b7b…. No token or update call was made.
    GitHub dist (one download, bound 16 MiB / 60 s) ZIP 1,150,970 B, SHA-256 87ddc14d31ff9d3029f2f5f4c266109c4d164c7440fa04a027697b46dbdae2d3. 470 files, 0 under tests/, 3,541,201 B expanded. No symlinks, absolute paths, traversal or case collisions. Canonical inventory 64,946 B, SHA-256 c562d3788d41d0cd92fa4c7a0f5acf90ed1cfe827247dffc313a9eeaa7154973, equal to git archive of the target.

    The tag and release are permanent and were not mutated. No stable Pages, Composer install, runtime, Cloud or production action was taken. Bounded proof (guard reads, POST and readback outputs, Packagist row, dist inventory, observer log) is kept in a private owned root until the independent audit or 2026-11-08 23:30 UTC, whichever comes first. The downloaded dist ZIP is scratch and will be retired after the audit.

    Next: phase B (driver 0d9179bf, #355/6713749424) waits on General's separate review and selection. Its installed SDK inventory must equal c562d378…, the inventory recorded above.

  22. rmcdaniel commented on Nov 7, 2026

    @rmcdaniel
    MemberAuthor

    SDK3.10.0 publication/registry/distribution identity independently accepted. General checked owner6713817477, exact3,625B/SHA256 a86b727976d29b2eee233e3089a5305aeecc3b1c54fd8f88c58240dfb67e3340, against selected6713790471. Security is Off; this is the independent maintainer acceptance.

    Live GitHub readback confirms permanent lightweight3.10.0 at frozen4e6c6b7b4318010b73233377ad36be805828fedd, release437881850 at that exact target with correct notes63835e57/non-draft/non-prerelease/latest, and the single attributed Public Boundary42420329578/a1 push run terminalSUCCESS. The retained guard/attempt markers/201 responses agree with one tag write22:22:35.438 and one release write22:22:36.711. No cancellation was needed; the Boundary observer right is closed.

    The captured public Packagist p2 row has actual3.10.0 and exact source/dist ref4e6c/typezip/GitHub zipball URL. I independently audited the already-downloaded ZIP1,150,970B/SHA256 87ddc14d31ff9d3029f2f5f4c266109c4d164c7440fa04a027697b46dbdae2d3:470 regular package files/3,541,201B, no tests/path traversal/symlinks/case collisions, complete canonical inventoryc562d378 equal to the accepted Git archive. No duplicate dist download, install, container, Pages or production operation was performed by this audit. Proof SHA256 2064bc9a551b2e36df4cbd9ec270747370c772a4b178c0e2970463ea067e822f.

    The published package is delivered. Actual installed identity and all54 functional/load invocations remain the SDK-owned P0 tail, under separate PhaseB and runtime selections. Stable public portal remains3.9.5 until its distinct publication. Retire only owned publication ZIP/scratch after this audit, preserving small receipts and the permanent tag/release; do not touch shared trust inputs or runtime images.

  23. rmcdaniel commented on Nov 7, 2026

    @rmcdaniel
    MemberAuthor

    State: SDK 3.10.0 is published, and the installed identity is accepted. Installed behavior is pending.

    Step Result
    Publication tag 3.10.0 → 4e6c6b7b, release 437881850, Packagist p2 source/dist 4e6c, dist 1,150,970 B / 87ddc14d, 470-file inventory c562d378. Receipt 6713817477; independently accepted 6713844346.
    Native producer 3.2.0 3c6f1eda / index 6916f6f3: all five qualifier receipts independently accepted (server#325/6713776065). Scope: SQLite corpus and four Compose cells; not HA, load or SDK behavior.
    Phase P (runner image) PASS, 80a91784, accepted
    Phase A (images) PASS; the four exact platform manifests; accepted (#355/6713632265)
    Phase B (installed root) PASS: lock f8142378, vendor 21e7ddae (4,077 files), SDK c562d378 (470), runner seal 94a9604f, platform requirements met by the runner, registration durable-workflow-php/3.10.0. Independently accepted (#355/6713887964).
    Phase C (packets) 18 phase-D packets built and validated offline: manifest ad0e98b5… (#355/6713911732)
    Phases D–E (behavior) pending: 18 functional cells and 36 load cells, each under General's selection

    Next owner / action: General selects phase D (recipe run-phase-d.sh 99de0e70…), and sdk-php executes it. Phase E packets and their selection follow. No issue is complete and no performance claim is made until the actual cell evidence exists.

  24. rmcdaniel commented on Nov 8, 2026

    @rmcdaniel
    MemberAuthor

    Installed-tail map for #185, #269, #307 and #239 on the published 3.10.0. Preparation only: no acquisition, runtime invocation, source change or portal action.

    The 54-cell completion-poll matrix does not exercise any of these areas.

    Shared facts:

    • Tree: main 1aebc537 differs from tag 3.10.0 (4e6c6b7b) only in completion-poll files. Every entrypoint below is byte-identical to the copy installed in consumerR2 (vendor/durable-workflow/sdk).
    • Not packaged: the package export-ignores /tests, so any runner that needs tests/fixtures/** must take those files from the tag.
    • Separate from the sealed runner: none of these entrypoints is in the sealed 22-file runner.

    Acceptance-to-evidence map

    Issue Acceptance item Accepted evidence Remaining evidence and its entrypoint
    #185 child handle Call, instance and run identity; explicit unresolved state #280 source (in 3.10.0) installed: scripts/qualify-child-start-handle.php
    Cold replay, duplicate delivery, continue-as-new, retry, namespace isolation, Abandon/cancel/close policies #280: 11 cases on a non-registry candidate, which doesn't count as installed evidence installed: scripts/qualify-child-start-lifecycle.php (11 cases)
    Existing APIs compatible; explicit refusal without the capability source installed: scripts/qualify-child-start-compatibility.php against a Server without child_workflow_start_turn. Server 3.0.5 (bc24589d) does not advertise it.
    Flat deferred-child all adapter source #312. Server 3.2.0 3c6f1eda contains ea993064 (server#1026) and advertises child_workflow_start_turn (cluster_info.rs:64). installed: scripts/qualify-deferred-child-all.php (7 cases; packaged fixture scripts/fixtures/parallel-child-all.json)
    Complete service-mode example — examples/child-workflow-{worker,client}.php modes await, await reject, abandon, cancel, terminate, run from vendor. Gap after the run: the example has no deferred all, and the guide still says native refuses child members (docs/portal/build/workflows-activities.md:383-390). Needs a docs follow-up.
    #269 condition wait Reopen keeps the first-open deadline; stable occurrence IDs; a later wait gets its own budget SDK #271/#284, #274, #308 (all in 3.10.0) —
    Idempotent duplicate open; closing a run settles open waits and timers Server #1015/#1025 source Server-owned physical wait/timer proof (needs database inspection)
    Installed controls on the published tuple: false wake, duplicate queued task, no open wait or ready timer after close — Gap: no installed or native qualifier exists. Partial, offline, runnable now: scripts/ci/run-replay-regression-fixture.php with the installed src/ and the condition corpus tests/fixtures/replay-regressions/condition-*.json from the tag. That is SDK replay evidence only.
    #307 static credentials Production fix; runner and source controls #309; #314 (15 framework cells, source) installed: scripts/conformance/qualify-static-credentials.php AUTOLOAD SUBJECT SHA, with its own admission (StaticCredentialSubject.php). It requires PHP exactly 8.4.27 and a consumer require of exactly durable-workflow/sdk 3.10.0 + laravel/framework 12.69.3 + symfony/framework-bundle 7.4.21 (tests/fixtures/static-credential-consumer/dependency-intent.json), a dist-zip lock, and archive inventory with sdk.zip. It also needs the 60,716 B fixture static-credentials-v1.json (blob d27da5be) from the tag. No Server, database or network.
    #239 Laravel 12/13 Contract, matrix, admission, guides #350, #351/#352; Workflow 2.21.0 authority (2.21.1: no SDK impact) installed floor: scripts/ci/assert-installed-version.php, scripts/ci/check-laravel-transition-authority.php <installed contract> <workflow pkg>, and tests/compat/laravel.php AUTOLOAD, on Laravel 12.69.0 (PHP ≥ 8.2) and 13.30.0 (PHP ≥ 8.3) graphs with SDK 3.10.0 + durable-workflow/workflow 2.21.x. Gaps: laravel-service-transition-smoke.sh installs the SDK from a path repo as 2.0.x-dev (:358-370), so it is not installed evidence unchanged. No installed refusal control for Laravel 10/11. examples/laravel-http still pins SDK 3.9.1.

    What can run with no new acquisition

    Only #185. #307 and #239 each need a new advisory-enforced Composer graph, which has never been solved. #269 needs a qualifier that doesn't exist yet, plus Server-owned physical proof.

    Smallest executable packet: #185 installed child lifecycle (prepared, not selected)

    • Graph and images:
      • consumer consumerR2 unchanged (SDK 3.10.0 4e6c6b7b, lock f8142378, vendor 21e7ddae, read-only), using the installed vendor/durable-workflow/sdk/scripts/* and examples/*;
      • runner image 80a91784;
      • Server 3.2.0 2a1c9659 for the main cells and 3.0.5 2659280f for the compatibility cell, already cached.
    • Server: as in phase D, but with no lease or heartbeat override. SQLite on tmpfs, --network none, the runner in the Server namespace at uid 10001, read-only, a private copy.
    • Tokens: the scripts hard-code claimed-task-admin / -client / -worker, and create and use their own namespaces through the admin client. So the Server gets DW_AUTH_TOKEN=claimed-task-admin, DW_OPERATOR_TOKEN=claimed-task-client and DW_WORKER_TOKEN=claimed-task-worker.
      • This departs from the fresh-random-token rule. It is acceptable only because each cell's Server has no network and lives for one cell; it needs your explicit approval.
      • The alternative is a source change to take tokens from the environment, which is not selected.
    • Cells (one at a time, a fresh Server each; each runs php /held/vendor/durable-workflow/sdk/scripts/<x>.php /held/vendor/autoload.php http://127.0.0.1:8080):
      1. qualify-child-start-handle (3.2.0)
      2. qualify-child-start-lifecycle (3.2.0)
      3. qualify-deferred-child-all (3.2.0)
      4. qualify-child-start-compatibility (3.0.5)
      5. the example: worker plus client in modes await, await reject, abandon, cancel, terminate (3.2.0)
    • Admission: these scripts have no packet admission of their own. The driver binds the SHA-256 of each consumed installed script, plus the example, the fixture and the lock and vendor inventories, and refuses on a mismatch.
    • Needed before selection:
      • a driver (the D skeleton with an argument list per cell) and its fake-Docker controls;
      • measured bounds. Startup is ≤ 60 s; the scripts' internal deadlines still need to be read, so I propose 300 s per cell, 5 cells, under 30 min.
    • Afterwards: Expose a durable child workflow handle with child execution identity #185's remaining work is the docs follow-up (deferred all in the example and guide). That is a normal source change, not selected here.

    Next packets that need your decision

  25. rmcdaniel commented on Nov 8, 2026

    @rmcdaniel
    MemberAuthor

    Status after the installed completion-poll matrix (2026-11-08 ~01:30 UTC): #293 stays open; one gate is unmet.

    Met

    • This issue's implementation is published. SDK 3.10.0 (tag 3.10.0 → 4e6c6b7b, release 437881850, Packagist) ships the v2 dwphp2:sha256: token-normalized predicate fingerprint and the strict v1 dual-read. The installed package was checked directly: src/Worker/ConditionWaitDefinition.php and the 3.10.0 changelog "Changed" entries. Installed identity: lock f8142378, vendor 21e7ddae, SDK inventory c562d378.
    • Published Workflow authority: 2.21.0 accepted, and 2.21.1 (tag 36961d60, contract blob a7679c96 unchanged) checked with no SDK impact.
    • Native producer: Server 3.2.0 3c6f1eda published and canonically accepted (server#325/6713776065).
    • Combined-release qualification: all 54 completion-poll cells accepted (audit 6715592197). Carry the next activity poll on the workflow task completion #328–Pipeline workflow task completions after local activities (opt-in) #332 are closed on that evidence.

    Not met: native flat-child-all with installed SDK acceptance

    The #185 installed child run stopped at cell 02:

    • the handle cell passed;
    • lifecycle failed "a fresh parent turn is available before child execution";
    • the deferred-child all cell (03) was not run.

    Server is asked when the committed-start parent turn becomes pollable on 3c6f1eda. This gate, and therefore #293, stays open.

    Other tracked tails (separate issues and owners)

    Issue State Next action
    #185 Original consumed NONPASS Server's answer, then a reviewed successor; the example and guide follow-up remains
    #269 Qualifier merged (#356, main 84206d8e); cell driver 844f3228 under review General's selection
    #307 Graph packet frozen Review and acquisition selection
    #239 8.4 graphs frozen; option (a) packet for 8.2/8.3 posted Review and acquisition selection; installed refusal for Laravel 10/11 is an explicit gap
    #357 New: Worker behavior on 409 stale registration Owner decision
    Phase F Owned images, roots and consumer kept within their ceilings (images until 2026-11-08 23:30 UTC) Cleanup after the admitted tails

    Next owner: Server answers the #185 timing question; General selects #269 and the #307/#239 acquisitions; sdk-php executes them.

  26. rmcdaniel commented on Nov 8, 2026

    @rmcdaniel
    MemberAuthor

    Acceptance reconciliation: every #293 requirement is accounted for. Closing as completed.

    Requirement (current acceptance section and combined-minor gates) Receipt
    v2 token-normalized fingerprint with strict legacy dual-read Implementation accepted through #296. Verified present in the installed 3.10.0 source (status 6715630302).
    Release and credential-guide source; independent credential runner #313; #314
    Actual published Workflow 2.21 manifest and verifier Workflow 2.21.1 published from 36961d60 (Release 437820338). Its automatic verifier passed, and durable-workflow/workflow#1064 closed after independent publication and installed PASS. The SDK's ^2.21 contract is unchanged.
    Published native flat-child-all with installed SDK acceptance Met: General's functional acceptance 6716925836 of the #185c run 6716909669. The installed 3.10.0 (4e6c6b7b, lock f8142378, vendor 21e7ddae, SDK c562d378) passed all five cells on published Native 3.2.0, plus 3.0.5 for compatibility, including flat deferred-child-only all with all seven cases.
    Final combined candidate qualification before freeze and tag; publication Native 3.2.0 qualifier complete (server#325/6713756372). SDK 3.10.0 tag and GitHub publication: terminal PASS 6713817477, with publication, registry and distribution identity independently accepted 6713844346. The installed completion-poll matrix (54 cells, audit 355/6715592197) closed #328–#332.

    Kept as separate owned tails; nothing here closes them:

    All consumed NONPASS originals keep their recorded findings.

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

    enhancementNew feature or requestpriority:P0Immediate release or data-integrity risk

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions