From 063b1e81364478419d1b79dc35f3ec053be29c62 Mon Sep 17 00:00:00 2001 From: James Maes Date: Fri, 6 Nov 2026 15:55:32 +0000 Subject: [PATCH 1/3] ci: pin shared workflow to v1 Co-Authored-By: Claude Opus 5.5 --- .gitea/workflows/build.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitea/workflows/build.yaml b/.gitea/workflows/build.yaml index ed42608..ce00351 100644 --- a/.gitea/workflows/build.yaml +++ b/.gitea/workflows/build.yaml @@ -3,5 +3,5 @@ on: push: jobs: maven: - uses: self:KofTwentyTwo/ci-workflows/.gitea/workflows/maven.yaml@main + uses: self:KofTwentyTwo/ci-workflows/.gitea/workflows/maven.yaml@v1 secrets: inherit -- 2.54.0 From 207e3ce0345065a58641d39636d7cf08b065168e Mon Sep 17 00:00:00 2001 From: James Maes Date: Fri, 6 Nov 2026 11:37:12 -0600 Subject: [PATCH 2/3] fix(renderer): make the renderer test suite pass on the shared CI workflow - BackgroundImageQualification expected the patched OpenHTML provider at the old fixed version 1.1.105-qqq-p1, but PR #1 publishes the vendored module at the family revision. The exact-GAV check now takes the expected version from the build's own ${revision} (surefire system property) and fails closed if absent; group, artifact, single-class-definition and companion checks are unchanged. - barHeight was advertised and accepted for every Okapi family but silently ignored by fixed-geometry encoders. It is now advertised/accepted only where it changes the symbol; the 16 fixed-geometry families and gs1-databar in STACKED mode refuse it with UNSUPPORTED_BARCODE_OPTION (catalog metadata carries notWithMode=STACKED). - UNSUPPORTED_BARCODE_OPTION now crosses the worker boundary as its closed code (foundation already models it), and PDF VALIDATE checks literal (template-free) barcode options of in-process encoders. Resolves the 3 known BarcodeDeclaredCapabilityTest failures and the PDF_PROVIDER_GAV_MISMATCH error; no tests skipped or weakened. Co-Authored-By: Claude Opus 5.5 --- docs/KNOWN-ISSUES.md | 2 +- renderer/BARCODES.md | 2 +- renderer/pom.xml | 2 +- .../qbits/renderer/BarcodeCatalog.java | 41 ++++++++++++++++++- .../kingsrook/qbits/renderer/PdfRenderer.java | 13 +++++- .../qbits/renderer/RendererMain.java | 5 ++- .../BackgroundImageQualification.java | 18 +++++++- 7 files changed, 74 insertions(+), 9 deletions(-) diff --git a/docs/KNOWN-ISSUES.md b/docs/KNOWN-ISSUES.md index 07a13ef..3f44c30 100644 --- a/docs/KNOWN-ISSUES.md +++ b/docs/KNOWN-ISSUES.md @@ -2,7 +2,7 @@ Updated: 2026-11-04. These are unresolved items, not a plan currently being executed. -- Renderer verification has **3 failing tests out of 174**: `BarcodeDeclaredCapabilityTest.barHeightIsAdvertisedAcceptedAndEffectiveTogether`, `gs1DatabarBarHeightDependsOnMode`, and `unsupportedOptionIsAClosedWorkerCode`. The imported main implementation and capability tests disagree; do not hide this by skipping tests or advertising unsupported options. +- Resolved 2026-11-06: the 3 renderer `BarcodeDeclaredCapabilityTest` failures (barHeight advertised/accepted but ignored by fixed-geometry encoders; `UNSUPPORTED_BARCODE_OPTION` not crossing the worker boundary or reported by PDF `VALIDATE`) are fixed in the implementation, not by skipping tests. - The Record Files and Scripting bridge dependencies, including their `tests` classifier artifacts, are not available as a completed public release cohort. The complete root reactor is not release-qualified. - Earlier foundation runs hit local socket exhaustion/PostgreSQL connection resets. The final 225-test run passed; the transport failures remain a reproducibility concern. - Renderer image deployment, hostile-template containment, production capacity and physical barcode/printing acceptance are not established by the Maven tests. Source-first templates are implemented; a visual designer is outside this version. diff --git a/renderer/BARCODES.md b/renderer/BARCODES.md index b612d45..35ddf4c 100644 --- a/renderer/BARCODES.md +++ b/renderer/BARCODES.md @@ -307,7 +307,7 @@ Provider contracts: [QR](https://github.com/woo-j/OkapiBarcode/blob/v0.5.7/src/m Payloads use each encoder's documented alphabet, length, checksums and application format. Library validation errors fail generation; the renderer does not truncate values or substitute another symbology. GS1 input uses Okapi's bracketed AI syntax, for example `[01]09501101530003`. GS1 syntax validation is not proof that a business identifier or carrier-specific label is authorized or operationally valid. -Common options are `barHeight` (1–1000), `dataType` (ECI/HIBC and GS1 where supported), and `eciMode` only on supporting encoders. The configured integer `scale` is 1–16; quiet zones are 4–64 modules for QR/Data Matrix/Aztec/PDF417 and conservatively 10–64 for other families. These conservative defaults are not a replacement for application-specific standards or physical barcode grading. +Common options are `barHeight` (1–1000; advertised and accepted only where it changes the symbol — the fixed-geometry families `australia-post`, `aztec`, `aztec-rune`, `code16k`, `code49`, `code-one`, `datamatrix`, `grid-matrix`, `japan-post`, `kix`, `maxicode`, `micro-qr`, `qr`, `royal-mail`, `swiss-qr`, `upn-qr`, and `gs1-databar` in `STACKED` mode, refuse it with `UNSUPPORTED_BARCODE_OPTION`, which crosses the worker boundary and is also reported by `VALIDATE` for literal options), `dataType` (ECI/HIBC and GS1 where supported), and `eciMode` only on supporting encoders. The configured integer `scale` is 1–16; quiet zones are 4–64 modules for QR/Data Matrix/Aztec/PDF417 and conservatively 10–64 for other families. These conservative defaults are not a replacement for application-specific standards or physical barcode grading. | ID / family | Additional typed options | | --- | --- | diff --git a/renderer/pom.xml b/renderer/pom.xml index 2085e25..2b02159 100644 --- a/renderer/pom.xml +++ b/renderer/pom.xml @@ -32,7 +32,7 @@ org.apache.maven.pluginsmaven-compiler-plugin3.14.1truetrue-XDcompilePolicy=simple--should-stop=ifError=FLOW-XDaddTypeAnnotationsToSymbol=true-Xplugin:ErrorProne -Xep:UnnecessaryParentheses:OFF -Xep:NotJavadoc:OFF-Xlint:all-Werrorcom.google.errorproneerror_prone_core2.49.0 - org.apache.maven.pluginsmaven-surefire-plugin3.5.4true${project.build.directory} + org.apache.maven.pluginsmaven-surefire-plugin3.5.4true${project.build.directory}${revision} org.apache.maven.pluginsmaven-dependency-plugin3.9.0runtime-librariespackagecopy-dependenciesruntime${project.build.directory}/lib org.apache.maven.pluginsmaven-jar-plugin3.4.2com.kingsrook.qbits.renderer.RendererMaintruelib/ org.apache.maven.pluginsmaven-checkstyle-plugin3.3.1com.puppycrawl.toolscheckstyle10.12.6${project.basedir}/checkstyle/config.xmlcheckstyle.reactor.root=${project.basedir}truetruewarningtruevalidatecheck diff --git a/renderer/src/main/java/com/kingsrook/qbits/renderer/BarcodeCatalog.java b/renderer/src/main/java/com/kingsrook/qbits/renderer/BarcodeCatalog.java index 188725e..21a11bf 100644 --- a/renderer/src/main/java/com/kingsrook/qbits/renderer/BarcodeCatalog.java +++ b/renderer/src/main/java/com/kingsrook/qbits/renderer/BarcodeCatalog.java @@ -51,6 +51,20 @@ public final class BarcodeCatalog { private static final Map> FACTORIES = factories(); + /******************************************************************************* + ** Families whose Okapi 0.5.7 geometry ignores barHeight (matrix, fixed-row + ** stacked and fixed-height postal symbols): barHeight is neither advertised + ** nor accepted for them, so it can never be silently ignored. + *******************************************************************************/ + private static final List FIXED_GEOMETRY = List.of("australia-post", "aztec", "aztec-rune", "code16k", "code49", "code-one", + "datamatrix", "grid-matrix", "japan-post", "kix", "maxicode", "micro-qr", "qr", "royal-mail", "swiss-qr", "upn-qr"); + + /******************************************************************************* + ** The one mode-dependent family: GS1 DataBar honors barHeight in LINEAR and + ** OMNI modes, but its STACKED rows have a fixed height. + *******************************************************************************/ + private static final String DATABAR_FIXED_MODE = "STACKED"; + /******************************************************************************* ** Utility class. @@ -142,7 +156,14 @@ public final class BarcodeCatalog { Symbol symbol = FACTORIES.get(id).get(); Map options = new LinkedHashMap<>(); - options.put("barHeight", Map.of("type", "integer", "minimum", 1, "maximum", 1000)); + if("gs1-databar".equals(id)) + { + options.put("barHeight", Map.of("type", "integer", "minimum", 1, "maximum", 1000, "notWithMode", DATABAR_FIXED_MODE)); + } + else if(!FIXED_GEOMETRY.contains(id)) + { + options.put("barHeight", Map.of("type", "integer", "minimum", 1, "maximum", 1000)); + } if(symbol instanceof Coop2Of5) { options.put("checkDigit", Map.of("type", "string", "values", List.of("NONE", "ADD", "VALIDATE"), "default", "NONE")); @@ -322,6 +343,20 @@ public final class BarcodeCatalog } + /*************************************************************************** + ** Static template preflight: literal options for in-process encoders are + ** checked without creating output; Zint and Ultracode ids keep their + ** render-time provider checks, and unknown ids are left to rendering. + ***************************************************************************/ + public static void validateLiteralOptions(String id, JsonNode options) + { + if(FACTORIES.containsKey(id) || PublicationBarcodes.IDS.contains(id)) + { + create(id, options); + } + } + + /******************************************************************************* ** Enumerate variants using only concrete compile-time enum types. *******************************************************************************/ @@ -378,6 +413,10 @@ public final class BarcodeCatalog { throw new IllegalArgumentException("UNSUPPORTED_BARCODE_OR_OPTIONS"); } + if(options.has("barHeight") && (FIXED_GEOMETRY.contains(type) || ("gs1-databar".equals(type) && DATABAR_FIXED_MODE.equals(options.path("mode").asText())))) + { + throw new IllegalArgumentException("UNSUPPORTED_BARCODE_OPTION"); + } Symbol symbol = factory.get(); structuredAppend(type, symbol, options); for(Map.Entry field : options.properties()) diff --git a/renderer/src/main/java/com/kingsrook/qbits/renderer/PdfRenderer.java b/renderer/src/main/java/com/kingsrook/qbits/renderer/PdfRenderer.java index 98a3f48..0bedff4 100644 --- a/renderer/src/main/java/com/kingsrook/qbits/renderer/PdfRenderer.java +++ b/renderer/src/main/java/com/kingsrook/qbits/renderer/PdfRenderer.java @@ -91,11 +91,22 @@ public final class PdfRenderer /******************************************************************************* - ** Syntax validation does not evaluate author code or claim layout success. + ** Syntax validation does not evaluate author code or claim layout success; literal + ** (template-free) barcode options are checked against the declared catalog. *******************************************************************************/ public static void validate(RenderInput input) throws Exception { template(input.source); + for(Element element : Jsoup.parse(input.source).select("qqq-barcode")) + { + String type = element.attr("type"); + String options = element.hasAttr("options") ? element.attr("options") : "{}"; + if(element.hasAttr("fit") || element.hasAttr("payloadencoding") || type.contains("${") || options.contains("${") || options.contains("<#")) + { + continue; + } + BarcodeCatalog.validateLiteralOptions(type, Wire.JSON.readTree(options)); + } } diff --git a/renderer/src/main/java/com/kingsrook/qbits/renderer/RendererMain.java b/renderer/src/main/java/com/kingsrook/qbits/renderer/RendererMain.java index 217ee8f..7b466c8 100644 --- a/renderer/src/main/java/com/kingsrook/qbits/renderer/RendererMain.java +++ b/renderer/src/main/java/com/kingsrook/qbits/renderer/RendererMain.java @@ -93,7 +93,7 @@ public final class RendererMain /******************************************************************************* - ** Only fixed public fit refusals cross the process boundary. Encoder messages + ** Only fixed public fit/option refusals cross the process boundary. Encoder messages ** and all other failures remain opaque because they can contain source data. *******************************************************************************/ static String errorCode(Exception failure) @@ -103,7 +103,8 @@ public final class RendererMain "BARCODE_FIT_TOO_SMALL", "BARCODE_FIT_UNSUPPORTED", "BARCODE_FIT_BOX_OUTSIDE_STOCK", "BARCODE_FIT_GEOMETRY_MISMATCH", "INVALID_BARCODE_FIT_PROFILE", "INVALID_BARCODE_FIT_REQUEST", "BARCODE_SYMBOLOGY_NOT_ALLOWED", "SYMBOLOGY_ALLOWLIST_REQUIRED", "SCANNER_BARCODE_PROFILE_UNSUPPORTED", - "SCANNER_BARCODE_PAYLOAD_UNSUPPORTED", "SCANNER_BARCODE_CHECKSUM_REQUIRED", "SCANNER_BARCODE_CHECKSUM_MISMATCH").contains(message)) + "SCANNER_BARCODE_PAYLOAD_UNSUPPORTED", "SCANNER_BARCODE_CHECKSUM_REQUIRED", "SCANNER_BARCODE_CHECKSUM_MISMATCH", + "UNSUPPORTED_BARCODE_OPTION").contains(message)) { return (message); } diff --git a/renderer/src/test/java/com/kingsrook/qbits/renderer/BackgroundImageQualification.java b/renderer/src/test/java/com/kingsrook/qbits/renderer/BackgroundImageQualification.java index 616e2da..6c0d20f 100644 --- a/renderer/src/test/java/com/kingsrook/qbits/renderer/BackgroundImageQualification.java +++ b/renderer/src/test/java/com/kingsrook/qbits/renderer/BackgroundImageQualification.java @@ -84,16 +84,30 @@ public final class BackgroundImageQualification cases += 2; } return (Map.of("cases", cases, "surfaces", List.of("element", "pseudo", "page"), "exactRgbAlphaAndDimensions", true, - "bothAliasPaintOrders", true, "provider", "com.kingsrook.thirdparty:openhtmltopdf-pdfbox:1.1.105-qqq-p1", + "bothAliasPaintOrders", true, "provider", "com.kingsrook.thirdparty:openhtmltopdf-pdfbox:" + providerVersion() + " (upstream 1.1.105 + QQQ patch p1)", "qualification", "trusted-product-fixtures-only")); } + /*************************************************************************** + ** The patched module is published at the QBit Document Generation family version (upstream 1.1.105 + QQQ + ** patch p1), so the exact expected version is the build's own revision, supplied by the build; absent fails closed. + ***************************************************************************/ + private static String providerVersion() + { + String version = System.getProperty("qbit.documentGeneration.revision"); + if(version == null || version.isBlank()) + { + throw new IllegalArgumentException("PDF_PROVIDER_EXPECTED_VERSION_MISSING"); + } + return (version); + } + /*************************************************************************** ** One provider class must come from the private patched GAV, with unchanged official companion versions. ***************************************************************************/ static void verifyProvider() throws Exception { - verifyArtifact(com.openhtmltopdf.pdfboxout.PdfBoxFastOutputDevice.class, "com.kingsrook.thirdparty", "openhtmltopdf-pdfbox", "1.1.105-qqq-p1"); + verifyArtifact(com.openhtmltopdf.pdfboxout.PdfBoxFastOutputDevice.class, "com.kingsrook.thirdparty", "openhtmltopdf-pdfbox", providerVersion()); verifyArtifact(com.openhtmltopdf.css.parser.CSSParser.class, "io.github.openhtmltopdf", "openhtmltopdf-core", "1.1.105"); verifyArtifact(org.apache.pdfbox.pdmodel.PDDocument.class, "org.apache.pdfbox", "pdfbox", "3.0.8"); } -- 2.54.0 From 6a3153456e8ad772917d2822b5f93b4114d15ebe Mon Sep 17 00:00:00 2001 From: James Maes Date: Fri, 6 Nov 2026 16:53:07 -0600 Subject: [PATCH 3/3] build: align the family on QQQ 4.1.0-RC.22 The published qbit-scripting 0.1.0-SNAPSHOT (and its tests jar) is built against QQQ Core 4.1.0-RC.22, whose Script entity carries the reviewed executionMode isolation marker. The scripting bridge pinned RC.21 through dependencyManagement, so ScriptingQBitProducer rejected the core script table ("Scripting requires the reviewed core isolation marker metadata") in every PublishedScriptContextAdapterTest. qbit-record-files and qbit-printing have also moved to RC.22, so move foundation and all bridges together rather than pinning older sibling snapshots. Co-Authored-By: Claude Opus 5.5 --- README.md | 4 ++-- bridges/printing/pom.xml | 2 +- bridges/record-files/pom.xml | 2 +- bridges/scripting/pom.xml | 2 +- foundation/pom.xml | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index a2a7899..0ed0bf5 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ Start with [current status and build prerequisites](docs/RELEASE-STATUS.md) and `foundation/` owns metadata, revisions, requests and audit contracts. `renderer/` contains rendering and vendored corresponding source. `bridges/` contains optional integrations. The root Maven reactor lists all modules. -Java 21 implementation of user-defined document metadata and generation coordination. Built against public QQQ `4.1.0-RC.21`. This is a development snapshot, not a qualified production 1.0 renderer. +Java 21 implementation of user-defined document metadata and generation coordination. Built against public QQQ `4.1.0-RC.22`. This is a development snapshot, not a qualified production 1.0 renderer. The QBit owns document types, stock, table bindings, template drafts, immutable published revisions, named asset-version references, batch pins and generation requests. It does not own retained file bytes, a scripting engine, a printer queue, or a generic workflow framework. @@ -26,7 +26,7 @@ The QBit owns document types, stock, table bindings, template drafts, immutable ## Host integration -Install metadata with `DocumentGenerationQBitProducer.withQBitConfig(config).produce(instance)`. Configure a backend through `DocumentGenerationQBitConfig.withBackendName(...)`. Registration never runs DDL automatically. Apply `DocumentGenerationSchema.mysqlScript(config)` through host migration tooling for native MySQL 8.4. `postgresScript(config)` generates the same tables for the native QQQ PostgreSQL 17 backend (and the file-H2 fixture); the PostgreSQL publication, audit and queue suites pass against `postgres:17` with QQQ 4.1.0-RC.21 (see Verification), but, as with MySQL, that does not qualify a production deployment. See [MySQL qualification](docs/MYSQL.md) for required current engine/settings, metadata mappings and deployment boundaries. +Install metadata with `DocumentGenerationQBitProducer.withQBitConfig(config).produce(instance)`. Configure a backend through `DocumentGenerationQBitConfig.withBackendName(...)`. Registration never runs DDL automatically. Apply `DocumentGenerationSchema.mysqlScript(config)` through host migration tooling for native MySQL 8.4. `postgresScript(config)` generates the same tables for the native QQQ PostgreSQL 17 backend (and the file-H2 fixture); the PostgreSQL publication, audit and queue suites pass against `postgres:17` with QQQ 4.1.0-RC.22 (see Verification), but, as with MySQL, that does not qualify a production deployment. See [MySQL qualification](docs/MYSQL.md) for required current engine/settings, metadata mappings and deployment boundaries. Use `DocumentDefinitionService` for types, stock, bindings, assets, drafts and publication. Use `DocumentGenerationService.generate`, `generateBatch` and `reprint` for operational work. Permissions are separate `document-generation.view`, `.configure`, `.publish`, `.generate` and `.print`; each generation/print additionally enforces current source-record access. diff --git a/bridges/printing/pom.xml b/bridges/printing/pom.xml index 957621b..939ac6e 100644 --- a/bridges/printing/pom.xml +++ b/bridges/printing/pom.xml @@ -4,7 +4,7 @@ com.kingsrook.qbitsqbit-document-generation-reactor${revision}../../pom.xml com.kingsrook.qbitsqbit-document-generation-printing${revision} Document Generation Printing Bridge - 4.1.0-RC.210.1.0-SNAPSHOT21noneUTF-8 + 4.1.0-RC.220.1.0-SNAPSHOT21noneUTF-8 1.0.0true com.kingsrook.qqqqqq-bom-pom${qqq.version}pomimport diff --git a/bridges/record-files/pom.xml b/bridges/record-files/pom.xml index 873f8c6..68c07dd 100644 --- a/bridges/record-files/pom.xml +++ b/bridges/record-files/pom.xml @@ -4,7 +4,7 @@ com.kingsrook.qbitsqbit-document-generation-reactor${revision}../../pom.xml com.kingsrook.qbitsqbit-document-generation-record-files${revision} Document Generation Record Files Bridge - 4.1.0-RC.210.1.0-SNAPSHOT21noneUTF-8true + 4.1.0-RC.220.1.0-SNAPSHOT21noneUTF-8true com.kingsrook.qqqqqq-bom-pom${qqq.version}pomimport com.kingsrook.qqqqqq-backend-core${qqq.version} com.kingsrook.qqqqqq-backend-module-rdbms${qqq.version} diff --git a/bridges/scripting/pom.xml b/bridges/scripting/pom.xml index feb5bb2..69873e3 100644 --- a/bridges/scripting/pom.xml +++ b/bridges/scripting/pom.xml @@ -5,7 +5,7 @@ com.kingsrook.qbitsqbit-document-generation-scripting${revision} Document Generation Scripting Bridge GNU Affero General Public License v3.0https://www.gnu.org/licenses/agpl-3.0-standalone.htmlrepo - 4.1.0-RC.210.1.0-SNAPSHOT21noneUTF-8true + 4.1.0-RC.220.1.0-SNAPSHOT21noneUTF-8true com.kingsrook.qqqqqq-backend-core${qqq.version} com.kingsrook.qqqqqq-backend-module-rdbms${qqq.version} diff --git a/foundation/pom.xml b/foundation/pom.xml index 92cb84f..775333f 100644 --- a/foundation/pom.xml +++ b/foundation/pom.xml @@ -7,7 +7,7 @@ ${revision} QBit Document Generation User-defined document templates and generation coordination for QQQ - 4.1.0-RC.212121noneUTF-8false + 4.1.0-RC.222121noneUTF-8false Apache License, Version 2.0https://www.apache.org/licenses/LICENSE-2.0repo com.kingsrook.qqqqqq-bom-pom${qqq.version}pomimport -- 2.54.0