feat(guardrails): architecture guardrails G1/G2/G3/G4/G7, report-first (#9) #10

Merged
KofTwentyTwo merged 1 commits from feature/architecture-guardrails into main 2026-10-14 00:57:57 +00:00
KofTwentyTwo commented 2026-10-14 00:56:40 +00:00 (Migrated from github.com)

Summary

Closes #9: guardrails G1, G2, G3, G4 and G7 from architecture review QRun-IO/qqq#1150, section 5. G5 (no HTML widgets) waits for the core typed widgets (qqq#1151).

Shape. The repo becomes a two-module reactor:

  • com.kingsrook:qbit-build-parent, the existing pom, now at 2.1.0;
  • com.kingsrook:qbit-guardrails, a new jar. It has no parent, which avoids a cycle. It depends on ArchUnit core, the JUnit Jupiter API and maven-artifact, and does not depend on QQQ.

A parent profile qbit-guardrails is active unless -Dqbit.guardrails.skip=true. It adds the jar in test scope and runs its *GuardrailTest classes inside each qbit's surefire run through dependenciesToScan, with configuration merged, not overridden. It also runs the enforcer at validate.

Rollout without breakage. Every rule only reports by default: the enforcer has fail=false, and the tests pass while printing [qbit-guardrails] Gx FAIL (report-only) lines. A qbit opts in with <qbit.guardrails.enforce>true</qbit.guardrails.enforce> and, for G2, <qbit.guardrails.strictUiApiRoutes>true</qbit.guardrails.strictUiApiRoutes>.

Rule Check
G1-deps Enforcer bannedDependencies: com.kingsrook.qbits:* in compile/runtime/provided/system scope (direct and transitive) is banned, except qbit-object-storage and *-api artifacts.
G1-arch ArchUnit: main classes in com.kingsrook.qbits.<own>.. depend only on their own packages, com.kingsrook.qqq.., the JDK, libraries and allowed com.kingsrook.qbits.<y>.api...
G1-literals Source scan: string literals naming another qbit's classes, e.g. Class.forName("com.kingsrook.qbits.alerts..."). Reports file and line.
G2 Forwards qqq.uiApi.strictRoutes=true to tests; core reads it on RC.6+. The default flips with core RC.7 (qqq#1159).
G3 If main code references MiddlewareSpecExtension, the qbit needs a committed openapi/qqq-v1/*.yaml and a test that uses UiApiContract/UiApiContractAssertions. Raw /qqq/v1 route literals are always reported as warnings.
G4 STAND-IN(core=OWNER/REPO#N, removeBy=VERSION): fails when the core version on the classpath (qqq-backend-core pom.properties) is at or past removeBy (ComparableVersion), or when a marker is malformed. Untagged "stand-in" prose is listed as a warning.
G7 Enforcer requireReleaseDeps for com.kingsrook.qqq:* and com.kingsrook.qbits:*. The project's own SNAPSHOT revision is fine.

The README has the full grammar, properties and opt-in instructions.

What fails today (enforce=true, against each qbit's develop)

qbit Fails
qbit-easypost-tracking G1-deps (qbit-alerts), G1-arch (17 edges into alerts internals), G1-literals ("...AlertsRuntime"). Fixed by qbit-easypost-tracking#16.
qbit-marketing G1-deps (qbit-assistant), G1-arch (180 edges into assistant internals). Waits for qbit-assistant-provider-api (assistant#30, then marketing#9).
qbit-assistant G1-deps (provider modules), G7 (assistant SNAPSHOT dependencies).
qbit-secured-data G7 (QQQ 4.1.0-SNAPSHOT; secured-data#4).
qbit-collaboration G1-arch: 1 edge, StorageBucketConfig.getMaxUploadBytes() from object-storage's non-api package.
alerts, sql-workbench, backups, object-storage, cdn, webhooks, quick-search, authentik, data-analysis, web-performance, cms pass

Raw /qqq/v1 route warnings: alerts (/alerts), sql-workbench (/sql-workbench) and assistant (/assistant). The first two are fixed by qbit-alerts' extension PR and qbit-sql-workbench#21.

Verification

  • mvn -B verify and install: 17 unit tests.
  • 18 enforcer integration cases (wildcards, scopes, optional deps, SNAPSHOT parents).
  • A consumer smoke test in report and enforce modes.
  • A fleet trial over the 16 qbits: 80 guardrail tests, with the 4 failing qbits listed above.

Consumer note: the trials used Maven 3.9.11, because Maven 3.10.0 hits an existing ${revision} parent-model error in consumers.

After merge

The release captain publishes qbit-build-parent 2.1.0 and qbit-guardrails 2.1.0 together. Qbits then move their parent to 2.1.0; the passing ones can set qbit.guardrails.enforce=true straight away.

🤖 Generated with Claude Code

## Summary Closes #9: guardrails G1, G2, G3, G4 and G7 from architecture review QRun-IO/qqq#1150, section 5. G5 (no HTML widgets) waits for the core typed widgets (qqq#1151). **Shape.** The repo becomes a two-module reactor: - `com.kingsrook:qbit-build-parent`, the existing pom, now at 2.1.0; - `com.kingsrook:qbit-guardrails`, a new jar. It has no parent, which avoids a cycle. It depends on ArchUnit core, the JUnit Jupiter API and maven-artifact, and does not depend on QQQ. A parent profile `qbit-guardrails` is active unless `-Dqbit.guardrails.skip=true`. It adds the jar in test scope and runs its `*GuardrailTest` classes inside each qbit's surefire run through `dependenciesToScan`, with configuration merged, not overridden. It also runs the enforcer at `validate`. **Rollout without breakage.** Every rule **only reports by default**: the enforcer has `fail=false`, and the tests pass while printing `[qbit-guardrails] Gx FAIL (report-only)` lines. A qbit opts in with `<qbit.guardrails.enforce>true</qbit.guardrails.enforce>` and, for G2, `<qbit.guardrails.strictUiApiRoutes>true</qbit.guardrails.strictUiApiRoutes>`. | Rule | Check | |---|---| | G1-deps | Enforcer `bannedDependencies`: `com.kingsrook.qbits:*` in compile/runtime/provided/system scope (direct and transitive) is banned, except `qbit-object-storage` and `*-api` artifacts. | | G1-arch | ArchUnit: main classes in `com.kingsrook.qbits.<own>..` depend only on their own packages, `com.kingsrook.qqq..`, the JDK, libraries and allowed `com.kingsrook.qbits.<y>.api..`. | | G1-literals | Source scan: string literals naming another qbit's classes, e.g. `Class.forName("com.kingsrook.qbits.alerts...")`. Reports file and line. | | G2 | Forwards `qqq.uiApi.strictRoutes=true` to tests; core reads it on RC.6+. The default flips with core RC.7 (qqq#1159). | | G3 | If main code references `MiddlewareSpecExtension`, the qbit needs a committed `openapi/qqq-v1/*.yaml` and a test that uses `UiApiContract`/`UiApiContractAssertions`. Raw `/qqq/v1` route literals are always reported as warnings. | | G4 | `STAND-IN(core=OWNER/REPO#N, removeBy=VERSION)`: fails when the core version on the classpath (`qqq-backend-core` pom.properties) is at or past removeBy (ComparableVersion), or when a marker is malformed. Untagged "stand-in" prose is listed as a warning. | | G7 | Enforcer `requireReleaseDeps` for `com.kingsrook.qqq:*` and `com.kingsrook.qbits:*`. The project's own SNAPSHOT revision is fine. | The README has the full grammar, properties and opt-in instructions. ## What fails today (enforce=true, against each qbit's `develop`) | qbit | Fails | |---|---| | qbit-easypost-tracking | G1-deps (qbit-alerts), G1-arch (17 edges into alerts internals), G1-literals (`"...AlertsRuntime"`). **Fixed by qbit-easypost-tracking#16.** | | qbit-marketing | G1-deps (qbit-assistant), G1-arch (180 edges into assistant internals). Waits for `qbit-assistant-provider-api` (assistant#30, then marketing#9). | | qbit-assistant | G1-deps (provider modules), G7 (assistant SNAPSHOT dependencies). | | qbit-secured-data | G7 (QQQ `4.1.0-SNAPSHOT`; secured-data#4). | | qbit-collaboration | G1-arch: 1 edge, `StorageBucketConfig.getMaxUploadBytes()` from object-storage's non-`api` package. | | alerts, sql-workbench, backups, object-storage, cdn, webhooks, quick-search, authentik, data-analysis, web-performance, cms | pass | Raw `/qqq/v1` route warnings: alerts (`/alerts`), sql-workbench (`/sql-workbench`) and assistant (`/assistant`). The first two are fixed by qbit-alerts' extension PR and qbit-sql-workbench#21. ## Verification - `mvn -B verify` and `install`: 17 unit tests. - 18 enforcer integration cases (wildcards, scopes, optional deps, SNAPSHOT parents). - A consumer smoke test in report and enforce modes. - A fleet trial over the 16 qbits: 80 guardrail tests, with the 4 failing qbits listed above. Consumer note: the trials used Maven 3.9.11, because Maven 3.10.0 hits an existing `${revision}` parent-model error in consumers. ## After merge The release captain publishes `qbit-build-parent` 2.1.0 and `qbit-guardrails` 2.1.0 together. Qbits then move their parent to 2.1.0; the passing ones can set `qbit.guardrails.enforce=true` straight away. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
Sign in to join this conversation.