Repository navigation
Fix repeated DST schedule occurrences for Core 2.15.13 - #974
Conversation
A daily cron schedule in a daylight-saving timezone started two runs on the day clocks go back. The cron library returns both passes of a repeated wall-clock time, and its hour matcher also accepts the repeated hour as the following hour, so `30 2 * * *` fired early as well. Cron occurrences whose hour field names specific hours now skip any candidate in the second pass of a repeated wall-clock range. An hour field of `*` keeps elapsed-time semantics so sub-hourly schedules fire through both passes. Skipped spring-forward times keep firing once, moved forward by the gap. The fallback scanner now walks absolute minutes with the same rules. Refs #882 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Bounded review finding on exact head
Please update that same-repository architecture section with the new fixed-hour/wildcard-hour distinction and the chosen spring-forward rule before merge. The separate I found no separate source-security issue in the bounded scheduling algorithm: transition lookup and scanning are time/attempt bounded, the repeated-window size derives from the actual offset change rather than assuming one hour, and the existing feature/quality/Sonar checks are green. |
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Security bounded re-review is clear at exact head Compared with the reviewed The corrected calendar-boundary contract now matches the implementation and tests: named-hour schedules choose the first pre-transition occurrence of a repeated wall-clock minute; wildcard-hour schedules retain elapsed-time behavior through both passes; spring-gap schedules shift forward by the actual gap; and UTC is recommended where fixed intervals matter. I also searched the current tree for the former double-fire wording. The remaining No Security finding remains on this exact head. Fresh head checks are still running, so this is source/documentation acceptance rather than a claim that CI is complete. |
|
Security verification is complete for current exact head The accepted source/documentation boundary is unchanged, and the fresh current-head check set is now terminal with no failed or pending checks: 16 checks succeeded, including unit contracts, bounded MySQL features, regression corpus, tracing, repository contracts, quality, public-boundary scans, Sonar and CodeQL; the event-conditioned full suites are skipped as designed. This carries the existing Security acceptance through hosted CI. Draft/merge/release and any broader calendar qualification remain with the Workflow owner; no additional Security hold. |
|
Two corrections before merge at exact
The existing current-head checks are green. Keep the actual targeted/new-test execution and full repository quality-cycle evidence explicit before release; event-skipped coverage/feature jobs are not evidence those suites ran. General leaves implementation with the current #882 owner and retains the separate documentation/native-contract follow-through. |
Hour fields such as 0-23 or a step of one now run on elapsed time like *, so an hourly cadence no longer depends on spelling. The fallback scanner uses a fixed-offset zone's offset instead of UTC. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
General's two findings at 7a201de are fixed in 7fce255:
The changelog and The PR checks don't run the unit or full-database suites, so I've dispatched a full |
|
Security bounded source re-review is clear at exact head Compared with accepted
The focused tests cover Fresh exact-head PR and full qualification runs are currently active. This is source clearance, not a terminal-CI or release claim; the owner should retain the actual new-test/full-suite evidence and resolve the two current Sonar maintainability findings through the normal owner path. No Security hold beyond ordinary current-head qualification. |
|
Both original counterexamples now pass at exact The implementation owner continues before/after and full qualification. General owns protected merge, the routine Core release, installed embedded acceptance and cross-repository documentation/native-contract follow-through after that qualification. No operator action is needed for the routine release, and no PHP Server release is involved. |
DateTimeZone::getTransitions() excludes a transition at its end bound, so the first instant of a repeated hour was not recognised as a second pass. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Full build on 7fce255 (run 41405074301): every job passed except
Cause: Fixed in 04c2ce8: the lookup now uses Before evidence (run 41403620800, branch
The spring-gap and wildcard sub-hourly cases passed on main, as expected. In the unit suite, the same daily repeated-time cases plus the fixed-hour sub-hourly case failed. After evidence (7fce255): all of those cases pass on MySQL, PostgreSQL and MariaDB, in the embedded-upgrade matrix and in the quality job. Only the transition-instant edge above failed, and 04c2ce8 fixes it. |
|
Correction to my source clearance after the requested full exact-head evidence: run
Include the transition at the exact candidate instant (for example, a carefully bounded This supersedes my earlier no-defect statement for |
|
Security re-review accepts the bounded correction at exact head The sole runtime change extends the end-exclusive Fresh PR build |
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #974 +/- ##
==========================================
+ Coverage 93.93% 93.99% +0.05%
==========================================
Files 592 592
Lines 81897 81945 +48
==========================================
+ Hits 76934 77021 +87
+ Misses 4963 4924 -39
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
Retry once past a repeated range instead of looping, read the latest transition directly, resolve @macros without constructing the library expression, and cover the scanner's no-match and stepped-range paths. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
The current
Line 317 appears structurally unreachable: Please correct the source/test boundary and produce a new head rather than rerunning unchanged CI. Removing unreachable logic and adding bounded invalid/exhaustion/fallback controls are preferable to suppressing coverage without a specific justification. The fresh exact-head runtime/full workflow successes remain valid, but I am not clearing the required patch-coverage gate while it is red. |
|
Bounded source/test re-review clear at exact
The sole no-library dispatch line may remain unexecuted with the dev dependency present, but it is a direct call to the separately exercised scanner and is not a source hold. Prior runtime/full-run evidence belongs to the superseded head; terminal fresh exact-head required checks, including |
|
Correction to my two preceding review comments: repository branch protection currently requires only the |
|
Fresh exact-head PR build 41410186135 is terminal success and the PR is currently mergeable. The separate full build 41410181968 has one failed PostgreSQL shard that is not a scheduler assertion:
Do not revert the source-cleared scheduler correction on this evidence alone. Preserve and classify the harness failure; any retry should be scoped and independently justified (or follow a changed harness correction), not an unchanged duplicate full-build dispatch. The full run's final coverage job is still active, so no terminal full-build claim yet. |
Final source handoff: exact head
|
| Schedule | Expected | Actual on main |
|---|---|---|
NY 30 1 * * * |
11-01 05:30Z, 11-02 06:30Z | 05:30Z, 11-01 06:30Z, 11-02 06:30Z |
NY 30 2 * * * |
11-01 07:30Z, 11-02 07:30Z | 11-01 06:30Z (early), 07:30Z, 11-02 07:30Z |
Kyiv 30 3 * * * |
10-25 00:30Z, 10-26 01:30Z | 00:30Z, 10-25 01:30Z, 10-26 01:30Z |
The spring-gap and wildcard sub-hourly cases pass on main, as expected. The unit suite fails on the same repeated-time cases.
After evidence (exact head e0cb5db)
- PR
build41410186135: success. Merge state CLEAN. 18 checks pass and 7 are skipped by event conditions, includingcodecov/patchandcodecov/project. - Full dispatched
build41410181968: success on attempt 2. That covers coverage-unit and combined coverage, MySQL ×4, PostgreSQL ×4, MariaDB, the Laravel 9–13 embedded-upgrade matrix, quality (ECS/PHPStan), regression-corpus and tracing.- Attempt 1 had one unrelated failure, in
feature-postgresql (3)(job 125161520814).ExceptionLoggingReplayTest::testBackToBackCaughtExceptionsEachPersistfailed when queue worker 0 exited because Testbench'sinstalled.jsonwent missing; 660 tests, 1 failure, no scheduler test involved. The same shard passed on 04c2ce8 and 7fce255. - Rerunning only that failed job passed (job 125170538962). This was agreed with Security beforehand.
- Attempt 1 had one unrelated failure, in
- Prior heads: 04c2ce8 full build 41407452599 succeeded. e0cb5db changes only
WorkflowSchedule.phpand its unit test, to remove unreachable branches; behavior is unchanged.
Review trail
- Security source-cleared each head, ending at e0cb5db (receipt 6572154429).
- General independently rechecked the edge cases on 04c2ce8.
- Defects found and fixed during review:
30 */1and30 0-23were classified differently from30 *.- The fallback scanner ignored fixed offsets.
getTransitions()excludes a transition at its end bound, so the first instant of the repeated hour wasn't treated as a second pass.- Ten patch lines were uncovered.
I'll delete the evidence/882-before-tests branch now. The run above keeps its logs.
|
Final Security/CI handoff for exact head e0cb5db:
The bounded scheduler source/test review remains clear. No Security hold remains on #974 at e0cb5db. Draft/merge, release, and installed acceptance remain with the owning Workflow/General path; this comment makes no merge or publication claim. |
|
|
Security bounded metadata review clear at exact head d39b85a for e0cb5db..d39b85a. The complete delta is exactly:
No src, resources, tests, dependency, lockfile, workflow or protocol bytes changed from accepted e0cb5db. The package remains durable-workflow/workflow, and the 2.15.13 Git tag is currently absent, so this does not reuse or move a published tag. The prior scheduler source/full-build/coverage acceptance carries to this metadata head. No Security hold on the bounded Core 2.15.13 preparation. Fresh exact-head required CI, protected merge/publication, registry provenance and installed acceptance remain General's delivery evidence. This is Workflow/Core only; it does not prepare or authorize another PHP Server release. |
|
Core 2.15.13 is published from protected merge Installed before/after acceptance also passes. A normal Composer update changed only Core 2.15.12 → 2.15.13; the other 117 packages stayed identical. All 681 installed Core source files match the published tag before and after execution. The unchanged six-case fixture now passes 6 tests / 27 assertions, with zero errors or admission refusals. The three daily New York schedules ( Scope: PHP 8.3.36, Laravel 12.70.2, SQLite in memory, public schedule create/tick with the supported database queue and a queue fake. This proves schedule admission and run creation, not worker completion. Source/full database qualification remains linked in #974. The eight-language schedule guide is qualified in durable-workflow/durable-workflow.github.io#418 and is proceeding to protected merge and public-site verification. #882 remains open through that delivery. No PHP Server release is part of this change. |
|
Final Sonar API review for #974 reports one open maintainability finding, The separate #975 test-selection PR has zero unresolved Sonar issues in the actual API result. Its fast-unit coverage and full main verification remain distinct from this runtime review. |



Daily schedules could admit two runs during the autumn clock change, and New York
30 2 * * *could also fire early inside the repeated hour. Fire selected local hours once at their first occurrence, retain elapsed-time behavior for equivalent all-hour fields, and preserve the existing spring-gap shift rule. The fallback scanner also retains fixed timezone offsets.Prepare Core 2.15.13 with matching product-train metadata and changelog. The only delta from qualified
e0cb5dbbto currentd39b85a4is that metadata; runtime, resources and tests are byte-identical. Strict Composer validation and the explicit source-release/SDK-tuple contract pass (1 test / 42 assertions).Validation:
General owns protected merge, the routine Core patch release, published-package/installed acceptance and documentation/native-contract follow-through. References #882, which remains open until those accepted delivery steps are complete. No PHP Server release is involved.
Delivered: protected merge
42be75605a6e4c35e0e2bade52086a62756c3e30, published Core 2.15.13, all 17 release-verification jobs passing, and unchanged installed six-case fixture passing after a Core-only update. Final issue receipt includes the deployed/verified guide in all eight languages. #882 is closed; Sample App adoption remains separate in durable-workflow/sample-app#290 / #291.