develop
5
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
f5acf93e3d
|
feat(renderer): scene 2 text: bundled faces, measurement before drawing, stated fit rules (P2)
A version 2 `text` element is now drawn. It replaces the placeholder that parsed and placed a text and refused it as RENDERER_TOO_OLD. What a scene can say - `font` names one of the five bundled faces (or comes from `defaults`); any other name is FONT_UNKNOWN. There is no printer font and no installed font. - `size` is the em as a physical length (1 pt to 1000 pt), not rounded to dots. - `value` or `valuePath`; `align`/`valign` place the block in the box and each line in the block; `lineHeight`, `rotation`, `reverse`, `threshold`. - `fit`: one line by default, shrunk in quarter-point steps to 70% of the size (not below 5 pt), then refused. Opt in to more lines (`maxLines`) and to cutting with an ellipsis (`overflow: truncate`). - `maxLength`: validation proves the longest value fits, so a length refusal happens when a scene is published; printing refuses a longer value first. How it is measured and drawn - Measurement is integer arithmetic on the face's own numbers (thousandths of the em, read once at a reference size), so it is the same on every machine. Every character sits at a whole-dot pen position and is drawn there by the Java rasteriser that version 1 raster text uses, then reduced to ink at the threshold. A line's box is its advance widened to its ink plus two dots a side; a render whose ink would leave it fails instead of clipping. - At each size a line is broken between words while that fits and at any character when it does not, which is also what makes a length provable. - One glyph for each character, left to right: no kerning, ligatures, mark placement or bidirectional text. A character that cannot be drawn that way is FONT_MISSING_GLYPH with a count. Diagnostics (ids and numbers only; no value ever enters one) TEXT_DOES_NOT_FIT, VALUE_MISSING, VALUE_TOO_LONG, FONT_UNKNOWN, FONT_MISSING_GLYPH, RESERVED_FONT_NAME; TEXT_TRUNCATED, TEXT_SMALL_FOR_DPI, TEXT_LIGHT_FACE, FIT_NOT_PROVEN; TEXT_SHRUNK, TEXT_WRAPPED. Core seams added: `ElementSource.inherit` gives an element the scene's `defaults` for the properties its type reads, and `ElementSource.refuse` raises a coded refusal at a property (FONT_UNKNOWN at the place that names the face, in the element, the defaults or an override). Tests: goldens for the five faces and for fit, rotation and reverse at 203, 300 and 600 dpi, generated in the CI image (Linux, Temurin 21.0.9) and the same bytes on Windows (21.0.12) and on Linux Temurin 21.0.13; every character of every face drawn inside its measured line; seeded property tests of fit (never shrunk when it fits, the largest size that fits, never below the floor, never more lines than allowed, cut only when asked and always with the mark, a proven length never refused); licence, provenance and hash of every face; the version 2 mutation campaign extended to text. The version 1 corpus is untouched. 100% line coverage of the scene 2 packages. 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> |
||
|
|
58051e7b99
|
fix(renderer): scene 2 core: the findings of the independent review
1. A length too long for any stock is a named refusal. Length.parse narrowed the micrometres to an int before it applied the 2 m limit, so "84600in" or "99999in" threw ArithmeticException: the opaque RENDER_FAILED, and an error instead of a REFUSED answer when collecting. The limit is now compared in long before narrowing, so it is SCENE_INVALID at the pointer of the length. 2. The printable area holds a box of its own size at every resolution. It was floor(far edge) less ceil(near margin), which can be one dot smaller than a box of the stated printable width: 100 mm stock with 3 mm margins and a 94 mm box fitted at 203 and 600 dpi and was refused at 300. It is now floor((W - L - R) x dpi) by floor((H - T - B) x dpi), the rounding of a box size, starting at ceil(L x dpi), ceil(T x dpi), moved back one dot where it would otherwise pass the page edge. New golden case `margins` with fractional-dot margins; the three existing goldens at 600 dpi are regenerated (the area grew by one dot each way; 203 and 300 unchanged). 3. The version 2 mutation campaign accepts only a Refusal (the package's own invariants are IllegalArgumentExceptions too) and renders about one input in four, reading the label back and comparing with validation. It found nothing at 20000 or 100000 iterations for either seed. 4. A refused answer carries no label bytes: with COLLECT and an error the answer had base64 of a label with elements missing. Scene2.render answers no label for a refused scene and the answer has no document fields. This changes the wire contract of section B.1 of the design, which records it. 5. One scene may paint sixteen times its printable area, an overlap counted each time, counted before any ink and in validation too. The element that would pass it is SCENE_INVALID with measured.paintedPercent against limit.paintedPercent 1600. 1000 fills of a 64 million dot canvas were 8 GB of byte writes; the worst scene is now 128 MB. 6. The README states what changed in the version 1 answer envelope in 0.2.0 (diagnostics on every answer; SCENE_INVALID with detail where unreadable JSON and a missing or unknown schema were RENDER_FAILED) and what the bridge must handle. The version 1 ZPL bytes are unchanged. 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> |
||
|
|
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> |