Skip to content

sdk-sync: API 2.0.0+ffb34b7 → sdk-java (minor) - #93

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

marketdata-sdk-sync[bot] wants to merge 5 commits into
mainfrom
sdk-sync/2.0.0-ffb34b7

Conversation

@marketdata-sdk-sync

@marketdata-sdk-sync marketdata-sdk-sync Bot commented Oct 13, 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: Only the two permitted test files were touched; gradle test --no-daemon --console=plain was run once and failed at compileTestJava, as required.

Summary:

  • Unit tests (OptionsResourceTest.java): added wire tests for the four new dte forms the delta enumerates — comma list (dteList), closed range (dteRange), and comparison (dteComparison, one test per StrikeFilter.Operator value: GT/GTE/LT/LTE) — plus a regression test proving the pre-existing dte(int) single-value factory still sends values above the new 36500-day bound unchanged (no new local check, no new error type), and validation tests for the new factories' empty-list, out-of-range, and min>max inputs.
  • Integration tests (OptionsIntegrationTest.java): added one live test per dte form (single, list, range, comparison) asserting decoded OptionQuote shape/bounds, not just status.
  • Chose to keep ExpirationFilter.dte(int) untouched and add new sealed-interface factories (dteList, dteRange, dteComparison reusing StrikeFilter.Operator) so the existing method's error behavior is preserved per repo convention — this is a design choice for phase 2 to implement, left undone here by design.

implement: All within allowed limits (main sources, test sources, docs, and the separately-built examples tree). No CHANGELOG.md edit, no commit made.

Implemented the dte type widening as three new ExpirationFilter sealed variants (DteList, DteRange, DteComparison, the last reusing StrikeFilter.Operator) alongside the unchanged Dte(int), so the pre-existing single-value call keeps its old behavior and error types.

  • Documentation: added each new factory's Javadoc, an interface-level note on the four dte syntaxes, and updated docs/options/chain.md's signature list and example.
  • Public member docs: every new public method, record, and constant carries its own doc comment.
  • Wire test per form/enum value: unit tests cover single (regression), list, range, and each of the four comparison operators individually.
  • Validation on every public path: each new record has a compact constructor (not just the static factory) enforcing non-negative/≤36500/min≤max/non-null, with direct-construction tests including an empty list, a null list, a null list element, and a null operator.
  • Coverage: no exclusions added; the only uncovered branches are pre-existing ones unrelated to this change (monthYear, formatStrike, a parser attribute check).
  • Examples/docs still correct: OptionsExample.java, README.md, and the Kotlin snippet in chain.md don't touch dte and remain accurate as-is; added a dteRange call to OptionsAdvancedExample.java (not compiled by this build) for coverage of the new forms.
  • Left unchanged, as they don't reference dte/ExpirationFilter or are historical: docs/adr/ADR-008-*.md (decision record, additive change doesn't contradict it), docs/client.md, docs/options/quotes.md (describes the unrelated response field), docs/options/{README,expirations,lookup}.md, docs/.sync-manifest.txt, docs/adr/ADR-006-*.md, MarketDataClient.java, OptionsCsvResource.java, OptionsChain.java, OptionsHtmlResource.java, JsonResponseParserTest.java, RequestValidationTest.java.
  • Outside my limits and left as-is: .github/ISSUE_TEMPLATE/bug.yml, build.gradle.kts, .github/BUG_FINDING.md — none reference dte specifically, so nothing is left wrong by this change.

changelog: Added ### Added section under ## [Unreleased] documenting the new DteList, DteRange, DteComparison sealed variants and their factory methods (dteList, dteRange, dteComparison), the MAX_DTE_DAYS constant, and the API 2.0.0 release that prompted them.

Files

  • CHANGELOG.md
  • docs/options/chain.md
  • examples/consumer-test/src/main/java/com/marketdata/examples/resources/OptionsAdvancedExample.java
  • src/integrationTest/java/com/marketdata/sdk/OptionsIntegrationTest.java
  • src/main/java/com/marketdata/sdk/OptionsResource.java
  • src/main/java/com/marketdata/sdk/options/ExpirationFilter.java
  • src/test/java/com/marketdata/sdk/OptionsResourceTest.java

Version

Public-surface change computed by the pipeline: minor

  • added: ExpirationFilter.MAX_DTE_DAYS
  • added: ExpirationFilter.dteList(int...)
  • added: ExpirationFilter.dteRange(int, int)
  • added: ExpirationFilter.dteComparison(StrikeFilter.Operator, int)
  • added: ExpirationFilter.DteList
  • added: ExpirationFilter.DteRange
  • added: ExpirationFilter.DteComparison

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); this pull request's CI does.

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) · 2 review(s) · 88 turns · 9,675,922 tokens · US$ 5.22 · item 5c097984-5f7b-401b-abba-235a3f417767

Agent runs
  • coder · claude-haiku-4-5-20251001, claude-sonnet-5 · 1,359,959 tokens (112,241 in, 1,217,016 cached, 30,702 out) · 20 turns · US$ 1.01 · 5 min 46 s
  • coder · claude-sonnet-5 · 7,282,007 tokens (56,701 in, 7,201,414 cached, 23,892 out) · 46 turns · US$ 1.91 · 6 min 05 s
  • reviewer · claude-haiku-4-5-20251001, claude-opus-5 · 712,722 tokens (97,379 in, 599,430 cached, 15,913 out) · 11 turns · US$ 1.72 · 4 min 00 s
  • security · claude-haiku-4-5-20251001, claude-sonnet-5 · 84,561 tokens (83,176 in, 0 cached, 1,385 out) · 2 turns · US$ 0.39 · 20 s
  • analyst · claude-haiku-4-5-20251001 · 141,714 tokens (36,391 in, 100,339 cached, 4,984 out) · 5 turns · US$ 0.12 · 49 s
  • changelog · claude-haiku-4-5-20251001 · 94,959 tokens (25,842 in, 67,305 cached, 1,812 out) · 4 turns · US$ 0.07 · 19 s

tests: Only the two permitted test files were touched; `gradle test --no-daemon --console=plain` was run once and failed at `compileTestJava`, as required.

Summary:
- Unit tests (`OptionsResourceTest.java`): added wire tests for the four new `dte` forms the delta enumerates — comma list (`dteList`), closed range (`dteRange`), and comparison (`dteComparison`, one test per `StrikeFilter.Operator` value: GT/GTE/LT/LTE) — plus a regression test proving the pre-existing `dte(int)` single-value factory still sends values above the new 36500-day bound unchanged (no new local check, no new error type), and validation tests for the new factories' empty-list, out-of-range, and min>max inputs.
- Integration tests (`OptionsIntegrationTest.java`): added one live test per `dte` form (single, list, range, comparison) asserting decoded `OptionQuote` shape/bounds, not just status.
- Chose to keep `ExpirationFilter.dte(int)` untouched and add new sealed-interface factories (`dteList`, `dteRange`, `dteComparison` reusing `StrikeFilter.Operator`) so the existing method's error behavior is preserved per repo convention — this is a design choice for phase 2 to implement, left undone here by design.

implement: All within allowed limits (main sources, test sources, docs, and the separately-built examples tree). No `CHANGELOG.md` edit, no commit made.

Implemented the `dte` type widening as three new `ExpirationFilter` sealed variants (`DteList`, `DteRange`, `DteComparison`, the last reusing `StrikeFilter.Operator`) alongside the unchanged `Dte(int)`, so the pre-existing single-value call keeps its old behavior and error types.

- Documentation: added each new factory's Javadoc, an interface-level note on the four `dte` syntaxes, and updated `docs/options/chain.md`'s signature list and example.
- Public member docs: every new public method, record, and constant carries its own doc comment.
- Wire test per form/enum value: unit tests cover single (regression), list, range, and each of the four comparison operators individually.
- Validation on every public path: each new record has a compact constructor (not just the static factory) enforcing non-negative/≤36500/min≤max/non-null, with direct-construction tests including an empty list, a null list, a null list element, and a null operator.
- Coverage: no exclusions added; the only uncovered branches are pre-existing ones unrelated to this change (`monthYear`, `formatStrike`, a parser attribute check).
- Examples/docs still correct: `OptionsExample.java`, `README.md`, and the Kotlin snippet in `chain.md` don't touch `dte` and remain accurate as-is; added a `dteRange` call to `OptionsAdvancedExample.java` (not compiled by this build) for coverage of the new forms.
- Left unchanged, as they don't reference `dte`/`ExpirationFilter` or are historical: `docs/adr/ADR-008-*.md` (decision record, additive change doesn't contradict it), `docs/client.md`, `docs/options/quotes.md` (describes the unrelated response field), `docs/options/{README,expirations,lookup}.md`, `docs/.sync-manifest.txt`, `docs/adr/ADR-006-*.md`, `MarketDataClient.java`, `OptionsCsvResource.java`, `OptionsChain.java`, `OptionsHtmlResource.java`, `JsonResponseParserTest.java`, `RequestValidationTest.java`.
- Outside my limits and left as-is: `.github/ISSUE_TEMPLATE/bug.yml`, `build.gradle.kts`, `.github/BUG_FINDING.md` — none reference `dte` specifically, so nothing is left wrong by this change.

changelog: Added `### Added` section under `## [Unreleased]` documenting the new `DteList`, `DteRange`, `DteComparison` sealed variants and their factory methods (`dteList`, `dteRange`, `dteComparison`), the `MAX_DTE_DAYS` constant, and the API 2.0.0 release that prompted them.
@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 Oct 13, 2026
@marketdata-sdk-sync

marketdata-sdk-sync Bot commented Oct 13, 2026 •

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-13 15:04:41Z
Outcome done

Changes in the API surface

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

1. tests

Coder (20 turns, US$ 1.01, 5 min 46 s):

Only the two permitted test files were touched; gradle test --no-daemon --console=plain was run once and failed at compileTestJava, as required.

Summary:

  • Unit tests (OptionsResourceTest.java): added wire tests for the four new dte forms the delta enumerates — comma list (dteList), closed range (dteRange), and comparison (dteComparison, one test per StrikeFilter.Operator value: GT/GTE/LT/LTE) — plus a regression test proving the pre-existing dte(int) single-value factory still sends values above the new 36500-day bound unchanged (no new local check, no new error type), and validation tests for the new factories' empty-list, out-of-range, and min>max inputs.
  • Integration tests (OptionsIntegrationTest.java): added one live test per dte form (single, list, range, comparison) asserting decoded OptionQuote shape/bounds, not just status.
  • Chose to keep ExpirationFilter.dte(int) untouched and add new sealed-interface factories (dteList, dteRange, dteComparison reusing StrikeFilter.Operator) so the existing method's error behavior is preserved per repo convention — this is a design choice for phase 2 to implement, left undone here by design.

Gates:

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

2. implement

Coder (46 turns, US$ 1.91, 6 min 05 s):

All within allowed limits (main sources, test sources, docs, and the separately-built examples tree). No CHANGELOG.md edit, no commit made.

Implemented the dte type widening as three new ExpirationFilter sealed variants (DteList, DteRange, DteComparison, the last reusing StrikeFilter.Operator) alongside the unchanged Dte(int), so the pre-existing single-value call keeps its old behavior and error types.

  • Documentation: added each new factory's Javadoc, an interface-level note on the four dte syntaxes, and updated docs/options/chain.md's signature list and example.
  • Public member docs: every new public method, record, and constant carries its own doc comment.
  • Wire test per form/enum value: unit tests cover single (regression), list, range, and each of the four comparison operators individually.
  • Validation on every public path: each new record has a compact constructor (not just the static factory) enforcing non-negative/≤36500/min≤max/non-null, with direct-construction tests including an empty list, a null list, a null list element, and a null operator.
  • Coverage: no exclusions added; the only uncovered branches are pre-existing ones unrelated to this change (monthYear, formatStrike, a parser attribute check).
  • Examples/docs still correct: OptionsExample.java, README.md, and the Kotlin snippet in chain.md don't touch dte and remain accurate as-is; added a dteRange call to OptionsAdvancedExample.java (not compiled by this build) for coverage of the new forms.
  • Left unchanged, as they don't reference dte/ExpirationFilter or are historical: docs/adr/ADR-008-*.md (decision record, additive change doesn't contradict it), docs/client.md, docs/options/quotes.md (describes the unrelated response field), docs/options/{README,expirations,lookup}.md, docs/.sync-manifest.txt, docs/adr/ADR-006-*.md, MarketDataClient.java, OptionsCsvResource.java, OptionsChain.java, OptionsHtmlResource.java, JsonResponseParserTest.java, RequestValidationTest.java.
  • Outside my limits and left as-is: .github/ISSUE_TEMPLATE/bug.yml, build.gradle.kts, .github/BUG_FINDING.md — none reference dte specifically, so nothing is left wrong by this change.

Gates:

  • tests, attempt 1: passed (7 s)
  • build, attempt 1: passed (7 s)

3. review 1

Reviewer (11 turns, US$ 1.72, 4 min 00 s): approved

The change models the widened dte as three new sealed ExpirationFilter variants (DteList, DteRange, DteComparison) alongside the untouched dte(int), wires each to its wire syntax, and covers all four forms with wire tests (including every Operator value), direct-construction validation tests, live integration tests and docs. Public surface is purely additive (new permitted subtypes + new MAX_DTE_DAYS constant), so version impact: minor. Only documentation-wording and a style duplication remain.

  • [minor] src/main/java/com/marketdata/sdk/options/ExpirationFilter.java:38 — The javadoc misstates the validation contract: MAX_DTE_DAYS is described as "shared by every dte syntax", and dteList/dteRange/dteComparison say each value is "validated the same way as dte(int)", but dte(int) enforces only non-negativity and deliberately has no 36500 cap (see the comment on record Dte). Reword so the cap is stated as applying to the three new forms only.
  • [minor] src/main/java/com/marketdata/sdk/OptionsResource.java:353 — joinDays hand-rolls comma joining, while the repository joins list-valued query params with String.join(",", …) (RequestSpec.java:111, StocksResource.java:362). Replace it with v.days().stream().map(String::valueOf).collect(Collectors.joining(",")) and drop the helper.

4. security

Security (2 turns, US$ 0.39, 20 s): approved

The change only adds new ExpirationFilter variants (DteList, DteRange, DteComparison) and wires them into query-string construction via OptionsResource, all operating on validated primitive ints and a closed enum (StrikeFilter.Operator) for the operator prefix. There is no string interpolation of untrusted input, no new credential handling, no logging change, no deserialization or build/CI change, and existing query-encoding (seen URL-encoding ">=" etc. in tests) is unaffected. No security issues found in this diff.

  • no findings

5. assess

Analyst (5 turns, US$ 0.12, 49 s) — public surface:

The change expands the days-to-expiration filter with three new syntax variants: comma-separated list, closed range, and comparison operators. All additions are backward-compatible; the existing dte(int) method retains its original validation behavior. New sealed subtypes DteList, DteRange, and DteComparison model the four wire syntaxes as distinct variants.

  • added: ExpirationFilter.MAX_DTE_DAYS
  • added: ExpirationFilter.dteList(int...)
  • added: ExpirationFilter.dteRange(int, int)
  • added: ExpirationFilter.dteComparison(StrikeFilter.Operator, int)
  • added: ExpirationFilter.DteList
  • added: ExpirationFilter.DteRange
  • added: ExpirationFilter.DteComparison

Computed by the pipeline: minor; changelog entry written

6. changelog

Coder (4 turns, US$ 0.07, 19 s):

Added ### Added section under ## [Unreleased] documenting the new DteList, DteRange, DteComparison sealed variants and their factory methods (dteList, dteRange, dteComparison), the MAX_DTE_DAYS constant, and the API 2.0.0 release that prompted them.

Gates:

  • build, attempt 1: passed (7 s)

Totals

  • Bump: minor
  • Coder runs: 3
  • Review runs: 2
  • Gates run: 4 (1 failed)
  • Files changed by the agent: 7
  • Turns: 88
  • Tokens: 9,675,922
  • Estimated cost: US$ 5.22
  • Time: 18 min 15 s (agents 17 min 19 s, gates 29 s)

Agent runs

  • coder · claude-haiku-4-5-20251001, claude-sonnet-5 · 1,359,959 tokens (112,241 in, 1,217,016 cached, 30,702 out) · 20 turns · US$ 1.01 · 5 min 46 s
  • coder · claude-sonnet-5 · 7,282,007 tokens (56,701 in, 7,201,414 cached, 23,892 out) · 46 turns · US$ 1.91 · 6 min 05 s
  • reviewer · claude-haiku-4-5-20251001, claude-opus-5 · 712,722 tokens (97,379 in, 599,430 cached, 15,913 out) · 11 turns · US$ 1.72 · 4 min 00 s
  • security · claude-haiku-4-5-20251001, claude-sonnet-5 · 84,561 tokens (83,176 in, 0 cached, 1,385 out) · 2 turns · US$ 0.39 · 20 s
  • analyst · claude-haiku-4-5-20251001 · 141,714 tokens (36,391 in, 100,339 cached, 4,984 out) · 5 turns · US$ 0.12 · 49 s
  • changelog · claude-haiku-4-5-20251001 · 94,959 tokens (25,842 in, 67,305 cached, 1,812 out) · 4 turns · US$ 0.07 · 19 s

Code review fix 1 — 2026-10-13 15:23:10Z

Outcome: done

Time: 2 min 48 s (agents 2 min 34 s, gates 14 s)

1. code review fix 1

The code review asked for changes:

  • [Should fix] Document the differing DTE validation (src/main/java/com/marketdata/sdk/options/ExpirationFilter.java:38-89)
    The public documentation says the 36500-day bound is shared by every syntax and that the new forms validate like dte(int), but dte(int) deliberately checks only for negative values. State that the three new forms enforce the API maximum locally while the legacy single-value factory does not, so callers can predict whether they receive IllegalArgumentException or a server error.
    Evidence: Contradictory lines: “Upper bound on a single dte value, shared by every dte syntax” and “every value is validated the same way as dte(int),” while dte(int) checks only days < 0 and the new variants call validateDteValue, which also rejects values above 36500.

Coder (15 turns, US$ 0.31, 1 min 31 s):

Finding: Document the differing DTE validation (ExpirationFilter.java) — fixed. Reworded the MAX_DTE_DAYS javadoc, dte(int)'s javadoc, and each of dteList/dteRange/dteComparison's javadocs to state plainly that only the three new forms enforce the 36500-day cap locally, while dte(int) checks only non-negativity and lets an over-cap value reach the API as a server-side rejection. No behavior, public surface, or test changed — doc wording only, so CHANGELOG.md is left as is. gradle test and gradle build both pass (the latter required a spotlessApply re-wrap of the new javadoc comment to satisfy formatting).

Gates:

  • tests, attempt 1: passed (7 s)
  • build, attempt 1: passed (7 s)

2. review 1

Reviewer (8 turns, US$ 0.42, 59 s): approved

Documentation-only fix; it accurately resolves the flagged contradiction — the Javadoc on MAX_DTE_DAYS, dte(int), dteList, dteRange and dteComparison now matches the code (dte(int) checks only days < 0, while the three new forms enforce the 36500 bound in their record constructors). No behaviour, public signature or test is touched, so no new test or CHANGELOG break is required. One residual inaccuracy remains: CHANGELOG.md still calls MAX_DTE_DAYS a "shared" bound.

  • [minor] CHANGELOG.md:16 — The entry still says "a shared upper bound MAX_DTE_DAYS limits values per the API", which repeats the misstatement the fix removed from the Javadoc — dte(int) does not enforce it. Reword to say the bound is enforced only by dteList, dteRange and dteComparison.

3. security

Security (2 turns, US$ 0.10, 4 s): approved

The fix only adds/edits Javadoc comments in ExpirationFilter.java to document the asymmetric validation between the legacy dte(int) and the new dteList/dteRange/dteComparison factories; no executable code changed. This is a documentation-only change with no new input handling, request construction, or security-relevant behavior.

  • no findings

Code review fix 2 — 2026-10-13 15:36:56Z

Outcome: done

Time: 3 min 16 s (agents 3 min 03 s, gates 13 s)

1. code review fix 2

The code review asked for changes:

  • [Should fix] Live list test does not prove filtering (src/integrationTest/java/com/marketdata/sdk/OptionsIntegrationTest.java:171-175)
    Allowing one distinct expiration means this test also passes if the server ignores the list or receives only one value. Assert results corresponding to the requested 15, 30, and 45-day targets, or otherwise require multiple distinct matching expirations.
    Evidence: assertThat(distinctExpirations)...isBetween(1L, 3L);

Coder (11 turns, US$ 0.29, 1 min 52 s):

This fix is doc/test-only (no public surface or behavior change), so CHANGELOG.md is left as-is.

[Should fix] Live list test does not prove filtering — fixed in OptionsIntegrationTest.java. The test now independently resolves the nearest expiration for each of 15, 30, and 45 days via three single-value dte() calls, then asserts the dteList(15, 30, 45) chain's distinct expirations equal exactly that expected set — so the test fails if the server ignores the list or returns a different set, rather than merely bounding the count to 1–3. gradle test --no-daemon --console=plain and gradle build --no-daemon --console=plain both pass (the latter also compiles the integration-test source set); the new/extra live calls are not run here per the brief.

Gates:

  • tests, attempt 1: passed (6 s)
  • build, attempt 1: passed (7 s)

2. review 1

Reviewer (7 turns, US$ 0.49, 1 min 11 s): approved

The fix replaces the weak isBetween(1L, 3L) bound with set equality against the three expirations independently resolved by single-value dte(15/30/45), which is the first alternative the finding offered and matches what the API description specifies for the list form. It weakens nothing and touches only the integration suite, so no CHANGELOG or docs follow-up is required (SDK rule 3). Two residual issues remain, both minor: the oracle is derived with the same parameter under test, and expiration() is @Nullable but dereferenced unguarded.

  • [minor] src/integrationTest/java/com/marketdata/sdk/OptionsIntegrationTest.java:164 — The expected set is resolved with the same dte parameter under test, so a server that ignored dte for both the single and list forms would return the front-month expiration from all four calls and the assertion would still pass. Add assertThat(expectedExpirations).hasSizeGreaterThan(1) before the chain call so the test also proves the server distinguishes the requested values.
  • [minor] src/integrationTest/java/com/marketdata/sdk/OptionsIntegrationTest.java:181 — OptionQuote.expiration() is @Nullable (OptionQuote.java:30), so q.expiration().toLocalDate() here and chain.get(0).expiration().toLocalDate() in the helper fail with a bare NullPointerException instead of a readable assertion if a row omits the column. Use the Objects.requireNonNull pattern this file already applies to the nullable optionSymbol() in quotesFansOutToMultipleContracts.

3. security

The pipeline:

  • the security reviewer did not run: the fix only touched tests and documentation

CI repair 1 — 2026-10-13 15:46:06Z

Outcome: done

Time: 8 min 35 s (agents 8 min 22 s, gates 13 s)

1. CI fix 1

The repository's CI failed:

Tests passed: failure

##[group]Run echo "gate said code=${CODE:-<nothing: the gate itself failed>}"
�[36;1mecho "gate said code=${CODE:-<nothing: the gate itself failed>}"�[0m
�[36;1m# one this workflow's gate asked for. If the gate failed, CODE is empty,�[0m
�[36;1m# FAILURE always fails: that includes the job refusing to run without�[0m
##[error]Process completed with exit code 1.
…
Current runner version: '2.337.0'
##[group]Runner Image Provisioner
Hosted Compute Agent
Version: 20261002.596
Commit: c3d12f3313a95f25162a1503be624f3b0617f8c0
Build Date: 2026-10-02T22:28:27Z
Worker ID: {52163367-0450-4c3c-99d9-bc2dcc26c999}
Region: eastus
Cloud: Azure
##[endgroup]
##[group]Operating System
Ubuntu
24.04.5
LTS
##[endgroup]
##[group]Runner Image
Image: ubuntu-24.04
Version: 20261004.327.1
Included Software: https://github.com/actions/runner-images/blob/ubuntu24/20261004.327/images/ubuntu/Ubuntu2404-Readme.md
Image Release: https://github.com/actions/runner-images/releases/tag/ubuntu24%2F20261004.327
##[endgroup]
##[group]GITHUB_TOKEN Permissions
Contents: read
Metadata: read
##[endgroup]
Secret source: Actions
Cache mode: write
Prepare workflow directory
Prepare all required actions
Complete job name: Tests passed
##[group]Run echo "gate said code=${CODE:-<nothing: the gate itself failed>}"
�[36;1mecho "gate said code=${CODE:-<nothing: the gate itself failed>}"�[0m

Coder (35 turns, US$ 1.11, 6 min 35 s):

CI's integration job failed because chainDteCommaListSelectsClosestExpirationPerValue threw an AssertionError at line 202, inside its nearestExpirationForDte helper's isNotEmpty() check — one of three separate live dte(15)/dte(30)/dte(45) round trips used as the test's oracle came back empty against real data. I rewrote the oracle to derive the expected nearest expirations locally from a single ExpirationFilter.all() chain (already proven non-empty by the neighboring chainExpirationAllSpansMultipleExpirations test) instead of three extra live calls, removing the dependency on the single-value dte() form sharing the list form's tie-breaking and removing two round trips that could land on a different trading moment than the call under test. This also fixes both residual review findings from round 2: the oracle is no longer derived from the same parameter under test, and nullable expiration() dereferences now go through Objects.requireNonNull. The change is test-only (no production code, no public-surface or behavior change), so CHANGELOG.md is left as is; gradle test --no-daemon --console=plain and gradle build --no-daemon --console=plain both pass.

Gates:

  • tests, attempt 1: passed (6 s)
  • build, attempt 1: passed (7 s)

2. review 1

Reviewer (5 turns, US$ 0.65, 1 min 47 s): approved

The repair replaces the failing oracle (three extra single-value dte() calls) with a locally-derived nearest-expiration computation over one expiration=all chain, which is the right shape of fix: it removes the untested assumption that the single-value and list forms resolve identically while still proving dteList reaches the wire and narrows the chain (a list silently ignored, or only its first value honoured, would still fail the set equality and the added size>1 guard). No public surface, docs or CHANGELOG impact — the diff is test-only — and the single-value regression test and the other dte live tests are untouched. One residual risk noted below.

  • [minor] src/integrationTest/java/com/marketdata/sdk/OptionsIntegrationTest.java:211 — The oracle reimplements the server's "closest expiration per value" rule (absolute distance, first-row tie-break) and still compares two separate live responses, so the exact-set assertion can flip if the server's list semantics are not plain absolute-nearest or if an Eastern day boundary falls between the two calls and shifts every dte by one. Since the SDK-side guarantee (the wire form of dte=15,30,45) is already covered by the unit wire test, consider the weaker shape assertion this class documents elsewhere — actual expirations are a subset of the full chain's, more than one and at most three — if this fails again.

3. security

The pipeline:

  • the security reviewer did not run: the fix only touched tests and documentation

CI repair 2 — 2026-10-13 16:00:06Z

Outcome: done

Time: 3 min 50 s (agents 3 min 37 s, gates 13 s)

1. CI fix 2

The repository's CI failed:

Tests passed: failure

##[group]Run echo "gate said code=${CODE:-<nothing: the gate itself failed>}"
�[36;1mecho "gate said code=${CODE:-<nothing: the gate itself failed>}"�[0m
�[36;1m# one this workflow's gate asked for. If the gate failed, CODE is empty,�[0m
�[36;1m# FAILURE always fails: that includes the job refusing to run without�[0m
##[error]Process completed with exit code 1.
…
Current runner version: '2.337.0'
##[group]Runner Image Provisioner
Hosted Compute Agent
Version: 20261002.596
Commit: c3d12f3313a95f25162a1503be624f3b0617f8c0
Build Date: 2026-10-02T22:28:27Z
Worker ID: {fadbc4f6-6886-4df9-a606-9d91571a5ab4}
Region: westus2
Cloud: Azure
##[endgroup]
##[group]Operating System
Ubuntu
24.04.5
LTS
##[endgroup]
##[group]Runner Image
Image: ubuntu-24.04
Version: 20261004.327.1
Included Software: https://github.com/actions/runner-images/blob/ubuntu24/20261004.327/images/ubuntu/Ubuntu2404-Readme.md
Image Release: https://github.com/actions/runner-images/releases/tag/ubuntu24%2F20261004.327
##[endgroup]
##[group]GITHUB_TOKEN Permissions
Contents: read
Metadata: read
##[endgroup]
Secret source: Actions
Cache mode: write
Prepare workflow directory
Prepare all required actions
Complete job name: Tests passed
##[group]Run echo "gate said code=${CODE:-<nothing: the gate itself failed>}"
�[36;1mecho "gate said code=${CODE:-<nothing: the gate itself failed>}"�[0m

Coder (14 turns, US$ 0.44, 2 min 23 s):

gradle test and gradle build both pass. Change is within src/integrationTest/**.

CI failed in the integration job (Integration tests (live API, JDK 17)) at OptionsIntegrationTest.chainDteCommaListSelectsClosestExpirationPerValue (line 209, isEqualTo(expectedExpirations)): the oracle reimplemented the server's nearest-expiration tie-break (absolute distance, first-row) locally, and that doesn't reliably match the server's own choice — exactly the residual risk the prior repair round's reviewer had already flagged. I replaced the exact-equality oracle with the shape assertion that reviewer suggested as the fallback: actual expirations must be a subset of the full all() chain's expirations, number more than one, and at most three — this proves the list reaches the server and narrows per-value without assuming its tie-break algorithm. Removed the now-unused nearestExpirationTo helper; no production code, public surface, or CHANGELOG change, since this is test-only.

Gates:

  • tests, attempt 1: passed (7 s)
  • build, attempt 1: passed (6 s)

2. review 1

Reviewer (7 turns, US$ 0.57, 1 min 14 s): approved

The failed integration test compared the server's dte=15,30,45 selection against a local absolute-distance reimplementation of the server's tie-break; the repair drops that oracle and asserts shape instead (subset of the full chain, >1 and <=3 distinct expirations). That is the correct fix, not a cover-up: the unit wire test (OptionsResourceTest.java:1015) proves the SDK sends ?dte=15,30,45, and the relaxed assertions still fail if dte were dropped or honored for only one value. No production code, docs, examples or public surface changed, so no CHANGELOG impact; the removed nearestExpirationTo helper had no other caller and no imports go unused.

  • [minor] src/integrationTest/java/com/marketdata/sdk/OptionsIntegrationTest.java:201 — The test now accepts any 2–3 expirations drawn from the chain, so a server that selected, say, the three furthest expirations would pass while the method name still claims "closest per value". A deterministic middle ground that does not reimplement the tie-break: assert each returned row's dte is within a generous window of one of 15/30/45 (e.g. ±10 days).

3. security

The pipeline:

  • the security reviewer did not run: the fix only touched tests and documentation

@codecov

codecov Bot commented Oct 13, 2026 •

Copy link
Copy Markdown

Codecov Report

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

Additional details and impacted files
@@             Coverage Diff              @@
##               main      #93      +/-   ##
============================================
+ Coverage     98.27%   98.30%   +0.02%     
- Complexity     1043     1056      +13     
============================================
  Files           123      123              
  Lines          2606     2649      +43     
  Branches        301      311      +10     
============================================
+ Hits           2561     2604      +43     
  Partials         45       45              
Files with missing lines Coverage Δ
.../main/java/com/marketdata/sdk/OptionsResource.java 98.61% <100.00%> (+0.08%) ⬆️
...a/com/marketdata/sdk/options/ExpirationFilter.java 98.03% <100.00%> (+3.03%) ⬆️

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 682a304...e179088. Read the comment docs.

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

@marketdata-code-review

marketdata-code-review Bot commented Oct 13, 2026 •

Copy link
Copy Markdown

✅ Ready — Code review

Version impact: minor; the change adds DTE list, range, and comparison filters without altering existing public calls. This is API capability support, not a shared-logic defect requiring sibling SDK follow-up.

Rating patch 5/6 (solid) · proof 6/6 (comprehensive) · overall 5/6

Since last review

  • Resolved: a6de3e4f
  • 0 still open, 0 new

Reviewed e179088 · revision 3 · codex (gpt-5.6-sol) · claude unavailable · rules: default, sdk

sdk-bot added 4 commits October 13, 2026 11:31
code review fix 1: Finding: Document the differing DTE validation (`ExpirationFilter.java`) — fixed. Reworded the `MAX_DTE_DAYS` javadoc, `dte(int)`'s javadoc, and each of `dteList`/`dteRange`/`dteComparison`'s javadocs to state plainly that only the three new forms enforce the 36500-day cap locally, while `dte(int)` checks only non-negativity and lets an over-cap value reach the API as a server-side rejection. No behavior, public surface, or test changed — doc wording only, so `CHANGELOG.md` is left as is. `gradle test` and `gradle build` both pass (the latter required a `spotlessApply` re-wrap of the new javadoc comment to satisfy formatting).
code review fix 2: This fix is doc/test-only (no public surface or behavior change), so `CHANGELOG.md` is left as-is.

[Should fix] Live list test does not prove filtering — fixed in `OptionsIntegrationTest.java`. The test now independently resolves the nearest expiration for each of 15, 30, and 45 days via three single-value `dte()` calls, then asserts the `dteList(15, 30, 45)` chain's distinct expirations equal exactly that expected set — so the test fails if the server ignores the list or returns a different set, rather than merely bounding the count to 1–3. `gradle test --no-daemon --console=plain` and `gradle build --no-daemon --console=plain` both pass (the latter also compiles the integration-test source set); the new/extra live calls are not run here per the brief.
CI fix 1: CI's `integration` job failed because `chainDteCommaListSelectsClosestExpirationPerValue` threw an `AssertionError` at line 202, inside its `nearestExpirationForDte` helper's `isNotEmpty()` check — one of three separate live `dte(15)`/`dte(30)`/`dte(45)` round trips used as the test's oracle came back empty against real data. I rewrote the oracle to derive the expected nearest expirations locally from a single `ExpirationFilter.all()` chain (already proven non-empty by the neighboring `chainExpirationAllSpansMultipleExpirations` test) instead of three extra live calls, removing the dependency on the single-value `dte()` form sharing the list form's tie-breaking and removing two round trips that could land on a different trading moment than the call under test. This also fixes both residual review findings from round 2: the oracle is no longer derived from the same parameter under test, and nullable `expiration()` dereferences now go through `Objects.requireNonNull`. The change is test-only (no production code, no public-surface or behavior change), so `CHANGELOG.md` is left as is; `gradle test --no-daemon --console=plain` and `gradle build --no-daemon --console=plain` both pass.
CI fix 2: `gradle test` and `gradle build` both pass. Change is within `src/integrationTest/`.

CI failed in the `integration` job (`Integration tests (live API, JDK 17)`) at `OptionsIntegrationTest.chainDteCommaListSelectsClosestExpirationPerValue` (line 209, `isEqualTo(expectedExpirations)`): the oracle reimplemented the server's nearest-expiration tie-break (absolute distance, first-row) locally, and that doesn't reliably match the server's own choice — exactly the residual risk the prior repair round's reviewer had already flagged. I replaced the exact-equality oracle with the shape assertion that reviewer suggested as the fallback: actual expirations must be a subset of the full `all()` chain's expirations, number more than one, and at most three — this proves the list reaches the server and narrows per-value without assuming its tie-break algorithm. Removed the now-unused `nearestExpirationTo` helper; no production code, public surface, or CHANGELOG change, since this is test-only.
@MarketDataDev03

Copy link
Copy Markdown
Collaborator

Closing to re-run the pipeline for this API release from scratch.

@MarketDataDev03
MarketDataDev03 deleted the sdk-sync/2.0.0-ffb34b7 branch October 14, 2026 12:33
@marketdata-sdk-sync marketdata-sdk-sync Bot removed the sdk-sync: in progress sdk-sync is still working on this PR: CI, code review, fixes label Oct 14, 2026
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 review: ready

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant