test(architecture): the rules assert against packages that exist - #1158
Merged
Conversation
Three constants named `net.blueshell.api.infrastructure`, removed by the architecture ADR-003 flattening, so every rule built on them matched nothing. SECURITY and PERMISSION now name `security` and `security.permission`, which is where ADR-003 puts them; INFRASTRUCTURE has no successor package and its two dependents are answered without it. Adds the missing vendor-import rule: only the module that wraps a generated client under `net.blueshell.clients` may import it. The one existing reach, cohort's BrevoTargetStrategy, is pinned in a decaying allowlist.
4 tasks
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.
Closes #1157.
Why
ArchitecturePackagesdeclaredINFRASTRUCTURE,SECURITYandPERMISSIONagainstnet.blueshell.api.infrastructure, a package architecture ADR-003 removed in the flattening.ArchUnit does not complain about a glob that matches nothing, so four rules were selecting an empty
set and passing. The most load-bearing of them is the one ADR-007 names as its enforcement: a
*Permissionwritten into the central permission package today would have passed.Separately, nothing looked at a third-party import at all. Modulith stops at the
net.blueshell.apiboundary, socohort/domain/BrevoTargetStrategyinjecting Brevo's generatedContactsApi— which API ADR-019 forbids in prose — compiled and verified cleanly.What this achieves
A
*Permissionin a central package fails the build, and so does a vendor client imported outsidethe module that wraps it. Both were rules on paper only.
How
SECURITYandPERMISSIONnow namesecurityandsecurity.permission, where ADR-003 putsthe auth filter chain and the two evaluators that stay central. That makes both their rules live:
configuration does not depend on web controllersnow actually covers the security config, and theADR-007 rule now sees the package it is guarding.
INFRASTRUCTUREis deleted rather than repointed. There is no successor package — ADR-003distributes cross-cutting concerns into
security,sharedand the application root, so anyrepointing would have been a guess dressed as a fix. Its two dependents are answered directly:
no field injection in application codelisted four layer packages, two of which(
APPLICATION,INFRASTRUCTURE) no longer exist. It now selectsnet.blueshell.api...Constructor injection is wanted everywhere, so the layer list was never doing anything the
broader selector does not do better. Still passes: the
@Autowiredoccurrences in main are allon constructors.
only the web layer reaches a domain module's web packageis deleted as redundant. Bothsides of it were dead — it also selected
net.blueshell.api.domain..web.., another grouping levelthe flattening removed — and
CrossModuleWebAccessArchitectureTeststates the stronger versionagainst today's packages: no module reaches another module's web package, whatever layer the
reach comes from. A note in the class header records the retirement, next to the one already
there for
domain model and domain services must not depend on outer layers.VendorClientArchitectureTestis new.VENDOR_OWNERSmaps each vendor undernet.blueshell.clientsto the module that wraps it (brevo -> contact,discord -> sync); anyother module reaching those types is a violation, and so is a vendor with no declared owner, which
makes adding a client a decision someone has to write down. It follows
CrossModuleWebAccessArchitectureTest's shape exactly: aPINNEDset, plus a second test thatfails when a pinned reach disappears so the ratchet cannot slip back.
The commented-out cycle rule is gone. Modulith verification covers cycles.
Not in scope
BrevoTargetStrategyis pinned, not fixed — six reaches from one class, the only violation in thecodebase. It is the double-port problem in
cohort: the class pushes list membership throughcontact'sContactListAdapterbut drives Brevo'sContactsApidirectly for the list catalog andfolder names, so one integration sits behind two ports and one of them is raw. Removing it means
publishing the catalog side — list enumeration, folder names, the paging that goes with them —
through
contact :: apisocohortspeaks only to the wrapper, which is acontactAPI designchange rather than an import edit. Worth its own issue.
The stale-constant problem is wider than the three this issue names:
APPLICATION,DOMAIN_WEB,DOMAIN_APPLICATION,LISTENER,EVENT,FACTORY,QUERYand most of thePLATFORM_INTEGRATIONfamily also name packages the flattening removed, so more rules than theseare quietly vacuous. Auditing all of them is a bigger sweep than this issue asked for.
Worth a reviewer's attention
Deleting a rule rather than repointing it is the arguable call, and it is made twice — once for the
INFRASTRUCTUREconstant and once for the domain-web rule. The test is whether anything is lost:for the domain-web rule nothing is, because the sibling test is strictly stronger; for the constant
nothing is, because the field-injection rule got wider rather than narrower.
vendorOfkeys on the first segment undernet.blueshell.clients, so a client published under adeeper or differently shaped package would read as an unknown vendor and fail loudly. That is the
intended failure mode, but it is a convention the map depends on.
Verification
./gradlew :services:api:test --tests '*ArchitectureTest*' --tests '*ArchTest*'— exit 0, 71passed.
./gradlew :services:api:test— exit 0, 916 passed.The ADR-007 rule was watched failing. A
ProbePermissionclass was placed innet.blueshell.api.security.permission, and the rule reported:DecoratorsArchitectureTest's "evaluators must be@Component" rule caught it in the same run,which is a second rule confirmed live. The probe class was removed; the run above is with it gone.
The vendor rule was likewise watched failing before
PINNEDwas filled, reporting the threereaches
BrevoTargetStrategymakes through return types rather than imports —GetFolder,GetFolders200Response,GetLists200Response— which is why the pinned set is six entries andnot the three the issue's
git grepshows.Diff breakdown —
█added░removed, scaled to the largest row.