Skip to content

Introduce tryAlter for preventive state validation (PR-B1)#1643

Merged
alexander-yevsyukov merged 5 commits into
masterfrom
de-event-sourcing-impl-1
Jul 6, 2026
Merged

Introduce tryAlter for preventive state validation (PR-B1)#1643
alexander-yevsyukov merged 5 commits into
masterfrom
de-event-sourcing-impl-1

Conversation

@alexander-yevsyukov

Copy link
Copy Markdown
Contributor

Implements PR-B1 of the de-event-sourcing delivery plan per ADR 0001, D9 — the additive, non-breaking slice of Phase B. ProcessManagers benefit immediately; aggregates adopt the same idiom with the PR-B2 cutover.

What changed

  • New tryAlter extension for TransactionalEntity (TransactionalEntityExts.kt), next to update {} / alter {}validate-before-apply:

    1. runs the mutation block on a scratch copy (clone()) of the live builder;
    2. validates the candidate via checkEntityState — the same path the transaction commit uses, so a clean probe verdict cannot be contradicted at commit;
    3. merges into the live builder only when clean (clear() + mergeFrom, the Transaction.initAll pattern); otherwise returns the violations and leaves the live builder untouched.

    Setter-thrown io.spine.validation.ValidationExceptions — (set_once) today — are folded into the returned list, so setter-time and build-time constraints surface uniformly. Any other exception propagates unchanged.

  • The two decisions ADR D9 deferred to PR-B1, now recorded in the ADR implementation notes:

    • Merge mechanics: clear() + mergeFrom(candidate) — no new Transaction mutator needed.
    • Java access: the existing TransactionalEntityExtensions facade. A same-name protected member taking Consumer<B> would shadow the extension in Kotlin subclasses (a member beats an extension in overload resolution), breaking the tryAlter { … } receiver-lambda idiom at every Kotlin call site.
  • Tests (12, all green):

    • TransactionalEntityExtensionsSpec.kt — the ADR-listed cases: clean apply, violation return with field_path, (set_once) folding, consecutive-call composition, exception propagation, and no-trace-after-commit (changed() == false — the exact store-gate predicate). Plus two dispatch-level tests through a real ProcessManagerRepository: a clean call is stored; a withheld change leaves the process manager unstored, with persisted state and version unchanged.
    • TransactionalEntityExtensionsJavaSpec.java — Java-bridge suite pinning the facade usage (tryAlter(entity, b -> { …; return Unit.INSTANCE; })).
    • Fixtures: StockKeeper process manager + spine/test/tryalter protos mirroring the ADR D9 samples (in_stock with (min).value = "0", (set_once) vendor), so the tests double as documentation of the receptor idioms.
  • Validation dependency consumed at 2.0.0-SNAPSHOT.447 (bumped on this branch), carrying ValidatingBuilder.validate() from Add validate() probe to ValidatingBuilder validation#316 (the D9 amendment companion). Verified present in the artifact; linked from the tryAlter KDoc. tryAlter itself does not depend on it.

Reviewer notes

  • tryAlter reaches the protected builder() / checkEntityState via same-package access, exactly like the existing update/alter (hence non-inline, per the API note).
  • The Java spec upcasts StockKeeper to TransactionalEntity to reach package-private members — javac does not inherit package-private members across packages (Kotlin resolves them by declaring-class package).
  • Verification: ./gradlew clean build --no-build-cache + ./gradlew build dokkaGenerate — green; reviewers spine-code-review, kotlin-engineer, review-docs, dependency-audit — all approve.
  • The version bump (2.0.0-SNAPSHOT.401) and regenerated dependency reports are separate commits, per convention.

🤖 Generated with Claude Code

alexander-yevsyukov and others added 5 commits July 6, 2026 16:06
Implement PR-B1 of the de-event-sourcing plan:

* Add the `tryAlter` extension for `TransactionalEntity` — validate-before-apply
  on a scratch copy of the live builder, returning `List<ConstraintViolation>`.
  Setter-thrown `ValidationException`s (e.g. `(set_once)`) are folded into
  the returned list; a failed attempt never dirties the live builder.
* Fix the two decisions deferred to PR-B1 in ADR D9: merge mechanics
  (`clear()` + `mergeFrom`, the `Transaction.initAll` pattern) and Java-caller
  access (the `TransactionalEntityExtensions` facade; a same-name `protected`
  member would shadow the extension in Kotlin overload resolution).
* Cover the ADR-listed cases with Kotlin tests, including dispatch-level
  proof via a real `ProcessManagerRepository` that a withheld change is not
  stored, and a Java-bridge spec pinning the facade usage.
* Add the `StockKeeper` fixture context mirroring the ADR D9 samples.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a validate-before-apply state mutation helper (tryAlter) for TransactionalEntity, enabling receptors (immediately: ProcessManagers; later: aggregates) to probe and apply state changes only when they pass the same constraint-validation path used at transaction commit.

Changes:

  • Introduced tryAlter { ... } extension that mutates a scratch builder, validates the candidate state, and merges into the live builder only when clean; folds setter-thrown ValidationExceptions into returned violations.
  • Added Kotlin + Java test coverage for the new API, including integration-style dispatch tests via a real ProcessManagerRepository, plus dedicated test fixtures/protos.
  • Bumped project/dependency versions and refreshed ADR + dependency reports accordingly.

Reviewed changes

Copilot reviewed 13 out of 13 changed files in this pull request and generated no comments.

Show a summary per file
File Description
version.gradle.kts Bumps published snapshot version to 2.0.0-SNAPSHOT.401.
server/src/main/kotlin/io/spine/server/entity/TransactionalEntityExts.kt Adds tryAlter extension with scratch-mutate + validate + merge semantics.
server/src/test/kotlin/io/spine/server/entity/TransactionalEntityExtensionsSpec.kt Adds Kotlin tests covering tryAlter behavior and repository dispatch persistence outcomes.
server/src/test/java/io/spine/server/entity/TransactionalEntityExtensionsJavaSpec.java Adds Java-facing tests verifying tryAlter is usable via the TransactionalEntityExtensions facade.
server/src/testFixtures/kotlin/io/spine/server/entity/given/tryalter/StockContext.kt Introduces StockKeeper/repo fixture demonstrating preventive validation via tryAlter in a reactor.
server/src/testFixtures/proto/spine/test/tryalter/stock.proto Adds constrained Stock state proto used in fixtures/tests (min, set_once).
server/src/testFixtures/proto/spine/test/tryalter/events.proto Adds event protos for the tryAlter fixture scenario.
server/src/testFixtures/proto/spine/test/tryalter/commands.proto Adds command proto for the tryAlter fixture scenario.
docs/dependencies/pom.xml Updates documented artifact/dependency versions (incl. validation runtime to .447).
docs/dependencies/dependencies.md Regenerates dependency/license report for the bumped snapshot version.
docs/adr/0001-aggregates-without-event-sourcing.md Records PR-B1 implementation notes for ADR D9 (merge mechanics + Java access decision).
buildSrc/src/main/kotlin/io/spine/dependency/local/Validation.kt Bumps validation dependency version constant to 2.0.0-SNAPSHOT.447.
.agents/tasks/de-event-sourcing-plan.md Updates the delivery plan document content/formatting in line with the ADR decisions.

@alexander-yevsyukov alexander-yevsyukov moved this from 🏗 In progress to In Review in v2.0 Jul 6, 2026
@codecov

codecov Bot commented Jul 6, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 88.35%. Comparing base (d5d53b8) to head (239c55d).

Additional details and impacted files
@@            Coverage Diff             @@
##           master    #1643      +/-   ##
==========================================
+ Coverage   88.32%   88.35%   +0.03%     
==========================================
  Files        1082     1083       +1     
  Lines       23620    23648      +28     
  Branches     1080     1082       +2     
==========================================
+ Hits        20863    20895      +32     
+ Misses       2365     2360       -5     
- Partials      392      393       +1     
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@alexander-yevsyukov alexander-yevsyukov merged commit a62592c into master Jul 6, 2026
12 checks passed
@github-project-automation github-project-automation Bot moved this from In Review to ✅ Done in v2.0 Jul 6, 2026
@alexander-yevsyukov alexander-yevsyukov deleted the de-event-sourcing-impl-1 branch July 6, 2026 18:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: ✅ Done

Development

Successfully merging this pull request may close these issues.

3 participants