All notable changes to this project will be documented in this file.
The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.
[Unreleased]
[1.3.4] - Unreleased
Fixed
- Supersedes the immutable failed
v1.3.3release attempt with a fresh exact 1.3.4 candidate. Complete credential-free release preflight remains the validation gate; only actual protected Hex publication receivesHEX_API_KEY.
[1.3.3] - Unreleased
Fixed
- Repaired the release-preflight test stdin deadlock and sealed candidate-mode
parity so exact-SHA proof cannot bypass repeated CI or either security audit.
This private candidate does not publish, retry, or mutate the immutable
failed
v1.3.0,v1.3.1, orv1.3.2tags.
[1.3.1] - 2026-08-21
This additive release makes the existing preset and configurator discovery path
available to public Hex and HexDocs users. Start with the README's bounded
Invoice / Swiss / #2C6BED / light route; presets remain starting points, not
design-quality, accessibility, PDF/UA, WCAG, or print-safety guarantees.
Added
- README-first
install -> select -> customize -> serve -> verifyhandoff for Phoenix teams, with the public~> 1.3dependency range and links to the formatter-owned preset/configurator sources and runnable reference app. - Candidate-bound HexDocs publication guardrails: an explicit exact-SHA dispatch under the protected Hex Publish environment is now required for docs release.
Changed
v2.7 Docs, Claims, and Release Hygiene
- Documented section-local page numbering,
{{section_page_number}}/{{section_total_pages}}, and physical odd/even running content with support-matrix-backed claim guards. - Kept global text shaping demand-gated outside the v2.7 scope while preserving the public
ADOPTION.mdthresholds. - Added
ADOPTION.mdto the Hex package and HexDocs extras so public README links resolve in package/docs contexts. - Set read-only
contents: readpermissions on CI and tag-gated release workflows.
LNCH-02: Zero-UAT mobile viewer evidence posture
- Added terminal
explicit_deferralrows for iOS Files/Preview and Google Drive PDF viewer on Android acrossformsandsigned_artifact. These rows intentionally publish no mobile GUI support claim until automated device-level CI evidence exists. - Mirrored the mobile deferral reasons in
guides/api_stability.md; signed-artifact deferrals distinguish Markup/drawn signatures from/Sigcryptographic validation.
Fixed
HYG-03: Cluster-boundary split_graphemes rewrite (D-11, D-12, D-13)
- Rewrote
split_graphemes/4inlib/rendro/pipeline/measure.exto shape runs at cluster boundaries instead of callingShaper.shape/3once per grapheme. The old per-grapheme shaping call is removed entirely. - Under
Shaper.Simple(cluster=0 for all glyphs), the new run-shaping path is byte-identical to the old per-grapheme path by construction — each glyph still maps 1:1 to a grapheme and x_advance values are unchanged. No golden regressions. - Under
Rendro.Adapters.HarfBuzz(cluster=byte offset), ligature clusters are now treated as atomic units for line-breaking, which was objectively wrong before. - StreamData property test added (
test/rendro/text/shaper_test.exs) formally proving per-grapheme width sum == per-run width underShaper.Simplefor random ASCII strings (D-12). - Re-bless event (D-13): No golden files changed. The Latin/Shaper.Simple path is byte-identical by construction (proven by property test). No HarfBuzz-path golden fixtures exist in the test suite, so no re-blessing was required.
[1.0.0] - 2026-06-05
This release marks the 1.0.0 milestone, establishing the first formal SemVer commitment. It consolidates the v2.3 Viewer Evidence work, the v2.4 Batteries-Included workflow features, and the v2.5 API stability cleanup.
The published 0.3.0 surface lifted v1.5–v2.2 work. This 1.0.0 release closes out the remaining core milestones. Operator-only evidence artifacts (priv/viewer_evidence/ and priv/support_matrix.json) intentionally remain out of the Hex package; the public contract is mirrored in guides/api_stability.md.
Stability
For details on the two-tier stability contract, the byte-output carve-out, and the soft-deprecation policy, see the Upgrading to 1.0 guide.
Added
API Stability & Surface (v2.5)
- Formal two-tier SemVer contract (
stableandadapter). priv/public_api.jsonmanifest as the canonical source of truth for the public API surface.- ExDoc stability badges for all public modules.
- Introspection-based docs-contract tests to mechanically pin the documented surface to the manifest.
Batteries-Included Workflow (v2.4)
Rendro.Pageprimitive for explicit page-level content control.- Five canonical, tested recipes:
Rendro.Recipes.Invoice,BrandedInvoice,Statement,Receipt, andCertificate. - Reference Phoenix application (
examples/phoenix_example) demonstrating integration, async delivery, and testing.
Viewer Evidence (v2.3)
Rendro.Adapters.Pdfiumoptional PATH-discovered adapter for pdfium-cli form/info observation used by the viewer-evidence live-proof lane.mix rendro.viewer_evidence record forms chrome_pdfiumto autogenerate evidence files from pdfium-cli observations.- Promoted
forms.viewers.chrome_pdfiumtosupportedwith evidence atpriv/viewer_evidence/forms/chrome_pdfium.md(viewer_kind: pdfium-cli). - Promoted
forms.viewers.adobe_acrobat_readertosupportedwith evidence atpriv/viewer_evidence/forms/adobe_acrobat_reader.md(viewer_kind: pdfium-cli). - Promoted
forms.signature_widget_viewers.adobe_acrobat_reader,apple_preview, andchrome_pdfiumtosupportedwith evidence underpriv/viewer_evidence/signature_widget/. - Promoted
signing_preparation.viewers.adobe_acrobat_readertosupportedwith evidence atpriv/viewer_evidence/signing_preparation/adobe_acrobat_reader.md; non-Acrobat rows inherit signature-widget evidence pointers (D-15). - Promoted
signing.viewers.adobe_acrobat_readerandchrome_pdfiumtosupportedwith evidence underpriv/viewer_evidence/signed_artifact/. - Promoted
signing.long_lived.viewers.adobe_acrobat_readertosupportedwith evidence atpriv/viewer_evidence/long_lived_signed_artifact/adobe_acrobat_reader.md. - Promoted
protection.viewers.adobe_acrobat_readertosupportedwith evidence atpriv/viewer_evidence/protection/adobe_acrobat_reader.md. - Phase 71 structural-proxy proof modules:
FormsAcrobatProof,ProtectionAcrobatProof,SignatureWidgetAcrobatProof,SignatureWidgetApplePreviewProof,SigningPreparationPdfiumProof,SignedArtifactAcrobatProof,LongLivedAcrobatProof. viewer-evidence-live-proofCI lane extended with pdfsig/pyhanko and Phase 71 live tests (trust_sensitive_viewer_evidence_live_test.exsand related adapters).mix rendro.viewer_evidence validate --strictoperator staleness gate (exit 1 onrecorded_atolder than 180 days); advisory and not merge-blocking in CI.- Explicit deferrals for
forms.viewers.pdfjs,forms.signature_widget_viewers.pdfjs,signing_preparation.viewers.pdfjs,signing.viewers.apple_preview,signing.viewers.pdfjs,signing.long_lived.viewers.{apple_preview,chrome_pdfium,pdfjs}, andembedded_files.viewers.apple_previewwith named reasons inpriv/support_matrix.json.
Changed
API Cleanup & Normalization (v2.5)
- Accidentally-public internals (
Rendro.PDF.CidFont,Rendro.PDF.FontSubsetter,Rendro.Sign.redact_*,Rendro.Protect.redact_*) are now hidden (@moduledoc falseor@doc false). Rendro.Metadatais now fully documented with a public@type t.- Recipe options (
sections/2) forInvoiceandBrandedInvoicecorrectly thread options instead of silently ignoring them.
Viewer Evidence (v2.3)
- Document viewer-evidence CHANGELOG discipline in
guides/api_stability.md— promotions, explicit deferrals, and legacy re-homes require CHANGELOG entries; re-validations refreshrecorded_atin the log. - Re-home
forms.viewers.apple_previewevidence topriv/viewer_evidence/forms/apple_preview.md(support status unchanged since v1.8 Phase 47). - Re-home
embedded_files.viewers.adobe_acrobat_readerevidence topriv/viewer_evidence/embedded_files/adobe_acrobat_reader.md(support status unchanged since v1.9 Phase 50). - Re-home
links.viewers.adobe_acrobat_readerevidence topriv/viewer_evidence/links/adobe_acrobat_reader.md(support status unchanged since v1.9 Phase 50). - Re-home
links.viewers.apple_previewevidence topriv/viewer_evidence/links/apple_preview.md(support status unchanged since v1.9 Phase 50). - Re-home
protection.viewers.apple_previewevidence topriv/viewer_evidence/protection/apple_preview.md(support status unchanged since v1.10 Phase 54). - Signing-preparation equivalence note in
guides/api_stability.md: non-Acrobatsigning_preparationrows inheritsignature_widgetevidence; Acrobat requires independent byte-range evidence. embedded_files.viewers.apple_previewstatus changed fromunverifiedtoexplicit_deferralafter Phase 71 re-verify (Attachments UI gap named explicitly).
Truthful Boundaries Held
priv/support_matrix.jsonandguides/api_stability.mdkeep unsupported narratives (HTML/CSS parity, browser-style layout, signer-identity trust by default, broad compliance branding, viewer promotion without recorded evidence, multi-signature workflows, HSM/key custody in core, remote asset fetching, broad complex-script support) explicit. Every supported viewer row is backed by recorded checklist proof; trust-sensitive surfaces without recorded proof useexplicit_deferralwith named reasons rather than bareunverified.- The canonical protected-delivery recipe documented in 0.2.0 stays unchanged:
render_to_artifact -> Protect.password -> store/deliver. Signing seams (prepare/2,sign/2,augment/2) live alongside protection on the artifact boundary, never insideRendro.render/2.
[0.3.0] - 2026-05-08
This release lifts the v1.5–v2.2 milestone work onto Hex. The 0.2.0 published surface ended at password-to-open protection; 0.3.0 adds validation/trust surfaces, interactive forms, embedded artifacts, signature widgets and signing preparation, cryptographic signing, and long-lived signature evidence — every public claim backed by priv/support_matrix.json rows and either a structural or live-tool proof lane. Per-viewer evidence remains the next milestone (v2.3) and is intentionally still recorded as unverified outside the rows that have promoted proof.
Added
Validation and Trust Surfaces (v1.5)
Rendro.Adapters.Popplerfor structural PDF validation throughpdfinfo/Poppler with stable redacted error reasons. The lane proves PDF structure only; it does not prove interactive viewer behavior.priv/support_matrix.jsonas the canonical machine-readable support contract, mirrored byguides/api_stability.md. Every public surface added in this release ships a row in the matrix; rows without recorded per-viewer evidence stayunverifiedrather than being promoted optimistically.- Widow/orphan layout controls and richer nested-layout structures.
Interactive Forms (v1.8)
Rendro.form_field/3with%Rendro.FormField{}for deterministic authored AcroForm text fields, checkboxes, and radio groups in the core pipeline.- Explicit appearance streams for every form widget rather than relying on viewer-generated
NeedAppearances— keeps deterministic render output stable across viewers. - Forms boundary in
priv/support_matrix.jsonand aforms_claims_test.exsdocs-contract lane. - Recorded Apple Preview proof for the
formssurface (Phase 47); other viewers held atunverifiedpending v2.3 viewer-evidence work.
Embedded Artifact Surfaces (v1.9)
- Document-level embedded files with explicit deterministic metadata, validate-stage rejection of ambiguous authored state, and writer emission of
/EmbeddedFile,/Filespec,/Names, and/AFcatalog wiring sorted by stable authored keys. - Curated link annotations limited to
http/httpsURIs and in-document page targets, serialized through the existing page/Annotsseam — no named destinations, no/GoToR, no generic action dictionaries. - Recorded Adobe Acrobat Reader proof for both
embedded_filesandlinks; recorded Apple Preview proof forlinks.
Signature Field Authoring and External Signing Preparation (v2.0)
Rendro.signature_field/2for explicit unsigned signature-field authoring on the existing%Rendro.FormField{}seam — narrow surface, no second forms engine.- Deterministic unsigned
/Sigwidget serialization and AcroForm structures without signer-owned placeholders or policy dictionaries leaking into ordinary render output. - Validate-stage rejection for scope-breaking signature metadata (signer identity, trust anchors, compliance claims) so unsupported semantics fail before render with typed errors.
Rendro.Sign.prepare/2artifact-first external-signing preparation that operates on final artifact bytes, publishes deterministic placeholder coordinates undermetadata.signing_preparation, and isolates adapter-specific handoff data undermetadata.signing_preparation_adapter.
Cryptographic Signing and Signed-Artifact Validation (v2.1)
Rendro.Sign.sign/2as the artifact-first cryptographic-signing seam over the v2.0 unsigned/preparation boundary.Rendro.Sign.Adapterbehaviour defining the narrow signing-adapter contract.- First-party optional
Rendro.Adapters.PyHanko(signing + signed-artifact validation) andRendro.Adapters.Pdfsig(validation) adapters with explicit runtime-executable, redaction, and integrity-vs-trust boundaries — neither package becomes a hard dependency. Rendro.Sign.validate/2with distinct signals for cryptographic integrity, certificate trust, and viewer behavior (rather than collapsing them into one "signed and valid" claim).signing-live-proofGitHub Actions lane required onmainthat exercises the canonicalsign → validatepath against checked-in static signing fixtures.- One signed-artifact support contract aligned across
priv/support_matrix.json,guides/api_stability.md,guides/integrations.md, docs-contract tests, and verification artifacts. Signature-specific viewer rows remainunverifieduntil recorded per-viewer evidence exists.
Long-Lived Signatures and Compliance Evidence (v2.2)
Rendro.Sign.augment/2as a separate seam that adds timestamp and revocation evidence over already-signed artifacts — keeps signing, augmentation, and validation as three explicit boundaries instead of one widening API.- First-party optional pyHanko long-lived adapter that adds timestamp and revocation evidence without claiming certificate-trust ownership.
- Validator-backed posture classification reporting cryptographic integrity, timestamp presence, revocation evidence presence, and narrow compliance posture as distinct signals — not a blanket PDF/A or PAdES claim.
metadata.long_livedshared posture andmetadata.long_lived_adapterfor tool-shaped facts; explicit non-determinism flagged on every augmented artifact.long-lived-live-proofGitHub Actions lane required onmain, backed by an offlinecertomancer-driven PKI/TSA/OCSP fixture so the supportedsign → augment → validatepath is operationally enforced without depending on any public PKI/TSA/CRL endpoint.- Nested
signing.long_livedtaxonomy inpriv/support_matrix.json, separate from blanket PDF/A claims, signer trust, viewer behavior, and multi-signature workflows.
Truthful Boundaries Held
priv/support_matrix.jsonandguides/api_stability.mdkeep unsupported narratives (HTML/CSS parity, browser-style layout, signer-identity trust by default, broad compliance branding, viewer promotion without recorded evidence, multi-signature workflows, HSM/key custody in core, remote asset fetching, broad complex-script support) explicit. Every supported viewer row is backed by recorded checklist proof; rows without recorded proof remainunverifiedrather than being promoted.- The canonical protected-delivery recipe documented in 0.2.0 stays unchanged: signing seams (
prepare/2,sign/2,augment/2) live alongside protection on the artifact boundary, never insideRendro.render/2.
[0.2.0] - 2026-05-06
Added
Rendro.Protect.password/2andRendro.render_protected/3for artifact-first AES-256 password-to-open protection through optional external adapters.Rendro.Adapters.Qpdfas the first-party external protection adapter, keepingqpdfas an optional runtime executable instead of a hard dependency.- Password-aware
Rendro.Adapters.Poppler.validate/2support so protected PDFs can still participate in the structural validation lane. - A new
protectionfamily inpriv/support_matrix.jsonplus docs-contract coverage for advisory-permissions wording and unsupported compliance/signature claims. - Proof-backed Apple Preview support for the
protectionsurface, with release guidance that points downstream users back to the canonicalrender_to_artifact -> Protect.password -> store/deliverrecipe instead of persisting passwords in Oban or pushing them into Mailglass. Rendro.Artifactstruct andRendro.render_to_artifact/2to encapsulate generation results (binary, hash, diagnostics, metadata).Rendro.Storagebehavior for persisting generated artifacts to external systems.Rendro.Auditbehavior defining the contract for logging render events and lifecycle telemetry.- Optional adapter
Rendro.Adapters.Accruefor building deterministic billing documents. - Optional adapter
Rendro.Adapters.Mailglassfor seamless attachment of artifacts to transactional emails. - Optional adapter
Rendro.Adapters.Oban.RenderWorkerfor reliable asynchronous document generation and storage. [:rendro, :pipeline, :validate, :start | :stop | :exception]telemetry events for the new trailing post-render validation stage. The stage performs PDF structural sanity checks (%PDF-header,%%EOFtrailer), page-count parity (PDF/Type /Pages /Count Nvslength(doc.pages)), and the:max_bytespolicy enforcement formerly inlined after:render. Closes BLOCKER-04 from.planning/v1.0-MILESTONE-AUDIT.md.Rendro.Pipeline.Validatemodule exposingrun/2 :: (binary(), Rendro.Document.t()) -> {:ok, binary()} | {:error, atom()}.Rendro.Error:validate-stagewhat/next_stepclauses for:structural_corruption,:page_count_mismatch, and:max_bytes_exceeded(D-09).
Changed (BREAKING)
- Pipeline stage execution order now matches the documented architecture:
build → compose → measure → paginate → render → validate. Previously stages ran in the orderbuild → measure → paginate → compose → render, which inverted compose/measure relative to the spec. Closes BLOCKER-05 from.planning/v1.0-MILESTONE-AUDIT.md. max_pages_exceededpolicy errors now fire from the:paginatestage stop event rather than mid-pipeline; the policy guard runs after:paginateand before:render, where page count is final.max_bytes_exceededpolicy errors are now attributed to the:validatestage rather than:render; the trailing inlinevalidate_policy(:bytes, ...)was absorbed into the:validatestage body.- Stage
:stopevents now carry a unified schema across success and error paths:%{render_id, document_type, deterministic, stage, status, page_count, byte_size}with an optional:errormap (%{kind, stage}) onstatus: :error. Error-pathpage_countis now derived from the latest known doc state rather than hardcoded to0. Closes MINOR-15 from.planning/v1.0-MILESTONE-AUDIT.md. - Top-level
[:rendro, :render, :stop]event payload mirrors the new stage stop schema (event name unchanged).
Notes
- Pre-1.0 release; the previous stage order was a bug against the documented architecture (
v1.0-MILESTONE-AUDIT.mdBLOCKER-04, BLOCKER-05). Top-level[:rendro, :render, :*]event names are unchanged; only their stop-metadata schema is updated. - The
Threadlineadapter (lib/rendro/adapters/threadline.ex) subscribes only to top-level events and is unaffected by these changes. - No bridge period, dual emission, or
telemetry_contract_versionfield is provided. See.planning/phases/06-pipeline-telemetry-contract/06-CONTEXT.mdD-17.