develop
14
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
05518acd02
|
fix(renderer): scene 2 barcodes after independent review: no symbol reads as another value, rules by symbology, nothing painted over a symbol
A label is scanned, so a symbol must never read as something other than the value it was given. Record values are untrusted and stay out of every diagnostic and exception. - No value, literal or bound, may hold the two characters an escape of the encoder begins with. \<FNC1> in a plain Code 128 value drew a GS1-128 of the record's choosing, \<FNC3> set the reader-programming flag, and QR dropped the escape. Refused in every symbology, with a count only. - Interleaved 2 of 5 of an odd number of digits is refused, not padded. - EAN and UPC values are the whole number with its check digit, which is verified; a shorter number is refused, never completed or padded. - The check digit of every GS1 key in a gs1-128 element string is verified: the identifiers the GS1 Syntax Dictionary marks, as the bundled Zint carries it. - VALUE_NOT_ENCODABLE joins the errors for these and for a value a symbology cannot hold; SCENE_INVALID is no longer used for a value. A symbol of more modules than the encoder draws is BARCODE_DOES_NOT_FIT. - Quiet zones and the smallest module are a table by symbology (scene2/barcode/Symbology), each number with its source. barcodeProfile names the rule: none, gs1-general or gs1-logistics; not stated, the strictest written for the symbology. A GS1-128 is so held to 0.495 mm unless its scene says otherwise, at which a GTIN with a date and a serial number fits no label 4 in wide. - The bars of a linear symbol must be as tall as its symbology asks, and the height is part of the fit. minHeight overrides, with the standing warning BARCODE_HEIGHT_BELOW_RECOMMENDED. - QUIET_ZONE_INTRUDED is an error: an element later in the list whose ink would enter a symbol or its quiet zones is refused, when a scene is validated as when it is rendered. - A barcode sits in the middle of its box unless the scene says otherwise. - A bound barcode takes maxLength and is proven at validation in a linear symbology. FIT_NOT_PROVEN stays for no length and for two-dimensional symbols, whose encoders have no largest symbol of a length. Codes and property names are added in one change: foundation's FailureCode and warning set, the preview's sentences, the bridge's accepted refusals and schema vocabulary, the renderer's vocabulary and the schema. The three barcode goldens are unchanged byte for byte; barcode-retail is new. Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com> |
||
|
|
a147efee88
|
Merge pull request 'feat(renderer): scene 2 text: bundled fonts, measurement before drawing, stated fit rules (P2)' (#16) from feat/scene2-text into develop | ||
|
|
589b6d41ee
|
fix(renderer): scene 2 text after independent review: a proof that never cuts, a bounded shrink search, named refusals
The proof of `maxLength` - The proof never cuts. With `overflow: truncate` the proof was given a cut block, which counts as fitting, so a bound element whose box held ten characters validated clean with `maxLength: 40` and every long value was cut at print. The proof now runs with cutting off. When it fails, an element that did not ask for cutting is refused as before; one that did still validates, since cutting is what its author chose, with the warning FIT_NOT_PROVEN at every validation carrying `measured.provenCharacters`, the longest length proven to fit whole (found by halving: fewer characters never fit worse), against `limit.characters`. No new code: FIT_NOT_PROVEN already means that the fit of a bound value is not proven. - A bound element with `maxLength` is judged for legibility, when validated, at the size the proof shrank to (the floor when it fails and the element cuts), not at its stated size. The shrink search - The size chosen is still exactly the one a search of every quarter-point step gives, but that search is no longer made. A count that errs only toward yes says whether a size could hold the text: lines filled at any character, each held to a width no real line can be under, and a block to its lines' ascent, pitches and descent. It never refuses a size that fits and, once it allows a size, allows every smaller one, so the largest size it allows is found by halving and only the steps from there are laid out. When one line at the floor is higher than the box nothing is searched, and a cut tries no line count the box is too low for. - 1024 characters at 600 dpi from 1000 pt to 1 pt took 180 to 250 ms a fit and now takes under 1 ms: at most 21 555 characters visited where the search of every size visits 15.6 million. - A text is fitted once: what `check` composed is what `paint` draws. - The text of one scene may take 64 million steps (a character visited while fitting is one, a character to be drawn 16, a glyph the scene draws for the first time at a size 4096, since the runtime rasterises it once). The element that passes it, and every text after it, is SCENE_INVALID at the element with `textWorkSteps`, as the painted-area limit is. The count is integer arithmetic: the same on every machine, and the same validated or rendered. A thousand of the worst elements validate in well under a second. Ink outside the measure - TEXT_INK_OUTSIDE_MEASURE was an IllegalStateException thrown while painting, which failed the whole render after part of the text was on the label. The dots of a text are now gathered first and reach the label only when none strayed; otherwise the one element is refused as TEXT_DOES_NOT_FIT with `glyphsOutsideMeasure` and `dotsOutsideMeasure`. A literal is held to the glyph bounds when the scene is validated. - The bound is tested at 1, 2, 300 and 1000 pt as well as from 5 to 72 pt, for every character of every face at the three resolutions; nothing strays. Schema and vocabulary - `fit` declares `maxLines`, `shrinkTo` and `overflow` under `properties` with `additionalProperties: false`. The three names are in the renderer's and the host bridge's pointer vocabularies, and a wrong member is reported at the member (`/elements/3/fit/maxLines`, or in the override that states `fit`). - A bound number is printed as the schema says: plain decimal digits, no exponent, no fraction that is only zeros (`1.0E10` prints `10000000000`, `2.50` prints `2.5`). A number that is not finite is VALUE_MISSING. Tests - The widest-advance check covers every character a face draws, inked or not (a no-break space advances the pen), so a font update cannot break the proof unseen. - Property: `fit` equals the search of every size, block for block, over 3600 generated texts, boxes, sizes, floors and line counts. - The goldens are unchanged. A README beside them records the JDK builds and the FreeType each ships. Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com> |
||
|
|
1db82957c9
|
fix(bridge): a placeholder of no area draws nothing; name the answer table for what it is
ZplRaster.hatch returns at once for an area of no width or no height. Its outline and diagonals would otherwise be placed one dot outside the area: with no width the diagonal's column divides down to -1 and a stray line is drawn. The guard that the refused page had around its call is now in the painter itself, so every caller has it. An empty printer font text field did not reach the painter before this change either: such a field is refused as no field (RASTER_FIELD), and by the output policy before that; the existing test for it is unchanged. ZplRaster stays at 100% lines. ReleasedRendererAnswerTest is renamed VersionOneAnswerTableTest and its header says what it is: 71 synthetic answers in the shape the released renderer answers with, and the outcomes of today's bridge for them. They were not captured at the released tag, unlike the job frame golden, so the table holds today's behaviour still and does not show equality with the release. Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com> |
||
|
|
1828ae9c48
|
fix(bridge): ask the renderer's version again after any RENDERER_TOO_OLD
The comments said that nothing of a version 2 scene reaches a renderer that cannot draw it. That is not so: the answer to the version question is remembered, so after a renderer image is rolled back ONE job reaches the old (0.1.0) renderer, scene and record values included, and is then refused as RENDERER_TOO_OLD. The class, field, invoke and probe comments now say exactly that. The window stays one job in every case: a job that ends in RENDERER_TOO_OLD, from render, validate or preview, forgets what was remembered, so the next job that needs renderer 0.2.0 asks the version first. An answer from 0.1.0 already did this; a refusal that renderer 0.2.0 names itself, as an error answer or among collected diagnostics, did not. FakeWorker can stand for an image that is replaced while a bridge uses it. Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com> |
||
|
|
bbb4b60a1b
|
test(bridge): golden of the released version 1 job frame and a table of released answers
Nothing held the version 1 print request to the released bytes, and the
0.1.0 answers were tested at the units and not through render().
- compat-v1/job-frame-render.json is the frame the bridge of tag
v1.1.0-RC.2 (
|
||
|
|
9e5b16d686
|
fix(bridge): bound preview painting to sixteen times the page
ZplRaster painted a box and a placeholder by testing every dot of the field's area. The output policy allows 6000 fields, so a label of page-sized boxes was tens of thousands of millions of dots of work on the host while an admission slot was held, and the page of a refused scene had the same cost for each of up to 2048 diagnostic boxes. - Every painter counts the dots it is about to paint, an overlap each time, and the field that would take the page past sixteen times its dots is refused as PREVIEW_TOO_LARGE. This is the renderer's own limit for a scene. A graphic counts eight dots for each byte. - A box is the whole area when its border meets itself, else four bars that do not overlap, filled whole bytes at a time. The dots are the same as before. - A placeholder (printer font text, a refused element's box) is an outline and its two diagonals, so it costs its perimeter and not its area. This changes its look: the diagonal hatch every six dots is gone. - preview() returns the refusal as a result, like the page limit: not printable, no page, PREVIEW_TOO_LARGE with limit.paintedPercent 1600. For a refused scene it joins the diagnostics the worker sent. Printing is not changed. Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com> |
||
|
|
ed11495120
|
feat(preview): layout preview inside the QBit: service, action and record widget (P6b)
A person editing a label template sees the picture that would print, with its refusals and warnings, before anything is printed, from the module's own screens and with no host code. - DocumentPreviewService: authorises by the existing permissions (a draft needs configure, a published revision needs view, a record needs generate and is read as the person, with their permissions and record locks, before any context is built), loads the draft or the published snapshot without writing, builds the context as generation does and calls IsolatedRenderer.preview. Data is a sample from the scene, the longest declared values, or one record. One log line, no content. - "Preview layout" action on templates and published revisions: data, sample, record, stock and resolution; the result is the preview widget. - "Label preview" section on the template record screen: the draft with sample data (the published revision for a person who may only view). - The widget is fetched, never seeded from a process value: QQQ keeps the state of a finished process for hours (in a table with the shared provider), so the picture, the context and the diagnostics exist only in the answer to the widget request. The process state holds the person's choices only. - Bounded answer: one page, a picture of at most 2 MiB, fifty diagnostics. - The existing action is relabelled "Generate retained preview file"; its process name and behaviour are unchanged. - The record selector asks for generate alone, so a person who may preview a published revision with a record can choose one. - Help on every new process, step, field, section, widget and choice list. Tests: DocumentPreviewTest (data sources, permission matrix, unreadable record, nothing written, process state, PDF refusal, refused scene, version 1 label, bounds, log line, help coverage, instance validation) and LayoutPreviewServiceTest in bridges/renderer (through the service and the bridge, the preview has the hash of the bytes the print path returns at 203, 300 and 600 dpi). The registration and process tests are updated for the new wiring and the relabel. bridges/renderer gains the RDBMS module at test scope for that test. Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com> |
||
|
|
bf546e16c5
|
feat(bridge): accept renderer 0.2.0, read its diagnostics, preview a label (P5)
On develop the renderer speaks qqq-renderer-0.2.0 and the bridge accepted only 0.1.0, so the bridge refused its own renderer, a label could not be previewed, and a render target was accepted and then ignored. The version rule (RendererVersion). The bridge accepts 0.1.0 (the released fields, the 13 released refusals) and 0.2.0 (the same with diagnostics and detail, those refusals and the 15 scene refusals); any other version is rejected. Each set is written out, replacing the temporary enum range. A job is framed as 0.1.0 reads it unless it needs more. Before a job only 0.2.0 can do (a version 2 scene, a preview) the bridge asks the worker its version by validating a fixed, empty version 1 scene, so an old image is refused as RENDERER_TOO_OLD and receives nothing of the scene or the record; an answer from 0.1.0 to such a job is refused whatever it says. Diagnostics (WorkerAnswer, SceneFacts). A version 2 refusal is RenderException(code, diagnostic). The worker is untrusted, so every field is checked again: the closed vocabulary, whole numbers in bounds, an element only if the scene that was sent declares it, and a pointer only of array indexes, schema property names and declared ids. An answer holds at most 2048 diagnostics in one megabyte beside its label, and no frame passes the frame of the largest document the deployment admits. A refused answer that carries any part of a label is rejected. Render target. targetDpi is sent with a version 2 scene and the label is held by the output policy to the page at that resolution. A version 1 scene or a PDF asked for another resolution than its stock's is refused as TARGET_REQUIRES_SCENE_2 before any worker is contacted, because renderer 0.1.0 does not read the field. supportsRenderTarget() is true. Preview. preview() is the print path stopped before retention: the same job with collected diagnostics, the same integrity checks and output policy, and a page decoded by ZplRaster from the accepted label bytes. ZplRaster is its own strict reader of the policy's grammar and runs the policy first; it paints ^GFA and ^GB exactly, hatches printer font text (the page is then not exact) and writes a one-bit PNG itself. Refusals come back as diagnostics, never as a label. A refused scene is drawn on the host from the diagnostics' boxes alone: the worker sends no label for it and the wire gains no field for the partial canvas, so no host can print a label with elements missing. The design records the decision in sections 6.1 and B.1, the version question in 11.3 and what the host now reads from a scene in 8.1. renderer/qualification.json said qqq-renderer-0.1.0 and qqq-barcodes-1; it now says what the worker reports, and a test holds it to the answer. The mutation campaign covers the page decoder and the answer frames. The new classes are gated at 100% line coverage and the bundle gate rises to the measured 90% of instructions and 88% of lines. The version 1 corpus is untouched. Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com> |
||
|
|
ad6b0ffa88
|
feat(renderer): scene 2 core: layout in physical units, one canvas, diagnostics (P1)
A source with schema qqq-zpl-scene/2 is a label layout in millimetres, inches, points, percentages and dots that renders at 203, 300 or 600 dpi. The worker routes by the schema alone: version 1 takes exactly the path it always took (the compatibility corpus is unchanged and green), version 2 takes the new package com.kingsrook.qbits.renderer.scene2, and anything else is refused by name. - Length: parse, whole micrometres, dots by the rule of each use (position nearest, box size down, thickness nearest and at least one, module up, font size not rounded). - Layout: nine-point anchors, offsets inward from the anchored edge, omitted sizes, content alignment, groups four deep, percentages of the container. Coordinates start at the top left of the printable area. - Canvas and ZplEmitter: the whole label on one 1-bit canvas, emitted as trimmed ^GFA bands that pass the unchanged ZplOutputPolicy. - Diagnostics: every refusal is one diagnostic with a code, the element id, the box and named integers; SCENE_INVALID carries a JSON pointer. A diagnostic names only an id the scene declares and points only through schema names, indexes and declared ids. - box and group elements; overrides by resolution, checked for all three resolutions; samples accepted and ignored. Text, barcodes and images are parsed and placed and then refused as RENDERER_TOO_OLD by placeholder factories in their own sub-packages. - Renderer 0.2.0: optional targetDpi and "diagnostics": "COLLECT" on the request, diagnostics on the answer, detail on a version 2 error, the REFUSED outcome, and INSPECT_ASSET and UPGRADE_SCENE routed and refused as UNSUPPORTED_OPERATION. A version 1 scene with a target other than its stock's dpi is refused as TARGET_REQUIRES_SCENE_2. Tests: every length and rounding rule; all nine anchors; seeded property tests (mirrored anchors, boxes never leave the printable area, the bitmap rebuilt from the emitted fields equals the canvas); goldens at three resolutions as pictures and as ZPL, the ZPL also checked against the host gate in bridges/renderer; every refusal asserted as the whole diagnostic; a mutation campaign over the version 2 parser. The new package is at 100% line coverage. Also, from the review of the foundations: the mutation campaigns accept only declared refusals (a NullPointerException in a parser is now a finding), git no longer treats the stored corpus as text, and both compatibility tests pin the digest of the corpus manifest. Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com> |
||
|
|
c6aa0bf6b0
|
feat(foundation): preview, diagnostic and render target ports with registration hooks (P6a)
The contracts the preview, bridge and render target packages plug into. No label prints differently and no existing host adapter changes. GenerationPorts: - Diagnostic (with Severity): a code from a closed vocabulary, an author element id, a box and named integers. It has no field that holds free text. - PreviewRequest, PreviewPage and Preview, and IsolatedRenderer.preview as a default that refuses, so an adapter written before it compiles unchanged. - 15 version 2 FailureCode values after the 13 released ones, and RenderException(FailureCode, Diagnostic) beside the existing constructor. - Integer targetDpi on RenderRequest (absent, 203, 300 or 600); the seven-argument constructor is kept and nothing reads the value yet. Registration points, each an empty class that is already called: GenerationPreviewProcesses, GenerationAssetProcesses, GenerationUpgradeProcesses and GenerationAssetTables from the producer, and GenerationPreviewWidget.section(table) from GenerationTables. Bridge: IsolatedRendererBridge maps any FailureCode name from a 0.1.0 worker to a typed refusal, so growing the enum alone would have widened what such a worker can name. The 13 released codes are now the set a 0.1.0 worker may name; BridgeTest asserts the other 15 stay generic. Tests: record validation, default refusals, source compatibility of the existing constructors, and that the producer registers exactly the tables, processes, choices, widgets and template sections it did before (the lists were captured from the untouched v1.1.0-RC.2 tag). Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com> |
||
|
|
3ba676106f
|
build(coverage): gate renderer and bridge coverage at baseline; seeded mutation campaigns (P13)
Coverage gates: - renderer and bridges/renderer gain JaCoCo (prepare-agent, report, check at verify) with a bundle rule at the measured baseline, rounded down: renderer 94% instructions and 91% lines, bridge 85% instructions and 82% lines. - New code is held to 100% line coverage from its first commit: packages com.kingsrook.qbits.renderer.scene2 and below, AssetInspector, ZplRaster, and the new foundation classes the label layout design names. The rules match nothing until those exist, so later packages do not edit these poms. - The foundation's 85% instruction and 90% class rule is unchanged. Fuzz scaffolding: - MutationCampaign in each module's test tree: a seeded, bounded mutation harness with no clock and no unseeded randomness; a finding replays from its seed and iteration. - One campaign per module in the normal test phase: what the version 1 scene parser accepts is a version 1 scene (checked by a second parser), and what the host printer gate accepts holds only the renderer's command set. - docs/security/fuzzing.md: targets, properties, limits, seeds and replay. Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com> |
||
|
|
ea776391ca
|
test(renderer): version 1 scene compatibility corpus from v1.1.0-RC.2 (P0)
Version 1 scenes (qqq-zpl-scene/1) are frozen. This adds 42 render requests
and the exact ZPL the released renderer returned for each, so later work can
prove that labels already printing are untouched.
- renderer/src/test/resources/compat-v1: cases, stored ZPL, SHA256SUMS and a
README with provenance and rules. The bytes were produced by the source of
tag v1.1.0-RC.2 (
|
||
|
|
ee782b7d6e |
chore: preserve unfinished document generation source and status
QRun-IO/ci-policy: ci / fork-guard (push) Skipped
QRun-IO/ci-policy: ci / head-profile (push) Skipped
QRun-IO/ci-policy: ci / application-template-0 (push) Skipped
QRun-IO/ci-policy: ci / gradle-1 (push) Skipped
QRun-IO/ci-policy: ci / java-docker-3 (push) Skipped
QRun-IO/ci-policy: ci / java-docker-4 (push) Skipped
QRun-IO/ci-policy: ci / java-frontend-browser-5 (push) Skipped
QRun-IO/ci-policy: ci / java-maven-6 (push) Skipped
QRun-IO/ci-policy: ci / java-maven-7 (push) Skipped
QRun-IO/ci-policy: ci / node-8 (push) Skipped
QRun-IO/ci-policy: ci / node-9 (push) Skipped
QRun-IO/ci-policy: ci / node-10 (push) Skipped
QRun-IO/ci-policy: ci / node-playwright-11 (push) Skipped
QRun-IO/ci-policy: ci / repository-policy-12 (push) Skipped
QRun-IO/ci-policy: ci / source-config-13 (push) Skipped
QRun-IO/ci-policy: ci / source-config-14 (push) Skipped
QRun-IO/ci-policy: ci / android-0 (push) Skipped
QRun-IO/ci-policy: ci / original-business (push) Skipped
QRun-IO/ci-policy: ci / original-mcp (push) Skipped
QRun-IO/ci-policy: ci / original-voyage (push) Skipped
QRun-IO/ci-policy: ci / original-cli (push) Skipped
QRun-IO/ci-policy: ci / not-enrolled (push) Failing after 7s
QRun-IO/ci-policy: native / fork-deny (push) Skipped
QRun-IO/ci-policy: native / dotnet-0 (push) Skipped
QRun-IO/ci-policy: ci / repository-policy (push) Skipped
QRun-IO/ci-policy: ci / java-core-2-head (push) Skipped
QRun-IO/ci-policy: ci / java-docker-3-head (push) Skipped
QRun-IO/ci-policy: ci / java-maven-6-head (push) Skipped
QRun-IO/ci-policy: ci / java-maven-7-head (push) Skipped
QRun-IO/ci-policy: ci / ci-result (push) Failing after 5s
QRun-IO/ci-policy: native / native-result (push) Successful in 6s
Checkpoint implementation at user-requested stop; document known failures and incomplete release qualification. Co-Authored-By: Claude <noreply@anthropic.com> Co-Authored-By: GPT-6 Codex <noreply@openai.com> |