diff --git a/.github/workflows/browser-starter.yml b/.github/workflows/browser-starter.yml index bab888c..533997e 100644 --- a/.github/workflows/browser-starter.yml +++ b/.github/workflows/browser-starter.yml @@ -3,9 +3,9 @@ name: Browser starter on: push: branches: [main] - paths: ['examples/browser/**', 'tools/check-browser-starter.py', 'tools/browser-requirements.txt', 'tools/starter_standard_fonts.py', 'tools/starter_engine_fixes.py', 'tools/starter-engine-2.5.22.json', 'tools/starter-engine-2.5.24.json', '.github/workflows/browser-starter.yml'] + paths: ['examples/browser/**', 'tools/check-browser-starter.py', 'tools/browser-requirements.txt', 'tools/starter_standard_fonts.py', 'tools/starter_engine_fixes.py', 'tools/starter-engine-2.5.22.json', 'tools/starter-engine-2.5.24.json', 'tools/starter-engine-2.5.38.json', '.github/workflows/browser-starter.yml'] pull_request: - paths: ['examples/browser/**', 'tools/check-browser-starter.py', 'tools/browser-requirements.txt', 'tools/starter_standard_fonts.py', 'tools/starter_engine_fixes.py', 'tools/starter-engine-2.5.22.json', 'tools/starter-engine-2.5.24.json', '.github/workflows/browser-starter.yml'] + paths: ['examples/browser/**', 'tools/check-browser-starter.py', 'tools/browser-requirements.txt', 'tools/starter_standard_fonts.py', 'tools/starter_engine_fixes.py', 'tools/starter-engine-2.5.22.json', 'tools/starter-engine-2.5.24.json', 'tools/starter-engine-2.5.38.json', '.github/workflows/browser-starter.yml'] workflow_dispatch: permissions: diff --git a/.github/workflows/react-starter.yml b/.github/workflows/react-starter.yml index cafc9f3..2fff3ee 100644 --- a/.github/workflows/react-starter.yml +++ b/.github/workflows/react-starter.yml @@ -3,9 +3,9 @@ name: React starter on: push: branches: [main] - paths: ['examples/react/**', 'tools/check-react-starter.py', 'tools/check-react-development.py', 'tools/prepare-react-check.mjs', 'tools/react_component_checks.py', 'tools/browser-requirements.txt', 'tools/starter_standard_fonts.py', 'tools/starter_engine_fixes.py', 'tools/starter-engine-2.5.22.json', 'tools/starter-engine-2.5.24.json', '.github/workflows/react-starter.yml'] + paths: ['examples/react/**', 'tools/check-react-starter.py', 'tools/check-react-development.py', 'tools/prepare-react-check.mjs', 'tools/react_component_checks.py', 'tools/browser-requirements.txt', 'tools/starter_standard_fonts.py', 'tools/starter_engine_fixes.py', 'tools/starter-engine-2.5.22.json', 'tools/starter-engine-2.5.24.json', 'tools/starter-engine-2.5.38.json', '.github/workflows/react-starter.yml'] pull_request: - paths: ['examples/react/**', 'tools/check-react-starter.py', 'tools/check-react-development.py', 'tools/prepare-react-check.mjs', 'tools/react_component_checks.py', 'tools/browser-requirements.txt', 'tools/starter_standard_fonts.py', 'tools/starter_engine_fixes.py', 'tools/starter-engine-2.5.22.json', 'tools/starter-engine-2.5.24.json', '.github/workflows/react-starter.yml'] + paths: ['examples/react/**', 'tools/check-react-starter.py', 'tools/check-react-development.py', 'tools/prepare-react-check.mjs', 'tools/react_component_checks.py', 'tools/browser-requirements.txt', 'tools/starter_standard_fonts.py', 'tools/starter_engine_fixes.py', 'tools/starter-engine-2.5.22.json', 'tools/starter-engine-2.5.24.json', 'tools/starter-engine-2.5.38.json', '.github/workflows/react-starter.yml'] workflow_dispatch: permissions: diff --git a/.github/workflows/vue-starter.yml b/.github/workflows/vue-starter.yml index 87a53c0..960276b 100644 --- a/.github/workflows/vue-starter.yml +++ b/.github/workflows/vue-starter.yml @@ -3,9 +3,9 @@ name: Vue starter on: push: branches: [main] - paths: ['examples/vue/**', 'tools/check-vue-starter.py', 'tools/prepare-vue-check.mjs', 'tools/browser-requirements.txt', 'tools/starter_standard_fonts.py', 'tools/starter_engine_fixes.py', 'tools/starter-engine-2.5.22.json', 'tools/starter-engine-2.5.24.json', '.github/workflows/vue-starter.yml'] + paths: ['examples/vue/**', 'tools/check-vue-starter.py', 'tools/prepare-vue-check.mjs', 'tools/browser-requirements.txt', 'tools/starter_standard_fonts.py', 'tools/starter_engine_fixes.py', 'tools/starter-engine-2.5.22.json', 'tools/starter-engine-2.5.24.json', 'tools/starter-engine-2.5.38.json', '.github/workflows/vue-starter.yml'] pull_request: - paths: ['examples/vue/**', 'tools/check-vue-starter.py', 'tools/prepare-vue-check.mjs', 'tools/browser-requirements.txt', 'tools/starter_standard_fonts.py', 'tools/starter_engine_fixes.py', 'tools/starter-engine-2.5.22.json', 'tools/starter-engine-2.5.24.json', '.github/workflows/vue-starter.yml'] + paths: ['examples/vue/**', 'tools/check-vue-starter.py', 'tools/prepare-vue-check.mjs', 'tools/browser-requirements.txt', 'tools/starter_standard_fonts.py', 'tools/starter_engine_fixes.py', 'tools/starter-engine-2.5.22.json', 'tools/starter-engine-2.5.24.json', 'tools/starter-engine-2.5.38.json', '.github/workflows/vue-starter.yml'] workflow_dispatch: permissions: diff --git a/examples/browser/README.md b/examples/browser/README.md index 3873d4b..98754e4 100644 --- a/examples/browser/README.md +++ b/examples/browser/README.md @@ -63,8 +63,8 @@ explains CSP, custom assets, structured errors, and browser worker lifecycle lim ## Versions and verification -The lockfile pins Fullbleed npm 0.8.2 / engine 2.5.37 and Vite 8.3.2. -The browser SDK is covered by the [versioned release evidence](https://github.com/fullbleed-engine/fullbleed-node/releases/tag/v0.8.2). +The lockfile pins Fullbleed npm 0.8.3 / engine 2.5.38 and Vite 8.3.2. +The browser SDK is covered by the [versioned release evidence](https://github.com/fullbleed-engine/fullbleed-node/releases/tag/v0.8.3). The repository's starter check builds this app, serves it below `/nested/demo/`, downloads actual PDFs, checks their text and page size, exercises editing and cancellation, and captures desktop/mobile screenshots. Playwright WebKit is not diff --git a/examples/browser/package-lock.json b/examples/browser/package-lock.json index 056f094..4227cdd 100644 --- a/examples/browser/package-lock.json +++ b/examples/browser/package-lock.json @@ -8,7 +8,7 @@ "name": "fullbleed-browser-starter", "version": "1.0.0", "dependencies": { - "fullbleed": "0.8.2" + "fullbleed": "0.8.3" }, "devDependencies": { "vite": "8.3.2" @@ -357,9 +357,9 @@ } }, "node_modules/fullbleed": { - "version": "0.8.2", - "resolved": "https://registry.npmjs.org/fullbleed/-/fullbleed-0.8.2.tgz", - "integrity": "sha512-OkqQzTbLE7JLx4nwriQEwqHiowLFx3j4AWtPYeSlP+dCdTd75oaBvS/h2VJj0WBI4zP2U9lE0Z6wH7bTASfIOA==", + "version": "0.8.3", + "resolved": "https://registry.npmjs.org/fullbleed/-/fullbleed-0.8.3.tgz", + "integrity": "sha512-Df9VSjsLEyygxvQTiFwgwndEyspzy6AIvLkbDm0IgIYSfXXuGy+C2MJWTxpy21hp6NwWVg6MHKx7mYTJUA7I6g==", "license": "MIT", "dependencies": { "@bjorn3/browser_wasi_shim": "0.4.2" diff --git a/examples/browser/package.json b/examples/browser/package.json index 0617396..55c079e 100644 --- a/examples/browser/package.json +++ b/examples/browser/package.json @@ -10,6 +10,6 @@ "build": "npm run assets && vite build", "preview": "vite preview --host 127.0.0.1" }, - "dependencies": { "fullbleed": "0.8.2" }, + "dependencies": { "fullbleed": "0.8.3" }, "devDependencies": { "vite": "8.3.2" } } diff --git a/examples/react/README.md b/examples/react/README.md index 914da4f..a74646e 100644 --- a/examples/react/README.md +++ b/examples/react/README.md @@ -54,7 +54,7 @@ See [supported print CSS](https://docs.fullbleed.dev/css-coverage/) for layout f ## Reuse the hook Copy `src/usePdfPreview.ts` and the `src/documents/` directory into your client application, install -`fullbleed@0.8.2`, and copy the runtime with +`fullbleed@0.8.3`, and copy the runtime with `npx fullbleed-browser-assets public/fullbleed`. Keep the document input stable with `useMemo` so ordinary component updates do not schedule another render: @@ -117,7 +117,7 @@ WebAssembly, and Web Crypto are required. ## Versions and verification -The lockfile pins Fullbleed 0.8.2 / engine 2.5.37, React 19.3.0, TypeScript 7.0.2, +The lockfile pins Fullbleed 0.8.3 / engine 2.5.38, React 19.3.0, TypeScript 7.0.2, and Vite 8.3.2. No Fullbleed engine or package release is needed for this example. The repository's `React starter` workflow builds the locked project and checks diff --git a/examples/react/package-lock.json b/examples/react/package-lock.json index cf93dad..7e72485 100644 --- a/examples/react/package-lock.json +++ b/examples/react/package-lock.json @@ -8,7 +8,7 @@ "name": "fullbleed-react-starter", "version": "1.0.0", "dependencies": { - "fullbleed": "0.8.2", + "fullbleed": "0.8.3", "react": "19.3.0", "react-dom": "19.3.0" }, @@ -838,9 +838,9 @@ } }, "node_modules/fullbleed": { - "version": "0.8.2", - "resolved": "https://registry.npmjs.org/fullbleed/-/fullbleed-0.8.2.tgz", - "integrity": "sha512-OkqQzTbLE7JLx4nwriQEwqHiowLFx3j4AWtPYeSlP+dCdTd75oaBvS/h2VJj0WBI4zP2U9lE0Z6wH7bTASfIOA==", + "version": "0.8.3", + "resolved": "https://registry.npmjs.org/fullbleed/-/fullbleed-0.8.3.tgz", + "integrity": "sha512-Df9VSjsLEyygxvQTiFwgwndEyspzy6AIvLkbDm0IgIYSfXXuGy+C2MJWTxpy21hp6NwWVg6MHKx7mYTJUA7I6g==", "license": "MIT", "dependencies": { "@bjorn3/browser_wasi_shim": "0.4.2" diff --git a/examples/react/package.json b/examples/react/package.json index 088a60d..3dceed8 100644 --- a/examples/react/package.json +++ b/examples/react/package.json @@ -14,7 +14,7 @@ "preview": "vite preview --host 127.0.0.1" }, "dependencies": { - "fullbleed": "0.8.2", + "fullbleed": "0.8.3", "react": "19.3.0", "react-dom": "19.3.0" }, diff --git a/examples/vue/README.md b/examples/vue/README.md index 97ede14..f98c402 100644 --- a/examples/vue/README.md +++ b/examples/vue/README.md @@ -43,7 +43,7 @@ Use [supported print CSS](https://docs.fullbleed.dev/css-coverage/). ## Reuse the composable Copy `src/usePdfPreview.ts` into your client application, install -`fullbleed@0.8.2`, and copy the runtime with +`fullbleed@0.8.3`, and copy the runtime with `npx fullbleed-browser-assets public/fullbleed`: ```vue @@ -111,7 +111,7 @@ WebAssembly, and Web Crypto are required. ## Versions and verification -The lockfile pins Fullbleed 0.8.2 / engine 2.5.37, Vue 3.5.43, TypeScript 6.0.3, +The lockfile pins Fullbleed 0.8.3 / engine 2.5.38, Vue 3.5.43, TypeScript 6.0.3, and Vite 8.3.2. TypeScript 6 is used because the pinned `vue-tsc` still needs TypeScript's JavaScript compiler entry; TypeScript 7 does not expose it. diff --git a/examples/vue/package-lock.json b/examples/vue/package-lock.json index e6a86b8..d9c9bdf 100644 --- a/examples/vue/package-lock.json +++ b/examples/vue/package-lock.json @@ -9,7 +9,7 @@ "version": "1.0.0", "license": "MIT", "dependencies": { - "fullbleed": "0.8.2", + "fullbleed": "0.8.3", "vue": "3.5.43" }, "devDependencies": { @@ -683,9 +683,9 @@ } }, "node_modules/fullbleed": { - "version": "0.8.2", - "resolved": "https://registry.npmjs.org/fullbleed/-/fullbleed-0.8.2.tgz", - "integrity": "sha512-OkqQzTbLE7JLx4nwriQEwqHiowLFx3j4AWtPYeSlP+dCdTd75oaBvS/h2VJj0WBI4zP2U9lE0Z6wH7bTASfIOA==", + "version": "0.8.3", + "resolved": "https://registry.npmjs.org/fullbleed/-/fullbleed-0.8.3.tgz", + "integrity": "sha512-Df9VSjsLEyygxvQTiFwgwndEyspzy6AIvLkbDm0IgIYSfXXuGy+C2MJWTxpy21hp6NwWVg6MHKx7mYTJUA7I6g==", "license": "MIT", "dependencies": { "@bjorn3/browser_wasi_shim": "0.4.2" diff --git a/examples/vue/package.json b/examples/vue/package.json index 9b4085c..19f7ab5 100644 --- a/examples/vue/package.json +++ b/examples/vue/package.json @@ -15,7 +15,7 @@ "preview": "vite preview --host 127.0.0.1" }, "dependencies": { - "fullbleed": "0.8.2", + "fullbleed": "0.8.3", "vue": "3.5.43" }, "devDependencies": { diff --git a/tools/starter-engine-2.5.38.json b/tools/starter-engine-2.5.38.json new file mode 100644 index 0000000..1a644ce --- /dev/null +++ b/tools/starter-engine-2.5.38.json @@ -0,0 +1,63 @@ +{ + "schema": "fullbleed.starter.engine-fixes.v1", + "upstreamRelease": "2.5.38", + "source": { + "path": "test/fixtures/generated-quotes-2.5.38.json", + "sha256": "892cf0862fe14d639cdb1f639ce755ce9a6fe5f88622217690da3da762ff4015", + "url": "https://github.com/fullbleed-engine/fullbleed-node/blob/v0.8.3/test/fixtures/generated-quotes-2.5.38.json" + }, + "cases": [ + { + "name": "quote-inline-nested", + "family": "quotation", + "html": "
Record Ada
outerinnerend", + "css": "@page { size: 600px 400px; margin: 12px }\nbody { margin: 0; font-family: Inter; font-size: 20px; quotes: \"[\" \"]\" \"{\" \"}\" }\n.q::before { content: open-quote } .q::after { content: close-quote }\n.open::before { content: no-open-quote } .after::after { content: no-open-quote }\n.close::before { content: no-close-quote } .closeafter::after { content: no-close-quote }\n.visibleclose::after { content: close-quote } .balanced::after { content: open-quote close-quote }\n.suppressed::before { display: none }\n", + "pages": 1, + "previewDpi": 96, + "previousEngineFails": false, + "expected": { + "text": "RecordAda[outer{inner}end]", + "pageSizePt": [ + 450, + 300 + ], + "minimumInkPixels": 100 + } + }, + { + "name": "quote-contents-nested", + "family": "quotation", + "html": "Record Ada
outerinnerend", + "css": "@page { size: 600px 400px; margin: 12px }\nbody { margin: 0; font-family: Inter; font-size: 20px; quotes: \"[\" \"]\" \"{\" \"}\" }\n.q::before { content: open-quote } .q::after { content: close-quote }\n.open::before { content: no-open-quote } .after::after { content: no-open-quote }\n.close::before { content: no-close-quote } .closeafter::after { content: no-close-quote }\n.visibleclose::after { content: close-quote } .balanced::after { content: open-quote close-quote }\n.suppressed::before { display: none }\n", + "pages": 1, + "previewDpi": 96, + "previousEngineFails": true, + "expected": { + "text": "RecordAda[outer{inner}end]", + "pageSizePt": [ + 450, + 300 + ], + "minimumInkPixels": 100 + } + }, + { + "name": "quote-block-nested", + "family": "quotation", + "html": "Record Ada
outerinnerend", + "css": "@page { size: 600px 400px; margin: 12px }\nbody { margin: 0; font-family: Inter; font-size: 20px; quotes: \"[\" \"]\" \"{\" \"}\" }\n.q::before { content: open-quote } .q::after { content: close-quote }\n.open::before { content: no-open-quote } .after::after { content: no-open-quote }\n.close::before { content: no-close-quote } .closeafter::after { content: no-close-quote }\n.visibleclose::after { content: close-quote } .balanced::after { content: open-quote close-quote }\n.suppressed::before { display: none }\n", + "pages": 1, + "previewDpi": 96, + "previousEngineFails": true, + "expected": { + "text": "RecordAda[outer{inner}end]", + "pageSizePt": [ + 450, + 300 + ], + "minimumInkPixels": 100 + } + } + ], + "scope": "Three reviewed quotation inputs through the actual starter editors and downloads. One healthy control and two earlier engine failures; no full CSS or arbitrary-template parity claim." +} diff --git a/tools/starter_engine_fixes.py b/tools/starter_engine_fixes.py index 3bbacad..acdec20 100644 --- a/tools/starter_engine_fixes.py +++ b/tools/starter_engine_fixes.py @@ -19,6 +19,7 @@ FIXTURES = Path(__file__).with_name('starter-engine-2.5.22.json') CURRENT_FIXTURES = Path(__file__).with_name('starter-engine-2.5.24.json') +QUOTATION_FIXTURES = Path(__file__).with_name('starter-engine-2.5.38.json') def decoration_widths(page, reader): @@ -64,6 +65,37 @@ def inspect_outputs(case, pdf_path, preview_path, out, check): if 'pdfSha256' in expected: check(name + ': PDF matches the released source/control fixture', hashlib.sha256(pdf_path.read_bytes()).hexdigest() == expected['pdfSha256']) + if case['family'] == 'quotation': + check(name + ': print CSS preserves the expected page geometry', + [float(reader.pages[0].mediabox.width), float(reader.pages[0].mediabox.height)] == expected['pageSizePt']) + document = pdfium.PdfDocument(pdf_path) + try: + pdf_page = document[0] + try: + text_page = pdf_page.get_textpage() + try: + independent_text = re.sub(r'\s+', '', text_page.get_text_range()) + finally: + text_page.close() + bitmap = pdf_page.render(scale=case['previewDpi'] / 72) + try: + raster = bitmap.to_pil().convert('RGB') + raster.save(out / (name + '-pdfium.png')) + finally: + bitmap.close() + finally: + pdf_page.close() + finally: + document.close() + check(name + ': a second PDF reader finds the exact quotation text', independent_text == expected['text']) + with Image.open(preview_path) as displayed: + preview = displayed.convert('RGB') + ink = {source: sum(image.convert('L').histogram()[:200]) + for source, image in [('pdfium', raster), ('preview', preview)]} + check(name + ': independent PDF render and displayed preview contain visible ink', + all(count >= expected['minimumInkPixels'] for count in ink.values())) + record.update(pdfiumText=independent_text, inkPixels=ink, + independentRasterSha256=hashlib.sha256((out / (name + '-pdfium.png')).read_bytes()).hexdigest()) if case['family'] == 'decoration': widths = decoration_widths(reader.pages[0], reader) check(name + ': decoration stroke count matches', len(widths) == expected['strokes']) @@ -108,6 +140,7 @@ def verify_engine_fixes(page, out, check, ready, *, manual=False, """Paste focused cases, inspect actual downloads, then restore the editor.""" fixtures = json.loads(FIXTURES.read_text(encoding='utf-8')) current = json.loads(CURRENT_FIXTURES.read_text(encoding='utf-8')) + quotations = json.loads(QUOTATION_FIXTURES.read_text(encoding='utf-8')) evidence = out / 'engine-fixes' evidence.mkdir(exist_ok=False) original_html = page.locator(html_selector).input_value() @@ -119,7 +152,7 @@ def edit(html, css): page.locator(html_selector).fill(html) page.locator(css_selector).fill(css) records = [] - for case in [*fixtures['cases'], *current['cases']]: + for case in [*fixtures['cases'], *current['cases'], *quotations['cases']]: name = case['name'] (evidence / (name + '.html')).write_text(case['html'], encoding='utf-8', newline='\n') (evidence / (name + '.css')).write_text(case['css'], encoding='utf-8', newline='\n') @@ -151,7 +184,8 @@ def edit(html, css): ready() result = {'ok': True, 'fixturesSha256': hashlib.sha256(FIXTURES.read_bytes()).hexdigest(), 'additionalFixturesSha256': hashlib.sha256(CURRENT_FIXTURES.read_bytes()).hexdigest(), + 'quotationFixturesSha256': hashlib.sha256(QUOTATION_FIXTURES.read_bytes()).hexdigest(), 'readers': {package: version(package) for package in ['pypdf', 'pypdfium2', 'pillow']}, - 'scope': fixtures['scope'] + ' ' + current['scope'], 'cases': records} + 'scope': fixtures['scope'] + ' ' + current['scope'] + ' ' + quotations['scope'], 'cases': records} (evidence / 'verification.json').write_text(json.dumps(result, indent=2) + '\n', encoding='utf-8', newline='\n') return result diff --git a/verification/starters-083.json b/verification/starters-083.json new file mode 100644 index 0000000..be1d753 --- /dev/null +++ b/verification/starters-083.json @@ -0,0 +1,443 @@ +{ + "ok": true, + "checkedAt": "2026-10-27T12:23:27.346667+00:00", + "package": "0.8.3", + "engine": "2.5.38", + "packageIntegrity": "sha512-Df9VSjsLEyygxvQTiFwgwndEyspzy6AIvLkbDm0IgIYSfXXuGy+C2MJWTxpy21hp6NwWVg6MHKx7mYTJUA7I6g==", + "publicTarballSha256": "9bdfd44de150e609819f9e46bf1bcd9c4bda4cdedc09aa477b593003f1e24b55", + "sourceFiles": { + "examples/browser/README.md": "4c3b962ac8e5ae81ac2d2234103755e9fb60b4b138f36ee3f00a5957a7b93a2e", + "examples/browser/package.json": "68c2577262ad8a92c81f3ec3ee68bebc3c9ca44fb0885ff339d9c663f19e6958", + "examples/browser/package-lock.json": "6f18c206a1f6fe030a94b59f987f162e217d2f5cdeaeff6680bbebfc26fe4341", + ".github/workflows/browser-starter.yml": "7c171044253314af2cc1681fdf37911b7bba36aa2f6aeccadf442043f7264d17", + "examples/react/README.md": "3143a9bab919265d69177d71f92bfc5e79cda1f3e3007add9a87084bf60a7193", + "examples/react/package.json": "7558b849e48ecbc214f636f2f97b1baff491dae3916fd2e4472ec71ea7df3651", + "examples/react/package-lock.json": "13611c811da54fbb4b0d4269b1362525607f4dd94fd6b102eef6d66ed056b964", + ".github/workflows/react-starter.yml": "38ecfb431c7180dbb84e6290ac0d370c646d4972d78e7f13443bc560c3d1cc9a", + "examples/vue/README.md": "829eb5e93811627816b8a3fcf7eaa4df1c47cb1eac3a890143c2df6973fe24dc", + "examples/vue/package.json": "92f6a541523f034864d87044d700977a6d302163e57fa77f5a5177179309d7b0", + "examples/vue/package-lock.json": "94621bff307a11a2ce43a7881f076a665ccfd7c40bcca6c6075c92a77d6db7ca", + ".github/workflows/vue-starter.yml": "d3d2438e9a527dd9b42923d371c89f82c9ff526fc0a72634abf7ce6f4bf63111", + "tools/starter_engine_fixes.py": "972cdd86569513817424758a8a5ac6a9998ed2c4988500219763b126485b2932", + "tools/starter-engine-2.5.38.json": "a3c43265bf4a1d749210bb3842a4a8ebd94ea0bf9608ac247f3268ea9867117d" + }, + "installedPackageFiles": { + "browser": { + "files": 47, + "matchesPublicTarball": true + }, + "react": { + "files": 47, + "matchesPublicTarball": true + }, + "vue": { + "files": 47, + "matchesPublicTarball": true + } + }, + "localVerification": { + "browser": { + "browser": "156.0.8078.47", + "checks": 94, + "documents": [ + { + "name": "invoice", + "filename": "invoice-NS-1042.pdf", + "pages": 1, + "sha256": "3078d155f30536f5ad721f7be3c241cd78661ae41249131fc0fd65f37f23e408" + }, + { + "name": "color-only", + "filename": "invoice-NS-1042.pdf", + "pages": 1, + "sha256": "a2b69ba41f7ad4c9bcbd38d803a46e70f0b9ccacd90ffbab5b0f7d87ffca5e4b" + }, + { + "name": "customized", + "filename": "invoice-TEST-2042.pdf", + "pages": 1, + "sha256": "31ff314b44a6f13534cc383e0cf24929f0695c1dd3d84769dedf8828c6486a93" + }, + { + "name": "edited", + "filename": "invoice-TEST-2042.pdf", + "pages": 1, + "sha256": "fecff59c1bfd6b59de2f0fb56965a5668023b3b88e64b5c6c30f95875592c4b2" + }, + { + "name": "report", + "filename": "community-report.pdf", + "pages": 3, + "sha256": "80fc4306db1898688d846cfea4fb1b4ef5bf07713fe9301662143619441205b5" + }, + { + "name": "recovered", + "filename": "invoice-TEST-2042.pdf", + "pages": 1, + "sha256": "31ff314b44a6f13534cc383e0cf24929f0695c1dd3d84769dedf8828c6486a93" + } + ], + "quotationCases": [ + { + "name": "quote-inline-nested", + "pages": 1, + "text": "Record Ada\n[outer{inner}end]", + "probes": [], + "pdfiumText": "RecordAda[outer{inner}end]", + "inkPixels": { + "pdfium": 1695, + "preview": 1627 + }, + "independentRasterSha256": "63eebe27b3c8518dfc43e9e79ebb503200f4c49d44bde60f4119fd0004791311", + "pdfSha256": "0dd4e8e1cad03da49a74a2451d97180f5212c42262addff402e087c0796e32f9", + "previewSha256": "817be578ca49e67329b503bdee74f8d4d202319c8988e966419c4f8087d50cd1", + "suggestedFilename": "invoice-TEST-2042.pdf" + }, + { + "name": "quote-contents-nested", + "pages": 1, + "text": "Record Ada\n[\nouter\n{inner}\nend\n]", + "probes": [], + "pdfiumText": "RecordAda[outer{inner}end]", + "inkPixels": { + "pdfium": 1677, + "preview": 1613 + }, + "independentRasterSha256": "8a155f599e8ad72c1f83768d9935732c5af56bcb7d9676864c1b6495304a328b", + "pdfSha256": "658681c73d9f6cb8e942ac331a64d9e4cb7c70190b5a7d7a7258bd7028163585", + "previewSha256": "bb3a35f08897bcecceec9afb57439388e448681fca8513023d2bba908bd516f8", + "suggestedFilename": "invoice-TEST-2042.pdf" + }, + { + "name": "quote-block-nested", + "pages": 1, + "text": "Record Ada\n[outer{inner}end]", + "probes": [], + "pdfiumText": "RecordAda[outer{inner}end]", + "inkPixels": { + "pdfium": 1695, + "preview": 1635 + }, + "independentRasterSha256": "63eebe27b3c8518dfc43e9e79ebb503200f4c49d44bde60f4119fd0004791311", + "pdfSha256": "b032ca751718d12ec90f10d4934044f1ac1024b9731ba2c72c1529fe9f44e6e7", + "previewSha256": "28cfba86ea6182baccff1322dcb100279bf10eef965e33266b3baaabd41ccccf", + "suggestedFilename": "invoice-TEST-2042.pdf" + } + ], + "reportSha256": "2238f332be48b5155e5ede7eb7e020d10bbb1f8216e0a301d93e977e0fcf8eec", + "engineFixesReportSha256": "2c87ed1f2a284ffcefdd754957241c217fe9b249a74d9f6343693cab3c66d800" + }, + "react": { + "browser": "156.0.8078.47", + "checks": 143, + "documents": [ + { + "name": "component-invoice", + "pages": 1, + "filename": "invoice-NS-1042.pdf", + "sha256": "f2553f220e9d30e26df785a4ed251f07ff1e615afd3972a5c29c19a0c5fd3f6c", + "whitespace_normalized_text_checks": true + }, + { + "name": "component-paid", + "pages": 1, + "filename": "invoice-NS-1042.pdf", + "sha256": "91d8c8360fac37cd413fe669ed8f06650658b9ca01777129879207aac014d4c2", + "whitespace_normalized_text_checks": true + }, + { + "name": "component-edited", + "pages": 1, + "filename": "invoice-Ref-aBc-2042.pdf", + "sha256": "a664f9fd84af1d2354537645aa6b70dd9abe3ab762b8a9631047aab742b1297e", + "whitespace_normalized_text_checks": true + }, + { + "name": "component-empty", + "pages": 1, + "filename": "invoice-NS-1042.pdf", + "sha256": "cc1982eaea9dfa05b014cffea44644ecc2f4d33e8eb22ae6f6a501ab6d7f1248", + "whitespace_normalized_text_checks": true + }, + { + "name": "component-credit", + "pages": 1, + "filename": "invoice-NS-1042.pdf", + "sha256": "cd57b56ec26e86365ab0223656d7e21b1543c9fbf404e967f0aef2e9b98024e6", + "whitespace_normalized_text_checks": true + }, + { + "name": "component-long", + "pages": 3, + "filename": "invoice-NS-1042.pdf", + "sha256": "589210d6b5bb0684fdbf5dbf62c5e32742c7166d3a8cfc5ae304c430e08357a3", + "whitespace_normalized_text_checks": true + }, + { + "name": "invoice", + "pages": 1, + "filename": "invoice-NS-1042.pdf", + "sha256": "3078d155f30536f5ad721f7be3c241cd78661ae41249131fc0fd65f37f23e408", + "whitespace_normalized_text_checks": false + }, + { + "name": "manual", + "pages": 1, + "filename": "invoice-NS-1042.pdf", + "sha256": "1df9b1852ad96e07d00520d190140044f528b14047df6e30432e91a512be8883", + "whitespace_normalized_text_checks": false + }, + { + "name": "latest-input", + "pages": 1, + "filename": "invoice-REACT-2042.pdf", + "sha256": "fccdad8d56abef7206e5efefc716af2c44c717c0e1c3619827c6d27931ed76be", + "whitespace_normalized_text_checks": false + }, + { + "name": "edited-template", + "pages": 1, + "filename": "invoice-REACT-2042.pdf", + "sha256": "c1fe667a39ac3eaae3292c3a1fab1c466999e798a5ab0a4616b73689acc79880", + "whitespace_normalized_text_checks": false + }, + { + "name": "report", + "pages": 3, + "filename": "community-report.pdf", + "sha256": "80fc4306db1898688d846cfea4fb1b4ef5bf07713fe9301662143619441205b5", + "whitespace_normalized_text_checks": false + }, + { + "name": "recovered", + "pages": 1, + "filename": "invoice-REACT-2042.pdf", + "sha256": "fccdad8d56abef7206e5efefc716af2c44c717c0e1c3619827c6d27931ed76be", + "whitespace_normalized_text_checks": false + }, + { + "name": "remounted", + "pages": 1, + "filename": "invoice-NS-1042.pdf", + "sha256": "3078d155f30536f5ad721f7be3c241cd78661ae41249131fc0fd65f37f23e408", + "whitespace_normalized_text_checks": false + } + ], + "quotationCases": [ + { + "name": "quote-inline-nested", + "pages": 1, + "text": "Record Ada\n[outer{inner}end]", + "probes": [], + "pdfiumText": "RecordAda[outer{inner}end]", + "inkPixels": { + "pdfium": 1695, + "preview": 1627 + }, + "independentRasterSha256": "63eebe27b3c8518dfc43e9e79ebb503200f4c49d44bde60f4119fd0004791311", + "pdfSha256": "0dd4e8e1cad03da49a74a2451d97180f5212c42262addff402e087c0796e32f9", + "previewSha256": "817be578ca49e67329b503bdee74f8d4d202319c8988e966419c4f8087d50cd1", + "suggestedFilename": "invoice-REACT-2042.pdf" + }, + { + "name": "quote-contents-nested", + "pages": 1, + "text": "Record Ada\n[\nouter\n{inner}\nend\n]", + "probes": [], + "pdfiumText": "RecordAda[outer{inner}end]", + "inkPixels": { + "pdfium": 1677, + "preview": 1613 + }, + "independentRasterSha256": "8a155f599e8ad72c1f83768d9935732c5af56bcb7d9676864c1b6495304a328b", + "pdfSha256": "658681c73d9f6cb8e942ac331a64d9e4cb7c70190b5a7d7a7258bd7028163585", + "previewSha256": "bb3a35f08897bcecceec9afb57439388e448681fca8513023d2bba908bd516f8", + "suggestedFilename": "invoice-REACT-2042.pdf" + }, + { + "name": "quote-block-nested", + "pages": 1, + "text": "Record Ada\n[outer{inner}end]", + "probes": [], + "pdfiumText": "RecordAda[outer{inner}end]", + "inkPixels": { + "pdfium": 1695, + "preview": 1635 + }, + "independentRasterSha256": "63eebe27b3c8518dfc43e9e79ebb503200f4c49d44bde60f4119fd0004791311", + "pdfSha256": "b032ca751718d12ec90f10d4934044f1ac1024b9731ba2c72c1529fe9f44e6e7", + "previewSha256": "28cfba86ea6182baccff1322dcb100279bf10eef965e33266b3baaabd41ccccf", + "suggestedFilename": "invoice-REACT-2042.pdf" + } + ], + "reportSha256": "3ee01492fef2b3e7a1b50985880907c4b3793edd52d2e1f43d2bab52a4a447b5", + "engineFixesReportSha256": "752f852579f14efc27ac8044fb1cf4bffc504121779c8ef267ae6b55cd312e82" + }, + "vue": { + "browser": "156.0.8078.47", + "checks": 102, + "documents": [ + { + "name": "invoice", + "pages": 1, + "filename": "invoice-NS-1042.pdf", + "sha256": "3078d155f30536f5ad721f7be3c241cd78661ae41249131fc0fd65f37f23e408" + }, + { + "name": "manual", + "pages": 1, + "filename": "invoice-NS-1042.pdf", + "sha256": "1df9b1852ad96e07d00520d190140044f528b14047df6e30432e91a512be8883" + }, + { + "name": "latest-input", + "pages": 1, + "filename": "invoice-VUE-2042.pdf", + "sha256": "f63a42a366b08f4f054cca5594dbcd22510455ddfe2e9129623facfb8371e8ee" + }, + { + "name": "edited-template", + "pages": 1, + "filename": "invoice-VUE-2042.pdf", + "sha256": "071d2bd98b7b90b52aa5b60e74ce0934ef54d3c6032c222d7237786dc12fc953" + }, + { + "name": "report", + "pages": 3, + "filename": "community-report.pdf", + "sha256": "80fc4306db1898688d846cfea4fb1b4ef5bf07713fe9301662143619441205b5" + }, + { + "name": "outage-recovery", + "pages": 1, + "filename": "invoice-VUE-2042.pdf", + "sha256": "f63a42a366b08f4f054cca5594dbcd22510455ddfe2e9129623facfb8371e8ee" + }, + { + "name": "recovered", + "pages": 1, + "filename": "invoice-VUE-2042.pdf", + "sha256": "f63a42a366b08f4f054cca5594dbcd22510455ddfe2e9129623facfb8371e8ee" + }, + { + "name": "remounted", + "pages": 1, + "filename": "invoice-NS-1042.pdf", + "sha256": "3078d155f30536f5ad721f7be3c241cd78661ae41249131fc0fd65f37f23e408" + } + ], + "quotationCases": [ + { + "name": "quote-inline-nested", + "pages": 1, + "text": "Record Ada\n[outer{inner}end]", + "probes": [], + "pdfiumText": "RecordAda[outer{inner}end]", + "inkPixels": { + "pdfium": 1695, + "preview": 1627 + }, + "independentRasterSha256": "63eebe27b3c8518dfc43e9e79ebb503200f4c49d44bde60f4119fd0004791311", + "pdfSha256": "0dd4e8e1cad03da49a74a2451d97180f5212c42262addff402e087c0796e32f9", + "previewSha256": "817be578ca49e67329b503bdee74f8d4d202319c8988e966419c4f8087d50cd1", + "suggestedFilename": "invoice-VUE-2042.pdf" + }, + { + "name": "quote-contents-nested", + "pages": 1, + "text": "Record Ada\n[\nouter\n{inner}\nend\n]", + "probes": [], + "pdfiumText": "RecordAda[outer{inner}end]", + "inkPixels": { + "pdfium": 1677, + "preview": 1613 + }, + "independentRasterSha256": "8a155f599e8ad72c1f83768d9935732c5af56bcb7d9676864c1b6495304a328b", + "pdfSha256": "658681c73d9f6cb8e942ac331a64d9e4cb7c70190b5a7d7a7258bd7028163585", + "previewSha256": "bb3a35f08897bcecceec9afb57439388e448681fca8513023d2bba908bd516f8", + "suggestedFilename": "invoice-VUE-2042.pdf" + }, + { + "name": "quote-block-nested", + "pages": 1, + "text": "Record Ada\n[outer{inner}end]", + "probes": [], + "pdfiumText": "RecordAda[outer{inner}end]", + "inkPixels": { + "pdfium": 1695, + "preview": 1635 + }, + "independentRasterSha256": "63eebe27b3c8518dfc43e9e79ebb503200f4c49d44bde60f4119fd0004791311", + "pdfSha256": "b032ca751718d12ec90f10d4934044f1ac1024b9731ba2c72c1529fe9f44e6e7", + "previewSha256": "28cfba86ea6182baccff1322dcb100279bf10eef965e33266b3baaabd41ccccf", + "suggestedFilename": "invoice-VUE-2042.pdf" + } + ], + "reportSha256": "62f972db0e525132dde58c5b4dfef9b1028cfe54ae119b0794e589370882e991", + "engineFixesReportSha256": "23892b7f580cc677c9934f1090f0ffa8fdfe3de918ba7e4402156f8a1d79b05b" + } + }, + "unchangedPdfDownloadsFrom082": { + "browser": 6, + "react": 13, + "vue": 8 + }, + "retainedPublicControls": { + "browser": [ + { + "case": "inline-nested", + "beforeText": "RecordAda[outer{inner}end]", + "afterText": "RecordAda[outer{inner}end]", + "beforePdfSha256": "0dd4e8e1cad03da49a74a2451d97180f5212c42262addff402e087c0796e32f9", + "afterPdfSha256": "0dd4e8e1cad03da49a74a2451d97180f5212c42262addff402e087c0796e32f9", + "unchangedHealthyControl": true + }, + { + "case": "block-nested", + "beforeText": "RecordAda[outer[inner]end", + "afterText": "RecordAda[outer{inner}end]", + "beforePdfSha256": "8bea79d1eaf3493291ba303acc16dbdf59cf989836408ebe7e240eccd878dfec", + "afterPdfSha256": "b032ca751718d12ec90f10d4934044f1ac1024b9731ba2c72c1529fe9f44e6e7", + "unchangedHealthyControl": false + } + ], + "react": [ + { + "case": "inline-nested", + "beforeText": "RecordAda[outer{inner}end]", + "afterText": "RecordAda[outer{inner}end]", + "beforePdfSha256": "0dd4e8e1cad03da49a74a2451d97180f5212c42262addff402e087c0796e32f9", + "afterPdfSha256": "0dd4e8e1cad03da49a74a2451d97180f5212c42262addff402e087c0796e32f9", + "unchangedHealthyControl": true + }, + { + "case": "block-nested", + "beforeText": "RecordAda[outer[inner]end", + "afterText": "RecordAda[outer{inner}end]", + "beforePdfSha256": "8bea79d1eaf3493291ba303acc16dbdf59cf989836408ebe7e240eccd878dfec", + "afterPdfSha256": "b032ca751718d12ec90f10d4934044f1ac1024b9731ba2c72c1529fe9f44e6e7", + "unchangedHealthyControl": false + } + ], + "vue": [ + { + "case": "inline-nested", + "beforeText": "RecordAda[outer{inner}end]", + "afterText": "RecordAda[outer{inner}end]", + "beforePdfSha256": "0dd4e8e1cad03da49a74a2451d97180f5212c42262addff402e087c0796e32f9", + "afterPdfSha256": "0dd4e8e1cad03da49a74a2451d97180f5212c42262addff402e087c0796e32f9", + "unchangedHealthyControl": true + }, + { + "case": "block-nested", + "beforeText": "RecordAda[outer[inner]end", + "afterText": "RecordAda[outer{inner}end]", + "beforePdfSha256": "8bea79d1eaf3493291ba303acc16dbdf59cf989836408ebe7e240eccd878dfec", + "afterPdfSha256": "b032ca751718d12ec90f10d4934044f1ac1024b9731ba2c72c1529fe9f44e6e7", + "unchangedHealthyControl": false + } + ] + }, + "publicBeforeObservationSha256": "21b125227fe1652220f8a850749e645bcbaac35caf345c80d1de1833b6ede781", + "scope": "Locked public npm installation and actual browser, React and Vue production editors in Chrome on Windows. Nine quotation downloads pass, including three unchanged healthy controls, and 27 previous document downloads remain byte-identical. The repository CI covers the other browser engines and React development checks separately." +}