Re-pins qbit-workflows to com.kingsrook:qbit-build-parent:2.0.0 (qqq 4.0.0 GA, Java 21) and verifies it on qqq 4.1.0-SNAPSHOT, so qqq-all can include it (plan task B6). The first commit back-merges main into develop, because main had 12 commits that develop lacked.
Merge this PR with a merge commit (not squash, not rebase). The first commit is the main back-merge; squashing or rebasing drops main from the history, and main and develop would diverge again.
34f620echore: merge main into develop (git merge --no-ff origin/main). Brings in main's Apache-2.0 LICENSE and NOTICE, .github/CODEOWNERS, .github/release.yml, CLAUDE.md, and the standardized README. Conflict resolutions are in the table below.
dd7c7f4build: re-pin to qbit-build-parent 2.0.0 (qqq 4.0.0)
Parent 1.5.1 to 2.0.0.
Removed the explicit <version>0.40.0-join-enhancements-24cb9791-20260216.220349-1</version> from qqq-backend-core, qqq-middleware-api and qqq-backend-module-rdbms, so the parent's qqq BOM (or the qqq-snapshot profile) sets them. That throwaway build no longer resolves anywhere. The join fix it carried (QRun-IO/qqq#400) is in qqq 4.0.0.
qqq-frontend-material-dashboard 0.27.0-RC.1 to 0.41.0 (see the next section).
qqq 4.0 API removals, migrated per docs/migration/4.0.adoc in qqq:
BREAK-04-26: InputRecordFilterStep.validate and RecordWorkflowUtils.updateFilterForApi now build a GetTableApiFieldsInput (api name, version, table). The removed ApiNameVersionAndTableName overload did exactly this, so behavior is unchanged.
BREAK-03-B: RunRecordWorkflowExtractStep now overrides customizeInputPreQuery(RunBackendStepInput, QueryInput). It sets includeAssociations and then calls super, so the process callback still runs after it, as before.
BREAK-04-11 (test only): BaseTest uses withInstanceDefaultAuthentication(...) in place of setAuthentication(...).
ca909fdtest: cover api field names in filters and extract associations. These are new tests for the migrated paths, which had no tests before:
InputRecordFilterStepTest.testFilterUsingApiFieldNames: a v1 filter on shoeCount matches the record's noOfShoes.
InputRecordFilterStepTest.testValidateUsingApiFieldNames: shoeCount is valid in v1, and noOfShoes is rejected in v1 because it joined the api in v2.
RunRecordWorkflowProcessTest.testExtractStepIncludesAssociations: checks that the extract step fetches associations.
3418279build: add opt-in qqq-snapshot profile.-Pqqq-snapshot imports qqq-bom-pom:${qqq.snapshot.version} (default 4.1.0-SNAPSHOT) ahead of the parent's BOM and adds the Central snapshots repository. It is the same profile as qbit-quick-search. Default builds get qqq only from the parent.
d1a8515ci: keep package installs unattended on machine executors. Copies the configure-package-install command from qbit-quick-search develop and adds it as a pre-steps entry on all 6 orb jobs. This keeps needrestart from hanging install_java (QRun-IO/qqq-orb#11). Orb stays at develop's kingsrook/qqq-orb@0.6.
7ac729edocs: the README prerequisite is now "QQQ application (v4.0.0+)" (it said v0.35.0+), and the stale build facts in CLAUDE.md are updated.
qqq-frontend-material-dashboard
The build needs this dependency, so it stays. Main source imports it: the form adjusters (FormAdjusterInterface, RunFormAdjusterProcess), MaterialDashboardFieldMetaData/MaterialDashboardTableMetaData, and field rules, in UpdateInputRecordFieldStep, UpdateInputRecordFieldMetaDataAdjuster, WorkflowTestAssertion and the two WorkflowTestAssertion*FieldMetaDataAdjusters. It is not in qqq-bom-pom, so it keeps an explicit version.
0.27.0-RC.1 was built for qqq 0.27.9 and does not work on qqq 4.0. With it, all 52 tests error with NoClassDefFoundError: com/kingsrook/qqq/backend/javalin/QJavalinMetaData, because qqq 4.0 moved that class to com.kingsrook.qqq.middleware.javalin. 0.41.0 is the release built for qqq 4.0.0 (Java 21), and it also passes on 4.1.0-SNAPSHOT.
Merge conflict resolutions
File
develop
main
Resolution
.circleci/config.yml
kingsrook/qqq-orb@0.6 (8770f63), plus a publish_feature workflow
Kept develop. 0.6 is newer, and develop's CI is green on it (build 89). The rest of develop's file, including publish_feature, is kept.
pom.xml<revision>
0.114.0-SNAPSHOT (set to 0.113.0 in 4f115e5, then CI-bumped)
0.4.0 (the 0.4.0 release bump)
Kept develop. 0.4.0 is already released, and develop's line is higher, so taking main's value would move develop's snapshots backwards. I did not choose the next release number.
Everything else merged cleanly. The parent bump in main (1.4.0 to 1.5.1) was already on develop. LICENSE (Apache-2.0), NOTICE, CODEOWNERS, release.yml, CLAUDE.md and the README came from main unchanged; develop had no LICENSE file.
Plan items with nothing to change here:
No child qqq-bom-pom import shadowed the parent.
There are no Docker-backed tests: every test uses in-memory H2 and the memory backend. So "fail, not skip, when CI=true" does not apply.
Type of Change
Bug fix (non-breaking change that fixes an issue): develop could not build at all (its pinned qqq build no longer resolves)
New feature (non-breaking change that adds functionality)
Breaking change (fix or feature that would cause existing functionality to not work as expected): consumers now need qqq 4.x
Documentation update
Refactoring (no functional changes)
Dependencies update
Testing
Everything ran in a fresh clone on Java 21.0.12.1 and Maven 3.9.16. The repo has no mvnw, so these are plain mvn runs. I never ran mvn install.
I added the third gate because the shared ~/.m2 holds a locally installed 4.1.0-SNAPSHOT (localCopy=true). The isolated repository shows the build passes against the published snapshot.
CircleCI config: I parsed it with Ruby's YAML loader, which shows pre-steps: [configure-package-install] on all 6 jobs. circleci config validate cannot check it locally, because it cannot see kingsrook/qqq-orb in the registry. The unmodified develop and main configs fail the same way. The real check is CircleCI on this PR: build 90 (qqq-orb/mvn_test_only, with the pre-step) passed.
Unit tests pass (mvn test)
Integration tests pass (mvn verify)
Manual testing performed
Checklist
My code follows the project's style guidelines
I have performed a self-review of my own code
I have commented my code, particularly in hard-to-understand areas (the profile and CI command carry comments; the migrations need none)
I have made corresponding changes to the documentation
My changes generate no new warnings (see the parent warning below)
I have added tests that prove my fix is effective or that my feature works
New and existing unit tests pass locally with my changes
Additional Notes
Upstream parent warning, not fixed here: every build logs [WARNING] Failed to build parent project for com.kingsrook.qbits:qbit-workflows:jar:0.114.0-SNAPSHOT. The published qbit-build-parent-2.0.0.pom declares its own version as the literal ${revision}. The effective model is still correct (qqq 4.0.0, Java 21). The fix belongs in qbit-bom, and it affects every qbit on 2.0.0.
Licensing left as is: this PR edits no license text. LICENSE and NOTICE arrive unchanged from main through the back-merge. The pom <licenses> block (AGPL-3.0), the source headers and checkstyle/license.txt are untouched. Aligning them is a separate owner decision.
Also left alone: the rest of the README (CLAUDE.md notes that it does not describe this codebase), CHANGELOG.md, the Kingsrook URLs in <url>/<scm>, and the open dependabot branch.
Not merged; this needs review first.
## Summary
Re-pins `qbit-workflows` to `com.kingsrook:qbit-build-parent:2.0.0` (qqq 4.0.0 GA, Java 21) and verifies it on qqq `4.1.0-SNAPSHOT`, so qqq-all can include it (plan task B6). The first commit back-merges `main` into `develop`, because `main` had 12 commits that `develop` lacked.
**Merge this PR with a merge commit** (not squash, not rebase). The first commit is the `main` back-merge; squashing or rebasing drops `main` from the history, and `main` and `develop` would diverge again.
Closes QRun-IO/qqq#768
Part of QRun-IO/qqq-all#1
## Changes
- `34f620e` **chore: merge main into develop** (`git merge --no-ff origin/main`). Brings in main's Apache-2.0 `LICENSE` and `NOTICE`, `.github/CODEOWNERS`, `.github/release.yml`, `CLAUDE.md`, and the standardized README. Conflict resolutions are in the table below.
- `dd7c7f4` **build: re-pin to qbit-build-parent 2.0.0 (qqq 4.0.0)**
- Parent 1.5.1 to 2.0.0.
- Removed the explicit `<version>0.40.0-join-enhancements-24cb9791-20260216.220349-1</version>` from `qqq-backend-core`, `qqq-middleware-api` and `qqq-backend-module-rdbms`, so the parent's qqq BOM (or the `qqq-snapshot` profile) sets them. That throwaway build no longer resolves anywhere. The join fix it carried (QRun-IO/qqq#400) is in qqq 4.0.0.
- `qqq-frontend-material-dashboard` 0.27.0-RC.1 to 0.41.0 (see the next section).
- qqq 4.0 API removals, migrated per `docs/migration/4.0.adoc` in qqq:
- BREAK-04-26: `InputRecordFilterStep.validate` and `RecordWorkflowUtils.updateFilterForApi` now build a `GetTableApiFieldsInput` (api name, version, table). The removed `ApiNameVersionAndTableName` overload did exactly this, so behavior is unchanged.
- BREAK-03-B: `RunRecordWorkflowExtractStep` now overrides `customizeInputPreQuery(RunBackendStepInput, QueryInput)`. It sets `includeAssociations` and then calls `super`, so the process callback still runs after it, as before.
- BREAK-04-11 (test only): `BaseTest` uses `withInstanceDefaultAuthentication(...)` in place of `setAuthentication(...)`.
- `ca909fd` **test: cover api field names in filters and extract associations.** These are new tests for the migrated paths, which had no tests before:
- `InputRecordFilterStepTest.testFilterUsingApiFieldNames`: a v1 filter on `shoeCount` matches the record's `noOfShoes`.
- `InputRecordFilterStepTest.testValidateUsingApiFieldNames`: `shoeCount` is valid in v1, and `noOfShoes` is rejected in v1 because it joined the api in v2.
- `RunRecordWorkflowProcessTest.testExtractStepIncludesAssociations`: checks that the extract step fetches associations.
- `3418279` **build: add opt-in qqq-snapshot profile.** `-Pqqq-snapshot` imports `qqq-bom-pom:${qqq.snapshot.version}` (default `4.1.0-SNAPSHOT`) ahead of the parent's BOM and adds the Central snapshots repository. It is the same profile as qbit-quick-search. Default builds get qqq only from the parent.
- `d1a8515` **ci: keep package installs unattended on machine executors.** Copies the `configure-package-install` command from qbit-quick-search `develop` and adds it as a `pre-steps` entry on all 6 orb jobs. This keeps needrestart from hanging `install_java` (QRun-IO/qqq-orb#11). Orb stays at develop's `kingsrook/qqq-orb@0.6`.
- `7ac729e` **docs:** the README prerequisite is now "QQQ application (v4.0.0+)" (it said v0.35.0+), and the stale build facts in `CLAUDE.md` are updated.
### qqq-frontend-material-dashboard
The build needs this dependency, so it stays. Main source imports it: the form adjusters (`FormAdjusterInterface`, `RunFormAdjusterProcess`), `MaterialDashboardFieldMetaData`/`MaterialDashboardTableMetaData`, and field rules, in `UpdateInputRecordFieldStep`, `UpdateInputRecordFieldMetaDataAdjuster`, `WorkflowTestAssertion` and the two `WorkflowTestAssertion*FieldMetaDataAdjuster`s. It is not in `qqq-bom-pom`, so it keeps an explicit version.
0.27.0-RC.1 was built for qqq 0.27.9 and does not work on qqq 4.0. With it, all 52 tests error with `NoClassDefFoundError: com/kingsrook/qqq/backend/javalin/QJavalinMetaData`, because qqq 4.0 moved that class to `com.kingsrook.qqq.middleware.javalin`. 0.41.0 is the release built for qqq 4.0.0 (Java 21), and it also passes on 4.1.0-SNAPSHOT.
### Merge conflict resolutions
| File | develop | main | Resolution |
|---|---|---|---|
| `.circleci/config.yml` | `kingsrook/qqq-orb@0.6` (8770f63), plus a `publish_feature` workflow | `kingsrook/qqq-orb@0.5.0` (Java 21 PR #4) | **Kept develop.** 0.6 is newer, and develop's CI is green on it (build 89). The rest of develop's file, including `publish_feature`, is kept. |
| `pom.xml` `<revision>` | `0.114.0-SNAPSHOT` (set to 0.113.0 in 4f115e5, then CI-bumped) | `0.4.0` (the 0.4.0 release bump) | **Kept develop.** 0.4.0 is already released, and develop's line is higher, so taking main's value would move develop's snapshots backwards. I did not choose the next release number. |
Everything else merged cleanly. The parent bump in main (1.4.0 to 1.5.1) was already on develop. `LICENSE` (Apache-2.0), `NOTICE`, `CODEOWNERS`, `release.yml`, `CLAUDE.md` and the README came from main unchanged; develop had no `LICENSE` file.
Plan items with nothing to change here:
- No child `qqq-bom-pom` import shadowed the parent.
- There are no Docker-backed tests: every test uses in-memory H2 and the memory backend. So "fail, not skip, when `CI=true`" does not apply.
## Type of Change
- [x] Bug fix (non-breaking change that fixes an issue): develop could not build at all (its pinned qqq build no longer resolves)
- [ ] New feature (non-breaking change that adds functionality)
- [x] Breaking change (fix or feature that would cause existing functionality to not work as expected): consumers now need qqq 4.x
- [x] Documentation update
- [ ] Refactoring (no functional changes)
- [x] Dependencies update
## Testing
Everything ran in a fresh clone on Java 21.0.12.1 and Maven 3.9.16. The repo has no `mvnw`, so these are plain `mvn` runs. I never ran `mvn install`.
| # | Command | Result |
|---|---|---|
| 1 | `mvn -B verify` on untouched `origin/develop` | **BUILD FAILURE**: cannot resolve `qqq-backend-core`, `qqq-middleware-api`, `qqq-backend-module-rdbms` `0.40.0-join-enhancements-24cb9791-20260216.220349-1` |
| 2 | `git merge --no-ff origin/main` | Conflicts in `.circleci/config.yml` and `pom.xml`, resolved as above |
| 3 | Parent 2.0.0 and explicit versions removed, then `mvn -B clean verify` | **FAIL** (compile): `GetTableApiFieldsAction.ApiNameVersionAndTableName` not found; `customizeInputPreQuery(QueryInput)` does not override |
| 4 | New tests written, API calls migrated, then `mvn -B clean verify` | **FAIL** (test compile): `QInstance.setAuthentication` not found |
| 5 | `BaseTest` migrated (material dashboard still 0.27.0-RC.1), then `mvn -B clean verify` | **FAIL**: 52 tests, 52 errors, `NoClassDefFoundError: com/kingsrook/qqq/backend/javalin/QJavalinMetaData` |
| 6 | Material dashboard 0.41.0, with the extract override only calling `super` (no `setIncludeAssociations`), then `mvn -B clean verify` | **FAIL (red)**: 52 tests, 1 failure, `testExtractStepIncludesAssociations` expected `true` but was `false` |
| 7 | `setIncludeAssociations(true)` restored, then `mvn -B clean verify` | BUILD SUCCESS, 52 tests, 0 failures |
| 8 | `dd7c7f4` alone (new tests stashed), then `mvn -B clean verify` | BUILD SUCCESS, 49 tests, 0 failures (each commit builds) |
| 9 | Before the profile: `mvn -B dependency:tree -Pqqq-snapshot -Dincludes=com.kingsrook.qqq` | "The requested profile qqq-snapshot could not be activated because it does not exist"; qqq resolves to 4.0.0 (red) |
| 10 | After the profile: same command, and again without `-Pqqq-snapshot` | With the profile, every qqq module resolves to 4.1.0-SNAPSHOT. Without it, they stay on 4.0.0 |
| 11 | `mvn -B checkstyle:check -Dcheckstyle.config.location=checkstyle/config.xml -Dcheckstyle.includeTestSourceDirectory=true -Dcheckstyle.failOnViolation=false` | No findings in changed files. The 12 warnings are all in files this PR does not touch |
Final gates on HEAD `7ac729e`:
| Gate | Command | Result |
|---|---|---|
| qqq 4.0.0 (parent) | `mvn -B verify` | BUILD SUCCESS, 52 tests, 0 failures, 0 errors, 0 skipped |
| qqq 4.1.0-SNAPSHOT | `mvn -B verify -Pqqq-snapshot` | BUILD SUCCESS, 52 tests, 0 failures, 0 errors, 0 skipped |
| qqq 4.1.0-SNAPSHOT, published artifacts only | `mvn -B -U verify -Pqqq-snapshot -Dmaven.repo.local=/tmp/b6-m2-snapshot` | BUILD SUCCESS, 52 tests, 0 failures. Resolved `qqq-backend-core-4.1.0-20260926.013614-9` from central.sonatype.com snapshots |
| Java 21 | `javap -v` on a compiled class | class file major version 65 |
I added the third gate because the shared `~/.m2` holds a locally installed `4.1.0-SNAPSHOT` (`localCopy=true`). The isolated repository shows the build passes against the published snapshot.
CircleCI config: I parsed it with Ruby's YAML loader, which shows `pre-steps: [configure-package-install]` on all 6 jobs. `circleci config validate` cannot check it locally, because it cannot see `kingsrook/qqq-orb` in the registry. The unmodified develop and main configs fail the same way. The real check is CircleCI on this PR: build 90 (`qqq-orb/mvn_test_only`, with the pre-step) passed.
- [x] Unit tests pass (`mvn test`)
- [x] Integration tests pass (`mvn verify`)
- [ ] Manual testing performed
## Checklist
- [x] My code follows the project's style guidelines
- [x] I have performed a self-review of my own code
- [x] I have commented my code, particularly in hard-to-understand areas (the profile and CI command carry comments; the migrations need none)
- [x] I have made corresponding changes to the documentation
- [ ] My changes generate no new warnings (see the parent warning below)
- [x] I have added tests that prove my fix is effective or that my feature works
- [x] New and existing unit tests pass locally with my changes
## Additional Notes
- **Upstream parent warning, not fixed here:** every build logs `[WARNING] Failed to build parent project for com.kingsrook.qbits:qbit-workflows:jar:0.114.0-SNAPSHOT`. The published `qbit-build-parent-2.0.0.pom` declares its own version as the literal `${revision}`. The effective model is still correct (qqq 4.0.0, Java 21). The fix belongs in `qbit-bom`, and it affects every qbit on 2.0.0.
- **Licensing left as is:** this PR edits no license text. `LICENSE` and `NOTICE` arrive unchanged from main through the back-merge. The pom `<licenses>` block (AGPL-3.0), the source headers and `checkstyle/license.txt` are untouched. Aligning them is a separate owner decision.
- **Also left alone:** the rest of the README (`CLAUDE.md` notes that it does not describe this codebase), `CHANGELOG.md`, the `Kingsrook` URLs in `<url>`/`<scm>`, and the open dependabot branch.
- Not merged; this needs review first.
No blocking issues. I reviewed HEAD 7ac729e against plan task B6 and the Global Constraints. Routed through local--review-pr: Deep tier (537/79 across 14 files; CI config and dependency changes). Passes run: code, tests, error handling.
Blocking
None.
Non-blocking
Merge with a merge commit. The repo allows squash and rebase. Either one drops main as a parent of 34f620e and undoes the back-merge. The PR body already says this. Step 1 asked for a separate back-merge PR first; folding it in here matches the B2–B5 re-pins.
LICENSE/NOTICE come in through the back-merge. James should confirm. develop had no LICENSE. After the merge it has main's Apache-2.0 LICENSE and NOTICE, while the pom <licenses> and file headers stay AGPL-3.0. Taking main's files is the right resolution (dropping them would delete LICENSE from main at the next release), and the implementer edited no license text. It still adds a license file to develop, so it needs the owner's decision under the plan's Licensing rule, the same as B2.
README version mismatch. The prerequisite now says qqq v4.0.0+, but the install snippet still pins qbit-workflows0.4.0, which is built on qqq 0.35. Update the snippet when the next release ships. The rest of the README (the QWorkflowMetaData state-machine API) does not describe this codebase. That text came from main, and CLAUDE.md says so.
ADR-0007 in the pom comment cannot be found from this repo. The qqq-snapshot profile comment cites it, but no ADR is in the repo. Either point to where it lives or drop the reference. (qbit-quick-search has the same comment.)
Closes QRun-IO/qqq#768 will not auto-close the issue. The repo's default branch is main and this PR targets develop. Close#768 by hand after merge.
Test gap (small).testExtractStepIncludesAssociations checks the flag, but no test checks that a process callback's customizeInputPreQuery still runs (that is, that super is called). The code is right. It is just not pinned by a test.
Parent ${revision} warning. Agreed that the fix belongs upstream in qbit-bom.
Verified
B6 requirements
Step 1: 34f620e has parents 80a6326 (develop) and 23ade22 (main). git log HEAD..origin/main is empty. Since the merge base, main changed only CI (orb 0.5.0), the pom (revision 0.4.0, parent 1.5.1, which develop already had) and new files. The merge takes all of main's new files and keeps develop's orb @0.6, publish_feature and 0.114.0-SNAPSHOT. git diff origin/develop 34f620e touches no source, so main's changes are all kept and develop loses nothing.
Step 2: parent is qbit-build-parent:2.0.0. No child qqq-bom-pom import outside the opt-in profile. Class files are major version 65 (Java 21).
Step 3: qqq-snapshot has no activation. qqq.snapshot.version defaults to 4.1.0-SNAPSHOT, the profile imports qqq-bom-pom:${qqq.snapshot.version} and adds the Central snapshots repository. dependency:tree with the profile shows every qqq module at 4.1.0-SNAPSHOT, and without it they are at 4.0.0. help:active-profiles lists the profile.
Step 4: no Docker-backed tests (H2 and the memory backend only), so it does not apply.
Step 5: the three explicit 0.40.0-join-enhancements-* versions are gone. qqq-frontend-material-dashboard keeps an explicit version because it is not in qqq-bom-pom 4.0.0. 0.41.0 is its latest release on Central, and its pom targets qqq.version 4.0.0 on Java 21.
qqq 4.0 migrations (checked against qqq tags v0.35.0, v0.40.0 and v4.0.0)
BREAK-04-26: the removed getTableApiFieldMap(ApiNameVersionAndTableName) built new GetTableApiFieldsInput().withTableName(..).withApiName(..).withVersion(..), which is what both call sites now do. The memoization key and the default inputSource are unchanged.
BREAK-03-B: in 0.35 the two-argument hook called the one-argument override (which set includeAssociations) and then the process callback. The new override sets the flag and then calls super, which runs the callback. The order is the same as before.
Tests
I checked that each new test fails when its fix is broken, using a scratch clone. Deleting setIncludeAssociations(true) makes testExtractStepIncludesAssociations fail ("expected true but was false"). Changing InputRecordFilterStep.validate to pass withVersion("v2") makes testValidateUsingApiFieldNames fail.
testFilterUsingApiFieldNames goes through execute into WorkflowStepUtils.useApi and RecordWorkflowUtils.updateFilterForApi, so both migrated call sites are covered.
Builds (fresh clone of 7ac729e, plain mvn, no mvn install)
BUILD SUCCESS, 52/52. Downloaded qqq-backend-core-4.1.0-20260926.014717-10.jar from sonatype-snapshots
mvn checkstyle:check with checkstyle/config.xml and test sources (not wired into the build)
12 warnings, none in files this PR touches
Coverage
Neither parent 1.5.1 nor 2.0.0 configures JaCoCo, so there is no coverage gate
Other
CI: qqq-orb/mvn_test_only (build 90) and test_only are green. The PR is mergeable (CLEAN). The configure-package-install command is identical to qbit-quick-search develop, and a YAML parse shows it as pre-steps on all 6 jobs. $nrconf{restart} is single-quoted, so the shell does not expand it.
Secrets: a scan of the diff found no credentials, tokens or keys. CODEOWNERS is * @KofTwentyTwo.
Not merged. The merge is James's call.
## Review, round 1 (plan task B6): approve
No blocking issues. I reviewed HEAD `7ac729e` against plan task B6 and the Global Constraints. Routed through `local--review-pr`: Deep tier (537/79 across 14 files; CI config and dependency changes). Passes run: code, tests, error handling.
### Blocking
None.
### Non-blocking
- **Merge with a merge commit.** The repo allows squash and rebase. Either one drops `main` as a parent of `34f620e` and undoes the back-merge. The PR body already says this. Step 1 asked for a separate back-merge PR first; folding it in here matches the B2–B5 re-pins.
- **LICENSE/NOTICE come in through the back-merge. James should confirm.** develop had no `LICENSE`. After the merge it has main's Apache-2.0 `LICENSE` and `NOTICE`, while the pom `<licenses>` and file headers stay AGPL-3.0. Taking main's files is the right resolution (dropping them would delete `LICENSE` from `main` at the next release), and the implementer edited no license text. It still adds a license file to develop, so it needs the owner's decision under the plan's Licensing rule, the same as B2.
- **README version mismatch.** The prerequisite now says qqq v4.0.0+, but the install snippet still pins `qbit-workflows` `0.4.0`, which is built on qqq 0.35. Update the snippet when the next release ships. The rest of the README (the `QWorkflowMetaData` state-machine API) does not describe this codebase. That text came from main, and `CLAUDE.md` says so.
- **`ADR-0007` in the pom comment cannot be found from this repo.** The `qqq-snapshot` profile comment cites it, but no ADR is in the repo. Either point to where it lives or drop the reference. (qbit-quick-search has the same comment.)
- **`Closes QRun-IO/qqq#768` will not auto-close the issue.** The repo's default branch is `main` and this PR targets `develop`. Close #768 by hand after merge.
- **Test gap (small).** `testExtractStepIncludesAssociations` checks the flag, but no test checks that a process callback's `customizeInputPreQuery` still runs (that is, that `super` is called). The code is right. It is just not pinned by a test.
- **Parent `${revision}` warning.** Agreed that the fix belongs upstream in `qbit-bom`.
### Verified
**B6 requirements**
- Step 1: `34f620e` has parents `80a6326` (develop) and `23ade22` (main). `git log HEAD..origin/main` is empty. Since the merge base, main changed only CI (orb 0.5.0), the pom (`revision` 0.4.0, parent 1.5.1, which develop already had) and new files. The merge takes all of main's new files and keeps develop's orb `@0.6`, `publish_feature` and `0.114.0-SNAPSHOT`. `git diff origin/develop 34f620e` touches no source, so main's changes are all kept and develop loses nothing.
- Step 2: parent is `qbit-build-parent:2.0.0`. No child `qqq-bom-pom` import outside the opt-in profile. Class files are major version 65 (Java 21).
- Step 3: `qqq-snapshot` has no activation. `qqq.snapshot.version` defaults to `4.1.0-SNAPSHOT`, the profile imports `qqq-bom-pom:${qqq.snapshot.version}` and adds the Central snapshots repository. `dependency:tree` with the profile shows every qqq module at `4.1.0-SNAPSHOT`, and without it they are at `4.0.0`. `help:active-profiles` lists the profile.
- Step 4: no Docker-backed tests (H2 and the memory backend only), so it does not apply.
- Step 5: the three explicit `0.40.0-join-enhancements-*` versions are gone. `qqq-frontend-material-dashboard` keeps an explicit version because it is not in `qqq-bom-pom` 4.0.0. 0.41.0 is its latest release on Central, and its pom targets `qqq.version` 4.0.0 on Java 21.
**qqq 4.0 migrations** (checked against qqq tags `v0.35.0`, `v0.40.0` and `v4.0.0`)
- BREAK-04-26: the removed `getTableApiFieldMap(ApiNameVersionAndTableName)` built `new GetTableApiFieldsInput().withTableName(..).withApiName(..).withVersion(..)`, which is what both call sites now do. The memoization key and the default `inputSource` are unchanged.
- BREAK-03-B: in 0.35 the two-argument hook called the one-argument override (which set `includeAssociations`) and then the process callback. The new override sets the flag and then calls `super`, which runs the callback. The order is the same as before.
**Tests**
- I checked that each new test fails when its fix is broken, using a scratch clone. Deleting `setIncludeAssociations(true)` makes `testExtractStepIncludesAssociations` fail ("expected true but was false"). Changing `InputRecordFilterStep.validate` to pass `withVersion("v2")` makes `testValidateUsingApiFieldNames` fail.
- `testFilterUsingApiFieldNames` goes through `execute` into `WorkflowStepUtils.useApi` and `RecordWorkflowUtils.updateFilterForApi`, so both migrated call sites are covered.
**Builds** (fresh clone of `7ac729e`, plain `mvn`, no `mvn install`)
| Command | Result |
|---|---|
| `mvn -B clean verify` | BUILD SUCCESS, 52 tests, 0 failures, 0 errors, 0 skipped |
| `mvn -B clean verify -Pqqq-snapshot` | BUILD SUCCESS, 52/52 |
| `mvn -B -U clean verify -Pqqq-snapshot -Dmaven.repo.local=/tmp/b6-rev-m2` (published artifacts only) | BUILD SUCCESS, 52/52. Downloaded `qqq-backend-core-4.1.0-20260926.014717-10.jar` from `sonatype-snapshots` |
| `mvn checkstyle:check` with `checkstyle/config.xml` and test sources (not wired into the build) | 12 warnings, none in files this PR touches |
| Coverage | Neither parent 1.5.1 nor 2.0.0 configures JaCoCo, so there is no coverage gate |
**Other**
- CI: `qqq-orb/mvn_test_only` (build 90) and `test_only` are green. The PR is mergeable (`CLEAN`). The `configure-package-install` command is identical to qbit-quick-search `develop`, and a YAML parse shows it as `pre-steps` on all 6 jobs. `$nrconf{restart}` is single-quoted, so the shell does not expand it.
- Secrets: a scan of the diff found no credentials, tokens or keys. `CODEOWNERS` is `* @KofTwentyTwo`.
Not merged. The merge is James's call.
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Summary
Re-pins
qbit-workflowstocom.kingsrook:qbit-build-parent:2.0.0(qqq 4.0.0 GA, Java 21) and verifies it on qqq4.1.0-SNAPSHOT, so qqq-all can include it (plan task B6). The first commit back-mergesmainintodevelop, becausemainhad 12 commits thatdeveloplacked.Merge this PR with a merge commit (not squash, not rebase). The first commit is the
mainback-merge; squashing or rebasing dropsmainfrom the history, andmainanddevelopwould diverge again.Closes QRun-IO/qqq#768
Part of QRun-IO/qqq-all#1
Changes
34f620echore: merge main into develop (git merge --no-ff origin/main). Brings in main's Apache-2.0LICENSEandNOTICE,.github/CODEOWNERS,.github/release.yml,CLAUDE.md, and the standardized README. Conflict resolutions are in the table below.dd7c7f4build: re-pin to qbit-build-parent 2.0.0 (qqq 4.0.0)<version>0.40.0-join-enhancements-24cb9791-20260216.220349-1</version>fromqqq-backend-core,qqq-middleware-apiandqqq-backend-module-rdbms, so the parent's qqq BOM (or theqqq-snapshotprofile) sets them. That throwaway build no longer resolves anywhere. The join fix it carried (QRun-IO/qqq#400) is in qqq 4.0.0.qqq-frontend-material-dashboard0.27.0-RC.1 to 0.41.0 (see the next section).docs/migration/4.0.adocin qqq:InputRecordFilterStep.validateandRecordWorkflowUtils.updateFilterForApinow build aGetTableApiFieldsInput(api name, version, table). The removedApiNameVersionAndTableNameoverload did exactly this, so behavior is unchanged.RunRecordWorkflowExtractStepnow overridescustomizeInputPreQuery(RunBackendStepInput, QueryInput). It setsincludeAssociationsand then callssuper, so the process callback still runs after it, as before.BaseTestuseswithInstanceDefaultAuthentication(...)in place ofsetAuthentication(...).ca909fdtest: cover api field names in filters and extract associations. These are new tests for the migrated paths, which had no tests before:InputRecordFilterStepTest.testFilterUsingApiFieldNames: a v1 filter onshoeCountmatches the record'snoOfShoes.InputRecordFilterStepTest.testValidateUsingApiFieldNames:shoeCountis valid in v1, andnoOfShoesis rejected in v1 because it joined the api in v2.RunRecordWorkflowProcessTest.testExtractStepIncludesAssociations: checks that the extract step fetches associations.3418279build: add opt-in qqq-snapshot profile.-Pqqq-snapshotimportsqqq-bom-pom:${qqq.snapshot.version}(default4.1.0-SNAPSHOT) ahead of the parent's BOM and adds the Central snapshots repository. It is the same profile as qbit-quick-search. Default builds get qqq only from the parent.d1a8515ci: keep package installs unattended on machine executors. Copies theconfigure-package-installcommand from qbit-quick-searchdevelopand adds it as apre-stepsentry on all 6 orb jobs. This keeps needrestart from hanginginstall_java(QRun-IO/qqq-orb#11). Orb stays at develop'skingsrook/qqq-orb@0.6.7ac729edocs: the README prerequisite is now "QQQ application (v4.0.0+)" (it said v0.35.0+), and the stale build facts inCLAUDE.mdare updated.qqq-frontend-material-dashboard
The build needs this dependency, so it stays. Main source imports it: the form adjusters (
FormAdjusterInterface,RunFormAdjusterProcess),MaterialDashboardFieldMetaData/MaterialDashboardTableMetaData, and field rules, inUpdateInputRecordFieldStep,UpdateInputRecordFieldMetaDataAdjuster,WorkflowTestAssertionand the twoWorkflowTestAssertion*FieldMetaDataAdjusters. It is not inqqq-bom-pom, so it keeps an explicit version.0.27.0-RC.1 was built for qqq 0.27.9 and does not work on qqq 4.0. With it, all 52 tests error with
NoClassDefFoundError: com/kingsrook/qqq/backend/javalin/QJavalinMetaData, because qqq 4.0 moved that class tocom.kingsrook.qqq.middleware.javalin. 0.41.0 is the release built for qqq 4.0.0 (Java 21), and it also passes on 4.1.0-SNAPSHOT.Merge conflict resolutions
.circleci/config.ymlkingsrook/qqq-orb@0.6(8770f63), plus apublish_featureworkflowkingsrook/qqq-orb@0.5.0(Java 21 PR #4)publish_feature, is kept.pom.xml<revision>0.114.0-SNAPSHOT(set to 0.113.0 in4f115e5, then CI-bumped)0.4.0(the 0.4.0 release bump)Everything else merged cleanly. The parent bump in main (1.4.0 to 1.5.1) was already on develop.
LICENSE(Apache-2.0),NOTICE,CODEOWNERS,release.yml,CLAUDE.mdand the README came from main unchanged; develop had noLICENSEfile.Plan items with nothing to change here:
qqq-bom-pomimport shadowed the parent.CI=true" does not apply.Type of Change
Testing
Everything ran in a fresh clone on Java 21.0.12.1 and Maven 3.9.16. The repo has no
mvnw, so these are plainmvnruns. I never ranmvn install.mvn -B verifyon untouchedorigin/developqqq-backend-core,qqq-middleware-api,qqq-backend-module-rdbms0.40.0-join-enhancements-24cb9791-20260216.220349-1git merge --no-ff origin/main.circleci/config.ymlandpom.xml, resolved as abovemvn -B clean verifyGetTableApiFieldsAction.ApiNameVersionAndTableNamenot found;customizeInputPreQuery(QueryInput)does not overridemvn -B clean verifyQInstance.setAuthenticationnot foundBaseTestmigrated (material dashboard still 0.27.0-RC.1), thenmvn -B clean verifyNoClassDefFoundError: com/kingsrook/qqq/backend/javalin/QJavalinMetaDatasuper(nosetIncludeAssociations), thenmvn -B clean verifytestExtractStepIncludesAssociationsexpectedtruebut wasfalsesetIncludeAssociations(true)restored, thenmvn -B clean verifydd7c7f4alone (new tests stashed), thenmvn -B clean verifymvn -B dependency:tree -Pqqq-snapshot -Dincludes=com.kingsrook.qqq-Pqqq-snapshotmvn -B checkstyle:check -Dcheckstyle.config.location=checkstyle/config.xml -Dcheckstyle.includeTestSourceDirectory=true -Dcheckstyle.failOnViolation=falseFinal gates on HEAD
7ac729e:mvn -B verifymvn -B verify -Pqqq-snapshotmvn -B -U verify -Pqqq-snapshot -Dmaven.repo.local=/tmp/b6-m2-snapshotqqq-backend-core-4.1.0-20260926.013614-9from central.sonatype.com snapshotsjavap -von a compiled classI added the third gate because the shared
~/.m2holds a locally installed4.1.0-SNAPSHOT(localCopy=true). The isolated repository shows the build passes against the published snapshot.CircleCI config: I parsed it with Ruby's YAML loader, which shows
pre-steps: [configure-package-install]on all 6 jobs.circleci config validatecannot check it locally, because it cannot seekingsrook/qqq-orbin the registry. The unmodified develop and main configs fail the same way. The real check is CircleCI on this PR: build 90 (qqq-orb/mvn_test_only, with the pre-step) passed.mvn test)mvn verify)Checklist
Additional Notes
[WARNING] Failed to build parent project for com.kingsrook.qbits:qbit-workflows:jar:0.114.0-SNAPSHOT. The publishedqbit-build-parent-2.0.0.pomdeclares its own version as the literal${revision}. The effective model is still correct (qqq 4.0.0, Java 21). The fix belongs inqbit-bom, and it affects every qbit on 2.0.0.LICENSEandNOTICEarrive unchanged from main through the back-merge. The pom<licenses>block (AGPL-3.0), the source headers andcheckstyle/license.txtare untouched. Aligning them is a separate owner decision.CLAUDE.mdnotes that it does not describe this codebase),CHANGELOG.md, theKingsrookURLs in<url>/<scm>, and the open dependabot branch.Review, round 1 (plan task B6): approve
No blocking issues. I reviewed HEAD
7ac729eagainst plan task B6 and the Global Constraints. Routed throughlocal--review-pr: Deep tier (537/79 across 14 files; CI config and dependency changes). Passes run: code, tests, error handling.Blocking
None.
Non-blocking
mainas a parent of34f620eand undoes the back-merge. The PR body already says this. Step 1 asked for a separate back-merge PR first; folding it in here matches the B2–B5 re-pins.LICENSE. After the merge it has main's Apache-2.0LICENSEandNOTICE, while the pom<licenses>and file headers stay AGPL-3.0. Taking main's files is the right resolution (dropping them would deleteLICENSEfrommainat the next release), and the implementer edited no license text. It still adds a license file to develop, so it needs the owner's decision under the plan's Licensing rule, the same as B2.qbit-workflows0.4.0, which is built on qqq 0.35. Update the snippet when the next release ships. The rest of the README (theQWorkflowMetaDatastate-machine API) does not describe this codebase. That text came from main, andCLAUDE.mdsays so.ADR-0007in the pom comment cannot be found from this repo. Theqqq-snapshotprofile comment cites it, but no ADR is in the repo. Either point to where it lives or drop the reference. (qbit-quick-search has the same comment.)Closes QRun-IO/qqq#768will not auto-close the issue. The repo's default branch ismainand this PR targetsdevelop. Close #768 by hand after merge.testExtractStepIncludesAssociationschecks the flag, but no test checks that a process callback'scustomizeInputPreQuerystill runs (that is, thatsuperis called). The code is right. It is just not pinned by a test.${revision}warning. Agreed that the fix belongs upstream inqbit-bom.Verified
B6 requirements
34f620ehas parents80a6326(develop) and23ade22(main).git log HEAD..origin/mainis empty. Since the merge base, main changed only CI (orb 0.5.0), the pom (revision0.4.0, parent 1.5.1, which develop already had) and new files. The merge takes all of main's new files and keeps develop's orb@0.6,publish_featureand0.114.0-SNAPSHOT.git diff origin/develop 34f620etouches no source, so main's changes are all kept and develop loses nothing.qbit-build-parent:2.0.0. No childqqq-bom-pomimport outside the opt-in profile. Class files are major version 65 (Java 21).qqq-snapshothas no activation.qqq.snapshot.versiondefaults to4.1.0-SNAPSHOT, the profile importsqqq-bom-pom:${qqq.snapshot.version}and adds the Central snapshots repository.dependency:treewith the profile shows every qqq module at4.1.0-SNAPSHOT, and without it they are at4.0.0.help:active-profileslists the profile.0.40.0-join-enhancements-*versions are gone.qqq-frontend-material-dashboardkeeps an explicit version because it is not inqqq-bom-pom4.0.0. 0.41.0 is its latest release on Central, and its pom targetsqqq.version4.0.0 on Java 21.qqq 4.0 migrations (checked against qqq tags
v0.35.0,v0.40.0andv4.0.0)getTableApiFieldMap(ApiNameVersionAndTableName)builtnew GetTableApiFieldsInput().withTableName(..).withApiName(..).withVersion(..), which is what both call sites now do. The memoization key and the defaultinputSourceare unchanged.includeAssociations) and then the process callback. The new override sets the flag and then callssuper, which runs the callback. The order is the same as before.Tests
setIncludeAssociations(true)makestestExtractStepIncludesAssociationsfail ("expected true but was false"). ChangingInputRecordFilterStep.validateto passwithVersion("v2")makestestValidateUsingApiFieldNamesfail.testFilterUsingApiFieldNamesgoes throughexecuteintoWorkflowStepUtils.useApiandRecordWorkflowUtils.updateFilterForApi, so both migrated call sites are covered.Builds (fresh clone of
7ac729e, plainmvn, nomvn install)mvn -B clean verifymvn -B clean verify -Pqqq-snapshotmvn -B -U clean verify -Pqqq-snapshot -Dmaven.repo.local=/tmp/b6-rev-m2(published artifacts only)qqq-backend-core-4.1.0-20260926.014717-10.jarfromsonatype-snapshotsmvn checkstyle:checkwithcheckstyle/config.xmland test sources (not wired into the build)Other
qqq-orb/mvn_test_only(build 90) andtest_onlyare green. The PR is mergeable (CLEAN). Theconfigure-package-installcommand is identical to qbit-quick-searchdevelop, and a YAML parse shows it aspre-stepson all 6 jobs.$nrconf{restart}is single-quoted, so the shell does not expand it.CODEOWNERSis* @KofTwentyTwo.Not merged. The merge is James's call.