Skip to content

sdk-sync: API 2.0.0+ffb34b7 - #88

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

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 Oct 5, 2026 •

Copy link
Copy Markdown

Needs human review. The internal review did not pass after 2 cycles, or a reviewer did not finish. This pull request is a draft, labelled sdk-sync: needs human. Left open by the internal review:

  • the reviewer did not finish, twice: success (1 turns · US$ 0.00)
  • the security did not finish, twice: success (1 turns · US$ 0.00)

Needs a person: no version. The version was not computed and the CHANGELOG entry was not written: the analyst did not finish, twice: success (1 turns · US$ 0.00). This pull request is a draft, labelled sdk-sync: needs human; what is left is to decide the version bump and to write the entry.
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: Confirmed red, as expected — fails to compile because DteFilter doesn't exist yet (phase 2 will add it). Stopping here per instructions.

Added 12 tests to OptionsResourceTest.java (3 wire, 1 regression, 4 validation, 1 parity) and OptionsIntegrationTest.java (3 integration), exactly per the plan, referencing a not-yet-existing DteFilter type. gradle test --no-daemon --console=plain fails as required, with compileTestJava erroring on the missing DteFilter symbol. No production code or other test lines were touched.

implement: All changes stay within production/test/doc scope, no CHANGELOG, no commit made.

Added DteFilter (sealed, extends ExpirationFilter): values/range/comparison factories for the chain endpoint's widened ?dte= parameter (comma-list, closed range, comparison operator), each bounded to 0..36500 per the API description. Added the pass-through overload ExpirationFilter.dte(DteFilter); the existing dte(int) single-value factory, its validation, and its wire form are unchanged. Wired the three new forms into OptionsResource.applyExpirationFilter and documented them in docs/options/chain.md. One wire test's expectation was wrong (commas are URL-encoded on this wire, per the repo's existing columns convention) — fixed the test to decode before asserting, as planned. gradle test and gradle build both pass.

Files

  • docs/options/chain.md
  • src/integrationTest/java/com/marketdata/sdk/OptionsIntegrationTest.java
  • src/main/java/com/marketdata/sdk/OptionsResource.java
  • src/main/java/com/marketdata/sdk/options/DteFilter.java
  • src/main/java/com/marketdata/sdk/options/ExpirationFilter.java
  • src/test/java/com/marketdata/sdk/OptionsResourceTest.java

Test plan

12 case(s) (wire 3, regression 1, validation 4, parity 1, integration 3)

# category test API form input expected
1 wire chainExpirationFilterDteValuesTranslatesToCommaSeparatedDte a comma-separated list (15,30,45) chainAsync(OptionsChainRequest.builder("AAPL").expirationFilter(ExpirationFilter.dte(DteFilter.values(15, 30, 45))).build()) client.captured.get(0).uri().toString() isEqualTo "http://localhost/v1/options/chain/AAPL/?dte=15,30,45"
2 wire chainExpirationFilterDteRangeTranslatesToDashedDte a closed range (0-45) chainAsync(OptionsChainRequest.builder("AAPL").expirationFilter(ExpirationFilter.dte(DteFilter.range(0, 45))).build()) client.captured.get(0).uri().toString() isEqualTo "http://localhost/v1/options/chain/AAPL/?dte=0-45"
3 wire chainExpirationFilterDteComparisonTranslatesToOperatorPrefixedDte a comparison operator (>=30, <45) chainAsync(OptionsChainRequest.builder("AAPL").expirationFilter(ExpirationFilter.dte(DteFilter.comparison(DteFilter.Operator.GTE, 30))).build()) url contains "dte=%3E%3D30" (URL-encoded ">=30")
4 regression chainExpirationFilterDteTranslatesToDteParam a single value chainAsync(OptionsChainRequest.builder("AAPL").expirationFilter(ExpirationFilter.dte(30)).build()) client.captured.get(0).uri().toString() isEqualTo "http://localhost/v1/options/chain/AAPL/?dte=30" (unchanged)
5 validation dteFilterValuesRejectsOutOfRangeValue Values are whole numbers of days, at most 36500 DteFilter.values(15, 36501) IllegalArgumentException "dte must be in 0..36500"
6 validation dteFilterRangeRejectsMinGreaterThanMax a closed range (0-45) DteFilter.range(45, 0) IllegalArgumentException "min must be <= max"
7 validation dteFilterRangeRejectsOutOfRangeBound Values are whole numbers of days, at most 36500 DteFilter.range(0, 36501) IllegalArgumentException "dte must be in 0..36500"
8 validation dteFilterComparisonRejectsOutOfRangeValue Values are whole numbers of days, at most 36500 DteFilter.comparison(DteFilter.Operator.GTE, 36501) IllegalArgumentException "dte must be in 0..36500"
9 parity chainExpirationFilterDteRangeSyncMatchesAsyncWire a closed range (0-45) resourceWith(client).chain(OptionsChainRequest.builder("AAPL").expirationFilter(ExpirationFilter.dte(DteFilter.range(0, 45))).build()) client.captured.get(0).uri().toString() contains "dte=0-45" (sync wrapper matches async wire translation)
10 integration chainDteValuesReturnsClosestExpirationPerValueDeduplicated a comma-separated list (15,30,45) client.options().chain(OptionsChainRequest.builder(UNDERLYING).expirationFilter(ExpirationFilter.dte(DteFilter.values(7, 14, 30))).side(OptionSide.CALL).strikeLimit(1).build()) resp.values() isNotEmpty; distinct dte values across rows hasSizeBetween(1, 3) (closest expiration per value, deduplicated)
11 integration chainDteRangeReturnsExpirationsWithinBounds a closed range (0-45) client.options().chain(OptionsChainRequest.builder(UNDERLYING).expirationFilter(ExpirationFilter.dte(DteFilter.range(0, 45))).side(OptionSide.CALL).strikeLimit(1).build()) resp.values() isNotEmpty; every row's dte() is between 0 and 45 inclusive
12 integration chainDteComparisonReturnsExpirationsSatisfyingOperator a comparison operator (>=30, <45) client.options().chain(OptionsChainRequest.builder(UNDERLYING).expirationFilter(ExpirationFilter.dte(DteFilter.comparison(DteFilter.Operator.GTE, 30))).side(OptionSide.CALL).strikeLimit(1).build()) resp.values() isNotEmpty; every row's dte() is greaterThanOrEqualTo 30

Live-API suite

  • src/integrationTest/java/com/marketdata/sdk/OptionsIntegrationTest.java

Files of this suite changed by this pull request. The pipeline did not run the suite (it has no API token); the repository runs it with /integrationtest.

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.


3 coder run(s) · 1 review(s) · 79 turns · 6,792,585 tokens · US$ 3.12 · item 5c097984-5f7b-401b-abba-235a3f417767

Agent runs
  • coder · claude-haiku-4-5-20251001, claude-sonnet-5 · 1,082,820 tokens (64,456 in, 986,213 cached, 32,151 out) · 21 turns · US$ 0.78
  • plan reviewer · claude-haiku-4-5-20251001, claude-opus-5 · 257,269 tokens (31,594 in, 220,036 cached, 5,639 out) · 15 turns · US$ 0.57
  • coder · claude-sonnet-5 · 1,203,821 tokens (97,360 in, 1,100,999 cached, 5,462 out) · 11 turns · US$ 0.66
  • coder · claude-sonnet-5 · 4,248,675 tokens (33,381 in, 4,202,661 cached, 12,633 out) · 32 turns · US$ 1.10

tests: Confirmed red, as expected — fails to compile because `DteFilter` doesn't exist yet (phase 2 will add it). Stopping here per instructions.

Added 12 tests to `OptionsResourceTest.java` (3 wire, 1 regression, 4 validation, 1 parity) and `OptionsIntegrationTest.java` (3 integration), exactly per the plan, referencing a not-yet-existing `DteFilter` type. `gradle test --no-daemon --console=plain` fails as required, with `compileTestJava` erroring on the missing `DteFilter` symbol. No production code or other test lines were touched.

implement: All changes stay within production/test/doc scope, no CHANGELOG, no commit made.

Added `DteFilter` (sealed, extends `ExpirationFilter`): `values`/`range`/`comparison` factories for the chain endpoint's widened `?dte=` parameter (comma-list, closed range, comparison operator), each bounded to 0..36500 per the API description. Added the pass-through overload `ExpirationFilter.dte(DteFilter)`; the existing `dte(int)` single-value factory, its validation, and its wire form are unchanged. Wired the three new forms into `OptionsResource.applyExpirationFilter` and documented them in `docs/options/chain.md`. One wire test's expectation was wrong (commas are URL-encoded on this wire, per the repo's existing `columns` convention) — fixed the test to decode before asserting, as planned. `gradle test` and `gradle build` both pass.
@marketdata-sdk-sync marketdata-sdk-sync Bot added the sdk-sync: needs human sdk-sync stopped: a person has to look (see the PR's comments) label Oct 5, 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-java
Branch sdk-sync/2.0.0-ffb34b7
API surface ae2b047c8f6f → c2a31e277345
Date 2026-10-05 14:35:48Z
Outcome needs human review — the reviewer did not finish, twice: success (1 turns · US$ 0.00); the security did not finish, twice: success (1 turns · US$ 0.00); the version is not computed and the changelog entry is not written: the analyst did not finish, twice: success (1 turns · US$ 0.00)

Changes in the API surface

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

1. test plan

Coder (21 turns, US$ 0.78) — test plan, 12 case(s) (wire 3, regression 1, validation 4, parity 1, integration 3):

Plan widens options/chain's dte filter from int to the API's string forms by adding a new sealed DteFilter (Values/Range/Comparison) that itself implements ExpirationFilter, plus an additive ExpirationFilter.dte(DteFilter) overload — mirrors the existing StrikeFilter Exact/Range/Comparison precedent (ADR-008). The existing ExpirationFilter.dte(int) factory, its non-negative check, and its ?dte=N wire form are left untouched (regression).

# category test API form input expected
1 wire chainExpirationFilterDteValuesTranslatesToCommaSeparatedDte a comma-separated list (15,30,45) chainAsync(OptionsChainRequest.builder("AAPL").expirationFilter(ExpirationFilter.dte(DteFilter.values(15, 30, 45))).build()) client.captured.get(0).uri().toString() isEqualTo "http://localhost/v1/options/chain/AAPL/?dte=15,30,45"
2 wire chainExpirationFilterDteRangeTranslatesToDashedDte a closed range (0-45) chainAsync(OptionsChainRequest.builder("AAPL").expirationFilter(ExpirationFilter.dte(DteFilter.range(0, 45))).build()) client.captured.get(0).uri().toString() isEqualTo "http://localhost/v1/options/chain/AAPL/?dte=0-45"
3 wire chainExpirationFilterDteComparisonTranslatesToOperatorPrefixedDte a comparison operator (>=30, <45) chainAsync(OptionsChainRequest.builder("AAPL").expirationFilter(ExpirationFilter.dte(DteFilter.comparison(DteFilter.Operator.GTE, 30))).build()) url contains "dte=%3E%3D30" (URL-encoded ">=30")
4 regression chainExpirationFilterDteTranslatesToDteParam a single value chainAsync(OptionsChainRequest.builder("AAPL").expirationFilter(ExpirationFilter.dte(30)).build()) client.captured.get(0).uri().toString() isEqualTo "http://localhost/v1/options/chain/AAPL/?dte=30" (unchanged)
5 validation dteFilterValuesRejectsOutOfRangeValue Values are whole numbers of days, at most 36500 DteFilter.values(15, 36501) IllegalArgumentException "dte must be in 0..36500"
6 validation dteFilterRangeRejectsMinGreaterThanMax a closed range (0-45) DteFilter.range(45, 0) IllegalArgumentException "min must be <= max"
7 validation dteFilterRangeRejectsOutOfRangeBound Values are whole numbers of days, at most 36500 DteFilter.range(0, 36501) IllegalArgumentException "dte must be in 0..36500"
8 validation dteFilterComparisonRejectsOutOfRangeValue Values are whole numbers of days, at most 36500 DteFilter.comparison(DteFilter.Operator.GTE, 36501) IllegalArgumentException "dte must be in 0..36500"
9 parity chainExpirationFilterDteRangeSyncMatchesAsyncWire a closed range (0-45) resourceWith(client).chain(OptionsChainRequest.builder("AAPL").expirationFilter(ExpirationFilter.dte(DteFilter.range(0, 45))).build()) client.captured.get(0).uri().toString() contains "dte=0-45" (sync wrapper matches async wire translation)
10 integration chainDteValuesReturnsClosestExpirationPerValueDeduplicated a comma-separated list (15,30,45) client.options().chain(OptionsChainRequest.builder(UNDERLYING).expirationFilter(ExpirationFilter.dte(DteFilter.values(7, 14, 30))).side(OptionSide.CALL).strikeLimit(1).build()) resp.values() isNotEmpty; distinct dte values across rows hasSizeBetween(1, 3) (closest expiration per value, deduplicated)
11 integration chainDteRangeReturnsExpirationsWithinBounds a closed range (0-45) client.options().chain(OptionsChainRequest.builder(UNDERLYING).expirationFilter(ExpirationFilter.dte(DteFilter.range(0, 45))).side(OptionSide.CALL).strikeLimit(1).build()) resp.values() isNotEmpty; every row's dte() is between 0 and 45 inclusive
12 integration chainDteComparisonReturnsExpirationsSatisfyingOperator a comparison operator (>=30, <45) client.options().chain(OptionsChainRequest.builder(UNDERLYING).expirationFilter(ExpirationFilter.dte(DteFilter.comparison(DteFilter.Operator.GTE, 30))).side(OptionSide.CALL).strikeLimit(1).build()) resp.values() isNotEmpty; every row's dte() is greaterThanOrEqualTo 30

Plan reviewer (15 turns, US$ 0.57): approved

All four forms the description enumerates (single value, comma list, closed range, comparison operator) have exact-request cases, with the single value kept as a regression, and nothing beyond them is asserted. Validation targets only the new DteFilter factories and keeps IllegalArgumentException, matching the StrikeFilter precedent; the existing ExpirationFilter.dte(int) error type is untouched. Parity, naming, file placement and the three live-API cases (one per new form, asserting decoded rows against the filter, no self-skip) match the repository's conventions; no new endpoint, so no response fixture is required.

  • no findings

2. tests

Coder (11 turns, US$ 0.66):

Confirmed red, as expected — fails to compile because DteFilter doesn't exist yet (phase 2 will add it). Stopping here per instructions.

Added 12 tests to OptionsResourceTest.java (3 wire, 1 regression, 4 validation, 1 parity) and OptionsIntegrationTest.java (3 integration), exactly per the plan, referencing a not-yet-existing DteFilter type. gradle test --no-daemon --console=plain fails as required, with compileTestJava erroring on the missing DteFilter symbol. No production code or other test lines were touched.

Gates:

  • tests (expected to fail), attempt 1: failed — Execution failed for task ':compileTestJava' (registered by plugin class 'org.gradle.api.plugins.JavaBasePlugin').

3. implement

Coder (32 turns, US$ 1.10):

All changes stay within production/test/doc scope, no CHANGELOG, no commit made.

Added DteFilter (sealed, extends ExpirationFilter): values/range/comparison factories for the chain endpoint's widened ?dte= parameter (comma-list, closed range, comparison operator), each bounded to 0..36500 per the API description. Added the pass-through overload ExpirationFilter.dte(DteFilter); the existing dte(int) single-value factory, its validation, and its wire form are unchanged. Wired the three new forms into OptionsResource.applyExpirationFilter and documented them in docs/options/chain.md. One wire test's expectation was wrong (commas are URL-encoded on this wire, per the repo's existing columns convention) — fixed the test to decode before asserting, as planned. gradle test and gradle build both pass.

Gates:

  • tests, attempt 1: passed
  • build, attempt 1: passed

4. review 1

5. assess

The pipeline:

  • the analyst did not finish, twice: success (1 turns · US$ 0.00); the version is not computed and the changelog step did not run

Unresolved findings

  • the reviewer did not finish, twice: success (1 turns · US$ 0.00)
  • the security did not finish, twice: success (1 turns · US$ 0.00)

Totals

  • Version: not assessed
  • Coder runs: 3
  • Review runs: 1
  • Gates run: 3 (1 failed)
  • Files changed by the agent: 6
  • Turns: 79
  • Tokens: 6,792,585
  • Estimated cost: US$ 3.12

Agent runs

  • coder · claude-haiku-4-5-20251001, claude-sonnet-5 · 1,082,820 tokens (64,456 in, 986,213 cached, 32,151 out) · 21 turns · US$ 0.78
  • plan reviewer · claude-haiku-4-5-20251001, claude-opus-5 · 257,269 tokens (31,594 in, 220,036 cached, 5,639 out) · 15 turns · US$ 0.57
  • coder · claude-sonnet-5 · 1,203,821 tokens (97,360 in, 1,100,999 cached, 5,462 out) · 11 turns · US$ 0.66
  • coder · claude-sonnet-5 · 4,248,675 tokens (33,381 in, 4,202,661 cached, 12,633 out) · 32 turns · US$ 1.10

@marketdata-sdk-sync marketdata-sdk-sync Bot added the sdk-sync: needs human sdk-sync stopped: a person has to look (see the PR's comments) label Oct 5, 2026
@codecov

codecov Bot commented Oct 5, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 94.73684% with 2 lines in your changes missing coverage. Please review.
✅ Project coverage is 98.26%. Comparing base (d744f98) to head (9c9a8f7).

Files with missing lines Patch % Lines
.../main/java/com/marketdata/sdk/OptionsResource.java 83.33% 0 Missing and 1 partial ⚠️
...ain/java/com/marketdata/sdk/options/DteFilter.java 96.77% 0 Missing and 1 partial ⚠️
Additional details and impacted files
@@             Coverage Diff              @@
##               main      #88      +/-   ##
============================================
- Coverage     98.27%   98.26%   -0.02%     
- Complexity     1043     1055      +12     
============================================
  Files           123      124       +1     
  Lines          2606     2644      +38     
  Branches        301      306       +5     
============================================
+ Hits           2561     2598      +37     
- Partials         45       46       +1     
Files with missing lines Coverage Δ
...a/com/marketdata/sdk/options/ExpirationFilter.java 95.23% <100.00%> (+0.23%) ⬆️
.../main/java/com/marketdata/sdk/OptionsResource.java 98.57% <83.33%> (+0.04%) ⬆️
...ain/java/com/marketdata/sdk/options/DteFilter.java 96.77% <96.77%> (ø)

Continue to review full report in Codecov by Harness.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update d744f98...9c9a8f7. Read the comment docs.

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

@MarketDataDev03

Copy link
Copy Markdown
Collaborator

Closed to rerun the sdk-sync pipeline from scratch for API 2.0.0 (shorter cycle).

@MarketDataDev03
MarketDataDev03 deleted the sdk-sync/2.0.0-ffb34b7 branch October 5, 2026 15:49
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

sdk-sync: needs human sdk-sync stopped: a person has to look (see the PR's comments)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant