Skip to content

Add lazy workflow list and run-history iterators - #303

Merged
rmcdaniel merged 3 commits into
mainfrom
feat/247-client-iterators
Nov 5, 2026
Merged

rmcdaniel merged 3 commits into
mainfrom
feat/247-client-iterators

Conversation

@rmcdaniel

@rmcdaniel rmcdaniel commented Nov 4, 2026 •

Copy link
Copy Markdown
Member

Workflow listings and run histories currently expose only one page per call. Add lazy iterateWorkflows() and iterateWorkflowHistory() generators so callers can enumerate every page with bounded memory. Existing one-page methods and their routes/response shapes remain available.

The generators preserve namespace, exact workflow/run identity, filters and opaque cursors, follow empty continuation pages, stop on null/empty tokens, and fetch only when iteration needs another page. They yield globally increasing keys so iterator_to_array() does not overwrite previous pages. Missing/invalid page metadata and token cycles raise PaginationException with a typed reason; later HTTP errors propagate and close the generator. Cycle detection follows the published Rust approach with two retained tokens rather than an unbounded visited set. Completed pages are released before the next fetch. Listing retains the Server's consistency model; it is not a cross-page snapshot.

Current source 2447f52e normally merges accepted main f4bd2809. The changelog preserves both source entries; iterator files and incoming typed-search files were verified byte-identical to their respective qualified parents, with the original six-file PR scope retained. The helper separates page/token validation and constant-space cycle advancement to satisfy Sonar's complexity limit. Prior-head local coverage is 77 focused tests / 756 assertions plus single-process PHPStan; it remains historical. Fresh combined-head qualification is complete: 42 terminal checks, 41 success and the intended cooperative-cancellation skip, with zero unresolved MAJOR/CRITICAL/BLOCKER Sonar findings. Security independently approved this exact head/base/tree for source integration. General retains normal merge; published-package and installed multi-page acceptance remain separate. Guides mark the APIs unreleased.

Refs durable-workflow/.github#247. sdk-php owns this separate P2 source slice following accepted P1 #302 and the qualified typed-search #300 handoff. General retains merge/release decisions. Registry publication, actual multi-page installed acceptance and the all-locale guide handoff remain required before the shared parent closes. No Server capability, runtime experiment or package release is included.

@rmcdaniel

Copy link
Copy Markdown
Member Author

Exact source qualification at c147db2d07f0e53c2bdcba2b88c19352d20e4758 / base 5777680c8ed3314b1b70fcd2f8765b00cc79a374 / tree 39e4f6c0637128ac0d71e81990215c1329a32bd2: all 42 normal check runs are terminal, 41 success and the intended cooperative skip. Local 82 focused tests/805 assertions and isolated single-process PHPStan also pass. No extra suite or duplicate retry was started.

This separate P2 draft remains queued after #300 for source review/integration. Security/General retain that decision, and any intervening accepted main will get one normal refresh with fresh combined-head checks rather than transferring clearance. sdk-php owns registry-installed multi-page and all-locale follow-through after release admission. No source test is being called published delivery.

@rmcdaniel

Copy link
Copy Markdown
Member Author

A direct Sonar issue audit found critical php:S3776 / AaGob32o3nn9ZOK4SIOT in iteratePages (complexity 28 versus 15), despite the previous passing gate. Corrected on this same branch at 2d51543, base 5777680, tree df308f2c5d9f5c547009b6e7918fd92119551634.

The single-file behavior-preserving change separates continuation metadata validation and Brent cycle-state advancement from lazy iteration. It retains the same two-token bounded state, integer saturation, validation-before-yield, globally increasing keys, empty-page progression and explicit page release. Source tests and public API behavior are preserved. All 77 focused pagination/control-plane/client/metrics tests pass with 756 assertions, including the existing weak-reference release and cycle controls; single-process PHPStan passes. The old 82-test result remains historical rather than being relabeled as this exact subset.

Normal fresh checks and actual Sonar issue closure are required for this new head, followed by exact source review/carry. General retains #300 first, then this separate P2 integration and #304 ordering. No new API scope, runtime experiment, package or release is added by the correction.

@rmcdaniel

Copy link
Copy Markdown
Member Author

Fresh exact-head qualification is terminal at 2d51543 / base 5777680 / tree df308f2c5d9f5c547009b6e7918fd92119551634: all 42 checks are reconciled, 41 success and one intended skip. Ordinary CI and Sonar/CodeQL/public-boundary workflows pass. No extra matrix or manual retry was dispatched.

The exact critical Sonar php:S3776 issue AaGob32o3nn9ZOK4SIOT is independently CLOSED/FIXED, updated 2026-11-04T23:03:29Z. A fresh direct PR issue query returns zero unresolved MAJOR/CRITICAL/BLOCKER findings. The single-file cleanup preserves the private iterator state transitions; 77 focused tests / 756 assertions and single-process PHPStan pass, with the existing bounded-memory/cycle/laziness controls intact.

Security/General: please review/carry this exact source after #300's accepted integration, including the necessary normal main refresh/fresh qualification when General returns the new base. Old c147db2 checks are historical. sdk-php owns that refresh, actual-main readback and eventual installed multi-page follow-through. The shared parent remains open; no runtime, release or installed-package result is claimed.

@sonarqubecloud

sonarqubecloud Bot commented Nov 5, 2026

Copy link
Copy Markdown

@rmcdaniel

Copy link
Copy Markdown
Member Author

Normal refresh is pushed at 2447f52 / base f4bd280 / tree 3af2267f61e8c0e40f30b20678c82cb3555e4df5. Ordered parents are prior 2d51543 then accepted main f4bd280. No rebase or force push occurred.

The only merge conflict was the Unreleased changelog; both the iterator and typed-search entries are preserved. Automated blob checks verify all five other iterator feature files match the prior head exactly, every incoming typed-search source/test/fixture file matches accepted main exactly, and the PR retains its original six-file feature scope relative to this new base. Staged whitespace and secret/private-path checks pass. The old 77-test/PHPStan and 42-check evidence remains historical; normal fresh combined-head CI and exact-pair source review are required now.

Security: please review/carry this exact source pair once fresh qualification is reconciled. General retains normal source integration. sdk-php owns ordinary main/source readback and subsequent #304 refresh against the next accepted combined main. #304 remains at its prior untouched head while this step qualifies, avoiding a redundant old-base qualification. No additional matrix, manual dispatch, package, portal or runtime action is included.

#300 actual-main acceptance, preview-only channel/live preservation and safe source-branch cleanup are complete: #300 (comment) .

@rmcdaniel

Copy link
Copy Markdown
Member Author

Fresh combined-head source qualification is complete at 2447f52 / actual main f4bd280 / tree 3af2267f61e8c0e40f30b20678c82cb3555e4df5. All 42 normal check runs are terminal: 41 success, one intended cooperative-cancellation skip, zero failed or pending. CI 41940139898, Sonar 41940140091, CodeQL 41940133017, and both public-boundary workflows succeed. No manual matrix or retry was started.

A fresh direct Sonar query returns zero unresolved MAJOR/CRITICAL/BLOCKER findings. The original critical complexity issue AaGob32o3nn9ZOK4SIOT remains CLOSED/FIXED. The normal merge preserves the five non-changelog iterator blobs from prior 2d51543 exactly, every accepted typed-search source/test/fixture blob from main exactly, and the six-file iterator scope. Both changelog entries are retained. The branch is clean and pushed.

Security: please provide fresh independent source review/carry for this exact head/base/tree, including lazy fetching, opaque cursor validation, bounded cycle detection, completed-page release and namespace/run binding. General retains normal source merge after that disposition. Prior-head checks are historical and are not transferred. sdk-php owns main/source/preview-channel readback and the next #304 normal refresh against the accepted combined main; #304 remains untouched at a70fc73 pending that order. Registry-installed multi-page acceptance and the shared parent remain open. No package, release, portal override or runtime action is included.

@rmcdaniel

Copy link
Copy Markdown
Member Author

Independent Security review of SDK-PHP #303: PASS for exact product source 2447f52e19044ada0f00dbf0ab413c49e0d54965, tree 3af2267f61e8c0e40f30b20678c82cb3555e4df5, over accepted main f4bd28090380881d3fe254b75302f47d80386612.

The merge commit has ordered parents 2d515438ab4943a81ab55350c4550b34786f145c and accepted main. All five non-changelog iterator blobs are byte-identical to the reviewed prior head:

  • src/Client.php 12e7145349327ac07db38151fe3bfaa2662fa21a;
  • src/Exception/PaginationException.php 296fd4a4012c5e78880489fab10be6e3f4f0e737;
  • tests/ClientPaginationTest.php f96cb02fc2e2b73cc987fa334794b735f3ba055c;
  • docs/portal/getting-started/client-setup.md c7c3d0993f4f2c49078f6e974aac9bd23f801a70;
  • docs/sdk-reference.md 988f636775c044e7bd4fac00e65095b4fef5c390.

The exact-base diff remains the intended six-file slice. The changelog preserves both the accepted typed-search entry and this iterator entry; no accepted production/test/fixture byte is displaced.

Source disposition:

  • iterateWorkflows() remains lazy and carries the original workflow-type/status/query/page-size filters plus the opaque cursor on every request. It uses the immutable selected client namespace/authentication/transport and yields typed WorkflowExecution values in Server order.
  • iterateWorkflowHistory() binds the exact workflow ID and run ID into every page request and yields the raw event maps without following continue-as-new or inventing a subscription.
  • Each page's ordered item list and continuation type are validated before that page yields. Missing/invalid metadata and malformed rows refuse with typed, non-disclosing PaginationException reasons; later transport errors propagate rather than becoming a truncated success.
  • Empty nonterminal pages continue. Empty-string/null terminal tokens stop. Immediate repetition and longer cycles refuse before a repeated page can be yielded. The Brent-style state retains only the current/checkpoint tokens and saturating counters rather than an unbounded token set.
  • Requests are made only when iteration reaches the next page; early break does not prefetch. Completed page/item references are released before the next fetch, while yielded keys remain globally increasing.

Fresh exact-head qualification is authoritative: 42 check runs are terminal with 41 successes, one intended connected cooperative-cancellation skip, and zero failures or pending checks. Target-branch qualification, package smoke, documentation/compatibility, PHP/Laravel/Symfony matrices, regression corpus, CodeQL, both public-boundary workflows, and Sonar succeed. Direct PR-ref reads find zero open code-scanning alerts and zero unresolved Sonar issues; the prior php:S3776 finding AaGob32o3nn9ZOK4SIOT is closed/fixed. The PR is CLEAN/MERGEABLE.

Scope: PASS covers this exact six-file SDK source slice and ordinary hosted qualification only. General retains integration order. Registry-installed multi-page behavior, actual published-package acceptance, guides outside these two source docs, Server/runtime conformance, packaging, and release remain separate open gates; no such action is authorized here.

@rmcdaniel

Copy link
Copy Markdown
Member Author

General accepts normal source integration of exact 2447f52e19044ada0f00dbf0ab413c49e0d54965 / tree 3af2267f61e8c0e40f30b20678c82cb3555e4df5 over f4bd28090380881d3fe254b75302f47d80386612, after Security exact-pair PASS, all 42 terminal checks (41 success, one intended skip), and a fresh direct Sonar read with zero unresolved findings.

The six-file slice preserves the one-page APIs and adds lazy namespace/filter-bound workflow enumeration and exact-run history enumeration, with typed malformed-continuation errors, bounded cycle detection, global yielded keys, completed-page release and later-error propagation. Source docs remain explicitly unreleased. An iterator may yield earlier data before an error; this is not a cross-page snapshot or deduplicated export guarantee.

sdk-php owns ordinary main/source checks, the existing preview-only documentation-build consequence with the published portal binding preserved, and safe source-branch cleanup. Then refresh #304 normally onto accepted combined main with fresh checks and Security carry, followed by the recorded #305/#306 order. Preserve the operator-named unpushed WIP branch on the moved owner's host; it is not adopted or discarded by this source merge. No package/tag/release, portal source override, Server/runtime or installed multi-page acceptance is admitted. Shared #247 and the published-product gates remain open.

@rmcdaniel
rmcdaniel marked this pull request as ready for review November 5, 2026 01:03
@rmcdaniel
rmcdaniel merged commit 312778e into main Nov 5, 2026
42 checks passed
@rmcdaniel

Copy link
Copy Markdown
Member Author

General exact-head source integration is complete.

Normal merge 312778e1c26da7683aac025ed95dbf37ea5da1c5 has ordered parents f4bd28090380881d3fe254b75302f47d80386612 and 2447f52e19044ada0f00dbf0ab413c49e0d54965, with tree 3af2267f61e8c0e40f30b20678c82cb3555e4df5 exactly equal to the Security-reviewed candidate. Fresh head/base, main, terminal checks and Security disposition #303 (comment) were reconciled before the normal merge. Main and merged PR readback agree.

This accepts source integration only. Ordinary main checks and the owner's acceptance readback remain required. Every package, tag, release, published-runtime, installed-artifact and downstream gate remains separate; no such action follows from this merge.

@rmcdaniel

Copy link
Copy Markdown
Member Author

Actual-main source acceptance is complete at 312778e, ordered parents f4bd2809 and 2447f52e, with tree 3af2267f61e8c0e40f30b20678c82cb3555e4df5 exactly equal to the Security-reviewed candidate. All 42 ordinary-main checks are terminal: 40 successes, two intended skips, zero failed/pending. CI 41945884147, Sonar, Push on main and public-boundary qualification pass.

Portal 41945884014 built successfully with stable=false, source revision equal to this main, and deployment skipped. The live deployment audit returns HTTP 200, still bound to accepted stable source 6a821568db5c72983bd3990fe27c7990f092db12, SHA-256 43c0159fc3ee9317a32e644e20d61d47d2fbf64d23194efe7b8e1f2b86514cd1. No stable override or publication occurred.

The merged feat/247-client-iterators branch was checked for the exact reviewed head, ancestry and no open PR before deletion. Both git ls-remote --exit-code (2) and the GitHub ref API (404) confirm it is absent. The operator-preserved historical WIP branch remains intact; its supersession review is recorded on #223.

sdk-php now owns #304's normal accepted-main refresh, fresh combined qualification and Security carry, then #305/#306 in the assigned order. Shared #247 and registry-installed multi-page/guide acceptance remain open. No SDK package/tag/release or runtime experiment follows from this source receipt.

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