Implement the velocity-spi contract (capability mix-ins + ADR-0009 result DTO) - #4
Merged
Conversation
…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>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
The first real code behind the
velocity-spicontract — the frozen core↔backend surface. This isthe 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):com.codeheadsystems.velocity.spi.model): enums (AggregationType,WindowType,Exactness,ReadYourWriteLevel,ApplyStatus,FailureCode); keys (Namespace,Subject,Feature,Window,Aggregation,DistinctMember); sealedIntent(Count/Sum/DistinctIntent)QueryTuple; the ADR-0009 result family — sealedFeatureResult(Success/Failure),FeatureValue,PerFeature,ApplyResult; seed types — sealedSeedAggregate,BucketValue; andBackendCapabilities(+ nestedWindowSpec).com.codeheadsystems.velocity.spi):VelocityBackendbase; aggregation mix-insCountStore/SumStore/DistinctStore; window markersSlidingSupport/TumblingSupport;SeedSupport.Faithful to the frozen decisions
FeatureResultis a sealedSuccess|Failure;Failurecarries aFailureCode, so"never a silent
0" is structurally enforced.apply*returnsApplyResult, so per-featureApplyStatus(APPLIED|FAILED|SKIPPED, FR-34) — including backend-ownedSKIPPED— is reachable.BackendCapabilitiesrejectsdistinctHllSliding == trueat construction;CARDINALITY_CAP_EXCEEDEDpresent.HllDistinctis opaque, same-implementation-only;SeedAggregateis per-bucket(single-total impossible by construction).
FeatureValueand onBackendCapabilities.Testing
54 JUnit5/AssertJ tests across 10 classes, on every non-trivial value type: validation invariants
(dimension-iff-DISTINCT, positive window duration,
WindowBoundsorder, scale-0 cents, intent↔featureaggregation match,
distinctHllSlidingfalse), defensive-copy immutability,DistinctMembercontentequality, and
FeatureResultfactories/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-validatoragent (per theCLAUDE.md working model). It returned CHANGES REQUESTED on one blocking item —
apply*returnedList<FeatureResult>, orphaningApplyResult/ApplyStatusand makingSKIPPEDunreportable — whichis fixed here (
apply*→ApplyResult). It approved everything else as faithful ADR encoding withmeaningful (non-padding) tests. ADR 0009's
FeatureValue.valuereconciled to uniformBigDecimal../gradlew :velocity-spi:build→ BUILD SUCCESSFUL (spotless + SPDX,-Xlint:all -Werror, coveragegate). Merging this PR freezes the contract.
🤖 Generated with Claude Code