Skip to content

§5 startup validation, §7 logging, §8 pre-flight#7

Closed
MarketDataDev03 wants to merge 2 commits into
06_retry_policiesfrom
07_logging_level
Closed

§5 startup validation, §7 logging, §8 pre-flight#7
MarketDataDev03 wants to merge 2 commits into
06_retry_policiesfrom
07_logging_level

Conversation

@MarketDataDev03

Copy link
Copy Markdown
Collaborator

Spec quick wins — §5 startup validation, §7 logging, §8 pre-flight

Wires up three spec-mandated behaviors that the previous PRs had left as seams: /user/ startup validation, MARKETDATA_LOGGING_LEVEL honoring + spec-shaped log format, and the pre-flight rate-limit check. All three were small (~150 LOC of prod) and ergonomically grouped — same constructor, same Configuration cascade, no architectural overlap with the retry work.


⚠️ Breaking change — constructor is no longer pure

Before this PR, the MarketDataClient constructors (both no-arg and 4-arg with validateOnStartup=true) were field-only: assign final fields, emit one INFO log line, return. No I/O, no blocking, no thrown exceptions.

After this PR, when validateOnStartup=true (the default) and the client is not in demo mode, the constructor performs a synchronous GET /user/ call. That changes the constructor's contract in three ways:

Aspect Before After
Latency microseconds up to 99 s (per-request timeout) on a slow/unreachable server
Exceptions thrown none AuthenticationError (401), NetworkError (connection failure / timeout)
Network dependency none requires reachability to the configured baseUrl

This is mandated by spec §5 ("Fail fast on invalid tokens") and aligns with the Python SDK. But existing consumer code that assumed construction couldn't fail will see new failure modes after upgrading.

Migration guide for consumers

Use case Recommended switch
Tests, CLI tools, or any short-lived runtime where the startup hit is undesirable Use the 4-arg ctor with validateOnStartup=false. The first authenticated request will still fail with AuthenticationError if the token is bad — just lazily instead of eagerly.
Serverless / cold-path code with strict latency budgets Same as above. The 99 s timeout is non-configurable in this PR.
Production long-lived processes Keep the default. The early failure is what you want — better to crash at boot than at the first business request.

Migration guide for the SDK's own test suite

All unit tests that construct MarketDataClient with the default URL must pass validateOnStartup=false, otherwise they reach api.marketdata.app over the network. Anything that genuinely needs the live-API smoke goes to src/integrationTest/ (gated by MARKETDATA_RUN_INTEGRATION_TESTS=true). The PR enforces this policy on the pre-existing tests — see "What changed" below.


Summary

  • §5 — /user/ startup validation: new HttpTransport.validateToken() (single-attempt, no retry — a 99 s + 1 s + 2 s retry chain on the constructor path is worse UX than failing fast). Wired into the MarketDataClient constructor.
  • §7 — Logging spec: new MarketDataLogFormatter (UTC ISO-8601 second resolution, {timestamp} - {logger_name} - {level} - {message} shape). configureLogging(Configuration) reads MARKETDATA_LOGGING_LEVEL from the cascade and applies it to the SDK's package-level logger. Idempotent; no-op when the env var is unset/blank/invalid.
  • §8 — Pre-flight rate-limit check: HttpTransport.executeOnce short-circuits with RateLimitError if the latest snapshot reports remaining <= 0. No-op for cold clients (snapshot starts null). The check fires before any permit is acquired and before any HTTP request is built.

What changed

New files

  • src/main/java/com/marketdata/sdk/MarketDataLogFormatter.java — package-private java.util.logging.Formatter. UTC second-resolution timestamp; (anonymous) placeholder when LogRecord.getLoggerName() returns null.
  • src/test/java/com/marketdata/sdk/MarketDataLogFormatterTest.java — formatter shape, MessageFormat placeholders, null logger name handling.
  • src/test/java/com/marketdata/sdk/MarketDataClientLoggingTest.javaconfigureLogging mechanics: env var application, case-insensitive level parsing, idempotency, no-op paths (unset / blank / invalid). Snapshots and restores the global logger state per test.
  • src/test/java/com/marketdata/sdk/MarketDataClientStartupValidationTest.java — end-to-end of /user/ validation against an in-process HttpServer: 200 path, 401 fail-fast, connection-refused fail-fast, validateOnStartup=false skip, demo-mode skip.
  • src/integrationTest/java/com/marketdata/sdk/MarketDataClientIT.java — moved smoke for the no-arg ctor that previously lived in unit tests but now requires the network.

Modified files

  • src/main/java/com/marketdata/sdk/HttpTransport.java — adds validateToken() and the pre-flight check in executeOnce. Both are <30 LOC inserts.
  • src/main/java/com/marketdata/sdk/MarketDataClient.javaconfigureLogging (static, package-private, called from the constructor before the first LOG.log); validation-on-startup call (single line at the end of the constructor); Javadoc on both constructors now spells out the side effects of validateOnStartup=true.
  • src/test/java/com/marketdata/sdk/HttpTransportRetryTest.java — two new pre-flight tests (preflightFailsImmediatelyWhenRemainingIsZero, preflightAllowsRequestWhenRemainingPositive).
  • src/test/java/com/marketdata/sdk/MarketDataClientTest.java — three pre-existing tests fixed: buildsWithExplicitToken and userAgentMatchesSpec now pass validateOnStartup=false; demoModeWhenNoTokenAvailable rewritten as demoModeWhenAllSourcesYieldNull using the 4-arg ctor + assumeTrue; noArgConstructorAppliesProductionDefaults removed (moved to IT — see new files).
  • CLAUDE.md — §5, §7, §8 moved from "Deliberately deferred" to "Already wired in" with implementation details. Latent-gaps section unchanged.
  • .gitignore — excludes .claude/ (personal Claude Code settings/commands).

@codecov

codecov Bot commented May 12, 2026

Copy link
Copy Markdown

The author of this PR, MarketDataDev03, is not an activated member of this organization on Codecov.
Please activate this user on Codecov to display this PR comment.
Coverage data is still being uploaded to Codecov.io for purposes of overall coverage calculations.
Please don't hesitate to email us at support@codecov.io with any questions.

@MarketDataDev03 MarketDataDev03 deleted the 07_logging_level branch June 9, 2026 18:56
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant