Skip to content

sdk-sync: API 2.0.0+ffb34b7 → sdk-php (minor) - #112

Open
marketdata-sdk-sync[bot] wants to merge 1 commit into
mainfrom
sdk-sync/2.0.0-ffb34b7
Open

marketdata-sdk-sync[bot] wants to merge 1 commit into
mainfrom
sdk-sync/2.0.0-ffb34b7

Conversation

@marketdata-sdk-sync

@marketdata-sdk-sync marketdata-sdk-sync Bot commented Nov 10, 2026 •

Copy link
Copy Markdown

Generated by sdk-auto-sync for API release 2.0.0 (commit ffb34b7).

Changes in the API surface

Snapshots ae2b047c8f6f → c2a31e277345:

~ GET /v1/options/chain/{underlying}/ ?dte: string  (was integer)

What the agent did

tests: Added unit wire tests (tests/Unit/Options/UrlConstructionTest.php) covering the three new dte forms the API now accepts on GET /v1/options/chain/{underlying}/: comma-separated list ("15,30,45"), closed range ("0-45"), and comparison operator (">=30" and "<45"), each asserting the exact query string sent; the existing single-integer-value test already covers the pre-existing form. Added live integration tests (tests/Integration/Options/OptionChainTest.php) for every dte form against AAPL, each tagged #[Group('ci')], asserting multiple distinct expirations are returned (impossible under the documented single-expiration default) and that returned dte values respect the stated bounds. Added the compatibility probe at build/sdk-sync-compat/SdkSyncCompatProbeTest.php covering today's option_chain(dte: int) call, verified green against current code.

implement: Widened option_chain()'s $dte parameter from ?int to int|string|null on src/Endpoints/Options.php, so it accepts a comma-separated list, a closed range, and a comparison operator in addition to the existing single integer, matching the API's new query syntax for GET /v1/options/chain/{underlying}/.
Correctness: the type was widened purely additively; the old int form keeps its exact behaviour and error (InvalidArgumentException via validatePositiveInteger, now gated behind is_int so string forms bypass it, same as strike/delta).
Docs: updated the @PARAM block for $dte with one bullet and example per form, in the same style as the neighbouring $delta/$strike docs.
New public members: none added — only an existing parameter's type widened, so no new doc comments needed beyond the updated @PARAM.
Wire tests: phase 1 already added one unit test per new form (list, range, >=, <) plus the pre-existing single-value regression, all asserting the literal query string.
Validation: no new validation surface was added for the string forms (consistent with strike/delta, which also accept free-form strings unchecked); the existing int validation is preserved unchanged.
Coverage: no code excluded; the is_int branch is exercised by both the existing int test and the new string-form tests.
Examples/docs still correct: examples/options_chain.md's dte entry describes the response field (always int), not the request filter, so it needed no change; options-screener examples and options_chain.php pass a plain int to dte and remain valid under the widened type.
Existing parameter compatibility: $dte still accepts every value it did before (plain int, unchanged signature position/default), only widened.
Left as-is (outside scope, no dte/option_chain content found despite being listed): tests/Unit/Options/ExpirationsTest.php, LookupTest.php, StrikesTest.php, tests/Unit/Options/QuotesTest.php, tests/Integration/Options/QuotesTest.php, tests/Unit/ToStringTest.php — these reference the unrelated response-side dte field or other Options endpoints, not the chain filter.
Outside my limits and left wrong/out of date: CHANGELOG.md has no entry yet (pipeline writes it); the .phpdoc/** cache still reflects the old ?int $dte signature until regenerated.

review fix 1: Added tests/Unit/Options/UrlConstructionTest.php::testOptionChain_withDteString_addsParameter, asserting dte=30 is sent for the string single value dte: '30' — the form the type change exists for, previously only tested with the old int type.
Fixed testOptionChain_dteCommaList_selectsMultipleExpirations: added assertLessThanOrEqual(3, count($response->option_chains)) alongside the existing lower bound, so the test now fails on a server that ignores dte and returns the whole chain, not only on one that returns the single default.
Added strike_limit: 3 to all five new dte live tests (single value, comma list, closed range, >=, <), matching the neighbouring multi-expiration tests' convention and bounding per-contract request cost; verified none of the dte/expiration-count assertions depend on the full, unbounded strike set.
Documented the dte=0 inconsistency in the @PARAM block for $dte (src/Endpoints/Options.php): a single int dte must be positive (unchanged, pre-existing validation on the existing public method, left as-is to avoid changing its error behavior), while the string forms (list, range, comparison) are passed through unvalidated and accept 0 as a bound, matching the API's documented closed-range syntax.
Left the <40 boundary question (inclusive vs exclusive) in testOptionChain_dteComparisonLt untouched, as instructed — it is a question for a person to settle with the API team, not something to resolve in code or tests.

changelog: Added changelog entry for Options::option_chain() parameter widening: dte now accepts string forms (comma-separated list, closed range, comparison operators) in addition to single integer values (API release 2.0.0); int form retains exact prior behavior.

Questions for a person

The internal reviewers raised these for a person to answer. They did not block the change, and the coder was not asked to resolve them.

  • tests/Integration/Options/OptionChainTest.php:452 — testOptionChain_dteComparisonLt asserts assertLessThan(40, $quote->dte), i.e. that <40 excludes dte exactly 40, while the API text says comparison operators are "inclusive" (and also says the syntax matches strike and delta, which would make < exclusive). The two readings differ only on days when an expiration sits at exactly dte 40, so the single passing live run does not settle it: please confirm with the API team whether <N excludes N before this assertion is relied on.

Files

  • CHANGELOG.md
  • src/Endpoints/Options.php
  • tests/Integration/Options/OptionChainTest.php
  • tests/Unit/Options/UrlConstructionTest.php

Version

Public-surface change computed by the pipeline: minor

  • added: Options::option_chain($dte) — ?int widened to int|string|null; dte: 30 still type-checks and validates exactly as before, while dte: '15,30,45', dte: '0-45', dte: '>=30' and dte: '<45' are new accepted forms.

Live-API suite

  • tests/Integration/Options/OptionChainTest.php

Files of this suite changed by this pull request. The pipeline ran the ones the change added or modified against the live API before the pull request, and they passed; this pull request's CI runs the whole suite.

Job log

The full record of this job — every phase, test and build result, review findings and how they were resolved, and each fix round after the PR was opened — is in the job log comment.


4 coder run(s) · 4 review(s) · 119 turns · 11,764,442 tokens · US$ 6.39 · item ac9f3c82-f79b-4c28-a080-fae6a871d90b

Agent runs
  • coder · claude-haiku-4-5-20251001, claude-sonnet-5 · 2,952,706 tokens (131,368 in, 2,794,080 cached, 27,258 out) · 31 turns · US$ 1.37 · 5 min 35 s
  • coder · claude-sonnet-5 · 4,461,205 tokens (24,953 in, 4,426,622 cached, 9,630 out) · 29 turns · US$ 1.08 · 3 min 14 s
  • reviewer · claude-haiku-4-5-20251001, claude-opus-5 · 815,828 tokens (100,327 in, 702,097 cached, 13,404 out) · 14 turns · US$ 1.74 · 3 min 07 s
  • coder · claude-sonnet-5 · 2,500,012 tokens (14,258 in, 2,478,265 cached, 7,489 out) · 15 turns · US$ 0.63 · 2 min 04 s
  • reviewer · claude-haiku-4-5-20251001, claude-opus-5 · 216,542 tokens (61,903 in, 150,801 cached, 3,838 out) · 5 turns · US$ 0.84 · 1 min 14 s
  • security · sonnet · 0 tokens (0 in, 0 cached, 0 out) · 1 turns · US$ 0.00 · 2 s · did not finish
  • security · claude-haiku-4-5-20251001, claude-sonnet-5 · 381,571 tokens (77,864 in, 301,855 cached, 1,852 out) · 6 turns · US$ 0.44 · 25 s
  • analyst · claude-haiku-4-5-20251001, claude-sonnet-5 · 196,860 tokens (36,624 in, 158,375 cached, 1,861 out) · 7 turns · US$ 0.21 · 27 s
  • changelog · claude-haiku-4-5-20251001 · 239,718 tokens (27,776 in, 209,158 cached, 2,784 out) · 11 turns · US$ 0.09 · 31 s

tests: Added unit wire tests (tests/Unit/Options/UrlConstructionTest.php) covering the three new `dte` forms the API now accepts on GET /v1/options/chain/{underlying}/: comma-separated list ("15,30,45"), closed range ("0-45"), and comparison operator (">=30" and "<45"), each asserting the exact query string sent; the existing single-integer-value test already covers the pre-existing form. Added live integration tests (tests/Integration/Options/OptionChainTest.php) for every dte form against AAPL, each tagged #[Group('ci')], asserting multiple distinct expirations are returned (impossible under the documented single-expiration default) and that returned dte values respect the stated bounds. Added the compatibility probe at build/sdk-sync-compat/SdkSyncCompatProbeTest.php covering today's `option_chain(dte: int)` call, verified green against current code.

implement: Widened `option_chain()`'s `$dte` parameter from `?int` to `int|string|null` on src/Endpoints/Options.php, so it accepts a comma-separated list, a closed range, and a comparison operator in addition to the existing single integer, matching the API's new query syntax for GET /v1/options/chain/{underlying}/.
Correctness: the type was widened purely additively; the old int form keeps its exact behaviour and error (InvalidArgumentException via validatePositiveInteger, now gated behind is_int so string forms bypass it, same as strike/delta).
Docs: updated the @PARAM block for $dte with one bullet and example per form, in the same style as the neighbouring $delta/$strike docs.
New public members: none added — only an existing parameter's type widened, so no new doc comments needed beyond the updated @PARAM.
Wire tests: phase 1 already added one unit test per new form (list, range, >=, <) plus the pre-existing single-value regression, all asserting the literal query string.
Validation: no new validation surface was added for the string forms (consistent with strike/delta, which also accept free-form strings unchecked); the existing int validation is preserved unchanged.
Coverage: no code excluded; the is_int branch is exercised by both the existing int test and the new string-form tests.
Examples/docs still correct: examples/options_chain.md's dte entry describes the response field (always int), not the request filter, so it needed no change; options-screener examples and options_chain.php pass a plain int to dte and remain valid under the widened type.
Existing parameter compatibility: $dte still accepts every value it did before (plain int, unchanged signature position/default), only widened.
Left as-is (outside scope, no dte/option_chain content found despite being listed): tests/Unit/Options/ExpirationsTest.php, LookupTest.php, StrikesTest.php, tests/Unit/Options/QuotesTest.php, tests/Integration/Options/QuotesTest.php, tests/Unit/ToStringTest.php — these reference the unrelated response-side `dte` field or other Options endpoints, not the chain filter.
Outside my limits and left wrong/out of date: CHANGELOG.md has no entry yet (pipeline writes it); the .phpdoc/ cache still reflects the old `?int $dte` signature until regenerated.

review fix 1: Added tests/Unit/Options/UrlConstructionTest.php::testOptionChain_withDteString_addsParameter, asserting dte=30 is sent for the string single value `dte: '30'` — the form the type change exists for, previously only tested with the old int type.
Fixed testOptionChain_dteCommaList_selectsMultipleExpirations: added assertLessThanOrEqual(3, count($response->option_chains)) alongside the existing lower bound, so the test now fails on a server that ignores dte and returns the whole chain, not only on one that returns the single default.
Added strike_limit: 3 to all five new dte live tests (single value, comma list, closed range, >=, <), matching the neighbouring multi-expiration tests' convention and bounding per-contract request cost; verified none of the dte/expiration-count assertions depend on the full, unbounded strike set.
Documented the dte=0 inconsistency in the @PARAM block for $dte (src/Endpoints/Options.php): a single int dte must be positive (unchanged, pre-existing validation on the existing public method, left as-is to avoid changing its error behavior), while the string forms (list, range, comparison) are passed through unvalidated and accept 0 as a bound, matching the API's documented closed-range syntax.
Left the <40 boundary question (inclusive vs exclusive) in testOptionChain_dteComparisonLt untouched, as instructed — it is a question for a person to settle with the API team, not something to resolve in code or tests.

changelog: Added changelog entry for `Options::option_chain()` parameter widening: `dte` now accepts string forms (comma-separated list, closed range, comparison operators) in addition to single integer values (API release 2.0.0); int form retains exact prior behavior.
@marketdata-sdk-sync marketdata-sdk-sync Bot added minor adds to the SDK's public surface and breaks nothing sdk-sync: in progress sdk-sync is still working on this PR: CI, code review, fixes labels Nov 10, 2026
@marketdata-sdk-sync

Copy link
Copy Markdown
Author

🧾 Job log — sdk-sync

sdk-auto-sync job log

API release 2.0.0 (commit ffb34b7)
SDK sdk-php
Branch sdk-sync/2.0.0-ffb34b7
API surface ae2b047c8f6f → c2a31e277345
Date 2026-11-10 18:42:29Z
Outcome done

Changes in the API surface

~ GET /v1/options/chain/{underlying}/ ?dte: string  (was integer)

1. setup

Gates:

  • setup, attempt 1: passed (0 s)

What it printed:

$ composer install --prefer-dist --no-interaction --no-progress --no-plugins --no-scripts
Installing dependencies from lock file (including require-dev)
Verifying lock file contents can be installed on current platform.
Nothing to install, update or remove
Generating autoload files
42 packages you are using are looking for funding.
Use the `composer fund` command to find out more!

2. tests

Coder (31 turns, US$ 1.37, 5 min 35 s):

vendor/bin/phpunit --testsuite Unit --no-coverage --do-not-cache-result --log-junit build/test-results/phpunit.xml → red as required: 4 new TypeErrors (Argument #12 ($dte) must be of type ?int, string given) from the new string-form wire tests; all other 1083 tests pass. vendor/bin/phpunit --no-coverage --do-not-cache-result build/sdk-sync-compat/SdkSyncCompatProbeTest.php → green (1 test, 1 assertion) against current main.

Added unit wire tests (tests/Unit/Options/UrlConstructionTest.php) covering the three new dte forms the API now accepts on GET /v1/options/chain/{underlying}/: comma-separated list ("15,30,45"), closed range ("0-45"), and comparison operator (">=30" and "<45"), each asserting the exact query string sent; the existing single-integer-value test already covers the pre-existing form. Added live integration tests (tests/Integration/Options/OptionChainTest.php) for every dte form against AAPL, each tagged #[Group('ci')], asserting multiple distinct expirations are returned (impossible under the documented single-expiration default) and that returned dte values respect the stated bounds. Added the compatibility probe at build/sdk-sync-compat/SdkSyncCompatProbeTest.php covering today's option_chain(dte: int) call, verified green against current code.

Gates:

  • compatibility probe on the base, attempt 1: passed (2 s)
  • tests (expected to fail), attempt 1: failed — 4 failing test(s): MarketDataApp.Tests.Unit.Options.UrlConstructionTest.testOptionChain_withDteComparisonGte_addsParameter, MarketDataApp.Tests.Unit.Options.UrlConstructionTest.testOptionChain_withDteCommaList_addsParameter, MarketDataApp.Tests.Unit.Options.UrlConstructionTest.testOptionChain_withDteClosedRange_addsParameter and 1 more (31 s)

3. implement

Coder (29 turns, US$ 1.08, 3 min 14 s):

vendor/bin/phpunit --testsuite Unit --no-coverage --do-not-cache-result --log-junit build/test-results/phpunit.xml → OK (1087 tests, 3367 assertions). vendor/bin/phpunit --testsuite Integration --list-tests --no-coverage --do-not-cache-result → lists all tests cleanly, including the 5 new dte integration tests, no errors.

Widened option_chain()'s $dte parameter from ?int to int|string|null on src/Endpoints/Options.php, so it accepts a comma-separated list, a closed range, and a comparison operator in addition to the existing single integer, matching the API's new query syntax for GET /v1/options/chain/{underlying}/.
Correctness: the type was widened purely additively; the old int form keeps its exact behaviour and error (InvalidArgumentException via validatePositiveInteger, now gated behind is_int so string forms bypass it, same as strike/delta).
Docs: updated the @PARAM block for $dte with one bullet and example per form, in the same style as the neighbouring $delta/$strike docs.
New public members: none added — only an existing parameter's type widened, so no new doc comments needed beyond the updated @PARAM.
Wire tests: phase 1 already added one unit test per new form (list, range, >=, <) plus the pre-existing single-value regression, all asserting the literal query string.
Validation: no new validation surface was added for the string forms (consistent with strike/delta, which also accept free-form strings unchecked); the existing int validation is preserved unchanged.
Coverage: no code excluded; the is_int branch is exercised by both the existing int test and the new string-form tests.
Examples/docs still correct: examples/options_chain.md's dte entry describes the response field (always int), not the request filter, so it needed no change; options-screener examples and options_chain.php pass a plain int to dte and remain valid under the widened type.
Existing parameter compatibility: $dte still accepts every value it did before (plain int, unchanged signature position/default), only widened.
Left as-is (outside scope, no dte/option_chain content found despite being listed): tests/Unit/Options/ExpirationsTest.php, LookupTest.php, StrikesTest.php, tests/Unit/Options/QuotesTest.php, tests/Integration/Options/QuotesTest.php, tests/Unit/ToStringTest.php — these reference the unrelated response-side dte field or other Options endpoints, not the chain filter.
Outside my limits and left wrong/out of date: CHANGELOG.md has no entry yet (pipeline writes it); the .phpdoc/** cache still reflects the old ?int $dte signature until regenerated.

Gates:

  • tests, attempt 1: passed (31 s)
  • build, attempt 1: passed (1 s)
  • compatibility probe, attempt 1: passed (0 s)
  • live API suite, attempt 1: passed (13 s) — vendor/bin/phpunit --no-coverage --do-not-cache-result --group ci --log-junit build/test-results/live.xml tests/Integration/Options/OptionChainTest.php

4. review 1

Reviewer (14 turns, US$ 1.74, 3 min 07 s): 3 blocking finding(s)

The widening of dte to int|string|null is correct and non-breaking (union widened; version impact: minor), the docblock mirrors the existing strike/delta wording, and both branches of the new is_int($dte) guard are exercised. Gaps remain in test coverage: the single value in the new string type has no wire test, the comma-list live test cannot tell the list semantics from a full chain, and the new live tests fetch unbounded chains on a free token. One boundary question (<N vs the documentation's "inclusive") is left for a person.

  • [major] tests/Unit/Options/UrlConstructionTest.php:808 — The single-value form is only tested in the old int type (dte: 30, line 800); no test passes the new type for that form, e.g. dte: '30'. The API delta is precisely integer -> string, so the string single value is the form the change exists for. Add a wire test asserting dte=30 is sent for dte: '30'.
  • [major] tests/Integration/Options/OptionChainTest.php:386 — testOptionChain_dteCommaList asserts only count($response->option_chains) > 1, which a server returning the whole chain also satisfies, so it does not check the documented semantics ("selects the closest expiration for each value, deduplicated"). Add an upper bound from the response itself — at most one expiration per requested value, i.e. assertLessThanOrEqual(3, count($response->option_chains)) for '7,30,90'.
  • [major] tests/Integration/Options/OptionChainTest.php:351 — The four new dte live tests request whole multi-expiration AAPL chains with no strike_limit, unlike the neighbouring multi-expiration tests in this file (strike_limit: 3 or 5) and against the docblock's own CAUTION that a request is consumed per priced contract; on a free token run on every pull request this can exhaust the daily credits and fail the rest of the suite. Pass strike_limit: 3 — it bounds strikes, not expirations, so every dte assertion still holds.
  • [minor · question for a person] tests/Integration/Options/OptionChainTest.php:452 — testOptionChain_dteComparisonLt asserts assertLessThan(40, $quote->dte), i.e. that <40 excludes dte exactly 40, while the API text says comparison operators are "inclusive" (and also says the syntax matches strike and delta, which would make < exclusive). The two readings differ only on days when an expiration sits at exactly dte 40, so the single passing live run does not settle it: please confirm with the API team whether <N excludes N before this assertion is relied on.
  • [minor] src/Endpoints/Options.php:399 — After the guard, dte: 0 still throws \InvalidArgumentException from validatePositiveInteger while dte: '0' and the documented '0-45' are sent unchanged — the same value is accepted or rejected depending on its type, and the new docblock presents 0 as a legal dte bound. Either let 0 through or note the restriction in the parameter's documentation.

5. review fix 1

Findings sent back to the coder:

  • [major] tests/Unit/Options/UrlConstructionTest.php:808 — The single-value form is only tested in the old int type (dte: 30, line 800); no test passes the new type for that form, e.g. dte: '30'. The API delta is precisely integer -> string, so the string single value is the form the change exists for. Add a wire test asserting dte=30 is sent for dte: '30'.
  • [major] tests/Integration/Options/OptionChainTest.php:386 — testOptionChain_dteCommaList asserts only count($response->option_chains) > 1, which a server returning the whole chain also satisfies, so it does not check the documented semantics ("selects the closest expiration for each value, deduplicated"). Add an upper bound from the response itself — at most one expiration per requested value, i.e. assertLessThanOrEqual(3, count($response->option_chains)) for '7,30,90'.
  • [major] tests/Integration/Options/OptionChainTest.php:351 — The four new dte live tests request whole multi-expiration AAPL chains with no strike_limit, unlike the neighbouring multi-expiration tests in this file (strike_limit: 3 or 5) and against the docblock's own CAUTION that a request is consumed per priced contract; on a free token run on every pull request this can exhaust the daily credits and fail the rest of the suite. Pass strike_limit: 3 — it bounds strikes, not expirations, so every dte assertion still holds.

Minor findings sent along, as optional:

  • [minor] src/Endpoints/Options.php:399 — After the guard, dte: 0 still throws \InvalidArgumentException from validatePositiveInteger while dte: '0' and the documented '0-45' are sent unchanged — the same value is accepted or rejected depending on its type, and the new docblock presents 0 as a legal dte bound. Either let 0 through or note the restriction in the parameter's documentation.

Questions for a person, shown to the coder and not for it to resolve:

  • [minor · question for a person] tests/Integration/Options/OptionChainTest.php:452 — testOptionChain_dteComparisonLt asserts assertLessThan(40, $quote->dte), i.e. that <40 excludes dte exactly 40, while the API text says comparison operators are "inclusive" (and also says the syntax matches strike and delta, which would make < exclusive). The two readings differ only on days when an expiration sits at exactly dte 40, so the single passing live run does not settle it: please confirm with the API team whether <N excludes N before this assertion is relied on.

Coder (15 turns, US$ 0.63, 2 min 04 s):

vendor/bin/phpunit --testsuite Unit --no-coverage --do-not-cache-result --log-junit build/test-results/phpunit.xml → OK (1088 tests, 3369 assertions). vendor/bin/phpunit --testsuite Integration --list-tests --no-coverage --do-not-cache-result → lists all tests including the 5 updated dte integration tests, no errors.

Added tests/Unit/Options/UrlConstructionTest.php::testOptionChain_withDteString_addsParameter, asserting dte=30 is sent for the string single value dte: '30' — the form the type change exists for, previously only tested with the old int type.
Fixed testOptionChain_dteCommaList_selectsMultipleExpirations: added assertLessThanOrEqual(3, count($response->option_chains)) alongside the existing lower bound, so the test now fails on a server that ignores dte and returns the whole chain, not only on one that returns the single default.
Added strike_limit: 3 to all five new dte live tests (single value, comma list, closed range, >=, <), matching the neighbouring multi-expiration tests' convention and bounding per-contract request cost; verified none of the dte/expiration-count assertions depend on the full, unbounded strike set.
Documented the dte=0 inconsistency in the @PARAM block for $dte (src/Endpoints/Options.php): a single int dte must be positive (unchanged, pre-existing validation on the existing public method, left as-is to avoid changing its error behavior), while the string forms (list, range, comparison) are passed through unvalidated and accept 0 as a bound, matching the API's documented closed-range syntax.
Left the <40 boundary question (inclusive vs exclusive) in testOptionChain_dteComparisonLt untouched, as instructed — it is a question for a person to settle with the API team, not something to resolve in code or tests.

Gates:

  • tests, attempt 1: passed (31 s)
  • build, attempt 1: passed (0 s)
  • compatibility probe, attempt 1: passed (0 s)
  • live API suite, attempt 1: passed (9 s) — vendor/bin/phpunit --no-coverage --do-not-cache-result --group ci --log-junit build/test-results/live.xml tests/Integration/Options/OptionChainTest.php

6. review 2

Reviewer (5 turns, US$ 0.84, 1 min 14 s): approved

All three blocking findings are addressed: a wire test now covers dte: '30', the comma-list live test has the per-value upper bound, and all four dte live tests pass strike_limit: 3. The added docblock NOTE accurately describes the existing int-only validatePositiveInteger check (ValidatesInputs.php:181 rejects 0), and nothing in the fix weakens an existing test or assertion. One minor note on the new unit test's discriminating power.

  • [minor] tests/Unit/Options/UrlConstructionTest.php:812 — testOptionChain_withDteString_addsParameter would also pass before the change: the file has no declare(strict_types=1), so under the old ?int $dte PHP coerces '30' to 30 silently. The delta is still proven by the other string-form tests (comma list, range, comparison), which would TypeError on the old signature; if you want this one to discriminate too, it needs a strict_types context.

7. security

Security (1 turns, US$ 0.00, 2 s): did not finish

The pipeline:

  • interrupted at 14:53 UTC: the agents were unavailable (You've hit your session limit · resets 1:40pm (America/New_York) (HTTP 429) (1 turns · US$ 0.00)); resumed at 18:42 UTC on the same working tree, developed on main at 5db046b87848

Security (6 turns, US$ 0.44, 25 s): approved

The change widens Options::option_chain()'s $dte parameter from int to int|string, skipping client-side validation for the new string forms (list, range, comparison) and passing them through as-is. These values reach the API only as a Guzzle query parameter (via the query option) and are never used in a path, shell command, or log format string, so there is no injection, path-traversal, or credential-exposure risk. No dependencies, build scripts, or CI were touched, and nothing else in the diff is unrelated to the stated dte type change.

  • no findings

8. assess

Analyst (7 turns, US$ 0.21, 27 s) — public surface:

The only public-surface change is Options::option_chain()'s $dte parameter, whose declared type widens from ?int to int|string|null to match the API's new string-based dte syntax (list, range, comparison operator). Existing calls passing an int for dte are unaffected: the method still runs the same positive-integer validation via validatePositiveInteger when $dte is an int, and only skips that check for the new string forms, which the API accepts unvalidated.

  • added: Options::option_chain($dte) — ?int widened to int|string|null; dte: 30 still type-checks and validates exactly as before, while dte: '15,30,45', dte: '0-45', dte: '>=30' and dte: '<45' are new accepted forms.

Computed by the pipeline: minor; changelog entry written

9. changelog

Coder (11 turns, US$ 0.09, 31 s):

Edit completed successfully, CHANGELOG.md updated under [Unreleased]/Added with the single-line entry.

Added changelog entry for Options::option_chain() parameter widening: dte now accepts string forms (comma-separated list, closed range, comparison operators) in addition to single integer values (API release 2.0.0); int form retains exact prior behavior.

Gates:

  • build, attempt 1: passed (1 s)

Questions for a person

The internal reviewers raised these for a person to answer. They did not block the change, and the coder was not asked to resolve them.

  • tests/Integration/Options/OptionChainTest.php:452 — testOptionChain_dteComparisonLt asserts assertLessThan(40, $quote->dte), i.e. that <40 excludes dte exactly 40, while the API text says comparison operators are "inclusive" (and also says the syntax matches strike and delta, which would make < exclusive). The two readings differ only on days when an expiration sits at exactly dte 40, so the single passing live run does not settle it: please confirm with the API team whether <N excludes N before this assertion is relied on.

Totals

  • Bump: minor
  • Coder runs: 4
  • Review runs: 4
  • Gates run: 12 (1 failed)
  • Files changed by the agent: 4
  • Turns: 119
  • Tokens: 11,764,442
  • Estimated cost: US$ 6.39
  • Time: 19 min 10 s (agents 16 min 39 s, gates 1 min 59 s)

Agent runs

  • coder · claude-haiku-4-5-20251001, claude-sonnet-5 · 2,952,706 tokens (131,368 in, 2,794,080 cached, 27,258 out) · 31 turns · US$ 1.37 · 5 min 35 s
  • coder · claude-sonnet-5 · 4,461,205 tokens (24,953 in, 4,426,622 cached, 9,630 out) · 29 turns · US$ 1.08 · 3 min 14 s
  • reviewer · claude-haiku-4-5-20251001, claude-opus-5 · 815,828 tokens (100,327 in, 702,097 cached, 13,404 out) · 14 turns · US$ 1.74 · 3 min 07 s
  • coder · claude-sonnet-5 · 2,500,012 tokens (14,258 in, 2,478,265 cached, 7,489 out) · 15 turns · US$ 0.63 · 2 min 04 s
  • reviewer · claude-haiku-4-5-20251001, claude-opus-5 · 216,542 tokens (61,903 in, 150,801 cached, 3,838 out) · 5 turns · US$ 0.84 · 1 min 14 s
  • security · sonnet · 0 tokens (0 in, 0 cached, 0 out) · 1 turns · US$ 0.00 · 2 s · did not finish
  • security · claude-haiku-4-5-20251001, claude-sonnet-5 · 381,571 tokens (77,864 in, 301,855 cached, 1,852 out) · 6 turns · US$ 0.44 · 25 s
  • analyst · claude-haiku-4-5-20251001, claude-sonnet-5 · 196,860 tokens (36,624 in, 158,375 cached, 1,861 out) · 7 turns · US$ 0.21 · 27 s
  • changelog · claude-haiku-4-5-20251001 · 239,718 tokens (27,776 in, 209,158 cached, 2,784 out) · 11 turns · US$ 0.09 · 31 s

@codecov

codecov Bot commented Nov 10, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 99.78%. Comparing base (e67d234) to head (ee12c24).
⚠️ Report is 1 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff            @@
##               main     #112   +/-   ##
=========================================
  Coverage     99.78%   99.78%           
- Complexity      971      972    +1     
=========================================
  Files            50       50           
  Lines          2829     2830    +1     
=========================================
+ Hits           2823     2824    +1     
  Misses            6        6           

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

This branch has not been deployed

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

Labels

minor adds to the SDK's public surface and breaks nothing sdk-sync: in progress sdk-sync is still working on this PR: CI, code review, fixes

Projects

None yet

Development

Successfully merging this pull request may close these issues.

0 participants