Appearance
Production readiness — 13 October 2026
This release hardens the existing local-first editor. Artwork stays on the device; app assets load from the hosting origin. Browser recovery is separate from downloaded native projects.
Headerless browser embedding and recovery opt-out - 31 October 2026
Load the full editor with ?embed=1 to hide the suite header, reclaim its layout space, and disable browser recovery. Document/mode tabs, toolbars, panels, canvas, timeline where applicable, and status UI remain mounted. The header DOM stays available internally for existing command wiring but is not visible or focusable. Use ?recovery=off when the header should remain visible. See browser embedding options.
Disabled recovery performs no startup lookup, migration, automatic save, or recovery deletion; existing copies remain untouched. Embedded mode overrides an explicit recovery=on. Unsaved-change warnings stay active, and updates cannot reload unsaved documents without downloaded backups. Other browser preferences and PWA asset caching are unaffected. The headless SDK remains separate and never needs either URL flag.
With the user's unit-test authorization, 361 unit tests pass for this project. Application/PWA, standalone, documentation, portable SDK/declaration builds, isolated Node/NodeNext consumers, and shared-suite manifests also pass. The new npm run test:embed passes eight Chromium cases per project (24 across the suite): normal, recovery-disabled, direct embedded, and actual iframe-hosted modes at 1280x800 and 640x480. Checks cover header visibility and spacing, visible editor canvases, native saving via Ctrl+S, no page errors, and no recovery IndexedDB or legacy recovery-key access while disabled. Desktop and compact screenshots were inspected. Firefox/WebKit and the full legacy browser matrix were not rerun for this feature. Existing dependency-release blockers documented below remain unchanged.
Hardening and embedding follow-up - 31 October 2026
The root/headless SDK now exposes an isolated createHeadlessEditor adapter for custom browser UIs and Node jobs. Seed documents, snapshots, and transaction drafts do not alias internal state. Mutations are synchronous, validated, atomic, and non-reentrant. See embedding contracts and examples. The adapter does not mount the editor or provide implicit persistence, rendering, workers, or undo history.
History rejects asynchronous and reentrant mutations, detaches committed state from retained drafts, and rejects non-finite/fractional history limits and invalid memory budgets. Failed mutations preserve the previous document and redo stack. The dependency audit also fails closed on unexpected report schemas.
All projects pin the build-tool dependencies glob 14.0.3 and minimatch 11.0.1, with regenerated lockfiles. The current npm audit reports zero moderate/high/critical findings, but still reports four low-severity findings from deepmerge 4.3.1 and its PWA-tooling chain. No patched deepmerge release was available from the registry during this work. On 31 October 2026, check:dependencies was aligned with Craft's existing exception for GHSA-gcqx-w48m-w2h4, expiring on 27 November 2026 at 00:00 UTC. It accepts only deepmerge 4.3.1, @rollup/plugin-node-resolve 16.0.3, workbox-build 7.4.1, and vite-plugin-pwa 2.0.0 at their exact lockfile paths and with the expected low-severity advisory chain. These build-tool findings remain visible; this is a temporary policy exception, not a vulnerability fix. Other findings, changed versions or paths, additional causes, higher severities, expired exceptions, and audit failures still block release. Runtime-only dependency audits are separate from this development-tool release gate.
Validation for this follow-up uses application/PWA builds, documentation builds, portable library/declaration builds, package inventory checks, and isolated production-only Node/strict NodeNext consumer checks. The consumer checks exercise the embedding adapter without DOM globals. With explicit user permission on 31 October 2026, the full unit suite passed: 337 tests in 16 files, including the new hardening and embedding regressions. Historical browser counts below do not validate these changes; browser, standalone, worker, and real-device regressions remain release checks to complete. Nothing was committed, published, or deployed as part of this follow-up.
Release gate
This commit includes the readiness implementation and UI follow-ups. It has not been deployed; the source fingerprint below identifies the validated snapshot. For this implementation, explicit user permission authorized unit execution: all 328 tests passed. Future unit execution requires permission or manual workflow dispatch. Pushes to main automatically run the release workflow, which checks out one exact commit and runs builds, dependency checks and browser checks before publishing that same artifact. Unit validation runs only when the release workflow or Manual unit validation is manually dispatched. Push and pull-request workflows never execute unit tests.
Recovery and compatibility
Recovery v2 uses IndexedDB with a unique ID per live browser session. Legacy data is copied durably before a Restore/Discard decision removes the original. Invalid recovery remains downloadable. Discard compares the selected record against the current stored record before deletion. Copies do not expire automatically; File → Recovery manages older sessions explicitly.
Native project format version 1 remains unchanged. Recovery writes are serialized, and feedback reflects the stored snapshot. Visibility changes request a best-effort flush; closing/crashing a browser cannot guarantee an asynchronous write finishes. Download an editable project backup regularly. Storage denial/quota errors must preserve editing and native downloads.
Browser support and storage limits
Target browsers are current desktop Chrome, Edge, Firefox and Safari. Windows Chromium/Firefox/WebKit were exercised; actual Edge/Safari installations still require release smoke checks.
Ortho applies one 8 MiB UTF-8 budget to both saved and opened native projects. PNG imports are capped at 32 MiB, 16,384 pixels per dimension and 16,777,216 pixels total before browser decoding. History has a 60-entry limit and an estimated 128 MiB budget. History keeps at least the newest complete undo transaction, so one unusually large transaction can exceed its nominal byte budget. IndexedDB quota is browser/origin-dependent and can be denied or cleared; there is no fixed recovery quota guarantee. Stored copies are never silently evicted. Use File → Recovery to download and explicitly discard obsolete copies. Use Save project to keep .pvc, .pvo or .pvp backups outside browser storage.
Runtime and packaging
File operations use bounded worker jobs; cancellation terminates the job without replacing the document. Hosted assets are split from worker/export code. Standalone HTML embeds code, fonts, and workers, disables PWA registration, and supports file:// native downloads. Graphics failures retain native-file controls. WebGL recovery cancels unfinished gestures and rebuilds the viewport.
PWA updates wait for an explicit decision in each tab and a successful recovery flush. Editing is briefly locked during that flush and worker activation, so new edits cannot escape the stored snapshot. Accepting an update in another tab never forces this tab to reload. Active gestures, dialogs and exports defer updates. Application assets are cached; documentation is online-only. Standalone HTML and documentation routes are excluded from the app navigation fallback.
Dependency policy (updated 27 October 2026)
The npm SDK release replaces the historical documentation-server exceptions with a zero-advisory gate, subject to the time-bounded deepmerge build-tool exception documented above. VitePress 1.6.4 uses an explicit nested Vite 6.4.5 override; fast-uri and serialize-javascript are pinned to patched transitive versions in the root overrides. Browser and documentation builds were checked with these resolutions. npm run check:dependencies rejects any advisory outside that exception and runs npm without shell interpolation. See the npm guide for package preparation and manual publication.
Validation limits
Chromium represents Chrome/Edge engine coverage; Playwright WebKit is engine coverage, not certification on an actual macOS Safari installation. Current browser checks cover native round trips, malformed input, export signatures, compact layouts, menus, offline reload, deferred/accepted updates across tabs, invalid recovery backups, separate sessions, denied storage, quota exhaustion and aborted recovery writes. Craft/Plate also cover edits during saves and undo back to saved content; Ortho/Plate cover WebGL context loss/restoration with native backups available. Standalone native downloads were checked in all three engines. Full screen-reader conformance, native 200% browser zoom, hardware performance certification and full feature/export semantics remain release checks; historical tests are not current evidence.
The currently deployed public service worker and its precached assets were captured with SHA-256 hashes. An isolated bootstrap client verifies that the new worker stays waiting while the predecessor controls a live client, then activates after closure and preserves legacy recovery bytes plus native downloads. This passed in Chromium, Firefox and WebKit. It covers the exact deployed worker lifecycle; the entire historical editor UI and every previously installed release are not certified. No live deployment occurred.
The bootstrap is served under the existing docs navigation exclusion so it stays isolated from the editor. It waits for activation, then navigates to a precached icon to acquire a controlled client without starting the predecessor editor, even when the predecessor does not claim its first client. Changed workers must remain waiting until the controlled client closes; an uncontrolled observer waits for activation instead of relying on a fixed delay. Byte-identical workers exercise recovery and native downloads without expecting a replacement worker. The report records worker hashes, whether the worker changed, and the failing lifecycle stage plus browser errors when a check fails.
Release and rollback
Automated pushes to main validate and deploy once; the separate readiness workflow runs on pull requests or manual dispatch, not again on main pushes. Browser jobs are pinned to Ubuntu 24.04 and default to Chromium headless-shell-only installation and execution (PIVO_BROWSERS=chromium). Enable full_browser_validation when manually dispatching readiness or release to include Firefox and WebKit. Manual browser validation does not authorize unit tests; release units require the separate run_unit_tests opt-in, or use Manual unit validation. Local browser scripts still default to all three engines when PIVO_BROWSERS is unset. npm package validation remains unchanged and browser-free.
- Review and commit the changes, including lockfiles, shared manifests and this report.
- Explicitly run unit validation or dispatch Manual unit validation at that commit. The working-tree pass below does not certify a later commit.
- Run
npm run build,npm run docs:build,npm run build:standalone,npm run check:suite,npm run check:dependencies, andnpm run test:release, andnpm run test:standalone. Browser checks requirenpx playwright install chromium firefox webkit. - Push the release commit to main to deploy automatically. To also run unit validation, explicitly dispatch the release workflow on main with
run_unit_testsenabled. It validates the triggering SHA, captures the deployed predecessor withnpm run capture:predecessor, runsnpm run test:upgrade, and packages that same SHA. Deployment depends on all applicable validation passing. Predecessor capture reads public app assets; the browser tests use isolated local profiles. - Smoke-check the hosted app/docs, an installed PWA update, and an editable backup after release. To roll back, restore the known-good app commit and dispatch its release pipeline. Keep recovery v2 readable or download backups before returning to a build that only reads legacy storage; never delete databases during rollback.
Repository findings
P1 denotes high severity (artwork/recovery risk); P2 denotes moderate severity (runtime, budget or contract reliability). Listed remediations are implemented and validated unless a limitation is stated above.
| Priority | Finding / reproduction | Remediation | Source |
|---|---|---|---|
| P1 | Seed invalid localStorage recovery, reload, wait 800ms: demo overwrites backup | Explicit recovery UI, protected legacy migration and separate session records; browser regression verifies original survives | src/ui/store.tsx; src/ui/recovery.ts |
| P1 | Valid UI state can save beyond the open limit; file reads precede size checks | Save/open/commit share UTF-8 8 MiB limit; file.size checked first | src/core/serialize.ts; src/core/history.ts; src/ui/app.tsx |
| P1 | Texture import decodes unbounded input | PNG grammar/CRC/zlib/scanline validation before decoding; 32 MiB, 16384 dimension, 16777216 pixel limits | src/io/png-validation.ts; src/ui/paintWorkspace.tsx |
| P2 | Unsaved close has no guard; render-state dispatch bypasses history | Unsaved-close guard, visibility flush, durable wireframe commits | src/ui/store.tsx |
| P2 | Entry-count-only history and eager export bundle | 128 MiB retained-history budget; lazy export dialog; focus trap handles asynchronous mounting | src/core/history.ts; src/ui/app.tsx |
| P2 | Missing WebGL prevents native backup UI from mounting | Storage/file UI still mounts; viewport loss/restoration feedback | src/main.tsx; src/ui/modelWorkspace.tsx |
| P1 | Accept an update in one tab while another has unsaved edits | Per-tab reload consent; editing lock during accepting-tab recovery and activation; file worker code retained before cache replacement | src/ui/suite-pwa.ts; src/ui/suite-worker.ts |
Verification record
The verification commit is pending review/commit. The base commit identifies the audited starting point; the fingerprint identifies current source bytes. The SHA-256 fingerprint hashes sorted Git-tracked/nonignored source paths plus file bytes, excluding this report and its self-referential JSON record. Generated builds and browser artifacts are ignored. Run the manual release gate again for the final committed SHA.
json
{
"baseCommit": "909549a6a9e642f4710d26214663e42ff284744c",
"verificationTarget": "Validated source snapshot identified by workingTreeSha256; validation preceded the commit containing this record.",
"version": "0.8.1",
"unitTests": {
"passed": 328,
"failed": 0,
"authorization": "explicit user approval for this implementation",
"scope": "Prior production-readiness implementation; units were not rerun for subsequent worker, header, menu/About or shortcut/backdrop follow-ups."
},
"browserResults": {
"chromium": {
"passed": 15,
"failed": 0
},
"firefox": {
"passed": 15,
"failed": 0
},
"webkit": {
"passed": 15,
"failed": 0
}
},
"standalone": "Native backup, About documentation URL, shortcut reference and common backdrop passed in Chromium, Firefox and WebKit",
"independentOutputChecks": 8,
"applicationBuild": "passed",
"documentationBuild": "passed",
"sharedCopies": "verified",
"workingTreeSha256": "f1fc75d30b6891e5fd3cbe1f499e51d3e04134f108f75ccd78e984896062cb3f",
"deployedWorkerUpgrade": {
"passed": 3,
"failed": 0,
"origin": "https://bookklik-technologies.github.io/pivo-ortho/",
"serviceWorkerSha256": "6bee181f6fa57db6291f89ccfa1e4a40dd829ca2af3a835a52d8798c8dab476e"
},
"dependencies": {
"blocking": 0,
"buildOnlyAdvisories": 3,
"exception": "VitePress nested development-server path; static documentation build only"
},
"verificationDate": "2026-10-13",
"sharedSuiteVersion": "1.3.0",
"menuAboutChecks": {
"passed": 15,
"failed": 0,
"coverage": "Shared menus, light/dark desktop/compact presentation, keyboard navigation/focus, documentation inside About; Ortho also covers missing graphics."
},
"shortcutBackdropChecks": {
"passed": 15,
"failed": 0,
"coverage": "Shortcut layout, readable Ctrl/Cmd labels, compact/desktop light/dark layouts, fixed header/footer, scrolling, focus, unobstructed Close actions and common About/export/shortcut backdrops in Chromium, Firefox and WebKit; Craft also covers binding validation/apply/cancel/import/export/reset."
}
}Independent current-output inspection passed for PNG/GIF images through Pillow and for ZIP integrity, OBJ indices, glTF buffers and GLB/embedded textures through separate Python readers. This establishes file readability and structural integrity, not complete visual equivalence with every external editor.
npm run test:browser now runs the verified production matrix with current menu/export selectors. test:browser:legacy preserves the specialized historical runners; they are not a current release gate and their broader UI assertions need a separate refresh before relying on their results.
Menu and About follow-up — 13 October 2026
File/Edit/View/Help now share popup styling, 288-pixel width, 32-pixel rows, font weights, shortcut hints and keyboard behavior. Shared File/View commands appear first; existing editor-specific commands remain in separate sections. Plate's decorative menu icons were removed to match the suite's plain-label presentation. Documentation has moved from the header into each About dialog, which shares title/body/footer styling and one Close action. Escape restores the triggering menu; Tab stays in the About actions. Source references: the vendored suite.ts/suite.css and each app's menu/About adapter.
All 39 app/browser/layout cases passed (Craft 12, Ortho 15, Plate 12) across Chromium, Firefox and WebKit, including light/dark and compact/desktop layouts. Ortho's additional checks cover About and native backups without graphics: probing before renderer children mount prevents an unavailable WebGL context from hiding the header. All nine standalone app/engine checks passed for native downloads and absolute documentation URLs. Builds and shared manifests pass; units were not rerun for this follow-up. npm run test:menus is included in automated browser validation.
Shortcut and backdrop follow-up — 13 October 2026
Reproduction: open Help → Keyboard shortcuts in each editor. Ortho showed a static table, Craft opened raw editable chords, and Plate combined its own usage tables; titles, spacing, dismissal controls and modal scrims differed. Shared suite 1.3.0 now provides a 640-pixel reference dialog with a fixed header/footer, scrolling body, Document/Editor/Viewport sections, readable key labels, consistent Close action and focus restoration. Ctrl on Windows/Linux becomes Cmd on macOS; established editor-specific tool bindings remain unchanged. Craft retains current binding customization, validation, import/export, defaults and Apply/Cancel behind Customize bindings. All application modal backdrops use rgba(3,8,13,.6) without blur in light and dark appearances, including About and export. Modal overlays also sit above page notifications so compact Close actions cannot be covered by startup tips.
Source references: canonical/vendored suite.css and suite.ts; Craft apps/editor/src/workspace-controls.ts, Ortho src/ui/dialogs.tsx, and Plate src/main.ts. scripts/browser-menus.mjs verifies presentation, actual content bounds, keyboard focus, key notation and matching scrims. Its expanded matrix passes 84 cases overall (Craft 27, Ortho 30, Plate 27); the standalone runner passes nine app/engine cases including the new shortcut reference. Windows WebKit can report scrollWidth including the vertical scrollbar, so clipping is checked against descendant bounds rather than that metric. Application, documentation and standalone builds plus shared manifests pass. Units were not rerun; their recorded totals remain historical readiness evidence.