Skip to content

Implement the velocity-spi contract (capability mix-ins + ADR-0009 result DTO) - #4

Merged
wolpert merged 1 commit into
mainfrom
velocity-spi-contract
Jul 18, 2026
Merged

Implement the velocity-spi contract (capability mix-ins + ADR-0009 result DTO)#4
wolpert merged 1 commit into
mainfrom
velocity-spi-contract

Conversation

@wolpert

@wolpert wolpert commented Jul 18, 2026

Copy link
Copy Markdown
Contributor

Summary

The first real code behind the velocity-spi contract — the frozen core↔backend surface. This is
the design ADRs 0002/0003/0005/0006/0007/0008/0009 rendered as Java 21. Contract + tests only; no
backend implementation yet.

What's in it

34 types, serialization-neutral (only java.* + jspecify — no Jackson/Dagger/Dropwizard, ADR 0002):

  • Value types (com.codeheadsystems.velocity.spi.model): enums (AggregationType, WindowType,
    Exactness, ReadYourWriteLevel, ApplyStatus, FailureCode); keys (Namespace, Subject,
    Feature, Window, Aggregation, DistinctMember); sealed Intent (Count/Sum/DistinctIntent)
    • QueryTuple; the ADR-0009 result family — sealed FeatureResult (Success/Failure),
      FeatureValue, PerFeature, ApplyResult; seed types — sealed SeedAggregate, BucketValue; and
      BackendCapabilities (+ nested WindowSpec).
  • Interfaces (com.codeheadsystems.velocity.spi): VelocityBackend base; aggregation mix-ins
    CountStore/SumStore/DistinctStore; window markers SlidingSupport/TumblingSupport;
    SeedSupport.

Faithful to the frozen decisions

  • ADR 0009FeatureResult is a sealed Success|Failure; Failure carries a FailureCode, so
    "never a silent 0" is structurally enforced. apply* returns ApplyResult, so per-feature
    ApplyStatus (APPLIED|FAILED|SKIPPED, FR-34) — including backend-owned SKIPPED — is reachable.
  • ADR 0005BackendCapabilities rejects distinctHllSliding == true at construction;
    CARDINALITY_CAP_EXCEEDED present.
  • ADR 0006/0008HllDistinct is opaque, same-implementation-only; SeedAggregate is per-bucket
    (single-total impossible by construction).
  • ADR 0007 — read-your-write level is per-FeatureValue and on BackendCapabilities.

Testing

54 JUnit5/AssertJ tests across 10 classes, on every non-trivial value type: validation invariants
(dimension-iff-DISTINCT, positive window duration, WindowBounds order, scale-0 cents, intent↔feature
aggregation match, distinctHllSliding false), defensive-copy immutability, DistinctMember content
equality, and FeatureResult factories/pattern-matching. Value types live in **/model/** (coverage-
exempt) but are tested directly — nothing hides behind the carve-out.

Review

Implemented against a precise spec, then reviewed by the repo's change-validator agent (per the
CLAUDE.md working model). It returned CHANGES REQUESTED on one blocking item — apply* returned
List<FeatureResult>, orphaning ApplyResult/ApplyStatus and making SKIPPED unreportable — which
is fixed here (apply*ApplyResult). It approved everything else as faithful ADR encoding with
meaningful (non-padding) tests. ADR 0009's FeatureValue.value reconciled to uniform BigDecimal.

./gradlew :velocity-spi:buildBUILD SUCCESSFUL (spotless + SPDX, -Xlint:all -Werror, coverage
gate). Merging this PR freezes the contract.

🤖 Generated with Claude Code

…sult DTO)

First real code behind the SPI. Implements ADR 0003 (capability mix-ins,
backend-neutral intents, BackendCapabilities), ADR 0009 (the value-or-failure
FeatureResult / ApplyResult apply path), ADR 0007 (per-result read-your-write
level), and ADR 0005/0006/0008 (HLL-tumbling-only, distinct threshold, seed).

- 26 value types in ...spi.model (enums, keys, sealed Intent, the result family
  FeatureResult/FeatureValue/PerFeature/ApplyResult, sealed SeedAggregate,
  BackendCapabilities) + 8 interfaces in ...spi (VelocityBackend base,
  Count/Sum/DistinctStore mix-ins, Sliding/TumblingSupport markers, SeedSupport).
- Serialization-neutral: no Jackson/Dagger/Dropwizard (ADR 0002); jspecify
  null-hostile via package @NullMarked.
- apply* return ApplyResult so per-feature ApplyStatus (APPLIED|FAILED|SKIPPED,
  FR-34) is reachable, incl. backend-owned SKIPPED (resolves the change-validator
  blocking finding).
- 54 JUnit5/AssertJ tests over all non-trivial value-type logic; :velocity-spi:build
  is green (spotless + SPDX header, -Xlint:all -Werror, coverage gate).

Validated by the change-validator agent (one blocking finding on the apply-path
return type, fixed). ADR 0009 FeatureValue.value reconciled to uniform BigDecimal.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@wolpert
wolpert merged commit 3c5f8e2 into main Jul 18, 2026
3 checks passed
@wolpert
wolpert deleted the velocity-spi-contract branch July 18, 2026 23:40
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