Skip to content

Expose an additive clock for consumed scalar replay - #320

Merged
rmcdaniel merged 5 commits into
mainfrom
feat/215-replay-clock
Nov 6, 2026
Merged

rmcdaniel merged 5 commits into
mainfrom
feat/215-replay-clock

Conversation

@rmcdaniel

@rmcdaniel rmcdaniel commented Nov 6, 2026 •

Copy link
Copy Markdown
Member

WorkflowContext::replayNow() returns the UTC DateTimeImmutable at the most recently consumed, proved scalar activity/timer boundary. Repeated reads stay identical; equal/backward instants and microseconds are preserved. Missing, invalid, ambiguous or unsupported authority throws the dedicated ReplayClockUnavailable instead of inventing time.

Each Fiber invocation has an engine-owned try/finally scope, and every resume/throw resets its authority. Only the matched supported scalar step supplies a new instant. This prevents retained, nested, direct, capture, predicate, local, cancellation and force-closed-finally callbacks from borrowing a prior clock. Existing cancellation's monotonic budget clock, errors, UUIDs, history and command behavior remain separate.

Canonical redrive entry/reuse binds the workflow/run, source, link, resume step and original-time evidence. A step below the resume boundary must have its original provenance even if both reuse keys are missing. Failed/timed-out/cancelled activity delivery retains its original error and uses its own consumed event time. Shared StartAccepted proves correlation only; it never identifies the producer.

Initial scope is bounded remote scalar activity lifecycles, plain persisted timers and canonical redrive. Local/inline/grouped/child/signal and other unproved families remain unavailable; queries/updates need their own validated consumed prefix. Ordinary-entry anchor adoption and remaining215 families are separate source work. This does not complete the original cross-SDK/published/guide acceptance.

Validation on exact head 3c53eb65e3ca288ea0dc330c531dbd5a3dcb6cf5:

  • All42 PR checks terminal:41success/one intended connected-test skip, including Target branch qualification. Supported PHP/Carbon and existing framework compatibility cells passed.
  • PHP8.4: 8,105 tests /85,119 assertions, 56 optional-dependency skips;53 focused clock controls. The local cached graph is source evidence, with no installed/framework or runtime claim from optional skips.
  • Official worker corpus 66→67, actual immutable-base failure / candidate pass, revision_verified1. Existing fixture bytes, selectors, validators and enforcement are unchanged; genuinely new source paths are included in related-change guards.
  • PHPStan passes; direct unresolved Sonar inventory is zero. Five actual analysis findings were fixed without suppression. Real draft old-fail/new-pass controls cover teardown leakage and missing-both redrive provenance; original failures remain recorded in the PR.

Maintained Core field/consumption readback and detailed source evidence: #320 (comment) . Persisted activity and timer event paths are compared with Core WorkflowExecutor 8fd6cb792e36f1583eb13006f0b5e40ac327a44a; its legacy model-only closed_at/fired_at fallback is not substituted for absent service history. Refs durable-workflow/.github#215 and its accepted additive/callback contracts.

P0 portal matching setup/adoption preempts when its input returns. No version/cohort/tag, package solve/install, native/runtime/authentication, operating route or publication is selected.

@sonarqubecloud

sonarqubecloud Bot commented Nov 6, 2026

Copy link
Copy Markdown

@rmcdaniel

Copy link
Copy Markdown
Member Author

The initial scalar implementation now has 53 focused clock controls passing, plus official corpus/redrive evidence controls and PHPStan. A prior full cached-source run passed8,087 tests /85,099 assertions with56 optional-dependency skips; fresh normal CI qualifies each subsequent source head. The official immutable-base comparison on9b6b979 already proved replay corpus66→67, candidate pass / base fail, consumer=worker, revision_verified=1. The new fixture follows the canonical Core redrive activity/timer prefix; old fixture bytes, selectors, validators and enforcement are retained. New implementation paths are covered by the existing related-change guards.

Two material draft-source findings were reproduced and corrected before readiness:

  • Force-closed Fiber finally could read the last scalar instant. Its new real teardown control failed on the earlier draft, then passed after explicit engine-owned invocation scopes with try/finally deactivation. All18 resume and7 throw sites reset clock authority; only the matched scalar step supplies a new instant. Parent/nested/error/retained/query/predicate/capture/local and legacy cancellation controls remain separate from the original cancellation clock.
  • Removing both reuse keys from a canonical timer below the redrive resume step exposed successor insertion time (00:05) instead of unavailability. The original control is retained as NONPASS. The corrected reader derives the reused-prefix role from the bound source/resume envelope and requires original-time provenance there; a claimed but unbound redrive cannot borrow ordinary row time. I returned the finite source counterexample to the Python owner for an independent check, without transferring PHP results.

Narrow source comparison used maintained Core ce24207ef86856e64f97b939c9aeef9d1fb387c8: RedriveReplayClock blob ef6cc5767f4c051dc4834f51f1436b94f153ccad supplies original run start versus redrive replayed_started_at, and reused original time versus recorded event time; FailedRunRedrivePlan blob 748be6d3e455c65a615b6c740a8a081691e14e03 supplies copied timer pair/new timer ID and reused activity ID/source/time; WorkflowStepHistory blob 9a5525f29ed4972774b657f3650c689749a76655 supplies step ownership. The approved PHP fixture registry's canonical producer shape is reused unchanged and the new behavioral fixture is appended. No producer is inferred from shared StartAccepted; no ordinary-entry run-row anchor is guessed. Core's narrow field/time owner return was requested, not made a new blanket review gate.

All five actual initial analysis findings were corrected without suppression; direct unresolved inventory on the later80c head was zero. Fresh current-head qualification is required for the provenance successor. This remains the initial bounded remote scalar activity/plain-timer/redrive SOURCE slice, not full215 acceptance. Child/signal/grouped and remaining callback/entry authority follow the maintained source contracts in the existing215 train; P0 matching setup/adoption still preempts. No release/cohort/tag, installed/native/runtime/authentication or publishing effect was selected.

@rmcdaniel
rmcdaniel marked this pull request as ready for review November 6, 2026 05:21
@rmcdaniel
rmcdaniel merged commit ce41318 into main Nov 6, 2026
42 checks passed
@rmcdaniel
rmcdaniel deleted the feat/215-replay-clock branch November 6, 2026 05:28
@rmcdaniel

Copy link
Copy Markdown
Member Author

Initial scalar clock source acceptance is complete.

  • Actual main ce41318, reviewed tree 6e77cfa115c9a3b4c4f4c36d458bd4aff99bc5cd, ordered parents 9b8baaa398e1af2bb0382f073e86e6821ce45b9f + 3c53eb65e3ca288ea0dc330c531dbd5a3dcb6cf5. Local Git and the independent GitHub object API agree; the reviewed and merged trees match.
  • PR42 terminal =41success/one intended connected skip. Actual-main42 terminal =40success/two intended skips, no failed/pending checks. Main CI42167944024, Sonar, CodeQL and Public Boundary passed. The final source qualification and actual worker66→67 base-fail/candidate-pass negative remain linked in the description. No source-quality finding or required check was waived.
  • Portal42167944158 built the exact unreleased preview and skipped deployment. Pages artifact 13479972062, 1,061,437B, SHA256 5d92a52507dafc2011f75f8295f6d962dff2dac0df7bf2b295ff8892326de9d1, was downloaded/hash-verified; v2 audit binds source/SDK/presentation/workflow to the actual main above.
  • Live audit at 2026-11-06T05:27:51.727306+00:00 stayed HTTP200/118B, original v1 source 6a821568db5c72983bd3990fe27c7990f092db12, SHA256 43c0159fc3ee9317a32e644e20d61d47d2fbf64d23194efe7b8e1f2b86514cd1. No stable promotion or runtime operation occurred.
  • After exact remote head/ancestry/tree and open-dependent-PR checks, the merged feat/215-replay-clock branch was removed normally, both remote and local. Git transport is empty and GitHub ref API returns404. The worktree is detached at accepted main and clean. Existing handoff/placement branches and cached tools are preserved.

This accepts the bounded scalar Activity/plain-Timer/canonical-redrive SOURCE cohort. It does not close full215, qualify ordinary-entry/callback/other-family authority, choose a version/cohort or supply installed/native/published conformance. The existing child/signal, then grouped Source sequence continues from this accepted main under General's maintained-source assignment; P0 matching setup/adoption preempts when that input returns. #219 remains draft/excluded and #267's ABI window remains separate.

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

Labels

agent:sdk-php Work done by the sdk-php repo agent

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant