Describe EMDK and optional AIM evidence, public QQQ RC.21 with qualified owner inputs, current Gitea review links, and implemented profile tooling. Remove stale test counts while retaining the physical acceptance limits. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Echo — scan a barcode and print a copy
Echo is an optional QQQ example application, using the shared Android scanner host. Choose a currently authorized printer and its supported paper/label profile once, then scan repeatedly. Each scan preserves its string value and actual symbology and uses the existing Document Generation → retained original → native Printing path. One event is admitted per run at a time. A successful acknowledgment means queued, not confirmed physical paper.
The source implements ordinary QQQ metadata and processes; no Echo-specific Android screen, business endpoint, barcode encoder or print queue is added. There is deliberately no fabricated printer, hardcoded stock, administrative-permission shortcut or in-process renderer fallback.
Status. The owner adapters and host composition are source-complete and pass verify (Checkstyle clean) against the qualified owner inputs described under Build and acceptance, and the runnable demo passes its tests, including a complete composed acceptance (current counts and progress: session state): an authenticated approved scanner, two scans, two retained originals and two accepted Printing jobs on one printer, an idempotent retry and leaving. That automated acceptance uses a controlled synthetic renderer and a simulated Printing queue.
The composed demo runs as one local server with a real Printing client, printer and 4x1 media, and a published Echo barcode document. A TC22 completed setup against it (printer, media and document, then Next) and Cancel then Leave. A separate, explicitly synthetic native HTTP event now completes the real render/retain/print pipeline: one ECHO-HTTP-TEST-001 Code128 job reached SPOOLED with a Windows spooler job assigned, and its Echo process closed successfully. This is printer delivery evidence, not physical trigger, paper output or rescan confirmation. See the delivery receipt. Public Maven publication and full production acceptance remain open.
The actual renderer's Code128 and leading-zero QR outputs now pass independent pixel decoding and 4x1 stock/fit checks. See the rendering evidence and scannable test images. This no-print check does not replace physical acceptance.
Host composition
- Install/configure the existing Mobile Scanners, Document Generation and retained-source Printing integration under their owner-qualified dependency tuple. Use the same backend/data source for Echo metadata and its state schema. Apply
echo-h2.sqlthrough host migrations; registration performs no DDL. - Configure Document Generation to allow
echoScanas a source table. Publish appropriate immutable barcode templates through its ordinary definition service and isolated worker. Stock measurements are micrometres with explicit DPI. Do not generate or publish a new template on every scan. EchoPrintingDestinationsimplements the destination seam from Printing's public operator authorization (PrintingOperatorAuthorization) and reported media profiles.authorizechecks the current actor, printer row, device and ZPL format and pins the exact reported media profile id and revision.planreauthorizes, then reads the published template revision with enforced permissions and requires its stock to equal that media. The setup step's printer field uses Printing's own table possible values (enabled and available printers);EchoMediaChoicesis a semantic possible-value provider that returns only the sizes of the printer already selected. App-selected document dimensions do not imply changing Windows printer stock.EchoDocumentGeneratorcalls Generation's publicgenerateand read-onlylookupAcceptedPrintwith the exact template, revision, stock and selected media profile, under the stable keyecho:<scanId>.QUEUEDis returned only for a durable, available retained receipt with a job id and the same media profile. Absent or unavailable lookup evidence refuses. It never uses the side-effectingreconcilecall or plain byte submission.EchoHost.install(instance, deployment)composes the above from the owners' public classes: Record Files retained output and print source,PrintingDispatch.forOwnerMediaEnforcement(source)(the owner's explicit adoption factory), Generation with its durable audit, then Echo. Registration order matters: Printing, then Echo'sechoScantable, then Generation, which validates its source tables. The isolated renderer,PrintingServiceand template map are deployment inputs; absent ones are refused. Grant the operatorecho.use, ordinary mobile scanning and the owner-approved generation and print-submit permissions. Do not grantprinting_adminto make Echo work.EchoTemplatePublisher.publishis the one-time operator action that publishes the ZPL barcode template for one reported media profile.
Supply the renderer's configured byte limit as Deployment.maximumOutputBytes. Both demo launchers propagate ECHO_RENDERER_MAXIMUM_BYTES to Generation and the renderer. Leaving Generation at its 20 MiB owner default with a 1 MiB renderer rejects every render request before the worker starts. The composed acceptance uses a bounded renderer and a nondefault 256 KiB cap. Existing six-argument Deployment callers retain the owner default and must only use it with a renderer that accepts that allowance.
The process begins with server-owned run state, shows printer/media setup, then loops only between the semantic SCANNER frontend and the print backend. Its native Cancel step closes the run, including cancellation during setup. Already processing or accepted work may still print; leaving prevents new admission and retains receipts. Protected framework process identity, rather than an echoed run ID alone, binds the selected printer to that process.
Copies per scan
Setup asks Copies per scan: an optional ordinary integer form field, default 1, registered with core ValueRangeBehavior limits of 1 and 100 (inclusive, error) so the native client's validation.minValue/maxValue match the server. Omitted, null or blank means 1; fractions, 0, 101 and non-numbers are rejected at setup. The server validates it, pins it on the run (echo_run.copies, a non-null additive column that defaults existing runs to 1) and uses that pinned count for every scan until Leave. A repeated setup can confirm but not change it, and a differing scan-stage copies value is refused before any event row exists; the value never decides what is printed. The scanner instructions state the count when it is above one. Bounds are Printing's own: a whole number from 1 to 100, expressed by that owner as the copies option of one print job, so Echo never queues one job per copy or renders per copy, and retries and lookup reuse the same pinned count.
EchoDocumentGenerator builds DocumentGenerationService.Request(..., mediaProfile, copies) with the run's pinned count, so Generation binds it to the echo:<scanId> key and its printing bridge submits one job with options.copies; the accepted-print lookup compares the committed count with the pinned one before Echo adopts a job. This needs the Generation copies cohort (GenerationPorts.PrintRequest/Request with the appended copies, the request-table copies migration 20261102-print-copies-h2.sql, and a Printing owner that honors options.copies); an owner without supportsCopies() refuses a count above 1 before any row, render or submit. Physical copy counts are not verified.
Fidelity and retries
The first explicit mapping covers CODE128, QRCODE, CODE39, Data Matrix, PDF417 and Aztec scanner identifiers and their documented legacy label aliases. Leading zeros are never parsed as numbers. EAN13/EAN8/UPCA/UPCE0 are admitted only with the scanner's AIM identifier (]E0, EAN-8 ]E4), a full-length value of the exact length with a valid GS1 check digit (UPC-E number system 0 only), and a document published with EchoTemplatePublisher.publishScannerFidelity. That separate, clearly named scanner-fidelity document passes the recorded scanner label and AIM identifier (echoScan.symbology, new nullable echoScan.aimIdentifier) to the renderer's scanner mode, which verifies them again and converts the value. It requires an AIM identifier on every scan, so the original plain document stays the choice for older scanners and servers; an EAN/UPC scan on a plain document, or a scan without AIM on a scanner-fidelity document, is refused before any print and the operator leaves Echo to choose the other document. The AIM column is an additive, nullable migration in echo-h2.sql (other databases need the equivalent); a retry is bound to the stored AIM. UNKNOWN, manual input, unsupported variants and control/binary/GS1 payloads are refused until their exact metadata/encoder profile is qualified. When the canonical scan context carries the optional mobile-scanners 1.5 evidence, Echo checks it before admission: an aimIdentifier other than the renderer's plain-mode identifier for that type (for example ]C1, ]Q3, ]A4) is refused as a GS1/ECI/structured mode, and rawDataBase64 must decode to exactly the ASCII bytes of the display value. Absent evidence (legacy 1.4 servers, older clients, or a Zebra read where the host did not confirm its AIM output profile by configuration read-back) is admitted as before and proves nothing, and physical AIM output on the handheld is not yet qualified; no fidelity is inferred from the display string. No symbology is inferred from value or substituted with QR/Code128.
Each canonical mobile scan has one durable echoScan source with the same ID and a stable echo:<scanId> generation request key across every run. A duplicate accepted event in the same run returns its existing job; moving that event into another run is rejected. A deliberate new trigger event with the same value is a new print intent. A changed value/type/source/timestamp cannot reuse the event. An uncertain/crashed call never automatically renders or prints again: recovery requires read-only exact owner acceptance evidence; absent/unavailable evidence remains visibly unconfirmed and the user may leave. Independent decoding and physical scanner/printer acceptance remain mandatory for any claimed barcode profile.
Build and acceptance
From the repository root, use Java 21 and the included wrapper:
./mvnw -f examples/echo/pom.xml verify
On Windows, run mvnw.cmd -f examples/echo/pom.xml verify from the repository root. From examples/echo, use ../../mvnw -f pom.xml verify (Windows: ..\..\mvnw.cmd -f pom.xml verify). Both forms use the checked-in wrapper; Checkstyle and resource paths resolve from the module directory.
This optional module is outside the root lifecycle. The POM's defaults are qqq.version 4.1.0-RC.21 (public), mobile.version and generation.version 0.1.0-SNAPSHOT, and printing.version 0.4.0-SNAPSHOT. The owner qbits (Generation and bridges, Printing, Collaboration, Record Files) are still qualified private inputs, not a fully public or released dependency cohort, so these snapshot defaults alone may not resolve or match what was verified. Copies per scan also needs the Generation copies change described above. Use a dedicated Maven repository and one coherent owner cohort; never install cross-chat snapshots over the shared cache. The source requires the narrow protected-process-identity API and current MobileScannerActions.capture(input, appName) API. These private artifacts are not published to a public Maven repository and are not a production handoff. The primary forge is Gitea; GitHub is a shadow/archive.
Tests: core and HTTP-fixture tests (real QQQ process state, H2 persistence and the mobile QBit's approval and binding, with synthetic destination, layout and queue fixtures) and adapter tests (controlled owner facades for exact pins, receipts, lookup, media filtering, the published scene geometry and the absent-deployment refusals). They qualify orchestration, event identity, permission boundaries and adapter mapping, not render output or physical printing. The adapter tests do not run the renderer worker.
Runnable demo
demo/ is a separate optional module that composes the real owners into a startable server (tested, Checkstyle clean). Its production EchoDemo keeps the owner's cold bridge, which defaults to the runsc Docker runtime and fails closed on Windows Docker Desktop (runc). TrustedLocalEchoDemo is the explicit developer launcher over the renderer owner's public trusted-local factory (owner tests pass; the demo copies no transport) and is not a production sandbox qualification. An earlier local run on an ephemeral loopback port (November 1, historical) had no printer or template. A real combined setup now exists: one local server runs Echo, Record Files, Document Generation and Printing with a real Printing client, printer, 4x1 media and a published Echo barcode document, and a TC22 completes setup against it. Physical output remains unproven. Operator prerequisites, from its README: a Printing tenant and administration token, a Windows printing agent that reports printer media, an approved scanner enrolled through the mobile flow, published Echo-compatible ZPL templates for the reported media, chosen by the operator during process setup, and Record Files' generated-file release switch.
What remains before any print claim: a TC22 scan against the real server that produces a physical print, independent decode of the output and a rescan of Code 128 and leading-zero QR labels. Beyond that: full AIM, EAN/UPC, GS1 and raw fidelity (the six admitted types are printable ASCII only, and the rest fail explicitly as unsupported), then public immutable SDK publication, Gitea CI and distribution, and signing. The source pull request is on Gitea (PR 7); earlier GitHub references are historical.
License packaging
Echo uses Apache License 2.0. Packaging includes the existing repository LICENSE and NOTICE unchanged under META-INF/qqq-echo/, alongside Echo's SQL resources. This namespace preserves dependency notices. No duplicate license source files or modified license text are maintained in the example.
Isolated native UI fixture
com.kingsrook.examples.echo.fixture.EchoHttpFixture is a test-scope HTTP host using the existing demo TABLE authentication and registered QQQ semantic routes. It brands itself Echo UI E2E — simulated printing. The simulated printer/media and acceptance recorder exercise navigation and receipts only; they never render or print.
Launch its test classpath with one unused loopback port argument and private environment variables ECHO_FIXTURE_TYPE=echo-ui-e2e, ECHO_FIXTURE_SCANNER_PASSWORD, and ECHO_FIXTURE_ADMIN_PASSWORD. Use generated secrets of at least 24 characters. Accounts are scanner and admin. The process initializes a fresh random in-memory H2 database, refuses known production/test-peer ports, and emits ECHO_UI_E2E_READY port=<port> simulatedPrinting=true. Closing it stops only its own server. Keep its credentials in private run descriptors, never this repository.
The printer/media choices are fixture-printer / fixture-4x6, labeled “Simulated printer” / “Simulated 4 x 6 in — 300 dpi”. Standard native queries of echoScan and test-only echoFixtureRun use the scanner session and approved device credentials, retaining actor locks. The HTTP smoke covers login, real enrollment/admin approval, metadata, setup, two symbologies, same-event retry, queued receipts, row inspection and cancellation. Android device acceptance remains a separate test; none of these fixture results qualify physical output.
Retained Echo source reads use a separate read-only permission: the current authenticated actor must still have echo.use, and native actor row locks restrict results to that actor. Desktop source reads after leaving Echo do not reconstruct a scanner session or grant capture authority. Echo app/process/widget/capture operations still require the currently approved device. Direct source-table writes are denied. Accepted print delivery/retry also requires the printing owner's reviewed original-actor source-reauthorization policy; this table read rule alone does not qualify delayed byte release.