fix(archunit): EntityVersionParity checks member-level @Version, not class-level (#315) #12

Merged
hibryda merged 5 commits from fix/entity-version-parity-field-level into main 2026-05-29 11:24:23 +02:00
Owner

Fix: EntityVersionParity must check member-level @Version, not class-level (#315)

The defect

EntityVersionParity.entitiesMustCarryVersion() used:

classes().that().areAnnotatedWith(Entity.class)...should().beAnnotatedWith(Version.class)

But jakarta.persistence.@Version is a FIELD/METHOD-target annotation — it is never present on the class itself. So should().beAnnotatedWith(Version.class) matched no entity and the rule failed for every @Entity in every consumer service. user-service (PR #8) and calendar-service (PR #8) each had to ship a local corrected EntityVersionParityArchTest instead of wiring this shared rule.

The fix

Replace the class-level should() with a custom ArchCondition<JavaClass> that inspects members:

entity.getAllFields().stream().anyMatch(f -> f.isAnnotatedWith(Version.class))
  || entity.getAllMethods().stream().anyMatch(m -> m.isAnnotatedWith(Version.class))

getAllFields()/getAllMethods() include inherited members, so JOINED / @MappedSuperclass hierarchies that carry the version on the root satisfy the rule for every subclass @Entity (the exact inheritance shape calendar-service navigated manually). Field-access and property-access (@Version getter) are both covered. The .that() filters (@Immutable, ..audit.., ..replica..), .because(...), and allowEmptyShould(true) are unchanged.

Self-test (the v1.0 scaffold's deferred "PR-PLATFORM-5")

EntityVersionParitySelfTest evaluates the rule against explicitly-imported fixture packages:

  • positive (asserts no violation): field-access, inherited-@MappedSuperclass, and accessor @Version entities + an @Immutable append-only entity (exclusion).
  • negative (asserts violation + message): a mutable @Entity with no @Version.

Each package is imported separately so the negative fixture never pollutes the positive evaluation. The positive case is the regression guard — it fails under the old class-level rule and passes under the fix.

Verification

  • mvn -B -pl archunit-rules test (JDK17) → BUILD SUCCESS, 2 tests, 0 warnings (parent pom failOnWarning=true).

Follow-up (separate)

Once this lands + the 1.1.0-SNAPSHOT is re-published to the Forgejo Maven registry, convert the local EntityVersionParityArchTest copies in user-service + calendar (and use the shared rule in family/notification/admin) to the fixed shared rule.

## Fix: EntityVersionParity must check member-level `@Version`, not class-level (#315) ### The defect `EntityVersionParity.entitiesMustCarryVersion()` used: ```java classes().that().areAnnotatedWith(Entity.class)...should().beAnnotatedWith(Version.class) ``` But `jakarta.persistence.@Version` is a **`FIELD`/`METHOD`-target** annotation — it is *never* present on the class itself. So `should().beAnnotatedWith(Version.class)` matched **no** entity and the rule failed for **every** `@Entity` in every consumer service. user-service (PR #8) and calendar-service (PR #8) each had to ship a **local** corrected `EntityVersionParityArchTest` instead of wiring this shared rule. ### The fix Replace the class-level `should()` with a custom `ArchCondition<JavaClass>` that inspects members: ```java entity.getAllFields().stream().anyMatch(f -> f.isAnnotatedWith(Version.class)) || entity.getAllMethods().stream().anyMatch(m -> m.isAnnotatedWith(Version.class)) ``` `getAllFields()`/`getAllMethods()` include **inherited** members, so JOINED / `@MappedSuperclass` hierarchies that carry the version on the root satisfy the rule for every subclass `@Entity` (the exact inheritance shape calendar-service navigated manually). Field-access **and** property-access (`@Version` getter) are both covered. The `.that()` filters (`@Immutable`, `..audit..`, `..replica..`), `.because(...)`, and `allowEmptyShould(true)` are unchanged. ### Self-test (the v1.0 scaffold's deferred "PR-PLATFORM-5") `EntityVersionParitySelfTest` evaluates the rule against explicitly-imported fixture packages: - **positive** (asserts no violation): field-access, inherited-`@MappedSuperclass`, and accessor `@Version` entities + an `@Immutable` append-only entity (exclusion). - **negative** (asserts violation + message): a mutable `@Entity` with no `@Version`. Each package is imported separately so the negative fixture never pollutes the positive evaluation. The positive case is the regression guard — it **fails under the old class-level rule** and **passes under the fix**. ### Verification - `mvn -B -pl archunit-rules test` (JDK17) → **BUILD SUCCESS, 2 tests, 0 warnings** (parent pom `failOnWarning=true`). ### Follow-up (separate) Once this lands + the `1.1.0-SNAPSHOT` is re-published to the Forgejo Maven registry, convert the **local** `EntityVersionParityArchTest` copies in user-service + calendar (and use the shared rule in family/notification/admin) to the fixed shared rule.
fix(archunit): EntityVersionParity checks member-level @Version, not class-level (#315)
All checks were successful
im2be-platform-libs CI / mvn install (pull_request) Successful in 1m10s
im2be-platform-libs CI / mvn verify (main only) (pull_request) Has been skipped
19130e5fbf
The rule used classes().should().beAnnotatedWith(Version.class), but
jakarta.persistence.@Version is a FIELD/METHOD-target annotation never present on
the class — so the rule matched no entity and failed for EVERY @Entity in every
consumer service (user-service + calendar worked around it with local copies).

Fix: replace the class-level should() with a custom ArchCondition<JavaClass> that
checks getAllFields()/getAllMethods() for @Version — covering field-access,
property-access (annotated getter), and inherited version members (JOINED /
@MappedSuperclass roots), so every subclass @Entity is satisfied by an ancestor's
@Version. The .that() filters (@Immutable, ..audit.., ..replica..) + .because() +
allowEmptyShould(true) are unchanged.

Adds the self-test the v1.0 scaffold deferred (CLAUDE.md "PR-PLATFORM-5"): positive
fixtures (field / inherited-@MappedSuperclass / accessor @Version + @Immutable
exclusion) assert no violation; a negative fixture (mutable @Entity, no @Version)
asserts the rule flags it. Each fixture package is imported explicitly so the
negative case never pollutes the positive evaluation.

Verification:
- mvn -B -pl archunit-rules test (JDK17) -> BUILD SUCCESS, 2 tests, 0 warnings

Follow-up: convert the local EntityVersionParityArchTest copies in user-service +
calendar (+ family/notification/admin) to the fixed shared rule once the SNAPSHOT
is re-published to the Forgejo registry.

Superseded by round 2.

Show previous round

hib-pr-reviewer review — PR #12 (affinity-intelligence-rework/im2be-platform-libs)

Round 1 — head 19130e5fbfc0, base main, trigger opened

TL;DR: CONDITIONAL_APPROVE — 0 agreed findings; verified and kept 2 minor (test fixture JPA false-negative, vacuous-pass guard) and 1 info (exclusion coverage gap) from unique-to-one reviewers.

Summary

Arbitration summary

This is the first run for PR #12. No prior Memora history. 0 agreed findings (A and B flagged entirely different concerns). All 3 findings are unique-to-one-reviewer and required verification.

A1 — KEPT (verified). VersionedAccessorEntity.java line 11 has @Id on the id field; line 16 has @Version on getVersion(). Under JPA §2.3.2, placing @Id on a field selects field-based access for the entity, which means method-level annotations are ignored at runtime. Confirmed by reading the file: @Id is on line 11, @Version is on line 16, and no @Access(AccessType.PROPERTY) is present. The ArchUnit condition finds @Version on the method via bytecode inspection, but JPA would silently skip it — a documented false-negative class. KEPT as minor.

B1 — KEPT (verified). EntityVersionParitySelfTest.java line 34 calls new ClassFileImporter().importPackages(POSITIVE) with no guard assertion before evaluation. EntityVersionParity.java line 70 confirms .allowEmptyShould(true). If the fixture package fails to load (typo, classpath issue, compile failure), the rule evaluates zero entities, produces no violations, and assertThat(result.hasViolation()).isFalse() passes vacuously without testing anything. KEPT as minor.

B2 — KEPT (verified, info). The test file has no fixture or assertion exercising the ..audit.. / ..replica.. package-exclusion paths. Confirmed by reading EntityVersionParitySelfTest.java — only @Immutable exclusion is covered. Reviewer correctly self-classifies as pre-existing, info-only, and deferred. KEPT as info.

Outcome: 0 agreed, 3 unique-to-one verified and kept (2 minor, 1 info). No blocking issues.

Blast Radius

All changes are confined to a single ArchUnit rules module (archunit-rules). The production code change introduces a private static ArchCondition factory in EntityVersionParity.java; the public API signature (entitiesMustCarryVersion()) is unchanged. All other modified files are test fixtures with no cross-module surface.

BLAST_SCORE: 2/10

CI status (head 19130e5fbfc0)

Overall: ✓ success

2 checks: 2 pending

Check State Link
im2be-platform-libs CI / mvn install (pull_request) pending details
im2be-platform-libs CI / mvn verify (main only) (pull_request) pending details

Findings (3)

[MINOR] Mixed JPA access mode: @Id on field + @Version on getter without @Access(PROPERTY) — getter annotation is silently ignored by JPA

archunit-rules/src/test/java/com/aim2be/platform/archunit/fixtures/positive/VersionedAccessorEntity.java:11

@Id is placed on the id field (line 11), which selects field-based access for this entity per JPA §2.3.2. Under field-based access, only field-level annotations are considered persistent state; the @Version annotation on getVersion() (line 16) is silently ignored by Hibernate/EclipseLink at runtime. The ArchUnit condition correctly finds @Version on the method via bytecode inspection — so the fixture passes the rule — but a production deployment of this entity would have no effective optimistic locking.

This is the rule's principal false-negative class: the heuristic finds @Version on some method, but JPA may never honour it.

Option A — keep property-access intent (add @Access and move @Id):

@Entity
@Access(AccessType.PROPERTY)
public class VersionedAccessorEntity {
    private Long id;
    private Long version;

    @Id
    public Long getId() { return id; }     // move @Id here
    public void setId(final Long id) { this.id = id; }

    @Version
    public Long getVersion() { return version; }   // unchanged
    public void setVersion(final Long version) { this.version = version; }
}

Option B — annotate the field instead:

    @Version
    private Long version;   // move annotation to field; remove from getter

Option A is preferable if the test is meant to cover the getAllMethods() path of the ArchCondition.

[MINOR] passesForCompliantFixtures can pass vacuously when fixture classes fail to load

archunit-rules/src/test/java/com/aim2be/platform/archunit/EntityVersionParitySelfTest.java:34

Line 34 calls new ClassFileImporter().importPackages(POSITIVE) and then evaluates the rule. Because EntityVersionParity.entitiesMustCarryVersion() is built with .allowEmptyShould(true) (EntityVersionParity.java:70), a zero-class import — caused by a package-name typo, a compile failure that drops fixture classes from the output, or a classpath ordering issue — produces zero rule candidates, zero violations, and result.hasViolation() returns false. The assertion at lines 36–38 then passes without exercising any entity at all.

Add a guard assertion immediately after line 34, before evaluate:

final JavaClasses positive = new ClassFileImporter().importPackages(POSITIVE);
assertThat(positive.contain(VersionedFieldEntity.class))
        .as("VersionedFieldEntity fixture must be importable from the positive package")
        .isTrue();
final EvaluationResult result = EntityVersionParity.entitiesMustCarryVersion().evaluate(positive);

This pins the test to at least one known entity, making a vacuous pass impossible.

[INFO] No fixture or assertion for ..audit.. / ..replica.. package exclusions

archunit-rules/src/test/java/com/aim2be/platform/archunit/EntityVersionParitySelfTest.java:29

The rule at EntityVersionParity.java:64 explicitly excludes two package patterns (..audit.., ..replica..). An unversioned @Entity in those packages should pass the rule, but no fixture class demonstrates this and no test asserts it. A future maintainer who inadvertently removes or narrows the resideOutsideOfPackages clause would have no regression signal.

This is a pre-existing omission predating this PR; deferring to a follow-on issue is reasonable. Low priority.

Verdict

CONDITIONAL_APPROVE


hib-pr-reviewer • round 1 • 3 findings (2m/1i) • 2026-05-29T09:00:43.064Z → 2026-05-29T09:02:43.335Z • posted-as: pr-reviewer-bot

<!-- hib-pr-reviewer collapsed --> > _Superseded by round 2._ <details> <summary>Show previous round</summary> ## hib-pr-reviewer review — PR #12 (affinity-intelligence-rework/im2be-platform-libs) **Round 1** — head `19130e5fbfc0`, base `main`, trigger `opened` **TL;DR:** CONDITIONAL_APPROVE — 0 agreed findings; verified and kept 2 minor (test fixture JPA false-negative, vacuous-pass guard) and 1 info (exclusion coverage gap) from unique-to-one reviewers. ### Summary ## Arbitration summary This is the first run for PR #12. No prior Memora history. **0 agreed findings** (A and B flagged entirely different concerns). All 3 findings are unique-to-one-reviewer and required verification. **A1 — KEPT (verified).** `VersionedAccessorEntity.java` line 11 has `@Id` on the `id` field; line 16 has `@Version` on `getVersion()`. Under JPA §2.3.2, placing `@Id` on a field selects field-based access for the entity, which means method-level annotations are ignored at runtime. Confirmed by reading the file: `@Id` is on line 11, `@Version` is on line 16, and no `@Access(AccessType.PROPERTY)` is present. The ArchUnit condition finds `@Version` on the method via bytecode inspection, but JPA would silently skip it — a documented false-negative class. **KEPT as minor.** **B1 — KEPT (verified).** `EntityVersionParitySelfTest.java` line 34 calls `new ClassFileImporter().importPackages(POSITIVE)` with no guard assertion before evaluation. `EntityVersionParity.java` line 70 confirms `.allowEmptyShould(true)`. If the fixture package fails to load (typo, classpath issue, compile failure), the rule evaluates zero entities, produces no violations, and `assertThat(result.hasViolation()).isFalse()` passes vacuously without testing anything. **KEPT as minor.** **B2 — KEPT (verified, info).** The test file has no fixture or assertion exercising the `..audit..` / `..replica..` package-exclusion paths. Confirmed by reading `EntityVersionParitySelfTest.java` — only `@Immutable` exclusion is covered. Reviewer correctly self-classifies as pre-existing, info-only, and deferred. **KEPT as info.** **Outcome:** 0 agreed, 3 unique-to-one verified and kept (2 minor, 1 info). No blocking issues. ### Blast Radius All changes are confined to a single ArchUnit rules module (`archunit-rules`). The production code change introduces a private static `ArchCondition` factory in `EntityVersionParity.java`; the public API signature (`entitiesMustCarryVersion()`) is unchanged. All other modified files are test fixtures with no cross-module surface. **BLAST_SCORE: 2/10** ### CI status (head `19130e5fbfc0`) **Overall: ✓ success** 2 checks: 2 pending | Check | State | Link | |---|---|---| | im2be-platform-libs CI / mvn install (pull_request) | ⏳ pending | [details](/affinity-intelligence-rework/im2be-platform-libs/actions/runs/82/jobs/0) | | im2be-platform-libs CI / mvn verify (main only) (pull_request) | ⏳ pending | [details](/affinity-intelligence-rework/im2be-platform-libs/actions/runs/82/jobs/1) | ### Findings (3) #### **[MINOR]** Mixed JPA access mode: `@Id` on field + `@Version` on getter without `@Access(PROPERTY)` — getter annotation is silently ignored by JPA _archunit-rules/src/test/java/com/aim2be/platform/archunit/fixtures/positive/VersionedAccessorEntity.java:11_ `@Id` is placed on the `id` **field** (line 11), which selects **field-based access** for this entity per JPA §2.3.2. Under field-based access, only field-level annotations are considered persistent state; the `@Version` annotation on `getVersion()` (line 16) is **silently ignored** by Hibernate/EclipseLink at runtime. The ArchUnit condition correctly finds `@Version` on the method via bytecode inspection — so the fixture passes the rule — but a production deployment of this entity would have no effective optimistic locking. This is the rule's principal false-negative class: the heuristic finds `@Version` on *some* method, but JPA may never honour it. **Option A — keep property-access intent (add `@Access` and move `@Id`):** ```java @Entity @Access(AccessType.PROPERTY) public class VersionedAccessorEntity { private Long id; private Long version; @Id public Long getId() { return id; } // move @Id here public void setId(final Long id) { this.id = id; } @Version public Long getVersion() { return version; } // unchanged public void setVersion(final Long version) { this.version = version; } } ``` **Option B — annotate the field instead:** ```java @Version private Long version; // move annotation to field; remove from getter ``` Option A is preferable if the test is meant to cover the `getAllMethods()` path of the `ArchCondition`. #### **[MINOR]** `passesForCompliantFixtures` can pass vacuously when fixture classes fail to load _archunit-rules/src/test/java/com/aim2be/platform/archunit/EntityVersionParitySelfTest.java:34_ Line 34 calls `new ClassFileImporter().importPackages(POSITIVE)` and then evaluates the rule. Because `EntityVersionParity.entitiesMustCarryVersion()` is built with `.allowEmptyShould(true)` (EntityVersionParity.java:70), a zero-class import — caused by a package-name typo, a compile failure that drops fixture classes from the output, or a classpath ordering issue — produces zero rule candidates, zero violations, and `result.hasViolation()` returns `false`. The assertion at lines 36–38 then passes without exercising any entity at all. Add a guard assertion immediately after line 34, before `evaluate`: ```java final JavaClasses positive = new ClassFileImporter().importPackages(POSITIVE); assertThat(positive.contain(VersionedFieldEntity.class)) .as("VersionedFieldEntity fixture must be importable from the positive package") .isTrue(); final EvaluationResult result = EntityVersionParity.entitiesMustCarryVersion().evaluate(positive); ``` This pins the test to at least one known entity, making a vacuous pass impossible. #### **[INFO]** No fixture or assertion for `..audit..` / `..replica..` package exclusions _archunit-rules/src/test/java/com/aim2be/platform/archunit/EntityVersionParitySelfTest.java:29_ The rule at EntityVersionParity.java:64 explicitly excludes two package patterns (`..audit..`, `..replica..`). An unversioned `@Entity` in those packages should pass the rule, but no fixture class demonstrates this and no test asserts it. A future maintainer who inadvertently removes or narrows the `resideOutsideOfPackages` clause would have no regression signal. This is a pre-existing omission predating this PR; deferring to a follow-on issue is reasonable. Low priority. ### Verdict **CONDITIONAL_APPROVE** --- <sub>hib-pr-reviewer • round 1 • 3 findings (2m/1i) • 2026-05-29T09:00:43.064Z → 2026-05-29T09:02:43.335Z • posted-as: pr-reviewer-bot</sub> </details>
Author
Owner

#315 — R1 response

Project: affinity-intelligence-rework/im2be-platform-libs • PR #12 • R1 response (human-applied) • head 6634d56 • 2026-05-29T09:05:46Z

TL;DR: all 3 findings ADDRESSED (2 minor + 1 info). mvn -B -pl archunit-rules test green (2 tests, 0 warnings). No defends.

Summary

R1 was CONDITIONAL_APPROVE (0 agreed; 2 minor + 1 info kept). All three were legitimate test-quality findings and are fixed in 6634d56 — the production rule (EntityVersionParity.java) is unchanged; only the self-test fixtures were hardened.

Findings

# Sev Status Resolution
1 MINOR FIXED VersionedAccessorEntity had @Id on the field (→ field-access) + @Version on the getter, which JPA silently ignores — a false-negative-shaped fixture. Rewrote it as coherent property-access (@Access(AccessType.PROPERTY), @Id + @Version on getters) so the getAllMethods() path is exercised by a JPA-valid entity.
2 MINOR FIXED passesForCompliantFixtures could pass vacuously on an empty import (typo/compile/classpath) given allowEmptyShould(true). Added JavaClasses.contain(...) guards pinning VersionedFieldEntity (+ the audit/replica exclusion fixtures), and a symmetric guard on the negative test's UnversionedEntity.
3 INFO ADDRESSED (not deferred) Added unversioned @Entity fixtures in fixtures/positive/audit + fixtures/positive/replica. The positive test imports the whole positive package, so its no-violation assertion now exercises both ..audit../..replica.. exclusion branches — a regressed resideOutsideOfPackages clause would make these unversioned entities violate. contain() guards confirm they're evaluated.

Verdict

All findings resolved (no defends). Self-test now covers: field-access / inherited-@MappedSuperclass / property-access @Version, the @Immutable exclusion, and the ..audit../..replica.. package exclusions; plus negative + vacuous-pass guards. Requesting re-review.

platform-libs • PR #12 • R1-response • fixed 3 / defended 0 • head 6634d56 • 2026-05-29T09:05:46Z

## #315 — R1 response **Project:** affinity-intelligence-rework/im2be-platform-libs • **PR #12** • R1 response (human-applied) • head `6634d56` • 2026-05-29T09:05:46Z **TL;DR:** all 3 findings ADDRESSED (2 minor + 1 info). `mvn -B -pl archunit-rules test` green (2 tests, 0 warnings). No defends. ### Summary R1 was CONDITIONAL_APPROVE (0 agreed; 2 minor + 1 info kept). All three were legitimate test-quality findings and are fixed in `6634d56` — the production rule (`EntityVersionParity.java`) is unchanged; only the self-test fixtures were hardened. ### Findings | # | Sev | Status | Resolution | |---|-----|--------|------------| | 1 | MINOR | ✅ FIXED | `VersionedAccessorEntity` had `@Id` on the field (→ field-access) + `@Version` on the getter, which JPA silently ignores — a false-negative-shaped fixture. Rewrote it as coherent **property-access** (`@Access(AccessType.PROPERTY)`, `@Id` + `@Version` on getters) so the `getAllMethods()` path is exercised by a JPA-valid entity. | | 2 | MINOR | ✅ FIXED | `passesForCompliantFixtures` could pass vacuously on an empty import (typo/compile/classpath) given `allowEmptyShould(true)`. Added `JavaClasses.contain(...)` guards pinning `VersionedFieldEntity` (+ the audit/replica exclusion fixtures), and a symmetric guard on the negative test's `UnversionedEntity`. | | 3 | INFO | ✅ ADDRESSED (not deferred) | Added unversioned `@Entity` fixtures in `fixtures/positive/audit` + `fixtures/positive/replica`. The positive test imports the whole `positive` package, so its **no-violation** assertion now exercises both `..audit..`/`..replica..` exclusion branches — a regressed `resideOutsideOfPackages` clause would make these unversioned entities violate. `contain()` guards confirm they're evaluated. | ### Verdict All findings resolved (no defends). Self-test now covers: field-access / inherited-`@MappedSuperclass` / property-access `@Version`, the `@Immutable` exclusion, and the `..audit..`/`..replica..` package exclusions; plus negative + vacuous-pass guards. Requesting re-review. ### Footer platform-libs • PR #12 • R1-response • fixed 3 / defended 0 • head `6634d56` • 2026-05-29T09:05:46Z
fix(archunit): #315 R1 — coherent property-access fixture + vacuous-pass guards + exclusion coverage
All checks were successful
im2be-platform-libs CI / mvn install (pull_request) Successful in 1m5s
im2be-platform-libs CI / mvn verify (main only) (pull_request) Has been skipped
6634d56ab4
R1 CONDITIONAL_APPROVE (0 agreed; 2 minor + 1 info kept). Addressed all 3:
(1) MINOR VersionedAccessorEntity had @Id on field (-> field-access) + @Version on
    the getter (silently ignored by JPA) — made it coherent property-access
    (@Access(PROPERTY), @Id + @Version on getters) so the getAllMethods() path is a
    JPA-valid fixture, not a false-negative.
(2) MINOR passesForCompliantFixtures could pass vacuously on an empty import (+
    allowEmptyShould(true)) — added JavaClasses.contain() guards pinning known
    fixtures (and the negative test's UnversionedEntity).
(3) INFO no ..audit../..replica.. exclusion coverage — added unversioned @Entity
    fixtures in positive/audit + positive/replica subpackages; the positive test's
    no-violation now exercises both exclusion branches (a regressed exclusion would
    make them violate), with contain() guards confirming they are evaluated.

Verification:
- mvn -B -pl archunit-rules test (JDK17) -> BUILD SUCCESS, 2 tests, 0 warnings

Superseded by round 3.

Show previous round

hib-pr-reviewer review — PR #12 (affinity-intelligence-rework/im2be-platform-libs)

Round 2 — head 6634d56ab4af, base main, trigger synchronize

TL;DR: CONDITIONAL_APPROVE — 1 agreed minor finding kept (EntityVersionParitySelfTest.java:47 conjunctive guard); 3 prior round-1 findings confirmed resolved; 0 findings dropped.

Summary

Arbitration — Round 2

Memora recall: No prior run history found (both queries returned empty); this is the create-new fallback path. Memora write was attempted but blocked by permission constraints.

Reconciliation: Both A and B produced exactly 1 finding each, citing the same file (EntityVersionParitySelfTest.java), the same line (47), and materially identical descriptions of the &&-inside-assertThat diagnostic-quality issue. Per Rule 1 this is an agreed finding and is kept without further debate.

Verification (Rule 1 / Rule 2): Read of the file at HEAD confirms the exact code at line 47:

assertThat(positive.contain(AuditTrailEntity.class) && positive.contain(ReplicaProjectionEntity.class))
        .as("unversioned ..audit../..replica.. exclusion fixtures must be imported + evaluated")
        .isTrue();

The && is evaluated as a plain Java boolean before assertThat receives it, so AssertJ can only report expected: true but was: false — it cannot identify which class was absent. The finding is real and the citations are accurate.

Prior round-1 findings: All 3 were resolved per both reviewers (VersionedAccessorEntity mixed-access fix, vacuous-pass guard, audit/replica fixture assertions) — not re-raised.

Result: 1 agreed finding kept (minor), 0 dropped.

Blast Radius

The diff touches one ArchUnit rule method and a set of new test fixtures under archunit-rules/src/test. No production code paths or exported API surfaces are modified. The blast radius is limited to the static-analysis build phase.

BLAST_SCORE: 3/10

CI status (head 6634d56ab4af)

Overall: ✓ success

2 checks: 2 pending

Check State Link
im2be-platform-libs CI / mvn install (pull_request) pending details
im2be-platform-libs CI / mvn verify (main only) (pull_request) pending details

Findings (1)

[MINOR] Conjunctive && inside assertThat hides which exclusion fixture failed to load

archunit-rules/src/test/java/com/aim2be/platform/archunit/EntityVersionParitySelfTest.java:47

assertThat(positive.contain(AuditTrailEntity.class) && positive.contain(ReplicaProjectionEntity.class))
        .as("unversioned ..audit../..replica.. exclusion fixtures must be imported + evaluated")
        .isTrue();

The && short-circuits and collapses the two boolean results into a single value before assertThat sees anything. When this guard fires in CI the failure message reads only expected: <true> but was: <false> under the combined description — it does not identify which class was absent. Since the purpose of this guard is diagnostic (preventing a silent vacuous pass), losing per-class granularity defeats half its value.

Replace with two independent assertions:

assertThat(positive.contain(AuditTrailEntity.class))
        .as("AuditTrailEntity (..audit.. exclusion fixture) must be importable")
        .isTrue();
assertThat(positive.contain(ReplicaProjectionEntity.class))
        .as("ReplicaProjectionEntity (..replica.. exclusion fixture) must be importable")
        .isTrue();

Each assertion now names the missing class in the failure message, making build-log triage immediate.

Verdict

CONDITIONAL_APPROVE


hib-pr-reviewer • round 2 • 1 finding (1m) • 2026-05-29T09:09:16.117Z → 2026-05-29T09:10:30.784Z • posted-as: pr-reviewer-bot

<!-- hib-pr-reviewer collapsed --> > _Superseded by round 3._ <details> <summary>Show previous round</summary> ## hib-pr-reviewer review — PR #12 (affinity-intelligence-rework/im2be-platform-libs) **Round 2** — head `6634d56ab4af`, base `main`, trigger `synchronize` **TL;DR:** CONDITIONAL_APPROVE — 1 agreed minor finding kept (EntityVersionParitySelfTest.java:47 conjunctive guard); 3 prior round-1 findings confirmed resolved; 0 findings dropped. ### Summary ## Arbitration — Round 2 **Memora recall:** No prior run history found (both queries returned empty); this is the create-new fallback path. Memora write was attempted but blocked by permission constraints. **Reconciliation:** Both A and B produced exactly 1 finding each, citing the same file (`EntityVersionParitySelfTest.java`), the same line (47), and materially identical descriptions of the `&&`-inside-`assertThat` diagnostic-quality issue. Per Rule 1 this is an **agreed finding** and is kept without further debate. **Verification (Rule 1 / Rule 2):** `Read` of the file at HEAD confirms the exact code at line 47: ```java assertThat(positive.contain(AuditTrailEntity.class) && positive.contain(ReplicaProjectionEntity.class)) .as("unversioned ..audit../..replica.. exclusion fixtures must be imported + evaluated") .isTrue(); ``` The `&&` is evaluated as a plain Java boolean before `assertThat` receives it, so AssertJ can only report `expected: true but was: false` — it cannot identify which class was absent. The finding is real and the citations are accurate. **Prior round-1 findings:** All 3 were resolved per both reviewers (VersionedAccessorEntity mixed-access fix, vacuous-pass guard, audit/replica fixture assertions) — not re-raised. **Result:** 1 agreed finding kept (minor), 0 dropped. ### Blast Radius The diff touches one ArchUnit rule method and a set of new test fixtures under `archunit-rules/src/test`. No production code paths or exported API surfaces are modified. The blast radius is limited to the static-analysis build phase. **BLAST_SCORE: 3/10** ### CI status (head `6634d56ab4af`) **Overall: ✓ success** 2 checks: 2 pending | Check | State | Link | |---|---|---| | im2be-platform-libs CI / mvn install (pull_request) | ⏳ pending | [details](/affinity-intelligence-rework/im2be-platform-libs/actions/runs/83/jobs/0) | | im2be-platform-libs CI / mvn verify (main only) (pull_request) | ⏳ pending | [details](/affinity-intelligence-rework/im2be-platform-libs/actions/runs/83/jobs/1) | ### Findings (1) #### **[MINOR]** Conjunctive `&&` inside `assertThat` hides which exclusion fixture failed to load _archunit-rules/src/test/java/com/aim2be/platform/archunit/EntityVersionParitySelfTest.java:47_ ```java assertThat(positive.contain(AuditTrailEntity.class) && positive.contain(ReplicaProjectionEntity.class)) .as("unversioned ..audit../..replica.. exclusion fixtures must be imported + evaluated") .isTrue(); ``` The `&&` short-circuits and collapses the two `boolean` results into a single value before `assertThat` sees anything. When this guard fires in CI the failure message reads only `expected: <true> but was: <false>` under the combined description — it does not identify *which* class was absent. Since the purpose of this guard is diagnostic (preventing a silent vacuous pass), losing per-class granularity defeats half its value. Replace with two independent assertions: ```java assertThat(positive.contain(AuditTrailEntity.class)) .as("AuditTrailEntity (..audit.. exclusion fixture) must be importable") .isTrue(); assertThat(positive.contain(ReplicaProjectionEntity.class)) .as("ReplicaProjectionEntity (..replica.. exclusion fixture) must be importable") .isTrue(); ``` Each assertion now names the missing class in the failure message, making build-log triage immediate. ### Verdict **CONDITIONAL_APPROVE** --- <sub>hib-pr-reviewer • round 2 • 1 finding (1m) • 2026-05-29T09:09:16.117Z → 2026-05-29T09:10:30.784Z • posted-as: pr-reviewer-bot</sub> </details>
Author
Owner

#315 — R2 response

Project: affinity-intelligence-rework/im2be-platform-libs • PR #12 • R2 response (human-applied) • head 81820d8 • 2026-05-29T09:11:53Z

TL;DR: the 1 R2 minor FIXED (split the conjunctive guard); R1's 3 findings confirmed resolved. mvn -B -pl archunit-rules test green (2 tests, 0 warnings). No defends.

Findings

# Sev Status Resolution
1 MINOR FIXED EntityVersionParitySelfTest:47 — the && collapsed both contain() checks into one boolean before assertThat, so a CI failure couldn't name which exclusion fixture was absent. Split into two independently-.as(...)-described assertions (AuditTrailEntity / ReplicaProjectionEntity) for immediate triage.

Verdict

Resolved (no defends). The production rule is unchanged across the R-cycle; only the self-test hardened (R1: property-access fixture + vacuous-pass guards + exclusion coverage; R2: per-class guard granularity). Requesting re-review.

platform-libs • PR #12 • R2-response • fixed 1 / defended 0 • head 81820d8 • 2026-05-29T09:11:53Z

## #315 — R2 response **Project:** affinity-intelligence-rework/im2be-platform-libs • **PR #12** • R2 response (human-applied) • head `81820d8` • 2026-05-29T09:11:53Z **TL;DR:** the 1 R2 minor FIXED (split the conjunctive guard); R1's 3 findings confirmed resolved. `mvn -B -pl archunit-rules test` green (2 tests, 0 warnings). No defends. ### Findings | # | Sev | Status | Resolution | |---|-----|--------|------------| | 1 | MINOR | ✅ FIXED | `EntityVersionParitySelfTest`:47 — the `&&` collapsed both `contain()` checks into one boolean before `assertThat`, so a CI failure couldn't name which exclusion fixture was absent. Split into two independently-`.as(...)`-described assertions (`AuditTrailEntity` / `ReplicaProjectionEntity`) for immediate triage. | ### Verdict Resolved (no defends). The production rule is unchanged across the R-cycle; only the self-test hardened (R1: property-access fixture + vacuous-pass guards + exclusion coverage; R2: per-class guard granularity). Requesting re-review. ### Footer platform-libs • PR #12 • R2-response • fixed 1 / defended 0 • head `81820d8` • 2026-05-29T09:11:53Z
test(archunit): #315 R2 — split conjunctive exclusion-fixture guard into per-class assertions
All checks were successful
im2be-platform-libs CI / mvn install (pull_request) Successful in 1m9s
im2be-platform-libs CI / mvn verify (main only) (pull_request) Has been skipped
81820d884a
R2 CONDITIONAL_APPROVE (1 minor; R1's 3 confirmed resolved). The && guard collapsed
both contain() checks into one boolean before assertThat, so a CI failure couldn't
name which exclusion fixture was missing. Split into two independently-described
assertions (AuditTrailEntity / ReplicaProjectionEntity) for immediate triage.

Verification:
- mvn -B -pl archunit-rules test (JDK17) -> BUILD SUCCESS, 2 tests, 0 warnings

Superseded by round 4.

Show previous round

hib-pr-reviewer review — PR #12 (affinity-intelligence-rework/im2be-platform-libs)

Round 3 — head 81820d884a65, base main, trigger synchronize

TL;DR: CONDITIONAL_APPROVE — kept 1 agreed finding (VersionedViaSuperclassEntity guard gap) plus 1 verified unique-to-A finding (ImmutableAppendOnlyEntity guard gap), combined into one minor finding; no blocking issues.

Summary

Reconciliation — Round 3

Memora: No prior run history found (despite round 3); created new entry (ID 330).

Verification performed:

  • Read EntityVersionParitySelfTest.java at HEAD (75 lines). Guard block confirmed at lines 44–52: only VersionedFieldEntity, AuditTrailEntity, and ReplicaProjectionEntity are asserted; VersionedViaSuperclassEntity and ImmutableAppendOnlyEntity are absent from both the import list and the guard block.
  • Read both fixture files at HEAD: VersionedViaSuperclassEntity (inherits @Version from VersionedMappedSuperclass) and ImmutableAppendOnlyEntity (@Immutable exclusion) both exist and are well-formed.

Agreed finding kept (Rule 1): Both A and B independently flagged that VersionedViaSuperclassEntity — the class exercising the very regression path this PR fixes — has no presence assertion in the guard block.

Unique-to-A finding verified and kept (Rule 2): A also flagged ImmutableAppendOnlyEntity having no guard assertion. Confirmed at HEAD: the class is not imported and not asserted. The @Immutable-exclusion path it exercises can silently disappear without any signal. Finding is valid.

Combined into one finding at line 52 (end of guard block, the natural insertion point for both additions). Severity kept as minor — both reviewers classified them minor.

Prior-round closed items confirmed resolved: R1 mixed-access @Version, R1 vacuous-pass risk, R1 audit/replica fixture gaps, R2 conjunctive && masking individual exclusion failures — all confirmed absent from HEAD.

Implementation correctness uncontested: haveAFieldOrAccessorAnnotatedWithVersion() using getAllFields()/getAllMethods() is correct.

Blast Radius

The diff is self-contained within the archunit-rules module: one production class (EntityVersionParity) gains a private condition method, and a new self-test with eight fixture classes is added. The rule applies transitively to every @Entity in any codebase that imports this library, but the change is additive — it only fixes a previously broken (always-violated) rule — so existing callers are unaffected at runtime. No cross-module dependencies are modified.

BLAST_SCORE: 3/10

CI status (head 81820d884a65)

Overall: ✓ success

2 checks: 2 pending

Check State Link
im2be-platform-libs CI / mvn install (pull_request) pending details
im2be-platform-libs CI / mvn verify (main only) (pull_request) pending details

Findings (1)

[MINOR] Guard block missing presence assertions for VersionedViaSuperclassEntity (agreed A+B) and ImmutableAppendOnlyEntity (verified unique-to-A)

archunit-rules/src/test/java/com/aim2be/platform/archunit/EntityVersionParitySelfTest.java:52

The passesForCompliantFixtures guard (lines 44–52) asserts only that VersionedFieldEntity, AuditTrailEntity, and ReplicaProjectionEntity were imported. Two fixture classes whose silent disappearance would leave key branches untested are unguarded:

  1. VersionedViaSuperclassEntity — the entity whose inherited @Version (via VersionedMappedSuperclass) is the core regression target of this entire PR. If this class or its superclass fails to compile/land on the classpath, the getAllFields() inherited-member code path goes silently unexercised while the test reports green (both reviewers independently agreed).
  2. ImmutableAppendOnlyEntity — the @Immutable-exclusion fixture. If it disappears, the @Immutable exclusion branch is never evaluated and the test still passes via allowEmptyShould(true) semantics (verified unique-to-A, confirmed at HEAD).

Add after line 52:

assertThat(positive.contain(VersionedViaSuperclassEntity.class))
        .as("VersionedViaSuperclassEntity (inherited @Version path) must be importable")
        .isTrue();
assertThat(positive.contain(ImmutableAppendOnlyEntity.class))
        .as("ImmutableAppendOnlyEntity (@Immutable exclusion path) must be importable")
        .isTrue();

Also add the corresponding imports:

import com.aim2be.platform.archunit.fixtures.positive.ImmutableAppendOnlyEntity;
import com.aim2be.platform.archunit.fixtures.positive.VersionedViaSuperclassEntity;

Verdict

CONDITIONAL_APPROVE


hib-pr-reviewer • round 3 • 1 finding (1m) • 2026-05-29T09:13:55.558Z → 2026-05-29T09:15:42.947Z • posted-as: pr-reviewer-bot

<!-- hib-pr-reviewer collapsed --> > _Superseded by round 4._ <details> <summary>Show previous round</summary> ## hib-pr-reviewer review — PR #12 (affinity-intelligence-rework/im2be-platform-libs) **Round 3** — head `81820d884a65`, base `main`, trigger `synchronize` **TL;DR:** CONDITIONAL_APPROVE — kept 1 agreed finding (VersionedViaSuperclassEntity guard gap) plus 1 verified unique-to-A finding (ImmutableAppendOnlyEntity guard gap), combined into one minor finding; no blocking issues. ### Summary ## Reconciliation — Round 3 **Memora:** No prior run history found (despite round 3); created new entry (ID 330). **Verification performed:** - Read `EntityVersionParitySelfTest.java` at HEAD (75 lines). Guard block confirmed at lines 44–52: only `VersionedFieldEntity`, `AuditTrailEntity`, and `ReplicaProjectionEntity` are asserted; `VersionedViaSuperclassEntity` and `ImmutableAppendOnlyEntity` are absent from both the import list and the guard block. - Read both fixture files at HEAD: `VersionedViaSuperclassEntity` (inherits `@Version` from `VersionedMappedSuperclass`) and `ImmutableAppendOnlyEntity` (`@Immutable` exclusion) both exist and are well-formed. **Agreed finding kept (Rule 1):** Both A and B independently flagged that `VersionedViaSuperclassEntity` — the class exercising the very regression path this PR fixes — has no presence assertion in the guard block. **Unique-to-A finding verified and kept (Rule 2):** A also flagged `ImmutableAppendOnlyEntity` having no guard assertion. Confirmed at HEAD: the class is not imported and not asserted. The `@Immutable`-exclusion path it exercises can silently disappear without any signal. Finding is valid. **Combined into one finding** at line 52 (end of guard block, the natural insertion point for both additions). Severity kept as minor — both reviewers classified them minor. **Prior-round closed items confirmed resolved:** R1 mixed-access `@Version`, R1 vacuous-pass risk, R1 audit/replica fixture gaps, R2 conjunctive `&&` masking individual exclusion failures — all confirmed absent from HEAD. **Implementation correctness uncontested:** `haveAFieldOrAccessorAnnotatedWithVersion()` using `getAllFields()`/`getAllMethods()` is correct. ### Blast Radius The diff is self-contained within the `archunit-rules` module: one production class (`EntityVersionParity`) gains a private condition method, and a new self-test with eight fixture classes is added. The rule applies transitively to every `@Entity` in any codebase that imports this library, but the change is additive — it only fixes a previously broken (always-violated) rule — so existing callers are unaffected at runtime. No cross-module dependencies are modified. **BLAST_SCORE: 3/10** ### CI status (head `81820d884a65`) **Overall: ✓ success** 2 checks: 2 pending | Check | State | Link | |---|---|---| | im2be-platform-libs CI / mvn install (pull_request) | ⏳ pending | [details](/affinity-intelligence-rework/im2be-platform-libs/actions/runs/84/jobs/0) | | im2be-platform-libs CI / mvn verify (main only) (pull_request) | ⏳ pending | [details](/affinity-intelligence-rework/im2be-platform-libs/actions/runs/84/jobs/1) | ### Findings (1) #### **[MINOR]** Guard block missing presence assertions for `VersionedViaSuperclassEntity` (agreed A+B) and `ImmutableAppendOnlyEntity` (verified unique-to-A) _archunit-rules/src/test/java/com/aim2be/platform/archunit/EntityVersionParitySelfTest.java:52_ The `passesForCompliantFixtures` guard (lines 44–52) asserts only that `VersionedFieldEntity`, `AuditTrailEntity`, and `ReplicaProjectionEntity` were imported. Two fixture classes whose silent disappearance would leave key branches untested are unguarded: 1. **`VersionedViaSuperclassEntity`** — the entity whose inherited `@Version` (via `VersionedMappedSuperclass`) is the core regression target of this entire PR. If this class or its superclass fails to compile/land on the classpath, the `getAllFields()` inherited-member code path goes silently unexercised while the test reports green (both reviewers independently agreed). 2. **`ImmutableAppendOnlyEntity`** — the `@Immutable`-exclusion fixture. If it disappears, the `@Immutable` exclusion branch is never evaluated and the test still passes via `allowEmptyShould(true)` semantics (verified unique-to-A, confirmed at HEAD). Add after line 52: ```java assertThat(positive.contain(VersionedViaSuperclassEntity.class)) .as("VersionedViaSuperclassEntity (inherited @Version path) must be importable") .isTrue(); assertThat(positive.contain(ImmutableAppendOnlyEntity.class)) .as("ImmutableAppendOnlyEntity (@Immutable exclusion path) must be importable") .isTrue(); ``` Also add the corresponding imports: ```java import com.aim2be.platform.archunit.fixtures.positive.ImmutableAppendOnlyEntity; import com.aim2be.platform.archunit.fixtures.positive.VersionedViaSuperclassEntity; ``` ### Verdict **CONDITIONAL_APPROVE** --- <sub>hib-pr-reviewer • round 3 • 1 finding (1m) • 2026-05-29T09:13:55.558Z → 2026-05-29T09:15:42.947Z • posted-as: pr-reviewer-bot</sub> </details>
Author
Owner

#315 — R3 response

Project: affinity-intelligence-rework/im2be-platform-libs • PR #12 • R3 response (human-applied) • head c195022 • 2026-05-29T09:17:53Z

TL;DR: R3 minor FIXED comprehensively — added presence guards for ALL remaining positive fixtures (not just the 2 flagged), so every rule branch is provably exercised. mvn -B -pl archunit-rules test green (2 tests, 0 warnings).

Findings

# Sev Status Resolution
1 MINOR FIXED (superset) The guard block covered 3 of 6 positive fixtures. Added presence guards for the remaining three — VersionedViaSuperclassEntity (inherited @Version, the core regression target), VersionedAccessorEntity (property-access path), ImmutableAppendOnlyEntity (@Immutable exclusion) — i.e. the 2 flagged plus the accessor fixture (the would-be next gap). All six branches (field / inherited / accessor / @Immutable / ..audit.. / ..replica..) + the negative are now guard-confirmed, so none can silently go unexercised under allowEmptyShould.

Verdict

Resolved. Production rule (EntityVersionParity.java) unchanged across the entire R-cycle — every round refined only the self-test's non-vacuity guarantees (R1: property-access fixture + initial guards + exclusion coverage; R2: per-class guard granularity; R3: complete per-fixture guarding). The rule + its self-test are now complete. Requesting re-review.

platform-libs • PR #12 • R3-response • fixed 1 (superset) / defended 0 • head c195022 • 2026-05-29T09:17:53Z

## #315 — R3 response **Project:** affinity-intelligence-rework/im2be-platform-libs • **PR #12** • R3 response (human-applied) • head `c195022` • 2026-05-29T09:17:53Z **TL;DR:** R3 minor FIXED comprehensively — added presence guards for ALL remaining positive fixtures (not just the 2 flagged), so every rule branch is provably exercised. `mvn -B -pl archunit-rules test` green (2 tests, 0 warnings). ### Findings | # | Sev | Status | Resolution | |---|-----|--------|------------| | 1 | MINOR | ✅ FIXED (superset) | The guard block covered 3 of 6 positive fixtures. Added presence guards for the remaining three — **`VersionedViaSuperclassEntity`** (inherited `@Version`, the core regression target), **`VersionedAccessorEntity`** (property-access path), **`ImmutableAppendOnlyEntity`** (`@Immutable` exclusion) — i.e. the 2 flagged **plus** the accessor fixture (the would-be next gap). All six branches (field / inherited / accessor / @Immutable / ..audit.. / ..replica..) + the negative are now guard-confirmed, so none can silently go unexercised under `allowEmptyShould`. | ### Verdict Resolved. Production rule (`EntityVersionParity.java`) unchanged across the entire R-cycle — every round refined only the self-test's non-vacuity guarantees (R1: property-access fixture + initial guards + exclusion coverage; R2: per-class guard granularity; R3: complete per-fixture guarding). The rule + its self-test are now complete. Requesting re-review. ### Footer platform-libs • PR #12 • R3-response • fixed 1 (superset) / defended 0 • head `c195022` • 2026-05-29T09:17:53Z
test(archunit): #315 R3 — guard every positive fixture's presence (no silently-skipped branch)
All checks were successful
im2be-platform-libs CI / mvn install (pull_request) Successful in 1m12s
im2be-platform-libs CI / mvn verify (main only) (pull_request) Has been skipped
c195022e08
R3 CONDITIONAL_APPROVE (1 minor). The vacuous-pass guards covered only 3 of the 6
positive fixtures, so a silent disappearance of the others would leave their branch
unexercised while the test still reported green (allowEmptyShould). Added presence
guards for ALL remaining positive fixtures — VersionedViaSuperclassEntity (inherited
@Version, the core regression target), VersionedAccessorEntity (property-access path),
ImmutableAppendOnlyEntity (@Immutable exclusion) — so every rule branch (field /
inherited / accessor / @Immutable / ..audit.. / ..replica..) is provably evaluated.

Verification:
- mvn -B -pl archunit-rules test (JDK17) -> BUILD SUCCESS, 2 tests, 0 warnings

Superseded by round 5.

Show previous round

hib-pr-reviewer review — PR #12 (affinity-intelligence-rework/im2be-platform-libs)

Round 4 — head c195022e0832, base main, trigger synchronize

TL;DR: CONDITIONAL_APPROVE — kept 1 verified minor unique-to-B finding (grammar error in violation message); all 5 carry-over findings from rounds 1–3 confirmed resolved by both reviewers.

Summary

Reconciliation Summary

Recalled Memora context: No prior run memories found for this PR or submodule tags — creating new entry (round 4 fallback path). Memora persistence failed due to server-side auto-tag validation error (memora/issues not in allowlist); all other reconciliation steps completed.

Actions taken:

  1. Memora recall: Both queries returned 0 results — first arbitration in this store for this PR.
  2. Unique-to-B finding verified (line 99, EntityVersionParity.java): Read confirmed line 99 reads entity.getName() + " is a @Entity but declares no @Version field or accessor". The article "a" before "@Entity" (vowel sound) is grammatically incorrect; it should be "an". Reviewer B is correct.
  3. Test escape confirmed (line 85, EntityVersionParitySelfTest.java): Read confirmed the failsForUnversionedEntity test asserts only .contains("no @Version field or accessor") — a suffix match that does not cover the prefix article, so the typo is not caught by any test.
  4. All 5 carry-over findings (R1–R3): Both A and B agree these are fully resolved. No re-raise warranted.
  5. Reviewer A had 0 findings — no agreed findings to keep; 1 unique-to-B finding verified and kept.

Result: Kept 1 verified unique-to-B minor finding; dropped 0.

Blast Radius

The diff touches a single ArchUnit rule module (archunit-rules) and its companion test fixtures. The production change is confined to one private static method in EntityVersionParity; the test additions are all net-new fixture classes. No exported API surface or protocol contract is modified.

BLAST_SCORE: 2/10

CI status (head c195022e0832)

Overall: ✓ success

2 checks: 2 pending

Check State Link
im2be-platform-libs CI / mvn install (pull_request) pending details
im2be-platform-libs CI / mvn verify (main only) (pull_request) pending details

Findings (1)

[MINOR] Violation message uses "a @Entity" — should be "an @Entity"

archunit-rules/src/main/java/com/aim2be/platform/archunit/EntityVersionParity.java:99

Line 99 reads:

entity.getName() + " is a @Entity but declares no @Version field or accessor"

@Entity begins with a vowel sound, so the indefinite article must be an. The existing failsForUnversionedEntity test (line 85) only asserts .contains("no @Version field or accessor") — a suffix match — so this grammatical error in the user-visible violation message is not caught by any test. Fix:

entity.getName() + " is an @Entity but declares no @Version field or accessor"

Verdict

CONDITIONAL_APPROVE


hib-pr-reviewer • round 4 • 1 finding (1m) • 2026-05-29T09:20:39.682Z → 2026-05-29T09:21:54.018Z • posted-as: pr-reviewer-bot

<!-- hib-pr-reviewer collapsed --> > _Superseded by round 5._ <details> <summary>Show previous round</summary> ## hib-pr-reviewer review — PR #12 (affinity-intelligence-rework/im2be-platform-libs) **Round 4** — head `c195022e0832`, base `main`, trigger `synchronize` **TL;DR:** CONDITIONAL_APPROVE — kept 1 verified minor unique-to-B finding (grammar error in violation message); all 5 carry-over findings from rounds 1–3 confirmed resolved by both reviewers. ### Summary ## Reconciliation Summary **Recalled Memora context:** No prior run memories found for this PR or submodule tags — creating new entry (round 4 fallback path). Memora persistence failed due to server-side auto-tag validation error (`memora/issues` not in allowlist); all other reconciliation steps completed. **Actions taken:** 1. **Memora recall:** Both queries returned 0 results — first arbitration in this store for this PR. 2. **Unique-to-B finding verified** (line 99, `EntityVersionParity.java`): `Read` confirmed line 99 reads `entity.getName() + " is a @Entity but declares no @Version field or accessor"`. The article `"a"` before `"@Entity"` (vowel sound) is grammatically incorrect; it should be `"an"`. Reviewer B is correct. 3. **Test escape confirmed** (line 85, `EntityVersionParitySelfTest.java`): `Read` confirmed the `failsForUnversionedEntity` test asserts only `.contains("no @Version field or accessor")` — a suffix match that does not cover the prefix article, so the typo is not caught by any test. 4. **All 5 carry-over findings (R1–R3):** Both A and B agree these are fully resolved. No re-raise warranted. 5. **Reviewer A had 0 findings** — no agreed findings to keep; 1 unique-to-B finding verified and kept. **Result:** Kept 1 verified unique-to-B minor finding; dropped 0. ### Blast Radius The diff touches a single ArchUnit rule module (`archunit-rules`) and its companion test fixtures. The production change is confined to one private static method in `EntityVersionParity`; the test additions are all net-new fixture classes. No exported API surface or protocol contract is modified. **BLAST_SCORE: 2/10** ### CI status (head `c195022e0832`) **Overall: ✓ success** 2 checks: 2 pending | Check | State | Link | |---|---|---| | im2be-platform-libs CI / mvn install (pull_request) | ⏳ pending | [details](/affinity-intelligence-rework/im2be-platform-libs/actions/runs/85/jobs/0) | | im2be-platform-libs CI / mvn verify (main only) (pull_request) | ⏳ pending | [details](/affinity-intelligence-rework/im2be-platform-libs/actions/runs/85/jobs/1) | ### Findings (1) #### **[MINOR]** Violation message uses "a @Entity" — should be "an @Entity" _archunit-rules/src/main/java/com/aim2be/platform/archunit/EntityVersionParity.java:99_ Line 99 reads: ```java entity.getName() + " is a @Entity but declares no @Version field or accessor" ``` `@Entity` begins with a vowel sound, so the indefinite article must be `an`. The existing `failsForUnversionedEntity` test (line 85) only asserts `.contains("no @Version field or accessor")` — a suffix match — so this grammatical error in the user-visible violation message is not caught by any test. Fix: ```java entity.getName() + " is an @Entity but declares no @Version field or accessor" ``` ### Verdict **CONDITIONAL_APPROVE** --- <sub>hib-pr-reviewer • round 4 • 1 finding (1m) • 2026-05-29T09:20:39.682Z → 2026-05-29T09:21:54.018Z • posted-as: pr-reviewer-bot</sub> </details>
fix(archunit): #315 R4 — "a @Entity" -> "an @Entity" in the violation message
All checks were successful
im2be-platform-libs CI / mvn install (pull_request) Successful in 1m27s
im2be-platform-libs CI / mvn verify (main only) (pull_request) Has been skipped
48e28f7b63
Grammar fix in the rule's user-visible violation text (@Entity begins with a vowel
sound). Last R4 minor; the production rule logic + the comprehensively-guarded
self-test are unchanged.

Verification:
- mvn -B -pl archunit-rules test (JDK17) -> BUILD SUCCESS, 2 tests, 0 warnings
hibryda deleted branch fix/entity-version-parity-field-level 2026-05-29 11:24:23 +02:00

hib-pr-reviewer review — PR #12 (affinity-intelligence-rework/im2be-platform-libs)

Round 5 — head 48e28f7b630e, base main, trigger synchronize

TL;DR: NO_NEW_FINDINGS — No new findings this round.

Summary

[quorum-converged] A=0 = B=0. ## Round 5 review — all prior findings addressed

Verified against HEAD files at the checkout path. Every open finding from rounds 1–4 is resolved:

Round Finding Status
1 VersionedAccessorEntity mixed JPA access (field @Id + getter @Version without @Access(PROPERTY)) Fixed — class now carries @Access(AccessType.PROPERTY) and both @Id/@Version are on getters
1 passesForCompliantFixtures vacuous pass Fixed — 6 individual assertThat(positive.contain(...)).isTrue() guards, one per fixture class
1 No audit/replica exclusion assertion Fixed — explicit guards for AuditTrailEntity and ReplicaProjectionEntity present at lines 50–55
2 Conjunctive && hiding which guard failed Fixed — replaced with 6 independent assertThat calls
3 Missing guards for VersionedViaSuperclassEntity and ImmutableAppendOnlyEntity Fixed — lines 56–58 and 62–64 respectively
4 Violation message used "a @Entity" Fixed — line 99 now reads "is an @Entity but declares no @Version field or accessor"

The core fix (haveAFieldOrAccessorAnnotatedWithVersion) correctly uses getAllFields() and getAllMethods() (both walk the full inheritance chain), so @MappedSuperclass-inherited private fields are visible to ArchUnit's bytecode reader and the rule correctly clears VersionedViaSuperclassEntity. No new actionable issues found.

CI status (head 48e28f7b630e)

Overall: ✓ success

2 checks: 2 pending

Check State Link
im2be-platform-libs CI / mvn install (pull_request) pending details
im2be-platform-libs CI / mvn verify (main only) (pull_request) pending details

Findings

No new findings this round.

Quorum converged on empty findings (A + B both returned 0).

Verdict

NO_NEW_FINDINGS


hib-pr-reviewer • round 5 • 0 findings • 2026-05-29T09:23:48.700Z → 2026-05-29T09:26:01.309Z • posted-as: pr-reviewer-bot • [bookkeeping fallback]

## hib-pr-reviewer review — PR #12 (affinity-intelligence-rework/im2be-platform-libs) **Round 5** — head `48e28f7b630e`, base `main`, trigger `synchronize` **TL;DR:** NO_NEW_FINDINGS — No new findings this round. ### Summary [quorum-converged] A=0 = B=0. ## Round 5 review — all prior findings addressed Verified against HEAD files at the checkout path. Every open finding from rounds 1–4 is resolved: | Round | Finding | Status | |---|---|---| | 1 | `VersionedAccessorEntity` mixed JPA access (field `@Id` + getter `@Version` without `@Access(PROPERTY)`) | ✅ Fixed — class now carries `@Access(AccessType.PROPERTY)` and both `@Id`/`@Version` are on getters | | 1 | `passesForCompliantFixtures` vacuous pass | ✅ Fixed — 6 individual `assertThat(positive.contain(...)).isTrue()` guards, one per fixture class | | 1 | No audit/replica exclusion assertion | ✅ Fixed — explicit guards for `AuditTrailEntity` and `ReplicaProjectionEntity` present at lines 50–55 | | 2 | Conjunctive `&&` hiding which guard failed | ✅ Fixed — replaced with 6 independent `assertThat` calls | | 3 | Missing guards for `VersionedViaSuperclassEntity` and `ImmutableAppendOnlyEntity` | ✅ Fixed — lines 56–58 and 62–64 respectively | | 4 | Violation message used "a @Entity" | ✅ Fixed — line 99 now reads `"is an @Entity but declares no @Version field or accessor"` | The core fix (`haveAFieldOrAccessorAnnotatedWithVersion`) correctly uses `getAllFields()` and `getAllMethods()` (both walk the full inheritance chain), so `@MappedSuperclass`-inherited private fields are visible to ArchUnit's bytecode reader and the rule correctly clears `VersionedViaSuperclassEntity`. No new actionable issues found. ### CI status (head `48e28f7b630e`) **Overall: ✓ success** 2 checks: 2 pending | Check | State | Link | |---|---|---| | im2be-platform-libs CI / mvn install (pull_request) | ⏳ pending | [details](/affinity-intelligence-rework/im2be-platform-libs/actions/runs/86/jobs/0) | | im2be-platform-libs CI / mvn verify (main only) (pull_request) | ⏳ pending | [details](/affinity-intelligence-rework/im2be-platform-libs/actions/runs/86/jobs/1) | ### Findings **No new findings this round.** _Quorum converged on empty findings (A + B both returned 0)._ ### Verdict **NO_NEW_FINDINGS** --- <sub>hib-pr-reviewer • round 5 • 0 findings • 2026-05-29T09:23:48.700Z → 2026-05-29T09:26:01.309Z • posted-as: pr-reviewer-bot • [bookkeeping fallback]</sub>
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
2 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
affinity-intelligence-rework/im2be-platform-libs!12
No description provided.