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

Archived in project

Development

Successfully merging this pull request may close these issues.

3 participants