fullbleed 2.5.2__tar.gz → 2.5.4__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {fullbleed-2.5.2 → fullbleed-2.5.4}/Cargo.lock +1 -1
- {fullbleed-2.5.2 → fullbleed-2.5.4}/Cargo.toml +1 -1
- {fullbleed-2.5.2 → fullbleed-2.5.4}/PKG-INFO +4 -2
- {fullbleed-2.5.2 → fullbleed-2.5.4}/README.md +3 -1
- fullbleed-2.5.4/THIRD_PARTY_LICENSES.md +119 -0
- {fullbleed-2.5.2 → fullbleed-2.5.4}/build_backend/fullbleed_build_backend.py +2 -0
- {fullbleed-2.5.2 → fullbleed-2.5.4}/fullbleed-agent-contract.json +25 -1
- {fullbleed-2.5.2 → fullbleed-2.5.4}/llms.txt +1 -1
- {fullbleed-2.5.2 → fullbleed-2.5.4}/pyproject.toml +1 -1
- {fullbleed-2.5.2 → fullbleed-2.5.4}/python/fullbleed_cli/cli.py +76 -22
- fullbleed-2.5.4/src/base14_metrics.rs +53 -0
- fullbleed-2.5.4/src/base14_metrics_data.rs +8745 -0
- {fullbleed-2.5.2 → fullbleed-2.5.4}/src/lib.rs +1 -0
- {fullbleed-2.5.2 → fullbleed-2.5.4}/src/pdf_raster.rs +317 -4
- fullbleed-2.5.4/tools/data/base14/Courier-Bold.afm +684 -0
- fullbleed-2.5.4/tools/data/base14/Courier-BoldOblique.afm +684 -0
- fullbleed-2.5.4/tools/data/base14/Courier-Oblique.afm +684 -0
- fullbleed-2.5.4/tools/data/base14/Courier.afm +684 -0
- fullbleed-2.5.4/tools/data/base14/Helvetica-Bold.afm +5654 -0
- fullbleed-2.5.4/tools/data/base14/Helvetica-BoldOblique.afm +5654 -0
- fullbleed-2.5.4/tools/data/base14/Helvetica-Oblique.afm +6102 -0
- fullbleed-2.5.4/tools/data/base14/Helvetica.afm +6102 -0
- fullbleed-2.5.4/tools/data/base14/MustRead.html +19 -0
- fullbleed-2.5.4/tools/data/base14/Symbol.afm +426 -0
- fullbleed-2.5.4/tools/data/base14/Times-Bold.afm +5176 -0
- fullbleed-2.5.4/tools/data/base14/Times-BoldItalic.afm +4768 -0
- fullbleed-2.5.4/tools/data/base14/Times-Italic.afm +5334 -0
- fullbleed-2.5.4/tools/data/base14/Times-Roman.afm +4838 -0
- fullbleed-2.5.4/tools/data/base14/ZapfDingbats.afm +450 -0
- fullbleed-2.5.4/tools/data/base14/agl-LICENSE.md +26 -0
- fullbleed-2.5.4/tools/data/base14/agl-glyphlist.txt +4325 -0
- fullbleed-2.5.4/tools/data/base14/agl-zapfdingbats.txt +245 -0
- fullbleed-2.5.4/tools/data/base14/sources.json +97 -0
- fullbleed-2.5.4/tools/generate_base14_metrics.py +113 -0
- fullbleed-2.5.2/THIRD_PARTY_LICENSES.md +0 -49
- {fullbleed-2.5.2 → fullbleed-2.5.4}/COPYRIGHT +0 -0
- {fullbleed-2.5.2 → fullbleed-2.5.4}/FONT_LICENSE_AUDIT.json +0 -0
- {fullbleed-2.5.2 → fullbleed-2.5.4}/FONT_LICENSE_AUDIT.md +0 -0
- {fullbleed-2.5.2 → fullbleed-2.5.4}/LICENSE +0 -0
- {fullbleed-2.5.2 → fullbleed-2.5.4}/LICENSING.md +0 -0
- {fullbleed-2.5.2 → fullbleed-2.5.4}/build.rs +0 -0
- {fullbleed-2.5.2 → fullbleed-2.5.4}/crates/fullbleed_audit_contract/Cargo.lock +0 -0
- {fullbleed-2.5.2 → fullbleed-2.5.4}/crates/fullbleed_audit_contract/Cargo.toml +0 -0
- {fullbleed-2.5.2 → fullbleed-2.5.4}/crates/fullbleed_audit_contract/LICENSE +0 -0
- {fullbleed-2.5.2 → fullbleed-2.5.4}/crates/fullbleed_audit_contract/README.md +0 -0
- {fullbleed-2.5.2 → fullbleed-2.5.4}/crates/fullbleed_audit_contract/specs/fullbleed.audit_registry.v1.yaml +0 -0
- {fullbleed-2.5.2 → fullbleed-2.5.4}/crates/fullbleed_audit_contract/specs/section508_html_registry.v1.yaml +0 -0
- {fullbleed-2.5.2 → fullbleed-2.5.4}/crates/fullbleed_audit_contract/specs/wcag20aa_registry.v1.yaml +0 -0
- {fullbleed-2.5.2 → fullbleed-2.5.4}/crates/fullbleed_audit_contract/src/json.rs +0 -0
- {fullbleed-2.5.2 → fullbleed-2.5.4}/crates/fullbleed_audit_contract/src/lib.rs +0 -0
- {fullbleed-2.5.2 → fullbleed-2.5.4}/crates/fullbleed_audit_contract/src/sha256.rs +0 -0
- {fullbleed-2.5.2 → fullbleed-2.5.4}/docs/specs/fullbleed.a11y.verify.v1.schema.json +0 -0
- {fullbleed-2.5.2 → fullbleed-2.5.4}/docs/specs/fullbleed.audit_registry.v1.yaml +0 -0
- {fullbleed-2.5.2 → fullbleed-2.5.4}/docs/specs/fullbleed.pmr.v1.schema.json +0 -0
- {fullbleed-2.5.2 → fullbleed-2.5.4}/docs/specs/section508_html_registry.v1.yaml +0 -0
- {fullbleed-2.5.2 → fullbleed-2.5.4}/docs/specs/wcag20aa_registry.v1.yaml +0 -0
- {fullbleed-2.5.2 → fullbleed-2.5.4}/python/fullbleed/__init__.py +0 -0
- {fullbleed-2.5.2 → fullbleed-2.5.4}/python/fullbleed/__main__.py +0 -0
- {fullbleed-2.5.2 → fullbleed-2.5.4}/python/fullbleed/_abi.py +0 -0
- {fullbleed-2.5.2 → fullbleed-2.5.4}/python/fullbleed/accessibility/__init__.py +0 -0
- {fullbleed-2.5.2 → fullbleed-2.5.4}/python/fullbleed/accessibility/engine.py +0 -0
- {fullbleed-2.5.2 → fullbleed-2.5.4}/python/fullbleed/accessibility/runtime.py +0 -0
- {fullbleed-2.5.2 → fullbleed-2.5.4}/python/fullbleed/accessibility/types.py +0 -0
- {fullbleed-2.5.2 → fullbleed-2.5.4}/python/fullbleed/audit_prototype.py +0 -0
- {fullbleed-2.5.2 → fullbleed-2.5.4}/python/fullbleed/audit_section508.py +0 -0
- {fullbleed-2.5.2 → fullbleed-2.5.4}/python/fullbleed/audit_wcag.py +0 -0
- {fullbleed-2.5.2 → fullbleed-2.5.4}/python/fullbleed/ui/__init__.py +0 -0
- {fullbleed-2.5.2 → fullbleed-2.5.4}/python/fullbleed/ui/accessibility.py +0 -0
- {fullbleed-2.5.2 → fullbleed-2.5.4}/python/fullbleed/ui/cav/__init__.py +0 -0
- {fullbleed-2.5.2 → fullbleed-2.5.4}/python/fullbleed/ui/cav/_core.py +0 -0
- {fullbleed-2.5.2 → fullbleed-2.5.4}/python/fullbleed/ui/cav/agency_letter.py +0 -0
- {fullbleed-2.5.2 → fullbleed-2.5.4}/python/fullbleed/ui/cav/court_motion_form.py +0 -0
- {fullbleed-2.5.2 → fullbleed-2.5.4}/python/fullbleed/ui/cav/declaration_form.py +0 -0
- {fullbleed-2.5.2 → fullbleed-2.5.4}/python/fullbleed/ui/cav/instruction_sheet.py +0 -0
- {fullbleed-2.5.2 → fullbleed-2.5.4}/python/fullbleed/ui/cav/investment_portfolio_report.py +0 -0
- {fullbleed-2.5.2 → fullbleed-2.5.4}/python/fullbleed/ui/cav/marriage_record.py +0 -0
- {fullbleed-2.5.2 → fullbleed-2.5.4}/python/fullbleed/ui/cav/profiles.py +0 -0
- {fullbleed-2.5.2 → fullbleed-2.5.4}/python/fullbleed/ui/cav/recorded_plat.py +0 -0
- {fullbleed-2.5.2 → fullbleed-2.5.4}/python/fullbleed/ui/cav/redaction_request_form.py +0 -0
- {fullbleed-2.5.2 → fullbleed-2.5.4}/python/fullbleed/ui/cav/warranty_deed.py +0 -0
- {fullbleed-2.5.2 → fullbleed-2.5.4}/python/fullbleed/ui/core.py +0 -0
- {fullbleed-2.5.2 → fullbleed-2.5.4}/python/fullbleed/ui/primitives.py +0 -0
- {fullbleed-2.5.2 → fullbleed-2.5.4}/python/fullbleed/ui/style.py +0 -0
- {fullbleed-2.5.2 → fullbleed-2.5.4}/python/fullbleed_assets/__init__.py +0 -0
- {fullbleed-2.5.2 → fullbleed-2.5.4}/python/fullbleed_assets/bootstrap.min.css +0 -0
- {fullbleed-2.5.2 → fullbleed-2.5.4}/python/fullbleed_assets/fonts/Inter-Variable.ttf +0 -0
- {fullbleed-2.5.2 → fullbleed-2.5.4}/python/fullbleed_assets/fonts/NotoSans-Regular.ttf +0 -0
- {fullbleed-2.5.2 → fullbleed-2.5.4}/python/fullbleed_assets/fonts/NotoSansMath-Regular.ttf +0 -0
- {fullbleed-2.5.2 → fullbleed-2.5.4}/python/fullbleed_assets/fonts/NotoSansSymbols-Regular.ttf +0 -0
- {fullbleed-2.5.2 → fullbleed-2.5.4}/python/fullbleed_assets/fonts/NotoSansSymbols2-Regular.ttf +0 -0
- {fullbleed-2.5.2 → fullbleed-2.5.4}/python/fullbleed_assets/icons/bootstrap-icons.svg +0 -0
- {fullbleed-2.5.2 → fullbleed-2.5.4}/python/fullbleed_cli/__init__.py +0 -0
- {fullbleed-2.5.2 → fullbleed-2.5.4}/python/fullbleed_cli/__main__.py +0 -0
- {fullbleed-2.5.2 → fullbleed-2.5.4}/python/fullbleed_cli/agent.py +0 -0
- {fullbleed-2.5.2 → fullbleed-2.5.4}/python/fullbleed_cli/agent_acceptance.py +0 -0
- {fullbleed-2.5.2 → fullbleed-2.5.4}/python/fullbleed_cli/agent_contract.py +0 -0
- {fullbleed-2.5.2 → fullbleed-2.5.4}/python/fullbleed_cli/assets.py +0 -0
- {fullbleed-2.5.2 → fullbleed-2.5.4}/python/fullbleed_cli/cache.py +0 -0
- {fullbleed-2.5.2 → fullbleed-2.5.4}/python/fullbleed_cli/finalize.py +0 -0
- {fullbleed-2.5.2 → fullbleed-2.5.4}/python/fullbleed_cli/mcp.py +0 -0
- {fullbleed-2.5.2 → fullbleed-2.5.4}/python/fullbleed_cli/scaffold.py +0 -0
- {fullbleed-2.5.2 → fullbleed-2.5.4}/python/fullbleed_cli/scaffold_templates/__init__.py +0 -0
- {fullbleed-2.5.2 → fullbleed-2.5.4}/python/fullbleed_cli/scaffold_templates/init/.gitignore +0 -0
- {fullbleed-2.5.2 → fullbleed-2.5.4}/python/fullbleed_cli/scaffold_templates/init/AGENTS.md +0 -0
- {fullbleed-2.5.2 → fullbleed-2.5.4}/python/fullbleed_cli/scaffold_templates/init/COMPLIANCE.md +0 -0
- {fullbleed-2.5.2 → fullbleed-2.5.4}/python/fullbleed_cli/scaffold_templates/init/SCAFFOLDING.md +0 -0
- {fullbleed-2.5.2 → fullbleed-2.5.4}/python/fullbleed_cli/scaffold_templates/init/components/__init__.py +0 -0
- {fullbleed-2.5.2 → fullbleed-2.5.4}/python/fullbleed_cli/scaffold_templates/init/components/body.py +0 -0
- {fullbleed-2.5.2 → fullbleed-2.5.4}/python/fullbleed_cli/scaffold_templates/init/components/fb_ui.py +0 -0
- {fullbleed-2.5.2 → fullbleed-2.5.4}/python/fullbleed_cli/scaffold_templates/init/components/footer.py +0 -0
- {fullbleed-2.5.2 → fullbleed-2.5.4}/python/fullbleed_cli/scaffold_templates/init/components/header.py +0 -0
- {fullbleed-2.5.2 → fullbleed-2.5.4}/python/fullbleed_cli/scaffold_templates/init/components/primitives.py +0 -0
- {fullbleed-2.5.2 → fullbleed-2.5.4}/python/fullbleed_cli/scaffold_templates/init/components/styles/body.css +0 -0
- {fullbleed-2.5.2 → fullbleed-2.5.4}/python/fullbleed_cli/scaffold_templates/init/components/styles/footer.css +0 -0
- {fullbleed-2.5.2 → fullbleed-2.5.4}/python/fullbleed_cli/scaffold_templates/init/components/styles/header.css +0 -0
- {fullbleed-2.5.2 → fullbleed-2.5.4}/python/fullbleed_cli/scaffold_templates/init/components/styles/primitives.css +0 -0
- {fullbleed-2.5.2 → fullbleed-2.5.4}/python/fullbleed_cli/scaffold_templates/init/report.py +0 -0
- {fullbleed-2.5.2 → fullbleed-2.5.4}/python/fullbleed_cli/scaffold_templates/init/styles/report.css +0 -0
- {fullbleed-2.5.2 → fullbleed-2.5.4}/python/fullbleed_cli/scaffold_templates/init/styles/tokens.css +0 -0
- {fullbleed-2.5.2 → fullbleed-2.5.4}/python/fullbleed_cli/scaffold_templates/new/accessible/README.md +0 -0
- {fullbleed-2.5.2 → fullbleed-2.5.4}/python/fullbleed_cli/scaffold_templates/new/accessible/output/.gitignore +0 -0
- {fullbleed-2.5.2 → fullbleed-2.5.4}/python/fullbleed_cli/scaffold_templates/new/accessible/output/.gitkeep +0 -0
- {fullbleed-2.5.2 → fullbleed-2.5.4}/python/fullbleed_cli/scaffold_templates/new/accessible/report.py +0 -0
- {fullbleed-2.5.2 → fullbleed-2.5.4}/python/fullbleed_cli/scaffold_templates/new/accessible/styles/report.css +0 -0
- {fullbleed-2.5.2 → fullbleed-2.5.4}/python/fullbleed_cli/scaffold_templates/new/accessible/vendor/fonts/Inter-Variable.ttf +0 -0
- {fullbleed-2.5.2 → fullbleed-2.5.4}/python/fullbleed_cli/scaffold_templates/new/invoice/output/.gitignore +0 -0
- {fullbleed-2.5.2 → fullbleed-2.5.4}/python/fullbleed_cli/scaffold_templates/new/invoice/output/.gitkeep +0 -0
- {fullbleed-2.5.2 → fullbleed-2.5.4}/python/fullbleed_cli/scaffold_templates/new/invoice/report.py +0 -0
- {fullbleed-2.5.2 → fullbleed-2.5.4}/python/fullbleed_cli/scaffold_templates/new/invoice/templates/invoice.css +0 -0
- {fullbleed-2.5.2 → fullbleed-2.5.4}/python/fullbleed_cli/scaffold_templates/new/invoice/templates/invoice.html +0 -0
- {fullbleed-2.5.2 → fullbleed-2.5.4}/python/fullbleed_cli/scaffold_templates/new/reference/COMPLIANCE.md +0 -0
- {fullbleed-2.5.2 → fullbleed-2.5.4}/python/fullbleed_cli/scaffold_templates/new/reference/README.md +0 -0
- {fullbleed-2.5.2 → fullbleed-2.5.4}/python/fullbleed_cli/scaffold_templates/new/reference/SCAFFOLDING.md +0 -0
- {fullbleed-2.5.2 → fullbleed-2.5.4}/python/fullbleed_cli/scaffold_templates/new/reference/assets/brand-mark.svg +0 -0
- {fullbleed-2.5.2 → fullbleed-2.5.4}/python/fullbleed_cli/scaffold_templates/new/reference/assets/reference-pattern.svg +0 -0
- {fullbleed-2.5.2 → fullbleed-2.5.4}/python/fullbleed_cli/scaffold_templates/new/reference/components/__init__.py +0 -0
- {fullbleed-2.5.2 → fullbleed-2.5.4}/python/fullbleed_cli/scaffold_templates/new/reference/components/appendix.py +0 -0
- {fullbleed-2.5.2 → fullbleed-2.5.4}/python/fullbleed_cli/scaffold_templates/new/reference/components/architecture.py +0 -0
- {fullbleed-2.5.2 → fullbleed-2.5.4}/python/fullbleed_cli/scaffold_templates/new/reference/components/cover.py +0 -0
- {fullbleed-2.5.2 → fullbleed-2.5.4}/python/fullbleed_cli/scaffold_templates/new/reference/components/data_pages.py +0 -0
- {fullbleed-2.5.2 → fullbleed-2.5.4}/python/fullbleed_cli/scaffold_templates/new/reference/components/fb_ui.py +0 -0
- {fullbleed-2.5.2 → fullbleed-2.5.4}/python/fullbleed_cli/scaffold_templates/new/reference/components/primitives.py +0 -0
- {fullbleed-2.5.2 → fullbleed-2.5.4}/python/fullbleed_cli/scaffold_templates/new/reference/components/styles/appendix.css +0 -0
- {fullbleed-2.5.2 → fullbleed-2.5.4}/python/fullbleed_cli/scaffold_templates/new/reference/components/styles/architecture.css +0 -0
- {fullbleed-2.5.2 → fullbleed-2.5.4}/python/fullbleed_cli/scaffold_templates/new/reference/components/styles/cover.css +0 -0
- {fullbleed-2.5.2 → fullbleed-2.5.4}/python/fullbleed_cli/scaffold_templates/new/reference/components/styles/data.css +0 -0
- {fullbleed-2.5.2 → fullbleed-2.5.4}/python/fullbleed_cli/scaffold_templates/new/reference/components/styles/primitives.css +0 -0
- {fullbleed-2.5.2 → fullbleed-2.5.4}/python/fullbleed_cli/scaffold_templates/new/reference/components/styles/visuals.css +0 -0
- {fullbleed-2.5.2 → fullbleed-2.5.4}/python/fullbleed_cli/scaffold_templates/new/reference/components/visuals.py +0 -0
- {fullbleed-2.5.2 → fullbleed-2.5.4}/python/fullbleed_cli/scaffold_templates/new/reference/data/reference.json +0 -0
- {fullbleed-2.5.2 → fullbleed-2.5.4}/python/fullbleed_cli/scaffold_templates/new/reference/output/.gitignore +0 -0
- {fullbleed-2.5.2 → fullbleed-2.5.4}/python/fullbleed_cli/scaffold_templates/new/reference/report.py +0 -0
- {fullbleed-2.5.2 → fullbleed-2.5.4}/python/fullbleed_cli/scaffold_templates/new/reference/styles/report.css +0 -0
- {fullbleed-2.5.2 → fullbleed-2.5.4}/python/fullbleed_cli/scaffold_templates/new/reference/styles/tokens.css +0 -0
- {fullbleed-2.5.2 → fullbleed-2.5.4}/python/fullbleed_cli/scaffold_templates/new/statement/output/.gitignore +0 -0
- {fullbleed-2.5.2 → fullbleed-2.5.4}/python/fullbleed_cli/scaffold_templates/new/statement/output/.gitkeep +0 -0
- {fullbleed-2.5.2 → fullbleed-2.5.4}/python/fullbleed_cli/scaffold_templates/new/statement/report.py +0 -0
- {fullbleed-2.5.2 → fullbleed-2.5.4}/python/fullbleed_cli/scaffold_templates/new/statement/templates/statement.css +0 -0
- {fullbleed-2.5.2 → fullbleed-2.5.4}/python/fullbleed_cli/scaffold_templates/new/statement/templates/statement.html +0 -0
- {fullbleed-2.5.2 → fullbleed-2.5.4}/python/fullbleed_cli/watch.py +0 -0
- {fullbleed-2.5.2 → fullbleed-2.5.4}/skills/fullbleed/SKILL.md +0 -0
- {fullbleed-2.5.2 → fullbleed-2.5.4}/skills/fullbleed/agents/openai.yaml +0 -0
- {fullbleed-2.5.2 → fullbleed-2.5.4}/skills/fullbleed/references/compliance.md +0 -0
- {fullbleed-2.5.2 → fullbleed-2.5.4}/skills/fullbleed/references/selection.md +0 -0
- {fullbleed-2.5.2 → fullbleed-2.5.4}/skills/fullbleed/references/workflows.md +0 -0
- {fullbleed-2.5.2 → fullbleed-2.5.4}/src/assets.rs +0 -0
- {fullbleed-2.5.2 → fullbleed-2.5.4}/src/authoring.rs +0 -0
- {fullbleed-2.5.2 → fullbleed-2.5.4}/src/base64.rs +0 -0
- {fullbleed-2.5.2 → fullbleed-2.5.4}/src/canvas.rs +0 -0
- {fullbleed-2.5.2 → fullbleed-2.5.4}/src/chart.rs +0 -0
- {fullbleed-2.5.2 → fullbleed-2.5.4}/src/chart_document.rs +0 -0
- {fullbleed-2.5.2 → fullbleed-2.5.4}/src/css_native.rs +0 -0
- {fullbleed-2.5.2 → fullbleed-2.5.4}/src/css_queries.rs +0 -0
- {fullbleed-2.5.2 → fullbleed-2.5.4}/src/debug.rs +0 -0
- {fullbleed-2.5.2 → fullbleed-2.5.4}/src/doc_context.rs +0 -0
- {fullbleed-2.5.2 → fullbleed-2.5.4}/src/doc_template.rs +0 -0
- {fullbleed-2.5.2 → fullbleed-2.5.4}/src/document_metadata.rs +0 -0
- {fullbleed-2.5.2 → fullbleed-2.5.4}/src/error.rs +0 -0
- {fullbleed-2.5.2 → fullbleed-2.5.4}/src/finalize.rs +0 -0
- {fullbleed-2.5.2 → fullbleed-2.5.4}/src/flate_native.rs +0 -0
- {fullbleed-2.5.2 → fullbleed-2.5.4}/src/flowable.rs +0 -0
- {fullbleed-2.5.2 → fullbleed-2.5.4}/src/font.rs +0 -0
- {fullbleed-2.5.2 → fullbleed-2.5.4}/src/font_subset.rs +0 -0
- {fullbleed-2.5.2 → fullbleed-2.5.4}/src/frame.rs +0 -0
- {fullbleed-2.5.2 → fullbleed-2.5.4}/src/glyph_report.rs +0 -0
- {fullbleed-2.5.2 → fullbleed-2.5.4}/src/html.rs +0 -0
- {fullbleed-2.5.2 → fullbleed-2.5.4}/src/html_dom.rs +0 -0
- {fullbleed-2.5.2 → fullbleed-2.5.4}/src/html_entities.rs +0 -0
- {fullbleed-2.5.2 → fullbleed-2.5.4}/src/html_entities_0.rs +0 -0
- {fullbleed-2.5.2 → fullbleed-2.5.4}/src/html_entities_1.rs +0 -0
- {fullbleed-2.5.2 → fullbleed-2.5.4}/src/html_entities_2.rs +0 -0
- {fullbleed-2.5.2 → fullbleed-2.5.4}/src/html_entities_3.rs +0 -0
- {fullbleed-2.5.2 → fullbleed-2.5.4}/src/html_entities_4.rs +0 -0
- {fullbleed-2.5.2 → fullbleed-2.5.4}/src/html_entities_5.rs +0 -0
- {fullbleed-2.5.2 → fullbleed-2.5.4}/src/icc.rs +0 -0
- {fullbleed-2.5.2 → fullbleed-2.5.4}/src/image_native.rs +0 -0
- {fullbleed-2.5.2 → fullbleed-2.5.4}/src/jit.rs +0 -0
- {fullbleed-2.5.2 → fullbleed-2.5.4}/src/jpeg_native.rs +0 -0
- {fullbleed-2.5.2 → fullbleed-2.5.4}/src/math.rs +0 -0
- {fullbleed-2.5.2 → fullbleed-2.5.4}/src/metrics.rs +0 -0
- {fullbleed-2.5.2 → fullbleed-2.5.4}/src/native_shape.rs +0 -0
- {fullbleed-2.5.2 → fullbleed-2.5.4}/src/page_data.rs +0 -0
- {fullbleed-2.5.2 → fullbleed-2.5.4}/src/page_template.rs +0 -0
- {fullbleed-2.5.2 → fullbleed-2.5.4}/src/parallel.rs +0 -0
- {fullbleed-2.5.2 → fullbleed-2.5.4}/src/pdf.rs +0 -0
- {fullbleed-2.5.2 → fullbleed-2.5.4}/src/pdf_encodings.rs +0 -0
- {fullbleed-2.5.2 → fullbleed-2.5.4}/src/pdf_identity.rs +0 -0
- {fullbleed-2.5.2 → fullbleed-2.5.4}/src/pdf_native.rs +0 -0
- {fullbleed-2.5.2 → fullbleed-2.5.4}/src/pdf_print_contract.rs +0 -0
- {fullbleed-2.5.2 → fullbleed-2.5.4}/src/pdf_profile.rs +0 -0
- {fullbleed-2.5.2 → fullbleed-2.5.4}/src/pdf_table.rs +0 -0
- {fullbleed-2.5.2 → fullbleed-2.5.4}/src/pdf_vt.rs +0 -0
- {fullbleed-2.5.2 → fullbleed-2.5.4}/src/pdf_vt_inspect.rs +0 -0
- {fullbleed-2.5.2 → fullbleed-2.5.4}/src/pdfinspect.rs +0 -0
- {fullbleed-2.5.2 → fullbleed-2.5.4}/src/perf.rs +0 -0
- {fullbleed-2.5.2 → fullbleed-2.5.4}/src/plan.rs +0 -0
- {fullbleed-2.5.2 → fullbleed-2.5.4}/src/python/abi_exports.rs +0 -0
- {fullbleed-2.5.2 → fullbleed-2.5.4}/src/python/pdf_vt.rs +0 -0
- {fullbleed-2.5.2 → fullbleed-2.5.4}/src/python.rs +0 -0
- {fullbleed-2.5.2 → fullbleed-2.5.4}/src/python_abi.rs +0 -0
- {fullbleed-2.5.2 → fullbleed-2.5.4}/src/raster.rs +0 -0
- {fullbleed-2.5.2 → fullbleed-2.5.4}/src/raster_native.rs +0 -0
- {fullbleed-2.5.2 → fullbleed-2.5.4}/src/sfnt.rs +0 -0
- {fullbleed-2.5.2 → fullbleed-2.5.4}/src/sfnt_cff.rs +0 -0
- {fullbleed-2.5.2 → fullbleed-2.5.4}/src/sfnt_outline.rs +0 -0
- {fullbleed-2.5.2 → fullbleed-2.5.4}/src/spill.rs +0 -0
- {fullbleed-2.5.2 → fullbleed-2.5.4}/src/style.rs +0 -0
- {fullbleed-2.5.2 → fullbleed-2.5.4}/src/svg.rs +0 -0
- {fullbleed-2.5.2 → fullbleed-2.5.4}/src/table_header_tests.rs +0 -0
- {fullbleed-2.5.2 → fullbleed-2.5.4}/src/table_semantics.rs +0 -0
- {fullbleed-2.5.2 → fullbleed-2.5.4}/src/text_shape.rs +0 -0
- {fullbleed-2.5.2 → fullbleed-2.5.4}/src/types.rs +0 -0
- {fullbleed-2.5.2 → fullbleed-2.5.4}/src/unicode_data.rs +0 -0
- {fullbleed-2.5.2 → fullbleed-2.5.4}/src/xml.rs +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: fullbleed
|
|
3
|
-
Version: 2.5.
|
|
3
|
+
Version: 2.5.4
|
|
4
4
|
Classifier: Development Status :: 5 - Production/Stable
|
|
5
5
|
Classifier: License :: OSI Approved :: MIT License
|
|
6
6
|
Classifier: Operating System :: MacOS
|
|
@@ -91,7 +91,9 @@ Open `invoice.pdf`. The [quickstart](https://docs.fullbleed.dev/getting-started/
|
|
|
91
91
|
| A native Rust application | [Rust quickstart and runnable examples](https://docs.fullbleed.dev/getting-started/rust/) |
|
|
92
92
|
| An invoice from JSON | [Complete, checked example](examples/agent_workflows) |
|
|
93
93
|
| Automatic rebuilds while editing HTML/CSS (2.5.0+) | [Watch-mode invoice example](examples/render_watch) |
|
|
94
|
+
| Catch PDF changes in pull requests | [Standalone project with a reviewed baseline and CI workflow](examples/pdf_regression) |
|
|
94
95
|
| A PDF download in FastAPI, Flask, or Django | [Runnable web app examples](examples/web_frameworks) |
|
|
96
|
+
| A styled PDF report from a pandas DataFrame | [Paginated report with CSV data and verification](examples/pandas_report) |
|
|
95
97
|
| A styled invoice from CSV | [Acme invoice project](examples/acme_invoice) |
|
|
96
98
|
| A report that flows across pages | [Business report example](examples/agent_workflows) |
|
|
97
99
|
| Tagged output with accessibility checks | [Accessibility workflow](docs/ui-accessibility.md) |
|
|
@@ -266,7 +268,7 @@ python -m pip install fullbleed
|
|
|
266
268
|
From a local wheel:
|
|
267
269
|
|
|
268
270
|
```bash
|
|
269
|
-
python -m pip install C:\path\to\fullbleed-2.5.
|
|
271
|
+
python -m pip install C:\path\to\fullbleed-2.5.4-cp310-abi3-win_amd64.whl
|
|
270
272
|
```
|
|
271
273
|
|
|
272
274
|
From a source checkout with Rust installed, no Python build package is needed:
|
|
@@ -48,7 +48,9 @@ Open `invoice.pdf`. The [quickstart](https://docs.fullbleed.dev/getting-started/
|
|
|
48
48
|
| A native Rust application | [Rust quickstart and runnable examples](https://docs.fullbleed.dev/getting-started/rust/) |
|
|
49
49
|
| An invoice from JSON | [Complete, checked example](examples/agent_workflows) |
|
|
50
50
|
| Automatic rebuilds while editing HTML/CSS (2.5.0+) | [Watch-mode invoice example](examples/render_watch) |
|
|
51
|
+
| Catch PDF changes in pull requests | [Standalone project with a reviewed baseline and CI workflow](examples/pdf_regression) |
|
|
51
52
|
| A PDF download in FastAPI, Flask, or Django | [Runnable web app examples](examples/web_frameworks) |
|
|
53
|
+
| A styled PDF report from a pandas DataFrame | [Paginated report with CSV data and verification](examples/pandas_report) |
|
|
52
54
|
| A styled invoice from CSV | [Acme invoice project](examples/acme_invoice) |
|
|
53
55
|
| A report that flows across pages | [Business report example](examples/agent_workflows) |
|
|
54
56
|
| Tagged output with accessibility checks | [Accessibility workflow](docs/ui-accessibility.md) |
|
|
@@ -223,7 +225,7 @@ python -m pip install fullbleed
|
|
|
223
225
|
From a local wheel:
|
|
224
226
|
|
|
225
227
|
```bash
|
|
226
|
-
python -m pip install C:\path\to\fullbleed-2.5.
|
|
228
|
+
python -m pip install C:\path\to\fullbleed-2.5.4-cp310-abi3-win_amd64.whl
|
|
227
229
|
```
|
|
228
230
|
|
|
229
231
|
From a source checkout with Rust installed, no Python build package is needed:
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
<!-- SPDX-License-Identifier: MIT -->
|
|
2
|
+
# Third-Party Licenses
|
|
3
|
+
|
|
4
|
+
Schema: `fullbleed.third_party_licenses.v1`
|
|
5
|
+
Last updated: 2026-10-02
|
|
6
|
+
Scope: third-party artifacts directly redistributed by this repository and wheel package.
|
|
7
|
+
|
|
8
|
+
## Bundled Artifacts
|
|
9
|
+
|
|
10
|
+
| Component | Bundled Path | License | Upstream | License Text |
|
|
11
|
+
| --- | --- | --- | --- | --- |
|
|
12
|
+
| Bootstrap CSS `v5.0.0` | `python/fullbleed_assets/bootstrap.min.css` | `MIT` | `https://getbootstrap.com/` | `https://github.com/twbs/bootstrap/blob/v5.0.0/LICENSE` |
|
|
13
|
+
| Bootstrap Icons SVG Sprite `v1.11.3` | `python/fullbleed_assets/icons/bootstrap-icons.svg` | `MIT` | `https://icons.getbootstrap.com/` | `https://raw.githubusercontent.com/twbs/icons/v1.11.3/LICENSE` |
|
|
14
|
+
| Inter Variable | `python/fullbleed_assets/fonts/Inter-Variable.ttf` | `OFL-1.1` | `https://fonts.google.com/specimen/Inter` | `https://raw.githubusercontent.com/google/fonts/main/ofl/inter/OFL.txt` |
|
|
15
|
+
| Noto Sans Regular | `python/fullbleed_assets/fonts/NotoSans-Regular.ttf` | `OFL-1.1` | `https://fonts.google.com/noto` | `https://raw.githubusercontent.com/google/fonts/main/ofl/notosans/OFL.txt` |
|
|
16
|
+
| Noto Sans Math Regular | `python/fullbleed_assets/fonts/NotoSansMath-Regular.ttf` | `OFL-1.1` | `https://fonts.google.com/noto` | `https://raw.githubusercontent.com/google/fonts/main/ofl/notosansmath/OFL.txt` |
|
|
17
|
+
| Noto Sans Symbols Regular | `python/fullbleed_assets/fonts/NotoSansSymbols-Regular.ttf` | `OFL-1.1` | `https://fonts.google.com/noto` | `https://raw.githubusercontent.com/google/fonts/main/ofl/notosanssymbols/OFL.txt` |
|
|
18
|
+
| Noto Sans Symbols2 Regular | `python/fullbleed_assets/fonts/NotoSansSymbols2-Regular.ttf` | `OFL-1.1` | `https://fonts.google.com/noto` | `https://raw.githubusercontent.com/google/fonts/main/ofl/notosanssymbols2/OFL.txt` |
|
|
19
|
+
| Adobe Core 14 metrics | `src/base14_metrics_data.rs`; originals in `tools/data/base14/*.afm` | Adobe AFM permission below | Pinned Apache PDFBox mirror | `tools/data/base14/MustRead.html` |
|
|
20
|
+
| Adobe Glyph List | `src/base14_metrics_data.rs`; originals in `tools/data/base14/agl-*.txt` | BSD-3-Clause | `https://github.com/adobe-type-tools/agl-aglfn` | `tools/data/base14/agl-LICENSE.md` and copyright notices below |
|
|
21
|
+
|
|
22
|
+
## Remote-Installable Asset Registry
|
|
23
|
+
|
|
24
|
+
`fullbleed assets install <name>` supports additional remote fonts.
|
|
25
|
+
|
|
26
|
+
- Current audit artifacts:
|
|
27
|
+
- `FONT_LICENSE_AUDIT.md`
|
|
28
|
+
- `FONT_LICENSE_AUDIT.json`
|
|
29
|
+
- Audit summary (2026-07-28):
|
|
30
|
+
- `39` fonts checked
|
|
31
|
+
- `39` passed
|
|
32
|
+
- Allowed license set: `OFL-1.1`, `Apache-2.0`, `UFL-1.0`, `MIT`
|
|
33
|
+
- Includes barcode families: `libre-barcode-128`, `libre-barcode-128-text`, `libre-barcode-39`, `libre-barcode-39-text`, `libre-barcode-39-extended`, `libre-barcode-ean13-text`
|
|
34
|
+
|
|
35
|
+
## Compliance Policy Semantics
|
|
36
|
+
|
|
37
|
+
Machine/readable policy identifier: `fullbleed.cli_compliance.v1`
|
|
38
|
+
|
|
39
|
+
- `LIC_MISSING_NOTICE`: bundled third-party artifact missing an entry in this document.
|
|
40
|
+
- `LIC_DISALLOWED`: artifact license is outside allowlist.
|
|
41
|
+
- `LIC_UNKNOWN`: artifact license cannot be determined.
|
|
42
|
+
- `LIC_AUDIT_STALE`: remote asset audit artifacts are missing or stale.
|
|
43
|
+
- `LIC_ASSET_UNMAPPED`: asset exists in distribution but has no license mapping.
|
|
44
|
+
|
|
45
|
+
## Notes
|
|
46
|
+
|
|
47
|
+
- This file focuses on directly redistributed static assets (CSS/fonts/font metrics) and remote asset registry policy.
|
|
48
|
+
- USPS IMB fonts are currently treated as manual user-supplied assets pending explicit redistribution policy sign-off.
|
|
49
|
+
- For project license terms, see `LICENSE`.
|
|
50
|
+
- For licensing questions, email `info@fullbleed.dev` or visit `fullbleed.dev`.
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
## Adobe Core 14 metrics
|
|
54
|
+
|
|
55
|
+
The original AFM files and accompanying `MustRead.html` are retained unchanged in
|
|
56
|
+
`tools/data/base14`. Their source commits, SHA-256 hashes, and byte lengths are
|
|
57
|
+
recorded in `sources.json`. The generated Rust tables are modified derivatives:
|
|
58
|
+
Fullbleed extracts and reorganizes advances, glyph names, and character mappings
|
|
59
|
+
for native PDF preview. They contain no font programs or glyph outlines.
|
|
60
|
+
|
|
61
|
+
Original copyright and trademark notices:
|
|
62
|
+
|
|
63
|
+
Copyright (c) 1985, 1987, 1988, 1989, 1997 Adobe Systems Incorporated. All Rights Reserved.
|
|
64
|
+
|
|
65
|
+
Copyright (c) 1985, 1987, 1988, 1989, 1997 Adobe Systems Incorporated. All Rights Reserved.ITC Zapf Dingbats is a registered trademark of International Typeface Corporation.
|
|
66
|
+
|
|
67
|
+
Copyright (c) 1985, 1987, 1989, 1990, 1993, 1997 Adobe Systems Incorporated. All Rights Reserved.
|
|
68
|
+
|
|
69
|
+
Copyright (c) 1985, 1987, 1989, 1990, 1993, 1997 Adobe Systems Incorporated. All Rights Reserved.Times is a trademark of Linotype-Hell AG and/or its subsidiaries.
|
|
70
|
+
|
|
71
|
+
Copyright (c) 1985, 1987, 1989, 1990, 1997 Adobe Systems Incorporated. All Rights Reserved.
|
|
72
|
+
|
|
73
|
+
Copyright (c) 1985, 1987, 1989, 1990, 1997 Adobe Systems Incorporated. All Rights Reserved.Helvetica is a trademark of Linotype-Hell AG and/or its subsidiaries.
|
|
74
|
+
|
|
75
|
+
Copyright (c) 1985, 1987, 1989, 1990, 1997 Adobe Systems Incorporated. All rights reserved.
|
|
76
|
+
|
|
77
|
+
Copyright (c) 1989, 1990, 1991, 1992, 1993, 1997 Adobe Systems Incorporated. All Rights Reserved.
|
|
78
|
+
|
|
79
|
+
Copyright (c) 1989, 1990, 1991, 1993, 1997 Adobe Systems Incorporated. All Rights Reserved.
|
|
80
|
+
|
|
81
|
+
Original redistribution permission (unchanged):
|
|
82
|
+
|
|
83
|
+
This file and the 14 PostScript(R) AFM files it accompanies may be used, copied, and distributed for any purpose and without charge, with or without modification, provided that all copyright notices are retained; that the AFM files are not distributed without this file; that all modifications to this file or any of the AFM files are prominently noted in the modified file(s); and that this paragraph is not modified. Adobe Systems has no responsibility or obligation to support the use of the AFM files.
|
|
84
|
+
|
|
85
|
+
## Adobe Glyph List
|
|
86
|
+
|
|
87
|
+
Copyright 2002-2019 Adobe (http://www.adobe.com/).
|
|
88
|
+
|
|
89
|
+
The generated character mappings derive from the Adobe Glyph List and its Zapf
|
|
90
|
+
Dingbats list. Original source files and license text are retained unchanged in
|
|
91
|
+
`tools/data/base14`. The redistribution terms below also apply to the derived
|
|
92
|
+
mappings in source and binary distributions.
|
|
93
|
+
|
|
94
|
+
Redistribution and use in source and binary forms, with or without
|
|
95
|
+
modification, are permitted provided that the following conditions are
|
|
96
|
+
met:
|
|
97
|
+
|
|
98
|
+
Redistributions of source code must retain the above copyright notice,
|
|
99
|
+
this list of conditions and the following disclaimer.
|
|
100
|
+
|
|
101
|
+
Redistributions in binary form must reproduce the above copyright
|
|
102
|
+
notice, this list of conditions and the following disclaimer in the
|
|
103
|
+
documentation and/or other materials provided with the distribution.
|
|
104
|
+
|
|
105
|
+
Neither the name of Adobe nor the names of its contributors may be
|
|
106
|
+
used to endorse or promote products derived from this software without
|
|
107
|
+
specific prior written permission.
|
|
108
|
+
|
|
109
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
110
|
+
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
111
|
+
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|
112
|
+
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
|
113
|
+
HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
114
|
+
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
115
|
+
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
116
|
+
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
117
|
+
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
118
|
+
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
119
|
+
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
@@ -941,6 +941,7 @@ def _sdist_files() -> list[Path]:
|
|
|
941
941
|
"Cargo.lock",
|
|
942
942
|
"build.rs",
|
|
943
943
|
"pyproject.toml",
|
|
944
|
+
"tools/generate_base14_metrics.py",
|
|
944
945
|
str(project.get("readme", "README.md")),
|
|
945
946
|
*project.get("license-files", []),
|
|
946
947
|
)
|
|
@@ -948,6 +949,7 @@ def _sdist_files() -> list[Path]:
|
|
|
948
949
|
roots = [
|
|
949
950
|
_ROOT / "src",
|
|
950
951
|
_ROOT / "build_backend",
|
|
952
|
+
_ROOT / "tools" / "data" / "base14",
|
|
951
953
|
_ROOT / "crates" / "fullbleed_audit_contract" / "src",
|
|
952
954
|
_ROOT / "crates" / "fullbleed_audit_contract" / "specs",
|
|
953
955
|
]
|
|
@@ -961,6 +961,7 @@
|
|
|
961
961
|
"new:statement": "fullbleed.new_template.v1",
|
|
962
962
|
"plan": "fullbleed.plan_result.v1",
|
|
963
963
|
"render": "fullbleed.render_result.v1",
|
|
964
|
+
"repro-record": "fullbleed.repro_record.v1",
|
|
964
965
|
"run": "fullbleed.run_result.v1",
|
|
965
966
|
"verify": "fullbleed.verify_result.v1"
|
|
966
967
|
},
|
|
@@ -4206,7 +4207,7 @@
|
|
|
4206
4207
|
"license": "MIT",
|
|
4207
4208
|
"name": "Fullbleed PDF Engine",
|
|
4208
4209
|
"python_package": "fullbleed",
|
|
4209
|
-
"version": "2.5.
|
|
4210
|
+
"version": "2.5.4"
|
|
4210
4211
|
},
|
|
4211
4212
|
"profiles": {
|
|
4212
4213
|
"pdf": {
|
|
@@ -5281,22 +5282,45 @@
|
|
|
5281
5282
|
},
|
|
5282
5283
|
"fullbleed.repro_record.v1": {
|
|
5283
5284
|
"properties": {
|
|
5285
|
+
"assets_lock": {
|
|
5286
|
+
"properties": {
|
|
5287
|
+
"path": {
|
|
5288
|
+
"type": "string"
|
|
5289
|
+
},
|
|
5290
|
+
"sha256": {
|
|
5291
|
+
"pattern": "^[0-9a-f]{64}$",
|
|
5292
|
+
"type": "string"
|
|
5293
|
+
}
|
|
5294
|
+
},
|
|
5295
|
+
"required": [
|
|
5296
|
+
"sha256"
|
|
5297
|
+
],
|
|
5298
|
+
"type": [
|
|
5299
|
+
"object",
|
|
5300
|
+
"null"
|
|
5301
|
+
]
|
|
5302
|
+
},
|
|
5284
5303
|
"cli_version": {
|
|
5285
5304
|
"type": "string"
|
|
5286
5305
|
},
|
|
5287
5306
|
"input_fingerprint_sha256": {
|
|
5307
|
+
"pattern": "^[0-9a-f]{64}$",
|
|
5288
5308
|
"type": "string"
|
|
5289
5309
|
},
|
|
5290
5310
|
"input_manifest_sha256": {
|
|
5311
|
+
"pattern": "^[0-9a-f]{64}$",
|
|
5291
5312
|
"type": "string"
|
|
5292
5313
|
},
|
|
5293
5314
|
"output_bytes_written": {
|
|
5315
|
+
"minimum": 0,
|
|
5294
5316
|
"type": "integer"
|
|
5295
5317
|
},
|
|
5296
5318
|
"output_pdf_sha256": {
|
|
5319
|
+
"pattern": "^[0-9a-f]{64}$",
|
|
5297
5320
|
"type": "string"
|
|
5298
5321
|
},
|
|
5299
5322
|
"schema": {
|
|
5323
|
+
"const": "fullbleed.repro_record.v1",
|
|
5300
5324
|
"type": "string"
|
|
5301
5325
|
}
|
|
5302
5326
|
},
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Fullbleed PDF Engine
|
|
2
2
|
|
|
3
|
-
> Fullbleed 2.5.
|
|
3
|
+
> Fullbleed 2.5.4 is a deterministic, self-contained document-generation runtime for Python and Rust. It turns structured data plus static HTML/CSS into validated PDF documents without a browser.
|
|
4
4
|
|
|
5
5
|
The installed runtime is authoritative. Do not infer its API from this file or from remembered release knowledge. Start with:
|
|
6
6
|
|
|
@@ -5,7 +5,7 @@ backend-path = ["build_backend"]
|
|
|
5
5
|
|
|
6
6
|
[project]
|
|
7
7
|
name = "fullbleed"
|
|
8
|
-
version = "2.5.
|
|
8
|
+
version = "2.5.4"
|
|
9
9
|
description = "Deterministic Python PDF engine for reports, invoices, accessible documents, print-ready output, and compiled VDP"
|
|
10
10
|
readme = "README.md"
|
|
11
11
|
requires-python = ">=3.10"
|
|
@@ -108,6 +108,7 @@ COMPLIANCE_POLICY = {
|
|
|
108
108
|
}
|
|
109
109
|
|
|
110
110
|
SCHEMA_REGISTRY = {
|
|
111
|
+
"repro-record": "fullbleed.repro_record.v1",
|
|
111
112
|
"render": "fullbleed.render_result.v1",
|
|
112
113
|
"verify": "fullbleed.verify_result.v1",
|
|
113
114
|
"plan": "fullbleed.plan_result.v1",
|
|
@@ -543,12 +544,20 @@ SCHEMA_DEFS = {
|
|
|
543
544
|
"type": "object",
|
|
544
545
|
"required": ["schema", "input_fingerprint_sha256", "output_pdf_sha256"],
|
|
545
546
|
"properties": {
|
|
546
|
-
"schema": {"type": "string"},
|
|
547
|
+
"schema": {"type": "string", "const": "fullbleed.repro_record.v1"},
|
|
547
548
|
"cli_version": {"type": "string"},
|
|
548
|
-
"input_manifest_sha256": {"type": "string"},
|
|
549
|
-
"input_fingerprint_sha256": {"type": "string"},
|
|
550
|
-
"output_pdf_sha256": {"type": "string"},
|
|
551
|
-
"output_bytes_written": {"type": "integer"},
|
|
549
|
+
"input_manifest_sha256": {"type": "string", "pattern": "^[0-9a-f]{64}$"},
|
|
550
|
+
"input_fingerprint_sha256": {"type": "string", "pattern": "^[0-9a-f]{64}$"},
|
|
551
|
+
"output_pdf_sha256": {"type": "string", "pattern": "^[0-9a-f]{64}$"},
|
|
552
|
+
"output_bytes_written": {"type": "integer", "minimum": 0},
|
|
553
|
+
"assets_lock": {
|
|
554
|
+
"type": ["object", "null"],
|
|
555
|
+
"required": ["sha256"],
|
|
556
|
+
"properties": {
|
|
557
|
+
"path": {"type": "string"},
|
|
558
|
+
"sha256": {"type": "string", "pattern": "^[0-9a-f]{64}$"},
|
|
559
|
+
},
|
|
560
|
+
},
|
|
552
561
|
},
|
|
553
562
|
},
|
|
554
563
|
}
|
|
@@ -2119,6 +2128,9 @@ def _enrich_repro_failures(failures):
|
|
|
2119
2128
|
"REPRO_RECORD_INVALID": [
|
|
2120
2129
|
"Regenerate the record from a trusted clean render; do not edit digest fields manually."
|
|
2121
2130
|
],
|
|
2131
|
+
"REPRO_RECORD_CONFLICT": [
|
|
2132
|
+
"Use different files for --repro-record and --repro-check so checking cannot replace the baseline."
|
|
2133
|
+
],
|
|
2122
2134
|
"REPRO_INPUT_DRIFT": [
|
|
2123
2135
|
"Compare the input manifest, vendored assets, fonts, and assets.lock.json with the recorded run."
|
|
2124
2136
|
],
|
|
@@ -2143,6 +2155,36 @@ def _enrich_repro_failures(failures):
|
|
|
2143
2155
|
)
|
|
2144
2156
|
|
|
2145
2157
|
|
|
2158
|
+
def _repro_record_error(value, definition=None, location="record"):
|
|
2159
|
+
"""Validate the record using the same shape and digest rules exposed by --schema."""
|
|
2160
|
+
if definition is None:
|
|
2161
|
+
definition = SCHEMA_DEFS["fullbleed.repro_record.v1"]
|
|
2162
|
+
expected_types = definition["type"]
|
|
2163
|
+
if isinstance(expected_types, str):
|
|
2164
|
+
expected_types = [expected_types]
|
|
2165
|
+
types = {"object": dict, "string": str, "integer": int, "null": type(None)}
|
|
2166
|
+
if not any(type(value) is types[name] for name in expected_types):
|
|
2167
|
+
return f"{location} must have type {' or '.join(expected_types)}"
|
|
2168
|
+
if value is None:
|
|
2169
|
+
return None
|
|
2170
|
+
if "const" in definition and value != definition["const"]:
|
|
2171
|
+
return f"{location} must be {definition['const']}"
|
|
2172
|
+
if "pattern" in definition and re.fullmatch(definition["pattern"], value) is None:
|
|
2173
|
+
return f"{location} must be a lowercase SHA-256 digest (64 hexadecimal characters)"
|
|
2174
|
+
if "minimum" in definition and value < definition["minimum"]:
|
|
2175
|
+
return f"{location} must be at least {definition['minimum']}"
|
|
2176
|
+
if isinstance(value, dict):
|
|
2177
|
+
for key in definition.get("required", []):
|
|
2178
|
+
if key not in value:
|
|
2179
|
+
return f"{location}.{key} is required"
|
|
2180
|
+
for key, child in definition.get("properties", {}).items():
|
|
2181
|
+
if key in value:
|
|
2182
|
+
error = _repro_record_error(value[key], child, f"{location}.{key}")
|
|
2183
|
+
if error:
|
|
2184
|
+
return error
|
|
2185
|
+
return None
|
|
2186
|
+
|
|
2187
|
+
|
|
2146
2188
|
def _run_repro_record_or_check(args, manifest, html, css, output_hash, bytes_written):
|
|
2147
2189
|
"""Write/check reproducibility records and return associated failures."""
|
|
2148
2190
|
repro_record_path = getattr(args, "repro_record", None)
|
|
@@ -2153,11 +2195,16 @@ def _run_repro_record_or_check(args, manifest, html, css, output_hash, bytes_wri
|
|
|
2153
2195
|
current_record = _build_repro_record(args, manifest, html, css, output_hash, bytes_written)
|
|
2154
2196
|
failures = []
|
|
2155
2197
|
|
|
2156
|
-
if repro_record_path:
|
|
2157
|
-
Path(repro_record_path)
|
|
2158
|
-
|
|
2159
|
-
|
|
2160
|
-
|
|
2198
|
+
if repro_record_path and repro_check_path:
|
|
2199
|
+
record_file, check_file = Path(repro_record_path), Path(repro_check_path)
|
|
2200
|
+
same_file = record_file.resolve() == check_file.resolve()
|
|
2201
|
+
if not same_file and record_file.exists() and check_file.exists():
|
|
2202
|
+
same_file = record_file.samefile(check_file)
|
|
2203
|
+
if same_file:
|
|
2204
|
+
return current_record, [{
|
|
2205
|
+
"code": "REPRO_RECORD_CONFLICT",
|
|
2206
|
+
"message": "The record output and checked baseline refer to the same file",
|
|
2207
|
+
}]
|
|
2161
2208
|
|
|
2162
2209
|
if repro_check_path:
|
|
2163
2210
|
check_file = Path(repro_check_path)
|
|
@@ -2171,46 +2218,53 @@ def _run_repro_record_or_check(args, manifest, html, css, output_hash, bytes_wri
|
|
|
2171
2218
|
else:
|
|
2172
2219
|
try:
|
|
2173
2220
|
expected = json.loads(check_file.read_text(encoding="utf-8"))
|
|
2174
|
-
except
|
|
2221
|
+
except (ValueError, OSError) as exc:
|
|
2175
2222
|
failures.append(
|
|
2176
2223
|
{
|
|
2177
2224
|
"code": "REPRO_RECORD_INVALID",
|
|
2178
|
-
"message": f"Failed to
|
|
2225
|
+
"message": f"Failed to read repro record JSON: {exc}",
|
|
2179
2226
|
}
|
|
2180
2227
|
)
|
|
2181
|
-
expected =
|
|
2182
|
-
|
|
2183
|
-
|
|
2184
|
-
|
|
2228
|
+
expected = None
|
|
2229
|
+
else:
|
|
2230
|
+
error = _repro_record_error(expected)
|
|
2231
|
+
if error:
|
|
2232
|
+
failures.append({"code": "REPRO_RECORD_INVALID", "message": error})
|
|
2233
|
+
expected = None
|
|
2234
|
+
if expected is not None and expected["input_fingerprint_sha256"] != current_record["input_fingerprint_sha256"]:
|
|
2185
2235
|
failures.append(
|
|
2186
2236
|
{
|
|
2187
2237
|
"code": "REPRO_INPUT_DRIFT",
|
|
2188
2238
|
"message": "Input fingerprint drift detected compared to repro record",
|
|
2189
|
-
"expected":
|
|
2239
|
+
"expected": expected["input_fingerprint_sha256"],
|
|
2190
2240
|
"observed": current_record["input_fingerprint_sha256"],
|
|
2191
2241
|
}
|
|
2192
2242
|
)
|
|
2193
|
-
if
|
|
2243
|
+
if expected is not None and expected["output_pdf_sha256"] != current_record["output_pdf_sha256"]:
|
|
2194
2244
|
failures.append(
|
|
2195
2245
|
{
|
|
2196
2246
|
"code": "REPRO_HASH_MISMATCH",
|
|
2197
2247
|
"message": "Output PDF hash mismatch against repro record",
|
|
2198
|
-
"expected":
|
|
2248
|
+
"expected": expected["output_pdf_sha256"],
|
|
2199
2249
|
"observed": current_record["output_pdf_sha256"],
|
|
2200
2250
|
}
|
|
2201
2251
|
)
|
|
2202
|
-
expected_lock = (expected.get("assets_lock") or {}).get("sha256")
|
|
2252
|
+
expected_lock = ((expected or {}).get("assets_lock") or {}).get("sha256")
|
|
2203
2253
|
observed_lock = (current_record.get("assets_lock") or {}).get("sha256")
|
|
2204
|
-
if
|
|
2254
|
+
if expected is not None and "assets_lock" in expected and expected_lock != observed_lock:
|
|
2205
2255
|
failures.append(
|
|
2206
2256
|
{
|
|
2207
2257
|
"code": "REPRO_LOCK_MISMATCH",
|
|
2208
|
-
"message": "assets.lock.json
|
|
2258
|
+
"message": "assets.lock.json content or presence differs from the repro record",
|
|
2209
2259
|
"expected": expected_lock,
|
|
2210
2260
|
"observed": observed_lock,
|
|
2211
2261
|
}
|
|
2212
2262
|
)
|
|
2213
2263
|
|
|
2264
|
+
if repro_record_path:
|
|
2265
|
+
Path(repro_record_path).write_text(
|
|
2266
|
+
_json_dumps(current_record, indent=2), encoding="utf-8"
|
|
2267
|
+
)
|
|
2214
2268
|
return current_record, failures
|
|
2215
2269
|
|
|
2216
2270
|
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
//! Standard 14 font metrics for interpreting existing PDF text positions.
|
|
2
|
+
//!
|
|
3
|
+
//! This module supplies advances and character mappings, not font programs.
|
|
4
|
+
//! It does not change authoring measurements or the emitted PDF.
|
|
5
|
+
|
|
6
|
+
#[path = "base14_metrics_data.rs"]
|
|
7
|
+
mod data;
|
|
8
|
+
|
|
9
|
+
pub(crate) struct GlyphMetric {
|
|
10
|
+
name: &'static str,
|
|
11
|
+
pub(crate) text: &'static str,
|
|
12
|
+
pub(crate) width: u16,
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
#[derive(Clone, Copy)]
|
|
16
|
+
pub(crate) struct Base14Font {
|
|
17
|
+
glyphs: &'static [GlyphMetric],
|
|
18
|
+
unicode: &'static [(u32, u16)],
|
|
19
|
+
builtin: &'static [u16; 256],
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
impl Base14Font {
|
|
23
|
+
pub(crate) fn glyph_by_name(self, name: &[u8]) -> Option<&'static GlyphMetric> {
|
|
24
|
+
let index = self
|
|
25
|
+
.glyphs
|
|
26
|
+
.binary_search_by(|glyph| glyph.name.as_bytes().cmp(name))
|
|
27
|
+
.ok()?;
|
|
28
|
+
self.glyphs.get(index)
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
pub(crate) fn glyph_by_unicode(self, ch: char) -> Option<&'static GlyphMetric> {
|
|
32
|
+
// These WinAnsi aliases use the ordinary space and hyphen glyphs.
|
|
33
|
+
let ch = match ch {
|
|
34
|
+
'\u{00a0}' => ' ',
|
|
35
|
+
'\u{00ad}' => '-',
|
|
36
|
+
other => other,
|
|
37
|
+
};
|
|
38
|
+
let index = self
|
|
39
|
+
.unicode
|
|
40
|
+
.binary_search_by_key(&(ch as u32), |pair| pair.0)
|
|
41
|
+
.ok()?;
|
|
42
|
+
self.glyphs.get(usize::from(self.unicode[index].1))
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
pub(crate) fn builtin_glyph(self, code: u8) -> Option<&'static GlyphMetric> {
|
|
46
|
+
let index = self.builtin[usize::from(code)].checked_sub(1)?;
|
|
47
|
+
self.glyphs.get(usize::from(index))
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
pub(crate) fn font(name: &str) -> Option<Base14Font> {
|
|
52
|
+
data::font(name)
|
|
53
|
+
}
|